agentplane 0.2.25 → 0.3.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 +3 -1
- package/assets/AGENTS.md +123 -526
- package/assets/agents/UPGRADER.json +10 -9
- package/assets/framework.manifest.json +112 -7
- package/assets/policy/check-routing.mjs +180 -0
- package/assets/policy/dod.code.md +25 -0
- package/assets/policy/dod.core.md +32 -0
- package/assets/policy/dod.docs.md +32 -0
- package/assets/policy/examples/migration-note.md +6 -0
- package/assets/policy/examples/pr-note.md +16 -0
- package/assets/policy/examples/unit-test-pattern.md +19 -0
- package/assets/policy/governance.md +37 -0
- package/assets/policy/incidents.md +36 -0
- package/assets/policy/security.must.md +7 -0
- package/assets/policy/workflow.branch_pr.md +34 -0
- package/assets/policy/workflow.direct.md +46 -0
- package/assets/policy/workflow.md +9 -0
- package/assets/policy/workflow.release.md +31 -0
- package/assets/policy/workflow.upgrade.md +20 -0
- package/bin/agentplane.js +47 -57
- package/bin/dist-guard.js +124 -0
- package/dist/.build-manifest.json +11 -0
- package/dist/agents/agents-template.d.ts +7 -0
- package/dist/agents/agents-template.d.ts.map +1 -1
- package/dist/agents/agents-template.js +41 -2
- package/dist/backends/task-backend/local-backend.d.ts +2 -0
- package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/local-backend.js +12 -1
- package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine/mapping.js +26 -1
- package/dist/backends/task-backend/redmine-backend.d.ts +4 -0
- package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
- package/dist/backends/task-backend/redmine-backend.js +92 -9
- package/dist/backends/task-backend/shared/types.d.ts +1 -0
- package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
- package/dist/backends/task-index.d.ts.map +1 -1
- package/dist/backends/task-index.js +8 -1
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +39 -17
- package/dist/cli/command-snippets.d.ts +24 -0
- package/dist/cli/command-snippets.d.ts.map +1 -0
- package/dist/cli/command-snippets.js +23 -0
- package/dist/cli/reason-codes.d.ts +9 -0
- package/dist/cli/reason-codes.d.ts.map +1 -0
- package/dist/cli/reason-codes.js +79 -0
- package/dist/cli/recipes-bundled.d.ts +1 -0
- package/dist/cli/recipes-bundled.d.ts.map +1 -1
- package/dist/cli/recipes-bundled.js +4 -1
- package/dist/cli/run-cli/command-catalog.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +40 -1
- package/dist/cli/run-cli/commands/config.d.ts +5 -0
- package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/config.js +86 -1
- package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core.js +57 -2
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +8 -3
- package/dist/cli/run-cli/commands/init/recipes.d.ts +5 -1
- package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/recipes.js +24 -4
- package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ui.js +1 -2
- package/dist/cli/run-cli/commands/init/write-agents.d.ts +2 -0
- package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-agents.js +24 -5
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts +12 -0
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/init/write-workflow.js +58 -0
- package/dist/cli/run-cli/commands/init.d.ts +4 -1
- package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init.js +126 -48
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +195 -8
- package/dist/commands/backend/sync.command.d.ts.map +1 -1
- package/dist/commands/backend/sync.command.js +7 -6
- package/dist/commands/backend.d.ts.map +1 -1
- package/dist/commands/backend.js +2 -0
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +107 -16
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +12 -6
- package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/install.js +36 -13
- package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
- package/dist/commands/recipes/impl/scenario.js +25 -0
- package/dist/commands/recipes/impl/types.d.ts +4 -0
- package/dist/commands/recipes/impl/types.d.ts.map +1 -1
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +9 -4
- package/dist/commands/release/plan.command.d.ts.map +1 -1
- package/dist/commands/release/plan.command.js +9 -3
- package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
- package/dist/commands/scenario/impl/commands.js +74 -3
- package/dist/commands/scenario/impl/report.d.ts +8 -0
- package/dist/commands/scenario/impl/report.d.ts.map +1 -1
- package/dist/commands/scenario/impl/report.js +1 -0
- package/dist/commands/shared/reconcile-check.d.ts +7 -0
- package/dist/commands/shared/reconcile-check.d.ts.map +1 -0
- package/dist/commands/shared/reconcile-check.js +60 -0
- package/dist/commands/sync.command.d.ts.map +1 -1
- package/dist/commands/sync.command.js +9 -2
- package/dist/commands/task/add.d.ts.map +1 -1
- package/dist/commands/task/add.js +32 -0
- package/dist/commands/task/doc.command.d.ts.map +1 -1
- package/dist/commands/task/doc.command.js +1 -0
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +11 -1
- package/dist/commands/task/list.d.ts.map +1 -1
- package/dist/commands/task/list.js +2 -1
- package/dist/commands/task/list.spec.d.ts.map +1 -1
- package/dist/commands/task/list.spec.js +7 -0
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +41 -4
- package/dist/commands/task/next.d.ts.map +1 -1
- package/dist/commands/task/next.js +2 -1
- package/dist/commands/task/next.spec.d.ts.map +1 -1
- package/dist/commands/task/next.spec.js +7 -0
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +7 -1
- package/dist/commands/task/search.d.ts.map +1 -1
- package/dist/commands/task/search.js +2 -1
- package/dist/commands/task/search.spec.d.ts.map +1 -1
- package/dist/commands/task/search.spec.js +7 -0
- package/dist/commands/task/shared.d.ts +14 -0
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +58 -1
- package/dist/commands/task/start-ready.js +1 -1
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +2 -0
- package/dist/commands/upgrade.command.d.ts.map +1 -1
- package/dist/commands/upgrade.command.js +2 -2
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +263 -294
- package/dist/commands/workflow-build.command.d.ts +8 -0
- package/dist/commands/workflow-build.command.d.ts.map +1 -0
- package/dist/commands/workflow-build.command.js +103 -0
- package/dist/commands/workflow-playbook.command.d.ts +10 -0
- package/dist/commands/workflow-playbook.command.d.ts.map +1 -0
- package/dist/commands/workflow-playbook.command.js +173 -0
- package/dist/commands/workflow-restore.command.d.ts +5 -0
- package/dist/commands/workflow-restore.command.d.ts.map +1 -0
- package/dist/commands/workflow-restore.command.js +30 -0
- package/dist/commands/workflow.command.d.ts +6 -0
- package/dist/commands/workflow.command.d.ts.map +1 -0
- package/dist/commands/workflow.command.js +36 -0
- package/dist/harness/dynamic-tool-contract.d.ts +29 -0
- package/dist/harness/dynamic-tool-contract.d.ts.map +1 -0
- package/dist/harness/dynamic-tool-contract.js +86 -0
- package/dist/harness/hooks-lifecycle.d.ts +27 -0
- package/dist/harness/hooks-lifecycle.d.ts.map +1 -0
- package/dist/harness/hooks-lifecycle.js +67 -0
- package/dist/harness/index.d.ts +9 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +8 -0
- package/dist/harness/reconcile.d.ts +37 -0
- package/dist/harness/reconcile.d.ts.map +1 -0
- package/dist/harness/reconcile.js +42 -0
- package/dist/harness/retry-policy.d.ts +31 -0
- package/dist/harness/retry-policy.d.ts.map +1 -0
- package/dist/harness/retry-policy.js +33 -0
- package/dist/harness/scheduler.d.ts +18 -0
- package/dist/harness/scheduler.d.ts.map +1 -0
- package/dist/harness/scheduler.js +55 -0
- package/dist/harness/state-machine.d.ts +17 -0
- package/dist/harness/state-machine.d.ts.map +1 -0
- package/dist/harness/state-machine.js +70 -0
- package/dist/harness/token-accounting.d.ts +19 -0
- package/dist/harness/token-accounting.d.ts.map +1 -0
- package/dist/harness/token-accounting.js +77 -0
- package/dist/harness/workspace-safety.d.ts +14 -0
- package/dist/harness/workspace-safety.d.ts.map +1 -0
- package/dist/harness/workspace-safety.js +62 -0
- package/dist/recipes/bundled-recipes.d.ts +4 -0
- package/dist/recipes/bundled-recipes.d.ts.map +1 -1
- package/dist/recipes/bundled-recipes.js +11 -0
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +1 -0
- package/dist/shared/policy-gateway.d.ts +15 -0
- package/dist/shared/policy-gateway.d.ts.map +1 -0
- package/dist/shared/policy-gateway.js +49 -0
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +1 -0
- package/dist/shared/runtime-artifacts.d.ts +2 -2
- package/dist/shared/runtime-artifacts.d.ts.map +1 -1
- package/dist/shared/runtime-artifacts.js +4 -0
- package/dist/workflow-runtime/build.d.ts +4 -0
- package/dist/workflow-runtime/build.d.ts.map +1 -0
- package/dist/workflow-runtime/build.js +126 -0
- package/dist/workflow-runtime/enforcement.d.ts +3 -0
- package/dist/workflow-runtime/enforcement.d.ts.map +1 -0
- package/dist/workflow-runtime/enforcement.js +10 -0
- package/dist/workflow-runtime/file-ops.d.ts +11 -0
- package/dist/workflow-runtime/file-ops.d.ts.map +1 -0
- package/dist/workflow-runtime/file-ops.js +248 -0
- package/dist/workflow-runtime/fix.d.ts +9 -0
- package/dist/workflow-runtime/fix.d.ts.map +1 -0
- package/dist/workflow-runtime/fix.js +107 -0
- package/dist/workflow-runtime/index.d.ts +11 -0
- package/dist/workflow-runtime/index.d.ts.map +1 -0
- package/dist/workflow-runtime/index.js +10 -0
- package/dist/workflow-runtime/markdown.d.ts +10 -0
- package/dist/workflow-runtime/markdown.d.ts.map +1 -0
- package/dist/workflow-runtime/markdown.js +147 -0
- package/dist/workflow-runtime/observability.d.ts +12 -0
- package/dist/workflow-runtime/observability.d.ts.map +1 -0
- package/dist/workflow-runtime/observability.js +14 -0
- package/dist/workflow-runtime/paths.d.ts +3 -0
- package/dist/workflow-runtime/paths.d.ts.map +1 -0
- package/dist/workflow-runtime/paths.js +11 -0
- package/dist/workflow-runtime/template.d.ts +7 -0
- package/dist/workflow-runtime/template.d.ts.map +1 -0
- package/dist/workflow-runtime/template.js +94 -0
- package/dist/workflow-runtime/types.d.ts +68 -0
- package/dist/workflow-runtime/types.d.ts.map +1 -0
- package/dist/workflow-runtime/types.js +1 -0
- package/dist/workflow-runtime/validate.d.ts +8 -0
- package/dist/workflow-runtime/validate.d.ts.map +1 -0
- package/dist/workflow-runtime/validate.js +331 -0
- package/package.json +3 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CommandHandler, CommandSpec } from "../cli/spec/spec.js";
|
|
2
|
+
export type WorkflowBuildParsed = {
|
|
3
|
+
validate: boolean;
|
|
4
|
+
dryRun: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const workflowBuildSpec: CommandSpec<WorkflowBuildParsed>;
|
|
7
|
+
export declare const runWorkflowBuild: CommandHandler<WorkflowBuildParsed>;
|
|
8
|
+
//# sourceMappingURL=workflow-build.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-build.command.d.ts","sourceRoot":"","sources":["../../src/commands/workflow-build.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAgC9D,CAAC;AAWF,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,mBAAmB,CA2EhE,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadConfig, resolveProject } from "@agentplaneorg/core";
|
|
4
|
+
import { successMessage, warnMessage } from "../cli/output.js";
|
|
5
|
+
import { DEFAULT_WORKFLOW_TEMPLATE, buildWorkflowFromTemplates, diagnosticsSummary, publishWorkflowCandidate, resolveWorkflowPaths, validateWorkflowText, } from "../workflow-runtime/index.js";
|
|
6
|
+
export const workflowBuildSpec = {
|
|
7
|
+
id: ["workflow", "build"],
|
|
8
|
+
group: "Workflow",
|
|
9
|
+
summary: "Build WORKFLOW.md from template layers with strict rendering checks.",
|
|
10
|
+
options: [
|
|
11
|
+
{
|
|
12
|
+
kind: "boolean",
|
|
13
|
+
name: "validate",
|
|
14
|
+
default: false,
|
|
15
|
+
description: "Validate built workflow and fail on errors.",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
kind: "boolean",
|
|
19
|
+
name: "dry-run",
|
|
20
|
+
default: false,
|
|
21
|
+
description: "Do not publish; print candidate and diagnostics only.",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
examples: [
|
|
25
|
+
{
|
|
26
|
+
cmd: "agentplane workflow build --validate --dry-run",
|
|
27
|
+
why: "Build and validate candidate workflow without publishing.",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
cmd: "agentplane workflow build --validate",
|
|
31
|
+
why: "Build, validate, and atomically publish workflow.",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
parse: (raw) => ({
|
|
35
|
+
validate: raw.opts.validate === true,
|
|
36
|
+
dryRun: raw.opts["dry-run"] === true,
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
async function maybeReadOverride(paths) {
|
|
40
|
+
const overridePath = path.join(paths.workflowDir, "template.override.md");
|
|
41
|
+
try {
|
|
42
|
+
return await fs.readFile(overridePath, "utf8");
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const runWorkflowBuild = async (ctx, flags) => {
|
|
49
|
+
const resolved = await resolveProject({ cwd: ctx.cwd, rootOverride: ctx.rootOverride ?? null });
|
|
50
|
+
const configLoaded = await loadConfig(resolved.agentplaneDir);
|
|
51
|
+
const workflowPaths = resolveWorkflowPaths(resolved.gitRoot);
|
|
52
|
+
const configApprovals = configLoaded.config.agents?.approvals;
|
|
53
|
+
const runtimeContext = {
|
|
54
|
+
workflow: {
|
|
55
|
+
mode: configLoaded.config.workflow_mode,
|
|
56
|
+
version: 1,
|
|
57
|
+
approvals: {
|
|
58
|
+
require_plan: configApprovals?.require_plan ?? true,
|
|
59
|
+
require_verify: configApprovals?.require_verify ?? true,
|
|
60
|
+
require_network: configApprovals?.require_network ?? true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
runtime: {
|
|
64
|
+
repo_name: path.basename(resolved.gitRoot),
|
|
65
|
+
repo_root: resolved.gitRoot,
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const overrideTemplate = await maybeReadOverride(workflowPaths);
|
|
70
|
+
const built = buildWorkflowFromTemplates({
|
|
71
|
+
baseTemplate: DEFAULT_WORKFLOW_TEMPLATE,
|
|
72
|
+
projectOverrideTemplate: overrideTemplate,
|
|
73
|
+
runtimeContext,
|
|
74
|
+
});
|
|
75
|
+
if (flags.dryRun) {
|
|
76
|
+
process.stdout.write(`${built.text}\n`);
|
|
77
|
+
}
|
|
78
|
+
let diagnostics = [...built.diagnostics];
|
|
79
|
+
if (flags.validate || flags.dryRun) {
|
|
80
|
+
const validation = await validateWorkflowText(resolved.gitRoot, built.text);
|
|
81
|
+
diagnostics = [...diagnostics, ...validation.diagnostics];
|
|
82
|
+
}
|
|
83
|
+
const hasError = diagnostics.some((d) => d.severity === "ERROR");
|
|
84
|
+
if (diagnostics.length > 0) {
|
|
85
|
+
process.stderr.write(`${warnMessage(`workflow diagnostics: ${diagnosticsSummary(diagnostics)}`)}\n`);
|
|
86
|
+
for (const diagnostic of diagnostics) {
|
|
87
|
+
process.stderr.write(`- [${diagnostic.severity}] ${diagnostic.code} ${diagnostic.path}: ${diagnostic.message}\n`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (flags.dryRun) {
|
|
91
|
+
return hasError ? 1 : 0;
|
|
92
|
+
}
|
|
93
|
+
const publish = await publishWorkflowCandidate(resolved.gitRoot, built.text);
|
|
94
|
+
if (!publish.ok) {
|
|
95
|
+
process.stderr.write(warnMessage("workflow publish failed") + "\n");
|
|
96
|
+
for (const diagnostic of publish.diagnostics) {
|
|
97
|
+
process.stderr.write(`- [${diagnostic.severity}] ${diagnostic.code} ${diagnostic.path}: ${diagnostic.message}\n`);
|
|
98
|
+
}
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
process.stdout.write(successMessage("workflow build", undefined, `Published ${path.relative(resolved.gitRoot, workflowPaths.workflowPath)}`) + "\n");
|
|
102
|
+
return hasError && flags.validate ? 1 : 0;
|
|
103
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CommandHandler, type CommandSpec } from "../cli/spec/spec.js";
|
|
2
|
+
type WorkflowPlaybookParsed = Record<string, never>;
|
|
3
|
+
export declare const workflowDebugSpec: CommandSpec<WorkflowPlaybookParsed>;
|
|
4
|
+
export declare const workflowSyncSpec: CommandSpec<WorkflowPlaybookParsed>;
|
|
5
|
+
export declare const workflowLandSpec: CommandSpec<WorkflowPlaybookParsed>;
|
|
6
|
+
export declare const runWorkflowDebug: CommandHandler<WorkflowPlaybookParsed>;
|
|
7
|
+
export declare const runWorkflowSync: CommandHandler<WorkflowPlaybookParsed>;
|
|
8
|
+
export declare const runWorkflowLand: CommandHandler<WorkflowPlaybookParsed>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=workflow-playbook.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-playbook.command.d.ts","sourceRoot":"","sources":["../../src/commands/workflow-playbook.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAoC5E,KAAK,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AA0JpD,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,sBAAsB,CAMjE,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,sBAAsB,CAMhE,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,sBAAsB,CAMhE,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,sBAAsB,CAEnE,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,sBAAsB,CAElE,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,sBAAsB,CAElE,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { atomicWriteFile, resolveProject } from "@agentplaneorg/core";
|
|
7
|
+
import { mapCoreError } from "../cli/error-map.js";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
const AGENTPLANE_BIN = fileURLToPath(new URL("../../bin/agentplane.js", import.meta.url));
|
|
10
|
+
const MAX_LOG_CHARS = 8000;
|
|
11
|
+
function truncate(text) {
|
|
12
|
+
if (text.length <= MAX_LOG_CHARS)
|
|
13
|
+
return text;
|
|
14
|
+
const rest = text.length - MAX_LOG_CHARS;
|
|
15
|
+
return `${text.slice(0, MAX_LOG_CHARS)}\n...[truncated ${rest} chars]`;
|
|
16
|
+
}
|
|
17
|
+
function toSafeToken(value) {
|
|
18
|
+
return value.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
|
|
19
|
+
}
|
|
20
|
+
function buildEvidencePath(repoRoot, mode, startedAt) {
|
|
21
|
+
const token = toSafeToken(startedAt);
|
|
22
|
+
return path.join(repoRoot, ".agentplane", "workflows", "evidence", `${mode}-${token}.json`);
|
|
23
|
+
}
|
|
24
|
+
function buildPlaybookCommands(opts) {
|
|
25
|
+
const ap = (...args) => ({
|
|
26
|
+
kind: "agentplane",
|
|
27
|
+
args: [...args, "--root", opts.repoRoot],
|
|
28
|
+
});
|
|
29
|
+
if (opts.mode === "debug") {
|
|
30
|
+
return [
|
|
31
|
+
ap("preflight", "--json", "--mode", "quick"),
|
|
32
|
+
ap("doctor"),
|
|
33
|
+
{ kind: "git", args: ["status", "--short", "--untracked-files=no"] },
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (opts.mode === "sync") {
|
|
37
|
+
return [
|
|
38
|
+
ap("task", "list"),
|
|
39
|
+
ap("task", "export"),
|
|
40
|
+
{ kind: "git", args: ["status", "--short", "--untracked-files=no"] },
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
ap("preflight", "--json", "--mode", "full"),
|
|
45
|
+
ap("doctor"),
|
|
46
|
+
{ kind: "git", args: ["status", "--short", "--untracked-files=no"] },
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
async function runWorkflowPlaybookCommand(opts) {
|
|
50
|
+
const startedMs = Date.now();
|
|
51
|
+
const startedAt = new Date(startedMs).toISOString();
|
|
52
|
+
let command = "";
|
|
53
|
+
let args = [];
|
|
54
|
+
if (opts.command.kind === "agentplane") {
|
|
55
|
+
command = process.execPath;
|
|
56
|
+
args = [AGENTPLANE_BIN, ...opts.command.args];
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
command = "git";
|
|
60
|
+
args = [...opts.command.args];
|
|
61
|
+
}
|
|
62
|
+
let exitCode = 0;
|
|
63
|
+
let stdout = "";
|
|
64
|
+
let stderr = "";
|
|
65
|
+
try {
|
|
66
|
+
const result = await execFileAsync(command, args, {
|
|
67
|
+
cwd: opts.repoRoot,
|
|
68
|
+
env: {
|
|
69
|
+
...process.env,
|
|
70
|
+
AGENTPLANE_NO_UPDATE_CHECK: process.env.AGENTPLANE_NO_UPDATE_CHECK ?? "1",
|
|
71
|
+
},
|
|
72
|
+
encoding: "utf8",
|
|
73
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
74
|
+
});
|
|
75
|
+
stdout = String(result.stdout ?? "");
|
|
76
|
+
stderr = String(result.stderr ?? "");
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const failed = err;
|
|
80
|
+
exitCode = typeof failed.code === "number" ? failed.code : 1;
|
|
81
|
+
stdout = typeof failed.stdout === "string" ? failed.stdout : "";
|
|
82
|
+
stderr = typeof failed.stderr === "string" ? failed.stderr : "";
|
|
83
|
+
if (!stderr && typeof failed.code === "string") {
|
|
84
|
+
stderr = failed.code;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const endedMs = Date.now();
|
|
88
|
+
return {
|
|
89
|
+
display: `${command} ${args.join(" ")}`.trim(),
|
|
90
|
+
started_at: startedAt,
|
|
91
|
+
ended_at: new Date(endedMs).toISOString(),
|
|
92
|
+
duration_ms: Math.max(0, endedMs - startedMs),
|
|
93
|
+
exit_code: exitCode,
|
|
94
|
+
stdout_tail: truncate(stdout),
|
|
95
|
+
stderr_tail: truncate(stderr),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function runWorkflowPlaybook(opts) {
|
|
99
|
+
try {
|
|
100
|
+
const resolved = await resolveProject({
|
|
101
|
+
cwd: opts.cwd,
|
|
102
|
+
rootOverride: opts.rootOverride ?? null,
|
|
103
|
+
});
|
|
104
|
+
const startedAt = new Date().toISOString();
|
|
105
|
+
const evidencePath = buildEvidencePath(resolved.gitRoot, opts.mode, startedAt);
|
|
106
|
+
const commands = buildPlaybookCommands({ mode: opts.mode, repoRoot: resolved.gitRoot });
|
|
107
|
+
const results = [];
|
|
108
|
+
let failed = false;
|
|
109
|
+
for (const command of commands) {
|
|
110
|
+
const result = await runWorkflowPlaybookCommand({
|
|
111
|
+
command,
|
|
112
|
+
repoRoot: resolved.gitRoot,
|
|
113
|
+
});
|
|
114
|
+
results.push(result);
|
|
115
|
+
if (result.stdout_tail)
|
|
116
|
+
process.stdout.write(`${result.stdout_tail}\n`);
|
|
117
|
+
if (result.stderr_tail)
|
|
118
|
+
process.stderr.write(`${result.stderr_tail}\n`);
|
|
119
|
+
if (result.exit_code !== 0)
|
|
120
|
+
failed = true;
|
|
121
|
+
}
|
|
122
|
+
await mkdir(path.dirname(evidencePath), { recursive: true });
|
|
123
|
+
const evidence = {
|
|
124
|
+
schema_version: 1,
|
|
125
|
+
mode: opts.mode,
|
|
126
|
+
status: failed ? "failed" : "success",
|
|
127
|
+
started_at: startedAt,
|
|
128
|
+
ended_at: new Date().toISOString(),
|
|
129
|
+
repo_root: resolved.gitRoot,
|
|
130
|
+
evidence_path: evidencePath,
|
|
131
|
+
commands: results,
|
|
132
|
+
};
|
|
133
|
+
await atomicWriteFile(evidencePath, `${JSON.stringify(evidence, null, 2)}\n`);
|
|
134
|
+
process.stdout.write(`Evidence: ${path.relative(resolved.gitRoot, evidencePath)}\n`);
|
|
135
|
+
return failed ? 1 : 0;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
throw mapCoreError(err, {
|
|
139
|
+
command: `workflow ${opts.mode}`,
|
|
140
|
+
root: opts.rootOverride ?? null,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export const workflowDebugSpec = {
|
|
145
|
+
id: ["workflow", "debug"],
|
|
146
|
+
group: "Workflow",
|
|
147
|
+
summary: "Run built-in debug checks and capture workflow evidence.",
|
|
148
|
+
parse: () => ({}),
|
|
149
|
+
examples: [{ cmd: "agentplane workflow debug", why: "Collect debug readiness evidence." }],
|
|
150
|
+
};
|
|
151
|
+
export const workflowSyncSpec = {
|
|
152
|
+
id: ["workflow", "sync"],
|
|
153
|
+
group: "Workflow",
|
|
154
|
+
summary: "Run built-in sync checks and capture workflow evidence.",
|
|
155
|
+
parse: () => ({}),
|
|
156
|
+
examples: [{ cmd: "agentplane workflow sync", why: "Collect sync-state evidence." }],
|
|
157
|
+
};
|
|
158
|
+
export const workflowLandSpec = {
|
|
159
|
+
id: ["workflow", "land"],
|
|
160
|
+
group: "Workflow",
|
|
161
|
+
summary: "Run built-in pre-land checks and capture workflow evidence.",
|
|
162
|
+
parse: () => ({}),
|
|
163
|
+
examples: [{ cmd: "agentplane workflow land", why: "Collect land-readiness evidence." }],
|
|
164
|
+
};
|
|
165
|
+
export const runWorkflowDebug = async (ctx) => {
|
|
166
|
+
return await runWorkflowPlaybook({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, mode: "debug" });
|
|
167
|
+
};
|
|
168
|
+
export const runWorkflowSync = async (ctx) => {
|
|
169
|
+
return await runWorkflowPlaybook({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, mode: "sync" });
|
|
170
|
+
};
|
|
171
|
+
export const runWorkflowLand = async (ctx) => {
|
|
172
|
+
return await runWorkflowPlaybook({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, mode: "land" });
|
|
173
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CommandHandler, CommandSpec } from "../cli/spec/spec.js";
|
|
2
|
+
export type WorkflowRestoreParsed = Record<string, never>;
|
|
3
|
+
export declare const workflowRestoreSpec: CommandSpec<WorkflowRestoreParsed>;
|
|
4
|
+
export declare const runWorkflowRestore: CommandHandler<WorkflowRestoreParsed>;
|
|
5
|
+
//# sourceMappingURL=workflow-restore.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-restore.command.d.ts","sourceRoot":"","sources":["../../src/commands/workflow-restore.command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvE,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE1D,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,qBAAqB,CAWlE,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,qBAAqB,CAuBpE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveProject } from "@agentplaneorg/core";
|
|
3
|
+
import { successMessage, warnMessage } from "../cli/output.js";
|
|
4
|
+
import { resolveWorkflowPaths, restoreWorkflowFromLastKnownGood, } from "../workflow-runtime/index.js";
|
|
5
|
+
export const workflowRestoreSpec = {
|
|
6
|
+
id: ["workflow", "restore"],
|
|
7
|
+
group: "Workflow",
|
|
8
|
+
summary: "Restore WORKFLOW.md from last-known-good snapshot.",
|
|
9
|
+
parse: () => ({}),
|
|
10
|
+
examples: [
|
|
11
|
+
{
|
|
12
|
+
cmd: "agentplane workflow restore",
|
|
13
|
+
why: "Restore active workflow from .agentplane/workflows/last-known-good.md.",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
export const runWorkflowRestore = async (ctx) => {
|
|
18
|
+
const resolved = await resolveProject({ cwd: ctx.cwd, rootOverride: ctx.rootOverride ?? null });
|
|
19
|
+
const workflowPaths = resolveWorkflowPaths(resolved.gitRoot);
|
|
20
|
+
const result = await restoreWorkflowFromLastKnownGood(resolved.gitRoot);
|
|
21
|
+
if (!result.ok) {
|
|
22
|
+
process.stderr.write(warnMessage("workflow restore failed") + "\n");
|
|
23
|
+
for (const diagnostic of result.diagnostics) {
|
|
24
|
+
process.stderr.write(`- [${diagnostic.severity}] ${diagnostic.code} ${diagnostic.path}: ${diagnostic.message}\n`);
|
|
25
|
+
}
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
process.stdout.write(successMessage("workflow restore", undefined, `Restored ${path.relative(resolved.gitRoot, workflowPaths.workflowPath)} from snapshot.`) + "\n");
|
|
29
|
+
return 0;
|
|
30
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CommandHandler, CommandSpec } from "../cli/spec/spec.js";
|
|
2
|
+
type WorkflowParsed = Record<string, never>;
|
|
3
|
+
export declare const workflowSpec: CommandSpec<WorkflowParsed>;
|
|
4
|
+
export declare const runWorkflow: CommandHandler<WorkflowParsed>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=workflow.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.command.d.ts","sourceRoot":"","sources":["../../src/commands/workflow.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAInF,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAI5C,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,cAAc,CAyBpD,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,cAAc,CAMtD,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { usageError } from "../cli/spec/errors.js";
|
|
2
|
+
import { suggestOne } from "../cli/spec/suggest.js";
|
|
3
|
+
const WORKFLOW_SUBCOMMANDS = ["build", "restore", "debug", "sync", "land"];
|
|
4
|
+
export const workflowSpec = {
|
|
5
|
+
id: ["workflow"],
|
|
6
|
+
group: "Workflow",
|
|
7
|
+
summary: "Workflow contract commands.",
|
|
8
|
+
synopsis: ["agentplane workflow <subcommand> [options]"],
|
|
9
|
+
args: [{ name: "subcommand", required: false, variadic: true, valueHint: "<subcommand>" }],
|
|
10
|
+
parse: () => ({}),
|
|
11
|
+
validateRaw: (raw) => {
|
|
12
|
+
const rest = Array.isArray(raw.args.subcommand) ? raw.args.subcommand : [];
|
|
13
|
+
const sub = rest[0];
|
|
14
|
+
if (!sub) {
|
|
15
|
+
throw usageError({
|
|
16
|
+
spec: workflowSpec,
|
|
17
|
+
command: "workflow",
|
|
18
|
+
message: "Missing workflow subcommand.",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const suggestion = suggestOne(String(sub), [...WORKFLOW_SUBCOMMANDS]);
|
|
22
|
+
const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
|
|
23
|
+
throw usageError({
|
|
24
|
+
spec: workflowSpec,
|
|
25
|
+
command: "workflow",
|
|
26
|
+
message: `Unknown workflow subcommand: ${String(sub)}.${suffix}`,
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export const runWorkflow = (_ctx) => {
|
|
31
|
+
throw usageError({
|
|
32
|
+
spec: workflowSpec,
|
|
33
|
+
command: "workflow",
|
|
34
|
+
message: "Missing workflow subcommand.",
|
|
35
|
+
});
|
|
36
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type DynamicToolInputSchema = {
|
|
2
|
+
required?: string[];
|
|
3
|
+
properties?: Record<string, {
|
|
4
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
5
|
+
}>;
|
|
6
|
+
additionalProperties?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type DynamicToolSpec = {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
inputSchema: DynamicToolInputSchema;
|
|
12
|
+
};
|
|
13
|
+
export type DynamicToolRegistry = Record<string, DynamicToolSpec>;
|
|
14
|
+
export type DynamicToolResponse = {
|
|
15
|
+
success: boolean;
|
|
16
|
+
code: "TOOL_OK" | "TOOL_UNSUPPORTED" | "TOOL_INVALID_ARGS" | "TOOL_EXECUTION_FAILED";
|
|
17
|
+
data?: unknown;
|
|
18
|
+
error?: {
|
|
19
|
+
message: string;
|
|
20
|
+
reason?: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export declare function executeDynamicTool(opts: {
|
|
24
|
+
registry: DynamicToolRegistry;
|
|
25
|
+
handlers: Record<string, (args: Record<string, unknown>) => unknown>;
|
|
26
|
+
toolName: string;
|
|
27
|
+
args: unknown;
|
|
28
|
+
}): Promise<DynamicToolResponse>;
|
|
29
|
+
//# sourceMappingURL=dynamic-tool-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-tool-contract.d.ts","sourceRoot":"","sources":["../../src/harness/dynamic-tool-contract.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAC5F,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,sBAAsB,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAElE,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,uBAAuB,CAAC;IACrF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AA+CF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAiD/B"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
function isObject(value) {
|
|
2
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
function matchesType(value, type) {
|
|
5
|
+
if (type === "array")
|
|
6
|
+
return Array.isArray(value);
|
|
7
|
+
if (type === "object")
|
|
8
|
+
return isObject(value);
|
|
9
|
+
return typeof value === type;
|
|
10
|
+
}
|
|
11
|
+
function validateInput(schema, args) {
|
|
12
|
+
if (!isObject(args)) {
|
|
13
|
+
return { ok: false, message: "Tool arguments must be an object." };
|
|
14
|
+
}
|
|
15
|
+
const required = schema.required ?? [];
|
|
16
|
+
for (const key of required) {
|
|
17
|
+
if (!(key in args)) {
|
|
18
|
+
return { ok: false, message: `Missing required field: ${key}` };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const properties = schema.properties ?? {};
|
|
22
|
+
for (const [key, value] of Object.entries(args)) {
|
|
23
|
+
const propSchema = properties[key];
|
|
24
|
+
if (!propSchema) {
|
|
25
|
+
if (schema.additionalProperties === false) {
|
|
26
|
+
return { ok: false, message: `Unknown argument: ${key}` };
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!matchesType(value, propSchema.type)) {
|
|
31
|
+
return {
|
|
32
|
+
ok: false,
|
|
33
|
+
message: `Invalid type for ${key}: expected ${propSchema.type}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { ok: true };
|
|
38
|
+
}
|
|
39
|
+
export async function executeDynamicTool(opts) {
|
|
40
|
+
const spec = opts.registry[opts.toolName];
|
|
41
|
+
if (!spec) {
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
code: "TOOL_UNSUPPORTED",
|
|
45
|
+
error: {
|
|
46
|
+
message: `Unsupported tool: ${opts.toolName}`,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const valid = validateInput(spec.inputSchema, opts.args);
|
|
51
|
+
if (!valid.ok) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
code: "TOOL_INVALID_ARGS",
|
|
55
|
+
error: {
|
|
56
|
+
message: valid.message ?? "Invalid tool arguments.",
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const handler = opts.handlers[opts.toolName];
|
|
61
|
+
if (!handler) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
code: "TOOL_UNSUPPORTED",
|
|
65
|
+
error: { message: `No handler registered for tool: ${opts.toolName}` },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const data = await handler(opts.args);
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
code: "TOOL_OK",
|
|
73
|
+
data,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
code: "TOOL_EXECUTION_FAILED",
|
|
80
|
+
error: {
|
|
81
|
+
message: "Tool execution failed.",
|
|
82
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type HookName = "after_create" | "before_run" | "after_run" | "before_remove";
|
|
2
|
+
export type HookPolicy = {
|
|
3
|
+
command?: string;
|
|
4
|
+
timeoutMs: number;
|
|
5
|
+
blocking: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type HookResult = {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
hook: HookName;
|
|
10
|
+
exitCode: number | null;
|
|
11
|
+
timedOut: boolean;
|
|
12
|
+
output: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function runLifecycleHook(opts: {
|
|
15
|
+
hook: HookName;
|
|
16
|
+
policy: HookPolicy;
|
|
17
|
+
cwd: string;
|
|
18
|
+
}): Promise<HookResult>;
|
|
19
|
+
export declare function runLifecycleHooks(opts: {
|
|
20
|
+
cwd: string;
|
|
21
|
+
hooks: Partial<Record<HookName, HookPolicy>>;
|
|
22
|
+
order: HookName[];
|
|
23
|
+
}): Promise<{
|
|
24
|
+
ok: boolean;
|
|
25
|
+
results: HookResult[];
|
|
26
|
+
}>;
|
|
27
|
+
//# sourceMappingURL=hooks-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-lifecycle.d.ts","sourceRoot":"","sources":["../../src/harness/hooks-lifecycle.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,eAAe,CAAC;AAErF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAAC,UAAU,CAAC,CAyDtB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IAC7C,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAclD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export async function runLifecycleHook(opts) {
|
|
3
|
+
if (!opts.policy.command || opts.policy.command.trim().length === 0) {
|
|
4
|
+
return {
|
|
5
|
+
ok: true,
|
|
6
|
+
hook: opts.hook,
|
|
7
|
+
exitCode: 0,
|
|
8
|
+
timedOut: false,
|
|
9
|
+
output: "",
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return await new Promise((resolve) => {
|
|
13
|
+
const child = spawn("sh", ["-lc", opts.policy.command], {
|
|
14
|
+
cwd: opts.cwd,
|
|
15
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16
|
+
});
|
|
17
|
+
let output = "";
|
|
18
|
+
let finished = false;
|
|
19
|
+
const timer = setTimeout(() => {
|
|
20
|
+
if (finished)
|
|
21
|
+
return;
|
|
22
|
+
finished = true;
|
|
23
|
+
child.kill("SIGKILL");
|
|
24
|
+
resolve({
|
|
25
|
+
ok: !opts.policy.blocking,
|
|
26
|
+
hook: opts.hook,
|
|
27
|
+
exitCode: null,
|
|
28
|
+
timedOut: true,
|
|
29
|
+
output,
|
|
30
|
+
});
|
|
31
|
+
}, Math.max(1, opts.policy.timeoutMs));
|
|
32
|
+
child.stdout.on("data", (chunk) => {
|
|
33
|
+
output += String(chunk);
|
|
34
|
+
});
|
|
35
|
+
child.stderr.on("data", (chunk) => {
|
|
36
|
+
output += String(chunk);
|
|
37
|
+
});
|
|
38
|
+
child.on("close", (code) => {
|
|
39
|
+
if (finished)
|
|
40
|
+
return;
|
|
41
|
+
finished = true;
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
const success = code === 0;
|
|
44
|
+
resolve({
|
|
45
|
+
ok: success || !opts.policy.blocking,
|
|
46
|
+
hook: opts.hook,
|
|
47
|
+
exitCode: code,
|
|
48
|
+
timedOut: false,
|
|
49
|
+
output,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function runLifecycleHooks(opts) {
|
|
55
|
+
const results = [];
|
|
56
|
+
for (const hook of opts.order) {
|
|
57
|
+
const policy = opts.hooks[hook];
|
|
58
|
+
if (!policy)
|
|
59
|
+
continue;
|
|
60
|
+
const result = await runLifecycleHook({ hook, policy, cwd: opts.cwd });
|
|
61
|
+
results.push(result);
|
|
62
|
+
if (!result.ok && policy.blocking) {
|
|
63
|
+
return { ok: false, results };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, results };
|
|
67
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./state-machine.js";
|
|
2
|
+
export * from "./scheduler.js";
|
|
3
|
+
export * from "./reconcile.js";
|
|
4
|
+
export * from "./retry-policy.js";
|
|
5
|
+
export * from "./workspace-safety.js";
|
|
6
|
+
export * from "./hooks-lifecycle.js";
|
|
7
|
+
export * from "./dynamic-tool-contract.js";
|
|
8
|
+
export * from "./token-accounting.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./state-machine.js";
|
|
2
|
+
export * from "./scheduler.js";
|
|
3
|
+
export * from "./reconcile.js";
|
|
4
|
+
export * from "./retry-policy.js";
|
|
5
|
+
export * from "./workspace-safety.js";
|
|
6
|
+
export * from "./hooks-lifecycle.js";
|
|
7
|
+
export * from "./dynamic-tool-contract.js";
|
|
8
|
+
export * from "./token-accounting.js";
|