@gobing-ai/spur 0.3.50 → 0.3.51
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/corpus-baseline.json +1995 -1939
- package/config/rules/quality/coverage-gate.yaml +3 -2
- package/config/workflows/pr-review.yaml +13 -11
- package/config/workflows/task-pipeline.yaml +37 -16
- package/package.json +1 -1
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/pr-reviewing.ts +35 -1
- package/plugins/sp/skills/pr-reviewing/SKILL.md +6 -3
- package/spur.js +53 -12
|
@@ -2,8 +2,9 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
|
2
2
|
# Coverage gate — per-file line coverage meets threshold from Bun's lcov output.
|
|
3
3
|
# Absorbed from ts-libs/.spur/rules/quality/coverage-gate.yaml, re-scoped to
|
|
4
4
|
# Spur's monorepo layout:
|
|
5
|
-
# - lcovPath kept at .coverage/lcov.info (Spur's `bun run test`
|
|
6
|
-
#
|
|
5
|
+
# - lcovPath kept at .coverage/lcov.info (Spur's `bun run test:coverage` —
|
|
6
|
+
# what `bun run check` and the `*:full` chains run — writes coverage there
|
|
7
|
+
# via --coverage-dir=.coverage; plain `bun run test` skips coverage)
|
|
7
8
|
# - include expanded to apps/** + packages/** (Spur tests cover both;
|
|
8
9
|
# ts-libs only covers packages/**)
|
|
9
10
|
# - threshold kept at 90 matching bunfig.toml coverageThreshold
|
|
@@ -43,19 +43,21 @@ terminalStates:
|
|
|
43
43
|
failureStates:
|
|
44
44
|
- failed
|
|
45
45
|
vars:
|
|
46
|
-
mode:
|
|
47
|
-
baseBranch:
|
|
48
|
-
focus:
|
|
49
|
-
noWait:
|
|
50
|
-
waitTimeoutSec:
|
|
51
|
-
waitIntervalSec:
|
|
52
|
-
preReviewCmd:
|
|
53
|
-
__runId:
|
|
46
|
+
mode: "full"
|
|
47
|
+
baseBranch: ""
|
|
48
|
+
focus: ""
|
|
49
|
+
noWait: "false"
|
|
50
|
+
waitTimeoutSec: "600"
|
|
51
|
+
waitIntervalSec: "30"
|
|
52
|
+
preReviewCmd: ""
|
|
53
|
+
__runId: ""
|
|
54
54
|
|
|
55
55
|
states:
|
|
56
56
|
- id: preflight
|
|
57
57
|
description: >
|
|
58
|
-
Soft probe: git/gh/repo checks (detached HEAD, dirty tree, gh auth, GitHub remote
|
|
58
|
+
Soft probe: git/gh/repo checks (detached HEAD, dirty tree, gh auth, GitHub remote,
|
|
59
|
+
base-branch refusal — preflight refuses when the current branch IS the resolved base,
|
|
60
|
+
before any push can publish it).
|
|
59
61
|
Writes PASS|FAIL to .spur/run/${vars.__runId}-pr-preflight.status; always exit 0.
|
|
60
62
|
onEnter:
|
|
61
63
|
- kind: shell
|
|
@@ -64,7 +66,7 @@ states:
|
|
|
64
66
|
mkdir -p .spur/run &&
|
|
65
67
|
STATUS_FILE=".spur/run/$__runId-pr-preflight.status" &&
|
|
66
68
|
set +e &&
|
|
67
|
-
bun "$(superskill script path sp pr-reviewing.ts)" preflight --json > ".spur/run/$__runId-pr-context.json";
|
|
69
|
+
bun "$(superskill script path sp pr-reviewing.ts)" preflight --base "$baseBranch" --json > ".spur/run/$__runId-pr-context.json";
|
|
68
70
|
rc=$?; set -e &&
|
|
69
71
|
if [ "$rc" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
70
72
|
exit 0
|
|
@@ -212,7 +214,7 @@ transitions:
|
|
|
212
214
|
command: 'test "$(cat .spur/run/$__runId-pr-preflight.status 2>/dev/null)" = PASS'
|
|
213
215
|
- from: preflight
|
|
214
216
|
to: failed
|
|
215
|
-
description: Preflight red (detached HEAD, dirty tree, gh auth, no GitHub remote) — stop before any publishing
|
|
217
|
+
description: Preflight red (detached HEAD, dirty tree, gh auth, no GitHub remote, or the current branch being the base branch) — stop before any publishing
|
|
216
218
|
guard:
|
|
217
219
|
kind: always
|
|
218
220
|
|
|
@@ -85,6 +85,12 @@ vars:
|
|
|
85
85
|
# TRUSTED CONFIG ONLY — this string is executed via `sh -c` (see test/test-recheck). Never
|
|
86
86
|
# interpolate untrusted operator/LLM input into qualityGateCmd (task 0436 SECUA residual).
|
|
87
87
|
qualityGateCmd: "bun run format && bun run spur-check"
|
|
88
|
+
# Cheap red-detector run before the full gate on **recheck only**; empty ⇒ no probe
|
|
89
|
+
# (full gate every recheck — the pre-0587 behavior). A project overriding qualityGateCmd
|
|
90
|
+
# should override this too. TRUSTED CONFIG ONLY — executed via `sh -c` (same surface as
|
|
91
|
+
# qualityGateCmd). Invariant: `review` is only ever entered through a full green
|
|
92
|
+
# qualityGateCmd — only the full gate writes PASS to <wbs>-test-gate.status.
|
|
93
|
+
gateProbeCmd: "bun run lint"
|
|
88
94
|
# Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
|
|
89
95
|
# Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
|
|
90
96
|
qualityGateMaxFixAttempts: "2"
|
|
@@ -300,7 +306,7 @@ states:
|
|
|
300
306
|
# `${vars.qualityGateCmd}` at `test` is the gate that actually decides.
|
|
301
307
|
- kind: shell
|
|
302
308
|
options:
|
|
303
|
-
command:
|
|
309
|
+
command: "$formatCmd ; exit 0"
|
|
304
310
|
|
|
305
311
|
# ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
|
|
306
312
|
# NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
|
|
@@ -389,28 +395,43 @@ states:
|
|
|
389
395
|
or the pipeline `failed` state (FAIL and attempts exhausted) — never a
|
|
390
396
|
raw lifecycle abort that skips the terminal `failed` state.
|
|
391
397
|
onEnter:
|
|
398
|
+
# 0587 R3: probe-then-full recheck. A red gateProbeCmd records FAIL and skips the full
|
|
399
|
+
# gate (the measured waste is re-running a 110–140s gate to learn the tree is still red);
|
|
400
|
+
# a green probe (or empty gateProbeCmd) falls through to the full-gate loop unchanged.
|
|
401
|
+
# Only the full gate writes PASS, so the `test-recheck → review` guard (reads PASS)
|
|
402
|
+
# still means a full green qualityGateCmd ran — invariant preserved by construction.
|
|
392
403
|
- kind: shell
|
|
393
404
|
options:
|
|
394
405
|
command: >-
|
|
395
406
|
mkdir -p .spur/run &&
|
|
396
407
|
STATUS_FILE=".spur/run/$wbs-test-gate.status" &&
|
|
397
408
|
LOG_FILE=".spur/run/$wbs-test-gate.log" &&
|
|
409
|
+
FINDINGS_FILE=".spur/run/$wbs-test-gate.findings" &&
|
|
398
410
|
: > "$LOG_FILE" &&
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
411
|
+
probe_rc=0;
|
|
412
|
+
if [ -n "$gateProbeCmd" ]; then
|
|
413
|
+
sh -c "$gateProbeCmd" > "$LOG_FILE.probe" 2>&1; probe_rc=$?;
|
|
414
|
+
cat "$LOG_FILE.probe" >> "$LOG_FILE";
|
|
415
|
+
rm -f "$LOG_FILE.probe";
|
|
416
|
+
fi;
|
|
417
|
+
if [ "$probe_rc" -ne 0 ]; then
|
|
418
|
+
gate_rc=$probe_rc;
|
|
419
|
+
else
|
|
420
|
+
gate_attempt=1;
|
|
421
|
+
while [ "$gate_attempt" -le 5 ]; do
|
|
422
|
+
ATTEMPT_LOG="$LOG_FILE.attempt-$gate_attempt";
|
|
423
|
+
sh -c "$qualityGateCmd" > "$ATTEMPT_LOG" 2>&1; gate_rc=$?;
|
|
424
|
+
gate_locked=0;
|
|
425
|
+
grep -q 'SQLiteError: database is locked' "$ATTEMPT_LOG" && gate_locked=1;
|
|
426
|
+
cat "$ATTEMPT_LOG" >> "$LOG_FILE";
|
|
427
|
+
rm -f "$ATTEMPT_LOG";
|
|
428
|
+
if [ "$gate_rc" -eq 0 ] || [ "$gate_locked" -ne 1 ] || [ "$gate_attempt" -ge 5 ]; then break; fi;
|
|
429
|
+
printf 'quality gate: database is locked; retrying (%s/5) in 10s\n' "$gate_attempt" | tee -a "$LOG_FILE";
|
|
430
|
+
sleep 10;
|
|
431
|
+
gate_attempt=$((gate_attempt + 1));
|
|
432
|
+
done;
|
|
433
|
+
fi &&
|
|
412
434
|
cat "$LOG_FILE" &&
|
|
413
|
-
FINDINGS_FILE=".spur/run/$wbs-test-gate.findings" &&
|
|
414
435
|
set +e; grep -oE '[A-Za-z0-9_./-]+\.[A-Za-z]+:[0-9]+' "$LOG_FILE" | sort -u | head -20 | tr '\n' ' ' > "$FINDINGS_FILE"; set -e &&
|
|
415
436
|
if [ "$gate_rc" -eq 0 ]; then
|
|
416
437
|
printf 'PASS\n' > "$STATUS_FILE";
|
|
@@ -709,4 +730,4 @@ transitions:
|
|
|
709
730
|
guard:
|
|
710
731
|
kind: shell
|
|
711
732
|
options:
|
|
712
|
-
command:
|
|
733
|
+
command: "! $spurBin task check $wbs"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.51",
|
|
4
4
|
"description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spur",
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.51",
|
|
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"]
|
|
@@ -88,6 +88,12 @@ interface PreflightContext {
|
|
|
88
88
|
defaultBranch: string;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
interface Upstream {
|
|
92
|
+
ref: string;
|
|
93
|
+
ahead: number;
|
|
94
|
+
behind: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
interface Finding {
|
|
92
98
|
kind: 'review' | 'inline' | 'comment';
|
|
93
99
|
severity: string;
|
|
@@ -433,6 +439,22 @@ function preflightContext(): PreflightContext {
|
|
|
433
439
|
};
|
|
434
440
|
}
|
|
435
441
|
|
|
442
|
+
/** Upstream divergence, non-fatal: a missing upstream is a normal state, not an error. */
|
|
443
|
+
function resolveUpstream(): Upstream | null {
|
|
444
|
+
const refRes = run(['git', 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}']);
|
|
445
|
+
if (refRes.code !== 0) return null;
|
|
446
|
+
const ref = refRes.stdout.trim();
|
|
447
|
+
const count = (res: CmdResult): number => {
|
|
448
|
+
const n = Number(res.stdout.trim());
|
|
449
|
+
return res.code === 0 && Number.isFinite(n) ? n : 0;
|
|
450
|
+
};
|
|
451
|
+
return {
|
|
452
|
+
ref,
|
|
453
|
+
ahead: count(run(['git', 'rev-list', '--count', '@{u}..HEAD'])),
|
|
454
|
+
behind: count(run(['git', 'rev-list', '--count', 'HEAD..@{u}'])),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
436
458
|
function viewPr(): GhPr | null {
|
|
437
459
|
const res = run([
|
|
438
460
|
'gh',
|
|
@@ -507,15 +529,27 @@ function cmdPreflight(args: ParsedArgs): void {
|
|
|
507
529
|
2,
|
|
508
530
|
);
|
|
509
531
|
}
|
|
532
|
+
const base = (args.flags.get('--base') ?? '').trim() || ctx.defaultBranch;
|
|
533
|
+
const upstream = resolveUpstream();
|
|
534
|
+
if (ctx.branch === base) {
|
|
535
|
+
writeStatus(args, 'FAIL');
|
|
536
|
+
fail(
|
|
537
|
+
args,
|
|
538
|
+
`current branch is the base branch (${base}) — a PR reviews a feature branch against it; ` +
|
|
539
|
+
'check out a feature branch (nothing on the base branch is reviewable)',
|
|
540
|
+
2,
|
|
541
|
+
);
|
|
542
|
+
}
|
|
510
543
|
writeStatus(args, 'PASS');
|
|
511
544
|
emit(
|
|
512
545
|
args,
|
|
513
|
-
{ ok: true, ...ctx },
|
|
546
|
+
{ ok: true, ...ctx, upstream },
|
|
514
547
|
[
|
|
515
548
|
`Repository: ${ctx.nameWithOwner}`,
|
|
516
549
|
`Branch: ${ctx.branch}`,
|
|
517
550
|
`HEAD: ${ctx.shortHead}`,
|
|
518
551
|
`Default: ${ctx.defaultBranch}`,
|
|
552
|
+
`Upstream: ${upstream ? `${upstream.ref} (ahead ${upstream.ahead}, behind ${upstream.behind})` : `none (publishing would create origin/${ctx.branch})`}`,
|
|
519
553
|
'Local: clean',
|
|
520
554
|
].join('\n'),
|
|
521
555
|
);
|
|
@@ -135,9 +135,12 @@ bun "$(superskill script path sp pr-reviewing.ts)" <subcommand> [flags]
|
|
|
135
135
|
Installed targets resolve the staged TypeScript source and execute it with Bun, matching the rest
|
|
136
136
|
of `plugins/sp/scripts`.
|
|
137
137
|
|
|
138
|
-
1. **Preflight** — `<script> preflight --json`. Hard-fails on a
|
|
139
|
-
detached HEAD, missing `gh` auth, no GitHub remote,
|
|
140
|
-
|
|
138
|
+
1. **Preflight** — `<script> preflight --base "$base" --json`. Hard-fails on a
|
|
139
|
+
detached HEAD, missing `gh` auth, no GitHub remote, a dirty tree, or the current branch
|
|
140
|
+
being the base branch (a PR reviews a feature branch against the base; nothing on the
|
|
141
|
+
base branch is reviewable, and the guard runs before any push can publish it). On a
|
|
142
|
+
dirty tree, triage with the user (commit/stash/exclude) before continuing — the
|
|
143
|
+
workflow refuses to guess.
|
|
141
144
|
2. **Hygiene** — `<script> hygiene --base "$base" --json`. `BLOCK` (secrets, `.env`, conflict markers,
|
|
142
145
|
private keys) stops the run — never submit a tainted diff. `WARN` (debug residue) rides along
|
|
143
146
|
into the report. This is a submission sanity check, not a second local review.
|
package/spur.js
CHANGED
|
@@ -67152,6 +67152,10 @@ var init_finding_codes2 = __esm(() => {
|
|
|
67152
67152
|
});
|
|
67153
67153
|
|
|
67154
67154
|
// ../../packages/app/src/services/planning-check-base.ts
|
|
67155
|
+
function key(e) {
|
|
67156
|
+
return `${e.kind}:${e.id}:${e.code}`;
|
|
67157
|
+
}
|
|
67158
|
+
|
|
67155
67159
|
class PlanningCheckService {
|
|
67156
67160
|
fs;
|
|
67157
67161
|
matrix;
|
|
@@ -67244,7 +67248,7 @@ class PlanningCheckService {
|
|
|
67244
67248
|
}
|
|
67245
67249
|
}
|
|
67246
67250
|
}
|
|
67247
|
-
summarizeWithStatus(status, findings, strict, overrides) {
|
|
67251
|
+
summarizeWithStatus(status, findings, strict, overrides, accepted, id) {
|
|
67248
67252
|
const effectiveFindings = [];
|
|
67249
67253
|
for (const f of findings) {
|
|
67250
67254
|
const override = overrides?.[f.code];
|
|
@@ -67257,6 +67261,13 @@ class PlanningCheckService {
|
|
|
67257
67261
|
if (strict && f.severity === "warning") {
|
|
67258
67262
|
f.severity = "error";
|
|
67259
67263
|
}
|
|
67264
|
+
if (accepted && id) {
|
|
67265
|
+
const k = key({ kind: this.docKind, id, code: f.code });
|
|
67266
|
+
const acceptedSev = accepted.get(k);
|
|
67267
|
+
if (acceptedSev !== undefined && acceptedSev === f.severity) {
|
|
67268
|
+
continue;
|
|
67269
|
+
}
|
|
67270
|
+
}
|
|
67260
67271
|
effectiveFindings.push(f);
|
|
67261
67272
|
}
|
|
67262
67273
|
let hasError = false;
|
|
@@ -67877,7 +67888,7 @@ class TaskLocator {
|
|
|
67877
67888
|
return;
|
|
67878
67889
|
}
|
|
67879
67890
|
const folderKeys = source.foldersConfig ? Object.keys(source.foldersConfig.folders) : [];
|
|
67880
|
-
this.dirs = [...new Set([source.tasksDir, ...folderKeys.map((
|
|
67891
|
+
this.dirs = [...new Set([source.tasksDir, ...folderKeys.map((key2) => source.fs.resolve(key2))])];
|
|
67881
67892
|
}
|
|
67882
67893
|
static forSingleDir(fs3, dir) {
|
|
67883
67894
|
return new TaskLocator({ fs: fs3, tasksDir: dir });
|
|
@@ -68171,7 +68182,10 @@ var init_task_check = __esm(() => {
|
|
|
68171
68182
|
const findings = [];
|
|
68172
68183
|
const doc2 = this.runL1(raw, wbs, findings);
|
|
68173
68184
|
if (doc2 === null) {
|
|
68174
|
-
return {
|
|
68185
|
+
return {
|
|
68186
|
+
wbs,
|
|
68187
|
+
...this.summarizeWithStatus("", findings, strict, options?.severityOverrides, options?.accepted, wbs)
|
|
68188
|
+
};
|
|
68175
68189
|
}
|
|
68176
68190
|
const fm = doc2.frontmatterData ?? {};
|
|
68177
68191
|
const status = fm.status ?? "backlog";
|
|
@@ -68186,7 +68200,10 @@ var init_task_check = __esm(() => {
|
|
|
68186
68200
|
if (status !== "done" && status !== "cancelled") {
|
|
68187
68201
|
await this.runL4Readiness(doc2, fm, wbs, status, findings, tasksDir);
|
|
68188
68202
|
}
|
|
68189
|
-
return {
|
|
68203
|
+
return {
|
|
68204
|
+
wbs,
|
|
68205
|
+
...this.summarizeWithStatus(status, findings, strict, options?.severityOverrides, options?.accepted, wbs)
|
|
68206
|
+
};
|
|
68190
68207
|
}
|
|
68191
68208
|
runL3(doc2, entry, status, findings) {
|
|
68192
68209
|
const reqBodyRaw = doc2.getSection("Requirements");
|
|
@@ -68883,9 +68900,6 @@ import { basename as basename4, dirname as dirname10, join as join11, relative,
|
|
|
68883
68900
|
function baselineSeverity(e) {
|
|
68884
68901
|
return e.severity ?? "error";
|
|
68885
68902
|
}
|
|
68886
|
-
function key(e) {
|
|
68887
|
-
return `${e.kind}:${e.id}:${e.code}`;
|
|
68888
|
-
}
|
|
68889
68903
|
function resolveProjectRoot(cwd) {
|
|
68890
68904
|
const fs3 = createNodeFileSystem3(cwd);
|
|
68891
68905
|
let current = resolve3(cwd);
|
|
@@ -69253,12 +69267,29 @@ async function runCorpusCheck(cwd, since) {
|
|
|
69253
69267
|
}
|
|
69254
69268
|
return result;
|
|
69255
69269
|
}
|
|
69270
|
+
async function loadAcceptedFindings(cwd) {
|
|
69271
|
+
const projectRoot = resolveProjectRoot(cwd);
|
|
69272
|
+
const baselineFile = join11(projectRoot, "config", "corpus-baseline.json");
|
|
69273
|
+
const accepted = new Map;
|
|
69274
|
+
try {
|
|
69275
|
+
if (await Bun.file(baselineFile).exists()) {
|
|
69276
|
+
const baseline = await Bun.file(baselineFile).json();
|
|
69277
|
+
if (Array.isArray(baseline?.entries)) {
|
|
69278
|
+
for (const e of baseline.entries) {
|
|
69279
|
+
accepted.set(key(e), baselineSeverity(e));
|
|
69280
|
+
}
|
|
69281
|
+
}
|
|
69282
|
+
}
|
|
69283
|
+
} catch {}
|
|
69284
|
+
return accepted;
|
|
69285
|
+
}
|
|
69256
69286
|
var FOG_HEADING, OUT_OF_SCOPE_HEADING, FEATURE_ID, DEFAULT_BRANCHES;
|
|
69257
69287
|
var init_corpus_check = __esm(() => {
|
|
69258
69288
|
init_loader();
|
|
69259
69289
|
init_dist5();
|
|
69260
69290
|
init_dist2();
|
|
69261
69291
|
init_feature_check();
|
|
69292
|
+
init_planning_check_base();
|
|
69262
69293
|
init_task_check();
|
|
69263
69294
|
init_task_locator();
|
|
69264
69295
|
FOG_HEADING = /^###\s+Not yet specified\b/;
|
|
@@ -79461,6 +79492,7 @@ __export(exports_src2, {
|
|
|
79461
79492
|
parseEtimeToSeconds: () => parseEtimeToSeconds,
|
|
79462
79493
|
normalizeSystemEventPayload: () => normalizeSystemEventPayload,
|
|
79463
79494
|
normalizeProjectPath: () => normalizeProjectPath,
|
|
79495
|
+
loadAcceptedFindings: () => loadAcceptedFindings,
|
|
79464
79496
|
isSystemEventEnvelopeV2: () => isSystemEventEnvelopeV2,
|
|
79465
79497
|
isPortLive: () => isPortLive,
|
|
79466
79498
|
isPortAvailable: () => isPortAvailable,
|
|
@@ -87871,7 +87903,7 @@ import { createRequire } from "module";
|
|
|
87871
87903
|
var CLI_CONFIG = {
|
|
87872
87904
|
binaryName: "spur",
|
|
87873
87905
|
binaryLabel: "spur",
|
|
87874
|
-
binaryVersion: "0.3.
|
|
87906
|
+
binaryVersion: "0.3.51",
|
|
87875
87907
|
configDir: ".spur",
|
|
87876
87908
|
configFile: ".spur/config.yaml",
|
|
87877
87909
|
databaseFile: ".spur/spur.db"
|
|
@@ -100429,6 +100461,7 @@ ${result.content}`);
|
|
|
100429
100461
|
}
|
|
100430
100462
|
const svc = await makeCheckService(context4);
|
|
100431
100463
|
const planningFolders = await resolvePlanningFolders(context4.fs);
|
|
100464
|
+
const accepted = await loadAcceptedFindings(context4.cwd);
|
|
100432
100465
|
const activeFolder = planningFolders.foldersConfig.active_folder;
|
|
100433
100466
|
const tasksDir = context4.fs.resolve(options.folder ?? activeFolder);
|
|
100434
100467
|
const printResult = (result) => {
|
|
@@ -100454,7 +100487,8 @@ ${result.wbs} (${result.status}): ${result.pass ? "PASS" : "FAIL"}`);
|
|
|
100454
100487
|
} else {
|
|
100455
100488
|
const result = await svc.check(hit.filePath, wbs, {
|
|
100456
100489
|
strict,
|
|
100457
|
-
severityOverrides: planningFolders.severityOverrides
|
|
100490
|
+
severityOverrides: planningFolders.severityOverrides,
|
|
100491
|
+
accepted
|
|
100458
100492
|
});
|
|
100459
100493
|
results.push(result);
|
|
100460
100494
|
printResult(result);
|
|
@@ -100471,7 +100505,8 @@ ${result.wbs} (${result.status}): ${result.pass ? "PASS" : "FAIL"}`);
|
|
|
100471
100505
|
}
|
|
100472
100506
|
const result = await svc.check(`${tasksDir}/${fileName}`, w, {
|
|
100473
100507
|
strict,
|
|
100474
|
-
severityOverrides: planningFolders.severityOverrides
|
|
100508
|
+
severityOverrides: planningFolders.severityOverrides,
|
|
100509
|
+
accepted
|
|
100475
100510
|
});
|
|
100476
100511
|
results.push(result);
|
|
100477
100512
|
printResult(result);
|
|
@@ -100673,14 +100708,20 @@ async function makeCheckService(context4) {
|
|
|
100673
100708
|
return new TaskCheckService(context4.fs, await loadSectionMatrix(context4.cwd), await makeTaskLocator(context4));
|
|
100674
100709
|
}
|
|
100675
100710
|
async function runDoneGateCheck(context4, wbs, folderOverride) {
|
|
100676
|
-
const
|
|
100711
|
+
const planningFolders = await resolvePlanningFolders(context4.fs);
|
|
100712
|
+
const foldersConfig = planningFolders.foldersConfig;
|
|
100677
100713
|
const tasksDir = folderOverride ?? context4.fs.resolve(foldersConfig.active_folder);
|
|
100678
100714
|
const hit = await new TaskLocator({ fs: context4.fs, tasksDir, foldersConfig }).findByWbs(wbs);
|
|
100679
100715
|
if (!hit) {
|
|
100680
100716
|
return false;
|
|
100681
100717
|
}
|
|
100682
100718
|
const svc = new TaskCheckService(context4.fs, await loadSectionMatrix(context4.cwd), await makeTaskLocator(context4));
|
|
100683
|
-
const
|
|
100719
|
+
const accepted = await loadAcceptedFindings(context4.cwd);
|
|
100720
|
+
const result = await svc.check(hit.filePath, wbs, {
|
|
100721
|
+
strict: false,
|
|
100722
|
+
severityOverrides: planningFolders.severityOverrides,
|
|
100723
|
+
accepted
|
|
100724
|
+
});
|
|
100684
100725
|
return result.pass;
|
|
100685
100726
|
}
|
|
100686
100727
|
var sectionMatrixCache = new Map;
|