@gobing-ai/spur 0.4.3 → 0.4.5
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/sourced-api-claims.yaml +3 -2
- package/config/rules/quality/coverage-gate.yaml +13 -0
- package/config/rules/recommended-pre-check.yaml +11 -5
- 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 +31 -65
- package/package.json +10 -10
- package/plugins/sp/agents/super-reviewer.md +11 -24
- 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.mjs +20 -34
- 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 +24 -38
- package/plugins/sp/scripts/residual-scan.ts +4 -6
- 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/code-verification/SKILL.md +1 -2
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +11 -32
- 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/execution-workflow.md +7 -11
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +29 -8
- package/schemas/section-matrix.schema.json +3 -2
- package/spur.js +24597 -32769
- 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
|
@@ -21,14 +21,6 @@ function hasClaimMarker(evidence) {
|
|
|
21
21
|
function hasCitationForm(evidence) {
|
|
22
22
|
return CITATION_FORMS.some((re) => re.test(evidence));
|
|
23
23
|
}
|
|
24
|
-
var CONFIDENCE_LEVELS = ["HIGH", "MEDIUM", "LOW"];
|
|
25
|
-
function extractAnswerConfidence(text) {
|
|
26
|
-
const matches = [...text.matchAll(/^\s*Confidence:\s*(\S+)\s*$/gim)];
|
|
27
|
-
if (matches.length !== 1)
|
|
28
|
-
return;
|
|
29
|
-
const value = (matches[0]?.[1] ?? "").toUpperCase();
|
|
30
|
-
return CONFIDENCE_LEVELS.includes(value) ? value : undefined;
|
|
31
|
-
}
|
|
32
24
|
|
|
33
25
|
// packages/app/src/services/residual-scan.ts
|
|
34
26
|
var MARKER_PATTERN = /TODO|FIXME|XXX|HACK/;
|
|
@@ -202,13 +194,6 @@ function blockingReviewFindings(taskContent, deferrals) {
|
|
|
202
194
|
}
|
|
203
195
|
function reviewContractViolations(taskContent) {
|
|
204
196
|
const violations = [];
|
|
205
|
-
const body = reviewBody(taskContent);
|
|
206
|
-
if (body !== null && extractAnswerConfidence(body.replace(/\*\*/g, "")) === undefined) {
|
|
207
|
-
violations.push({
|
|
208
|
-
location: "task-file:Review",
|
|
209
|
-
text: "Review report carries no single valid `**Confidence:** HIGH | MEDIUM | LOW` line — " + "state the level the report can defend (HIGH: every requirement row MET, every finding " + "dispositioned, evidence cited; MEDIUM/LOW: name the gap)."
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
197
|
for (const row of parseReviewFindings(taskContent)) {
|
|
213
198
|
if (hasClaimMarker(row.text) && !hasCitationForm(row.text)) {
|
|
214
199
|
violations.push({
|
|
@@ -220,9 +205,10 @@ function reviewContractViolations(taskContent) {
|
|
|
220
205
|
return violations;
|
|
221
206
|
}
|
|
222
207
|
function buildReviewGateArtifact(wbs, taskContent, deferrals) {
|
|
208
|
+
const contractViolations = reviewContractViolations(taskContent);
|
|
223
209
|
const items = [
|
|
224
210
|
...blockingReviewFindings(taskContent, deferrals),
|
|
225
|
-
...
|
|
211
|
+
...contractViolations.map((v) => ({
|
|
226
212
|
id: makeItemId("review-contract", v.location, v.text),
|
|
227
213
|
category: "review-contract",
|
|
228
214
|
class: "blocking",
|
|
@@ -375,23 +361,23 @@ function parseScanArgs(argv, cwd, defaultTmpDir) {
|
|
|
375
361
|
return mode === "" || wbs === "" ? null : { mode, wbs, spurBin, root, tmpDir };
|
|
376
362
|
}
|
|
377
363
|
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,
|
|
364
|
+
ALLOW_PRAGMA,
|
|
395
365
|
blockingAnchors,
|
|
396
|
-
|
|
366
|
+
blockingReviewFindings,
|
|
367
|
+
buildReviewGateArtifact,
|
|
368
|
+
classify,
|
|
369
|
+
findUncheckedBoxes,
|
|
370
|
+
foldVerdict,
|
|
371
|
+
locationOf,
|
|
372
|
+
makeItemId,
|
|
373
|
+
normalizeAnchor,
|
|
374
|
+
parseDeferralEntries,
|
|
375
|
+
parseDiffMarkers,
|
|
376
|
+
parseReviewFindings,
|
|
377
|
+
parseScanArgs,
|
|
378
|
+
recordedVerdictPath,
|
|
379
|
+
renderReport,
|
|
380
|
+
reviewContractViolations,
|
|
381
|
+
scanResiduals,
|
|
382
|
+
verdictDisagreementNote
|
|
397
383
|
};
|
|
@@ -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.5",
|
|
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
|
});
|
|
@@ -18,10 +18,16 @@
|
|
|
18
18
|
* Always exits 0 after a completed pass; the transition guard reads the status file and the
|
|
19
19
|
* completion boundary validates the receipt (fail-closed). Unsafe ids are refused by the operation.
|
|
20
20
|
*
|
|
21
|
+
* The installed `.mjs` twin may be launched with plain `node` (the `feature-verification` workflow
|
|
22
|
+
* selects `installed -> node`), but the generated inline bundle keeps `bun:sqlite` external by design, so the
|
|
23
|
+
* twin re-enters Bun at the top of `main()` (task 1197). Unlike daily-summary it fails closed when Bun
|
|
24
|
+
* is missing — a verifier that cannot load its bundle cannot run the checks.
|
|
25
|
+
*
|
|
21
26
|
* Node-builtin imports only (ADR-065); the application seams come from the generated inline bundle,
|
|
22
27
|
* never from `packages/app/src/index.ts`, which is not a plugin-script contract surface (0948 R3).
|
|
23
28
|
*/
|
|
24
29
|
|
|
30
|
+
import { spawnSync } from 'node:child_process';
|
|
25
31
|
import { existsSync } from 'node:fs';
|
|
26
32
|
import { fileURLToPath } from 'node:url';
|
|
27
33
|
import { getEnvVar } from '../lib/env';
|
|
@@ -97,6 +103,8 @@ async function verify(
|
|
|
97
103
|
cmdOverride: string,
|
|
98
104
|
spurBin: string,
|
|
99
105
|
mode: ModuleMode,
|
|
106
|
+
confidenceOverride: string,
|
|
107
|
+
ackLowConfidence: boolean,
|
|
100
108
|
): Promise<void> {
|
|
101
109
|
const mod = await loadModule(spurBin, mode);
|
|
102
110
|
const result = await mod.runFeatureVerification({
|
|
@@ -104,11 +112,26 @@ async function verify(
|
|
|
104
112
|
featureId,
|
|
105
113
|
runId,
|
|
106
114
|
cmdOverride,
|
|
115
|
+
// Operator-declared level (empty = derive from the pass) and the acknowledgement of a LOW
|
|
116
|
+
// level. Both ride the receipt, so the completion boundary reads them from the evidence
|
|
117
|
+
// rather than from whatever flags a later transition happens to pass.
|
|
118
|
+
confidenceOverride,
|
|
119
|
+
ackLowConfidence,
|
|
107
120
|
});
|
|
108
121
|
console.log(`feature-verification-steps: ${featureId} ${result.message}`);
|
|
109
122
|
}
|
|
110
123
|
|
|
111
124
|
function main(): void {
|
|
125
|
+
// The portable Node twin has no workspace imports; the generated bundle still uses Spur's Bun
|
|
126
|
+
// runtime (bun:sqlite stays external by design). Re-enter Bun before any app import; fail closed
|
|
127
|
+
// when Bun is missing — the verifier must not report a pass it could not run.
|
|
128
|
+
if (!process.versions.bun) {
|
|
129
|
+
const child = spawnSync('bun', [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
|
|
130
|
+
stdio: 'inherit',
|
|
131
|
+
});
|
|
132
|
+
if (child.error) console.error(`feature-verification-steps requires Bun on PATH: ${child.error.message}`);
|
|
133
|
+
process.exit(child.status ?? 1);
|
|
134
|
+
}
|
|
112
135
|
const args = process.argv.slice(2);
|
|
113
136
|
const command = args[0];
|
|
114
137
|
const flag = (name: string): string => {
|
|
@@ -116,7 +139,10 @@ function main(): void {
|
|
|
116
139
|
return i >= 0 && i + 1 < args.length ? (args[i + 1] ?? '') : '';
|
|
117
140
|
};
|
|
118
141
|
if (command !== 'verify') {
|
|
119
|
-
console.error(
|
|
142
|
+
console.error(
|
|
143
|
+
'Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>] ' +
|
|
144
|
+
'[--confidence HIGH|MEDIUM|LOW] [--ack-low-confidence]',
|
|
145
|
+
);
|
|
120
146
|
process.exit(2);
|
|
121
147
|
}
|
|
122
148
|
verify(
|
|
@@ -125,6 +151,8 @@ function main(): void {
|
|
|
125
151
|
flag('--cmd') || getEnvVar('verificationCmd') || '',
|
|
126
152
|
flag('--spur-bin') || getEnvVar('spurBin') || '',
|
|
127
153
|
resolveModuleMode(flag('--module-mode')),
|
|
154
|
+
flag('--confidence') || getEnvVar('confidence') || '',
|
|
155
|
+
args.includes('--ack-low-confidence') || getEnvVar('ackLowConfidence') === 'true',
|
|
128
156
|
)
|
|
129
157
|
.then(() => process.exit(0))
|
|
130
158
|
.catch((err: unknown) => {
|