projectstore-claude 0.29.1 → 0.29.3

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 (57) hide show
  1. package/README.md +2 -1
  2. package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
  3. package/node_modules/projectstore/.claude-plugin/plugin.json +2 -1
  4. package/node_modules/projectstore/README.md +37 -9
  5. package/node_modules/projectstore/commands/bar.md +30 -0
  6. package/node_modules/projectstore/commands/bind.md +14 -7
  7. package/node_modules/projectstore/commands/scaffold.md +24 -16
  8. package/node_modules/projectstore/commands/status.md +1 -1
  9. package/node_modules/projectstore/commands/statusline.md +1 -1
  10. package/node_modules/projectstore/docs/alongside.md +167 -0
  11. package/node_modules/projectstore/docs/extending.md +17 -3
  12. package/node_modules/projectstore/docs/getting-started.md +18 -9
  13. package/node_modules/projectstore/docs/harnesses.md +1 -1
  14. package/node_modules/projectstore/docs/how-it-works.md +7 -0
  15. package/node_modules/projectstore/harnesses/claude-code.json +18 -3
  16. package/node_modules/projectstore/harnesses/codex.json +12 -1
  17. package/node_modules/projectstore/hooks/band-state.d.ts +44 -0
  18. package/node_modules/projectstore/hooks/band.tsx +594 -0
  19. package/node_modules/projectstore/hooks/hooks.json +1 -0
  20. package/node_modules/projectstore/hooks/session-start.mjs +6 -2
  21. package/node_modules/projectstore/package.json +2 -1
  22. package/node_modules/projectstore/scaffold/headings.json +8 -0
  23. package/node_modules/projectstore/scripts/band-shared.mjs +329 -0
  24. package/node_modules/projectstore/scripts/band.mjs +156 -0
  25. package/node_modules/projectstore/scripts/binding.mjs +157 -17
  26. package/node_modules/projectstore/scripts/build-adapters.mjs +26 -7
  27. package/node_modules/projectstore/scripts/cli.mjs +549 -180
  28. package/node_modules/projectstore/scripts/convergence.mjs +468 -0
  29. package/node_modules/projectstore/scripts/doctor-report.mjs +185 -0
  30. package/node_modules/projectstore/scripts/doctor.mjs +80 -62
  31. package/node_modules/projectstore/scripts/fetch-shell.mjs +283 -0
  32. package/node_modules/projectstore/scripts/harness.mjs +178 -7
  33. package/node_modules/projectstore/scripts/install-harness.mjs +1571 -257
  34. package/node_modules/projectstore/scripts/kanban.mjs +4 -20
  35. package/node_modules/projectstore/scripts/lib.mjs +269 -58
  36. package/node_modules/projectstore/scripts/portable-registration.mjs +68 -16
  37. package/node_modules/projectstore/scripts/query.mjs +83 -12
  38. package/node_modules/projectstore/scripts/run-host.mjs +94 -0
  39. package/node_modules/projectstore/scripts/scaffold.mjs +183 -0
  40. package/node_modules/projectstore/scripts/stages.mjs +80 -0
  41. package/node_modules/projectstore/scripts/statusline.mjs +25 -2
  42. package/node_modules/projectstore/scripts/surfaces.mjs +78 -13
  43. package/node_modules/projectstore/scripts/term.mjs +729 -39
  44. package/node_modules/projectstore/scripts/version-guard.mjs +5 -0
  45. package/node_modules/projectstore/templates/de/strings.json +63 -1
  46. package/node_modules/projectstore/templates/de/vault-readme.md.tmpl +13 -0
  47. package/node_modules/projectstore/templates/en/strings.json +63 -1
  48. package/node_modules/projectstore/templates/en/vault-readme.md.tmpl +13 -0
  49. package/node_modules/projectstore/templates/es/strings.json +63 -1
  50. package/node_modules/projectstore/templates/es/vault-readme.md.tmpl +13 -0
  51. package/node_modules/projectstore/templates/fr/strings.json +63 -1
  52. package/node_modules/projectstore/templates/fr/vault-readme.md.tmpl +13 -0
  53. package/node_modules/projectstore/templates/ru/strings.json +63 -1
  54. package/node_modules/projectstore/templates/ru/vault-readme.md.tmpl +13 -0
  55. package/node_modules/projectstore/templates/zh/strings.json +63 -1
  56. package/node_modules/projectstore/templates/zh/vault-readme.md.tmpl +13 -0
  57. package/package.json +2 -2
@@ -37,11 +37,7 @@ You should see `projectstore` (displayName) with prefix `projectstore`.
37
37
 
38
38
  ## First-time setup
39
39
 
40
- 1. **Pick a vault directory** — any folder where you want your project artifacts to live. Obsidian opens it natively. Git tracks it cleanly.
41
-
42
- ```bash
43
- mkdir -p ~/Documents/projects/my-project-vault
44
- ```
40
+ 1. **Pick a vault directory** — any folder where you want your project artifacts to live. Obsidian opens it natively. Git tracks it cleanly. There is nothing to create by hand: step 2 creates the vault when the folder does not exist yet or is empty.
45
41
 
46
42
  2. **Bind your current project to that vault**:
47
43
 
@@ -49,7 +45,15 @@ You should see `projectstore` (displayName) with prefix `projectstore`.
49
45
  /projectstore:bind ~/Documents/projects/my-project-vault
50
46
  ```
51
47
 
52
- This creates `.projectstore/projectstore.json` in your project root (machine-local, gitignored) — and then walks you through a short interview: gitignore entries → scaffold offer → agent registration in `CLAUDE.md` (recommended: Yes) → model preset for the review agents (the default `opus` is fine) → status line offer (you'll see a preview of the exact line). Every step shows what it wants to write and waits for your approval.
48
+ This creates `.projectstore/projectstore.json` in your project root (machine-local, gitignored) — and then walks you through a short interview: gitignore entries → scaffold offer → vault policy → agent registration in `CLAUDE.md` (recommended: Yes) → model preset for the review agents (the default `opus` is fine) → status line offer (you'll see a preview of the exact line). Every step shows what it wants to write and waits for your approval. When the folder is missing or empty, the interview offers to create the whole vault there through `init` — the directory, its own git repository, the layout's folders and their README indexes — and then has no scaffold to offer.
49
+
50
+ **From a terminal instead**, outside a session, one command creates the same vault and binds this project to it:
51
+
52
+ ```bash
53
+ npx projectstore init ~/Documents/projects/my-project-vault
54
+ ```
55
+
56
+ It skips the rest of the interview: no agents block, no status line, no vault policy, no model preset. A later `/projectstore:bind` on that project only reports "Already bound" — it does not run those steps either. Choose this path when you want the vault and the binding alone.
53
57
 
54
58
  **Working in a git worktree?** That config is gitignored, so a worktree of a bound checkout starts unbound and `/projectstore:*` will not run there. Session start says so and names the fix:
55
59
 
@@ -59,13 +63,17 @@ You should see `projectstore` (displayName) with prefix `projectstore`.
59
63
 
60
64
  It copies the binding of the checkout the worktree was forked from — same vault, shared and unchanged, no session state carried over — and skips the interview, since the parent already answered it.
61
65
 
62
- 3. **Scaffold the layout** if the vault is empty (bind offers this automatically):
66
+ 3. **Scaffold the layout** of a vault that was bound without its folders (bind offers this automatically; a vault `init` made already has them):
63
67
 
64
68
  ```
65
- /projectstore:scaffold engineering
69
+ /projectstore:scaffold
66
70
  ```
67
71
 
68
- Creates `adr/`, `specs/`, `epics/`, `research/`, `concepts/`, `meetings/`, `ops/`, `diagrams/` and a top-level `README.md`.
72
+ Creates whichever of `adr/`, `specs/`, `epics/`, `research/`, `concepts/`, `meetings/`, `ops/`, `diagrams/`, their `README.md` indexes and the top-level `README.md` are missing, in the vault's language, and never rewrites a file that is there. The layout is the binding's. From a terminal:
73
+
74
+ ```bash
75
+ npx projectstore scaffold --write
76
+ ```
69
77
 
70
78
  ## Daily flow
71
79
 
@@ -81,6 +89,7 @@ You should see `projectstore` (displayName) with prefix `projectstore`.
81
89
  /projectstore:codemap # epic ↔ code mapping view
82
90
  /projectstore:graph # vault link graph: nodes + typed edges
83
91
  /projectstore:agents status # routing block + model config state
92
+ /projectstore:bar status # the band above the prompt: on/off, a pinned epic, why it is not drawing
84
93
  ```
85
94
 
86
95
  ## How approval works
@@ -13,7 +13,7 @@ This page says which harnesses exist, how far each one is trusted, and what
13
13
 
14
14
  | Harness | id | Status | Verified | Surfaces installed |
15
15
  |---|---|---|---|---|
16
- | Claude Code | `claude-code` | **supported** | 2026-08-30 | hooks, commands, agents, skills, MCP, status line, agents block |
16
+ | Claude Code | `claude-code` | **supported** | 2026-08-30 | hooks, commands, agents, skills, MCP, status line, agents block; the band above the prompt (experimental until its own live run) |
17
17
  | Codex | `codex` | **experimental** | — | portable plugin, hooks, rendered workflow skills, agents block |
18
18
 
19
19
  **supported** means the manifest carries a `verified` block: a session id and a
@@ -134,6 +134,13 @@ has one, else `~/.claude/settings.json`), prints its output
134
134
  verbatim, and adds one `[PS#version] 📚 …` line above it (`statusline.position`:
135
135
  `above`/`below`). With no base command it renders a standalone line.
136
136
 
137
+ While this session's band above the prompt is drawing, the line gives way to
138
+ it: the band keeps a heartbeat file fresh in the session-state directory, and
139
+ the renderer leaves its own line out while that file is younger than 30 s —
140
+ the base HUD prints as it always does. A band that stops, or never starts
141
+ (an older Claude Code, modules switched off), lets the heartbeat go stale, and
142
+ the line is back on its own.
143
+
137
144
  ## Doctor and reconcile: the trust layer
138
145
 
139
146
  The vault's guarantees used to depend on everyone using the gated commands —
@@ -57,9 +57,14 @@
57
57
  }
58
58
  ],
59
59
  "session_env": [
60
- "CLAUDECODE"
60
+ "CLAUDECODE",
61
+ "CLAUDE_CODE_SESSION_ID"
61
62
  ],
62
- "session_env_reason": "set to 1 in every Bash tool of a live session (measured 2026-09-05, 2.1.261); detect_env names the variables a hook or plugin process receives, which a Bash tool does not — the two questions differ.",
63
+ "session_env_reason": "set to 1 in every Bash tool of a live session (measured 2026-09-05, 2.1.261); detect_env names the variables a hook or plugin process receives, which a Bash tool does not — the two questions differ. CLAUDE_CODE_SESSION_ID is set there too (measured 2026-10-10, 2.1.296).",
64
+ "session_id_env": "CLAUDE_CODE_SESSION_ID",
65
+ "session_id_env_reason": "the session's id in every Bash tool of a live session (measured 2026-10-10 and 2026-10-11, 2.1.296): the id the session-state files are keyed by, which `band status` needs to find this session's pointer and heartbeat (the band spec, contract 13). Read only through hostSessionId(), since scripts/ names no branded variable.",
66
+ "registration_defer_env": [],
67
+ "registration_defer_env_reason": "Empty: session_env already defers this harness's registration inside its own session (measured: the host's CLI and the session's exit rewrite the same settings files), and registrationDeferred reads both lists. Present on every manifest, an array, so an absent key is never a forgotten one (story: projectstore setup asks, shows one plan and installs every harness it finds, with the vault, rule 15).",
63
68
  "overlay": "claude-code",
64
69
  "overlay_reason": "the file under <project>/.projectstore/harness/ that carries this harness's agents block — the models, per agent, that plugin surfaces pass per invocation (ADR-008; the layout ADR decision 3)"
65
70
  },
@@ -246,6 +251,15 @@
246
251
  "scope_reason": "Claude Code loads the plugin's hooks.json from the plugin installation itself; per-project hooks live in settings, which projectstore does not write.",
247
252
  "registered_by": "plugin"
248
253
  },
254
+ "band": {
255
+ "supported": true,
256
+ "kind": "host",
257
+ "registered_by": "plugin",
258
+ "scope": "user",
259
+ "scope_reason": "Claude Code loads the band as a hooks module named under `modules` in the plugin's own hooks.json, from the plugin installation itself; nothing is written into a project to draw it.",
260
+ "verified": null,
261
+ "verified_reason": "null until a recorded live session (terminal and Desktop) observes it drawing, hiding during a question, and the status line yielding and coming back (the band spec, contract 15). The harness's own `verified` block predates the surface and does not cover it."
262
+ },
249
263
  "agents_block": {
250
264
  "supported": true,
251
265
  "kind": "shared",
@@ -385,7 +399,8 @@
385
399
  "-y accepts a marketplace-declared command; this marketplace declares none",
386
400
  "the project of a --scope local command is the process cwd; there is no --project flag",
387
401
  "a live session marks its Bash environment with CLAUDECODE=1 (not the plugin-root or project-dir variables, which reach hooks only); the registration defers on that marker",
388
- "`plugin update` at an unchanged version answers \"already at the latest version\" and copies nothing, even after `marketplace update`: a same-version content refresh is uninstall + install"
402
+ "`plugin update` at an unchanged version answers \"already at the latest version\" and copies nothing, even after `marketplace update`: a same-version content refresh is uninstall + install",
403
+ "2.1.296, 2026-10-10: the plugin of this directory marketplace loads in place from <dir>/<plugin_subdir> — the MCP server's argv, the slash commands' plugin root and the SessionStart hook all name it — while the registry row's installPath stays the cache copy the launcher renders; the SessionStart refresh therefore never demotes a launcher entry (install spec, contract 0 as amended 2026-10-10)"
389
404
  ]
390
405
  },
391
406
  "commands": {
@@ -29,7 +29,11 @@
29
29
  ],
30
30
  "shared_env_reason": "Codex sets Claude Code's plugin-root names too, for compatibility — measured in every one of the 759 captured hook payloads. Without declaring them, a Codex session scores a strong detection hit for claude-code, ties with codex, and loses the tie to manifest filename order. A variable two harnesses both set identifies neither, so these are demoted to weak for every manifest (generation spec, contract 1, amended 2026-09-08).",
31
31
  "session_env": [],
32
- "session_env_reason": "Deliberately empty, though measured. Codex's exec tool sets CODEX_THREAD_ID and CODEX_SESSION_ID in every command (measured 2026-10-05, codex-cli 0.160.0; CODEX_SANDBOX* depend on the sandbox mode), and CODEX_HOME never appeared in a hook environment. Declaring them would identify a session, but session_env also defers the registration and the layout move inside a session (insideHostSession), which would stop the doctor skill's upgrade --json fix from running there. Splitting identity from deferral is the question of *Codex hook contract measured in a live session* (PS-HARNESS); until then a core run from a rendered skill is identified by the shell that bundles it (generation spec, contract 18)."
32
+ "session_env_reason": "Deliberately empty, though measured. Codex's exec tool sets CODEX_THREAD_ID and CODEX_SESSION_ID in every command (measured 2026-10-05, codex-cli 0.160.0; CODEX_SANDBOX* depend on the sandbox mode), and CODEX_HOME never appeared in a hook environment. Declaring them would identify a session, but session_env also defers the registration and the layout move inside a session (insideHostSession), which would stop the doctor skill's upgrade --json fix from running there. Splitting identity from deferral is the question of *Codex hook contract measured in a live session* (PS-HARNESS); until then a core run from a rendered skill is identified by the shell that bundles it (generation spec, contract 18). The deferral half of that split is registration_defer_env below (the maintainer's decision of 2026-10-08).",
33
+ "registration_defer_env": [
34
+ "CODEX_THREAD_ID"
35
+ ],
36
+ "registration_defer_env_reason": "Defers this harness's registration, and the shell fetch that would feed it, and nothing else (harness.mjs registrationDeferred): install, upgrade and setup leave the registration for a terminal outside the session, and so does uninstall --global's removal, which runs the same host CLI against the same CODEX_HOME. Codex's exec tool sets CODEX_THREAD_ID in every command (measured 2026-10-05, codex-cli 0.160.0; session_env_reason above). Whether a Codex session rewrites config.toml at exit is not measured; the maintainer chose deferral on 2026-10-08, answering the front-door ADR's first open question (story: projectstore setup asks, shows one plan and installs every harness it finds, with the vault, rule 15). isInteractive, the layout move and session identity do not read this key, so the doctor skill's upgrade --json still moves the layout inside a session. Lifting the deferral needs a measurement of its own."
33
37
  },
34
38
  "tools": {
35
39
  "write_tools": [
@@ -242,6 +246,13 @@
242
246
  "scope_reason": "There is no per-project status-line slot to occupy: Codex has no status-line surface at all, so nothing of ours is written anywhere and the scope is the host's, not a file's.",
243
247
  "why_unsupported": "No status-line mechanism was found in the harness — no settings slot, no plugin field, no handler contract. Recorded as a row rather than an absence so the generator's coverage invariant sees a stated omission (contract 9) instead of a surface that quietly does not exist here."
244
248
  },
249
+ "band": {
250
+ "supported": false,
251
+ "kind": "host",
252
+ "scope": "user",
253
+ "scope_reason": "There is no surface above the prompt to draw into: nothing of ours is written anywhere, so the scope is the host's, not a file's.",
254
+ "why_unsupported": "Codex has no plugin surface that draws above the prompt and no hooks module runtime. The generator drops the module from this tree's hooks.json and renders the bar command as a skill that says so (the band spec, contract 1)."
255
+ },
245
256
  "plugin": {
246
257
  "supported": true,
247
258
  "kind": "registration",
@@ -0,0 +1,44 @@
1
+ // projectstore — the band's values in the host's session state ($.state):
2
+ // what hooks/band.tsx draws from. Named in .claude-plugin/plugin.json under
3
+ // "types", so `claude plugin validate` holds every key the module names to it.
4
+
5
+ export type BandCounts = { done: number; active: number; backlog: number }
6
+
7
+ // The epic the band shows and everything its rows need, written by the
8
+ // module's clock only when it changed (a write redraws the band).
9
+ export type BandView = {
10
+ id: string
11
+ title: string
12
+ goal: string
13
+ // null until the stories have been read whole once: no progress row.
14
+ counts: BandCounts | null
15
+ why: 'this' | 'pinned'
16
+ story: { title: string; status: string | null } | null
17
+ version: string | null
18
+ hint: boolean
19
+ words: Record<string, string>
20
+ }
21
+
22
+ export type BandAgentStatus = 'running' | 'done' | 'error'
23
+
24
+ // A ProjectStore agent this session spawned: its role, the model and effort
25
+ // its own requests name, and the vault document its prompt names.
26
+ export type BandAgent = {
27
+ id: string
28
+ role: string
29
+ model: string
30
+ effort: string | null
31
+ subject: string | null
32
+ description: string
33
+ status: BandAgentStatus
34
+ startedAt: number
35
+ endedAt?: number
36
+ }
37
+
38
+ declare module 'claude-code' {
39
+ interface PluginState {
40
+ // `steps` is apart from `crew` on purpose: only the terminal's band reads
41
+ // it, so an agent's every step never redraws Desktop's drawing.
42
+ projectstore: { band: BandView | null; crew: BandAgent[]; steps: Record<string, string> }
43
+ }
44
+ }