@hegemonart/get-design-done 1.55.0 → 1.57.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 +90 -0
- package/README.md +6 -0
- package/SKILL.md +2 -0
- package/agents/design-fixer.md +16 -0
- package/dist/claude-code/.claude/skills/override/SKILL.md +86 -0
- package/dist/claude-code/.claude/skills/state/SKILL.md +106 -0
- package/hooks/gdd-decision-injector.js +58 -0
- package/hooks/gdd-fact-force.js +434 -0
- package/hooks/gdd-risk-gate.js +406 -0
- package/hooks/hooks.json +18 -0
- package/package.json +1 -1
- package/reference/schemas/events.schema.json +61 -1
- package/reference/skill-graph.md +3 -1
- package/scripts/lib/manifest/skills.json +16 -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/scripts/lib/state/migrate-to-sqlite.cjs +664 -0
- package/scripts/lib/state/query-surface.cjs +391 -0
- package/scripts/lib/state/render-markdown.cjs +717 -0
- package/scripts/lib/state/state-backend.cjs +345 -0
- package/scripts/lib/state/state-store.cjs +735 -0
- package/sdk/cli/index.js +193 -96
- package/sdk/dashboard/data/source.cjs +44 -5
- package/sdk/mcp/gdd-state/server.js +127 -30
- package/sdk/mcp/gdd-state/tools/get.ts +8 -0
- package/sdk/state/index.ts +267 -13
- package/sdk/state/lockfile.ts +48 -0
- package/sdk/state/schema.sql +218 -0
- package/skills/override/SKILL.md +86 -0
- package/skills/state/SKILL.md +106 -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.57.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.57.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.57.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,96 @@ All notable changes to get-design-done are documented here. Versions follow [sem
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.57.0] - 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Phase 57 - SQLite State Backbone (Cross-Session Query Layer)
|
|
10
|
+
|
|
11
|
+
GDD project state lives in per-file markdown (STATE.md blocks, recall, instincts). Cross-cycle queries ("every decision
|
|
12
|
+
tagged accessibility across the last five cycles") require fan-out greps and are effectively infeasible. Phase 57 adds an
|
|
13
|
+
opt-in `.design/state.sqlite` as an indexed query layer over that state, while markdown stays the human-editable source of
|
|
14
|
+
truth. It is **built with zero new dependency**: SQLite is reached through the existing opportunistic
|
|
15
|
+
`probeOptional('better-sqlite3')` runtime probe (the same pattern Phase 51 uses for the instinct store), with a guaranteed
|
|
16
|
+
markdown / JS-scan fallback whenever the module is absent. Migration is opt-in (`--migrate-state`) in v1.57.0, dual-writes
|
|
17
|
+
for one minor version, and is fully reversible (`/gdd:state demigrate`). When better-sqlite3 is not installed, GDD behaves
|
|
18
|
+
exactly as before. Planned and executed via the GSD pipeline (3 + 1 + 2 parallel executors with one reconciliation pass).
|
|
19
|
+
|
|
20
|
+
### Breaking changes
|
|
21
|
+
|
|
22
|
+
- **Opt-in SQLite state backbone.** Running `node scripts/lib/state/migrate-to-sqlite.cjs --migrate-state` builds
|
|
23
|
+
`.design/state.sqlite` (14 tables plus FTS5) from your STATE.md. After migration, state mutations dual-write: SQLite is
|
|
24
|
+
the authoritative store and STATE.md is rendered from it byte-for-byte (the existing `gdd-state` `read`/`mutate`/`transition`
|
|
25
|
+
API is unchanged). Without migration, or when better-sqlite3 is absent, nothing changes - markdown stays authoritative.
|
|
26
|
+
Markdown is always human-editable; a hand-edit is detected on the next write and folded back into SQLite.
|
|
27
|
+
- **New `/gdd:state` skill** with three subcommands: `query "<sql>"` (engine-level read-only SELECT over the
|
|
28
|
+
decisions/blockers/plans tables), `recover` (rebuild a corrupt `state.sqlite` from markdown), and `demigrate` (drop
|
|
29
|
+
`state.sqlite` and fall back to the markdown-only source of truth).
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`scripts/lib/state/`** - `state-backend.cjs` (`probeOptional('better-sqlite3')` + FTS5 probe -> `{Database, BACKEND}`;
|
|
34
|
+
WAL / busy_timeout / foreign_keys pragmas; engine-level readonly opens), `state-store.cjs` (dual-backend dispatch; the
|
|
35
|
+
SQLite-authoritative -> render-markdown -> write-STATE.md transaction; hand-edit freshness guard), `migrate-to-sqlite.cjs`
|
|
36
|
+
(idempotent UPSERT migration, `--migrate-state` opt-in, `--dry-run`), `render-markdown.cjs` (byte-equal STATE.md
|
|
37
|
+
reconstruction from SQLite via the proven serializer), `query-surface.cjs` (readonly SQL + first-token denylist, recover,
|
|
38
|
+
demigrate, cap-10 `.bak` rotation).
|
|
39
|
+
- **`sdk/state/schema.sql`** - 14 tables (state_position, decisions, blockers, must_haves, plans, findings, design_debt,
|
|
40
|
+
recall_records, instincts, sessions, worktree_state, conflict_incidents, plus `_meta`/`_block_meta`) with FTS5 virtual
|
|
41
|
+
tables on decisions/findings/recall/instincts.
|
|
42
|
+
- **Consumers read SQLite when migrated** - `gdd_state__get` and the dashboard data plane read SQLite-direct (markdown
|
|
43
|
+
scrape fallback; the MCP tool schema is unchanged), and the Phase 56 fact-force gate gains an FTS5 tier-0 lookup with the
|
|
44
|
+
grep fallback intact.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **`sdk/state/index.ts`** routes `read`/`mutate`/`transition` through the SQLite dual-write path only when migration is
|
|
49
|
+
active for the resolved state file (a sibling `state.sqlite` exists); otherwise the markdown path runs byte-identically.
|
|
50
|
+
The new SQLite sibling lock (`state.sqlite.lock`) is always acquired before `STATE.md.lock`.
|
|
51
|
+
|
|
52
|
+
## [1.56.0] - 2026-06-03
|
|
53
|
+
|
|
54
|
+
### Phase 56 - Risk-Scoring + Fact-Forcing Gate (Quantified Action Confidence)
|
|
55
|
+
|
|
56
|
+
Every writer action now carries a quantified risk score instead of a binary allow/deny. Phase 56 adds a pure,
|
|
57
|
+
deterministic risk scorer (no I/O, frozen tables) that grades each Write / Edit / MultiEdit / Bash by tool, file
|
|
58
|
+
sensitivity, and input shape, then routes it through two PreToolUse hooks: a risk gate that emits a `risk_assessment`
|
|
59
|
+
event and blocks only genuinely dangerous actions, and a fact-force gate that holds the FIRST write to a file until its
|
|
60
|
+
graph consumers and recorded decisions have actually been read. Both are **dep-free** (a maintainer Rule-4 decision: a
|
|
61
|
+
pure scorer plus static tables, no ML, no new dependency). The gate softens to a warning whenever the Phase 52
|
|
62
|
+
DesignContext graph is absent, so greenfield projects are never over-blocked. A new `/gdd:override` escalation skill
|
|
63
|
+
clears a block or a fact-force hold with an approver and reason (audit-trailed as a `D-XX` override decision), and
|
|
64
|
+
`design-fixer` gains a confidence-times-risk routing step. Planned and executed via the GSD pipeline (3 + 2 parallel
|
|
65
|
+
executors).
|
|
66
|
+
|
|
67
|
+
### Breaking changes
|
|
68
|
+
|
|
69
|
+
- **Writer actions are now risk-gated.** A new PreToolUse hook (`hooks/gdd-risk-gate.js`, matcher
|
|
70
|
+
`Write|Edit|MultiEdit|Bash`) scores every writer action and blocks the few that score at or above 0.85 (destructive
|
|
71
|
+
bash, high-sensitivity-file rewrites). Blocking uses the house-style `{continue:false, stopReason}` contract; `allow`
|
|
72
|
+
is silent, `review` and `require_confirmation` attach advisory context for the agent to surface. Read-only agents are
|
|
73
|
+
allowlisted through.
|
|
74
|
+
- **The first write to a file is fact-forced.** A second PreToolUse hook (`hooks/gdd-fact-force.js`, matcher
|
|
75
|
+
`Edit|Write|MultiEdit`) holds the first mutation of a file until its DesignContext consumers and any recorded
|
|
76
|
+
decisions or blockers for it have been Read this session. The hold is soft (a `stopReason` listing the missing facts)
|
|
77
|
+
and softens to a warning when no graph exists; clear it deliberately with `/gdd:override factforce <path>`.
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- **Risk scorer** `scripts/lib/risk/` - `compute-risk.cjs` (`computeRisk(tool, input) -> {score, reasons, suggested_action, breakdown}`,
|
|
82
|
+
pure and deterministic), `tables.cjs` (frozen BASE_TOOL_RISK / FILE_SENSITIVITY / INPUT_PATTERN_RISK / THRESHOLDS,
|
|
83
|
+
config-overridable extend-only), `route.cjs` (`route(confidence, action) -> auto|confirm|skip|override`),
|
|
84
|
+
`consumers.cjs` (best-effort file-to-node consumers lookup, soften-if-absent), `calibration.cjs` (rolling-50 per-agent
|
|
85
|
+
calibration plus drift detection feeding the bandit reward), `override.cjs`.
|
|
86
|
+
- **`/gdd:override`** - escalation surface for a risk-gate block or a fact-force hold; writes a `D-XX` override-tagged
|
|
87
|
+
decision (audit trail) or clears the `checked[path]` lock, always with an approver and reason.
|
|
88
|
+
- **`risk_assessment` event type** in `reference/schemas/events.schema.json` (score, suggested_action, reasons),
|
|
89
|
+
surfaced by the Phase 55 dashboard risk pane.
|
|
90
|
+
- **`design-fixer` Step 2.5** - a confidence-times-risk routing filter (auto-apply / confirm-with-diff / skip / escalate).
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
|
|
94
|
+
- **`hooks/gdd-decision-injector.js`** now records per-file reads so the fact-force gate can tell which files you have
|
|
95
|
+
legitimately reviewed this session.
|
|
96
|
+
|
|
7
97
|
## [1.55.0] - 2026-06-03
|
|
8
98
|
|
|
9
99
|
### Phase 55 - GDD Dashboard (Multi-Harness Control Plane + Graph Visualization + Session Surface)
|
package/README.md
CHANGED
|
@@ -271,6 +271,10 @@ All 14 runtimes receive their native artifact layout (`skills/`, `command/`, `ag
|
|
|
271
271
|
|
|
272
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
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
|
+
|
|
276
|
+
**SQLite state backbone (v1.57.0).** Project state (decisions, blockers, plans, findings, recall, instincts) lives in per-file markdown, which makes cross-cycle queries ("every accessibility decision across the last five cycles") infeasible. Phase 57 adds an opt-in `.design/state.sqlite` as an indexed query layer while markdown stays the human-editable source of truth. It is **built with zero new dependency**: SQLite is reached through the existing opportunistic `probeOptional('better-sqlite3')` runtime probe (the Phase 51 pattern), with a guaranteed markdown / JS-scan fallback whenever the module is absent. Run `migrate-to-sqlite.cjs --migrate-state` to build the database (14 tables plus FTS5); afterwards state mutations dual-write (SQLite authoritative, STATE.md rendered from it byte-for-byte) while the `gdd-state` read/mutate/transition API is unchanged. `/gdd:state query "<sql>"` runs read-only SELECTs (engine-level readonly), `/gdd:state recover` rebuilds a corrupt database from markdown, and `/gdd:state demigrate` reverts to markdown-only. When better-sqlite3 is not installed, GDD behaves exactly as before. **No new runtime dependency.**
|
|
277
|
+
|
|
274
278
|
Verify with:
|
|
275
279
|
|
|
276
280
|
```
|
|
@@ -845,6 +849,8 @@ GDD ships defense-in-depth security since Phase 14.5:
|
|
|
845
849
|
|
|
846
850
|
- **`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.
|
|
847
851
|
- **`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/**`).
|
|
852
|
+
- **`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`.
|
|
853
|
+
- **`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>`.
|
|
848
854
|
- **`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.
|
|
849
855
|
- **`scripts/lib/blast-radius.cjs`** - `design-executor` preflight refuses tasks above `max_files_per_task: 10` / `max_lines_per_task: 400`.
|
|
850
856
|
- **`hooks/gdd-mcp-circuit-breaker.js`** - breaks consecutive-timeout loops on `use_figma` / `use_paper` / `use_pencil`.
|
package/SKILL.md
CHANGED
|
@@ -116,6 +116,8 @@ 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 |
|
|
120
|
+
| `state <query "<sql>" \| recover \| demigrate>` | `get-design-done:gdd-state` | Phase 57 - operate the opt-in SQLite state backbone: `query` runs a read-only SELECT over the decisions/blockers/plans tables (engine-level readonly), `recover` rebuilds a corrupt `state.sqlite` from the markdown STATE.md, `demigrate` removes `state.sqlite` to fall back to the markdown-only source of truth. Markdown stays the human-editable SoT; SQLite is opportunistic and reversible |
|
|
119
121
|
|
|
120
122
|
## Handoff Routing
|
|
121
123
|
|
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,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
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gdd-state
|
|
3
|
+
description: "Query, recover, or roll back the Phase 57 SQLite state backbone. Use when you need to inspect the decisions/blockers/plans tables with a raw SELECT, rebuild a corrupt state.sqlite from the markdown STATE.md, or revert to the markdown-only source of truth by removing state.sqlite. Activates for requests involving querying the SQLite state database, recovering from SQLite corruption, or reverting the migration (demigrate)."
|
|
4
|
+
argument-hint: "<query \"<sql>\" | recover | demigrate>"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
tools: Read, Bash, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /gdd:state
|
|
10
|
+
|
|
11
|
+
The Phase 57 SQLite state backbone is opt-in (`--migrate-state`) and fully reversible.
|
|
12
|
+
Markdown `.design/STATE.md` is always the human-editable SoT; SQLite is a faster query
|
|
13
|
+
layer derived from it. This skill exposes three subcommands for operating on that layer.
|
|
14
|
+
|
|
15
|
+
## Subcommands
|
|
16
|
+
|
|
17
|
+
| Subcommand | What it does |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `/gdd:state query "<sql>"` | Run a read-only SELECT against `.design/state.sqlite`. |
|
|
20
|
+
| `/gdd:state recover` | Rotate the current sqlite to a `.bak` and rebuild from markdown. |
|
|
21
|
+
| `/gdd:state demigrate` | Remove `.design/state.sqlite`; markdown becomes the SoT again. |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## query
|
|
26
|
+
|
|
27
|
+
Execute a read-only SELECT against the state database.
|
|
28
|
+
|
|
29
|
+
The engine opens the file with `readonly:true` so all writes are rejected at the
|
|
30
|
+
engine level. A first-token denylist (Set membership, no regex) additionally blocks
|
|
31
|
+
DROP, DELETE, UPDATE, INSERT, ALTER, ATTACH, CREATE, PRAGMA, VACUUM, ANALYZE,
|
|
32
|
+
REINDEX, and REPLACE before the connection is opened.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node -e '
|
|
36
|
+
const qs = require("./scripts/lib/state/query-surface.cjs");
|
|
37
|
+
const result = qs.query(process.argv[1], { projectRoot: process.cwd() });
|
|
38
|
+
console.log(JSON.stringify(result, null, 2));
|
|
39
|
+
' "<sql>"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Outputs `{ rows: [...], backend: "sqlite" }` on success, or
|
|
43
|
+
`{ degraded: true, message: "..." }` when SQLite is not active.
|
|
44
|
+
|
|
45
|
+
Degrades gracefully (no throw) when `BACKEND==='markdown'` or when
|
|
46
|
+
`.design/state.sqlite` has not been created yet (run `--migrate-state` first).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## recover
|
|
51
|
+
|
|
52
|
+
Rotate the current (possibly corrupt) `.design/state.sqlite` to `.bak.0`, then
|
|
53
|
+
rebuild a fresh database from the markdown `.design/STATE.md` using
|
|
54
|
+
`migrate-to-sqlite.cjs` in force mode. Runs `PRAGMA integrity_check` on the
|
|
55
|
+
result and reports the outcome.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
node -e '
|
|
59
|
+
const qs = require("./scripts/lib/state/query-surface.cjs");
|
|
60
|
+
const result = qs.recover({ projectRoot: process.cwd() });
|
|
61
|
+
console.log(JSON.stringify(result, null, 2));
|
|
62
|
+
'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Outputs `{ recovered: true, integrity: true, message: "..." }` on success.
|
|
66
|
+
|
|
67
|
+
Backup rotation keeps at most 10 files (`.bak.0` through `.bak.9`). The oldest
|
|
68
|
+
backup is overwritten when the cap is reached.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## demigrate
|
|
73
|
+
|
|
74
|
+
Remove `.design/state.sqlite` so the markdown `STATE.md` becomes the SoT again.
|
|
75
|
+
Idempotent: if the file does not exist, returns a clear no-op message without error.
|
|
76
|
+
A backup is taken in `.bak.0` before removal.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
node -e '
|
|
80
|
+
const qs = require("./scripts/lib/state/query-surface.cjs");
|
|
81
|
+
const result = qs.demigrate({ projectRoot: process.cwd() });
|
|
82
|
+
console.log(JSON.stringify(result, null, 2));
|
|
83
|
+
'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Outputs `{ demigrated: true, message: "..." }` when the file was removed, or
|
|
87
|
+
`{ demigrated: false, message: "..." }` when it was already absent (no-op).
|
|
88
|
+
|
|
89
|
+
To re-enable SQLite after a demigrate, run `--migrate-state` again.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Key design decisions
|
|
94
|
+
|
|
95
|
+
- **Markdown is always the SoT.** SQLite is opt-in via `--migrate-state` and
|
|
96
|
+
reversible via `demigrate`. The markdown file is never silently overwritten.
|
|
97
|
+
- **Read-only queries only.** The `query` subcommand enforces SELECT-only via both
|
|
98
|
+
the engine (`readonly:true`) and a defense-in-depth denylist. No writes
|
|
99
|
+
are possible through this skill.
|
|
100
|
+
- **Backup rotation cap.** `rotateBak` shifts `.bak.0..8` up by one index and caps
|
|
101
|
+
at `.bak.9` (10 files total). The oldest backup is overwritten automatically.
|
|
102
|
+
- **Graceful degradation.** All subcommands return a clear `{ degraded, message }`
|
|
103
|
+
object (no throw) when `better-sqlite3` is not installed or when
|
|
104
|
+
`GDD_STATE_BACKEND=markdown` is set.
|
|
105
|
+
|
|
106
|
+
## STATE 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
|
};
|