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.
- package/bin/projectstore-claude.mjs +1 -1
- package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
- package/node_modules/projectstore/.claude-plugin/plugin.json +1 -1
- package/node_modules/projectstore/README.md +17 -0
- package/node_modules/projectstore/commands/bind.md +6 -17
- package/node_modules/projectstore/commands/doctor.md +12 -7
- package/node_modules/projectstore/commands/statusline.md +1 -1
- package/node_modules/projectstore/commands/story.md +15 -2
- package/node_modules/projectstore/docs/how-it-works.md +5 -3
- package/node_modules/projectstore/harnesses/claude-code.json +5 -5
- package/node_modules/projectstore/harnesses/codex.json +4 -5
- package/node_modules/projectstore/hooks/band.tsx +48 -20
- package/node_modules/projectstore/hooks/pre-compact.mjs +7 -10
- package/node_modules/projectstore/hooks/session-rules.mjs +14 -8
- package/node_modules/projectstore/hooks/session-start.mjs +50 -18
- package/node_modules/projectstore/hooks/session-stop.mjs +8 -6
- package/node_modules/projectstore/package.json +11 -2
- package/node_modules/projectstore/scripts/band-shared.mjs +141 -24
- package/node_modules/projectstore/scripts/band.mjs +72 -21
- package/node_modules/projectstore/scripts/binding.mjs +616 -85
- package/node_modules/projectstore/scripts/build-adapters.mjs +73 -29
- package/node_modules/projectstore/scripts/cli.mjs +1015 -185
- package/node_modules/projectstore/scripts/codemap.mjs +22 -7
- package/node_modules/projectstore/scripts/convergence.mjs +253 -83
- package/node_modules/projectstore/scripts/diff-refs.mjs +14 -8
- package/node_modules/projectstore/scripts/doctor-report.mjs +91 -23
- package/node_modules/projectstore/scripts/doctor.mjs +1317 -371
- package/node_modules/projectstore/scripts/draft.mjs +5 -2
- package/node_modules/projectstore/scripts/fetch-shell.mjs +106 -20
- package/node_modules/projectstore/scripts/graph.mjs +19 -13
- package/node_modules/projectstore/scripts/harness.mjs +123 -48
- package/node_modules/projectstore/scripts/install-harness.mjs +3511 -616
- package/node_modules/projectstore/scripts/kanban.mjs +2 -1
- package/node_modules/projectstore/scripts/lib.mjs +694 -159
- package/node_modules/projectstore/scripts/mcp.mjs +386 -105
- package/node_modules/projectstore/scripts/portable-registration.mjs +224 -51
- package/node_modules/projectstore/scripts/provenance.mjs +26 -10
- package/node_modules/projectstore/scripts/query.mjs +378 -80
- package/node_modules/projectstore/scripts/reconcile.mjs +55 -18
- package/node_modules/projectstore/scripts/run-host.mjs +62 -17
- package/node_modules/projectstore/scripts/scaffold.mjs +89 -28
- package/node_modules/projectstore/scripts/setup.mjs +987 -0
- package/node_modules/projectstore/scripts/stages.mjs +5 -1
- package/node_modules/projectstore/scripts/statusline-launcher.mjs +36 -11
- package/node_modules/projectstore/scripts/statusline.mjs +32 -14
- package/node_modules/projectstore/scripts/story-section.mjs +39 -17
- package/node_modules/projectstore/scripts/surfaces.mjs +416 -95
- package/node_modules/projectstore/scripts/term.mjs +382 -97
- package/node_modules/projectstore/scripts/tokens.mjs +106 -28
- package/node_modules/projectstore/scripts/touch-session.mjs +109 -70
- package/node_modules/projectstore/scripts/version-guard.mjs +74 -27
- package/node_modules/projectstore/scripts/worktree.mjs +16 -5
- 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))
|
|
30
|
-
|
|
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)
|
|
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") =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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("'")))
|
|
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:
|
|
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:
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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 [
|
|
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
|
-
|
|
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")
|
|
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
|
|
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)
|
|
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 + "/")
|
|
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 = [
|
|
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 (
|
|
270
|
-
|
|
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))
|
|
359
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url))
|
|
360
|
+
process.exitCode = main(process.argv.slice(2));
|