agentplane 0.2.26 → 0.3.2
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 +124 -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 +47 -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 +88 -87
- package/bin/dist-guard.js +124 -0
- package/bin/runtime-context.d.ts +20 -0
- package/bin/runtime-context.js +81 -0
- package/dist/.build-manifest.json +5 -5
- 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/cli/bootstrap-guide.d.ts +18 -0
- package/dist/cli/bootstrap-guide.d.ts.map +1 -0
- package/dist/cli/bootstrap-guide.js +132 -0
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +58 -183
- package/dist/cli/command-snippets.d.ts +3 -3
- package/dist/cli/command-snippets.js +3 -3
- package/dist/cli/run-cli/commands/core.js +3 -3
- 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/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 +5 -0
- package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-workflow.js +6 -0
- package/dist/cli/run-cli/commands/init.d.ts +2 -0
- package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init.js +47 -19
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +125 -7
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +48 -6
- package/dist/commands/finish.run.d.ts.map +1 -1
- package/dist/commands/finish.run.js +1 -0
- package/dist/commands/finish.spec.d.ts +1 -0
- package/dist/commands/finish.spec.d.ts.map +1 -1
- package/dist/commands/finish.spec.js +23 -2
- package/dist/commands/release/apply.command.d.ts +1 -0
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +20 -9
- package/dist/commands/release/plan.command.d.ts.map +1 -1
- package/dist/commands/release/plan.command.js +9 -3
- 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 +1 -0
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +28 -7
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +41 -4
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +7 -1
- package/dist/commands/task/shared.d.ts +7 -0
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +37 -0
- package/dist/commands/task/start-ready.js +1 -1
- package/dist/commands/upgrade.command.d.ts.map +1 -1
- package/dist/commands/upgrade.command.js +11 -7
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +284 -296
- package/dist/commands/workflow-build.command.d.ts.map +1 -1
- package/dist/commands/workflow-build.command.js +7 -0
- package/dist/commands/workflow-playbook.command.d.ts.map +1 -1
- package/dist/commands/workflow-playbook.command.js +0 -1
- 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 +1 -1
- package/dist/workflow-runtime/build.d.ts.map +1 -1
- package/dist/workflow-runtime/build.js +14 -2
- package/package.json +2 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Workflow: release
|
|
2
|
+
|
|
3
|
+
Use this module when task touches release/version/publish flows.
|
|
4
|
+
|
|
5
|
+
## Required sequence
|
|
6
|
+
|
|
7
|
+
1. CHECKPOINT A: confirm clean tracked tree and approved scope.
|
|
8
|
+
2. CHECKPOINT B: generate release plan and freeze version/tag target.
|
|
9
|
+
3. Generate release notes with complete human-readable coverage of all task-level changes.
|
|
10
|
+
4. Run release prepublish checks.
|
|
11
|
+
5. CHECKPOINT C: apply release and push/tag only after all gates pass.
|
|
12
|
+
6. Record release evidence (commands, outputs, resulting version/tag).
|
|
13
|
+
|
|
14
|
+
## Command contract
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git status --short --untracked-files=no
|
|
18
|
+
agentplane task plan set <task-id> --text "Release plan: version=<v>, tag=<t>, scope=<...>" --updated-by <ROLE>
|
|
19
|
+
agentplane task plan approve <task-id> --by ORCHESTRATOR
|
|
20
|
+
agentplane release plan --patch
|
|
21
|
+
agentplane release apply --push --yes
|
|
22
|
+
agentplane verify <task-id> --ok|--rework --by <ROLE> --note "Release checks: ..."
|
|
23
|
+
agentplane finish <task-id> --author <ROLE> --body "Verified: release" --result "Release <v> published" --commit <git-rev> --close-commit
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Constraints
|
|
27
|
+
|
|
28
|
+
- MUST NOT perform irreversible release actions before explicit approval.
|
|
29
|
+
- MUST NOT skip parity/version checks.
|
|
30
|
+
- MUST NOT bypass required notes validation.
|
|
31
|
+
- MUST stop and request re-approval if release scope/tag/version changes.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Workflow: upgrade
|
|
2
|
+
|
|
3
|
+
Use this module when task runs `agentplane upgrade` or touches `.agentplane/.upgrade/**`.
|
|
4
|
+
|
|
5
|
+
## Required sequence
|
|
6
|
+
|
|
7
|
+
1. Run upgrade command and capture run directory.
|
|
8
|
+
2. Read upgrade review report:
|
|
9
|
+
- agent mode: `.agentplane/.upgrade/agent/<runId>/review.json`
|
|
10
|
+
- auto mode: `.agentplane/.upgrade/last-review.json`
|
|
11
|
+
3. Apply upgrade as replace-all for managed files (`agentplane upgrade --auto`), excluding task data paths.
|
|
12
|
+
4. For `.agentplane/policy/incidents.md`, keep existing local content and append incoming policy content (never replace non-empty local incidents file).
|
|
13
|
+
5. Ensure the upgrade produced a dedicated upgrade commit with version in commit message.
|
|
14
|
+
6. Verify policy/agent consistency and routing checks.
|
|
15
|
+
7. Record run path and reviewed files in task notes.
|
|
16
|
+
|
|
17
|
+
## Minimum verification
|
|
18
|
+
|
|
19
|
+
- `node .agentplane/policy/check-routing.mjs`
|
|
20
|
+
- `agentplane agents`
|
package/bin/agentplane.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { stat } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { distExists, isPackageBuildFresh } from "./dist-guard.js";
|
|
7
|
+
import { resolveFrameworkBinaryContext } from "./runtime-context.js";
|
|
6
8
|
|
|
7
9
|
async function exists(p) {
|
|
8
10
|
try {
|
|
@@ -14,15 +16,12 @@ async function exists(p) {
|
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
async function maybeWarnGlobalBinaryInRepoCheckout() {
|
|
17
|
-
const cwd = process.cwd();
|
|
18
|
-
const repoCli = path.join(cwd, "packages", "agentplane", "src", "cli.ts");
|
|
19
|
-
const repoBin = path.join(cwd, "packages", "agentplane", "bin", "agentplane.js");
|
|
20
|
-
if (!(await exists(repoCli)) || !(await exists(repoBin))) return;
|
|
21
|
-
|
|
22
19
|
const thisBin = fileURLToPath(import.meta.url);
|
|
20
|
+
const context = resolveFrameworkBinaryContext({ cwd: process.cwd(), thisBin });
|
|
21
|
+
if (!context.inFrameworkCheckout || context.isRepoLocalBinary) return;
|
|
22
|
+
|
|
23
23
|
const normalizedThis = path.resolve(thisBin);
|
|
24
|
-
const normalizedRepo = path.resolve(repoBin);
|
|
25
|
-
if (normalizedThis === normalizedRepo) return;
|
|
24
|
+
const normalizedRepo = path.resolve(context.checkout.repoBin);
|
|
26
25
|
|
|
27
26
|
process.stderr.write(
|
|
28
27
|
"warning: running global agentplane binary inside repository checkout.\n" +
|
|
@@ -36,88 +35,65 @@ async function maybeWarnGlobalBinaryInRepoCheckout() {
|
|
|
36
35
|
);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
raw = await readFile(p, "utf8");
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
return JSON.parse(raw);
|
|
48
|
-
} catch {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
38
|
+
function shouldUseGlobalBinaryInFramework() {
|
|
39
|
+
return (process.env.AGENTPLANE_USE_GLOBAL_IN_FRAMEWORK ?? "").trim() === "1";
|
|
51
40
|
}
|
|
52
41
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim() || null;
|
|
56
|
-
} catch {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
42
|
+
function isRepoLocalHandoffInvocation() {
|
|
43
|
+
return (process.env.AGENTPLANE_REPO_LOCAL_HANDOFF ?? "").trim() === "1";
|
|
59
44
|
}
|
|
60
45
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"git",
|
|
65
|
-
["status", "--porcelain", "--untracked-files=all", "--", "src"],
|
|
66
|
-
{
|
|
67
|
-
cwd,
|
|
68
|
-
encoding: "utf8",
|
|
69
|
-
},
|
|
70
|
-
);
|
|
71
|
-
return out.trim().length > 0;
|
|
72
|
-
} catch {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
46
|
+
function handoffToRepoLocalBinary(context) {
|
|
47
|
+
const repoBin = context.checkout?.repoBin;
|
|
48
|
+
if (!repoBin) return false;
|
|
76
49
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
`info: detected framework checkout; delegating to repo-local binary: ${repoBin}\n`,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const result = spawnSync(process.execPath, [repoBin, ...process.argv.slice(2)], {
|
|
55
|
+
cwd: process.cwd(),
|
|
56
|
+
stdio: "inherit",
|
|
57
|
+
env: {
|
|
58
|
+
...process.env,
|
|
59
|
+
AGENTPLANE_REPO_LOCAL_HANDOFF: "1",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (result.error) {
|
|
64
|
+
process.stderr.write(`error: failed to launch repo-local binary: ${result.error.message}\n`);
|
|
65
|
+
process.exitCode = 2;
|
|
66
|
+
return true;
|
|
84
67
|
}
|
|
68
|
+
|
|
69
|
+
process.exitCode = result.status ?? (result.signal ? 1 : 0);
|
|
70
|
+
return true;
|
|
85
71
|
}
|
|
86
72
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const manifest = await readJsonIfExists(manifestPath);
|
|
90
|
-
if (!manifest || manifest.schema_version !== 1) {
|
|
91
|
-
return { ok: false, reason: "manifest_missing" };
|
|
92
|
-
}
|
|
73
|
+
function maybeHandoffToRepoLocalBinary() {
|
|
74
|
+
if (shouldUseGlobalBinaryInFramework() || isRepoLocalHandoffInvocation()) return false;
|
|
93
75
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
76
|
+
const context = resolveFrameworkBinaryContext({
|
|
77
|
+
cwd: process.cwd(),
|
|
78
|
+
thisBin: fileURLToPath(import.meta.url),
|
|
79
|
+
});
|
|
80
|
+
if (!context.inFrameworkCheckout || context.isRepoLocalBinary) return false;
|
|
98
81
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
82
|
+
return handoffToRepoLocalBinary(context);
|
|
83
|
+
}
|
|
102
84
|
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
srcCliMtimeMs > manifest.src_cli_mtime_ms
|
|
109
|
-
) {
|
|
110
|
-
return { ok: false, reason: "src_cli_newer_than_manifest" };
|
|
111
|
-
}
|
|
112
|
-
if (
|
|
113
|
-
typeof manifest.src_index_mtime_ms === "number" &&
|
|
114
|
-
typeof srcIndexMtimeMs === "number" &&
|
|
115
|
-
srcIndexMtimeMs > manifest.src_index_mtime_ms
|
|
116
|
-
) {
|
|
117
|
-
return { ok: false, reason: "src_index_newer_than_manifest" };
|
|
85
|
+
function isHooksRunCommitMsgInvocation(argv) {
|
|
86
|
+
const args = argv.slice(2).map((value) => String(value ?? "").trim());
|
|
87
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
88
|
+
if (args[i] !== "hooks") continue;
|
|
89
|
+
return args[i + 1] === "run" && args[i + 2] === "commit-msg";
|
|
118
90
|
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
119
93
|
|
|
120
|
-
|
|
94
|
+
function isPathInside(baseDir, targetPath) {
|
|
95
|
+
const rel = path.relative(path.resolve(baseDir), path.resolve(targetPath));
|
|
96
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
121
97
|
}
|
|
122
98
|
|
|
123
99
|
async function assertDistUpToDate() {
|
|
@@ -127,8 +103,7 @@ async function assertDistUpToDate() {
|
|
|
127
103
|
if (!inRepo) return true;
|
|
128
104
|
|
|
129
105
|
const allowStale = (process.env.AGENTPLANE_DEV_ALLOW_STALE_DIST ?? "").trim() === "1";
|
|
130
|
-
|
|
131
|
-
if (!(await exists(agentplaneDistDir))) {
|
|
106
|
+
if (!(await distExists(agentplaneRoot))) {
|
|
132
107
|
process.stderr.write(
|
|
133
108
|
"error: agentplane dist is missing for this repo checkout.\n" +
|
|
134
109
|
"Fix:\n" +
|
|
@@ -141,16 +116,40 @@ async function assertDistUpToDate() {
|
|
|
141
116
|
|
|
142
117
|
const repoRoot = path.resolve(agentplaneRoot, "..", "..");
|
|
143
118
|
const coreRoot = path.join(repoRoot, "packages", "core");
|
|
144
|
-
const checks = [
|
|
145
|
-
|
|
119
|
+
const checks = [
|
|
120
|
+
{
|
|
121
|
+
name: "agentplane",
|
|
122
|
+
root: agentplaneRoot,
|
|
123
|
+
watchedPaths: ["src", "bin/agentplane.js", "bin/dist-guard.js"],
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
if (await exists(path.join(coreRoot, "src")))
|
|
127
|
+
checks.push({ name: "core", root: coreRoot, watchedPaths: ["src"] });
|
|
146
128
|
|
|
147
129
|
const staleReasons = [];
|
|
148
130
|
for (const check of checks) {
|
|
149
|
-
const result = await isPackageBuildFresh(check.root);
|
|
150
|
-
if (!result.ok)
|
|
131
|
+
const result = await isPackageBuildFresh(check.root, { watchedPaths: check.watchedPaths });
|
|
132
|
+
if (!result.ok) {
|
|
133
|
+
const detail =
|
|
134
|
+
Array.isArray(result.changedPaths) && result.changedPaths.length > 0
|
|
135
|
+
? `(${result.changedPaths.slice(0, 5).join(", ")}${result.changedPaths.length > 5 ? ", ..." : ""})`
|
|
136
|
+
: "";
|
|
137
|
+
staleReasons.push(`${check.name}:${result.reason}${detail}`);
|
|
138
|
+
}
|
|
151
139
|
}
|
|
152
140
|
|
|
153
141
|
if (staleReasons.length > 0 && !allowStale) {
|
|
142
|
+
const runningInsideCheckout = isPathInside(repoRoot, process.cwd());
|
|
143
|
+
if (!runningInsideCheckout) {
|
|
144
|
+
process.stderr.write(
|
|
145
|
+
"warning: linked development binary has a stale build, but current working directory is outside the agentplane checkout.\n" +
|
|
146
|
+
"proceeding with existing dist output.\n" +
|
|
147
|
+
`detected: ${staleReasons.join(", ")}\n` +
|
|
148
|
+
"tip: rebuild (`bun run --filter=@agentplaneorg/core build && bun run --filter=agentplane build`) or reinstall from npm for stable global usage.\n",
|
|
149
|
+
);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
154
153
|
process.stderr.write(
|
|
155
154
|
"error: refusing to run a stale repo build (manifest/git quick-check failed).\n" +
|
|
156
155
|
"Fix:\n" +
|
|
@@ -166,6 +165,8 @@ async function assertDistUpToDate() {
|
|
|
166
165
|
return true;
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
if (!maybeHandoffToRepoLocalBinary()) {
|
|
169
|
+
await maybeWarnGlobalBinaryInRepoCheckout();
|
|
170
|
+
const ok = isHooksRunCommitMsgInvocation(process.argv) ? true : await assertDistUpToDate();
|
|
171
|
+
if (ok) await import("../dist/cli.js");
|
|
172
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
async function exists(p) {
|
|
6
|
+
try {
|
|
7
|
+
await stat(p);
|
|
8
|
+
return true;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function readJsonIfExists(p) {
|
|
15
|
+
let raw = "";
|
|
16
|
+
try {
|
|
17
|
+
raw = await readFile(p, "utf8");
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveGitHead(cwd) {
|
|
29
|
+
try {
|
|
30
|
+
return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim() || null;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function listGitPaths(cwd, args) {
|
|
37
|
+
try {
|
|
38
|
+
const out = execFileSync("git", args, { cwd, encoding: "utf8" });
|
|
39
|
+
return out
|
|
40
|
+
.split(/\r?\n/u)
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function uniqueSorted(values) {
|
|
49
|
+
return [...new Set(values)].toSorted((a, b) => a.localeCompare(b));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function workingTreeChangedPaths(cwd, watchedPaths) {
|
|
53
|
+
const lines = listGitPaths(cwd, [
|
|
54
|
+
"status",
|
|
55
|
+
"--porcelain",
|
|
56
|
+
"--untracked-files=all",
|
|
57
|
+
"--",
|
|
58
|
+
...watchedPaths,
|
|
59
|
+
]);
|
|
60
|
+
return uniqueSorted(lines.map((line) => line.slice(3).trim()).filter(Boolean));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function committedChangedPathsSince(cwd, fromGitHead, watchedPaths) {
|
|
64
|
+
if (!fromGitHead) return [];
|
|
65
|
+
return uniqueSorted(
|
|
66
|
+
listGitPaths(cwd, ["diff", "--name-only", `${fromGitHead}..HEAD`, "--", ...watchedPaths]),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function fileMtimeMs(p) {
|
|
71
|
+
try {
|
|
72
|
+
const s = await stat(p);
|
|
73
|
+
if (!s.isFile()) return null;
|
|
74
|
+
return s.mtimeMs;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function isPackageBuildFresh(packageRoot, options = {}) {
|
|
81
|
+
const watchedPaths = options.watchedPaths ?? ["src"];
|
|
82
|
+
const manifestPath = path.join(packageRoot, "dist", ".build-manifest.json");
|
|
83
|
+
const manifest = await readJsonIfExists(manifestPath);
|
|
84
|
+
if (!manifest || manifest.schema_version !== 1) {
|
|
85
|
+
return { ok: false, reason: "manifest_missing", changedPaths: [] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const currentHead = resolveGitHead(packageRoot);
|
|
89
|
+
const changedPaths = uniqueSorted([
|
|
90
|
+
...committedChangedPathsSince(packageRoot, manifest.git_head, watchedPaths),
|
|
91
|
+
...workingTreeChangedPaths(packageRoot, watchedPaths),
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
if (changedPaths.length > 0) {
|
|
95
|
+
return { ok: false, reason: "watched_paths_changed", changedPaths };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const srcCliMtimeMs = await fileMtimeMs(path.join(packageRoot, "src", "cli.ts"));
|
|
99
|
+
const srcIndexMtimeMs = await fileMtimeMs(path.join(packageRoot, "src", "index.ts"));
|
|
100
|
+
if (
|
|
101
|
+
typeof manifest.src_cli_mtime_ms === "number" &&
|
|
102
|
+
typeof srcCliMtimeMs === "number" &&
|
|
103
|
+
srcCliMtimeMs > manifest.src_cli_mtime_ms
|
|
104
|
+
) {
|
|
105
|
+
return { ok: false, reason: "src_cli_newer_than_manifest", changedPaths: [] };
|
|
106
|
+
}
|
|
107
|
+
if (
|
|
108
|
+
typeof manifest.src_index_mtime_ms === "number" &&
|
|
109
|
+
typeof srcIndexMtimeMs === "number" &&
|
|
110
|
+
srcIndexMtimeMs > manifest.src_index_mtime_ms
|
|
111
|
+
) {
|
|
112
|
+
return { ok: false, reason: "src_index_newer_than_manifest", changedPaths: [] };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (manifest.git_head && currentHead && manifest.git_head !== currentHead) {
|
|
116
|
+
return { ok: true, reason: "fresh_after_non_runtime_head_change", changedPaths: [] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { ok: true, reason: "fresh", changedPaths: [] };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function distExists(packageRoot) {
|
|
123
|
+
return await exists(path.join(packageRoot, "dist"));
|
|
124
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type FrameworkCheckout = {
|
|
2
|
+
repoRoot: string;
|
|
3
|
+
packageRoot: string;
|
|
4
|
+
repoBin: string;
|
|
5
|
+
repoCli: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type FrameworkBinaryContext = {
|
|
9
|
+
inFrameworkCheckout: boolean;
|
|
10
|
+
isRepoLocalBinary: boolean;
|
|
11
|
+
checkout: FrameworkCheckout | null;
|
|
12
|
+
thisBin: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function findFrameworkCheckout(startDir: string): FrameworkCheckout | null;
|
|
16
|
+
|
|
17
|
+
export function resolveFrameworkBinaryContext(options: {
|
|
18
|
+
cwd: string;
|
|
19
|
+
thisBin: string;
|
|
20
|
+
}): FrameworkBinaryContext;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {{
|
|
6
|
+
* repoRoot: string;
|
|
7
|
+
* packageRoot: string;
|
|
8
|
+
* repoBin: string;
|
|
9
|
+
* repoCli: string;
|
|
10
|
+
* }} FrameworkCheckout
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {{
|
|
15
|
+
* cwd: string;
|
|
16
|
+
* thisBin: string;
|
|
17
|
+
* }} FrameworkBinaryContextOptions
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {{
|
|
22
|
+
* inFrameworkCheckout: boolean;
|
|
23
|
+
* isRepoLocalBinary: boolean;
|
|
24
|
+
* checkout: FrameworkCheckout | null;
|
|
25
|
+
* thisBin: string;
|
|
26
|
+
* }} FrameworkBinaryContext
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
function fileExists(p) {
|
|
30
|
+
return existsSync(p);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} startDir
|
|
35
|
+
* @returns {FrameworkCheckout | null}
|
|
36
|
+
*/
|
|
37
|
+
export function findFrameworkCheckout(startDir) {
|
|
38
|
+
let dir = path.resolve(startDir);
|
|
39
|
+
for (;;) {
|
|
40
|
+
const packageRoot = path.join(dir, "packages", "agentplane");
|
|
41
|
+
const repoBin = path.join(packageRoot, "bin", "agentplane.js");
|
|
42
|
+
const repoCli = path.join(packageRoot, "src", "cli.ts");
|
|
43
|
+
if (fileExists(repoBin) && fileExists(repoCli)) {
|
|
44
|
+
return {
|
|
45
|
+
repoRoot: dir,
|
|
46
|
+
packageRoot,
|
|
47
|
+
repoBin,
|
|
48
|
+
repoCli,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const parent = path.dirname(dir);
|
|
53
|
+
if (parent === dir) return null;
|
|
54
|
+
dir = parent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {FrameworkBinaryContextOptions} options
|
|
60
|
+
* @returns {FrameworkBinaryContext}
|
|
61
|
+
*/
|
|
62
|
+
export function resolveFrameworkBinaryContext(options) {
|
|
63
|
+
const cwd = path.resolve(options.cwd);
|
|
64
|
+
const thisBin = path.resolve(options.thisBin);
|
|
65
|
+
const checkout = findFrameworkCheckout(cwd);
|
|
66
|
+
if (!checkout) {
|
|
67
|
+
return {
|
|
68
|
+
inFrameworkCheckout: false,
|
|
69
|
+
isRepoLocalBinary: false,
|
|
70
|
+
checkout: null,
|
|
71
|
+
thisBin,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
inFrameworkCheckout: true,
|
|
77
|
+
isRepoLocalBinary: path.resolve(checkout.repoBin) === thisBin,
|
|
78
|
+
checkout,
|
|
79
|
+
thisBin,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"package_dir": "/home/runner/work/agentplane/agentplane/packages/agentplane",
|
|
4
|
-
"generated_at": "2026-03-
|
|
5
|
-
"git_head": "
|
|
6
|
-
"src_cli_mtime_ms":
|
|
4
|
+
"generated_at": "2026-03-07T17:34:46.688Z",
|
|
5
|
+
"git_head": "8ffbebd27d5fa6dcf906b1781f8fe2d0030c6c98",
|
|
6
|
+
"src_cli_mtime_ms": 1772904835121.3193,
|
|
7
7
|
"src_index_mtime_ms": null,
|
|
8
|
-
"dist_cli_mtime_ms":
|
|
8
|
+
"dist_cli_mtime_ms": 1772904886214.584,
|
|
9
9
|
"dist_index_mtime_ms": null,
|
|
10
|
-
"tsbuildinfo_mtime_ms":
|
|
10
|
+
"tsbuildinfo_mtime_ms": 1772904886278.5845
|
|
11
11
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { type PolicyGatewayFlavor } from "../shared/policy-gateway.js";
|
|
1
2
|
export type WorkflowMode = "direct" | "branch_pr";
|
|
2
3
|
type AgentTemplate = {
|
|
3
4
|
fileName: string;
|
|
4
5
|
contents: string;
|
|
5
6
|
};
|
|
7
|
+
export type PolicyTemplate = {
|
|
8
|
+
relativePath: string;
|
|
9
|
+
contents: string;
|
|
10
|
+
};
|
|
6
11
|
export declare function loadAgentsTemplate(): Promise<string>;
|
|
7
12
|
export declare function loadAgentTemplates(): Promise<AgentTemplate[]>;
|
|
13
|
+
export declare function loadPolicyTemplates(): Promise<PolicyTemplate[]>;
|
|
8
14
|
export declare function filterAgentsByWorkflow(template: string, workflow: WorkflowMode): string;
|
|
15
|
+
export declare function loadPolicyGatewayTemplate(flavor: PolicyGatewayFlavor): Promise<string>;
|
|
9
16
|
export {};
|
|
10
17
|
//# sourceMappingURL=agents-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-template.d.ts","sourceRoot":"","sources":["../../src/agents/agents-template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents-template.d.ts","sourceRoot":"","sources":["../../src/agents/agents-template.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElD,KAAK,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAwCxE,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAanE;AAsBD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAerE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CASvF;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5F"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { policyGatewayFileName, renderPolicyGatewayTemplateText, } from "../shared/policy-gateway.js";
|
|
4
5
|
const AGENTS_TEMPLATE_URL = new URL("../../assets/AGENTS.md", import.meta.url);
|
|
5
6
|
const AGENTS_DIR_URL = new URL("../../assets/agents/", import.meta.url);
|
|
7
|
+
const POLICY_DIR_URL = new URL("../../assets/policy/", import.meta.url);
|
|
6
8
|
const HEADING_RE = /^(#+)\s+(.*)$/;
|
|
7
9
|
function ensureTrailingNewline(text) {
|
|
8
10
|
return text.endsWith("\n") ? text : `${text}\n`;
|
|
@@ -41,8 +43,7 @@ function removeSections(lines, titles) {
|
|
|
41
43
|
return lines.filter((_line, index) => !shouldRemove.has(index));
|
|
42
44
|
}
|
|
43
45
|
export async function loadAgentsTemplate() {
|
|
44
|
-
|
|
45
|
-
return ensureTrailingNewline(text.trimEnd());
|
|
46
|
+
return loadPolicyGatewayTemplate("codex");
|
|
46
47
|
}
|
|
47
48
|
export async function loadAgentTemplates() {
|
|
48
49
|
const dirPath = fileURLToPath(AGENTS_DIR_URL);
|
|
@@ -56,6 +57,39 @@ export async function loadAgentTemplates() {
|
|
|
56
57
|
}
|
|
57
58
|
return templates;
|
|
58
59
|
}
|
|
60
|
+
async function listFilesRecursive(dirPath, relPrefix = "") {
|
|
61
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
62
|
+
const sorted = entries.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
63
|
+
const files = [];
|
|
64
|
+
for (const entry of sorted) {
|
|
65
|
+
// Ignore editor/OS hidden metadata files.
|
|
66
|
+
if (entry.name.startsWith("."))
|
|
67
|
+
continue;
|
|
68
|
+
const absPath = path.join(dirPath, entry.name);
|
|
69
|
+
const relPath = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
files.push(...(await listFilesRecursive(absPath, relPath)));
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (entry.isFile())
|
|
75
|
+
files.push(relPath);
|
|
76
|
+
}
|
|
77
|
+
return files;
|
|
78
|
+
}
|
|
79
|
+
export async function loadPolicyTemplates() {
|
|
80
|
+
const dirPath = fileURLToPath(POLICY_DIR_URL);
|
|
81
|
+
const relFiles = await listFilesRecursive(dirPath);
|
|
82
|
+
const templates = [];
|
|
83
|
+
for (const relFile of relFiles) {
|
|
84
|
+
const filePath = path.join(dirPath, relFile);
|
|
85
|
+
const contents = await readFile(filePath, "utf8");
|
|
86
|
+
templates.push({
|
|
87
|
+
relativePath: relFile.replaceAll("\\", "/"),
|
|
88
|
+
contents: ensureTrailingNewline(contents.trimEnd()),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return templates;
|
|
92
|
+
}
|
|
59
93
|
export function filterAgentsByWorkflow(template, workflow) {
|
|
60
94
|
const lines = template.replaceAll("\r\n", "\n").split("\n");
|
|
61
95
|
const removeTitles = workflow === "direct"
|
|
@@ -64,3 +98,8 @@ export function filterAgentsByWorkflow(template, workflow) {
|
|
|
64
98
|
const filtered = removeSections(lines, removeTitles);
|
|
65
99
|
return ensureTrailingNewline(filtered.join("\n").trimEnd());
|
|
66
100
|
}
|
|
101
|
+
export async function loadPolicyGatewayTemplate(flavor) {
|
|
102
|
+
const text = await readFile(AGENTS_TEMPLATE_URL, "utf8");
|
|
103
|
+
const rendered = renderPolicyGatewayTemplateText(text, policyGatewayFileName(flavor));
|
|
104
|
+
return ensureTrailingNewline(rendered.trimEnd());
|
|
105
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const AGENT_BOOTSTRAP_DOC_PATH = "docs/user/agent-bootstrap.generated.mdx";
|
|
2
|
+
export type BootstrapSection = {
|
|
3
|
+
heading: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
commands: readonly string[];
|
|
6
|
+
notes?: readonly string[];
|
|
7
|
+
};
|
|
8
|
+
export declare const BOOTSTRAP_PREFLIGHT_COMMANDS: readonly ["agentplane config show", "agentplane quickstart", "agentplane task list", "git status --short --untracked-files=no", "git rev-parse --abbrev-ref HEAD"];
|
|
9
|
+
export declare const BOOTSTRAP_TASK_PREP_COMMANDS: string[];
|
|
10
|
+
export declare const BOOTSTRAP_TASK_LIFECYCLE_COMMANDS: readonly [...string[], "agentplane task start-ready <task-id> --author <ROLE> --body \"Start: ...\"", "agentplane verify <task-id> --ok|--rework --by <ROLE> --note \"...\"", "agentplane finish <task-id> --author <ROLE> --body \"Verified: ...\" --result \"...\" --commit <git-rev>"];
|
|
11
|
+
export declare const BOOTSTRAP_VERIFY_AND_FINISH_COMMANDS: readonly ["agentplane task verify-show <task-id>", "agentplane verify <task-id> --ok|--rework --by <ROLE> --note \"...\"", "agentplane finish <task-id> --author <ROLE> --body \"Verified: ...\" --result \"...\" --commit <git-rev>"];
|
|
12
|
+
export declare const BOOTSTRAP_VERIFICATION_COMMANDS: readonly ["agentplane task verify-show <task-id>", "agentplane verify <task-id> --ok|--rework --by <ROLE> --note \"...\"", "agentplane doctor", "node .agentplane/policy/check-routing.mjs"];
|
|
13
|
+
export declare const BOOTSTRAP_RECOVERY_COMMANDS: readonly ["agentplane doctor", "agentplane upgrade --dry-run", "agentplane upgrade"];
|
|
14
|
+
export declare const BOOTSTRAP_SECTIONS: readonly BootstrapSection[];
|
|
15
|
+
export declare function renderBootstrapReferenceLine(): string;
|
|
16
|
+
export declare function renderBootstrapSectionLines(sections: readonly BootstrapSection[]): string[];
|
|
17
|
+
export declare function renderBootstrapDoc(): string;
|
|
18
|
+
//# sourceMappingURL=bootstrap-guide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-guide.d.ts","sourceRoot":"","sources":["../../src/cli/bootstrap-guide.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB,4CAA4C,CAAC;AAElF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,4BAA4B,oKAM/B,CAAC;AAEX,eAAO,MAAM,4BAA4B,UAIxC,CAAC;AAEF,eAAO,MAAM,iCAAiC,2RAKpC,CAAC;AAEX,eAAO,MAAM,oCAAoC,wOAIvC,CAAC;AAEX,eAAO,MAAM,+BAA+B,8LAKlC,CAAC;AAEX,eAAO,MAAM,2BAA2B,sFAI9B,CAAC;AAEX,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EA+ChD,CAAC;AAEX,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,EAAE,CAiB3F;AAMD,wBAAgB,kBAAkB,IAAI,MAAM,CA0B3C"}
|