@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
package/dist/installer.js CHANGED
@@ -2456,12 +2456,10 @@ function requireBank(access, bank, operation) {
2456
2456
  }
2457
2457
  function classifyOperation(method, suffix) {
2458
2458
  if (method === "POST" && ["/memories/recall", "/reflect"].includes(suffix)) return "read";
2459
- if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|knowledge-base)(?:\/[^/]+)*$/.test(
2460
- suffix
2461
- ))
2459
+ if (method === "GET" && /^\/(?:config|stats|tags|graph|documents|operations|memories|mental-models|pages)(?:\/[^/]+)*$/.test(suffix))
2462
2460
  return "read";
2463
2461
  if (method === "GET" && suffix === "") return "read";
2464
- if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|knowledge-base|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
2462
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && /^(?:\/(?:config|import|memories|documents|mental-models|pages|consolidate|consolidation)(?:\/[^/]+)*)?$/.test(
2465
2463
  suffix
2466
2464
  ))
2467
2465
  return "write";
@@ -2756,6 +2754,54 @@ var RouterTransport = class {
2756
2754
  // ../../coding-agents/human-session.ts
2757
2755
  import { createHash as createHash2 } from "crypto";
2758
2756
  import { createRequire } from "module";
2757
+
2758
+ // src/harness/names.ts
2759
+ var HARNESS_NAMES = [
2760
+ "opencode",
2761
+ // opencode v2 (binary `opencode2`) — a ground-up rewrite of the plugin API, loaded from the
2762
+ // package's root index.js (src/opencode2.ts). Like opencode it has NO hook binary.
2763
+ "opencode2",
2764
+ // Kilo CLI is an opencode fork loaded as a persistent plugin (src/kilo.ts), so like opencode it
2765
+ // has NO hook binary — deliberately absent from HOOK_BINS below.
2766
+ "kilo",
2767
+ // Cline CLI loads dist/cline.js through its native plugin manager; file hooks cannot inject.
2768
+ "cline-cli",
2769
+ // DeepSeek Harness loads dist/dsh.js as a native Cordis plugin (src/dsh.ts). Its Claude Code /
2770
+ // Codex hook bridges are optional packages, so there is no hook binary to install either.
2771
+ "dsh",
2772
+ // pi loads dist/pi.js as an extension (src/pi.ts), and Prime Agent — a fork of pi — loads
2773
+ // dist/prime-agent.js the same way (src/prime-agent.ts). Neither has a hook binary.
2774
+ "pi",
2775
+ "prime-agent",
2776
+ "claude-code",
2777
+ "cursor-cli",
2778
+ "codex",
2779
+ "dcode",
2780
+ "antigravity-cli",
2781
+ "devin-cli",
2782
+ "copilot-cli",
2783
+ "grok-build",
2784
+ "qwen-code",
2785
+ // Factory Droid is a per-prompt HOOK host: the installer wires ~/.factory/hooks.json and the
2786
+ // stdio MCP registration in ~/.factory/mcp.json (see src/installer.ts).
2787
+ "factory-droid",
2788
+ // ZCode is a per-prompt HOOK host too, registered in its own CLI config
2789
+ // (~/.zcode/cli/config.json) under `hooks.events` — never the user's real Claude Code settings.
2790
+ "zcode",
2791
+ // TraeCode is a per-prompt HOOK host registered in ~/.trae-cn/hooks.json (see src/installer.ts).
2792
+ "traecode",
2793
+ "kimi-code",
2794
+ // WorkBuddy is a per-prompt HOOK host too: the installer wires ~/.workbuddy/settings.json and
2795
+ // the stdio MCP registration in ~/.workbuddy/mcp.json (see src/installer.ts).
2796
+ "workbuddy",
2797
+ // CodeBuddy Code is the SAME @genie/agent-cli HOOK host, one product config apart (WorkBuddy only
2798
+ // renames the home folder): the installer wires ~/.codebuddy/settings.json and the stdio MCP
2799
+ // registration in CodeBuddy's priority-chained MCP file (see src/installer.ts). The CLI
2800
+ // writes WorkBuddy's transcript format; the CodeBuddy IDE has a reader of its own.
2801
+ "codebuddy"
2802
+ ];
2803
+
2804
+ // ../../coding-agents/human-session.ts
2759
2805
  var HUMAN_TOKEN_PATTERN = /^mrh_[0-9a-f]{32}_[0-9a-f]{64}$/;
2760
2806
  var HumanLoginRequiredError = class extends AccessDeniedError {
2761
2807
  constructor() {
@@ -2781,14 +2827,14 @@ function humanRouterUrl(value) {
2781
2827
  if (url.search || url.hash) throw new HumanLoginRequiredError();
2782
2828
  return canonical;
2783
2829
  }
2784
- function secureEntry(routerUrl, credentialRef) {
2830
+ function secureEntry(routerUrl, credentialRef, harness) {
2785
2831
  try {
2786
- if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef)) {
2832
+ if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef) || !HARNESS_NAMES.includes(harness)) {
2787
2833
  throw new HumanLoginRequiredError();
2788
2834
  }
2789
2835
  const { Entry: NativeEntry } = createRequire(import.meta.url)("@napi-rs/keyring");
2790
- const service = `hindsight-memory-router:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
2791
- return new NativeEntry(service, credentialRef, { linux: { store: "secret-service" } });
2836
+ const service = `hindsight-memory-router:human-v2:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
2837
+ return new NativeEntry(service, `${harness}:${credentialRef}`, { linux: { store: "secret-service" } });
2792
2838
  } catch {
2793
2839
  throw new HumanLoginRequiredError();
2794
2840
  }
@@ -2806,9 +2852,9 @@ function validateHumanSession(value, routerUrl, allowExpired = false) {
2806
2852
  routerUrl: session.routerUrl
2807
2853
  };
2808
2854
  }
2809
- function readHumanSession(routerUrl, credentialRef) {
2855
+ function readHumanSession(routerUrl, credentialRef, harness) {
2810
2856
  try {
2811
- const password = secureEntry(routerUrl, credentialRef).getPassword();
2857
+ const password = secureEntry(routerUrl, credentialRef, harness).getPassword();
2812
2858
  if (!password || password.length > 4096) throw new HumanLoginRequiredError();
2813
2859
  return validateHumanSession(JSON.parse(password), routerUrl);
2814
2860
  } catch {
@@ -2820,11 +2866,11 @@ function readHumanSession(routerUrl, credentialRef) {
2820
2866
  function harnessTransport(harness) {
2821
2867
  return transportForConfig(harness, loadManagedConfig(process.env, harness));
2822
2868
  }
2823
- function transportForConfig(harness, { config: config2, principal }) {
2869
+ function transportForConfig(harness, { config: config2, principal, principalId }) {
2824
2870
  if (principal.human) {
2825
2871
  const routerUrl = humanRouterUrl(config2.routerUrl);
2826
2872
  const reference = principal.human.credentialRef;
2827
- let session = readHumanSession(routerUrl, reference);
2873
+ let session = readHumanSession(routerUrl, reference, principalId);
2828
2874
  return new RouterTransport({
2829
2875
  routerUrl,
2830
2876
  access: principal,
@@ -2832,7 +2878,7 @@ function transportForConfig(harness, { config: config2, principal }) {
2832
2878
  tokenPattern: HUMAN_TOKEN_PATTERN,
2833
2879
  unauthorizedError: () => new HumanLoginRequiredError(),
2834
2880
  token: () => {
2835
- session = readHumanSession(routerUrl, reference);
2881
+ session = readHumanSession(routerUrl, reference, principalId);
2836
2882
  return session.token;
2837
2883
  }
2838
2884
  });
@@ -2978,9 +3024,9 @@ async function openLoginBrowser(url) {
2978
3024
  });
2979
3025
  });
2980
3026
  }
2981
- async function loginHuman(routerUrl, credentialRef, openBrowser = openLoginBrowser) {
3027
+ async function loginHuman(routerUrl, credentialRef, harness, openBrowser = openLoginBrowser) {
2982
3028
  const base = humanRouterUrl(routerUrl);
2983
- const entry = secureEntry(base, credentialRef);
3029
+ const entry = secureEntry(base, credentialRef, harness);
2984
3030
  entry.getPassword();
2985
3031
  const state = randomBytes(32).toString("base64url");
2986
3032
  const verifier = randomBytes(32).toString("base64url");
@@ -3068,9 +3114,9 @@ async function loginHuman(routerUrl, credentialRef, openBrowser = openLoginBrows
3068
3114
  if (server.listening) await new Promise((resolve6) => server.close(() => resolve6()));
3069
3115
  }
3070
3116
  }
3071
- async function signOutHuman(routerUrl, credentialRef) {
3117
+ async function signOutHuman(routerUrl, credentialRef, harness) {
3072
3118
  const base = humanRouterUrl(routerUrl);
3073
- const entry = secureEntry(base, credentialRef);
3119
+ const entry = secureEntry(base, credentialRef, harness);
3074
3120
  let revoked = false;
3075
3121
  try {
3076
3122
  const stored = entry.getPassword();
@@ -3094,17 +3140,20 @@ async function runHumanAuth(argv, log2, interactive) {
3094
3140
  if (!["login", "sign-out"].includes(command) || args.length > 1 || args.some((arg) => arg.startsWith("--"))) {
3095
3141
  throw new HumanLoginRequiredError();
3096
3142
  }
3097
- const { config: config2, principal } = loadManagedConfig(process.env, args[0] ?? process.env.HINDSIGHT_MCP_HARNESS);
3143
+ const { config: config2, principal, principalId } = loadManagedConfig(
3144
+ process.env,
3145
+ args[0] ?? process.env.HINDSIGHT_MCP_HARNESS
3146
+ );
3098
3147
  if (!principal.human) throw new HumanLoginRequiredError();
3099
3148
  if (command === "login") {
3100
3149
  if (!interactive) throw new HumanLoginRequiredError();
3101
- await loginHuman(config2.routerUrl, principal.human.credentialRef);
3150
+ await loginHuman(config2.routerUrl, principal.human.credentialRef, principalId);
3102
3151
  log2(
3103
3152
  "Signed in. Run install for the configured coding agent. Sessions expire within one hour; login again when required."
3104
3153
  );
3105
3154
  return 0;
3106
3155
  }
3107
- const revoked = await signOutHuman(config2.routerUrl, principal.human.credentialRef);
3156
+ const revoked = await signOutHuman(config2.routerUrl, principal.human.credentialRef, principalId);
3108
3157
  log2(
3109
3158
  revoked ? "Signed out." : "Local credential removed; server revocation could not be confirmed. The session remains valid until expiry or operator revocation."
3110
3159
  );
@@ -3407,7 +3456,7 @@ var PAGE_TAXONOMY = [
3407
3456
  var PAGE_NAMES = PAGE_TAXONOMY.map((page) => page.name);
3408
3457
 
3409
3458
  // package.json
3410
- var version = "0.8.9";
3459
+ var version = "0.8.14";
3411
3460
 
3412
3461
  // src/core/util.ts
3413
3462
  import { accessSync, constants } from "fs";
package/dist/kilo.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;
package/dist/kimi-hook.js CHANGED
@@ -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";
@@ -393,6 +391,54 @@ var RouterTransport = class {
393
391
  // ../../coding-agents/human-session.ts
394
392
  import { createHash as createHash2 } from "crypto";
395
393
  import { createRequire } from "module";
394
+
395
+ // src/harness/names.ts
396
+ var HARNESS_NAMES = [
397
+ "opencode",
398
+ // opencode v2 (binary `opencode2`) — a ground-up rewrite of the plugin API, loaded from the
399
+ // package's root index.js (src/opencode2.ts). Like opencode it has NO hook binary.
400
+ "opencode2",
401
+ // Kilo CLI is an opencode fork loaded as a persistent plugin (src/kilo.ts), so like opencode it
402
+ // has NO hook binary — deliberately absent from HOOK_BINS below.
403
+ "kilo",
404
+ // Cline CLI loads dist/cline.js through its native plugin manager; file hooks cannot inject.
405
+ "cline-cli",
406
+ // DeepSeek Harness loads dist/dsh.js as a native Cordis plugin (src/dsh.ts). Its Claude Code /
407
+ // Codex hook bridges are optional packages, so there is no hook binary to install either.
408
+ "dsh",
409
+ // pi loads dist/pi.js as an extension (src/pi.ts), and Prime Agent — a fork of pi — loads
410
+ // dist/prime-agent.js the same way (src/prime-agent.ts). Neither has a hook binary.
411
+ "pi",
412
+ "prime-agent",
413
+ "claude-code",
414
+ "cursor-cli",
415
+ "codex",
416
+ "dcode",
417
+ "antigravity-cli",
418
+ "devin-cli",
419
+ "copilot-cli",
420
+ "grok-build",
421
+ "qwen-code",
422
+ // Factory Droid is a per-prompt HOOK host: the installer wires ~/.factory/hooks.json and the
423
+ // stdio MCP registration in ~/.factory/mcp.json (see src/installer.ts).
424
+ "factory-droid",
425
+ // ZCode is a per-prompt HOOK host too, registered in its own CLI config
426
+ // (~/.zcode/cli/config.json) under `hooks.events` — never the user's real Claude Code settings.
427
+ "zcode",
428
+ // TraeCode is a per-prompt HOOK host registered in ~/.trae-cn/hooks.json (see src/installer.ts).
429
+ "traecode",
430
+ "kimi-code",
431
+ // WorkBuddy is a per-prompt HOOK host too: the installer wires ~/.workbuddy/settings.json and
432
+ // the stdio MCP registration in ~/.workbuddy/mcp.json (see src/installer.ts).
433
+ "workbuddy",
434
+ // CodeBuddy Code is the SAME @genie/agent-cli HOOK host, one product config apart (WorkBuddy only
435
+ // renames the home folder): the installer wires ~/.codebuddy/settings.json and the stdio MCP
436
+ // registration in CodeBuddy's priority-chained MCP file (see src/installer.ts). The CLI
437
+ // writes WorkBuddy's transcript format; the CodeBuddy IDE has a reader of its own.
438
+ "codebuddy"
439
+ ];
440
+
441
+ // ../../coding-agents/human-session.ts
396
442
  var HUMAN_TOKEN_PATTERN = /^mrh_[0-9a-f]{32}_[0-9a-f]{64}$/;
397
443
  var HumanLoginRequiredError = class extends AccessDeniedError {
398
444
  constructor() {
@@ -418,14 +464,14 @@ function humanRouterUrl(value) {
418
464
  if (url.search || url.hash) throw new HumanLoginRequiredError();
419
465
  return canonical2;
420
466
  }
421
- function secureEntry(routerUrl, credentialRef) {
467
+ function secureEntry(routerUrl, credentialRef, harness) {
422
468
  try {
423
- if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef)) {
469
+ if (!["darwin", "win32", "linux"].includes(process.platform) || !/^[A-Za-z0-9._-]{1,64}$/.test(credentialRef) || !HARNESS_NAMES.includes(harness)) {
424
470
  throw new HumanLoginRequiredError();
425
471
  }
426
472
  const { Entry: NativeEntry } = createRequire(import.meta.url)("@napi-rs/keyring");
427
- const service = `hindsight-memory-router:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
428
- return new NativeEntry(service, credentialRef, { linux: { store: "secret-service" } });
473
+ const service = `hindsight-memory-router:human-v2:${createHash2("sha256").update(humanRouterUrl(routerUrl)).digest("hex")}`;
474
+ return new NativeEntry(service, `${harness}:${credentialRef}`, { linux: { store: "secret-service" } });
429
475
  } catch {
430
476
  throw new HumanLoginRequiredError();
431
477
  }
@@ -443,9 +489,9 @@ function validateHumanSession(value, routerUrl, allowExpired = false) {
443
489
  routerUrl: session.routerUrl
444
490
  };
445
491
  }
446
- function readHumanSession(routerUrl, credentialRef) {
492
+ function readHumanSession(routerUrl, credentialRef, harness) {
447
493
  try {
448
- const password = secureEntry(routerUrl, credentialRef).getPassword();
494
+ const password = secureEntry(routerUrl, credentialRef, harness).getPassword();
449
495
  if (!password || password.length > 4096) throw new HumanLoginRequiredError();
450
496
  return validateHumanSession(JSON.parse(password), routerUrl);
451
497
  } catch {
@@ -457,11 +503,11 @@ function readHumanSession(routerUrl, credentialRef) {
457
503
  function harnessTransport(harness) {
458
504
  return transportForConfig(harness, loadManagedConfig(process.env, harness));
459
505
  }
460
- function transportForConfig(harness, { config: config2, principal }) {
506
+ function transportForConfig(harness, { config: config2, principal, principalId }) {
461
507
  if (principal.human) {
462
508
  const routerUrl = humanRouterUrl(config2.routerUrl);
463
509
  const reference = principal.human.credentialRef;
464
- let session = readHumanSession(routerUrl, reference);
510
+ let session = readHumanSession(routerUrl, reference, principalId);
465
511
  return new RouterTransport({
466
512
  routerUrl,
467
513
  access: principal,
@@ -469,7 +515,7 @@ function transportForConfig(harness, { config: config2, principal }) {
469
515
  tokenPattern: HUMAN_TOKEN_PATTERN,
470
516
  unauthorizedError: () => new HumanLoginRequiredError(),
471
517
  token: () => {
472
- session = readHumanSession(routerUrl, reference);
518
+ session = readHumanSession(routerUrl, reference, principalId);
473
519
  return session.token;
474
520
  }
475
521
  });
@@ -1277,7 +1323,7 @@ var PLUGIN_GOVERNED_BANK_FIELDS = [
1277
1323
  ];
1278
1324
 
1279
1325
  // package.json
1280
- var version = "0.8.9";
1326
+ var version = "0.8.14";
1281
1327
 
1282
1328
  // src/core/util.ts
1283
1329
  import { accessSync, constants } from "fs";
@@ -1791,7 +1837,7 @@ var HindsightClient = class _HindsightClient {
1791
1837
  */
1792
1838
  async tree() {
1793
1839
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1794
- const r = await this.req("GET", this.bankUrl("/knowledge-base/tree"));
1840
+ const r = await this.req("GET", this.bankUrl("/pages/tree"));
1795
1841
  if (await this.pagesUnsupported(r)) throw new KnowledgePagesUnavailableError();
1796
1842
  if (r.status === 404) return [];
1797
1843
  this.knowledgePagesSupported = true;
@@ -1839,7 +1885,7 @@ var HindsightClient = class _HindsightClient {
1839
1885
  if (this.knowledgePagesSupported === false) throw new KnowledgePagesUnavailableError();
1840
1886
  const r = await this.req(
1841
1887
  "GET",
1842
- this.bankUrl(`/knowledge-base/pages/${encodeURIComponent(pageId)}`)
1888
+ this.bankUrl(`/pages/${encodeURIComponent(pageId)}`)
1843
1889
  );
1844
1890
  if (r.status === 404) throw new Error(`knowledge page not found: ${pageId}`);
1845
1891
  return shapePage(await r.json());
@@ -1852,7 +1898,7 @@ var HindsightClient = class _HindsightClient {
1852
1898
  const q = `?q=${encodeURIComponent(query)}&limit=${opts.limit ?? this.pageSearchLimit}`;
1853
1899
  const r = await this.req(
1854
1900
  "GET",
1855
- this.bankUrl(`/knowledge-base/search${q}`),
1901
+ this.bankUrl(`/pages/search${q}`),
1856
1902
  void 0,
1857
1903
  [],
1858
1904
  opts.timeoutMs
@@ -1871,7 +1917,7 @@ var HindsightClient = class _HindsightClient {
1871
1917
  /**
1872
1918
  * Seed the fixed page taxonomy as knowledge-base pages at the tree root, idempotently.
1873
1919
  *
1874
- * Matched by NAME, not id: `/knowledge-base/pages` mints its own `kp-…` id, so a stable
1920
+ * Matched by NAME, not id: `/pages` mints its own `kp-…` id, so a stable
1875
1921
  * client-chosen id isn't available to match on (unlike the old mental-model path, which keyed
1876
1922
  * off a slug). Names are unique per folder server-side, which makes them a sound key.
1877
1923
  *
@@ -1910,7 +1956,7 @@ var HindsightClient = class _HindsightClient {
1910
1956
  trigger: pageTriggerFor(pageTrigger, this.bank, page.name)
1911
1957
  };
1912
1958
  if (!hit) {
1913
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), body, [409]);
1959
+ const r = await this.req("POST", this.bankUrl("/pages"), body, [409]);
1914
1960
  if (await this.pagesUnsupported(r)) {
1915
1961
  this.log(
1916
1962
  `[bank] knowledge pages unavailable on ${this.apiUrl}; continuing without pages`
@@ -1937,7 +1983,7 @@ var HindsightClient = class _HindsightClient {
1937
1983
  if (triggerDrift) patch.trigger = pageTriggerPatch(body.trigger);
1938
1984
  const r = await this.req(
1939
1985
  "PATCH",
1940
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(hit.id)}`),
1986
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(hit.id)}`),
1941
1987
  patch
1942
1988
  );
1943
1989
  if (await this.pagesUnsupported(r)) {
@@ -1991,7 +2037,7 @@ var HindsightClient = class _HindsightClient {
1991
2037
  if (!patch.trigger && !patch.source_query) continue;
1992
2038
  const r = await this.req(
1993
2039
  "PATCH",
1994
- this.bankUrl(`/knowledge-base/nodes/${encodeURIComponent(page.id)}`),
2040
+ this.bankUrl(`/pages/nodes/${encodeURIComponent(page.id)}`),
1995
2041
  patch
1996
2042
  );
1997
2043
  if (r.status === 404) continue;
@@ -2020,7 +2066,7 @@ var HindsightClient = class _HindsightClient {
2020
2066
  let pageId = args.relatesToPageId;
2021
2067
  if (!pageId) {
2022
2068
  const folderId = await this.ensureFolder("Initiatives");
2023
- const r = await this.req("POST", this.bankUrl("/knowledge-base/pages"), {
2069
+ const r = await this.req("POST", this.bankUrl("/pages"), {
2024
2070
  name: args.title,
2025
2071
  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),
2026
2072
  parent_id: folderId,
@@ -2048,7 +2094,7 @@ var HindsightClient = class _HindsightClient {
2048
2094
  /** Find a root folder by name (case-insensitive) or create it; returns its id. Fail-open to undefined. */
2049
2095
  async ensureFolder(name) {
2050
2096
  try {
2051
- const tree = await (await this.req("GET", this.bankUrl("/knowledge-base/tree"))).json();
2097
+ const tree = await (await this.req("GET", this.bankUrl("/pages/tree"))).json();
2052
2098
  const hit = (tree.roots || []).find(
2053
2099
  (n) => n.kind === "folder" && (n.name || "").toLowerCase() === name.toLowerCase()
2054
2100
  );
@@ -2057,7 +2103,7 @@ var HindsightClient = class _HindsightClient {
2057
2103
  if (error instanceof AccessDeniedError) throw error;
2058
2104
  }
2059
2105
  try {
2060
- const r = await this.req("POST", this.bankUrl("/knowledge-base/folders"), { name });
2106
+ const r = await this.req("POST", this.bankUrl("/pages/folders"), { name });
2061
2107
  return (await r.json()).id;
2062
2108
  } catch (error) {
2063
2109
  if (error instanceof AccessDeniedError) throw error;