@wrongstack/core 0.277.2 → 0.280.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/dist/{agent-bridge-BFJ2ODzI.d.ts → agent-bridge-DXC6QDJ4.d.ts} +1 -1
- package/dist/{agent-subagent-runner-BimKihiC.d.ts → agent-subagent-runner-PoqNKiR4.d.ts} +563 -471
- package/dist/{compactor-D3BGw26y.d.ts → compactor-U3agvUIG.d.ts} +1 -1
- package/dist/{config-DAOjriz9.d.ts → config-Cr3312zc.d.ts} +102 -4
- package/dist/coordination/index.d.ts +1087 -998
- package/dist/coordination/index.js +12235 -12052
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +31 -30
- package/dist/defaults/index.js +403 -189
- package/dist/defaults/index.js.map +1 -1
- package/dist/{brain-CCfuEOdp.d.ts → events-Bs2fmldo.d.ts} +117 -112
- package/dist/execution/index.d.ts +27 -19
- package/dist/execution/index.js +216 -63
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +8 -7
- package/dist/{global-mailbox-Dr4cTKqL.d.ts → global-mailbox-Ct7IorLJ.d.ts} +84 -6
- package/dist/{goal-store-C1uH4srH.d.ts → goal-store-C4F6DjC0.d.ts} +1 -1
- package/dist/hq/index.d.ts +504 -7
- package/dist/hq/index.js +1069 -20
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-DJXj-dcr.d.ts → index-kidebiDh.d.ts} +8 -5
- package/dist/{index-cMEmzCVN.d.ts → index-nP09-oP2.d.ts} +2 -2
- package/dist/index.d.ts +153 -76
- package/dist/index.js +5791 -3163
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +7 -6
- package/dist/kernel/index.d.ts +14 -13
- package/dist/kernel/index.js +31 -15
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mailbox-types-DTl7bRH3.d.ts → mailbox-types-BGZWrYTJ.d.ts} +38 -0
- package/dist/{mcp-servers-CFb60-pH.d.ts → mcp-servers-D910X5_r.d.ts} +3 -3
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-5Ufn7f2m.d.ts → models-registry-CLkoOcHk.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-CcrcncvG.d.ts → multi-agent-coordinator-CieyUoEL.d.ts} +1 -1
- package/dist/{null-fleet-bus-C9KsYyrI.d.ts → null-fleet-bus-DkdmZJ_W.d.ts} +464 -464
- package/dist/observability/index.d.ts +3 -2
- package/dist/{path-resolver-CEeX9I7O.d.ts → path-resolver-XfZ9eLxG.d.ts} +3 -3
- package/dist/{permission-DbsGOA1C.d.ts → permission-Dx6dIqS2.d.ts} +2 -7
- package/dist/{permission-policy-BpEea3r7.d.ts → permission-policy-C8vJcnX5.d.ts} +2 -2
- package/dist/{pipeline-CEjBjzVA.d.ts → pipeline-BwAP21_4.d.ts} +9 -4
- package/dist/{provider-model-resolve-BpfXp3Jj.d.ts → provider-model-resolve-CwQNZWt_.d.ts} +3 -3
- package/dist/{provider-runner-CnOSr5BN.d.ts → provider-runner-CYHFImzV.d.ts} +3 -3
- package/dist/{retry-policy-Git9WF6d.d.ts → retry-policy-D4feSLk3.d.ts} +1 -1
- package/dist/sdd/index.d.ts +11 -10
- package/dist/sdd/index.js +2 -2
- package/dist/sdd/index.js.map +1 -1
- package/dist/secret-scrubber-3MHDDAtm.d.ts +6 -0
- package/dist/{secret-vault-DDSMHqIm.d.ts → secret-vault-CImt2XrR.d.ts} +1 -1
- package/dist/security/index.d.ts +6 -5
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Cq72C0Oy.d.ts → selector-Dy-MzKp1.d.ts} +1 -1
- package/dist/{session-event-bridge-DG94B3Bk.d.ts → session-event-bridge-CqdiGnfU.d.ts} +1 -1
- package/dist/{session-reader-BzT-iMQT.d.ts → session-reader-Hk0WbNm9.d.ts} +1 -1
- package/dist/{skill-DGIXCtdv.d.ts → skill-DHniprNl.d.ts} +15 -1
- package/dist/skills/index.d.ts +472 -26
- package/dist/skills/index.js +872 -129
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +27 -14
- package/dist/storage/index.js +264 -85
- package/dist/storage/index.js.map +1 -1
- package/dist/{strategy-compactor-Bt_ZH6R0.d.ts → strategy-compactor-CQwhbErd.d.ts} +32 -17
- package/dist/{todos-checkpoint-CH1pcua9.d.ts → todos-checkpoint-Bk2uP7Ex.d.ts} +6 -6
- package/dist/{context-DPlA6kid.d.ts → tool-BkOgs_KL.d.ts} +306 -286
- package/dist/{tool-executor-SVFq7IOR.d.ts → tool-executor-SiE1wlZo.d.ts} +9 -9
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +22 -21
- package/dist/types/index.js +7 -9
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +30 -4
- package/dist/utils/index.js +50 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{worktree-manager-C4YIf1Fa.d.ts → worktree-manager-BjOFF6bt.d.ts} +1 -1
- package/dist/{wstack-paths-_NrRovdr.d.ts → wstack-paths-CMl_cYgq.d.ts} +8 -0
- package/package.json +1 -1
- package/skills/mailbox-bridge/SKILL.md +1 -0
- package/skills/plugin-author/SKILL.md +350 -0
- package/skills/sdd/SKILL.md +134 -134
- package/skills/skill-creator/SKILL.md +45 -7
- package/skills/wrongstack-mailbox/SKILL.md +40 -21
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
interface WstackPaths {
|
|
10
10
|
/** ~/.wrongstack — global root. */
|
|
11
11
|
globalRoot: string;
|
|
12
|
+
/** Absolute project root. */
|
|
13
|
+
projectRoot: string;
|
|
14
|
+
/** Home directory (~) — base for foreign tool state (~/.codex, ~/.agents, …). */
|
|
15
|
+
homeDir: string;
|
|
12
16
|
/**
|
|
13
17
|
* ~/.wrongstack — directory for user-global stateful config files
|
|
14
18
|
* (mode.json, theme.json, …). Currently an alias for `globalRoot`;
|
|
@@ -24,6 +28,8 @@ interface WstackPaths {
|
|
|
24
28
|
globalMemory: string;
|
|
25
29
|
/** ~/.wrongstack/skills — user-global skills. */
|
|
26
30
|
globalSkills: string;
|
|
31
|
+
/** ~/.claude/skills — user-global skills from foreign coding agents (Claude Code, Codex, …). Read-only. */
|
|
32
|
+
globalClaudeSkills: string;
|
|
27
33
|
/** ~/.wrongstack/design-kits — user-global Design Studio kits. */
|
|
28
34
|
globalDesignKits: string;
|
|
29
35
|
/** ~/.wrongstack/prompts — user-global prompt library. */
|
|
@@ -67,6 +73,8 @@ interface WstackPaths {
|
|
|
67
73
|
inProjectAgentsFile: string;
|
|
68
74
|
/** <project>/.wrongstack/skills — committed project skills. */
|
|
69
75
|
inProjectSkills: string;
|
|
76
|
+
/** <project>/.claude/skills — project skills authored for foreign coding agents (Claude Code, …). Read-only. */
|
|
77
|
+
inProjectClaudeSkills: string;
|
|
70
78
|
/** <project>/.wrongstack/prompts — committed project prompt library. */
|
|
71
79
|
inProjectPrompts: string;
|
|
72
80
|
/** <project>/.wrongstack/instructions — committed project instruction overrides. */
|
package/package.json
CHANGED
|
@@ -126,6 +126,7 @@ require `Authorization: Bearer <token>`. All responses are JSON.
|
|
|
126
126
|
|--------|------|-------|
|
|
127
127
|
| POST | `/mailbox/send` | `GlobalMailbox.send` |
|
|
128
128
|
| POST | `/mailbox/query` | `GlobalMailbox.query` |
|
|
129
|
+
| POST | `/mailbox/check` | convenience inbox check: direct/base/broadcast query plus optional read/completion batch ack |
|
|
129
130
|
| POST | `/mailbox/ack` | `GlobalMailbox.ack` |
|
|
130
131
|
| POST | `/mailbox/ack-many` | `GlobalMailbox.ackMany` (batch under one lock + rewrite) |
|
|
131
132
|
| POST | `/mailbox/unread-count` | `GlobalMailbox.unreadCount` |
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plugin-author
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when creating, reviewing, or refactoring a WrongStack plugin
|
|
5
|
+
in `packages/plugins/`. Covers the Plugin interface, tool registration, config
|
|
6
|
+
schema, the H1 audit pattern (teardown + health), PluginAPI extension for host
|
|
7
|
+
data, and the entry-point registration steps (tsup, package.json, index.ts).
|
|
8
|
+
Triggers: user says "new plugin", "add a plugin", "plugin teardown", "plugin
|
|
9
|
+
health", "register a tool", "PluginAPI extension".
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Plugin Author — WrongStack
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Guides the creation and maintenance of first-party plugins in
|
|
18
|
+
`packages/plugins/`. A plugin is a TypeScript module that implements
|
|
19
|
+
the `Plugin` interface from `@wrongstack/core`, registering tools,
|
|
20
|
+
hooks, slash commands, or pipelines into the agent's runtime.
|
|
21
|
+
|
|
22
|
+
There are currently **21 official plugins** in the suite:
|
|
23
|
+
|
|
24
|
+
| Plugin | Tools | Hooks | Stateful |
|
|
25
|
+
|--------|-------|-------|----------|
|
|
26
|
+
| `auto-doc` | `auto_doc` | — | ✅ teardown+health |
|
|
27
|
+
| `git-autocommit` | `git_autocommit` | — | ✅ teardown+health |
|
|
28
|
+
| `shell-check` | `shellcheck` | — | ✅ teardown+health |
|
|
29
|
+
| `cost-tracker` | `cost_summary`, `cost_reset`, `cost_export` | — | ✅ teardown+health |
|
|
30
|
+
| `file-watcher` | `watch_start`, `watch_stop`, `watch_list` | — | ✅ teardown+health |
|
|
31
|
+
| `cron` | `cron_schedule`, `cron_list`, `cron_cancel` | — | ✅ teardown+health |
|
|
32
|
+
| `template-engine` | `template_expand`, `template_render`, `template_create`, `template_list` | — | ✅ teardown+health |
|
|
33
|
+
| `semver-bump` | `semver_bump`, `semver_current`, `semver_changelog` | — | ✅ teardown+health |
|
|
34
|
+
| `secret-scanner` | `secret_scanner_status`, `secret_scanner_test` | `PreToolUse` + `PostToolUse` | ✅ teardown+health |
|
|
35
|
+
| `todo-tracker` | `todo_tracker_list/add/complete/drop/remove/pull/status` | — | ✅ teardown+health |
|
|
36
|
+
| `token-budget` | `token_budget_status` | `Stop` + `PostToolUse` | ✅ teardown+health |
|
|
37
|
+
| `lint-gate` | `lint_gate_status` | `PreToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
38
|
+
| `branch-guard` | `branch_guard_status` | `PreToolUse` (`bash\|git_autocommit`) | ✅ teardown+health |
|
|
39
|
+
| `diff-summary` | `diff_summary_status` | `PostToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
40
|
+
| `commit-validator` | `commit_validator_status` | `PreToolUse` (`bash\|git_autocommit`) | ✅ teardown+health |
|
|
41
|
+
| `format-on-save` | `format_on_save_status` | `PostToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
42
|
+
| `test-runner-gate` | `test_gate_status` | `PostToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
43
|
+
| `import-organizer` | `import_organizer_status` | `PostToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
44
|
+
| `todo-listener` | `todo_listener_status` | `PostToolUse` (`todo`) | ✅ teardown+health |
|
|
45
|
+
| `session-recap` | `session_recap_status` | `Stop` | ✅ teardown+health |
|
|
46
|
+
| `spec-linker` | `spec_linker_status` | `PostToolUse` (`write\|edit`) | ✅ teardown+health |
|
|
47
|
+
|
|
48
|
+
## Rules
|
|
49
|
+
|
|
50
|
+
1. **Every plugin must implement `teardown()` and `health()`.** Even
|
|
51
|
+
stateless plugins (shell-check, semver-bump) add both — the teardown
|
|
52
|
+
logs a completion line with per-session counters, and `health()`
|
|
53
|
+
reports `ok: true` + counters for `/diag plugins`. This is the **H1
|
|
54
|
+
audit pattern** (see below).
|
|
55
|
+
2. **State at module scope, not in the setup() closure.** The Plugin
|
|
56
|
+
interface does not thread state from `setup()` → `teardown()`. If
|
|
57
|
+
teardown needs to clean up a resource (timer, watcher, counter),
|
|
58
|
+
the reference must live at module scope. State in the setup
|
|
59
|
+
closure is unreachable from teardown and **leaks on reload**.
|
|
60
|
+
3. **`setup()` is idempotent.** It must zero/clear state before
|
|
61
|
+
re-initializing. Calling `setup()` twice (e.g. across a hot-reload)
|
|
62
|
+
leaves a clean slate, not accumulated state.
|
|
63
|
+
4. **`teardown()` never deletes on-disk state.** File-based plugins
|
|
64
|
+
(todo-tracker) leave the file in place — the user may return. Only
|
|
65
|
+
in-memory counters and resource handles (timers, watchers) are
|
|
66
|
+
cleaned up.
|
|
67
|
+
5. **Tool names use `snake_case`.** Plugin-level tools registered via
|
|
68
|
+
`api.tools.register()` must be unique across the suite. The built-in
|
|
69
|
+
tools (`bash`, `write`, `read`, `edit`, `fetch`, `search`, `json`,
|
|
70
|
+
`todo`, `git`, etc.) are always present; don't collide.
|
|
71
|
+
6. **`apiVersion` must satisfy `^0.1` (current kernel API = `0.1.10`).**
|
|
72
|
+
Bump only when the PluginAPI surface breaks. Additive changes (new
|
|
73
|
+
optional fields on PluginAPI) do NOT require a bump.
|
|
74
|
+
7. **Config goes under `config.extensions['<plugin-name>']`**, not
|
|
75
|
+
`config.plugins`. The loader's `buildPluginOptions` merges both
|
|
76
|
+
surfaces; plugins read from `api.config.extensions`.
|
|
77
|
+
|
|
78
|
+
## The Plugin interface
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import type { Plugin } from '@wrongstack/core';
|
|
82
|
+
|
|
83
|
+
const plugin: Plugin = {
|
|
84
|
+
name: 'my-plugin',
|
|
85
|
+
version: '0.1.0',
|
|
86
|
+
description: 'One-line summary for wstack plugins list',
|
|
87
|
+
apiVersion: '^0.1.10',
|
|
88
|
+
capabilities: { tools: true }, // hints for /diag
|
|
89
|
+
|
|
90
|
+
// Optional: JSON Schema for config validation
|
|
91
|
+
defaultConfig: { enabled: true },
|
|
92
|
+
configSchema: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
enabled: { type: 'boolean', default: true },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Called by the host to activate the plugin.
|
|
100
|
+
setup(api) { /* register tools, hooks, events */ },
|
|
101
|
+
|
|
102
|
+
// Called by the host during unload. Same api instance as setup.
|
|
103
|
+
teardown(api) { /* clear state, release resources, log */ },
|
|
104
|
+
|
|
105
|
+
// Called by /diag plugins. Return ok + message + counters.
|
|
106
|
+
async health() {
|
|
107
|
+
return { ok: true, message: 'healthy', invocationCount: 0 };
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export default plugin;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## H1 audit pattern
|
|
115
|
+
|
|
116
|
+
After the 2026-06-03 audit found that several plugins leaked resources
|
|
117
|
+
on reload (timers, chokidar watchers, in-memory caches unreachable from
|
|
118
|
+
teardown), the following lifecycle pattern was formalized. **All 10
|
|
119
|
+
plugins follow it.**
|
|
120
|
+
|
|
121
|
+
### 1. State at module scope
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// ✅ Module scope — teardown can reach this
|
|
125
|
+
const state = {
|
|
126
|
+
invocationCount: 0,
|
|
127
|
+
timers: new Map<string, NodeJS.Timeout>(),
|
|
128
|
+
lastRun: null as null | { when: string; result: string },
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// ❌ NEVER — setup closure, unreachable from teardown
|
|
132
|
+
setup(api) {
|
|
133
|
+
const timers = new Map(); // LEAKS on reload
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 2. Idempotent setup
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
setup(api) {
|
|
141
|
+
// Clear everything first, then re-init from config.
|
|
142
|
+
state.invocationCount = 0;
|
|
143
|
+
for (const t of state.timers.values()) clearTimeout(t);
|
|
144
|
+
state.timers.clear();
|
|
145
|
+
state.lastRun = null;
|
|
146
|
+
|
|
147
|
+
// Now register tools, apply config, subscribe to events.
|
|
148
|
+
api.tools.register({ /* ... */ });
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 3. Teardown releases resources
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
teardown(api) {
|
|
156
|
+
const count = state.invocationCount;
|
|
157
|
+
state.invocationCount = 0;
|
|
158
|
+
state.lastRun = null;
|
|
159
|
+
// Release every resource that was acquired in setup().
|
|
160
|
+
for (const t of state.timers.values()) clearTimeout(t);
|
|
161
|
+
state.timers.clear();
|
|
162
|
+
api.log.info('my-plugin: teardown complete', { invocations: count });
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 4. Health reports per-session visibility
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
async health() {
|
|
170
|
+
return {
|
|
171
|
+
ok: true,
|
|
172
|
+
message: state.lastRun === null
|
|
173
|
+
? 'my-plugin: no calls yet'
|
|
174
|
+
: `my-plugin: last call at ${state.lastRun.when}`,
|
|
175
|
+
invocationCount: state.invocationCount,
|
|
176
|
+
lastRun: state.lastRun,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Tool registration
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
api.tools.register({
|
|
185
|
+
name: 'my_tool',
|
|
186
|
+
description: 'What this tool does. Include when to use and what it returns.',
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
path: { type: 'string', description: 'File path' },
|
|
191
|
+
},
|
|
192
|
+
required: ['path'],
|
|
193
|
+
},
|
|
194
|
+
permission: 'auto', // 'auto' | 'confirm'
|
|
195
|
+
mutating: false, // does it change external state?
|
|
196
|
+
category: 'Project',
|
|
197
|
+
async execute(input: Record<string, unknown>) {
|
|
198
|
+
const path = input['path'] as string;
|
|
199
|
+
// ... do the work ...
|
|
200
|
+
return { ok: true, path, result: '...' };
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Permission levels
|
|
206
|
+
|
|
207
|
+
| Permission | When |
|
|
208
|
+
|------------|------|
|
|
209
|
+
| `auto` | Safe operations (read, list, query). No user confirmation. |
|
|
210
|
+
| `confirm` | Destructive or side-effecting operations (write, commit, delete). User must approve. |
|
|
211
|
+
|
|
212
|
+
## Config surface
|
|
213
|
+
|
|
214
|
+
Two surfaces exist. The loader merges them:
|
|
215
|
+
|
|
216
|
+
1. **`config.plugins`** — loading control: `[{ name: 'my-plugin', enabled: false }]`
|
|
217
|
+
2. **`config.extensions['my-plugin']`** — options: `{ option1: value1 }`
|
|
218
|
+
|
|
219
|
+
Plugins read from `api.config.extensions`:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
setup(api) {
|
|
223
|
+
const ext = api.config.extensions?.['my-plugin'] as Record<string, unknown> | undefined;
|
|
224
|
+
const myOption = (ext?.['myOption'] as string) ?? 'default';
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
If the plugin declares `configSchema`, the loader validates the
|
|
229
|
+
options section before calling `setup` and rejects the plugin with a
|
|
230
|
+
clear error on failure.
|
|
231
|
+
|
|
232
|
+
## Hook registration (PreToolUse, PostToolUse, etc.)
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// secret-scanner pattern: block tools whose args contain secrets
|
|
236
|
+
api.registerHook('PreToolUse', 'bash|write|edit', (input) => {
|
|
237
|
+
const text = JSON.stringify(input.toolInput ?? {});
|
|
238
|
+
if (detectSecret(text)) {
|
|
239
|
+
return {
|
|
240
|
+
decision: 'block',
|
|
241
|
+
reason: 'Plaintext credential detected in tool arguments',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Omitted decision = allow (no-op)
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Available events: `PreToolUse`, `PostToolUse`, `UserPromptSubmit`,
|
|
249
|
+
`SessionStart`, `Stop`.
|
|
250
|
+
|
|
251
|
+
`HookOutcome` fields:
|
|
252
|
+
- `decision: 'block' | 'allow'` — block stops the action
|
|
253
|
+
- `reason: string` — surfaced to the model when blocking
|
|
254
|
+
- `modifiedInput: Record<string, unknown>` — PreToolUse replacement args
|
|
255
|
+
- `additionalContext: string` — extra context folded back to the model
|
|
256
|
+
|
|
257
|
+
## PluginAPI extension (cross-package host data)
|
|
258
|
+
|
|
259
|
+
When a plugin needs host data not yet on `PluginAPI` (e.g.
|
|
260
|
+
`modelsRegistry`, `projectDir`), extend the surface in three steps:
|
|
261
|
+
|
|
262
|
+
1. **`packages/core/src/types/plugin.ts`** — add the optional field to `PluginAPI`
|
|
263
|
+
2. **`packages/core/src/plugin/api.ts`** — add to `PluginAPIInit` + `DefaultPluginAPI`
|
|
264
|
+
3. **`packages/cli/src/wiring/plugins.ts`** — destructure + forward in `setupPlugins`
|
|
265
|
+
|
|
266
|
+
Precedent: commit `9bed619f` added `modelsRegistry?: ModelsRegistry` for
|
|
267
|
+
cost-tracker's pricing hydration.
|
|
268
|
+
|
|
269
|
+
## Entry-point registration (3 files)
|
|
270
|
+
|
|
271
|
+
After writing `src/<name>/index.ts`, wire it into three files:
|
|
272
|
+
|
|
273
|
+
### 1. `src/index.ts` — named re-export
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
export { default as myPluginPlugin } from './my-plugin/index.js';
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 2. `tsup.config.ts` — build entry
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
entry: {
|
|
283
|
+
// ...
|
|
284
|
+
'my-plugin': 'src/my-plugin/index.ts',
|
|
285
|
+
},
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 3. `package.json` — subpath export
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
"./my-plugin": {
|
|
292
|
+
"types": "./dist/my-plugin.d.ts",
|
|
293
|
+
"import": "./dist/my-plugin.js"
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 4. `packages/cli/src/wiring/plugins.ts` — built-in factory
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
async () => (await import('@wrongstack/plugins/my-plugin')).default,
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Tests
|
|
304
|
+
|
|
305
|
+
Every plugin gets two test files:
|
|
306
|
+
|
|
307
|
+
- **`tests/<name>.test.ts`** — unit tests (mock API, tool registration,
|
|
308
|
+
config validation, teardown log line, health() shape)
|
|
309
|
+
- **`tests/<name>-exec.test.ts`** — integration tests (real filesystem,
|
|
310
|
+
real CLI tools if applicable)
|
|
311
|
+
|
|
312
|
+
For the H1 pattern, extend `tests/plugin-teardown.test.ts` with a
|
|
313
|
+
`describe('<name>')` block covering:
|
|
314
|
+
- `teardown` logs a completion line and does not throw
|
|
315
|
+
- `health()` reports ok + non-empty message
|
|
316
|
+
- `teardown` zeros counters
|
|
317
|
+
|
|
318
|
+
## Anti-patterns
|
|
319
|
+
|
|
320
|
+
- **State in setup closure** — leaks on reload. Always module scope.
|
|
321
|
+
- **Missing teardown** — `/diag plugins` shows a gap; reload leaks.
|
|
322
|
+
- **Missing health()** — operator can't confirm the plugin is alive.
|
|
323
|
+
- **Tool name collision** — `read`, `write`, `bash`, etc. are built-in.
|
|
324
|
+
- **Deleting on-disk state in teardown** — the user may return.
|
|
325
|
+
- **Blocking setup with async hydration** — use `void (async () => { ... })()`
|
|
326
|
+
for fire-and-forget; let the first call fall through to fallback if
|
|
327
|
+
the async hasn't completed yet.
|
|
328
|
+
- **Not lowercasing model/config keys** — case-insensitive lookup is
|
|
329
|
+
the convention; `model.toLowerCase()` everywhere.
|
|
330
|
+
|
|
331
|
+
## Workflow
|
|
332
|
+
|
|
333
|
+
1. **Create the plugin directory**: `src/<name>/index.ts`
|
|
334
|
+
2. **Write the Plugin object**: name, version, apiVersion, setup, teardown, health
|
|
335
|
+
3. **Register tools/hooks** in `setup()`
|
|
336
|
+
4. **Add state + teardown + health** following the H1 pattern
|
|
337
|
+
5. **Wire into 3 files**: `index.ts`, `tsup.config.ts`, `package.json`
|
|
338
|
+
6. **Add to `BUILTIN_PLUGIN_FACTORIES`** in CLI wiring
|
|
339
|
+
7. **Write tests**: `<name>.test.ts` (unit) + extend `plugin-teardown.test.ts`
|
|
340
|
+
8. **Run verification**: `npx vitest run packages/plugins` + `npx tsc --noEmit` + `npx tsup`
|
|
341
|
+
9. **Update `src/index.ts` doc comment** — bump the plugin count
|
|
342
|
+
|
|
343
|
+
## Skills in scope
|
|
344
|
+
|
|
345
|
+
- `skill-creator` — for the SKILL.md format and frontmatter rules
|
|
346
|
+
- `prompt-engineering` — for crafting tool descriptions and usageHint
|
|
347
|
+
- `typescript-strict` — for strict TypeScript patterns in plugin code
|
|
348
|
+
- `node-modern` — for ESM imports, AbortSignal, and async patterns
|
|
349
|
+
- `testing` — for vitest patterns and mock API construction
|
|
350
|
+
- `output-standards` — for standardized `<next_steps>` formatting
|
package/skills/sdd/SKILL.md
CHANGED
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sdd
|
|
3
|
-
description: |
|
|
4
|
-
Use this skill when starting a non-trivial implementation, bug fix, or refactor
|
|
5
|
-
in WrongStack. Triggers: user says "/sdd", "spec", "specification", "task graph",
|
|
6
|
-
"SDD", "acceptance criteria", or starts a new feature.
|
|
7
|
-
version: 2.1.0
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Spec-Driven Development — WrongStack
|
|
11
|
-
|
|
12
|
-
## Overview
|
|
13
|
-
|
|
14
|
-
Every non-trivial change starts with a spec. The spec is the source of truth — it defines what to build, how to verify it, and what counts as done. SDD uses `/sdd` slash commands to create specs, generate task graphs, and track execution.
|
|
15
|
-
|
|
16
|
-
## Rules
|
|
17
|
-
|
|
18
|
-
1. Every non-trivial task needs a spec before writing code — you'll rewrite it anyway.
|
|
19
|
-
2. Spec must have acceptance criteria — without them, you can't know when it's done.
|
|
20
|
-
3. Tasks must have dependencies — everything is a dependency of something.
|
|
21
|
-
4. Spec must be specific: "Users authenticate via OAuth2 with PKCE" not "improve auth".
|
|
22
|
-
5. Skipping `/sdd` for urgent tasks backfires — the spec is what makes "urgent" possible.
|
|
23
|
-
6. When the spec reveals a multi-file refactor, delegate to `refactor-planner` first.
|
|
24
|
-
|
|
25
|
-
## When to use
|
|
26
|
-
|
|
27
|
-
- New feature implementation
|
|
28
|
-
- Bug fix with complexity
|
|
29
|
-
- Refactoring with scope
|
|
30
|
-
- Any task requiring more than 1 hour
|
|
31
|
-
|
|
32
|
-
## The SDD workflow
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
1. /sdd new [title] → Build spec from questions
|
|
36
|
-
2. /sdd tasks <id> → Generate task graph from spec
|
|
37
|
-
3. /sdd graph <id> → Visualize dependencies
|
|
38
|
-
4. /sdd critical <id> → Find bottlenecks
|
|
39
|
-
5. /sdd execute <id> → Run tasks (or execute manually)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Task lifecycle commands
|
|
43
|
-
|
|
44
|
-
| Command | What it does |
|
|
45
|
-
|---------|--------------|
|
|
46
|
-
| `/sdd tasks` | Show task list with progress bar (sorted: in_progress → pending → review → blocked → failed → completed) |
|
|
47
|
-
| `/sdd next` | Show next executable task + blockers |
|
|
48
|
-
| `/sdd done <N>` | Complete a task (by number or fuzzy title match) |
|
|
49
|
-
| `/sdd skip <N>` | Skip a task back to pending |
|
|
50
|
-
| `/sdd fail <N>` | Mark a task as failed |
|
|
51
|
-
| `/sdd review <N>` | Send a task to review |
|
|
52
|
-
| `/sdd edit <N> <text>` | Edit task title (short text) or description (long text) |
|
|
53
|
-
| `/sdd undo` | Undo last task completion |
|
|
54
|
-
| `/sdd graph` | ASCII task dependency visualization |
|
|
55
|
-
| `/sdd critical` | Critical path analysis + bottlenecks |
|
|
56
|
-
|
|
57
|
-
## Spec templates
|
|
58
|
-
|
|
59
|
-
| Template | Best for |
|
|
60
|
-
|---|---|
|
|
61
|
-
| `feature` | New feature development |
|
|
62
|
-
| `bugfix` | Bug fix with root cause analysis |
|
|
63
|
-
| `refactor` | Code refactoring with goals |
|
|
64
|
-
| `infra` | Infrastructure/tooling changes |
|
|
65
|
-
| `integration` | External service integration |
|
|
66
|
-
| `cli-command` | New CLI commands/slash commands |
|
|
67
|
-
|
|
68
|
-
## Spec structure
|
|
69
|
-
|
|
70
|
-
A complete spec has:
|
|
71
|
-
1. **Overview** — What problem does this solve?
|
|
72
|
-
2. **Requirements** — `[priority] description` format
|
|
73
|
-
3. **Architecture** — High-level design (if needed)
|
|
74
|
-
4. **API Design** — Endpoints, inputs, outputs (if applicable)
|
|
75
|
-
5. **Acceptance Criteria** — How do we know it's done?
|
|
76
|
-
|
|
77
|
-
### Requirement format
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
[critical] Users can authenticate with OAuth2
|
|
81
|
-
[high] Rate limiting: 100 req/min per user
|
|
82
|
-
[medium] Response time < 200ms p95
|
|
83
|
-
[low] Support dark mode
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Task graph generation
|
|
87
|
-
|
|
88
|
-
Each requirement generates one or more tasks. Tasks have states:
|
|
89
|
-
```
|
|
90
|
-
pending → in_progress → review → completed
|
|
91
|
-
↓
|
|
92
|
-
blocked (waiting on dependencies)
|
|
93
|
-
↓
|
|
94
|
-
failed
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Critical path
|
|
98
|
-
|
|
99
|
-
The critical path finds:
|
|
100
|
-
- **Bottleneck tasks** blocking the most downstream work
|
|
101
|
-
- **Parallel groups** that can run concurrently
|
|
102
|
-
- **Ready tasks** that can start immediately
|
|
103
|
-
- **Execution order** respecting all dependencies
|
|
104
|
-
|
|
105
|
-
## Goal & Eternal Mode
|
|
106
|
-
|
|
107
|
-
`/sdd` pairs with `/goal` for autonomous execution:
|
|
108
|
-
|
|
109
|
-
| Command | What it does |
|
|
110
|
-
|---------|--------------|
|
|
111
|
-
| `/goal set <text>` | Set an autonomous mission |
|
|
112
|
-
| `/goal pause` | Pause at end of current iteration |
|
|
113
|
-
| `/goal resume` | Resume a paused goal |
|
|
114
|
-
| `/goal journal [N]` | Show recent journal entries |
|
|
115
|
-
| `/goal clear` | Clear goal and stop eternal mode |
|
|
116
|
-
| `/autonomy eternal` | Run goal loop indefinitely |
|
|
117
|
-
| `/autonomy stop` | Stop eternal mode |
|
|
118
|
-
|
|
119
|
-
**Eternal stage flow:** `decide → execute → reflect → sleep | paused | stopped`
|
|
120
|
-
Stage shown in real-time. Pause stops after current iteration completes.
|
|
121
|
-
|
|
122
|
-
## Anti-patterns
|
|
123
|
-
|
|
124
|
-
- **Writing code before the spec** — you'll rewrite it anyway
|
|
125
|
-
- **Spec that's too vague** — "improve auth" is not a spec, "Users authenticate via OAuth2 with PKCE" is
|
|
126
|
-
- **Tasks with no dependencies** — everything is a dependency of something
|
|
127
|
-
- **Spec without acceptance criteria** — how do you know when it's done?
|
|
128
|
-
- **Skipping /sdd for urgent tasks** — the spec is what makes "urgent" possible
|
|
129
|
-
|
|
130
|
-
## Skills in scope
|
|
131
|
-
|
|
132
|
-
- `refactor-planner` — when the spec reveals a multi-file refactor
|
|
133
|
-
- `bug-hunter` — when a bugfix spec needs a root cause analysis section
|
|
134
|
-
- `multi-agent` — for executing parallel task groups
|
|
1
|
+
---
|
|
2
|
+
name: sdd
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when starting a non-trivial implementation, bug fix, or refactor
|
|
5
|
+
in WrongStack. Triggers: user says "/sdd", "spec", "specification", "task graph",
|
|
6
|
+
"SDD", "acceptance criteria", or starts a new feature.
|
|
7
|
+
version: 2.1.0
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Spec-Driven Development — WrongStack
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
Every non-trivial change starts with a spec. The spec is the source of truth — it defines what to build, how to verify it, and what counts as done. SDD uses `/sdd` slash commands to create specs, generate task graphs, and track execution.
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
1. Every non-trivial task needs a spec before writing code — you'll rewrite it anyway.
|
|
19
|
+
2. Spec must have acceptance criteria — without them, you can't know when it's done.
|
|
20
|
+
3. Tasks must have dependencies — everything is a dependency of something.
|
|
21
|
+
4. Spec must be specific: "Users authenticate via OAuth2 with PKCE" not "improve auth".
|
|
22
|
+
5. Skipping `/sdd` for urgent tasks backfires — the spec is what makes "urgent" possible.
|
|
23
|
+
6. When the spec reveals a multi-file refactor, delegate to `refactor-planner` first.
|
|
24
|
+
|
|
25
|
+
## When to use
|
|
26
|
+
|
|
27
|
+
- New feature implementation
|
|
28
|
+
- Bug fix with complexity
|
|
29
|
+
- Refactoring with scope
|
|
30
|
+
- Any task requiring more than 1 hour
|
|
31
|
+
|
|
32
|
+
## The SDD workflow
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
1. /sdd new [title] → Build spec from questions
|
|
36
|
+
2. /sdd tasks <id> → Generate task graph from spec
|
|
37
|
+
3. /sdd graph <id> → Visualize dependencies
|
|
38
|
+
4. /sdd critical <id> → Find bottlenecks
|
|
39
|
+
5. /sdd execute <id> → Run tasks (or execute manually)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Task lifecycle commands
|
|
43
|
+
|
|
44
|
+
| Command | What it does |
|
|
45
|
+
|---------|--------------|
|
|
46
|
+
| `/sdd tasks` | Show task list with progress bar (sorted: in_progress → pending → review → blocked → failed → completed) |
|
|
47
|
+
| `/sdd next` | Show next executable task + blockers |
|
|
48
|
+
| `/sdd done <N>` | Complete a task (by number or fuzzy title match) |
|
|
49
|
+
| `/sdd skip <N>` | Skip a task back to pending |
|
|
50
|
+
| `/sdd fail <N>` | Mark a task as failed |
|
|
51
|
+
| `/sdd review <N>` | Send a task to review |
|
|
52
|
+
| `/sdd edit <N> <text>` | Edit task title (short text) or description (long text) |
|
|
53
|
+
| `/sdd undo` | Undo last task completion |
|
|
54
|
+
| `/sdd graph` | ASCII task dependency visualization |
|
|
55
|
+
| `/sdd critical` | Critical path analysis + bottlenecks |
|
|
56
|
+
|
|
57
|
+
## Spec templates
|
|
58
|
+
|
|
59
|
+
| Template | Best for |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `feature` | New feature development |
|
|
62
|
+
| `bugfix` | Bug fix with root cause analysis |
|
|
63
|
+
| `refactor` | Code refactoring with goals |
|
|
64
|
+
| `infra` | Infrastructure/tooling changes |
|
|
65
|
+
| `integration` | External service integration |
|
|
66
|
+
| `cli-command` | New CLI commands/slash commands |
|
|
67
|
+
|
|
68
|
+
## Spec structure
|
|
69
|
+
|
|
70
|
+
A complete spec has:
|
|
71
|
+
1. **Overview** — What problem does this solve?
|
|
72
|
+
2. **Requirements** — `[priority] description` format
|
|
73
|
+
3. **Architecture** — High-level design (if needed)
|
|
74
|
+
4. **API Design** — Endpoints, inputs, outputs (if applicable)
|
|
75
|
+
5. **Acceptance Criteria** — How do we know it's done?
|
|
76
|
+
|
|
77
|
+
### Requirement format
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
[critical] Users can authenticate with OAuth2
|
|
81
|
+
[high] Rate limiting: 100 req/min per user
|
|
82
|
+
[medium] Response time < 200ms p95
|
|
83
|
+
[low] Support dark mode
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Task graph generation
|
|
87
|
+
|
|
88
|
+
Each requirement generates one or more tasks. Tasks have states:
|
|
89
|
+
```
|
|
90
|
+
pending → in_progress → review → completed
|
|
91
|
+
↓
|
|
92
|
+
blocked (waiting on dependencies)
|
|
93
|
+
↓
|
|
94
|
+
failed
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Critical path
|
|
98
|
+
|
|
99
|
+
The critical path finds:
|
|
100
|
+
- **Bottleneck tasks** blocking the most downstream work
|
|
101
|
+
- **Parallel groups** that can run concurrently
|
|
102
|
+
- **Ready tasks** that can start immediately
|
|
103
|
+
- **Execution order** respecting all dependencies
|
|
104
|
+
|
|
105
|
+
## Goal & Eternal Mode
|
|
106
|
+
|
|
107
|
+
`/sdd` pairs with `/goal` for autonomous execution:
|
|
108
|
+
|
|
109
|
+
| Command | What it does |
|
|
110
|
+
|---------|--------------|
|
|
111
|
+
| `/goal set <text>` | Set an autonomous mission |
|
|
112
|
+
| `/goal pause` | Pause at end of current iteration |
|
|
113
|
+
| `/goal resume` | Resume a paused goal |
|
|
114
|
+
| `/goal journal [N]` | Show recent journal entries |
|
|
115
|
+
| `/goal clear` | Clear goal and stop eternal mode |
|
|
116
|
+
| `/autonomy eternal` | Run goal loop indefinitely |
|
|
117
|
+
| `/autonomy stop` | Stop eternal mode |
|
|
118
|
+
|
|
119
|
+
**Eternal stage flow:** `decide → execute → reflect → sleep | paused | stopped`
|
|
120
|
+
Stage shown in real-time. Pause stops after current iteration completes.
|
|
121
|
+
|
|
122
|
+
## Anti-patterns
|
|
123
|
+
|
|
124
|
+
- **Writing code before the spec** — you'll rewrite it anyway
|
|
125
|
+
- **Spec that's too vague** — "improve auth" is not a spec, "Users authenticate via OAuth2 with PKCE" is
|
|
126
|
+
- **Tasks with no dependencies** — everything is a dependency of something
|
|
127
|
+
- **Spec without acceptance criteria** — how do you know when it's done?
|
|
128
|
+
- **Skipping /sdd for urgent tasks** — the spec is what makes "urgent" possible
|
|
129
|
+
|
|
130
|
+
## Skills in scope
|
|
131
|
+
|
|
132
|
+
- `refactor-planner` — when the spec reveals a multi-file refactor
|
|
133
|
+
- `bug-hunter` — when a bugfix spec needs a root cause analysis section
|
|
134
|
+
- `multi-agent` — for executing parallel task groups
|
|
135
135
|
- `output-standards` — for standardized `<next_steps>` formatting
|