shapeup-sdlc 3.18.3 → 4.0.0
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/settings.local.example.json +2 -3
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +115 -56
- package/README.md +101 -143
- package/SECURITY.md +16 -25
- package/agents/orient.md +14 -0
- package/agents/qa-edge-hunter.md +13 -0
- package/agents/spec-evaluator.md +14 -0
- package/agents/task-executor.md +14 -0
- package/bin/init.mjs +13 -16
- package/bin/lib/grant.mjs +8 -19
- package/commands/build.md +9 -14
- package/commands/eval.md +3 -3
- package/commands/hammer.md +9 -5
- package/commands/retro.md +12 -11
- package/commands/scopes.md +1 -12
- package/commands/ship.md +45 -88
- package/commands/wire.md +1 -8
- package/hooks/dispatch-receipt.mjs +94 -8
- package/hooks/hooks.json +0 -41
- package/hooks/lib/decision.mjs +6 -9
- package/hooks/lib/tier.mjs +50 -0
- package/hooks/sandbox-guard.mjs +140 -64
- package/kernel/gate.mjs +203 -22
- package/kernel/harness.mjs +20 -67
- package/kernel/init/run.mjs +175 -523
- package/kernel/lib/contract.mjs +9 -93
- package/kernel/lib/floor.mjs +64 -0
- package/kernel/lib/paths.mjs +39 -112
- package/kernel/order.mjs +157 -0
- package/kernel/probe/digest.mjs +2 -38
- package/kernel/schemas/domain.schema.json +146 -1125
- package/kernel/schemas/work-order.schema.json +8 -4
- package/kernel/schemas/work-result.schema.json +1 -1
- package/kernel/verify/envelope.mjs +2 -2
- package/kernel/verify/skills.mjs +27 -8
- package/kernel/verify/t0.mjs +2 -2
- package/package.json +4 -2
- package/skills/building/SKILL.md +144 -0
- package/skills/building/resources/gates.md +76 -0
- package/skills/building/resources/guidance.md +23 -0
- package/skills/{translator/references/preservation-rules.md → building/resources/intake-preservation.md} +1 -1
- package/skills/building/resources/intake.md +157 -0
- package/skills/building/resources/orders.md +69 -0
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/doc-schemas.md +1 -1
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/task-generation.md +13 -13
- package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/test-surface.md +6 -7
- package/skills/building/resources/plan-scopes.md +95 -0
- package/skills/building/resources/plan-spec.md +102 -0
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/_index.tmpl.md +1 -1
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/assess-report.tmpl.md +10 -11
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/run-state.tmpl.md +4 -4
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/scope-summary.tmpl.md +2 -2
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/synthesis.tmpl.md +4 -4
- package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/usecase.tmpl.md +2 -2
- package/skills/building/resources/plan-wire.md +82 -0
- package/skills/building/resources/plan.md +98 -0
- package/skills/building/resources/retro-research.md +60 -0
- package/skills/building/resources/retro-scan.md +49 -0
- package/skills/building/resources/retro.md +225 -0
- package/skills/building/resources/rounds.md +78 -0
- package/skills/building/resources/stop.md +127 -0
- package/skills/orient/SKILL.md +37 -37
- package/skills/qa-edge-hunter/SKILL.md +14 -14
- package/skills/shapeup/SKILL.md +5 -5
- package/skills/shapeup/resources/breadboarding.md +1 -1
- package/skills/shapeup/resources/context-compaction.md +5 -5
- package/skills/shapeup/resources/shaping.md +1 -1
- package/skills/spec-evaluator/SKILL.md +17 -21
- package/skills/spec-evaluator/references/dimension-contract.md +1 -1
- package/skills/spec-evaluator/references/dimensions/completeness.md +3 -3
- package/skills/spec-evaluator/references/dimensions/spec-conformance.md +1 -1
- package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +5 -5
- package/skills/task-executor/SKILL.md +11 -15
- package/commands/hill.md +0 -10
- package/hooks/gate-intake.mjs +0 -109
- package/hooks/gate-zerowork.mjs +0 -349
- package/hooks/tier-guard.mjs +0 -162
- package/kernel/compile.mjs +0 -1419
- package/kernel/init/fit.mjs +0 -199
- package/kernel/init/run-args.mjs +0 -206
- package/kernel/lib/breadboard.mjs +0 -165
- package/kernel/probe/attempts.mjs +0 -161
- package/kernel/probe/concurrency.mjs +0 -535
- package/kernel/probe/eval.mjs +0 -405
- package/kernel/probe/hunt.mjs +0 -104
- package/kernel/probe/leg.mjs +0 -229
- package/kernel/probe/owner.mjs +0 -142
- package/kernel/probe/requirements.mjs +0 -328
- package/kernel/probe/resume.mjs +0 -1110
- package/kernel/probe/rounds.mjs +0 -115
- package/kernel/probe/staged.mjs +0 -83
- package/kernel/probe/stats.mjs +0 -477
- package/kernel/probe/t0.mjs +0 -115
- package/kernel/reduce/board.mjs +0 -350
- package/kernel/reduce/graph.mjs +0 -482
- package/kernel/reduce/hill.mjs +0 -322
- package/kernel/reduce/ingest.mjs +0 -767
- package/kernel/reduce/leftovers.mjs +0 -159
- package/kernel/reduce/ship.mjs +0 -529
- package/kernel/reduce/snapshot.mjs +0 -291
- package/kernel/reduce/verdict.mjs +0 -172
- package/kernel/report/export.mjs +0 -384
- package/kernel/report/facts.mjs +0 -234
- package/kernel/verify/budget.mjs +0 -153
- package/kernel/verify/build.mjs +0 -428
- package/kernel/verify/dispatch.mjs +0 -114
- package/kernel/verify/spec.mjs +0 -975
- package/kernel/verify/trace.mjs +0 -604
- package/skills/ba-pitch-analyzer/SKILL.md +0 -204
- package/skills/coach/SKILL.md +0 -397
- package/skills/hill-chart/SKILL.md +0 -154
- package/skills/hill-chart/assets/dashboard.template.html +0 -1432
- package/skills/scope-architect/SKILL.md +0 -174
- package/skills/scope-hammer/SKILL.md +0 -231
- package/skills/solution-architect/SKILL.md +0 -158
- package/skills/tech-lead/SKILL.md +0 -151
- package/skills/tech-lead/references/gates.md +0 -605
- package/skills/tech-lead/references/protocol.md +0 -889
- package/skills/tech-lead/references/tiny-lane.md +0 -53
- package/skills/tech-lead/workflows/shapeup-run.js +0 -2187
- package/skills/translator/SKILL.md +0 -258
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/contract-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ddd-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/integration-analysis.md +0 -0
- /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ux-behavior-patterns.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/api-feasibility.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/be-service.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/offline-storage.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/third-party-api.contract.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/context-map.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/event-choreography.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/migration-plan.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/team-handoff.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/domain-model.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/feedback.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/integration.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-board.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-spike.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task.tmpl.md +0 -0
- /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/ux-behavior.tmpl.md +0 -0
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
// leftovers — what the run's own diff still carries that nobody meant to ship.
|
|
2
|
-
//
|
|
3
|
-
// TODO/FIXME markers, `console.log`/`debugger`, blocks of commented-out code, one file swallowing
|
|
4
|
-
// hundreds of added lines. Added lines only: a marker the feature did not introduce is somebody
|
|
5
|
-
// else's, and a report that lists those is a report people learn to skim.
|
|
6
|
-
//
|
|
7
|
-
// WHY IT IS PART OF THE SHIP REPORT AND NOT A STOP HOOK. It used to be an advisory Stop hook that
|
|
8
|
-
// printed once, into a transcript, at the moment a session ended — the channel least likely to be
|
|
9
|
-
// read and impossible to check later. The ship report is the artifact a human actually reads at
|
|
10
|
-
// GATE L4 and the one a teammate finds on `git pull`, so a leftover recorded there is a leftover
|
|
11
|
-
// somebody can act on. Nothing about the check changed; only where its answer lands.
|
|
12
|
-
//
|
|
13
|
-
// Advisory by construction: it is a SECTION, never a verdict. QA is a level-up, not a gate.
|
|
14
|
-
|
|
15
|
-
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
|
|
16
|
-
import { join } from "node:path";
|
|
17
|
-
import { spawnSync } from "node:child_process";
|
|
18
|
-
import { LOCAL, SHARED, resultsDir } from "../lib/paths.mjs";
|
|
19
|
-
|
|
20
|
-
// Harness bookkeeping is never a leftover — skip both storage roots, whichever names they carry.
|
|
21
|
-
const SKIP_PATH = new RegExp(`^(${[LOCAL, SHARED].map((r) => r.replace(/[.\\]/g, "\\$&")).join("|")})/`);
|
|
22
|
-
const MAX_FILES = 30;
|
|
23
|
-
const MAX_ADDED_LINES_PER_FILE = 400;
|
|
24
|
-
|
|
25
|
-
const MARKERS = [
|
|
26
|
-
{ name: "TODO/FIXME", re: /\b(TODO|FIXME|XXX|HACK)\b/ },
|
|
27
|
-
{ name: "console.log", re: /\bconsole\.(log|debug)\s*\(/ },
|
|
28
|
-
{ name: "debugger", re: /^\s*debugger\b/ },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Scan a unified diff for leftovers in ADDED lines only.
|
|
33
|
-
*
|
|
34
|
-
* Added lines only, deliberately: a TODO the feature did not introduce is somebody else's, and a
|
|
35
|
-
* report that lists it is a report people learn to skim.
|
|
36
|
-
*
|
|
37
|
-
* @param {string} diffText - A unified diff.
|
|
38
|
-
* @returns {Array<{file:string, markers:Object<string,number>, added:number, big:boolean, commented_code:boolean}>}
|
|
39
|
-
* One entry per dirty file, capped at MAX_FILES.
|
|
40
|
-
*/
|
|
41
|
-
export function scanDiff(diffText) {
|
|
42
|
-
const findings = [];
|
|
43
|
-
let current = null;
|
|
44
|
-
let commentRun = 0;
|
|
45
|
-
let filesSeen = 0;
|
|
46
|
-
|
|
47
|
-
const push = () => {
|
|
48
|
-
if (!current) return;
|
|
49
|
-
const dirty = current.added > MAX_ADDED_LINES_PER_FILE ||
|
|
50
|
-
current.commented_code ||
|
|
51
|
-
Object.keys(current.markers).length > 0;
|
|
52
|
-
current.big = current.added > MAX_ADDED_LINES_PER_FILE;
|
|
53
|
-
if (dirty) findings.push(current);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
for (const line of (diffText || "").split("\n")) {
|
|
57
|
-
if (line.startsWith("+++ ")) {
|
|
58
|
-
push();
|
|
59
|
-
commentRun = 0;
|
|
60
|
-
const file = line.replace(/^\+\+\+ (b\/)?/, "").trim();
|
|
61
|
-
if (file === "/dev/null" || SKIP_PATH.test(file) || ++filesSeen > MAX_FILES) {
|
|
62
|
-
current = null;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
current = { file, markers: {}, added: 0, big: false, commented_code: false };
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (!current || !line.startsWith("+") || line.startsWith("+++")) { commentRun = 0; continue; }
|
|
69
|
-
const added = line.slice(1);
|
|
70
|
-
current.added++;
|
|
71
|
-
for (const { name, re } of MARKERS) {
|
|
72
|
-
if (re.test(added)) current.markers[name] = (current.markers[name] || 0) + 1;
|
|
73
|
-
}
|
|
74
|
-
// ≥4 consecutive added comment lines that look like code = a commented-out block
|
|
75
|
-
if (/^\s*(\/\/|#)/.test(added) && /[;{}()=]/.test(added)) {
|
|
76
|
-
if (++commentRun >= 4) current.commented_code = true;
|
|
77
|
-
} else {
|
|
78
|
-
commentRun = 0;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
push();
|
|
82
|
-
return findings;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* One human-readable fragment per finding.
|
|
87
|
-
* @param {Array} findings - The result of {@link scanDiff}.
|
|
88
|
-
* @returns {string[]} At most six lines, each naming a file and what it carries.
|
|
89
|
-
*/
|
|
90
|
-
export function summarize(findings) {
|
|
91
|
-
return findings.slice(0, 6).map((f) => {
|
|
92
|
-
const bits = Object.entries(f.markers).map(([name, n]) => `${name} ×${n}`);
|
|
93
|
-
if (f.commented_code) bits.push("commented-out code block");
|
|
94
|
-
if (f.big) bits.push(`+${f.added} lines in one file`);
|
|
95
|
-
return `${f.file}: ${bits.join(", ")}`;
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Run git, returning stdout on success and null otherwise.
|
|
101
|
-
* @param {string} cwd - Working directory.
|
|
102
|
-
* @param {string[]} args - Arguments after `git`.
|
|
103
|
-
* @returns {(string|null)} stdout, or null when git failed or is absent.
|
|
104
|
-
*/
|
|
105
|
-
function git(cwd, args) {
|
|
106
|
-
const r = spawnSync("git", args, { cwd, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 });
|
|
107
|
-
return r.status === 0 ? r.stdout : null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* The run's change set as a unified diff — git first, WorkResult fallback.
|
|
112
|
-
* @param {string} cwd - Project root.
|
|
113
|
-
* @param {string} slug - Feature slug.
|
|
114
|
-
* @returns {(string|null)} A unified diff, or null when there is nothing to scan.
|
|
115
|
-
*/
|
|
116
|
-
export
|
|
117
|
-
function collectDiff(cwd, slug) {
|
|
118
|
-
const tracked = git(cwd, ["diff", "HEAD"]);
|
|
119
|
-
if (tracked !== null) {
|
|
120
|
-
// Untracked files never show in `diff HEAD`; synthesize +lines for small text ones.
|
|
121
|
-
let extra = "";
|
|
122
|
-
const status = git(cwd, ["status", "--porcelain"]) || "";
|
|
123
|
-
for (const line of status.split("\n")) {
|
|
124
|
-
const m = /^\?\?\s+(.+)$/.exec(line);
|
|
125
|
-
if (!m || SKIP_PATH.test(m[1])) continue;
|
|
126
|
-
const p = join(cwd, m[1]);
|
|
127
|
-
try {
|
|
128
|
-
if (statSync(p).size > 200 * 1024) continue;
|
|
129
|
-
const body = readFileSync(p, "utf8");
|
|
130
|
-
if (body.includes("\u0000")) continue; // binary
|
|
131
|
-
extra += `+++ b/${m[1]}\n` + body.split("\n").map((l) => `+${l}`).join("\n") + "\n";
|
|
132
|
-
} catch { /* unreadable → skip */ }
|
|
133
|
-
}
|
|
134
|
-
return tracked + extra;
|
|
135
|
-
}
|
|
136
|
-
// Not a git repo → fall back to the newest WorkResult's files_touched.
|
|
137
|
-
const resultsPath = resultsDir(cwd, slug);
|
|
138
|
-
if (!existsSync(resultsPath)) return null;
|
|
139
|
-
const newest = readdirSync(resultsPath).filter((f) => f.endsWith(".json"))
|
|
140
|
-
.map((f) => join(resultsPath, f))
|
|
141
|
-
.sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs)[0];
|
|
142
|
-
if (!newest) return null;
|
|
143
|
-
let diff = "";
|
|
144
|
-
try {
|
|
145
|
-
const result = JSON.parse(readFileSync(newest, "utf8"));
|
|
146
|
-
for (const t of (result.files_touched || []).slice(0, MAX_FILES)) {
|
|
147
|
-
const rel = t?.path;
|
|
148
|
-
if (!rel || SKIP_PATH.test(rel)) continue;
|
|
149
|
-
const p = join(cwd, rel);
|
|
150
|
-
try {
|
|
151
|
-
if (statSync(p).size > 200 * 1024) continue;
|
|
152
|
-
const body = readFileSync(p, "utf8");
|
|
153
|
-
if (body.includes("\u0000")) continue;
|
|
154
|
-
diff += `+++ b/${rel}\n` + body.split("\n").map((l) => `+${l}`).join("\n") + "\n";
|
|
155
|
-
} catch { /* unreadable → skip */ }
|
|
156
|
-
}
|
|
157
|
-
} catch { return null; }
|
|
158
|
-
return diff || null;
|
|
159
|
-
}
|