janissary 0.5.1 → 0.5.2

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.
Files changed (69) hide show
  1. package/ai/guidelines/architecture-principles.md +75 -0
  2. package/ai/guidelines/code-guidelines.md +17 -0
  3. package/ai/guidelines/conventional-commits.md +192 -0
  4. package/ai/guidelines/developer-documentation.md +124 -0
  5. package/ai/guidelines/documentation.md +80 -0
  6. package/ai/guidelines/human-writing-guidelines.md +42 -0
  7. package/ai/guidelines/imports-and-barrel-files.md +49 -0
  8. package/ai/guidelines/pull-request-automation.md +98 -0
  9. package/ai/guidelines/strategies-for-readable-summaries.md +27 -0
  10. package/ai/guidelines/user-documentation.md +177 -0
  11. package/ai/personas/algorithm.md +14 -0
  12. package/ai/personas/assistant.md +25 -0
  13. package/ai/personas/link-scout.md +16 -0
  14. package/ai/personas/researcher.md +12 -0
  15. package/ai/personas/security.md +12 -0
  16. package/ai/personas/summarizer.md +11 -0
  17. package/ai/tasks/build-a-feature.md +133 -0
  18. package/ai/tasks/fix-a-small-issue.md +138 -0
  19. package/ai/tasks/improve-codebase.md +187 -0
  20. package/ai/tasks/improve-modularity.md +188 -0
  21. package/ai/tasks/improve-namespacing.md +253 -0
  22. package/ai/tasks/improve-plan.md +121 -0
  23. package/ai/tasks/improve-security.md +144 -0
  24. package/ai/tasks/improve-style.md +147 -0
  25. package/ai/tasks/improve-test-coverage.md +178 -0
  26. package/ai/tasks/merge-change-to-master.md +144 -0
  27. package/ai/tasks/open-feature-pull-request.md +161 -0
  28. package/ai/tasks/plan-ready-features.md +154 -0
  29. package/ai/tasks/prepare-workspace.md +35 -0
  30. package/ai/tasks/quick-commit.md +82 -0
  31. package/ai/tasks/reduce-complexity.md +185 -0
  32. package/ai/tasks/remove-deadcode.md +206 -0
  33. package/ai/tasks/remove-duplication.md +202 -0
  34. package/ai/tasks/update-package.md +137 -0
  35. package/package.json +4 -2
  36. package/scripts/changed-files.mjs +22 -0
  37. package/scripts/check-diff.mjs +100 -0
  38. package/scripts/coverage-file.mjs +85 -0
  39. package/scripts/docs-screenshots/capture.mjs +82 -0
  40. package/scripts/docs-screenshots/fixtures/docs/api.md +3 -0
  41. package/scripts/docs-screenshots/fixtures/docs/guide.md +3 -0
  42. package/scripts/docs-screenshots/fixtures/page.html +31 -0
  43. package/scripts/docs-screenshots/fixtures/profiles/demo/editor.json +1 -0
  44. package/scripts/docs-screenshots/fixtures/profiles/demo/writer.json +1 -0
  45. package/scripts/docs-screenshots/fixtures/sample.md +26 -0
  46. package/scripts/docs-screenshots/fixtures/sample.png +0 -0
  47. package/scripts/docs-screenshots/fixtures/sample.ts +25 -0
  48. package/scripts/docs-screenshots/fixtures/src/app.ts +2 -0
  49. package/scripts/docs-screenshots/fixtures/src/tides.ts +2 -0
  50. package/scripts/docs-screenshots/janus.mjs +51 -0
  51. package/scripts/docs-screenshots/manifest.mjs +122 -0
  52. package/scripts/docs-screenshots/scratch.mjs +53 -0
  53. package/scripts/docs-screenshots.mjs +86 -0
  54. package/scripts/lint-files.mjs +47 -0
  55. package/scripts/postinstall.mjs +14 -0
  56. package/scripts/pr-check-changes.sh +15 -0
  57. package/scripts/pr-check-gate.sh +29 -0
  58. package/scripts/pr-check-mergeable.sh +29 -0
  59. package/scripts/pr-commit.sh +23 -0
  60. package/scripts/pr-create-branch.sh +20 -0
  61. package/scripts/pr-create-pr.sh +29 -0
  62. package/scripts/pr-merge.sh +22 -0
  63. package/scripts/pr-push-branch.sh +24 -0
  64. package/scripts/pr-rebase.sh +56 -0
  65. package/scripts/pr-resolve-remote.sh +9 -0
  66. package/scripts/pr-wait-checks.sh +41 -0
  67. package/scripts/publish.mjs +61 -0
  68. package/scripts/release.mjs +209 -0
  69. package/scripts/run.mjs +40 -0
@@ -0,0 +1,253 @@
1
+ # Improve Code Namespacing (one directory namespace per run)
2
+
3
+ Your job: make **one** safe, mechanical change that improves the codebase's organization by **moving a cohesive group of related files that share a naming prefix out of a flat directory and into a sub-directory that gives them a logical namespace** — renaming each file to drop the now-redundant prefix, and updating every import that points at or out of those files so nothing breaks. Do exactly one namespace, then verify.
4
+
5
+ For example, the flat files `src/acp-loop.ts`, `src/acp-manager.ts`, `src/acp-runner.ts`, `src/acp-tools.ts` all share the `acp-` prefix and belong together. They can move into `src/acp/` as `loop.ts`, `manager.ts`, `runner.ts`, `tools.ts` — the directory now carries the namespace, so the prefix is dropped from each filename. The same opportunity exists for `src/agent-*`, `src/harness-*`, and other prefix clusters.
6
+
7
+ **A file's colocated test moves with it — always.** Every `src/<prefix>-name.test.ts` moves into the namespace beside its source as `src/<prefix>/name.test.ts`. Tests are part of the group, not a separate concern: `src/acp-loop.test.ts` → `src/acp/loop.test.ts`. A namespace move that relocates the source files but leaves their `.test.ts` files behind in `src/` is **wrong and incomplete** — the tests keep the prefix while the code they exercise does not, and the colocation the codebase relies on is broken. Move source and test together, every time.
8
+
9
+ **Run everything synchronously, in the foreground.** Never use `run_in_background`, `&`, or otherwise start a background process (dev servers, watchers, long-lived processes) — every command must finish and return its exit code before you move to the next step.
10
+
11
+ **No subagents, no background agents.** Do every step yourself — never launch a subagent (Task/Agent tool, `fork`, or otherwise) to research, explore, or implement any part of this task on your behalf.
12
+
13
+ **No AI attribution — anywhere.** Never credit an AI agent as an author or contributor in anything this task produces. That means: no `Co-Authored-By:` trailers naming Claude or any other AI, no “Generated with Claude Code” (or similar) lines or badges, and no AI authorship notes in code, comments, docs, spec files, plan files, commit messages, or PR titles and bodies. This overrides any default convention that appends such attribution. The commit's configured git author is the only authorship ever recorded.
14
+
15
+ This is a **pure move-and-rewire refactor**: relocate whole files and fix the import paths that point at or out of them. Never change what any file *does* — no logic edits, no signature changes, no reformatting of code that only moved. The **only** edits you make inside any file are to the **strings in its import/export statements**. If you find yourself changing anything else, stop.
16
+
17
+ Moving files rewires real code, so the rule is simple: **the tests must pass before you start and still pass after. If you cannot keep them passing, put the files back the way they were** (the exact undo command is in Step 5).
18
+
19
+ Do the steps below **in order**. Do not skip steps. Do not invent your own process. This task is deliberately mechanical — follow the rules literally rather than trying to be clever, and lean on the compiler (Step 6) to catch every mistake for you.
20
+
21
+ **Shell hygiene:** run every command on its own line — no `&&` chaining, no `; echo "Exit code: $?"` suffixes, no subshell captures. The exit code and output are visible in the tool result. To run a project script, always use `./scripts/run.mjs <name>` — never call `node scripts/<name>.mjs` directly. Use `git mv` for every relocation so history is preserved.
22
+
23
+ **Run autonomously.** This task runs unattended — do not ask the user questions or wait for feedback at any step. Make the best judgment call yourself, using the rules in this document, and keep going. Only stop early if the project isn't green before you start (Step 1), or if every remaining candidate group is blocked (see "Blocked work" below).
24
+
25
+ ## What you may and may not do
26
+
27
+ ### Safe work — DO IT AUTOMATICALLY, never ask
28
+
29
+ When your plan is **only** safe work, you **must carry it out yourself, start to finish, without stopping.** Do **not** ask "Do you want me to proceed?". Do **not** pause to show the plan for approval. Do **not** wait for confirmation. Just make the change and verify it.
30
+
31
+ Safe work is exactly this: **move one cohesive prefix group of files into a new sub-directory, drop the redundant prefix from each filename, and update every import path that points at or out of those files** — done by the Recipe in Step 5, and nothing else. Because the whole namespace moves as a unit, this **includes moving and re-pathing the group's colocated `*.test.ts(x)` files** — that is expected here, and is *not* the forbidden "editing a test" from other tasks, because you change only their location and import paths, never their assertions or logic.
32
+
33
+ ### Blocked work — skip and pick a different group
34
+
35
+ If doing the move would require any of the following, **go back to Step 3** and pick the next-best group instead. Never ask the user — just skip and move on.
36
+
37
+ 1. Changing any file's **behavior, logic, exports' shapes, or call signatures** — a namespace move only relocates files and rewrites import *paths*. If a group can't be moved without a logic edit, it's blocked.
38
+ 2. A group **too small to be a namespace** — fewer than **3** source files sharing the prefix. Two files don't justify a directory; leave them flat.
39
+ 3. A **name collision**: the target sub-directory `src/<prefix>/` already exists, or dropping the prefix would make two moved files collide (e.g. both `acp-loop.ts` and some `acp/loop.ts` would land on `src/acp/loop.ts`).
40
+ 4. Touching **`src/controller.ts`** — if it is one of the files you'd have to *move*, the group is blocked (it's the biggest, riskiest file). It may still *import* the moved files; updating those import paths in it is fine and expected.
41
+ 5. A **config or build file hard-codes an exact old path.** Glob patterns like `src/**/*.ts` in `tsconfig.json`, `vitest`/`vite` config, or `eslint.config.mjs` already cover sub-directories and need no change. But if `package.json`, a script, or a config literally names `src/acp-loop.ts` (not a glob), the group is blocked — skip it.
42
+
43
+ If every remaining candidate group is blocked, report which groups you considered and why each was blocked, and stop without moving any files.
44
+
45
+ > **The only files you may touch:** (a) the files in the one group you picked — you *move* them; and (b) any file, anywhere in `src/` or `web/src/`, that imports a moved file — you edit **only the import path string** in it. You may **not** edit any file's logic, move code *within* a file, change any test's assertions, or reformat anything.
46
+
47
+ ---
48
+
49
+ ## Step 0 — Prepare the workspace
50
+
51
+ Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
52
+
53
+ ---
54
+
55
+ ## Step 1 — See the starting state (run these, write the numbers down)
56
+
57
+ Run all four and read the output:
58
+
59
+ ```bash
60
+ npm run typecheck 2>&1
61
+ npm run lint 2>&1
62
+ npm run test 2>&1
63
+ npm run quality 2>&1
64
+ ```
65
+
66
+ Then record these starting numbers — you will compare against them at the end. Put them straight into your report draft (Step 7):
67
+
68
+ - **TypeScript:** `npm run typecheck` must finish with **no errors**. If it errors before you touch anything, STOP and tell the user — do not start a move on a project that doesn't compile.
69
+ - **Lint:** near the end of `npm run lint` there is a summary line like `✖ 16 problems (0 errors, 16 warnings)`. Write down the **errors** and **warnings** counts. A namespace move should leave both **unchanged**.
70
+ - **Tests:** they must be **green** (all passing). If any test is already failing **before** you touch anything, STOP and tell the user.
71
+ - **Quality (FTA):** `npm run quality` prints a table per area. A namespace move does not change any file's score or line count — treat this as a **must-not-regress** check, not a target to improve.
72
+
73
+ Always run these fresh. Do not trust earlier output in the conversation. If any of the three gates (TypeScript clean, tests green) is not met, stop now.
74
+
75
+ ---
76
+
77
+ ## Step 2 — Find the prefix clusters
78
+
79
+ You are looking for a group of flat files that share a leading `prefix-` and clearly form one concern. List the candidates by counting files per prefix:
80
+
81
+ ```bash
82
+ ls src/*.ts | grep -vE '\.test\.ts$' | sed -E 's#src/##; s#-.*##' | sort | uniq -c | sort -rn
83
+ ```
84
+
85
+ Each row is a candidate namespace: the count is how many source files share that prefix, and the name is the prefix. Rows with **3 or more** files are real namespace opportunities (e.g. `acp`, `harness`, `agent`). Ignore rows with 1–2 files.
86
+
87
+ ---
88
+
89
+ ## Step 3 — Pick exactly one group to namespace
90
+
91
+ 1. From the counts, list every `src/` prefix group with **3+ source files**.
92
+ 2. **Cross out** any group that is blocked by **What you may and may not do** (too small, target dir already exists, would need a logic edit, includes `src/controller.ts` among the files to move, hard-coded in config), already namespaced, or only *coincidentally* shares a prefix (unrelated files that happen to start with the same word — a namespace must be one real concern).
93
+ 3. From what remains, prefer a group of **3 to 6 source files**. A moderate group is the least error-prone; that is the goal here. Only pick a larger group if no moderate one is available. Among eligible groups, pick the one whose files most obviously belong together.
94
+
95
+ State your pick in one short sentence: the prefix and how many source and test files it has. Write those into your report draft.
96
+
97
+ Now list the **exact files** in the group so nothing is guessed later:
98
+
99
+ ```bash
100
+ ls src/<prefix>-*.ts
101
+ ```
102
+
103
+ This is your definitive move list, and it **includes the `*.test.ts` files** — that glob matches them too. Every source file *and* its `.test.ts` twin is on this list and must move. Confirm the pairs: if you see `<prefix>-name.ts`, you should also see `<prefix>-name.test.ts` right below it, and both move together. Also check for a **bare** entry file that matches the prefix exactly:
104
+
105
+ ```bash
106
+ ls src/<prefix>.ts 2>&1
107
+ ```
108
+
109
+ If `src/<prefix>.ts` exists, it is part of the move and becomes `src/<prefix>/index.ts`. If it doesn't exist (the `ls` errors), there is no bare entry — do **not** create one. We never invent a barrel `index.ts` where none existed; callers import files directly (see [`../guidelines/imports-and-barrel-files.md`](../guidelines/imports-and-barrel-files.md)).
110
+
111
+ ---
112
+
113
+ ## Step 4 — Write the move inventory (a note to yourself, then keep going)
114
+
115
+ Before touching anything, write down — for yourself, not as a message to send — the complete inventory. This is what keeps a large move from losing track:
116
+
117
+ **A. The move list.** One line per file, `old → new`, prefix dropped:
118
+
119
+ ```
120
+ src/<prefix>-loop.ts → src/<prefix>/loop.ts
121
+ src/<prefix>-loop.test.ts → src/<prefix>/loop.test.ts
122
+ src/<prefix>-manager.ts → src/<prefix>/manager.ts
123
+ ...
124
+ src/<prefix>.ts → src/<prefix>/index.ts (only if a bare entry exists)
125
+ ```
126
+
127
+ Drop **only** the leading `<prefix>-` segment; keep the rest (`harness-recording-file.ts` → `recording-file.ts`).
128
+
129
+ **B. The inbound importer list.** Every file that imports one of the moved files. Find them all:
130
+
131
+ ```bash
132
+ grep -rn "<prefix>-" src web --include=*.ts --include=*.tsx
133
+ ```
134
+
135
+ Read each hit. The ones that matter are **import/require/mock paths** — lines like `from '.../<prefix>-name.js'`, `import('.../<prefix>-name.js')`, or `vi.mock('.../<prefix>-name.js')`. (Hits that are string literals, comments, or command names — not module paths — do not move; leave them.) Note which files contain such paths. These, plus the moved files themselves, are the only files you will edit.
136
+
137
+ Re-check the plan against **What you may and may not do**. If any point 1–5 applies → go back to Step 3. Otherwise → go to Step 5 and make the change **now, on your own, without asking.**
138
+
139
+ ---
140
+
141
+ ## Step 5 — Make the change
142
+
143
+ Do the three sub-steps **in order**: move, then rewire, then let the compiler catch the rest.
144
+
145
+ ### 5a — Move every file with `git mv`
146
+
147
+ Create the directory, then move each file from your inventory on its own line:
148
+
149
+ ```bash
150
+ mkdir -p src/<prefix>
151
+ git mv src/<prefix>-loop.ts src/<prefix>/loop.ts
152
+ git mv src/<prefix>-loop.test.ts src/<prefix>/loop.test.ts
153
+ git mv src/<prefix>-manager.ts src/<prefix>/manager.ts
154
+ git mv src/<prefix>-manager.test.ts src/<prefix>/manager.test.ts
155
+ ```
156
+
157
+ Notice each source `git mv` is immediately followed by its `.test.ts` twin — do this for **every** file. Repeat for every line in your move list, source and test alike. If a bare entry exists: `git mv src/<prefix>.ts src/<prefix>/index.ts`.
158
+
159
+ Then sanity-check that the moves match your inventory exactly:
160
+
161
+ ```bash
162
+ git status
163
+ ```
164
+
165
+ You should see one rename per file in your list — **including a rename for every `.test.ts` file** — and nothing else. Confirm no `src/<prefix>-*.test.ts` is left behind (`ls src/<prefix>-*.test.ts` should error with "No such file"). If any source or test file is missing from the renames, you skipped it — move it now.
166
+
167
+ ### 5b — Rewire import paths using two mechanical rules
168
+
169
+ There are only two kinds of edits, and each is a literal string substitution. Do not reason about directory depth — apply the rule.
170
+
171
+ > **Rule IN — inbound (files that did NOT move).** In every import/require/mock **path string** that names a moved file, replace the substring **`<prefix>-` with `<prefix>/`**. That's the whole edit; the number of leading `../` never changes.
172
+ > - `from '../acp-loop.js'` → `from '../acp/loop.js'`
173
+ > - `from './acp-manager.js'` → `from './acp/manager.js'`
174
+ > - `vi.mock('../acp-tools.js')` → `vi.mock('../acp/tools.js')`
175
+ > - Bare entry only: replace `<prefix>.js` at the end of the path with `<prefix>/index.js` (e.g. `from './acp.js'` → `from './acp/index.js'`).
176
+
177
+ > **Rule OUT — outbound (imports written INSIDE a moved file).** Each moved file dropped one directory level deeper, so classify every import line in it:
178
+ > 1. **Package / built-in specifier** (starts with a letter, `@`, or `node:` — e.g. `'react'`, `'node:fs'`): **leave it unchanged.**
179
+ > 2. **Points at another file in the same group** (the path contains `<prefix>-`): rewrite to a sibling — drop the leading `./` or `../` depth and the prefix, leaving `./<name>.js`. E.g. `./acp-manager.js` → `./manager.js`.
180
+ > 3. **Points at the old bare entry** (`./<prefix>.js`): → `./index.js`.
181
+ > 4. **Any other relative path** (`./x.js`, `../y.js`, `./sub/z.js`): **prepend one `../`.** E.g. `./config.js` → `../config.js`; `../util.js` → `../../util.js`; `./sub/z.js` → `../sub/z.js`.
182
+
183
+ Apply Rule IN to each inbound importer from your list, and Rule OUT to each moved file. Keep the **`.js`** extension on every relative path (NodeNext requires it; the source is `.ts` but the import says `.js`). Change **nothing** else in any file.
184
+
185
+ If you are ever unsure which `../` count Rule OUT needs, make your best guess and move on — Step 6 (the compiler) will name the exact file and unresolved path, and you fix it then. Do not agonize; the compiler is your safety net.
186
+
187
+ ### If you need to undo
188
+
189
+ If the move gets tangled and you cannot get it clean, revert everything this task did and go back to Step 3 (or report that no safe namespace was available). This is the reliable undo — `git checkout .` does **not** undo a staged `git mv`, so use:
190
+
191
+ ```bash
192
+ git reset --hard HEAD
193
+ git clean -fd src web
194
+ ```
195
+
196
+ `reset --hard` restores every tracked file (returning the moved files to their old names) and `git clean -fd src web` deletes the now-empty new directory and any leftover new files. This discards all uncommitted work under `src`/`web`, which — after Step 0 — is only this task's own changes.
197
+
198
+ ---
199
+
200
+ ## Step 6 — Verify with the compiler-driven fix loop
201
+
202
+ This is where mistakes get caught and fixed. Run typecheck first; it pinpoints every broken path.
203
+
204
+ ```bash
205
+ npm run typecheck 2>&1
206
+ ```
207
+
208
+ **The fix loop:**
209
+
210
+ 1. Read each error. A namespace-move error is always a module-resolution error — TypeScript names the file it's in and the import path it can't resolve. It is one of exactly two mistakes: an **inbound** path where you didn't apply Rule IN, or an **outbound** path in a moved file with the wrong number of `../` (Rule OUT case 4). Fix the path string; touch nothing else.
211
+ 2. Re-run `npm run typecheck 2>&1`.
212
+ 3. Repeat until it reports **no errors**.
213
+
214
+ Guardrail against looping forever: the error count must **drop on every pass**. If you complete a pass and the count did not go down (you're guessing at the same path, or an error isn't a path problem), **stop guessing** — run the reliable undo in Step 5 and report what blocked you. Do not thrash.
215
+
216
+ Once TypeScript is clean, run the rest — in this order:
217
+
218
+ ```bash
219
+ npm run test 2>&1
220
+ npm run lint 2>&1
221
+ npm run quality 2>&1
222
+ ```
223
+
224
+ - **Tests pass.** Every test stays green. A failure is again a stale import/mock path (in a moved test or a file it imports) — fix the **path**, never a test's assertions. If it won't go green quickly, undo (Step 5) and report.
225
+ - **Lint is no worse.** The `✖ … problems (… errors, … warnings)` line must match Step 1 — **errors 0**, warnings the **same** count. A new finding is usually a dropped `.js` extension or an import left unused/misordered by a re-path — fix it in the source. Never silence with `eslint-disable`.
226
+ - **Quality did not regress.** FTA scores and line counts should be **unchanged** (files only moved). If a score changed, you edited more than a path — find and revert that stray edit.
227
+
228
+ Finally, confirm no old path survives. For **each** old filename stem in your move list, grep and inspect:
229
+
230
+ ```bash
231
+ grep -rn "<prefix>-loop" src web --include=*.ts --include=*.tsx
232
+ ```
233
+
234
+ (substitute each stem: `<prefix>-manager`, `<prefix>-runner`, …). Any hit that is an **import/require/mock path** is a straggler — fix it with Rule IN and re-run typecheck. Hits that are plain strings, comments, or unrelated identifiers are fine; leave them.
235
+
236
+ ---
237
+
238
+ ## Step 7 — Report
239
+
240
+ Give the user a short report in this exact shape:
241
+
242
+ ```
243
+ Namespace: src/<prefix>/ (from src/<prefix>-*)
244
+ Files moved: <n> source + <n> test (old -> new, one per line)
245
+ Bare entry: src/<prefix>.ts -> src/<prefix>/index.ts (or: none)
246
+ Imports rewired: <n> inbound files, <n> moved files re-pathed
247
+ Typecheck loop: clean after <n> pass(es)
248
+ Tests: all pass / <what failed>
249
+ Lint problems: <before> -> <after> (must be unchanged)
250
+ Quality (FTA): unchanged / <what moved>
251
+ ```
252
+
253
+ Keep it brief. Done.
@@ -0,0 +1,121 @@
1
+ # Improve a Draft Plan (one plan per run)
2
+
3
+ Your job: take **one** plan from `product/plans/draft/`, check every claim it makes against the real codebase, and edit the plan so an implementer is less likely to go wrong — then assess its complexity and record it at the top of the plan. You improve the **plan document only**; you change no source code.
4
+
5
+ **No AI attribution — anywhere.** Never credit an AI agent as an author or contributor in anything this task produces. That means: no `Co-Authored-By:` trailers naming Claude or any other AI, no “Generated with Claude Code” (or similar) lines or badges, and no AI authorship notes in code, comments, docs, spec files, plan files, commit messages, or PR titles and bodies. This overrides any default convention that appends such attribution. The commit's configured git author is the only authorship ever recorded.
6
+
7
+ This is a **planning** task, not pre-implementation. A good plan decides *what* to build, *where* it goes, and *which existing code to reuse* — it does not write the code. The implementer writes the code.
8
+
9
+ **Run everything synchronously, in the foreground.** Never use `run_in_background`, `&`, or otherwise start a background process (dev servers, watchers, long-lived processes) — every command must finish and return its exit code before you move to the next step.
10
+
11
+ **No subagents, no background agents.** Do every step yourself — never launch a subagent (Task/Agent tool, `fork`, or otherwise) to research, explore, or implement any part of this task on your behalf.
12
+
13
+ Do the steps below **in order**. Do not skip steps. Do not invent your own process.
14
+
15
+ **Shell hygiene:** run every command on its own line — no `&&` chaining, no `; echo "Exit code: $?"` suffixes, no subshell captures. To run a project script, always use `./scripts/run.mjs <name>` — never call `node scripts/<name>.mjs` directly.
16
+
17
+ **Run autonomously.** This task runs unattended — do not ask the user questions or wait for feedback at any step. Make the best judgment call yourself, using the rules in this document, and keep going. Only stop early for the conditions explicitly listed under "Forbidden" below.
18
+
19
+ ## What you may and may not do
20
+
21
+ ### Allowed — do it automatically, never ask
22
+
23
+ Edit the **one plan file** you picked: correct it, disambiguate it, restructure it, and add the complexity line. Read anything in the repo you need to verify the plan's claims. When the work is only this, carry it out start to finish without stopping — do **not** ask "Do you want me to proceed?", do **not** pause for approval.
24
+
25
+ ### Forbidden — no exceptions
26
+
27
+ 1. **Adding code to the plan.** Never add implementation code blocks — no function bodies, no method implementations, no JSX/CSS blocks, no "here's the code to write". Name the module, function, or type and describe its contract and behavior in prose instead. (Illustrative examples of *observable output* — a CLI transcript, an error message the user will see, an ASCII sketch of UI — are fine. A type or code the implementer would paste is not.) If the draft already contains implementation code, you may leave it, but do not extend it; if it contradicts what you verified in the repo, replace it with a prose description rather than corrected code.
28
+ 2. **Editing any file other than the chosen plan.** No source, no tests, no config, no other plans.
29
+ 3. **Moving the plan out of `product/plans/draft/`.** Promotion to `ready/` is the human's status decision (see the plan-storage section in [`CLAUDE.md`](../../CLAUDE.md)).
30
+ 4. **Deciding product scope.** If the plan's *goal* seems wrong or not worth doing, say so in your report — do not rewrite the goal.
31
+
32
+ ---
33
+
34
+ ## Step 0 — Prepare the workspace
35
+
36
+ Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
37
+
38
+ ---
39
+
40
+ ## Step 1 — Pick the plan
41
+
42
+ - If you were pointed at a specific plan file, use that one.
43
+ - Otherwise list `product/plans/draft/`. Exactly one plan there → that is your target. More than one → report the list and stop (the human picks). None → report that and stop.
44
+
45
+ State your pick in one sentence.
46
+
47
+ ---
48
+
49
+ ## Step 2 — Read the plan, then read the code it talks about
50
+
51
+ 1. Read the entire plan.
52
+ 2. For **every** file path, function, type, command, line anchor, and behavioral claim the plan makes, open the real thing and check it. Grep for symbols rather than trusting quoted line numbers — line anchors drift.
53
+ 3. Read the project constraints that shape any implementation here: the ESLint rules and file-size limit in [`CLAUDE.md`](../../CLAUDE.md) (200-line `max-lines`, `.js` import extensions in `src/`, type-aware rules), and the test conventions (`src/**/*.test.ts`, `web/src/**/*.test.tsx`).
54
+ 4. Skim one or two plans in `product/plans/ready/` to match the house style — they follow a shape like: Goal, Design decisions, "What already exists (reuse, don't rebuild)" table, Implementation steps, Tests, Verification, Out of scope.
55
+
56
+ ---
57
+
58
+ ## Step 3 — Find the ways an implementer could go wrong
59
+
60
+ Judge the plan against each of these. Take notes; you will fix them in Step 4.
61
+
62
+ - **Wrong or stale references.** Paths, symbols, or line anchors that don't match the repo. These silently derail an implementation.
63
+ - **Missed call sites and paths.** The plan changes behavior at one site, but the behavior has other entry points the plan never mentions. Grep for every caller/consumer of what the plan touches and check the plan accounts for each.
64
+ - **Ambiguity.** Any step a reasonable implementer could read two ways; vague verbs ("handle errors", "update the UI") with no stated behavior; names left unchosen.
65
+ - **Undecided decisions.** Choices the implementer would be forced to make mid-flight — file placement, naming, edge-case behavior, error handling, what happens on the empty/duplicate/oversized input. Plans decide; implementers execute. Make the decision (grounded in how the codebase already does it) and write it into the plan as prose.
66
+ - **Unstated dependencies and ordering.** Does it depend on another plan landing first? Must its steps land in a particular order to keep typecheck/tests green at each checkpoint? Say so explicitly.
67
+ - **Constraint collisions.** Will a touched file blow the 200-line limit (plan an extraction, don't leave it to chance)? Do proposed imports follow the `.js`-extension rule? Would the approach trip a lint rule from `eslint.config.mjs`?
68
+ - **Reuse blindness.** Does the plan rebuild something the repo already has? Every mechanism the plan needs that already exists should be named with its location — a "What already exists (reuse, don't rebuild)" table is the house pattern.
69
+ - **Testing gaps.** Behavior the plan changes with no test that would catch a regression, or tests named without their location/convention.
70
+ - **Missing boundaries.** No "Out of scope" section, or a goal that quietly grows mid-document.
71
+ - **Missing verification.** The plan should end with how to verify: `./scripts/run.mjs check-diff` during development plus a concrete manual end-to-end check.
72
+
73
+ ---
74
+
75
+ ## Step 4 — Improve the plan
76
+
77
+ Edit the plan file to remove everything you found. Rules of thumb:
78
+
79
+ - Every sentence you add must close off a way to go wrong or record a decision that was open. If it does neither, don't add it.
80
+ - Anchor references as `path:line` **plus** the quoted identifier or code fragment, so the reference survives line drift.
81
+ - Prefer "do it like `<existing thing>` at `<location>`" over describing a mechanism from scratch — pointing at a working example in the repo is the strongest ambiguity-killer that adds no code.
82
+ - Do not rewrite sections that are already precise; keep the author's structure and voice where it works. This is an edit pass, not a rewrite.
83
+ - Use natural line breaks — never wrap lines at a fixed column (per `CLAUDE.md`).
84
+
85
+ ---
86
+
87
+ ## Step 5 — Assess and record complexity
88
+
89
+ Rate the (now improved) plan **1–10** for implementation complexity. Calibration, consistent with the ratings on the plans in `product/plans/ready/`:
90
+
91
+ - **1–2** — one small module or pure wiring; no new protocol/persistence/UI surface. (`cli-help-version`, `prompt-click-prefill` are 2s.)
92
+ - **3–4** — small feature, but correctness depends on catching several call sites or coordinating with other plans; or it spans server and web with a new RPC or persistence field. (`unread-badge` is a 3, `tab-name-alias` a 4.)
93
+ - **5–7** — a new subsystem or protocol surface, many touched files, real state-machine or concurrency reasoning.
94
+ - **8–9** — a major feature: multiple new modules on both sides, novel interaction logic, first-of-its-kind surface in the app. (`editor-tab` is a 9.)
95
+ - **10** — architecture-level overhaul touching most of the system.
96
+
97
+ Record it directly under the plan's `#` title as a single line:
98
+
99
+ ```
100
+ **Complexity: N/10** — <one-line rationale naming what drives the number>
101
+ ```
102
+
103
+ If the plan already has a complexity line, update it — after your improvements the number may have changed.
104
+
105
+ ---
106
+
107
+ ## Step 6 — Verify and report
108
+
109
+ 1. `git status` / `git diff` — confirm the **only** modified file is the plan (untracked plan files: confirm nothing else changed).
110
+ 2. Re-read your edits once: no implementation code added, every decision you made is stated as a decision (not hedged with "maybe" or "either"), complexity line present and formatted as above.
111
+
112
+ Then give the user a short report in this exact shape:
113
+
114
+ ```
115
+ Plan: product/plans/draft/<file>
116
+ Complexity: N/10 — <rationale>
117
+ Fixed: <short bullets — each wrong reference corrected, ambiguity resolved, decision made, gap filled>
118
+ Open: <anything only the human can decide, e.g. scope doubts — or "nothing">
119
+ ```
120
+
121
+ Keep it brief. Done.
@@ -0,0 +1,144 @@
1
+ # Improve Security (detect everything, fix only the safe case, report the rest)
2
+
3
+ Your job: run the security tools, list **every** finding, automatically apply the **one** kind of fix that is safe and mechanical (a dependency patch), and **report all other findings for a human** — do not change that code yourself.
4
+
5
+ **No AI attribution — anywhere.** Never credit an AI agent as an author or contributor in anything this task produces. That means: no `Co-Authored-By:` trailers naming Claude or any other AI, no “Generated with Claude Code” (or similar) lines or badges, and no AI authorship notes in code, comments, docs, spec files, plan files, commit messages, or PR titles and bodies. This overrides any default convention that appends such attribution. The commit's configured git author is the only authorship ever recorded.
6
+
7
+ **Shell hygiene:** run every command on its own line — no `&&` chaining, no `; echo "Exit code: $?"` suffixes, no subshell captures. The exit code and output are visible in the tool result. To run a project script, always use `./scripts/run.mjs <name>` — never call `node scripts/<name>.mjs` directly.
8
+
9
+ **Run everything synchronously, in the foreground.** Never use `run_in_background`, `&`, or otherwise start a background process (dev servers, watchers, long-lived processes) — every command must finish and return its exit code before you move to the next step.
10
+
11
+ **No subagents, no background agents.** Do every step yourself — never launch a subagent (Task/Agent tool, `fork`, or otherwise) to research, explore, or implement any part of this task on your behalf.
12
+
13
+ **Why security is different from other cleanups:** a wrong security "fix" still passes the tests. If you silence a warning, weaken a check, or delete a guard, `tsc`, the linter, and the tests all stay green — so they **cannot** tell you that you made the code less safe. Because nothing will catch a bad call, you must not make security judgment calls. Detect and report; let a human decide.
14
+
15
+ Do the steps below **in order**. Do not skip steps. Do not invent your own process.
16
+
17
+ **Run autonomously.** This task runs unattended — do not ask the user questions or wait for feedback at any step. Make the best judgment call yourself, using the rules in this document, and keep going. There is nothing to stop for: every finding either gets the one safe dependency-patch fix, or gets reported under "Never do on your own" below — you always finish by producing the Step 3 report, never by pausing to ask.
18
+
19
+ ## The one safety rule (read this first)
20
+
21
+ ### Safe to do on your own — the ONLY change you may make
22
+
23
+ - **Apply dependency patches** with `npm audit fix` (this fixes known CVEs using compatible versions). Then verify the project is still green. That is the only fix you apply on your own.
24
+
25
+ ### Never do on your own — REPORT it, do not touch the code
26
+
27
+ Leave every one of these to a human. List it in your report (Step 3); do **not** edit the code:
28
+
29
+ - Add or change **input validation / sanitisation**.
30
+ - Add an `eslint-disable` comment, or **silence / suppress** any security finding in any way.
31
+ - Rewrite a **regex**, remove an **`eval`**, or change any **auth / crypto / token** code or `src/security.ts`.
32
+ - **Remove a committed secret** or rewrite git history.
33
+ - Run **`npm audit fix --force`** (it makes breaking changes).
34
+
35
+ Each of those is a judgment call, and a wrong call hides a real problem that the tests will not catch. Never edit config files or test files by hand. (`npm audit fix` may edit `package.json` / `package-lock.json` — that is fine.)
36
+
37
+ ---
38
+
39
+ ## Step 0 — Prepare the workspace
40
+
41
+ Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
42
+
43
+ ---
44
+
45
+ ## Step 1 — Run the security tools and list every finding
46
+
47
+ Detection is always safe, so do it even if the project is not green right now.
48
+
49
+ ### 1a — ESLint security findings
50
+
51
+ ```bash
52
+ npm run lint 2>&1
53
+ ```
54
+
55
+ ESLint groups findings under each file: the **file path is printed on its own line**, and its findings are **indented below it**, like this:
56
+
57
+ ```
58
+ /Users/you/janissary/src/agent-state.ts
59
+ 33:8 warning Found existsSync from package "node:fs" with non literal argument at index 0 security/detect-non-literal-fs-filename
60
+ ```
61
+
62
+ A security finding is any indented line whose last column is a rule starting with **`security/`**. For each one, record: the **file** (the path line above it), the **line:column** (e.g. `33:8`), the **severity** (`error` or `warning`), and the **rule**. (Quick filter: `npm run lint 2>&1 | grep -E "security/|^/"` keeps the security lines and the file-path headers.)
63
+
64
+ ### 1b — Dependency CVEs
65
+
66
+ ```bash
67
+ npm run security:deps 2>&1
68
+ ```
69
+
70
+ If it lists vulnerabilities, record for each: the **package**, the **CVE/advisory**, the **severity** (`low`/`moderate`/`high`/`critical`), and whether a **fix is available**. If it says `found 0 vulnerabilities`, record "No dependency CVEs."
71
+
72
+ ### 1c — Secrets scan
73
+
74
+ ```bash
75
+ npm run security:secrets 2>&1
76
+ ```
77
+
78
+ If the output says the command is not found / not installed, record "Secrets not scanned (gitleaks not installed)" and move on — this is **not** a failure. Otherwise record every finding (file, line, what was detected).
79
+
80
+ **If all three are clean, report "No security findings." and stop.** Otherwise continue.
81
+
82
+ ---
83
+
84
+ ## Step 2 — Apply the one safe fix: dependency patches (only if there are any)
85
+
86
+ Do this step **only if Step 1b found a vulnerability with a fix available.** If there were no dependency CVEs, skip straight to Step 3.
87
+
88
+ 1. **Confirm the project is green first** (you are about to change code):
89
+ ```bash
90
+ npx tsc --noEmit 2>&1
91
+ npm test 2>&1
92
+ npm run lint 2>&1
93
+ ```
94
+ The compiler must have no errors, every test must pass, and lint must have no errors (warnings are fine). **If it is not green, do not fix anything** — report the CVE in Step 3 with the note "not auto-fixed: project was not green," and stop.
95
+
96
+ 2. **Back up the manifest and lock file:**
97
+ ```bash
98
+ cp package.json package.json.bak
99
+ cp package-lock.json package-lock.json.bak
100
+ ```
101
+
102
+ 3. **Apply the fix** (never use `--force`):
103
+ ```bash
104
+ npm audit fix
105
+ ```
106
+
107
+ 4. **Verify** — everything must be green and the CVE gone:
108
+ ```bash
109
+ npx tsc --noEmit 2>&1
110
+ npm test 2>&1
111
+ npm run lint 2>&1
112
+ npm run security:deps 2>&1
113
+ ```
114
+ If anything is no longer green, **restore the backups and report**:
115
+ ```bash
116
+ cp package.json.bak package.json && cp package-lock.json.bak package-lock.json && npm install
117
+ ```
118
+ If `npm audit` says the remaining vulnerabilities can only be fixed with `--force` (breaking changes), do **not** force them — list them in Step 3 for a human.
119
+
120
+ When green, delete the backups: `rm package.json.bak package-lock.json.bak`.
121
+
122
+ ---
123
+
124
+ ## Step 3 — Report
125
+
126
+ Give the user a short report in this exact shape. Group the ESLint findings by rule so the list stays short.
127
+
128
+ ```
129
+ Fixed automatically:
130
+ Dependencies: <packages patched + new versions, or "none">
131
+
132
+ Needs a human — NOT auto-fixed:
133
+ ESLint security:
134
+ <rule> (<error/warning>) ×<count> in: <file:line, file:line, ...>
135
+ → <one-line suggestion, e.g. "confirm each path is trusted, or add validation at the entry point">
136
+ ... (one block per rule)
137
+ Secrets: <findings, or "none", or "not scanned — gitleaks not installed">
138
+ Dependency CVEs not fixed: <CVEs needing --force or with no fix, or "none">
139
+
140
+ Scans skipped: <e.g. "gitleaks not installed", "opengrep not installed", or "none">
141
+ Verify (only if a fix was applied): compiler / tests / lint all green
142
+ ```
143
+
144
+ For a deeper scan, a human can run `npm run security:sast` (requires opengrep). Keep the report brief. Done.