feat: flexible intake — deferred variables + prepared sessions (#103)

* feat: flexible intake — deferred variables + prepared sessions

Remove blocking intake form modal. Variables are now filled inline during
flow execution or pre-filled via prepared sessions. Adds PATCH /sessions/{id}/variables
endpoint, POST /sessions/prepare for session pre-staging, inline variable prompts
in StepDetail, editable Session Variables panel, and "Prepared for You" dashboard section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: pass treeData directly to startSession to avoid stale state

setTree(treeData) hasn't committed when startSession runs immediately
after, so tree is still null and getStepsFromTree returns []. This
caused the step detail area to render empty on new session start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire PrepareSessionModal entry point in Flow Library

Add "Prepare session" button (clipboard icon) to grid, list, and table
views for procedural/maintenance flows. Clicking fetches tree intake
fields and account members, then opens PrepareSessionModal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #103.
This commit is contained in:
chihlasm
2026-03-10 09:49:51 -04:00
committed by GitHub
parent 4727106141
commit ccd06c9ed4
25 changed files with 1214 additions and 102 deletions

View File

@@ -5,6 +5,21 @@
* - [USER_INPUT:prompt] → replaced with variables[prompt]
* - [SAVE_AS:name] → removed from display
*/
export interface UnresolvedVariable {
variableName: string
token: string // e.g. "[VAR:server_name]"
}
export interface ResolveResult {
text: string
unresolvedVariables: UnresolvedVariable[]
}
/**
* Resolve variables in text, replacing tokens with values.
* Missing/empty values are replaced with "N/A".
*/
export function resolveVariables(text: string, variables: Record<string, string>): string {
// Replace [VAR:name] — empty/missing values show "N/A"
let result = text.replace(/\[VAR:([^\]]+)\]/g, (_, name) => {
@@ -26,6 +41,41 @@ export function resolveVariables(text: string, variables: Record<string, string>
return result
}
/**
* Resolve variables but also return info about which variables are unresolved.
* Unresolved variables are left as their original tokens in the text (not replaced with N/A).
*/
export function resolveVariablesWithStatus(text: string, variables: Record<string, string>): ResolveResult {
const unresolvedVariables: UnresolvedVariable[] = []
// Replace [VAR:name] — resolved values get substituted, unresolved stay as tokens
let result = text.replace(/\[VAR:([^\]]+)\]/g, (match, name) => {
const key = name.trim()
const value = variables[key]
if (value && value.trim()) {
return value
}
unresolvedVariables.push({ variableName: key, token: match })
return match // Keep original token for inline prompt rendering
})
// Replace [USER_INPUT:prompt]
result = result.replace(/\[USER_INPUT:([^\]]+)\]/g, (match, prompt) => {
const key = prompt.trim()
const value = variables[key]
if (value && value.trim()) {
return value
}
unresolvedVariables.push({ variableName: key, token: match })
return match
})
// Remove [SAVE_AS:name]
result = result.replace(/\[SAVE_AS:[^\]]+\]/g, '')
return { text: result, unresolvedVariables }
}
/**
* Extract all [USER_INPUT:prompt] tokens from text.
* Returns array of prompt strings.