agentplane 0.3.10 → 0.3.11
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/policy/governance.md +3 -4
- package/assets/policy/incidents.md +19 -88
- package/assets/policy/workflow.branch_pr.md +1 -1
- package/assets/policy/workflow.direct.md +2 -2
- package/bin/agentplane.js +56 -1
- package/bin/runtime-watch.js +1 -0
- package/bin/stale-dist-policy.d.ts +1 -1
- package/bin/stale-dist-policy.js +13 -0
- package/dist/.build-manifest.json +219 -154
- 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/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.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +12 -0
- package/dist/commands/branch/cleanup-merged.d.ts +2 -0
- package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
- package/dist/commands/branch/cleanup-merged.js +132 -28
- package/dist/commands/branch/work-start.d.ts.map +1 -1
- package/dist/commands/branch/work-start.js +60 -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.map +1 -1
- package/dist/commands/guard/impl/commands.js +24 -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.map +1 -1
- package/dist/commands/hooks/index.js +98 -1
- 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 +238 -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 +16 -0
- 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/finalize.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/finalize.js +40 -12
- 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/prepare.d.ts +3 -2
- package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/prepare.js +101 -38
- package/dist/commands/pr/internal/freshness.d.ts +20 -0
- package/dist/commands/pr/internal/freshness.d.ts.map +1 -0
- package/dist/commands/pr/internal/freshness.js +50 -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 +462 -122
- 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 +13 -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 +59 -1
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +3 -17
- package/dist/commands/release/apply.preflight.d.ts.map +1 -1
- package/dist/commands/release/apply.preflight.js +1 -1
- 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/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 +22 -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 +34 -22
- 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 +1 -0
- package/dist/commands/task/finish-shared.d.ts.map +1 -1
- package/dist/commands/task/finish-shared.js +55 -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 +414 -0
- package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
- package/dist/commands/task/hosted-close.command.js +49 -1
- package/dist/commands/task/hosted-merge-sync.d.ts +38 -0
- package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
- package/dist/commands/task/hosted-merge-sync.js +249 -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-ready.d.ts.map +1 -1
- package/dist/commands/task/start-ready.js +86 -0
- 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
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
3
5
|
import { loadConfig, resolveBaseBranch, resolveProject } from "@agentplaneorg/core";
|
|
4
6
|
import { evaluatePolicy } from "../../policy/evaluate.js";
|
|
5
7
|
import { mapBackendError, mapCoreError } from "../../cli/error-map.js";
|
|
@@ -9,10 +11,20 @@ import { CliError } from "../../shared/errors.js";
|
|
|
9
11
|
import { GitContext } from "../shared/git-context.js";
|
|
10
12
|
import { throwIfPolicyDenied } from "../shared/policy-deny.js";
|
|
11
13
|
import { gitCurrentBranch, gitRevParse } from "../shared/git-ops.js";
|
|
14
|
+
import { parseTaskIdFromBranch, parseTaskIdFromCloseBranch } from "../shared/git-worktree.js";
|
|
12
15
|
import { isPathWithin } from "../shared/path.js";
|
|
13
16
|
const HOOK_MARKER = "agentplane-hook";
|
|
14
17
|
const SHIM_MARKER = "agentplane-hook-shim";
|
|
15
18
|
export const HOOK_NAMES = ["commit-msg", "pre-commit", "pre-push"];
|
|
19
|
+
async function inferTaskIdFromBranchContext(opts) {
|
|
20
|
+
try {
|
|
21
|
+
const branch = await gitCurrentBranch(opts.gitRoot);
|
|
22
|
+
return (parseTaskIdFromBranch(opts.taskPrefix, branch) ?? parseTaskIdFromCloseBranch(branch) ?? "");
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
16
28
|
async function resolveGitHooksDir(cwd) {
|
|
17
29
|
const repoRoot = await gitRevParse(cwd, ["--show-toplevel"]);
|
|
18
30
|
const commonDirRaw = await gitRevParse(cwd, ["--git-common-dir"]);
|
|
@@ -116,6 +128,47 @@ function readCommitSubject(message) {
|
|
|
116
128
|
}
|
|
117
129
|
return "";
|
|
118
130
|
}
|
|
131
|
+
function resolveBundledPrePushHookScriptPath() {
|
|
132
|
+
return fileURLToPath(new URL("../../../../../scripts/run-pre-push-hook.mjs", import.meta.url));
|
|
133
|
+
}
|
|
134
|
+
async function readHookStdinUtf8(timeoutMs = 25) {
|
|
135
|
+
if (process.stdin.isTTY)
|
|
136
|
+
return "";
|
|
137
|
+
const chunks = [];
|
|
138
|
+
const consume = () => {
|
|
139
|
+
let chunk = process.stdin.read();
|
|
140
|
+
while (chunk !== null) {
|
|
141
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
142
|
+
chunk = process.stdin.read();
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
consume();
|
|
146
|
+
if (chunks.length > 0 || process.stdin.readableEnded) {
|
|
147
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
148
|
+
}
|
|
149
|
+
await new Promise((resolve) => {
|
|
150
|
+
const finish = () => {
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
process.stdin.off("readable", onReadable);
|
|
153
|
+
process.stdin.off("end", onEnd);
|
|
154
|
+
resolve();
|
|
155
|
+
};
|
|
156
|
+
const onReadable = () => {
|
|
157
|
+
consume();
|
|
158
|
+
finish();
|
|
159
|
+
};
|
|
160
|
+
const onEnd = () => {
|
|
161
|
+
consume();
|
|
162
|
+
finish();
|
|
163
|
+
};
|
|
164
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
165
|
+
process.stdin.on("readable", onReadable);
|
|
166
|
+
process.stdin.on("end", onEnd);
|
|
167
|
+
process.stdin.resume();
|
|
168
|
+
});
|
|
169
|
+
consume();
|
|
170
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
171
|
+
}
|
|
119
172
|
export async function cmdHooksInstall(opts) {
|
|
120
173
|
try {
|
|
121
174
|
const resolved = await resolveProject({
|
|
@@ -201,7 +254,11 @@ export async function cmdHooksRun(opts) {
|
|
|
201
254
|
rootOverride: opts.rootOverride ?? null,
|
|
202
255
|
});
|
|
203
256
|
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
204
|
-
const taskId = (process.env.AGENTPLANE_TASK_ID ?? "").trim()
|
|
257
|
+
const taskId = (process.env.AGENTPLANE_TASK_ID ?? "").trim() ||
|
|
258
|
+
(await inferTaskIdFromBranchContext({
|
|
259
|
+
gitRoot: resolved.gitRoot,
|
|
260
|
+
taskPrefix: loaded.config.branch.task_prefix,
|
|
261
|
+
}));
|
|
205
262
|
const statusTo = (process.env.AGENTPLANE_STATUS_TO ?? "").trim().toUpperCase();
|
|
206
263
|
const emoji = subject.split(/\s+/).find(Boolean) ?? "";
|
|
207
264
|
if (taskId && statusTo === "DONE" && emoji !== "✅") {
|
|
@@ -269,9 +326,49 @@ export async function cmdHooksRun(opts) {
|
|
|
269
326
|
throwIfPolicyDenied(res);
|
|
270
327
|
return 0;
|
|
271
328
|
}
|
|
329
|
+
if (opts.hook === "pre-push") {
|
|
330
|
+
const resolved = await resolveProject({
|
|
331
|
+
cwd: opts.cwd,
|
|
332
|
+
rootOverride: opts.rootOverride ?? null,
|
|
333
|
+
});
|
|
334
|
+
const scriptPath = resolveBundledPrePushHookScriptPath();
|
|
335
|
+
if (!(await fileExists(scriptPath))) {
|
|
336
|
+
throw new CliError({
|
|
337
|
+
exitCode: 2,
|
|
338
|
+
code: "E_USAGE",
|
|
339
|
+
message: `Missing pre-push hook script: ${scriptPath}`,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const result = spawnSync("node", [scriptPath], {
|
|
343
|
+
cwd: resolved.gitRoot,
|
|
344
|
+
env: process.env,
|
|
345
|
+
encoding: "utf8",
|
|
346
|
+
input: await readHookStdinUtf8(),
|
|
347
|
+
stdio: "pipe",
|
|
348
|
+
});
|
|
349
|
+
if (typeof result.stdout === "string" && result.stdout.length > 0) {
|
|
350
|
+
process.stdout.write(result.stdout);
|
|
351
|
+
}
|
|
352
|
+
if (typeof result.stderr === "string" && result.stderr.length > 0) {
|
|
353
|
+
process.stderr.write(result.stderr);
|
|
354
|
+
}
|
|
355
|
+
if (result.error)
|
|
356
|
+
throw result.error;
|
|
357
|
+
return result.status ?? (result.signal ? 1 : 0);
|
|
358
|
+
}
|
|
272
359
|
return 0;
|
|
273
360
|
}
|
|
274
361
|
catch (err) {
|
|
362
|
+
const status = err?.status;
|
|
363
|
+
const stdout = err?.stdout;
|
|
364
|
+
const stderr = err?.stderr;
|
|
365
|
+
if (typeof stdout === "string" && stdout.length > 0)
|
|
366
|
+
process.stdout.write(stdout);
|
|
367
|
+
if (typeof stderr === "string" && stderr.length > 0)
|
|
368
|
+
process.stderr.write(stderr);
|
|
369
|
+
if (typeof status === "number" && Number.isInteger(status) && status >= 0) {
|
|
370
|
+
return status;
|
|
371
|
+
}
|
|
275
372
|
if (err instanceof CliError)
|
|
276
373
|
throw err;
|
|
277
374
|
throw mapBackendError(err, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collect.command.d.ts","sourceRoot":"","sources":["../../../src/commands/incidents/collect.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpF,KAAK,sBAAsB,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAIF,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,sBAAsB,
|
|
1
|
+
{"version":3,"file":"collect.command.d.ts","sourceRoot":"","sources":["../../../src/commands/incidents/collect.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpF,KAAK,sBAAsB,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAIF,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,sBAAsB,CAmCpE,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC/E,KAAK,UAAU,EAAE,GAAG,sBAAsB,KAAG,OAAO,CAAC,MAAM,CAAC,CAsC3E"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createCliEmitter } from "../../cli/output.js";
|
|
2
2
|
import { loadCommandContext } from "../shared/task-backend.js";
|
|
3
|
-
import { collectTaskIncidents } from "./shared.js";
|
|
3
|
+
import { collectTaskIncidents, renderIncidentCollectionPlanOutcome } from "./shared.js";
|
|
4
4
|
const output = createCliEmitter();
|
|
5
5
|
export const incidentsCollectSpec = {
|
|
6
6
|
id: ["incidents", "collect"],
|
|
7
7
|
group: "Policy",
|
|
8
|
-
summary: "Promote
|
|
8
|
+
summary: "Promote reusable resolved external findings from a task into the incident registry.",
|
|
9
9
|
args: [{ name: "task-id", required: true, valueHint: "<task-id>" }],
|
|
10
10
|
options: [
|
|
11
11
|
{
|
|
@@ -28,7 +28,7 @@ export const incidentsCollectSpec = {
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
cmd: "agentplane incidents collect 202604031416-HEJWTM --check --json",
|
|
31
|
-
why: "Validate that
|
|
31
|
+
why: "Validate that reusable resolved external findings are complete before finish.",
|
|
32
32
|
},
|
|
33
33
|
],
|
|
34
34
|
parse: (raw) => ({
|
|
@@ -51,17 +51,22 @@ export function makeRunIncidentsCollectHandler(getCtx) {
|
|
|
51
51
|
task_id: p.taskId,
|
|
52
52
|
checked_only: p.check,
|
|
53
53
|
candidates: result.plan.candidates.length,
|
|
54
|
+
skipped: result.plan.skipped,
|
|
54
55
|
promotable: result.plan.promotable.map((item) => item.entry),
|
|
55
56
|
duplicates: result.plan.duplicates.map((item) => item.entry.id),
|
|
56
57
|
wrote: result.wrote,
|
|
57
58
|
registry_path: result.registryPath,
|
|
59
|
+
registry_paths: result.registryPaths,
|
|
58
60
|
});
|
|
59
61
|
return 0;
|
|
60
62
|
}
|
|
61
|
-
output.success(p.check ? "checked" : "collected", p.taskId, `candidates=${result.plan.candidates.length} promoted=${result.plan.promotable.length} duplicates=${result.plan.duplicates.length}`);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
output.success(p.check ? "checked" : "collected", p.taskId, `candidates=${result.plan.candidates.length} skipped=${result.plan.skipped.length} promoted=${result.plan.promotable.length} duplicates=${result.plan.duplicates.length}`);
|
|
64
|
+
output.info(renderIncidentCollectionPlanOutcome(result.plan, {
|
|
65
|
+
wrote: result.wrote,
|
|
66
|
+
context: "collect",
|
|
67
|
+
promotedIds: result.plan.promotable.map((item) => item.entry.id),
|
|
68
|
+
registryPaths: result.registryPaths,
|
|
69
|
+
}));
|
|
65
70
|
return 0;
|
|
66
71
|
};
|
|
67
72
|
}
|
|
@@ -6,7 +6,7 @@ export const incidentsSpec = {
|
|
|
6
6
|
synopsis: ["agentplane incidents <collect|advise> [args] [options]"],
|
|
7
7
|
args: [{ name: "cmd", required: false, variadic: true, valueHint: "<command>" }],
|
|
8
8
|
notes: [
|
|
9
|
-
"Use `incidents collect` to promote
|
|
9
|
+
"Use `incidents collect` to promote resolved reusable external findings into `.agentplane/policy/incidents.md`.",
|
|
10
10
|
"Use `incidents advise` to query registry advice by task id or lightweight scope/tags.",
|
|
11
11
|
],
|
|
12
12
|
parse: (raw) => parseGroupCommand(raw),
|
|
@@ -2,6 +2,7 @@ import type { TaskData } from "../../backends/task-backend.js";
|
|
|
2
2
|
import { type IncidentAdviceMatch, type IncidentAdviceQuery, type IncidentCollectionPlan, type IncidentRegistry } from "../../runtime/incidents/index.js";
|
|
3
3
|
import type { CommandContext } from "../shared/task-backend.js";
|
|
4
4
|
export declare const INCIDENTS_POLICY_PATH = ".agentplane/policy/incidents.md";
|
|
5
|
+
export declare const INCIDENTS_POLICY_ASSET_PATH = "packages/agentplane/assets/policy/incidents.md";
|
|
5
6
|
export type LoadedTaskIncidents = {
|
|
6
7
|
task: TaskData;
|
|
7
8
|
findings: string;
|
|
@@ -9,6 +10,7 @@ export type LoadedTaskIncidents = {
|
|
|
9
10
|
query: IncidentAdviceQuery;
|
|
10
11
|
};
|
|
11
12
|
export declare function incidentRegistryPath(ctx: CommandContext): string;
|
|
13
|
+
export declare function incidentRegistryAssetPath(ctx: CommandContext): string;
|
|
12
14
|
export declare function loadIncidentRegistry(ctx: CommandContext): Promise<{
|
|
13
15
|
registryPath: string;
|
|
14
16
|
registryText: string;
|
|
@@ -25,11 +27,43 @@ export declare function collectTaskIncidents(opts: {
|
|
|
25
27
|
}): Promise<{
|
|
26
28
|
loaded: LoadedTaskIncidents;
|
|
27
29
|
registryPath: string;
|
|
30
|
+
registryPaths: string[];
|
|
28
31
|
registryText: string;
|
|
29
32
|
registry: IncidentRegistry;
|
|
30
33
|
plan: IncidentCollectionPlan;
|
|
31
34
|
wrote: boolean;
|
|
32
35
|
}>;
|
|
36
|
+
export declare function inspectTaskIncidents(opts: {
|
|
37
|
+
ctx: CommandContext;
|
|
38
|
+
taskId: string;
|
|
39
|
+
task?: TaskData | null;
|
|
40
|
+
now?: Date;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
loaded: LoadedTaskIncidents;
|
|
43
|
+
registryPath: string;
|
|
44
|
+
registryPaths: string[];
|
|
45
|
+
registryText: string;
|
|
46
|
+
registry: IncidentRegistry;
|
|
47
|
+
plan: IncidentCollectionPlan;
|
|
48
|
+
}>;
|
|
49
|
+
export declare function renderIncidentCollectionOutcome(promotedCount: number): string;
|
|
50
|
+
export declare function renderIncidentCollectionPlanOutcome(plan: {
|
|
51
|
+
candidates?: readonly unknown[];
|
|
52
|
+
skipped?: readonly unknown[];
|
|
53
|
+
promotable?: readonly unknown[];
|
|
54
|
+
duplicates?: readonly unknown[];
|
|
55
|
+
issues?: readonly {
|
|
56
|
+
missingFields?: readonly string[];
|
|
57
|
+
}[];
|
|
58
|
+
findingsTextPresent?: boolean;
|
|
59
|
+
structuredFindingCount?: number;
|
|
60
|
+
}, opts?: {
|
|
61
|
+
wrote?: boolean;
|
|
62
|
+
context?: "collect" | "verify" | "finish" | "generic";
|
|
63
|
+
promotedIds?: readonly string[];
|
|
64
|
+
registryPaths?: readonly string[];
|
|
65
|
+
taskId?: string | null;
|
|
66
|
+
}): string;
|
|
33
67
|
export declare function adviseTaskIncidents(opts: {
|
|
34
68
|
ctx: CommandContext;
|
|
35
69
|
taskId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/incidents/shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG/D,OAAO,EAOL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAM1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/incidents/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;AAgLnC,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,CA2NlB"}
|