@runcore-sh/runcore 0.1.8 → 0.1.10

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 (225) hide show
  1. package/dist/access/manifest.d.ts +59 -0
  2. package/dist/access/manifest.d.ts.map +1 -0
  3. package/dist/access/manifest.js +251 -0
  4. package/dist/access/manifest.js.map +1 -0
  5. package/dist/activity/log.d.ts +1 -1
  6. package/dist/activity/log.d.ts.map +1 -1
  7. package/dist/agents/autonomous.d.ts.map +1 -1
  8. package/dist/agents/autonomous.js +38 -0
  9. package/dist/agents/autonomous.js.map +1 -1
  10. package/dist/agents/governance.d.ts +70 -0
  11. package/dist/agents/governance.d.ts.map +1 -0
  12. package/dist/agents/governance.js +220 -0
  13. package/dist/agents/governance.js.map +1 -0
  14. package/dist/agents/governed-spawn.d.ts +83 -0
  15. package/dist/agents/governed-spawn.d.ts.map +1 -0
  16. package/dist/agents/governed-spawn.js +186 -0
  17. package/dist/agents/governed-spawn.js.map +1 -0
  18. package/dist/agents/heartbeat.d.ts +91 -0
  19. package/dist/agents/heartbeat.d.ts.map +1 -0
  20. package/dist/agents/heartbeat.js +323 -0
  21. package/dist/agents/heartbeat.js.map +1 -0
  22. package/dist/agents/index.d.ts +4 -1
  23. package/dist/agents/index.d.ts.map +1 -1
  24. package/dist/agents/index.js +6 -1
  25. package/dist/agents/index.js.map +1 -1
  26. package/dist/agents/spawn-policy.d.ts +45 -0
  27. package/dist/agents/spawn-policy.d.ts.map +1 -0
  28. package/dist/agents/spawn-policy.js +202 -0
  29. package/dist/agents/spawn-policy.js.map +1 -0
  30. package/dist/alert.d.ts +16 -0
  31. package/dist/alert.d.ts.map +1 -0
  32. package/dist/alert.js +70 -0
  33. package/dist/alert.js.map +1 -0
  34. package/dist/cli.js +261 -32
  35. package/dist/cli.js.map +1 -1
  36. package/dist/credentials/store.d.ts +1 -1
  37. package/dist/credentials/store.d.ts.map +1 -1
  38. package/dist/credentials/store.js +14 -3
  39. package/dist/credentials/store.js.map +1 -1
  40. package/dist/crystallizer.d.ts +56 -0
  41. package/dist/crystallizer.d.ts.map +1 -0
  42. package/dist/crystallizer.js +159 -0
  43. package/dist/crystallizer.js.map +1 -0
  44. package/dist/distiller.d.ts +48 -0
  45. package/dist/distiller.d.ts.map +1 -0
  46. package/dist/distiller.js +140 -0
  47. package/dist/distiller.js.map +1 -0
  48. package/dist/files/deep-index.d.ts +59 -0
  49. package/dist/files/deep-index.d.ts.map +1 -0
  50. package/dist/files/deep-index.js +337 -0
  51. package/dist/files/deep-index.js.map +1 -0
  52. package/dist/files/import.d.ts +44 -0
  53. package/dist/files/import.d.ts.map +1 -0
  54. package/dist/files/import.js +213 -0
  55. package/dist/files/import.js.map +1 -0
  56. package/dist/files/index-local.d.ts +37 -0
  57. package/dist/files/index-local.d.ts.map +1 -0
  58. package/dist/files/index-local.js +198 -0
  59. package/dist/files/index-local.js.map +1 -0
  60. package/dist/google/auth.d.ts +2 -0
  61. package/dist/google/auth.d.ts.map +1 -1
  62. package/dist/google/auth.js +2 -0
  63. package/dist/google/auth.js.map +1 -1
  64. package/dist/integrations/gate.d.ts +40 -0
  65. package/dist/integrations/gate.d.ts.map +1 -0
  66. package/dist/integrations/gate.js +100 -0
  67. package/dist/integrations/gate.js.map +1 -0
  68. package/dist/lib/audit.d.ts +43 -0
  69. package/dist/lib/audit.d.ts.map +1 -0
  70. package/dist/lib/audit.js +120 -0
  71. package/dist/lib/audit.js.map +1 -0
  72. package/dist/lib/brain-io.d.ts.map +1 -1
  73. package/dist/lib/brain-io.js +52 -0
  74. package/dist/lib/brain-io.js.map +1 -1
  75. package/dist/lib/dpapi.d.ts +14 -0
  76. package/dist/lib/dpapi.d.ts.map +1 -0
  77. package/dist/lib/dpapi.js +104 -0
  78. package/dist/lib/dpapi.js.map +1 -0
  79. package/dist/lib/glob-match.d.ts +22 -0
  80. package/dist/lib/glob-match.d.ts.map +1 -0
  81. package/dist/lib/glob-match.js +64 -0
  82. package/dist/lib/glob-match.js.map +1 -0
  83. package/dist/lib/locked.d.ts +40 -0
  84. package/dist/lib/locked.d.ts.map +1 -0
  85. package/dist/lib/locked.js +130 -0
  86. package/dist/lib/locked.js.map +1 -0
  87. package/dist/llm/complete.d.ts.map +1 -1
  88. package/dist/llm/complete.js +5 -2
  89. package/dist/llm/complete.js.map +1 -1
  90. package/dist/llm/fetch-guard.d.ts +16 -0
  91. package/dist/llm/fetch-guard.d.ts.map +1 -0
  92. package/dist/llm/fetch-guard.js +61 -0
  93. package/dist/llm/fetch-guard.js.map +1 -0
  94. package/dist/llm/guard.d.ts +40 -0
  95. package/dist/llm/guard.d.ts.map +1 -0
  96. package/dist/llm/guard.js +88 -0
  97. package/dist/llm/guard.js.map +1 -0
  98. package/dist/llm/membrane.d.ts +46 -0
  99. package/dist/llm/membrane.d.ts.map +1 -0
  100. package/dist/llm/membrane.js +123 -0
  101. package/dist/llm/membrane.js.map +1 -0
  102. package/dist/llm/providers/index.d.ts +5 -1
  103. package/dist/llm/providers/index.d.ts.map +1 -1
  104. package/dist/llm/providers/index.js +8 -1
  105. package/dist/llm/providers/index.js.map +1 -1
  106. package/dist/llm/redact.d.ts +39 -0
  107. package/dist/llm/redact.d.ts.map +1 -0
  108. package/dist/llm/redact.js +155 -0
  109. package/dist/llm/redact.js.map +1 -0
  110. package/dist/llm/sensitive-registry.d.ts +33 -0
  111. package/dist/llm/sensitive-registry.d.ts.map +1 -0
  112. package/dist/llm/sensitive-registry.js +106 -0
  113. package/dist/llm/sensitive-registry.js.map +1 -0
  114. package/dist/mcp-server.d.ts +11 -0
  115. package/dist/mcp-server.d.ts.map +1 -0
  116. package/dist/mcp-server.js +520 -0
  117. package/dist/mcp-server.js.map +1 -0
  118. package/dist/mdns.d.ts +17 -0
  119. package/dist/mdns.d.ts.map +1 -0
  120. package/dist/mdns.js +110 -0
  121. package/dist/mdns.js.map +1 -0
  122. package/dist/nerve/push.d.ts +26 -0
  123. package/dist/nerve/push.d.ts.map +1 -0
  124. package/dist/nerve/push.js +170 -0
  125. package/dist/nerve/push.js.map +1 -0
  126. package/dist/nerve/state.d.ts +35 -0
  127. package/dist/nerve/state.d.ts.map +1 -0
  128. package/dist/nerve/state.js +257 -0
  129. package/dist/nerve/state.js.map +1 -0
  130. package/dist/posture/engine.d.ts +41 -0
  131. package/dist/posture/engine.d.ts.map +1 -0
  132. package/dist/posture/engine.js +217 -0
  133. package/dist/posture/engine.js.map +1 -0
  134. package/dist/posture/index.d.ts +11 -0
  135. package/dist/posture/index.d.ts.map +1 -0
  136. package/dist/posture/index.js +10 -0
  137. package/dist/posture/index.js.map +1 -0
  138. package/dist/posture/middleware.d.ts +30 -0
  139. package/dist/posture/middleware.d.ts.map +1 -0
  140. package/dist/posture/middleware.js +92 -0
  141. package/dist/posture/middleware.js.map +1 -0
  142. package/dist/posture/types.d.ts +61 -0
  143. package/dist/posture/types.d.ts.map +1 -0
  144. package/dist/posture/types.js +48 -0
  145. package/dist/posture/types.js.map +1 -0
  146. package/dist/resend/inbox.d.ts +23 -0
  147. package/dist/resend/inbox.d.ts.map +1 -0
  148. package/dist/resend/inbox.js +198 -0
  149. package/dist/resend/inbox.js.map +1 -0
  150. package/dist/resend/webhooks.d.ts +30 -0
  151. package/dist/resend/webhooks.d.ts.map +1 -0
  152. package/dist/resend/webhooks.js +244 -0
  153. package/dist/resend/webhooks.js.map +1 -0
  154. package/dist/server.d.ts +5 -1
  155. package/dist/server.d.ts.map +1 -1
  156. package/dist/server.js +773 -58
  157. package/dist/server.js.map +1 -1
  158. package/dist/settings.d.ts +14 -1
  159. package/dist/settings.d.ts.map +1 -1
  160. package/dist/settings.js +32 -1
  161. package/dist/settings.js.map +1 -1
  162. package/dist/tier/bond.d.ts +51 -0
  163. package/dist/tier/bond.d.ts.map +1 -0
  164. package/dist/tier/bond.js +154 -0
  165. package/dist/tier/bond.js.map +1 -0
  166. package/dist/tier/freeze.d.ts +21 -0
  167. package/dist/tier/freeze.d.ts.map +1 -0
  168. package/dist/tier/freeze.js +73 -0
  169. package/dist/tier/freeze.js.map +1 -0
  170. package/dist/tier/gate.d.ts +11 -0
  171. package/dist/tier/gate.d.ts.map +1 -0
  172. package/dist/tier/gate.js +25 -0
  173. package/dist/tier/gate.js.map +1 -0
  174. package/dist/tier/heartbeat.d.ts +22 -0
  175. package/dist/tier/heartbeat.d.ts.map +1 -0
  176. package/dist/tier/heartbeat.js +128 -0
  177. package/dist/tier/heartbeat.js.map +1 -0
  178. package/dist/tier/token.d.ts +22 -0
  179. package/dist/tier/token.d.ts.map +1 -0
  180. package/dist/tier/token.js +100 -0
  181. package/dist/tier/token.js.map +1 -0
  182. package/dist/tier/types.d.ts +44 -0
  183. package/dist/tier/types.d.ts.map +1 -0
  184. package/dist/tier/types.js +61 -0
  185. package/dist/tier/types.js.map +1 -0
  186. package/dist/updater.d.ts +32 -0
  187. package/dist/updater.d.ts.map +1 -0
  188. package/dist/updater.js +145 -0
  189. package/dist/updater.js.map +1 -0
  190. package/dist/vault/policy.d.ts +42 -0
  191. package/dist/vault/policy.d.ts.map +1 -0
  192. package/dist/vault/policy.js +159 -0
  193. package/dist/vault/policy.js.map +1 -0
  194. package/dist/vault/store.d.ts +6 -0
  195. package/dist/vault/store.d.ts.map +1 -1
  196. package/dist/vault/store.js +15 -5
  197. package/dist/vault/store.js.map +1 -1
  198. package/dist/vault/transfer.d.ts +33 -0
  199. package/dist/vault/transfer.d.ts.map +1 -0
  200. package/dist/vault/transfer.js +187 -0
  201. package/dist/vault/transfer.js.map +1 -0
  202. package/dist/voucher.d.ts +39 -0
  203. package/dist/voucher.d.ts.map +1 -0
  204. package/dist/voucher.js +105 -0
  205. package/dist/voucher.js.map +1 -0
  206. package/dist/webhooks/handlers.d.ts +10 -0
  207. package/dist/webhooks/handlers.d.ts.map +1 -1
  208. package/dist/webhooks/handlers.js +53 -0
  209. package/dist/webhooks/handlers.js.map +1 -1
  210. package/dist/webhooks/index.d.ts +2 -2
  211. package/dist/webhooks/index.d.ts.map +1 -1
  212. package/dist/webhooks/index.js +2 -2
  213. package/dist/webhooks/index.js.map +1 -1
  214. package/dist/webhooks/verify.d.ts +8 -0
  215. package/dist/webhooks/verify.d.ts.map +1 -1
  216. package/dist/webhooks/verify.js +56 -0
  217. package/dist/webhooks/verify.js.map +1 -1
  218. package/package.json +8 -2
  219. package/public/board.html +8 -3
  220. package/public/browser.html +8 -3
  221. package/public/library.html +8 -3
  222. package/public/observatory.html +8 -3
  223. package/public/ops.html +8 -3
  224. package/public/registry.html +627 -0
  225. package/public/roadmap.html +975 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Centralized .locked file enforcement for brain paths.
3
+ *
4
+ * Shared by both MCP server (stdio) and direct file access (brain-io).
5
+ * Ensures locked paths are consistently protected regardless of access channel.
6
+ *
7
+ * Lock rules:
8
+ * - Exact path match (e.g. "identity/human.json")
9
+ * - Filename-only match (e.g. ".session-key" matches "identity/.session-key")
10
+ * - Directory prefix match (e.g. "identity/" matches "identity/foo.md")
11
+ */
12
+ import { readFile } from "node:fs/promises";
13
+ import { readFileSync, existsSync } from "node:fs";
14
+ import { join, relative, resolve } from "node:path";
15
+ const BRAIN_DIR = resolve(process.cwd(), "brain");
16
+ const LOCKED_FILE = join(BRAIN_DIR, ".locked");
17
+ /** Hardcoded minimum locked paths (always locked even without .locked file). */
18
+ const HARDCODED_LOCKED = [".session-key", "human.json"];
19
+ /** Cached locked paths (relative to brain/, forward slashes). */
20
+ let lockedPaths = [];
21
+ let loaded = false;
22
+ /**
23
+ * Read brain/.locked and merge with hardcoded minimums. Caches result.
24
+ * Safe to call multiple times — returns cached paths after first load.
25
+ */
26
+ export async function loadLockedPaths() {
27
+ const paths = new Set(HARDCODED_LOCKED);
28
+ try {
29
+ const raw = await readFile(LOCKED_FILE, "utf-8");
30
+ for (const line of raw.split("\n")) {
31
+ const trimmed = line.trim();
32
+ if (!trimmed || trimmed.startsWith("#"))
33
+ continue;
34
+ paths.add(trimmed.replace(/\\/g, "/"));
35
+ }
36
+ }
37
+ catch {
38
+ // .locked file doesn't exist — use hardcoded only
39
+ }
40
+ lockedPaths = Array.from(paths);
41
+ loaded = true;
42
+ return lockedPaths;
43
+ }
44
+ /**
45
+ * Synchronous variant — reads .locked file on first call, caches after.
46
+ */
47
+ export function loadLockedPathsSync() {
48
+ if (loaded)
49
+ return lockedPaths;
50
+ const paths = new Set(HARDCODED_LOCKED);
51
+ try {
52
+ if (existsSync(LOCKED_FILE)) {
53
+ const raw = readFileSync(LOCKED_FILE, "utf-8");
54
+ for (const line of raw.split("\n")) {
55
+ const trimmed = line.trim();
56
+ if (!trimmed || trimmed.startsWith("#"))
57
+ continue;
58
+ paths.add(trimmed.replace(/\\/g, "/"));
59
+ }
60
+ }
61
+ }
62
+ catch {
63
+ // .locked file doesn't exist — use hardcoded only
64
+ }
65
+ lockedPaths = Array.from(paths);
66
+ loaded = true;
67
+ return lockedPaths;
68
+ }
69
+ /** Force reload of locked paths (e.g. when listing current locks). */
70
+ export async function reloadLockedPaths() {
71
+ loaded = false;
72
+ return loadLockedPaths();
73
+ }
74
+ /** Get the currently cached locked paths. Loads synchronously if not yet cached. */
75
+ export function getLockedPaths() {
76
+ if (!loaded)
77
+ loadLockedPathsSync();
78
+ return lockedPaths;
79
+ }
80
+ /**
81
+ * Check if a brain-relative path (forward slashes) is locked.
82
+ * Matches exact paths, filename-only, and directory prefixes.
83
+ */
84
+ export function isLocked(relPath) {
85
+ if (!loaded)
86
+ loadLockedPathsSync();
87
+ const normalized = relPath.replace(/\\/g, "/");
88
+ for (const locked of lockedPaths) {
89
+ // Exact match
90
+ if (normalized === locked)
91
+ return true;
92
+ // Filename-only match (e.g. ".session-key" matches "identity/.session-key")
93
+ const filename = normalized.split("/").pop() ?? "";
94
+ if (filename === locked)
95
+ return true;
96
+ // Directory prefix match (e.g. locked="identity/" matches "identity/foo.md")
97
+ if (locked.endsWith("/") && normalized.startsWith(locked))
98
+ return true;
99
+ }
100
+ return false;
101
+ }
102
+ /**
103
+ * Convert an absolute file path to a brain-relative path.
104
+ * Returns null if the path is not under brain/.
105
+ */
106
+ export function toBrainRelativePath(absolutePath) {
107
+ try {
108
+ const rel = relative(BRAIN_DIR, absolutePath);
109
+ // Escapes brain/ — not a brain path
110
+ if (rel.startsWith("..") || rel.startsWith("/"))
111
+ return null;
112
+ return rel.replace(/\\/g, "/");
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ /**
119
+ * Assert that an absolute path is not locked. Throws if locked.
120
+ * No-op for paths outside brain/.
121
+ */
122
+ export function assertNotLocked(absolutePath) {
123
+ const rel = toBrainRelativePath(absolutePath);
124
+ if (rel === null)
125
+ return; // Not a brain path — no lock applies
126
+ if (isLocked(rel)) {
127
+ throw new Error(`🔒 Locked: ${rel} — access denied`);
128
+ }
129
+ }
130
+ //# sourceMappingURL=locked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locked.js","sourceRoot":"","sources":["../../src/lib/locked.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../src/llm/complete.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AASzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,mCAAmC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF"}
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../src/llm/complete.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAUzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,mCAAmC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF"}
@@ -8,6 +8,7 @@ import { getProvider } from "./providers/index.js";
8
8
  import { completeChatCached } from "./cache.js";
9
9
  import { LLMError } from "./errors.js";
10
10
  import { withRetry } from "./retry.js";
11
+ import { rehydrateResponse } from "./redact.js";
11
12
  import { createLogger } from "../utils/logger.js";
12
13
  const log = createLogger("llm");
13
14
  /**
@@ -29,10 +30,11 @@ async function completeChatUncached(options) {
29
30
  messageCount: options.messages.length,
30
31
  });
31
32
  try {
32
- return await withRetry(() => {
33
+ const raw = await withRetry(() => {
33
34
  const timeout = AbortSignal.timeout(60_000);
34
35
  return provider.completeChat(options.messages, options.model, timeout);
35
36
  }, { maxRetries: 3, baseDelayMs: 1_000, maxDelayMs: 30_000 });
37
+ return rehydrateResponse(raw);
36
38
  }
37
39
  catch (err) {
38
40
  // On credit/billing errors from cloud providers, try Ollama as a fallback
@@ -44,10 +46,11 @@ async function completeChatUncached(options) {
44
46
  provider: options.provider,
45
47
  status: err.statusCode,
46
48
  });
47
- return withRetry(() => {
49
+ const fallbackRaw = await withRetry(() => {
48
50
  const fallbackTimeout = AbortSignal.timeout(120_000);
49
51
  return ollama.completeChat(options.messages, undefined, fallbackTimeout);
50
52
  }, { maxRetries: 3, baseDelayMs: 1_000, maxDelayMs: 30_000 });
53
+ return rehydrateResponse(fallbackRaw);
51
54
  }
52
55
  }
53
56
  throw err;
@@ -1 +1 @@
1
- {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../src/llm/complete.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;AAYhC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;AAC/E,CAAC;AAED,2EAA2E;AAC3E,KAAK,UAAU,oBAAoB,CAAC,OAA4B;IAC9D,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE/C,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;QACjC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;KACtC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CACpB,GAAG,EAAE;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,EACD,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAC1D,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACnF,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YACnD,IAAI,eAAe,EAAE,CAAC;gBACpB,GAAG,CAAC,IAAI,CAAC,0DAA0D,EAAE;oBACnE,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,MAAM,EAAE,GAAG,CAAC,UAAU;iBACvB,CAAC,CAAC;gBACH,OAAO,SAAS,CACd,GAAG,EAAE;oBACH,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACrD,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;gBAC3E,CAAC,EACD,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAC1D,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../src/llm/complete.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;AAYhC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;AAC/E,CAAC;AAED,2EAA2E;AAC3E,KAAK,UAAU,oBAAoB,CAAC,OAA4B;IAC9D,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE/C,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;QACjC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;KACtC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CACzB,GAAG,EAAE;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,EACD,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAC1D,CAAC;QACF,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACnF,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YACnD,IAAI,eAAe,EAAE,CAAC;gBACpB,GAAG,CAAC,IAAI,CAAC,0DAA0D,EAAE;oBACnE,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,MAAM,EAAE,GAAG,CAAC,UAAU;iBACvB,CAAC,CAAC;gBACH,MAAM,WAAW,GAAG,MAAM,SAAS,CACjC,GAAG,EAAE;oBACH,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACrD,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;gBAC3E,CAAC,EACD,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAC1D,CAAC;gBACF,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Global fetch interceptor — defense-in-depth for privateMode + sensitive data redaction.
3
+ *
4
+ * Two layers:
5
+ * 1. privateMode enforcement — blocks outbound requests to known cloud LLM API hosts.
6
+ * 2. Sensitive data redaction — strips secrets/PII from LLM request bodies before network egress.
7
+ *
8
+ * The function-level guard in guard.ts → assertProviderAllowed() remains the
9
+ * primary enforcement. This is the safety net.
10
+ */
11
+ /**
12
+ * Monkey-patch globalThis.fetch to block cloud LLM hosts in privateMode.
13
+ * Safe to call multiple times — only installs once.
14
+ */
15
+ export declare function installFetchGuard(): void;
16
+ //# sourceMappingURL=fetch-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-guard.d.ts","sourceRoot":"","sources":["../../src/llm/fetch-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuBH;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAiCxC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Global fetch interceptor — defense-in-depth for privateMode + sensitive data redaction.
3
+ *
4
+ * Two layers:
5
+ * 1. privateMode enforcement — blocks outbound requests to known cloud LLM API hosts.
6
+ * 2. Sensitive data redaction — strips secrets/PII from LLM request bodies before network egress.
7
+ *
8
+ * The function-level guard in guard.ts → assertProviderAllowed() remains the
9
+ * primary enforcement. This is the safety net.
10
+ */
11
+ import { isPrivateMode, PrivateModeError } from "./guard.js";
12
+ import { redactRequestBody } from "./redact.js";
13
+ import { createLogger } from "../utils/logger.js";
14
+ const log = createLogger("llm.fetch-guard");
15
+ const BLOCKED_HOSTS = new Set([
16
+ "api.openai.com",
17
+ "api.anthropic.com",
18
+ "openrouter.ai",
19
+ "api.perplexity.ai",
20
+ ]);
21
+ /** Hosts where outbound request bodies should be redacted (LLM API endpoints). */
22
+ const LLM_HOSTS = new Set([
23
+ ...BLOCKED_HOSTS,
24
+ "generativelanguage.googleapis.com",
25
+ ]);
26
+ let installed = false;
27
+ /**
28
+ * Monkey-patch globalThis.fetch to block cloud LLM hosts in privateMode.
29
+ * Safe to call multiple times — only installs once.
30
+ */
31
+ export function installFetchGuard() {
32
+ if (installed)
33
+ return;
34
+ installed = true;
35
+ const originalFetch = globalThis.fetch;
36
+ globalThis.fetch = function guardedFetch(input, init) {
37
+ let hostname;
38
+ try {
39
+ const raw = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
40
+ hostname = new URL(raw).hostname;
41
+ }
42
+ catch {
43
+ // URL parse failure — skip host-based logic
44
+ }
45
+ // Layer 1: privateMode enforcement
46
+ if (isPrivateMode() && hostname && BLOCKED_HOSTS.has(hostname)) {
47
+ log.error("Fetch guard blocked outbound request", { host: hostname });
48
+ throw new PrivateModeError("cloud-api");
49
+ }
50
+ // Layer 2: redact sensitive data from LLM request bodies
51
+ if (hostname && LLM_HOSTS.has(hostname) && init?.body && typeof init.body === "string") {
52
+ const redacted = redactRequestBody(init.body);
53
+ if (redacted !== init.body) {
54
+ init = { ...init, body: redacted };
55
+ }
56
+ }
57
+ return originalFetch.call(globalThis, input, init);
58
+ };
59
+ log.info("Fetch guard installed — privateMode enforcement + sensitive data redaction");
60
+ }
61
+ //# sourceMappingURL=fetch-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-guard.js","sourceRoot":"","sources":["../../src/llm/fetch-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;AAE5C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,gBAAgB;IAChB,mBAAmB;IACnB,eAAe;IACf,mBAAmB;CACpB,CAAC,CAAC;AAEH,kFAAkF;AAClF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,GAAG,aAAa;IAChB,mCAAmC;CACpC,CAAC,CAAC;AAEH,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IAEjB,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IAEvC,UAAU,CAAC,KAAK,GAAG,SAAS,YAAY,CAAC,KAA6B,EAAE,IAAkB;QACxF,IAAI,QAA4B,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAE,KAAiB,CAAC,GAAG,CAAC;YAC3G,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,4CAA4C;QAC9C,CAAC;QAED,mCAAmC;QACnC,IAAI,aAAa,EAAE,IAAI,QAAQ,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,sCAAsC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YACtE,MAAM,IAAI,gBAAgB,CAAC,WAAkB,CAAC,CAAC;QACjD,CAAC;QAED,yDAAyD;QACzD,IAAI,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,QAAQ,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC3B,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YACrC,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * LLM request guard — enforces privateMode at the request layer.
3
+ *
4
+ * When privateMode is enabled, ALL outbound LLM API calls to cloud providers
5
+ * are blocked. Only local providers (Ollama) are allowed through.
6
+ * This is network-level isolation, not just provider swapping.
7
+ */
8
+ import type { ProviderName } from "./providers/types.js";
9
+ /**
10
+ * Error thrown when a cloud LLM call is attempted in private mode.
11
+ * Intentionally loud — this should never be silently swallowed.
12
+ */
13
+ export declare class PrivateModeError extends Error {
14
+ constructor(provider: ProviderName);
15
+ }
16
+ /**
17
+ * Check whether the current settings enforce private mode.
18
+ * privateMode takes precedence over airplaneMode — it's the hard enforcement layer.
19
+ */
20
+ export declare function isPrivateMode(): boolean;
21
+ /**
22
+ * Assert that a provider is allowed under current mode.
23
+ * Throws PrivateModeError if a cloud provider is requested while privateMode is on.
24
+ * Call this at the request boundary, before any fetch() is made.
25
+ */
26
+ export declare function assertProviderAllowed(provider: ProviderName): void;
27
+ /**
28
+ * Lightweight Ollama health probe. Returns a result object instead of throwing,
29
+ * useful for non-critical paths (SSE error hints, status endpoints).
30
+ */
31
+ export declare function checkOllamaHealth(): Promise<{
32
+ ok: boolean;
33
+ message: string;
34
+ }>;
35
+ /**
36
+ * Check if Ollama is reachable. Used to fail loudly at startup when
37
+ * privateMode is on but Ollama isn't available.
38
+ */
39
+ export declare function assertOllamaAvailable(): Promise<void>;
40
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/llm/guard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOzD;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,QAAQ,EAAE,YAAY;CAQnC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAGvC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAOlE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAenF;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3D"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * LLM request guard — enforces privateMode at the request layer.
3
+ *
4
+ * When privateMode is enabled, ALL outbound LLM API calls to cloud providers
5
+ * are blocked. Only local providers (Ollama) are allowed through.
6
+ * This is network-level isolation, not just provider swapping.
7
+ */
8
+ import { getSettings } from "../settings.js";
9
+ import { createLogger } from "../utils/logger.js";
10
+ const log = createLogger("llm.guard");
11
+ /** Providers that are allowed in private mode (local-only, no outbound network). */
12
+ const LOCAL_PROVIDERS = new Set(["ollama"]);
13
+ /**
14
+ * Error thrown when a cloud LLM call is attempted in private mode.
15
+ * Intentionally loud — this should never be silently swallowed.
16
+ */
17
+ export class PrivateModeError extends Error {
18
+ constructor(provider) {
19
+ super(`[PRIVATE MODE] Blocked outbound LLM request to "${provider}". ` +
20
+ `privateMode is enabled — only local providers (Ollama) are allowed. ` +
21
+ `Disable privateMode in brain/settings.json to use cloud providers.`);
22
+ this.name = "PrivateModeError";
23
+ }
24
+ }
25
+ /**
26
+ * Check whether the current settings enforce private mode.
27
+ * privateMode takes precedence over airplaneMode — it's the hard enforcement layer.
28
+ */
29
+ export function isPrivateMode() {
30
+ const settings = getSettings();
31
+ return settings.privateMode === true;
32
+ }
33
+ /**
34
+ * Assert that a provider is allowed under current mode.
35
+ * Throws PrivateModeError if a cloud provider is requested while privateMode is on.
36
+ * Call this at the request boundary, before any fetch() is made.
37
+ */
38
+ export function assertProviderAllowed(provider) {
39
+ if (!isPrivateMode())
40
+ return;
41
+ if (!LOCAL_PROVIDERS.has(provider)) {
42
+ log.error("Blocked cloud LLM request in private mode", { provider });
43
+ throw new PrivateModeError(provider);
44
+ }
45
+ }
46
+ /**
47
+ * Lightweight Ollama health probe. Returns a result object instead of throwing,
48
+ * useful for non-critical paths (SSE error hints, status endpoints).
49
+ */
50
+ export async function checkOllamaHealth() {
51
+ const baseUrl = process.env.OLLAMA_URL ?? "http://localhost:11434";
52
+ try {
53
+ const res = await fetch(`${baseUrl}/api/tags`, {
54
+ method: "HEAD",
55
+ signal: AbortSignal.timeout(3_000),
56
+ });
57
+ if (!res.ok) {
58
+ return { ok: false, message: `Ollama responded with status ${res.status}` };
59
+ }
60
+ return { ok: true, message: "Ollama is reachable" };
61
+ }
62
+ catch (err) {
63
+ const msg = err instanceof Error ? err.message : String(err);
64
+ return { ok: false, message: `Ollama not available at ${baseUrl}: ${msg}` };
65
+ }
66
+ }
67
+ /**
68
+ * Check if Ollama is reachable. Used to fail loudly at startup when
69
+ * privateMode is on but Ollama isn't available.
70
+ */
71
+ export async function assertOllamaAvailable() {
72
+ const baseUrl = process.env.OLLAMA_URL ?? "http://localhost:11434";
73
+ try {
74
+ const res = await fetch(`${baseUrl}/api/tags`, {
75
+ signal: AbortSignal.timeout(5_000),
76
+ });
77
+ if (!res.ok) {
78
+ throw new Error(`Ollama responded with status ${res.status}`);
79
+ }
80
+ }
81
+ catch (err) {
82
+ const msg = err instanceof Error ? err.message : String(err);
83
+ throw new Error(`[PRIVATE MODE] Ollama is required but not available at ${baseUrl}. ` +
84
+ `privateMode blocks all cloud providers — Ollama must be running. ` +
85
+ `Error: ${msg}`);
86
+ }
87
+ }
88
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/llm/guard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;AAEtC,oFAAoF;AACpF,MAAM,eAAe,GAA8B,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,QAAsB;QAChC,KAAK,CACH,mDAAmD,QAAQ,KAAK;YAChE,sEAAsE;YACtE,oEAAoE,CACrE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,OAAO,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAsB;IAC1D,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IAE7B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,wBAAwB,CAAC;IACnE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,WAAW,EAAE;YAC7C,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,gCAAgC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9E,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,2BAA2B,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,wBAAwB,CAAC;IAEnE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,WAAW,EAAE;YAC7C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,0DAA0D,OAAO,IAAI;YACrE,mEAAmE;YACnE,UAAU,GAAG,EAAE,CAChB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * PrivacyMembrane — reversible typed-placeholder redaction.
3
+ *
4
+ * Outbound: replaces sensitive spans with `<<CATEGORY_N>>` placeholders.
5
+ * Inbound: restores placeholders to original values.
6
+ *
7
+ * Same value always maps to the same placeholder across turns.
8
+ * Audit log tracks categories + counts (never raw values).
9
+ */
10
+ import type { SensitiveRegistry } from "./sensitive-registry.js";
11
+ interface AuditEntry {
12
+ timestamp: string;
13
+ direction: "apply" | "rehydrate";
14
+ categories: Record<string, number>;
15
+ }
16
+ export declare class PrivacyMembrane {
17
+ private readonly registry;
18
+ /** original value → placeholder */
19
+ private readonly forward;
20
+ /** placeholder → original value */
21
+ private readonly reverse;
22
+ /** category → next index counter */
23
+ private readonly counters;
24
+ /** audit log (categories + counts only, never values) */
25
+ private readonly audit;
26
+ constructor(registry: SensitiveRegistry);
27
+ /**
28
+ * Replace sensitive content with typed placeholders.
29
+ * Same value always gets the same placeholder.
30
+ */
31
+ apply(text: string): string;
32
+ /**
33
+ * Restore placeholders to original values.
34
+ */
35
+ rehydrate(text: string): string;
36
+ /** Get audit log (safe — no raw values). */
37
+ getAuditLog(): readonly AuditEntry[];
38
+ /** Number of unique sensitive values tracked. */
39
+ get size(): number;
40
+ /**
41
+ * Get existing placeholder or create a new one for a value+category pair.
42
+ */
43
+ private getOrCreatePlaceholder;
44
+ }
45
+ export {};
46
+ //# sourceMappingURL=membrane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"membrane.d.ts","sourceRoot":"","sources":["../../src/llm/membrane.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQjE,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,GAAG,WAAW,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,qBAAa,eAAe;IAUd,OAAO,CAAC,QAAQ,CAAC,QAAQ;IATrC,mCAAmC;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,mCAAmC;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,oCAAoC;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;gBAEb,QAAQ,EAAE,iBAAiB;IAExD;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAgD3B;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAyB/B,4CAA4C;IAC5C,WAAW,IAAI,SAAS,UAAU,EAAE;IAIpC,iDAAiD;IACjD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAY/B"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * PrivacyMembrane — reversible typed-placeholder redaction.
3
+ *
4
+ * Outbound: replaces sensitive spans with `<<CATEGORY_N>>` placeholders.
5
+ * Inbound: restores placeholders to original values.
6
+ *
7
+ * Same value always maps to the same placeholder across turns.
8
+ * Audit log tracks categories + counts (never raw values).
9
+ */
10
+ import { createLogger } from "../utils/logger.js";
11
+ const log = createLogger("llm.membrane");
12
+ /** Matches our placeholder format: <<CATEGORY_N>> */
13
+ const PLACEHOLDER_RE = /<<([A-Z_]+_\d+)>>/g;
14
+ export class PrivacyMembrane {
15
+ registry;
16
+ /** original value → placeholder */
17
+ forward = new Map();
18
+ /** placeholder → original value */
19
+ reverse = new Map();
20
+ /** category → next index counter */
21
+ counters = new Map();
22
+ /** audit log (categories + counts only, never values) */
23
+ audit = [];
24
+ constructor(registry) {
25
+ this.registry = registry;
26
+ }
27
+ /**
28
+ * Replace sensitive content with typed placeholders.
29
+ * Same value always gets the same placeholder.
30
+ */
31
+ apply(text) {
32
+ let result = text;
33
+ const categoryCounts = {};
34
+ // 1. Explicit terms (longest-first, from registry)
35
+ for (const term of this.registry.sensitiveTerms) {
36
+ if (!result.includes(term.value))
37
+ continue;
38
+ const ph = this.getOrCreatePlaceholder(term.value, term.category);
39
+ // Use split+join for literal replacement (no regex escaping needed)
40
+ const before = result;
41
+ result = result.split(term.value).join(ph);
42
+ if (result !== before) {
43
+ const count = (before.length - result.length + ph.length * ((before.length - result.length) / (term.value.length - ph.length) || 1));
44
+ categoryCounts[term.category] = (categoryCounts[term.category] ?? 0) + 1;
45
+ }
46
+ }
47
+ // 2. Pattern-based detection (built-in + custom from registry)
48
+ for (const rule of this.registry.patterns) {
49
+ rule.pattern.lastIndex = 0;
50
+ const matches = result.match(rule.pattern);
51
+ rule.pattern.lastIndex = 0;
52
+ if (!matches)
53
+ continue;
54
+ for (const match of matches) {
55
+ // Skip false positives for CARD rule
56
+ if (rule.category === "CARD" && match.replace(/[\s-]/g, "").length < 13)
57
+ continue;
58
+ // Don't re-redact something already replaced with a placeholder
59
+ if (match.startsWith("<<") && match.endsWith(">>"))
60
+ continue;
61
+ const ph = this.getOrCreatePlaceholder(match, rule.category);
62
+ result = result.replace(match, ph);
63
+ categoryCounts[rule.category] = (categoryCounts[rule.category] ?? 0) + 1;
64
+ }
65
+ }
66
+ if (Object.keys(categoryCounts).length > 0) {
67
+ this.audit.push({
68
+ timestamp: new Date().toISOString(),
69
+ direction: "apply",
70
+ categories: categoryCounts,
71
+ });
72
+ log.info("Membrane applied", { categories: categoryCounts });
73
+ }
74
+ return result;
75
+ }
76
+ /**
77
+ * Restore placeholders to original values.
78
+ */
79
+ rehydrate(text) {
80
+ const categoryCounts = {};
81
+ const result = text.replace(PLACEHOLDER_RE, (match) => {
82
+ const original = this.reverse.get(match);
83
+ if (original) {
84
+ const cat = match.replace(/<<|_\d+>>/g, "");
85
+ categoryCounts[cat] = (categoryCounts[cat] ?? 0) + 1;
86
+ return original;
87
+ }
88
+ return match; // unknown placeholder — leave as-is
89
+ });
90
+ if (Object.keys(categoryCounts).length > 0) {
91
+ this.audit.push({
92
+ timestamp: new Date().toISOString(),
93
+ direction: "rehydrate",
94
+ categories: categoryCounts,
95
+ });
96
+ log.debug("Membrane rehydrated", { categories: categoryCounts });
97
+ }
98
+ return result;
99
+ }
100
+ /** Get audit log (safe — no raw values). */
101
+ getAuditLog() {
102
+ return this.audit;
103
+ }
104
+ /** Number of unique sensitive values tracked. */
105
+ get size() {
106
+ return this.forward.size;
107
+ }
108
+ /**
109
+ * Get existing placeholder or create a new one for a value+category pair.
110
+ */
111
+ getOrCreatePlaceholder(value, category) {
112
+ const existing = this.forward.get(value);
113
+ if (existing)
114
+ return existing;
115
+ const idx = this.counters.get(category) ?? 0;
116
+ this.counters.set(category, idx + 1);
117
+ const placeholder = `<<${category}_${idx}>>`;
118
+ this.forward.set(value, placeholder);
119
+ this.reverse.set(placeholder, value);
120
+ return placeholder;
121
+ }
122
+ }
123
+ //# sourceMappingURL=membrane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"membrane.js","sourceRoot":"","sources":["../../src/llm/membrane.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,10 @@
3
3
  * Manages provider instances and provides a single entry point for LLM operations.
4
4
  */
5
5
  import type { LLMProvider, ProviderName } from "./types.js";
6
- /** Get a provider by name. Throws if unknown. */
6
+ /**
7
+ * Get a provider by name. Throws if unknown.
8
+ * Enforces privateMode — cloud providers are blocked when private mode is on.
9
+ */
7
10
  export declare function getProvider(name: ProviderName): LLMProvider;
8
11
  /** Register a custom provider (for plugins or testing). */
9
12
  export declare function registerProvider(provider: LLMProvider): void;
@@ -17,4 +20,5 @@ export { anthropicProvider } from "./anthropic.js";
17
20
  export { openAIProvider } from "./openai.js";
18
21
  export { ollamaProvider } from "./ollama.js";
19
22
  export { LLMError, classifyApiError } from "../errors.js";
23
+ export { PrivateModeError, isPrivateMode } from "../guard.js";
20
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAC;AAkB3E,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CAI3D;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAG5D;AAED,0CAA0C;AAC1C,wBAAgB,aAAa,IAAI,YAAY,EAAE,CAE9C;AAED,qFAAqF;AACrF,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAQrE;AAID,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAC;AAmB3E;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CAO3D;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAG5D;AAED,0CAA0C;AAC1C,wBAAgB,aAAa,IAAI,YAAY,EAAE,CAE9C;AAED,qFAAqF;AACrF,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAQrE;AAID,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}