@kolisachint/hoocode-agent 0.4.147 → 0.4.149

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.149] - 2026-07-22
4
+
5
+ ## [0.4.148] - 2026-07-21
6
+
7
+ ### Fixed
8
+
9
+ - Context GC no longer evicts a `read` result just because the same file was read again over a **different** line range. Eviction is now range-aware: a read is superseded only by a later read whose `offset`/`limit` window overlaps it (or by any later edit/write). This fixes a read loop where alternating reads of two disjoint regions of one large file would repeatedly stub each other, and the "Re-read the file if you need its current contents" hint would drive the model to re-read indefinitely.
10
+
3
11
  ## [0.4.147] - 2026-07-20
4
12
 
5
13
  ### Changed
@@ -13,10 +13,13 @@
13
13
  *
14
14
  * A `read` result for a path P is stale once, later in the transcript, the
15
15
  * same path is edited/written (its on-disk content changed) or read again
16
- * (the newer read reflects newer state). The most recent read of each path is
17
- * always kept, and a read is only evicted when a *successful* later event
18
- * supersedes it so a read whose edit failed (and which the model still needs
19
- * to retry) is never touched.
16
+ * over an overlapping line range (the newer read reflects that region's newer
17
+ * state). Reads of disjoint regions of the same file coexist — a later read of
18
+ * lines 200-260 does not evict an earlier read of lines 1-40 so paginating
19
+ * through a large file never makes the model re-fetch a region it already has.
20
+ * A read is only evicted when a *successful* later event supersedes it — so a
21
+ * read whose edit failed (and which the model still needs to retry) is never
22
+ * touched.
20
23
  *
21
24
  * Deliberately conservative: paths are matched after `path.resolve`, so two
22
25
  * different files never collide, and any ambiguity results in NOT evicting.
@@ -1 +1 @@
1
- {"version":3,"file":"context-gc.d.ts","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAoBpE,MAAM,WAAW,gBAAgB;IAChC,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAuBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,EAAE,CA8FxG","sourcesContent":["/**\n * Context garbage collection.\n *\n * The whole transcript is re-sent on every turn, so a tool result that has\n * become useless keeps costing tokens for the rest of the session. This pass\n * runs on the OUTGOING message copy (via the agent's `transformContext` hook),\n * never on the persisted session, and replaces provably-dead `read` results\n * with a short stub. Nothing is lost: the persisted history is untouched and\n * the file is re-readable on demand.\n *\n * Current rule — superseded reads only (the read-then-edit / re-read pattern,\n * which dominates coding sessions):\n *\n * A `read` result for a path P is stale once, later in the transcript, the\n * same path is edited/written (its on-disk content changed) or read again\n * (the newer read reflects newer state). The most recent read of each path is\n * always kept, and a read is only evicted when a *successful* later event\n * supersedes it — so a read whose edit failed (and which the model still needs\n * to retry) is never touched.\n *\n * Deliberately conservative: paths are matched after `path.resolve`, so two\n * different files never collide, and any ambiguity results in NOT evicting.\n *\n * Bash-output eviction is additionally gated on token-budget pressure\n * (`options.budgetPressure`, the fraction of the model's context window in\n * use). At 0 pressure — the default — behaviour is identical to read-only GC.\n * Bash output is not always recoverable, so it carries its own safeguards: a\n * command that looks side-effecting is never elided (re-running it, as the\n * stub invites, could repeat a destructive action), and below 80% pressure\n * only large outputs are elided.\n */\n\nimport { resolve } from \"node:path\";\nimport type { AgentMessage } from \"@kolisachint/hoocode-agent-core\";\n\n/** Tool names whose result injects file contents into the transcript. */\nconst READ_TOOLS = new Set([\"read\"]);\n/** Tool names that change a file, making a prior read of that path stale. */\nconst MUTATE_TOOLS = new Set([\"edit\", \"write\"]);\n\n/**\n * Commands whose bash output must never be elided, because the stub invites\n * the model to re-run the command and re-running could repeat a destructive or\n * state-changing action. Tested against the whole command string, and\n * deliberately over-broad: a false positive merely keeps an output (safe),\n * while the common verbose *read* commands (cat/grep/ls/find/git log/diff,\n * test runners) intentionally do NOT match, so they stay evictable.\n */\nconst BASH_SIDE_EFFECT_PATTERN =\n\t/(\\b(write|insert|delete|update|curl|wget|psql|mysql|sqlite3|migrate|drop|truncate|rm|rmdir|mv|cp|dd|kill|tee|chmod|chown|ln|mkdir|touch)\\b|\\bgit\\s+(commit|push|reset|checkout|rebase|clean|apply|merge)\\b|\\bsed\\b[^|]*-i|>>?)/i;\n/** Below 80% pressure, only bash outputs larger than this (chars) are elided. */\nconst BASH_EVICTION_CHAR_THRESHOLD = 2000;\n\nexport interface ContextGcOptions {\n\t/** Working directory used to resolve relative tool path arguments. */\n\tcwd: string;\n\t/**\n\t * Token-budget pressure in [0, 1] — the fraction of the model's context\n\t * window currently in use. Absent or 0 reproduces read-only GC behaviour.\n\t * Bash-output eviction begins at 0.6 and becomes unconditional at 0.8.\n\t */\n\tbudgetPressure?: number;\n}\n\ninterface AssistantLike {\n\trole: \"assistant\";\n\tcontent: Array<{ type: string; id?: string; name?: string; arguments?: Record<string, unknown> }>;\n}\n\ninterface ToolResultLike {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: Array<{ type: string; text?: string }>;\n\tisError: boolean;\n}\n\nfunction isAssistant(m: AgentMessage): m is AgentMessage & AssistantLike {\n\treturn (m as { role?: string }).role === \"assistant\" && Array.isArray((m as AssistantLike).content);\n}\n\nfunction isToolResult(m: AgentMessage): m is AgentMessage & ToolResultLike {\n\treturn (m as { role?: string }).role === \"toolResult\";\n}\n\n/**\n * Return a message array with superseded `read` results stubbed out. Returns the\n * original array reference unchanged when there is nothing to evict, so a\n * no-op turn does not needlessly perturb the outgoing context.\n */\nexport function evictSupersededReads(messages: AgentMessage[], options: ContextGcOptions): AgentMessage[] {\n\t// Map each tool call id -> the resolved path it operated on, plus a friendly\n\t// display path (the original argument) for the stub text.\n\tconst resolvedPathByCallId = new Map<string, string>();\n\tconst displayPathByResolved = new Map<string, string>();\n\t// Bash calls carry a `command`, not a `path`; capture it so the eviction\n\t// pass can consult the side-effect guard by tool call id.\n\tconst bashCommandByCallId = new Map<string, string>();\n\tfor (const m of messages) {\n\t\tif (!isAssistant(m)) continue;\n\t\tfor (const block of m.content) {\n\t\t\tif (block.type !== \"toolCall\" || !block.id) continue;\n\t\t\tif (block.name === \"bash\") {\n\t\t\t\tconst cmd = block.arguments?.command;\n\t\t\t\tif (typeof cmd === \"string\" && cmd.length > 0) bashCommandByCallId.set(block.id, cmd);\n\t\t\t}\n\t\t\tconst rawPath = block.arguments?.path;\n\t\t\tif (typeof rawPath !== \"string\" || rawPath.length === 0) continue;\n\t\t\tconst resolved = resolve(options.cwd, rawPath);\n\t\t\tresolvedPathByCallId.set(block.id, resolved);\n\t\t\tif (!displayPathByResolved.has(resolved)) displayPathByResolved.set(resolved, rawPath);\n\t\t}\n\t}\n\n\t// First pass: per path, the index of the last read and the last successful\n\t// mutate. A read at index i is superseded when a later read (index > i) or a\n\t// later successful mutate (index > i) exists for the same path.\n\tconst lastReadIndex = new Map<string, number>();\n\tconst lastMutateIndex = new Map<string, number>();\n\tmessages.forEach((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return;\n\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\tif (!path) return;\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tlastReadIndex.set(path, i);\n\t\t} else if (MUTATE_TOOLS.has(m.toolName)) {\n\t\t\tlastMutateIndex.set(path, i);\n\t\t}\n\t});\n\n\t// Second pass: build the output, stubbing evicted reads. Keep every other\n\t// message by reference; clone only the ones we rewrite so the persisted\n\t// history (which may share these objects) is never mutated.\n\tconst pressure = options.budgetPressure ?? 0;\n\tlet changed = false;\n\tconst out = messages.map((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return m;\n\n\t\t// Superseded-read eviction — always on, pressure-independent.\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\t\tif (!path) return m;\n\t\t\tconst laterRead = (lastReadIndex.get(path) ?? -1) > i;\n\t\t\tconst laterMutate = (lastMutateIndex.get(path) ?? -1) > i;\n\t\t\tif (!laterRead && !laterMutate) return m;\n\t\t\tchanged = true;\n\t\t\tconst display = displayPathByResolved.get(path) ?? path;\n\t\t\tconst reason = laterMutate ? \"the file was modified after this read\" : \"the file was read again later\";\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `[Superseded read of ${display} elided to save context — ${reason}. Re-read the file if you need its current contents.]`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Bash-output eviction — only under token-budget pressure (>= 0.6).\n\t\tif (pressure >= 0.6 && m.toolName === \"bash\") {\n\t\t\tconst cmd = bashCommandByCallId.get(m.toolCallId) ?? \"\";\n\t\t\tif (BASH_SIDE_EFFECT_PATTERN.test(cmd)) return m;\n\t\t\tconst textLen = m.content.filter((c) => c.type === \"text\").reduce((sum, c) => sum + (c.text?.length ?? 0), 0);\n\t\t\t// 60–79%: elide only large outputs. 80%+: elide unconditionally.\n\t\t\tconst shouldEvict = pressure >= 0.8 || textLen > BASH_EVICTION_CHAR_THRESHOLD;\n\t\t\tif (shouldEvict) {\n\t\t\t\tchanged = true;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `[Bash output elided at ${Math.round(pressure * 100)}% token budget — re-run if needed.]`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn m;\n\t});\n\n\treturn changed ? out : messages;\n}\n"]}
1
+ {"version":3,"file":"context-gc.d.ts","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAoBpE,MAAM,WAAW,gBAAgB;IAChC,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAoDD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,EAAE,CAyGxG","sourcesContent":["/**\n * Context garbage collection.\n *\n * The whole transcript is re-sent on every turn, so a tool result that has\n * become useless keeps costing tokens for the rest of the session. This pass\n * runs on the OUTGOING message copy (via the agent's `transformContext` hook),\n * never on the persisted session, and replaces provably-dead `read` results\n * with a short stub. Nothing is lost: the persisted history is untouched and\n * the file is re-readable on demand.\n *\n * Current rule — superseded reads only (the read-then-edit / re-read pattern,\n * which dominates coding sessions):\n *\n * A `read` result for a path P is stale once, later in the transcript, the\n * same path is edited/written (its on-disk content changed) or read again\n * over an overlapping line range (the newer read reflects that region's newer\n * state). Reads of disjoint regions of the same file coexist — a later read of\n * lines 200-260 does not evict an earlier read of lines 1-40 — so paginating\n * through a large file never makes the model re-fetch a region it already has.\n * A read is only evicted when a *successful* later event supersedes it — so a\n * read whose edit failed (and which the model still needs to retry) is never\n * touched.\n *\n * Deliberately conservative: paths are matched after `path.resolve`, so two\n * different files never collide, and any ambiguity results in NOT evicting.\n *\n * Bash-output eviction is additionally gated on token-budget pressure\n * (`options.budgetPressure`, the fraction of the model's context window in\n * use). At 0 pressure — the default — behaviour is identical to read-only GC.\n * Bash output is not always recoverable, so it carries its own safeguards: a\n * command that looks side-effecting is never elided (re-running it, as the\n * stub invites, could repeat a destructive action), and below 80% pressure\n * only large outputs are elided.\n */\n\nimport { resolve } from \"node:path\";\nimport type { AgentMessage } from \"@kolisachint/hoocode-agent-core\";\n\n/** Tool names whose result injects file contents into the transcript. */\nconst READ_TOOLS = new Set([\"read\"]);\n/** Tool names that change a file, making a prior read of that path stale. */\nconst MUTATE_TOOLS = new Set([\"edit\", \"write\"]);\n\n/**\n * Commands whose bash output must never be elided, because the stub invites\n * the model to re-run the command and re-running could repeat a destructive or\n * state-changing action. Tested against the whole command string, and\n * deliberately over-broad: a false positive merely keeps an output (safe),\n * while the common verbose *read* commands (cat/grep/ls/find/git log/diff,\n * test runners) intentionally do NOT match, so they stay evictable.\n */\nconst BASH_SIDE_EFFECT_PATTERN =\n\t/(\\b(write|insert|delete|update|curl|wget|psql|mysql|sqlite3|migrate|drop|truncate|rm|rmdir|mv|cp|dd|kill|tee|chmod|chown|ln|mkdir|touch)\\b|\\bgit\\s+(commit|push|reset|checkout|rebase|clean|apply|merge)\\b|\\bsed\\b[^|]*-i|>>?)/i;\n/** Below 80% pressure, only bash outputs larger than this (chars) are elided. */\nconst BASH_EVICTION_CHAR_THRESHOLD = 2000;\n\nexport interface ContextGcOptions {\n\t/** Working directory used to resolve relative tool path arguments. */\n\tcwd: string;\n\t/**\n\t * Token-budget pressure in [0, 1] — the fraction of the model's context\n\t * window currently in use. Absent or 0 reproduces read-only GC behaviour.\n\t * Bash-output eviction begins at 0.6 and becomes unconditional at 0.8.\n\t */\n\tbudgetPressure?: number;\n}\n\ninterface AssistantLike {\n\trole: \"assistant\";\n\tcontent: Array<{ type: string; id?: string; name?: string; arguments?: Record<string, unknown> }>;\n}\n\ninterface ToolResultLike {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: Array<{ type: string; text?: string }>;\n\tisError: boolean;\n}\n\nfunction isAssistant(m: AgentMessage): m is AgentMessage & AssistantLike {\n\treturn (m as { role?: string }).role === \"assistant\" && Array.isArray((m as AssistantLike).content);\n}\n\nfunction isToolResult(m: AgentMessage): m is AgentMessage & ToolResultLike {\n\treturn (m as { role?: string }).role === \"toolResult\";\n}\n\n/** Half-open line interval [start, end) a read call covers; end is exclusive. */\ninterface ReadRange {\n\tstart: number;\n\tend: number;\n}\n\n/**\n * Derive the line range a read call covers from its `offset`/`limit` args.\n * Missing offset means \"from line 1\"; missing limit means \"to end of file\"\n * (open-ended, so it overlaps any later read of the same file).\n */\nfunction readRangeFromArgs(args: Record<string, unknown> | undefined): ReadRange {\n\tconst offsetRaw = args?.offset;\n\tconst limitRaw = args?.limit;\n\tconst offset = typeof offsetRaw === \"number\" && Number.isFinite(offsetRaw) && offsetRaw > 0 ? offsetRaw : 1;\n\tconst end =\n\t\ttypeof limitRaw === \"number\" && Number.isFinite(limitRaw)\n\t\t\t? offset + Math.max(0, limitRaw)\n\t\t\t: Number.POSITIVE_INFINITY;\n\treturn { start: offset, end };\n}\n\n/** Whether two half-open line ranges intersect. */\nfunction rangesOverlap(a: ReadRange, b: ReadRange): boolean {\n\treturn a.start < b.end && b.start < a.end;\n}\n\nconst WHOLE_FILE_RANGE: ReadRange = { start: 1, end: Number.POSITIVE_INFINITY };\n\n/**\n * Return a message array with superseded `read` results stubbed out. Returns the\n * original array reference unchanged when there is nothing to evict, so a\n * no-op turn does not needlessly perturb the outgoing context.\n */\nexport function evictSupersededReads(messages: AgentMessage[], options: ContextGcOptions): AgentMessage[] {\n\t// Map each tool call id -> the resolved path it operated on, plus a friendly\n\t// display path (the original argument) for the stub text.\n\tconst resolvedPathByCallId = new Map<string, string>();\n\tconst displayPathByResolved = new Map<string, string>();\n\t// Bash calls carry a `command`, not a `path`; capture it so the eviction\n\t// pass can consult the side-effect guard by tool call id.\n\tconst bashCommandByCallId = new Map<string, string>();\n\t// Read calls carry `offset`/`limit`; capture the line range each covers so a\n\t// later read only supersedes an earlier one when their ranges overlap.\n\tconst rangeByCallId = new Map<string, ReadRange>();\n\tfor (const m of messages) {\n\t\tif (!isAssistant(m)) continue;\n\t\tfor (const block of m.content) {\n\t\t\tif (block.type !== \"toolCall\" || !block.id) continue;\n\t\t\tif (block.name === \"bash\") {\n\t\t\t\tconst cmd = block.arguments?.command;\n\t\t\t\tif (typeof cmd === \"string\" && cmd.length > 0) bashCommandByCallId.set(block.id, cmd);\n\t\t\t}\n\t\t\tconst rawPath = block.arguments?.path;\n\t\t\tif (typeof rawPath !== \"string\" || rawPath.length === 0) continue;\n\t\t\tconst resolved = resolve(options.cwd, rawPath);\n\t\t\tresolvedPathByCallId.set(block.id, resolved);\n\t\t\tif (block.name && READ_TOOLS.has(block.name)) rangeByCallId.set(block.id, readRangeFromArgs(block.arguments));\n\t\t\tif (!displayPathByResolved.has(resolved)) displayPathByResolved.set(resolved, rawPath);\n\t\t}\n\t}\n\n\t// First pass: per path, collect every successful read (index + line range)\n\t// and the last successful mutate. A read at index i is superseded when a later\n\t// successful mutate exists (index > i, whole file changed) or a later read of\n\t// an overlapping range exists (index > i) for the same path.\n\tconst readsByPath = new Map<string, Array<{ index: number; range: ReadRange }>>();\n\tconst lastMutateIndex = new Map<string, number>();\n\tmessages.forEach((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return;\n\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\tif (!path) return;\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;\n\t\t\tconst list = readsByPath.get(path);\n\t\t\tif (list) list.push({ index: i, range });\n\t\t\telse readsByPath.set(path, [{ index: i, range }]);\n\t\t} else if (MUTATE_TOOLS.has(m.toolName)) {\n\t\t\tlastMutateIndex.set(path, i);\n\t\t}\n\t});\n\n\t// Second pass: build the output, stubbing evicted reads. Keep every other\n\t// message by reference; clone only the ones we rewrite so the persisted\n\t// history (which may share these objects) is never mutated.\n\tconst pressure = options.budgetPressure ?? 0;\n\tlet changed = false;\n\tconst out = messages.map((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return m;\n\n\t\t// Superseded-read eviction — always on, pressure-independent.\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\t\tif (!path) return m;\n\t\t\tconst range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;\n\t\t\tconst laterMutate = (lastMutateIndex.get(path) ?? -1) > i;\n\t\t\tconst laterOverlappingRead = (readsByPath.get(path) ?? []).some(\n\t\t\t\t(r) => r.index > i && rangesOverlap(r.range, range),\n\t\t\t);\n\t\t\tif (!laterOverlappingRead && !laterMutate) return m;\n\t\t\tchanged = true;\n\t\t\tconst display = displayPathByResolved.get(path) ?? path;\n\t\t\tconst reason = laterMutate ? \"the file was modified after this read\" : \"the file was read again later\";\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `[Superseded read of ${display} elided to save context — ${reason}. Re-read the file if you need its current contents.]`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Bash-output eviction — only under token-budget pressure (>= 0.6).\n\t\tif (pressure >= 0.6 && m.toolName === \"bash\") {\n\t\t\tconst cmd = bashCommandByCallId.get(m.toolCallId) ?? \"\";\n\t\t\tif (BASH_SIDE_EFFECT_PATTERN.test(cmd)) return m;\n\t\t\tconst textLen = m.content.filter((c) => c.type === \"text\").reduce((sum, c) => sum + (c.text?.length ?? 0), 0);\n\t\t\t// 60–79%: elide only large outputs. 80%+: elide unconditionally.\n\t\t\tconst shouldEvict = pressure >= 0.8 || textLen > BASH_EVICTION_CHAR_THRESHOLD;\n\t\t\tif (shouldEvict) {\n\t\t\t\tchanged = true;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `[Bash output elided at ${Math.round(pressure * 100)}% token budget — re-run if needed.]`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn m;\n\t});\n\n\treturn changed ? out : messages;\n}\n"]}
@@ -13,10 +13,13 @@
13
13
  *
14
14
  * A `read` result for a path P is stale once, later in the transcript, the
15
15
  * same path is edited/written (its on-disk content changed) or read again
16
- * (the newer read reflects newer state). The most recent read of each path is
17
- * always kept, and a read is only evicted when a *successful* later event
18
- * supersedes it so a read whose edit failed (and which the model still needs
19
- * to retry) is never touched.
16
+ * over an overlapping line range (the newer read reflects that region's newer
17
+ * state). Reads of disjoint regions of the same file coexist — a later read of
18
+ * lines 200-260 does not evict an earlier read of lines 1-40 so paginating
19
+ * through a large file never makes the model re-fetch a region it already has.
20
+ * A read is only evicted when a *successful* later event supersedes it — so a
21
+ * read whose edit failed (and which the model still needs to retry) is never
22
+ * touched.
20
23
  *
21
24
  * Deliberately conservative: paths are matched after `path.resolve`, so two
22
25
  * different files never collide, and any ambiguity results in NOT evicting.
@@ -51,6 +54,25 @@ function isAssistant(m) {
51
54
  function isToolResult(m) {
52
55
  return m.role === "toolResult";
53
56
  }
57
+ /**
58
+ * Derive the line range a read call covers from its `offset`/`limit` args.
59
+ * Missing offset means "from line 1"; missing limit means "to end of file"
60
+ * (open-ended, so it overlaps any later read of the same file).
61
+ */
62
+ function readRangeFromArgs(args) {
63
+ const offsetRaw = args?.offset;
64
+ const limitRaw = args?.limit;
65
+ const offset = typeof offsetRaw === "number" && Number.isFinite(offsetRaw) && offsetRaw > 0 ? offsetRaw : 1;
66
+ const end = typeof limitRaw === "number" && Number.isFinite(limitRaw)
67
+ ? offset + Math.max(0, limitRaw)
68
+ : Number.POSITIVE_INFINITY;
69
+ return { start: offset, end };
70
+ }
71
+ /** Whether two half-open line ranges intersect. */
72
+ function rangesOverlap(a, b) {
73
+ return a.start < b.end && b.start < a.end;
74
+ }
75
+ const WHOLE_FILE_RANGE = { start: 1, end: Number.POSITIVE_INFINITY };
54
76
  /**
55
77
  * Return a message array with superseded `read` results stubbed out. Returns the
56
78
  * original array reference unchanged when there is nothing to evict, so a
@@ -64,6 +86,9 @@ export function evictSupersededReads(messages, options) {
64
86
  // Bash calls carry a `command`, not a `path`; capture it so the eviction
65
87
  // pass can consult the side-effect guard by tool call id.
66
88
  const bashCommandByCallId = new Map();
89
+ // Read calls carry `offset`/`limit`; capture the line range each covers so a
90
+ // later read only supersedes an earlier one when their ranges overlap.
91
+ const rangeByCallId = new Map();
67
92
  for (const m of messages) {
68
93
  if (!isAssistant(m))
69
94
  continue;
@@ -80,14 +105,17 @@ export function evictSupersededReads(messages, options) {
80
105
  continue;
81
106
  const resolved = resolve(options.cwd, rawPath);
82
107
  resolvedPathByCallId.set(block.id, resolved);
108
+ if (block.name && READ_TOOLS.has(block.name))
109
+ rangeByCallId.set(block.id, readRangeFromArgs(block.arguments));
83
110
  if (!displayPathByResolved.has(resolved))
84
111
  displayPathByResolved.set(resolved, rawPath);
85
112
  }
86
113
  }
87
- // First pass: per path, the index of the last read and the last successful
88
- // mutate. A read at index i is superseded when a later read (index > i) or a
89
- // later successful mutate (index > i) exists for the same path.
90
- const lastReadIndex = new Map();
114
+ // First pass: per path, collect every successful read (index + line range)
115
+ // and the last successful mutate. A read at index i is superseded when a later
116
+ // successful mutate exists (index > i, whole file changed) or a later read of
117
+ // an overlapping range exists (index > i) for the same path.
118
+ const readsByPath = new Map();
91
119
  const lastMutateIndex = new Map();
92
120
  messages.forEach((m, i) => {
93
121
  if (!isToolResult(m) || m.isError)
@@ -96,7 +124,12 @@ export function evictSupersededReads(messages, options) {
96
124
  if (!path)
97
125
  return;
98
126
  if (READ_TOOLS.has(m.toolName)) {
99
- lastReadIndex.set(path, i);
127
+ const range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;
128
+ const list = readsByPath.get(path);
129
+ if (list)
130
+ list.push({ index: i, range });
131
+ else
132
+ readsByPath.set(path, [{ index: i, range }]);
100
133
  }
101
134
  else if (MUTATE_TOOLS.has(m.toolName)) {
102
135
  lastMutateIndex.set(path, i);
@@ -115,9 +148,10 @@ export function evictSupersededReads(messages, options) {
115
148
  const path = resolvedPathByCallId.get(m.toolCallId);
116
149
  if (!path)
117
150
  return m;
118
- const laterRead = (lastReadIndex.get(path) ?? -1) > i;
151
+ const range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;
119
152
  const laterMutate = (lastMutateIndex.get(path) ?? -1) > i;
120
- if (!laterRead && !laterMutate)
153
+ const laterOverlappingRead = (readsByPath.get(path) ?? []).some((r) => r.index > i && rangesOverlap(r.range, range));
154
+ if (!laterOverlappingRead && !laterMutate)
121
155
  return m;
122
156
  changed = true;
123
157
  const display = displayPathByResolved.get(path) ?? path;
@@ -1 +1 @@
1
- {"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context garbage collection.\n *\n * The whole transcript is re-sent on every turn, so a tool result that has\n * become useless keeps costing tokens for the rest of the session. This pass\n * runs on the OUTGOING message copy (via the agent's `transformContext` hook),\n * never on the persisted session, and replaces provably-dead `read` results\n * with a short stub. Nothing is lost: the persisted history is untouched and\n * the file is re-readable on demand.\n *\n * Current rule — superseded reads only (the read-then-edit / re-read pattern,\n * which dominates coding sessions):\n *\n * A `read` result for a path P is stale once, later in the transcript, the\n * same path is edited/written (its on-disk content changed) or read again\n * (the newer read reflects newer state). The most recent read of each path is\n * always kept, and a read is only evicted when a *successful* later event\n * supersedes it — so a read whose edit failed (and which the model still needs\n * to retry) is never touched.\n *\n * Deliberately conservative: paths are matched after `path.resolve`, so two\n * different files never collide, and any ambiguity results in NOT evicting.\n *\n * Bash-output eviction is additionally gated on token-budget pressure\n * (`options.budgetPressure`, the fraction of the model's context window in\n * use). At 0 pressure — the default — behaviour is identical to read-only GC.\n * Bash output is not always recoverable, so it carries its own safeguards: a\n * command that looks side-effecting is never elided (re-running it, as the\n * stub invites, could repeat a destructive action), and below 80% pressure\n * only large outputs are elided.\n */\n\nimport { resolve } from \"node:path\";\nimport type { AgentMessage } from \"@kolisachint/hoocode-agent-core\";\n\n/** Tool names whose result injects file contents into the transcript. */\nconst READ_TOOLS = new Set([\"read\"]);\n/** Tool names that change a file, making a prior read of that path stale. */\nconst MUTATE_TOOLS = new Set([\"edit\", \"write\"]);\n\n/**\n * Commands whose bash output must never be elided, because the stub invites\n * the model to re-run the command and re-running could repeat a destructive or\n * state-changing action. Tested against the whole command string, and\n * deliberately over-broad: a false positive merely keeps an output (safe),\n * while the common verbose *read* commands (cat/grep/ls/find/git log/diff,\n * test runners) intentionally do NOT match, so they stay evictable.\n */\nconst BASH_SIDE_EFFECT_PATTERN =\n\t/(\\b(write|insert|delete|update|curl|wget|psql|mysql|sqlite3|migrate|drop|truncate|rm|rmdir|mv|cp|dd|kill|tee|chmod|chown|ln|mkdir|touch)\\b|\\bgit\\s+(commit|push|reset|checkout|rebase|clean|apply|merge)\\b|\\bsed\\b[^|]*-i|>>?)/i;\n/** Below 80% pressure, only bash outputs larger than this (chars) are elided. */\nconst BASH_EVICTION_CHAR_THRESHOLD = 2000;\n\nexport interface ContextGcOptions {\n\t/** Working directory used to resolve relative tool path arguments. */\n\tcwd: string;\n\t/**\n\t * Token-budget pressure in [0, 1] — the fraction of the model's context\n\t * window currently in use. Absent or 0 reproduces read-only GC behaviour.\n\t * Bash-output eviction begins at 0.6 and becomes unconditional at 0.8.\n\t */\n\tbudgetPressure?: number;\n}\n\ninterface AssistantLike {\n\trole: \"assistant\";\n\tcontent: Array<{ type: string; id?: string; name?: string; arguments?: Record<string, unknown> }>;\n}\n\ninterface ToolResultLike {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: Array<{ type: string; text?: string }>;\n\tisError: boolean;\n}\n\nfunction isAssistant(m: AgentMessage): m is AgentMessage & AssistantLike {\n\treturn (m as { role?: string }).role === \"assistant\" && Array.isArray((m as AssistantLike).content);\n}\n\nfunction isToolResult(m: AgentMessage): m is AgentMessage & ToolResultLike {\n\treturn (m as { role?: string }).role === \"toolResult\";\n}\n\n/**\n * Return a message array with superseded `read` results stubbed out. Returns the\n * original array reference unchanged when there is nothing to evict, so a\n * no-op turn does not needlessly perturb the outgoing context.\n */\nexport function evictSupersededReads(messages: AgentMessage[], options: ContextGcOptions): AgentMessage[] {\n\t// Map each tool call id -> the resolved path it operated on, plus a friendly\n\t// display path (the original argument) for the stub text.\n\tconst resolvedPathByCallId = new Map<string, string>();\n\tconst displayPathByResolved = new Map<string, string>();\n\t// Bash calls carry a `command`, not a `path`; capture it so the eviction\n\t// pass can consult the side-effect guard by tool call id.\n\tconst bashCommandByCallId = new Map<string, string>();\n\tfor (const m of messages) {\n\t\tif (!isAssistant(m)) continue;\n\t\tfor (const block of m.content) {\n\t\t\tif (block.type !== \"toolCall\" || !block.id) continue;\n\t\t\tif (block.name === \"bash\") {\n\t\t\t\tconst cmd = block.arguments?.command;\n\t\t\t\tif (typeof cmd === \"string\" && cmd.length > 0) bashCommandByCallId.set(block.id, cmd);\n\t\t\t}\n\t\t\tconst rawPath = block.arguments?.path;\n\t\t\tif (typeof rawPath !== \"string\" || rawPath.length === 0) continue;\n\t\t\tconst resolved = resolve(options.cwd, rawPath);\n\t\t\tresolvedPathByCallId.set(block.id, resolved);\n\t\t\tif (!displayPathByResolved.has(resolved)) displayPathByResolved.set(resolved, rawPath);\n\t\t}\n\t}\n\n\t// First pass: per path, the index of the last read and the last successful\n\t// mutate. A read at index i is superseded when a later read (index > i) or a\n\t// later successful mutate (index > i) exists for the same path.\n\tconst lastReadIndex = new Map<string, number>();\n\tconst lastMutateIndex = new Map<string, number>();\n\tmessages.forEach((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return;\n\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\tif (!path) return;\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tlastReadIndex.set(path, i);\n\t\t} else if (MUTATE_TOOLS.has(m.toolName)) {\n\t\t\tlastMutateIndex.set(path, i);\n\t\t}\n\t});\n\n\t// Second pass: build the output, stubbing evicted reads. Keep every other\n\t// message by reference; clone only the ones we rewrite so the persisted\n\t// history (which may share these objects) is never mutated.\n\tconst pressure = options.budgetPressure ?? 0;\n\tlet changed = false;\n\tconst out = messages.map((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return m;\n\n\t\t// Superseded-read eviction — always on, pressure-independent.\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\t\tif (!path) return m;\n\t\t\tconst laterRead = (lastReadIndex.get(path) ?? -1) > i;\n\t\t\tconst laterMutate = (lastMutateIndex.get(path) ?? -1) > i;\n\t\t\tif (!laterRead && !laterMutate) return m;\n\t\t\tchanged = true;\n\t\t\tconst display = displayPathByResolved.get(path) ?? path;\n\t\t\tconst reason = laterMutate ? \"the file was modified after this read\" : \"the file was read again later\";\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `[Superseded read of ${display} elided to save context — ${reason}. Re-read the file if you need its current contents.]`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Bash-output eviction — only under token-budget pressure (>= 0.6).\n\t\tif (pressure >= 0.6 && m.toolName === \"bash\") {\n\t\t\tconst cmd = bashCommandByCallId.get(m.toolCallId) ?? \"\";\n\t\t\tif (BASH_SIDE_EFFECT_PATTERN.test(cmd)) return m;\n\t\t\tconst textLen = m.content.filter((c) => c.type === \"text\").reduce((sum, c) => sum + (c.text?.length ?? 0), 0);\n\t\t\t// 60–79%: elide only large outputs. 80%+: elide unconditionally.\n\t\t\tconst shouldEvict = pressure >= 0.8 || textLen > BASH_EVICTION_CHAR_THRESHOLD;\n\t\t\tif (shouldEvict) {\n\t\t\t\tchanged = true;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `[Bash output elided at ${Math.round(pressure * 100)}% token budget — re-run if needed.]`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn m;\n\t});\n\n\treturn changed ? out : messages;\n}\n"]}
1
+ {"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context garbage collection.\n *\n * The whole transcript is re-sent on every turn, so a tool result that has\n * become useless keeps costing tokens for the rest of the session. This pass\n * runs on the OUTGOING message copy (via the agent's `transformContext` hook),\n * never on the persisted session, and replaces provably-dead `read` results\n * with a short stub. Nothing is lost: the persisted history is untouched and\n * the file is re-readable on demand.\n *\n * Current rule — superseded reads only (the read-then-edit / re-read pattern,\n * which dominates coding sessions):\n *\n * A `read` result for a path P is stale once, later in the transcript, the\n * same path is edited/written (its on-disk content changed) or read again\n * over an overlapping line range (the newer read reflects that region's newer\n * state). Reads of disjoint regions of the same file coexist — a later read of\n * lines 200-260 does not evict an earlier read of lines 1-40 — so paginating\n * through a large file never makes the model re-fetch a region it already has.\n * A read is only evicted when a *successful* later event supersedes it — so a\n * read whose edit failed (and which the model still needs to retry) is never\n * touched.\n *\n * Deliberately conservative: paths are matched after `path.resolve`, so two\n * different files never collide, and any ambiguity results in NOT evicting.\n *\n * Bash-output eviction is additionally gated on token-budget pressure\n * (`options.budgetPressure`, the fraction of the model's context window in\n * use). At 0 pressure — the default — behaviour is identical to read-only GC.\n * Bash output is not always recoverable, so it carries its own safeguards: a\n * command that looks side-effecting is never elided (re-running it, as the\n * stub invites, could repeat a destructive action), and below 80% pressure\n * only large outputs are elided.\n */\n\nimport { resolve } from \"node:path\";\nimport type { AgentMessage } from \"@kolisachint/hoocode-agent-core\";\n\n/** Tool names whose result injects file contents into the transcript. */\nconst READ_TOOLS = new Set([\"read\"]);\n/** Tool names that change a file, making a prior read of that path stale. */\nconst MUTATE_TOOLS = new Set([\"edit\", \"write\"]);\n\n/**\n * Commands whose bash output must never be elided, because the stub invites\n * the model to re-run the command and re-running could repeat a destructive or\n * state-changing action. Tested against the whole command string, and\n * deliberately over-broad: a false positive merely keeps an output (safe),\n * while the common verbose *read* commands (cat/grep/ls/find/git log/diff,\n * test runners) intentionally do NOT match, so they stay evictable.\n */\nconst BASH_SIDE_EFFECT_PATTERN =\n\t/(\\b(write|insert|delete|update|curl|wget|psql|mysql|sqlite3|migrate|drop|truncate|rm|rmdir|mv|cp|dd|kill|tee|chmod|chown|ln|mkdir|touch)\\b|\\bgit\\s+(commit|push|reset|checkout|rebase|clean|apply|merge)\\b|\\bsed\\b[^|]*-i|>>?)/i;\n/** Below 80% pressure, only bash outputs larger than this (chars) are elided. */\nconst BASH_EVICTION_CHAR_THRESHOLD = 2000;\n\nexport interface ContextGcOptions {\n\t/** Working directory used to resolve relative tool path arguments. */\n\tcwd: string;\n\t/**\n\t * Token-budget pressure in [0, 1] — the fraction of the model's context\n\t * window currently in use. Absent or 0 reproduces read-only GC behaviour.\n\t * Bash-output eviction begins at 0.6 and becomes unconditional at 0.8.\n\t */\n\tbudgetPressure?: number;\n}\n\ninterface AssistantLike {\n\trole: \"assistant\";\n\tcontent: Array<{ type: string; id?: string; name?: string; arguments?: Record<string, unknown> }>;\n}\n\ninterface ToolResultLike {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: Array<{ type: string; text?: string }>;\n\tisError: boolean;\n}\n\nfunction isAssistant(m: AgentMessage): m is AgentMessage & AssistantLike {\n\treturn (m as { role?: string }).role === \"assistant\" && Array.isArray((m as AssistantLike).content);\n}\n\nfunction isToolResult(m: AgentMessage): m is AgentMessage & ToolResultLike {\n\treturn (m as { role?: string }).role === \"toolResult\";\n}\n\n/** Half-open line interval [start, end) a read call covers; end is exclusive. */\ninterface ReadRange {\n\tstart: number;\n\tend: number;\n}\n\n/**\n * Derive the line range a read call covers from its `offset`/`limit` args.\n * Missing offset means \"from line 1\"; missing limit means \"to end of file\"\n * (open-ended, so it overlaps any later read of the same file).\n */\nfunction readRangeFromArgs(args: Record<string, unknown> | undefined): ReadRange {\n\tconst offsetRaw = args?.offset;\n\tconst limitRaw = args?.limit;\n\tconst offset = typeof offsetRaw === \"number\" && Number.isFinite(offsetRaw) && offsetRaw > 0 ? offsetRaw : 1;\n\tconst end =\n\t\ttypeof limitRaw === \"number\" && Number.isFinite(limitRaw)\n\t\t\t? offset + Math.max(0, limitRaw)\n\t\t\t: Number.POSITIVE_INFINITY;\n\treturn { start: offset, end };\n}\n\n/** Whether two half-open line ranges intersect. */\nfunction rangesOverlap(a: ReadRange, b: ReadRange): boolean {\n\treturn a.start < b.end && b.start < a.end;\n}\n\nconst WHOLE_FILE_RANGE: ReadRange = { start: 1, end: Number.POSITIVE_INFINITY };\n\n/**\n * Return a message array with superseded `read` results stubbed out. Returns the\n * original array reference unchanged when there is nothing to evict, so a\n * no-op turn does not needlessly perturb the outgoing context.\n */\nexport function evictSupersededReads(messages: AgentMessage[], options: ContextGcOptions): AgentMessage[] {\n\t// Map each tool call id -> the resolved path it operated on, plus a friendly\n\t// display path (the original argument) for the stub text.\n\tconst resolvedPathByCallId = new Map<string, string>();\n\tconst displayPathByResolved = new Map<string, string>();\n\t// Bash calls carry a `command`, not a `path`; capture it so the eviction\n\t// pass can consult the side-effect guard by tool call id.\n\tconst bashCommandByCallId = new Map<string, string>();\n\t// Read calls carry `offset`/`limit`; capture the line range each covers so a\n\t// later read only supersedes an earlier one when their ranges overlap.\n\tconst rangeByCallId = new Map<string, ReadRange>();\n\tfor (const m of messages) {\n\t\tif (!isAssistant(m)) continue;\n\t\tfor (const block of m.content) {\n\t\t\tif (block.type !== \"toolCall\" || !block.id) continue;\n\t\t\tif (block.name === \"bash\") {\n\t\t\t\tconst cmd = block.arguments?.command;\n\t\t\t\tif (typeof cmd === \"string\" && cmd.length > 0) bashCommandByCallId.set(block.id, cmd);\n\t\t\t}\n\t\t\tconst rawPath = block.arguments?.path;\n\t\t\tif (typeof rawPath !== \"string\" || rawPath.length === 0) continue;\n\t\t\tconst resolved = resolve(options.cwd, rawPath);\n\t\t\tresolvedPathByCallId.set(block.id, resolved);\n\t\t\tif (block.name && READ_TOOLS.has(block.name)) rangeByCallId.set(block.id, readRangeFromArgs(block.arguments));\n\t\t\tif (!displayPathByResolved.has(resolved)) displayPathByResolved.set(resolved, rawPath);\n\t\t}\n\t}\n\n\t// First pass: per path, collect every successful read (index + line range)\n\t// and the last successful mutate. A read at index i is superseded when a later\n\t// successful mutate exists (index > i, whole file changed) or a later read of\n\t// an overlapping range exists (index > i) for the same path.\n\tconst readsByPath = new Map<string, Array<{ index: number; range: ReadRange }>>();\n\tconst lastMutateIndex = new Map<string, number>();\n\tmessages.forEach((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return;\n\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\tif (!path) return;\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;\n\t\t\tconst list = readsByPath.get(path);\n\t\t\tif (list) list.push({ index: i, range });\n\t\t\telse readsByPath.set(path, [{ index: i, range }]);\n\t\t} else if (MUTATE_TOOLS.has(m.toolName)) {\n\t\t\tlastMutateIndex.set(path, i);\n\t\t}\n\t});\n\n\t// Second pass: build the output, stubbing evicted reads. Keep every other\n\t// message by reference; clone only the ones we rewrite so the persisted\n\t// history (which may share these objects) is never mutated.\n\tconst pressure = options.budgetPressure ?? 0;\n\tlet changed = false;\n\tconst out = messages.map((m, i) => {\n\t\tif (!isToolResult(m) || m.isError) return m;\n\n\t\t// Superseded-read eviction — always on, pressure-independent.\n\t\tif (READ_TOOLS.has(m.toolName)) {\n\t\t\tconst path = resolvedPathByCallId.get(m.toolCallId);\n\t\t\tif (!path) return m;\n\t\t\tconst range = rangeByCallId.get(m.toolCallId) ?? WHOLE_FILE_RANGE;\n\t\t\tconst laterMutate = (lastMutateIndex.get(path) ?? -1) > i;\n\t\t\tconst laterOverlappingRead = (readsByPath.get(path) ?? []).some(\n\t\t\t\t(r) => r.index > i && rangesOverlap(r.range, range),\n\t\t\t);\n\t\t\tif (!laterOverlappingRead && !laterMutate) return m;\n\t\t\tchanged = true;\n\t\t\tconst display = displayPathByResolved.get(path) ?? path;\n\t\t\tconst reason = laterMutate ? \"the file was modified after this read\" : \"the file was read again later\";\n\t\t\treturn {\n\t\t\t\t...m,\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `[Superseded read of ${display} elided to save context — ${reason}. Re-read the file if you need its current contents.]`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// Bash-output eviction — only under token-budget pressure (>= 0.6).\n\t\tif (pressure >= 0.6 && m.toolName === \"bash\") {\n\t\t\tconst cmd = bashCommandByCallId.get(m.toolCallId) ?? \"\";\n\t\t\tif (BASH_SIDE_EFFECT_PATTERN.test(cmd)) return m;\n\t\t\tconst textLen = m.content.filter((c) => c.type === \"text\").reduce((sum, c) => sum + (c.text?.length ?? 0), 0);\n\t\t\t// 60–79%: elide only large outputs. 80%+: elide unconditionally.\n\t\t\tconst shouldEvict = pressure >= 0.8 || textLen > BASH_EVICTION_CHAR_THRESHOLD;\n\t\t\tif (shouldEvict) {\n\t\t\t\tchanged = true;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `[Bash output elided at ${Math.round(pressure * 100)}% token budget — re-run if needed.]`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn m;\n\t});\n\n\treturn changed ? out : messages;\n}\n"]}
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Shared helpers for the fd-backed file search tools (find, glob).
3
- *
4
- * These are pure functions extracted to remove duplication between find.ts and
5
- * glob.ts. The tools keep their own control flow (find streams a single fd run;
6
- * glob fans out one fd run per pattern), but path normalization and fd glob
7
- * argument handling are identical and live here.
2
+ * Shared helpers for the fd-backed `find` tool: path normalization and fd glob
3
+ * argument handling. `find` runs one fd invocation per pattern (OR logic across
4
+ * an array). These are pure functions; `toPosixPath` is also reused for stable
5
+ * forward-slash output elsewhere in the codebase (native-search, skills, read,
6
+ * package resource discovery).
8
7
  */
9
8
  /** Convert a platform path to forward-slash (POSIX) form for stable output. */
10
9
  export declare function toPosixPath(value: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"fd-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/fd-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAUzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS1E","sourcesContent":["/**\n * Shared helpers for the fd-backed file search tools (find, glob).\n *\n * These are pure functions extracted to remove duplication between find.ts and\n * glob.ts. The tools keep their own control flow (find streams a single fd run;\n * glob fans out one fd run per pattern), but path normalization and fd glob\n * argument handling are identical and live here.\n */\n\nimport path from \"path\";\n\n/** Convert a platform path to forward-slash (POSIX) form for stable output. */\nexport function toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\n/**\n * Relativize an fd result line against the search root, preserving any trailing\n * slash that marked a directory, and return it in POSIX form.\n */\nexport function relativizeFdLine(line: string, searchPath: string): string {\n\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\tlet relativePath: string;\n\tif (line.startsWith(searchPath)) {\n\t\trelativePath = line.slice(searchPath.length + 1);\n\t} else {\n\t\trelativePath = path.relative(searchPath, line);\n\t}\n\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\treturn toPosixPath(relativePath);\n}\n\n/**\n * Append a glob pattern (and any required --full-path flag) to an fd argument\n * list. fd --glob matches against the basename unless --full-path is set; in\n * --full-path mode a path-containing pattern like 'src/**\\/*.ts' needs a leading\n * '**\\/' to match anything.\n */\nexport function applyFdGlobPattern(args: string[], pattern: string): string {\n\tlet effectivePattern = pattern;\n\tif (pattern.includes(\"/\")) {\n\t\targs.push(\"--full-path\");\n\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\teffectivePattern = `**/${pattern}`;\n\t\t}\n\t}\n\treturn effectivePattern;\n}\n"]}
1
+ {"version":3,"file":"fd-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/fd-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAUzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS1E","sourcesContent":["/**\n * Shared helpers for the fd-backed `find` tool: path normalization and fd glob\n * argument handling. `find` runs one fd invocation per pattern (OR logic across\n * an array). These are pure functions; `toPosixPath` is also reused for stable\n * forward-slash output elsewhere in the codebase (native-search, skills, read,\n * package resource discovery).\n */\n\nimport path from \"path\";\n\n/** Convert a platform path to forward-slash (POSIX) form for stable output. */\nexport function toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\n/**\n * Relativize an fd result line against the search root, preserving any trailing\n * slash that marked a directory, and return it in POSIX form.\n */\nexport function relativizeFdLine(line: string, searchPath: string): string {\n\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\tlet relativePath: string;\n\tif (line.startsWith(searchPath)) {\n\t\trelativePath = line.slice(searchPath.length + 1);\n\t} else {\n\t\trelativePath = path.relative(searchPath, line);\n\t}\n\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\treturn toPosixPath(relativePath);\n}\n\n/**\n * Append a glob pattern (and any required --full-path flag) to an fd argument\n * list. fd --glob matches against the basename unless --full-path is set; in\n * --full-path mode a path-containing pattern like 'src/**\\/*.ts' needs a leading\n * '**\\/' to match anything.\n */\nexport function applyFdGlobPattern(args: string[], pattern: string): string {\n\tlet effectivePattern = pattern;\n\tif (pattern.includes(\"/\")) {\n\t\targs.push(\"--full-path\");\n\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\teffectivePattern = `**/${pattern}`;\n\t\t}\n\t}\n\treturn effectivePattern;\n}\n"]}
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Shared helpers for the fd-backed file search tools (find, glob).
3
- *
4
- * These are pure functions extracted to remove duplication between find.ts and
5
- * glob.ts. The tools keep their own control flow (find streams a single fd run;
6
- * glob fans out one fd run per pattern), but path normalization and fd glob
7
- * argument handling are identical and live here.
2
+ * Shared helpers for the fd-backed `find` tool: path normalization and fd glob
3
+ * argument handling. `find` runs one fd invocation per pattern (OR logic across
4
+ * an array). These are pure functions; `toPosixPath` is also reused for stable
5
+ * forward-slash output elsewhere in the codebase (native-search, skills, read,
6
+ * package resource discovery).
8
7
  */
9
8
  import path from "path";
10
9
  /** Convert a platform path to forward-slash (POSIX) form for stable output. */
@@ -1 +1 @@
1
- {"version":3,"file":"fd-utils.js","sourceRoot":"","sources":["../../../src/core/tools/fd-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,KAAa,EAAU;IAClD,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CACvC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAAkB,EAAU;IAC1E,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnE,IAAI,YAAoB,CAAC;IACzB,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,gBAAgB,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,YAAY,IAAI,GAAG,CAAC;IACzE,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;AAAA,CACjC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAc,EAAE,OAAe,EAAU;IAC3E,IAAI,gBAAgB,GAAG,OAAO,CAAC;IAC/B,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YAChF,gBAAgB,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,CAAC;IACF,CAAC;IACD,OAAO,gBAAgB,CAAC;AAAA,CACxB","sourcesContent":["/**\n * Shared helpers for the fd-backed file search tools (find, glob).\n *\n * These are pure functions extracted to remove duplication between find.ts and\n * glob.ts. The tools keep their own control flow (find streams a single fd run;\n * glob fans out one fd run per pattern), but path normalization and fd glob\n * argument handling are identical and live here.\n */\n\nimport path from \"path\";\n\n/** Convert a platform path to forward-slash (POSIX) form for stable output. */\nexport function toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\n/**\n * Relativize an fd result line against the search root, preserving any trailing\n * slash that marked a directory, and return it in POSIX form.\n */\nexport function relativizeFdLine(line: string, searchPath: string): string {\n\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\tlet relativePath: string;\n\tif (line.startsWith(searchPath)) {\n\t\trelativePath = line.slice(searchPath.length + 1);\n\t} else {\n\t\trelativePath = path.relative(searchPath, line);\n\t}\n\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\treturn toPosixPath(relativePath);\n}\n\n/**\n * Append a glob pattern (and any required --full-path flag) to an fd argument\n * list. fd --glob matches against the basename unless --full-path is set; in\n * --full-path mode a path-containing pattern like 'src/**\\/*.ts' needs a leading\n * '**\\/' to match anything.\n */\nexport function applyFdGlobPattern(args: string[], pattern: string): string {\n\tlet effectivePattern = pattern;\n\tif (pattern.includes(\"/\")) {\n\t\targs.push(\"--full-path\");\n\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\teffectivePattern = `**/${pattern}`;\n\t\t}\n\t}\n\treturn effectivePattern;\n}\n"]}
1
+ {"version":3,"file":"fd-utils.js","sourceRoot":"","sources":["../../../src/core/tools/fd-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,KAAa,EAAU;IAClD,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CACvC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAAkB,EAAU;IAC1E,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnE,IAAI,YAAoB,CAAC;IACzB,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,gBAAgB,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,YAAY,IAAI,GAAG,CAAC;IACzE,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;AAAA,CACjC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAc,EAAE,OAAe,EAAU;IAC3E,IAAI,gBAAgB,GAAG,OAAO,CAAC;IAC/B,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YAChF,gBAAgB,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,CAAC;IACF,CAAC;IACD,OAAO,gBAAgB,CAAC;AAAA,CACxB","sourcesContent":["/**\n * Shared helpers for the fd-backed `find` tool: path normalization and fd glob\n * argument handling. `find` runs one fd invocation per pattern (OR logic across\n * an array). These are pure functions; `toPosixPath` is also reused for stable\n * forward-slash output elsewhere in the codebase (native-search, skills, read,\n * package resource discovery).\n */\n\nimport path from \"path\";\n\n/** Convert a platform path to forward-slash (POSIX) form for stable output. */\nexport function toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\n/**\n * Relativize an fd result line against the search root, preserving any trailing\n * slash that marked a directory, and return it in POSIX form.\n */\nexport function relativizeFdLine(line: string, searchPath: string): string {\n\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\tlet relativePath: string;\n\tif (line.startsWith(searchPath)) {\n\t\trelativePath = line.slice(searchPath.length + 1);\n\t} else {\n\t\trelativePath = path.relative(searchPath, line);\n\t}\n\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\treturn toPosixPath(relativePath);\n}\n\n/**\n * Append a glob pattern (and any required --full-path flag) to an fd argument\n * list. fd --glob matches against the basename unless --full-path is set; in\n * --full-path mode a path-containing pattern like 'src/**\\/*.ts' needs a leading\n * '**\\/' to match anything.\n */\nexport function applyFdGlobPattern(args: string[], pattern: string): string {\n\tlet effectivePattern = pattern;\n\tif (pattern.includes(\"/\")) {\n\t\targs.push(\"--full-path\");\n\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\teffectivePattern = `**/${pattern}`;\n\t\t}\n\t}\n\treturn effectivePattern;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Off-by-default tools (enabled per session via flags/settings).\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Search: always active. It degrades to grep-backed lexical retrieval when no\n// semantic index is present; the `--enable-embsearchtools` flag only gates\n// whether the semantic index is built and fused in, not whether the tool exists.\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
@@ -10,7 +10,9 @@ export { createGrepTool, createGrepToolDefinition, } from "./grep.js";
10
10
  export { createLsTool, createLsToolDefinition, } from "./ls.js";
11
11
  export { expandPath, resolveReadPath, resolveToCwd } from "./path-utils.js";
12
12
  export { createReadTool, createReadToolDefinition, } from "./read.js";
13
- // Off-by-default tools (enabled per session via flags/settings).
13
+ // Search: always active. It degrades to grep-backed lexical retrieval when no
14
+ // semantic index is present; the `--enable-embsearchtools` flag only gates
15
+ // whether the semantic index is built and fused in, not whether the tool exists.
14
16
  export { createSearchTool, createSearchToolDefinition, } from "./search.js";
15
17
  export { buildTaskMainPrompt, createTaskOutputToolDefinition, createTaskToolDefinition, } from "./subagent.js";
16
18
  export { createTodoWriteToolDefinition } from "./todo.js";
@@ -58,10 +60,10 @@ const TOOL_FACTORIES = {
58
60
  DocPeek: createDocPeekToolDefinition,
59
61
  };
60
62
  export const allToolNames = new Set(Object.keys(TOOL_FACTORIES));
61
- /** The default coding bundle (read/write + shell). */
62
- const CODING_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
63
+ /** The default coding bundle (read/write + shell + search). */
64
+ const CODING_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls", "search"];
63
65
  /** Read-only exploration bundle. */
64
- const READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls"];
66
+ const READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls", "search"];
65
67
  export function createToolDefinition(toolName, cwd, options) {
66
68
  const factory = TOOL_FACTORIES[toolName];
67
69
  if (!factory) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Off-by-default tools (enabled per session via flags/settings).\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Search: always active. It degrades to grep-backed lexical retrieval when no\n// semantic index is present; the `--enable-embsearchtools` flag only gates\n// whether the semantic index is built and fused in, not whether the tool exists.\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.2.144",
4
+ "version": "0.2.146",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.2.144",
4
+ "version": "0.2.146",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-sandbox",
3
3
  "private": true,
4
- "version": "0.2.144",
4
+ "version": "0.2.146",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.2.144",
4
+ "version": "0.2.146",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-agent",
3
- "version": "0.4.147",
3
+ "version": "0.4.149",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "hoocodeConfig": {
@@ -45,9 +45,9 @@
45
45
  "prepublishOnly": "npm run clean && npm run build"
46
46
  },
47
47
  "dependencies": {
48
- "@kolisachint/hoocode-agent-core": "^0.4.147",
49
- "@kolisachint/hoocode-ai": "^0.4.147",
50
- "@kolisachint/hoocode-tui": "^0.4.147",
48
+ "@kolisachint/hoocode-agent-core": "^0.4.149",
49
+ "@kolisachint/hoocode-ai": "^0.4.149",
50
+ "@kolisachint/hoocode-tui": "^0.4.149",
51
51
  "@silvia-odwyer/photon-node": "^0.3.4",
52
52
  "chalk": "^5.5.0",
53
53
  "cli-highlight": "^2.1.11",