agentplane 0.2.6 → 0.2.13
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 +11 -0
- package/assets/AGENTS.md +35 -0
- package/assets/agents/CODER.json +0 -1
- package/assets/agents/INTEGRATOR.json +0 -1
- package/assets/agents/ORCHESTRATOR.json +1 -2
- package/assets/agents/PLANNER.json +1 -3
- package/assets/agents/TESTER.json +0 -1
- package/assets/agents/UPGRADER.json +17 -15
- package/dist/cli/archive.d.ts.map +1 -1
- package/dist/cli/archive.js +61 -36
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +5 -3
- package/dist/cli/run-cli/command-catalog.d.ts +4 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +44 -26
- package/dist/cli/run-cli/commands/config.d.ts +5 -4
- package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/config.js +47 -58
- package/dist/cli/run-cli/commands/core.d.ts +2 -1
- package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core.js +187 -51
- package/dist/cli/run-cli/commands/ide.d.ts +3 -1
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +7 -12
- package/dist/cli/run-cli/commands/init/ide-sync.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ide-sync.js +10 -1
- package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-agents.js +4 -24
- package/dist/cli/run-cli/commands/init/write-gitignore.d.ts +5 -0
- package/dist/cli/run-cli/commands/init/write-gitignore.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/init/write-gitignore.js +48 -0
- package/dist/cli/run-cli/commands/init.d.ts +1 -0
- package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init.js +34 -8
- package/dist/cli/run-cli/commands/wrap-command.d.ts +6 -0
- package/dist/cli/run-cli/commands/wrap-command.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/wrap-command.js +17 -0
- package/dist/cli/run-cli/registry.run.d.ts +6 -2
- package/dist/cli/run-cli/registry.run.d.ts.map +1 -1
- package/dist/cli/run-cli/registry.run.js +7 -2
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +96 -75
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +99 -3
- package/dist/cli/spec/parse-utils.d.ts +11 -0
- package/dist/cli/spec/parse-utils.d.ts.map +1 -0
- package/dist/cli/spec/parse-utils.js +28 -0
- package/dist/commands/block.command.d.ts +3 -18
- package/dist/commands/block.command.d.ts.map +1 -1
- package/dist/commands/block.command.js +2 -143
- package/dist/commands/block.run.d.ts +5 -0
- package/dist/commands/block.run.d.ts.map +1 -0
- package/dist/commands/block.run.js +22 -0
- package/dist/commands/block.spec.d.ts +17 -0
- package/dist/commands/block.spec.d.ts.map +1 -0
- package/dist/commands/block.spec.js +115 -0
- package/dist/commands/doctor.command.d.ts +2 -7
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +2 -137
- package/dist/commands/doctor.run.d.ts +4 -0
- package/dist/commands/doctor.run.d.ts.map +1 -0
- package/dist/commands/doctor.run.js +174 -0
- package/dist/commands/doctor.spec.d.ts +7 -0
- package/dist/commands/doctor.spec.d.ts.map +1 -0
- package/dist/commands/doctor.spec.js +20 -0
- package/dist/commands/finish.command.d.ts +3 -27
- package/dist/commands/finish.command.d.ts.map +1 -1
- package/dist/commands/finish.command.js +2 -237
- package/dist/commands/finish.run.d.ts +5 -0
- package/dist/commands/finish.run.d.ts.map +1 -0
- package/dist/commands/finish.run.js +40 -0
- package/dist/commands/finish.spec.d.ts +26 -0
- package/dist/commands/finish.spec.d.ts.map +1 -0
- package/dist/commands/finish.spec.js +193 -0
- package/dist/commands/recipes/install.command.d.ts +2 -11
- package/dist/commands/recipes/install.command.d.ts.map +1 -1
- package/dist/commands/recipes/install.command.js +2 -161
- package/dist/commands/recipes/install.run.d.ts +4 -0
- package/dist/commands/recipes/install.run.d.ts.map +1 -0
- package/dist/commands/recipes/install.run.js +23 -0
- package/dist/commands/recipes/install.spec.d.ts +11 -0
- package/dist/commands/recipes/install.spec.d.ts.map +1 -0
- package/dist/commands/recipes/install.spec.js +140 -0
- package/dist/commands/release/apply.command.d.ts +11 -0
- package/dist/commands/release/apply.command.d.ts.map +1 -0
- package/dist/commands/release/apply.command.js +343 -0
- package/dist/commands/release/plan.command.d.ts +12 -0
- package/dist/commands/release/plan.command.d.ts.map +1 -0
- package/dist/commands/release/plan.command.js +206 -0
- package/dist/commands/release/release.command.d.ts +5 -0
- package/dist/commands/release/release.command.d.ts.map +1 -0
- package/dist/commands/release/release.command.js +18 -0
- package/dist/commands/shared/git-context.d.ts +3 -0
- package/dist/commands/shared/git-context.d.ts.map +1 -1
- package/dist/commands/shared/git-context.js +10 -0
- package/dist/commands/shared/task-backend.d.ts +1 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/start.command.d.ts +3 -18
- package/dist/commands/start.command.d.ts.map +1 -1
- package/dist/commands/start.command.js +2 -143
- package/dist/commands/start.run.d.ts +5 -0
- package/dist/commands/start.run.d.ts.map +1 -0
- package/dist/commands/start.run.js +22 -0
- package/dist/commands/start.spec.d.ts +17 -0
- package/dist/commands/start.spec.d.ts.map +1 -0
- package/dist/commands/start.spec.js +115 -0
- package/dist/commands/task/add.command.d.ts.map +1 -1
- package/dist/commands/task/add.command.js +1 -7
- package/dist/commands/task/derive.command.d.ts.map +1 -1
- package/dist/commands/task/derive.command.js +1 -7
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +34 -2
- package/dist/commands/task/list.command.d.ts +3 -8
- package/dist/commands/task/list.command.d.ts.map +1 -1
- package/dist/commands/task/list.command.js +2 -67
- package/dist/commands/task/list.run.d.ts +5 -0
- package/dist/commands/task/list.run.d.ts.map +1 -0
- package/dist/commands/task/list.run.js +10 -0
- package/dist/commands/task/list.spec.d.ts +7 -0
- package/dist/commands/task/list.spec.d.ts.map +1 -0
- package/dist/commands/task/list.spec.js +51 -0
- package/dist/commands/task/next.command.d.ts +3 -8
- package/dist/commands/task/next.command.d.ts.map +1 -1
- package/dist/commands/task/next.command.js +2 -89
- package/dist/commands/task/next.run.d.ts +5 -0
- package/dist/commands/task/next.run.d.ts.map +1 -0
- package/dist/commands/task/next.run.js +11 -0
- package/dist/commands/task/next.spec.d.ts +7 -0
- package/dist/commands/task/next.spec.d.ts.map +1 -0
- package/dist/commands/task/next.spec.js +69 -0
- package/dist/commands/task/search.command.d.ts +3 -10
- package/dist/commands/task/search.command.d.ts.map +1 -1
- package/dist/commands/task/search.command.js +2 -101
- package/dist/commands/task/search.run.d.ts +5 -0
- package/dist/commands/task/search.run.d.ts.map +1 -0
- package/dist/commands/task/search.run.js +13 -0
- package/dist/commands/task/search.spec.d.ts +9 -0
- package/dist/commands/task/search.spec.d.ts.map +1 -0
- package/dist/commands/task/search.spec.js +79 -0
- package/dist/commands/task/set-status.command.d.ts.map +1 -1
- package/dist/commands/task/set-status.command.js +1 -7
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +15 -8
- package/dist/commands/task/show.command.d.ts +3 -7
- package/dist/commands/task/show.command.d.ts.map +1 -1
- package/dist/commands/task/show.command.js +2 -19
- package/dist/commands/task/show.run.d.ts +5 -0
- package/dist/commands/task/show.run.d.ts.map +1 -0
- package/dist/commands/task/show.run.js +11 -0
- package/dist/commands/task/show.spec.d.ts +6 -0
- package/dist/commands/task/show.spec.d.ts.map +1 -0
- package/dist/commands/task/show.spec.js +8 -0
- package/dist/commands/task/update.command.d.ts.map +1 -1
- package/dist/commands/task/update.command.js +1 -7
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +171 -32
- package/dist/commands/verify.command.d.ts +3 -15
- package/dist/commands/verify.command.d.ts.map +1 -1
- package/dist/commands/verify.command.js +2 -113
- package/dist/commands/verify.run.d.ts +5 -0
- package/dist/commands/verify.run.d.ts.map +1 -0
- package/dist/commands/verify.run.js +17 -0
- package/dist/commands/verify.spec.d.ts +14 -0
- package/dist/commands/verify.spec.d.ts.map +1 -0
- package/dist/commands/verify.spec.js +96 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAmCA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAgGF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,GAAG;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,CAWA;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GACG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAqB1C;AAUD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAgBT;AAqQD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,YAAY,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2mBlB"}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { lstat, mkdir, mkdtemp, readdir, readFile, readlink, rm,
|
|
1
|
+
import { lstat, mkdir, mkdtemp, readdir, readFile, readlink, rm, writeFile, } from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -15,6 +15,21 @@ const DEFAULT_UPGRADE_ASSET = "agentplane-upgrade.tar.gz";
|
|
|
15
15
|
const DEFAULT_UPGRADE_CHECKSUM_ASSET = "agentplane-upgrade.tar.gz.sha256";
|
|
16
16
|
const UPGRADE_DOWNLOAD_TIMEOUT_MS = 60_000;
|
|
17
17
|
const UPGRADE_RELEASE_METADATA_TIMEOUT_MS = 15_000;
|
|
18
|
+
async function safeRemovePath(targetPath) {
|
|
19
|
+
try {
|
|
20
|
+
await rm(targetPath, { recursive: true, force: true });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// best-effort cleanup
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function cleanupAutoUpgradeArtifacts(opts) {
|
|
27
|
+
for (const backupPath of opts.createdBackups) {
|
|
28
|
+
await safeRemovePath(backupPath);
|
|
29
|
+
}
|
|
30
|
+
// Keep durable state files at .upgrade root; remove transient per-run agent artifacts.
|
|
31
|
+
await safeRemovePath(path.join(opts.upgradeStateDir, "agent"));
|
|
32
|
+
}
|
|
18
33
|
const ASSETS_DIR_URL = new URL("../../assets/", import.meta.url);
|
|
19
34
|
async function loadFrameworkManifestFromPath(manifestPath) {
|
|
20
35
|
const text = await readFile(manifestPath, "utf8");
|
|
@@ -230,6 +245,23 @@ function jsonEqual(a, b) {
|
|
|
230
245
|
const cb = JSON.stringify(canonicalizeJson(b)) ?? "__undefined__";
|
|
231
246
|
return ca === cb;
|
|
232
247
|
}
|
|
248
|
+
function textChangedForType(opts) {
|
|
249
|
+
if (opts.aText === null && opts.bText === null)
|
|
250
|
+
return false;
|
|
251
|
+
if (opts.aText === null || opts.bText === null)
|
|
252
|
+
return true;
|
|
253
|
+
if (opts.type === "json") {
|
|
254
|
+
try {
|
|
255
|
+
const a = JSON.parse(opts.aText);
|
|
256
|
+
const b = JSON.parse(opts.bText);
|
|
257
|
+
return !jsonEqual(a, b);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return opts.aText.trim() !== opts.bText.trim();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return opts.aText.trimEnd() !== opts.bText.trimEnd();
|
|
264
|
+
}
|
|
233
265
|
// Used as a fallback for 3-way merges when no baseline is available. Incoming (upstream) values
|
|
234
266
|
// win for scalar/object conflicts, while user-added keys and array items are preserved.
|
|
235
267
|
function mergeAgentJsonIncomingWins(incomingText, currentText) {
|
|
@@ -398,6 +430,7 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
398
430
|
const useRemote = flags.remote === true || hasRemoteHints;
|
|
399
431
|
let tempRoot = null;
|
|
400
432
|
let extractRoot = null;
|
|
433
|
+
const createdBackups = [];
|
|
401
434
|
try {
|
|
402
435
|
tempRoot = await mkdtemp(path.join(os.tmpdir(), "agentplane-upgrade-"));
|
|
403
436
|
let bundlePath = "";
|
|
@@ -519,6 +552,8 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
519
552
|
const fileContents = new Map();
|
|
520
553
|
const merged = [];
|
|
521
554
|
const missingRequired = [];
|
|
555
|
+
const reviewRecords = [];
|
|
556
|
+
const reviewSnapshots = new Map();
|
|
522
557
|
const readBaselineText = async (baselineKey) => {
|
|
523
558
|
try {
|
|
524
559
|
return await readFile(path.join(baselineDirNew, baselineKey), "utf8");
|
|
@@ -588,6 +623,12 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
588
623
|
if (kind !== null) {
|
|
589
624
|
existingBuf = await readFile(destPath);
|
|
590
625
|
}
|
|
626
|
+
const incomingTextOriginal = data.toString("utf8");
|
|
627
|
+
const currentTextForReview = existingBuf ? existingBuf.toString("utf8") : null;
|
|
628
|
+
const baselineKey = toBaselineKey(rel);
|
|
629
|
+
const baselineText = baselineKey ? await readBaselineText(baselineKey) : null;
|
|
630
|
+
let mergeApplied = false;
|
|
631
|
+
let mergePath = "none";
|
|
591
632
|
// Merge logic only needs text for a small subset of managed files.
|
|
592
633
|
if (existingBuf) {
|
|
593
634
|
if (entry.merge_strategy === "agents_policy_markdown" && rel === "AGENTS.md") {
|
|
@@ -595,18 +636,16 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
595
636
|
const mergedText = mergeAgentsPolicyMarkdown(data.toString("utf8"), existingText);
|
|
596
637
|
data = Buffer.from(mergedText, "utf8");
|
|
597
638
|
merged.push(rel);
|
|
639
|
+
mergeApplied = true;
|
|
640
|
+
mergePath = "markdownOverrides";
|
|
598
641
|
}
|
|
599
642
|
else if (entry.merge_strategy === "agent_json_3way" &&
|
|
600
643
|
rel.startsWith(".agentplane/agents/") &&
|
|
601
644
|
rel.endsWith(".json")) {
|
|
602
645
|
existingText = existingBuf.toString("utf8");
|
|
603
|
-
const baselineKey = toBaselineKey(rel);
|
|
604
646
|
let mergedText = null;
|
|
605
|
-
if (
|
|
647
|
+
if (baselineText !== null) {
|
|
606
648
|
try {
|
|
607
|
-
const baselineText = await readBaselineText(baselineKey);
|
|
608
|
-
if (!baselineText)
|
|
609
|
-
throw new Error("missing baseline");
|
|
610
649
|
mergedText = mergeAgentJson3Way({
|
|
611
650
|
incomingText: data.toString("utf8"),
|
|
612
651
|
currentText: existingText,
|
|
@@ -617,13 +656,75 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
617
656
|
mergedText = null;
|
|
618
657
|
}
|
|
619
658
|
}
|
|
620
|
-
|
|
659
|
+
if (mergedText) {
|
|
660
|
+
mergePath = "3way";
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
mergedText = mergeAgentJsonIncomingWins(data.toString("utf8"), existingText);
|
|
664
|
+
if (mergedText) {
|
|
665
|
+
mergePath = baselineText === null ? "incomingWins" : "incomingWinsFallback";
|
|
666
|
+
}
|
|
667
|
+
}
|
|
621
668
|
if (mergedText) {
|
|
622
669
|
data = Buffer.from(mergedText, "utf8");
|
|
623
670
|
merged.push(rel);
|
|
671
|
+
mergeApplied = true;
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
mergePath = "parseFailed";
|
|
624
675
|
}
|
|
625
676
|
}
|
|
626
677
|
}
|
|
678
|
+
const hasBaseline = baselineText !== null;
|
|
679
|
+
let changedCurrentVsBaseline = null;
|
|
680
|
+
let changedIncomingVsBaseline = null;
|
|
681
|
+
if (baselineText !== null) {
|
|
682
|
+
changedCurrentVsBaseline = textChangedForType({
|
|
683
|
+
type: entry.type,
|
|
684
|
+
aText: currentTextForReview,
|
|
685
|
+
bText: baselineText,
|
|
686
|
+
});
|
|
687
|
+
changedIncomingVsBaseline = textChangedForType({
|
|
688
|
+
type: entry.type,
|
|
689
|
+
aText: incomingTextOriginal,
|
|
690
|
+
bText: baselineText,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const proposedText = data.toString("utf8");
|
|
694
|
+
const currentDiffersFromIncoming = currentTextForReview === null
|
|
695
|
+
? false
|
|
696
|
+
: textChangedForType({
|
|
697
|
+
type: entry.type,
|
|
698
|
+
aText: currentTextForReview,
|
|
699
|
+
bText: incomingTextOriginal,
|
|
700
|
+
});
|
|
701
|
+
const baselineConflict = baselineText === null
|
|
702
|
+
? false
|
|
703
|
+
: currentDiffersFromIncoming &&
|
|
704
|
+
Boolean(changedCurrentVsBaseline) &&
|
|
705
|
+
Boolean(changedIncomingVsBaseline);
|
|
706
|
+
const noBaselineConflict = baselineText === null ? currentDiffersFromIncoming : false;
|
|
707
|
+
const mergeNotAppliedConflict = mergeApplied ? false : currentDiffersFromIncoming;
|
|
708
|
+
const needsSemanticReview = baselineConflict || noBaselineConflict || mergeNotAppliedConflict;
|
|
709
|
+
reviewRecords.push({
|
|
710
|
+
relPath: rel,
|
|
711
|
+
mergeStrategy: entry.merge_strategy,
|
|
712
|
+
hasBaseline,
|
|
713
|
+
changedCurrentVsBaseline,
|
|
714
|
+
changedIncomingVsBaseline,
|
|
715
|
+
currentDiffersFromIncoming,
|
|
716
|
+
needsSemanticReview,
|
|
717
|
+
mergeApplied,
|
|
718
|
+
mergePath,
|
|
719
|
+
});
|
|
720
|
+
if (flags.mode === "agent" && needsSemanticReview) {
|
|
721
|
+
reviewSnapshots.set(rel, {
|
|
722
|
+
incomingText: incomingTextOriginal,
|
|
723
|
+
currentText: currentTextForReview,
|
|
724
|
+
baselineText,
|
|
725
|
+
proposedText,
|
|
726
|
+
});
|
|
727
|
+
}
|
|
627
728
|
fileContents.set(rel, data);
|
|
628
729
|
if (kind === null)
|
|
629
730
|
additions.push(rel);
|
|
@@ -691,7 +792,7 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
691
792
|
`- .git/**\n\n` +
|
|
692
793
|
`## Notes\n\n` +
|
|
693
794
|
`- The upgrade bundle is validated against framework.manifest.json.\n` +
|
|
694
|
-
`- AGENTS.md is
|
|
795
|
+
`- AGENTS.md is the canonical policy file at the workspace root.\n`;
|
|
695
796
|
const reportMd = `# Upgrade report (${runId})\n\n` +
|
|
696
797
|
`## Actions taken\n\n` +
|
|
697
798
|
`- [ ] Reviewed plan.md\n` +
|
|
@@ -704,48 +805,77 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
704
805
|
await writeFile(path.join(runDir, "constraints.md"), constraintsMd, "utf8");
|
|
705
806
|
await writeFile(path.join(runDir, "report.md"), reportMd, "utf8");
|
|
706
807
|
await writeFile(path.join(runDir, "files.json"), JSON.stringify({ additions, updates, skipped, merged }, null, 2) + "\n", "utf8");
|
|
707
|
-
|
|
808
|
+
const needsReview = reviewRecords.filter((r) => r.needsSemanticReview);
|
|
809
|
+
await writeFile(path.join(runDir, "review.json"), JSON.stringify({
|
|
810
|
+
generated_at: new Date().toISOString(),
|
|
811
|
+
counts: {
|
|
812
|
+
total: reviewRecords.length,
|
|
813
|
+
needsSemanticReview: needsReview.length,
|
|
814
|
+
},
|
|
815
|
+
files: reviewRecords,
|
|
816
|
+
}, null, 2) + "\n", "utf8");
|
|
817
|
+
if (needsReview.length > 0) {
|
|
818
|
+
const snapshotsRoot = path.join(runDir, "snapshots");
|
|
819
|
+
for (const [rel, snap] of reviewSnapshots.entries()) {
|
|
820
|
+
const variants = [
|
|
821
|
+
["current", snap.currentText],
|
|
822
|
+
["incoming", snap.incomingText],
|
|
823
|
+
["baseline", snap.baselineText],
|
|
824
|
+
["proposed", snap.proposedText],
|
|
825
|
+
];
|
|
826
|
+
for (const [variant, text] of variants) {
|
|
827
|
+
if (text === null)
|
|
828
|
+
continue;
|
|
829
|
+
const outPath = path.join(snapshotsRoot, variant, rel);
|
|
830
|
+
await mkdir(path.dirname(outPath), { recursive: true });
|
|
831
|
+
await writeFile(outPath, text, "utf8");
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
const relRunDir = path.relative(resolved.gitRoot, runDir);
|
|
836
|
+
process.stdout.write(`Upgrade plan written: ${relRunDir}\n`);
|
|
837
|
+
process.stdout.write(`Prompt merge required: ${needsReview.length} files\n`);
|
|
838
|
+
if (needsReview.length > 0) {
|
|
839
|
+
process.stdout.write(`Hint: Create an UPGRADER task and attach ${relRunDir}\n`);
|
|
840
|
+
}
|
|
708
841
|
return 0;
|
|
709
842
|
}
|
|
710
843
|
for (const rel of [...additions, ...updates]) {
|
|
711
844
|
const destPath = path.join(resolved.gitRoot, rel);
|
|
712
845
|
if (flags.backup && (await fileExists(destPath))) {
|
|
713
|
-
await backupPath(destPath);
|
|
846
|
+
const backup = await backupPath(destPath);
|
|
847
|
+
createdBackups.push(backup);
|
|
714
848
|
}
|
|
715
849
|
await mkdir(path.dirname(destPath), { recursive: true });
|
|
716
850
|
const data = fileContents.get(rel);
|
|
717
851
|
if (data) {
|
|
718
852
|
if (rel === "AGENTS.md") {
|
|
719
|
-
//
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
await mkdir(path.dirname(managedPath), { recursive: true });
|
|
723
|
-
await writeFile(managedPath, data);
|
|
724
|
-
// Replace AGENTS.md with a symlink if needed.
|
|
725
|
-
const relTarget = path.relative(resolved.gitRoot, managedPath);
|
|
853
|
+
// If AGENTS.md is a symlink, avoid overwriting an arbitrary external target.
|
|
854
|
+
// This permits repo-internal symlinks (e.g. the agentplane repo itself) while
|
|
855
|
+
// keeping user workspaces safe.
|
|
726
856
|
try {
|
|
727
857
|
const st = await lstat(destPath);
|
|
728
858
|
if (st.isSymbolicLink()) {
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
|
|
859
|
+
const linkTarget = await readlink(destPath);
|
|
860
|
+
const targetAbs = path.resolve(path.dirname(destPath), linkTarget);
|
|
861
|
+
const relFromRoot = path.relative(resolved.gitRoot, targetAbs);
|
|
862
|
+
if (relFromRoot.startsWith("..") || path.isAbsolute(relFromRoot)) {
|
|
863
|
+
throw new CliError({
|
|
864
|
+
exitCode: exitCodeForError("E_VALIDATION"),
|
|
865
|
+
code: "E_VALIDATION",
|
|
866
|
+
message: `Refusing to overwrite symlinked AGENTS.md target outside repo: ${linkTarget}. ` +
|
|
867
|
+
"Replace the symlink with a regular file and retry.",
|
|
868
|
+
});
|
|
732
869
|
}
|
|
733
870
|
}
|
|
734
|
-
else {
|
|
735
|
-
// If it's a regular file, remove it (backup already happened above when enabled).
|
|
736
|
-
await rm(destPath, { force: true });
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
catch {
|
|
740
|
-
// destPath doesn't exist
|
|
741
871
|
}
|
|
742
|
-
|
|
743
|
-
|
|
872
|
+
catch (err) {
|
|
873
|
+
const code = err?.code;
|
|
874
|
+
if (code !== "ENOENT")
|
|
875
|
+
throw err;
|
|
744
876
|
}
|
|
745
877
|
}
|
|
746
|
-
|
|
747
|
-
await writeFile(destPath, data);
|
|
748
|
-
}
|
|
878
|
+
await writeFile(destPath, data);
|
|
749
879
|
}
|
|
750
880
|
// Record a baseline copy for future three-way merges.
|
|
751
881
|
const baselineKey = toBaselineKey(rel);
|
|
@@ -766,6 +896,15 @@ export async function cmdUpgradeParsed(opts) {
|
|
|
766
896
|
source: bundleLayout,
|
|
767
897
|
updated: { add: additions.length, update: updates.length, unchanged: skipped.length },
|
|
768
898
|
}, null, 2) + "\n", "utf8");
|
|
899
|
+
await writeFile(path.join(upgradeStateDir, "last-review.json"), JSON.stringify({
|
|
900
|
+
generated_at: new Date().toISOString(),
|
|
901
|
+
counts: {
|
|
902
|
+
total: reviewRecords.length,
|
|
903
|
+
needsSemanticReview: reviewRecords.filter((r) => r.needsSemanticReview).length,
|
|
904
|
+
},
|
|
905
|
+
files: reviewRecords,
|
|
906
|
+
}, null, 2) + "\n", "utf8");
|
|
907
|
+
await cleanupAutoUpgradeArtifacts({ upgradeStateDir, createdBackups });
|
|
769
908
|
process.stdout.write(`Upgrade applied: ${additions.length} add, ${updates.length} update, ${skipped.length} unchanged\n`);
|
|
770
909
|
return 0;
|
|
771
910
|
}
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export type VerifyParsed = {
|
|
5
|
-
taskId: string;
|
|
6
|
-
state: VerifyState;
|
|
7
|
-
by: string;
|
|
8
|
-
note: string;
|
|
9
|
-
details?: string;
|
|
10
|
-
file?: string;
|
|
11
|
-
quiet: boolean;
|
|
12
|
-
};
|
|
13
|
-
export declare const verifySpec: CommandSpec<VerifyParsed>;
|
|
14
|
-
export declare function makeRunVerifyHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: VerifyParsed) => Promise<number>;
|
|
15
|
-
export {};
|
|
1
|
+
export { verifySpec } from "./verify.spec.js";
|
|
2
|
+
export type { VerifyParsed } from "./verify.spec.js";
|
|
3
|
+
export { makeRunVerifyHandler } from "./verify.run.js";
|
|
16
4
|
//# sourceMappingURL=verify.command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.command.d.ts","sourceRoot":"","sources":["../../src/commands/verify.command.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"verify.command.d.ts","sourceRoot":"","sources":["../../src/commands/verify.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,113 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const verifySpec = {
|
|
4
|
-
id: ["verify"],
|
|
5
|
-
group: "Lifecycle",
|
|
6
|
-
summary: "Record a verification outcome for a task (record-only; does not execute commands).",
|
|
7
|
-
args: [
|
|
8
|
-
{
|
|
9
|
-
name: "task-id",
|
|
10
|
-
required: true,
|
|
11
|
-
valueHint: "<task-id>",
|
|
12
|
-
description: "Existing task id.",
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
options: [
|
|
16
|
-
{
|
|
17
|
-
kind: "boolean",
|
|
18
|
-
name: "ok",
|
|
19
|
-
default: false,
|
|
20
|
-
description: "Record an OK verification outcome.",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
kind: "boolean",
|
|
24
|
-
name: "rework",
|
|
25
|
-
default: false,
|
|
26
|
-
description: "Record a needs-rework verification outcome.",
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
kind: "string",
|
|
30
|
-
name: "by",
|
|
31
|
-
valueHint: "<id>",
|
|
32
|
-
required: true,
|
|
33
|
-
description: "Verifier id (e.g. REVIEWER).",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
kind: "string",
|
|
37
|
-
name: "note",
|
|
38
|
-
valueHint: "<text>",
|
|
39
|
-
required: true,
|
|
40
|
-
description: "Short note describing the verification outcome.",
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
kind: "string",
|
|
44
|
-
name: "details",
|
|
45
|
-
valueHint: "<text>",
|
|
46
|
-
description: "Optional free-form details (mutually exclusive with --file).",
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
kind: "string",
|
|
50
|
-
name: "file",
|
|
51
|
-
valueHint: "<path>",
|
|
52
|
-
description: "Read details from a file path (mutually exclusive with --details).",
|
|
53
|
-
},
|
|
54
|
-
{ kind: "boolean", name: "quiet", default: false, description: "Suppress output." },
|
|
55
|
-
],
|
|
56
|
-
examples: [
|
|
57
|
-
{
|
|
58
|
-
cmd: 'agentplane verify 202602030608-F1Q8AB --ok --by REVIEWER --note "Looks good" --quiet',
|
|
59
|
-
why: "Record an OK verification outcome.",
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
cmd: 'agentplane verify 202602030608-F1Q8AB --rework --by REVIEWER --note "Needs changes" --details "Missing tests"',
|
|
63
|
-
why: "Record a needs-rework outcome with details.",
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
validateRaw: (raw) => {
|
|
67
|
-
const ok = raw.opts.ok === true;
|
|
68
|
-
const rework = raw.opts.rework === true;
|
|
69
|
-
if (ok === rework) {
|
|
70
|
-
throw usageError({
|
|
71
|
-
spec: verifySpec,
|
|
72
|
-
command: "verify",
|
|
73
|
-
message: "Exactly one of --ok or --rework must be provided.",
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
if (typeof raw.opts.details === "string" && typeof raw.opts.file === "string") {
|
|
77
|
-
throw usageError({
|
|
78
|
-
spec: verifySpec,
|
|
79
|
-
command: "verify",
|
|
80
|
-
message: "Options --details and --file are mutually exclusive.",
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
parse: (raw) => {
|
|
85
|
-
const ok = raw.opts.ok === true;
|
|
86
|
-
const state = ok ? "ok" : "needs_rework";
|
|
87
|
-
return {
|
|
88
|
-
taskId: typeof raw.args["task-id"] === "string" ? raw.args["task-id"] : "",
|
|
89
|
-
state,
|
|
90
|
-
by: raw.opts.by,
|
|
91
|
-
note: raw.opts.note,
|
|
92
|
-
details: raw.opts.details,
|
|
93
|
-
file: raw.opts.file,
|
|
94
|
-
quiet: raw.opts.quiet === true,
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
export function makeRunVerifyHandler(getCtx) {
|
|
99
|
-
return async (ctx, p) => {
|
|
100
|
-
return await cmdVerifyParsed({
|
|
101
|
-
ctx: await getCtx("verify"),
|
|
102
|
-
cwd: ctx.cwd,
|
|
103
|
-
rootOverride: ctx.rootOverride,
|
|
104
|
-
taskId: p.taskId,
|
|
105
|
-
state: p.state,
|
|
106
|
-
by: p.by,
|
|
107
|
-
note: p.note,
|
|
108
|
-
details: p.details,
|
|
109
|
-
file: p.file,
|
|
110
|
-
quiet: p.quiet,
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
}
|
|
1
|
+
export { verifySpec } from "./verify.spec.js";
|
|
2
|
+
export { makeRunVerifyHandler } from "./verify.run.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CommandCtx } from "../cli/spec/spec.js";
|
|
2
|
+
import type { CommandContext } from "./shared/task-backend.js";
|
|
3
|
+
import type { VerifyParsed } from "./verify.spec.js";
|
|
4
|
+
export declare function makeRunVerifyHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: VerifyParsed) => Promise<number>;
|
|
5
|
+
//# sourceMappingURL=verify.run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.run.d.ts","sourceRoot":"","sources":["../../src/commands/verify.run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAcjE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { cmdVerifyParsed } from "./task/verify-record.js";
|
|
2
|
+
export function makeRunVerifyHandler(getCtx) {
|
|
3
|
+
return async (ctx, p) => {
|
|
4
|
+
return await cmdVerifyParsed({
|
|
5
|
+
ctx: await getCtx("verify"),
|
|
6
|
+
cwd: ctx.cwd,
|
|
7
|
+
rootOverride: ctx.rootOverride,
|
|
8
|
+
taskId: p.taskId,
|
|
9
|
+
state: p.state,
|
|
10
|
+
by: p.by,
|
|
11
|
+
note: p.note,
|
|
12
|
+
details: p.details,
|
|
13
|
+
file: p.file,
|
|
14
|
+
quiet: p.quiet,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CommandSpec } from "../cli/spec/spec.js";
|
|
2
|
+
type VerifyState = "ok" | "needs_rework";
|
|
3
|
+
export type VerifyParsed = {
|
|
4
|
+
taskId: string;
|
|
5
|
+
state: VerifyState;
|
|
6
|
+
by: string;
|
|
7
|
+
note: string;
|
|
8
|
+
details?: string;
|
|
9
|
+
file?: string;
|
|
10
|
+
quiet: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare const verifySpec: CommandSpec<VerifyParsed>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=verify.spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.spec.d.ts","sourceRoot":"","sources":["../../src/commands/verify.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,KAAK,WAAW,GAAG,IAAI,GAAG,cAAc,CAAC;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA8FhD,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { usageError } from "../cli/spec/errors.js";
|
|
2
|
+
export const verifySpec = {
|
|
3
|
+
id: ["verify"],
|
|
4
|
+
group: "Lifecycle",
|
|
5
|
+
summary: "Record a verification outcome for a task (record-only; does not execute commands).",
|
|
6
|
+
args: [
|
|
7
|
+
{
|
|
8
|
+
name: "task-id",
|
|
9
|
+
required: true,
|
|
10
|
+
valueHint: "<task-id>",
|
|
11
|
+
description: "Existing task id.",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
options: [
|
|
15
|
+
{
|
|
16
|
+
kind: "boolean",
|
|
17
|
+
name: "ok",
|
|
18
|
+
default: false,
|
|
19
|
+
description: "Record an OK verification outcome.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
kind: "boolean",
|
|
23
|
+
name: "rework",
|
|
24
|
+
default: false,
|
|
25
|
+
description: "Record a needs-rework verification outcome.",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
kind: "string",
|
|
29
|
+
name: "by",
|
|
30
|
+
valueHint: "<id>",
|
|
31
|
+
required: true,
|
|
32
|
+
description: "Verifier id (e.g. REVIEWER).",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
kind: "string",
|
|
36
|
+
name: "note",
|
|
37
|
+
valueHint: "<text>",
|
|
38
|
+
required: true,
|
|
39
|
+
description: "Short note describing the verification outcome.",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
kind: "string",
|
|
43
|
+
name: "details",
|
|
44
|
+
valueHint: "<text>",
|
|
45
|
+
description: "Optional free-form details (mutually exclusive with --file).",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
kind: "string",
|
|
49
|
+
name: "file",
|
|
50
|
+
valueHint: "<path>",
|
|
51
|
+
description: "Read details from a file path (mutually exclusive with --details).",
|
|
52
|
+
},
|
|
53
|
+
{ kind: "boolean", name: "quiet", default: false, description: "Suppress output." },
|
|
54
|
+
],
|
|
55
|
+
examples: [
|
|
56
|
+
{
|
|
57
|
+
cmd: 'agentplane verify 202602030608-F1Q8AB --ok --by REVIEWER --note "Looks good" --quiet',
|
|
58
|
+
why: "Record an OK verification outcome.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
cmd: 'agentplane verify 202602030608-F1Q8AB --rework --by REVIEWER --note "Needs changes" --details "Missing tests"',
|
|
62
|
+
why: "Record a needs-rework outcome with details.",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
validateRaw: (raw) => {
|
|
66
|
+
const ok = raw.opts.ok === true;
|
|
67
|
+
const rework = raw.opts.rework === true;
|
|
68
|
+
if (ok === rework) {
|
|
69
|
+
throw usageError({
|
|
70
|
+
spec: verifySpec,
|
|
71
|
+
command: "verify",
|
|
72
|
+
message: "Exactly one of --ok or --rework must be provided.",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (typeof raw.opts.details === "string" && typeof raw.opts.file === "string") {
|
|
76
|
+
throw usageError({
|
|
77
|
+
spec: verifySpec,
|
|
78
|
+
command: "verify",
|
|
79
|
+
message: "Options --details and --file are mutually exclusive.",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
parse: (raw) => {
|
|
84
|
+
const ok = raw.opts.ok === true;
|
|
85
|
+
const state = ok ? "ok" : "needs_rework";
|
|
86
|
+
return {
|
|
87
|
+
taskId: typeof raw.args["task-id"] === "string" ? raw.args["task-id"] : "",
|
|
88
|
+
state,
|
|
89
|
+
by: raw.opts.by,
|
|
90
|
+
note: raw.opts.note,
|
|
91
|
+
details: raw.opts.details,
|
|
92
|
+
file: raw.opts.file,
|
|
93
|
+
quiet: raw.opts.quiet === true,
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
};
|