@stigmer/runner 3.12.4 → 3.12.6

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 (180) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/call-agent.js +19 -6
  3. package/dist/activities/call-agent.js.map +1 -1
  4. package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +45 -0
  5. package/dist/activities/execute-cursor/cursor-mcp-config.js +76 -0
  6. package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -0
  7. package/dist/activities/execute-cursor/error-classifier.d.ts +9 -0
  8. package/dist/activities/execute-cursor/error-classifier.js +30 -1
  9. package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
  10. package/dist/activities/execute-cursor/index.d.ts +10 -1
  11. package/dist/activities/execute-cursor/index.js +62 -36
  12. package/dist/activities/execute-cursor/index.js.map +1 -1
  13. package/dist/activities/execute-cursor/prompt-builder.d.ts +13 -2
  14. package/dist/activities/execute-cursor/prompt-builder.js +11 -0
  15. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  16. package/dist/activities/execute-cursor/service-tier.d.ts +38 -29
  17. package/dist/activities/execute-cursor/service-tier.js +92 -63
  18. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  19. package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -1
  20. package/dist/activities/execute-cursor/skill-resolver.d.ts +2 -21
  21. package/dist/activities/execute-cursor/skill-resolver.js +5 -108
  22. package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
  23. package/dist/activities/execute-cursor/usage-accumulator.d.ts +16 -2
  24. package/dist/activities/execute-cursor/usage-accumulator.js +12 -2
  25. package/dist/activities/execute-cursor/usage-accumulator.js.map +1 -1
  26. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +9 -0
  27. package/dist/activities/execute-deep-agent/approval-file-change.js +2 -1
  28. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  29. package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +18 -1
  30. package/dist/activities/execute-deep-agent/cas-capture-backend.js +20 -3
  31. package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
  32. package/dist/activities/execute-deep-agent/index.js +57 -5
  33. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  34. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +9 -0
  35. package/dist/activities/execute-deep-agent/prompt-builder.js +10 -0
  36. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  37. package/dist/activities/execute-deep-agent/setup.js +17 -16
  38. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  39. package/dist/activities/execute-deep-agent/subagent-transformer.js +17 -11
  40. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  41. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -3
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.js +1 -1
  44. package/dist/middleware/path-normalization.d.ts +49 -49
  45. package/dist/middleware/path-normalization.js +73 -84
  46. package/dist/middleware/path-normalization.js.map +1 -1
  47. package/dist/middleware/types.d.ts +3 -3
  48. package/dist/runner-manager.d.ts +1 -1
  49. package/dist/runner-manager.js +22 -15
  50. package/dist/runner-manager.js.map +1 -1
  51. package/dist/runner.js +11 -0
  52. package/dist/runner.js.map +1 -1
  53. package/dist/shared/args-preview.d.ts +8 -0
  54. package/dist/shared/args-preview.js +14 -3
  55. package/dist/shared/args-preview.js.map +1 -1
  56. package/dist/shared/artifact-storage.d.ts +11 -1
  57. package/dist/shared/artifact-storage.js +10 -1
  58. package/dist/shared/artifact-storage.js.map +1 -1
  59. package/dist/shared/caller-identity.d.ts +10 -7
  60. package/dist/shared/caller-identity.js +10 -7
  61. package/dist/shared/caller-identity.js.map +1 -1
  62. package/dist/shared/declared-preferences.d.ts +47 -0
  63. package/dist/shared/declared-preferences.js +64 -0
  64. package/dist/shared/declared-preferences.js.map +1 -0
  65. package/dist/shared/mcp-enabled-tools.d.ts +2 -3
  66. package/dist/shared/mcp-enabled-tools.js +2 -3
  67. package/dist/shared/mcp-enabled-tools.js.map +1 -1
  68. package/dist/shared/mcp-resolver.d.ts +20 -15
  69. package/dist/shared/mcp-resolver.js +11 -12
  70. package/dist/shared/mcp-resolver.js.map +1 -1
  71. package/dist/shared/placeholder-resolver.d.ts +9 -2
  72. package/dist/shared/placeholder-resolver.js +9 -2
  73. package/dist/shared/placeholder-resolver.js.map +1 -1
  74. package/dist/shared/plan-mode-permissions.d.ts +26 -46
  75. package/dist/shared/plan-mode-permissions.js +27 -55
  76. package/dist/shared/plan-mode-permissions.js.map +1 -1
  77. package/dist/shared/skill-mount.d.ts +89 -0
  78. package/dist/shared/skill-mount.js +142 -0
  79. package/dist/shared/skill-mount.js.map +1 -0
  80. package/dist/shared/skill-writer.d.ts +28 -26
  81. package/dist/shared/skill-writer.js +79 -102
  82. package/dist/shared/skill-writer.js.map +1 -1
  83. package/dist/shared/thinking-mode.d.ts +35 -0
  84. package/dist/shared/thinking-mode.js +43 -0
  85. package/dist/shared/thinking-mode.js.map +1 -0
  86. package/dist/shared/worker-shutdown.d.ts +67 -0
  87. package/dist/shared/worker-shutdown.js +79 -0
  88. package/dist/shared/worker-shutdown.js.map +1 -0
  89. package/dist/shared/workspace/types.d.ts +3 -2
  90. package/dist/workflow-engine/loader.js +82 -6
  91. package/dist/workflow-engine/loader.js.map +1 -1
  92. package/dist/workflow-engine/tasks/human-input.d.ts +2 -1
  93. package/dist/workflow-engine/tasks/human-input.js +31 -3
  94. package/dist/workflow-engine/tasks/human-input.js.map +1 -1
  95. package/dist/workflow-engine/types.d.ts +17 -3
  96. package/dist/workflow-engine/types.js.map +1 -1
  97. package/dist/workflows/human-input-orchestrator.d.ts +4 -0
  98. package/dist/workflows/human-input-orchestrator.js +13 -0
  99. package/dist/workflows/human-input-orchestrator.js.map +1 -1
  100. package/package.json +15 -11
  101. package/src/activities/call-agent.ts +20 -6
  102. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +50 -0
  103. package/src/activities/execute-cursor/__tests__/cursor-mcp-config.test.ts +111 -0
  104. package/src/activities/execute-cursor/__tests__/error-classifier-billing.test.ts +67 -0
  105. package/src/activities/execute-cursor/__tests__/service-tier.test.ts +67 -7
  106. package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +3 -94
  107. package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +33 -1
  108. package/src/activities/execute-cursor/cursor-mcp-config.ts +107 -0
  109. package/src/activities/execute-cursor/error-classifier.ts +42 -1
  110. package/src/activities/execute-cursor/index.ts +78 -41
  111. package/src/activities/execute-cursor/prompt-builder.ts +29 -2
  112. package/src/activities/execute-cursor/service-tier.ts +94 -63
  113. package/src/activities/execute-cursor/session-lifecycle.ts +1 -1
  114. package/src/activities/execute-cursor/skill-resolver.ts +10 -137
  115. package/src/activities/execute-cursor/usage-accumulator.ts +11 -1
  116. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +15 -0
  117. package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +75 -0
  118. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +1 -0
  119. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
  120. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
  121. package/src/activities/execute-deep-agent/__tests__/index.test.ts +1 -0
  122. package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +42 -29
  123. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +52 -0
  124. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
  125. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +11 -8
  126. package/src/activities/execute-deep-agent/approval-file-change.ts +11 -1
  127. package/src/activities/execute-deep-agent/cas-capture-backend.ts +20 -3
  128. package/src/activities/execute-deep-agent/index.ts +57 -5
  129. package/src/activities/execute-deep-agent/prompt-builder.ts +22 -0
  130. package/src/activities/execute-deep-agent/setup.ts +21 -19
  131. package/src/activities/execute-deep-agent/subagent-transformer.ts +19 -12
  132. package/src/activities/execute-deep-agent/subagent-wiring.ts +3 -3
  133. package/src/index.ts +1 -1
  134. package/src/middleware/__tests__/path-normalization.test.ts +32 -32
  135. package/src/middleware/path-normalization.ts +78 -90
  136. package/src/middleware/types.ts +3 -3
  137. package/src/runner-manager.ts +26 -16
  138. package/src/runner.ts +14 -0
  139. package/src/shared/__tests__/artifact-storage.test.ts +28 -0
  140. package/src/shared/__tests__/bedrock-seam.test.ts +5 -5
  141. package/src/shared/__tests__/declared-preferences.test.ts +109 -0
  142. package/src/shared/__tests__/foundry-seam.test.ts +5 -5
  143. package/src/shared/__tests__/plan-mode-permissions.test.ts +15 -44
  144. package/src/shared/__tests__/skill-mount.test.ts +238 -0
  145. package/src/shared/__tests__/skill-writer.test.ts +151 -128
  146. package/src/shared/__tests__/vertex-adapter.test.ts +30 -3
  147. package/src/shared/__tests__/vertex-seam.test.ts +5 -5
  148. package/src/shared/__tests__/worker-shutdown.test.ts +101 -0
  149. package/src/shared/args-preview.ts +17 -3
  150. package/src/shared/artifact-storage.ts +20 -1
  151. package/src/shared/caller-identity.ts +10 -7
  152. package/src/shared/declared-preferences.ts +84 -0
  153. package/src/shared/mcp-enabled-tools.ts +2 -3
  154. package/src/shared/mcp-resolver.ts +20 -20
  155. package/src/shared/placeholder-resolver.ts +9 -2
  156. package/src/shared/plan-mode-permissions.ts +27 -58
  157. package/src/shared/skill-mount.ts +179 -0
  158. package/src/shared/skill-writer.ts +96 -130
  159. package/src/shared/thinking-mode.ts +52 -0
  160. package/src/shared/worker-shutdown.ts +99 -0
  161. package/src/shared/workspace/types.ts +3 -2
  162. package/src/workflow-engine/__tests__/loader.test.ts +95 -0
  163. package/src/workflow-engine/__tests__/tasks/human-input.test.ts +156 -0
  164. package/src/workflow-engine/loader.ts +97 -6
  165. package/src/workflow-engine/tasks/human-input.ts +41 -6
  166. package/src/workflow-engine/types.ts +18 -3
  167. package/src/workflows/human-input-orchestrator.ts +20 -2
  168. package/dist/activities/execute-cursor/connect-backfill.d.ts +0 -19
  169. package/dist/activities/execute-cursor/connect-backfill.js +0 -27
  170. package/dist/activities/execute-cursor/connect-backfill.js.map +0 -1
  171. package/dist/activities/execute-cursor/mcp-resolver.d.ts +0 -120
  172. package/dist/activities/execute-cursor/mcp-resolver.js +0 -194
  173. package/dist/activities/execute-cursor/mcp-resolver.js.map +0 -1
  174. package/dist/activities/execute-cursor/placeholder-resolver.d.ts +0 -34
  175. package/dist/activities/execute-cursor/placeholder-resolver.js +0 -82
  176. package/dist/activities/execute-cursor/placeholder-resolver.js.map +0 -1
  177. package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +0 -125
  178. package/src/activities/execute-cursor/connect-backfill.ts +0 -52
  179. package/src/activities/execute-cursor/mcp-resolver.ts +0 -324
  180. package/src/activities/execute-cursor/placeholder-resolver.ts +0 -109
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Skill writing and prompt generation for the deep-agent execution path.
2
+ * Skill mounting and prompt generation for the deep-agent execution path.
3
3
  *
4
4
  * Follows the Agent Skills specification progressive disclosure model:
5
5
  *
@@ -10,13 +10,23 @@
10
10
  * 3. Resources (on demand) — scripts, references, and assets are
11
11
  * loaded by the agent only when required.
12
12
  *
13
- * Skills live under `.stigmer/skills/{name}/` relative to the workspace root.
14
- * Returned paths are workspace-relative so that the agent's sandbox backend
15
- * resolves them correctly regardless of mount strategy.
13
+ * Skills physically live in the session's platform directory
14
+ * (`{platformDir}/skills/{name}/` the SAME location the Cursor harness
15
+ * mounts into), and the agent sees them as `.stigmer/skills/{name}/`
16
+ * through the per-turn workspace symlink (see workspace/stigmer-link.ts).
17
+ * Returned paths are the agent-visible `.stigmer/…` form.
18
+ *
19
+ * Mounts are cached by the skill's content-addressed version hash via the
20
+ * shared skill-mount mechanics (issue #337, mirroring the Cursor harness's
21
+ * #672 fix): metadata is fetched every execution — a pushed skill update
22
+ * still lands on the very next message — but an unchanged skill skips the
23
+ * artifact download and rewrite entirely.
16
24
  */
17
- import { extractZipFileEntries } from "./zip-extract.js";
18
- const SKILLS_RELATIVE_BASE = ".stigmer/skills";
19
- const SCRIPT_EXTENSIONS = new Set([".sh", ".py", ".js", ".ts", ".rb", ".pl"]);
25
+ import { join } from "node:path";
26
+ import { SKILLS_SUBDIR, mountIsFresh, downloadArtifact, writeSkillMount, } from "./skill-mount.js";
27
+ import { STIGMER_LOCAL_STATE_DIR } from "./workspace/stigmer-link.js";
28
+ /** Agent-visible base of the skills tree (via the workspace `.stigmer` symlink). */
29
+ const SKILLS_RELATIVE_BASE = `${STIGMER_LOCAL_STATE_DIR}/${SKILLS_SUBDIR}`;
20
30
  // ─── Fetch ───────────────────────────────────────────────────────────────
21
31
  /**
22
32
  * Merge skill refs from agent and session specs (union, dedup by slug,
@@ -59,87 +69,80 @@ export async function fetchSkillsByRefs(client, refs) {
59
69
  }
60
70
  return results;
61
71
  }
62
- // ─── Write ───────────────────────────────────────────────────────────────
72
+ // ─── Mount ───────────────────────────────────────────────────────────────
63
73
  /**
64
- * Write skill artifacts to the workspace. Returns a map of
65
- * skill-id -> workspace-relative directory path.
74
+ * Mount skills into the session's platform directory, downloading each
75
+ * skill's artifact only on a version-hash cache miss (see skill-mount.ts
76
+ * for the marker mechanics). Returns a map of skill-id -> agent-visible
77
+ * directory path.
78
+ *
79
+ * The returned map is a NAMING function, not a success record: every skill
80
+ * gets its path entry so prompt generation stays total, while mount
81
+ * failures degrade that one skill (loud log, no throw) — one broken skill
82
+ * must never kill the run.
66
83
  *
67
- * For each skill:
68
- * - If a ZIP artifact is available, extract it to .stigmer/skills/{name}/
69
- * - Otherwise, write just the SKILL.md from the spec
70
- * - Make scripts executable
84
+ * Skills mount in parallel (each owns an independent directory), EXCEPT
85
+ * when two skills resolve to the same directory name (same `spec.name`
86
+ * from different orgs): concurrent remove-and-rewrite passes on one
87
+ * directory would corrupt the mount, so only the first claimant mounts and
88
+ * the collision is logged loudly. (The sequential code this replaced
89
+ * silently let the last writer win — no better, just quieter.)
71
90
  */
72
- export async function writeSkills(skills, workspaceBackend, artifacts) {
91
+ export async function mountSkills(client, skills, platformDir) {
73
92
  const paths = new Map();
93
+ const claims = new Map();
74
94
  for (const skill of skills) {
75
95
  const name = skill.spec?.name || skill.metadata?.slug || "unknown";
76
96
  const skillId = skill.metadata?.id ?? name;
77
- const relativeDir = `${SKILLS_RELATIVE_BASE}/${name}`;
78
- paths.set(skillId, relativeDir);
79
- const artifactBytes = artifacts.get(skillId);
80
- if (skill.spec?.skillMd) {
81
- const skillMdPath = `${relativeDir}/SKILL.md`;
82
- await workspaceBackend.writeFile(skillMdPath, skill.spec.skillMd);
83
- if (artifactBytes && artifactBytes.length > 0) {
84
- await extractZipToWorkspaceExcluding(artifactBytes, "SKILL.md", relativeDir, workspaceBackend);
85
- }
97
+ paths.set(skillId, `${SKILLS_RELATIVE_BASE}/${name}`);
98
+ // Impossible through the push pipeline (push.go hard-fails a ZIP
99
+ // without an extractable SKILL.md and always populates spec.skill_md),
100
+ // so an empty skillMd means a broken resource — skip, same as Cursor.
101
+ if (!skill.spec?.skillMd) {
102
+ console.warn(`[skill-writer] skill ${name} (${skillId}) has no skillMd content — skipping mount`);
103
+ continue;
86
104
  }
87
- else if (artifactBytes && artifactBytes.length > 0) {
88
- await extractZipToWorkspace(artifactBytes, relativeDir, workspaceBackend);
105
+ const prev = claims.get(name);
106
+ if (prev) {
107
+ console.warn(`[skill-writer] mount directory collision on '${name}': ` +
108
+ `${prev.metadata?.org}/${prev.metadata?.slug} already claims it, ` +
109
+ `skipping ${skill.metadata?.org}/${skill.metadata?.slug}`);
110
+ continue;
89
111
  }
90
- await makeScriptsExecutable(relativeDir, workspaceBackend);
112
+ claims.set(name, skill);
91
113
  }
114
+ await Promise.all([...claims.entries()].map(async ([name, skill]) => {
115
+ const skillDir = join(platformDir, SKILLS_SUBDIR, name);
116
+ try {
117
+ const versionHash = skill.status?.versionHash ?? "";
118
+ const wantsArtifact = Boolean(skill.status?.artifactStorageKey);
119
+ if (versionHash !== "" && (await mountIsFresh(skillDir, versionHash, wantsArtifact))) {
120
+ console.log(`[skill-writer] mount cache hit: ${name} (version ${versionHash.slice(0, 12)}) — skipping artifact transfer`);
121
+ return;
122
+ }
123
+ let artifactBytes;
124
+ if (wantsArtifact) {
125
+ try {
126
+ artifactBytes = await downloadArtifact(client, skill.status.artifactStorageKey);
127
+ }
128
+ catch (err) {
129
+ // Deliberate degradation, but LOUD (#675): the run still gets
130
+ // SKILL.md, and the marker records artifactMounted=false so the
131
+ // next execution retries the download.
132
+ console.error(`[skill-writer] artifact download FAILED for ${name} ` +
133
+ `(key=${skill.status.artifactStorageKey}) — mounting SKILL.md WITHOUT the skill's ` +
134
+ `supporting files (scripts/references will be missing): ${err instanceof Error ? err.message : err}`);
135
+ }
136
+ }
137
+ await writeSkillMount(skill, skillDir, artifactBytes);
138
+ console.log(`[skill-writer] wrote skill mount: ${name}`);
139
+ }
140
+ catch (err) {
141
+ console.warn(`[skill-writer] failed to mount skill ${name}: ${err instanceof Error ? err.message : err}`);
142
+ }
143
+ }));
92
144
  return { paths };
93
145
  }
94
- /**
95
- * Compute skill paths without writing anything (for resume integrity checks).
96
- */
97
- export function computeSkillPaths(skills) {
98
- const paths = new Map();
99
- for (const skill of skills) {
100
- const name = skill.spec?.name || skill.metadata?.slug || "unknown";
101
- const skillId = skill.metadata?.id ?? name;
102
- paths.set(skillId, `${SKILLS_RELATIVE_BASE}/${name}`);
103
- }
104
- return paths;
105
- }
106
- /**
107
- * Check workspace integrity for resume fast-path.
108
- * Returns true if the sentinel SKILL.md file exists for the first skill.
109
- */
110
- export async function checkSkillIntegrity(skills, workspaceBackend) {
111
- if (skills.length === 0)
112
- return true;
113
- const paths = computeSkillPaths(skills);
114
- const firstPath = paths.values().next().value;
115
- if (!firstPath)
116
- return true;
117
- const sentinel = `${firstPath}/SKILL.md`;
118
- return workspaceBackend.exists(sentinel);
119
- }
120
- // ─── ZIP extraction ──────────────────────────────────────────────────────
121
- async function extractZipToWorkspace(zipBytes, targetDir, backend) {
122
- const entries = await extractZipFileEntries(zipBytes);
123
- for (const entry of entries) {
124
- await backend.writeFileBuffer(`${targetDir}/${entry.path}`, Buffer.from(entry.content));
125
- }
126
- }
127
- async function extractZipToWorkspaceExcluding(zipBytes, excludeName, targetDir, backend) {
128
- const entries = await extractZipFileEntries(zipBytes, { exclude: [excludeName] });
129
- for (const entry of entries) {
130
- await backend.writeFileBuffer(`${targetDir}/${entry.path}`, Buffer.from(entry.content));
131
- }
132
- }
133
- async function makeScriptsExecutable(relativeDir, backend) {
134
- const extensions = [...SCRIPT_EXTENSIONS].map(ext => `-name '*${ext}'`).join(" -o ");
135
- const cmd = `find ${relativeDir} -type f \\( ${extensions} \\) -exec chmod +x {} \\; 2>/dev/null || true`;
136
- try {
137
- await backend.execute(cmd);
138
- }
139
- catch {
140
- // Non-fatal: scripts may not be executable in all environments
141
- }
142
- }
143
146
  // ─── Prompt generation ───────────────────────────────────────────────────
144
147
  /**
145
148
  * Generate the system prompt section following the Agent Skills spec
@@ -201,30 +204,4 @@ export function generateAlsoAvailableSection(excludedNames) {
201
204
  "If you determine one of them is relevant to your task, " +
202
205
  "read its SKILL.md at `.stigmer/skills/<name>/SKILL.md` to activate it.\n");
203
206
  }
204
- // ─── Artifact fetching ───────────────────────────────────────────────────
205
- /**
206
- * Download skill artifacts for all skills that have a storage key.
207
- * Returns a map from skill ID to artifact bytes.
208
- */
209
- export async function fetchSkillArtifacts(client, skills) {
210
- const artifacts = new Map();
211
- const fetches = skills
212
- .filter(s => s.status?.artifactStorageKey)
213
- .map(async (skill) => {
214
- const key = skill.status.artifactStorageKey;
215
- const skillId = skill.metadata?.id ?? skill.spec?.name ?? "unknown";
216
- try {
217
- const response = await client.getSkillArtifact(key);
218
- if (response.artifact && response.artifact.length > 0) {
219
- artifacts.set(skillId, response.artifact);
220
- }
221
- }
222
- catch (err) {
223
- console.warn(`[skill-writer] Failed to download artifact for ${skill.spec?.name}: ` +
224
- `${err instanceof Error ? err.message : String(err)}. Falling back to SKILL.md only.`);
225
- }
226
- });
227
- await Promise.all(fetches);
228
- return artifacts;
229
- }
230
207
  //# sourceMappingURL=skill-writer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-writer.js","sourceRoot":"","sources":["../../src/shared/skill-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skill-writer.js","sourceRoot":"","sources":["../../src/shared/skill-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Harness-neutral thinking-mode semantics (stigmer/stigmer#772) — the
3
+ * second variant dimension alongside `shared/service-tier.ts`.
4
+ *
5
+ * The platform contract mirrors the service tier's: the thinking pin is
6
+ * ALWAYS explicit by the time a provider request leaves the runner.
7
+ * UNSPECIFIED resolves to DISABLED here and ONLY here — every upstream
8
+ * layer preserves the caller's raw enum so "user chose disabled" stays
9
+ * distinguishable from "platform default" all the way to the ledger.
10
+ *
11
+ * Unlike the fast tier, thinking is NOT separately priced: Cursor bills
12
+ * thinking variants at base per-token rates (ledger-verified 2026-08-15 —
13
+ * 277 events at exactly base; thinking+fast at exactly the fast rate).
14
+ * The cost of ENABLED is the extra reasoning tokens, billed as output.
15
+ * Selection is therefore capability-gated (registry capabilities.thinking)
16
+ * rather than pricing-gated, and the estimate/billing paths need no
17
+ * thinking-specific rates.
18
+ *
19
+ * v1 translates thinking on the Cursor harness only (the explicit
20
+ * `thinking` variant parameter, `execute-cursor/service-tier.ts`). No
21
+ * native wire mapping exists yet — create-time validation refuses ENABLED
22
+ * for native-harness models, mirroring the tier's #361 posture.
23
+ */
24
+ import { ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
25
+ /**
26
+ * The effective mode after platform-default resolution: never UNSPECIFIED.
27
+ */
28
+ export type EffectiveThinkingMode = ThinkingMode.DISABLED | ThinkingMode.ENABLED;
29
+ /**
30
+ * Resolve the configured mode to its effective value. The single place in
31
+ * the platform where UNSPECIFIED becomes DISABLED.
32
+ */
33
+ export declare function resolveEffectiveThinkingMode(configured: ThinkingMode | undefined): EffectiveThinkingMode;
34
+ /** Human-readable mode label for logs and error messages. */
35
+ export declare function thinkingModeLabel(mode: ThinkingMode): string;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Harness-neutral thinking-mode semantics (stigmer/stigmer#772) — the
3
+ * second variant dimension alongside `shared/service-tier.ts`.
4
+ *
5
+ * The platform contract mirrors the service tier's: the thinking pin is
6
+ * ALWAYS explicit by the time a provider request leaves the runner.
7
+ * UNSPECIFIED resolves to DISABLED here and ONLY here — every upstream
8
+ * layer preserves the caller's raw enum so "user chose disabled" stays
9
+ * distinguishable from "platform default" all the way to the ledger.
10
+ *
11
+ * Unlike the fast tier, thinking is NOT separately priced: Cursor bills
12
+ * thinking variants at base per-token rates (ledger-verified 2026-08-15 —
13
+ * 277 events at exactly base; thinking+fast at exactly the fast rate).
14
+ * The cost of ENABLED is the extra reasoning tokens, billed as output.
15
+ * Selection is therefore capability-gated (registry capabilities.thinking)
16
+ * rather than pricing-gated, and the estimate/billing paths need no
17
+ * thinking-specific rates.
18
+ *
19
+ * v1 translates thinking on the Cursor harness only (the explicit
20
+ * `thinking` variant parameter, `execute-cursor/service-tier.ts`). No
21
+ * native wire mapping exists yet — create-time validation refuses ENABLED
22
+ * for native-harness models, mirroring the tier's #361 posture.
23
+ */
24
+ import { ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
25
+ /**
26
+ * Resolve the configured mode to its effective value. The single place in
27
+ * the platform where UNSPECIFIED becomes DISABLED.
28
+ */
29
+ export function resolveEffectiveThinkingMode(configured) {
30
+ return configured === ThinkingMode.ENABLED ? ThinkingMode.ENABLED : ThinkingMode.DISABLED;
31
+ }
32
+ /** Human-readable mode label for logs and error messages. */
33
+ export function thinkingModeLabel(mode) {
34
+ switch (mode) {
35
+ case ThinkingMode.ENABLED:
36
+ return "enabled";
37
+ case ThinkingMode.DISABLED:
38
+ return "disabled";
39
+ default:
40
+ return "unspecified";
41
+ }
42
+ }
43
+ //# sourceMappingURL=thinking-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-mode.js","sourceRoot":"","sources":["../../src/shared/thinking-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;AAO5F;;;GAGG;AACH,MAAM,UAAU,4BAA4B,CAC1C,UAAoC;IAEpC,OAAO,UAAU,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC;AAC5F,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,iBAAiB,CAAC,IAAkB;IAClD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,YAAY,CAAC,OAAO;YACvB,OAAO,SAAS,CAAC;QACnB,KAAK,YAAY,CAAC,QAAQ;YACxB,OAAO,UAAU,CAAC;QACpB;YACE,OAAO,aAAa,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Per-task-queue worker-shutdown signals — the classification channel that
3
+ * lets an in-flight activity distinguish "my worker is shutting down" from
4
+ * "the orchestrator cancelled me" (a user pause).
5
+ *
6
+ * The signal carries NO lifecycle authority: aborting it never stops a
7
+ * worker or an activity (Temporal's own drain does that). It exists purely
8
+ * so the activity's cancellation handling can classify the interruption
9
+ * honestly — a shutdown is not a pause, and must surface as the
10
+ * worker-shutdown failure shape the control planes recognize (issue #776).
11
+ *
12
+ * Ownership contract:
13
+ * - whoever creates a Worker registers a signal for its queue BEFORE the
14
+ * worker starts polling;
15
+ * - whoever initiates a full shutdown (SIGTERM handler, desktop quit)
16
+ * aborts the signal BEFORE calling worker.shutdown(), so activities
17
+ * cancelled by the drain observe it already aborted;
18
+ * - a graceful single-worker teardown (view close, deferred teardown in
19
+ * the runner-manager) must NOT abort — those paths only run once no
20
+ * activity is in flight, and aborting earlier is exactly the regression
21
+ * that killed running activities on a view close.
22
+ *
23
+ * Module-level (not per-manager) because activities resolve their signal by
24
+ * task-queue name via {@link getShutdownSignalForQueue} without a handle to
25
+ * the runner/manager instance that created their worker.
26
+ */
27
+ /**
28
+ * Register a fresh shutdown signal for a task queue, replacing any previous
29
+ * registration (a re-created worker on a reused queue must not observe the
30
+ * old worker's aborted signal). Returns the controller so the worker's owner
31
+ * can abort it at shutdown.
32
+ */
33
+ export declare function registerWorkerShutdownSignal(taskQueue: string): AbortController;
34
+ /** The signal an activity on `taskQueue` should observe, if one is registered. */
35
+ export declare function getShutdownSignalForQueue(taskQueue: string): AbortSignal | undefined;
36
+ /**
37
+ * Abort the queue's signal, marking any in-flight activity's imminent
38
+ * cancellation as a worker shutdown. Idempotent; no-op for an unknown queue.
39
+ */
40
+ export declare function signalWorkerShutdown(taskQueue: string): void;
41
+ /** Drop the registration once the queue's worker is fully torn down. */
42
+ export declare function unregisterWorkerShutdownSignal(taskQueue: string): void;
43
+ /** The evidence a turn's post-stream classification weighs (see below). */
44
+ export interface TurnInterruptionEvidence {
45
+ /** The periodic heartbeat threw CancelledFailure with no shutdown signal. */
46
+ heartbeatCancelled: boolean;
47
+ /** The periodic heartbeat threw CancelledFailure with the signal aborted. */
48
+ heartbeatWorkerShutdown: boolean;
49
+ /** Temporal delivered cancellation to the activity. */
50
+ cancellationSignalAborted: boolean;
51
+ /** This queue's worker-shutdown signal is aborted. */
52
+ shutdownSignalAborted: boolean;
53
+ }
54
+ /**
55
+ * Classify how (whether) a turn's stream was interrupted, from the evidence
56
+ * available after the stream ends. Pure so the decision table is directly
57
+ * testable — the activities feed it their heartbeat flags and signals.
58
+ *
59
+ * The load-bearing rule is the grace-window guard (#776): an aborted
60
+ * shutdown signal ALONE is "none", because a run that completes normally
61
+ * inside the drain grace window reaches the classification with the signal
62
+ * already aborted and nothing actually interrupted. Shutdown requires
63
+ * interruption evidence (a heartbeat CancelledFailure or a delivered
64
+ * cancellation) alongside the signal; a heartbeat cancellation with no
65
+ * shutdown signal is the orchestrator's pause.
66
+ */
67
+ export declare function classifyTurnInterruption(evidence: TurnInterruptionEvidence): "worker-shutdown" | "pause" | "none";
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Per-task-queue worker-shutdown signals — the classification channel that
3
+ * lets an in-flight activity distinguish "my worker is shutting down" from
4
+ * "the orchestrator cancelled me" (a user pause).
5
+ *
6
+ * The signal carries NO lifecycle authority: aborting it never stops a
7
+ * worker or an activity (Temporal's own drain does that). It exists purely
8
+ * so the activity's cancellation handling can classify the interruption
9
+ * honestly — a shutdown is not a pause, and must surface as the
10
+ * worker-shutdown failure shape the control planes recognize (issue #776).
11
+ *
12
+ * Ownership contract:
13
+ * - whoever creates a Worker registers a signal for its queue BEFORE the
14
+ * worker starts polling;
15
+ * - whoever initiates a full shutdown (SIGTERM handler, desktop quit)
16
+ * aborts the signal BEFORE calling worker.shutdown(), so activities
17
+ * cancelled by the drain observe it already aborted;
18
+ * - a graceful single-worker teardown (view close, deferred teardown in
19
+ * the runner-manager) must NOT abort — those paths only run once no
20
+ * activity is in flight, and aborting earlier is exactly the regression
21
+ * that killed running activities on a view close.
22
+ *
23
+ * Module-level (not per-manager) because activities resolve their signal by
24
+ * task-queue name via {@link getShutdownSignalForQueue} without a handle to
25
+ * the runner/manager instance that created their worker.
26
+ */
27
+ const registry = new Map();
28
+ /**
29
+ * Register a fresh shutdown signal for a task queue, replacing any previous
30
+ * registration (a re-created worker on a reused queue must not observe the
31
+ * old worker's aborted signal). Returns the controller so the worker's owner
32
+ * can abort it at shutdown.
33
+ */
34
+ export function registerWorkerShutdownSignal(taskQueue) {
35
+ const controller = new AbortController();
36
+ registry.set(taskQueue, controller);
37
+ return controller;
38
+ }
39
+ /** The signal an activity on `taskQueue` should observe, if one is registered. */
40
+ export function getShutdownSignalForQueue(taskQueue) {
41
+ return registry.get(taskQueue)?.signal;
42
+ }
43
+ /**
44
+ * Abort the queue's signal, marking any in-flight activity's imminent
45
+ * cancellation as a worker shutdown. Idempotent; no-op for an unknown queue.
46
+ */
47
+ export function signalWorkerShutdown(taskQueue) {
48
+ registry.get(taskQueue)?.abort();
49
+ }
50
+ /** Drop the registration once the queue's worker is fully torn down. */
51
+ export function unregisterWorkerShutdownSignal(taskQueue) {
52
+ registry.delete(taskQueue);
53
+ }
54
+ /**
55
+ * Classify how (whether) a turn's stream was interrupted, from the evidence
56
+ * available after the stream ends. Pure so the decision table is directly
57
+ * testable — the activities feed it their heartbeat flags and signals.
58
+ *
59
+ * The load-bearing rule is the grace-window guard (#776): an aborted
60
+ * shutdown signal ALONE is "none", because a run that completes normally
61
+ * inside the drain grace window reaches the classification with the signal
62
+ * already aborted and nothing actually interrupted. Shutdown requires
63
+ * interruption evidence (a heartbeat CancelledFailure or a delivered
64
+ * cancellation) alongside the signal; a heartbeat cancellation with no
65
+ * shutdown signal is the orchestrator's pause.
66
+ */
67
+ export function classifyTurnInterruption(evidence) {
68
+ const interrupted = evidence.heartbeatCancelled ||
69
+ evidence.heartbeatWorkerShutdown ||
70
+ evidence.cancellationSignalAborted;
71
+ if (!interrupted) {
72
+ return "none";
73
+ }
74
+ if (evidence.heartbeatWorkerShutdown || evidence.shutdownSignalAborted) {
75
+ return "worker-shutdown";
76
+ }
77
+ return evidence.heartbeatCancelled ? "pause" : "none";
78
+ }
79
+ //# sourceMappingURL=worker-shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-shutdown.js","sourceRoot":"","sources":["../../src/shared/worker-shutdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,SAAiB;IAC5D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACpC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,yBAAyB,CAAC,SAAiB;IACzD,OAAO,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,8BAA8B,CAAC,SAAiB;IAC9D,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAcD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAkC;IAElC,MAAM,WAAW,GACf,QAAQ,CAAC,kBAAkB;QAC3B,QAAQ,CAAC,uBAAuB;QAChC,QAAQ,CAAC,yBAAyB,CAAC;IACrC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,CAAC,uBAAuB,IAAI,QAAQ,CAAC,qBAAqB,EAAE,CAAC;QACvE,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,OAAO,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC"}
@@ -36,8 +36,9 @@ export declare class WorkspaceProvisionError extends Error {
36
36
  /**
37
37
  * Abstraction for executing commands inside a workspace.
38
38
  *
39
- * In local mode, commands run via child_process. In cloud mode (Phase 3),
40
- * commands route through the Daytona sandbox proxy.
39
+ * Commands run via child_process in both modes: in cloud mode the runner
40
+ * itself lives inside the sandbox, so "local" execution is already
41
+ * sandbox-scoped there.
41
42
  *
42
43
  * When `platformDir` is set, paths under `.stigmer/` are transparently
43
44
  * routed to the platform directory instead of the workspace root, keeping
@@ -449,11 +449,13 @@ function parseAgentCallRunConfig(raw) {
449
449
  throw new Error("call:agent 'run_config' must be a mapping");
450
450
  }
451
451
  const obj = raw;
452
- const known = new Set(["model_name", "max_cost_usd", "max_tool_rounds", "service_tier"]);
452
+ const known = new Set([
453
+ "model_name", "max_cost_usd", "max_tool_rounds", "service_tier", "thinking_mode",
454
+ ]);
453
455
  for (const key of Object.keys(obj)) {
454
456
  if (!known.has(key)) {
455
457
  throw new Error(`call:agent 'run_config' has unknown field '${key}' ` +
456
- `(expected: model_name, max_cost_usd, max_tool_rounds, service_tier)`);
458
+ `(expected: model_name, max_cost_usd, max_tool_rounds, service_tier, thinking_mode)`);
457
459
  }
458
460
  }
459
461
  const modelName = obj.model_name;
@@ -469,11 +471,13 @@ function parseAgentCallRunConfig(raw) {
469
471
  throw new Error("call:agent 'run_config.max_tool_rounds' must be a number >= 0");
470
472
  }
471
473
  const serviceTier = parseServiceTier(obj.service_tier);
474
+ const thinkingMode = parseThinkingMode(obj.thinking_mode);
472
475
  return {
473
476
  model_name: modelName,
474
477
  max_cost_usd: maxCostUsd,
475
478
  max_tool_rounds: maxToolRounds,
476
479
  service_tier: serviceTier,
480
+ thinking_mode: thinkingMode,
477
481
  };
478
482
  }
479
483
  /**
@@ -500,6 +504,63 @@ function parseServiceTier(raw) {
500
504
  }
501
505
  return canonical;
502
506
  }
507
+ /**
508
+ * Maps YAML thinking-mode shorthands to canonical enum names, mirroring
509
+ * SERVICE_TIER_SHORTHANDS (stigmer/stigmer#772). Unknown values are
510
+ * authoring errors: the mode exists to make the served variant
511
+ * deterministic, so a typo must never silently fall back to the default.
512
+ */
513
+ const THINKING_MODE_SHORTHANDS = {
514
+ disabled: "THINKING_MODE_DISABLED",
515
+ enabled: "THINKING_MODE_ENABLED",
516
+ };
517
+ function parseThinkingMode(raw) {
518
+ if (raw === undefined || raw === null)
519
+ return undefined;
520
+ if (typeof raw !== "string") {
521
+ throw new Error("call:agent 'run_config.thinking_mode' must be a string");
522
+ }
523
+ const canonical = THINKING_MODE_SHORTHANDS[raw.toLowerCase()] ??
524
+ (Object.values(THINKING_MODE_SHORTHANDS).includes(raw) ? raw : undefined);
525
+ if (!canonical) {
526
+ throw new Error(`call:agent 'run_config.thinking_mode' has unknown value '${raw}' ` +
527
+ `(expected: disabled, enabled)`);
528
+ }
529
+ return canonical;
530
+ }
531
+ /**
532
+ * Maps on_timeout values to the runner's internal policy words, mirroring
533
+ * SERVICE_TIER_SHORTHANDS. The persisted CNCF YAML carries the proto enum
534
+ * NAMES (the server converter emits `HumanInputTimeoutPolicy.String()`),
535
+ * while hand-written fixtures use the lowercase words — both are accepted.
536
+ * Unknown values are authoring errors: a timeout policy must never silently
537
+ * fall back to fail (stigmer/stigmer#779 — the unvalidated cast let every
538
+ * enum-name policy reach the orchestrator unrecognized, so gates configured
539
+ * to auto-approve/deny failed at their first real timeout instead).
540
+ */
541
+ const ON_TIMEOUT_VOCABULARY = {
542
+ fail: "fail",
543
+ approve: "approve",
544
+ deny: "deny",
545
+ escalate: "escalate",
546
+ HUMAN_INPUT_TIMEOUT_FAIL: "fail",
547
+ HUMAN_INPUT_TIMEOUT_APPROVE: "approve",
548
+ HUMAN_INPUT_TIMEOUT_DENY: "deny",
549
+ HUMAN_INPUT_TIMEOUT_ESCALATE: "escalate",
550
+ };
551
+ function parseOnTimeout(taskName, raw) {
552
+ if (raw === undefined || raw === null)
553
+ return undefined;
554
+ if (typeof raw !== "string") {
555
+ throw new Error(`human_input task '${taskName}': 'on_timeout' must be a string`);
556
+ }
557
+ const policy = ON_TIMEOUT_VOCABULARY[raw];
558
+ if (!policy) {
559
+ throw new Error(`human_input task '${taskName}': unknown on_timeout value '${raw}' ` +
560
+ `(expected: fail, approve, deny, escalate, or a HUMAN_INPUT_TIMEOUT_* enum name)`);
561
+ }
562
+ return policy;
563
+ }
503
564
  function parseHumanInputConfig(taskName, raw) {
504
565
  if (!raw || typeof raw !== "object") {
505
566
  throw new Error(`human_input task '${taskName}' requires a 'with' configuration block`);
@@ -508,11 +569,26 @@ function parseHumanInputConfig(taskName, raw) {
508
569
  if (typeof obj.prompt !== "string" || !obj.prompt) {
509
570
  throw new Error(`human_input task '${taskName}' requires 'prompt' in 'with'`);
510
571
  }
572
+ const outcomes = Array.isArray(obj.outcomes) && obj.outcomes.length > 0
573
+ ? obj.outcomes.map((o) => ({ name: o.name, label: o.label, then: o.then }))
574
+ : undefined;
575
+ const onTimeout = parseOnTimeout(taskName, obj.on_timeout);
576
+ // The escalate policy's outcome-by-name contract (stigmer/stigmer#781):
577
+ // a timeout resolves to the outcome NAMED "escalate", so that outcome must
578
+ // exist and declare where the escalation branch goes. Checked at load so a
579
+ // misconfigured gate fails before it ever waits on a reviewer — the server
580
+ // validator enforces the same shape at apply; this covers hand-written YAML.
581
+ if (onTimeout === "escalate") {
582
+ const escalation = outcomes?.find((o) => o.name === "escalate");
583
+ if (!escalation || !escalation.then) {
584
+ throw new Error(`human_input task '${taskName}': on_timeout policy 'escalate' requires ` +
585
+ `an outcome named 'escalate' with 'then' set (the timeout resolves to ` +
586
+ `that outcome and follows its 'then' branch)`);
587
+ }
588
+ }
511
589
  return {
512
590
  prompt: obj.prompt,
513
- outcomes: Array.isArray(obj.outcomes) && obj.outcomes.length > 0
514
- ? obj.outcomes.map((o) => ({ name: o.name, label: o.label, then: o.then }))
515
- : undefined,
591
+ outcomes,
516
592
  formSchema: obj.form_schema && typeof obj.form_schema === "object"
517
593
  ? obj.form_schema
518
594
  : undefined,
@@ -520,7 +596,7 @@ function parseHumanInputConfig(taskName, raw) {
520
596
  ? obj.approvers.filter((a) => typeof a === "string")
521
597
  : undefined,
522
598
  timeout: typeof obj.timeout === "number" ? obj.timeout : undefined,
523
- onTimeout: obj.on_timeout ?? undefined,
599
+ onTimeout,
524
600
  // Any JSON shape is a valid payload (expression string, object, array),
525
601
  // so only null/undefined mean "no payload" here.
526
602
  payload: obj.payload ?? undefined,