agentplane 0.3.10 → 0.3.12
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/assets/AGENTS.md +2 -2
- package/assets/agents/CODER.json +4 -0
- package/assets/agents/CREATOR.json +1 -0
- package/assets/agents/DOCS.json +2 -1
- package/assets/agents/INTEGRATOR.json +2 -1
- package/assets/agents/ORCHESTRATOR.json +2 -0
- package/assets/agents/PLANNER.json +3 -1
- package/assets/agents/REVIEWER.json +1 -0
- package/assets/agents/TESTER.json +2 -2
- package/assets/agents/UPDATER.json +1 -0
- package/assets/agents/UPGRADER.json +1 -1
- package/assets/policy/governance.md +3 -4
- package/assets/policy/incidents.md +20 -88
- package/assets/policy/workflow.branch_pr.md +1 -1
- package/assets/policy/workflow.direct.md +2 -2
- package/bin/agentplane.js +114 -4
- package/bin/runtime-watch.js +1 -0
- package/bin/stale-dist-policy.d.ts +1 -1
- package/bin/stale-dist-policy.js +19 -1
- package/dist/.build-manifest.json +251 -166
- package/dist/cli/bootstrap-guide.d.ts.map +1 -1
- package/dist/cli/bootstrap-guide.js +3 -2
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +2 -1
- package/dist/cli/command-invocations.d.ts.map +1 -1
- package/dist/cli/command-invocations.js +4 -1
- package/dist/cli/run-cli/command-catalog/core.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/core.js +6 -1
- package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/project.js +3 -1
- package/dist/cli/run-cli/command-catalog/task.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/task.js +10 -0
- 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/commands/core/preflight.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core/preflight.js +44 -1
- package/dist/cli/run-cli.test-helpers.d.ts +1 -0
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +26 -0
- package/dist/commands/branch/cleanup-merged.d.ts +3 -0
- package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
- package/dist/commands/branch/cleanup-merged.js +149 -36
- package/dist/commands/branch/work-start.d.ts.map +1 -1
- package/dist/commands/branch/work-start.js +137 -1
- package/dist/commands/cleanup/merged.command.d.ts +2 -0
- package/dist/commands/cleanup/merged.command.d.ts.map +1 -1
- package/dist/commands/cleanup/merged.command.js +24 -0
- package/dist/commands/doctor/branch-pr.d.ts +4 -0
- package/dist/commands/doctor/branch-pr.d.ts.map +1 -0
- package/dist/commands/doctor/branch-pr.js +96 -0
- package/dist/commands/doctor/fixes.d.ts +5 -0
- package/dist/commands/doctor/fixes.d.ts.map +1 -1
- package/dist/commands/doctor/fixes.js +70 -0
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +6 -1
- package/dist/commands/finish.run.d.ts.map +1 -1
- package/dist/commands/finish.run.js +11 -0
- package/dist/commands/finish.spec.d.ts +11 -0
- package/dist/commands/finish.spec.d.ts.map +1 -1
- package/dist/commands/finish.spec.js +51 -0
- package/dist/commands/guard/impl/close-message.d.ts.map +1 -1
- package/dist/commands/guard/impl/close-message.js +23 -6
- package/dist/commands/guard/impl/commands.d.ts +1 -0
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +94 -2
- package/dist/commands/guard/impl/env.d.ts +1 -0
- package/dist/commands/guard/impl/env.d.ts.map +1 -1
- package/dist/commands/guard/impl/env.js +1 -0
- package/dist/commands/hooks/index.d.ts +1 -1
- package/dist/commands/hooks/index.d.ts.map +1 -1
- package/dist/commands/hooks/index.js +139 -6
- package/dist/commands/incidents/collect.command.d.ts.map +1 -1
- package/dist/commands/incidents/collect.command.js +12 -7
- package/dist/commands/incidents/incidents.command.js +1 -1
- package/dist/commands/incidents/shared.d.ts +34 -0
- package/dist/commands/incidents/shared.d.ts.map +1 -1
- package/dist/commands/incidents/shared.js +166 -12
- package/dist/commands/pr/check.d.ts.map +1 -1
- package/dist/commands/pr/check.js +241 -135
- package/dist/commands/pr/close-superseded.d.ts +9 -0
- package/dist/commands/pr/close-superseded.d.ts.map +1 -0
- package/dist/commands/pr/close-superseded.js +129 -0
- package/dist/commands/pr/close.d.ts +11 -0
- package/dist/commands/pr/close.d.ts.map +1 -0
- package/dist/commands/pr/close.js +116 -0
- package/dist/commands/pr/index.d.ts +2 -0
- package/dist/commands/pr/index.d.ts.map +1 -1
- package/dist/commands/pr/index.js +2 -0
- package/dist/commands/pr/integrate/artifacts.d.ts +7 -0
- package/dist/commands/pr/integrate/artifacts.d.ts.map +1 -1
- package/dist/commands/pr/integrate/artifacts.js +66 -1
- package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
- package/dist/commands/pr/integrate/cmd.js +43 -2
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts +8 -0
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.js +59 -0
- package/dist/commands/pr/integrate/internal/cleanup.d.ts +1 -11
- package/dist/commands/pr/integrate/internal/cleanup.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/cleanup.js +1 -46
- package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/finalize.js +43 -12
- package/dist/commands/pr/integrate/internal/github-protection.d.ts +5 -0
- package/dist/commands/pr/integrate/internal/github-protection.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/github-protection.js +13 -0
- package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/merge.js +36 -13
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts +13 -0
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.js +25 -0
- package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts +15 -0
- package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.js +35 -0
- package/dist/commands/pr/integrate/internal/prepare.d.ts +4 -2
- package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/prepare.js +109 -38
- package/dist/commands/pr/internal/auto-commit.d.ts +7 -0
- package/dist/commands/pr/internal/auto-commit.d.ts.map +1 -0
- package/dist/commands/pr/internal/auto-commit.js +64 -0
- package/dist/commands/pr/internal/freshness.d.ts +21 -0
- package/dist/commands/pr/internal/freshness.d.ts.map +1 -0
- package/dist/commands/pr/internal/freshness.js +52 -0
- package/dist/commands/pr/internal/gh-api.d.ts +6 -0
- package/dist/commands/pr/internal/gh-api.d.ts.map +1 -0
- package/dist/commands/pr/internal/gh-api.js +80 -0
- package/dist/commands/pr/internal/pr-paths.d.ts +10 -0
- package/dist/commands/pr/internal/pr-paths.d.ts.map +1 -1
- package/dist/commands/pr/internal/pr-paths.js +10 -0
- package/dist/commands/pr/internal/review-template.d.ts.map +1 -1
- package/dist/commands/pr/internal/review-template.js +37 -4
- package/dist/commands/pr/internal/sync.d.ts +9 -0
- package/dist/commands/pr/internal/sync.d.ts.map +1 -1
- package/dist/commands/pr/internal/sync.js +531 -124
- package/dist/commands/pr/open.d.ts +1 -0
- package/dist/commands/pr/open.d.ts.map +1 -1
- package/dist/commands/pr/open.js +24 -2
- package/dist/commands/pr/pr.command.d.ts +15 -0
- package/dist/commands/pr/pr.command.d.ts.map +1 -1
- package/dist/commands/pr/pr.command.js +118 -2
- package/dist/commands/pr/update.d.ts.map +1 -1
- package/dist/commands/pr/update.js +71 -2
- package/dist/commands/release/apply.command.d.ts +3 -1
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +356 -34
- package/dist/commands/release/apply.mutation.d.ts.map +1 -1
- package/dist/commands/release/apply.mutation.js +1 -0
- package/dist/commands/release/apply.preflight.d.ts.map +1 -1
- package/dist/commands/release/apply.preflight.js +1 -1
- package/dist/commands/release/apply.reporting.d.ts +1 -0
- package/dist/commands/release/apply.reporting.d.ts.map +1 -1
- package/dist/commands/release/apply.reporting.js +12 -8
- package/dist/commands/release/apply.types.d.ts +13 -0
- package/dist/commands/release/apply.types.d.ts.map +1 -1
- package/dist/commands/release/plan.command.d.ts.map +1 -1
- package/dist/commands/release/plan.command.js +48 -0
- package/dist/commands/shared/gh-transport.d.ts +16 -0
- package/dist/commands/shared/gh-transport.d.ts.map +1 -0
- package/dist/commands/shared/gh-transport.js +71 -0
- package/dist/commands/shared/git-diff.d.ts +3 -1
- package/dist/commands/shared/git-diff.d.ts.map +1 -1
- package/dist/commands/shared/git-diff.js +10 -2
- package/dist/commands/shared/git-ops.d.ts +1 -0
- package/dist/commands/shared/git-ops.d.ts.map +1 -1
- package/dist/commands/shared/git-ops.js +15 -0
- package/dist/commands/shared/git-worktree.d.ts +2 -0
- package/dist/commands/shared/git-worktree.d.ts.map +1 -1
- package/dist/commands/shared/git-worktree.js +22 -2
- package/dist/commands/shared/merged-branch-cleanup.d.ts +12 -0
- package/dist/commands/shared/merged-branch-cleanup.d.ts.map +1 -0
- package/dist/commands/shared/merged-branch-cleanup.js +46 -0
- package/dist/commands/shared/post-commit-pr-artifacts.d.ts +9 -0
- package/dist/commands/shared/post-commit-pr-artifacts.d.ts.map +1 -0
- package/dist/commands/shared/post-commit-pr-artifacts.js +57 -0
- package/dist/commands/shared/pr-meta.d.ts +20 -0
- package/dist/commands/shared/pr-meta.d.ts.map +1 -1
- package/dist/commands/shared/pr-meta.js +125 -0
- package/dist/commands/shared/task-backend.d.ts +7 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/shared/task-backend.js +71 -27
- package/dist/commands/shared/task-local-freshness.d.ts +2 -0
- package/dist/commands/shared/task-local-freshness.d.ts.map +1 -1
- package/dist/commands/shared/task-local-freshness.js +7 -1
- package/dist/commands/task/close-duplicate.d.ts.map +1 -1
- package/dist/commands/task/close-duplicate.js +34 -1
- package/dist/commands/task/derive.js +1 -1
- package/dist/commands/task/doc-template.d.ts.map +1 -1
- package/dist/commands/task/doc-template.js +7 -11
- package/dist/commands/task/findings-add.command.d.ts +20 -0
- package/dist/commands/task/findings-add.command.d.ts.map +1 -0
- package/dist/commands/task/findings-add.command.js +165 -0
- package/dist/commands/task/findings.command.d.ts +7 -0
- package/dist/commands/task/findings.command.d.ts.map +1 -0
- package/dist/commands/task/findings.command.js +20 -0
- package/dist/commands/task/findings.d.ts +63 -0
- package/dist/commands/task/findings.d.ts.map +1 -0
- package/dist/commands/task/findings.js +188 -0
- package/dist/commands/task/finish-shared.d.ts +2 -0
- package/dist/commands/task/finish-shared.d.ts.map +1 -1
- package/dist/commands/task/finish-shared.js +56 -1
- package/dist/commands/task/finish.d.ts +10 -0
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +125 -6
- package/dist/commands/task/hosted-close-pr.command.d.ts +11 -0
- package/dist/commands/task/hosted-close-pr.command.d.ts.map +1 -0
- package/dist/commands/task/hosted-close-pr.command.js +449 -0
- package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
- package/dist/commands/task/hosted-close.command.js +234 -19
- package/dist/commands/task/hosted-merge-sync.d.ts +41 -0
- package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
- package/dist/commands/task/hosted-merge-sync.js +291 -17
- package/dist/commands/task/index.d.ts +1 -0
- package/dist/commands/task/index.d.ts.map +1 -1
- package/dist/commands/task/index.js +1 -0
- package/dist/commands/task/new.d.ts +1 -0
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +71 -1
- package/dist/commands/task/new.spec.d.ts.map +1 -1
- package/dist/commands/task/new.spec.js +7 -0
- package/dist/commands/task/normalize.command.d.ts +2 -0
- package/dist/commands/task/normalize.command.d.ts.map +1 -1
- package/dist/commands/task/normalize.command.js +45 -0
- package/dist/commands/task/normalize.d.ts +2 -0
- package/dist/commands/task/normalize.d.ts.map +1 -1
- package/dist/commands/task/normalize.js +85 -8
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +7 -10
- package/dist/commands/task/shared/docs.d.ts +6 -0
- package/dist/commands/task/shared/docs.d.ts.map +1 -1
- package/dist/commands/task/shared/docs.js +14 -0
- package/dist/commands/task/shared/transitions.d.ts.map +1 -1
- package/dist/commands/task/shared/transitions.js +11 -1
- package/dist/commands/task/shared.d.ts +1 -1
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +1 -1
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +7 -10
- package/dist/commands/task/task.command.d.ts.map +1 -1
- package/dist/commands/task/task.command.js +4 -0
- package/dist/commands/task/verify-command-shared.d.ts +19 -0
- package/dist/commands/task/verify-command-shared.d.ts.map +1 -1
- package/dist/commands/task/verify-command-shared.js +152 -1
- package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
- package/dist/commands/task/verify-ok.command.js +15 -2
- package/dist/commands/task/verify-record.d.ts +36 -0
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +166 -11
- package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
- package/dist/commands/task/verify-rework.command.js +15 -2
- package/dist/commands/task/verify-show.command.d.ts +1 -1
- package/dist/commands/task/verify-show.command.d.ts.map +1 -1
- package/dist/commands/task/verify-show.command.js +28 -1
- package/dist/commands/verify.run.d.ts.map +1 -1
- package/dist/commands/verify.run.js +12 -0
- package/dist/commands/verify.spec.d.ts +2 -6
- package/dist/commands/verify.spec.d.ts.map +1 -1
- package/dist/commands/verify.spec.js +30 -3
- package/dist/runtime/incidents/index.d.ts +1 -1
- package/dist/runtime/incidents/index.d.ts.map +1 -1
- package/dist/runtime/incidents/resolve.d.ts.map +1 -1
- package/dist/runtime/incidents/resolve.js +319 -73
- package/dist/runtime/incidents/types.d.ts +14 -2
- package/dist/runtime/incidents/types.d.ts.map +1 -1
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.d.ts.map +1 -1
- package/dist/shared/env.js +22 -1
- package/dist/shared/protected-paths.d.ts +1 -1
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +4 -0
- package/package.json +2 -2
|
@@ -5,6 +5,8 @@ import { writeTextIfChanged } from "../../shared/write-if-changed.js";
|
|
|
5
5
|
import { appendIncidentRegistryEntries, buildIncidentAdviceQueryFromTask, createIncidentRegistrySkeleton, parseIncidentRegistry, planIncidentCollection, resolveIncidentAdviceMatches, } from "../../runtime/incidents/index.js";
|
|
6
6
|
import { extractDocSection, extractTaskObservationSection, normalizeTaskDocVersion, } from "../task/shared.js";
|
|
7
7
|
export const INCIDENTS_POLICY_PATH = ".agentplane/policy/incidents.md";
|
|
8
|
+
export const INCIDENTS_POLICY_ASSET_PATH = "packages/agentplane/assets/policy/incidents.md";
|
|
9
|
+
const INCIDENTS_POLICY_LINE_BUDGET = 100;
|
|
8
10
|
async function readTextIfExists(filePath) {
|
|
9
11
|
try {
|
|
10
12
|
return await readFile(filePath, "utf8");
|
|
@@ -19,6 +21,41 @@ async function readTextIfExists(filePath) {
|
|
|
19
21
|
export function incidentRegistryPath(ctx) {
|
|
20
22
|
return path.join(ctx.resolvedProject.gitRoot, INCIDENTS_POLICY_PATH);
|
|
21
23
|
}
|
|
24
|
+
export function incidentRegistryAssetPath(ctx) {
|
|
25
|
+
return path.join(ctx.resolvedProject.gitRoot, INCIDENTS_POLICY_ASSET_PATH);
|
|
26
|
+
}
|
|
27
|
+
function normalizeIncidentRegistryDocument(text) {
|
|
28
|
+
const normalized = text.replaceAll("\r\n", "\n").trimEnd();
|
|
29
|
+
return normalized.length > 0 ? `${normalized}\n` : createIncidentRegistrySkeleton();
|
|
30
|
+
}
|
|
31
|
+
async function writeIncidentRegistryMirrors(ctx, content) {
|
|
32
|
+
const registryPath = incidentRegistryPath(ctx);
|
|
33
|
+
const assetPath = incidentRegistryAssetPath(ctx);
|
|
34
|
+
const assetExists = (await readTextIfExists(assetPath)) !== null;
|
|
35
|
+
const normalizedContent = normalizeIncidentRegistryDocument(content);
|
|
36
|
+
let wroteRegistry = await writeTextIfChanged(registryPath, normalizedContent);
|
|
37
|
+
let wroteAsset = false;
|
|
38
|
+
if (assetExists) {
|
|
39
|
+
const canonicalText = (await readTextIfExists(registryPath)) ?? normalizedContent;
|
|
40
|
+
wroteAsset = await writeTextIfChanged(assetPath, canonicalText);
|
|
41
|
+
const registryText = await readTextIfExists(registryPath);
|
|
42
|
+
if (registryText !== canonicalText) {
|
|
43
|
+
wroteRegistry = (await writeTextIfChanged(registryPath, canonicalText)) || wroteRegistry;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return wroteRegistry || wroteAsset;
|
|
47
|
+
}
|
|
48
|
+
async function resolveIncidentRegistryMirrorPaths(ctx) {
|
|
49
|
+
const paths = [INCIDENTS_POLICY_PATH];
|
|
50
|
+
const assetPath = incidentRegistryAssetPath(ctx);
|
|
51
|
+
if ((await readTextIfExists(assetPath)) !== null) {
|
|
52
|
+
paths.push(INCIDENTS_POLICY_ASSET_PATH);
|
|
53
|
+
}
|
|
54
|
+
return paths;
|
|
55
|
+
}
|
|
56
|
+
function countTextLines(text) {
|
|
57
|
+
return text.replaceAll("\r\n", "\n").split("\n").length;
|
|
58
|
+
}
|
|
22
59
|
export async function loadIncidentRegistry(ctx) {
|
|
23
60
|
const registryPath = incidentRegistryPath(ctx);
|
|
24
61
|
const registryText = (await readTextIfExists(registryPath)) ?? createIncidentRegistrySkeleton();
|
|
@@ -60,19 +97,48 @@ export function formatIncidentCollectionIssues(taskId, plan) {
|
|
|
60
97
|
return `line ${issue.candidate.line}: ${scope} -> missing ${issue.missingFields.join(", ")}`;
|
|
61
98
|
});
|
|
62
99
|
return [
|
|
63
|
-
`${taskId}:
|
|
100
|
+
`${taskId}: reusable external findings need explicit external marking and enough recovery detail before promotion.`,
|
|
64
101
|
"Required fields:",
|
|
65
102
|
...issueLines.map((line) => `- ${line}`),
|
|
66
103
|
].join("\n");
|
|
67
104
|
}
|
|
68
105
|
export async function collectTaskIncidents(opts) {
|
|
106
|
+
const inspected = await inspectTaskIncidents(opts);
|
|
107
|
+
const { loaded, registryPath, registryPaths, registryText, registry, plan } = inspected;
|
|
108
|
+
if (plan.issues.length > 0) {
|
|
109
|
+
throw new CliError({
|
|
110
|
+
exitCode: 3,
|
|
111
|
+
code: "E_VALIDATION",
|
|
112
|
+
message: formatIncidentCollectionIssues(opts.taskId, plan),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const nextText = appendIncidentRegistryEntries(registryText, plan.promotable.map((item) => item.entry));
|
|
116
|
+
if (plan.promotable.length > 0) {
|
|
117
|
+
const nextLineCount = countTextLines(nextText);
|
|
118
|
+
if (nextLineCount > INCIDENTS_POLICY_LINE_BUDGET) {
|
|
119
|
+
throw new CliError({
|
|
120
|
+
exitCode: 3,
|
|
121
|
+
code: "E_VALIDATION",
|
|
122
|
+
message: `Incident registry write would exceed policy budget: ${nextLineCount} lines ` +
|
|
123
|
+
`(limit ${INCIDENTS_POLICY_LINE_BUDGET}). Compact or promote fewer entries before writing.`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const wrote = opts.write && plan.promotable.length > 0
|
|
128
|
+
? await writeIncidentRegistryMirrors(opts.ctx, nextText)
|
|
129
|
+
: false;
|
|
130
|
+
return { loaded, registryPath, registryPaths, registryText, registry, plan, wrote };
|
|
131
|
+
}
|
|
132
|
+
export async function inspectTaskIncidents(opts) {
|
|
69
133
|
const loaded = await loadTaskIncidents(opts.ctx, opts.taskId, opts.task ?? null);
|
|
70
134
|
const { registryPath, registryText, registry } = await loadIncidentRegistry(opts.ctx);
|
|
135
|
+
const registryPaths = await resolveIncidentRegistryMirrorPaths(opts.ctx);
|
|
71
136
|
const plan = planIncidentCollection({
|
|
72
137
|
task: {
|
|
73
138
|
id: loaded.task.id,
|
|
74
139
|
title: loaded.task.title,
|
|
75
140
|
description: loaded.task.description,
|
|
141
|
+
scope: loaded.scope,
|
|
76
142
|
tags: loaded.task.tags ?? [],
|
|
77
143
|
commitHash: loaded.task.commit?.hash ?? null,
|
|
78
144
|
},
|
|
@@ -80,18 +146,106 @@ export async function collectTaskIncidents(opts) {
|
|
|
80
146
|
registry,
|
|
81
147
|
now: opts.now,
|
|
82
148
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
149
|
+
return { loaded, registryPath, registryPaths, registryText, registry, plan };
|
|
150
|
+
}
|
|
151
|
+
export function renderIncidentCollectionOutcome(promotedCount) {
|
|
152
|
+
return promotedCount > 0
|
|
153
|
+
? `incident registry updated (${promotedCount} promoted)`
|
|
154
|
+
: "incident registry unchanged (no promotable external findings)";
|
|
155
|
+
}
|
|
156
|
+
function summarizeDetailList(values, maxItems = 3) {
|
|
157
|
+
const filtered = values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
158
|
+
if (filtered.length === 0)
|
|
159
|
+
return null;
|
|
160
|
+
if (filtered.length <= maxItems)
|
|
161
|
+
return filtered.join(", ");
|
|
162
|
+
return `${filtered.slice(0, maxItems).join(", ")}, +${filtered.length - maxItems} more`;
|
|
163
|
+
}
|
|
164
|
+
export function renderIncidentCollectionPlanOutcome(plan, opts) {
|
|
165
|
+
const candidates = Array.isArray(plan.candidates) ? plan.candidates.length : 0;
|
|
166
|
+
const skipped = Array.isArray(plan.skipped) ? plan.skipped.length : 0;
|
|
167
|
+
const promoted = Array.isArray(plan.promotable) ? plan.promotable.length : 0;
|
|
168
|
+
const duplicates = Array.isArray(plan.duplicates) ? plan.duplicates.length : 0;
|
|
169
|
+
const issues = Array.isArray(plan.issues) ? plan.issues.length : 0;
|
|
170
|
+
const findingsTextPresent = plan.findingsTextPresent === true;
|
|
171
|
+
const structuredFindingCount = typeof plan.structuredFindingCount === "number" ? plan.structuredFindingCount : 0;
|
|
172
|
+
const wrote = opts?.wrote === true;
|
|
173
|
+
const context = opts?.context ?? "generic";
|
|
174
|
+
const taskId = typeof opts?.taskId === "string" && opts.taskId.trim().length > 0 ? opts.taskId.trim() : null;
|
|
175
|
+
const findingsNextStep = taskId
|
|
176
|
+
? ` next: agentplane task findings add ${taskId} --observation "<observation>" --impact "<impact>" --resolution "<resolution>"`
|
|
177
|
+
: "";
|
|
178
|
+
if (promoted > 0 && wrote) {
|
|
179
|
+
const suffix = [];
|
|
180
|
+
if (duplicates > 0)
|
|
181
|
+
suffix.push(`${duplicates} duplicate${duplicates === 1 ? "" : "s"}`);
|
|
182
|
+
if (skipped > 0)
|
|
183
|
+
suffix.push(`${skipped} skipped structured finding${skipped === 1 ? "" : "s"}`);
|
|
184
|
+
const base = suffix.length > 0
|
|
185
|
+
? `incident registry updated (${promoted} promoted; ${suffix.join("; ")})`
|
|
186
|
+
: renderIncidentCollectionOutcome(promoted);
|
|
187
|
+
const details = [];
|
|
188
|
+
const promotedIds = Array.isArray(opts?.promotedIds)
|
|
189
|
+
? opts.promotedIds.filter((id) => typeof id === "string" && id.trim().length > 0)
|
|
190
|
+
: [];
|
|
191
|
+
const registryPaths = Array.isArray(opts?.registryPaths)
|
|
192
|
+
? opts.registryPaths.filter((filePath) => typeof filePath === "string" && filePath.trim().length > 0)
|
|
193
|
+
: [];
|
|
194
|
+
const idsSummary = summarizeDetailList(promotedIds);
|
|
195
|
+
const pathsSummary = summarizeDetailList(registryPaths);
|
|
196
|
+
if (idsSummary)
|
|
197
|
+
details.push(`ids=${idsSummary}`);
|
|
198
|
+
if (pathsSummary)
|
|
199
|
+
details.push(`files=${pathsSummary}`);
|
|
200
|
+
return details.length > 0 ? `${base} ${details.join(" ")}` : base;
|
|
89
201
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
202
|
+
if (promoted > 0 && !wrote) {
|
|
203
|
+
if (context === "collect") {
|
|
204
|
+
return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} validated; rerun without --check to update incidents.md)`;
|
|
205
|
+
}
|
|
206
|
+
if (context === "verify") {
|
|
207
|
+
return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} stayed task-local in the current task worktree; run verify --collect-incidents, agentplane incidents collect <task-id>, or finish on the base branch to update incidents.md)`;
|
|
208
|
+
}
|
|
209
|
+
return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} pending promotion)`;
|
|
210
|
+
}
|
|
211
|
+
if (issues > 0) {
|
|
212
|
+
const issueEntries = Array.isArray(plan.issues)
|
|
213
|
+
? plan.issues
|
|
214
|
+
: [];
|
|
215
|
+
const firstIssue = issueEntries[0];
|
|
216
|
+
const rawMissingFields = firstIssue?.missingFields;
|
|
217
|
+
const missingFields = Array.isArray(rawMissingFields)
|
|
218
|
+
? rawMissingFields.filter((field) => typeof field === "string" && field.trim().length > 0)
|
|
219
|
+
: [];
|
|
220
|
+
const detail = missingFields.length > 0
|
|
221
|
+
? ` missing required fields: ${missingFields.join(", ")}`
|
|
222
|
+
: " missing required promotion fields";
|
|
223
|
+
const suffix = issues > 1 ? `; +${issues - 1} more candidate${issues - 1 === 1 ? "" : "s"}` : "";
|
|
224
|
+
return `incident registry unchanged (${issues} structured finding candidate${issues === 1 ? "" : "s"} still invalid;${detail}${suffix})`;
|
|
225
|
+
}
|
|
226
|
+
if (skipped > 0) {
|
|
227
|
+
return `incident registry unchanged (${skipped} structured finding${skipped === 1 ? "" : "s"} stayed task-local in the current checkout: mark reusable external findings with Promotion: incident-candidate plus Fixability: external, or use task findings add without --local-only)`;
|
|
228
|
+
}
|
|
229
|
+
if (candidates === 0 && structuredFindingCount === 0 && findingsTextPresent) {
|
|
230
|
+
return "incident registry unchanged (plain Findings text stays task-local in the current checkout and does not update incidents.md: add a structured Observation/Impact/Resolution block for reusable external incidents, or use task findings add without --local-only)";
|
|
231
|
+
}
|
|
232
|
+
if (candidates === 0) {
|
|
233
|
+
if (context === "verify") {
|
|
234
|
+
return ("incident registry unchanged (plain verify note stayed task-local and did not update " +
|
|
235
|
+
"incidents.md: add --observation, --impact, and --resolution for a reusable incident, " +
|
|
236
|
+
`then rerun with --collect-incidents or collect later on the base branch.${findingsNextStep})`);
|
|
237
|
+
}
|
|
238
|
+
if (context === "finish") {
|
|
239
|
+
return ("incident registry unchanged (plain finish body/result stayed task-local and did not " +
|
|
240
|
+
"update incidents.md: add --observation, --impact, and --resolution for a reusable " +
|
|
241
|
+
`incident before closeout.${findingsNextStep})`);
|
|
242
|
+
}
|
|
243
|
+
return "incident registry unchanged (no structured incident findings)";
|
|
244
|
+
}
|
|
245
|
+
if (duplicates > 0 && duplicates === candidates) {
|
|
246
|
+
return `incident registry unchanged (${duplicates} duplicate incident${duplicates === 1 ? "" : "s"} already recorded)`;
|
|
247
|
+
}
|
|
248
|
+
return "incident registry unchanged (no promotable external findings)";
|
|
95
249
|
}
|
|
96
250
|
export async function adviseTaskIncidents(opts) {
|
|
97
251
|
const loaded = await loadTaskIncidents(opts.ctx, opts.taskId, opts.task ?? null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/check.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAkLnC,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6NlB"}
|
|
@@ -6,12 +6,12 @@ import { fileExists } from "../../cli/fs-utils.js";
|
|
|
6
6
|
import { createCliEmitter, workflowModeMessage } from "../../cli/output.js";
|
|
7
7
|
import { CliError } from "../../shared/errors.js";
|
|
8
8
|
import { parsePrMeta } from "../shared/pr-meta.js";
|
|
9
|
-
import { gitListTaskBranches, parseTaskIdFromBranch } from "../shared/git-worktree.js";
|
|
9
|
+
import { findWorktreeForBranch, gitListTaskBranches, parseTaskIdFromBranch, } from "../shared/git-worktree.js";
|
|
10
10
|
import { gitRevParse } from "../shared/git-ops.js";
|
|
11
|
-
import { isTaskLocalOnlyAdvance } from "../shared/task-local-freshness.js";
|
|
12
11
|
import { loadBackendTask, loadCommandContext, } from "../shared/task-backend.js";
|
|
13
|
-
import {
|
|
12
|
+
import { readPrArtifactFromBranch, resolvePrPaths } from "./internal/pr-paths.js";
|
|
14
13
|
import { validateGithubPrBodyContents, validateReviewContents, } from "./internal/review-template.js";
|
|
14
|
+
import { assessPrArtifactFreshness } from "./internal/freshness.js";
|
|
15
15
|
function isUnknownRevisionError(err) {
|
|
16
16
|
const message = err instanceof Error ? err.message : String(err);
|
|
17
17
|
return /unknown revision or path not in the working tree/i.test(message);
|
|
@@ -31,26 +31,102 @@ async function resolveArtifactBranch(opts) {
|
|
|
31
31
|
}
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
|
-
async function
|
|
35
|
-
const localPath = path.join(
|
|
36
|
-
if (await fileExists(localPath))
|
|
37
|
-
return
|
|
34
|
+
async function readLocalPrArtifactText(prDir, fileName) {
|
|
35
|
+
const localPath = path.join(prDir, fileName);
|
|
36
|
+
if (!(await fileExists(localPath)))
|
|
37
|
+
return null;
|
|
38
|
+
return await readFile(localPath, "utf8");
|
|
39
|
+
}
|
|
40
|
+
function validateSnapshotContents(opts) {
|
|
41
|
+
const errors = [];
|
|
42
|
+
let meta = null;
|
|
43
|
+
if (opts.texts.metaText) {
|
|
44
|
+
try {
|
|
45
|
+
meta = parsePrMeta(opts.texts.metaText, opts.taskId);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49
|
+
errors.push(message);
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
ctx: opts.ctx,
|
|
42
|
-
resolved: opts.resolved,
|
|
43
|
-
taskId: opts.taskId,
|
|
44
|
-
});
|
|
52
|
+
else {
|
|
53
|
+
errors.push(`Missing PR directory: ${opts.relPrDir}`, `Missing ${opts.relMetaPath}`);
|
|
45
54
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
if (opts.texts.diffstatText === null)
|
|
56
|
+
errors.push(`Missing ${opts.relDiffstatPath}`);
|
|
57
|
+
if (opts.texts.verifyLogText === null)
|
|
58
|
+
errors.push(`Missing ${opts.relVerifyLogPath}`);
|
|
59
|
+
if (opts.texts.reviewText) {
|
|
60
|
+
validateReviewContents(opts.texts.reviewText, errors);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
errors.push(`Missing ${opts.relReviewPath}`);
|
|
64
|
+
}
|
|
65
|
+
if (!opts.texts.githubTitleText?.trim()) {
|
|
66
|
+
errors.push(`Missing ${opts.relGithubTitlePath}`);
|
|
67
|
+
}
|
|
68
|
+
if (opts.texts.githubBodyText) {
|
|
69
|
+
validateGithubPrBodyContents(opts.texts.githubBodyText, errors);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
errors.push(`Missing ${opts.relGithubBodyPath}`);
|
|
73
|
+
}
|
|
74
|
+
return { meta, errors };
|
|
75
|
+
}
|
|
76
|
+
async function evaluateSnapshotFreshness(opts) {
|
|
77
|
+
if (!opts.snapshot.meta || !opts.branchHeadSha)
|
|
78
|
+
return;
|
|
79
|
+
const freshness = await assessPrArtifactFreshness({
|
|
80
|
+
gitRoot: opts.gitRoot,
|
|
81
|
+
workflowDir: opts.workflowDir,
|
|
82
|
+
tasksPath: opts.tasksPath,
|
|
83
|
+
taskId: opts.taskId,
|
|
84
|
+
branchHeadSha: opts.branchHeadSha,
|
|
85
|
+
metaHeadSha: opts.snapshot.meta.head_sha ?? null,
|
|
86
|
+
metaLastVerifiedSha: opts.snapshot.meta.last_verified_sha ?? null,
|
|
87
|
+
metaVerifyStatus: opts.snapshot.meta.verify?.status ?? null,
|
|
88
|
+
taskVerificationState: opts.taskVerificationState,
|
|
89
|
+
verifyLogText: opts.snapshot.texts.verifyLogText,
|
|
90
|
+
requiresVerify: opts.requiresVerify,
|
|
53
91
|
});
|
|
92
|
+
opts.snapshot.freshnessEvaluated = true;
|
|
93
|
+
opts.snapshot.freshnessReviewFresh = freshness.reviewFresh;
|
|
94
|
+
opts.snapshot.freshnessVerifySatisfied = freshness.verifySatisfied;
|
|
95
|
+
opts.snapshot.freshnessVerifyFresh = freshness.verifyFresh;
|
|
96
|
+
opts.snapshot.freshnessVerifyLogSha = freshness.verifyLogSha;
|
|
97
|
+
}
|
|
98
|
+
function finalizeSnapshotErrors(opts) {
|
|
99
|
+
const errors = [...opts.snapshot.errors];
|
|
100
|
+
const meta = opts.snapshot.meta;
|
|
101
|
+
if (!meta)
|
|
102
|
+
return errors;
|
|
103
|
+
if (opts.branchHeadSha && opts.snapshot.freshnessEvaluated) {
|
|
104
|
+
if (!opts.snapshot.freshnessReviewFresh) {
|
|
105
|
+
errors.push(`PR artifacts stale: head_sha=${meta.head_sha ?? "<missing>"} current_head=${opts.branchHeadSha}`);
|
|
106
|
+
}
|
|
107
|
+
if (opts.requiresVerify && !opts.snapshot.freshnessVerifySatisfied) {
|
|
108
|
+
if (meta.verify?.status !== "pass") {
|
|
109
|
+
errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
|
|
110
|
+
}
|
|
111
|
+
if ((!meta.last_verified_sha || !meta.last_verified_at) &&
|
|
112
|
+
!opts.snapshot.freshnessVerifyLogSha) {
|
|
113
|
+
errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (opts.requiresVerify && meta.last_verified_sha && !opts.snapshot.freshnessVerifyFresh) {
|
|
117
|
+
errors.push(`Verify state stale: last_verified_sha=${meta.last_verified_sha} current_head=${opts.branchHeadSha}`);
|
|
118
|
+
}
|
|
119
|
+
return errors;
|
|
120
|
+
}
|
|
121
|
+
if (opts.requiresVerify) {
|
|
122
|
+
if (meta.verify?.status !== "pass") {
|
|
123
|
+
errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
|
|
124
|
+
}
|
|
125
|
+
if (!meta.last_verified_sha || !meta.last_verified_at) {
|
|
126
|
+
errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return errors;
|
|
54
130
|
}
|
|
55
131
|
export async function cmdPrCheck(opts) {
|
|
56
132
|
try {
|
|
@@ -80,99 +156,51 @@ export async function cmdPrCheck(opts) {
|
|
|
80
156
|
const relGithubTitlePath = path.relative(resolved.gitRoot, githubTitlePath);
|
|
81
157
|
const relGithubBodyPath = path.relative(resolved.gitRoot, githubBodyPath);
|
|
82
158
|
const branchCache = {};
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
prDir,
|
|
88
|
-
|
|
159
|
+
const requiresVerify = Boolean(task.verify && task.verify.length > 0);
|
|
160
|
+
const localTexts = {
|
|
161
|
+
metaText: await readLocalPrArtifactText(prDir, "meta.json"),
|
|
162
|
+
diffstatText: await readLocalPrArtifactText(prDir, "diffstat.txt"),
|
|
163
|
+
verifyLogText: await readLocalPrArtifactText(prDir, "verify.log"),
|
|
164
|
+
reviewText: await readLocalPrArtifactText(prDir, "review.md"),
|
|
165
|
+
githubTitleText: await readLocalPrArtifactText(prDir, "github-title.txt"),
|
|
166
|
+
githubBodyText: await readLocalPrArtifactText(prDir, "github-body.md"),
|
|
167
|
+
};
|
|
168
|
+
const localParsed = validateSnapshotContents({
|
|
169
|
+
texts: localTexts,
|
|
170
|
+
relPrDir,
|
|
171
|
+
relMetaPath,
|
|
172
|
+
relDiffstatPath,
|
|
173
|
+
relVerifyLogPath,
|
|
174
|
+
relReviewPath,
|
|
175
|
+
relGithubTitlePath,
|
|
176
|
+
relGithubBodyPath,
|
|
89
177
|
taskId: task.id,
|
|
90
|
-
branchCache,
|
|
91
178
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
179
|
+
const localSnapshot = {
|
|
180
|
+
source: "local",
|
|
181
|
+
texts: localTexts,
|
|
182
|
+
meta: localParsed.meta,
|
|
183
|
+
errors: localParsed.errors,
|
|
184
|
+
freshnessEvaluated: false,
|
|
185
|
+
freshnessReviewFresh: false,
|
|
186
|
+
freshnessVerifySatisfied: false,
|
|
187
|
+
freshnessVerifyFresh: false,
|
|
188
|
+
freshnessVerifyLogSha: null,
|
|
189
|
+
};
|
|
190
|
+
const localBranch = localSnapshot.meta?.branch?.trim() ?? "";
|
|
191
|
+
if (localBranch) {
|
|
192
|
+
branchCache.value = localBranch;
|
|
100
193
|
}
|
|
101
|
-
else {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
prDir,
|
|
108
|
-
fileName: "diffstat.txt",
|
|
109
|
-
taskId: task.id,
|
|
110
|
-
branchCache,
|
|
111
|
-
});
|
|
112
|
-
if (diffstatText === null) {
|
|
113
|
-
errors.push(`Missing ${relDiffstatPath}`);
|
|
114
|
-
}
|
|
115
|
-
const verifyLogText = await readPrArtifactWithOptionalBranch({
|
|
116
|
-
ctx,
|
|
117
|
-
resolved,
|
|
118
|
-
prDir,
|
|
119
|
-
fileName: "verify.log",
|
|
120
|
-
taskId: task.id,
|
|
121
|
-
branchCache,
|
|
122
|
-
});
|
|
123
|
-
if (verifyLogText === null) {
|
|
124
|
-
errors.push(`Missing ${relVerifyLogPath}`);
|
|
125
|
-
}
|
|
126
|
-
const reviewText = await readPrArtifactWithOptionalBranch({
|
|
127
|
-
ctx,
|
|
128
|
-
resolved,
|
|
129
|
-
prDir,
|
|
130
|
-
fileName: "review.md",
|
|
131
|
-
taskId: task.id,
|
|
132
|
-
branchCache,
|
|
133
|
-
});
|
|
134
|
-
if (reviewText) {
|
|
135
|
-
validateReviewContents(reviewText, errors);
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
errors.push(`Missing ${relReviewPath}`);
|
|
139
|
-
}
|
|
140
|
-
const githubTitleText = await readPrArtifactWithOptionalBranch({
|
|
141
|
-
ctx,
|
|
142
|
-
resolved,
|
|
143
|
-
prDir,
|
|
144
|
-
fileName: "github-title.txt",
|
|
145
|
-
taskId: task.id,
|
|
146
|
-
branchCache,
|
|
147
|
-
});
|
|
148
|
-
if (!githubTitleText?.trim()) {
|
|
149
|
-
errors.push(`Missing ${relGithubTitlePath}`);
|
|
150
|
-
}
|
|
151
|
-
const githubBodyText = await readPrArtifactWithOptionalBranch({
|
|
152
|
-
ctx,
|
|
153
|
-
resolved,
|
|
154
|
-
prDir,
|
|
155
|
-
fileName: "github-body.md",
|
|
156
|
-
taskId: task.id,
|
|
157
|
-
branchCache,
|
|
158
|
-
});
|
|
159
|
-
if (githubBodyText) {
|
|
160
|
-
validateGithubPrBodyContents(githubBodyText, errors);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
errors.push(`Missing ${relGithubBodyPath}`);
|
|
164
|
-
}
|
|
165
|
-
if (task.verify && task.verify.length > 0) {
|
|
166
|
-
if (meta?.verify?.status !== "pass") {
|
|
167
|
-
errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
|
|
168
|
-
}
|
|
169
|
-
if (!meta?.last_verified_sha || !meta.last_verified_at) {
|
|
170
|
-
errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
|
|
171
|
-
}
|
|
194
|
+
else if (branchCache.value === undefined) {
|
|
195
|
+
branchCache.value = await resolveArtifactBranch({
|
|
196
|
+
ctx,
|
|
197
|
+
resolved,
|
|
198
|
+
taskId: task.id,
|
|
199
|
+
});
|
|
172
200
|
}
|
|
173
|
-
const branchForFreshness = branchCache.value ??
|
|
174
|
-
|
|
175
|
-
|
|
201
|
+
const branchForFreshness = branchCache.value ?? null;
|
|
202
|
+
let branchHeadSha = null;
|
|
203
|
+
if (branchForFreshness) {
|
|
176
204
|
try {
|
|
177
205
|
branchHeadSha = await gitRevParse(resolved.gitRoot, [branchForFreshness]);
|
|
178
206
|
}
|
|
@@ -180,34 +208,112 @@ export async function cmdPrCheck(opts) {
|
|
|
180
208
|
if (!isUnknownRevisionError(err))
|
|
181
209
|
throw err;
|
|
182
210
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
211
|
+
}
|
|
212
|
+
await evaluateSnapshotFreshness({
|
|
213
|
+
snapshot: localSnapshot,
|
|
214
|
+
gitRoot: resolved.gitRoot,
|
|
215
|
+
workflowDir: config.paths.workflow_dir,
|
|
216
|
+
tasksPath: config.paths.tasks_path,
|
|
217
|
+
taskId: task.id,
|
|
218
|
+
branchHeadSha,
|
|
219
|
+
taskVerificationState: task.verification?.state ?? null,
|
|
220
|
+
requiresVerify,
|
|
221
|
+
});
|
|
222
|
+
let selectedSnapshot = localSnapshot;
|
|
223
|
+
if (branchForFreshness &&
|
|
224
|
+
branchHeadSha &&
|
|
225
|
+
(!localSnapshot.meta ||
|
|
226
|
+
!localSnapshot.freshnessReviewFresh ||
|
|
227
|
+
(requiresVerify && !localSnapshot.freshnessVerifySatisfied))) {
|
|
228
|
+
const worktreePath = await findWorktreeForBranch(resolved.gitRoot, branchForFreshness);
|
|
229
|
+
const branchTexts = {
|
|
230
|
+
metaText: await readPrArtifactFromBranch({
|
|
231
|
+
resolved,
|
|
232
|
+
prDir,
|
|
233
|
+
fileName: "meta.json",
|
|
234
|
+
branch: branchForFreshness,
|
|
235
|
+
worktreePath,
|
|
236
|
+
}),
|
|
237
|
+
diffstatText: await readPrArtifactFromBranch({
|
|
238
|
+
resolved,
|
|
239
|
+
prDir,
|
|
240
|
+
fileName: "diffstat.txt",
|
|
241
|
+
branch: branchForFreshness,
|
|
242
|
+
worktreePath,
|
|
243
|
+
}),
|
|
244
|
+
verifyLogText: await readPrArtifactFromBranch({
|
|
245
|
+
resolved,
|
|
246
|
+
prDir,
|
|
247
|
+
fileName: "verify.log",
|
|
248
|
+
branch: branchForFreshness,
|
|
249
|
+
worktreePath,
|
|
250
|
+
}),
|
|
251
|
+
reviewText: await readPrArtifactFromBranch({
|
|
252
|
+
resolved,
|
|
253
|
+
prDir,
|
|
254
|
+
fileName: "review.md",
|
|
255
|
+
branch: branchForFreshness,
|
|
256
|
+
worktreePath,
|
|
257
|
+
}),
|
|
258
|
+
githubTitleText: await readPrArtifactFromBranch({
|
|
259
|
+
resolved,
|
|
260
|
+
prDir,
|
|
261
|
+
fileName: "github-title.txt",
|
|
262
|
+
branch: branchForFreshness,
|
|
263
|
+
worktreePath,
|
|
264
|
+
}),
|
|
265
|
+
githubBodyText: await readPrArtifactFromBranch({
|
|
266
|
+
resolved,
|
|
267
|
+
prDir,
|
|
268
|
+
fileName: "github-body.md",
|
|
269
|
+
branch: branchForFreshness,
|
|
270
|
+
worktreePath,
|
|
271
|
+
}),
|
|
272
|
+
};
|
|
273
|
+
const branchParsed = validateSnapshotContents({
|
|
274
|
+
texts: branchTexts,
|
|
275
|
+
relPrDir,
|
|
276
|
+
relMetaPath,
|
|
277
|
+
relDiffstatPath,
|
|
278
|
+
relVerifyLogPath,
|
|
279
|
+
relReviewPath,
|
|
280
|
+
relGithubTitlePath,
|
|
281
|
+
relGithubBodyPath,
|
|
282
|
+
taskId: task.id,
|
|
283
|
+
});
|
|
284
|
+
const branchSnapshot = {
|
|
285
|
+
source: "branch",
|
|
286
|
+
texts: branchTexts,
|
|
287
|
+
meta: branchParsed.meta,
|
|
288
|
+
errors: branchParsed.errors,
|
|
289
|
+
freshnessEvaluated: false,
|
|
290
|
+
freshnessReviewFresh: false,
|
|
291
|
+
freshnessVerifySatisfied: false,
|
|
292
|
+
freshnessVerifyFresh: false,
|
|
293
|
+
freshnessVerifyLogSha: null,
|
|
294
|
+
};
|
|
295
|
+
await evaluateSnapshotFreshness({
|
|
296
|
+
snapshot: branchSnapshot,
|
|
297
|
+
gitRoot: resolved.gitRoot,
|
|
298
|
+
workflowDir: config.paths.workflow_dir,
|
|
299
|
+
tasksPath: config.paths.tasks_path,
|
|
300
|
+
taskId: task.id,
|
|
301
|
+
branchHeadSha,
|
|
302
|
+
taskVerificationState: task.verification?.state ?? null,
|
|
303
|
+
requiresVerify,
|
|
304
|
+
});
|
|
305
|
+
if (branchSnapshot.errors.length === 0 &&
|
|
306
|
+
branchSnapshot.meta &&
|
|
307
|
+
branchSnapshot.freshnessReviewFresh &&
|
|
308
|
+
(!requiresVerify || branchSnapshot.freshnessVerifySatisfied)) {
|
|
309
|
+
selectedSnapshot = branchSnapshot;
|
|
209
310
|
}
|
|
210
311
|
}
|
|
312
|
+
errors.push(...finalizeSnapshotErrors({
|
|
313
|
+
snapshot: selectedSnapshot,
|
|
314
|
+
branchHeadSha,
|
|
315
|
+
requiresVerify,
|
|
316
|
+
}));
|
|
211
317
|
if (errors.length > 0) {
|
|
212
318
|
throw new CliError({
|
|
213
319
|
exitCode: exitCodeForError("E_VALIDATION"),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CommandContext } from "../shared/task-backend.js";
|
|
2
|
+
export declare function cmdPrCloseSuperseded(opts: {
|
|
3
|
+
ctx?: CommandContext;
|
|
4
|
+
cwd: string;
|
|
5
|
+
rootOverride?: string;
|
|
6
|
+
taskId: string;
|
|
7
|
+
deleteRemoteBranch: boolean;
|
|
8
|
+
}): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=close-superseded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"close-superseded.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/close-superseded.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAiCnC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,CAAC,CAsHlB"}
|