projectstore-claude 0.28.2 → 0.29.1
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/README.md +3 -1
- package/bin/projectstore-claude.mjs +14 -9
- 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 +2 -2
- package/node_modules/projectstore/commands/review.md +1 -1
- package/node_modules/projectstore/harnesses/claude-code.json +20 -2
- package/node_modules/projectstore/harnesses/codex.json +24 -4
- package/node_modules/projectstore/hooks/pre-compact.mjs +2 -1
- package/node_modules/projectstore/hooks/session-rules.mjs +19 -7
- package/node_modules/projectstore/hooks/session-start.mjs +20 -18
- package/node_modules/projectstore/package.json +2 -2
- package/node_modules/projectstore/scripts/binding.mjs +3 -3
- package/node_modules/projectstore/scripts/build-adapters.mjs +51 -18
- package/node_modules/projectstore/scripts/cli.mjs +176 -29
- package/node_modules/projectstore/scripts/codemap.mjs +2 -2
- package/node_modules/projectstore/scripts/doctor.mjs +110 -58
- package/node_modules/projectstore/scripts/draft.mjs +4 -3
- package/node_modules/projectstore/scripts/graph.mjs +3 -2
- package/node_modules/projectstore/scripts/harness.mjs +89 -0
- package/node_modules/projectstore/scripts/install-harness.mjs +336 -93
- package/node_modules/projectstore/scripts/kanban.mjs +3 -2
- package/node_modules/projectstore/scripts/lib.mjs +69 -8
- package/node_modules/projectstore/scripts/mcp.mjs +2 -2
- package/node_modules/projectstore/scripts/query.mjs +2 -1
- package/node_modules/projectstore/scripts/reconcile.mjs +4 -3
- package/node_modules/projectstore/scripts/story-section.mjs +2 -1
- package/node_modules/projectstore/scripts/surfaces.mjs +2 -1
- package/node_modules/projectstore/scripts/term.mjs +149 -0
- package/node_modules/projectstore/scripts/touch-session.mjs +6 -1
- package/node_modules/projectstore/scripts/worktree.mjs +12 -7
- package/package.json +2 -2
|
@@ -217,6 +217,8 @@ function ranked(env, dir) {
|
|
|
217
217
|
// process.env to impersonate a harness needs the next call to look again.
|
|
218
218
|
export function resetDetection() {
|
|
219
219
|
_detected = null;
|
|
220
|
+
_speaking = null;
|
|
221
|
+
_bundling = undefined;
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
// Which harnesses this PROJECT uses — by directory (install spec, contract
|
|
@@ -247,6 +249,93 @@ export function activeHarness(env = process.env, dir = MANIFEST_DIR) {
|
|
|
247
249
|
return loadHarness(detectHarnessId(env, dir), dir) || sourceHarness(dir);
|
|
248
250
|
}
|
|
249
251
|
|
|
252
|
+
// ─── Who a message is for (generation spec, contract 18) ───────────────
|
|
253
|
+
//
|
|
254
|
+
// The core prints for ONE harness at a time, and a command it names must be
|
|
255
|
+
// one that harness can run: `/projectstore:doctor` in Claude Code,
|
|
256
|
+
// `$projectstore-doctor` in Codex, where commands arrive as rendered skills.
|
|
257
|
+
// The form is manifest data; these functions only fill it in.
|
|
258
|
+
|
|
259
|
+
// How a harness calls one of our commands (kind "commands") or roles (kind
|
|
260
|
+
// "agents"): the surface's own `invocation` template, or — for a surface the
|
|
261
|
+
// generator renders as skills — its `rendered_name` filled into the skills'
|
|
262
|
+
// template. `*` names the family ("/projectstore:*"). Filled by split/join, so
|
|
263
|
+
// a `$` in a template is never read as a replacement pattern.
|
|
264
|
+
export function invocation(manifest, name, { kind = "commands", args = "" } = {}) {
|
|
265
|
+
// No manifest (a partial tarball): the bare name, never a throw in a hook.
|
|
266
|
+
const surfaces = manifest?.surfaces || {};
|
|
267
|
+
const s = surfaces[kind] || {};
|
|
268
|
+
let template = s.invocation || null;
|
|
269
|
+
if (!template && s.rendered_as === "skill" && s.rendered_name && surfaces.skills?.invocation) {
|
|
270
|
+
template = surfaces.skills.invocation.split("<name>").join(s.rendered_name);
|
|
271
|
+
}
|
|
272
|
+
const form = template ? template.split("<name>").join(name) : name;
|
|
273
|
+
return args ? `${form} ${args}` : form;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// The UI words a manifest declares (ui_vocabulary), as patterns. A word glued
|
|
277
|
+
// to a longer name or to a path is not the word: `/plugin-x` is not `/plugin`,
|
|
278
|
+
// and neither is the one in `.claude-plugin/plugin.json`; a full stop after it
|
|
279
|
+
// still ends a sentence. The generator's leak check and the vocabulary lint
|
|
280
|
+
// read these same patterns.
|
|
281
|
+
export function uiWordPatterns(manifest) {
|
|
282
|
+
const esc = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
283
|
+
return (manifest?.ui_vocabulary || []).map((word) => ({ word, re: new RegExp(`(?<![\\w.-])${esc(word)}(?![\\w-]|\\.\\w)`, "g") }));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// The harness whose distribution shell bundles this core, by the shell's
|
|
287
|
+
// package name: a shell installs the core at <shell>/node_modules/projectstore,
|
|
288
|
+
// and its package.json names it as a manifest's install.shell. A hook, a
|
|
289
|
+
// rendered skill's command and an npx run inside that tree all belong to that
|
|
290
|
+
// harness by construction — nothing to export, nothing a model can forget.
|
|
291
|
+
// A source checkout or a host's own cache of the core answers null.
|
|
292
|
+
let _bundling;
|
|
293
|
+
export function bundlingShellHarnessId({ core = REPO_ROOT, dir = MANIFEST_DIR } = {}) {
|
|
294
|
+
const memo = core === REPO_ROOT && dir === MANIFEST_DIR;
|
|
295
|
+
if (memo && _bundling !== undefined) return _bundling;
|
|
296
|
+
let id = null;
|
|
297
|
+
try {
|
|
298
|
+
const real = realOr(core);
|
|
299
|
+
const parent = dirname(real);
|
|
300
|
+
if (parent.split(sep).pop() === "node_modules") {
|
|
301
|
+
const name = JSON.parse(readFileSync(join(dirname(parent), "package.json"), "utf8")).name;
|
|
302
|
+
id = [...loadHarnesses(dir).values()].find((m) => m.install?.shell && m.install.shell === name)?.id ?? null;
|
|
303
|
+
}
|
|
304
|
+
} catch { id = null; }
|
|
305
|
+
if (memo) _bundling = id;
|
|
306
|
+
return id;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// The harness a message is FOR: forced (PROJECTSTORE_HARNESS); else the one
|
|
310
|
+
// that identifies itself — a strong signal or its session marker; else the
|
|
311
|
+
// shell that bundles this core; else the shell the environment names
|
|
312
|
+
// (PROJECTSTORE_SHELL, which only the shells set); else the source harness.
|
|
313
|
+
// `--harness <id>` names an install target and plays no part in this.
|
|
314
|
+
let _speaking = null;
|
|
315
|
+
export function speakingHarnessId(env = process.env, dir = MANIFEST_DIR) {
|
|
316
|
+
const memo = env === process.env && dir === MANIFEST_DIR;
|
|
317
|
+
if (memo && _speaking) return _speaking;
|
|
318
|
+
const id = speaker(env, dir);
|
|
319
|
+
if (memo) _speaking = id;
|
|
320
|
+
return id;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function speaker(env, dir) {
|
|
324
|
+
const identified = identifiedHarnessId(env, dir);
|
|
325
|
+
if (identified) return identified;
|
|
326
|
+
const bundled = bundlingShellHarnessId({ dir });
|
|
327
|
+
if (bundled) return bundled;
|
|
328
|
+
if (env.PROJECTSTORE_SHELL) {
|
|
329
|
+
const named = [...loadHarnesses(dir).values()].find((m) => m.install?.shell === env.PROJECTSTORE_SHELL);
|
|
330
|
+
if (named) return named.id;
|
|
331
|
+
}
|
|
332
|
+
return sourceHarness(dir)?.id ?? null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function speakingHarness(env = process.env, dir = MANIFEST_DIR) {
|
|
336
|
+
return loadHarness(speakingHarnessId(env, dir), dir) || sourceHarness(dir);
|
|
337
|
+
}
|
|
338
|
+
|
|
250
339
|
// ─── Runtime names and paths ───────────────────────────────────────────
|
|
251
340
|
|
|
252
341
|
// The three branded names the active harness uses, so a caller can say which
|