superwiki 0.1.0 → 0.1.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/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +60 -20
- package/package.json +1 -1
- package/skills/sw-config/SKILL.md +5 -5
- package/skills/sw-config/assets/implementer.md +13 -8
- package/skills/sw-config/assets/planner.md +29 -14
- package/skills/sw-config/scripts/config.mjs +161 -86
- package/skills/sw-implement/SKILL.md +12 -7
- package/skills/sw-init/assets/agents-block.md +22 -5
- package/skills/sw-init/assets/sw.mjs +360 -165
- package/skills/sw-init/assets/templates/guide.md +31 -0
- package/skills/sw-init/assets/templates/page.md +1 -0
- package/skills/sw-init/assets/templates/plan.md +11 -4
- package/skills/sw-init/assets/viewer.html +7 -2
- package/skills/sw-init/scripts/init.mjs +1 -1
- package/skills/sw-migrate/SKILL.md +2 -2
- package/skills/sw-plan/SKILL.md +17 -15
package/README.md
CHANGED
|
@@ -153,33 +153,71 @@ A project's `docs/` folder is plain markdown and keeps working as an Obsidian va
|
|
|
153
153
|
|
|
154
154
|
## Use
|
|
155
155
|
|
|
156
|
+
| Skill | What it does |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| `sw-init` | set up `docs/` in the current project, or upgrade it |
|
|
159
|
+
| `sw-migrate` | convert an existing table-based task index, on a new git branch |
|
|
160
|
+
| `sw-ingest` | file a source into the wiki |
|
|
161
|
+
| `sw-plan` | plan a task with the planner subagent and get your approval |
|
|
162
|
+
| `sw-implement` | run a task with the implementer subagent and record the result |
|
|
163
|
+
| `sw-explain` | explain a task: what, why, dependencies, what it unblocks |
|
|
164
|
+
| `sw-triage` | for a problem: seen before? lessons, likely causes |
|
|
165
|
+
| `sw-lint` | structural checks by script, semantic review on request |
|
|
166
|
+
| `sw-visualize` | open the viewer |
|
|
167
|
+
| `sw-config` | the model each tool uses for planning and implementing; task areas |
|
|
168
|
+
|
|
169
|
+
### Examples
|
|
170
|
+
|
|
171
|
+
Shown as typed in Claude Code. In Codex, write `$sw-plan` instead of `/sw-plan`. Task ids are an area prefix and a number, such as `P-15`.
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
/sw-init set up the vault; asks whether you want tasks
|
|
175
|
+
/sw-migrate convert the task tables this project already has
|
|
176
|
+
|
|
177
|
+
/sw-plan what can start now? pick one and plan it
|
|
178
|
+
/sw-plan P-15 plan task P-15 (a small task is sent straight to sw-implement)
|
|
179
|
+
/sw-plan add CSV export to the sources page
|
|
180
|
+
new work: creates the task, then plans it
|
|
181
|
+
|
|
182
|
+
/sw-implement P-15 run P-15; refuses if a dependency is not done
|
|
183
|
+
/sw-implement continue what is in progress, or pick a ready task
|
|
184
|
+
|
|
185
|
+
/sw-explain M-06 what M-06 is, why it exists, what it waits on and unblocks
|
|
186
|
+
/sw-triage photo uploads hang at 100% on mobile since yesterday
|
|
187
|
+
has this happened before? lessons and likely causes
|
|
188
|
+
/sw-ingest ~/Downloads/interview-notes.md
|
|
189
|
+
file a source and summarise it into the wiki
|
|
190
|
+
|
|
191
|
+
/sw-config plan with opus, implement with sonnet
|
|
192
|
+
/sw-lint check links, frontmatter and task dependencies
|
|
193
|
+
/sw-visualize open the task board and the wiki in the browser
|
|
156
194
|
```
|
|
157
|
-
|
|
158
|
-
sw-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
sw-visualize open the viewer
|
|
166
|
-
sw-config models per role and tool, task areas
|
|
195
|
+
|
|
196
|
+
You do not have to type a command. The rules `sw-init` adds to `AGENTS.md` tell the agent which skill fits, so a plain request should reach the same skill:
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
What should I work on next?
|
|
200
|
+
Implement P-15.
|
|
201
|
+
Why does M-06 exist, and what is it blocked by?
|
|
202
|
+
Users get the magic-link email twice. Have we seen this before?
|
|
167
203
|
```
|
|
168
204
|
|
|
169
205
|
A filled-in example vault is in [examples/demo/docs](examples/demo/docs).
|
|
170
206
|
|
|
171
|
-
|
|
207
|
+
### The CLI
|
|
208
|
+
|
|
209
|
+
The skills call a small script that answers questions without the agent reading the vault. You can run it yourself, from the project root:
|
|
172
210
|
|
|
173
211
|
```bash
|
|
174
|
-
node docs/.sw/sw.mjs status
|
|
175
|
-
node docs/.sw/sw.mjs ready
|
|
176
|
-
node docs/.sw/sw.mjs check
|
|
177
|
-
node docs/.sw/sw.mjs explain
|
|
178
|
-
node docs/.sw/sw.mjs search sync timeout
|
|
179
|
-
node docs/.sw/sw.mjs next-id
|
|
180
|
-
node docs/.sw/sw.mjs lint
|
|
181
|
-
node docs/.sw/sw.mjs serve --open
|
|
182
|
-
node docs/.sw/sw.mjs snapshot
|
|
212
|
+
node docs/.sw/sw.mjs status # counts per area
|
|
213
|
+
node docs/.sw/sw.mjs ready # tasks that can start now
|
|
214
|
+
node docs/.sw/sw.mjs check P-15 # can it start or finish, and what is open
|
|
215
|
+
node docs/.sw/sw.mjs explain P-15 # dependencies, what it unblocks, plan, area guide
|
|
216
|
+
node docs/.sw/sw.mjs search sync timeout # where something is mentioned
|
|
217
|
+
node docs/.sw/sw.mjs next-id P # next free id in an area
|
|
218
|
+
node docs/.sw/sw.mjs lint # broken links, bad frontmatter, dependency errors
|
|
219
|
+
node docs/.sw/sw.mjs serve --open # the viewer, reading files live
|
|
220
|
+
node docs/.sw/sw.mjs snapshot # or: freeze the vault into docs/viewer.html, no server
|
|
183
221
|
```
|
|
184
222
|
|
|
185
223
|
## Develop
|
|
@@ -188,6 +226,8 @@ node docs/.sw/sw.mjs snapshot # or: freeze the vault into docs/viewer.html,
|
|
|
188
226
|
npm test # builds skills/sw-init/assets/sw.mjs, then runs the tests
|
|
189
227
|
```
|
|
190
228
|
|
|
229
|
+
Releases are cut by the `Release` workflow (Actions → Release → Run workflow): it tests, bumps the version in `package.json` and the plugin manifests, publishes to npm, tags, and creates a GitHub release. It needs the repository secret `NPM_TOKEN`.
|
|
230
|
+
|
|
191
231
|
`node scripts/build-demo.mjs` builds the public demo into `site/` (the viewer with the example vault baked in); the Pages workflow deploys it on every push to `main`.
|
|
192
232
|
|
|
193
233
|
`src/core.js` is shared by the CLI and the viewer. Edit sources in `src/`; the files in `skills/sw-init/assets/` named `sw.mjs` and `viewer.html` are generated.
|
package/package.json
CHANGED
|
@@ -20,11 +20,11 @@ node <skill-dir>/scripts/config.mjs sync --tools claude,codex,copilot
|
|
|
20
20
|
|
|
21
21
|
A model is chosen per role (`plan`, `implement`) and per tool (`claude`, `codex`, `copilot`), because each tool can only run its own models. No tool lets a skill change the model of the running session, so sw-plan and sw-implement hand the work to a subagent, and the subagent's file carries the model.
|
|
22
22
|
|
|
23
|
-
| Tool |
|
|
24
|
-
|
|
25
|
-
| Claude Code | `.claude/agents/sw-planner.md`, `sw-implementer.md` |
|
|
26
|
-
| Codex | `.codex/agents/sw-planner.toml`, `sw-implementer.toml` |
|
|
27
|
-
| Copilot CLI | `.github/agents/sw-planner.agent.md`, `sw-implementer.agent.md` |
|
|
23
|
+
| Tool | Files the script writes |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Claude Code | `.claude/agents/sw-planner.md`, `sw-implementer.md` |
|
|
26
|
+
| Codex | `.codex/agents/sw-planner.toml`, `sw-implementer.toml` |
|
|
27
|
+
| Copilot CLI | `.github/agents/sw-planner.agent.md`, `sw-implementer.agent.md` |
|
|
28
28
|
|
|
29
29
|
When the user asks to set a model:
|
|
30
30
|
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
You implement one task in a Superwiki vault.
|
|
2
2
|
|
|
3
|
-
Input: a task id.
|
|
3
|
+
Input: a task id; possibly which checks you may run that need services or data.
|
|
4
4
|
|
|
5
|
-
1. Read `docs/tasks/<ID>.md` and, if it exists, `docs/plans/<ID>-plan.md`.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
1. Read `docs/tasks/<ID>.md` and, if it exists, `docs/plans/<ID>-plan.md`.
|
|
6
|
+
- With a plan: open the files under its "Read first", then work. Do not explore beyond what a step turns out to need.
|
|
7
|
+
- Without a plan: run `node docs/.sw/sw.mjs explain <ID>`, read the area guide it names if any, then find the files to change.
|
|
8
|
+
- Do not re-read instruction files that are already in your context. Read linked pages only when a step needs them.
|
|
9
|
+
2. Do the work. Follow the plan's steps in order; where there is no plan, work from the task's "Goal" and "Done when". Follow the repository's own rules.
|
|
10
|
+
3. Verify. After a step, run the narrowest check that covers it. Run the full verification list once, at the end, after the last edit.
|
|
11
|
+
- A check marked `needs: ...` in the plan runs only if your input says it may. Otherwise report it as not verified, with what it needs.
|
|
12
|
+
4. Do not edit `docs/tasks/<ID>.md`, `docs/log.md`, `docs/index.md` or the plan: the session that dispatched you records status.
|
|
9
13
|
5. Stop and report, without guessing, if the plan cannot be followed as written, a dependency is missing, or a "Done when" item cannot be met.
|
|
10
14
|
|
|
11
|
-
Report:
|
|
15
|
+
Report, in about 25 lines:
|
|
12
16
|
- each "Done when" item: met or not, with the command you ran and its result;
|
|
13
17
|
- files changed;
|
|
14
|
-
- deviations from the plan and why;
|
|
15
|
-
-
|
|
18
|
+
- deviations from the plan, and why;
|
|
19
|
+
- `Guide:` facts you had to find in the code that neither the plan nor the area guide stated and the next task in this area would need. One line each, at most eight;
|
|
20
|
+
- anything else the wiki or a follow-up task should record.
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
You write the plan for one task in a Superwiki vault.
|
|
1
|
+
You write the plan for one task in a Superwiki vault. The only file you create or change is `docs/plans/<ID>-plan.md`.
|
|
2
2
|
|
|
3
|
-
Input: a task id
|
|
3
|
+
Input: a task id and today's date; possibly notes, or feedback on an earlier draft.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
2. Read the code the task touches. Find the existing patterns the work must follow and the commands that verify it.
|
|
7
|
-
3. Return the plan as the complete content of `docs/plans/<ID>-plan.md`, in the format of `docs/.sw/templates/plan.md`: frontmatter (`type: plan`, `task: <ID>`, `updated:` today), then `## Approach`, `## Steps`, `## Verification`.
|
|
8
|
-
- Steps are ordered, each names the files it touches and how to check it. Someone with no other context must be able to follow them.
|
|
9
|
-
- Verification maps every "Done when" item of the task to a command or check.
|
|
10
|
-
- Link vault pages as `[[file-name]]`; refer to code by plain path.
|
|
11
|
-
- The plan is saved without the notes and read by someone who has only the task file and the plan. Do not refer to the notes, to these instructions or to agent files from inside it. Where you had to assume an answer to an open question, state the assumption in `## Approach`.
|
|
12
|
-
- Check every example output you quote by running or tracing the code; do not guess what the current code returns.
|
|
13
|
-
4. After the plan, under a line `=== notes ===`, list:
|
|
14
|
-
- open questions that only the user can answer;
|
|
15
|
-
- if the work does not fit one working session: how to split it into tasks (title and dependencies for each).
|
|
5
|
+
Planning is paid for in what you read. Read to decide, not to be thorough.
|
|
16
6
|
|
|
17
|
-
|
|
7
|
+
1. Run `node docs/.sw/sw.mjs explain <ID>` and read `docs/tasks/<ID>.md`. If `explain` names an area guide, read it: it records where things are, the patterns to follow and how to verify, so you need not rediscover them. Read other linked pages only if the plan depends on what they say. If the plan file already exists, you are revising it.
|
|
8
|
+
2. Read code to answer three questions: which files change, which existing pattern to copy, how the result is verified. Stop when you can answer them.
|
|
9
|
+
- Search first, then open the part you need; open a whole file only when you must edit across it.
|
|
10
|
+
- Do not re-read instruction files that are already in your context.
|
|
11
|
+
- Trust what the task and the guide state. Check a stated fact in code only where the plan would be wrong if the fact were false.
|
|
12
|
+
3. Write `docs/plans/<ID>-plan.md`. Keep it as short as the work allows; most plans fit in 40 to 60 lines.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
---
|
|
16
|
+
type: plan
|
|
17
|
+
task: <ID>
|
|
18
|
+
status: draft
|
|
19
|
+
updated: <today>
|
|
20
|
+
---
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `## Approach`: the chosen approach and every assumption you made, in a few lines. Mention a rejected option only if someone would otherwise try it.
|
|
24
|
+
- `## Read first`: the files the implementer must open, each with the part that matters (function, section or line range). After these, nothing should need exploring.
|
|
25
|
+
- `## Steps`: in order. Each step names its files, says the change in one or two sentences, and gives its check. Write exact text only where exactness matters: keys, user-facing strings, signatures, test cases (as a table). Leave out code the implementer can write from the description, and leave out status bookkeeping (task file, log): the dispatching session does that.
|
|
26
|
+
- `## Verification`: each "Done when" item with the command or check that proves it. Put `needs: running stack` or `needs: data change` on a check that cannot run from a clean checkout without starting services or altering data.
|
|
27
|
+
- Link vault pages as `[[file-name]]`; refer to code by plain path. Verify any current output you quote by running or tracing the code.
|
|
28
|
+
4. Return a short message, not the plan:
|
|
29
|
+
- `Approach:` three lines at most.
|
|
30
|
+
- `Questions:` what only the user can answer, each with the answer the plan assumes. Leave out if none.
|
|
31
|
+
- `Split:` if the work does not fit one session, the tasks to split it into (title, dependencies). Leave out if not needed.
|
|
32
|
+
- `Guide:` facts you had to find in the code that the area guide did not state and the next task in this area would need (where something lives, a convention, a verification command). One line each, at most eight.
|
|
@@ -1,104 +1,179 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Reads and changes docs/.sw/config.json, and writes the planner and implementer agent
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
// Reads and changes docs/.sw/config.json, and writes the planner and implementer agent files.
|
|
3
|
+
// A coding tool binds a model to an agent definition, not to a running session, so choosing a
|
|
4
|
+
// model for a role means writing that role's agent file for that tool.
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
6
|
import { dirname, join, resolve } from 'node:path';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const ASSETS = join(dirname(fileURLToPath(import.meta.url)), '..', 'assets');
|
|
10
|
+
const GENERATED = 'Generated by sw-config from docs/.sw/config.json. Change models with sw-config, not here.';
|
|
11
|
+
const AREA_ID = /^[A-Za-z][A-Za-z0-9]*$/;
|
|
12
|
+
|
|
10
13
|
const ROLES = {
|
|
11
|
-
plan: {
|
|
12
|
-
|
|
14
|
+
plan: {
|
|
15
|
+
name: 'sw-planner',
|
|
16
|
+
instructions: 'planner.md',
|
|
17
|
+
description: 'Writes the plan file for one Superwiki task. Use from sw-plan.',
|
|
18
|
+
},
|
|
19
|
+
implement: {
|
|
20
|
+
name: 'sw-implementer',
|
|
21
|
+
instructions: 'implementer.md',
|
|
22
|
+
description: 'Implements one Superwiki task from its task and plan files. Use from sw-implement.',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// How each tool wants an agent defined: where the file goes and what it looks like.
|
|
27
|
+
const TOOLS = {
|
|
28
|
+
claude: {
|
|
29
|
+
path: role => `.claude/agents/${role.name}.md`,
|
|
30
|
+
render: (role, body, model) => markdownAgent(role, body, model),
|
|
31
|
+
},
|
|
32
|
+
codex: {
|
|
33
|
+
path: role => `.codex/agents/${role.name}.toml`,
|
|
34
|
+
render: (role, body, model) => [
|
|
35
|
+
`# ${GENERATED}`,
|
|
36
|
+
`name = "${role.name.replace(/-/g, '_')}"`,
|
|
37
|
+
`description = ${JSON.stringify(role.description)}`,
|
|
38
|
+
...(model ? [`model = ${JSON.stringify(model)}`] : []),
|
|
39
|
+
// TOML literal strings cannot contain three single quotes in a row.
|
|
40
|
+
`developer_instructions = '''\n${body.replace(/'''/g, "' ' '")}\n'''`,
|
|
41
|
+
'',
|
|
42
|
+
].join('\n'),
|
|
43
|
+
},
|
|
44
|
+
copilot: {
|
|
45
|
+
path: role => `.github/agents/${role.name}.agent.md`,
|
|
46
|
+
render: (role, body, model) => markdownAgent(role, body, model),
|
|
47
|
+
},
|
|
13
48
|
};
|
|
49
|
+
|
|
50
|
+
function markdownAgent(role, body, model) {
|
|
51
|
+
const frontmatter = [`name: ${role.name}`, `description: ${role.description}`, ...(model ? [`model: ${model}`] : [])];
|
|
52
|
+
return `---\n${frontmatter.join('\n')}\n---\n\n<!-- ${GENERATED} -->\n\n${body}\n`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const TOOL_NAMES = Object.keys(TOOLS);
|
|
56
|
+
const ROLE_NAMES = Object.keys(ROLES);
|
|
57
|
+
|
|
14
58
|
const HELP = `config.mjs <command> [--root <dir>]
|
|
15
59
|
|
|
16
60
|
show print the configuration
|
|
17
|
-
model
|
|
18
|
-
model
|
|
61
|
+
model <${ROLE_NAMES.join('|')}> <tool> <model> set the model a tool uses for a role (tool: ${TOOL_NAMES.join(', ')})
|
|
62
|
+
model <${ROLE_NAMES.join('|')}> <tool> --unset go back to the tool's default model
|
|
19
63
|
areas "M=Mobile,B=Backend" add or rename task areas (existing areas are never removed)
|
|
20
64
|
sync [--tools claude,codex] (re)write agent files for the given tools, or for every configured tool`;
|
|
21
65
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
put(`.github/agents/${r.name}.agent.md`, `${fm.join('\n')}\n---\n\n<!-- ${header} -->\n\n${body}\n`);
|
|
66
|
+
class UsageError extends Error {}
|
|
67
|
+
|
|
68
|
+
function parseArgs(argv) {
|
|
69
|
+
const args = [];
|
|
70
|
+
let root = '.';
|
|
71
|
+
let tools = null;
|
|
72
|
+
for (let i = 0; i < argv.length; i++) {
|
|
73
|
+
if (argv[i] === '--root') root = argv[++i] ?? '.';
|
|
74
|
+
else if (argv[i] === '--tools') tools = (argv[++i] ?? '').split(',').map(s => s.trim()).filter(Boolean);
|
|
75
|
+
else args.push(argv[i]);
|
|
76
|
+
}
|
|
77
|
+
return { command: args[0], args: args.slice(1), root: resolve(root), tools };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function loadConfig(root) {
|
|
81
|
+
const path = join(root, 'docs/.sw/config.json');
|
|
82
|
+
if (!existsSync(path)) throw new UsageError('no docs/.sw/config.json here; run sw-init first');
|
|
83
|
+
const config = JSON.parse(readFileSync(path, 'utf8'));
|
|
84
|
+
config.models = { plan: {}, implement: {}, ...config.models };
|
|
85
|
+
config.tools ??= [];
|
|
86
|
+
return { config, save: () => writeFileSync(path, JSON.stringify(config, null, 2) + '\n') };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const formatAreas = areas => Object.entries(areas).map(([id, name]) => `${id}=${name}`).join(', ');
|
|
90
|
+
|
|
91
|
+
// Writes a generated file and says what happened to it, judged by content.
|
|
92
|
+
function writeGenerated(root, relPath, content) {
|
|
93
|
+
const path = join(root, relPath);
|
|
94
|
+
const before = existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
95
|
+
if (before !== content) {
|
|
96
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
97
|
+
writeFileSync(path, content);
|
|
98
|
+
}
|
|
99
|
+
const state = before === null ? 'created ' : before === content ? 'unchanged' : 'updated ';
|
|
100
|
+
console.log(`${state} ${relPath}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function writeAgentFiles(root, config, toolNames) {
|
|
104
|
+
for (const [roleName, role] of Object.entries(ROLES)) {
|
|
105
|
+
const body = readFileSync(join(ASSETS, role.instructions), 'utf8').trim();
|
|
106
|
+
for (const toolName of toolNames) {
|
|
107
|
+
const tool = TOOLS[toolName];
|
|
108
|
+
writeGenerated(root, tool.path(role), tool.render(role, body, config.models[roleName][toolName]));
|
|
66
109
|
}
|
|
67
110
|
}
|
|
68
111
|
}
|
|
69
|
-
const save = () => writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
70
112
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
113
|
+
function rememberTools(config, toolNames) {
|
|
114
|
+
for (const name of toolNames) if (!config.tools.includes(name)) config.tools.push(name);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const COMMANDS = {
|
|
118
|
+
show({ config }) {
|
|
119
|
+
console.log(`tasks: ${config.tasks ? 'on' : 'off'}`);
|
|
120
|
+
if (config.tasks) console.log(`areas: ${formatAreas(config.areas)}`);
|
|
121
|
+
for (const role of ROLE_NAMES) {
|
|
122
|
+
console.log(`${role}: ${TOOL_NAMES.map(tool => `${tool}=${config.models[role][tool] || 'default'}`).join(' ')}`);
|
|
123
|
+
}
|
|
124
|
+
console.log(`agent files for: ${config.tools.join(', ') || 'none'}`);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
model({ root, config, save, args }) {
|
|
128
|
+
const [role, tool, model] = args;
|
|
129
|
+
if (!ROLES[role] || !TOOLS[tool] || !model) {
|
|
130
|
+
throw new UsageError(`usage: config.mjs model <${ROLE_NAMES.join('|')}> <${TOOL_NAMES.join('|')}> <model|--unset>`);
|
|
131
|
+
}
|
|
132
|
+
if (model === '--unset') delete config.models[role][tool];
|
|
133
|
+
else config.models[role][tool] = model;
|
|
134
|
+
rememberTools(config, [tool]);
|
|
135
|
+
save();
|
|
136
|
+
writeAgentFiles(root, config, [tool]);
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
areas({ config, save, args }) {
|
|
140
|
+
if (!config.tasks) throw new UsageError('the task module is off; run sw-init with --tasks first');
|
|
141
|
+
for (const pair of (args[0] || '').split(',').map(s => s.trim()).filter(Boolean)) {
|
|
142
|
+
const [id, ...nameParts] = pair.split('=');
|
|
143
|
+
if (!AREA_ID.test(id)) throw new UsageError(`bad area id "${id}"`);
|
|
144
|
+
config.areas[id] = nameParts.join('=').trim() || config.areas[id] || id;
|
|
145
|
+
}
|
|
146
|
+
save();
|
|
147
|
+
console.log(`areas: ${formatAreas(config.areas)}`);
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
sync({ root, config, save, tools }) {
|
|
151
|
+
const toolNames = tools ?? config.tools;
|
|
152
|
+
const unknown = toolNames.filter(name => !TOOLS[name]);
|
|
153
|
+
if (unknown.length) throw new UsageError(`unknown tool: ${unknown.join(', ')}`);
|
|
154
|
+
if (!toolNames.length) throw new UsageError(`no tools configured; pass --tools ${TOOL_NAMES.join(',')}`);
|
|
155
|
+
rememberTools(config, toolNames);
|
|
156
|
+
save();
|
|
157
|
+
writeAgentFiles(root, config, toolNames);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
function main(argv) {
|
|
162
|
+
const { command, args, root, tools } = parseArgs(argv);
|
|
163
|
+
if (!command || command === 'help' || command === '--help') {
|
|
164
|
+
console.log(HELP);
|
|
165
|
+
return 0;
|
|
76
166
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} else if (cmd === 'areas') {
|
|
87
|
-
if (!config.tasks) fail('the task module is off; run sw-init with --tasks first');
|
|
88
|
-
for (const pair of (rest[0] || '').split(',').map(s => s.trim()).filter(Boolean)) {
|
|
89
|
-
const [id, ...name] = pair.split('=');
|
|
90
|
-
if (!/^[A-Za-z][A-Za-z0-9]*$/.test(id)) fail(`bad area id "${id}"`);
|
|
91
|
-
config.areas[id] = name.join('=').trim() || config.areas[id] || id;
|
|
167
|
+
try {
|
|
168
|
+
const run = COMMANDS[command];
|
|
169
|
+
if (!run) throw new UsageError(`unknown command ${command}\n\n${HELP}`);
|
|
170
|
+
run({ root, args, tools, ...loadConfig(root) });
|
|
171
|
+
return 0;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (!(error instanceof UsageError)) throw error;
|
|
174
|
+
console.error(error.message);
|
|
175
|
+
return 2;
|
|
92
176
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const ti = rest.indexOf('--tools');
|
|
97
|
-
const tools = ti >= 0 ? rest[ti + 1].split(',').map(s => s.trim()) : config.tools;
|
|
98
|
-
const bad = tools.filter(t => !TOOLS.includes(t));
|
|
99
|
-
if (bad.length) fail(`unknown tool: ${bad.join(', ')}`);
|
|
100
|
-
if (!tools.length) fail('no tools configured; pass --tools claude,codex,copilot');
|
|
101
|
-
for (const t of tools) if (!config.tools.includes(t)) config.tools.push(t);
|
|
102
|
-
save();
|
|
103
|
-
sync(tools);
|
|
104
|
-
} else fail(`unknown command ${cmd}\n\n${HELP}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
process.exitCode = main(process.argv.slice(2));
|
|
@@ -5,7 +5,7 @@ description: Use when the user wants to implement, build, execute, start or cont
|
|
|
5
5
|
|
|
6
6
|
# sw-implement
|
|
7
7
|
|
|
8
|
-
Runs one task. You keep the task's status true and judge the result; an implementer subagent, running the model set in sw-config, does the work from the task and plan files.
|
|
8
|
+
Runs one task. You keep the task's status true and judge the result; an implementer subagent, running the model set in sw-config, does the work from the task and plan files. You do not read the code or the plan: the report is your input.
|
|
9
9
|
|
|
10
10
|
Run commands from the project root. `<skill-dir>` is the directory this SKILL.md is in.
|
|
11
11
|
|
|
@@ -16,9 +16,11 @@ Run commands from the project root. `<skill-dir>` is the directory this SKILL.md
|
|
|
16
16
|
- `can start: no open deps: ...`: stop. Tell the user which tasks block it and offer to run the first blocker instead; do not run it unasked. Do not start the task anyway, and do not edit `deps` to get past this.
|
|
17
17
|
- `can start: n/a, status is in-progress`: this is a continuation; skip step 3.
|
|
18
18
|
- `can start: n/a, status is done` or `cancelled`: stop and ask what the user wants.
|
|
19
|
-
- `plan:
|
|
19
|
+
- `plan: ... (draft, not approved)`: stop; the plan needs the user's approval (sw-plan).
|
|
20
|
+
- `plan: none`: fine for a small task (one area, three "Done when" items or fewer, nothing open in its notes, a few files). For anything larger, recommend sw-plan first and let the user choose.
|
|
20
21
|
3. **Mark it started** before any work: in the frontmatter of `docs/tasks/<ID>.md` set `status: in-progress` and `started:` today. Append `## [date] task | <ID> started` to `docs/log.md`, in the layout its last entries use.
|
|
21
|
-
4. **
|
|
22
|
+
4. **Checks that need the environment.** If the task has a plan, look for `needs:` in it: `grep -n 'needs:' docs/plans/<ID>-plan.md`. Each hit is a check that starts services or changes data. Ask the user which of them the implementer may run; without a yes, none.
|
|
23
|
+
5. **Dispatch the implementer.** Its prompt is the task id, the project root if it is not your working directory, and which `needs:` checks it may run. Do not paste the plan into the prompt; it reads the files.
|
|
22
24
|
|
|
23
25
|
| Tool | How |
|
|
24
26
|
|---|---|
|
|
@@ -27,8 +29,8 @@ Run commands from the project root. `<skill-dir>` is the directory this SKILL.md
|
|
|
27
29
|
| Copilot CLI | `task` tool with agent `sw-implementer` |
|
|
28
30
|
| No subagents available, or the agent is not defined | follow `implementer.md` yourself, in this session, and tell the user the configured model was not used |
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
6. **Judge the report** against the task's "Done when" list. Every item needs evidence: a command and its result. Re-run one verification command yourself when the report is vague. An item without evidence is not met.
|
|
33
|
+
7. **Record the outcome.**
|
|
32
34
|
|
|
33
35
|
| Outcome | Task file | Log entry |
|
|
34
36
|
|---|---|---|
|
|
@@ -36,11 +38,14 @@ Run commands from the project root. `<skill-dir>` is the directory this SKILL.md
|
|
|
36
38
|
| Items met but soft deps open | stays `in-progress` | `task \| <ID> waiting on <ids>` |
|
|
37
39
|
| Blocked or partly done | stays `in-progress`; add what is left to "Notes" | `task \| <ID> blocked: <reason>` |
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
8. **Keep the area guide.** Add the report's `Guide:` lines to the guide of the task's area, `docs/wiki/guide-<area, lowercase>.md` (`type: guide`, `area: <AREA>`; `node docs/.sw/sw.mjs explain <ID>` prints its path). No guide yet: create it from `docs/.sw/templates/guide.md` and list it in `index.md`. One line per fact under Layout, Patterns, Verify or Gotchas; replace a line the new fact corrects; keep the page under 60 lines. Do this without asking: the guide is what makes the next task in this area cheaper, because planners and implementers read it instead of exploring.
|
|
42
|
+
9. **File what else was learned.** If the implementer reported a decision or constraint the wiki should hold, offer to save it as a wiki page (`type: decision` or `concept`) and add it to `index.md`. If the task fixed a problem whose cause is now known, offer a `type: lesson` page (Symptom, Cause, Fix, How to notice it earlier); sw-triage finds these later. If it reported follow-up work, offer to create the tasks. These are separate offers: act on each only when the user says yes to that one.
|
|
43
|
+
10. **Report** to the user: outcome, evidence per "Done when" item, files changed, deviations from the plan, and which tasks this unblocked (`node docs/.sw/sw.mjs ready`). Commit only if the user asks.
|
|
41
44
|
|
|
42
45
|
## Common mistakes
|
|
43
46
|
|
|
44
47
|
- Marking `done` because the implementer said so. Done means every "Done when" item has evidence.
|
|
45
48
|
- Starting work before the task file says `in-progress`. If the session dies, nobody knows the task was touched.
|
|
46
49
|
- Letting the implementer edit the task file or the log. One writer for status: you.
|
|
50
|
+
- Reading the plan or the code "to follow along". The implementer already paid for that.
|
|
51
|
+
- Skipping the guide update. Every fact left out is explored again by the next task.
|
|
@@ -11,19 +11,36 @@
|
|
|
11
11
|
- `docs/tasks/<ID>.md`: one task per file. `docs/plans/<ID>-plan.md`: its plan, if any.
|
|
12
12
|
{{/tasks}}
|
|
13
13
|
- Anything else under `docs/` belongs to other tools. Leave it alone.
|
|
14
|
+
- File formats: `docs/.sw/templates/`.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Wiki:
|
|
16
17
|
|
|
17
18
|
- Link vault pages as `[[file-name]]`; file names are unique across the vault. Use normal markdown links for `raw/` files and URLs, and plain paths for code.
|
|
18
19
|
- When you add or rename a wiki page, update its line in `index.md`.
|
|
19
20
|
- Answer questions from the wiki, index first. Offer to save an answer worth keeping as a wiki page.
|
|
21
|
+
{{^tasks}}
|
|
22
|
+
- When you change the project, append one `change` entry to `log.md`: what changed and why, in a line.
|
|
23
|
+
- `node docs/.sw/sw.mjs search <words>` finds where something is mentioned; `lint` checks links and frontmatter. Neither needs you to read files. Run `lint` after you add, rename or relink pages.
|
|
24
|
+
{{/tasks}}
|
|
20
25
|
{{#tasks}}
|
|
21
|
-
|
|
26
|
+
|
|
27
|
+
Tasks:
|
|
28
|
+
|
|
29
|
+
- A task's status lives only in its frontmatter. Before you start: `status: in-progress` and `started:`. When its "Done when" list is met: `status: done` and `finished:`. Each change of status gets a `task` entry in `log.md`.
|
|
22
30
|
- Do not start a task while any of its `deps` is not done.
|
|
31
|
+
- Before you change code for a task, read the area guide that `explain <ID>` names (`docs/wiki/guide-<area>.md`): where things are, patterns, how to verify. Afterwards add the facts it was missing, one line each.
|
|
32
|
+
- Work that belongs to no task (a quick fix, a small request) needs no task file. Append one `change` entry to `log.md` instead: what changed and why, in a line.
|
|
23
33
|
- `node docs/.sw/sw.mjs status|ready|check <ID>|explain <ID>|search <words>|next-id <AREA>|lint` answers overview, startable tasks, blockers, a task's place in the chain, where something is mentioned, new ids and structural checks without reading files. Run `lint` after you add, rename or relink pages.
|
|
24
34
|
{{/tasks}}
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
|
|
36
|
+
Skills. Use these without being asked. For work in this vault they come before any other planning, implementing or debugging skill:
|
|
37
|
+
|
|
38
|
+
{{#tasks}}
|
|
39
|
+
- Planning a task, or the user asks what to work on next: `sw-plan`.
|
|
40
|
+
- Implementing a task: `sw-implement`. A change that needs no plan and touches one or two files may be done directly, under the task rules above.
|
|
41
|
+
- A question about a task (what, why, what it blocks): `sw-explain`.
|
|
27
42
|
{{/tasks}}
|
|
28
|
-
-
|
|
43
|
+
- A bug, failure or unexpected behavior is reported: `sw-triage` first, before any debugging.
|
|
44
|
+
- A source to file (article, notes, transcript, URL): `sw-ingest`.
|
|
45
|
+
- If a skill is not installed, follow the rules above by hand.
|
|
29
46
|
<!-- sw:end -->
|