@yycholla/pi-dynamic-workflows 3.3.0

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 (179) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +325 -0
  3. package/assets/readme/hero.png +0 -0
  4. package/assets/readme/hero.svg +70 -0
  5. package/assets/readme/package-cover.png +0 -0
  6. package/assets/readme/package-cover.svg +66 -0
  7. package/assets/readme/workflow.png +0 -0
  8. package/assets/readme/workflow.svg +77 -0
  9. package/dist/accept-workflow-guidance.d.ts +14 -0
  10. package/dist/accept-workflow-guidance.js +53 -0
  11. package/dist/adversarial-review.d.ts +30 -0
  12. package/dist/adversarial-review.js +107 -0
  13. package/dist/agent-history.d.ts +20 -0
  14. package/dist/agent-history.js +122 -0
  15. package/dist/agent-registry.d.ts +83 -0
  16. package/dist/agent-registry.js +190 -0
  17. package/dist/agent.d.ts +364 -0
  18. package/dist/agent.js +714 -0
  19. package/dist/builtin-commands.d.ts +19 -0
  20. package/dist/builtin-commands.js +251 -0
  21. package/dist/builtin-workflows.d.ts +45 -0
  22. package/dist/builtin-workflows.js +121 -0
  23. package/dist/code-review.d.ts +26 -0
  24. package/dist/code-review.js +181 -0
  25. package/dist/config.d.ts +37 -0
  26. package/dist/config.js +44 -0
  27. package/dist/deep-research.d.ts +30 -0
  28. package/dist/deep-research.js +124 -0
  29. package/dist/display.d.ts +134 -0
  30. package/dist/display.js +248 -0
  31. package/dist/effort-command.d.ts +28 -0
  32. package/dist/effort-command.js +68 -0
  33. package/dist/enums.d.ts +69 -0
  34. package/dist/enums.js +78 -0
  35. package/dist/errors.d.ts +113 -0
  36. package/dist/errors.js +140 -0
  37. package/dist/extension-reload.d.ts +37 -0
  38. package/dist/extension-reload.js +78 -0
  39. package/dist/fs-persistence.d.ts +63 -0
  40. package/dist/fs-persistence.js +102 -0
  41. package/dist/index.d.ts +57 -0
  42. package/dist/index.js +35 -0
  43. package/dist/logger.d.ts +21 -0
  44. package/dist/logger.js +66 -0
  45. package/dist/model-routing.d.ts +30 -0
  46. package/dist/model-routing.js +50 -0
  47. package/dist/model-spec.d.ts +29 -0
  48. package/dist/model-spec.js +252 -0
  49. package/dist/model-tier-config.d.ts +133 -0
  50. package/dist/model-tier-config.js +249 -0
  51. package/dist/run-persistence.d.ts +180 -0
  52. package/dist/run-persistence.js +294 -0
  53. package/dist/saved-commands.d.ts +28 -0
  54. package/dist/saved-commands.js +100 -0
  55. package/dist/shared-store.d.ts +98 -0
  56. package/dist/shared-store.js +212 -0
  57. package/dist/structured-output.d.ts +19 -0
  58. package/dist/structured-output.js +30 -0
  59. package/dist/task-panel.d.ts +61 -0
  60. package/dist/task-panel.js +422 -0
  61. package/dist/usage-limit-scheduler.d.ts +145 -0
  62. package/dist/usage-limit-scheduler.js +368 -0
  63. package/dist/web-tools.d.ts +20 -0
  64. package/dist/web-tools.js +120 -0
  65. package/dist/workflow-authoring-coverage.d.ts +70 -0
  66. package/dist/workflow-authoring-coverage.js +421 -0
  67. package/dist/workflow-authoring-reference.d.ts +20 -0
  68. package/dist/workflow-authoring-reference.js +156 -0
  69. package/dist/workflow-capability-contract.d.ts +131 -0
  70. package/dist/workflow-capability-contract.js +604 -0
  71. package/dist/workflow-commands.d.ts +18 -0
  72. package/dist/workflow-commands.js +260 -0
  73. package/dist/workflow-comprehension.d.ts +133 -0
  74. package/dist/workflow-comprehension.js +1321 -0
  75. package/dist/workflow-context-measurement.d.ts +72 -0
  76. package/dist/workflow-context-measurement.js +213 -0
  77. package/dist/workflow-control-tool.d.ts +30 -0
  78. package/dist/workflow-control-tool.js +176 -0
  79. package/dist/workflow-delivery-choice.d.ts +20 -0
  80. package/dist/workflow-delivery-choice.js +48 -0
  81. package/dist/workflow-editor.d.ts +93 -0
  82. package/dist/workflow-editor.js +363 -0
  83. package/dist/workflow-manager.d.ts +492 -0
  84. package/dist/workflow-manager.js +1124 -0
  85. package/dist/workflow-paths.d.ts +22 -0
  86. package/dist/workflow-paths.js +46 -0
  87. package/dist/workflow-release-gate.d.ts +39 -0
  88. package/dist/workflow-release-gate.js +309 -0
  89. package/dist/workflow-saved.d.ts +38 -0
  90. package/dist/workflow-saved.js +126 -0
  91. package/dist/workflow-settings.d.ts +70 -0
  92. package/dist/workflow-settings.js +131 -0
  93. package/dist/workflow-tool.d.ts +71 -0
  94. package/dist/workflow-tool.js +367 -0
  95. package/dist/workflow-ui.d.ts +182 -0
  96. package/dist/workflow-ui.js +1587 -0
  97. package/dist/workflow.d.ts +333 -0
  98. package/dist/workflow.js +1151 -0
  99. package/dist/workflows-models-command.d.ts +31 -0
  100. package/dist/workflows-models-command.js +156 -0
  101. package/dist/worktree.d.ts +25 -0
  102. package/dist/worktree.js +61 -0
  103. package/extensions/workflow.ts +151 -0
  104. package/package.json +104 -0
  105. package/skills/workflow-authoring/SKILL.md +30 -0
  106. package/skills/workflow-authoring/examples/adversarial-verification.js +63 -0
  107. package/skills/workflow-authoring/examples/bounded-semantic-retry.js +56 -0
  108. package/skills/workflow-authoring/examples/classify-and-act.js +67 -0
  109. package/skills/workflow-authoring/examples/fan-out-and-synthesize.js +47 -0
  110. package/skills/workflow-authoring/examples/generate-and-filter.js +68 -0
  111. package/skills/workflow-authoring/examples/loop-until-done.js +68 -0
  112. package/skills/workflow-authoring/examples/phased-budgets.js +75 -0
  113. package/skills/workflow-authoring/examples/saved-nested-workflows.js +44 -0
  114. package/skills/workflow-authoring/examples/structured-output.js +37 -0
  115. package/skills/workflow-authoring/examples/tournament.js +81 -0
  116. package/skills/workflow-authoring/examples/validated-gate.js +63 -0
  117. package/skills/workflow-authoring/references/capabilities.md +41 -0
  118. package/skills/workflow-authoring/references/capability-details.md +357 -0
  119. package/skills/workflow-authoring/references/common-helpers.md +4 -0
  120. package/skills/workflow-authoring/references/debugging.md +27 -0
  121. package/skills/workflow-authoring/references/focused-recipes.md +11 -0
  122. package/skills/workflow-authoring/references/helpers.md +9 -0
  123. package/skills/workflow-authoring/references/lifecycle.md +33 -0
  124. package/skills/workflow-authoring/references/pattern-selection.md +15 -0
  125. package/skills/workflow-authoring/references/quality-helpers.md +8 -0
  126. package/skills/workflow-authoring/references/registry-ownership.md +15 -0
  127. package/skills/workflow-authoring/references/retry-helper.md +5 -0
  128. package/skills/workflow-authoring/references/review.md +43 -0
  129. package/skills/workflow-authoring/references/runtime.md +27 -0
  130. package/skills/workflow-authoring/references/specialized-helpers.md +19 -0
  131. package/skills/workflow-authoring/references/versions.md +13 -0
  132. package/skills/workflow-patterns/SKILL.md +51 -0
  133. package/src/accept-workflow-guidance.ts +71 -0
  134. package/src/adversarial-review.ts +120 -0
  135. package/src/agent-history.ts +157 -0
  136. package/src/agent-registry.ts +221 -0
  137. package/src/agent.ts +929 -0
  138. package/src/builtin-commands.ts +286 -0
  139. package/src/builtin-workflows.ts +155 -0
  140. package/src/code-review.ts +183 -0
  141. package/src/config.ts +55 -0
  142. package/src/deep-research.ts +135 -0
  143. package/src/display.ts +367 -0
  144. package/src/effort-command.ts +87 -0
  145. package/src/enums.ts +77 -0
  146. package/src/errors.ts +199 -0
  147. package/src/extension-reload.ts +100 -0
  148. package/src/fs-persistence.ts +124 -0
  149. package/src/index.ts +176 -0
  150. package/src/logger.ts +88 -0
  151. package/src/model-routing.ts +73 -0
  152. package/src/model-spec.ts +309 -0
  153. package/src/model-tier-config.ts +296 -0
  154. package/src/run-persistence.ts +484 -0
  155. package/src/saved-commands.ts +115 -0
  156. package/src/shared-store.ts +228 -0
  157. package/src/structured-output.ts +47 -0
  158. package/src/task-panel.ts +490 -0
  159. package/src/usage-limit-scheduler.ts +432 -0
  160. package/src/web-tools.ts +124 -0
  161. package/src/workflow-authoring-coverage.ts +486 -0
  162. package/src/workflow-authoring-reference.ts +186 -0
  163. package/src/workflow-capability-contract.ts +806 -0
  164. package/src/workflow-commands.ts +287 -0
  165. package/src/workflow-comprehension.ts +1673 -0
  166. package/src/workflow-context-measurement.ts +262 -0
  167. package/src/workflow-control-tool.ts +238 -0
  168. package/src/workflow-delivery-choice.ts +69 -0
  169. package/src/workflow-editor.ts +444 -0
  170. package/src/workflow-manager.ts +1405 -0
  171. package/src/workflow-paths.ts +63 -0
  172. package/src/workflow-release-gate.ts +529 -0
  173. package/src/workflow-saved.ts +180 -0
  174. package/src/workflow-settings.ts +194 -0
  175. package/src/workflow-tool.ts +464 -0
  176. package/src/workflow-ui.ts +1789 -0
  177. package/src/workflow.ts +1615 -0
  178. package/src/workflows-models-command.ts +211 -0
  179. package/src/worktree.ts +76 -0
@@ -0,0 +1,604 @@
1
+ import packageJson from "../package.json" with { type: "json" };
2
+ import { CapabilityClassification, CapabilityOrigin, CapabilitySupport, DiagnosticSeverity, DiscoveryPlacement, } from "./enums.js";
3
+ import { WorkflowCapabilityContractError } from "./errors.js";
4
+ /** Re-exported capability domains used by contract consumers. */
5
+ export { CapabilityClassification, CapabilityOrigin, CapabilitySupport, DiagnosticSeverity, DiscoveryPlacement, } from "./enums.js";
6
+ /** Re-exported contract failure type retained for existing consumers. */
7
+ export { WorkflowCapabilityContractError } from "./errors.js";
8
+ const REFERENCE_PATH = "skills/workflow-authoring/references/capability-details.md";
9
+ const PRESENT_AT = { kind: "present-at", version: packageJson.version };
10
+ const noOptions = [];
11
+ const option = (name, type, optional, defaultValue = null, constraints = noOptions, dynamicReference = null) => ({ name, type, optional, default: defaultValue, constraints, dynamicReference });
12
+ const AGENT_OPTIONS = {
13
+ id: "agent-options",
14
+ options: [
15
+ option("label", "string", true, "derived from phase and call count"),
16
+ option("phase", "string", true, "current phase"),
17
+ option("schema", "plain JSON Schema", true),
18
+ option("model", "string", true, null, ["highest-priority exact model selector"]),
19
+ option("tier", "string", true, null, ["configured route name"], "model-routes"),
20
+ option("isolation", '"worktree"', true),
21
+ option("agentType", "string", true, null, ["must come from provided context"], "agent-types"),
22
+ option("timeoutMs", "number | null", true, "run timeout; null disables"),
23
+ option("retries", "number", true, "run retry count", ["finite values are floored and clamped to 0..3"]),
24
+ ],
25
+ };
26
+ const CHECKPOINT_OPTIONS = {
27
+ id: "checkpoint-options",
28
+ options: [
29
+ option("default", "unknown", true, "true when no UI and omitted"),
30
+ option("headless", '"default" | "abort"', true, '"default"'),
31
+ option("kind", '"confirm" | "input" | "select"', true, '"confirm"'),
32
+ option("choices", "string[]", true),
33
+ option("timeoutMs", "number", true),
34
+ ],
35
+ };
36
+ const PHASE_OPTIONS = {
37
+ id: "phase-options",
38
+ options: [option("budget", "number", true, null, ["positive soft pre-call token gate"])],
39
+ };
40
+ const VERIFY_OPTIONS = {
41
+ id: "verify-options",
42
+ options: [
43
+ option("reviewers", "number", true, "2", ["authors should provide a finite integer; runtime clamps below 1"]),
44
+ option("threshold", "number", true, "0.5"),
45
+ option("lens", "string | string[]", true),
46
+ ],
47
+ };
48
+ const JUDGE_PANEL_OPTIONS = {
49
+ id: "judge-panel-options",
50
+ options: [
51
+ option("judges", "number", true, "3", ["authors should provide a finite integer; runtime clamps below 1"]),
52
+ option("rubric", "string", true, '"overall quality and correctness"'),
53
+ ],
54
+ };
55
+ const LOOP_UNTIL_DRY_OPTIONS = {
56
+ id: "loop-until-dry-options",
57
+ options: [
58
+ option("round", "(roundIndex: number) => unknown[] | Promise<unknown[]>", false),
59
+ option("key", "(item: unknown) => string", true, "JSON.stringify"),
60
+ option("consecutiveEmpty", "number", true, "2", [
61
+ "authors should provide a finite integer; runtime clamps below 1",
62
+ ]),
63
+ option("maxRounds", "number", true, "50", ["authors should provide a finite positive integer"]),
64
+ ],
65
+ };
66
+ const RETRY_OPTIONS = {
67
+ id: "retry-options",
68
+ options: [
69
+ option("attempts", "number", true, "3", [
70
+ "authors must provide a finite integer; runtime clamps values below 1 to 1",
71
+ ]),
72
+ option("until", "(result: unknown) => boolean", true, "accept first result when omitted", [
73
+ "must be synchronous; use gate for asynchronous validation",
74
+ ]),
75
+ ],
76
+ };
77
+ const GATE_OPTIONS = {
78
+ id: "gate-options",
79
+ options: [
80
+ option("attempts", "number", true, "3", [
81
+ "authors must provide a finite integer; runtime clamps values below 1 to 1",
82
+ ]),
83
+ ],
84
+ };
85
+ const runtimeGlobal = (name, options = {}) => ({
86
+ id: `workflow.runtime.${name}`,
87
+ label: name,
88
+ classification: CapabilityClassification.RUNTIME_GLOBAL,
89
+ support: options.support ?? CapabilitySupport.SUPPORTED,
90
+ discovery: options.discovery ?? DiscoveryPlacement.COMPACT_GUIDANCE,
91
+ origin: CapabilityOrigin.PROJECT,
92
+ lifecycle: PRESENT_AT,
93
+ signature: options.signature ?? name,
94
+ optionShape: options.optionShape ?? null,
95
+ constraints: options.constraints ?? noOptions,
96
+ enforcementOwner: "runWorkflow context assembly",
97
+ runtimeBinding: {
98
+ global: name,
99
+ implementation: name,
100
+ ...(options.allowsUndefined ? { allowsUndefined: true } : {}),
101
+ },
102
+ behaviorEvidence: options.evidence ?? ["tests/workflow-runtime.test.ts"],
103
+ staticReference: { path: REFERENCE_PATH, anchor: name.toLowerCase() },
104
+ dynamicReference: null,
105
+ });
106
+ const toolInput = (name, signature, constraints = noOptions) => ({
107
+ id: `workflow.tool-input.${name}`,
108
+ label: name,
109
+ classification: CapabilityClassification.WORKFLOW_TOOL_INPUT,
110
+ support: CapabilitySupport.SUPPORTED,
111
+ discovery: DiscoveryPlacement.COMPACT_GUIDANCE,
112
+ origin: CapabilityOrigin.TOOL_ADAPTER,
113
+ lifecycle: PRESENT_AT,
114
+ signature,
115
+ optionShape: null,
116
+ constraints,
117
+ enforcementOwner: "workflowToolSchema and createWorkflowTool",
118
+ runtimeBinding: null,
119
+ behaviorEvidence: ["tests/workflow-tool.test.ts"],
120
+ staticReference: { path: REFERENCE_PATH, anchor: `tool-input-${name.toLowerCase()}` },
121
+ dynamicReference: null,
122
+ });
123
+ const capabilities = [
124
+ runtimeGlobal("agent", {
125
+ signature: "agent(prompt, options?) => Promise<string | structured value | null>",
126
+ optionShape: "agent-options",
127
+ constraints: [
128
+ "recoverable failures return null after retries; nonrecoverable failures throw",
129
+ "schema noncompliance after bounded structured-output repair is nonrecoverable and bypasses agent retries",
130
+ "per-agent retries override invocation retries; retries are floored and clamped to 0..3",
131
+ "resume replays only the longest unchanged prefix; the first miss and every later call execute live",
132
+ "selector priority is explicit model > agentType model > tier > phase model > metadata model > implicit medium > session default",
133
+ "if the selected model or route is unavailable, execution falls directly to the session default rather than trying lower-priority selectors",
134
+ "worktree isolation is best-effort; failure logs that isolation was ignored and continues without an isolated working directory",
135
+ ],
136
+ evidence: ["tests/workflow-runtime.test.ts", "tests/agent-registry.test.ts", "tests/structured-output.test.ts"],
137
+ }),
138
+ runtimeGlobal("parallel", {
139
+ signature: "parallel(thunks) => Promise<Array<unknown | null>>",
140
+ constraints: [
141
+ "requires functions rather than promises",
142
+ "result order matches input order",
143
+ "recoverable thunk failures become null; nonrecoverable failures throw",
144
+ ],
145
+ }),
146
+ runtimeGlobal("pipeline", {
147
+ signature: "pipeline(items, ...stages) => Promise<Array<unknown | null>>",
148
+ constraints: [
149
+ "items run concurrently while stages per item run sequentially",
150
+ "each stage receives previousValue, originalItem, and zero-based index",
151
+ "a null stage result is passed to the next stage; authors must guard missing coverage explicitly",
152
+ "recoverable stage failures become null; nonrecoverable failures throw",
153
+ ],
154
+ }),
155
+ runtimeGlobal("workflow", {
156
+ signature: "workflow(savedName, childArgs?) => Promise<unknown>",
157
+ constraints: [
158
+ "one nested level",
159
+ "shares limiter, counters, token accounting, and store",
160
+ "nested workflows do not reuse the parent resume journal",
161
+ ],
162
+ evidence: ["tests/workflow-saved.test.ts", "tests/shared-store.test.ts"],
163
+ }),
164
+ runtimeGlobal("verify", {
165
+ signature: "verify(item: unknown, options?: { reviewers?: number; threshold?: number; lens?: string | string[] }) => Promise<{ real: boolean; realCount: number; total: number; votes: Array<{ real: boolean; reason?: string }> }>",
166
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
167
+ optionShape: "verify-options",
168
+ constraints: [
169
+ "reviewer failures are omitted; successful votes form the denominator in realCount / total",
170
+ "threshold comparison is inclusive and real is false when no reviewer succeeds",
171
+ "multiple lenses cycle across reviewers",
172
+ ],
173
+ evidence: ["tests/quality-stdlib.test.ts"],
174
+ }),
175
+ runtimeGlobal("judgePanel", {
176
+ signature: "judgePanel(attempts: unknown[], options?: { judges?: number; rubric?: string }) => Promise<{ index: number; attempt: unknown; score: number; judgments: Array<{ score: number; reason?: string }> } | undefined>",
177
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
178
+ optionShape: "judge-panel-options",
179
+ constraints: [
180
+ "failed judgments are omitted and each candidate score averages successful judgments only",
181
+ "a candidate with no successful judgments scores 0",
182
+ "highest mean score wins with stable input index as the tie-break; empty input returns undefined",
183
+ ],
184
+ evidence: ["tests/quality-stdlib.test.ts"],
185
+ }),
186
+ runtimeGlobal("loopUntilDry", {
187
+ signature: "loopUntilDry(options: { round: (roundIndex: number) => unknown[] | Promise<unknown[]>; key?: (item: unknown) => string; consecutiveEmpty?: number; maxRounds?: number }) => Promise<unknown[]>",
188
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
189
+ optionShape: "loop-until-dry-options",
190
+ constraints: [
191
+ "roundIndex is zero-based; null, non-array, or duplicate-only round results count as empty",
192
+ "token-budget or agent-limit capacity exhaustion returns the accumulated partial array instead of throwing",
193
+ "the returned array does not report whether termination came from dryness, maxRounds, or capacity exhaustion",
194
+ "authors must retain failed-round identity and truthful termination state outside the helper",
195
+ ],
196
+ evidence: ["tests/quality-stdlib.test.ts"],
197
+ }),
198
+ runtimeGlobal("completenessCheck", {
199
+ signature: "completenessCheck(taskArgs: unknown, results: unknown) => Promise<{ complete: boolean; missing?: string[] } | null>",
200
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
201
+ constraints: [
202
+ "only the first 4,000 characters of serialized result evidence are sent to the critic",
203
+ "missing is optional and recoverable critic failure returns null",
204
+ "large evidence sets must be chunked or summarized before relying on the advisory verdict",
205
+ ],
206
+ evidence: ["tests/quality-stdlib.test.ts"],
207
+ }),
208
+ runtimeGlobal("retry", {
209
+ signature: "retry(thunk: (attempt: number) => unknown | Promise<unknown>, options?: { attempts?: number; until?: (result: unknown) => boolean }) => Promise<unknown>",
210
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
211
+ optionShape: "retry-options",
212
+ constraints: [
213
+ "attempt is zero-based and attempts counts total thunk calls",
214
+ "until is synchronous; returning a Promise is truthy and accepts the first result",
215
+ "omitting until accepts the first result regardless of attempts",
216
+ "stops when until(result) is true; exhaustion returns only the last result without attempt metadata",
217
+ "authors must supply a finite attempts bound when overriding the default",
218
+ ],
219
+ evidence: ["tests/quality-stdlib.test.ts"],
220
+ }),
221
+ runtimeGlobal("gate", {
222
+ signature: "gate(thunk: (feedback: string | undefined, attempt: number) => unknown | Promise<unknown>, validator: (value: unknown) => { ok: boolean; feedback?: string } | Promise<{ ok: boolean; feedback?: string }>, options?: { attempts?: number }) => Promise<{ ok: boolean; value: unknown; attempts: number }>",
223
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
224
+ optionShape: "gate-options",
225
+ constraints: [
226
+ "feedback is undefined on the first thunk call and then receives the previous validator feedback string",
227
+ "attempt is zero-based for the thunk while the returned attempts count is one-based",
228
+ "a value is accepted when the validator returns an object with a truthy ok property; a bare boolean is not accepted",
229
+ "exhaustion returns ok false with the last value and the bounded attempts count",
230
+ "authors must supply a finite attempts bound when overriding the default",
231
+ ],
232
+ evidence: ["tests/quality-stdlib.test.ts"],
233
+ }),
234
+ runtimeGlobal("checkpoint", {
235
+ signature: "checkpoint(prompt, options?) => Promise<unknown>",
236
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
237
+ optionShape: "checkpoint-options",
238
+ constraints: [
239
+ "foreground confirm and headless behavior are implemented; input/select/timeout are declared-only",
240
+ "consumes one agent slot and no tokens",
241
+ "journaled answers replay only within an unchanged resume prefix",
242
+ ],
243
+ evidence: ["tests/checkpoint.test.ts"],
244
+ }),
245
+ runtimeGlobal("log", { signature: "log(message) => void" }),
246
+ runtimeGlobal("phase", {
247
+ signature: "phase(title, options?) => void",
248
+ optionShape: "phase-options",
249
+ constraints: ["phase budgets are soft pre-call gates"],
250
+ }),
251
+ runtimeGlobal("args", { signature: "args: unknown", allowsUndefined: true }),
252
+ runtimeGlobal("cwd", { signature: "cwd: string" }),
253
+ runtimeGlobal("process", { signature: "process: { cwd(): string }" }),
254
+ runtimeGlobal("budget", {
255
+ signature: "budget: { total, spent(), remaining() }",
256
+ constraints: [
257
+ "frozen view over shared soft token accounting",
258
+ "spend accrues after agents finish, so in-flight work can overshoot",
259
+ "nested workflows share the same accounting",
260
+ ],
261
+ }),
262
+ runtimeGlobal("console", {
263
+ signature: "console: { log, info, warn, error }",
264
+ support: CapabilitySupport.COMPATIBILITY,
265
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
266
+ constraints: ["new workflows should use log()"],
267
+ }),
268
+ toolInput("script", "script?: string", ["required raw JavaScript workflow source unless `name` is given"]),
269
+ toolInput("name", "name?: string", [
270
+ "resolves a project/user saved workflow first, then one of the 5 built-in patterns",
271
+ "mutually exclusive with resumeFromRunId",
272
+ ]),
273
+ toolInput("args", "args?: unknown"),
274
+ toolInput("background", "background?: boolean = true", [
275
+ "background workflows are headless; use background false when checkpoint must show foreground confirmation",
276
+ ]),
277
+ toolInput("maxAgents", "maxAgents?: number = 1000", ["default, not a hard product maximum"]),
278
+ toolInput("concurrency", "concurrency?: number", ["runtime clamps to 1..16"]),
279
+ toolInput("agentRetries", "agentRetries?: number = configured value or 0", ["floored and clamped to 0..3"]),
280
+ toolInput("agentTimeoutMs", "agentTimeoutMs?: number = configured default or unbounded"),
281
+ toolInput("tokenBudget", "tokenBudget?: number = configured default or unlimited", [
282
+ "soft pre-call gate; in-flight work can overshoot",
283
+ ]),
284
+ toolInput("resumeFromRunId", "resumeFromRunId?: string", [
285
+ "resumes a prior incomplete run with an edited script",
286
+ "unchanged positional agent calls replay from cache until the first changed or inserted call",
287
+ "always runs in the background",
288
+ ]),
289
+ {
290
+ id: "workflow.script.metadata",
291
+ label: "export const meta",
292
+ classification: CapabilityClassification.SCRIPT_CONTRACT,
293
+ support: CapabilitySupport.SUPPORTED,
294
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
295
+ origin: CapabilityOrigin.PROJECT,
296
+ lifecycle: PRESENT_AT,
297
+ signature: "export const meta = { name: string, description: string, phases?: Array<{ title: string; detail?: string; model?: string }>, model?: string }",
298
+ optionShape: null,
299
+ constraints: [
300
+ "must be the first statement",
301
+ "name and description must be nonblank strings",
302
+ "metadata must use literal values; expressions such as string concatenation and template interpolation are rejected",
303
+ "the meta declaration is the only legal export because the remaining body executes inside an async function",
304
+ ],
305
+ enforcementOwner: "parseWorkflowScript",
306
+ runtimeBinding: null,
307
+ behaviorEvidence: ["tests/workflow-parser.test.ts"],
308
+ staticReference: { path: REFERENCE_PATH, anchor: "metadata" },
309
+ dynamicReference: null,
310
+ },
311
+ {
312
+ id: "workflow.script.return-value",
313
+ label: "workflow return value",
314
+ classification: CapabilityClassification.SCRIPT_CONTRACT,
315
+ support: CapabilitySupport.SUPPORTED,
316
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
317
+ origin: CapabilityOrigin.PROJECT,
318
+ lifecycle: PRESENT_AT,
319
+ signature: "return JSON-serializable data",
320
+ optionShape: null,
321
+ constraints: ["do not return functions, promises, cyclic objects, BigInt, or runtime handles"],
322
+ enforcementOwner: "workflow tool result boundary",
323
+ runtimeBinding: null,
324
+ behaviorEvidence: ["tests/workflow-authoring-skill.test.ts", "tests/workflow-tool.test.ts"],
325
+ staticReference: { path: REFERENCE_PATH, anchor: "return-value" },
326
+ dynamicReference: null,
327
+ },
328
+ {
329
+ id: "workflow.script.determinism",
330
+ label: "deterministic script execution",
331
+ classification: CapabilityClassification.SCRIPT_CONTRACT,
332
+ support: CapabilitySupport.SUPPORTED,
333
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
334
+ origin: CapabilityOrigin.PROJECT,
335
+ lifecycle: PRESENT_AT,
336
+ signature: null,
337
+ optionShape: null,
338
+ constraints: [
339
+ "Date.now(), Math.random(), and no-argument new Date() are unavailable",
340
+ "pass timestamps and randomness through args",
341
+ ],
342
+ enforcementOwner: "parseWorkflowScript and VM determinism prelude",
343
+ runtimeBinding: null,
344
+ behaviorEvidence: ["tests/workflow-parser.test.ts", "tests/workflow-runtime.test.ts"],
345
+ staticReference: { path: REFERENCE_PATH, anchor: "determinism" },
346
+ dynamicReference: null,
347
+ },
348
+ {
349
+ id: "workflow.compat.markdown-fences",
350
+ label: "whole-script Markdown fence stripping",
351
+ classification: CapabilityClassification.COMPATIBILITY_BEHAVIOR,
352
+ support: CapabilitySupport.COMPATIBILITY,
353
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
354
+ origin: CapabilityOrigin.TOOL_ADAPTER,
355
+ lifecycle: PRESENT_AT,
356
+ signature: null,
357
+ optionShape: null,
358
+ constraints: ["accepted for compatibility but not recommended"],
359
+ enforcementOwner: "normalizeWorkflowScript",
360
+ runtimeBinding: null,
361
+ behaviorEvidence: ["tests/workflow-tool.test.ts"],
362
+ staticReference: { path: REFERENCE_PATH, anchor: "compatibility" },
363
+ dynamicReference: null,
364
+ },
365
+ {
366
+ id: "workflow.vm.realm-substrate",
367
+ label: "VM realm JavaScript substrate",
368
+ classification: CapabilityClassification.INTERNAL_SUBSTRATE,
369
+ support: CapabilitySupport.INTERNAL,
370
+ discovery: DiscoveryPlacement.NONE,
371
+ origin: CapabilityOrigin.VM_REALM,
372
+ lifecycle: PRESENT_AT,
373
+ signature: null,
374
+ optionShape: null,
375
+ constraints: ["Node-version-dependent globals are not project-owned workflow API", "VM is not a security sandbox"],
376
+ enforcementOwner: "node:vm",
377
+ runtimeBinding: null,
378
+ behaviorEvidence: ["tests/workflow-runtime.test.ts"],
379
+ staticReference: null,
380
+ dynamicReference: null,
381
+ },
382
+ {
383
+ id: "workflow.dynamic.model-routes",
384
+ label: "model routes",
385
+ classification: CapabilityClassification.DYNAMIC_REFERENCE,
386
+ support: CapabilitySupport.SUPPORTED,
387
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
388
+ origin: CapabilityOrigin.LIVE_CONFIGURATION,
389
+ lifecycle: PRESENT_AT,
390
+ signature: null,
391
+ optionShape: null,
392
+ constraints: ["live values must not be copied into static contract data"],
393
+ enforcementOwner: "model-tier-config",
394
+ runtimeBinding: null,
395
+ behaviorEvidence: ["tests/workflows-models-command.test.ts"],
396
+ staticReference: { path: REFERENCE_PATH, anchor: "model-routes" },
397
+ dynamicReference: "model-routes",
398
+ },
399
+ {
400
+ id: "workflow.dynamic.agent-types",
401
+ label: "agent types",
402
+ classification: CapabilityClassification.DYNAMIC_REFERENCE,
403
+ support: CapabilitySupport.SUPPORTED,
404
+ discovery: DiscoveryPlacement.WORKFLOW_AUTHORING_SKILL,
405
+ origin: CapabilityOrigin.LIVE_CONFIGURATION,
406
+ lifecycle: PRESENT_AT,
407
+ signature: null,
408
+ optionShape: null,
409
+ constraints: ["live values must not be copied into static contract data"],
410
+ enforcementOwner: "agent-registry",
411
+ runtimeBinding: null,
412
+ behaviorEvidence: ["tests/agent-registry.test.ts"],
413
+ staticReference: { path: REFERENCE_PATH, anchor: "agent-types" },
414
+ dynamicReference: "agent-types",
415
+ },
416
+ ];
417
+ /** Authoritative versioned inventory used by runtime assembly and every static projection. */
418
+ export const WORKFLOW_CAPABILITY_DEFINITION = {
419
+ versions: {
420
+ extension: packageJson.version,
421
+ format: { kind: "present-at", version: "1.0.0" },
422
+ content: PRESENT_AT,
423
+ },
424
+ optionShapes: [
425
+ AGENT_OPTIONS,
426
+ CHECKPOINT_OPTIONS,
427
+ PHASE_OPTIONS,
428
+ VERIFY_OPTIONS,
429
+ JUDGE_PANEL_OPTIONS,
430
+ LOOP_UNTIL_DRY_OPTIONS,
431
+ RETRY_OPTIONS,
432
+ GATE_OPTIONS,
433
+ ],
434
+ capabilities,
435
+ dynamicReferences: [
436
+ {
437
+ id: "model-routes",
438
+ owner: "model-tier-config",
439
+ itemShape: "{ name: string; description?: string }",
440
+ connection: "loadModelTierConfig",
441
+ },
442
+ {
443
+ id: "agent-types",
444
+ owner: "agent-registry",
445
+ itemShape: "{ name: string; description?: string }",
446
+ connection: "loadAgentRegistry",
447
+ },
448
+ ],
449
+ };
450
+ /** Validate and freeze a definition, throwing with diagnostics when its identities or references conflict. */
451
+ export function defineWorkflowCapabilityContract(definition) {
452
+ deepFreeze(definition);
453
+ const definitionDiagnostics = validateDefinition(definition);
454
+ if (definitionDiagnostics.length > 0) {
455
+ throw new WorkflowCapabilityContractError("invalid workflow capability definition", definitionDiagnostics);
456
+ }
457
+ const optionShapes = new Map(definition.optionShapes.map((shape) => [shape.id, shape]));
458
+ const dynamicReferences = new Map(definition.dynamicReferences.map((reference) => [reference.id, reference]));
459
+ const bindings = definition.capabilities.flatMap((capability) => capability.runtimeBinding ? [{ ...capability.runtimeBinding }] : []);
460
+ const implementations = new Set(bindings.map((binding) => binding.implementation));
461
+ const globals = new Set(bindings.map((binding) => binding.global));
462
+ const diagnoseAlignment = (evidence) => {
463
+ const diagnostics = [];
464
+ if (evidence.suppliedImplementations) {
465
+ for (const binding of bindings) {
466
+ if (!Object.hasOwn(evidence.suppliedImplementations, binding.implementation) ||
467
+ (evidence.suppliedImplementations[binding.implementation] === undefined && !binding.allowsUndefined)) {
468
+ diagnostics.push({
469
+ code: "MISSING_RUNTIME_IMPLEMENTATION",
470
+ severity: DiagnosticSeverity.ERROR,
471
+ subject: binding.implementation,
472
+ message: `Declared workflow global "${binding.global}" has no supplied implementation "${binding.implementation}".`,
473
+ });
474
+ }
475
+ }
476
+ for (const name of Object.keys(evidence.suppliedImplementations)) {
477
+ if (!implementations.has(name)) {
478
+ diagnostics.push({
479
+ code: "UNDECLARED_RUNTIME_IMPLEMENTATION",
480
+ severity: DiagnosticSeverity.WARNING,
481
+ subject: name,
482
+ message: `Supplied runtime implementation "${name}" is undeclared and was ignored.`,
483
+ });
484
+ }
485
+ }
486
+ }
487
+ if (evidence.observedProjectGlobals) {
488
+ const observed = new Set(evidence.observedProjectGlobals);
489
+ for (const name of globals) {
490
+ if (!observed.has(name)) {
491
+ diagnostics.push({
492
+ code: "DECLARED_GLOBAL_UNOBSERVED",
493
+ severity: DiagnosticSeverity.ERROR,
494
+ subject: name,
495
+ message: `Declared workflow global "${name}" was not observed in the assembled context.`,
496
+ });
497
+ }
498
+ }
499
+ for (const name of observed) {
500
+ if (!globals.has(name)) {
501
+ diagnostics.push({
502
+ code: "OBSERVED_GLOBAL_UNDECLARED",
503
+ severity: DiagnosticSeverity.ERROR,
504
+ subject: name,
505
+ message: `Observed project-owned workflow global "${name}" is undeclared.`,
506
+ });
507
+ }
508
+ }
509
+ }
510
+ return diagnostics;
511
+ };
512
+ return {
513
+ definition,
514
+ assembleRuntimeBindings(supplied) {
515
+ const diagnostics = diagnoseAlignment({ suppliedImplementations: supplied });
516
+ const missing = diagnostics.filter((diagnostic) => diagnostic.code === "MISSING_RUNTIME_IMPLEMENTATION");
517
+ if (missing.length > 0) {
518
+ throw new WorkflowCapabilityContractError(`missing declared runtime implementation: ${missing.map((diagnostic) => diagnostic.subject).join(", ")}`, diagnostics);
519
+ }
520
+ const assembled = {};
521
+ for (const binding of bindings)
522
+ assembled[binding.global] = supplied[binding.implementation];
523
+ return { globals: assembled, diagnostics };
524
+ },
525
+ projectStaticReferenceFacts() {
526
+ return definition.capabilities
527
+ .filter((capability) => capability.staticReference !== null)
528
+ .map((capability) => ({
529
+ id: capability.id,
530
+ label: capability.label,
531
+ classification: capability.classification,
532
+ support: capability.support,
533
+ signature: capability.signature,
534
+ options: capability.optionShape ? (optionShapes.get(capability.optionShape) ?? null) : null,
535
+ constraints: capability.constraints,
536
+ reference: capability.staticReference
537
+ ? `${capability.staticReference.path}#${capability.staticReference.anchor}`
538
+ : null,
539
+ dynamicReference: capability.dynamicReference
540
+ ? (dynamicReferences.get(capability.dynamicReference) ?? null)
541
+ : null,
542
+ }));
543
+ },
544
+ diagnoseAlignment,
545
+ };
546
+ }
547
+ function validateDefinition(definition) {
548
+ const diagnostics = [];
549
+ const ids = new Set();
550
+ const globals = new Set();
551
+ const runtimeImplementations = new Set();
552
+ const optionShapes = new Set();
553
+ const dynamicReferences = new Set();
554
+ const invalid = (subject, message) => diagnostics.push({ code: "INVALID_CAPABILITY_DEFINITION", severity: DiagnosticSeverity.ERROR, subject, message });
555
+ for (const shape of definition.optionShapes) {
556
+ if (optionShapes.has(shape.id))
557
+ invalid(shape.id, `Duplicate option shape "${shape.id}".`);
558
+ optionShapes.add(shape.id);
559
+ }
560
+ for (const reference of definition.dynamicReferences) {
561
+ if (dynamicReferences.has(reference.id))
562
+ invalid(reference.id, `Duplicate dynamic reference "${reference.id}".`);
563
+ dynamicReferences.add(reference.id);
564
+ }
565
+ for (const capability of definition.capabilities) {
566
+ if (ids.has(capability.id))
567
+ invalid(capability.id, `Duplicate capability id "${capability.id}".`);
568
+ ids.add(capability.id);
569
+ if (capability.classification === CapabilityClassification.RUNTIME_GLOBAL && !capability.runtimeBinding) {
570
+ invalid(capability.id, "Runtime-global capabilities require a runtime binding.");
571
+ }
572
+ if (capability.runtimeBinding) {
573
+ if (globals.has(capability.runtimeBinding.global)) {
574
+ invalid(capability.runtimeBinding.global, `Duplicate runtime global "${capability.runtimeBinding.global}".`);
575
+ }
576
+ globals.add(capability.runtimeBinding.global);
577
+ if (runtimeImplementations.has(capability.runtimeBinding.implementation)) {
578
+ invalid(capability.runtimeBinding.implementation, `Duplicate runtime implementation identity "${capability.runtimeBinding.implementation}".`);
579
+ }
580
+ runtimeImplementations.add(capability.runtimeBinding.implementation);
581
+ if (capability.classification !== CapabilityClassification.RUNTIME_GLOBAL ||
582
+ capability.origin !== CapabilityOrigin.PROJECT) {
583
+ invalid(capability.id, "Runtime bindings require runtime-global classification and project origin.");
584
+ }
585
+ }
586
+ if (capability.optionShape && !optionShapes.has(capability.optionShape)) {
587
+ invalid(capability.id, `Unknown option shape "${capability.optionShape}".`);
588
+ }
589
+ if (capability.dynamicReference && !dynamicReferences.has(capability.dynamicReference)) {
590
+ invalid(capability.id, `Unknown dynamic reference "${capability.dynamicReference}".`);
591
+ }
592
+ }
593
+ return diagnostics;
594
+ }
595
+ function deepFreeze(value) {
596
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
597
+ for (const nested of Object.values(value))
598
+ deepFreeze(nested);
599
+ Object.freeze(value);
600
+ }
601
+ return value;
602
+ }
603
+ /** Installed validated workflow capability contract. */
604
+ export const WORKFLOW_CAPABILITY_CONTRACT = defineWorkflowCapabilityContract(WORKFLOW_CAPABILITY_DEFINITION);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `/workflows` slash command: list, inspect, and control background workflow runs.
3
+ * Shares the extension's single WorkflowManager so background runs are reachable.
4
+ */
5
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+ import { type EffortState } from "./effort-command.js";
7
+ import type { WorkflowManager } from "./workflow-manager.js";
8
+ import type { WorkflowStorage } from "./workflow-saved.js";
9
+ export interface WorkflowCommandOptions {
10
+ /** Saved-workflow storage, enabling `/workflows save`. */
11
+ storage?: WorkflowStorage;
12
+ /** Working directory for saved workflows registered via `save`. */
13
+ cwd?: string;
14
+ /** Standing effort mode; when high/ultra, `/workflows run` carries its directive too. */
15
+ effort?: EffortState;
16
+ }
17
+ /** Register the `/workflows` command against the shared manager. Idempotent. */
18
+ export declare function registerWorkflowCommands(pi: ExtensionAPI, manager: WorkflowManager, opts?: WorkflowCommandOptions): void;