@hegemonart/get-design-done 1.54.0 → 1.56.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-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +92 -0
- package/README.md +6 -0
- package/SKILL.md +1 -0
- package/agents/design-fixer.md +16 -0
- package/bin/gdd-dashboard +91 -0
- package/dist/claude-code/.claude/skills/override/SKILL.md +86 -0
- package/hooks/gdd-decision-injector.js +58 -0
- package/hooks/gdd-fact-force.js +345 -0
- package/hooks/gdd-risk-gate.js +406 -0
- package/hooks/hooks.json +18 -0
- package/package.json +2 -1
- package/reference/schemas/events.schema.json +61 -1
- package/reference/skill-graph.md +2 -1
- package/scripts/lib/dashboard/graph-html.cjs +0 -0
- package/scripts/lib/health-mirror/index.cjs +146 -1
- package/scripts/lib/manifest/skills.json +8 -0
- package/scripts/lib/risk/calibration.cjs +385 -0
- package/scripts/lib/risk/compute-risk.cjs +229 -0
- package/scripts/lib/risk/consumers.cjs +211 -0
- package/scripts/lib/risk/override.cjs +87 -0
- package/scripts/lib/risk/route.cjs +59 -0
- package/scripts/lib/risk/tables.cjs +221 -0
- package/sdk/cli/commands/dashboard.ts +419 -0
- package/sdk/cli/index.js +253 -2
- package/sdk/cli/index.ts +7 -0
- package/sdk/dashboard/data/_pkg-root.cjs +92 -0
- package/sdk/dashboard/data/cost-aggregator.cjs +187 -0
- package/sdk/dashboard/data/discovery.cjs +297 -0
- package/sdk/dashboard/data/risk-surface.cjs +136 -0
- package/sdk/dashboard/data/source.cjs +576 -0
- package/sdk/dashboard/tui/ansi.cjs +355 -0
- package/sdk/dashboard/tui/index.cjs +778 -0
- package/sdk/mcp/gdd-mcp/server.js +70 -0
- package/skills/override/SKILL.md +86 -0
|
@@ -1718,6 +1718,32 @@ var require_health_mirror = __commonJS({
|
|
|
1718
1718
|
}
|
|
1719
1719
|
checks.push({ name: "stack_addendums", status, detail });
|
|
1720
1720
|
}
|
|
1721
|
+
{
|
|
1722
|
+
let status;
|
|
1723
|
+
let detail;
|
|
1724
|
+
try {
|
|
1725
|
+
const gddRoot = resolveDashboardRoot(rootDir);
|
|
1726
|
+
const binPresent = dashboardBinResolves(gddRoot);
|
|
1727
|
+
const dataPlaneOk = dashboardDataPlaneLoads(gddRoot);
|
|
1728
|
+
if (binPresent && dataPlaneOk) {
|
|
1729
|
+
status = "ok";
|
|
1730
|
+
detail = "dashboard: bin/gdd-dashboard present; data plane ok";
|
|
1731
|
+
} else {
|
|
1732
|
+
status = "warn";
|
|
1733
|
+
if (!binPresent && !dataPlaneOk) {
|
|
1734
|
+
detail = "dashboard: bin missing; data plane unavailable";
|
|
1735
|
+
} else if (!binPresent) {
|
|
1736
|
+
detail = "dashboard: bin missing";
|
|
1737
|
+
} else {
|
|
1738
|
+
detail = "dashboard: data plane unavailable";
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
} catch {
|
|
1742
|
+
status = "warn";
|
|
1743
|
+
detail = "dashboard: unavailable";
|
|
1744
|
+
}
|
|
1745
|
+
checks.push({ name: "dashboard_reachable", status, detail });
|
|
1746
|
+
}
|
|
1721
1747
|
return { checks };
|
|
1722
1748
|
}
|
|
1723
1749
|
function sessionStartWiresInject(rootDir) {
|
|
@@ -1772,6 +1798,50 @@ var require_health_mirror = __commonJS({
|
|
|
1772
1798
|
return false;
|
|
1773
1799
|
}
|
|
1774
1800
|
}
|
|
1801
|
+
function findGddPackageRoot(startDir) {
|
|
1802
|
+
try {
|
|
1803
|
+
let dir = path.resolve(startDir);
|
|
1804
|
+
for (let i = 0; i < 12; i++) {
|
|
1805
|
+
try {
|
|
1806
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8"));
|
|
1807
|
+
if (pkg && typeof pkg.name === "string") {
|
|
1808
|
+
if (pkg.name === "get-design-done" || /\/get-design-done$/.test(pkg.name)) {
|
|
1809
|
+
return dir;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
} catch {
|
|
1813
|
+
}
|
|
1814
|
+
const parent = path.dirname(dir);
|
|
1815
|
+
if (parent === dir) break;
|
|
1816
|
+
dir = parent;
|
|
1817
|
+
}
|
|
1818
|
+
return null;
|
|
1819
|
+
} catch {
|
|
1820
|
+
return null;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
function resolveDashboardRoot(rootDir) {
|
|
1824
|
+
const fromRoot = findGddPackageRoot(rootDir);
|
|
1825
|
+
if (fromRoot) return fromRoot;
|
|
1826
|
+
return findGddPackageRoot(__dirname);
|
|
1827
|
+
}
|
|
1828
|
+
function dashboardBinResolves(gddRoot) {
|
|
1829
|
+
if (!gddRoot) return false;
|
|
1830
|
+
try {
|
|
1831
|
+
return fs.statSync(path.join(gddRoot, "bin", "gdd-dashboard")).isFile();
|
|
1832
|
+
} catch {
|
|
1833
|
+
return false;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
function dashboardDataPlaneLoads(gddRoot) {
|
|
1837
|
+
if (!gddRoot) return false;
|
|
1838
|
+
try {
|
|
1839
|
+
const mod = require(path.join(gddRoot, "sdk", "dashboard", "data", "source.cjs"));
|
|
1840
|
+
return !!(mod && typeof mod.loadDashboardModel === "function");
|
|
1841
|
+
} catch {
|
|
1842
|
+
return false;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1775
1845
|
module2.exports = { getHealthChecks: getHealthChecks2 };
|
|
1776
1846
|
}
|
|
1777
1847
|
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gdd-override
|
|
3
|
+
description: "Escalation surface for a risk-blocked action or a fact-force gate. Use when the Phase 56 risk gate blocked a writer action (suggested_action=block) and a reviewer has signed off, or when the first-write fact-force gate is holding a file you have legitimately reviewed. Activates for requests involving overriding a blocked edit, approving a high-risk change, or clearing a fact-force hold on a path."
|
|
4
|
+
argument-hint: "<finding-id | factforce <path>> [--approver <who>] [--reason <text>]"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
tools: Read, Write, Bash, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /gdd:override
|
|
10
|
+
|
|
11
|
+
A risk-blocked action is hard: the Phase 56 risk gate routes `suggested_action=block`
|
|
12
|
+
to `override` (see `scripts/lib/risk/route.cjs`), and the fact-force gate holds the
|
|
13
|
+
first write to a file until its facts are read. This skill is the audited way past
|
|
14
|
+
either hold. It mirrors `/gdd:unlock-decision`: a named approver plus a
|
|
15
|
+
reason, recorded before anything is let through. Override is never silent.
|
|
16
|
+
|
|
17
|
+
## Invocation
|
|
18
|
+
|
|
19
|
+
| Command | Behavior |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `/gdd:override <finding-id> --approver <who> --reason <text>` | Record a `D-XX` `override`-tagged decision in STATE.md `<decisions>` and let the risk-blocked action through. |
|
|
22
|
+
| `/gdd:override factforce <path> --approver <who> --reason <text>` | Set `checked[path]` in the session fact-force state so the fact-force gate stops holding that path. |
|
|
23
|
+
|
|
24
|
+
Both modes ask for a rationale: the audit trail is the reason override exists.
|
|
25
|
+
|
|
26
|
+
## Steps
|
|
27
|
+
|
|
28
|
+
1. **Parse args.** Mode is `factforce` when the first token is the literal `factforce`
|
|
29
|
+
(the next token is the `<path>`); otherwise the first token is a `<finding-id>`.
|
|
30
|
+
`--approver` is required (a non-empty name). Missing `--approver` prints the usage
|
|
31
|
+
and changes nothing. If `--reason` is absent, ASK for one (AskUserQuestion or a
|
|
32
|
+
prompt) before continuing: an override with no rationale is rejected.
|
|
33
|
+
|
|
34
|
+
2. **Preview.** Show what will be written and stop for confirmation:
|
|
35
|
+
- finding mode: the decision entry from `overrideDecisionEntry(<id>, {approver, reason})`
|
|
36
|
+
(its `text`, `status: locked`, and `override` tag) plus the action it unblocks.
|
|
37
|
+
- factforce mode: the `<path>` that will gain `checked[path] = true` and the
|
|
38
|
+
session-state file it lands in.
|
|
39
|
+
|
|
40
|
+
3. **Apply (finding mode).** Record the audited decision via the STATE writer
|
|
41
|
+
`mcp__gdd_state__add_decision` (it auto-assigns the next `D-N`). Pass the `text`
|
|
42
|
+
from the pure builder so the `override` tag is embedded and greppable:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node -e '
|
|
46
|
+
const o = require("./scripts/lib/risk/override.cjs");
|
|
47
|
+
const [id, who, reason] = process.argv.slice(1);
|
|
48
|
+
const entry = o.overrideDecisionEntry(id, { approver: who, reason });
|
|
49
|
+
console.log(JSON.stringify(entry));
|
|
50
|
+
' "<finding-id>" "<who>" "<reason>"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then call `mcp__gdd_state__add_decision` with `{ text: <entry.text>, status: "locked" }`.
|
|
54
|
+
The blocked action is now approved on the audit record; proceed with it.
|
|
55
|
+
|
|
56
|
+
4. **Apply (factforce mode).** Set `checked[path]` in the session state file at
|
|
57
|
+
`<cwd>/.design/locks/factforce-<session_id>.json` (atomic tmp then rename), using
|
|
58
|
+
the pure helper so the shape matches what the fact-force gate reads:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node -e '
|
|
62
|
+
const fs = require("fs"); const path = require("path");
|
|
63
|
+
const o = require("./scripts/lib/risk/override.cjs");
|
|
64
|
+
const [file, p] = process.argv.slice(1);
|
|
65
|
+
let state = {}; try { state = JSON.parse(fs.readFileSync(file, "utf8")); } catch {}
|
|
66
|
+
const next = o.setFactForceChecked(state, p);
|
|
67
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
68
|
+
const tmp = file + ".tmp";
|
|
69
|
+
fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
70
|
+
fs.renameSync(tmp, file);
|
|
71
|
+
console.log(JSON.stringify(next.checked));
|
|
72
|
+
' "<cwd>/.design/locks/factforce-<session_id>.json" "<path>"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The fact-force gate stops holding `<path>` for the rest of the session.
|
|
76
|
+
|
|
77
|
+
5. **Report** the recorded approver, the reason, and either the new `D-XX` id (finding
|
|
78
|
+
mode) or the unblocked path (factforce mode).
|
|
79
|
+
|
|
80
|
+
## Do Not
|
|
81
|
+
|
|
82
|
+
- Do not skip the rationale: every override is audited.
|
|
83
|
+
- Do not override a finding that the risk gate did not actually block.
|
|
84
|
+
- Do not edit `scripts/lib/risk/route.cjs` or `compute-risk.cjs`: this skill consumes them.
|
|
85
|
+
|
|
86
|
+
## OVERRIDE COMPLETE
|