@mickey-kras/hindsight-memory-router-coding-agents 0.8.9 → 0.8.14

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 (59) hide show
  1. package/dist/antigravity-hook.js +70 -24
  2. package/dist/antigravity-statusline.js +60 -14
  3. package/dist/antigravity-stop-hook.js +70 -24
  4. package/dist/claude-hook.js +70 -24
  5. package/dist/claude-sessionstart-hook.js +70 -24
  6. package/dist/claude-stop-hook.js +70 -24
  7. package/dist/cline.js +70 -24
  8. package/dist/codebuddy-hook.js +70 -24
  9. package/dist/codebuddy-sessionstart-hook.js +70 -24
  10. package/dist/codebuddy-stop-hook.js +70 -24
  11. package/dist/codex-hook.js +70 -24
  12. package/dist/codex-sessionstart-hook.js +70 -24
  13. package/dist/codex-stop-hook.js +70 -24
  14. package/dist/copilot-hook.js +70 -24
  15. package/dist/copilot-sessionstart-hook.js +70 -24
  16. package/dist/copilot-stop-hook.js +70 -24
  17. package/dist/cursor-hook.js +70 -24
  18. package/dist/cursor-sessionstart-hook.js +70 -24
  19. package/dist/cursor-stop-hook.js +70 -24
  20. package/dist/dcode-hook.js +70 -24
  21. package/dist/dcode-sessionstart-hook.js +70 -24
  22. package/dist/dcode-stop-hook.js +70 -24
  23. package/dist/deepen.js +70 -68
  24. package/dist/devin-hook.js +70 -24
  25. package/dist/devin-sessionstart-hook.js +70 -24
  26. package/dist/devin-stop-hook.js +70 -24
  27. package/dist/droid-hook.js +70 -24
  28. package/dist/droid-sessionstart-hook.js +70 -24
  29. package/dist/droid-stop-hook.js +70 -24
  30. package/dist/dsh.js +70 -24
  31. package/dist/grok-hook.js +70 -24
  32. package/dist/grok-sessionstart-hook.js +70 -24
  33. package/dist/grok-stop-hook.js +70 -24
  34. package/dist/hindsight-seed.js +60 -14
  35. package/dist/index.js +70 -24
  36. package/dist/installer.js +70 -21
  37. package/dist/kilo.js +70 -24
  38. package/dist/kimi-hook.js +70 -24
  39. package/dist/kimi-sessionstart-hook.js +70 -24
  40. package/dist/kimi-stop-hook.js +70 -24
  41. package/dist/mcp-server.js +79 -24
  42. package/dist/opencode2.js +70 -24
  43. package/dist/pi.js +70 -24
  44. package/dist/prime-agent.js +70 -24
  45. package/dist/qwen-hook.js +70 -24
  46. package/dist/qwen-sessionstart-hook.js +70 -24
  47. package/dist/qwen-stop-hook.js +70 -24
  48. package/dist/status.js +70 -24
  49. package/dist/traecode-hook.js +70 -24
  50. package/dist/traecode-sessionstart-hook.js +70 -24
  51. package/dist/traecode-stop-hook.js +70 -24
  52. package/dist/workbuddy-hook.js +70 -24
  53. package/dist/workbuddy-sessionstart-hook.js +70 -24
  54. package/dist/workbuddy-stop-hook.js +70 -24
  55. package/dist/zcode-hook.js +70 -24
  56. package/dist/zcode-sessionstart-hook.js +70 -24
  57. package/dist/zcode-stop-hook.js +70 -24
  58. package/npm-shrinkwrap.json +257 -711
  59. package/package.json +8 -5
@@ -36,12 +36,10 @@ function requireBank(access, bank, operation) {
36
36
  }
37
37
  function classifyOperation(method, suffix) {
38
38
  if (method === "POST" && ["/memories/recall", "/reflect"].includes(suffix)) return "read";
39
- if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|knowledge-base)(?:\/[^/]+)*$/.test(
40
- suffix
41
- ))
39
+ if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|pages)(?:\/[^/]+)*$/.test(suffix))
42
40
  return "read";
43
41
  if (method === "GET" && suffix === "") return "read";
44
- if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|knowledge-base|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
42
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|pages|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
45
43
  suffix
46
44
  ))
47
45
  return "write";
@@ -379,6 +377,54 @@ var RouterTransport = class {
379
377
  // ../../coding-agents/human-session.ts
380
378
  import { createHash as createHash2 } from "crypto";
381
379
  import { createRequire } from "module";
380
+
381
+ // src/harness/names.ts
382
+ var HARNESS_NAMES = [
383
+ "opencode",
384
+ // opencode v2 (binary `opencode2`) — a ground-up rewrite of the plugin API, loaded from the
385
+ // package's root index.js (src/opencode2.ts). Like opencode it has NO hook binary.
386
+ "opencode2",
387
+ // Kilo CLI is an opencode fork loaded as a persistent plugin (src/kilo.ts), so like opencode it
388
+ // has NO hook binary — deliberately absent from HOOK_BINS below.
389
+ "kilo",
390
+ // Cline CLI loads dist/cline.js through its native plugin manager; file hooks cannot inject.
391
+ "cline-cli",
392
+ // DeepSeek Harness loads dist/dsh.js as a native Cordis plugin (src/dsh.ts). Its Claude Code /
393
+ // Codex hook bridges are optional packages, so there is no hook binary to install either.
394
+ "dsh",
395
+ // pi loads dist/pi.js as an extension (src/pi.ts), and Prime Agent — a fork of pi — loads
396
+ // dist/prime-agent.js the same way (src/prime-agent.ts). Neither has a hook binary.
397
+ "pi",
398
+ "prime-agent",
399
+ "claude-code",
400
+ "cursor-cli",
401
+ "codex",
402
+ "dcode",
403
+ "antigravity-cli",
404
+ "devin-cli",
405
+ "copilot-cli",
406
+ "grok-build",
407
+ "qwen-code",
408
+ // Factory Droid is a per-prompt HOOK host: the installer wires ~/.factory/hooks.json and the
409
+ // stdio MCP registration in ~/.factory/mcp.json (see src/installer.ts).
410
+ "factory-droid",
411
+ // ZCode is a per-prompt HOOK host too, registered in its own CLI config
412
+ // (~/.zcode/cli/config.json) under `hooks.events` — never the user's real Claude Code settings.
413
+ "zcode",
414
+ // TraeCode is a per-prompt HOOK host registered in ~/.trae-cn/hooks.json (see src/installer.ts).
415
+ "traecode",
416
+ "kimi-code",
417
+ // WorkBuddy is a per-prompt HOOK host too: the installer wires ~/.workbuddy/settings.json and
418
+ // the stdio MCP registration in ~/.workbuddy/mcp.json (see src/installer.ts).
419
+ "workbuddy",
420
+ // CodeBuddy Code is the SAME @genie/agent-cli HOOK host, one product config apart (WorkBuddy only
421
+ // renames the home folder): the installer wires ~/.codebuddy/settings.json and the stdio MCP
422
+ // registration in CodeBuddy's priority-chained MCP file (see src/installer.ts). The CLI
423
+ // writes WorkBuddy's transcript format; the CodeBuddy IDE has a reader of its own.
424
+ "codebuddy"
425
+ ];
426
+
427
+ // ../../coding-agents/human-session.ts
382
428
  var HUMAN_TOKEN_PATTERN = /^mrh_[0-9a-f]{32}_[0-9a-f]{64}$/;
383
429
  var HumanLoginRequiredError = class extends AccessDeniedError {
384
430
  constructor() {
@@ -404,14 +450,14 @@ function humanRouterUrl(value) {
404
450
  if (url.search || url.hash) throw new HumanLoginRequiredError();
405
451
  return canonical2;
406
452
  }
407
- function secureEntry(routerUrl, credentialRef) {
453
+ function secureEntry(routerUrl, credentialRef, harness) {
408
454
  try {
409
- if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef)) {
455
+ if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef) || !HARNESS_NAMES.includes(harness)) {
410
456
  throw new HumanLoginRequiredError();
411
457
  }
412
458
  const { Entry: NativeEntry } = createRequire(import.meta.url)("@napi-rs/keyring");
413
- const service = `hindsight-memory-router:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
414
- return new NativeEntry(service, credentialRef, { linux: { store: "secret-service" } });
459
+ const service = `hindsight-memory-router:human-v2:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
460
+ return new NativeEntry(service, `${harness}:${credentialRef}`, { linux: { store: "secret-service" } });
415
461
  } catch {
416
462
  throw new HumanLoginRequiredError();
417
463
  }
@@ -429,9 +475,9 @@ function validateHumanSession(value, routerUrl, allowExpired = false) {
429
475
  routerUrl: session.routerUrl
430
476
  };
431
477
  }
432
- function readHumanSession(routerUrl, credentialRef) {
478
+ function readHumanSession(routerUrl, credentialRef, harness) {
433
479
  try {
434
- const password = secureEntry(routerUrl, credentialRef).getPassword();
480
+ const password = secureEntry(routerUrl, credentialRef, harness).getPassword();
435
481
  if (!password || password.length > 4096) throw new HumanLoginRequiredError();
436
482
  return validateHumanSession(JSON.parse(password), routerUrl);
437
483
  } catch {
@@ -443,11 +489,11 @@ function readHumanSession(routerUrl, credentialRef) {
443
489
  function harnessTransport(harness) {
444
490
  return transportForConfig(harness, loadManagedConfig(process.env, harness));
445
491
  }
446
- function transportForConfig(harness, { config: config2, principal }) {
492
+ function transportForConfig(harness, { config: config2, principal, principalId }) {
447
493
  if (principal.human) {
448
494
  const routerUrl = humanRouterUrl(config2.routerUrl);
449
495
  const reference = principal.human.credentialRef;
450
- let session = readHumanSession(routerUrl, reference);
496
+ let session = readHumanSession(routerUrl, reference, principalId);
451
497
  return new RouterTransport({
452
498
  routerUrl,
453
499
  access: principal,
@@ -455,7 +501,7 @@ function transportForConfig(harness, { config: config2, principal }) {
455
501
  tokenPattern: HUMAN_TOKEN_PATTERN,
456
502
  unauthorizedError: () => new HumanLoginRequiredError(),
457
503
  token: () => {
458
- session = readHumanSession(routerUrl, reference);
504
+ session = readHumanSession(routerUrl, reference, principalId);
459
505
  return session.token;
460
506
  }
461
507
  });
@@ -1214,7 +1260,7 @@ var PLUGIN_GOVERNED_BANK_FIELDS = [
1214
1260
  ];
1215
1261
 
1216
1262
  // package.json
1217
- var version = "0.8.9";
1263
+ var version = "0.8.14";
1218
1264
 
1219
1265
  // src/core/util.ts
1220
1266
  import { accessSync, constants } from "fs";
@@ -1728,7 +1774,7 @@ var HindsightClient = class _HindsightClient {
1728
1774
  */
1729
1775
  async tree() {
1730
1776
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1731
- const r = await this.req("GET", this.bankUrl("/knowledge-base/tree"));
1777
+ const r = await this.req("GET", this.bankUrl("/pages/tree"));
1732
1778
  if (await this.pagesUnsupported(r)) throw new KnowledgePagesUnavailableError();
1733
1779
  if (r.status === 404) return [];
1734
1780
  this.knowledgePagesSupported = true;
@@ -1776,7 +1822,7 @@ var HindsightClient = class _HindsightClient {
1776
1822
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1777
1823
  const r = await this.req(
1778
1824
  "GET",
1779
- this.bankUrl(`/knowledge-base/pages/${encodeURIComponent(pageId)}`)
1825
+ this.bankUrl(`/pages/${encodeURIComponent(pageId)}`)
1780
1826
  );
1781
1827
  if (r.status === 404) throw new Error(`knowledge page not found: ${pageId}`);
1782
1828
  return shapePage(await r.json());
@@ -1789,7 +1835,7 @@ var HindsightClient = class _HindsightClient {
1789
1835
  const q = `?q=${encodeURIComponent(query)}&limit=${opts.limit ?? this.pageSearchLimit}`;
1790
1836
  const r = await this.req(
1791
1837
  "GET",
1792
- this.bankUrl(`/knowledge-base/search${q}`),
1838
+ this.bankUrl(`/pages/search${q}`),
1793
1839
  void 0,
1794
1840
  [],
1795
1841
  opts.timeoutMs
@@ -1808,7 +1854,7 @@ var HindsightClient = class _HindsightClient {
1808
1854
  /**
1809
1855
  * Seed the fixed page taxonomy as knowledge-base pages at the tree root, idempotently.
1810
1856
  *
1811
- * Matched by NAME, not id: `/knowledge-base/pages` mints its own `kp-…` id, so a stable
1857
+ * Matched by NAME, not id: `/pages` mints its own `kp-…` id, so a stable
1812
1858
  * client-chosen id isn't available to match on (unlike the old mental-model path, which keyed
1813
1859
  * off a slug). Names are unique per folder server-side, which makes them a sound key.
1814
1860
  *
@@ -1847,7 +1893,7 @@ var HindsightClient = class _HindsightClient {
1847
1893
  trigger: pageTriggerFor(pageTrigger, this.bank, page.name)
1848
1894
  };
1849
1895
  if (!hit) {
1850
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), body, [409]);
1896
+ const r = await this.req("POST", this.bankUrl("/pages"), body, [409]);
1851
1897
  if (await this.pagesUnsupported(r)) {
1852
1898
  this.log(
1853
1899
  `[bank] knowledge pages unavailable on ${this.apiUrl}; continuing without pages`
@@ -1874,7 +1920,7 @@ var HindsightClient = class _HindsightClient {
1874
1920
  if (triggerDrift) patch.trigger = pageTriggerPatch(body.trigger);
1875
1921
  const r = await this.req(
1876
1922
  "PATCH",
1877
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(hit.id)}`),
1923
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(hit.id)}`),
1878
1924
  patch
1879
1925
  );
1880
1926
  if (await this.pagesUnsupported(r)) {
@@ -1928,7 +1974,7 @@ var HindsightClient = class _HindsightClient {
1928
1974
  if (!patch.trigger && !patch.source_query) continue;
1929
1975
  const r = await this.req(
1930
1976
  "PATCH",
1931
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(page.id)}`),
1977
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(page.id)}`),
1932
1978
  patch
1933
1979
  );
1934
1980
  if (r.status === 404) continue;
@@ -1957,7 +2003,7 @@ var HindsightClient = class _HindsightClient {
1957
2003
  let pageId = args.relatesToPageId;
1958
2004
  if (!pageId) {
1959
2005
  const folderId = await this.ensureFolder("Initiatives");
1960
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), {
2006
+ const r = await this.req("POST", this.bankUrl("/pages"), {
1961
2007
  name: args.title,
1962
2008
  source_query: `Summarize the "${args.title}" initiative: what is being built or changed and why, and its current state \u2014 drawn from the project's memory.` + pageScopeRule(this.project),
1963
2009
  parent_id: folderId,
@@ -1985,7 +2031,7 @@ var HindsightClient = class _HindsightClient {
1985
2031
  /** Find a root folder by name (case-insensitive) or create it; returns its id. Fail-open to undefined. */
1986
2032
  async ensureFolder(name) {
1987
2033
  try {
1988
- const tree = await (await this.req("GET", this.bankUrl("/knowledge-base/tree"))).json();
2034
+ const tree = await (await this.req("GET", this.bankUrl("/pages/tree"))).json();
1989
2035
  const hit = (tree.roots || []).find(
1990
2036
  (n) => n.kind === "folder" && (n.name || "").toLowerCase() === name.toLowerCase()
1991
2037
  );
@@ -1994,7 +2040,7 @@ var HindsightClient = class _HindsightClient {
1994
2040
  if (error instanceof AccessDeniedError) throw error;
1995
2041
  }
1996
2042
  try {
1997
- const r = await this.req("POST", this.bankUrl("/knowledge-base/folders"), { name });
2043
+ const r = await this.req("POST", this.bankUrl("/pages/folders"), { name });
1998
2044
  return (await r.json()).id;
1999
2045
  } catch (error) {
2000
2046
  if (error instanceof AccessDeniedError) throw error;
@@ -27,12 +27,10 @@ function requireBank(access, bank, operation) {
27
27
  }
28
28
  function classifyOperation(method, suffix) {
29
29
  if (method === "POST" && ["/memories/recall", "/reflect"].includes(suffix)) return "read";
30
- if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|knowledge-base)(?:\/[^/]+)*$/.test(
31
- suffix
32
- ))
30
+ if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|pages)(?:\/[^/]+)*$/.test(suffix))
33
31
  return "read";
34
32
  if (method === "GET" && suffix === "") return "read";
35
- if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|knowledge-base|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
33
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|pages|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
36
34
  suffix
37
35
  ))
38
36
  return "write";
@@ -354,6 +352,54 @@ var RouterTransport = class {
354
352
  // ../../coding-agents/human-session.ts
355
353
  import { createHash as createHash2 } from "crypto";
356
354
  import { createRequire } from "module";
355
+
356
+ // src/harness/names.ts
357
+ var HARNESS_NAMES = [
358
+ "opencode",
359
+ // opencode v2 (binary `opencode2`) — a ground-up rewrite of the plugin API, loaded from the
360
+ // package's root index.js (src/opencode2.ts). Like opencode it has NO hook binary.
361
+ "opencode2",
362
+ // Kilo CLI is an opencode fork loaded as a persistent plugin (src/kilo.ts), so like opencode it
363
+ // has NO hook binary — deliberately absent from HOOK_BINS below.
364
+ "kilo",
365
+ // Cline CLI loads dist/cline.js through its native plugin manager; file hooks cannot inject.
366
+ "cline-cli",
367
+ // DeepSeek Harness loads dist/dsh.js as a native Cordis plugin (src/dsh.ts). Its Claude Code /
368
+ // Codex hook bridges are optional packages, so there is no hook binary to install either.
369
+ "dsh",
370
+ // pi loads dist/pi.js as an extension (src/pi.ts), and Prime Agent — a fork of pi — loads
371
+ // dist/prime-agent.js the same way (src/prime-agent.ts). Neither has a hook binary.
372
+ "pi",
373
+ "prime-agent",
374
+ "claude-code",
375
+ "cursor-cli",
376
+ "codex",
377
+ "dcode",
378
+ "antigravity-cli",
379
+ "devin-cli",
380
+ "copilot-cli",
381
+ "grok-build",
382
+ "qwen-code",
383
+ // Factory Droid is a per-prompt HOOK host: the installer wires ~/.factory/hooks.json and the
384
+ // stdio MCP registration in ~/.factory/mcp.json (see src/installer.ts).
385
+ "factory-droid",
386
+ // ZCode is a per-prompt HOOK host too, registered in its own CLI config
387
+ // (~/.zcode/cli/config.json) under `hooks.events` — never the user's real Claude Code settings.
388
+ "zcode",
389
+ // TraeCode is a per-prompt HOOK host registered in ~/.trae-cn/hooks.json (see src/installer.ts).
390
+ "traecode",
391
+ "kimi-code",
392
+ // WorkBuddy is a per-prompt HOOK host too: the installer wires ~/.workbuddy/settings.json and
393
+ // the stdio MCP registration in ~/.workbuddy/mcp.json (see src/installer.ts).
394
+ "workbuddy",
395
+ // CodeBuddy Code is the SAME @genie/agent-cli HOOK host, one product config apart (WorkBuddy only
396
+ // renames the home folder): the installer wires ~/.codebuddy/settings.json and the stdio MCP
397
+ // registration in CodeBuddy's priority-chained MCP file (see src/installer.ts). The CLI
398
+ // writes WorkBuddy's transcript format; the CodeBuddy IDE has a reader of its own.
399
+ "codebuddy"
400
+ ];
401
+
402
+ // ../../coding-agents/human-session.ts
357
403
  var HUMAN_TOKEN_PATTERN = /^mrh_[0-9a-f]{32}_[0-9a-f]{64}$/;
358
404
  var HumanLoginRequiredError = class extends AccessDeniedError {
359
405
  constructor() {
@@ -379,14 +425,14 @@ function humanRouterUrl(value) {
379
425
  if (url.search || url.hash) throw new HumanLoginRequiredError();
380
426
  return canonical;
381
427
  }
382
- function secureEntry(routerUrl, credentialRef) {
428
+ function secureEntry(routerUrl, credentialRef, harness) {
383
429
  try {
384
- if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef)) {
430
+ if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef) || !HARNESS_NAMES.includes(harness)) {
385
431
  throw new HumanLoginRequiredError();
386
432
  }
387
433
  const { Entry: NativeEntry } = createRequire(import.meta.url)("@napi-rs/keyring");
388
- const service = `hindsight-memory-router:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
389
- return new NativeEntry(service, credentialRef, { linux: { store: "secret-service" } });
434
+ const service = `hindsight-memory-router:human-v2:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
435
+ return new NativeEntry(service, `${harness}:${credentialRef}`, { linux: { store: "secret-service" } });
390
436
  } catch {
391
437
  throw new HumanLoginRequiredError();
392
438
  }
@@ -404,9 +450,9 @@ function validateHumanSession(value, routerUrl, allowExpired = false) {
404
450
  routerUrl: session.routerUrl
405
451
  };
406
452
  }
407
- function readHumanSession(routerUrl, credentialRef) {
453
+ function readHumanSession(routerUrl, credentialRef, harness) {
408
454
  try {
409
- const password = secureEntry(routerUrl, credentialRef).getPassword();
455
+ const password = secureEntry(routerUrl, credentialRef, harness).getPassword();
410
456
  if (!password || password.length > 4096) throw new HumanLoginRequiredError();
411
457
  return validateHumanSession(JSON.parse(password), routerUrl);
412
458
  } catch {
@@ -415,11 +461,11 @@ function readHumanSession(routerUrl, credentialRef) {
415
461
  }
416
462
 
417
463
  // ../../coding-agents/runtime.ts
418
- function transportForConfig(harness, { config, principal }) {
464
+ function transportForConfig(harness, { config, principal, principalId }) {
419
465
  if (principal.human) {
420
466
  const routerUrl = humanRouterUrl(config.routerUrl);
421
467
  const reference = principal.human.credentialRef;
422
- let session = readHumanSession(routerUrl, reference);
468
+ let session = readHumanSession(routerUrl, reference, principalId);
423
469
  return new RouterTransport({
424
470
  routerUrl,
425
471
  access: principal,
@@ -427,7 +473,7 @@ function transportForConfig(harness, { config, principal }) {
427
473
  tokenPattern: HUMAN_TOKEN_PATTERN,
428
474
  unauthorizedError: () => new HumanLoginRequiredError(),
429
475
  token: () => {
430
- session = readHumanSession(routerUrl, reference);
476
+ session = readHumanSession(routerUrl, reference, principalId);
431
477
  return session.token;
432
478
  }
433
479
  });
@@ -761,7 +807,7 @@ var PLUGIN_GOVERNED_BANK_FIELDS = [
761
807
  ];
762
808
 
763
809
  // package.json
764
- var version = "0.8.9";
810
+ var version = "0.8.14";
765
811
 
766
812
  // src/core/util.ts
767
813
  import { accessSync, constants } from "fs";
package/dist/index.js CHANGED
@@ -34,12 +34,10 @@ function requireBank(access, bank, operation) {
34
34
  }
35
35
  function classifyOperation(method, suffix) {
36
36
  if (method === "POST" && ["/memories/recall", "/reflect"].includes(suffix)) return "read";
37
- if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|knowledge-base)(?:\/[^/]+)*$/.test(
38
- suffix
39
- ))
37
+ if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|pages)(?:\/[^/]+)*$/.test(suffix))
40
38
  return "read";
41
39
  if (method === "GET" && suffix === "") return "read";
42
- if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|knowledge-base|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
40
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|pages|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
43
41
  suffix
44
42
  ))
45
43
  return "write";
@@ -451,6 +449,54 @@ var RouterTransport = class {
451
449
  // ../../coding-agents/human-session.ts
452
450
  import { createHash as createHash2 } from "crypto";
453
451
  import { createRequire } from "module";
452
+
453
+ // src/harness/names.ts
454
+ var HARNESS_NAMES = [
455
+ "opencode",
456
+ // opencode v2 (binary `opencode2`) — a ground-up rewrite of the plugin API, loaded from the
457
+ // package's root index.js (src/opencode2.ts). Like opencode it has NO hook binary.
458
+ "opencode2",
459
+ // Kilo CLI is an opencode fork loaded as a persistent plugin (src/kilo.ts), so like opencode it
460
+ // has NO hook binary — deliberately absent from HOOK_BINS below.
461
+ "kilo",
462
+ // Cline CLI loads dist/cline.js through its native plugin manager; file hooks cannot inject.
463
+ "cline-cli",
464
+ // DeepSeek Harness loads dist/dsh.js as a native Cordis plugin (src/dsh.ts). Its Claude Code /
465
+ // Codex hook bridges are optional packages, so there is no hook binary to install either.
466
+ "dsh",
467
+ // pi loads dist/pi.js as an extension (src/pi.ts), and Prime Agent — a fork of pi — loads
468
+ // dist/prime-agent.js the same way (src/prime-agent.ts). Neither has a hook binary.
469
+ "pi",
470
+ "prime-agent",
471
+ "claude-code",
472
+ "cursor-cli",
473
+ "codex",
474
+ "dcode",
475
+ "antigravity-cli",
476
+ "devin-cli",
477
+ "copilot-cli",
478
+ "grok-build",
479
+ "qwen-code",
480
+ // Factory Droid is a per-prompt HOOK host: the installer wires ~/.factory/hooks.json and the
481
+ // stdio MCP registration in ~/.factory/mcp.json (see src/installer.ts).
482
+ "factory-droid",
483
+ // ZCode is a per-prompt HOOK host too, registered in its own CLI config
484
+ // (~/.zcode/cli/config.json) under `hooks.events` — never the user's real Claude Code settings.
485
+ "zcode",
486
+ // TraeCode is a per-prompt HOOK host registered in ~/.trae-cn/hooks.json (see src/installer.ts).
487
+ "traecode",
488
+ "kimi-code",
489
+ // WorkBuddy is a per-prompt HOOK host too: the installer wires ~/.workbuddy/settings.json and
490
+ // the stdio MCP registration in ~/.workbuddy/mcp.json (see src/installer.ts).
491
+ "workbuddy",
492
+ // CodeBuddy Code is the SAME @genie/agent-cli HOOK host, one product config apart (WorkBuddy only
493
+ // renames the home folder): the installer wires ~/.codebuddy/settings.json and the stdio MCP
494
+ // registration in CodeBuddy's priority-chained MCP file (see src/installer.ts). The CLI
495
+ // writes WorkBuddy's transcript format; the CodeBuddy IDE has a reader of its own.
496
+ "codebuddy"
497
+ ];
498
+
499
+ // ../../coding-agents/human-session.ts
454
500
  var HUMAN_TOKEN_PATTERN = /^mrh_[0-9a-f]{32}_[0-9a-f]{64}$/;
455
501
  var HumanLoginRequiredError = class extends AccessDeniedError {
456
502
  constructor() {
@@ -476,14 +522,14 @@ function humanRouterUrl(value) {
476
522
  if (url2.search || url2.hash) throw new HumanLoginRequiredError();
477
523
  return canonical2;
478
524
  }
479
- function secureEntry(routerUrl, credentialRef) {
525
+ function secureEntry(routerUrl, credentialRef, harness) {
480
526
  try {
481
- if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef)) {
527
+ if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef) || !HARNESS_NAMES.includes(harness)) {
482
528
  throw new HumanLoginRequiredError();
483
529
  }
484
530
  const { Entry: NativeEntry } = createRequire(import.meta.url)("@napi-rs/keyring");
485
- const service = `hindsight-memory-router:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
486
- return new NativeEntry(service, credentialRef, { linux: { store: "secret-service" } });
531
+ const service = `hindsight-memory-router:human-v2:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
532
+ return new NativeEntry(service, `${harness}:${credentialRef}`, { linux: { store: "secret-service" } });
487
533
  } catch {
488
534
  throw new HumanLoginRequiredError();
489
535
  }
@@ -501,9 +547,9 @@ function validateHumanSession(value, routerUrl, allowExpired = false) {
501
547
  routerUrl: session.routerUrl
502
548
  };
503
549
  }
504
- function readHumanSession(routerUrl, credentialRef) {
550
+ function readHumanSession(routerUrl, credentialRef, harness) {
505
551
  try {
506
- const password = secureEntry(routerUrl, credentialRef).getPassword();
552
+ const password = secureEntry(routerUrl, credentialRef, harness).getPassword();
507
553
  if (!password || password.length > 4096) throw new HumanLoginRequiredError();
508
554
  return validateHumanSession(JSON.parse(password), routerUrl);
509
555
  } catch {
@@ -515,11 +561,11 @@ function readHumanSession(routerUrl, credentialRef) {
515
561
  function harnessTransport(harness) {
516
562
  return transportForConfig(harness, loadManagedConfig(process.env, harness));
517
563
  }
518
- function transportForConfig(harness, { config: config2, principal }) {
564
+ function transportForConfig(harness, { config: config2, principal, principalId }) {
519
565
  if (principal.human) {
520
566
  const routerUrl = humanRouterUrl(config2.routerUrl);
521
567
  const reference = principal.human.credentialRef;
522
- let session = readHumanSession(routerUrl, reference);
568
+ let session = readHumanSession(routerUrl, reference, principalId);
523
569
  return new RouterTransport({
524
570
  routerUrl,
525
571
  access: principal,
@@ -527,7 +573,7 @@ function transportForConfig(harness, { config: config2, principal }) {
527
573
  tokenPattern: HUMAN_TOKEN_PATTERN,
528
574
  unauthorizedError: () => new HumanLoginRequiredError(),
529
575
  token: () => {
530
- session = readHumanSession(routerUrl, reference);
576
+ session = readHumanSession(routerUrl, reference, principalId);
531
577
  return session.token;
532
578
  }
533
579
  });
@@ -1334,7 +1380,7 @@ var PLUGIN_GOVERNED_BANK_FIELDS = [
1334
1380
  ];
1335
1381
 
1336
1382
  // package.json
1337
- var version = "0.8.9";
1383
+ var version = "0.8.14";
1338
1384
 
1339
1385
  // src/core/util.ts
1340
1386
  import { accessSync, constants } from "fs";
@@ -1867,7 +1913,7 @@ var HindsightClient = class _HindsightClient {
1867
1913
  */
1868
1914
  async tree() {
1869
1915
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1870
- const r = await this.req("GET", this.bankUrl("/knowledge-base/tree"));
1916
+ const r = await this.req("GET", this.bankUrl("/pages/tree"));
1871
1917
  if (await this.pagesUnsupported(r)) throw new KnowledgePagesUnavailableError();
1872
1918
  if (r.status === 404) return [];
1873
1919
  this.knowledgePagesSupported = true;
@@ -1915,7 +1961,7 @@ var HindsightClient = class _HindsightClient {
1915
1961
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1916
1962
  const r = await this.req(
1917
1963
  "GET",
1918
- this.bankUrl(`/knowledge-base/pages/${encodeURIComponent(pageId)}`)
1964
+ this.bankUrl(`/pages/${encodeURIComponent(pageId)}`)
1919
1965
  );
1920
1966
  if (r.status === 404) throw new Error(`knowledge page not found: ${pageId}`);
1921
1967
  return shapePage(await r.json());
@@ -1928,7 +1974,7 @@ var HindsightClient = class _HindsightClient {
1928
1974
  const q = `?q=${encodeURIComponent(query)}&limit=${opts.limit ?? this.pageSearchLimit}`;
1929
1975
  const r = await this.req(
1930
1976
  "GET",
1931
- this.bankUrl(`/knowledge-base/search${q}`),
1977
+ this.bankUrl(`/pages/search${q}`),
1932
1978
  void 0,
1933
1979
  [],
1934
1980
  opts.timeoutMs
@@ -1947,7 +1993,7 @@ var HindsightClient = class _HindsightClient {
1947
1993
  /**
1948
1994
  * Seed the fixed page taxonomy as knowledge-base pages at the tree root, idempotently.
1949
1995
  *
1950
- * Matched by NAME, not id: `/knowledge-base/pages` mints its own `kp-…` id, so a stable
1996
+ * Matched by NAME, not id: `/pages` mints its own `kp-…` id, so a stable
1951
1997
  * client-chosen id isn't available to match on (unlike the old mental-model path, which keyed
1952
1998
  * off a slug). Names are unique per folder server-side, which makes them a sound key.
1953
1999
  *
@@ -1986,7 +2032,7 @@ var HindsightClient = class _HindsightClient {
1986
2032
  trigger: pageTriggerFor(pageTrigger, this.bank, page.name)
1987
2033
  };
1988
2034
  if (!hit) {
1989
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), body, [409]);
2035
+ const r = await this.req("POST", this.bankUrl("/pages"), body, [409]);
1990
2036
  if (await this.pagesUnsupported(r)) {
1991
2037
  this.log(
1992
2038
  `[bank] knowledge pages unavailable on ${this.apiUrl}; continuing without pages`
@@ -2013,7 +2059,7 @@ var HindsightClient = class _HindsightClient {
2013
2059
  if (triggerDrift) patch.trigger = pageTriggerPatch(body.trigger);
2014
2060
  const r = await this.req(
2015
2061
  "PATCH",
2016
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(hit.id)}`),
2062
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(hit.id)}`),
2017
2063
  patch
2018
2064
  );
2019
2065
  if (await this.pagesUnsupported(r)) {
@@ -2067,7 +2113,7 @@ var HindsightClient = class _HindsightClient {
2067
2113
  if (!patch.trigger && !patch.source_query) continue;
2068
2114
  const r = await this.req(
2069
2115
  "PATCH",
2070
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(page.id)}`),
2116
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(page.id)}`),
2071
2117
  patch
2072
2118
  );
2073
2119
  if (r.status === 404) continue;
@@ -2096,7 +2142,7 @@ var HindsightClient = class _HindsightClient {
2096
2142
  let pageId = args.relatesToPageId;
2097
2143
  if (!pageId) {
2098
2144
  const folderId = await this.ensureFolder("Initiatives");
2099
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), {
2145
+ const r = await this.req("POST", this.bankUrl("/pages"), {
2100
2146
  name: args.title,
2101
2147
  source_query: `Summarize the "${args.title}" initiative: what is being built or changed and why, and its current state \u2014 drawn from the project's memory.` + pageScopeRule(this.project),
2102
2148
  parent_id: folderId,
@@ -2124,7 +2170,7 @@ var HindsightClient = class _HindsightClient {
2124
2170
  /** Find a root folder by name (case-insensitive) or create it; returns its id. Fail-open to undefined. */
2125
2171
  async ensureFolder(name) {
2126
2172
  try {
2127
- const tree = await (await this.req("GET", this.bankUrl("/knowledge-base/tree"))).json();
2173
+ const tree = await (await this.req("GET", this.bankUrl("/pages/tree"))).json();
2128
2174
  const hit = (tree.roots || []).find(
2129
2175
  (n) => n.kind === "folder" && (n.name || "").toLowerCase() === name.toLowerCase()
2130
2176
  );
@@ -2133,7 +2179,7 @@ var HindsightClient = class _HindsightClient {
2133
2179
  if (error62 instanceof AccessDeniedError) throw error62;
2134
2180
  }
2135
2181
  try {
2136
- const r = await this.req("POST", this.bankUrl("/knowledge-base/folders"), { name });
2182
+ const r = await this.req("POST", this.bankUrl("/pages/folders"), { name });
2137
2183
  return (await r.json()).id;
2138
2184
  } catch (error62) {
2139
2185
  if (error62 instanceof AccessDeniedError) throw error62;