feat(profiles): add typed live step config profiles

Profiles store script + default config per owner. Workflow steps reference
them with profile:, overlay keys win, and the UI marks overrides. Profile
name is immutable after create so YAML refs stay stable.

Co-authored-by: Nasyarobby Putra <nasyarobby@gmail.com>
This commit is contained in:
Cursor Agent
2026-08-21 06:12:49 +00:00
co-authored by nsrb
parent 210fdb2244
commit e84432a492
25 changed files with 1512 additions and 123 deletions
+30 -17
View File
@@ -6,20 +6,22 @@ export const SET_STEP_SCRIPT = "set";
* @typedef {{ alias: string, from: string }} NeedEdge
* @typedef {{
* kind: "script",
* script: string,
* config: unknown | null,
* expression?: undefined,
* id: string | null,
* needsKind: "none" | "list" | "map",
* needs: NeedEdge[],
* when: string | null,
* }} ParsedScriptStep
* script: string,
* profile: string | null,
* config: unknown | null,
* expression?: undefined,
* id: string | null,
* needsKind: "none" | "list" | "map",
* needs: NeedEdge[],
* when: string | null,
* }} ParsedScriptStep
* @typedef {{
* kind: "set",
* script: typeof SET_STEP_SCRIPT,
* config: { expression: string },
* expression: string,
* id: string | null,
* script: typeof SET_STEP_SCRIPT,
* profile: null,
* config: { expression: string },
* expression: string,
* id: string | null,
* needsKind: "none" | "list" | "map",
* needs: NeedEdge[],
* when: string | null,
@@ -85,6 +87,7 @@ export function parseScriptStep(step) {
return {
kind: "script",
script: step,
profile: null,
config: null,
id: null,
needsKind: "none",
@@ -97,24 +100,33 @@ export function parseScriptStep(step) {
}
const hasScript = step.script != null && step.script !== "";
const hasProfile = step.profile != null && step.profile !== "";
const hasSet = step.set != null;
if (hasScript && hasSet) {
throw new Error("Step cannot have both script and set");
}
if (hasProfile && hasSet) {
throw new Error("Step cannot have both profile and set");
}
if (hasSet) {
return parseSetStep(step);
}
if (hasScript) {
if (typeof step.script !== "string") {
throw new Error(`Invalid script step: ${JSON.stringify(step)}`);
}
if (hasProfile && typeof step.profile !== "string") {
throw new Error(`Invalid profile: ${JSON.stringify(step.profile)}`);
}
if (hasScript && typeof step.script !== "string") {
throw new Error(`Invalid script step: ${JSON.stringify(step)}`);
}
if (hasScript || hasProfile) {
const { needsKind, needs } = parseNeeds(step.needs);
return {
kind: "script",
script: step.script,
script: hasScript ? step.script : "",
profile: hasProfile ? step.profile : null,
config: step.config ?? null,
id: parseOptionalId(step.id),
needsKind,
@@ -265,6 +277,7 @@ function parseSetStep(step) {
return {
kind: "set",
script: SET_STEP_SCRIPT,
profile: null,
config: { expression },
expression,
id: parseOptionalId(step.id),