@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
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "Get Design Done — 5-stage agent-orchestrated design pipeline with 9 connections, handoff-first workflow, bidirectional Figma write-back, 22+ specialized agents, queryable knowledge layer (intel store, dependency analysis, learnings extraction), and a self-improvement loop (reflector, frontmatter + budget feedback, global-skills layer). v1.20.0 ships the SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream, and resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) for rate-limit + 429 + context-overflow recovery. Full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation (auto-tag + GitHub Release + release-time smoke test).",
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.56.0"
|
|
9
9
|
},
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "get-design-done",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), Claude Design handoff, bidirectional Figma write-back, and a queryable intel store (.design/intel/) for dependency and learnings queries. Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation. Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain.",
|
|
15
|
-
"version": "1.
|
|
15
|
+
"version": "1.56.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "hegemonart"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get-design-done",
|
|
3
3
|
"short_name": "gdd",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.56.0",
|
|
5
5
|
"description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 59 specialized agents, 88 skills, 41 connection integrations (Figma, Refero, Preview, Storybook, Chromatic, Graphify, Slack, Linear, Jira, Notion, and more), handoff-first workflow via Claude Design bundles, bidirectional Figma write-back (annotations, Code Connect), queryable intel store (`.design/intel/`) for O(1) design surface lookups, and self-improvement loop (reflector agent, frontmatter + budget feedback, global-skills layer at `~/.claude/gdd/global-skills/`). Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings, reflect, apply-reflections. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows, lint + schema + frontmatter + stale-ref + shellcheck + gitleaks + injection-scan + blocking size-budget) and release automation (auto-tag + GitHub Release + release-time smoke test). Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain. v1.27.7 ships gdd-mcp (Phase 27.7): 12 read-only MCP tools for sub-3s priming. v1.28.0 (Phase 28): Foundational References Tier 2 — 5 new reference files (color-theory, composition, proportion-systems, i18n, contrast-advanced), 2 verifier i18n probes + 1 explore i18n-readiness probe, 12 additive cross-link insertions across 10 existing references, 2 orthogonal audit-scoring lens-tags (composition_alignment + i18n_readiness).",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "hegemonart",
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,98 @@ All notable changes to get-design-done are documented here. Versions follow [sem
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.56.0] - 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Phase 56 - Risk-Scoring + Fact-Forcing Gate (Quantified Action Confidence)
|
|
10
|
+
|
|
11
|
+
Every writer action now carries a quantified risk score instead of a binary allow/deny. Phase 56 adds a pure,
|
|
12
|
+
deterministic risk scorer (no I/O, frozen tables) that grades each Write / Edit / MultiEdit / Bash by tool, file
|
|
13
|
+
sensitivity, and input shape, then routes it through two PreToolUse hooks: a risk gate that emits a `risk_assessment`
|
|
14
|
+
event and blocks only genuinely dangerous actions, and a fact-force gate that holds the FIRST write to a file until its
|
|
15
|
+
graph consumers and recorded decisions have actually been read. Both are **dep-free** (a maintainer Rule-4 decision: a
|
|
16
|
+
pure scorer plus static tables, no ML, no new dependency). The gate softens to a warning whenever the Phase 52
|
|
17
|
+
DesignContext graph is absent, so greenfield projects are never over-blocked. A new `/gdd:override` escalation skill
|
|
18
|
+
clears a block or a fact-force hold with an approver and reason (audit-trailed as a `D-XX` override decision), and
|
|
19
|
+
`design-fixer` gains a confidence-times-risk routing step. Planned and executed via the GSD pipeline (3 + 2 parallel
|
|
20
|
+
executors).
|
|
21
|
+
|
|
22
|
+
### Breaking changes
|
|
23
|
+
|
|
24
|
+
- **Writer actions are now risk-gated.** A new PreToolUse hook (`hooks/gdd-risk-gate.js`, matcher
|
|
25
|
+
`Write|Edit|MultiEdit|Bash`) scores every writer action and blocks the few that score at or above 0.85 (destructive
|
|
26
|
+
bash, high-sensitivity-file rewrites). Blocking uses the house-style `{continue:false, stopReason}` contract; `allow`
|
|
27
|
+
is silent, `review` and `require_confirmation` attach advisory context for the agent to surface. Read-only agents are
|
|
28
|
+
allowlisted through.
|
|
29
|
+
- **The first write to a file is fact-forced.** A second PreToolUse hook (`hooks/gdd-fact-force.js`, matcher
|
|
30
|
+
`Edit|Write|MultiEdit`) holds the first mutation of a file until its DesignContext consumers and any recorded
|
|
31
|
+
decisions or blockers for it have been Read this session. The hold is soft (a `stopReason` listing the missing facts)
|
|
32
|
+
and softens to a warning when no graph exists; clear it deliberately with `/gdd:override factforce <path>`.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **Risk scorer** `scripts/lib/risk/` - `compute-risk.cjs` (`computeRisk(tool, input) -> {score, reasons, suggested_action, breakdown}`,
|
|
37
|
+
pure and deterministic), `tables.cjs` (frozen BASE_TOOL_RISK / FILE_SENSITIVITY / INPUT_PATTERN_RISK / THRESHOLDS,
|
|
38
|
+
config-overridable extend-only), `route.cjs` (`route(confidence, action) -> auto|confirm|skip|override`),
|
|
39
|
+
`consumers.cjs` (best-effort file-to-node consumers lookup, soften-if-absent), `calibration.cjs` (rolling-50 per-agent
|
|
40
|
+
calibration plus drift detection feeding the bandit reward), `override.cjs`.
|
|
41
|
+
- **`/gdd:override`** - escalation surface for a risk-gate block or a fact-force hold; writes a `D-XX` override-tagged
|
|
42
|
+
decision (audit trail) or clears the `checked[path]` lock, always with an approver and reason.
|
|
43
|
+
- **`risk_assessment` event type** in `reference/schemas/events.schema.json` (score, suggested_action, reasons),
|
|
44
|
+
surfaced by the Phase 55 dashboard risk pane.
|
|
45
|
+
- **`design-fixer` Step 2.5** - a confidence-times-risk routing filter (auto-apply / confirm-with-diff / skip / escalate).
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- **`hooks/gdd-decision-injector.js`** now records per-file reads so the fact-force gate can tell which files you have
|
|
50
|
+
legitimately reviewed this session.
|
|
51
|
+
|
|
52
|
+
## [1.55.0] - 2026-06-03
|
|
53
|
+
|
|
54
|
+
### Phase 55 - GDD Dashboard (Multi-Harness Control Plane + Graph Visualization + Session Surface)
|
|
55
|
+
|
|
56
|
+
GDD ships to 14 runtimes and users run multi-harness sessions in parallel; a control plane is the natural way to surface
|
|
57
|
+
that. Phase 55 ships a READ-ONLY dashboard: a terminal TUI (`bin/gdd-dashboard`) and an opt-in browser graph view
|
|
58
|
+
(`gdd dashboard --web`) that visualizes the Phase 52 DesignContext graph. **Built fully dep-free** (maintainer Rule-4
|
|
59
|
+
decision): no Ink, no React / Vite / React Flow. The ROADMAP had named those stacks (~100 packages / ~84 MB + a CI build
|
|
60
|
+
gate); a footprint study plus the read-only / single-machine / opt-in scale made a hand-rolled ANSI TUI + a
|
|
61
|
+
self-contained-HTML graph (extending the Phase 35.5 `build-html.cjs` precedent) the better fit, and it keeps the
|
|
62
|
+
zero-new-dependency streak intact. The web layer is kept swappable, so a React Flow migration later needs no data rewrite.
|
|
63
|
+
Planned and executed via the GSD pipeline (3 + 3 parallel executors).
|
|
64
|
+
|
|
65
|
+
### Breaking changes
|
|
66
|
+
|
|
67
|
+
- **New `bin/gdd-dashboard` + `gdd dashboard [--web]`.** A new bin (the TUI) and a new SDK CLI subcommand. Read-only by
|
|
68
|
+
design: the dashboard never mutates state (the action surface is "open this file / copy this command / run the
|
|
69
|
+
slash-skill"). The `--web` server is an ephemeral LOCAL loopback (127.0.0.1, OS-assigned port) serving a single
|
|
70
|
+
self-contained HTML file to your own browser, then exits.
|
|
71
|
+
- **`gsd-health` gains a 10th check** (`dashboard_reachable`); the health check count moves 9 -> 10.
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **Data plane** `sdk/dashboard/data/` - `source.cjs` (`loadDashboardModel` reads state / events / graph / health via the
|
|
76
|
+
shared libs in-process, with a `.design/*` file-scrape fallback; never throws), `cost-aggregator.cjs` (per-runtime +
|
|
77
|
+
cumulative + per-cycle), `discovery.cjs` (14-runtime detection, worktree enumeration via `git worktree list`,
|
|
78
|
+
best-effort session manifests).
|
|
79
|
+
- **TUI** `bin/gdd-dashboard` + `sdk/dashboard/tui/` - a hand-rolled ANSI render core (`ansi.cjs`: box/column layout,
|
|
80
|
+
width-aware truncation incl. CJK, line-diff repaint) + 5 panes (Sessions / Cycle / Cost / Findings /
|
|
81
|
+
DesignContext-tree), keyboard navigation, alt-screen, event-tail live refresh. Plain `.cjs` (no bundle, no flags).
|
|
82
|
+
- **Web graph** `scripts/lib/dashboard/graph-html.cjs` (`buildGraphHtml`) - one self-contained HTML doc (inline SVG +
|
|
83
|
+
vanilla JS): layered Atomic / Molecular / Organism / Template layout with barycenter crossing-reduction, viewBox
|
|
84
|
+
pan/zoom, click-to-inspect, type/tag filters, find-consumers highlight, unreachable outline, PNG export, minimap.
|
|
85
|
+
Deterministic (hermetic byte-equal test). Launched by `gdd dashboard --web` (`node:http` loopback + browser-open;
|
|
86
|
+
headless prints the URL; `--once` writes `.design/dashboard.html`).
|
|
87
|
+
- **Risk surfacing** `sdk/dashboard/data/risk-surface.cjs` - reads `risk_score`/`confidence` when present (Phase 56),
|
|
88
|
+
color-routes Allow/Review/RequireConfirmation/Block; a blank placeholder pre-56.
|
|
89
|
+
|
|
90
|
+
### Notes
|
|
91
|
+
|
|
92
|
+
- 6-manifest lockstep at **v1.55.0** + `OFF_CADENCE_VERSIONS.add('1.55.0')` + 37 `manifests-version.txt` baselines.
|
|
93
|
+
No new skill (the dashboard is a bin + CLI subcommand) -> skill-list / build:skills / skills.json unchanged. No new
|
|
94
|
+
agent. The dashboard's local `node:http` server is allowlisted in `scripts/security/outbound-allowlist.json` (an
|
|
95
|
+
inbound loopback read-only server, not outbound egress). Tarball golden 969 -> 979. **No new runtime dependency.**
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
7
99
|
## [1.54.0] - 2026-06-03
|
|
8
100
|
|
|
9
101
|
### Phase 54 - Composable Reference Addendums (Per-DS + Per-Framework + Per-Motion-Lib)
|
package/README.md
CHANGED
|
@@ -269,6 +269,10 @@ All 14 runtimes receive their native artifact layout (`skills/`, `command/`, `ag
|
|
|
269
269
|
|
|
270
270
|
**Composable reference addendums (v1.54.0).** One general mapper prompt cannot know Tailwind's `@theme` tokens from shadcn's `cn()` from vanilla-extract's `style({})`. Phase 54 adds 18 stack-specific addendums (8 design systems, 6 frameworks, 4 motion libraries) under `reference/{systems,frameworks,motion}/`, each at most 50 lines with Conventions / File patterns / Gotchas / Example-output sections. `scripts/lib/detect/stack.cjs` detects the project stack from dependencies plus config files and import signatures; `scripts/lib/mapper-spawn.cjs` composes the matching addendums (capped at one DS + one framework + one motion) into each explore mapper's prompt at spawn time, additively, so a project on an unknown stack just keeps the base prompt and `gsd-health` reports the coverage gap. A `/gdd:new-addendum` scaffolder adds more. Maintainer-authored, vendor-cross-checked, no LLM-generated content. **No new runtime dependency.**
|
|
271
271
|
|
|
272
|
+
**GDD dashboard (v1.55.0).** A read-only multi-harness control plane. `gdd-dashboard` opens a terminal TUI with five panes (sessions per runtime, current cycle, cost telemetry, findings, a DesignContext tree); `gdd dashboard --web` opens an interactive browser view of the Phase 52 graph (layered Atomic/Molecular/Organism/Template layout, pan/zoom, click-to-inspect, type/tag filters, find-consumers highlight, PNG export, minimap). It is **built fully dep-free** (a maintainer decision over the roadmap's Ink + React Flow + Vite stack, which would have added ~100 packages): the TUI is a hand-rolled ANSI renderer, the graph view is a self-contained HTML file (inline SVG + vanilla JS, extending the export builder), and the data plane reads GDD state through the existing shared libraries in-process. Read-only by design (the action surface is open-file / copy-command / run-skill); the `--web` server is a local loopback that serves to your own browser and exits. **No new runtime dependency.**
|
|
273
|
+
|
|
274
|
+
**Risk-scoring and fact-forcing gate (v1.56.0).** Writer actions now carry a quantified risk score instead of a binary allow/deny. A pure, deterministic scorer (`scripts/lib/risk/compute-risk.cjs`, frozen tables, no I/O) grades each Write / Edit / MultiEdit / Bash by tool, file sensitivity, and input shape, then two PreToolUse hooks act on it: `gdd-risk-gate.js` emits a `risk_assessment` event and blocks only the genuinely dangerous actions (destructive bash, high-sensitivity-file rewrites at or above 0.85), while `gdd-fact-force.js` holds the first write to a file until its DesignContext consumers and recorded decisions have actually been read this session. The fact-force hold is soft and softens to a warning when the Phase 52 graph is absent, so greenfield projects are never over-blocked. `/gdd:override` clears a block or a fact-force hold with an approver and reason (audit-trailed as a `D-XX` override decision), and `design-fixer` routes findings by confidence times risk. **Built dep-free** (a maintainer decision: a pure scorer plus static tables, no ML). **No new runtime dependency.**
|
|
275
|
+
|
|
272
276
|
Verify with:
|
|
273
277
|
|
|
274
278
|
```
|
|
@@ -843,6 +847,8 @@ GDD ships defense-in-depth security since Phase 14.5:
|
|
|
843
847
|
|
|
844
848
|
- **`hooks/gdd-bash-guard.js`** - PreToolUse:Bash blocks ~50 dangerous patterns (`rm -rf /`, `chmod 777`, `curl | sh`, `git reset --hard`, fork bombs) after Unicode NFKC + ANSI normalization.
|
|
845
849
|
- **`hooks/gdd-protected-paths.js`** - PreToolUse:Edit/Write/Bash enforces `protected_paths` glob list (defaults: `reference/**`, `.design/archive/**`, `skills/**`, `commands/**`, `hooks/**`, `.design/config.json`, `.design/telemetry/**`).
|
|
850
|
+
- **`hooks/gdd-risk-gate.js`** - PreToolUse:Write/Edit/MultiEdit/Bash scores each writer action via the pure `scripts/lib/risk/compute-risk.cjs` (tool x file-sensitivity x input shape), emits a `risk_assessment` event, and blocks only actions at or above 0.85; `allow` is silent, `review` / `require_confirmation` attach advisory context. Clear a block with `/gdd:override`.
|
|
851
|
+
- **`hooks/gdd-fact-force.js`** - PreToolUse:Edit/Write/MultiEdit holds the first write to a file until its DesignContext consumers and recorded decisions have been Read this session; soft block, softens to a warning when the graph is absent, cleared with `/gdd:override factforce <path>`.
|
|
846
852
|
- **`hooks/gdd-read-injection-scanner.ts`** - scans inbound Read content for invisible-Unicode (zero-width, word-joiner, BOM, bidi overrides) + HTML-comment + secret-exfil patterns.
|
|
847
853
|
- **`scripts/lib/blast-radius.cjs`** - `design-executor` preflight refuses tasks above `max_files_per_task: 10` / `max_lines_per_task: 400`.
|
|
848
854
|
- **`hooks/gdd-mcp-circuit-breaker.js`** - breaks consecutive-timeout loops on `use_figma` / `use_paper` / `use_pencil`.
|
package/SKILL.md
CHANGED
|
@@ -116,6 +116,7 @@ Each stage produces artifacts in `.design/` inside the current project.
|
|
|
116
116
|
| `locale [<code>]` | `get-design-done:gdd-locale` | Phase 40.5 - inspect or set the GDD CLI locale (en/ru/uk/de/fr/zh/ja) for `--help`, errors, and skill prompt headers; missing keys fall back to English. No arg reports the resolved locale + coverage |
|
|
117
117
|
| `context [nodes --type X \| edges --type Z \| path <a> <b> \| consumers-of <id> \| unreachable \| cycles \| coverage]` | `get-design-done:gdd-context` | Phase 52 - read-only query front end for the typed DesignContext graph at `.design/context-graph.json`; lists/filters nodes and edges, traces a path between two nodes, finds a node's consumers, and reports unreachable nodes, dependency cycles, and coverage. Never writes |
|
|
118
118
|
| `migrate-context [--dry-run]` | `get-design-done:gdd-migrate-context` | Phase 52 - migrate a pre-Phase-52 project from flat `.design/map/*.md` mapper notes to the typed DesignContext graph; runs the extract-*.mjs passes, merges fragments, validates with `validate-design-context.cjs`, and flags low-confidence transforms for review. Preview-first; `--dry-run` previews without writing |
|
|
119
|
+
| `override <finding-id \| factforce <path>> [--approver <who>] [--reason <text>]` | `get-design-done:gdd-override` | Phase 56 - escalation surface for a risk-gate block or a first-write fact-force hold; with an approver and reason, writes a `D-XX` override-tagged decision (audit trail) for a blocked finding, or clears the fact-force `checked[path]` lock for a path you have legitimately reviewed. Mirrors unlock-decision; never overrides silently |
|
|
119
120
|
|
|
120
121
|
## Handoff Routing
|
|
121
122
|
|
package/agents/design-fixer.md
CHANGED
|
@@ -125,6 +125,22 @@ f. **Record status.** Note `G-NN: fixed` in your running tracker.
|
|
|
125
125
|
- **Rule 3 - Blocking issue:** If something prevents applying this specific fix (missing import, wrong file structure), resolve the blocking issue first, then apply the fix → continue.
|
|
126
126
|
- **Rule 4 - Architectural change required:** If resolving the gap requires a new DB table, major schema change, switching libraries, or breaking API changes → DO NOT force a fix. Classify as unresolvable and proceed to Step 3 for this gap.
|
|
127
127
|
|
|
128
|
+
### Step 2.5 - Confidence x risk routing (Phase 56)
|
|
129
|
+
|
|
130
|
+
Step 1's confidence filter (`scripts/lib/confidence-route.cjs`) already dropped tentative and low-confidence gaps. Step 2.5 adds the action-risk dimension: a fix that is correct can still be dangerous to APPLY (touching STATE.md, a schema, a hook, a large diff). Score the write, then combine score and confidence into one routing decision per gap.
|
|
131
|
+
|
|
132
|
+
For each in-scope gap, before applying its edit:
|
|
133
|
+
|
|
134
|
+
1. **Score the write.** `risk = computeRisk('Edit', { file_path, new_string })` from `scripts/lib/risk/compute-risk.cjs` (use `MultiEdit` with `edits[]` for multi-hunk fixes, `Write` for full rewrites). `risk.suggested_action` is one of `allow | review | require_confirmation | block`.
|
|
135
|
+
2. **Route.** `decision = route(gap.confidence, risk.suggested_action)` from `scripts/lib/risk/route.cjs`:
|
|
136
|
+
- `auto` (high confidence, low risk): apply the fix via the Step 2 sequence and commit.
|
|
137
|
+
- `confirm` (medium confidence, or `require_confirmation` risk): propose the fix with its diff via `AskUserQuestion` before writing. Apply only on approval; otherwise treat it as `skip`. This agent is the only place the confirmation prompt happens (the writer hooks just score and flag).
|
|
138
|
+
- `skip` (confidence below 0.5, non-block): leave the gap as a deferred finding; do not write. Note it in the tracker.
|
|
139
|
+
- `override` (risk `block`, at any confidence): do NOT auto-apply a block-risk write. Route the user to `{{command_prefix}}override <G-NN> --approver <who> --reason <text>`; apply only after the audited override is recorded.
|
|
140
|
+
3. **Record.** Note each gap as `G-NN: auto | confirm | skip | override` in your running tracker, then carry the `auto` and approved-`confirm` gaps into the Step 2 fix sequence.
|
|
141
|
+
|
|
142
|
+
`route` and `computeRisk` are pure and dependency-free, so this filter is deterministic. A gap whose confidence field is missing is treated as the lowest tier (skip, unless the action is `block`, which routes to override).
|
|
143
|
+
|
|
128
144
|
### Step 3 - Handle unresolvable gaps
|
|
129
145
|
|
|
130
146
|
A gap is unresolvable if:
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/gdd-dashboard — Phase 55 (GDD Dashboard, DEP-FREE), TUI-01 (executor D).
|
|
3
|
+
//
|
|
4
|
+
// CJS trampoline that launches the terminal dashboard
|
|
5
|
+
// (sdk/dashboard/tui/index.cjs) under `node`, forwarding argv + the child's
|
|
6
|
+
// exit code / signal. Windows-safe.
|
|
7
|
+
//
|
|
8
|
+
// SIMPLER than bin/gdd-sdk (R8): the TUI is plain `.cjs` (Node builtins only),
|
|
9
|
+
// so there is NO esbuild bundle and NO `--experimental-strip-types` flag — we
|
|
10
|
+
// just `node <entry>`. The only reason this is a spawning trampoline (rather
|
|
11
|
+
// than a direct require) is the same one gdd-sdk documents: npm's
|
|
12
|
+
// auto-generated Windows `.cmd` shim invokes `node bin/gdd-dashboard` and we
|
|
13
|
+
// want a single, platform-uniform launch path that cleanly forwards the exit
|
|
14
|
+
// code and re-raises a terminating signal (so Ctrl-C tears down correctly).
|
|
15
|
+
//
|
|
16
|
+
// Sibling resolution uses a PACKAGE-ROOT WALK-UP (the Phase 53/54 lesson, D7),
|
|
17
|
+
// never a fixed `__dirname`-relative cross-tree jump: we climb from this file's
|
|
18
|
+
// directory to the GDD package root (package.json with name
|
|
19
|
+
// "get-design-done") and resolve `sdk/dashboard/tui/index.cjs` from there. This
|
|
20
|
+
// keeps the bin correct even if it is copied/relocated within the tree.
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const { spawn } = require('node:child_process');
|
|
25
|
+
const fs = require('node:fs');
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Walk up from `startDir` to the GDD package root: the first ancestor whose
|
|
30
|
+
* package.json declares `name === "get-design-done"`. Falls back to the first
|
|
31
|
+
* ancestor that has any package.json, then to `startDir`. Bounded climb.
|
|
32
|
+
* @param {string} startDir
|
|
33
|
+
* @returns {string} absolute package-root directory
|
|
34
|
+
*/
|
|
35
|
+
function findPackageRoot(startDir) {
|
|
36
|
+
let dir = path.resolve(startDir);
|
|
37
|
+
let firstWithPkg = null;
|
|
38
|
+
for (let i = 0; i < 12; i++) {
|
|
39
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
40
|
+
let pkg = null;
|
|
41
|
+
try {
|
|
42
|
+
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
43
|
+
} catch {
|
|
44
|
+
pkg = null;
|
|
45
|
+
}
|
|
46
|
+
if (pkg) {
|
|
47
|
+
if (firstWithPkg === null) firstWithPkg = dir;
|
|
48
|
+
if (pkg.name === 'get-design-done') return dir;
|
|
49
|
+
}
|
|
50
|
+
const parent = path.dirname(dir);
|
|
51
|
+
if (parent === dir) break;
|
|
52
|
+
dir = parent;
|
|
53
|
+
}
|
|
54
|
+
return firstWithPkg || path.resolve(startDir);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const root = findPackageRoot(__dirname);
|
|
58
|
+
const entry = path.join(root, 'sdk', 'dashboard', 'tui', 'index.cjs');
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(entry)) {
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.error(`gdd-dashboard: TUI entry not found at ${entry}`);
|
|
63
|
+
process.exit(3);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const child = spawn(process.execPath, [entry, ...process.argv.slice(2)], {
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
shell: false,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
child.on('exit', (code, signal) => {
|
|
72
|
+
if (signal) {
|
|
73
|
+
// Re-raise the signal so the parent shell sees the same termination mode
|
|
74
|
+
// (e.g. Ctrl+C propagates as SIGINT). Falls back to a non-zero exit if the
|
|
75
|
+
// self-signal cannot be delivered.
|
|
76
|
+
try {
|
|
77
|
+
process.kill(process.pid, signal);
|
|
78
|
+
} catch {
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
child.on('error', (err) => {
|
|
87
|
+
// Failure to spawn node itself — extremely rare; surface to stderr.
|
|
88
|
+
// eslint-disable-next-line no-console
|
|
89
|
+
console.error('gdd-dashboard: failed to launch the TUI:', err.message);
|
|
90
|
+
process.exit(3);
|
|
91
|
+
});
|
|
@@ -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
|
|
@@ -524,6 +524,58 @@ function buildRecallBlock(matches, basename, backendLabel) {
|
|
|
524
524
|
return lines.join('\n');
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
/**
|
|
528
|
+
* Phase 56 (fact-force) read-tracking — ADDITIVE, best-effort, non-blocking.
|
|
529
|
+
*
|
|
530
|
+
* On every Read, record `reads[<normalizedRelPath>] = <ISO>` into the SAME
|
|
531
|
+
* session-state file the fact-forcing gate consults
|
|
532
|
+
* (`<cwd>/.design/locks/factforce-<sanitized session_id>.json`). This is how the
|
|
533
|
+
* gate knows which importer files an agent has already opened before its first
|
|
534
|
+
* mutation. Fully swallowed on any error so it can NEVER change this Read hook's
|
|
535
|
+
* existing decision-injection behavior or its `{ continue: true }` contract.
|
|
536
|
+
*
|
|
537
|
+
* Self-contained (no new import): mirrors the gate's session_id derivation
|
|
538
|
+
* (`payload.session_id ?? GDD_SESSION_ID ?? 'hook'`), path normalization, and
|
|
539
|
+
* atomic tmp+rename write so the two hooks agree byte-for-byte on the file.
|
|
540
|
+
*/
|
|
541
|
+
function recordReadForFactForce(payload) {
|
|
542
|
+
try {
|
|
543
|
+
const fp = payload && payload.tool_input && payload.tool_input.file_path;
|
|
544
|
+
if (!fp) return;
|
|
545
|
+
const cwd = (payload && payload.cwd) || process.cwd();
|
|
546
|
+
|
|
547
|
+
let rel = String(fp);
|
|
548
|
+
if (rel.startsWith('/') || /^[A-Za-z]:[\\/]/.test(rel)) {
|
|
549
|
+
try { rel = path.relative(cwd, rel); } catch { /* keep rel */ }
|
|
550
|
+
}
|
|
551
|
+
rel = rel.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
552
|
+
if (!rel) return;
|
|
553
|
+
|
|
554
|
+
const rawSid = (payload && (payload.session_id || payload.sessionId))
|
|
555
|
+
|| process.env.GDD_SESSION_ID
|
|
556
|
+
|| 'hook';
|
|
557
|
+
const sid = String(rawSid).replace(/[^A-Za-z0-9_-]+/g, '-').slice(0, 120) || 'hook';
|
|
558
|
+
const stateFile = path.join(cwd, '.design', 'locks', `factforce-${sid}.json`);
|
|
559
|
+
|
|
560
|
+
let state = { reads: {}, first_mutation_seen: {}, checked: {} };
|
|
561
|
+
try {
|
|
562
|
+
const parsed = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
563
|
+
if (parsed && typeof parsed === 'object') {
|
|
564
|
+
state.reads = (typeof parsed.reads === 'object' && parsed.reads) || {};
|
|
565
|
+
state.first_mutation_seen = (typeof parsed.first_mutation_seen === 'object' && parsed.first_mutation_seen) || {};
|
|
566
|
+
state.checked = (typeof parsed.checked === 'object' && parsed.checked) || {};
|
|
567
|
+
}
|
|
568
|
+
} catch { /* missing/corrupt -> start fresh */ }
|
|
569
|
+
|
|
570
|
+
state.reads[rel] = new Date().toISOString();
|
|
571
|
+
|
|
572
|
+
fs.mkdirSync(path.dirname(stateFile), { recursive: true });
|
|
573
|
+
const tmp = `${stateFile}.tmp`;
|
|
574
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
575
|
+
fs.renameSync(tmp, stateFile);
|
|
576
|
+
} catch { /* best-effort: never let read-tracking affect the Read hook */ }
|
|
577
|
+
}
|
|
578
|
+
|
|
527
579
|
async function main() {
|
|
528
580
|
let buf = '';
|
|
529
581
|
for await (const chunk of process.stdin) buf += chunk;
|
|
@@ -539,6 +591,11 @@ async function main() {
|
|
|
539
591
|
return;
|
|
540
592
|
}
|
|
541
593
|
|
|
594
|
+
// Phase 56: record this Read into the fact-force session state for EVERY
|
|
595
|
+
// Read (not just recall-matching .md files), before the recall matcher gate.
|
|
596
|
+
// Best-effort + fully swallowed — does not alter the behavior below.
|
|
597
|
+
recordReadForFactForce(payload);
|
|
598
|
+
|
|
542
599
|
const fp = payload?.tool_input?.file_path || '';
|
|
543
600
|
if (!MATCHER_RE.test(fp)) {
|
|
544
601
|
process.stdout.write(JSON.stringify({ continue: true }));
|
|
@@ -651,5 +708,6 @@ module.exports = {
|
|
|
651
708
|
buildInstinctsBlock,
|
|
652
709
|
instinctTokens,
|
|
653
710
|
queryInstinctsBlock,
|
|
711
|
+
recordReadForFactForce,
|
|
654
712
|
main,
|
|
655
713
|
};
|