@gobing-ai/spur 0.4.3 → 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/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 +3 -0
- package/config/rules/surface/check-cli-surface.yaml +1 -3
- package/config/templates/AGENTS.md +7 -0
- package/config/workflows/feature-verification.yaml +9 -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/agents/super-reviewer.md +5 -2
- 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/lib/history-anatomy.generated.mjs +18 -18
- package/plugins/sp/lib/idea-handoff.generated.mjs +91 -91
- package/plugins/sp/lib/inline-run.generated.mjs +233 -277
- package/plugins/sp/lib/plan-projection.generated.mjs +62 -38
- package/plugins/sp/lib/quality-gate.generated.d.mts +1 -0
- package/plugins/sp/lib/quality-gate.generated.mjs +13793 -13966
- package/plugins/sp/lib/residual-scan.generated.d.mts +13 -0
- package/plugins/sp/lib/residual-scan.generated.mjs +51 -21
- package/plugins/sp/lib/step-profile.generated.mjs +8 -8
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +62 -40
- package/plugins/sp/scripts/batch-preflight.mjs +34 -12
- package/plugins/sp/scripts/commit-guard.mjs +6 -6
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +26 -28
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +11 -11
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +4 -4
- package/plugins/sp/scripts/feature-verification-steps.mjs +15 -4
- package/plugins/sp/scripts/feature-verification-steps.ts +29 -1
- 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 +2 -2
- package/plugins/sp/scripts/inline-run-setup.mjs +20 -20
- 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 +13715 -13884
- package/plugins/sp/scripts/residual-scan.mjs +58 -27
- package/plugins/sp/scripts/residual-scan.ts +8 -8
- package/plugins/sp/scripts/run-summary.mjs +15 -15
- package/plugins/sp/scripts/script-root.mjs +6 -6
- package/plugins/sp/scripts/session-timeline.mjs +16 -16
- package/plugins/sp/scripts/task-diffstat.mjs +8 -8
- 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/next-router/SKILL.md +3 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +9 -3
- 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.md +6 -3
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +22 -2
- package/schemas/section-matrix.schema.json +3 -2
- package/spur.js +24403 -32459
- package/web/_astro/{BoardApp.5IIl2O-z.js → BoardApp.Niubpe6z.js} +1 -1
- package/web/_astro/{BoardApp.Drnx-KeM.js → BoardApp.hF0RAIrg.js} +112 -112
- package/web/_astro/TaskDetail.DJpapt38.js +1 -0
- package/web/_astro/{arc.j2EVkYVd.js → arc.BgKcK0i8.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DZWSFqEG.js → architectureDiagram-3BPJPVTR.ChP-Ig0V.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DE6GpXCN.js → blockDiagram-GPEHLZMM.BVaCBoeN.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.DoVR1G6B.js → c4Diagram-AAUBKEIU.CHSDpEO5.js} +1 -1
- package/web/_astro/channel.DkpvN2tD.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.Do6-Gbyf.js → chunk-2J33WTMH.MYRcYVRa.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BYV1HGHx.js → chunk-4BX2VUAB.S5j22Zqa.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.CvI1zkrc.js → chunk-55IACEB6.gciRPvmZ.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DNGSCRlX.js → chunk-727SXJPM.CdqrSQkX.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DXhhgT5z.js → chunk-AQP2D5EJ.CyokdHT3.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.dzkRKP2u.js → chunk-FMBD7UC4.Bg9KJhjW.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.DujGLeEf.js → chunk-ND2GUHAM.1gxxI-vD.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BWtIT3ZU.js → chunk-QZHKN3VN.DDEYtCKU.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.DyApg0Nn.js → classDiagram-4FO5ZUOK.Ch3zi37T.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.DyApg0Nn.js → classDiagram-v2-Q7XG4LA2.Ch3zi37T.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.DJQB-u_l.js → cose-bilkent-S5V4N54A.D2q5AINI.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.bi3D_siV.js → cynefin-OW5HDTMX.BA9kC2YT.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.C-f7TrRg.js → dagre-BM42HDAG.CHO08nRp.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DrPfjHQB.js → diagram-2AECGRRQ.BfFQt0LW.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.C9S4WUHO.js → diagram-5GNKFQAL.CHMwMTe4.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.Dzzye8QH.js → diagram-KO2AKTUF.BJ-7gK-w.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.DX-LRiof.js → diagram-LMA3HP47.C5xqcc0t.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.Z-kAKwIz.js → diagram-OG6HWLK6.C2pQjfrC.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.D6dyClSv.js → erDiagram-TEJ5UH35._FoNyxgC.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.Cx3q2cxD.js → flowDiagram-I6XJVG4X.B_ENkT2I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DU3gH6CT.js → ganttDiagram-6RSMTGT7.B3q8h77C.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.ISmCnJ87.js → gitGraphDiagram-PVQCEYII.QWZFDboZ.js} +1 -1
- package/web/_astro/index.BFyW13JJ.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DR6_iNOK.js → infoDiagram-5YYISTIA.Cs6eEc92.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.D7wY-ZGA.js → ishikawaDiagram-YF4QCWOH.BU9DJMHA.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.DkP9-WK8.js → journeyDiagram-JHISSGLW.D35k6Jpe.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.wtgY98M2.js → kanban-definition-UN3LZRKU.DBqcAT4m.js} +1 -1
- package/web/_astro/{linear.CI6djNi7.js → linear.D-LSNK8W.js} +1 -1
- package/web/_astro/{mermaid.core.CuQPxS8b.js → mermaid.core.CSruWVOa.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.5HNIEG7R.js → mindmap-definition-RKZ34NQL.BiFaUsfj.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.CchhDFjE.js → pieDiagram-4H26LBE5.D1KTKqb9.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.PYXXJPSJ.js → quadrantDiagram-W4KKPZXB.DBHflsMG.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.cUQuNAKU.js → requirementDiagram-4Y6WPE33.hwX9CNdk.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BO7MnRIA.js → sankeyDiagram-5OEKKPKP.DkI8mJiE.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.D9bElyD6.js → sequenceDiagram-3UESZ5HK.DMz7jBDx.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DhGdRz7I.js → stateDiagram-AJRCARHV.B6Ef2xJ1.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.5GvLeAoL.js → stateDiagram-v2-BHNVJYJU.CgoaufB9.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.LtAT9haM.js → timeline-definition-PNZ67QCA.B3c8h1t-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DRth1yLA.js → vennDiagram-CIIHVFJN.BdHPAxAb.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.h9MlZfcr.js → wardleyDiagram-YWT4CUSO.BrJXPPAj.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DHqy9DYA.js → xychartDiagram-2RQKCTM6.CMH5yFsV.js} +1 -1
- package/web/index.html +2 -2
- package/web/spur_logo.svg +1 -1
- package/web/_astro/TaskDetail.Ci4LNn9S.js +0 -1
- package/web/_astro/channel.DmdDxGsq.js +0 -1
- package/web/_astro/index.Do2lLdgo.css +0 -1
|
@@ -47,6 +47,8 @@ export declare interface ParsedScanArgs {
|
|
|
47
47
|
spurBin?: string;
|
|
48
48
|
root: string;
|
|
49
49
|
tmpDir: string;
|
|
50
|
+
/** The --review-answer <path> flag: the review answer the review-gate mode grades (task 1204). */
|
|
51
|
+
reviewAnswer?: string;
|
|
50
52
|
}
|
|
51
53
|
export declare const ALLOW_PRAGMA: 'residual-scan:allow';
|
|
52
54
|
export declare function recordedVerdictPath(runDir: string, wbs: string, fs: Pick<typeof import('node:fs'), 'lstatSync' | 'existsSync'>): string;
|
|
@@ -68,10 +70,21 @@ export declare function scanResiduals(inputs: ResidualScanInputs): ResidualArtif
|
|
|
68
70
|
export declare function parseDeferralEntries(raw: unknown): Deferral[];
|
|
69
71
|
export declare function blockingReviewFindings(taskContent: string, deferrals: Deferral[]): ResidualItem[];
|
|
70
72
|
export declare function reviewContractViolations(taskContent: string): Array<{ location: string; text: string }>;
|
|
73
|
+
export declare function reviewConfidenceViolation(
|
|
74
|
+
reviewAnswer: string,
|
|
75
|
+
ackLowConfidence: string | undefined,
|
|
76
|
+
): { location: string; text: string } | null;
|
|
77
|
+
export declare function reviewGradingInput(
|
|
78
|
+
root: string,
|
|
79
|
+
reviewAnswer: string | undefined,
|
|
80
|
+
ackLowConfidence: string | undefined,
|
|
81
|
+
fs: Pick<typeof import('node:fs'), 'readFileSync' | 'statSync'>,
|
|
82
|
+
): { answer: string; ackLowConfidence: string | undefined } | undefined;
|
|
71
83
|
export declare function buildReviewGateArtifact(
|
|
72
84
|
wbs: string,
|
|
73
85
|
taskContent: string,
|
|
74
86
|
deferrals: Deferral[],
|
|
87
|
+
review?: { answer: string; ackLowConfidence: string | undefined },
|
|
75
88
|
): { artifact: ResidualArtifact; note: string };
|
|
76
89
|
export declare function parseScanArgs(
|
|
77
90
|
argv: readonly (string | undefined)[],
|
|
@@ -219,10 +219,35 @@ function reviewContractViolations(taskContent) {
|
|
|
219
219
|
}
|
|
220
220
|
return violations;
|
|
221
221
|
}
|
|
222
|
-
function
|
|
222
|
+
function reviewConfidenceViolation(reviewAnswer, ackLowConfidence) {
|
|
223
|
+
if (ackLowConfidence === "true")
|
|
224
|
+
return null;
|
|
225
|
+
const level = extractAnswerConfidence(reviewAnswer.replace(/\*\*/g, ""));
|
|
226
|
+
if (level === "HIGH" || level === "MEDIUM")
|
|
227
|
+
return null;
|
|
228
|
+
return {
|
|
229
|
+
location: "review-answer:Confidence",
|
|
230
|
+
text: level === undefined ? "The review answer carries no valid `**Confidence:** HIGH | MEDIUM | LOW` line — a " + "PASS must be graded, or the operator must set ackLowConfidence" : `The review answer graded its PASS ${level} — HIGH/MEDIUM cross unadorned, ` + "LOW/absent needs the operator’s ackLowConfidence"
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function reviewGradingInput(root, reviewAnswer, ackLowConfidence, fs) {
|
|
234
|
+
if (reviewAnswer === undefined)
|
|
235
|
+
return;
|
|
236
|
+
const path = join(root, reviewAnswer);
|
|
237
|
+
let isFile = false;
|
|
238
|
+
try {
|
|
239
|
+
isFile = fs.statSync(path).isFile();
|
|
240
|
+
} catch {
|
|
241
|
+
isFile = false;
|
|
242
|
+
}
|
|
243
|
+
return { answer: isFile ? fs.readFileSync(path, "utf8") : "", ackLowConfidence };
|
|
244
|
+
}
|
|
245
|
+
function buildReviewGateArtifact(wbs, taskContent, deferrals, review) {
|
|
246
|
+
const confidence = review === undefined ? null : reviewConfidenceViolation(review.answer, review.ackLowConfidence);
|
|
247
|
+
const contractViolations = [...reviewContractViolations(taskContent), ...confidence === null ? [] : [confidence]];
|
|
223
248
|
const items = [
|
|
224
249
|
...blockingReviewFindings(taskContent, deferrals),
|
|
225
|
-
...
|
|
250
|
+
...contractViolations.map((v) => ({
|
|
226
251
|
id: makeItemId("review-contract", v.location, v.text),
|
|
227
252
|
category: "review-contract",
|
|
228
253
|
class: "blocking",
|
|
@@ -355,6 +380,7 @@ function parseScanArgs(argv, cwd, defaultTmpDir) {
|
|
|
355
380
|
let spurBin;
|
|
356
381
|
let root = cwd;
|
|
357
382
|
let tmpDir = defaultTmpDir;
|
|
383
|
+
let reviewAnswer;
|
|
358
384
|
for (let i = 0;i < argv.length; i++) {
|
|
359
385
|
const a = argv[i];
|
|
360
386
|
if (a === undefined)
|
|
@@ -365,6 +391,8 @@ function parseScanArgs(argv, cwd, defaultTmpDir) {
|
|
|
365
391
|
root = argv[++i] ?? root;
|
|
366
392
|
else if (a === "--tmp-dir")
|
|
367
393
|
tmpDir = argv[++i] ?? tmpDir;
|
|
394
|
+
else if (a === "--review-answer")
|
|
395
|
+
reviewAnswer = argv[++i];
|
|
368
396
|
else if (a === "--help" || a === "-h")
|
|
369
397
|
return null;
|
|
370
398
|
else if (mode === "")
|
|
@@ -372,26 +400,28 @@ function parseScanArgs(argv, cwd, defaultTmpDir) {
|
|
|
372
400
|
else if (wbs === "")
|
|
373
401
|
wbs = a;
|
|
374
402
|
}
|
|
375
|
-
return mode === "" || wbs === "" ? null : { mode, wbs, spurBin, root, tmpDir };
|
|
403
|
+
return mode === "" || wbs === "" ? null : { mode, wbs, spurBin, root, tmpDir, reviewAnswer };
|
|
376
404
|
}
|
|
377
405
|
export {
|
|
378
|
-
|
|
379
|
-
scanResiduals,
|
|
380
|
-
reviewContractViolations,
|
|
381
|
-
renderReport,
|
|
382
|
-
recordedVerdictPath,
|
|
383
|
-
parseScanArgs,
|
|
384
|
-
parseReviewFindings,
|
|
385
|
-
parseDiffMarkers,
|
|
386
|
-
parseDeferralEntries,
|
|
387
|
-
normalizeAnchor,
|
|
388
|
-
makeItemId,
|
|
389
|
-
locationOf,
|
|
390
|
-
foldVerdict,
|
|
391
|
-
findUncheckedBoxes,
|
|
392
|
-
classify,
|
|
393
|
-
buildReviewGateArtifact,
|
|
394
|
-
blockingReviewFindings,
|
|
406
|
+
ALLOW_PRAGMA,
|
|
395
407
|
blockingAnchors,
|
|
396
|
-
|
|
408
|
+
blockingReviewFindings,
|
|
409
|
+
buildReviewGateArtifact,
|
|
410
|
+
classify,
|
|
411
|
+
findUncheckedBoxes,
|
|
412
|
+
foldVerdict,
|
|
413
|
+
locationOf,
|
|
414
|
+
makeItemId,
|
|
415
|
+
normalizeAnchor,
|
|
416
|
+
parseDeferralEntries,
|
|
417
|
+
parseDiffMarkers,
|
|
418
|
+
parseReviewFindings,
|
|
419
|
+
parseScanArgs,
|
|
420
|
+
recordedVerdictPath,
|
|
421
|
+
renderReport,
|
|
422
|
+
reviewConfidenceViolation,
|
|
423
|
+
reviewContractViolations,
|
|
424
|
+
reviewGradingInput,
|
|
425
|
+
scanResiduals,
|
|
426
|
+
verdictDisagreementNote
|
|
397
427
|
};
|
|
@@ -162,13 +162,13 @@ function formatStepProfileHuman(profile) {
|
|
|
162
162
|
`;
|
|
163
163
|
}
|
|
164
164
|
export {
|
|
165
|
-
|
|
166
|
-
nonDryRuns,
|
|
167
|
-
nearestRankP50,
|
|
168
|
-
formatStepProfileHuman,
|
|
169
|
-
extractExecutions,
|
|
170
|
-
buildStepProfile,
|
|
171
|
-
buildRows,
|
|
165
|
+
DEFAULT_LAST,
|
|
172
166
|
DEFAULT_WINDOW_SEC,
|
|
173
|
-
|
|
167
|
+
buildRows,
|
|
168
|
+
buildStepProfile,
|
|
169
|
+
extractExecutions,
|
|
170
|
+
formatStepProfileHuman,
|
|
171
|
+
nearestRankP50,
|
|
172
|
+
nonDryRuns,
|
|
173
|
+
rowFlags
|
|
174
174
|
};
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
import { readFileSync } from "fs";
|
|
6
6
|
|
|
7
7
|
// plugins/sp/lib/plan-projection.generated.mjs
|
|
8
|
+
function isTaskFrozen(status) {
|
|
9
|
+
return status?.toLowerCase() === "deprecated";
|
|
10
|
+
}
|
|
11
|
+
function undeprecateTaskCommand(wbs) {
|
|
12
|
+
return `spur task update ${wbs} todo`;
|
|
13
|
+
}
|
|
8
14
|
var NON_ABORTING_PREFLIGHT_CODES = new Set([
|
|
9
15
|
"L4.scenario-unverified",
|
|
10
16
|
"L4.verifying-incomplete-tasks"
|
|
@@ -55,6 +61,13 @@ function quickReadiness(input) {
|
|
|
55
61
|
};
|
|
56
62
|
}
|
|
57
63
|
}
|
|
64
|
+
if (isTaskFrozen(status)) {
|
|
65
|
+
return {
|
|
66
|
+
action: "skipped",
|
|
67
|
+
code: "DEPRECATED",
|
|
68
|
+
reason: `quick-readiness: deprecated (frozen) — no ${operation} hop; un-deprecate with \`${undeprecateTaskCommand(input.wbs)}\` (${input.wbs})`
|
|
69
|
+
};
|
|
70
|
+
}
|
|
58
71
|
if (status === "cancelled" || status === "done") {
|
|
59
72
|
if (operation === "verify" && input.force === true) {
|
|
60
73
|
return {
|
|
@@ -79,10 +92,12 @@ function quickReadiness(input) {
|
|
|
79
92
|
if (operation === "run" && input.dependencies && input.dependencies.length > 0) {
|
|
80
93
|
const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? "missing").toLowerCase() !== "done");
|
|
81
94
|
if (unmet.length > 0) {
|
|
95
|
+
const frozen = unmet.filter((d) => isTaskFrozen(input.depStatuses?.[d]));
|
|
96
|
+
const hint = frozen.length > 0 ? ` — ${frozen.map((d) => `${d} deprecated (frozen); re-point the edge or un-deprecate: \`${undeprecateTaskCommand(d)}\``).join("; ")}` : "";
|
|
82
97
|
return {
|
|
83
98
|
action: "blocked",
|
|
84
99
|
code: "DEP",
|
|
85
|
-
reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})`,
|
|
100
|
+
reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})${hint}`,
|
|
86
101
|
unmetDeps: unmet
|
|
87
102
|
};
|
|
88
103
|
}
|
|
@@ -167,6 +182,13 @@ function preflightTask(input) {
|
|
|
167
182
|
reason: `dev-next: blocked — do not launch pipeline; human/handover first (${input.wbs})`
|
|
168
183
|
};
|
|
169
184
|
}
|
|
185
|
+
if (isTaskFrozen(status)) {
|
|
186
|
+
return {
|
|
187
|
+
action: "skip",
|
|
188
|
+
code: "DEPRECATED",
|
|
189
|
+
reason: `dev-next: deprecated (frozen) — un-deprecate first: ${undeprecateTaskCommand(input.wbs)} (${input.wbs})`
|
|
190
|
+
};
|
|
191
|
+
}
|
|
170
192
|
if (status === "todo" || status === "backlog") {
|
|
171
193
|
const unmet = deps.filter((d) => {
|
|
172
194
|
const st = (depStatuses[d] ?? "missing").toLowerCase();
|
|
@@ -274,21 +296,21 @@ function accumulate(acc, row, ts) {
|
|
|
274
296
|
if (row.type === "message") {
|
|
275
297
|
const m = row.message;
|
|
276
298
|
if (m?.role === "assistant") {
|
|
277
|
-
const
|
|
278
|
-
for (const b of
|
|
299
|
+
const blocks = Array.isArray(m.content) ? m.content : [];
|
|
300
|
+
for (const b of blocks) {
|
|
279
301
|
if (b.type === "toolCall" && b.id) {
|
|
280
302
|
acc.toolIds.add(b.id);
|
|
281
303
|
if (b.name && OPERATOR_TOOLS.has(b.name))
|
|
282
304
|
acc.asks.set(b.id, ts);
|
|
283
305
|
}
|
|
284
306
|
}
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
307
|
+
const u = m.usage;
|
|
308
|
+
if (u && row.id)
|
|
287
309
|
acc.messages.set(row.id, {
|
|
288
|
-
input:
|
|
289
|
-
cacheCreate:
|
|
290
|
-
cacheRead:
|
|
291
|
-
output:
|
|
310
|
+
input: u.input ?? 0,
|
|
311
|
+
cacheCreate: u.cacheWrite ?? 0,
|
|
312
|
+
cacheRead: u.cacheRead ?? 0,
|
|
313
|
+
output: u.output ?? 0
|
|
292
314
|
});
|
|
293
315
|
} else if (m?.role === "toolResult" && m.toolCallId && acc.asks.has(m.toolCallId)) {
|
|
294
316
|
acc.askMs += ts - (acc.asks.get(m.toolCallId) ?? ts);
|
|
@@ -1039,36 +1061,36 @@ function main(argv) {
|
|
|
1039
1061
|
process.exit(main(process.argv.slice(2)));
|
|
1040
1062
|
}
|
|
1041
1063
|
export {
|
|
1042
|
-
|
|
1043
|
-
validatePhaseTable,
|
|
1044
|
-
taskPhaseChildren,
|
|
1045
|
-
sumTokens,
|
|
1046
|
-
sumSpans,
|
|
1047
|
-
skillInvocationPrompt,
|
|
1048
|
-
sensitiveReasonForPath,
|
|
1049
|
-
scheduleBatch,
|
|
1050
|
-
quickReadiness,
|
|
1051
|
-
promptText,
|
|
1052
|
-
preflightTask,
|
|
1053
|
-
planLetter,
|
|
1054
|
-
planChild,
|
|
1055
|
-
newAcc,
|
|
1056
|
-
main,
|
|
1057
|
-
isCompaction,
|
|
1058
|
-
insertOnEntry,
|
|
1059
|
-
hostText,
|
|
1060
|
-
hostStatus,
|
|
1061
|
-
formatTokens,
|
|
1062
|
-
formatTokenSplit,
|
|
1063
|
-
formatDuration,
|
|
1064
|
-
classifyFeaturePreflightFindings,
|
|
1065
|
-
buildRunSummary,
|
|
1066
|
-
buildPhasedPlan,
|
|
1067
|
-
buildBatchPlan,
|
|
1068
|
-
actorSplit,
|
|
1069
|
-
accumulate,
|
|
1070
|
-
SENSITIVE_PREFIXES,
|
|
1071
|
-
SENSITIVE_GLOBS,
|
|
1064
|
+
BATCH_PLAN_USAGE,
|
|
1072
1065
|
NON_ABORTING_PREFLIGHT_CODES,
|
|
1073
|
-
|
|
1066
|
+
SENSITIVE_GLOBS,
|
|
1067
|
+
SENSITIVE_PREFIXES,
|
|
1068
|
+
accumulate,
|
|
1069
|
+
actorSplit,
|
|
1070
|
+
buildBatchPlan,
|
|
1071
|
+
buildPhasedPlan,
|
|
1072
|
+
buildRunSummary,
|
|
1073
|
+
classifyFeaturePreflightFindings,
|
|
1074
|
+
formatDuration,
|
|
1075
|
+
formatTokenSplit,
|
|
1076
|
+
formatTokens,
|
|
1077
|
+
hostStatus,
|
|
1078
|
+
hostText,
|
|
1079
|
+
insertOnEntry,
|
|
1080
|
+
isCompaction,
|
|
1081
|
+
main,
|
|
1082
|
+
newAcc,
|
|
1083
|
+
planChild,
|
|
1084
|
+
planLetter,
|
|
1085
|
+
preflightTask,
|
|
1086
|
+
promptText,
|
|
1087
|
+
quickReadiness,
|
|
1088
|
+
scheduleBatch,
|
|
1089
|
+
sensitiveReasonForPath,
|
|
1090
|
+
skillInvocationPrompt,
|
|
1091
|
+
sumSpans,
|
|
1092
|
+
sumTokens,
|
|
1093
|
+
taskPhaseChildren,
|
|
1094
|
+
validatePhaseTable,
|
|
1095
|
+
zeroTokens
|
|
1074
1096
|
};
|
|
@@ -3,6 +3,12 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
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();
|
|
@@ -332,7 +354,7 @@ function runPreflightCli(argv) {
|
|
|
332
354
|
return { exitCode: 0, stdout: body, stderr: "" };
|
|
333
355
|
}
|
|
334
356
|
if (args.operation !== null) {
|
|
335
|
-
const
|
|
357
|
+
const result = quickReadiness({
|
|
336
358
|
wbs: args.wbs,
|
|
337
359
|
status: args.status,
|
|
338
360
|
operation: args.operation,
|
|
@@ -343,14 +365,14 @@ function runPreflightCli(argv) {
|
|
|
343
365
|
...args.presentSections.length > 0 ? { presentSections: args.presentSections } : {},
|
|
344
366
|
...args.force ? { force: true } : {}
|
|
345
367
|
});
|
|
346
|
-
const runnable =
|
|
368
|
+
const runnable = result.action === "runnable" || result.action === "needs-refinement";
|
|
347
369
|
if (args.json) {
|
|
348
|
-
return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(
|
|
370
|
+
return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(result, null, 2)}
|
|
349
371
|
`, stderr: "" };
|
|
350
372
|
}
|
|
351
373
|
return {
|
|
352
374
|
exitCode: runnable ? 0 : 2,
|
|
353
|
-
stdout: `${
|
|
375
|
+
stdout: `${result.action}${result.code ? ` ${result.code}` : ""}: ${result.reason}
|
|
354
376
|
`,
|
|
355
377
|
stderr: ""
|
|
356
378
|
};
|
|
@@ -390,12 +412,12 @@ function runPreflightCli(argv) {
|
|
|
390
412
|
process.exit(exitCode);
|
|
391
413
|
}
|
|
392
414
|
export {
|
|
393
|
-
|
|
394
|
-
recoveryHint,
|
|
395
|
-
quickReadiness,
|
|
396
|
-
preflightTask,
|
|
397
|
-
parsePreflightCliArgs,
|
|
398
|
-
classifyFeaturePreflightFindings,
|
|
415
|
+
NON_ABORTING_PREFLIGHT_CODES,
|
|
399
416
|
PREFLIGHT_CLI_USAGE,
|
|
400
|
-
|
|
417
|
+
classifyFeaturePreflightFindings,
|
|
418
|
+
parsePreflightCliArgs,
|
|
419
|
+
preflightTask,
|
|
420
|
+
quickReadiness,
|
|
421
|
+
recoveryHint,
|
|
422
|
+
runPreflightCli
|
|
401
423
|
};
|
|
@@ -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
|
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @bun
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
5
3
|
|
|
6
4
|
// plugins/sp/scripts/daily-summary/daily-summary.ts
|
|
7
5
|
import { spawn, spawnSync } from "child_process";
|
|
@@ -41,8 +39,8 @@ function resolveAppEntry(spurBin) {
|
|
|
41
39
|
}
|
|
42
40
|
return { entry, portable: true };
|
|
43
41
|
}
|
|
44
|
-
async function loadInlineApp(spurBin,
|
|
45
|
-
const { entry, portable } =
|
|
42
|
+
async function loadInlineApp(spurBin, resolveAppEntry, required) {
|
|
43
|
+
const { entry, portable } = resolveAppEntry(spurBin);
|
|
46
44
|
const app = await import(entry);
|
|
47
45
|
const missing = portable ? required.filter((name) => typeof app[name] !== "function") : [];
|
|
48
46
|
if (missing.length > 0) {
|
|
@@ -143,7 +141,7 @@ function getDateRange(dateStr) {
|
|
|
143
141
|
return { start, end };
|
|
144
142
|
}
|
|
145
143
|
var defaultProcessSpawner = (cmd, args, env) => {
|
|
146
|
-
return new Promise((
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
147
145
|
try {
|
|
148
146
|
const proc = spawn(cmd, args, {
|
|
149
147
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -154,7 +152,7 @@ var defaultProcessSpawner = (cmd, args, env) => {
|
|
|
154
152
|
proc.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.from(chunk)));
|
|
155
153
|
proc.stderr.on("data", (chunk) => stderrChunks.push(Buffer.from(chunk)));
|
|
156
154
|
proc.on("close", (exitCode) => {
|
|
157
|
-
|
|
155
|
+
resolve({
|
|
158
156
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
159
157
|
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
160
158
|
exitCode: exitCode ?? 0
|
|
@@ -319,12 +317,12 @@ Please provide the following (press Enter to skip):
|
|
|
319
317
|
chunks.push(chunk);
|
|
320
318
|
}
|
|
321
319
|
const buffered = Buffer.concat(chunks).toString("utf-8");
|
|
322
|
-
const [
|
|
320
|
+
const [learnings = "", issuesFixed = "", pending = ""] = buffered.split(`
|
|
323
321
|
`);
|
|
324
322
|
return {
|
|
325
|
-
learnings:
|
|
326
|
-
issuesFixed:
|
|
327
|
-
pending:
|
|
323
|
+
learnings: learnings.trim(),
|
|
324
|
+
issuesFixed: issuesFixed.trim(),
|
|
325
|
+
pending: pending.trim()
|
|
328
326
|
};
|
|
329
327
|
}
|
|
330
328
|
const readline = await import("readline");
|
|
@@ -332,9 +330,9 @@ Please provide the following (press Enter to skip):
|
|
|
332
330
|
input: process.stdin,
|
|
333
331
|
output: process.stdout
|
|
334
332
|
});
|
|
335
|
-
const question = (prompt) => new Promise((
|
|
333
|
+
const question = (prompt) => new Promise((resolve) => {
|
|
336
334
|
rl.question(prompt, (answer) => {
|
|
337
|
-
|
|
335
|
+
resolve(answer.trim());
|
|
338
336
|
});
|
|
339
337
|
});
|
|
340
338
|
const learnings = await question(`1. What did you learn today? (optional)
|
|
@@ -608,21 +606,21 @@ ${markdown}
|
|
|
608
606
|
});
|
|
609
607
|
}
|
|
610
608
|
export {
|
|
611
|
-
|
|
612
|
-
writeSummary,
|
|
613
|
-
todayLocal,
|
|
614
|
-
setProcessSpawner,
|
|
615
|
-
promptUser,
|
|
616
|
-
printUsage,
|
|
617
|
-
parseArgs,
|
|
618
|
-
main,
|
|
619
|
-
getSpurHistoryHealth,
|
|
620
|
-
getGitCommits,
|
|
621
|
-
getDateRange,
|
|
622
|
-
getCcusageData,
|
|
623
|
-
generateMarkdown,
|
|
624
|
-
ensureDir,
|
|
625
|
-
enableLogger,
|
|
609
|
+
buildDailySummary,
|
|
626
610
|
defaultProcessSpawner,
|
|
627
|
-
|
|
611
|
+
enableLogger,
|
|
612
|
+
ensureDir,
|
|
613
|
+
generateMarkdown,
|
|
614
|
+
getCcusageData,
|
|
615
|
+
getDateRange,
|
|
616
|
+
getGitCommits,
|
|
617
|
+
getSpurHistoryHealth,
|
|
618
|
+
main,
|
|
619
|
+
parseArgs,
|
|
620
|
+
printUsage,
|
|
621
|
+
promptUser,
|
|
622
|
+
setProcessSpawner,
|
|
623
|
+
todayLocal,
|
|
624
|
+
writeSummary,
|
|
625
|
+
yesterdayLocal
|
|
628
626
|
};
|
|
@@ -196,16 +196,16 @@ function runCli(argv) {
|
|
|
196
196
|
process.exit(exitCode);
|
|
197
197
|
}
|
|
198
198
|
export {
|
|
199
|
-
|
|
200
|
-
parseCliArgs,
|
|
201
|
-
isImplementHeavyStep,
|
|
202
|
-
hasMutatingFixMode,
|
|
203
|
-
evaluateDogfoodGate,
|
|
204
|
-
detectPipelineDriving,
|
|
205
|
-
detectImplementHeavy,
|
|
206
|
-
PIPELINE_TOKENS,
|
|
207
|
-
PIPELINE_DRIVING_REFUSE_MESSAGE,
|
|
208
|
-
MUTATING_FIX_REFUSE_MESSAGE,
|
|
199
|
+
CLI_USAGE,
|
|
209
200
|
IMPLEMENT_HEAVY_ADVISORY_MESSAGE,
|
|
210
|
-
|
|
201
|
+
MUTATING_FIX_REFUSE_MESSAGE,
|
|
202
|
+
PIPELINE_DRIVING_REFUSE_MESSAGE,
|
|
203
|
+
PIPELINE_TOKENS,
|
|
204
|
+
detectImplementHeavy,
|
|
205
|
+
detectPipelineDriving,
|
|
206
|
+
evaluateDogfoodGate,
|
|
207
|
+
hasMutatingFixMode,
|
|
208
|
+
isImplementHeavyStep,
|
|
209
|
+
parseCliArgs,
|
|
210
|
+
runCli
|
|
211
211
|
};
|
|
@@ -274,9 +274,9 @@ function mainCli(argv = process.argv.slice(2)) {
|
|
|
274
274
|
process.exit(mainCli());
|
|
275
275
|
}
|
|
276
276
|
export {
|
|
277
|
-
|
|
278
|
-
runValidateCli,
|
|
279
|
-
parseValidateCliArgs,
|
|
277
|
+
VALIDATE_CLI_USAGE,
|
|
280
278
|
mainCli,
|
|
281
|
-
|
|
279
|
+
parseValidateCliArgs,
|
|
280
|
+
runValidateCli,
|
|
281
|
+
validateReport
|
|
282
282
|
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// plugins/sp/scripts/feature-verification-steps.ts
|
|
5
|
+
import { spawnSync } from "child_process";
|
|
5
6
|
import { existsSync } from "fs";
|
|
6
7
|
import { fileURLToPath } from "url";
|
|
7
8
|
|
|
@@ -42,17 +43,27 @@ async function requireModule(entry, mode) {
|
|
|
42
43
|
}
|
|
43
44
|
return mod;
|
|
44
45
|
}
|
|
45
|
-
async function verify(featureId, runId, cmdOverride, spurBin, mode) {
|
|
46
|
+
async function verify(featureId, runId, cmdOverride, spurBin, mode, confidenceOverride, ackLowConfidence) {
|
|
46
47
|
const mod = await loadModule(spurBin, mode);
|
|
47
48
|
const result = await mod.runFeatureVerification({
|
|
48
49
|
workdir: process.cwd(),
|
|
49
50
|
featureId,
|
|
50
51
|
runId,
|
|
51
|
-
cmdOverride
|
|
52
|
+
cmdOverride,
|
|
53
|
+
confidenceOverride,
|
|
54
|
+
ackLowConfidence
|
|
52
55
|
});
|
|
53
56
|
console.log(`feature-verification-steps: ${featureId} ${result.message}`);
|
|
54
57
|
}
|
|
55
58
|
function main() {
|
|
59
|
+
if (!process.versions.bun) {
|
|
60
|
+
const child = spawnSync("bun", [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
|
|
61
|
+
stdio: "inherit"
|
|
62
|
+
});
|
|
63
|
+
if (child.error)
|
|
64
|
+
console.error(`feature-verification-steps requires Bun on PATH: ${child.error.message}`);
|
|
65
|
+
process.exit(child.status ?? 1);
|
|
66
|
+
}
|
|
56
67
|
const args = process.argv.slice(2);
|
|
57
68
|
const command = args[0];
|
|
58
69
|
const flag = (name) => {
|
|
@@ -60,10 +71,10 @@ function main() {
|
|
|
60
71
|
return i >= 0 && i + 1 < args.length ? args[i + 1] ?? "" : "";
|
|
61
72
|
};
|
|
62
73
|
if (command !== "verify") {
|
|
63
|
-
console.error("Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>]");
|
|
74
|
+
console.error("Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>] [--confidence HIGH|MEDIUM|LOW] [--ack-low-confidence]");
|
|
64
75
|
process.exit(2);
|
|
65
76
|
}
|
|
66
|
-
verify(flag("--feature-id") || getEnvVar("featureId") || "", flag("--run-id") || getEnvVar("__runId") || "", flag("--cmd") || getEnvVar("verificationCmd") || "", flag("--spur-bin") || getEnvVar("spurBin") || "", resolveModuleMode(flag("--module-mode"))).then(() => process.exit(0)).catch((err) => {
|
|
77
|
+
verify(flag("--feature-id") || getEnvVar("featureId") || "", flag("--run-id") || getEnvVar("__runId") || "", flag("--cmd") || getEnvVar("verificationCmd") || "", flag("--spur-bin") || getEnvVar("spurBin") || "", resolveModuleMode(flag("--module-mode")), flag("--confidence") || getEnvVar("confidence") || "", args.includes("--ack-low-confidence") || getEnvVar("ackLowConfidence") === "true").then(() => process.exit(0)).catch((err) => {
|
|
67
78
|
console.error(`feature-verification-steps: ${String(err)}`);
|
|
68
79
|
process.exit(1);
|
|
69
80
|
});
|