primitive-admin 1.0.60 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/bin/primitive.js +4 -0
  2. package/dist/bin/primitive.js.map +1 -1
  3. package/dist/src/commands/admins.js +22 -8
  4. package/dist/src/commands/admins.js.map +1 -1
  5. package/dist/src/commands/analytics.js +60 -0
  6. package/dist/src/commands/analytics.js.map +1 -1
  7. package/dist/src/commands/blob-buckets.js +37 -2
  8. package/dist/src/commands/blob-buckets.js.map +1 -1
  9. package/dist/src/commands/connections.d.ts +2 -0
  10. package/dist/src/commands/connections.js +95 -0
  11. package/dist/src/commands/connections.js.map +1 -0
  12. package/dist/src/commands/init.js +2 -2
  13. package/dist/src/commands/init.js.map +1 -1
  14. package/dist/src/commands/sessions.d.ts +2 -0
  15. package/dist/src/commands/sessions.js +63 -0
  16. package/dist/src/commands/sessions.js.map +1 -0
  17. package/dist/src/commands/skill.js +2 -2
  18. package/dist/src/commands/skill.js.map +1 -1
  19. package/dist/src/commands/sync.js +120 -13
  20. package/dist/src/commands/sync.js.map +1 -1
  21. package/dist/src/commands/workflows.js +56 -13
  22. package/dist/src/commands/workflows.js.map +1 -1
  23. package/dist/src/lib/api-client.d.ts +89 -0
  24. package/dist/src/lib/api-client.js +118 -15
  25. package/dist/src/lib/api-client.js.map +1 -1
  26. package/dist/src/lib/generated-allowlist.js +1 -0
  27. package/dist/src/lib/generated-allowlist.js.map +1 -1
  28. package/dist/src/lib/skill-installer.d.ts +4 -2
  29. package/dist/src/lib/skill-installer.js +139 -11
  30. package/dist/src/lib/skill-installer.js.map +1 -1
  31. package/dist/src/lib/workflow-fragments.d.ts +23 -0
  32. package/dist/src/lib/workflow-fragments.js +229 -8
  33. package/dist/src/lib/workflow-fragments.js.map +1 -1
  34. package/dist/src/lib/workflow-payload.d.ts +1 -1
  35. package/dist/src/lib/workflow-payload.js +17 -0
  36. package/dist/src/lib/workflow-payload.js.map +1 -1
  37. package/dist/src/lib/workflow-toml-validator.d.ts +57 -1
  38. package/dist/src/lib/workflow-toml-validator.js +104 -1
  39. package/dist/src/lib/workflow-toml-validator.js.map +1 -1
  40. package/package.json +1 -1
@@ -14,6 +14,29 @@
14
14
  * - Unique step ids validated post-expansion; collisions name both
15
15
  * locations in the error message.
16
16
  *
17
+ * Parameterized includes (#1448):
18
+ * - Two include forms are supported. The bare form
19
+ * `include = ["name", ...]` (an array of fragment-name strings) is
20
+ * unchanged. The parameterized form uses `[[include]]` array-of-tables:
21
+ *
22
+ * [[include]]
23
+ * fragment = "lifecycle-email" # required
24
+ * runIf = "input.type == 'x'" # optional; ANDed onto each step
25
+ * with = { id = "...", subject = "..." } # params, exposed as {{ params.* }}
26
+ *
27
+ * - A file uses one form or the other — mixing string and table entries in a
28
+ * single `include` array is an error.
29
+ * - `{{ params.* }}` references inside the fragment's steps are substituted
30
+ * at EXPAND time from the include's `with` table. A whole-string
31
+ * `{{ params.x }}` splices the raw typed value (number/bool/table);
32
+ * an embedded `{{ params.x }}` inside a larger string stringifies it.
33
+ * A missing param is a hard error. Only the `params.` namespace is
34
+ * touched — every other `{{ ... }}` template passes through to the server
35
+ * verbatim, and `params.` never survives into the expanded output.
36
+ * - The include-level `runIf` (CEL) is ANDed onto every expanded step:
37
+ * both present → `(<includeRunIf>) && (<stepRunIf>)`; one present → that
38
+ * one; neither → no runIf.
39
+ *
17
40
  * Wiring: `parseTomlFile()` in `cli/src/commands/sync.ts` calls
18
41
  * `expandWorkflowTomlData()` after parsing. All 24 push parse sites in
19
42
  * sync.ts route through that single seam, so the expansion is uniform.
@@ -14,6 +14,29 @@
14
14
  * - Unique step ids validated post-expansion; collisions name both
15
15
  * locations in the error message.
16
16
  *
17
+ * Parameterized includes (#1448):
18
+ * - Two include forms are supported. The bare form
19
+ * `include = ["name", ...]` (an array of fragment-name strings) is
20
+ * unchanged. The parameterized form uses `[[include]]` array-of-tables:
21
+ *
22
+ * [[include]]
23
+ * fragment = "lifecycle-email" # required
24
+ * runIf = "input.type == 'x'" # optional; ANDed onto each step
25
+ * with = { id = "...", subject = "..." } # params, exposed as {{ params.* }}
26
+ *
27
+ * - A file uses one form or the other — mixing string and table entries in a
28
+ * single `include` array is an error.
29
+ * - `{{ params.* }}` references inside the fragment's steps are substituted
30
+ * at EXPAND time from the include's `with` table. A whole-string
31
+ * `{{ params.x }}` splices the raw typed value (number/bool/table);
32
+ * an embedded `{{ params.x }}` inside a larger string stringifies it.
33
+ * A missing param is a hard error. Only the `params.` namespace is
34
+ * touched — every other `{{ ... }}` template passes through to the server
35
+ * verbatim, and `params.` never survives into the expanded output.
36
+ * - The include-level `runIf` (CEL) is ANDed onto every expanded step:
37
+ * both present → `(<includeRunIf>) && (<stepRunIf>)`; one present → that
38
+ * one; neither → no runIf.
39
+ *
17
40
  * Wiring: `parseTomlFile()` in `cli/src/commands/sync.ts` calls
18
41
  * `expandWorkflowTomlData()` after parsing. All 24 push parse sites in
19
42
  * sync.ts route through that single seam, so the expansion is uniform.
@@ -23,6 +46,22 @@
23
46
  import { existsSync, readFileSync } from "fs";
24
47
  import { dirname, join, basename } from "path";
25
48
  import { parseConfigToml } from "./config-toml.js";
49
+ /**
50
+ * True only for a genuine plain TOML table: a non-null, non-array object whose
51
+ * prototype is `Object.prototype` or `null`. This deliberately rejects the
52
+ * non-plain objects that a bare `typeof x === "object"` check would accept —
53
+ * notably smol-toml's `TomlDate` (a `Date` subclass) and any other boxed value
54
+ * — so a TOML date/time literal (`with = 1979-05-27T07:32:00Z`) can never slip
55
+ * through a guard that expects a parameter table. Used everywhere a `with` /
56
+ * params sub-table is required so the plain-table rule is applied consistently.
57
+ */
58
+ function isPlainTable(value) {
59
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
60
+ return false;
61
+ }
62
+ const proto = Object.getPrototypeOf(value);
63
+ return proto === Object.prototype || proto === null;
64
+ }
26
65
  /**
27
66
  * Read and expand a workflow TOML file from disk. Returns the parsed
28
67
  * TOML with all `include` fragments spliced in. If the file has no
@@ -58,16 +97,35 @@ export function expandWorkflowTomlData(parsed, workflowPath) {
58
97
  ? parsed.steps
59
98
  : [];
60
99
  const allOriginated = [];
61
- for (const fragmentName of includeList) {
62
- if (typeof fragmentName !== "string" || fragmentName.length === 0) {
63
- throw new Error(`Workflow '${workflowPath}' has an invalid include entry: ${JSON.stringify(fragmentName)}. Each entry must be a fragment name string.`);
100
+ // Classify each entry as a bare fragment-name string or a parameterized
101
+ // `[[include]]` table. A single file must use one form throughout. A
102
+ // `[[include]]` entry must be a genuine plain table a non-plain object
103
+ // (e.g. a TOML date literal parsed to a `TomlDate`) is neither a valid
104
+ // string entry nor a valid table and falls through to the per-entry error.
105
+ const isTable = (e) => isPlainTable(e);
106
+ const hasStringEntry = includeList.some((e) => typeof e === "string");
107
+ const hasTableEntry = includeList.some((e) => isTable(e));
108
+ if (hasStringEntry && hasTableEntry) {
109
+ throw new Error(`Workflow '${workflowPath}' mixes bare-string include entries and [[include]] tables in one 'include' array. Pick one form per file: either \`include = ["a", "b"]\` or repeated \`[[include]]\` tables.`);
110
+ }
111
+ includeList.forEach((entry, index) => {
112
+ if (typeof entry === "string") {
113
+ if (entry.length === 0) {
114
+ throw new Error(`Workflow '${workflowPath}' has an invalid include entry: ${JSON.stringify(entry)}. Each entry must be a fragment name string.`);
115
+ }
116
+ const fragmentPath = join(fragmentsDir, `${entry}.toml`);
117
+ const fragment = readFragmentSafely(fragmentPath, workflowPath, entry);
118
+ for (const step of fragment.steps) {
119
+ allOriginated.push({ step, origin: `fragment '${entry}'` });
120
+ }
121
+ return;
64
122
  }
65
- const fragmentPath = join(fragmentsDir, `${fragmentName}.toml`);
66
- const fragment = readFragmentSafely(fragmentPath, workflowPath, fragmentName);
67
- for (const step of fragment.steps) {
68
- allOriginated.push({ step, origin: `fragment '${fragmentName}'` });
123
+ if (isTable(entry)) {
124
+ expandParameterizedInclude(entry, index, fragmentsDir, workflowPath, allOriginated);
125
+ return;
69
126
  }
70
- }
127
+ throw new Error(`Workflow '${workflowPath}' has an invalid include entry: ${JSON.stringify(entry)}. Each entry must be a fragment name string or a [[include]] table.`);
128
+ });
71
129
  for (const step of workflowOwnSteps) {
72
130
  allOriginated.push({ step, origin: `workflow '${basename(workflowPath)}'` });
73
131
  }
@@ -103,6 +161,169 @@ function readFragmentSafely(fragmentPath, workflowPath, fragmentName) {
103
161
  : [];
104
162
  return { steps };
105
163
  }
164
+ // ── Parameterized include expansion (#1448) ─────────────────────────────────
165
+ const ALLOWED_INCLUDE_KEYS = new Set(["fragment", "runIf", "with"]);
166
+ // The dotted path after `params.`. Each segment is a TOML bare key, which may
167
+ // contain letters, digits, `_` and `-`; segments are joined by dots. Keeping
168
+ // the full bare-key charset means hyphenated keys like `subject-line` expand
169
+ // instead of leaking `{{ params.subject-line }}` to the server.
170
+ const PARAM_PATH = "[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+)*";
171
+ // A string that is EXACTLY one `{{ params.<path> }}` token (raw typed splice).
172
+ const WHOLE_PARAM_RE = new RegExp(`^\\{\\{\\s*params\\.(${PARAM_PATH})\\s*\\}\\}$`);
173
+ // Any embedded `{{ params.<path> }}` token (string interpolation).
174
+ const EMBEDDED_PARAM_RE = new RegExp(`\\{\\{\\s*params\\.(${PARAM_PATH})\\s*\\}\\}`, "g");
175
+ function expandParameterizedInclude(entry, index, fragmentsDir, workflowPath, allOriginated) {
176
+ const includeLabel = `[[include]] #${index + 1}`;
177
+ for (const key of Object.keys(entry)) {
178
+ if (!ALLOWED_INCLUDE_KEYS.has(key)) {
179
+ throw new Error(`Workflow '${workflowPath}' has an unknown key '${key}' in ${includeLabel}. Allowed keys are: fragment, runIf, with.`);
180
+ }
181
+ }
182
+ const fragmentName = entry.fragment;
183
+ if (typeof fragmentName !== "string" || fragmentName.length === 0) {
184
+ throw new Error(`Workflow '${workflowPath}' has a ${includeLabel} missing a valid 'fragment' name (got ${JSON.stringify(fragmentName)}).`);
185
+ }
186
+ const includeRunIf = entry.runIf;
187
+ if (includeRunIf !== undefined && typeof includeRunIf !== "string") {
188
+ throw new Error(`Workflow '${workflowPath}' has a non-string 'runIf' in ${includeLabel} (fragment '${fragmentName}'). runIf must be a CEL string.`);
189
+ }
190
+ const withParams = entry.with;
191
+ // `with` must be a genuine plain table. `isPlainTable` rejects arrays and any
192
+ // non-plain object — including a TOML date/time literal (`with = 1979-…Z`),
193
+ // which parses to a `TomlDate` and would otherwise be accepted as a param
194
+ // table by a bare `typeof === "object"` check.
195
+ if (withParams !== undefined && !isPlainTable(withParams)) {
196
+ throw new Error(`Workflow '${workflowPath}' has a non-table 'with' in ${includeLabel} (fragment '${fragmentName}'). 'with' must be a table of parameters.`);
197
+ }
198
+ const params = withParams ?? {};
199
+ const fragmentPath = join(fragmentsDir, `${fragmentName}.toml`);
200
+ const fragment = readFragmentSafely(fragmentPath, workflowPath, fragmentName);
201
+ const ctx = {
202
+ fragment: fragmentName,
203
+ includeLabel,
204
+ workflowPath,
205
+ };
206
+ for (const rawStep of fragment.steps) {
207
+ const step = substituteParamsDeep(rawStep, params, ctx);
208
+ applyIncludeRunIf(step, includeRunIf, ctx);
209
+ allOriginated.push({
210
+ step,
211
+ origin: `fragment '${fragmentName}' (${includeLabel})`,
212
+ });
213
+ }
214
+ }
215
+ /**
216
+ * Recursively substitute `{{ params.* }}` references throughout a fragment
217
+ * step. Returns a new value; the input is not mutated. Only the `params.`
218
+ * namespace is touched — every other `{{ ... }}` template is preserved
219
+ * verbatim for the server to render.
220
+ */
221
+ function substituteParamsDeep(node, params, ctx) {
222
+ if (typeof node === "string") {
223
+ return substituteParamsInString(node, params, ctx);
224
+ }
225
+ if (Array.isArray(node)) {
226
+ return node.map((el) => substituteParamsDeep(el, params, ctx));
227
+ }
228
+ if (node !== null && typeof node === "object") {
229
+ // Only recurse into plain tables. Non-plain objects (e.g. smol-toml's
230
+ // `TomlDate`, which extends `Date`) carry internal state that is not
231
+ // enumerable, so rebuilding them via `Object.entries` would collapse them
232
+ // to `{}`. TOML date/time literals can only appear as leaf param values —
233
+ // there is nothing to substitute inside them — so pass them through
234
+ // unchanged.
235
+ const proto = Object.getPrototypeOf(node);
236
+ if (proto !== Object.prototype && proto !== null) {
237
+ return node;
238
+ }
239
+ // Clone into a null-prototype object so a legal TOML key that collides with
240
+ // a prototype member — `__proto__`, `constructor`, `prototype` — is written
241
+ // as an ordinary own data property instead of tripping the `__proto__`
242
+ // setter (which would drop the field or reparent the clone). `Object.entries`
243
+ // reads only own enumerable keys, so no inherited members leak in either.
244
+ const out = Object.create(null);
245
+ for (const [k, v] of Object.entries(node)) {
246
+ out[k] = substituteParamsDeep(v, params, ctx);
247
+ }
248
+ return out;
249
+ }
250
+ return node;
251
+ }
252
+ function substituteParamsInString(value, params, ctx) {
253
+ // Whole-string `{{ params.x }}` → splice the raw typed value.
254
+ const whole = value.match(WHOLE_PARAM_RE);
255
+ if (whole) {
256
+ return resolveParamPath(whole[1], params, ctx);
257
+ }
258
+ // Embedded `{{ params.x }}` → stringify the resolved value in place.
259
+ return value.replace(EMBEDDED_PARAM_RE, (_match, path) => stringifyParamValue(resolveParamPath(path, params, ctx)));
260
+ }
261
+ /**
262
+ * Resolve a dotted `params.<path>` reference against the include's `with`
263
+ * table. A missing key (or missing sub-path) is a hard error naming the
264
+ * fragment, the param, and the include.
265
+ */
266
+ function resolveParamPath(path, params, ctx) {
267
+ const segments = path.split(".");
268
+ let cursor = params;
269
+ for (const segment of segments) {
270
+ // Resolve only OWN properties at each segment. Using `in` here would walk
271
+ // the prototype chain, so `{{ params.constructor }}`, `{{ params.toString }}`,
272
+ // `{{ params.__proto__ }}`, or `{{ params.hasOwnProperty }}` would resolve
273
+ // an inherited `Object.prototype` member instead of hard-erroring like any
274
+ // other missing param. `Object.hasOwn` restricts the lookup to real,
275
+ // author-declared keys.
276
+ if (cursor === null ||
277
+ typeof cursor !== "object" ||
278
+ Array.isArray(cursor) ||
279
+ !Object.hasOwn(cursor, segment)) {
280
+ throw new Error(`Fragment '${ctx.fragment}' references '{{ params.${path} }}' but no matching key exists in the ${ctx.includeLabel} 'with' table (workflow '${ctx.workflowPath}').`);
281
+ }
282
+ cursor = cursor[segment];
283
+ }
284
+ return cursor;
285
+ }
286
+ function stringifyParamValue(value) {
287
+ if (value === null || value === undefined)
288
+ return "";
289
+ if (typeof value === "object")
290
+ return JSON.stringify(value);
291
+ return String(value);
292
+ }
293
+ /**
294
+ * AND the include-level `runIf` onto a step's own `runIf`. Each operand is
295
+ * paren-wrapped because CEL's `&&` binds tighter than `||`. Mutates `step`.
296
+ */
297
+ function applyIncludeRunIf(step, includeRunIf, ctx) {
298
+ // A non-string step `runIf` (e.g. `runIf = 123`, or a param that spliced a
299
+ // non-string value in) must hard-error, consistent with the include-level
300
+ // non-string `runIf` rejection. Otherwise it would fall through the
301
+ // string-only guard below and be silently dropped, turning a guarded step
302
+ // into an unconditional one.
303
+ if ("runIf" in step &&
304
+ step.runIf !== undefined &&
305
+ typeof step.runIf !== "string") {
306
+ throw new Error(`Fragment '${ctx.fragment}' produced a non-string 'runIf' (got ${JSON.stringify(step.runIf)}) in ${ctx.includeLabel} (workflow '${ctx.workflowPath}'). runIf must be a CEL string.`);
307
+ }
308
+ const include = typeof includeRunIf === "string" && includeRunIf.length > 0
309
+ ? includeRunIf
310
+ : undefined;
311
+ const own = typeof step.runIf === "string" && step.runIf.length > 0
312
+ ? step.runIf
313
+ : undefined;
314
+ let combined;
315
+ if (include && own)
316
+ combined = `(${include}) && (${own})`;
317
+ else
318
+ combined = include ?? own;
319
+ if (combined === undefined) {
320
+ if ("runIf" in step)
321
+ delete step.runIf;
322
+ }
323
+ else {
324
+ step.runIf = combined;
325
+ }
326
+ }
106
327
  function assertUniqueStepIds(originated, workflowPath) {
107
328
  const seen = new Map();
108
329
  for (const { step, origin } of originated) {
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-fragments.js","sourceRoot":"","sources":["../../../src/lib/workflow-fragments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AASnD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB;IACjD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAwB,CAAC;IAC/D,OAAO,sBAAsB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAA2B,EAC3B,YAAoB;IAEpB,sEAAsE;IACtE,sEAAsE;IACtE,0DAA0D;IAC1D,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,MAA0B,CAAC;IACpC,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,aAAa,YAAY,qFAAqF,CAC/G,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,8CAA8C;IAC9C,0DAA0D;IAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAE7E,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAClD,CAAC,CAAE,MAAM,CAAC,KAAoC;QAC9C,CAAC,CAAC,EAAE,CAAC;IAOP,MAAM,aAAa,GAAqB,EAAE,CAAC;IAE3C,KAAK,MAAM,YAAY,IAAI,WAAW,EAAE,CAAC;QACvC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CACb,aAAa,YAAY,mCAAmC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,8CAA8C,CACvI,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,YAAY,OAAO,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;QAC9E,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAClC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,YAAY,GAAG,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,mBAAmB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAEjD,sEAAsE;IACtE,kEAAkE;IAClE,8CAA8C;IAC9C,MAAM,MAAM,GAAwB,EAAE,GAAG,MAAM,EAAE,CAAC;IAClD,OAAO,MAAM,CAAC,OAAO,CAAC;IACtB,MAAM,CAAC,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,MAA0B,CAAC;AACpC,CAAC;AAMD,SAAS,kBAAkB,CACzB,YAAoB,EACpB,YAAoB,EACpB,YAAoB;IAEpB,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,aAAa,YAAY,wBAAwB,YAAY,qCAAqC,YAAY,IAAI,CACnH,CAAC;IACJ,CAAC;IACD,IAAI,MAA2B,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,GAAG,eAAe,CAAC,OAAO,CAAwB,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,6BAA6B,YAAY,SAAS,YAAY,MAAM,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC1F,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,aAAa,YAAY,SAAS,YAAY,8HAA8H,CAC7K,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,aAAa,YAAY,SAAS,YAAY,6EAA6E,CAC5H,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACvC,CAAC,CAAE,MAAM,CAAC,KAAoC;QAC9C,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAC1B,UAAgE,EAChE,YAAoB;IAEpB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;QACpB,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI;YAAE,SAAS,CAAC,iDAAiD;QAChG,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CACb,YAAY,EAAE,4CAA4C,YAAY,eAAe,WAAW,aAAa,MAAM,GAAG,CACvH,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"workflow-fragments.js","sourceRoot":"","sources":["../../../src/lib/workflow-fragments.ts"],"names":[],"mappings":"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"}
@@ -73,7 +73,7 @@ export declare function parseWorkflowExpressionsToml(tomlData: any): WorkflowExp
73
73
  * the recurring bug class this builder closes. `update` omits `syncCallable`
74
74
  * (deferred second PATCH, #807); everything else is shared.
75
75
  */
76
- export declare const WORKFLOW_PAYLOAD_FIELDS_CREATE: readonly ["name", "description", "status", "accessRule", "runAs", "capabilities", "perUserMaxRunning", "perUserMaxQueued", "perAppMaxRunning", "perAppMaxQueued", "queueTtlSeconds", "dequeueOrder", "requiresClientApply", "inputSchema", "outputSchema", "syncCallable"];
76
+ export declare const WORKFLOW_PAYLOAD_FIELDS_CREATE: readonly ["name", "description", "status", "accessRule", "runAs", "capabilities", "perUserMaxRunning", "perUserMaxQueued", "perAppMaxRunning", "perAppMaxQueued", "queueTtlSeconds", "dequeueOrder", "requiresClientApply", "inputSchema", "outputSchema", "lock", "syncCallable"];
77
77
  export declare const WORKFLOW_PAYLOAD_FIELDS_UPDATE: ReadonlyArray<string>;
78
78
  /**
79
79
  * Build the workflow payload's `[workflow]`-derived fields from a parsed TOML
@@ -96,6 +96,7 @@ export const WORKFLOW_PAYLOAD_FIELDS_CREATE = [
96
96
  "requiresClientApply",
97
97
  "inputSchema",
98
98
  "outputSchema",
99
+ "lock",
99
100
  "syncCallable",
100
101
  ];
101
102
  export const WORKFLOW_PAYLOAD_FIELDS_UPDATE = WORKFLOW_PAYLOAD_FIELDS_CREATE.filter((f) => f !== "syncCallable");
@@ -160,6 +161,22 @@ export function buildWorkflowPayloadFromToml(workflow, { mode }) {
160
161
  : create
161
162
  ? undefined
162
163
  : null,
164
+ // #1972 — declarative run-scoped lock (`[workflow.lock]`, #1518 Phase 3).
165
+ // A TOML-owned nested-object field, mirroring the schemas above. Presence-
166
+ // keyed, not truthiness-keyed: forward the value whenever the KEY is present
167
+ // (`!== undefined`) — the server's create/PATCH accept an object OR a JSON
168
+ // string, so a present-but-malformed falsy value (`lock = false`/`0`) must
169
+ // be forwarded so the server surfaces its validation error, rather than
170
+ // being silently treated as absent (dropped on create, cleared on update).
171
+ // Absent on create → omit (server default: no lock); absent on update →
172
+ // null so removing `[workflow.lock]` clears the server-side lock
173
+ // (config-as-code). Before this the field was dropped from both sync paths,
174
+ // so a pull → push cycle silently lost the lock (#1972).
175
+ lock: workflow.lock !== undefined
176
+ ? workflow.lock
177
+ : create
178
+ ? undefined
179
+ : null,
163
180
  };
164
181
  // syncCallable — create includes it (raw boolean pass-through); update omits
165
182
  // it (deferred second PATCH, #807 — see module doc).
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-payload.js","sourceRoot":"","sources":["../../../src/lib/workflow-payload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-payload.js","sourceRoot":"","sources":["../../../src/lib/workflow-payload.ts"],"names":[],"mappings":"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"}
@@ -54,6 +54,9 @@ export declare const KNOWN_KINDS_FOR_DRIFT_GUARD: ReadonlySet<string>;
54
54
  * errors:
55
55
  * - `__steps_shape__`: `steps` is not an array (table or scalar).
56
56
  * - `__step_shape__`: a step is not an object.
57
+ * - `__workflow_system_access_rule__`: `[workflow] runAs = "system"` with a
58
+ * non-empty `accessRule` — dead config the server rejects (#1447/#1258).
59
+ * A workflow-level error (not tied to a step): `stepIndex: -1, stepId: null`.
57
60
  * `hint` is a short, user-facing explanation (used by
58
61
  * `formatWorkflowTomlErrors` to render the multi-line diagnostic).
59
62
  * `parentStepId` is set when this error came from a `collect` step's
@@ -70,14 +73,67 @@ export type WorkflowTomlError = {
70
73
  hint: string;
71
74
  parentStepId?: string | null;
72
75
  };
76
+ /**
77
+ * #1447 workflow-identity predicate, extracted (codex review, 2026-07-15) so
78
+ * command sites that apply command-line metadata overrides can re-run it
79
+ * against the merged/effective workflow rather than only the parsed file.
80
+ *
81
+ * `runAs = "system"` + a non-empty `accessRule` is dead config: a system run
82
+ * can only be started by the system and never evaluates its accessRule, so any
83
+ * non-empty rule is inert. The server rejects this at save time (#1258,
84
+ * `src/workflows/definition-store.ts:271-280`); catching it locally keeps
85
+ * `sync push` all-or-nothing instead of failing mid-push and leaving partial
86
+ * server state (#1418 drift).
87
+ *
88
+ * Mirrors the server predicate byte-for-byte: returns the sentinel error only
89
+ * when `runAs === "system"` AND `typeof accessRule === "string"` AND
90
+ * `accessRule.trim() !== ""`. Default/unset/empty/whitespace-only runAs or
91
+ * accessRule (and a bare non-string boolean accessRule) return `null`.
92
+ *
93
+ * @param workflow The workflow-metadata object — the `[workflow]` table, or
94
+ * for commands that accept unwrapped root-level metadata, the root TOML
95
+ * object (`tomlData.workflow || tomlData`). Non-object inputs return `null`.
96
+ */
97
+ export declare function validateWorkflowIdentity(workflow: any): WorkflowTomlError | null;
98
+ /** The runAs / accessRule pair the identity lint reads. */
99
+ export interface WorkflowIdentityFields {
100
+ runAs?: unknown;
101
+ accessRule?: unknown;
102
+ }
103
+ /**
104
+ * #1447 (maintainer decision, 2026-07-21): compute the EFFECTIVE workflow
105
+ * identity that an `update --from-file` push will leave on the server — the
106
+ * merge of the persisted record with the incoming file/flags.
107
+ *
108
+ * `applyWorkflowBody` omits undefined fields, so the server retains whichever
109
+ * side of the runAs/accessRule pair the incoming payload doesn't set. Linting
110
+ * the incoming payload alone therefore misses the case where the OTHER side is
111
+ * already `system` / a stored rule: an existing `runAs="system"` workflow plus
112
+ * a file adding only an `accessRule`, or a file flipping a workflow with a
113
+ * stored rule to `runAs="system"`. Both pass a payload-only lint and are then
114
+ * rejected by the server's PATCH. Merging the two before `validateWorkflowIdentity`
115
+ * catches them locally at zero extra cost — the persisted record is already
116
+ * fetched at the call site.
117
+ *
118
+ * Presence semantics mirror the update payload builder: a field PRESENT in
119
+ * `incoming` (including an empty-string clear) overrides the stored value; an
120
+ * ABSENT field (undefined) falls back to what the server keeps.
121
+ */
122
+ export declare function effectiveWorkflowIdentity(existing: WorkflowIdentityFields | null | undefined, incoming: WorkflowIdentityFields | null | undefined): WorkflowIdentityFields;
73
123
  /**
74
124
  * Walk a parsed workflow TOML document and return all unknown-field errors.
75
125
  *
76
126
  * @param tomlData The output of `parseConfigToml()` for a workflow TOML file.
127
+ * @param opts.skipWorkflowIdentity When true, suppress the #1447 workflow
128
+ * identity check (`runAs="system"` + non-empty `accessRule`). Callers that
129
+ * merge command-line overrides after parsing re-run `validateWorkflowIdentity`
130
+ * against the effective metadata themselves.
77
131
  * @returns An array of error objects, one per offending field. Empty if no
78
132
  * errors were found.
79
133
  */
80
- export declare function validateWorkflowToml(tomlData: any): WorkflowTomlError[];
134
+ export declare function validateWorkflowToml(tomlData: any, opts?: {
135
+ skipWorkflowIdentity?: boolean;
136
+ }): WorkflowTomlError[];
81
137
  /**
82
138
  * Render a multi-line diagnostic for a list of errors. Designed for the
83
139
  * shape called out in the issue:
@@ -57,18 +57,115 @@ export const ALLOWLISTED_FIELDS_FOR_DRIFT_GUARD = ALLOWLISTED_FIELDS;
57
57
  * guard assert the generated known-kind set matches a fresh scan.
58
58
  */
59
59
  export const KNOWN_KINDS_FOR_DRIFT_GUARD = KNOWN_KINDS;
60
+ /**
61
+ * #1447 workflow-identity predicate, extracted (codex review, 2026-07-15) so
62
+ * command sites that apply command-line metadata overrides can re-run it
63
+ * against the merged/effective workflow rather than only the parsed file.
64
+ *
65
+ * `runAs = "system"` + a non-empty `accessRule` is dead config: a system run
66
+ * can only be started by the system and never evaluates its accessRule, so any
67
+ * non-empty rule is inert. The server rejects this at save time (#1258,
68
+ * `src/workflows/definition-store.ts:271-280`); catching it locally keeps
69
+ * `sync push` all-or-nothing instead of failing mid-push and leaving partial
70
+ * server state (#1418 drift).
71
+ *
72
+ * Mirrors the server predicate byte-for-byte: returns the sentinel error only
73
+ * when `runAs === "system"` AND `typeof accessRule === "string"` AND
74
+ * `accessRule.trim() !== ""`. Default/unset/empty/whitespace-only runAs or
75
+ * accessRule (and a bare non-string boolean accessRule) return `null`.
76
+ *
77
+ * @param workflow The workflow-metadata object — the `[workflow]` table, or
78
+ * for commands that accept unwrapped root-level metadata, the root TOML
79
+ * object (`tomlData.workflow || tomlData`). Non-object inputs return `null`.
80
+ */
81
+ export function validateWorkflowIdentity(workflow) {
82
+ if (workflow === null ||
83
+ typeof workflow !== "object" ||
84
+ Array.isArray(workflow)) {
85
+ return null;
86
+ }
87
+ const runAs = workflow.runAs;
88
+ const accessRule = workflow.accessRule;
89
+ if (runAs === "system" &&
90
+ typeof accessRule === "string" &&
91
+ accessRule.trim() !== "") {
92
+ return {
93
+ stepIndex: -1,
94
+ stepId: null,
95
+ field: "__workflow_system_access_rule__",
96
+ hint: 'accessRule has no effect when runAs = "system" (system runs skip ' +
97
+ "accessRule; gate callers with syncCallable + caller-mode, or see #1433)",
98
+ };
99
+ }
100
+ return null;
101
+ }
102
+ /**
103
+ * #1447 (maintainer decision, 2026-07-21): compute the EFFECTIVE workflow
104
+ * identity that an `update --from-file` push will leave on the server — the
105
+ * merge of the persisted record with the incoming file/flags.
106
+ *
107
+ * `applyWorkflowBody` omits undefined fields, so the server retains whichever
108
+ * side of the runAs/accessRule pair the incoming payload doesn't set. Linting
109
+ * the incoming payload alone therefore misses the case where the OTHER side is
110
+ * already `system` / a stored rule: an existing `runAs="system"` workflow plus
111
+ * a file adding only an `accessRule`, or a file flipping a workflow with a
112
+ * stored rule to `runAs="system"`. Both pass a payload-only lint and are then
113
+ * rejected by the server's PATCH. Merging the two before `validateWorkflowIdentity`
114
+ * catches them locally at zero extra cost — the persisted record is already
115
+ * fetched at the call site.
116
+ *
117
+ * Presence semantics mirror the update payload builder: a field PRESENT in
118
+ * `incoming` (including an empty-string clear) overrides the stored value; an
119
+ * ABSENT field (undefined) falls back to what the server keeps.
120
+ */
121
+ export function effectiveWorkflowIdentity(existing, incoming) {
122
+ const ex = existing ?? {};
123
+ const inc = incoming ?? {};
124
+ return {
125
+ runAs: inc.runAs !== undefined ? inc.runAs : ex.runAs,
126
+ accessRule: inc.accessRule !== undefined ? inc.accessRule : ex.accessRule,
127
+ };
128
+ }
60
129
  /**
61
130
  * Walk a parsed workflow TOML document and return all unknown-field errors.
62
131
  *
63
132
  * @param tomlData The output of `parseConfigToml()` for a workflow TOML file.
133
+ * @param opts.skipWorkflowIdentity When true, suppress the #1447 workflow
134
+ * identity check (`runAs="system"` + non-empty `accessRule`). Callers that
135
+ * merge command-line overrides after parsing re-run `validateWorkflowIdentity`
136
+ * against the effective metadata themselves.
64
137
  * @returns An array of error objects, one per offending field. Empty if no
65
138
  * errors were found.
66
139
  */
67
- export function validateWorkflowToml(tomlData) {
140
+ export function validateWorkflowToml(tomlData, opts) {
68
141
  const errors = [];
69
142
  if (tomlData === null || tomlData === undefined) {
70
143
  return errors;
71
144
  }
145
+ // #1447 — workflow-level identity lint: `runAs = "system"` + a non-empty
146
+ // `accessRule` is dead config. See `validateWorkflowIdentity` for the
147
+ // predicate. This runs BEFORE the `steps` early-returns below so a file
148
+ // carrying the bad combo but with missing/malformed `[[steps]]` is still
149
+ // flagged.
150
+ //
151
+ // Metadata shape (codex review, 2026-07-15): read the workflow table with
152
+ // the same `tomlData.workflow || tomlData` fallback the consuming commands
153
+ // use (`workflows create/update --from-file`), so an UNWRAPPED root-level
154
+ // TOML carrying `runAs`/`accessRule` is checked too — not only the wrapped
155
+ // `[workflow]` form.
156
+ //
157
+ // `skipWorkflowIdentity` (codex review, 2026-07-15): callers that apply
158
+ // command-line metadata overrides AFTER parsing (e.g. `workflows update
159
+ // --from-file` with `--access-rule`) pass this to suppress the identity
160
+ // check on the raw file, then re-run `validateWorkflowIdentity` against the
161
+ // merged/effective metadata themselves. Otherwise `--access-rule ""` could
162
+ // not repair an offending file, and an override-introduced accessRule would
163
+ // escape the lint. Structural checks (#685 misnest, etc.) still run.
164
+ if (!opts?.skipWorkflowIdentity) {
165
+ const identityError = validateWorkflowIdentity(tomlData.workflow || tomlData);
166
+ if (identityError)
167
+ errors.push(identityError);
168
+ }
72
169
  const steps = tomlData.steps;
73
170
  // No steps section at all → nothing to validate. This is fine for
74
171
  // partial TOML files (some commands accept a metadata-only file).
@@ -291,6 +388,12 @@ export function formatWorkflowTomlErrors(filePath, errors) {
291
388
  lines.push(` steps[${err.stepIndex}] is malformed: ${err.hint}`);
292
389
  continue;
293
390
  }
391
+ // #1447 — workflow-level error, not tied to a step. Render the bare hint
392
+ // (no `steps[N]` prefix) under the file header.
393
+ if (err.field === "__workflow_system_access_rule__") {
394
+ lines.push(` ${err.hint}`);
395
+ continue;
396
+ }
294
397
  // For errors inside a `collect` step's nested inner step (codex review,
295
398
  // 2026-05-15), use a `steps[N].step` slot prefix so operators see that
296
399
  // the offending field is on the inner step, not the outer collect.