janissary 0.5.0 → 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.
- package/ai/guidelines/architecture-principles.md +75 -0
- package/ai/guidelines/code-guidelines.md +17 -0
- package/ai/guidelines/conventional-commits.md +192 -0
- package/ai/guidelines/developer-documentation.md +124 -0
- package/ai/guidelines/documentation.md +80 -0
- package/ai/guidelines/human-writing-guidelines.md +42 -0
- package/ai/guidelines/imports-and-barrel-files.md +49 -0
- package/ai/guidelines/pull-request-automation.md +98 -0
- package/ai/guidelines/strategies-for-readable-summaries.md +27 -0
- package/ai/guidelines/user-documentation.md +177 -0
- package/ai/personas/algorithm.md +14 -0
- package/ai/personas/assistant.md +25 -0
- package/ai/personas/link-scout.md +16 -0
- package/ai/personas/researcher.md +12 -0
- package/ai/personas/security.md +12 -0
- package/ai/personas/summarizer.md +11 -0
- package/ai/tasks/build-a-feature.md +133 -0
- package/ai/tasks/fix-a-small-issue.md +138 -0
- package/ai/tasks/improve-codebase.md +187 -0
- package/ai/tasks/improve-modularity.md +188 -0
- package/ai/tasks/improve-namespacing.md +253 -0
- package/ai/tasks/improve-plan.md +121 -0
- package/ai/tasks/improve-security.md +144 -0
- package/ai/tasks/improve-style.md +147 -0
- package/ai/tasks/improve-test-coverage.md +178 -0
- package/ai/tasks/merge-change-to-master.md +144 -0
- package/ai/tasks/open-feature-pull-request.md +161 -0
- package/ai/tasks/plan-ready-features.md +154 -0
- package/ai/tasks/prepare-workspace.md +35 -0
- package/ai/tasks/quick-commit.md +82 -0
- package/ai/tasks/reduce-complexity.md +185 -0
- package/ai/tasks/remove-deadcode.md +206 -0
- package/ai/tasks/remove-duplication.md +202 -0
- package/ai/tasks/update-package.md +137 -0
- package/package.json +5 -3
- package/scripts/changed-files.mjs +22 -0
- package/scripts/check-diff.mjs +100 -0
- package/scripts/coverage-file.mjs +85 -0
- package/scripts/docs-screenshots/capture.mjs +82 -0
- package/scripts/docs-screenshots/fixtures/docs/api.md +3 -0
- package/scripts/docs-screenshots/fixtures/docs/guide.md +3 -0
- package/scripts/docs-screenshots/fixtures/page.html +31 -0
- package/scripts/docs-screenshots/fixtures/profiles/demo/editor.json +1 -0
- package/scripts/docs-screenshots/fixtures/profiles/demo/writer.json +1 -0
- package/scripts/docs-screenshots/fixtures/sample.md +26 -0
- package/scripts/docs-screenshots/fixtures/sample.png +0 -0
- package/scripts/docs-screenshots/fixtures/sample.ts +25 -0
- package/scripts/docs-screenshots/fixtures/src/app.ts +2 -0
- package/scripts/docs-screenshots/fixtures/src/tides.ts +2 -0
- package/scripts/docs-screenshots/janus.mjs +51 -0
- package/scripts/docs-screenshots/manifest.mjs +122 -0
- package/scripts/docs-screenshots/scratch.mjs +53 -0
- package/scripts/docs-screenshots.mjs +86 -0
- package/scripts/lint-files.mjs +47 -0
- package/scripts/postinstall.mjs +14 -0
- package/scripts/pr-check-changes.sh +15 -0
- package/scripts/pr-check-gate.sh +29 -0
- package/scripts/pr-check-mergeable.sh +29 -0
- package/scripts/pr-commit.sh +23 -0
- package/scripts/pr-create-branch.sh +20 -0
- package/scripts/pr-create-pr.sh +29 -0
- package/scripts/pr-merge.sh +22 -0
- package/scripts/pr-push-branch.sh +24 -0
- package/scripts/pr-rebase.sh +56 -0
- package/scripts/pr-resolve-remote.sh +9 -0
- package/scripts/pr-wait-checks.sh +41 -0
- package/scripts/publish.mjs +61 -0
- package/scripts/release.mjs +209 -0
- package/scripts/run.mjs +40 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Remove Dead Code (clear all findings in one pass)
|
|
2
|
+
|
|
3
|
+
Your job: run Knip, delete the dead code it reports, then prove the project is still green. Dead-code removal is mechanical — you only ever **delete code that nothing uses**, never add or rewrite logic. Clear all the safe findings in one pass.
|
|
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
|
+
The rule is simple: **the compiler, the linter, and the tests must be green before you start and green again after you finish.** If the project is not green before you start, stop and tell the user. If you cannot keep it green, put the code back.
|
|
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
|
+
**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.
|
|
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. Only stop early if the project isn't green before you start, or if you cannot keep it green after a removal (put the code back and report instead of pausing).
|
|
18
|
+
|
|
19
|
+
## The one safety rule (read this first)
|
|
20
|
+
|
|
21
|
+
There are two kinds of finding: **remove automatically** and **leave alone**.
|
|
22
|
+
|
|
23
|
+
### Remove automatically — never ask
|
|
24
|
+
|
|
25
|
+
You may remove these four kinds of finding on your own, start to finish, without stopping. Do **not** ask "Do you want me to proceed?". Do **not** wait for confirmation. Asking permission for safe removals is a mistake.
|
|
26
|
+
|
|
27
|
+
- **Unused dependency / devDependency** — remove the package from `package.json`.
|
|
28
|
+
- **Unused file** — delete the file (nothing imports it).
|
|
29
|
+
- **Unused export** — delete the whole declaration.
|
|
30
|
+
- **Unused exported type** — delete the whole type/interface.
|
|
31
|
+
|
|
32
|
+
### Leave alone — skip it and list it (do NOT remove)
|
|
33
|
+
|
|
34
|
+
Do **not** remove a finding if it is any of these. Just leave it in place and list it in your report. You never need to stop and ask in this task — skipping a piece of dead code is always safe.
|
|
35
|
+
|
|
36
|
+
- A finding in **`src/controller.ts`** (the biggest, riskiest file).
|
|
37
|
+
- A finding in **security, password/crypto, shell-execution, PTY/terminal, or network/browser** code.
|
|
38
|
+
- A finding you could only remove by **editing a test file** (`*.test.ts`, `*.test.tsx`).
|
|
39
|
+
- A finding whose removal looks like it would touch **more than 5 files**.
|
|
40
|
+
- A name you can see is used in a **non-obvious way** — referenced as a string, via dynamic `import()`, or by something outside this repo.
|
|
41
|
+
|
|
42
|
+
### Guardrails
|
|
43
|
+
|
|
44
|
+
- **Do NOT run `knip --fix`.** It removes everything it finds and ignores the "leave alone" list above. Remove findings by hand.
|
|
45
|
+
- **Act only on the four "unused" categories above.** If Knip prints any other kind of finding (`Unlisted dependencies`, `Unresolved imports`, `Duplicate exports`, `Unused class members`, …), do not touch it — just list it under "Other" in your report.
|
|
46
|
+
- Never edit `knip.json`, `tsconfig.json`, `eslint.config.mjs`, or `package.json` (except to remove an unused-dependency line). Never add `// @public` tags or `ignore` entries to silence a finding.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Step 0 — Prepare the workspace
|
|
51
|
+
|
|
52
|
+
Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Step 1 — See the starting state (run these, write the numbers down)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx tsc --noEmit 2>&1
|
|
60
|
+
npm test 2>&1
|
|
61
|
+
npm run lint 2>&1
|
|
62
|
+
npm run knip 2>&1
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The first three must all be **green** before you touch anything:
|
|
66
|
+
|
|
67
|
+
- **Compiler (`npx tsc --noEmit`):** must finish with **no errors**.
|
|
68
|
+
- **Tests (`npm test`):** **every** test must pass.
|
|
69
|
+
- **Lint (`npm run lint`):** must report **no errors**. (Warnings are fine and do not count as red — the line `✖ 16 problems (0 errors, 16 warnings)` is green because errors is 0.)
|
|
70
|
+
|
|
71
|
+
**If any of those three is not green, STOP and tell the user. Do not remove dead code on a project that is not already green** — fixing a pre-existing failure is not your job here.
|
|
72
|
+
|
|
73
|
+
- **Knip (`npm run knip`):** this is your to-do list of findings. **If Knip reports no findings, there is nothing to do — report "No dead code found" and stop.**
|
|
74
|
+
|
|
75
|
+
Always run these fresh; do not trust earlier output in the conversation.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Step 2 — Read the Knip findings
|
|
80
|
+
|
|
81
|
+
Knip groups findings under headers, like this:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Unused files (1)
|
|
85
|
+
src/old-feature.ts
|
|
86
|
+
|
|
87
|
+
Unused dependencies (1)
|
|
88
|
+
some-package package.json
|
|
89
|
+
|
|
90
|
+
Unused exports (2)
|
|
91
|
+
helperFn function src/utils.ts:12:17
|
|
92
|
+
CONSTANT unknown src/config.ts:5:14
|
|
93
|
+
|
|
94
|
+
Unused exported types (1)
|
|
95
|
+
OldType type src/types.ts:42:13
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For each finding note the **category**, the **file path**, and (for exports/types) the **line number**.
|
|
99
|
+
|
|
100
|
+
Two facts about how Knip is set up here:
|
|
101
|
+
|
|
102
|
+
- Because of the `ignoreExportsUsedInFile` setting, **every "unused export" Knip lists is used nowhere at all** — not in other files and not even in its own file. So the fix is always to **delete the entire declaration**, never just the `export` keyword.
|
|
103
|
+
- Test files already count as usage. If a test imports something, Knip will **not** list it — so you do not need to grep test files yourself.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 3 — Decide what to remove
|
|
108
|
+
|
|
109
|
+
Go through every finding from Step 2 and sort it:
|
|
110
|
+
|
|
111
|
+
- If it is one of the four removable categories **and** none of the "leave alone" conditions apply → it goes on your **removal list**.
|
|
112
|
+
- Otherwise → it goes on your **skip list** (you will name these in the report, but not touch them).
|
|
113
|
+
|
|
114
|
+
You do not need to ask anyone. Just build the two lists and continue.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Step 4 — Back up, then remove (safest first)
|
|
119
|
+
|
|
120
|
+
**Back up every file you will edit or delete** so you can restore it exactly:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cp src/foo.ts src/foo.ts.bak
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Work through your removal list in this order:
|
|
127
|
+
|
|
128
|
+
### 1. Unused dependency / devDependency
|
|
129
|
+
|
|
130
|
+
Back up both lock and manifest first, because this also rewrites them:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cp package.json package.json.bak
|
|
134
|
+
cp package-lock.json package-lock.json.bak
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Remove the one line for that package from `package.json`, then:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm install
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
(To undo later: copy both `.bak` files back, then run `npm install` again.)
|
|
144
|
+
|
|
145
|
+
### 2. Unused file
|
|
146
|
+
|
|
147
|
+
Back it up, then delete it:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
cp src/old-feature.ts src/old-feature.ts.bak
|
|
151
|
+
rm src/old-feature.ts
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
(First make sure the file is not named in a `package.json` script or in `bin` — if it is, skip it.)
|
|
155
|
+
|
|
156
|
+
### 3. Unused export / unused exported type
|
|
157
|
+
|
|
158
|
+
Open the file at the line Knip gave you and **delete the whole declaration** — the entire `function` / `const` / `type` / `interface`, from its first line to its closing brace.
|
|
159
|
+
|
|
160
|
+
- If the finding is a **re-export line** (`export { X } from './y.js'` or `export type { X } from './y.js'`), just delete that line (or only the one name, if the line lists several).
|
|
161
|
+
- Keep the diff minimal — do not reformat or tidy unrelated lines.
|
|
162
|
+
|
|
163
|
+
Do not chase down unused imports by hand right now — the linter in Step 5 will list any import that became unused, and you will delete those then.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Step 5 — Verify (run in this order; everything must be green)
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npx tsc --noEmit 2>&1
|
|
171
|
+
npm run lint 2>&1
|
|
172
|
+
npm test 2>&1
|
|
173
|
+
npm run knip 2>&1
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Each command checks one thing. Fix or restore before moving on.
|
|
177
|
+
|
|
178
|
+
1. **Compiler — green (no errors).** An error like `Cannot find name 'X'` or `has no exported member 'X'`, naming something you removed, means it was **not** dead — a reference still exists. **Restore that finding's backup**, move it to your skip list, and re-run.
|
|
179
|
+
2. **Lint — green (no errors).** A new error is almost always an **import that became unused** after you deleted a declaration. The linter prints its file and line — delete that import line, then re-run. Never silence anything with an `eslint-disable` comment.
|
|
180
|
+
3. **Tests — green (all pass).** If a test now fails, something you removed was used in a way the compiler could not see. **Restore that finding's backup**, skip it, and re-run. Never edit a test to make it pass.
|
|
181
|
+
4. **Knip — the findings you removed are gone.** Re-running Knip should no longer list anything you removed. (Findings you deliberately skipped will still be listed — that is expected; they go in your report.)
|
|
182
|
+
|
|
183
|
+
The compiler, the linter, and the tests must all end **green**, exactly as they were in Step 1. When they are, **delete the backup files**: `rm *.bak src/**/*.bak` (and `package-lock.json.bak` if you made one).
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Step 6 — Report
|
|
188
|
+
|
|
189
|
+
Give the user a short report in this exact shape:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
Removed:
|
|
193
|
+
Dependencies: <packages removed, or "none">
|
|
194
|
+
Files: <files deleted, or "none">
|
|
195
|
+
Exports/types: <count> removed, in <files>
|
|
196
|
+
|
|
197
|
+
Skipped (left in place): <findings you did not touch + one-word reason each, or "none">
|
|
198
|
+
Other Knip findings: <non-"unused" findings, or "none">
|
|
199
|
+
|
|
200
|
+
Compiler: green / <errors, if any>
|
|
201
|
+
Lint: green / <errors, if any>
|
|
202
|
+
Tests: green / <what failed>
|
|
203
|
+
Knip: <N findings before> -> <N remaining (all deliberately skipped)>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Keep it brief. Done.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Remove Code Duplication (one clone per run)
|
|
2
|
+
|
|
3
|
+
Your job: remove **one** duplicated block of code, then prove nothing broke. Do exactly one clone, then verify.
|
|
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
|
+
Deduplication edits real code that other files may import, so the rule is simple: **the tests must pass before you start and still pass after. If you cannot keep them passing, put the code back the way it was.**
|
|
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
|
+
**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.
|
|
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. Only stop early if the project isn't green before you start (Step 1), or if every remaining candidate clone is blocked (see "Blocked work" below).
|
|
18
|
+
|
|
19
|
+
## What you may and may not do
|
|
20
|
+
|
|
21
|
+
### Safe work — DO IT AUTOMATICALLY, never ask
|
|
22
|
+
|
|
23
|
+
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.
|
|
24
|
+
|
|
25
|
+
Safe work is exactly these three fixes (and nothing else), each done by its Recipe in Step 5:
|
|
26
|
+
|
|
27
|
+
- **Recipe 1 — within-file** (preferred, safest): two blocks in the **same** file → one local helper in that same file. No other file changes.
|
|
28
|
+
- **Recipe 2 — move to the owner file**: the shared block clearly belongs to one of the two files (e.g. formatting logic → `state-format.ts`); put it there and import it at the other site. Two files change.
|
|
29
|
+
- **Recipe 3 — new shared file**: neither file owns it → put the shared block in a new `src/<name>.ts` and import it at both sites. Three files change (the new file + the two sites).
|
|
30
|
+
|
|
31
|
+
Adding a **new** function (even an exported one) is safe. Renaming or removing an **existing** export is not (see below).
|
|
32
|
+
|
|
33
|
+
### Blocked work — skip and pick a different clone
|
|
34
|
+
|
|
35
|
+
If removing the clone would require any of the following, **go back to Step 3** and pick the next clone instead. Never ask the user — just skip and move on.
|
|
36
|
+
|
|
37
|
+
1. Renaming, removing, or changing the arguments of an **existing** `export` (other files import it).
|
|
38
|
+
2. Editing **more than 3 files** in total.
|
|
39
|
+
3. Touching **`src/controller.ts`** (the biggest, riskiest file — its clones are high-value but not for an unattended run).
|
|
40
|
+
4. A helper that would be shared **between `src/` and `web/src/`** (that needs a build change).
|
|
41
|
+
5. Editing **any test file** (`*.test.ts`, `*.test.tsx`).
|
|
42
|
+
6. Touching **security, password/crypto, shell-execution, PTY/terminal, or network/browser** code.
|
|
43
|
+
|
|
44
|
+
If every remaining clone is blocked, list each one and why it was blocked in your report, and stop without changing any code.
|
|
45
|
+
|
|
46
|
+
> You may edit **only** the clone-site files, plus (optionally) **one** new helper file you create. Never edit `.jscpd.json`, `fta.json`, `eslint.config.mjs`, `package.json`, `tsconfig.json`, any other config file, or any test file. Leave the `threshold` in `.jscpd.json` alone.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Step 0 — Prepare the workspace
|
|
51
|
+
|
|
52
|
+
Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Step 1 — See the starting state (run these, write the numbers down)
|
|
57
|
+
|
|
58
|
+
Run all three and read the output:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm test 2>&1
|
|
62
|
+
npm run lint 2>&1
|
|
63
|
+
npm run duplication 2>&1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Record these starting numbers — you will compare against them at the end. Put them straight into your report draft (Step 7):
|
|
67
|
+
|
|
68
|
+
- **Tests:** they must be **green** (all passing). If any test is already failing **before** you touch anything, STOP and tell the user — do not start on a broken suite.
|
|
69
|
+
- **Lint:** near the end of `npm run lint` is a line like `✖ 16 problems (0 errors, 16 warnings)`. Write down the **errors** and **warnings** counts.
|
|
70
|
+
- **Duplication:** near the end of `npm run duplication` is a line `Found N clones.` — write down **N**. The table just above it has a `Total:` row; in its `Duplicated lines` column is a percentage like `152 (2.47%)` — write down that **%**. (Ignore the promotional lines at the very bottom.)
|
|
71
|
+
|
|
72
|
+
Always run these fresh. Do not trust earlier output in the conversation.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Step 2 — Read the clone list
|
|
77
|
+
|
|
78
|
+
`npm run duplication` prints each clone as two lines, like this:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Clone found (typescript)
|
|
82
|
+
- commands/state.ts [11:64 - 34:58]
|
|
83
|
+
state-format.ts [4:57 - 24:115]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Reading it:
|
|
87
|
+
|
|
88
|
+
- The two lines are the **two copies** of the same code: file, then `[startLine:startCol - endLine:endCol]`.
|
|
89
|
+
- **Same file name on both lines = a within-file clone** (Recipe 1, the safest). Two different files = a cross-file clone.
|
|
90
|
+
- **Clone size in lines ≈ `endLine − startLine`** (jscpd does not print it). The two sides may differ by a line or two; use the bigger number. You only need this for ranking, so a rough count is fine.
|
|
91
|
+
- **Path gotcha:** jscpd drops the scan-root prefix. A path like `messaging.ts` is really **`src/messaging.ts`**, and `commands/state.ts` is **`src/commands/state.ts`**. If a file is not under `src/`, it is under `web/src/`. When in doubt, search for the file by name before editing.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Step 3 — Pick exactly one clone to remove
|
|
96
|
+
|
|
97
|
+
1. List every clone from Step 2.
|
|
98
|
+
2. **Cross out** any clone where **either** side is:
|
|
99
|
+
- a `*.test.ts` / `*.test.tsx` file,
|
|
100
|
+
- `src/main.ts`,
|
|
101
|
+
- `src/controller.ts`,
|
|
102
|
+
- `src/pty.ts`, `src/shell.ts`, or any file whose main job is spawning processes, running a terminal, doing network, or driving a browser,
|
|
103
|
+
- and cross out any clone whose two sides are split across `src/` and `web/src/`.
|
|
104
|
+
3. From what remains, pick **one**, in this order:
|
|
105
|
+
1. **Any within-file clone** (same file on both lines) — pick the largest of these. These are the safest.
|
|
106
|
+
2. If there are no within-file clones left, pick the **largest cross-file clone**.
|
|
107
|
+
4. Open both sides and read the duplicated code. If removing it cleanly would require renaming/removing an existing `export`, or editing more than 3 files → it is needs-permission (rules 1–2); cross it out and pick the next one.
|
|
108
|
+
|
|
109
|
+
State your pick in one sentence: both file paths (with the real `src/` prefix), the line ranges, the rough size, and whether it is within-file or cross-file.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Step 4 — Plan the fix (a quick note to yourself, then keep going)
|
|
114
|
+
|
|
115
|
+
Jot a one- or two-line plan: the name of the helper you will create and which file it lives in, and what each clone site becomes (a call to the helper). This is a note for **you**, not a message to send — do **not** post it and wait for a reply.
|
|
116
|
+
|
|
117
|
+
Check the plan against **What you may and may not do**:
|
|
118
|
+
|
|
119
|
+
- If any of points 1–6 applies → go back to Step 3 and pick a different clone.
|
|
120
|
+
- Otherwise (all safe work) → go straight to Step 5 and make the change **now, on your own, without asking.**
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Step 5 — Make the change
|
|
125
|
+
|
|
126
|
+
**First, back up every file you are about to edit**, so you can restore it exactly if anything goes wrong:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
cp src/foo.ts src/foo.ts.bak
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Then apply the Recipe that matches your clone. Keep the diff as small as possible — do not reformat or "tidy" unrelated lines.
|
|
133
|
+
|
|
134
|
+
### Recipe 1 — within-file (same file on both lines)
|
|
135
|
+
|
|
136
|
+
1. Confirm both blocks are inside function bodies, not whole `export`ed declarations.
|
|
137
|
+
2. Add a new helper function (not exported) **below** the second block in the same file. Give it the values the block needs as parameters; have it `return` what the block produced.
|
|
138
|
+
3. Replace **both** blocks with a call to the helper.
|
|
139
|
+
4. Nothing else changes — no new imports, no other files.
|
|
140
|
+
|
|
141
|
+
### Recipe 2 — move the block into the file that owns it
|
|
142
|
+
|
|
143
|
+
1. Decide which of the two files clearly owns the logic (e.g. formatting → `state-format.ts`).
|
|
144
|
+
2. In that file, add a **new exported** helper (or reuse one that already does exactly this). Adding a new export is fine; do **not** rename or change an existing export.
|
|
145
|
+
3. In the other file, import the helper and replace its block with a call.
|
|
146
|
+
4. Only these two files change.
|
|
147
|
+
|
|
148
|
+
### Recipe 3 — new shared file (only if neither file owns it)
|
|
149
|
+
|
|
150
|
+
1. Create `src/<descriptive-name>.ts` with the shared function exported:
|
|
151
|
+
```ts
|
|
152
|
+
export function sharedThing(/* params */) {
|
|
153
|
+
// the duplicated logic, once
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
2. At **each** clone site, import it and replace the block with a call:
|
|
157
|
+
```ts
|
|
158
|
+
import { sharedThing } from './descriptive-name.js'; // .js on purpose
|
|
159
|
+
```
|
|
160
|
+
3. Only three files change (new file + the two sites).
|
|
161
|
+
|
|
162
|
+
If you open the code and cannot see a clean way to extract it (for example the two ranges overlap, or the block depends on lots of surrounding variables), **do not force it** — restore your backup, go back to Step 3, and pick a different clone (or report that no safe fix was available).
|
|
163
|
+
|
|
164
|
+
### Style
|
|
165
|
+
|
|
166
|
+
- Match nearby naming: `camelCase` functions, `kebab-case` filenames.
|
|
167
|
+
- Relative imports use a **`.js`** extension even though the source is `.ts` (`import { x } from './foo.js'`). A new helper file must follow this.
|
|
168
|
+
- Add a comment only if the *why* is non-obvious; never one that just restates *what* the code does.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Step 6 — Verify (run in this order; fix or put it back)
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm run lint 2>&1
|
|
176
|
+
npm test 2>&1
|
|
177
|
+
npm run duplication 2>&1
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Check each, in order:
|
|
181
|
+
|
|
182
|
+
1. **Lint is no worse.** Look at the `✖ … problems (… errors, … warnings)` line again. **Errors and warnings must each be the same as Step 1 or lower — never higher.** A new error after a dedup is almost always a missing `.js` import extension or an import left unused after you deleted a block — fix it in your source file. Never silence anything with an `eslint-disable` comment.
|
|
183
|
+
2. **Tests pass.** If a test now fails, your change moved or renamed something a test relied on. Try the obvious fix in your source file (run lint first — a broken import shows up clearly there but as a confusing crash in tests). If it does not pass quickly, **restore your backups** (`cp src/foo.ts.bak src/foo.ts`, and delete any new file you created) and report what blocked you. Never edit a test to make it pass.
|
|
184
|
+
3. **Duplication went down.** In the new `npm run duplication` output, **the clone you targeted must be gone**, and the `Total:` row percentage must be the same or lower than Step 1 — never higher. If your clone still appears, you updated only one of the two sides; fix the other.
|
|
185
|
+
|
|
186
|
+
When all three pass, **delete the backup file(s)**: `rm src/foo.ts.bak`.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Step 7 — Report
|
|
191
|
+
|
|
192
|
+
Give the user a short report in this exact shape:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
Clone removed: <file A> [lines] ↔ <file B> [lines]
|
|
196
|
+
Fix: <one sentence — e.g. "extracted buildTabState() into tab-state.ts">
|
|
197
|
+
Duplication: <before %> -> <after %> (clones: <before N> -> <after N>)
|
|
198
|
+
Lint: <before E errors, W warnings> -> <after>
|
|
199
|
+
Tests: all pass / <what failed>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Keep it brief. Done.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Update a Package (one package per run)
|
|
2
|
+
|
|
3
|
+
Your job: update **one** npm package to the latest version its existing `package.json` range allows, fix any code that breaks, and prove the project is still green. Do exactly one package, then verify. Follow the steps **in order, exactly as written** — do not skip a step or combine steps.
|
|
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
|
+
**Run autonomously.** This task runs unattended — do not ask the user questions or wait for feedback at any step. Only stop early for the conditions explicitly listed below.
|
|
14
|
+
|
|
15
|
+
The rule is simple: **the compiler, the linter, and the tests must be green before you start and green again after you finish.** If not green before you start, stop and tell the user. If you can't get it green again after two fix attempts, put the package back and stop.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Step 0 — Prepare the workspace
|
|
20
|
+
|
|
21
|
+
Execute `ai/tasks/prepare-workspace.md` in full before doing anything else.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Step 1 — Confirm the project is green
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx tsc --noEmit 2>&1
|
|
29
|
+
npm run lint 2>&1
|
|
30
|
+
npm test 2>&1
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
All three must pass: compiler has no errors, lint has no errors (warnings are fine), every test passes.
|
|
34
|
+
|
|
35
|
+
**If any of the three is not green, STOP and tell the user.** Do not proceed.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 2 — List outdated packages
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm outdated 2>&1
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
A non-zero exit code here is normal and expected when it lists rows — it is not a failure.
|
|
46
|
+
|
|
47
|
+
**If it prints nothing, report "No outdated packages found" and stop.**
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 3 — Pick one package (mechanical, no judgment needed)
|
|
52
|
+
|
|
53
|
+
`npm outdated` prints a table with columns `Package`, `Current`, `Wanted`, `Latest`.
|
|
54
|
+
|
|
55
|
+
1. Look only at rows where `Current` and `Wanted` are **different**. Ignore the `Latest` column entirely — you are never bumping the version range in `package.json` in this task, only updating within the range it already allows.
|
|
56
|
+
2. Take the **first such row, top to bottom**. That is your package.
|
|
57
|
+
3. If you already tried this exact package earlier in this run (see Step 6), skip it and take the next row instead.
|
|
58
|
+
4. If no row has `Current` different from `Wanted` (every remaining row only differs in `Latest`), report "No in-range updates available" plus the full `npm outdated` output, and stop.
|
|
59
|
+
|
|
60
|
+
State your pick in one line: `<package> <Current> -> <Wanted>`.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Step 4 — Install the update
|
|
65
|
+
|
|
66
|
+
Back up the manifest and lock file (this step rewrites both):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cp package.json package.json.bak
|
|
70
|
+
cp package-lock.json package-lock.json.bak
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Install:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm update <package>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
(`npm update` moves the package to `Wanted` without changing the version range in `package.json`.)
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Step 5 — Re-check, fix, repeat (max 2 attempts)
|
|
84
|
+
|
|
85
|
+
Run:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx tsc --noEmit 2>&1
|
|
89
|
+
npm run lint 2>&1
|
|
90
|
+
npm test 2>&1
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**All three green →** delete the backups (`rm package.json.bak package-lock.json.bak`) and go to Step 7.
|
|
94
|
+
|
|
95
|
+
**Not all green →** this is attempt 1 of at most 2:
|
|
96
|
+
|
|
97
|
+
1. Read the compiler's error output first — it names the file, line, and the missing/changed symbol. That is almost always enough to know what to fix. Only look inside `node_modules/<package>` for the current type definitions if the compiler message alone isn't enough to tell you the new shape.
|
|
98
|
+
2. Edit only the files the errors point at. Do not touch anything else.
|
|
99
|
+
3. Re-run the three commands above.
|
|
100
|
+
4. If still not green, make **one more** attempt (attempt 2 of 2), same process.
|
|
101
|
+
5. If still not green after attempt 2, go to Step 6 (revert).
|
|
102
|
+
|
|
103
|
+
If all three are green at any point in this loop, delete the backups and go to Step 7.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 6 — Revert (only if Step 5 never went green)
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cp package.json.bak package.json
|
|
111
|
+
cp package-lock.json.bak package-lock.json
|
|
112
|
+
npm install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
If this is the **first** package you've reverted this run, go back to Step 3 and pick the next candidate. If this is the **second** package you've reverted this run, stop — report both packages tried and why each was reverted.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Step 7 — Merge the change to master
|
|
120
|
+
|
|
121
|
+
Execute `ai/tasks/merge-change-to-master.md` in full. That document owns the merge workflow — follow its steps without deviation. Use commit type `build`, unless the code fixes from Step 5 are large enough that `fix` describes the change better.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Step 8 — Report
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Package: <name> <old-version> -> <new-version>
|
|
129
|
+
Code changes: <files touched to fix API changes, or "none needed">
|
|
130
|
+
Compiler: green
|
|
131
|
+
Lint: green
|
|
132
|
+
Tests: green
|
|
133
|
+
PR: <url> (#<number>)
|
|
134
|
+
Status: merged
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If you stopped early (nothing outdated, no in-range update available, or both attempts reverted), report that in one or two sentences plus the full `npm outdated` output. Keep it brief. Done.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "janissary",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "A terminal UI shell with built-in commands and shell execution",
|
|
5
5
|
"bin": {
|
|
6
6
|
"janus": "./bin/janus.mjs"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"check:full": "npm run typecheck && npm run lint && npm run test && npm run lint:css && npm run quality && npm run duplication && npm run knip",
|
|
29
29
|
"lint:files": "node scripts/lint-files.mjs",
|
|
30
30
|
"format": "prettier --write .",
|
|
31
|
-
"postinstall": "
|
|
31
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
32
32
|
"playwright:install-chromium": "npx playwright install chromium",
|
|
33
33
|
"test:server": "vitest run --project server",
|
|
34
34
|
"test:watch": "vitest --project server --project client",
|
|
@@ -79,11 +79,13 @@
|
|
|
79
79
|
"@vitejs/plugin-vue": "^6.0.7"
|
|
80
80
|
},
|
|
81
81
|
"files": [
|
|
82
|
+
"ai",
|
|
82
83
|
"bin",
|
|
83
84
|
"dist",
|
|
84
85
|
"chrome-extension",
|
|
85
86
|
"agent-names.json",
|
|
86
|
-
"help.md"
|
|
87
|
+
"help.md",
|
|
88
|
+
"scripts"
|
|
87
89
|
],
|
|
88
90
|
"type": "module",
|
|
89
91
|
"dependencies": {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Detect changed files in the working tree (uncommitted + untracked).
|
|
3
|
+
// Used by lint-files, check-diff, and other dev tools.
|
|
4
|
+
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line unicorn/no-exports-in-scripts
|
|
8
|
+
export function changedFiles() {
|
|
9
|
+
try {
|
|
10
|
+
// No explicit paths: everything not yet committed. `git diff HEAD` covers both
|
|
11
|
+
// staged and unstaged changes; `--diff-filter=d` drops deletions (can't lint a gone
|
|
12
|
+
// file); `ls-files --others --exclude-standard` adds new, non-ignored files.
|
|
13
|
+
const fromGit = (command, commandArguments) =>
|
|
14
|
+
execFileSync(command, commandArguments, { encoding: 'utf8' }).split('\n').filter(Boolean);
|
|
15
|
+
const changed = fromGit('git', ['diff', '--name-only', '--diff-filter=d', 'HEAD']);
|
|
16
|
+
const untracked = fromGit('git', ['ls-files', '--others', '--exclude-standard']);
|
|
17
|
+
return [...new Set([...changed, ...untracked])];
|
|
18
|
+
} catch {
|
|
19
|
+
// No git or no HEAD (fresh clone, initial commit): treat as no changes.
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|