praana 0.5.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 (204) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/bin/praana.js +17 -0
  4. package/bin/pran.js +17 -0
  5. package/dist/app-banner.d.ts +11 -0
  6. package/dist/app-banner.js +161 -0
  7. package/dist/app-controller.d.ts +44 -0
  8. package/dist/app-controller.js +143 -0
  9. package/dist/app-identity.d.ts +18 -0
  10. package/dist/app-identity.js +52 -0
  11. package/dist/auto-compact.d.ts +16 -0
  12. package/dist/auto-compact.js +101 -0
  13. package/dist/cli-args.d.ts +14 -0
  14. package/dist/cli-args.js +69 -0
  15. package/dist/compile-classic.d.ts +21 -0
  16. package/dist/compile-classic.js +106 -0
  17. package/dist/compiler.d.ts +75 -0
  18. package/dist/compiler.js +406 -0
  19. package/dist/config.d.ts +3 -0
  20. package/dist/config.js +433 -0
  21. package/dist/context-engine/activity-log.d.ts +9 -0
  22. package/dist/context-engine/activity-log.js +109 -0
  23. package/dist/context-engine/artifact-store.d.ts +32 -0
  24. package/dist/context-engine/artifact-store.js +272 -0
  25. package/dist/context-engine/bm25.d.ts +3 -0
  26. package/dist/context-engine/bm25.js +32 -0
  27. package/dist/context-engine/checkpoint.d.ts +34 -0
  28. package/dist/context-engine/checkpoint.js +430 -0
  29. package/dist/context-engine/classify.d.ts +3 -0
  30. package/dist/context-engine/classify.js +60 -0
  31. package/dist/context-engine/db.d.ts +73 -0
  32. package/dist/context-engine/db.js +505 -0
  33. package/dist/context-engine/distiller.d.ts +30 -0
  34. package/dist/context-engine/distiller.js +67 -0
  35. package/dist/context-engine/engine-compiler.d.ts +23 -0
  36. package/dist/context-engine/engine-compiler.js +297 -0
  37. package/dist/context-engine/error-tracker.d.ts +21 -0
  38. package/dist/context-engine/error-tracker.js +74 -0
  39. package/dist/context-engine/event-lineage.d.ts +26 -0
  40. package/dist/context-engine/event-lineage.js +120 -0
  41. package/dist/context-engine/extraction.d.ts +26 -0
  42. package/dist/context-engine/extraction.js +83 -0
  43. package/dist/context-engine/index.d.ts +82 -0
  44. package/dist/context-engine/index.js +238 -0
  45. package/dist/context-engine/scoring.d.ts +13 -0
  46. package/dist/context-engine/scoring.js +47 -0
  47. package/dist/context-engine/state-snapshot.d.ts +8 -0
  48. package/dist/context-engine/state-snapshot.js +50 -0
  49. package/dist/context-engine/summarize.d.ts +6 -0
  50. package/dist/context-engine/summarize.js +32 -0
  51. package/dist/context-engine/telemetry.d.ts +25 -0
  52. package/dist/context-engine/telemetry.js +64 -0
  53. package/dist/context-engine/turn-digest.d.ts +50 -0
  54. package/dist/context-engine/turn-digest.js +250 -0
  55. package/dist/context-engine/turn-ledger.d.ts +18 -0
  56. package/dist/context-engine/turn-ledger.js +184 -0
  57. package/dist/context-engine/turn-recorder.d.ts +24 -0
  58. package/dist/context-engine/turn-recorder.js +88 -0
  59. package/dist/context-engine/types.d.ts +201 -0
  60. package/dist/context-engine/types.js +4 -0
  61. package/dist/context-pressure.d.ts +19 -0
  62. package/dist/context-pressure.js +36 -0
  63. package/dist/distillers/generic.d.ts +14 -0
  64. package/dist/distillers/generic.js +93 -0
  65. package/dist/distillers/git-diff.d.ts +8 -0
  66. package/dist/distillers/git-diff.js +119 -0
  67. package/dist/distillers/index.d.ts +2 -0
  68. package/dist/distillers/index.js +16 -0
  69. package/dist/distillers/npm-test.d.ts +8 -0
  70. package/dist/distillers/npm-test.js +50 -0
  71. package/dist/distillers/rg-results.d.ts +8 -0
  72. package/dist/distillers/rg-results.js +28 -0
  73. package/dist/distillers/tsc-errors.d.ts +8 -0
  74. package/dist/distillers/tsc-errors.js +52 -0
  75. package/dist/event-log.d.ts +56 -0
  76. package/dist/event-log.js +214 -0
  77. package/dist/llm.d.ts +29 -0
  78. package/dist/llm.js +155 -0
  79. package/dist/logger.d.ts +94 -0
  80. package/dist/logger.js +287 -0
  81. package/dist/main.d.ts +1 -0
  82. package/dist/main.js +54 -0
  83. package/dist/memory/confidence.d.ts +7 -0
  84. package/dist/memory/confidence.js +37 -0
  85. package/dist/memory/consolidation.d.ts +26 -0
  86. package/dist/memory/consolidation.js +166 -0
  87. package/dist/memory/db.d.ts +40 -0
  88. package/dist/memory/db.js +283 -0
  89. package/dist/memory/dedup.d.ts +6 -0
  90. package/dist/memory/dedup.js +50 -0
  91. package/dist/memory/embedder-factory.d.ts +3 -0
  92. package/dist/memory/embedder-factory.js +81 -0
  93. package/dist/memory/embeddings.d.ts +15 -0
  94. package/dist/memory/embeddings.js +67 -0
  95. package/dist/memory/index.d.ts +9 -0
  96. package/dist/memory/index.js +11 -0
  97. package/dist/memory/ollama-summarizer.d.ts +19 -0
  98. package/dist/memory/ollama-summarizer.js +72 -0
  99. package/dist/memory/openai-summarizer.d.ts +21 -0
  100. package/dist/memory/openai-summarizer.js +51 -0
  101. package/dist/memory/store.d.ts +61 -0
  102. package/dist/memory/store.js +502 -0
  103. package/dist/memory/summarizer-factory.d.ts +3 -0
  104. package/dist/memory/summarizer-factory.js +69 -0
  105. package/dist/memory/summarizer.d.ts +4 -0
  106. package/dist/memory/summarizer.js +112 -0
  107. package/dist/memory/types.d.ts +87 -0
  108. package/dist/memory/types.js +17 -0
  109. package/dist/model-context.d.ts +15 -0
  110. package/dist/model-context.js +212 -0
  111. package/dist/project-detector.d.ts +37 -0
  112. package/dist/project-detector.js +604 -0
  113. package/dist/render.d.ts +15 -0
  114. package/dist/render.js +46 -0
  115. package/dist/session.d.ts +118 -0
  116. package/dist/session.js +809 -0
  117. package/dist/skills/index.d.ts +69 -0
  118. package/dist/skills/index.js +885 -0
  119. package/dist/skills/types.d.ts +93 -0
  120. package/dist/skills/types.js +8 -0
  121. package/dist/slash-commands.d.ts +14 -0
  122. package/dist/slash-commands.js +301 -0
  123. package/dist/state-graph.d.ts +38 -0
  124. package/dist/state-graph.js +255 -0
  125. package/dist/status-bar.d.ts +54 -0
  126. package/dist/status-bar.js +184 -0
  127. package/dist/thinking-display.d.ts +21 -0
  128. package/dist/thinking-display.js +37 -0
  129. package/dist/tool-summary.d.ts +4 -0
  130. package/dist/tool-summary.js +67 -0
  131. package/dist/tools/index.d.ts +925 -0
  132. package/dist/tools/index.js +86 -0
  133. package/dist/tools/knowledge.d.ts +140 -0
  134. package/dist/tools/knowledge.js +260 -0
  135. package/dist/tools/memory.d.ts +39 -0
  136. package/dist/tools/memory.js +300 -0
  137. package/dist/tools/search-code.d.ts +134 -0
  138. package/dist/tools/search-code.js +390 -0
  139. package/dist/tools/system.d.ts +16 -0
  140. package/dist/tools/system.js +499 -0
  141. package/dist/tools/tool-def.d.ts +6 -0
  142. package/dist/tools/tool-def.js +3 -0
  143. package/dist/turn-control.d.ts +51 -0
  144. package/dist/turn-control.js +210 -0
  145. package/dist/turn.d.ts +20 -0
  146. package/dist/turn.js +624 -0
  147. package/dist/types.d.ts +233 -0
  148. package/dist/types.js +4 -0
  149. package/dist/ui/readline-ui.d.ts +2 -0
  150. package/dist/ui/readline-ui.js +176 -0
  151. package/dist/ui/tui/app.d.ts +13 -0
  152. package/dist/ui/tui/app.js +270 -0
  153. package/dist/ui/tui/busy-indicator.d.ts +2 -0
  154. package/dist/ui/tui/busy-indicator.js +13 -0
  155. package/dist/ui/tui/components/gutter-rule.d.ts +5 -0
  156. package/dist/ui/tui/components/gutter-rule.js +9 -0
  157. package/dist/ui/tui/components/inline-tool-row.d.ts +10 -0
  158. package/dist/ui/tui/components/inline-tool-row.js +8 -0
  159. package/dist/ui/tui/components/prompt-input.d.ts +20 -0
  160. package/dist/ui/tui/components/prompt-input.js +120 -0
  161. package/dist/ui/tui/components/system-line.d.ts +5 -0
  162. package/dist/ui/tui/components/system-line.js +6 -0
  163. package/dist/ui/tui/components/thinking-block.d.ts +11 -0
  164. package/dist/ui/tui/components/thinking-block.js +31 -0
  165. package/dist/ui/tui/components/toast-line.d.ts +4 -0
  166. package/dist/ui/tui/components/toast-line.js +8 -0
  167. package/dist/ui/tui/components/tool-result-line.d.ts +5 -0
  168. package/dist/ui/tui/components/tool-result-line.js +6 -0
  169. package/dist/ui/tui/components/turn-footer.d.ts +5 -0
  170. package/dist/ui/tui/components/turn-footer.js +7 -0
  171. package/dist/ui/tui/components/user-block.d.ts +6 -0
  172. package/dist/ui/tui/components/user-block.js +6 -0
  173. package/dist/ui/tui/logo-banner.d.ts +5 -0
  174. package/dist/ui/tui/logo-banner.js +8 -0
  175. package/dist/ui/tui/markdown-render.d.ts +16 -0
  176. package/dist/ui/tui/markdown-render.js +218 -0
  177. package/dist/ui/tui/palette.d.ts +12 -0
  178. package/dist/ui/tui/palette.js +13 -0
  179. package/dist/ui/tui/reasoning-summary.d.ts +12 -0
  180. package/dist/ui/tui/reasoning-summary.js +27 -0
  181. package/dist/ui/tui/reducer.d.ts +92 -0
  182. package/dist/ui/tui/reducer.js +260 -0
  183. package/dist/ui/tui/run.d.ts +3 -0
  184. package/dist/ui/tui/run.js +40 -0
  185. package/dist/ui/tui/sink.d.ts +4 -0
  186. package/dist/ui/tui/sink.js +89 -0
  187. package/dist/ui/tui/status-bar-view.d.ts +5 -0
  188. package/dist/ui/tui/status-bar-view.js +44 -0
  189. package/dist/ui/tui/terminal-height.d.ts +12 -0
  190. package/dist/ui/tui/terminal-height.js +20 -0
  191. package/dist/ui/tui/terminal-width.d.ts +2 -0
  192. package/dist/ui/tui/terminal-width.js +5 -0
  193. package/dist/ui/tui/tool-display.d.ts +23 -0
  194. package/dist/ui/tui/tool-display.js +217 -0
  195. package/dist/ui/tui/transcript-line.d.ts +12 -0
  196. package/dist/ui/tui/transcript-line.js +43 -0
  197. package/dist/ui/tui/transcript-replay.d.ts +12 -0
  198. package/dist/ui/tui/transcript-replay.js +117 -0
  199. package/dist/ui-events.d.ts +39 -0
  200. package/dist/ui-events.js +33 -0
  201. package/dist/ui.d.ts +77 -0
  202. package/dist/ui.js +179 -0
  203. package/package.json +73 -0
  204. package/praana.config.example.toml +231 -0
@@ -0,0 +1,300 @@
1
+ import { defineTool } from "./tool-def.js";
2
+ import { z } from "zod";
3
+ export function createMemoryTools(ctx) {
4
+ const { eventLog, stateGraph, searchTurnEvents } = ctx;
5
+ const includeWorkingMemory = ctx.includeWorkingMemoryTools !== false;
6
+ const logAction = (action, payload) => {
7
+ eventLog.append({
8
+ kind: "context_action",
9
+ actor: "kernel",
10
+ payload: { action, ...payload },
11
+ });
12
+ };
13
+ const workingMemoryTools = includeWorkingMemory
14
+ ? {
15
+ create_task: defineTool({
16
+ description: "Create a new task in working memory. Tasks track what you're working on.",
17
+ parameters: z.object({
18
+ title: z.string().describe("Task title"),
19
+ description: z.string().optional().describe("Optional details"),
20
+ }),
21
+ execute: async ({ title, description }) => {
22
+ const obj = stateGraph.create("task", {
23
+ title,
24
+ description,
25
+ status: "todo",
26
+ });
27
+ logAction("create", {
28
+ id: obj.id,
29
+ kind: "task",
30
+ tier: obj.tier,
31
+ statePayload: obj.payload,
32
+ created: obj.created,
33
+ updated: obj.updated,
34
+ lastTouched: obj.lastTouched,
35
+ });
36
+ return { ok: true, id: obj.id };
37
+ },
38
+ }),
39
+ complete_task: defineTool({
40
+ description: "Mark a task as done. Use when you've completed a task.",
41
+ parameters: z.object({
42
+ id: z.string().describe("Task ID to complete"),
43
+ }),
44
+ execute: async ({ id }) => {
45
+ const obj = stateGraph.get(id);
46
+ if (!obj || obj.kind !== "task") {
47
+ return { ok: false, error: `Task ${id} not found` };
48
+ }
49
+ const updated = stateGraph.update(id, { status: "done" });
50
+ if (updated) {
51
+ logAction("update", {
52
+ id,
53
+ statePayload: { status: "done" },
54
+ updated: updated.updated,
55
+ lastTouched: updated.lastTouched,
56
+ });
57
+ }
58
+ // Auto-soft-unload on complete_task
59
+ stateGraph.setTier(id, "soft");
60
+ logAction("setTier", {
61
+ id,
62
+ tier: "soft",
63
+ lastTouched: stateGraph.get(id).lastTouched,
64
+ });
65
+ return { ok: true };
66
+ },
67
+ }),
68
+ retract_task: defineTool({
69
+ description: "Retract a task from working memory. The task is tombstoned (not deleted) so it won't appear in prompts or state listings.",
70
+ parameters: z.object({
71
+ id: z.string().describe("Task/object ID to retract"),
72
+ }),
73
+ execute: async ({ id }) => {
74
+ const obj = stateGraph.get(id);
75
+ if (!obj) {
76
+ return { ok: false, error: `Object ${id} not found` };
77
+ }
78
+ const retracted = stateGraph.retractObject(id);
79
+ if (retracted) {
80
+ logAction("retract", { id, kind: obj.kind });
81
+ }
82
+ return { ok: true, retracted };
83
+ },
84
+ }),
85
+ add_constraint: defineTool({
86
+ description: "Add a constraint to working memory. Use for rules, limitations, or requirements to keep in mind.",
87
+ parameters: z.object({
88
+ text: z.string().describe("The constraint text"),
89
+ }),
90
+ execute: async ({ text }) => {
91
+ const obj = stateGraph.create("constraint", { text });
92
+ logAction("create", {
93
+ id: obj.id,
94
+ kind: "constraint",
95
+ tier: obj.tier,
96
+ statePayload: obj.payload,
97
+ created: obj.created,
98
+ updated: obj.updated,
99
+ lastTouched: obj.lastTouched,
100
+ });
101
+ return { ok: true, id: obj.id };
102
+ },
103
+ }),
104
+ decide: defineTool({
105
+ description: "Record a decision in working memory with its rationale.",
106
+ parameters: z.object({
107
+ summary: z.string().describe("Short summary of the decision"),
108
+ rationale: z.string().describe("Why this decision was made"),
109
+ }),
110
+ execute: async ({ summary, rationale }) => {
111
+ const obj = stateGraph.create("decision", {
112
+ summary,
113
+ rationale,
114
+ });
115
+ logAction("create", {
116
+ id: obj.id,
117
+ kind: "decision",
118
+ tier: obj.tier,
119
+ statePayload: obj.payload,
120
+ created: obj.created,
121
+ updated: obj.updated,
122
+ lastTouched: obj.lastTouched,
123
+ });
124
+ return { ok: true, id: obj.id };
125
+ },
126
+ }),
127
+ add_note: defineTool({
128
+ description: "Add a general note to working memory. Capture semantic findings (facts, behavior, decisions) — not activity logs or file lists. After significant analysis, add notes immediately so findings survive context truncation.",
129
+ parameters: z.object({
130
+ text: z.string().describe("The note text — a finding or fact, not a list of files read"),
131
+ }),
132
+ execute: async ({ text }) => {
133
+ const qualityWarning = detectActivityLogNote(text);
134
+ const obj = stateGraph.create("note", { text });
135
+ logAction("create", {
136
+ id: obj.id,
137
+ kind: "note",
138
+ tier: obj.tier,
139
+ statePayload: obj.payload,
140
+ created: obj.created,
141
+ updated: obj.updated,
142
+ lastTouched: obj.lastTouched,
143
+ });
144
+ return qualityWarning
145
+ ? { ok: true, id: obj.id, warning: qualityWarning }
146
+ : { ok: true, id: obj.id };
147
+ },
148
+ }),
149
+ soft_unload: defineTool({
150
+ description: "Demote a state object to the soft tier (shown as one-line stub in memory). Use when something is less relevant now.",
151
+ parameters: z.object({
152
+ id: z.string().describe("Object ID to demote"),
153
+ }),
154
+ execute: async ({ id }) => {
155
+ const obj = stateGraph.get(id);
156
+ if (!obj)
157
+ return { ok: false, error: `Object ${id} not found` };
158
+ stateGraph.setTier(id, "soft");
159
+ logAction("setTier", {
160
+ id,
161
+ tier: "soft",
162
+ lastTouched: stateGraph.get(id).lastTouched,
163
+ });
164
+ return { ok: true };
165
+ },
166
+ }),
167
+ hard_unload: defineTool({
168
+ description: "Demote a state object to the hard tier (shown as minimal anchor in memory). Use when something is even less relevant.",
169
+ parameters: z.object({
170
+ id: z.string().describe("Object ID to demote to hard"),
171
+ }),
172
+ execute: async ({ id }) => {
173
+ const obj = stateGraph.get(id);
174
+ if (!obj)
175
+ return { ok: false, error: `Object ${id} not found` };
176
+ stateGraph.setTier(id, "hard");
177
+ logAction("setTier", {
178
+ id,
179
+ tier: "hard",
180
+ lastTouched: stateGraph.get(id).lastTouched,
181
+ });
182
+ return { ok: true };
183
+ },
184
+ }),
185
+ hydrate: defineTool({
186
+ description: "Promote a peripheral (soft/hard) object back to active memory, restoring its full content.",
187
+ parameters: z.object({
188
+ id: z.string().describe("Object ID to hydrate"),
189
+ }),
190
+ execute: async ({ id }) => {
191
+ const obj = stateGraph.get(id);
192
+ if (!obj)
193
+ return { ok: false, error: `Object ${id} not found` };
194
+ stateGraph.setTier(id, "active");
195
+ logAction("setTier", {
196
+ id,
197
+ tier: "active",
198
+ lastTouched: stateGraph.get(id).lastTouched,
199
+ });
200
+ return { ok: true, payload: obj.payload };
201
+ },
202
+ }),
203
+ list_state: defineTool({
204
+ description: "List all state objects with their id, kind, tier, and summary.",
205
+ parameters: z.object({}),
206
+ execute: async () => {
207
+ const objects = stateGraph.list();
208
+ return { ok: true, objects };
209
+ },
210
+ }),
211
+ focus_task: defineTool({
212
+ description: "Pin a task (or any state object) as the current focus. Focused objects render first in active state.",
213
+ parameters: z.object({
214
+ id: z.string().describe("Object ID to focus"),
215
+ }),
216
+ execute: async ({ id }) => {
217
+ const obj = stateGraph.get(id);
218
+ if (!obj)
219
+ return { ok: false, error: `Object ${id} not found` };
220
+ stateGraph.setFocus(id);
221
+ logAction("setFocus", {
222
+ id,
223
+ lastTouched: stateGraph.get(id).lastTouched,
224
+ });
225
+ return { ok: true, id };
226
+ },
227
+ }),
228
+ }
229
+ : {};
230
+ return {
231
+ ...workingMemoryTools,
232
+ search_session_log: defineTool({
233
+ description: "Search the current session's event log for earlier messages, tool calls, and results. " +
234
+ "Use this to recover in-session context (e.g. a code review from earlier turns) — not recall, which only searches cross-session memory. " +
235
+ "Session log path: events.jsonl",
236
+ parameters: z.object({
237
+ query: z
238
+ .string()
239
+ .describe("Search terms (ANDed, case-insensitive). Use | for OR, e.g. 'issue|review'"),
240
+ kinds: z
241
+ .array(z.enum([
242
+ "user_message",
243
+ "agent_message",
244
+ "tool_call",
245
+ "tool_result",
246
+ "context_action",
247
+ "system_note",
248
+ ]))
249
+ .optional()
250
+ .describe("Optional event kinds to filter"),
251
+ limit: z
252
+ .number()
253
+ .int()
254
+ .min(1)
255
+ .max(50)
256
+ .default(20)
257
+ .describe("Max matches to return"),
258
+ }),
259
+ execute: async ({ query, kinds, limit }) => {
260
+ if (searchTurnEvents && !kinds?.length) {
261
+ const ledgerMatches = searchTurnEvents(query, limit ?? 20);
262
+ return {
263
+ ok: true,
264
+ query,
265
+ source: "turn_ledger",
266
+ matchCount: ledgerMatches.length,
267
+ matches: ledgerMatches,
268
+ };
269
+ }
270
+ const matches = eventLog.search(query, { kinds, limit: limit ?? 20 });
271
+ return {
272
+ ok: true,
273
+ query,
274
+ source: "event_log",
275
+ matchCount: matches.length,
276
+ matches: matches.map(({ event, excerpt }) => ({
277
+ event_id: event.event_id,
278
+ kind: event.kind,
279
+ actor: event.actor,
280
+ timestamp: event.timestamp,
281
+ excerpt,
282
+ })),
283
+ };
284
+ },
285
+ }),
286
+ };
287
+ }
288
+ /** Warn when a note looks like an activity log instead of a semantic finding. */
289
+ export function detectActivityLogNote(text) {
290
+ const trimmed = text.trim();
291
+ if (trimmed.length < 20)
292
+ return null;
293
+ const fileListPattern = /(?:read|analyzed|reviewed|checked).{0,40}(?:src\/|\b[\w.-]+\.(?:ts|js|tsx|jsx|py|go|rs)\b)/i;
294
+ const commaFileRun = /(?:src\/[\w./-]+(?:,\s*|\s+and\s+)){2,}/i;
295
+ const lacksFindingLanguage = !/\b(uses|implements|returns|calls|handles|because|found|decided|pattern|via|is a|are stored)\b/i.test(trimmed);
296
+ if ((fileListPattern.test(trimmed) || commaFileRun.test(trimmed)) && lacksFindingLanguage) {
297
+ return "This note looks like an activity log. Prefer a semantic finding (what you learned), not which files you read.";
298
+ }
299
+ return null;
300
+ }
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+ import type { SandboxConfig } from "../types.js";
3
+ /**
4
+ * search_code — ripgrep-backed structured code search.
5
+ *
6
+ * Wraps `rg --json` with a stable JSON contract the model can consume:
7
+ * { matches: [{ file, line, column, text, context_before, context_after }],
8
+ * stats: { totalMatches, filesWithMatches, truncated } }
9
+ *
10
+ * rg is resolved from the inherited PATH by default; an override is accepted
11
+ * for tests and packaged-binary scenarios.
12
+ */
13
+ export interface SearchCodeMatch {
14
+ file: string;
15
+ line: number;
16
+ column: number;
17
+ text: string;
18
+ context_before: string[];
19
+ context_after: string[];
20
+ }
21
+ export interface SearchCodeStats {
22
+ totalMatches: number;
23
+ filesWithMatches: number;
24
+ truncated: boolean;
25
+ /** Minimum number of matches dropped due to `max_results`. 0 when not truncated. */
26
+ dropped: number;
27
+ }
28
+ export interface SearchCodeSuccess {
29
+ ok: true;
30
+ pattern: string;
31
+ path: string;
32
+ matches: SearchCodeMatch[];
33
+ stats: SearchCodeStats;
34
+ duration_ms: number;
35
+ }
36
+ export interface SearchCodeError {
37
+ ok: false;
38
+ error: string;
39
+ }
40
+ export type SearchCodeResult = SearchCodeSuccess | SearchCodeError;
41
+ export interface SearchCodeToolContext {
42
+ cwd: string;
43
+ getAbortSignal?: () => AbortSignal | undefined;
44
+ sandbox?: SandboxConfig;
45
+ /** Override ripgrep binary path (default: "rg" via PATH lookup). */
46
+ rgPath?: string;
47
+ }
48
+ declare const searchCodeSchema: z.ZodObject<{
49
+ pattern: z.ZodString;
50
+ path: z.ZodOptional<z.ZodString>;
51
+ glob: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
52
+ glob_exclude: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
53
+ case_insensitive: z.ZodOptional<z.ZodBoolean>;
54
+ context: z.ZodOptional<z.ZodNumber>;
55
+ max_results: z.ZodOptional<z.ZodNumber>;
56
+ file_type: z.ZodOptional<z.ZodString>;
57
+ include_hidden: z.ZodOptional<z.ZodBoolean>;
58
+ no_ignore: z.ZodOptional<z.ZodBoolean>;
59
+ multiline: z.ZodOptional<z.ZodBoolean>;
60
+ timeout: z.ZodOptional<z.ZodNumber>;
61
+ }, "strip", z.ZodTypeAny, {
62
+ pattern: string;
63
+ path?: string | undefined;
64
+ timeout?: number | undefined;
65
+ glob?: string | string[] | undefined;
66
+ glob_exclude?: string | string[] | undefined;
67
+ case_insensitive?: boolean | undefined;
68
+ context?: number | undefined;
69
+ max_results?: number | undefined;
70
+ file_type?: string | undefined;
71
+ include_hidden?: boolean | undefined;
72
+ no_ignore?: boolean | undefined;
73
+ multiline?: boolean | undefined;
74
+ }, {
75
+ pattern: string;
76
+ path?: string | undefined;
77
+ timeout?: number | undefined;
78
+ glob?: string | string[] | undefined;
79
+ glob_exclude?: string | string[] | undefined;
80
+ case_insensitive?: boolean | undefined;
81
+ context?: number | undefined;
82
+ max_results?: number | undefined;
83
+ file_type?: string | undefined;
84
+ include_hidden?: boolean | undefined;
85
+ no_ignore?: boolean | undefined;
86
+ multiline?: boolean | undefined;
87
+ }>;
88
+ export type SearchCodeArgs = z.infer<typeof searchCodeSchema>;
89
+ /**
90
+ * Build the ripgrep argv for the given arguments.
91
+ *
92
+ * Pattern is passed as `--` then `pattern` so it can't be misinterpreted as
93
+ * a flag even if it starts with `-`.
94
+ */
95
+ export declare function buildRipgrepArgs(args: SearchCodeArgs, searchPath: string): string[];
96
+ /**
97
+ * Streaming ripgrep-JSON parser.
98
+ *
99
+ * The parser holds mutable state (matches array, per-file context map, last
100
+ * match in file) that the caller can feed events into incrementally. This
101
+ * lets `runRipgrep` parse as bytes arrive from rg's stdout rather than
102
+ * buffering every event in a `string[]` until the child closes — which
103
+ * previously grew linearly with match count and OOM'd on broad searches.
104
+ *
105
+ * Context events are accumulated into a per-file line map. For each match,
106
+ * the lines with `line_number ∈ [match.line - context, match.line + context]`
107
+ * populate `context_before` / `context_after`. The last match's "after"
108
+ * context is back-filled on the file's `end` event so trailing context
109
+ * lines aren't lost.
110
+ */
111
+ export interface ParseState {
112
+ matches: SearchCodeMatch[];
113
+ totalMatches: number;
114
+ truncated: boolean;
115
+ _currentFile: string | null;
116
+ _currentFileLineMap: Map<number, string>;
117
+ _lastMatchInFile: SearchCodeMatch | null;
118
+ }
119
+ export declare function createParseState(): ParseState;
120
+ /** Feed raw rg --json lines into the parse state. Triggers `onTruncate` on cap. */
121
+ export declare function feedParseState(state: ParseState, rawLines: string[], context: number, maxResults: number | undefined, onTruncate: () => void): void;
122
+ /** Convenience wrapper: feed a complete log at once. Used by tests. */
123
+ export declare function parseRipgrepEvents(rawLines: string[], context: number, maxResults: number | undefined, onTruncate: () => void): {
124
+ matches: SearchCodeMatch[];
125
+ totalMatches: number;
126
+ filesWithMatches: number;
127
+ truncated: boolean;
128
+ };
129
+ /** Spawn ripgrep, return structured result. */
130
+ export declare function runRipgrep(args: SearchCodeArgs, rgBin: string, cwd: string, sandbox: SandboxConfig | undefined, getAbortSignal?: () => AbortSignal | undefined): Promise<SearchCodeResult>;
131
+ export declare function createSearchCodeTool(ctx: SearchCodeToolContext): {
132
+ search_code: import("./tool-def.js").ToolDefinition;
133
+ };
134
+ export {};