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
|
@@ -32,6 +32,7 @@ export function protectedPathKindForFile(opts) {
|
|
|
32
32
|
return "tasks";
|
|
33
33
|
// "Rules of the game": authoring/agent policies and registry.
|
|
34
34
|
if (p === "AGENTS.md" ||
|
|
35
|
+
p === "CLAUDE.md" ||
|
|
35
36
|
p === "packages/agentplane/assets/AGENTS.md" ||
|
|
36
37
|
pathIsUnder(p, ".agentplane/agents")) {
|
|
37
38
|
return "policy";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const RUNTIME_GITIGNORE_LINES: readonly ["# agentplane: ignore runtime/transient workspace artifacts", ".env", ".agentplane/worktrees", ".agentplane/cache", ".agentplane/recipes-cache", ".agentplane/.upgrade", ".agentplane/.release", ".agentplane/upgrade", ".agentplane/tasks.json", "AGENTS.md.bak-*", ".agentplane/agents/*.bak-*"];
|
|
2
|
-
export declare const AGENT_PROMPT_GITIGNORE_LINES: readonly ["# agentplane: ignore local agent prompts/templates", "AGENTS.md", ".agentplane/agents/"];
|
|
1
|
+
export declare const RUNTIME_GITIGNORE_LINES: readonly ["# agentplane: ignore runtime/transient workspace artifacts", ".env", ".agentplane/worktrees", ".agentplane/cache", ".agentplane/recipes-cache", ".agentplane/.upgrade", ".agentplane/.release", ".agentplane/upgrade", ".agentplane/tasks.json", "AGENTS.md.bak-*", "CLAUDE.md.bak-*", ".agentplane/agents/*.bak-*", ".agentplane/policy/**/*.bak-*"];
|
|
2
|
+
export declare const AGENT_PROMPT_GITIGNORE_LINES: readonly ["# agentplane: ignore local agent prompts/templates", "AGENTS.md", "CLAUDE.md", ".agentplane/agents/", ".agentplane/policy/"];
|
|
3
3
|
//# sourceMappingURL=runtime-artifacts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-artifacts.d.ts","sourceRoot":"","sources":["../../src/shared/runtime-artifacts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"runtime-artifacts.d.ts","sourceRoot":"","sources":["../../src/shared/runtime-artifacts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,kWAc1B,CAAC;AAEX,eAAO,MAAM,4BAA4B,yIAM/B,CAAC"}
|
|
@@ -9,10 +9,14 @@ export const RUNTIME_GITIGNORE_LINES = [
|
|
|
9
9
|
".agentplane/upgrade",
|
|
10
10
|
".agentplane/tasks.json",
|
|
11
11
|
"AGENTS.md.bak-*",
|
|
12
|
+
"CLAUDE.md.bak-*",
|
|
12
13
|
".agentplane/agents/*.bak-*",
|
|
14
|
+
".agentplane/policy/**/*.bak-*",
|
|
13
15
|
];
|
|
14
16
|
export const AGENT_PROMPT_GITIGNORE_LINES = [
|
|
15
17
|
"# agentplane: ignore local agent prompts/templates",
|
|
16
18
|
"AGENTS.md",
|
|
19
|
+
"CLAUDE.md",
|
|
17
20
|
".agentplane/agents/",
|
|
21
|
+
".agentplane/policy/",
|
|
18
22
|
];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WorkflowBuildInput, WorkflowBuildOutput } from "./types.js";
|
|
2
|
+
export declare function buildWorkflowFromTemplates(input: WorkflowBuildInput): WorkflowBuildOutput;
|
|
3
|
+
export declare const DEFAULT_WORKFLOW_TEMPLATE = "---\nversion: 1\nmode: direct\nowners:\n orchestrator: ORCHESTRATOR\napprovals:\n require_plan: true\n require_verify: true\n require_network: true\nretry_policy:\n normal_exit_continuation: true\n abnormal_backoff: exponential\n max_attempts: 5\ntimeouts:\n stall_seconds: 900\nin_scope_paths:\n - packages/**\n---\n\n## Prompt Template\nRepository: {{ runtime.repo_name }}\nWorkflow mode: {{ workflow.mode }}\n\n## Checks\n- preflight\n- verify\n- finish\n\n## Fallback\nlast_known_good: .agentplane/workflows/last-known-good.md\n";
|
|
4
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAsB,MAAM,YAAY,CAAC;AAqC9F,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CA4EzF;AAED,eAAO,MAAM,yBAAyB,kiBA8BrC,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parseWorkflowMarkdown, serializeWorkflowMarkdown } from "./markdown.js";
|
|
2
|
+
import { emitWorkflowEvent } from "./observability.js";
|
|
3
|
+
import { renderTemplateStrict, validateTemplateStrict } from "./template.js";
|
|
4
|
+
import { validateWorkflowDocument } from "./validate.js";
|
|
5
|
+
function mergeRecord(baseValue, overrideValue) {
|
|
6
|
+
const out = { ...baseValue };
|
|
7
|
+
for (const [key, value] of Object.entries(overrideValue)) {
|
|
8
|
+
if (value &&
|
|
9
|
+
typeof value === "object" &&
|
|
10
|
+
!Array.isArray(value) &&
|
|
11
|
+
out[key] &&
|
|
12
|
+
typeof out[key] === "object" &&
|
|
13
|
+
!Array.isArray(out[key])) {
|
|
14
|
+
out[key] = mergeRecord(out[key], value);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
out[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
function mergeSections(baseSections, overrideSections) {
|
|
22
|
+
const out = { ...baseSections };
|
|
23
|
+
for (const [key, value] of Object.entries(overrideSections)) {
|
|
24
|
+
if (value.trim().length === 0)
|
|
25
|
+
continue;
|
|
26
|
+
out[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
export function buildWorkflowFromTemplates(input) {
|
|
31
|
+
emitWorkflowEvent({ event: "workflow_build_started" });
|
|
32
|
+
const diagnostics = [];
|
|
33
|
+
const base = parseWorkflowMarkdown(input.baseTemplate);
|
|
34
|
+
diagnostics.push(...base.diagnostics);
|
|
35
|
+
const override = input.projectOverrideTemplate
|
|
36
|
+
? parseWorkflowMarkdown(input.projectOverrideTemplate)
|
|
37
|
+
: null;
|
|
38
|
+
if (override)
|
|
39
|
+
diagnostics.push(...override.diagnostics);
|
|
40
|
+
const mergedFrontMatter = mergeRecord(base.document.frontMatterRaw, override?.document.frontMatterRaw ?? {});
|
|
41
|
+
const runtimeWorkflow = input.runtimeContext.workflow;
|
|
42
|
+
if (runtimeWorkflow && typeof runtimeWorkflow === "object" && !Array.isArray(runtimeWorkflow)) {
|
|
43
|
+
const runtimeWorkflowRecord = runtimeWorkflow;
|
|
44
|
+
const runtimeMode = runtimeWorkflowRecord.mode;
|
|
45
|
+
if (runtimeMode === "direct" || runtimeMode === "branch_pr") {
|
|
46
|
+
mergedFrontMatter.mode = runtimeMode;
|
|
47
|
+
}
|
|
48
|
+
const runtimeApprovals = runtimeWorkflowRecord.approvals;
|
|
49
|
+
if (runtimeApprovals &&
|
|
50
|
+
typeof runtimeApprovals === "object" &&
|
|
51
|
+
!Array.isArray(runtimeApprovals)) {
|
|
52
|
+
const approvalsRecord = runtimeApprovals;
|
|
53
|
+
mergedFrontMatter.approvals = {
|
|
54
|
+
require_plan: approvalsRecord.require_plan === true,
|
|
55
|
+
require_verify: approvalsRecord.require_verify === true,
|
|
56
|
+
require_network: approvalsRecord.require_network === true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const mergedSections = mergeSections(base.document.sections, override?.document.sections ?? {});
|
|
61
|
+
const promptTemplate = mergedSections["Prompt Template"] ?? "";
|
|
62
|
+
const strict = validateTemplateStrict(promptTemplate, input.runtimeContext, {
|
|
63
|
+
strictVariables: true,
|
|
64
|
+
strictFilters: true,
|
|
65
|
+
});
|
|
66
|
+
diagnostics.push(...strict.diagnostics);
|
|
67
|
+
const renderedPrompt = renderTemplateStrict(promptTemplate, input.runtimeContext, {
|
|
68
|
+
strictVariables: true,
|
|
69
|
+
strictFilters: true,
|
|
70
|
+
});
|
|
71
|
+
diagnostics.push(...renderedPrompt.diagnostics);
|
|
72
|
+
mergedSections["Prompt Template"] = renderedPrompt.text;
|
|
73
|
+
const renderedText = serializeWorkflowMarkdown(mergedFrontMatter, mergedSections);
|
|
74
|
+
const parsedRendered = parseWorkflowMarkdown(renderedText);
|
|
75
|
+
diagnostics.push(...parsedRendered.diagnostics);
|
|
76
|
+
const schema = validateWorkflowDocument(parsedRendered.document);
|
|
77
|
+
diagnostics.push(...schema.diagnostics);
|
|
78
|
+
const hasError = diagnostics.some((d) => d.severity === "ERROR");
|
|
79
|
+
if (hasError) {
|
|
80
|
+
emitWorkflowEvent({
|
|
81
|
+
event: "workflow_build_failed",
|
|
82
|
+
details: { diagnostics: diagnostics.length },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
emitWorkflowEvent({
|
|
87
|
+
event: "workflow_build_completed",
|
|
88
|
+
details: { diagnostics: diagnostics.length },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
text: renderedText,
|
|
93
|
+
diagnostics,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export const DEFAULT_WORKFLOW_TEMPLATE = `---
|
|
97
|
+
version: 1
|
|
98
|
+
mode: direct
|
|
99
|
+
owners:
|
|
100
|
+
orchestrator: ORCHESTRATOR
|
|
101
|
+
approvals:
|
|
102
|
+
require_plan: true
|
|
103
|
+
require_verify: true
|
|
104
|
+
require_network: true
|
|
105
|
+
retry_policy:
|
|
106
|
+
normal_exit_continuation: true
|
|
107
|
+
abnormal_backoff: exponential
|
|
108
|
+
max_attempts: 5
|
|
109
|
+
timeouts:
|
|
110
|
+
stall_seconds: 900
|
|
111
|
+
in_scope_paths:
|
|
112
|
+
- packages/**
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Prompt Template
|
|
116
|
+
Repository: {{ runtime.repo_name }}
|
|
117
|
+
Workflow mode: {{ workflow.mode }}
|
|
118
|
+
|
|
119
|
+
## Checks
|
|
120
|
+
- preflight
|
|
121
|
+
- verify
|
|
122
|
+
- finish
|
|
123
|
+
|
|
124
|
+
## Fallback
|
|
125
|
+
last_known_good: .agentplane/workflows/last-known-good.md
|
|
126
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/enforcement.ts"],"names":[],"mappings":"AAEA,wBAAgB,6BAA6B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAI3F;AAED,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const DISABLED_VALUES = new Set(["0", "false", "off", "disabled"]);
|
|
2
|
+
export function isWorkflowEnforcementDisabled(env = process.env) {
|
|
3
|
+
const raw = env.AGENTPLANE_WORKFLOW_ENFORCEMENT ?? env.AGENTPLANE_WORKFLOW_CONTRACT;
|
|
4
|
+
if (typeof raw !== "string")
|
|
5
|
+
return false;
|
|
6
|
+
return DISABLED_VALUES.has(raw.trim().toLowerCase());
|
|
7
|
+
}
|
|
8
|
+
export function workflowEnforcementEnvHint() {
|
|
9
|
+
return "AGENTPLANE_WORKFLOW_ENFORCEMENT";
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { WorkflowDiagnostic, WorkflowDocument, WorkflowValidationResult } from "./types.js";
|
|
2
|
+
export declare function readWorkflowDocument(repoRoot: string, absPath?: string): Promise<{
|
|
3
|
+
document: WorkflowDocument | null;
|
|
4
|
+
diagnostics: WorkflowDiagnostic[];
|
|
5
|
+
path: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function validateWorkflowAtPath(repoRoot: string, absPath?: string): Promise<WorkflowValidationResult>;
|
|
8
|
+
export declare function validateWorkflowText(repoRoot: string, workflowText: string): Promise<WorkflowValidationResult>;
|
|
9
|
+
export declare function publishWorkflowCandidate(repoRoot: string, candidateText: string): Promise<WorkflowValidationResult>;
|
|
10
|
+
export declare function restoreWorkflowFromLastKnownGood(repoRoot: string): Promise<WorkflowValidationResult>;
|
|
11
|
+
//# sourceMappingURL=file-ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/file-ops.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAiDjG,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BjG;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CAuBnC;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,CAAC,CAanC;AAED,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,wBAAwB,CAAC,CA0DnC;AAED,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CA6EnC"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadConfig } from "@agentplaneorg/core";
|
|
4
|
+
import { parseWorkflowMarkdown } from "./markdown.js";
|
|
5
|
+
import { emitWorkflowEvent } from "./observability.js";
|
|
6
|
+
import { resolveWorkflowPaths } from "./paths.js";
|
|
7
|
+
import { validateWorkflowDocument } from "./validate.js";
|
|
8
|
+
async function pathExists(absPath) {
|
|
9
|
+
try {
|
|
10
|
+
await fs.access(absPath);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function resolveWorkflowReadPath(paths) {
|
|
18
|
+
if (await pathExists(paths.workflowPath))
|
|
19
|
+
return paths.workflowPath;
|
|
20
|
+
if (await pathExists(paths.legacyWorkflowPath))
|
|
21
|
+
return paths.legacyWorkflowPath;
|
|
22
|
+
return paths.workflowPath;
|
|
23
|
+
}
|
|
24
|
+
async function removeLegacyWorkflowIfPresent(paths) {
|
|
25
|
+
if (paths.workflowPath === paths.legacyWorkflowPath)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
await fs.rm(paths.legacyWorkflowPath, { force: true });
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// best effort cleanup
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function listAgentIds(agentplaneDir) {
|
|
35
|
+
const ids = new Set();
|
|
36
|
+
const dir = path.join(agentplaneDir, "agents");
|
|
37
|
+
try {
|
|
38
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
39
|
+
for (const ent of entries) {
|
|
40
|
+
if (ent.isFile() && ent.name.endsWith(".json")) {
|
|
41
|
+
ids.add(ent.name.replace(/\.json$/i, ""));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// best effort
|
|
47
|
+
}
|
|
48
|
+
return ids;
|
|
49
|
+
}
|
|
50
|
+
export async function readWorkflowDocument(repoRoot, absPath) {
|
|
51
|
+
const paths = resolveWorkflowPaths(repoRoot);
|
|
52
|
+
const targetPath = absPath ?? (await resolveWorkflowReadPath(paths));
|
|
53
|
+
try {
|
|
54
|
+
const content = await fs.readFile(targetPath, "utf8");
|
|
55
|
+
const parsed = parseWorkflowMarkdown(content, targetPath);
|
|
56
|
+
return {
|
|
57
|
+
document: parsed.document,
|
|
58
|
+
diagnostics: parsed.diagnostics,
|
|
59
|
+
path: targetPath,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
document: null,
|
|
65
|
+
diagnostics: [
|
|
66
|
+
{
|
|
67
|
+
code: (await pathExists(targetPath)) ? "WF_READ_FAILED" : "WF_MISSING_FILE",
|
|
68
|
+
severity: "ERROR",
|
|
69
|
+
path: "file",
|
|
70
|
+
message: `Cannot read workflow file ${targetPath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
path: targetPath,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export async function validateWorkflowAtPath(repoRoot, absPath) {
|
|
78
|
+
const read = await readWorkflowDocument(repoRoot, absPath);
|
|
79
|
+
const diagnostics = [...read.diagnostics];
|
|
80
|
+
if (!read.document) {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
diagnostics,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const loaded = await loadConfig(path.join(repoRoot, ".agentplane"));
|
|
87
|
+
const knownAgentIds = await listAgentIds(path.join(repoRoot, ".agentplane"));
|
|
88
|
+
const validated = validateWorkflowDocument(read.document, {
|
|
89
|
+
repoRoot,
|
|
90
|
+
knownAgentIds,
|
|
91
|
+
config: loaded.config,
|
|
92
|
+
});
|
|
93
|
+
diagnostics.push(...validated.diagnostics);
|
|
94
|
+
return {
|
|
95
|
+
ok: diagnostics.every((d) => d.severity !== "ERROR"),
|
|
96
|
+
diagnostics,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export async function validateWorkflowText(repoRoot, workflowText) {
|
|
100
|
+
const parsed = parseWorkflowMarkdown(workflowText);
|
|
101
|
+
const loaded = await loadConfig(path.join(repoRoot, ".agentplane"));
|
|
102
|
+
const knownAgentIds = await listAgentIds(path.join(repoRoot, ".agentplane"));
|
|
103
|
+
const validated = validateWorkflowDocument(parsed.document, {
|
|
104
|
+
repoRoot,
|
|
105
|
+
knownAgentIds,
|
|
106
|
+
config: loaded.config,
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
ok: [...parsed.diagnostics, ...validated.diagnostics].every((d) => d.severity !== "ERROR"),
|
|
110
|
+
diagnostics: [...parsed.diagnostics, ...validated.diagnostics],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export async function publishWorkflowCandidate(repoRoot, candidateText) {
|
|
114
|
+
const paths = resolveWorkflowPaths(repoRoot);
|
|
115
|
+
const tempPath = `${paths.workflowPath}.tmp.${Date.now()}`;
|
|
116
|
+
const parsed = parseWorkflowMarkdown(candidateText, paths.workflowPath);
|
|
117
|
+
const configLoaded = await loadConfig(path.join(repoRoot, ".agentplane"));
|
|
118
|
+
const validation = validateWorkflowDocument(parsed.document, {
|
|
119
|
+
repoRoot,
|
|
120
|
+
knownAgentIds: await listAgentIds(path.join(repoRoot, ".agentplane")),
|
|
121
|
+
config: configLoaded.config,
|
|
122
|
+
});
|
|
123
|
+
const diagnostics = [...parsed.diagnostics, ...validation.diagnostics];
|
|
124
|
+
if (diagnostics.some((d) => d.severity === "ERROR")) {
|
|
125
|
+
emitWorkflowEvent({
|
|
126
|
+
event: "workflow_publish_failed",
|
|
127
|
+
code: "WF_PARSE_ERROR",
|
|
128
|
+
details: { reason: "validation failed before publish", diagnostics: diagnostics.length },
|
|
129
|
+
});
|
|
130
|
+
return { ok: false, diagnostics };
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
await fs.mkdir(path.dirname(paths.workflowPath), { recursive: true });
|
|
134
|
+
await fs.mkdir(paths.workflowDir, { recursive: true });
|
|
135
|
+
await fs.writeFile(tempPath, candidateText, "utf8");
|
|
136
|
+
await fs.rename(tempPath, paths.workflowPath);
|
|
137
|
+
await removeLegacyWorkflowIfPresent(paths);
|
|
138
|
+
await fs.copyFile(paths.workflowPath, paths.lastKnownGoodPath);
|
|
139
|
+
emitWorkflowEvent({
|
|
140
|
+
event: "workflow_publish_completed",
|
|
141
|
+
details: { workflowPath: paths.workflowPath, lastKnownGoodPath: paths.lastKnownGoodPath },
|
|
142
|
+
});
|
|
143
|
+
return { ok: true, diagnostics };
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
try {
|
|
147
|
+
await fs.rm(tempPath, { force: true });
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// best effort cleanup
|
|
151
|
+
}
|
|
152
|
+
emitWorkflowEvent({
|
|
153
|
+
event: "workflow_publish_failed",
|
|
154
|
+
code: "WF_READ_FAILED",
|
|
155
|
+
details: { reason: error instanceof Error ? error.message : String(error) },
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
diagnostics: [
|
|
160
|
+
...diagnostics,
|
|
161
|
+
{
|
|
162
|
+
code: "WF_READ_FAILED",
|
|
163
|
+
severity: "ERROR",
|
|
164
|
+
path: "file",
|
|
165
|
+
message: `Failed to atomically publish workflow: ${error instanceof Error ? error.message : String(error)}`,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function restoreWorkflowFromLastKnownGood(repoRoot) {
|
|
172
|
+
const paths = resolveWorkflowPaths(repoRoot);
|
|
173
|
+
const tempPath = `${paths.workflowPath}.restore.tmp.${Date.now()}`;
|
|
174
|
+
let lkgText = "";
|
|
175
|
+
try {
|
|
176
|
+
lkgText = await fs.readFile(paths.lastKnownGoodPath, "utf8");
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
emitWorkflowEvent({
|
|
180
|
+
event: "workflow_restore_failed",
|
|
181
|
+
code: "WF_MISSING_FILE",
|
|
182
|
+
details: { reason: error instanceof Error ? error.message : String(error) },
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
diagnostics: [
|
|
187
|
+
{
|
|
188
|
+
code: "WF_MISSING_FILE",
|
|
189
|
+
severity: "ERROR",
|
|
190
|
+
path: "file",
|
|
191
|
+
message: `Missing last-known-good workflow snapshot at ${paths.lastKnownGoodPath}`,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const parsed = parseWorkflowMarkdown(lkgText, paths.lastKnownGoodPath);
|
|
197
|
+
const configLoaded = await loadConfig(path.join(repoRoot, ".agentplane"));
|
|
198
|
+
const validated = validateWorkflowDocument(parsed.document, {
|
|
199
|
+
repoRoot,
|
|
200
|
+
knownAgentIds: await listAgentIds(path.join(repoRoot, ".agentplane")),
|
|
201
|
+
config: configLoaded.config,
|
|
202
|
+
});
|
|
203
|
+
const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];
|
|
204
|
+
if (diagnostics.some((d) => d.severity === "ERROR")) {
|
|
205
|
+
emitWorkflowEvent({
|
|
206
|
+
event: "workflow_restore_failed",
|
|
207
|
+
code: "WF_PARSE_ERROR",
|
|
208
|
+
details: { reason: "last-known-good validation failed" },
|
|
209
|
+
});
|
|
210
|
+
return { ok: false, diagnostics };
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
await fs.mkdir(path.dirname(paths.workflowPath), { recursive: true });
|
|
214
|
+
await fs.writeFile(tempPath, lkgText, "utf8");
|
|
215
|
+
await fs.rename(tempPath, paths.workflowPath);
|
|
216
|
+
await removeLegacyWorkflowIfPresent(paths);
|
|
217
|
+
emitWorkflowEvent({
|
|
218
|
+
event: "workflow_restore_completed",
|
|
219
|
+
details: { workflowPath: paths.workflowPath, from: paths.lastKnownGoodPath },
|
|
220
|
+
});
|
|
221
|
+
return { ok: true, diagnostics };
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
try {
|
|
225
|
+
await fs.rm(tempPath, { force: true });
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// best effort cleanup
|
|
229
|
+
}
|
|
230
|
+
emitWorkflowEvent({
|
|
231
|
+
event: "workflow_restore_failed",
|
|
232
|
+
code: "WF_READ_FAILED",
|
|
233
|
+
details: { reason: error instanceof Error ? error.message : String(error) },
|
|
234
|
+
});
|
|
235
|
+
return {
|
|
236
|
+
ok: false,
|
|
237
|
+
diagnostics: [
|
|
238
|
+
...diagnostics,
|
|
239
|
+
{
|
|
240
|
+
code: "WF_READ_FAILED",
|
|
241
|
+
severity: "ERROR",
|
|
242
|
+
path: "file",
|
|
243
|
+
message: `Failed to restore workflow from snapshot: ${error instanceof Error ? error.message : String(error)}`,
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WorkflowDiagnostic } from "./types.js";
|
|
2
|
+
type WorkflowFixResult = {
|
|
3
|
+
changed: boolean;
|
|
4
|
+
text: string;
|
|
5
|
+
diagnostics: WorkflowDiagnostic[];
|
|
6
|
+
};
|
|
7
|
+
export declare function safeAutofixWorkflowText(text: string): WorkflowFixResult;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=fix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/fix.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,YAAY,CAAC;AAE1E,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC,CAAC;AAoFF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA6CvE"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { parseWorkflowMarkdown, serializeWorkflowMarkdown } from "./markdown.js";
|
|
2
|
+
const DEFAULT_FRONT_MATTER = {
|
|
3
|
+
version: 1,
|
|
4
|
+
mode: "direct",
|
|
5
|
+
owners: { orchestrator: "ORCHESTRATOR" },
|
|
6
|
+
approvals: {
|
|
7
|
+
require_plan: true,
|
|
8
|
+
require_verify: true,
|
|
9
|
+
require_network: true,
|
|
10
|
+
},
|
|
11
|
+
retry_policy: {
|
|
12
|
+
normal_exit_continuation: true,
|
|
13
|
+
abnormal_backoff: "exponential",
|
|
14
|
+
max_attempts: 5,
|
|
15
|
+
},
|
|
16
|
+
timeouts: {
|
|
17
|
+
stall_seconds: 900,
|
|
18
|
+
},
|
|
19
|
+
in_scope_paths: ["packages/**"],
|
|
20
|
+
};
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
function withDefaults(raw) {
|
|
25
|
+
const out = { ...raw };
|
|
26
|
+
if (typeof out.version !== "number" || !Number.isInteger(out.version) || out.version < 1) {
|
|
27
|
+
out.version = 1;
|
|
28
|
+
}
|
|
29
|
+
if (out.mode !== "direct" && out.mode !== "branch_pr") {
|
|
30
|
+
out.mode = DEFAULT_FRONT_MATTER.mode;
|
|
31
|
+
}
|
|
32
|
+
const owners = isRecord(out.owners) ? { ...out.owners } : {};
|
|
33
|
+
if (typeof owners.orchestrator !== "string" || owners.orchestrator.trim().length === 0) {
|
|
34
|
+
owners.orchestrator = DEFAULT_FRONT_MATTER.owners.orchestrator;
|
|
35
|
+
}
|
|
36
|
+
out.owners = owners;
|
|
37
|
+
const approvals = isRecord(out.approvals) ? { ...out.approvals } : {};
|
|
38
|
+
for (const key of ["require_plan", "require_verify", "require_network"]) {
|
|
39
|
+
if (typeof approvals[key] !== "boolean")
|
|
40
|
+
approvals[key] = DEFAULT_FRONT_MATTER.approvals[key];
|
|
41
|
+
}
|
|
42
|
+
out.approvals = approvals;
|
|
43
|
+
const retryPolicy = isRecord(out.retry_policy) ? { ...out.retry_policy } : {};
|
|
44
|
+
if (typeof retryPolicy.normal_exit_continuation !== "boolean") {
|
|
45
|
+
retryPolicy.normal_exit_continuation =
|
|
46
|
+
DEFAULT_FRONT_MATTER.retry_policy.normal_exit_continuation;
|
|
47
|
+
}
|
|
48
|
+
if (retryPolicy.abnormal_backoff !== "exponential") {
|
|
49
|
+
retryPolicy.abnormal_backoff = DEFAULT_FRONT_MATTER.retry_policy.abnormal_backoff;
|
|
50
|
+
}
|
|
51
|
+
if (typeof retryPolicy.max_attempts !== "number" ||
|
|
52
|
+
!Number.isInteger(retryPolicy.max_attempts) ||
|
|
53
|
+
retryPolicy.max_attempts < 1) {
|
|
54
|
+
retryPolicy.max_attempts = DEFAULT_FRONT_MATTER.retry_policy.max_attempts;
|
|
55
|
+
}
|
|
56
|
+
out.retry_policy = retryPolicy;
|
|
57
|
+
const timeouts = isRecord(out.timeouts) ? { ...out.timeouts } : {};
|
|
58
|
+
if (typeof timeouts.stall_seconds !== "number" ||
|
|
59
|
+
!Number.isInteger(timeouts.stall_seconds) ||
|
|
60
|
+
timeouts.stall_seconds < 1) {
|
|
61
|
+
timeouts.stall_seconds = DEFAULT_FRONT_MATTER.timeouts.stall_seconds;
|
|
62
|
+
}
|
|
63
|
+
out.timeouts = timeouts;
|
|
64
|
+
const inScope = Array.isArray(out.in_scope_paths)
|
|
65
|
+
? out.in_scope_paths.filter((v) => typeof v === "string" && v.trim().length > 0)
|
|
66
|
+
: [];
|
|
67
|
+
out.in_scope_paths = inScope.length > 0 ? inScope : DEFAULT_FRONT_MATTER.in_scope_paths;
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
export function safeAutofixWorkflowText(text) {
|
|
71
|
+
const parsed = parseWorkflowMarkdown(text);
|
|
72
|
+
const diagnostics = [];
|
|
73
|
+
const unknownKeyDiagnostics = Object.keys(parsed.document.frontMatterRaw)
|
|
74
|
+
.filter((key) => ![
|
|
75
|
+
"version",
|
|
76
|
+
"mode",
|
|
77
|
+
"owners",
|
|
78
|
+
"approvals",
|
|
79
|
+
"retry_policy",
|
|
80
|
+
"timeouts",
|
|
81
|
+
"in_scope_paths",
|
|
82
|
+
].includes(key))
|
|
83
|
+
.map((key) => ({
|
|
84
|
+
code: "WF_FIX_SKIPPED_UNSAFE",
|
|
85
|
+
severity: "WARN",
|
|
86
|
+
path: `front_matter.${key}`,
|
|
87
|
+
message: `Unsafe autofix skipped for unknown key: ${key}`,
|
|
88
|
+
}));
|
|
89
|
+
diagnostics.push(...unknownKeyDiagnostics);
|
|
90
|
+
if (unknownKeyDiagnostics.length > 0) {
|
|
91
|
+
return { changed: false, text, diagnostics };
|
|
92
|
+
}
|
|
93
|
+
const nextFrontMatter = withDefaults(parsed.document.frontMatterRaw);
|
|
94
|
+
const sections = {
|
|
95
|
+
...parsed.document.sections,
|
|
96
|
+
"Prompt Template": parsed.document.sections["Prompt Template"] ?? "",
|
|
97
|
+
Checks: parsed.document.sections.Checks ?? "- preflight\n- verify\n- finish",
|
|
98
|
+
Fallback: parsed.document.sections.Fallback ??
|
|
99
|
+
"last_known_good: .agentplane/workflows/last-known-good.md",
|
|
100
|
+
};
|
|
101
|
+
const nextText = serializeWorkflowMarkdown(nextFrontMatter, sections);
|
|
102
|
+
return {
|
|
103
|
+
changed: nextText !== text,
|
|
104
|
+
text: nextText,
|
|
105
|
+
diagnostics,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./paths.js";
|
|
3
|
+
export * from "./observability.js";
|
|
4
|
+
export * from "./enforcement.js";
|
|
5
|
+
export * from "./markdown.js";
|
|
6
|
+
export * from "./validate.js";
|
|
7
|
+
export * from "./template.js";
|
|
8
|
+
export * from "./build.js";
|
|
9
|
+
export * from "./file-ops.js";
|
|
10
|
+
export * from "./fix.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./paths.js";
|
|
3
|
+
export * from "./observability.js";
|
|
4
|
+
export * from "./enforcement.js";
|
|
5
|
+
export * from "./markdown.js";
|
|
6
|
+
export * from "./validate.js";
|
|
7
|
+
export * from "./template.js";
|
|
8
|
+
export * from "./build.js";
|
|
9
|
+
export * from "./file-ops.js";
|
|
10
|
+
export * from "./fix.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkflowDiagnostic, WorkflowDocument, WorkflowFrontMatter, WorkflowSections, WorkflowValidationResult } from "./types.js";
|
|
2
|
+
export declare function parseWorkflowMarkdown(text: string, sourcePath?: string): {
|
|
3
|
+
document: Omit<WorkflowDocument, "frontMatter"> & {
|
|
4
|
+
frontMatter: WorkflowFrontMatter;
|
|
5
|
+
};
|
|
6
|
+
diagnostics: WorkflowDiagnostic[];
|
|
7
|
+
};
|
|
8
|
+
export declare function serializeWorkflowMarkdown(frontMatter: Record<string, unknown>, sections: WorkflowSections): string;
|
|
9
|
+
export declare function diagnosticsToValidationResult(diagnostics: WorkflowDiagnostic[]): WorkflowValidationResult;
|
|
10
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAmHpB,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB;IACD,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,GAAG;QAAE,WAAW,EAAE,mBAAmB,CAAA;KAAE,CAAC;IACvF,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC,CAmBA;AAOD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,EAAE,gBAAgB,GACzB,MAAM,CAkBR;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,kBAAkB,EAAE,GAChC,wBAAwB,CAM1B"}
|