@osolmaz/pi-workflows 0.12.1 → 0.13.1
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.
- package/README.md +59 -33
- package/dist/builtins/autodoc.workflow.d.ts +194 -7
- package/dist/builtins/autodoc.workflow.js +156 -30
- package/dist/builtins/autodoc.workflow.js.map +1 -1
- package/dist/builtins/autoimplement-command-batches.d.ts +1 -0
- package/dist/builtins/autoimplement-command-batches.js +29 -31
- package/dist/builtins/autoimplement-command-batches.js.map +1 -1
- package/dist/builtins/autoimplement.workflow.d.ts +1619 -97
- package/dist/builtins/autoimplement.workflow.js +416 -153
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/autoplan.workflow.d.ts +126 -13
- package/dist/builtins/autoplan.workflow.js +200 -29
- package/dist/builtins/autoplan.workflow.js.map +1 -1
- package/dist/builtins/catalog.js +7 -5
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/change-verification.workflow.d.ts +110 -0
- package/dist/builtins/change-verification.workflow.js +860 -0
- package/dist/builtins/change-verification.workflow.js.map +1 -0
- package/dist/builtins/index.d.ts +2 -1
- package/dist/builtins/index.js +1 -0
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/monitor.workflow.d.ts +56 -21
- package/dist/builtins/monitor.workflow.js +499 -217
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/plain-summary.workflow.d.ts +32 -0
- package/dist/builtins/plain-summary.workflow.js +134 -0
- package/dist/builtins/plain-summary.workflow.js.map +1 -0
- package/dist/builtins/plan-change.workflow.d.ts +527 -26
- package/dist/builtins/plan-change.workflow.js +26 -0
- package/dist/builtins/plan-change.workflow.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.d.ts +45 -3
- package/dist/builtins/sanity-check.workflow.js +45 -7
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/builtins/workspace-preparation.workflow.d.ts +75 -0
- package/dist/builtins/workspace-preparation.workflow.js +498 -0
- package/dist/builtins/workspace-preparation.workflow.js.map +1 -0
- package/dist/controllers/effects.d.ts +3 -2
- package/dist/controllers/effects.js +8 -1
- package/dist/controllers/effects.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/index.js +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/manager.d.ts +1 -0
- package/dist/controllers/manager.js +41 -17
- package/dist/controllers/manager.js.map +1 -1
- package/dist/controllers/sqlite.d.ts +107 -85
- package/dist/controllers/sqlite.js +1611 -1486
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/controllers/store.d.ts +9 -8
- package/dist/controllers/store.js +1 -31
- package/dist/controllers/store.js.map +1 -1
- package/dist/controllers/types.d.ts +3 -0
- package/dist/controllers/workflow-engine-scheduler.d.ts +1 -1
- package/dist/controllers/workflow-engine-scheduler.js +3 -5
- package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
- package/dist/controllers/workflows.d.ts +2 -2
- package/dist/controllers/workflows.js +11 -10
- package/dist/controllers/workflows.js.map +1 -1
- package/dist/extension/controller-host.js +2 -2
- package/dist/extension/controller-host.js.map +1 -1
- package/dist/extension/decision-channels.d.ts +2 -0
- package/dist/extension/decision-channels.js +311 -118
- package/dist/extension/decision-channels.js.map +1 -1
- package/dist/extension/executor.d.ts +9 -2
- package/dist/extension/executor.js +90 -6
- package/dist/extension/executor.js.map +1 -1
- package/dist/extension/herdr-viewer.d.ts +0 -1
- package/dist/extension/herdr-viewer.js +0 -4
- package/dist/extension/herdr-viewer.js.map +1 -1
- package/dist/extension/index.js +156 -117
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +3 -10
- package/dist/extension/recorder.js +13 -22
- package/dist/extension/recorder.js.map +1 -1
- package/dist/extension/step-message.d.ts +7 -2
- package/dist/extension/step-message.js +94 -2
- package/dist/extension/step-message.js.map +1 -1
- package/dist/extension/widget.js +6 -0
- package/dist/extension/widget.js.map +1 -1
- package/dist/host/rpc-executor.d.ts +3 -0
- package/dist/host/rpc-executor.js +2 -0
- package/dist/host/rpc-executor.js.map +1 -1
- package/dist/host/runner.d.ts +3 -6
- package/dist/host/runner.js +83 -32
- package/dist/host/runner.js.map +1 -1
- package/dist/render/graph-render.js +14 -8
- package/dist/render/graph-render.js.map +1 -1
- package/dist/state/database.d.ts +35 -0
- package/dist/state/database.js +287 -0
- package/dist/state/database.js.map +1 -0
- package/dist/state/index.d.ts +4 -0
- package/dist/state/index.js +5 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/json.d.ts +6 -0
- package/dist/state/json.js +38 -0
- package/dist/state/json.js.map +1 -0
- package/dist/state/mutation.d.ts +57 -0
- package/dist/state/mutation.js +255 -0
- package/dist/state/mutation.js.map +1 -0
- package/dist/state/schema.d.ts +6 -0
- package/dist/state/schema.js +473 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/viewer/cli.d.ts +2 -2
- package/dist/viewer/cli.js +142 -122
- package/dist/viewer/cli.js.map +1 -1
- package/dist/viewer/render.d.ts +4 -4
- package/dist/viewer/render.js +2 -17
- package/dist/viewer/render.js.map +1 -1
- package/dist/viewer/session-reducer.d.ts +1 -1
- package/dist/viewer/session-reducer.js +1 -1
- package/dist/viewer/tui.d.ts +3 -3
- package/dist/viewer/tui.js +15 -13
- package/dist/viewer/tui.js.map +1 -1
- package/dist/viewer/watch.d.ts +2 -5
- package/dist/viewer/watch.js +13 -13
- package/dist/viewer/watch.js.map +1 -1
- package/dist/workflows/composition.js +12 -2
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/definition.d.ts +6 -2
- package/dist/workflows/definition.js +17 -0
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +6 -6
- package/dist/workflows/engine.js +183 -103
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +3 -3
- package/dist/workflows/errors.js +3 -3
- package/dist/workflows/human-decision.d.ts +29 -4
- package/dist/workflows/human-decision.js +547 -283
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +4 -5
- package/dist/workflows/index.js +3 -4
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/schema.js +17 -1
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.d.ts +83 -103
- package/dist/workflows/store.js +902 -951
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +55 -81
- package/docs/CONTROLLERS.md +10 -8
- package/docs/DEFERRED_TURNS.md +2 -2
- package/docs/DESIGN_PHILOSOPHY.md +4 -2
- package/docs/HUMAN_DECISIONS.md +13 -14
- package/docs/MONITOR.md +179 -231
- package/docs/SQLITE_STATE.md +219 -0
- package/docs/WORKFLOW_COMPOSITION.md +27 -19
- package/docs/WORKFLOW_STEP_MESSAGES.md +20 -18
- package/docs/WORKFLOW_UPDATES.md +10 -9
- package/docs/development.md +9 -9
- package/docs/live-replay-protocol.md +28 -37
- package/docs/plans/2026-08-16-workflow-updates-plan.md +1 -1
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
- package/docs/plans/2026-08-21-autoimplement-timeout-fallback-plan.md +1 -1
- package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +1 -1
- package/docs/plans/2026-08-21-sanity-check-plan.md +30 -16
- package/docs/plans/2026-08-22-goal-finishing-monitor-plan.md +200 -0
- package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +701 -0
- package/docs/plans/2026-08-23-sqlite-state-plan.md +970 -0
- package/docs/plans/2026-08-24-change-scoped-verification-plan.md +419 -0
- package/docs/plans/replayable-run-bundles-implementation-plan.md +2 -2
- package/docs/plans/session-event-replay-implementation-plan.md +1 -1
- package/docs/plans/tui-viewer-implementation-plan.md +1 -1
- package/docs/session-event-journal.md +63 -434
- package/docs/tui-viewer.md +13 -15
- package/docs/workflows.md +111 -62
- package/examples/workflows/plain-summary.workflow.ts +1 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/plugins/herdr/viewer.mjs +1 -11
- package/skills/autodoc/SKILL.md +7 -0
- package/skills/autoimplement/SKILL.md +4 -0
- package/skills/autoplan/SKILL.md +5 -4
- package/skills/monitor/SKILL.md +91 -163
- package/skills/pi-workflows/SKILL.md +7 -7
- package/skills/sanity-check/SKILL.md +1 -1
- package/src/builtins/autodoc.workflow.ts +184 -33
- package/src/builtins/autoimplement-command-batches.ts +39 -33
- package/src/builtins/autoimplement.workflow.ts +483 -175
- package/src/builtins/autoplan.workflow.ts +290 -40
- package/src/builtins/catalog.ts +7 -5
- package/src/builtins/change-verification.workflow.ts +1143 -0
- package/src/builtins/index.ts +7 -1
- package/src/builtins/monitor.workflow.ts +667 -250
- package/src/builtins/plain-summary.workflow.ts +185 -0
- package/src/builtins/plan-change.workflow.ts +35 -0
- package/src/builtins/sanity-check.workflow.ts +62 -7
- package/src/builtins/workspace-preparation.workflow.ts +668 -0
- package/src/controllers/effects.ts +7 -0
- package/src/controllers/index.ts +0 -6
- package/src/controllers/manager.ts +72 -32
- package/src/controllers/sqlite.ts +2420 -1948
- package/src/controllers/store.ts +17 -38
- package/src/controllers/types.ts +3 -0
- package/src/controllers/workflow-engine-scheduler.ts +4 -8
- package/src/controllers/workflows.ts +45 -21
- package/src/extension/controller-host.ts +1 -2
- package/src/extension/decision-channels.ts +427 -144
- package/src/extension/executor.ts +106 -6
- package/src/extension/herdr-viewer.ts +0 -5
- package/src/extension/index.ts +180 -132
- package/src/extension/recorder.ts +13 -22
- package/src/extension/step-message.ts +106 -4
- package/src/extension/widget.ts +8 -0
- package/src/host/rpc-executor.ts +4 -0
- package/src/host/runner.ts +93 -41
- package/src/render/graph-render.ts +11 -4
- package/src/state/database.ts +375 -0
- package/src/state/index.ts +29 -0
- package/src/state/json.ts +42 -0
- package/src/state/mutation.ts +435 -0
- package/src/state/schema.ts +475 -0
- package/src/viewer/cli.ts +151 -144
- package/src/viewer/render.ts +12 -24
- package/src/viewer/session-reducer.ts +1 -1
- package/src/viewer/tui.ts +18 -17
- package/src/viewer/watch.ts +13 -17
- package/src/workflows/composition.ts +12 -3
- package/src/workflows/definition.ts +36 -3
- package/src/workflows/engine.ts +212 -116
- package/src/workflows/errors.ts +3 -3
- package/src/workflows/human-decision.ts +795 -340
- package/src/workflows/index.ts +15 -19
- package/src/workflows/schema.ts +19 -1
- package/src/workflows/store.ts +1295 -1163
- package/src/workflows/types.ts +61 -81
- package/dist/workflows/artifacts.d.ts +0 -40
- package/dist/workflows/artifacts.js +0 -155
- package/dist/workflows/artifacts.js.map +0 -1
- package/dist/workflows/migrate-sources.d.ts +0 -42
- package/dist/workflows/migrate-sources.js +0 -133
- package/dist/workflows/migrate-sources.js.map +0 -1
- package/docs/run-bundles.md +0 -481
- package/src/workflows/artifacts.ts +0 -188
- package/src/workflows/migrate-sources.ts +0 -178
|
@@ -1,11 +1,35 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
agent,
|
|
4
|
+
compute,
|
|
5
|
+
defineWorkflow,
|
|
6
|
+
includeWorkflow,
|
|
7
|
+
includedResult,
|
|
8
|
+
} from "../workflows/definition.js";
|
|
2
9
|
import { digest } from "../workflows/human-decision.js";
|
|
3
10
|
import type { WorkflowNodeContext } from "../workflows/types.js";
|
|
11
|
+
import changeVerificationWorkflow, {
|
|
12
|
+
type ChangeVerificationInput,
|
|
13
|
+
type ChangeVerificationResult,
|
|
14
|
+
type VerificationCheck,
|
|
15
|
+
} from "./change-verification.workflow.js";
|
|
16
|
+
import workspacePreparationWorkflow, {
|
|
17
|
+
parsePreparedWorkspace,
|
|
18
|
+
type PreparedWorkspace,
|
|
19
|
+
type WorkspaceMode,
|
|
20
|
+
type WorkspacePreparationInput,
|
|
21
|
+
} from "./workspace-preparation.workflow.js";
|
|
4
22
|
|
|
5
23
|
export type AutodocInput = {
|
|
6
24
|
task: string;
|
|
7
25
|
plan?: unknown;
|
|
8
26
|
repository?: string;
|
|
27
|
+
baseBranch?: string;
|
|
28
|
+
scope?: string;
|
|
29
|
+
workspaceMode?: WorkspaceMode;
|
|
30
|
+
directDefaultBranchAuthorized?: boolean;
|
|
31
|
+
preparedWorkspace?: PreparedWorkspace;
|
|
32
|
+
verificationChecks?: VerificationCheck[];
|
|
9
33
|
documents?: string[];
|
|
10
34
|
evidence?: unknown;
|
|
11
35
|
};
|
|
@@ -21,7 +45,8 @@ export type DocumentedPlan = {
|
|
|
21
45
|
digests: Record<string, string>;
|
|
22
46
|
evidence: unknown;
|
|
23
47
|
};
|
|
24
|
-
verification:
|
|
48
|
+
verification: ChangeVerificationResult | { route: "ready"; reason: string };
|
|
49
|
+
workspace?: PreparedWorkspace;
|
|
25
50
|
};
|
|
26
51
|
|
|
27
52
|
export type AutodocBlocked = {
|
|
@@ -29,6 +54,7 @@ export type AutodocBlocked = {
|
|
|
29
54
|
task: string;
|
|
30
55
|
reason: string;
|
|
31
56
|
evidence: unknown;
|
|
57
|
+
sourceNode?: string;
|
|
32
58
|
};
|
|
33
59
|
|
|
34
60
|
type LocatedPlan = {
|
|
@@ -47,6 +73,10 @@ type DocumentationAssessment = {
|
|
|
47
73
|
evidence: unknown;
|
|
48
74
|
};
|
|
49
75
|
|
|
76
|
+
type WorkspaceGuard =
|
|
77
|
+
| { route: "ready"; repository: string }
|
|
78
|
+
| { route: "blocked"; reason: string; evidence: string[] };
|
|
79
|
+
|
|
50
80
|
function requireRecord(value: unknown, label: string): Record<string, unknown> {
|
|
51
81
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
52
82
|
throw new Error(`${label} must be an object`);
|
|
@@ -61,6 +91,12 @@ function requireString(value: unknown, label: string): string {
|
|
|
61
91
|
return value.trim();
|
|
62
92
|
}
|
|
63
93
|
|
|
94
|
+
function requireAbsolutePath(value: unknown, label: string): string {
|
|
95
|
+
const result = requireString(value, label);
|
|
96
|
+
if (!path.isAbsolute(result)) throw new Error(`${label} must be absolute`);
|
|
97
|
+
return path.resolve(result);
|
|
98
|
+
}
|
|
99
|
+
|
|
64
100
|
function stringArray(value: unknown, label: string): string[] {
|
|
65
101
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
66
102
|
throw new Error(`${label} must be an array of strings`);
|
|
@@ -77,15 +113,38 @@ function stringRecord(value: unknown, label: string): Record<string, string> {
|
|
|
77
113
|
return record as Record<string, string>;
|
|
78
114
|
}
|
|
79
115
|
|
|
116
|
+
function parseWorkspaceMode(value: unknown): WorkspaceMode | undefined {
|
|
117
|
+
if (value === undefined) return undefined;
|
|
118
|
+
if (value !== "auto" && value !== "branch" && value !== "worktree" && value !== "defaultBranch") {
|
|
119
|
+
throw new Error("autodoc workspaceMode must be auto, branch, worktree, or defaultBranch");
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
|
|
80
124
|
function parseInput(value: unknown): AutodocInput {
|
|
81
125
|
const input = requireRecord(value, "autodoc input");
|
|
82
126
|
const documents = input.documents;
|
|
127
|
+
const workspaceMode = parseWorkspaceMode(input.workspaceMode);
|
|
83
128
|
return {
|
|
84
129
|
task: requireString(input.task, "autodoc task"),
|
|
85
130
|
...(input.plan !== undefined ? { plan: input.plan } : {}),
|
|
86
131
|
...(input.repository !== undefined
|
|
87
|
-
? { repository:
|
|
132
|
+
? { repository: requireAbsolutePath(input.repository, "autodoc repository") }
|
|
133
|
+
: {}),
|
|
134
|
+
...(input.baseBranch !== undefined
|
|
135
|
+
? { baseBranch: requireString(input.baseBranch, "autodoc baseBranch") }
|
|
88
136
|
: {}),
|
|
137
|
+
...(input.scope !== undefined ? { scope: requireString(input.scope, "autodoc scope") } : {}),
|
|
138
|
+
...(workspaceMode === undefined ? {} : { workspaceMode }),
|
|
139
|
+
...(input.directDefaultBranchAuthorized === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { directDefaultBranchAuthorized: input.directDefaultBranchAuthorized === true }),
|
|
142
|
+
...(input.preparedWorkspace === undefined
|
|
143
|
+
? {}
|
|
144
|
+
: { preparedWorkspace: parsePreparedWorkspace(input.preparedWorkspace) }),
|
|
145
|
+
...(input.verificationChecks === undefined
|
|
146
|
+
? {}
|
|
147
|
+
: { verificationChecks: input.verificationChecks as VerificationCheck[] }),
|
|
89
148
|
...(documents !== undefined ? { documents: stringArray(documents, "autodoc documents") } : {}),
|
|
90
149
|
...(input.evidence !== undefined ? { evidence: input.evidence } : {}),
|
|
91
150
|
};
|
|
@@ -132,10 +191,61 @@ function currentPlan(context: WorkflowNodeContext): unknown {
|
|
|
132
191
|
throw new Error("autodoc does not have a selected plan");
|
|
133
192
|
}
|
|
134
193
|
|
|
194
|
+
function mutationRepository(request: AutodocInput): string {
|
|
195
|
+
if (request.repository !== undefined) return request.repository;
|
|
196
|
+
if (request.preparedWorkspace !== undefined) return request.preparedWorkspace.repository;
|
|
197
|
+
throw new Error("autodoc mutation requires an explicit repository");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function preparedWorkspace(context: WorkflowNodeContext): PreparedWorkspace {
|
|
201
|
+
const request = context.input as AutodocInput;
|
|
202
|
+
if (request.preparedWorkspace !== undefined) return request.preparedWorkspace;
|
|
203
|
+
const result = includedResult(workspacePreparationWorkflow, context.outputs.workspace);
|
|
204
|
+
if (result.exit !== "ready") throw new Error("autodoc workspace is not ready");
|
|
205
|
+
return result.output;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function verificationResult(context: WorkflowNodeContext): ChangeVerificationResult {
|
|
209
|
+
const result = includedResult(changeVerificationWorkflow, context.outputs.verification);
|
|
210
|
+
return result.output;
|
|
211
|
+
}
|
|
212
|
+
|
|
135
213
|
function blockedReason(context: WorkflowNodeContext): AutodocBlocked {
|
|
136
214
|
const request = context.input as AutodocInput;
|
|
137
215
|
const assessment = context.outputs.inspectDocumentation as DocumentationAssessment | undefined;
|
|
138
216
|
const located = context.outputs.locatePlan as LocatedPlan | undefined;
|
|
217
|
+
if (context.outputs.verification !== undefined) {
|
|
218
|
+
const result = includedResult(changeVerificationWorkflow, context.outputs.verification);
|
|
219
|
+
return {
|
|
220
|
+
status: "blocked",
|
|
221
|
+
task: request.task,
|
|
222
|
+
reason: result.output.reason,
|
|
223
|
+
evidence: result.output,
|
|
224
|
+
sourceNode: result.output.qualifiedNode,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const guard = context.outputs.workspaceGuard as WorkspaceGuard | undefined;
|
|
228
|
+
if (guard?.route === "blocked") {
|
|
229
|
+
return {
|
|
230
|
+
status: "blocked",
|
|
231
|
+
task: request.task,
|
|
232
|
+
reason: guard.reason,
|
|
233
|
+
evidence: guard.evidence,
|
|
234
|
+
sourceNode: "autodoc/workspaceGuard",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (context.outputs.workspace !== undefined) {
|
|
238
|
+
const result = includedResult(workspacePreparationWorkflow, context.outputs.workspace);
|
|
239
|
+
if (result.exit === "blocked") {
|
|
240
|
+
return {
|
|
241
|
+
status: "blocked",
|
|
242
|
+
task: request.task,
|
|
243
|
+
reason: result.output.reason,
|
|
244
|
+
evidence: result.output,
|
|
245
|
+
sourceNode: "autodoc/workspace",
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
139
249
|
return {
|
|
140
250
|
status: "blocked",
|
|
141
251
|
task: request.task,
|
|
@@ -146,6 +256,8 @@ function blockedReason(context: WorkflowNodeContext): AutodocBlocked {
|
|
|
146
256
|
? located.reason
|
|
147
257
|
: "Autodoc could not identify a clear selected plan or canonical document target.",
|
|
148
258
|
evidence: assessment?.evidence ?? located?.evidence ?? null,
|
|
259
|
+
sourceNode:
|
|
260
|
+
assessment?.route === "blocked" ? "autodoc/inspectDocumentation" : "autodoc/locatePlan",
|
|
149
261
|
};
|
|
150
262
|
}
|
|
151
263
|
|
|
@@ -156,7 +268,42 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
156
268
|
input: parseInput,
|
|
157
269
|
title: ({ input }) => `autodoc: ${input.task.slice(0, 60)}`,
|
|
158
270
|
startAt: "prepare",
|
|
159
|
-
maxSteps:
|
|
271
|
+
maxSteps: 80,
|
|
272
|
+
includes: {
|
|
273
|
+
workspace: includeWorkflow(workspacePreparationWorkflow, {
|
|
274
|
+
input: (context): WorkspacePreparationInput => {
|
|
275
|
+
const request = context.input as AutodocInput;
|
|
276
|
+
return {
|
|
277
|
+
repository: mutationRepository(request),
|
|
278
|
+
...(request.baseBranch === undefined ? {} : { baseBranch: request.baseBranch }),
|
|
279
|
+
...(request.scope === undefined ? {} : { scope: request.scope }),
|
|
280
|
+
...(request.workspaceMode === undefined ? {} : { workspaceMode: request.workspaceMode }),
|
|
281
|
+
...(request.directDefaultBranchAuthorized === undefined
|
|
282
|
+
? {}
|
|
283
|
+
: { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
|
|
284
|
+
...(request.preparedWorkspace === undefined
|
|
285
|
+
? {}
|
|
286
|
+
: { preparedWorkspace: request.preparedWorkspace }),
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
}),
|
|
290
|
+
verification: includeWorkflow(changeVerificationWorkflow, {
|
|
291
|
+
input: (context): ChangeVerificationInput => {
|
|
292
|
+
const request = context.input as AutodocInput;
|
|
293
|
+
const update = requireRecord(context.outputs.updateDocumentation, "documentation update");
|
|
294
|
+
return {
|
|
295
|
+
originatingWorkflow: "autodoc",
|
|
296
|
+
qualifiedNode: "autodoc/verification",
|
|
297
|
+
workspace: preparedWorkspace(context),
|
|
298
|
+
...(request.verificationChecks === undefined
|
|
299
|
+
? {}
|
|
300
|
+
: { checks: request.verificationChecks }),
|
|
301
|
+
changedFiles: stringArray(update.files, "updated documentation files"),
|
|
302
|
+
plan: currentPlan(context),
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
}),
|
|
306
|
+
},
|
|
160
307
|
exits: {
|
|
161
308
|
ready: {
|
|
162
309
|
from: "finalize",
|
|
@@ -184,14 +331,26 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
184
331
|
"Return blocked when no single clear selected plan exists.",
|
|
185
332
|
`Task: ${request.task}`,
|
|
186
333
|
`Repository: ${request.repository ?? "current repository"}`,
|
|
187
|
-
`
|
|
188
|
-
`Evidence: ${JSON.stringify(request.evidence ?? null)}`,
|
|
334
|
+
`Preferred documents: ${JSON.stringify(request.documents ?? [])}`,
|
|
189
335
|
].join("\n");
|
|
190
336
|
},
|
|
191
337
|
expectedOutput:
|
|
192
338
|
'{ "route": "found" | "blocked", "plan": {} (required when found), "sources": ["source"], "reason": "reason", "evidence": "evidence" }',
|
|
193
339
|
validate: parseLocatedPlan,
|
|
194
340
|
}),
|
|
341
|
+
workspaceGuard: compute({
|
|
342
|
+
run: ({ input }): WorkspaceGuard => {
|
|
343
|
+
const request = input as AutodocInput;
|
|
344
|
+
if (request.repository !== undefined || request.preparedWorkspace !== undefined) {
|
|
345
|
+
return { route: "ready", repository: mutationRepository(request) };
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
route: "blocked",
|
|
349
|
+
reason: "Updating canonical documentation requires an explicit repository path.",
|
|
350
|
+
evidence: ["repository was not supplied", "preparedWorkspace was not supplied"],
|
|
351
|
+
};
|
|
352
|
+
},
|
|
353
|
+
}),
|
|
195
354
|
inspectDocumentation: agent({
|
|
196
355
|
statusDetail: "checking canonical documentation",
|
|
197
356
|
prompt: (context) => {
|
|
@@ -221,6 +380,7 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
221
380
|
"Update the canonical specification and implementation plan to preserve the selected plan exactly.",
|
|
222
381
|
"Use the repository documentation rules and keep the text plain and complete.",
|
|
223
382
|
"Do not redesign the solution and do not implement code.",
|
|
383
|
+
`Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
|
|
224
384
|
`Task: ${request.task}`,
|
|
225
385
|
`Selected plan: ${JSON.stringify(currentPlan(context))}`,
|
|
226
386
|
`Canonical files: ${JSON.stringify(assessment.files)}`,
|
|
@@ -239,26 +399,6 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
239
399
|
return result;
|
|
240
400
|
},
|
|
241
401
|
}),
|
|
242
|
-
verifyDocumentation: agent({
|
|
243
|
-
timeoutMs: 20 * 60_000,
|
|
244
|
-
statusDetail: "verifying documentation",
|
|
245
|
-
prompt: ({ outputs }) =>
|
|
246
|
-
[
|
|
247
|
-
"Verify the changed canonical documentation.",
|
|
248
|
-
"Run the repository documentation, formatting, link, and privacy checks that apply.",
|
|
249
|
-
"Do not implement code.",
|
|
250
|
-
`Documentation update: ${JSON.stringify(outputs.updateDocumentation)}`,
|
|
251
|
-
].join("\n"),
|
|
252
|
-
expectedOutput:
|
|
253
|
-
'{ "passed": true | false, "commands": [{ "command": "exact command", "outcome": "result" }], "failures": ["failure"] }',
|
|
254
|
-
validate: (value) => {
|
|
255
|
-
const result = requireRecord(value, "documentation verification");
|
|
256
|
-
if (typeof result.passed !== "boolean") {
|
|
257
|
-
throw new Error("documentation verification passed must be boolean");
|
|
258
|
-
}
|
|
259
|
-
return result;
|
|
260
|
-
},
|
|
261
|
-
}),
|
|
262
402
|
finalize: compute({
|
|
263
403
|
run: (context) => {
|
|
264
404
|
const request = context.input as AutodocInput;
|
|
@@ -277,7 +417,13 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
277
417
|
digests: assessment.digests,
|
|
278
418
|
evidence: assessment.evidence,
|
|
279
419
|
},
|
|
280
|
-
verification: {
|
|
420
|
+
verification: {
|
|
421
|
+
route: "ready",
|
|
422
|
+
reason: "Canonical documentation was already current.",
|
|
423
|
+
},
|
|
424
|
+
...(request.preparedWorkspace === undefined
|
|
425
|
+
? {}
|
|
426
|
+
: { workspace: request.preparedWorkspace }),
|
|
281
427
|
} satisfies DocumentedPlan;
|
|
282
428
|
}
|
|
283
429
|
const updateRecord = requireRecord(updated, "documentation update");
|
|
@@ -290,9 +436,10 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
290
436
|
state: "updated",
|
|
291
437
|
files: stringArray(updateRecord.files, "updated documentation files"),
|
|
292
438
|
digests: stringRecord(updateRecord.digests, "updated documentation digests"),
|
|
293
|
-
evidence: context
|
|
439
|
+
evidence: verificationResult(context),
|
|
294
440
|
},
|
|
295
|
-
verification: context
|
|
441
|
+
verification: verificationResult(context),
|
|
442
|
+
workspace: preparedWorkspace(context),
|
|
296
443
|
} satisfies DocumentedPlan;
|
|
297
444
|
},
|
|
298
445
|
}),
|
|
@@ -311,14 +458,18 @@ export const autodocWorkflow = defineWorkflow({
|
|
|
311
458
|
from: "inspectDocumentation",
|
|
312
459
|
switch: {
|
|
313
460
|
on: "$.route",
|
|
314
|
-
cases: { current: "finalize", update: "
|
|
461
|
+
cases: { current: "finalize", update: "workspaceGuard", blocked: "blocked" },
|
|
315
462
|
},
|
|
316
463
|
},
|
|
317
|
-
{ from: "updateDocumentation", to: "verifyDocumentation" },
|
|
318
464
|
{
|
|
319
|
-
from: "
|
|
320
|
-
switch: { on: "$.
|
|
465
|
+
from: "workspaceGuard",
|
|
466
|
+
switch: { on: "$.route", cases: { ready: "workspace", blocked: "blocked" } },
|
|
321
467
|
},
|
|
468
|
+
{ from: "workspace.ready", to: "updateDocumentation" },
|
|
469
|
+
{ from: "workspace.blocked", to: "blocked" },
|
|
470
|
+
{ from: "updateDocumentation", to: "verification" },
|
|
471
|
+
{ from: "verification.ready", to: "finalize" },
|
|
472
|
+
{ from: "verification.blocked", to: "blocked" },
|
|
322
473
|
],
|
|
323
474
|
});
|
|
324
475
|
|
|
@@ -131,17 +131,10 @@ export function parseVerificationCommandPlan(value: unknown): VerificationComman
|
|
|
131
131
|
if (!Array.isArray(result.commands) || result.commands.length === 0) {
|
|
132
132
|
throw new Error("verification commands must be a non-empty array");
|
|
133
133
|
}
|
|
134
|
-
const directories = new Set<string>();
|
|
135
134
|
const commands = result.commands.map((entry, index) => {
|
|
136
135
|
const command = parseCommandItem(entry, `verification commands[${index}]`, {
|
|
137
136
|
maxTimeoutMs: VERIFICATION_TIMEOUT_MS,
|
|
138
137
|
});
|
|
139
|
-
if (directories.has(command.cwd)) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
`verification commands must use distinct working directories: ${command.cwd}`,
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
directories.add(command.cwd);
|
|
145
138
|
validateVerificationCommand(command, index);
|
|
146
139
|
return command;
|
|
147
140
|
});
|
|
@@ -285,37 +278,50 @@ function parseCommandItem(
|
|
|
285
278
|
return { id, command, args: [...raw.args] as string[], cwd, timeoutMs, maxOutputChars };
|
|
286
279
|
}
|
|
287
280
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
281
|
+
const FORBIDDEN_VERIFICATION_EXECUTABLES = new Set([
|
|
282
|
+
"ash",
|
|
283
|
+
"bash",
|
|
284
|
+
"cmd",
|
|
285
|
+
"cmd.exe",
|
|
286
|
+
"csh",
|
|
287
|
+
"dash",
|
|
288
|
+
"fish",
|
|
289
|
+
"gh",
|
|
290
|
+
"git",
|
|
291
|
+
"ksh",
|
|
292
|
+
"powershell",
|
|
293
|
+
"powershell.exe",
|
|
294
|
+
"pwsh",
|
|
295
|
+
"pwsh.exe",
|
|
296
|
+
"rm",
|
|
297
|
+
"sh",
|
|
298
|
+
"tcsh",
|
|
299
|
+
"zsh",
|
|
300
|
+
]);
|
|
301
|
+
|
|
302
|
+
export function validateVerificationCommandSafety(
|
|
303
|
+
command: string,
|
|
304
|
+
args: readonly string[],
|
|
305
|
+
label: string,
|
|
306
|
+
): void {
|
|
307
|
+
const executable = path.win32.basename(path.basename(command)).toLowerCase();
|
|
308
|
+
if (FORBIDDEN_VERIFICATION_EXECUTABLES.has(executable)) {
|
|
309
|
+
throw new Error(`${label}.command is not allowed`);
|
|
312
310
|
}
|
|
313
|
-
const joined =
|
|
311
|
+
const joined = args.join(" ").toLowerCase();
|
|
314
312
|
if (/\b(publish|release|deploy|push|merge)\b/.test(joined)) {
|
|
315
|
-
throw new Error(
|
|
313
|
+
throw new Error(`${label} contains a mutation or publication action`);
|
|
316
314
|
}
|
|
317
315
|
}
|
|
318
316
|
|
|
317
|
+
function validateVerificationCommand(command: CommandBatchItem, index: number): void {
|
|
318
|
+
validateVerificationCommandSafety(
|
|
319
|
+
command.command,
|
|
320
|
+
command.args,
|
|
321
|
+
`verification commands[${index}]`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
319
325
|
function concurrencyValue(value: unknown, field: string): number {
|
|
320
326
|
return positiveInteger(
|
|
321
327
|
value,
|