@agimon-ai/doompi-grep 0.0.1-alpha.1
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/LICENSE +22 -0
- package/README.md +78 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/pi/extension.d.cts +10 -0
- package/dist/adapters/pi/extension.d.cts.map +1 -0
- package/dist/adapters/pi/extension.d.mts +10 -0
- package/dist/adapters/pi/extension.d.mts.map +1 -0
- package/dist/adapters/pi/extension.mjs +2 -0
- package/dist/adapters/pi/extension.mjs.map +1 -0
- package/dist/adapters/pi/grepTool.cjs +10 -0
- package/dist/adapters/pi/grepTool.cjs.map +1 -0
- package/dist/adapters/pi/grepTool.d.cts +9 -0
- package/dist/adapters/pi/grepTool.d.cts.map +1 -0
- package/dist/adapters/pi/grepTool.d.mts +9 -0
- package/dist/adapters/pi/grepTool.d.mts.map +1 -0
- package/dist/adapters/pi/grepTool.mjs +10 -0
- package/dist/adapters/pi/grepTool.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +1 -0
- package/dist/schemas/grepTool.cjs +2 -0
- package/dist/schemas/grepTool.cjs.map +1 -0
- package/dist/schemas/grepTool.d.cts +15 -0
- package/dist/schemas/grepTool.d.cts.map +1 -0
- package/dist/schemas/grepTool.d.mts +15 -0
- package/dist/schemas/grepTool.d.mts.map +1 -0
- package/dist/schemas/grepTool.mjs +2 -0
- package/dist/schemas/grepTool.mjs.map +1 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vuong Ngo
|
|
4
|
+
Copyright (c) 2026 pulseaiclub
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @agimon-ai/doompi-grep
|
|
2
|
+
|
|
3
|
+
Snapshot-bound hashline grep for Pi and DoomPi.
|
|
4
|
+
|
|
5
|
+
Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
|
|
6
|
+
|
|
7
|
+
The package replaces only Pi's `grep` registration. It delegates searching to
|
|
8
|
+
Pi's native grep tool, preserving its ripgrep behavior, then attaches an exact
|
|
9
|
+
file tag and a stable three-letter anchor to matching or context lines from
|
|
10
|
+
writable files. Matches in non-writable files retain Pi's native output to save
|
|
11
|
+
model context. The matching `@agimon-ai/doompi-read` and `@agimon-ai/doompi-edit`
|
|
12
|
+
packages use the same hashline protocol.
|
|
13
|
+
|
|
14
|
+
> **Alpha:** tool and protocol contracts may change between releases.
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
- Node.js 22.19.0 or newer
|
|
19
|
+
- Pi 0.84.2 and Pi TUI 0.84.2
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pi install npm:@agimon-ai/doompi-grep
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Pi discovers `@agimon-ai/doompi-grep/extensions/pi` from the package manifest.
|
|
28
|
+
|
|
29
|
+
Install `@agimon-ai/doompi-edit` when the model should apply the anchors emitted by this package.
|
|
30
|
+
|
|
31
|
+
When `@agimon-ai/doompi-ui` is installed directly in standalone Pi, list
|
|
32
|
+
`@agimon-ai/doompi-grep` first so its `grep` registration owns the shared tool name. DoomPi's
|
|
33
|
+
composed runtime loads selectable packages after the UI package, so the hashline tool owns `grep`
|
|
34
|
+
there.
|
|
35
|
+
|
|
36
|
+
## Tool protocol
|
|
37
|
+
|
|
38
|
+
Writable search results group matching and context lines beneath an exact-byte
|
|
39
|
+
file header:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
@file src/example.ts#A1b2C3d4
|
|
43
|
+
4#def|const previous = true;
|
|
44
|
+
>> 5#abc|const match = true;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The eight-character file tag and three-letter line anchors are model-facing protocol data. DoomPi's
|
|
48
|
+
human renderer hides the protocol tags and anchors while retaining file paths, line numbers, match
|
|
49
|
+
markers, and syntax highlighting.
|
|
50
|
+
|
|
51
|
+
## Attribution
|
|
52
|
+
|
|
53
|
+
The hashline protocol and FNV anchor approach are adapted from
|
|
54
|
+
[Phi's writetool](https://github.com/pulseaiclub/phi/tree/main/internal/tools/writetool), licensed
|
|
55
|
+
under MIT by pulseaiclub. DoomPi uses an exact-byte SHA-256 file tag as an intentional compatibility
|
|
56
|
+
boundary.
|
|
57
|
+
|
|
58
|
+
## Public API
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { GrepParamsSchema, registerHashlineGrepTool } from '@agimon-ai/doompi-grep';
|
|
62
|
+
import type { GrepParams } from '@agimon-ai/doompi-grep';
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pnpm build
|
|
69
|
+
pnpm typecheck
|
|
70
|
+
pnpm test
|
|
71
|
+
pnpm lint
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Maintained by [Agimon](https://agimon.ai/about).
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./grepTool.cjs");let t=require("@agimon-ai/doompi-extension-contracts/cordis-host"),n=require("@agimon-ai/doompi-extension-contracts/tool-overrides");const r=`@agimon-ai/doompi-grep`;function i(t,i){t.inject([n.DOOM_TOOL_OVERRIDES_SERVICE],t=>{let a=(0,n.requireDoomToolOverrides)(t).claim({source:r,tools:[`grep`]});if(a.granted){try{e.registerHashlineGrepTool(i)}catch(e){throw a.dispose(),e}return()=>a.dispose()}})}async function a(e){let n=await(0,t.connectDoomCordisHost)(e,r),i=n.root.plugin(o,{pi:e});try{await i}catch(e){try{await i.dispose()}finally{await n.dispose()}throw e}let a;e.on(`session_shutdown`,()=>a??=(async()=>{try{await i.dispose()}finally{await n.dispose()}})())}function o(e,t){i(e,t.pi)}exports.activateDoomPiGrepExtension=a,exports.default=a,exports.installDoomPiGrepRuntime=i;
|
|
2
|
+
//# sourceMappingURL=extension.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["DOOM_TOOL_OVERRIDES_SERVICE","requireDoomToolOverrides","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_TOOL_OVERRIDES_SERVICE,\n requireDoomToolOverrides,\n} from '@agimon-ai/doompi-extension-contracts/tool-overrides';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerHashlineGrepTool } from './grepTool.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-grep';\n\n/** Install the hashline grep replacement after claiming its Pi tool name. */\nexport function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.inject([DOOM_TOOL_OVERRIDES_SERVICE], (overridesContext) => {\n const registration = requireDoomToolOverrides(overridesContext).claim({\n source: PACKAGE_SOURCE,\n tools: ['grep'],\n });\n if (!registration.granted) return;\n try {\n registerHashlineGrepTool(pi);\n } catch (error) {\n registration.dispose();\n throw error;\n }\n return () => registration.dispose();\n });\n}\n\n/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */\nexport async function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiGrepPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface DoomPiGrepPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction doomPiGrepPlugin(cordis: Context, config: DoomPiGrepPluginConfig): void {\n installDoomPiGrepRuntime(cordis, config.pi);\n}\n\nexport default activateDoomPiGrepExtension;\n"],"mappings":"uKASA,MAAM,EAAiB,yBAGvB,SAAgB,EAAyB,EAAiB,EAAwB,CAChF,EAAO,OAAO,CAACA,EAAAA,2BAA2B,EAAI,GAAqB,CACjE,IAAM,GAAA,EAAeC,EAAAA,yBAAAA,CAAyB,CAAgB,CAAC,CAAC,MAAM,CACpE,OAAQ,EACR,MAAO,CAAC,MAAM,CAChB,CAAC,EACI,KAAa,QAClB,IAAI,CACF,EAAA,yBAAyB,CAAE,CAC7B,OAAS,EAAO,CAEd,MADA,EAAa,QAAQ,EACf,CACR,CACA,UAAa,EAAa,QAAQ,CADlC,CAEF,CAAC,CACH,CAGA,eAAsB,EAA4B,EAAiC,CACjF,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAkB,CAAE,IAAG,CAAC,EAC7D,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAiB,EAAiB,EAAsC,CAC/E,EAAyB,EAAQ,EAAO,EAAE,CAC5C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/** Install the hashline grep replacement after claiming its Pi tool name. */
|
|
5
|
+
declare function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void;
|
|
6
|
+
/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
|
|
7
|
+
declare function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { activateDoomPiGrepExtension, activateDoomPiGrepExtension as default, installDoomPiGrepRuntime };
|
|
10
|
+
//# sourceMappingURL=extension.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;iBAkBxC,4BAA4B,IAAI,eAAe"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/** Install the hashline grep replacement after claiming its Pi tool name. */
|
|
5
|
+
declare function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void;
|
|
6
|
+
/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
|
|
7
|
+
declare function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { activateDoomPiGrepExtension, activateDoomPiGrepExtension as default, installDoomPiGrepRuntime };
|
|
10
|
+
//# sourceMappingURL=extension.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;iBAkBxC,4BAA4B,IAAI,eAAe"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{registerHashlineGrepTool as e}from"./grepTool.mjs";import{connectDoomCordisHost as t}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_TOOL_OVERRIDES_SERVICE as n,requireDoomToolOverrides as r}from"@agimon-ai/doompi-extension-contracts/tool-overrides";const i=`@agimon-ai/doompi-grep`;function a(t,a){t.inject([n],t=>{let n=r(t).claim({source:i,tools:[`grep`]});if(n.granted){try{e(a)}catch(e){throw n.dispose(),e}return()=>n.dispose()}})}async function o(e){let n=await t(e,i),r=n.root.plugin(s,{pi:e});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let a;e.on(`session_shutdown`,()=>a??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}function s(e,t){a(e,t.pi)}export{o as activateDoomPiGrepExtension,o as default,a as installDoomPiGrepRuntime};
|
|
2
|
+
//# sourceMappingURL=extension.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_TOOL_OVERRIDES_SERVICE,\n requireDoomToolOverrides,\n} from '@agimon-ai/doompi-extension-contracts/tool-overrides';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerHashlineGrepTool } from './grepTool.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-grep';\n\n/** Install the hashline grep replacement after claiming its Pi tool name. */\nexport function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.inject([DOOM_TOOL_OVERRIDES_SERVICE], (overridesContext) => {\n const registration = requireDoomToolOverrides(overridesContext).claim({\n source: PACKAGE_SOURCE,\n tools: ['grep'],\n });\n if (!registration.granted) return;\n try {\n registerHashlineGrepTool(pi);\n } catch (error) {\n registration.dispose();\n throw error;\n }\n return () => registration.dispose();\n });\n}\n\n/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */\nexport async function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiGrepPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface DoomPiGrepPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction doomPiGrepPlugin(cordis: Context, config: DoomPiGrepPluginConfig): void {\n installDoomPiGrepRuntime(cordis, config.pi);\n}\n\nexport default activateDoomPiGrepExtension;\n"],"mappings":"qRASA,MAAM,EAAiB,yBAGvB,SAAgB,EAAyB,EAAiB,EAAwB,CAChF,EAAO,OAAO,CAAC,CAA2B,EAAI,GAAqB,CACjE,IAAM,EAAe,EAAyB,CAAgB,CAAC,CAAC,MAAM,CACpE,OAAQ,EACR,MAAO,CAAC,MAAM,CAChB,CAAC,EACI,KAAa,QAClB,IAAI,CACF,EAAyB,CAAE,CAC7B,OAAS,EAAO,CAEd,MADA,EAAa,QAAQ,EACf,CACR,CACA,UAAa,EAAa,QAAQ,CADlC,CAEF,CAAC,CACH,CAGA,eAAsB,EAA4B,EAAiC,CACjF,IAAM,EAAa,MAAM,EAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAkB,CAAE,IAAG,CAAC,EAC7D,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAiB,EAAiB,EAAsC,CAC/E,EAAyB,EAAQ,EAAO,EAAE,CAC5C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const e=require("../../schemas/grepTool.cjs");let t=require("node:fs/promises"),n=require("node:path"),r=require("@agimon-ai/doompi-hashline/files"),i=require("@agimon-ai/doompi-hashline"),a=require("@agimon-ai/doompi-ui/hashlineRendering"),o=require("@earendil-works/pi-coding-agent");const s=/:(\d+): /gu,c=/-(\d+)- /gu;function l(t,n=r.isWritableFile){t.registerTool({name:`grep`,label:`grep`,description:`Search file contents using Pi-compatible ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Non-writable matches retain native Pi output. Respects .gitignore.`,promptSnippet:`Search file contents and return editable hashline anchors`,parameters:e.GrepParamsSchema,executionMode:`parallel`,renderShell:`self`,async execute(e,t,r,i,a){let s=t,c=await(0,o.createGrepToolDefinition)(a.cwd).execute(e,s,r,i,a);return m(r),u(c,s,a.cwd,r,n)},renderCall(e,t){let n=e,r=[n.path??`.`,n.glob,n.ignoreCase===!0?`ignore case`:void 0,n.limit===void 0?void 0:`${n.limit} matches`].filter(e=>e!==void 0);return(0,a.renderHashlineCall)(`grep`,n.pattern,r,t)},renderResult(e,t,n,r){return(0,a.renderHashlineResult)(e,t,n,r,`grep`)}})}async function u(e,n,a,s,c=r.isWritableFile){let l=e.content.find(e=>e.type===`text`);if(!l||l.text===`No matches found`)return e;let u=l.text.lastIndexOf(`
|
|
2
|
+
|
|
3
|
+
[`),f=u===-1?l.text:l.text.slice(0,u),h=u===-1?``:l.text.slice(u),g=(0,r.resolveInputPath)(n.path??`.`,a),_=await(0,t.stat)(g);m(s);let v=await d(f,g,_.isDirectory(),s);if(v.length===0)return e;let y=p(v,g,_.isDirectory(),a),b=[],x=0,S=e.details?.linesTruncated??!1;for(let e of y.values()){m(s);let n=await c(e.absolutePath);if(m(s),!n){b.push(e.nativeRows.join(`
|
|
4
|
+
`));continue}let a;try{a=await(0,t.readFile)(e.absolutePath)}catch{b.push(e.nativeRows.join(`
|
|
5
|
+
`));continue}m(s);let l=(0,i.splitLines)((0,r.decodeUtf8)(a,e.path)),u=[(0,i.formatFileHeader)(e.path,(0,r.computeFileTag)(a))];for(let[t,n]of[...e.rows].sort(([e],[t])=>e-t)){let e=l[t-1];if(e===void 0)continue;let r=(0,o.truncateLine)(e);r.wasTruncated&&(S=!0),u.push((0,i.formatTaggedLine)(r.text,t,n?`>> `:` `,e))}u.length>1?(b.push(u.join(`
|
|
6
|
+
`)),x++):b.push(e.nativeRows.join(`
|
|
7
|
+
`))}if(b.length===0||x===0)return e;let C=(0,o.truncateHead)(b.join(`
|
|
8
|
+
`),{maxLines:2**53-1}),w=C.truncated?`\n\n[${(0,o.formatSize)(o.DEFAULT_MAX_BYTES)} tagged output limit reached]`:``,T={...e.details,...C.truncated?{truncation:C}:{},...S?{linesTruncated:!0}:{}};return m(s),{...e,content:[{type:`text`,text:`${C.content}${h}${w}`}],details:Object.keys(T).length>0?T:void 0}}async function d(e,r,i,a){let o=new Map,s=[];for(let c of e.split(`
|
|
9
|
+
`)){m(a);let e;for(let l of f(c)){if(!i){if(l.path===(0,n.basename)(r)){s.push({...l,native:c});break}continue}let u=(0,n.resolve)(r,l.path),d=o.get(u);d===void 0&&(d=await(0,t.stat)(u).then(e=>e.isFile()).catch(()=>!1),m(a),o.set(u,d)),d&&(e={...l,native:c})}e&&s.push(e)}return s}function f(e){let t=[];for(let n of e.matchAll(s))t.push({index:n.index,row:{path:e.slice(0,n.index),line:Number.parseInt(n[1]??``,10),match:!0}});for(let n of e.matchAll(c))t.push({index:n.index,row:{path:e.slice(0,n.index),line:Number.parseInt(n[1]??``,10),match:!1}});return t.sort((e,t)=>e.index-t.index).map(({row:e})=>e)}function p(e,t,i,a){let o=new Map;for(let s of e){let e=i?(0,n.resolve)(t,s.path):t,c=o.get(e);c||(c={path:(0,r.displayPath)(e,a),absolutePath:e,nativeRows:[],rows:new Map},o.set(e,c)),s.native!==void 0&&c.nativeRows.push(s.native),c.rows.set(s.line,s.match||c.rows.get(s.line)===!0)}return o}function m(e){if(e?.aborted)throw Error(`Operation aborted`)}exports.groupGrepRows=p,exports.registerHashlineGrepTool=l,exports.tagGrepResult=u;
|
|
10
|
+
//# sourceMappingURL=grepTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.cjs","names":["isWritableFile","GrepParamsSchema","createGrepToolDefinition","renderHashlineCall","renderHashlineResult","resolveInputPath","stat","readFile","splitLines","decodeUtf8","formatFileHeader","computeFileTag","truncateLine","formatTaggedLine","truncateHead","formatSize","DEFAULT_MAX_BYTES","basename","resolve","displayPath"],"sources":["../../../src/adapters/pi/grepTool.ts"],"sourcesContent":["import { readFile, stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport {\n displayPath,\n computeFileTag,\n decodeUtf8,\n isWritableFile,\n resolveInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n createGrepToolDefinition,\n DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n type ExtensionAPI,\n type GrepToolDetails,\n} from '@earendil-works/pi-coding-agent';\nimport { GrepParamsSchema, type GrepParams } from '../../schemas/grepTool.ts';\n\nconst MATCH_DELIMITER = /:(\\d+): /gu;\nconst CONTEXT_DELIMITER = /-(\\d+)- /gu;\nconst NO_MATCHES = 'No matches found';\n\ninterface GrepRow {\n readonly path: string;\n readonly line: number;\n readonly match: boolean;\n readonly native?: string;\n}\n\ninterface GrepGroup {\n readonly path: string;\n readonly absolutePath: string;\n readonly nativeRows: string[];\n readonly rows: Map<number, boolean>;\n}\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\n/** Register only the snapshot-bound replacement for Pi's grep tool. */\nexport function registerHashlineGrepTool(\n pi: Pick<ExtensionAPI, 'registerTool'>,\n writable: WritableCheck = isWritableFile,\n): void {\n pi.registerTool({\n name: 'grep',\n label: 'grep',\n description:\n 'Search file contents using Pi-compatible ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Non-writable matches retain native Pi output. Respects .gitignore.',\n promptSnippet: 'Search file contents and return editable hashline anchors',\n parameters: GrepParamsSchema,\n executionMode: 'parallel',\n renderShell: 'self',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as GrepParams;\n const nativeGrep = createGrepToolDefinition(ctx.cwd);\n const nativeResult = await nativeGrep.execute(toolCallId, input, signal, onUpdate, ctx);\n assertNotAborted(signal);\n return tagGrepResult(nativeResult, input, ctx.cwd, signal, writable);\n },\n renderCall(args, theme) {\n const input = args as GrepParams;\n const details = [\n input.path ?? '.',\n input.glob,\n input.ignoreCase === true ? 'ignore case' : undefined,\n input.limit === undefined ? undefined : `${input.limit} matches`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('grep', input.pattern, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'grep');\n },\n });\n}\n\nexport async function tagGrepResult(\n nativeResult: Awaited<ReturnType<ReturnType<typeof createGrepToolDefinition>['execute']>>,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: WritableCheck = isWritableFile,\n): Promise<typeof nativeResult> {\n const textPart = nativeResult.content.find((part) => part.type === 'text');\n if (!textPart || textPart.text === NO_MATCHES) return nativeResult;\n\n const noticeIndex = textPart.text.lastIndexOf('\\n\\n[');\n const rowsText = noticeIndex === -1 ? textPart.text : textPart.text.slice(0, noticeIndex);\n const notice = noticeIndex === -1 ? '' : textPart.text.slice(noticeIndex);\n const searchPath = resolveInputPath(params.path ?? '.', cwd);\n const searchStats = await stat(searchPath);\n assertNotAborted(signal);\n const rows = await parseValidatedGrepRows(rowsText, searchPath, searchStats.isDirectory(), signal);\n if (rows.length === 0) return nativeResult;\n\n const groups = groupGrepRows(rows, searchPath, searchStats.isDirectory(), cwd);\n const blocks: string[] = [];\n let taggedFiles = 0;\n let linesTruncated = nativeResult.details?.linesTruncated ?? false;\n\n for (const group of groups.values()) {\n assertNotAborted(signal);\n const canEdit = await writable(group.absolutePath);\n assertNotAborted(signal);\n if (!canEdit) {\n blocks.push(group.nativeRows.join('\\n'));\n continue;\n }\n let bytes: Buffer;\n try {\n bytes = await readFile(group.absolutePath);\n } catch {\n blocks.push(group.nativeRows.join('\\n'));\n continue;\n }\n assertNotAborted(signal);\n const lines = splitLines(decodeUtf8(bytes, group.path));\n const output = [formatFileHeader(group.path, computeFileTag(bytes))];\n for (const [lineNumber, isMatch] of [...group.rows].sort(([left], [right]) => left - right)) {\n const line = lines[lineNumber - 1];\n if (line === undefined) continue;\n const compact = truncateLine(line);\n if (compact.wasTruncated) linesTruncated = true;\n output.push(formatTaggedLine(compact.text, lineNumber, isMatch ? '>> ' : ' ', line));\n }\n if (output.length > 1) {\n blocks.push(output.join('\\n'));\n taggedFiles++;\n } else {\n blocks.push(group.nativeRows.join('\\n'));\n }\n }\n\n if (blocks.length === 0 || taggedFiles === 0) return nativeResult;\n const truncation = truncateHead(blocks.join('\\n'), { maxLines: Number.MAX_SAFE_INTEGER });\n const extraNotice = truncation.truncated ? `\\n\\n[${formatSize(DEFAULT_MAX_BYTES)} tagged output limit reached]` : '';\n const details: GrepToolDetails = {\n ...nativeResult.details,\n ...(truncation.truncated ? { truncation } : {}),\n ...(linesTruncated ? { linesTruncated: true } : {}),\n };\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: [{ type: 'text', text: `${truncation.content}${notice}${extraNotice}` }],\n details: Object.keys(details).length > 0 ? details : undefined,\n };\n}\n\nexport function parseGrepRow(value: string): GrepRow[] {\n return grepRowCandidates(value)\n .slice(0, 1)\n .map(({ line, match, path }) => ({ line, match, path }));\n}\n\nasync function parseValidatedGrepRows(\n rowsText: string,\n searchPath: string,\n directory: boolean,\n signal: AbortSignal | undefined,\n): Promise<GrepRow[]> {\n const pathCache = new Map<string, boolean>();\n const rows: GrepRow[] = [];\n for (const value of rowsText.split('\\n')) {\n assertNotAborted(signal);\n let resolvedCandidate: GrepRow | undefined;\n for (const candidate of grepRowCandidates(value)) {\n if (!directory) {\n if (candidate.path === basename(searchPath)) {\n rows.push({ ...candidate, native: value });\n break;\n }\n continue;\n }\n const absolutePath = resolve(searchPath, candidate.path);\n let exists = pathCache.get(absolutePath);\n if (exists === undefined) {\n exists = await stat(absolutePath)\n .then((value) => value.isFile())\n .catch(() => false);\n assertNotAborted(signal);\n pathCache.set(absolutePath, exists);\n }\n if (exists) {\n // A delimiter can be part of a valid POSIX filename. Keep the longest\n // existing prefix so `foo:42: bar.txt` does not resolve to sibling `foo`.\n resolvedCandidate = { ...candidate, native: value };\n }\n }\n if (resolvedCandidate) rows.push(resolvedCandidate);\n }\n return rows;\n}\n\nfunction grepRowCandidates(value: string): GrepRow[] {\n const candidates: Array<{ readonly index: number; readonly row: GrepRow }> = [];\n for (const match of value.matchAll(MATCH_DELIMITER)) {\n candidates.push({\n index: match.index,\n row: { path: value.slice(0, match.index), line: Number.parseInt(match[1] ?? '', 10), match: true },\n });\n }\n for (const match of value.matchAll(CONTEXT_DELIMITER)) {\n candidates.push({\n index: match.index,\n row: { path: value.slice(0, match.index), line: Number.parseInt(match[1] ?? '', 10), match: false },\n });\n }\n return candidates.sort((left, right) => left.index - right.index).map(({ row }) => row);\n}\n\nexport function groupGrepRows(\n rows: readonly GrepRow[],\n searchPath: string,\n directory: boolean,\n cwd: string,\n): Map<string, GrepGroup> {\n const groups = new Map<string, GrepGroup>();\n for (const row of rows) {\n const absolutePath = directory ? resolve(searchPath, row.path) : searchPath;\n let group = groups.get(absolutePath);\n if (!group) {\n group = { path: displayPath(absolutePath, cwd), absolutePath, nativeRows: [], rows: new Map() };\n groups.set(absolutePath, group);\n }\n if (row.native !== undefined) group.nativeRows.push(row.native);\n group.rows.set(row.line, row.match || group.rows.get(row.line) === true);\n }\n return groups;\n}\n\nfunction assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "../../schemas/grepTool.cjs";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/grepTool.d.ts
|
|
4
|
+
type WritableCheck = (path: string) => Promise<boolean>;
|
|
5
|
+
/** Register only the snapshot-bound replacement for Pi's grep tool. */
|
|
6
|
+
declare function registerHashlineGrepTool(pi: Pick<ExtensionAPI, 'registerTool'>, writable?: WritableCheck): void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { registerHashlineGrepTool };
|
|
9
|
+
//# sourceMappingURL=grepTool.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.d.cts","names":[],"sources":["../../../src/adapters/pi/grepTool.ts"],"mappings":";;;KAwCK,iBAAiB,iBAAiB;;iBAGvB,yBACd,IAAI,KAAK,+BACT,WAAU"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "../../schemas/grepTool.mjs";
|
|
2
|
+
import { ExtensionAPI, createGrepToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/grepTool.d.ts
|
|
4
|
+
type WritableCheck = (path: string) => Promise<boolean>;
|
|
5
|
+
/** Register only the snapshot-bound replacement for Pi's grep tool. */
|
|
6
|
+
declare function registerHashlineGrepTool(pi: Pick<ExtensionAPI, 'registerTool'>, writable?: WritableCheck): void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { registerHashlineGrepTool };
|
|
9
|
+
//# sourceMappingURL=grepTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.d.mts","names":[],"sources":["../../../src/adapters/pi/grepTool.ts"],"mappings":";;;KAwCK,iBAAiB,iBAAiB;;iBAGvB,yBACd,IAAI,KAAK,+BACT,WAAU"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{GrepParamsSchema as e}from"../../schemas/grepTool.mjs";import{readFile as t,stat as n}from"node:fs/promises";import{basename as r,resolve as i}from"node:path";import{computeFileTag as a,decodeUtf8 as o,displayPath as s,isWritableFile as c,resolveInputPath as l}from"@agimon-ai/doompi-hashline/files";import{formatFileHeader as u,formatTaggedLine as d,splitLines as f}from"@agimon-ai/doompi-hashline";import{renderHashlineCall as p,renderHashlineResult as m}from"@agimon-ai/doompi-ui/hashlineRendering";import{DEFAULT_MAX_BYTES as h,createGrepToolDefinition as g,formatSize as _,truncateHead as v,truncateLine as y}from"@earendil-works/pi-coding-agent";const b=/:(\d+): /gu,x=/-(\d+)- /gu;function S(t,n=c){t.registerTool({name:`grep`,label:`grep`,description:`Search file contents using Pi-compatible ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Non-writable matches retain native Pi output. Respects .gitignore.`,promptSnippet:`Search file contents and return editable hashline anchors`,parameters:e,executionMode:`parallel`,renderShell:`self`,async execute(e,t,r,i,a){let o=t,s=await g(a.cwd).execute(e,o,r,i,a);return D(r),C(s,o,a.cwd,r,n)},renderCall(e,t){let n=e,r=[n.path??`.`,n.glob,n.ignoreCase===!0?`ignore case`:void 0,n.limit===void 0?void 0:`${n.limit} matches`].filter(e=>e!==void 0);return p(`grep`,n.pattern,r,t)},renderResult(e,t,n,r){return m(e,t,n,r,`grep`)}})}async function C(e,r,i,s,p=c){let m=e.content.find(e=>e.type===`text`);if(!m||m.text===`No matches found`)return e;let g=m.text.lastIndexOf(`
|
|
2
|
+
|
|
3
|
+
[`),b=g===-1?m.text:m.text.slice(0,g),x=g===-1?``:m.text.slice(g),S=l(r.path??`.`,i),C=await n(S);D(s);let T=await w(b,S,C.isDirectory(),s);if(T.length===0)return e;let O=E(T,S,C.isDirectory(),i),k=[],A=0,j=e.details?.linesTruncated??!1;for(let e of O.values()){D(s);let n=await p(e.absolutePath);if(D(s),!n){k.push(e.nativeRows.join(`
|
|
4
|
+
`));continue}let r;try{r=await t(e.absolutePath)}catch{k.push(e.nativeRows.join(`
|
|
5
|
+
`));continue}D(s);let i=f(o(r,e.path)),c=[u(e.path,a(r))];for(let[t,n]of[...e.rows].sort(([e],[t])=>e-t)){let e=i[t-1];if(e===void 0)continue;let r=y(e);r.wasTruncated&&(j=!0),c.push(d(r.text,t,n?`>> `:` `,e))}c.length>1?(k.push(c.join(`
|
|
6
|
+
`)),A++):k.push(e.nativeRows.join(`
|
|
7
|
+
`))}if(k.length===0||A===0)return e;let M=v(k.join(`
|
|
8
|
+
`),{maxLines:2**53-1}),N=M.truncated?`\n\n[${_(h)} tagged output limit reached]`:``,P={...e.details,...M.truncated?{truncation:M}:{},...j?{linesTruncated:!0}:{}};return D(s),{...e,content:[{type:`text`,text:`${M.content}${x}${N}`}],details:Object.keys(P).length>0?P:void 0}}async function w(e,t,a,o){let s=new Map,c=[];for(let l of e.split(`
|
|
9
|
+
`)){D(o);let e;for(let u of T(l)){if(!a){if(u.path===r(t)){c.push({...u,native:l});break}continue}let d=i(t,u.path),f=s.get(d);f===void 0&&(f=await n(d).then(e=>e.isFile()).catch(()=>!1),D(o),s.set(d,f)),f&&(e={...u,native:l})}e&&c.push(e)}return c}function T(e){let t=[];for(let n of e.matchAll(b))t.push({index:n.index,row:{path:e.slice(0,n.index),line:Number.parseInt(n[1]??``,10),match:!0}});for(let n of e.matchAll(x))t.push({index:n.index,row:{path:e.slice(0,n.index),line:Number.parseInt(n[1]??``,10),match:!1}});return t.sort((e,t)=>e.index-t.index).map(({row:e})=>e)}function E(e,t,n,r){let a=new Map;for(let o of e){let e=n?i(t,o.path):t,c=a.get(e);c||(c={path:s(e,r),absolutePath:e,nativeRows:[],rows:new Map},a.set(e,c)),o.native!==void 0&&c.nativeRows.push(o.native),c.rows.set(o.line,o.match||c.rows.get(o.line)===!0)}return a}function D(e){if(e?.aborted)throw Error(`Operation aborted`)}export{E as groupGrepRows,S as registerHashlineGrepTool,C as tagGrepResult};
|
|
10
|
+
//# sourceMappingURL=grepTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.mjs","names":[],"sources":["../../../src/adapters/pi/grepTool.ts"],"sourcesContent":["import { readFile, stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport {\n displayPath,\n computeFileTag,\n decodeUtf8,\n isWritableFile,\n resolveInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n createGrepToolDefinition,\n DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n type ExtensionAPI,\n type GrepToolDetails,\n} from '@earendil-works/pi-coding-agent';\nimport { GrepParamsSchema, type GrepParams } from '../../schemas/grepTool.ts';\n\nconst MATCH_DELIMITER = /:(\\d+): /gu;\nconst CONTEXT_DELIMITER = /-(\\d+)- /gu;\nconst NO_MATCHES = 'No matches found';\n\ninterface GrepRow {\n readonly path: string;\n readonly line: number;\n readonly match: boolean;\n readonly native?: string;\n}\n\ninterface GrepGroup {\n readonly path: string;\n readonly absolutePath: string;\n readonly nativeRows: string[];\n readonly rows: Map<number, boolean>;\n}\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\n/** Register only the snapshot-bound replacement for Pi's grep tool. */\nexport function registerHashlineGrepTool(\n pi: Pick<ExtensionAPI, 'registerTool'>,\n writable: WritableCheck = isWritableFile,\n): void {\n pi.registerTool({\n name: 'grep',\n label: 'grep',\n description:\n 'Search file contents using Pi-compatible ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Non-writable matches retain native Pi output. Respects .gitignore.',\n promptSnippet: 'Search file contents and return editable hashline anchors',\n parameters: GrepParamsSchema,\n executionMode: 'parallel',\n renderShell: 'self',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as GrepParams;\n const nativeGrep = createGrepToolDefinition(ctx.cwd);\n const nativeResult = await nativeGrep.execute(toolCallId, input, signal, onUpdate, ctx);\n assertNotAborted(signal);\n return tagGrepResult(nativeResult, input, ctx.cwd, signal, writable);\n },\n renderCall(args, theme) {\n const input = args as GrepParams;\n const details = [\n input.path ?? '.',\n input.glob,\n input.ignoreCase === true ? 'ignore case' : undefined,\n input.limit === undefined ? undefined : `${input.limit} matches`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('grep', input.pattern, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'grep');\n },\n });\n}\n\nexport async function tagGrepResult(\n nativeResult: Awaited<ReturnType<ReturnType<typeof createGrepToolDefinition>['execute']>>,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: WritableCheck = isWritableFile,\n): Promise<typeof nativeResult> {\n const textPart = nativeResult.content.find((part) => part.type === 'text');\n if (!textPart || textPart.text === NO_MATCHES) return nativeResult;\n\n const noticeIndex = textPart.text.lastIndexOf('\\n\\n[');\n const rowsText = noticeIndex === -1 ? textPart.text : textPart.text.slice(0, noticeIndex);\n const notice = noticeIndex === -1 ? '' : textPart.text.slice(noticeIndex);\n const searchPath = resolveInputPath(params.path ?? '.', cwd);\n const searchStats = await stat(searchPath);\n assertNotAborted(signal);\n const rows = await parseValidatedGrepRows(rowsText, searchPath, searchStats.isDirectory(), signal);\n if (rows.length === 0) return nativeResult;\n\n const groups = groupGrepRows(rows, searchPath, searchStats.isDirectory(), cwd);\n const blocks: string[] = [];\n let taggedFiles = 0;\n let linesTruncated = nativeResult.details?.linesTruncated ?? false;\n\n for (const group of groups.values()) {\n assertNotAborted(signal);\n const canEdit = await writable(group.absolutePath);\n assertNotAborted(signal);\n if (!canEdit) {\n blocks.push(group.nativeRows.join('\\n'));\n continue;\n }\n let bytes: Buffer;\n try {\n bytes = await readFile(group.absolutePath);\n } catch {\n blocks.push(group.nativeRows.join('\\n'));\n continue;\n }\n assertNotAborted(signal);\n const lines = splitLines(decodeUtf8(bytes, group.path));\n const output = [formatFileHeader(group.path, computeFileTag(bytes))];\n for (const [lineNumber, isMatch] of [...group.rows].sort(([left], [right]) => left - right)) {\n const line = lines[lineNumber - 1];\n if (line === undefined) continue;\n const compact = truncateLine(line);\n if (compact.wasTruncated) linesTruncated = true;\n output.push(formatTaggedLine(compact.text, lineNumber, isMatch ? '>> ' : ' ', line));\n }\n if (output.length > 1) {\n blocks.push(output.join('\\n'));\n taggedFiles++;\n } else {\n blocks.push(group.nativeRows.join('\\n'));\n }\n }\n\n if (blocks.length === 0 || taggedFiles === 0) return nativeResult;\n const truncation = truncateHead(blocks.join('\\n'), { maxLines: Number.MAX_SAFE_INTEGER });\n const extraNotice = truncation.truncated ? `\\n\\n[${formatSize(DEFAULT_MAX_BYTES)} tagged output limit reached]` : '';\n const details: GrepToolDetails = {\n ...nativeResult.details,\n ...(truncation.truncated ? { truncation } : {}),\n ...(linesTruncated ? { linesTruncated: true } : {}),\n };\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: [{ type: 'text', text: `${truncation.content}${notice}${extraNotice}` }],\n details: Object.keys(details).length > 0 ? details : undefined,\n };\n}\n\nexport function parseGrepRow(value: string): GrepRow[] {\n return grepRowCandidates(value)\n .slice(0, 1)\n .map(({ line, match, path }) => ({ line, match, path }));\n}\n\nasync function parseValidatedGrepRows(\n rowsText: string,\n searchPath: string,\n directory: boolean,\n signal: AbortSignal | undefined,\n): Promise<GrepRow[]> {\n const pathCache = new Map<string, boolean>();\n const rows: GrepRow[] = [];\n for (const value of rowsText.split('\\n')) {\n assertNotAborted(signal);\n let resolvedCandidate: GrepRow | undefined;\n for (const candidate of grepRowCandidates(value)) {\n if (!directory) {\n if (candidate.path === basename(searchPath)) {\n rows.push({ ...candidate, native: value });\n break;\n }\n continue;\n }\n const absolutePath = resolve(searchPath, candidate.path);\n let exists = pathCache.get(absolutePath);\n if (exists === undefined) {\n exists = await stat(absolutePath)\n .then((value) => value.isFile())\n .catch(() => false);\n assertNotAborted(signal);\n pathCache.set(absolutePath, exists);\n }\n if (exists) {\n // A delimiter can be part of a valid POSIX filename. Keep the longest\n // existing prefix so `foo:42: bar.txt` does not resolve to sibling `foo`.\n resolvedCandidate = { ...candidate, native: value };\n }\n }\n if (resolvedCandidate) rows.push(resolvedCandidate);\n }\n return rows;\n}\n\nfunction grepRowCandidates(value: string): GrepRow[] {\n const candidates: Array<{ readonly index: number; readonly row: GrepRow }> = [];\n for (const match of value.matchAll(MATCH_DELIMITER)) {\n candidates.push({\n index: match.index,\n row: { path: value.slice(0, match.index), line: Number.parseInt(match[1] ?? '', 10), match: true },\n });\n }\n for (const match of value.matchAll(CONTEXT_DELIMITER)) {\n candidates.push({\n index: match.index,\n row: { path: value.slice(0, match.index), line: Number.parseInt(match[1] ?? '', 10), match: false },\n });\n }\n return candidates.sort((left, right) => left.index - right.index).map(({ row }) => row);\n}\n\nexport function groupGrepRows(\n rows: readonly GrepRow[],\n searchPath: string,\n directory: boolean,\n cwd: string,\n): Map<string, GrepGroup> {\n const groups = new Map<string, GrepGroup>();\n for (const row of rows) {\n const absolutePath = directory ? resolve(searchPath, row.path) : searchPath;\n let group = groups.get(absolutePath);\n if (!group) {\n group = { path: displayPath(absolutePath, cwd), absolutePath, nativeRows: [], rows: new Map() };\n groups.set(absolutePath, group);\n }\n if (row.native !== undefined) group.nativeRows.push(row.native);\n group.rows.set(row.line, row.match || group.rows.get(row.line) === true);\n }\n return groups;\n}\n\nfunction assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../adapters/pi/extension.cjs");module.exports=e.activateDoomPiGrepExtension;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{activateDoomPiGrepExtension as e}from"../adapters/pi/extension.mjs";export{e as default};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./schemas/grepTool.cjs"),t=require("./adapters/pi/grepTool.cjs"),n=require("./adapters/pi/extension.cjs");exports.GrepParamsSchema=e.GrepParamsSchema,exports.activateDoomPiGrepExtension=n.activateDoomPiGrepExtension,exports.installDoomPiGrepRuntime=n.installDoomPiGrepRuntime,exports.registerHashlineGrepTool=t.registerHashlineGrepTool;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { activateDoomPiGrepExtension, installDoomPiGrepRuntime } from "./adapters/pi/extension.cjs";
|
|
2
|
+
import { GrepParams, GrepParamsSchema } from "./schemas/grepTool.cjs";
|
|
3
|
+
import { registerHashlineGrepTool } from "./adapters/pi/grepTool.cjs";
|
|
4
|
+
export { type GrepParams, GrepParamsSchema, activateDoomPiGrepExtension, installDoomPiGrepRuntime, registerHashlineGrepTool };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { activateDoomPiGrepExtension, installDoomPiGrepRuntime } from "./adapters/pi/extension.mjs";
|
|
2
|
+
import { GrepParams, GrepParamsSchema } from "./schemas/grepTool.mjs";
|
|
3
|
+
import { registerHashlineGrepTool } from "./adapters/pi/grepTool.mjs";
|
|
4
|
+
export { type GrepParams, GrepParamsSchema, activateDoomPiGrepExtension, installDoomPiGrepRuntime, registerHashlineGrepTool };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{GrepParamsSchema as e}from"./schemas/grepTool.mjs";import{registerHashlineGrepTool as t}from"./adapters/pi/grepTool.mjs";import{activateDoomPiGrepExtension as n,installDoomPiGrepRuntime as r}from"./adapters/pi/extension.mjs";export{e as GrepParamsSchema,n as activateDoomPiGrepExtension,r as installDoomPiGrepRuntime,t as registerHashlineGrepTool};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("typebox");const t=e.Type.Object({pattern:e.Type.String({description:`Regular expression or literal text to find.`}),path:e.Type.Optional(e.Type.String({description:`File or directory to search. Defaults to the working directory.`})),glob:e.Type.Optional(e.Type.String({description:`Glob filter for files to search.`})),ignoreCase:e.Type.Optional(e.Type.Boolean({description:`Match without case sensitivity.`})),literal:e.Type.Optional(e.Type.Boolean({description:`Treat pattern as literal text.`})),context:e.Type.Optional(e.Type.Integer({minimum:0,description:`Context lines around every match.`})),limit:e.Type.Optional(e.Type.Integer({minimum:1,description:`Maximum number of matches.`}))});exports.GrepParamsSchema=t;
|
|
2
|
+
//# sourceMappingURL=grepTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.cjs","names":["Type"],"sources":["../../src/schemas/grepTool.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const GrepParamsSchema = Type.Object({\n pattern: Type.String({ description: 'Regular expression or literal text to find.' }),\n path: Type.Optional(Type.String({ description: 'File or directory to search. Defaults to the working directory.' })),\n glob: Type.Optional(Type.String({ description: 'Glob filter for files to search.' })),\n ignoreCase: Type.Optional(Type.Boolean({ description: 'Match without case sensitivity.' })),\n literal: Type.Optional(Type.Boolean({ description: 'Treat pattern as literal text.' })),\n context: Type.Optional(Type.Integer({ minimum: 0, description: 'Context lines around every match.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of matches.' })),\n});\n\nexport type GrepParams = Static<typeof GrepParamsSchema>;\n"],"mappings":"yBAEA,MAAa,EAAmBA,EAAAA,KAAK,OAAO,CAC1C,QAASA,EAAAA,KAAK,OAAO,CAAE,YAAa,6CAA8C,CAAC,EACnF,KAAMA,EAAAA,KAAK,SAASA,EAAAA,KAAK,OAAO,CAAE,YAAa,iEAAkE,CAAC,CAAC,EACnH,KAAMA,EAAAA,KAAK,SAASA,EAAAA,KAAK,OAAO,CAAE,YAAa,kCAAmC,CAAC,CAAC,EACpF,WAAYA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,YAAa,iCAAkC,CAAC,CAAC,EAC1F,QAASA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,YAAa,gCAAiC,CAAC,CAAC,EACtF,QAASA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,QAAS,EAAG,YAAa,mCAAoC,CAAC,CAAC,EACrG,MAAOA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,QAAS,EAAG,YAAa,4BAA6B,CAAC,CAAC,CAC9F,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Static, Type } from "typebox";
|
|
2
|
+
//#region src/schemas/grepTool.d.ts
|
|
3
|
+
declare const GrepParamsSchema: Type.TObject<{
|
|
4
|
+
pattern: Type.TString;
|
|
5
|
+
path: Type.TOptional<Type.TString>;
|
|
6
|
+
glob: Type.TOptional<Type.TString>;
|
|
7
|
+
ignoreCase: Type.TOptional<Type.TBoolean>;
|
|
8
|
+
literal: Type.TOptional<Type.TBoolean>;
|
|
9
|
+
context: Type.TOptional<Type.TInteger>;
|
|
10
|
+
limit: Type.TOptional<Type.TInteger>;
|
|
11
|
+
}>;
|
|
12
|
+
type GrepParams = Static<typeof GrepParamsSchema>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { GrepParams, GrepParamsSchema };
|
|
15
|
+
//# sourceMappingURL=grepTool.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.d.cts","names":[],"sources":["../../src/schemas/grepTool.ts"],"mappings":";;cAEa,kBAAgB,KAAA;;;;;;;;;KAUjB,aAAa,cAAc"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Static, Type } from "typebox";
|
|
2
|
+
//#region src/schemas/grepTool.d.ts
|
|
3
|
+
declare const GrepParamsSchema: Type.TObject<{
|
|
4
|
+
pattern: Type.TString;
|
|
5
|
+
path: Type.TOptional<Type.TString>;
|
|
6
|
+
glob: Type.TOptional<Type.TString>;
|
|
7
|
+
ignoreCase: Type.TOptional<Type.TBoolean>;
|
|
8
|
+
literal: Type.TOptional<Type.TBoolean>;
|
|
9
|
+
context: Type.TOptional<Type.TInteger>;
|
|
10
|
+
limit: Type.TOptional<Type.TInteger>;
|
|
11
|
+
}>;
|
|
12
|
+
type GrepParams = Static<typeof GrepParamsSchema>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { GrepParams, GrepParamsSchema };
|
|
15
|
+
//# sourceMappingURL=grepTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.d.mts","names":[],"sources":["../../src/schemas/grepTool.ts"],"mappings":";;cAEa,kBAAgB,KAAA;;;;;;;;;KAUjB,aAAa,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Type as e}from"typebox";const t=e.Object({pattern:e.String({description:`Regular expression or literal text to find.`}),path:e.Optional(e.String({description:`File or directory to search. Defaults to the working directory.`})),glob:e.Optional(e.String({description:`Glob filter for files to search.`})),ignoreCase:e.Optional(e.Boolean({description:`Match without case sensitivity.`})),literal:e.Optional(e.Boolean({description:`Treat pattern as literal text.`})),context:e.Optional(e.Integer({minimum:0,description:`Context lines around every match.`})),limit:e.Optional(e.Integer({minimum:1,description:`Maximum number of matches.`}))});export{t as GrepParamsSchema};
|
|
2
|
+
//# sourceMappingURL=grepTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grepTool.mjs","names":[],"sources":["../../src/schemas/grepTool.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const GrepParamsSchema = Type.Object({\n pattern: Type.String({ description: 'Regular expression or literal text to find.' }),\n path: Type.Optional(Type.String({ description: 'File or directory to search. Defaults to the working directory.' })),\n glob: Type.Optional(Type.String({ description: 'Glob filter for files to search.' })),\n ignoreCase: Type.Optional(Type.Boolean({ description: 'Match without case sensitivity.' })),\n literal: Type.Optional(Type.Boolean({ description: 'Treat pattern as literal text.' })),\n context: Type.Optional(Type.Integer({ minimum: 0, description: 'Context lines around every match.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of matches.' })),\n});\n\nexport type GrepParams = Static<typeof GrepParamsSchema>;\n"],"mappings":"+BAEA,MAAa,EAAmB,EAAK,OAAO,CAC1C,QAAS,EAAK,OAAO,CAAE,YAAa,6CAA8C,CAAC,EACnF,KAAM,EAAK,SAAS,EAAK,OAAO,CAAE,YAAa,iEAAkE,CAAC,CAAC,EACnH,KAAM,EAAK,SAAS,EAAK,OAAO,CAAE,YAAa,kCAAmC,CAAC,CAAC,EACpF,WAAY,EAAK,SAAS,EAAK,QAAQ,CAAE,YAAa,iCAAkC,CAAC,CAAC,EAC1F,QAAS,EAAK,SAAS,EAAK,QAAQ,CAAE,YAAa,gCAAiC,CAAC,CAAC,EACtF,QAAS,EAAK,SAAS,EAAK,QAAQ,CAAE,QAAS,EAAG,YAAa,mCAAoC,CAAC,CAAC,EACrG,MAAO,EAAK,SAAS,EAAK,QAAQ,CAAE,QAAS,EAAG,YAAa,4BAA6B,CAAC,CAAC,CAC9F,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agimon-ai/doompi-grep",
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
|
+
"description": "Snapshot-bound hashline grep for Pi and DoomPi.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"coding-agent",
|
|
8
|
+
"developer-tools",
|
|
9
|
+
"doompi",
|
|
10
|
+
"grep",
|
|
11
|
+
"hashline",
|
|
12
|
+
"pi-coding-agent",
|
|
13
|
+
"pi-extension",
|
|
14
|
+
"pi-package"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://agimon.ai",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Vuong Ngo",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "./dist/index.cjs",
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"jsnext:main": "./dist/index.mjs",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.mts",
|
|
29
|
+
"import": "./dist/index.mjs",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./extensions/pi": {
|
|
33
|
+
"types": "./dist/extensions/pi.d.mts",
|
|
34
|
+
"import": "./dist/extensions/pi.mjs",
|
|
35
|
+
"require": "./dist/extensions/pi.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
44
|
+
"typebox": "1.3.16",
|
|
45
|
+
"@agimon-ai/doompi-hashline": "0.0.1-alpha.1",
|
|
46
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.29",
|
|
47
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.29"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
51
|
+
"@earendil-works/pi-tui": "0.84.2",
|
|
52
|
+
"@types/node": "26.2.0",
|
|
53
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
54
|
+
"tsdown": "0.22.14",
|
|
55
|
+
"typescript": "7.0.2",
|
|
56
|
+
"vitest": "4.1.11"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
60
|
+
"@earendil-works/pi-tui": "0.84.2"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@earendil-works/pi-coding-agent": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@earendil-works/pi-tui": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=22.19.0"
|
|
72
|
+
},
|
|
73
|
+
"pi": {
|
|
74
|
+
"extensions": [
|
|
75
|
+
"./dist/extensions/pi.mjs"
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"build": "tsdown",
|
|
80
|
+
"test": "vitest --run",
|
|
81
|
+
"typecheck": "tsc --noEmit",
|
|
82
|
+
"lint": "oxlint . && oxfmt . --check",
|
|
83
|
+
"fixcode": "oxlint . --fix && oxfmt ."
|
|
84
|
+
}
|
|
85
|
+
}
|