@gobing-ai/spur 0.4.2 → 0.4.4
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/.claude-plugin/marketplace.json +1 -1
- package/config/decisions/maker-liveness.yaml +39 -0
- package/config/plugin-scripts.json +0 -4
- package/config/rules/README.md +1 -0
- package/config/rules/docs/sourced-api-claims.yaml +56 -12
- package/config/rules/docs/verdict-confidence.yaml +68 -0
- package/config/rules/quality/coverage-gate.yaml +13 -0
- package/config/rules/recommended-pre-check.yaml +6 -2
- package/config/rules/strict/runtime-boundaries.yaml +10 -0
- package/config/rules/surface/check-cli-surface.yaml +1 -3
- package/config/script-placement-baseline.json +1 -19
- package/config/templates/AGENTS.md +7 -0
- package/config/workflows/feature-lifecycle.yaml +46 -1
- package/config/workflows/feature-verification.yaml +20 -1
- package/config/workflows/task-lifecycle.yaml +50 -0
- package/config/workflows/task-pipeline.yaml +15 -9
- package/package.json +10 -10
- package/plugins/sp/README.md +22 -16
- package/plugins/sp/agents/super-reviewer.md +46 -0
- package/plugins/sp/bunfig.toml +8 -5
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/commands/dev-gitmsg.md +6 -2
- package/plugins/sp/commands/dev-handover.md +1 -0
- package/plugins/sp/commands/dev-job-dump.md +2 -1
- package/plugins/sp/commands/dev-refine.md +14 -2
- package/plugins/sp/commands/dev-refineall.md +7 -1
- package/plugins/sp/commands/dev-review.md +1 -0
- package/plugins/sp/hooks/careful-guard.ts +1 -1
- package/plugins/sp/hooks/context-post-tool.ts +7 -427
- package/plugins/sp/hooks/context-session-start.ts +5 -213
- package/plugins/sp/hooks/context-session-stop.ts +5 -191
- package/plugins/sp/hooks/pi/guard-extension.ts +6 -5
- package/plugins/sp/hooks/task-write-guard.ts +1 -1
- package/plugins/sp/{hooks → lib}/agent-hint.ts +1 -1
- package/plugins/sp/lib/context-post-tool.ts +432 -0
- package/plugins/sp/lib/context-session-start.ts +214 -0
- package/plugins/sp/lib/context-session-stop.ts +196 -0
- package/plugins/sp/lib/dogfood-pipeline.ts +265 -0
- package/plugins/sp/lib/dogfood-report.ts +278 -0
- package/plugins/sp/lib/history-anatomy.generated.mjs +18 -18
- package/plugins/sp/lib/idea-handoff.generated.mjs +91 -91
- package/plugins/sp/lib/inline-run-app.ts +40 -0
- package/plugins/sp/lib/inline-run.generated.d.mts +3 -3
- package/plugins/sp/lib/inline-run.generated.mjs +1425 -212
- package/plugins/sp/lib/plan-projection.generated.d.mts +150 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +623 -9
- package/plugins/sp/lib/quality-gate.generated.d.mts +1 -0
- package/plugins/sp/lib/quality-gate.generated.mjs +13809 -13969
- package/plugins/sp/lib/residual-scan.generated.d.mts +20 -1
- package/plugins/sp/lib/residual-scan.generated.mjs +120 -25
- package/plugins/sp/lib/run-summary-core.ts +34 -370
- package/plugins/sp/lib/step-profile.generated.mjs +8 -8
- package/plugins/sp/lib/transcript.ts +37 -228
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +619 -11
- package/plugins/sp/scripts/batch-preflight.mjs +57 -13
- package/plugins/sp/scripts/batch-preflight.ts +35 -295
- package/plugins/sp/scripts/commit-guard.mjs +6 -6
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +127 -108
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +111 -104
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +13 -12
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +7 -265
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +7 -4
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +6 -272
- package/plugins/sp/scripts/feature-verification-steps.mjs +20 -125
- package/plugins/sp/scripts/feature-verification-steps.ts +57 -181
- package/plugins/sp/scripts/history-anatomy-cache.mjs +19 -19
- package/plugins/sp/scripts/idea-handoff.mjs +2 -2
- package/plugins/sp/scripts/inline-run-dispatch.mjs +25 -24
- package/plugins/sp/scripts/inline-run-dispatch.ts +1 -21
- package/plugins/sp/scripts/inline-run-setup.mjs +164 -137
- package/plugins/sp/scripts/inline-run-setup.ts +1 -21
- package/plugins/sp/scripts/persist-out-check.mjs +5 -5
- package/plugins/sp/scripts/pr-reviewing.mjs +13 -13
- package/plugins/sp/scripts/quality-gate.mjs +13730 -13887
- package/plugins/sp/scripts/residual-scan.mjs +129 -31
- package/plugins/sp/scripts/residual-scan.ts +16 -13
- package/plugins/sp/scripts/run-summary.mjs +166 -112
- package/plugins/sp/scripts/run-summary.ts +7 -5
- package/plugins/sp/scripts/script-root.mjs +6 -6
- package/plugins/sp/scripts/session-timeline.mjs +62 -35
- package/plugins/sp/scripts/task-diffstat.mjs +19 -9
- package/plugins/sp/scripts/task-diffstat.ts +8 -39
- package/plugins/sp/scripts/workflow-step-profile.mjs +12 -12
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +9 -9
- package/plugins/sp/scripts/wrapup-steps.mjs +25 -25
- package/plugins/sp/skills/code-implementation/SKILL.md +7 -1
- package/plugins/sp/skills/code-verification/references/secu-review.md +2 -1
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +4 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +2 -2
- package/plugins/sp/skills/next-feature/SKILL.md +1 -1
- package/plugins/sp/skills/next-router/SKILL.md +3 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +9 -3
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
- package/plugins/sp/skills/spur-cli/references/builder.md +3 -2
- package/plugins/sp/skills/spur-cli/references/decision.md +32 -7
- package/plugins/sp/skills/spur-cli/references/features.md +46 -5
- package/plugins/sp/skills/spur-cli/references/tasks.md +24 -4
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +8 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +37 -11
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -6
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +22 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +14 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +49 -12
- package/schemas/section-matrix.schema.json +3 -2
- package/spur.js +66591 -73262
- package/web/_astro/{BoardApp.B3GQZvj8.js → BoardApp.Niubpe6z.js} +1 -1
- package/web/_astro/{BoardApp.BT7L2kSb.js → BoardApp.hF0RAIrg.js} +150 -150
- package/web/_astro/TaskDetail.DJpapt38.js +1 -0
- package/web/_astro/{arc.vaT7tPOB.js → arc.BgKcK0i8.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DRMmTjkN.js → architectureDiagram-3BPJPVTR.ChP-Ig0V.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.cla0LO_q.js → blockDiagram-GPEHLZMM.BVaCBoeN.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.D4YAIBKn.js → c4Diagram-AAUBKEIU.CHSDpEO5.js} +1 -1
- package/web/_astro/channel.DkpvN2tD.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.BrSJbMRZ.js → chunk-2J33WTMH.MYRcYVRa.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CuLMgKF5.js → chunk-4BX2VUAB.S5j22Zqa.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.zkvgu54F.js → chunk-55IACEB6.gciRPvmZ.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DxWkACh8.js → chunk-727SXJPM.CdqrSQkX.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.42XrmIlH.js → chunk-AQP2D5EJ.CyokdHT3.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.Bao2wMK9.js → chunk-FMBD7UC4.Bg9KJhjW.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BhydojD1.js → chunk-ND2GUHAM.1gxxI-vD.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CmZ82g-H.js → chunk-QZHKN3VN.DDEYtCKU.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.Blr83Gt_.js → classDiagram-4FO5ZUOK.Ch3zi37T.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.Blr83Gt_.js → classDiagram-v2-Q7XG4LA2.Ch3zi37T.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.qmfv0SPn.js → cose-bilkent-S5V4N54A.D2q5AINI.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.BtELhXPR.js → cynefin-OW5HDTMX.BA9kC2YT.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.AWmaAvXo.js → dagre-BM42HDAG.CHO08nRp.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DdH34KDi.js → diagram-2AECGRRQ.BfFQt0LW.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BmNPix1k.js → diagram-5GNKFQAL.CHMwMTe4.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BNQd_Ppo.js → diagram-KO2AKTUF.BJ-7gK-w.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.BAPgDi0e.js → diagram-LMA3HP47.C5xqcc0t.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.DZ4zyLdC.js → diagram-OG6HWLK6.C2pQjfrC.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.Q1TySMmw.js → erDiagram-TEJ5UH35._FoNyxgC.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BXhFBicG.js → flowDiagram-I6XJVG4X.B_ENkT2I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.vHSgcuo2.js → ganttDiagram-6RSMTGT7.B3q8h77C.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.Bi1f73C7.js → gitGraphDiagram-PVQCEYII.QWZFDboZ.js} +1 -1
- package/web/_astro/index.BFyW13JJ.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DPvXZEWm.js → infoDiagram-5YYISTIA.Cs6eEc92.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.Cz829fsV.js → ishikawaDiagram-YF4QCWOH.BU9DJMHA.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.enRnB9Me.js → journeyDiagram-JHISSGLW.D35k6Jpe.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DnTNk6d2.js → kanban-definition-UN3LZRKU.DBqcAT4m.js} +1 -1
- package/web/_astro/{linear.BzGnBwNL.js → linear.D-LSNK8W.js} +1 -1
- package/web/_astro/{mermaid.core.CSbTpIVz.js → mermaid.core.CSruWVOa.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.DGJDy8zT.js → mindmap-definition-RKZ34NQL.BiFaUsfj.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.HSPdi5_8.js → pieDiagram-4H26LBE5.D1KTKqb9.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.6Gv8mz2Y.js → quadrantDiagram-W4KKPZXB.DBHflsMG.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CnBCtFwa.js → requirementDiagram-4Y6WPE33.hwX9CNdk.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.5M8VWAu8.js → sankeyDiagram-5OEKKPKP.DkI8mJiE.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DN41XN-U.js → sequenceDiagram-3UESZ5HK.DMz7jBDx.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.ErOO3W8j.js → stateDiagram-AJRCARHV.B6Ef2xJ1.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.B_ZHICM-.js → stateDiagram-v2-BHNVJYJU.CgoaufB9.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CWdosr07.js → timeline-definition-PNZ67QCA.B3c8h1t-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.BHzYjNV5.js → vennDiagram-CIIHVFJN.BdHPAxAb.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.h8x4IwPX.js → wardleyDiagram-YWT4CUSO.BrJXPPAj.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.RTapW2X8.js → xychartDiagram-2RQKCTM6.CMH5yFsV.js} +1 -1
- package/web/index.html +2 -2
- package/web/spur_logo.svg +1 -1
- package/config/proportional-route-table.ts +0 -155
- package/plugins/sp/scripts/daily-summary/logger.ts +0 -28
- package/web/_astro/TaskDetail.Cxov1_N_.js +0 -1
- package/web/_astro/channel.D4nG9YLf.js +0 -1
- package/web/_astro/index.BhSwN8yY.css +0 -1
- /package/plugins/sp/{hooks → lib}/context-owner.ts +0 -0
- /package/plugins/sp/{hooks → lib}/destructive-policy.ts +0 -0
- /package/plugins/sp/{hooks → lib}/task-file-policy.ts +0 -0
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
|
-
// plugins/sp/
|
|
5
|
+
// plugins/sp/lib/plan-projection.generated.mjs
|
|
6
|
+
function isTaskFrozen(status) {
|
|
7
|
+
return status?.toLowerCase() === "deprecated";
|
|
8
|
+
}
|
|
9
|
+
function undeprecateTaskCommand(wbs) {
|
|
10
|
+
return `spur task update ${wbs} todo`;
|
|
11
|
+
}
|
|
6
12
|
var NON_ABORTING_PREFLIGHT_CODES = new Set([
|
|
7
13
|
"L4.scenario-unverified",
|
|
8
14
|
"L4.verifying-incomplete-tasks"
|
|
@@ -53,6 +59,13 @@ function quickReadiness(input) {
|
|
|
53
59
|
};
|
|
54
60
|
}
|
|
55
61
|
}
|
|
62
|
+
if (isTaskFrozen(status)) {
|
|
63
|
+
return {
|
|
64
|
+
action: "skipped",
|
|
65
|
+
code: "DEPRECATED",
|
|
66
|
+
reason: `quick-readiness: deprecated (frozen) — no ${operation} hop; un-deprecate with \`${undeprecateTaskCommand(input.wbs)}\` (${input.wbs})`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
56
69
|
if (status === "cancelled" || status === "done") {
|
|
57
70
|
if (operation === "verify" && input.force === true) {
|
|
58
71
|
return {
|
|
@@ -77,10 +90,12 @@ function quickReadiness(input) {
|
|
|
77
90
|
if (operation === "run" && input.dependencies && input.dependencies.length > 0) {
|
|
78
91
|
const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? "missing").toLowerCase() !== "done");
|
|
79
92
|
if (unmet.length > 0) {
|
|
93
|
+
const frozen = unmet.filter((d) => isTaskFrozen(input.depStatuses?.[d]));
|
|
94
|
+
const hint = frozen.length > 0 ? ` — ${frozen.map((d) => `${d} deprecated (frozen); re-point the edge or un-deprecate: \`${undeprecateTaskCommand(d)}\``).join("; ")}` : "";
|
|
80
95
|
return {
|
|
81
96
|
action: "blocked",
|
|
82
97
|
code: "DEP",
|
|
83
|
-
reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})`,
|
|
98
|
+
reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})${hint}`,
|
|
84
99
|
unmetDeps: unmet
|
|
85
100
|
};
|
|
86
101
|
}
|
|
@@ -165,6 +180,13 @@ function preflightTask(input) {
|
|
|
165
180
|
reason: `dev-next: blocked — do not launch pipeline; human/handover first (${input.wbs})`
|
|
166
181
|
};
|
|
167
182
|
}
|
|
183
|
+
if (isTaskFrozen(status)) {
|
|
184
|
+
return {
|
|
185
|
+
action: "skip",
|
|
186
|
+
code: "DEPRECATED",
|
|
187
|
+
reason: `dev-next: deprecated (frozen) — un-deprecate first: ${undeprecateTaskCommand(input.wbs)} (${input.wbs})`
|
|
188
|
+
};
|
|
189
|
+
}
|
|
168
190
|
if (status === "todo" || status === "backlog") {
|
|
169
191
|
const unmet = deps.filter((d) => {
|
|
170
192
|
const st = (depStatuses[d] ?? "missing").toLowerCase();
|
|
@@ -181,6 +203,28 @@ function preflightTask(input) {
|
|
|
181
203
|
}
|
|
182
204
|
return { action: "run", code: "OK", reason: `preflight clear — launch task-pipeline for ${input.wbs}` };
|
|
183
205
|
}
|
|
206
|
+
var OPERATOR_TOOLS = new Set(["AskUserQuestion", "ask_user_question"]);
|
|
207
|
+
var SHELL_TOOLS = new Set(["bash", "shell", "exec", "exec_command", "run_command", "command"]);
|
|
208
|
+
var SUBAGENT_TOOLS = new Set(["agent", "task", "invoke_subagent", "subagent", "dispatch_agent"]);
|
|
209
|
+
var LOWERCASE_OPERATOR_TOOLS = new Set(["askuserquestion", "ask_user_question"]);
|
|
210
|
+
var SENSITIVE_PREFIXES = ["drizzle/", "packages/config/", ".github/", "plugins/sp/hooks/"];
|
|
211
|
+
var SENSITIVE_GLOBS = ["apps/server/src/**/auth*", "**/*secret*", "**/*.sql"];
|
|
212
|
+
function globToRegex(glob) {
|
|
213
|
+
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("**/", "\x00").replaceAll("**", "\x01").replaceAll("*", "[^/]*").replaceAll("\x00", "(?:.*/)?").replaceAll("\x01", ".*");
|
|
214
|
+
return new RegExp(`^${escaped}$`, "s");
|
|
215
|
+
}
|
|
216
|
+
var SENSITIVE_MATCHERS = [
|
|
217
|
+
...SENSITIVE_PREFIXES.map((prefix) => ({
|
|
218
|
+
label: prefix,
|
|
219
|
+
test: (path) => path.startsWith(prefix)
|
|
220
|
+
})),
|
|
221
|
+
...SENSITIVE_GLOBS.map((glob) => {
|
|
222
|
+
const regex = globToRegex(glob);
|
|
223
|
+
return { label: glob, test: (path) => regex.test(path) };
|
|
224
|
+
})
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
// plugins/sp/scripts/batch-preflight.ts
|
|
184
228
|
function recoveryHint(status, wbs) {
|
|
185
229
|
const st = (status ?? "").toLowerCase();
|
|
186
230
|
switch (st) {
|
|
@@ -310,7 +354,7 @@ function runPreflightCli(argv) {
|
|
|
310
354
|
return { exitCode: 0, stdout: body, stderr: "" };
|
|
311
355
|
}
|
|
312
356
|
if (args.operation !== null) {
|
|
313
|
-
const
|
|
357
|
+
const result = quickReadiness({
|
|
314
358
|
wbs: args.wbs,
|
|
315
359
|
status: args.status,
|
|
316
360
|
operation: args.operation,
|
|
@@ -321,14 +365,14 @@ function runPreflightCli(argv) {
|
|
|
321
365
|
...args.presentSections.length > 0 ? { presentSections: args.presentSections } : {},
|
|
322
366
|
...args.force ? { force: true } : {}
|
|
323
367
|
});
|
|
324
|
-
const runnable =
|
|
368
|
+
const runnable = result.action === "runnable" || result.action === "needs-refinement";
|
|
325
369
|
if (args.json) {
|
|
326
|
-
return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(
|
|
370
|
+
return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(result, null, 2)}
|
|
327
371
|
`, stderr: "" };
|
|
328
372
|
}
|
|
329
373
|
return {
|
|
330
374
|
exitCode: runnable ? 0 : 2,
|
|
331
|
-
stdout: `${
|
|
375
|
+
stdout: `${result.action}${result.code ? ` ${result.code}` : ""}: ${result.reason}
|
|
332
376
|
`,
|
|
333
377
|
stderr: ""
|
|
334
378
|
};
|
|
@@ -368,12 +412,12 @@ function runPreflightCli(argv) {
|
|
|
368
412
|
process.exit(exitCode);
|
|
369
413
|
}
|
|
370
414
|
export {
|
|
371
|
-
|
|
372
|
-
recoveryHint,
|
|
373
|
-
quickReadiness,
|
|
374
|
-
preflightTask,
|
|
375
|
-
parsePreflightCliArgs,
|
|
376
|
-
classifyFeaturePreflightFindings,
|
|
415
|
+
NON_ABORTING_PREFLIGHT_CODES,
|
|
377
416
|
PREFLIGHT_CLI_USAGE,
|
|
378
|
-
|
|
417
|
+
classifyFeaturePreflightFindings,
|
|
418
|
+
parsePreflightCliArgs,
|
|
419
|
+
preflightTask,
|
|
420
|
+
quickReadiness,
|
|
421
|
+
recoveryHint,
|
|
422
|
+
runPreflightCli
|
|
379
423
|
};
|
|
@@ -1,303 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* batch-preflight —
|
|
2
|
+
* batch-preflight — planner adapter over the pure admission policy (task 0279; task 1176 move).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The decisions — TABLE A STOP evaluation, quick command-aware readiness and feature-finding
|
|
5
|
+
* classification — are application policy in `packages/app/src/services/planning-admission.ts`,
|
|
6
|
+
* reached through the generated pure bundle. This entry keeps what belongs to the planner: the CLI
|
|
7
|
+
* surface, its argv/usage/error contracts, and the one-shot recovery hints the batch driver prints.
|
|
8
8
|
*
|
|
9
|
-
* Recovery hints (one-shot after FAIL) map stuck statuses to a single /sp:dev-* hop
|
|
10
|
-
*
|
|
9
|
+
* Recovery hints (one-shot after FAIL) map stuck statuses to a single /sp:dev-* hop per TABLE A; the
|
|
10
|
+
* batch driver prints or dispatches at most once per WBS.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
severity: string;
|
|
42
|
-
message: string;
|
|
43
|
-
section?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface FeaturePreflightClassification {
|
|
47
|
-
aborting: FeaturePreflightFinding[];
|
|
48
|
-
nonAborting: FeaturePreflightFinding[];
|
|
49
|
-
shouldAbort: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function classifyFeaturePreflightFindings(findings: FeaturePreflightFinding[]): FeaturePreflightClassification {
|
|
53
|
-
const aborting: FeaturePreflightFinding[] = [];
|
|
54
|
-
const nonAborting: FeaturePreflightFinding[] = [];
|
|
55
|
-
for (const f of findings) {
|
|
56
|
-
if (f.severity === 'error') {
|
|
57
|
-
if (NON_ABORTING_PREFLIGHT_CODES.has(f.code)) {
|
|
58
|
-
nonAborting.push(f);
|
|
59
|
-
} else {
|
|
60
|
-
aborting.push(f);
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
nonAborting.push(f);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
aborting,
|
|
68
|
-
nonAborting,
|
|
69
|
-
shouldAbort: aborting.length > 0,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ── Command-aware quick readiness (task 0814 R2) ──────────────────────────────
|
|
74
|
-
// Read-only admission decision for the requested dev operation. Distinguishes
|
|
75
|
-
// runnable / needs-refinement / blocked / skipped / invalid outcomes without
|
|
76
|
-
// LLM dispatch, full tests/lint, live-data probes, feature mutation, or
|
|
77
|
-
// corpus-wide relational checking. Refinement gaps are work to do, not errors.
|
|
78
|
-
|
|
79
|
-
export type ReadinessOperation = 'run' | 'refine' | 'verify';
|
|
80
|
-
|
|
81
|
-
export interface QuickReadinessInput {
|
|
82
|
-
wbs: string;
|
|
83
|
-
status: TaskStatus;
|
|
84
|
-
operation: ReadinessOperation;
|
|
85
|
-
/** Frontmatter dependencies[] WBS list (run only). */
|
|
86
|
-
dependencies?: string[];
|
|
87
|
-
/** Status of each dependency WBS; missing → treated as unmet (run only). */
|
|
88
|
-
depStatuses?: Record<string, string>;
|
|
89
|
-
/** Size of the status-filtered candidate set after the selector resolved; 0 = empty set. */
|
|
90
|
-
filteredCount?: number;
|
|
91
|
-
/** Required planning sections for this variant+status; empty = not applicable. */
|
|
92
|
-
requiredSections?: string[];
|
|
93
|
-
/** Sections that are actually present (non-placeholder) in the task. */
|
|
94
|
-
presentSections?: string[];
|
|
95
|
-
/** L1/L2/L3 content-policy findings keyed by section; empty = clean. */
|
|
96
|
-
sectionFindings?: Record<string, string>;
|
|
97
|
-
/** Verify only: re-verification semantics (--force) — never a dirty-tree bypass. */
|
|
98
|
-
force?: boolean;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export type QuickReadinessResult =
|
|
102
|
-
| { action: 'runnable'; code: string; reason: string }
|
|
103
|
-
| { action: 'needs-refinement'; code: string; reason: string; gaps: string[] }
|
|
104
|
-
| { action: 'blocked'; code: string; reason: string; unmetDeps?: string[] }
|
|
105
|
-
| { action: 'skipped'; code: string; reason: string }
|
|
106
|
-
| { action: 'invalid'; code: string; reason: string };
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Evaluate quick readiness for a requested dev operation (0814 R2). Read-only:
|
|
110
|
-
* no model, no full tests/lint, no live-data probe, no feature mutation, no
|
|
111
|
-
* corpus-wide relational check. An empty status-filtered set is `skipped`
|
|
112
|
-
* (mirrors the zero-task rule), never an error. Refinement gaps under `refine`
|
|
113
|
-
* are work to do, so they do not block; under `run` they are `needs-refinement`.
|
|
114
|
-
*/
|
|
115
|
-
export function quickReadiness(input: QuickReadinessInput): QuickReadinessResult {
|
|
116
|
-
const status = (input.status ?? '').toLowerCase();
|
|
117
|
-
const operation = input.operation;
|
|
118
|
-
|
|
119
|
-
if (operation !== 'run' && operation !== 'refine' && operation !== 'verify') {
|
|
120
|
-
return {
|
|
121
|
-
action: 'invalid',
|
|
122
|
-
code: 'IV',
|
|
123
|
-
reason: `quick-readiness: unknown operation '${operation}' (${input.wbs})`,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (input.filteredCount !== undefined) {
|
|
128
|
-
if (input.filteredCount < 0) {
|
|
129
|
-
return {
|
|
130
|
-
action: 'invalid',
|
|
131
|
-
code: 'IV',
|
|
132
|
-
reason: `quick-readiness: invalid negative filtered count '${input.filteredCount}' (${input.wbs})`,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
if (input.filteredCount === 0) {
|
|
136
|
-
return {
|
|
137
|
-
action: 'skipped',
|
|
138
|
-
code: 'EMPTY',
|
|
139
|
-
reason: `quick-readiness: empty status-filtered set — nothing to ${operation} (${input.wbs})`,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (status === 'cancelled' || status === 'done') {
|
|
145
|
-
// verify --force re-verification (R2 AC): an already-verified terminal task
|
|
146
|
-
// is re-checked, not skipped — but force never bypasses a dirty tree or the
|
|
147
|
-
// owning gates; it only re-admits a terminal task for re-verification.
|
|
148
|
-
if (operation === 'verify' && input.force === true) {
|
|
149
|
-
return {
|
|
150
|
-
action: 'runnable',
|
|
151
|
-
code: 'FORCE',
|
|
152
|
-
reason: `quick-readiness: verify --force re-verification of ${status} task ${input.wbs}`,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
action: 'skipped',
|
|
157
|
-
code: status === 'done' ? 'DONE' : 'CANCELLED',
|
|
158
|
-
reason: `quick-readiness: already ${status} — no ${operation} hop (${input.wbs})`,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (status === 'blocked') {
|
|
163
|
-
return {
|
|
164
|
-
action: 'blocked',
|
|
165
|
-
code: 'BLK',
|
|
166
|
-
reason: `quick-readiness: blocked — human/handover first (${input.wbs})`,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Unmet out-of-set dependency is a block for the operation that needs it.
|
|
171
|
-
if (operation === 'run' && input.dependencies && input.dependencies.length > 0) {
|
|
172
|
-
const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? 'missing').toLowerCase() !== 'done');
|
|
173
|
-
if (unmet.length > 0) {
|
|
174
|
-
return {
|
|
175
|
-
action: 'blocked',
|
|
176
|
-
code: 'DEP',
|
|
177
|
-
reason: `quick-readiness: unmet deps — ${unmet.join(', ')} (${input.wbs})`,
|
|
178
|
-
unmetDeps: unmet,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const required = input.requiredSections ?? [];
|
|
184
|
-
const present = input.presentSections ?? [];
|
|
185
|
-
// A required section is a gap when it is absent from the present-set OR carries a
|
|
186
|
-
// content-policy finding (the caller-supplied `sectionFindings` from the matrix /
|
|
187
|
-
// `TaskCheckService.checkContentPolicy`). This lets the function detect a gap itself
|
|
188
|
-
// rather than depending on the caller to pre-enumerate every missing section.
|
|
189
|
-
const gaps = required.filter((s) => {
|
|
190
|
-
const finding = input.sectionFindings?.[s];
|
|
191
|
-
return !present.includes(s) || (finding !== undefined && finding !== '');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// refine: missing/incomplete planning sections are the work, not a failure.
|
|
195
|
-
if (operation === 'refine') {
|
|
196
|
-
if (status !== 'backlog' && status !== 'todo') {
|
|
197
|
-
return {
|
|
198
|
-
action: 'skipped',
|
|
199
|
-
code: 'NONPLAN',
|
|
200
|
-
reason: `quick-readiness: refine targets backlog/todo only, not '${status}' (${input.wbs})`,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
action: 'runnable',
|
|
205
|
-
code: 'OK',
|
|
206
|
-
reason: `quick-readiness: refine ready for ${input.wbs} (${gaps.length} planning gap(s) to fill)`,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (operation === 'verify') {
|
|
211
|
-
if (status !== 'testing' && status !== 'wip') {
|
|
212
|
-
return {
|
|
213
|
-
action: 'invalid',
|
|
214
|
-
code: 'NOVERIFY',
|
|
215
|
-
reason: `quick-readiness: verify needs testing/wip, not '${status}' (${input.wbs})`,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
action: 'runnable',
|
|
220
|
-
code: 'OK',
|
|
221
|
-
reason: `quick-readiness: verify ready for ${input.wbs}`,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// run: implementation admission. Eligible statuses are todo/wip/testing;
|
|
226
|
-
// a backlog task needs the chain's auto-promotion first (step 0).
|
|
227
|
-
if (status !== 'todo' && status !== 'wip' && status !== 'testing') {
|
|
228
|
-
return {
|
|
229
|
-
action: 'invalid',
|
|
230
|
-
code: 'NORUN',
|
|
231
|
-
reason: `quick-readiness: run needs todo/wip/testing, not '${status}' (${input.wbs})`,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
if (gaps.length > 0) {
|
|
235
|
-
return {
|
|
236
|
-
action: 'needs-refinement',
|
|
237
|
-
code: 'REFINE',
|
|
238
|
-
reason: `quick-readiness: implementation sections incomplete (${input.wbs})`,
|
|
239
|
-
gaps,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
return {
|
|
243
|
-
action: 'runnable',
|
|
244
|
-
code: 'OK',
|
|
245
|
-
reason: `quick-readiness: run ready for ${input.wbs}`,
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Evaluate whether the batch should launch task-pipeline.yaml for this WBS.
|
|
251
|
-
* STOP codes align with routing-table TABLE A row ids (A2, A7, A8, A9).
|
|
252
|
-
*/
|
|
253
|
-
export function preflightTask(input: PreflightInput): PreflightResult {
|
|
254
|
-
const status = (input.status ?? '').toLowerCase();
|
|
255
|
-
const deps = input.dependencies ?? [];
|
|
256
|
-
const depStatuses = input.depStatuses ?? {};
|
|
257
|
-
|
|
258
|
-
if (status === 'cancelled') {
|
|
259
|
-
return {
|
|
260
|
-
action: 'skip',
|
|
261
|
-
code: 'A9',
|
|
262
|
-
reason: `dev-next: cancelled — nothing to advance (${input.wbs})`,
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (status === 'done') {
|
|
267
|
-
return {
|
|
268
|
-
action: 'skip',
|
|
269
|
-
code: 'A8',
|
|
270
|
-
reason: `dev-next: already done — batch does not auto-wrap (${input.wbs})`,
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (status === 'blocked') {
|
|
275
|
-
return {
|
|
276
|
-
action: 'skip',
|
|
277
|
-
code: 'A7',
|
|
278
|
-
reason: `dev-next: blocked — do not launch pipeline; human/handover first (${input.wbs})`,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// A2: todo/backlog with any dependency not done (mirrors TABLE A2 / ready filter).
|
|
283
|
-
if (status === 'todo' || status === 'backlog') {
|
|
284
|
-
const unmet = deps.filter((d) => {
|
|
285
|
-
const st = (depStatuses[d] ?? 'missing').toLowerCase();
|
|
286
|
-
return st !== 'done';
|
|
287
|
-
});
|
|
288
|
-
if (unmet.length > 0) {
|
|
289
|
-
return {
|
|
290
|
-
action: 'skip',
|
|
291
|
-
code: 'A2',
|
|
292
|
-
reason: `dev-next: blocked by deps — unmet: ${unmet.join(', ')} (${input.wbs})`,
|
|
293
|
-
unmetDeps: unmet,
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Ready for pipeline: backlog/todo (deps ok), wip, testing.
|
|
299
|
-
return { action: 'run', code: 'OK', reason: `preflight clear — launch task-pipeline for ${input.wbs}` };
|
|
300
|
-
}
|
|
13
|
+
import {
|
|
14
|
+
classifyFeaturePreflightFindings,
|
|
15
|
+
type FeaturePreflightClassification,
|
|
16
|
+
type FeaturePreflightFinding,
|
|
17
|
+
NON_ABORTING_PREFLIGHT_CODES,
|
|
18
|
+
type PreflightInput,
|
|
19
|
+
type PreflightResult,
|
|
20
|
+
preflightTask,
|
|
21
|
+
type QuickReadinessInput,
|
|
22
|
+
type QuickReadinessResult,
|
|
23
|
+
quickReadiness,
|
|
24
|
+
type ReadinessOperation,
|
|
25
|
+
type TaskStatus,
|
|
26
|
+
} from '../lib/plan-projection.generated.mjs';
|
|
27
|
+
|
|
28
|
+
export type {
|
|
29
|
+
FeaturePreflightClassification,
|
|
30
|
+
FeaturePreflightFinding,
|
|
31
|
+
PreflightInput,
|
|
32
|
+
PreflightResult,
|
|
33
|
+
QuickReadinessInput,
|
|
34
|
+
QuickReadinessResult,
|
|
35
|
+
ReadinessOperation,
|
|
36
|
+
TaskStatus,
|
|
37
|
+
};
|
|
38
|
+
// R1: existing plugin callers keep their import path — the moved names are re-exported, not relocated
|
|
39
|
+
// out from under them.
|
|
40
|
+
export { classifyFeaturePreflightFindings, NON_ABORTING_PREFLIGHT_CODES, preflightTask, quickReadiness };
|
|
301
41
|
|
|
302
42
|
/**
|
|
303
43
|
* One-shot recovery hint after a non-PASS pipeline or stuck status (TABLE A primary hop).
|
|
@@ -206,11 +206,11 @@ function main(argv, options = {}) {
|
|
|
206
206
|
process.exit(main(process.argv.slice(2)));
|
|
207
207
|
}
|
|
208
208
|
export {
|
|
209
|
-
|
|
210
|
-
runStage,
|
|
211
|
-
runCheck,
|
|
212
|
-
parsePorcelainZ,
|
|
213
|
-
main,
|
|
209
|
+
COMMIT_GUARD_USAGE,
|
|
214
210
|
conflictMarkerLine,
|
|
215
|
-
|
|
211
|
+
main,
|
|
212
|
+
parsePorcelainZ,
|
|
213
|
+
runCheck,
|
|
214
|
+
runStage,
|
|
215
|
+
runStart
|
|
216
216
|
};
|