@hegemonart/get-design-done 1.58.0 → 1.59.1
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 +4 -4
- package/.claude-plugin/plugin.json +17 -3
- package/CHANGELOG.md +70 -5
- package/README.md +1 -1
- package/SKILL.md +1 -0
- package/bin/gdd-mcp +12 -1
- package/bin/gdd-state-mcp +12 -1
- package/connections/gdd-state.md +8 -8
- package/package.json +2 -4
- package/reference/codex-tools.md +1 -1
- package/reference/gemini-tools.md +1 -1
- package/reference/known-failure-modes.md +2 -2
- package/reference/registry.json +1 -1
- package/reference/schemas/generated.d.ts +240 -4
- package/reference/schemas/mcp-gdd-state-tools.schema.json +1 -1
- package/reference/schemas/mcp-gdd-tools.schema.json +1 -1
- package/reference/skill-graph.md +2 -1
- package/scripts/install.cjs +21 -14
- package/scripts/lib/install/mcp-register.cjs +131 -50
- package/scripts/lib/manifest/skills.json +7 -0
- package/sdk/cli/commands/audit.ts +66 -6
- package/sdk/cli/index.js +33 -3
- package/skills/bandit-reset/SKILL.md +91 -0
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
"argument_hint": "[--retroactive] [--quick] [--no-reflect]",
|
|
30
30
|
"tools": "Read, Write, Task, Glob, Bash"
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"name": "bandit-reset",
|
|
34
|
+
"description": "Confirm-then-reset the per-(agent, bin, delegate) bandit posterior - backs up .design/telemetry/posterior.json to posterior.json.bak, then clears it to a fresh empty envelope. Mutation companion to read-only bandit-status. Use when the posterior is corrupted/unparseable, after a major agent/skill roster change invalidates accumulated arms, or when you deliberately want to rebootstrap adaptive routing from informed priors.",
|
|
35
|
+
"argument_hint": "[--yes to skip the confirmation prompt]",
|
|
36
|
+
"tools": "Read, Write, Bash, AskUserQuestion",
|
|
37
|
+
"disable_model_invocation": true
|
|
38
|
+
},
|
|
32
39
|
{
|
|
33
40
|
"name": "bandit-status",
|
|
34
41
|
"description": "Surface read-only per-(agent, bin, delegate) bandit posterior snapshot - alpha/beta/mean/stddev/count/last-used per arm. Phase 27.5 (v1.27.5) diagnostic. Use when investigating 'why did the bandit pick tier X for agent Y?' or when verifying posterior convergence after enabling adaptive_mode: full.",
|
|
@@ -89,6 +89,11 @@ export interface AuditReport {
|
|
|
89
89
|
readonly connections: readonly ConnectionReport[];
|
|
90
90
|
readonly must_haves: readonly MustHaveReport[];
|
|
91
91
|
readonly baseline?: BaselineReport;
|
|
92
|
+
// `true` when there is no active cycle (.design/STATE.md absent). The audit
|
|
93
|
+
// then runs only the static checks that do not require cycle state and exits
|
|
94
|
+
// 0 with this flag set, rather than failing. Omitted (undefined) on a normal
|
|
95
|
+
// run with an active cycle.
|
|
96
|
+
readonly degraded?: boolean;
|
|
92
97
|
readonly summary: {
|
|
93
98
|
readonly connections_ok: boolean;
|
|
94
99
|
readonly must_haves_ok: boolean;
|
|
@@ -135,14 +140,23 @@ export async function auditCommand(
|
|
|
135
140
|
|
|
136
141
|
const cwd: string =
|
|
137
142
|
typeof flags['cwd'] === 'string' ? (flags['cwd'] as string) : process.cwd();
|
|
138
|
-
const
|
|
139
|
-
typeof flags['state-path'] === 'string' && (flags['state-path'] as string).length > 0
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
const explicitStatePath: boolean =
|
|
144
|
+
typeof flags['state-path'] === 'string' && (flags['state-path'] as string).length > 0;
|
|
145
|
+
const statePath: string = explicitStatePath
|
|
146
|
+
? resolvePath(cwd, flags['state-path'] as string)
|
|
147
|
+
: resolvePath(cwd, '.design', 'STATE.md');
|
|
142
148
|
|
|
143
149
|
if (!existsSync(statePath)) {
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
// An explicit --state-path that does not exist is an arg error: the
|
|
151
|
+
// caller pointed us at a specific file that should be present.
|
|
152
|
+
if (explicitStatePath) {
|
|
153
|
+
stderr.write(`gdd-sdk audit: STATE.md not found at ${statePath}\n`);
|
|
154
|
+
return 3;
|
|
155
|
+
}
|
|
156
|
+
// No active cycle (default .design/STATE.md absent). Graceful degrade:
|
|
157
|
+
// emit a clear message + a degraded report covering the static checks
|
|
158
|
+
// that do not require cycle state, then exit 0 — never throw.
|
|
159
|
+
return emitDegraded(flags, stdout, stderr);
|
|
146
160
|
}
|
|
147
161
|
|
|
148
162
|
const readFn = deps.readState ?? read;
|
|
@@ -218,6 +232,46 @@ export async function auditCommand(
|
|
|
218
232
|
return overallOk ? 0 : 1;
|
|
219
233
|
}
|
|
220
234
|
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// Degraded (no active cycle) path.
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Emit a degraded audit report when there is no active cycle (no
|
|
241
|
+
* `.design/STATE.md`). Connections + must-haves are sourced from STATE.md,
|
|
242
|
+
* so without a cycle there is nothing cycle-bound to evaluate; we report
|
|
243
|
+
* empty sets and exit 0. The `degraded` flag signals callers (and the JSON
|
|
244
|
+
* consumers) that this was a no-cycle run, not a clean active-cycle audit.
|
|
245
|
+
*/
|
|
246
|
+
function emitDegraded(
|
|
247
|
+
flags: Record<string, unknown>,
|
|
248
|
+
stdout: NodeJS.WritableStream,
|
|
249
|
+
stderr: NodeJS.WritableStream,
|
|
250
|
+
): number {
|
|
251
|
+
// Human-facing notice on stderr so JSON on stdout stays machine-parseable.
|
|
252
|
+
stderr.write('gdd-sdk audit: no active cycle — run /gdd:start\n');
|
|
253
|
+
|
|
254
|
+
const report: AuditReport = {
|
|
255
|
+
connections: Object.freeze([]),
|
|
256
|
+
must_haves: Object.freeze([]),
|
|
257
|
+
degraded: true,
|
|
258
|
+
summary: {
|
|
259
|
+
connections_ok: true,
|
|
260
|
+
must_haves_ok: true,
|
|
261
|
+
baseline_ok: true,
|
|
262
|
+
overall_ok: true,
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
if (flags['json'] === true) {
|
|
267
|
+
stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
268
|
+
} else {
|
|
269
|
+
stdout.write(renderHuman(report));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
221
275
|
// ---------------------------------------------------------------------------
|
|
222
276
|
// Baseline comparison.
|
|
223
277
|
// ---------------------------------------------------------------------------
|
|
@@ -352,6 +406,12 @@ function parseBaselineStateSync(raw: string): Pick<ParsedState, 'connections' |
|
|
|
352
406
|
|
|
353
407
|
function renderHuman(report: AuditReport): string {
|
|
354
408
|
const lines: string[] = [];
|
|
409
|
+
if (report.degraded === true) {
|
|
410
|
+
lines.push('audit: degraded (no active cycle — run /gdd:start)');
|
|
411
|
+
lines.push('');
|
|
412
|
+
lines.push('No active cycle: skipped connection + must-have checks.');
|
|
413
|
+
return lines.join('\n') + '\n';
|
|
414
|
+
}
|
|
355
415
|
lines.push(`audit: ${report.summary.overall_ok ? 'clean' : 'REGRESSIONS'}`);
|
|
356
416
|
lines.push('');
|
|
357
417
|
lines.push(`connections (${report.summary.connections_ok ? 'ok' : 'degraded'}):`);
|
package/sdk/cli/index.js
CHANGED
|
@@ -8774,11 +8774,15 @@ async function auditCommand(args, deps = {}) {
|
|
|
8774
8774
|
return 3;
|
|
8775
8775
|
}
|
|
8776
8776
|
const cwd = typeof flags["cwd"] === "string" ? flags["cwd"] : process.cwd();
|
|
8777
|
-
const
|
|
8777
|
+
const explicitStatePath = typeof flags["state-path"] === "string" && flags["state-path"].length > 0;
|
|
8778
|
+
const statePath = explicitStatePath ? (0, import_node_path17.resolve)(cwd, flags["state-path"]) : (0, import_node_path17.resolve)(cwd, ".design", "STATE.md");
|
|
8778
8779
|
if (!(0, import_node_fs17.existsSync)(statePath)) {
|
|
8779
|
-
|
|
8780
|
+
if (explicitStatePath) {
|
|
8781
|
+
stderr.write(`gdd-sdk audit: STATE.md not found at ${statePath}
|
|
8780
8782
|
`);
|
|
8781
|
-
|
|
8783
|
+
return 3;
|
|
8784
|
+
}
|
|
8785
|
+
return emitDegraded(flags, stdout, stderr);
|
|
8782
8786
|
}
|
|
8783
8787
|
const readFn = deps.readState ?? read;
|
|
8784
8788
|
let state;
|
|
@@ -8841,6 +8845,26 @@ async function auditCommand(args, deps = {}) {
|
|
|
8841
8845
|
}
|
|
8842
8846
|
return overallOk ? 0 : 1;
|
|
8843
8847
|
}
|
|
8848
|
+
function emitDegraded(flags, stdout, stderr) {
|
|
8849
|
+
stderr.write("gdd-sdk audit: no active cycle \u2014 run /gdd:start\n");
|
|
8850
|
+
const report = {
|
|
8851
|
+
connections: Object.freeze([]),
|
|
8852
|
+
must_haves: Object.freeze([]),
|
|
8853
|
+
degraded: true,
|
|
8854
|
+
summary: {
|
|
8855
|
+
connections_ok: true,
|
|
8856
|
+
must_haves_ok: true,
|
|
8857
|
+
baseline_ok: true,
|
|
8858
|
+
overall_ok: true
|
|
8859
|
+
}
|
|
8860
|
+
};
|
|
8861
|
+
if (flags["json"] === true) {
|
|
8862
|
+
stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
8863
|
+
} else {
|
|
8864
|
+
stdout.write(renderHuman(report));
|
|
8865
|
+
}
|
|
8866
|
+
return 0;
|
|
8867
|
+
}
|
|
8844
8868
|
function computeBaselineDrift(current, baselineDir) {
|
|
8845
8869
|
const baselinePath = (0, import_node_path17.resolve)(baselineDir, "STATE.md");
|
|
8846
8870
|
if (!(0, import_node_fs17.existsSync)(baselinePath)) {
|
|
@@ -8923,6 +8947,12 @@ function parseBaselineStateSync(raw) {
|
|
|
8923
8947
|
}
|
|
8924
8948
|
function renderHuman(report) {
|
|
8925
8949
|
const lines = [];
|
|
8950
|
+
if (report.degraded === true) {
|
|
8951
|
+
lines.push("audit: degraded (no active cycle \u2014 run /gdd:start)");
|
|
8952
|
+
lines.push("");
|
|
8953
|
+
lines.push("No active cycle: skipped connection + must-have checks.");
|
|
8954
|
+
return lines.join("\n") + "\n";
|
|
8955
|
+
}
|
|
8926
8956
|
lines.push(`audit: ${report.summary.overall_ok ? "clean" : "REGRESSIONS"}`);
|
|
8927
8957
|
lines.push("");
|
|
8928
8958
|
lines.push(`connections (${report.summary.connections_ok ? "ok" : "degraded"}):`);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gdd-bandit-reset
|
|
3
|
+
description: "Confirm-then-reset the per-(agent, bin, delegate) bandit posterior - backs up .design/telemetry/posterior.json to posterior.json.bak, then clears it to a fresh empty envelope. Mutation companion to read-only bandit-status. Use when the posterior is corrupted/unparseable, after a major agent/skill roster change invalidates accumulated arms, or when you deliberately want to rebootstrap adaptive routing from informed priors."
|
|
4
|
+
argument-hint: "[--yes to skip the confirmation prompt]"
|
|
5
|
+
tools: Read, Write, Bash, AskUserQuestion
|
|
6
|
+
disable-model-invocation: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# gdd-bandit-reset
|
|
10
|
+
|
|
11
|
+
## Role
|
|
12
|
+
|
|
13
|
+
You are a deterministic, destructive maintenance skill. You are the ONLY skill that clears the bandit posterior - the mutation companion to read-only `/gdd:bandit-status`. You read the posterior path declared by `scripts/lib/bandit-router.cjs`'s `DEFAULT_POSTERIOR_PATH` (`.design/telemetry/posterior.json`), REQUIRE explicit confirmation, back the file up to `posterior.json.bak`, then overwrite it with a fresh empty envelope so the next bandit pull rebootstraps from informed priors. See `./reference/bandit-integration.md` for setup, interpretation, and convergence guidance.
|
|
14
|
+
|
|
15
|
+
## Invocation Contract
|
|
16
|
+
|
|
17
|
+
- **Input**: optional `--yes` to skip the interactive confirmation (for non-interactive/automated runs).
|
|
18
|
+
- **Output**: a Markdown reset receipt to stdout (backup path + arms cleared + envelope written).
|
|
19
|
+
|
|
20
|
+
## Procedure
|
|
21
|
+
|
|
22
|
+
### 1. Locate the posterior file
|
|
23
|
+
|
|
24
|
+
Read `.design/telemetry/posterior.json` (path declared by `scripts/lib/bandit-router.cjs`'s `DEFAULT_POSTERIOR_PATH` - never hardcode a different path). Missing → nothing to reset; emit and skip to Section 5 (Record):
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
## Bandit Posterior Reset
|
|
28
|
+
|
|
29
|
+
No posterior file found at `.design/telemetry/posterior.json` — nothing to reset.
|
|
30
|
+
|
|
31
|
+
The next bandit pull with `adaptive_mode: full` will bootstrap a fresh posterior from informed priors. See `reference/bandit-integration.md`.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If present, count the arms (`arms.length`, treating a missing/non-array `arms` as `0`) so the confirmation and receipt can report what will be cleared. A corrupted/unparseable file is still resettable - report `arms: unknown (file unparseable)` and continue.
|
|
35
|
+
|
|
36
|
+
### 2. Require explicit confirmation
|
|
37
|
+
|
|
38
|
+
This is a DESTRUCTIVE operation. Do NOT proceed without confirmation.
|
|
39
|
+
|
|
40
|
+
- If `--yes` was passed, skip straight to Section 3.
|
|
41
|
+
- Otherwise, prompt via AskUserQuestion: "Reset the bandit posterior at `.design/telemetry/posterior.json`? This clears <N> learned arms. A backup will be written to `posterior.json.bak` first." with options **Reset** and **Cancel**.
|
|
42
|
+
- On **Cancel** (or any non-affirmative answer), abort WITHOUT touching either the posterior or the backup, and emit:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
## Bandit Posterior Reset — Cancelled
|
|
46
|
+
|
|
47
|
+
No changes made. The posterior at `.design/telemetry/posterior.json` is untouched (<N> arms).
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then skip to Section 5 (Record) with `reset: false`.
|
|
51
|
+
|
|
52
|
+
### 3. Back up the current posterior
|
|
53
|
+
|
|
54
|
+
Copy the live posterior to `.design/telemetry/posterior.json.bak` (sibling backup) BEFORE clearing it, so the previous state is always recoverable. Overwrite any existing `.bak` from a prior reset. If the backup write fails, ABORT before clearing; never clear without a successful backup.
|
|
55
|
+
|
|
56
|
+
### 4. Clear to a fresh empty envelope
|
|
57
|
+
|
|
58
|
+
Overwrite `.design/telemetry/posterior.json` with a fresh empty envelope matching `scripts/lib/bandit-router.cjs`'s `loadPosterior()` shape (`SCHEMA_VERSION` = `1.0.0`, current ISO `generated_at`, empty `arms`):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"schema_version": "1.0.0",
|
|
63
|
+
"generated_at": "<ISO>",
|
|
64
|
+
"arms": []
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Write atomically where possible (`.tmp` + rename, mirroring `savePosterior()`). Then emit the receipt:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
## Bandit Posterior Reset
|
|
72
|
+
|
|
73
|
+
Posterior cleared. The next bandit pull with `adaptive_mode: full` will rebootstrap from informed priors.
|
|
74
|
+
|
|
75
|
+
- Backup: `.design/telemetry/posterior.json.bak`
|
|
76
|
+
- Arms cleared: <N>
|
|
77
|
+
- Fresh envelope: `.design/telemetry/posterior.json` (schema_version 1.0.0, 0 arms)
|
|
78
|
+
|
|
79
|
+
Restore the previous state with: `cp .design/telemetry/posterior.json.bak .design/telemetry/posterior.json`
|
|
80
|
+
Verify the cleared state with `/gdd:bandit-status`. See `reference/bandit-integration.md`.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 5. Record
|
|
84
|
+
|
|
85
|
+
Append one JSONL line to `.design/skill-records.jsonl`: `{"skill":"gdd-bandit-reset","ts":"<ISO>","reset":<bool>,"arms_cleared":<count>,"backup_written":<bool>}`. The skill mutates ONLY the posterior (+ its `.bak`) and appends to skill-records.jsonl (telemetry); it touches no other state.
|
|
86
|
+
|
|
87
|
+
## Cross-references
|
|
88
|
+
|
|
89
|
+
- `/gdd:bandit-status` - read-only companion; inspect the posterior before/after a reset.
|
|
90
|
+
- `./reference/bandit-integration.md` - operator guide; interpretation patterns and when a reset is warranted.
|
|
91
|
+
- `scripts/lib/bandit-router.cjs` - posterior shape, `DEFAULT_POSTERIOR_PATH`, `SCHEMA_VERSION`, `loadPosterior()`, `savePosterior()`, `reset()`.
|