fixo-cli 1.0.0

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 (303) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +530 -0
  3. package/dist/agent/agent-client.d.ts +108 -0
  4. package/dist/agent/agent-client.d.ts.map +1 -0
  5. package/dist/agent/agent-client.js +1247 -0
  6. package/dist/agent/agent-client.js.map +1 -0
  7. package/dist/agent/agent-pool.d.ts +20 -0
  8. package/dist/agent/agent-pool.d.ts.map +1 -0
  9. package/dist/agent/agent-pool.js +217 -0
  10. package/dist/agent/agent-pool.js.map +1 -0
  11. package/dist/agent/background-awareness.d.ts +55 -0
  12. package/dist/agent/background-awareness.d.ts.map +1 -0
  13. package/dist/agent/background-awareness.js +104 -0
  14. package/dist/agent/background-awareness.js.map +1 -0
  15. package/dist/agent/command-parser.d.ts +33 -0
  16. package/dist/agent/command-parser.d.ts.map +1 -0
  17. package/dist/agent/command-parser.js +120 -0
  18. package/dist/agent/command-parser.js.map +1 -0
  19. package/dist/agent/context-budget.d.ts +91 -0
  20. package/dist/agent/context-budget.d.ts.map +1 -0
  21. package/dist/agent/context-budget.js +219 -0
  22. package/dist/agent/context-budget.js.map +1 -0
  23. package/dist/agent/conversation.d.ts +190 -0
  24. package/dist/agent/conversation.d.ts.map +1 -0
  25. package/dist/agent/conversation.js +547 -0
  26. package/dist/agent/conversation.js.map +1 -0
  27. package/dist/agent/hooks.d.ts +72 -0
  28. package/dist/agent/hooks.d.ts.map +1 -0
  29. package/dist/agent/hooks.js +214 -0
  30. package/dist/agent/hooks.js.map +1 -0
  31. package/dist/agent/mcp-bridge.d.ts +13 -0
  32. package/dist/agent/mcp-bridge.d.ts.map +1 -0
  33. package/dist/agent/mcp-bridge.js +86 -0
  34. package/dist/agent/mcp-bridge.js.map +1 -0
  35. package/dist/agent/mcp-client.d.ts +24 -0
  36. package/dist/agent/mcp-client.d.ts.map +1 -0
  37. package/dist/agent/mcp-client.js +146 -0
  38. package/dist/agent/mcp-client.js.map +1 -0
  39. package/dist/agent/mcp-manager.d.ts +13 -0
  40. package/dist/agent/mcp-manager.d.ts.map +1 -0
  41. package/dist/agent/mcp-manager.js +84 -0
  42. package/dist/agent/mcp-manager.js.map +1 -0
  43. package/dist/agent/mcp-registry.d.ts +45 -0
  44. package/dist/agent/mcp-registry.d.ts.map +1 -0
  45. package/dist/agent/mcp-registry.js +98 -0
  46. package/dist/agent/mcp-registry.js.map +1 -0
  47. package/dist/agent/orchestrator.d.ts +14 -0
  48. package/dist/agent/orchestrator.d.ts.map +1 -0
  49. package/dist/agent/orchestrator.js +118 -0
  50. package/dist/agent/orchestrator.js.map +1 -0
  51. package/dist/agent/parser-adapter.d.ts +120 -0
  52. package/dist/agent/parser-adapter.d.ts.map +1 -0
  53. package/dist/agent/parser-adapter.js +265 -0
  54. package/dist/agent/parser-adapter.js.map +1 -0
  55. package/dist/agent/parsers/imports.d.ts +11 -0
  56. package/dist/agent/parsers/imports.d.ts.map +1 -0
  57. package/dist/agent/parsers/imports.js +94 -0
  58. package/dist/agent/parsers/imports.js.map +1 -0
  59. package/dist/agent/parsers/shell.d.ts +23 -0
  60. package/dist/agent/parsers/shell.d.ts.map +1 -0
  61. package/dist/agent/parsers/shell.js +200 -0
  62. package/dist/agent/parsers/shell.js.map +1 -0
  63. package/dist/agent/parsers/symbols.d.ts +17 -0
  64. package/dist/agent/parsers/symbols.d.ts.map +1 -0
  65. package/dist/agent/parsers/symbols.js +103 -0
  66. package/dist/agent/parsers/symbols.js.map +1 -0
  67. package/dist/agent/permissions.d.ts +65 -0
  68. package/dist/agent/permissions.d.ts.map +1 -0
  69. package/dist/agent/permissions.js +219 -0
  70. package/dist/agent/permissions.js.map +1 -0
  71. package/dist/agent/predictive-gate.d.ts +69 -0
  72. package/dist/agent/predictive-gate.d.ts.map +1 -0
  73. package/dist/agent/predictive-gate.js +128 -0
  74. package/dist/agent/predictive-gate.js.map +1 -0
  75. package/dist/agent/provider-cooldown.d.ts +144 -0
  76. package/dist/agent/provider-cooldown.d.ts.map +1 -0
  77. package/dist/agent/provider-cooldown.js +300 -0
  78. package/dist/agent/provider-cooldown.js.map +1 -0
  79. package/dist/agent/providers-manager.d.ts +109 -0
  80. package/dist/agent/providers-manager.d.ts.map +1 -0
  81. package/dist/agent/providers-manager.js +464 -0
  82. package/dist/agent/providers-manager.js.map +1 -0
  83. package/dist/agent/repo-map.d.ts +6 -0
  84. package/dist/agent/repo-map.d.ts.map +1 -0
  85. package/dist/agent/repo-map.js +221 -0
  86. package/dist/agent/repo-map.js.map +1 -0
  87. package/dist/agent/retry.d.ts +103 -0
  88. package/dist/agent/retry.d.ts.map +1 -0
  89. package/dist/agent/retry.js +276 -0
  90. package/dist/agent/retry.js.map +1 -0
  91. package/dist/agent/search/index.d.ts +61 -0
  92. package/dist/agent/search/index.d.ts.map +1 -0
  93. package/dist/agent/search/index.js +314 -0
  94. package/dist/agent/search/index.js.map +1 -0
  95. package/dist/agent/single-agent.d.ts +76 -0
  96. package/dist/agent/single-agent.d.ts.map +1 -0
  97. package/dist/agent/single-agent.js +697 -0
  98. package/dist/agent/single-agent.js.map +1 -0
  99. package/dist/agent/skills.d.ts +22 -0
  100. package/dist/agent/skills.d.ts.map +1 -0
  101. package/dist/agent/skills.js +139 -0
  102. package/dist/agent/skills.js.map +1 -0
  103. package/dist/agent/stream-glue.d.ts +85 -0
  104. package/dist/agent/stream-glue.d.ts.map +1 -0
  105. package/dist/agent/stream-glue.js +120 -0
  106. package/dist/agent/stream-glue.js.map +1 -0
  107. package/dist/agent/subagent.d.ts +72 -0
  108. package/dist/agent/subagent.d.ts.map +1 -0
  109. package/dist/agent/subagent.js +193 -0
  110. package/dist/agent/subagent.js.map +1 -0
  111. package/dist/agent/telemetry.d.ts +192 -0
  112. package/dist/agent/telemetry.d.ts.map +1 -0
  113. package/dist/agent/telemetry.js +400 -0
  114. package/dist/agent/telemetry.js.map +1 -0
  115. package/dist/agent/tokenizer.d.ts +42 -0
  116. package/dist/agent/tokenizer.d.ts.map +1 -0
  117. package/dist/agent/tokenizer.js +107 -0
  118. package/dist/agent/tokenizer.js.map +1 -0
  119. package/dist/agent/tool-executor.d.ts +289 -0
  120. package/dist/agent/tool-executor.d.ts.map +1 -0
  121. package/dist/agent/tool-executor.js +2519 -0
  122. package/dist/agent/tool-executor.js.map +1 -0
  123. package/dist/agent/web-impl.d.ts +2 -0
  124. package/dist/agent/web-impl.d.ts.map +1 -0
  125. package/dist/agent/web-impl.js +34 -0
  126. package/dist/agent/web-impl.js.map +1 -0
  127. package/dist/agent/web.d.ts +8 -0
  128. package/dist/agent/web.d.ts.map +1 -0
  129. package/dist/agent/web.js +8 -0
  130. package/dist/agent/web.js.map +1 -0
  131. package/dist/agent/worker-agent.d.ts +27 -0
  132. package/dist/agent/worker-agent.d.ts.map +1 -0
  133. package/dist/agent/worker-agent.js +503 -0
  134. package/dist/agent/worker-agent.js.map +1 -0
  135. package/dist/config.d.ts +162 -0
  136. package/dist/config.d.ts.map +1 -0
  137. package/dist/config.js +138 -0
  138. package/dist/config.js.map +1 -0
  139. package/dist/context/fixo-md-watcher.d.ts +42 -0
  140. package/dist/context/fixo-md-watcher.d.ts.map +1 -0
  141. package/dist/context/fixo-md-watcher.js +126 -0
  142. package/dist/context/fixo-md-watcher.js.map +1 -0
  143. package/dist/context/fixo-md.d.ts +50 -0
  144. package/dist/context/fixo-md.d.ts.map +1 -0
  145. package/dist/context/fixo-md.js +118 -0
  146. package/dist/context/fixo-md.js.map +1 -0
  147. package/dist/context/todo.d.ts +65 -0
  148. package/dist/context/todo.d.ts.map +1 -0
  149. package/dist/context/todo.js +194 -0
  150. package/dist/context/todo.js.map +1 -0
  151. package/dist/git/git-manager.d.ts +33 -0
  152. package/dist/git/git-manager.d.ts.map +1 -0
  153. package/dist/git/git-manager.js +293 -0
  154. package/dist/git/git-manager.js.map +1 -0
  155. package/dist/git/git-ops.d.ts +10 -0
  156. package/dist/git/git-ops.d.ts.map +1 -0
  157. package/dist/git/git-ops.js +131 -0
  158. package/dist/git/git-ops.js.map +1 -0
  159. package/dist/index.d.ts +3 -0
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +352 -0
  162. package/dist/index.js.map +1 -0
  163. package/dist/indexer.d.ts +30 -0
  164. package/dist/indexer.d.ts.map +1 -0
  165. package/dist/indexer.js +273 -0
  166. package/dist/indexer.js.map +1 -0
  167. package/dist/lsp/lsp-client.d.ts +24 -0
  168. package/dist/lsp/lsp-client.d.ts.map +1 -0
  169. package/dist/lsp/lsp-client.js +205 -0
  170. package/dist/lsp/lsp-client.js.map +1 -0
  171. package/dist/lsp/lsp-manager.d.ts +17 -0
  172. package/dist/lsp/lsp-manager.d.ts.map +1 -0
  173. package/dist/lsp/lsp-manager.js +154 -0
  174. package/dist/lsp/lsp-manager.js.map +1 -0
  175. package/dist/lsp/lsp-pre-save.d.ts +137 -0
  176. package/dist/lsp/lsp-pre-save.d.ts.map +1 -0
  177. package/dist/lsp/lsp-pre-save.js +245 -0
  178. package/dist/lsp/lsp-pre-save.js.map +1 -0
  179. package/dist/lsp/syntax-fallback.d.ts +83 -0
  180. package/dist/lsp/syntax-fallback.d.ts.map +1 -0
  181. package/dist/lsp/syntax-fallback.js +275 -0
  182. package/dist/lsp/syntax-fallback.js.map +1 -0
  183. package/dist/model-outcomes.d.ts +12 -0
  184. package/dist/model-outcomes.d.ts.map +1 -0
  185. package/dist/model-outcomes.js +46 -0
  186. package/dist/model-outcomes.js.map +1 -0
  187. package/dist/planner.d.ts +32 -0
  188. package/dist/planner.d.ts.map +1 -0
  189. package/dist/planner.js +163 -0
  190. package/dist/planner.js.map +1 -0
  191. package/dist/project-memory.d.ts +29 -0
  192. package/dist/project-memory.d.ts.map +1 -0
  193. package/dist/project-memory.js +349 -0
  194. package/dist/project-memory.js.map +1 -0
  195. package/dist/review.d.ts +2 -0
  196. package/dist/review.d.ts.map +1 -0
  197. package/dist/review.js +61 -0
  198. package/dist/review.js.map +1 -0
  199. package/dist/runtime/background-jobs.d.ts +97 -0
  200. package/dist/runtime/background-jobs.d.ts.map +1 -0
  201. package/dist/runtime/background-jobs.js +331 -0
  202. package/dist/runtime/background-jobs.js.map +1 -0
  203. package/dist/runtime/credential-vault.d.ts +124 -0
  204. package/dist/runtime/credential-vault.d.ts.map +1 -0
  205. package/dist/runtime/credential-vault.js +184 -0
  206. package/dist/runtime/credential-vault.js.map +1 -0
  207. package/dist/runtime/loop-trap.d.ts +197 -0
  208. package/dist/runtime/loop-trap.d.ts.map +1 -0
  209. package/dist/runtime/loop-trap.js +420 -0
  210. package/dist/runtime/loop-trap.js.map +1 -0
  211. package/dist/runtime/policy.d.ts +15 -0
  212. package/dist/runtime/policy.d.ts.map +1 -0
  213. package/dist/runtime/policy.js +60 -0
  214. package/dist/runtime/policy.js.map +1 -0
  215. package/dist/runtime/redaction.d.ts +66 -0
  216. package/dist/runtime/redaction.d.ts.map +1 -0
  217. package/dist/runtime/redaction.js +155 -0
  218. package/dist/runtime/redaction.js.map +1 -0
  219. package/dist/runtime/session-snapshots.d.ts +76 -0
  220. package/dist/runtime/session-snapshots.d.ts.map +1 -0
  221. package/dist/runtime/session-snapshots.js +166 -0
  222. package/dist/runtime/session-snapshots.js.map +1 -0
  223. package/dist/runtime/staging.d.ts +205 -0
  224. package/dist/runtime/staging.d.ts.map +1 -0
  225. package/dist/runtime/staging.js +526 -0
  226. package/dist/runtime/staging.js.map +1 -0
  227. package/dist/runtime/task-session.d.ts +95 -0
  228. package/dist/runtime/task-session.d.ts.map +1 -0
  229. package/dist/runtime/task-session.js +263 -0
  230. package/dist/runtime/task-session.js.map +1 -0
  231. package/dist/runtime/worktree.d.ts +55 -0
  232. package/dist/runtime/worktree.d.ts.map +1 -0
  233. package/dist/runtime/worktree.js +175 -0
  234. package/dist/runtime/worktree.js.map +1 -0
  235. package/dist/setup-wizard.d.ts +8 -0
  236. package/dist/setup-wizard.d.ts.map +1 -0
  237. package/dist/setup-wizard.js +73 -0
  238. package/dist/setup-wizard.js.map +1 -0
  239. package/dist/shared/content.d.ts +43 -0
  240. package/dist/shared/content.d.ts.map +1 -0
  241. package/dist/shared/content.js +61 -0
  242. package/dist/shared/content.js.map +1 -0
  243. package/dist/shared/types.d.ts +217 -0
  244. package/dist/shared/types.d.ts.map +1 -0
  245. package/dist/shared/types.js +3 -0
  246. package/dist/shared/types.js.map +1 -0
  247. package/dist/test-runner.d.ts +5 -0
  248. package/dist/test-runner.d.ts.map +1 -0
  249. package/dist/test-runner.js +42 -0
  250. package/dist/test-runner.js.map +1 -0
  251. package/dist/types.d.ts +85 -0
  252. package/dist/types.d.ts.map +1 -0
  253. package/dist/types.js +2 -0
  254. package/dist/types.js.map +1 -0
  255. package/dist/ui/ascii.d.ts +23 -0
  256. package/dist/ui/ascii.d.ts.map +1 -0
  257. package/dist/ui/ascii.js +45 -0
  258. package/dist/ui/ascii.js.map +1 -0
  259. package/dist/ui/colors.d.ts +111 -0
  260. package/dist/ui/colors.d.ts.map +1 -0
  261. package/dist/ui/colors.js +166 -0
  262. package/dist/ui/colors.js.map +1 -0
  263. package/dist/ui/image-attach.d.ts +27 -0
  264. package/dist/ui/image-attach.d.ts.map +1 -0
  265. package/dist/ui/image-attach.js +100 -0
  266. package/dist/ui/image-attach.js.map +1 -0
  267. package/dist/ui/index.d.ts +18 -0
  268. package/dist/ui/index.d.ts.map +1 -0
  269. package/dist/ui/index.js +18 -0
  270. package/dist/ui/index.js.map +1 -0
  271. package/dist/ui/markdown-stream.d.ts +91 -0
  272. package/dist/ui/markdown-stream.d.ts.map +1 -0
  273. package/dist/ui/markdown-stream.js +524 -0
  274. package/dist/ui/markdown-stream.js.map +1 -0
  275. package/dist/ui/plan-renderer.d.ts +36 -0
  276. package/dist/ui/plan-renderer.d.ts.map +1 -0
  277. package/dist/ui/plan-renderer.js +79 -0
  278. package/dist/ui/plan-renderer.js.map +1 -0
  279. package/dist/ui/prompt.d.ts +11 -0
  280. package/dist/ui/prompt.d.ts.map +1 -0
  281. package/dist/ui/prompt.js +1960 -0
  282. package/dist/ui/prompt.js.map +1 -0
  283. package/dist/ui/render-primitives.d.ts +117 -0
  284. package/dist/ui/render-primitives.d.ts.map +1 -0
  285. package/dist/ui/render-primitives.js +322 -0
  286. package/dist/ui/render-primitives.js.map +1 -0
  287. package/dist/ui/render.d.ts +133 -0
  288. package/dist/ui/render.d.ts.map +1 -0
  289. package/dist/ui/render.js +547 -0
  290. package/dist/ui/render.js.map +1 -0
  291. package/dist/ui/session-header.d.ts +30 -0
  292. package/dist/ui/session-header.d.ts.map +1 -0
  293. package/dist/ui/session-header.js +74 -0
  294. package/dist/ui/session-header.js.map +1 -0
  295. package/dist/workspace-guard.d.ts +68 -0
  296. package/dist/workspace-guard.d.ts.map +1 -0
  297. package/dist/workspace-guard.js +168 -0
  298. package/dist/workspace-guard.js.map +1 -0
  299. package/dist/workspace-lock.d.ts +27 -0
  300. package/dist/workspace-lock.d.ts.map +1 -0
  301. package/dist/workspace-lock.js +95 -0
  302. package/dist/workspace-lock.js.map +1 -0
  303. package/package.json +63 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * symbols.ts — Per-language symbol extraction using pure regex.
3
+ *
4
+ * Output is intentionally limited to the first `MAX_SYMBOLS_PER_FILE`
5
+ * matches so we never blow up the LLM's context window on a single
6
+ * oversized file. Coordinates are 1-based, line-inclusive, end-inclusive
7
+ * to match the LSP convention.
8
+ */
9
+ const MAX_SYMBOLS_PER_FILE = 100;
10
+ const JS_TS_PATTERNS = [
11
+ // export class Foo / class Foo
12
+ { re: /^[ \t]*(?:export\s+(?:default\s+)?|abstract\s+)?class\s+([A-Za-z_$][\w$]*)/gm, kind: 'class' },
13
+ // export interface Foo
14
+ { re: /^[ \t]*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)/gm, kind: 'interface' },
15
+ // export type Foo
16
+ { re: /^[ \t]*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)/gm, kind: 'type' },
17
+ // export enum Foo
18
+ { re: /^[ \t]*(?:export\s+)?enum\s+([A-Za-z_$][\w$]*)/gm, kind: 'enum' },
19
+ // function foo(...)
20
+ {
21
+ re: /^[ \t]*(?:export\s+(?:default\s+)?)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/gm,
22
+ kind: 'function',
23
+ },
24
+ // const/let/var foo = ...
25
+ {
26
+ re: /^[ \t]*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/gm,
27
+ kind: 'const',
28
+ },
29
+ ];
30
+ const PYTHON_PATTERNS = [
31
+ { re: /^[ \t]*class\s+([A-Za-z_][\w]*)/gm, kind: 'class' },
32
+ { re: /^[ \t]*(?:async\s+)?def\s+([A-Za-z_][\w]*)/gm, kind: 'function' },
33
+ ];
34
+ const GO_PATTERNS = [
35
+ { re: /^[ \t]*type\s+([A-Za-z_][\w]*)\s+struct/gm, kind: 'type' },
36
+ { re: /^[ \t]*type\s+([A-Za-z_][\w]*)\s+interface/gm, kind: 'interface' },
37
+ { re: /^[ \t]*func\s+(?:\([^)]*\)\s+)?([A-Za-z_][\w]*)/gm, kind: 'function' },
38
+ { re: /^[ \t]*(?:var|const)\s+([A-Za-z_][\w]*)/gm, kind: 'const' },
39
+ ];
40
+ const RUST_PATTERNS = [
41
+ { re: /^[ \t]*(?:pub\s+)?(?:async\s+)?fn\s+([A-Za-z_][\w]*)/gm, kind: 'function' },
42
+ { re: /^[ \t]*(?:pub\s+)?struct\s+([A-Za-z_][\w]*)/gm, kind: 'type' },
43
+ { re: /^[ \t]*(?:pub\s+)?enum\s+([A-Za-z_][\w]*)/gm, kind: 'enum' },
44
+ { re: /^[ \t]*(?:pub\s+)?trait\s+([A-Za-z_][\w]*)/gm, kind: 'interface' },
45
+ ];
46
+ const GENERIC_PATTERNS = [
47
+ {
48
+ re: /\b(?:export\s+)?(?:class|function|interface|type|const|let|var|enum)\s+([A-Za-z_$][\w$]*)/g,
49
+ kind: 'unknown',
50
+ },
51
+ ];
52
+ const PATTERNS = {
53
+ typescript: JS_TS_PATTERNS,
54
+ javascript: JS_TS_PATTERNS,
55
+ python: PYTHON_PATTERNS,
56
+ go: GO_PATTERNS,
57
+ rust: RUST_PATTERNS,
58
+ bash: [],
59
+ json: [],
60
+ markdown: [],
61
+ generic: GENERIC_PATTERNS,
62
+ };
63
+ /**
64
+ * Extracts symbol declarations from `source`. The result is capped at
65
+ * `MAX_SYMBOLS_PER_FILE` entries and deduped by name; the first
66
+ * occurrence wins so an `export class Foo` is preferred over a later
67
+ * `class Foo` reference.
68
+ */
69
+ export function extractSymbols(source, language) {
70
+ const patterns = PATTERNS[language] ?? GENERIC_PATTERNS;
71
+ if (patterns.length === 0)
72
+ return [];
73
+ const out = [];
74
+ const seen = new Set();
75
+ const lines = source.split('\n');
76
+ const totalLines = lines.length;
77
+ for (const { re, kind } of patterns) {
78
+ re.lastIndex = 0;
79
+ let match;
80
+ while ((match = re.exec(source)) !== null) {
81
+ if (out.length >= MAX_SYMBOLS_PER_FILE)
82
+ return out;
83
+ const name = match[1];
84
+ if (!name || seen.has(name))
85
+ continue;
86
+ seen.add(name);
87
+ const startIndex = match.index;
88
+ const line = indexToLine(source, startIndex);
89
+ const exported = /^\s*export\b/m.test(match[0]);
90
+ out.push({ name, kind, line, endLine: Math.min(totalLines, line + 5), exported });
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ function indexToLine(source, index) {
96
+ let line = 1;
97
+ for (let i = 0; i < index && i < source.length; i++) {
98
+ if (source.charCodeAt(i) === 10)
99
+ line++;
100
+ }
101
+ return line;
102
+ }
103
+ //# sourceMappingURL=symbols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../../../src/agent/parsers/symbols.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { type PolicyProfile } from '../runtime/policy.js';
2
+ export type PermissionDecision = 'allow' | 'ask' | 'deny';
3
+ export interface PermissionRule {
4
+ /** Glob pattern in the form `Tool(pattern)`. */
5
+ pattern: string;
6
+ decision: PermissionDecision;
7
+ /** Optional human-readable reason (shown when denying). */
8
+ reason?: string;
9
+ }
10
+ export interface PermissionsFile {
11
+ version: 1;
12
+ rules: PermissionRule[];
13
+ }
14
+ export interface PermissionCheckResult {
15
+ decision: PermissionDecision;
16
+ reason: string;
17
+ matchedRule: string | null;
18
+ source: 'rule' | 'default-ask' | 'fallback-policy';
19
+ }
20
+ /**
21
+ * Tools introduced in Phases 1–3. When the user runs one of
22
+ * these with no matching rule, we force `ask` (rather than
23
+ * letting `decidePolicy` quietly return `allow`).
24
+ */
25
+ export declare const NEW_TOOL_DEFAULT_ASK: ReadonlySet<string>;
26
+ /** Read `.fixo/permissions.json` from cwd. */
27
+ export declare function loadPermissionsFile(cwd: string): PermissionsFile | null;
28
+ /** Save the permissions file. */
29
+ export declare function savePermissionsFile(cwd: string, file: PermissionsFile): {
30
+ ok: boolean;
31
+ error?: string;
32
+ };
33
+ /** Get the permissions file path (test-only introspection). */
34
+ export declare function getPermissionsPath(cwd: string): string;
35
+ /**
36
+ * Convert a glob pattern to a RegExp anchored at both ends.
37
+ * - `*` matches any chars except `/`
38
+ * - `**` matches any chars including `/`
39
+ * - `?` matches any single char except `/`
40
+ */
41
+ export declare function globToRegExp(glob: string): RegExp;
42
+ /** Parse `Tool(pattern)` into `{tool, argPattern}`. */
43
+ export declare function parseRulePattern(pattern: string): {
44
+ tool: string;
45
+ argPattern: string | null;
46
+ };
47
+ /**
48
+ * Build the input string that the rule's argPattern matches
49
+ * against. We pick a sensible string projection of args
50
+ * for the tool at hand. For most tools, that's the joined
51
+ * string of all arg values. This is intentionally simple —
52
+ * it lets users write rules like Edit(src/dstar/star.ts)
53
+ * and have them work.
54
+ */
55
+ export declare function buildArgString(tool: string, args: Record<string, unknown>): string;
56
+ /** Match a tool call against the rule list (first match wins). */
57
+ export declare function matchPermission(tool: string, args: Record<string, unknown>, rules: PermissionRule[]): PermissionRule | null;
58
+ /**
59
+ * Top-level check: try a rule match, then fall back to
60
+ * `decidePolicy` for the legacy policy logic, then apply
61
+ * the default-ask rule for new tools. Returns a unified
62
+ * `PermissionCheckResult`.
63
+ */
64
+ export declare function checkPermission(tool: string, args: Record<string, unknown>, cwd: string, profile: PolicyProfile): PermissionCheckResult;
65
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/agent/permissions.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,iBAAiB,CAAC;CACpD;AAID;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAOnD,CAAC;AAEH,8CAA8C;AAC9C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAUvE;AAED,iCAAiC;AACjC,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,eAAe,GACpB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CASjC;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BjD;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAI7F;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAclF;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,cAAc,EAAE,GACtB,cAAc,GAAG,IAAI,CAevB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,aAAa,GACrB,qBAAqB,CAqCvB"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * permissions.ts — Pattern-based permission rules.
3
+ *
4
+ * Phase 3.5 spec:
5
+ * - Each rule is a glob-style pattern over
6
+ * `Tool(arg-glob)`. Examples:
7
+ * Bash(npm test:star) — any run_command with the
8
+ * "npm test..." shell text.
9
+ * Edit(src/dstar/star.ts) — any tool whose args.path
10
+ * matches the glob.
11
+ * - First-match-wins: rules are evaluated top-to-bottom;
12
+ * the first match returns the decision.
13
+ * - Decision values: allow (auto), ask (default — prompt
14
+ * the user), deny (block).
15
+ * - Fallback: when no rule matches, call
16
+ * decidePolicy(profile, action, detail, allowRules)
17
+ * from runtime/policy.ts.
18
+ * - Storage: <cwd>/.fixo/permissions.json.
19
+ * - Default rules: every tool introduced in Phases 1–3
20
+ * defaults to ask if no rule is configured.
21
+ */
22
+ import fs from 'node:fs';
23
+ import path from 'node:path';
24
+ import { decidePolicy, } from '../runtime/policy.js';
25
+ const PERMISSIONS_PATH_FOR = (cwd) => path.join(cwd, '.fixo', 'permissions.json');
26
+ /**
27
+ * Tools introduced in Phases 1–3. When the user runs one of
28
+ * these with no matching rule, we force `ask` (rather than
29
+ * letting `decidePolicy` quietly return `allow`).
30
+ */
31
+ export const NEW_TOOL_DEFAULT_ASK = new Set([
32
+ 'str_replace',
33
+ 'glob_files',
34
+ 'todo_write',
35
+ 'run_command_async',
36
+ 'poll_command_status',
37
+ 'kill_command',
38
+ ]);
39
+ /** Read `.fixo/permissions.json` from cwd. */
40
+ export function loadPermissionsFile(cwd) {
41
+ const p = PERMISSIONS_PATH_FOR(cwd);
42
+ if (!fs.existsSync(p))
43
+ return null;
44
+ try {
45
+ const raw = JSON.parse(fs.readFileSync(p, 'utf-8'));
46
+ if (raw.version !== 1 || !Array.isArray(raw.rules))
47
+ return null;
48
+ return raw;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ /** Save the permissions file. */
55
+ export function savePermissionsFile(cwd, file) {
56
+ const p = PERMISSIONS_PATH_FOR(cwd);
57
+ try {
58
+ fs.mkdirSync(path.dirname(p), { recursive: true });
59
+ fs.writeFileSync(p, JSON.stringify(file, null, 2));
60
+ return { ok: true };
61
+ }
62
+ catch (err) {
63
+ return { ok: false, error: err.message };
64
+ }
65
+ }
66
+ /** Get the permissions file path (test-only introspection). */
67
+ export function getPermissionsPath(cwd) {
68
+ return PERMISSIONS_PATH_FOR(cwd);
69
+ }
70
+ /**
71
+ * Convert a glob pattern to a RegExp anchored at both ends.
72
+ * - `*` matches any chars except `/`
73
+ * - `**` matches any chars including `/`
74
+ * - `?` matches any single char except `/`
75
+ */
76
+ export function globToRegExp(glob) {
77
+ let out = '^';
78
+ for (let i = 0; i < glob.length; i++) {
79
+ const c = glob[i];
80
+ if (c === '*') {
81
+ if (glob[i + 1] === '*') {
82
+ // dstar: matches zero or more path segments. If a
83
+ // slash follows, the slash is optional (so the
84
+ // pattern matches a/b/c as well as a).
85
+ if (glob[i + 2] === '/') {
86
+ out += '(?:.*/)?';
87
+ i += 2;
88
+ }
89
+ else {
90
+ out += '.*';
91
+ i += 1;
92
+ }
93
+ }
94
+ else {
95
+ out += '[^/]*';
96
+ }
97
+ }
98
+ else if (c === '?') {
99
+ out += '[^/]';
100
+ }
101
+ else if ('.+()[]{}|^$\\'.includes(c)) {
102
+ out += '\\' + c;
103
+ }
104
+ else {
105
+ out += c;
106
+ }
107
+ }
108
+ out += '$';
109
+ return new RegExp(out);
110
+ }
111
+ /** Parse `Tool(pattern)` into `{tool, argPattern}`. */
112
+ export function parseRulePattern(pattern) {
113
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)(?:\((.+)\))?$/.exec(pattern);
114
+ if (!m)
115
+ return { tool: pattern, argPattern: null };
116
+ return { tool: m[1], argPattern: m[2] ?? null };
117
+ }
118
+ /**
119
+ * Build the input string that the rule's argPattern matches
120
+ * against. We pick a sensible string projection of args
121
+ * for the tool at hand. For most tools, that's the joined
122
+ * string of all arg values. This is intentionally simple —
123
+ * it lets users write rules like Edit(src/dstar/star.ts)
124
+ * and have them work.
125
+ */
126
+ export function buildArgString(tool, args) {
127
+ // For path-shaped tools, prefer the `path` / `filePath` /
128
+ // `cmd` field so globs land where users expect.
129
+ const pathField = typeof args.path === 'string' ? args.path :
130
+ typeof args.filePath === 'string' ? args.filePath :
131
+ typeof args.cmd === 'string' ? args.cmd :
132
+ typeof args.command === 'string' ? args.command :
133
+ null;
134
+ if (pathField !== null)
135
+ return pathField;
136
+ return Object.values(args)
137
+ .filter(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
138
+ .map(v => String(v))
139
+ .join(' ');
140
+ }
141
+ /** Match a tool call against the rule list (first match wins). */
142
+ export function matchPermission(tool, args, rules) {
143
+ for (const rule of rules) {
144
+ const { tool: ruleTool, argPattern } = parseRulePattern(rule.pattern);
145
+ if (ruleTool !== tool)
146
+ continue;
147
+ if (argPattern === null)
148
+ return rule;
149
+ const argString = buildArgString(tool, args);
150
+ try {
151
+ const re = globToRegExp(argPattern);
152
+ if (re.test(argString))
153
+ return rule;
154
+ }
155
+ catch {
156
+ // Malformed glob — skip the rule rather than crashing.
157
+ continue;
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+ /**
163
+ * Top-level check: try a rule match, then fall back to
164
+ * `decidePolicy` for the legacy policy logic, then apply
165
+ * the default-ask rule for new tools. Returns a unified
166
+ * `PermissionCheckResult`.
167
+ */
168
+ export function checkPermission(tool, args, cwd, profile) {
169
+ const file = loadPermissionsFile(cwd);
170
+ const rules = file?.rules ?? [];
171
+ // 1. First-match-wins rule check.
172
+ const match = matchPermission(tool, args, rules);
173
+ if (match) {
174
+ return {
175
+ decision: match.decision,
176
+ reason: match.reason ?? `${tool} matched rule ${match.pattern}`,
177
+ matchedRule: match.pattern,
178
+ source: 'rule',
179
+ };
180
+ }
181
+ // 2. Default-ask for tools introduced in Phases 1–3.
182
+ if (NEW_TOOL_DEFAULT_ASK.has(tool)) {
183
+ return {
184
+ decision: 'ask',
185
+ reason: `${tool} is a new tool with no rule — default-ask applies`,
186
+ matchedRule: null,
187
+ source: 'default-ask',
188
+ };
189
+ }
190
+ // 3. Fallback to legacy decidePolicy.
191
+ const action = tool === 'run_command' || tool === 'run_command_async' ? 'command' :
192
+ MUTATION_TOOLS.has(tool) ? 'write' :
193
+ 'read';
194
+ const detail = buildArgString(tool, args);
195
+ const policyDecision = decidePolicy(profile, action, detail);
196
+ return {
197
+ decision: policyDecision.allowed
198
+ ? (policyDecision.needsConfirmation ? 'ask' : 'allow')
199
+ : 'deny',
200
+ reason: policyDecision.reason,
201
+ matchedRule: null,
202
+ source: 'fallback-policy',
203
+ };
204
+ }
205
+ const MUTATION_TOOLS = new Set([
206
+ 'write_file',
207
+ 'apply_patch',
208
+ 'replace_range',
209
+ 'insert_after',
210
+ 'rename_file',
211
+ 'delete_file',
212
+ 'create_branch',
213
+ 'commit_changes',
214
+ 'push_branch',
215
+ 'create_pull_request',
216
+ 'str_replace',
217
+ 'todo_write',
218
+ ]);
219
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/agent/permissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * predictive-gate.ts — token-aware predictive read gate.
3
+ *
4
+ * Phase 4 spec:
5
+ * - The existing 15 KiB / 350-line byte gate in `executeReadFile`
6
+ * is a cheap pre-filter. It does not know about the *current*
7
+ * conversation pressure, so a series of small reads can still
8
+ * blow the window.
9
+ * - This module adds a second tier: before we read a file, we
10
+ * estimate its token cost via `gpt-tokenizer` and compare the
11
+ * projected total (conversation + file) against the model's
12
+ * effective input limit. If the projected total exceeds the
13
+ * configured pct (default 85%), we defer and return a
14
+ * directive telling the model to use the surgical alternative.
15
+ *
16
+ * Layering:
17
+ * read_file dispatch
18
+ * ├── existing byte gate (cheapest)
19
+ * └── predictive gate (this module — fires only when byte gate passes)
20
+ *
21
+ * Fail-open: any error in encoding or model resolution allows the
22
+ * read to proceed. The gate is an optimisation, never a correctness
23
+ * boundary, so availability beats precision.
24
+ */
25
+ /** Default fraction of the model window we will let the next read fill. */
26
+ export declare const DEFAULT_PREDICTIVE_BUDGET_PCT = 0.85;
27
+ export interface ReadEstimate {
28
+ /** File size in bytes (0 if the file is missing). */
29
+ readonly bytes: number;
30
+ /** Estimated token cost of reading the full file. */
31
+ readonly projectedTokens: number;
32
+ /** True if the file could be tokenised exactly (small enough to fit in sample). */
33
+ readonly exact: boolean;
34
+ }
35
+ export interface DeferDecision {
36
+ /** True if the caller should NOT read the file. */
37
+ readonly defer: boolean;
38
+ /** Human-readable explanation. */
39
+ readonly reason: string;
40
+ /** Projected total tokens (conversation + read). */
41
+ readonly projectedTotal: number;
42
+ /** Effective hard cap used for the decision. */
43
+ readonly hardCap: number;
44
+ }
45
+ /**
46
+ * Estimate the token cost of reading a file. The function never
47
+ * throws — on any error it returns `{ bytes: 0, projectedTokens: 0,
48
+ * exact: false }` and the caller treats that as "no signal, fall
49
+ * through."
50
+ */
51
+ export declare function estimateReadCost(absolutePath: string, model: string | undefined | null): ReadEstimate;
52
+ /**
53
+ * Decide whether the projected read would push the conversation
54
+ * over the model's effective budget.
55
+ *
56
+ * `conversationTokens` is the count *before* this read. `model` is
57
+ * used to look up the per-model context limit (see
58
+ * `resolveModelContextLimit`). `budgetPct` lets callers tune the
59
+ * threshold; passing `1.0` effectively disables the gate.
60
+ */
61
+ export declare function shouldDeferRead(estimate: ReadEstimate, conversationTokens: number, model: string | undefined | null, budgetPct?: number): DeferDecision;
62
+ /**
63
+ * Format the synthetic directive returned to the model when the
64
+ * gate fires. The shape matches the existing
65
+ * `[Context-Budget Guard]` directive used by the byte gate so the
66
+ * model's existing routing behaviour applies unchanged.
67
+ */
68
+ export declare function formatPredictiveGateDirective(relativePath: string, estimate: ReadEstimate, decision: DeferDecision): string;
69
+ //# sourceMappingURL=predictive-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predictive-gate.d.ts","sourceRoot":"","sources":["../../src/agent/predictive-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAC/B,YAAY,CAoCd;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,kBAAkB,EAAE,MAAM,EAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAChC,SAAS,GAAE,MAAsC,GAChD,aAAa,CAkBf;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,aAAa,GACtB,MAAM,CASR"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * predictive-gate.ts — token-aware predictive read gate.
3
+ *
4
+ * Phase 4 spec:
5
+ * - The existing 15 KiB / 350-line byte gate in `executeReadFile`
6
+ * is a cheap pre-filter. It does not know about the *current*
7
+ * conversation pressure, so a series of small reads can still
8
+ * blow the window.
9
+ * - This module adds a second tier: before we read a file, we
10
+ * estimate its token cost via `gpt-tokenizer` and compare the
11
+ * projected total (conversation + file) against the model's
12
+ * effective input limit. If the projected total exceeds the
13
+ * configured pct (default 85%), we defer and return a
14
+ * directive telling the model to use the surgical alternative.
15
+ *
16
+ * Layering:
17
+ * read_file dispatch
18
+ * ├── existing byte gate (cheapest)
19
+ * └── predictive gate (this module — fires only when byte gate passes)
20
+ *
21
+ * Fail-open: any error in encoding or model resolution allows the
22
+ * read to proceed. The gate is an optimisation, never a correctness
23
+ * boundary, so availability beats precision.
24
+ */
25
+ import fs from 'node:fs';
26
+ import { countTokens } from './tokenizer.js';
27
+ import { resolveModelContextLimit } from './conversation.js';
28
+ /** ~4 bytes per token is the industry-standard rough estimate for English text. */
29
+ const FALLBACK_BYTES_PER_TOKEN = 4;
30
+ /** Cap the sample we tokenise to keep cold reads predictable. */
31
+ const SAMPLE_BYTES = 16 * 1024;
32
+ /** Default fraction of the model window we will let the next read fill. */
33
+ export const DEFAULT_PREDICTIVE_BUDGET_PCT = 0.85;
34
+ /**
35
+ * Estimate the token cost of reading a file. The function never
36
+ * throws — on any error it returns `{ bytes: 0, projectedTokens: 0,
37
+ * exact: false }` and the caller treats that as "no signal, fall
38
+ * through."
39
+ */
40
+ export function estimateReadCost(absolutePath, model) {
41
+ try {
42
+ const stat = fs.statSync(absolutePath);
43
+ if (!stat.isFile())
44
+ return { bytes: 0, projectedTokens: 0, exact: false };
45
+ const bytes = stat.size;
46
+ if (bytes === 0)
47
+ return { bytes: 0, projectedTokens: 0, exact: true };
48
+ if (bytes <= SAMPLE_BYTES) {
49
+ // Small enough to tokenise exactly.
50
+ const text = fs.readFileSync(absolutePath, 'utf-8');
51
+ try {
52
+ const projectedTokens = countTokens(text, model);
53
+ return { bytes, projectedTokens, exact: true };
54
+ }
55
+ catch {
56
+ return { bytes, projectedTokens: Math.ceil(bytes / FALLBACK_BYTES_PER_TOKEN), exact: false };
57
+ }
58
+ }
59
+ // Larger file: tokenise the first SAMPLE_BYTES and extrapolate.
60
+ const fd = fs.openSync(absolutePath, 'r');
61
+ try {
62
+ const buf = Buffer.alloc(SAMPLE_BYTES);
63
+ const read = fs.readSync(fd, buf, 0, SAMPLE_BYTES, 0);
64
+ const sample = buf.subarray(0, read).toString('utf-8');
65
+ const sampleTokens = countTokens(sample, model);
66
+ const tokensPerByte = sampleTokens / Math.max(read, 1);
67
+ const projectedTokens = Math.ceil(tokensPerByte * bytes);
68
+ return { bytes, projectedTokens, exact: false };
69
+ }
70
+ catch {
71
+ return { bytes, projectedTokens: Math.ceil(bytes / FALLBACK_BYTES_PER_TOKEN), exact: false };
72
+ }
73
+ finally {
74
+ try {
75
+ fs.closeSync(fd);
76
+ }
77
+ catch { /* ignore */ }
78
+ }
79
+ }
80
+ catch {
81
+ return { bytes: 0, projectedTokens: 0, exact: false };
82
+ }
83
+ }
84
+ /**
85
+ * Decide whether the projected read would push the conversation
86
+ * over the model's effective budget.
87
+ *
88
+ * `conversationTokens` is the count *before* this read. `model` is
89
+ * used to look up the per-model context limit (see
90
+ * `resolveModelContextLimit`). `budgetPct` lets callers tune the
91
+ * threshold; passing `1.0` effectively disables the gate.
92
+ */
93
+ export function shouldDeferRead(estimate, conversationTokens, model, budgetPct = DEFAULT_PREDICTIVE_BUDGET_PCT) {
94
+ const modelLimit = resolveModelContextLimit(model);
95
+ // budgetPct is sanitised: clamp to (0, 1].
96
+ const pct = !Number.isFinite(budgetPct) || budgetPct <= 0
97
+ ? DEFAULT_PREDICTIVE_BUDGET_PCT
98
+ : Math.min(budgetPct, 1);
99
+ const hardCap = Math.floor(modelLimit * pct);
100
+ const projectedTotal = Math.max(0, conversationTokens) + Math.max(0, estimate.projectedTokens);
101
+ if (projectedTotal <= hardCap) {
102
+ return { defer: false, reason: 'within budget', projectedTotal, hardCap };
103
+ }
104
+ const overshoot = projectedTotal - hardCap;
105
+ return {
106
+ defer: true,
107
+ reason: `predicted ${projectedTotal.toLocaleString()} tokens would exceed budget ${hardCap.toLocaleString()} by ${overshoot.toLocaleString()}`,
108
+ projectedTotal,
109
+ hardCap,
110
+ };
111
+ }
112
+ /**
113
+ * Format the synthetic directive returned to the model when the
114
+ * gate fires. The shape matches the existing
115
+ * `[Context-Budget Guard]` directive used by the byte gate so the
116
+ * model's existing routing behaviour applies unchanged.
117
+ */
118
+ export function formatPredictiveGateDirective(relativePath, estimate, decision) {
119
+ return [
120
+ `[Context-Budget Guard] read_file ${relativePath} deferred.`,
121
+ ` bytes=${estimate.bytes.toLocaleString()} projected_tokens=${estimate.projectedTokens.toLocaleString()}${estimate.exact ? '' : ' (estimated)'}`,
122
+ ` ${decision.reason}.`,
123
+ ` → Use extract_symbols or extract_imports to scan the file's surface, then`,
124
+ ` read_file with explicit lines, or use str_replace to edit without`,
125
+ ` pulling the full file into context.`,
126
+ ].join('\n');
127
+ }
128
+ //# sourceMappingURL=predictive-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predictive-gate.js","sourceRoot":"","sources":["../../src/agent/predictive-gate.ts"],"names":[],"mappings":"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"}