projectstore-claude 0.29.3 → 0.29.4

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 (53) hide show
  1. package/bin/projectstore-claude.mjs +1 -1
  2. package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
  3. package/node_modules/projectstore/.claude-plugin/plugin.json +1 -1
  4. package/node_modules/projectstore/README.md +17 -0
  5. package/node_modules/projectstore/commands/bind.md +6 -17
  6. package/node_modules/projectstore/commands/doctor.md +12 -7
  7. package/node_modules/projectstore/commands/statusline.md +1 -1
  8. package/node_modules/projectstore/commands/story.md +15 -2
  9. package/node_modules/projectstore/docs/how-it-works.md +5 -3
  10. package/node_modules/projectstore/harnesses/claude-code.json +5 -5
  11. package/node_modules/projectstore/harnesses/codex.json +4 -5
  12. package/node_modules/projectstore/hooks/band.tsx +48 -20
  13. package/node_modules/projectstore/hooks/pre-compact.mjs +7 -10
  14. package/node_modules/projectstore/hooks/session-rules.mjs +14 -8
  15. package/node_modules/projectstore/hooks/session-start.mjs +50 -18
  16. package/node_modules/projectstore/hooks/session-stop.mjs +8 -6
  17. package/node_modules/projectstore/package.json +11 -2
  18. package/node_modules/projectstore/scripts/band-shared.mjs +141 -24
  19. package/node_modules/projectstore/scripts/band.mjs +72 -21
  20. package/node_modules/projectstore/scripts/binding.mjs +616 -85
  21. package/node_modules/projectstore/scripts/build-adapters.mjs +73 -29
  22. package/node_modules/projectstore/scripts/cli.mjs +1015 -185
  23. package/node_modules/projectstore/scripts/codemap.mjs +22 -7
  24. package/node_modules/projectstore/scripts/convergence.mjs +253 -83
  25. package/node_modules/projectstore/scripts/diff-refs.mjs +14 -8
  26. package/node_modules/projectstore/scripts/doctor-report.mjs +91 -23
  27. package/node_modules/projectstore/scripts/doctor.mjs +1317 -371
  28. package/node_modules/projectstore/scripts/draft.mjs +5 -2
  29. package/node_modules/projectstore/scripts/fetch-shell.mjs +106 -20
  30. package/node_modules/projectstore/scripts/graph.mjs +19 -13
  31. package/node_modules/projectstore/scripts/harness.mjs +123 -48
  32. package/node_modules/projectstore/scripts/install-harness.mjs +3511 -616
  33. package/node_modules/projectstore/scripts/kanban.mjs +2 -1
  34. package/node_modules/projectstore/scripts/lib.mjs +694 -159
  35. package/node_modules/projectstore/scripts/mcp.mjs +386 -105
  36. package/node_modules/projectstore/scripts/portable-registration.mjs +224 -51
  37. package/node_modules/projectstore/scripts/provenance.mjs +26 -10
  38. package/node_modules/projectstore/scripts/query.mjs +378 -80
  39. package/node_modules/projectstore/scripts/reconcile.mjs +55 -18
  40. package/node_modules/projectstore/scripts/run-host.mjs +62 -17
  41. package/node_modules/projectstore/scripts/scaffold.mjs +89 -28
  42. package/node_modules/projectstore/scripts/setup.mjs +987 -0
  43. package/node_modules/projectstore/scripts/stages.mjs +5 -1
  44. package/node_modules/projectstore/scripts/statusline-launcher.mjs +36 -11
  45. package/node_modules/projectstore/scripts/statusline.mjs +32 -14
  46. package/node_modules/projectstore/scripts/story-section.mjs +39 -17
  47. package/node_modules/projectstore/scripts/surfaces.mjs +416 -95
  48. package/node_modules/projectstore/scripts/term.mjs +382 -97
  49. package/node_modules/projectstore/scripts/tokens.mjs +106 -28
  50. package/node_modules/projectstore/scripts/touch-session.mjs +109 -70
  51. package/node_modules/projectstore/scripts/version-guard.mjs +74 -27
  52. package/node_modules/projectstore/scripts/worktree.mjs +16 -5
  53. package/package.json +2 -2
@@ -26,19 +26,27 @@ const SOURCE_UI = uiWordPatterns(SOURCE);
26
26
  // way only the source harness calls it. Never inside another form
27
27
  // (`/projectstore:`, `$projectstore-`), never a longer name.
28
28
  const ROLE_SUFFIX = SOURCE.surfaces.agents.file.replace("<name>", "");
29
- const SOURCE_ROLES = readdirSync(join(ROOT, SOURCE.surfaces.agents.dir)).filter((f) => f.endsWith(ROLE_SUFFIX)).map((f) => f.slice(0, -ROLE_SUFFIX.length)).sort();
30
- const SOURCE_ROLE = new RegExp(`(?<![\\w/$:-])${escapeRe(SOURCE.surfaces.agents.invocation.split("<name>")[0])}(${SOURCE_ROLES.map(escapeRe).join("|")})(?![\\w-])`, "g");
29
+ const SOURCE_ROLES = readdirSync(join(ROOT, SOURCE.surfaces.agents.dir))
30
+ .filter((f) => f.endsWith(ROLE_SUFFIX))
31
+ .map((f) => f.slice(0, -ROLE_SUFFIX.length))
32
+ .sort();
33
+ const SOURCE_ROLE = new RegExp(
34
+ `(?<![\\w/$:-])${escapeRe(SOURCE.surfaces.agents.invocation.split("<name>")[0])}(${SOURCE_ROLES.map(escapeRe).join("|")})(?![\\w-])`,
35
+ "g",
36
+ );
31
37
  const TARGETS = emittingHarnesses();
32
- if (TARGETS.length !== 1) throw new Error(`this renderer currently requires exactly one emitting harness; found ${TARGETS.length}`);
38
+ if (TARGETS.length !== 1)
39
+ throw new Error(`this renderer currently requires exactly one emitting harness; found ${TARGETS.length}`);
33
40
  const TARGET = TARGETS[0];
34
41
  const OUT = resolve(ROOT, TARGET.output_dir);
35
42
 
36
43
  const read = (p) => readFileSync(p, "utf8");
37
44
  const json = (p) => JSON.parse(read(p));
38
- const files = (dir, suffix = ".md") => readdirSync(dir)
39
- .filter((name) => name.endsWith(suffix))
40
- .sort()
41
- .map((name) => join(dir, name));
45
+ const files = (dir, suffix = ".md") =>
46
+ readdirSync(dir)
47
+ .filter((name) => name.endsWith(suffix))
48
+ .sort()
49
+ .map((name) => join(dir, name));
42
50
 
43
51
  function frontmatter(text, file) {
44
52
  const m = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
@@ -48,7 +56,8 @@ function frontmatter(text, file) {
48
56
  const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
49
57
  if (!kv) continue;
50
58
  let value = kv[2].trim();
51
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) value = value.slice(1, -1);
59
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")))
60
+ value = value.slice(1, -1);
52
61
  data[kv[1]] = value;
53
62
  }
54
63
  return { data, body: m[2].replace(/^\n+/, "") };
@@ -92,7 +101,8 @@ function skill(name, description, body, { runtime = true } = {}) {
92
101
 
93
102
  const COMMAND_OVERRIDES = {
94
103
  agents: {
95
- description: "Register or remove ProjectStore's shared agents block, inspect its Codex model overlay, or configure per-role models. Arguments: <register | unregister | status | configure>.",
104
+ description:
105
+ "Register or remove ProjectStore's shared agents block, inspect its Codex model overlay, or configure per-role models. Arguments: <register | unregister | status | configure>.",
96
106
  body: `You are managing ProjectStore's Codex agent integration. Require a bound project.
97
107
 
98
108
  ## register / unregister
@@ -122,7 +132,8 @@ contract. A configured model is consumed by the role-orchestration skills on
122
132
  their next spawn; no restart is needed.`,
123
133
  },
124
134
  bind: {
125
- description: "Bind this project to an existing ProjectStore vault, or initialize and bind a new vault, using the harness-neutral core. Arguments: [vault-path] [--layout <name>] [--language <code>].",
135
+ description:
136
+ "Bind this project to an existing ProjectStore vault, or initialize and bind a new vault, using the harness-neutral core. Arguments: [vault-path] [--layout <name>] [--language <code>].",
126
137
  body: `Bind the current project through the core; never write the binding by
127
138
  hand.
128
139
 
@@ -147,14 +158,16 @@ hand.
147
158
  --project "$PWD"\` and offer \`$projectstore-scaffold\` only when a row
148
159
  reads \`create\`.
149
160
 
150
- Codex plugin updates are performed with the \`projectstore-codex upgrade\`
151
- installer command; this skill never sends the user to another harness's plugin
152
- UI. Codex has no ProjectStore status-line surface, so binding does not offer or
153
- write one. Model choices, when requested, go through \`$projectstore-agents
154
- configure\` and the Codex overlay.`,
161
+ Codex plugin updates are the core's \`upgrade\` with \`--harness codex\`, which
162
+ the person runs from a terminal in this project; this skill never sends the
163
+ user to another harness's plugin UI.
164
+ Codex has no ProjectStore status-line surface, so binding does not offer or
165
+ write one. Model choices, when requested, go through
166
+ \`$projectstore-agents configure\` and the Codex overlay.`,
155
167
  },
156
168
  doctor: {
157
- description: "Diagnose the ProjectStore install and vault through the harness-neutral doctor; fixes remain previewed and approval-gated. Arguments: [--install | --vault] [--fix].",
169
+ description:
170
+ "Diagnose the ProjectStore install and vault through the harness-neutral doctor; fixes remain previewed and approval-gated. Arguments: [--install | --vault] [--fix].",
158
171
  body: `Run the deterministic doctor through the bundled core with the user's
159
172
  arguments and \`--json\`. Summarize every finding without re-deriving it.
160
173
 
@@ -168,7 +181,8 @@ surfaces remain unsupported; do not create host configuration by hand. Never
168
181
  claim a fix after a non-zero exit.`,
169
182
  },
170
183
  bar: {
171
- description: "Explain ProjectStore band availability for Codex. This surface is unsupported and the skill never writes configuration. Arguments: on | off | status | epic [<ID>].",
184
+ description:
185
+ "Explain ProjectStore band availability for Codex. This surface is unsupported and the skill never writes configuration. Arguments: on | off | status | epic [<ID>].",
172
186
  body: `ProjectStore's band above the prompt is not supported by the Codex
173
187
  harness: Codex has no surface that draws above the prompt and no module
174
188
  runtime to draw it. Do not run the band verb's writes and do not edit project
@@ -176,7 +190,8 @@ or host configuration. Report the surface as unsupported. For project state
176
190
  use \`$projectstore-status\`.`,
177
191
  },
178
192
  statusline: {
179
- description: "Explain ProjectStore status-line availability for Codex. This surface is unsupported and the skill never writes configuration. Arguments: on | off | status.",
193
+ description:
194
+ "Explain ProjectStore status-line availability for Codex. This surface is unsupported and the skill never writes configuration. Arguments: on | off | status.",
180
195
  body: `ProjectStore's status-line surface is not supported by the Codex
181
196
  harness. Do not run install or uninstall for \`--surface statusline\`, and do
182
197
  not edit project or host configuration. Report the surface as unsupported.
@@ -203,7 +218,10 @@ function renderCommand(file) {
203
218
  const override = COMMAND_OVERRIDES[verb];
204
219
  if (override) return [join("skills", name, "SKILL.md"), skill(name, override.description, override.body)];
205
220
  const hint = data["argument-hint"] ? ` Arguments: ${data["argument-hint"]}.` : "";
206
- return [join("skills", name, "SKILL.md"), skill(name, `${data.description || `Run the ProjectStore ${verb} workflow.`}${hint}`, body)];
221
+ return [
222
+ join("skills", name, "SKILL.md"),
223
+ skill(name, `${data.description || `Run the ProjectStore ${verb} workflow.`}${hint}`, body),
224
+ ];
207
225
  }
208
226
 
209
227
  function renderPassive(file) {
@@ -219,8 +237,10 @@ function renderRole(file) {
219
237
  const role = file.split("/").pop().replace(/\.md$/, "");
220
238
  const name = renderedName("agents", role);
221
239
  const orchestration = `## Codex orchestration\n\nThis is a role-orchestration skill, not a native agent registration. Resolve the\nrole model by running:\n\n\`\`\`bash\nnode "\${PROJECTSTORE_CORE_ROOT}/bin/projectstore.mjs" agents model ${role} --json --project "$PWD"\n\`\`\`\n\nSpawn a collaboration agent for the bounded task. If the result names a model,\npass that model and use an empty or bounded context fork; otherwise inherit the\ncurrent model. Do not pass a reasoning-effort override: per-role effort belongs\nto a separate accepted story. Give the spawned agent the role contract below\nand the exact artifact/diff it must inspect. Wait for its final result.\n\n## Role contract\n\n`;
222
- const description = (data.description || `Run the ProjectStore ${role} role in a fresh collaboration agent.`)
223
- .replace(/^(?:Opus|Sonnet) \(max-effort\)\s+/, "");
240
+ const description = (data.description || `Run the ProjectStore ${role} role in a fresh collaboration agent.`).replace(
241
+ /^(?:Opus|Sonnet) \(max-effort\)\s+/,
242
+ "",
243
+ );
224
244
  return [join("skills", name, "SKILL.md"), skill(name, description, orchestration + body)];
225
245
  }
226
246
 
@@ -234,12 +254,15 @@ export function renderHooks(manifest, root = ROOT) {
234
254
  for (const group of post) if (group.matcher) group.matcher = (manifest.tools?.write_tools || []).join("|");
235
255
  const rewrite = (value) => {
236
256
  if (Array.isArray(value)) return value.map(rewrite);
237
- if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, rewrite(v)]));
257
+ if (value && typeof value === "object")
258
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, rewrite(v)]));
238
259
  if (typeof value !== "string") return value;
239
260
  const sourceRoot = "${" + SOURCE.runtime.plugin_root_env + "}";
240
261
  const targetRoot = "${" + manifest.runtime.plugin_root_env + "}";
241
262
  const command = value.startsWith(`node ${sourceRoot}/`) ? value.slice(`node ${sourceRoot}/`.length) : null;
242
- return command ? `node "${targetRoot}/node_modules/projectstore/${command}"` : value.replaceAll(sourceRoot, `${targetRoot}/node_modules/projectstore`);
263
+ return command
264
+ ? `node "${targetRoot}/node_modules/projectstore/${command}"`
265
+ : value.replaceAll(sourceRoot, `${targetRoot}/node_modules/projectstore`);
243
266
  };
244
267
  const text = JSON.stringify(rewrite(source), null, 2) + "\n";
245
268
  return [join("hooks", "hooks.json"), text];
@@ -247,7 +270,8 @@ export function renderHooks(manifest, root = ROOT) {
247
270
 
248
271
  export function renderCodexAdapter(root = ROOT) {
249
272
  const manifest = json(join(root, "harnesses", `${TARGET.id}.json`));
250
- if (!manifest.emit || !manifest.output_dir) throw new Error(`${TARGET.id} must declare an output_dir when emit is true`);
273
+ if (!manifest.emit || !manifest.output_dir)
274
+ throw new Error(`${TARGET.id} must declare an output_dir when emit is true`);
251
275
  const rows = [
252
276
  ...files(join(root, "commands")).map(renderCommand),
253
277
  ...files(join(root, "agents")).map(renderRole),
@@ -259,15 +283,34 @@ export function renderCodexAdapter(root = ROOT) {
259
283
  ];
260
284
  const out = new Map();
261
285
  for (const [rel, text] of rows) {
262
- if (rel.startsWith("..") || resolve(OUT, rel).slice(0, OUT.length + 1) !== OUT + "/") throw new Error(`adapter path escapes output root: ${rel}`);
286
+ if (rel.startsWith("..") || resolve(OUT, rel).slice(0, OUT.length + 1) !== OUT + "/")
287
+ throw new Error(`adapter path escapes output root: ${rel}`);
263
288
  if (out.has(rel)) throw new Error(`adapter collision: ${rel}`);
264
289
  out.set(rel, text);
265
290
  }
266
291
  for (const [rel, text] of out) {
267
- const sourceTokens = [SOURCE.runtime.plugin_root_env, SOURCE.runtime.project_dir_env, SOURCE.display_name, SOURCE.runtime.harness_dir + "/"].filter(Boolean);
292
+ const sourceTokens = [
293
+ SOURCE.runtime.plugin_root_env,
294
+ SOURCE.runtime.project_dir_env,
295
+ SOURCE.display_name,
296
+ SOURCE.runtime.harness_dir + "/",
297
+ ].filter(Boolean);
268
298
  const sourceAgentEnvs = (SOURCE.runtime.agent_overrides || []).map((row) => row.env).filter(Boolean);
269
- if (sourceTokens.some((token) => text.includes(token)) || sourceAgentEnvs.some((token) => text.includes(token)) || text.includes(SOURCE_COMMAND_PREFIX) || new RegExp(SOURCE_ROLE.source).test(text) || /\$ARGUMENTS/.test(text)) throw new Error(`${rel}: source-harness vocabulary leaked into ${TARGET.display_name} adapter`);
270
- if (SOURCE_UI.some(({ re }) => new RegExp(re.source).test(text)) || /harness\/codex-code\.json|\b(?:opus|sonnet|fable)\b/i.test(text)) throw new Error(`${rel}: source-harness model, environment or UI semantics leaked into ${TARGET.display_name} adapter`);
299
+ if (
300
+ sourceTokens.some((token) => text.includes(token)) ||
301
+ sourceAgentEnvs.some((token) => text.includes(token)) ||
302
+ text.includes(SOURCE_COMMAND_PREFIX) ||
303
+ new RegExp(SOURCE_ROLE.source).test(text) ||
304
+ /\$ARGUMENTS/.test(text)
305
+ )
306
+ throw new Error(`${rel}: source-harness vocabulary leaked into ${TARGET.display_name} adapter`);
307
+ if (
308
+ SOURCE_UI.some(({ re }) => new RegExp(re.source).test(text)) ||
309
+ /harness\/codex-code\.json|\b(?:opus|sonnet|fable)\b/i.test(text)
310
+ )
311
+ throw new Error(
312
+ `${rel}: source-harness model, environment or UI semantics leaked into ${TARGET.display_name} adapter`,
313
+ );
271
314
  }
272
315
  return out;
273
316
  }
@@ -313,4 +356,5 @@ function main(argv) {
313
356
  return result.ok ? 0 : 1;
314
357
  }
315
358
 
316
- if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) process.exitCode = main(process.argv.slice(2));
359
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url))
360
+ process.exitCode = main(process.argv.slice(2));