@agimon-ai/doompi-grep 0.0.1-alpha.41 → 0.0.1-alpha.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +3 -1
  2. package/dist/api-contracts.cjs +1 -0
  3. package/dist/api-contracts.d.cts +2 -0
  4. package/dist/api-contracts.d.mts +2 -0
  5. package/dist/api-contracts.mjs +1 -0
  6. package/dist/constants/package.cjs +2 -0
  7. package/dist/constants/package.cjs.map +1 -0
  8. package/dist/constants/package.mjs +2 -0
  9. package/dist/constants/package.mjs.map +1 -0
  10. package/dist/extensions/pi.cjs +2 -1
  11. package/dist/extensions/pi.cjs.map +1 -0
  12. package/dist/extensions/pi.d.cts +5 -2
  13. package/dist/extensions/pi.d.cts.map +1 -0
  14. package/dist/extensions/pi.d.mts +5 -2
  15. package/dist/extensions/pi.d.mts.map +1 -0
  16. package/dist/extensions/pi.mjs +2 -1
  17. package/dist/extensions/pi.mjs.map +1 -0
  18. package/dist/extensions/server.cjs +2 -0
  19. package/dist/extensions/server.cjs.map +1 -0
  20. package/dist/extensions/server.d.cts +5 -0
  21. package/dist/extensions/server.d.cts.map +1 -0
  22. package/dist/extensions/server.d.mts +5 -0
  23. package/dist/extensions/server.d.mts.map +1 -0
  24. package/dist/extensions/server.mjs +2 -0
  25. package/dist/extensions/server.mjs.map +1 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.mts +3 -3
  29. package/dist/index.mjs +1 -1
  30. package/dist/schemas/apiContracts.cjs +2 -0
  31. package/dist/schemas/apiContracts.cjs.map +1 -0
  32. package/dist/schemas/apiContracts.d.cts +53 -0
  33. package/dist/schemas/apiContracts.d.cts.map +1 -0
  34. package/dist/schemas/apiContracts.d.mts +53 -0
  35. package/dist/schemas/apiContracts.d.mts.map +1 -0
  36. package/dist/schemas/apiContracts.mjs +2 -0
  37. package/dist/schemas/apiContracts.mjs.map +1 -0
  38. package/dist/services/grepTool/index.cjs +10 -0
  39. package/dist/services/grepTool/index.cjs.map +1 -0
  40. package/dist/services/grepTool/index.d.cts +1 -0
  41. package/dist/services/grepTool/index.d.mts +1 -0
  42. package/dist/services/grepTool/index.mjs +10 -0
  43. package/dist/services/grepTool/index.mjs.map +1 -0
  44. package/dist/services/headlessGrep/index.cjs +4 -0
  45. package/dist/services/headlessGrep/index.cjs.map +1 -0
  46. package/dist/services/headlessGrep/index.d.cts +6 -0
  47. package/dist/services/headlessGrep/index.d.cts.map +1 -0
  48. package/dist/services/headlessGrep/index.d.mts +6 -0
  49. package/dist/services/headlessGrep/index.d.mts.map +1 -0
  50. package/dist/services/headlessGrep/index.mjs +4 -0
  51. package/dist/services/headlessGrep/index.mjs.map +1 -0
  52. package/dist/tools/piGrep.cjs +2 -0
  53. package/dist/tools/piGrep.cjs.map +1 -0
  54. package/dist/tools/piGrep.d.cts +9 -0
  55. package/dist/tools/piGrep.d.cts.map +1 -0
  56. package/dist/tools/piGrep.d.mts +9 -0
  57. package/dist/tools/piGrep.d.mts.map +1 -0
  58. package/dist/tools/piGrep.mjs +2 -0
  59. package/dist/tools/piGrep.mjs.map +1 -0
  60. package/package.json +26 -8
  61. package/src/extensions/web.ts +14 -0
  62. package/src/web/components/GrepToolMessage.tsx +3 -2
  63. package/src/web/tsconfig.json +1 -1
  64. package/dist/adapters/pi/extension.cjs +0 -2
  65. package/dist/adapters/pi/extension.cjs.map +0 -1
  66. package/dist/adapters/pi/extension.d.cts +0 -10
  67. package/dist/adapters/pi/extension.d.cts.map +0 -1
  68. package/dist/adapters/pi/extension.d.mts +0 -10
  69. package/dist/adapters/pi/extension.d.mts.map +0 -1
  70. package/dist/adapters/pi/extension.mjs +0 -2
  71. package/dist/adapters/pi/extension.mjs.map +0 -1
  72. package/dist/adapters/pi/grepTool.cjs +0 -10
  73. package/dist/adapters/pi/grepTool.cjs.map +0 -1
  74. package/dist/adapters/pi/grepTool.d.cts +0 -8
  75. package/dist/adapters/pi/grepTool.d.cts.map +0 -1
  76. package/dist/adapters/pi/grepTool.d.mts +0 -8
  77. package/dist/adapters/pi/grepTool.d.mts.map +0 -1
  78. package/dist/adapters/pi/grepTool.mjs +0 -10
  79. package/dist/adapters/pi/grepTool.mjs.map +0 -1
  80. package/src/exports/webClient.ts +0 -1
  81. package/src/web/index.ts +0 -11
package/README.md CHANGED
@@ -58,7 +58,7 @@ boundary.
58
58
  ## Public API
59
59
 
60
60
  ```ts
61
- import { GrepParamsSchema, registerHashlineGrepTool } from '@agimon-ai/doompi-grep';
61
+ import { GrepParamsSchema, createHashlineGrepTool } from '@agimon-ai/doompi-grep';
62
62
  import type { GrepParams } from '@agimon-ai/doompi-grep';
63
63
  ```
64
64
 
@@ -76,3 +76,5 @@ Maintained by [Agimon](https://agimon.ai/about).
76
76
  ## License
77
77
 
78
78
  MIT
79
+
80
+ The Pi and server plugins are declared directly in `src/extensions`. The Pi helper owns the grep override claim and cleanup. Tool factories consume named service folders; reusable declarations and schemas are exposed through flat `src/exports`.
@@ -0,0 +1 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./schemas/apiContracts.cjs");exports.apiContracts=e.apiContracts,exports.default=e.apiContracts;
@@ -0,0 +1,2 @@
1
+ import { apiContracts } from "./schemas/apiContracts.cjs";
2
+ export { apiContracts, apiContracts as default };
@@ -0,0 +1,2 @@
1
+ import { apiContracts } from "./schemas/apiContracts.mjs";
2
+ export { apiContracts, apiContracts as default };
@@ -0,0 +1 @@
1
+ import{apiContracts as e}from"./schemas/apiContracts.mjs";export{e as apiContracts,e as default};
@@ -0,0 +1,2 @@
1
+ exports.PACKAGE_SOURCE=`@agimon-ai/doompi-grep`;
2
+ //# sourceMappingURL=package.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.cjs","names":[],"sources":["../../src/constants/package.ts"],"sourcesContent":["export const PACKAGE_SOURCE = '@agimon-ai/doompi-grep';\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ const e=`@agimon-ai/doompi-grep`;export{e as PACKAGE_SOURCE};
2
+ //# sourceMappingURL=package.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.mjs","names":[],"sources":["../../src/constants/package.ts"],"sourcesContent":["export const PACKAGE_SOURCE = '@agimon-ai/doompi-grep';\n"],"mappings":"AAAA,MAAa,EAAiB"}
@@ -1 +1,2 @@
1
- const e=require("../adapters/pi/extension.cjs");module.exports=e.activateDoomPiGrepExtension;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../tools/piGrep.cjs"),t=require("../constants/package.cjs");let n=require("@agimon-ai/doompi-core/pi-extension");const r=(0,n.definePiExtension)(t.PACKAGE_SOURCE,()=>({toolOverrides:[{source:t.PACKAGE_SOURCE,tools:[`grep`],replacements:[(0,n.definePiTool)(e.createHashlineGrepTool())]}]}));exports.activateDoomPiGrepExtension=r,exports.default=r;
2
+ //# sourceMappingURL=pi.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.cjs","names":["definePiExtension","PACKAGE_SOURCE","definePiTool","createHashlineGrepTool"],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { definePiExtension, definePiTool } from '@agimon-ai/doompi-core/pi-extension';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { createHashlineGrepTool } from '../tools/piGrep';\n\nexport const activateDoomPiGrepExtension = definePiExtension(PACKAGE_SOURCE, () => ({\n toolOverrides: [{ source: PACKAGE_SOURCE, tools: ['grep'], replacements: [definePiTool(createHashlineGrepTool())] }],\n}));\nexport default activateDoomPiGrepExtension;\n"],"mappings":"iOAKA,MAAa,GAAA,EAA8BA,EAAAA,kBAAAA,CAAkBC,EAAAA,oBAAuB,CAClF,cAAe,CAAC,CAAE,OAAQA,EAAAA,eAAgB,MAAO,CAAC,MAAM,EAAG,aAAc,EAAA,EAACC,EAAAA,aAAAA,CAAaC,EAAAA,uBAAuB,CAAC,CAAC,CAAE,CAAC,CACrH,EAAE"}
@@ -1,2 +1,5 @@
1
- import { activateDoomPiGrepExtension } from "../adapters/pi/extension.cjs";
2
- export = activateDoomPiGrepExtension;
1
+ //#region src/extensions/pi.d.ts
2
+ export declare const activateDoomPiGrepExtension: import("@agimon-ai/doompi-core/runtime-pi-extension").DefinedPiExtension<undefined>;
3
+ //#endregion
4
+ export { activateDoomPiGrepExtension as default };
5
+ //# sourceMappingURL=pi.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";qBAKa,mFAA2B"}
@@ -1,2 +1,5 @@
1
- import { activateDoomPiGrepExtension } from "../adapters/pi/extension.mjs";
2
- export { activateDoomPiGrepExtension as default };
1
+ //#region src/extensions/pi.d.ts
2
+ export declare const activateDoomPiGrepExtension: import("@agimon-ai/doompi-core/runtime-pi-extension").DefinedPiExtension<undefined>;
3
+ //#endregion
4
+ export { activateDoomPiGrepExtension as default };
5
+ //# sourceMappingURL=pi.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";qBAKa,mFAA2B"}
@@ -1 +1,2 @@
1
- import{activateDoomPiGrepExtension as e}from"../adapters/pi/extension.mjs";export{e as default};
1
+ import{createHashlineGrepTool as e}from"../tools/piGrep.mjs";import{PACKAGE_SOURCE as t}from"../constants/package.mjs";import{definePiExtension as n,definePiTool as r}from"@agimon-ai/doompi-core/pi-extension";const i=n(t,()=>({toolOverrides:[{source:t,tools:[`grep`],replacements:[r(e())]}]}));export{i as activateDoomPiGrepExtension,i as default};
2
+ //# sourceMappingURL=pi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.mjs","names":[],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { definePiExtension, definePiTool } from '@agimon-ai/doompi-core/pi-extension';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { createHashlineGrepTool } from '../tools/piGrep';\n\nexport const activateDoomPiGrepExtension = definePiExtension(PACKAGE_SOURCE, () => ({\n toolOverrides: [{ source: PACKAGE_SOURCE, tools: ['grep'], replacements: [definePiTool(createHashlineGrepTool())] }],\n}));\nexport default activateDoomPiGrepExtension;\n"],"mappings":"iNAKA,MAAa,EAA8B,EAAkB,OAAuB,CAClF,cAAe,CAAC,CAAE,OAAQ,EAAgB,MAAO,CAAC,MAAM,EAAG,aAAc,CAAC,EAAa,EAAuB,CAAC,CAAC,CAAE,CAAC,CACrH,EAAE"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../services/headlessGrep/index.cjs"),t=require("../constants/package.cjs"),n=(0,require("@agimon-ai/doompi-core/server-facet").defineServerPlugin)({name:t.PACKAGE_SOURCE,session:()=>({tools:[e.createHeadlessGrepTool()]})});exports.default=n,exports.grepServerFacet=n;
2
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.cjs","names":["defineServerPlugin","PACKAGE_SOURCE","createHeadlessGrepTool"],"sources":["../../src/extensions/server.ts"],"sourcesContent":["import { defineServerPlugin } from '@agimon-ai/doompi-core/server-facet';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { createHeadlessGrepTool } from '../services/headlessGrep';\n\nexport const grepServerFacet = defineServerPlugin({\n name: PACKAGE_SOURCE,\n session: () => ({ tools: [createHeadlessGrepTool()] }),\n});\nexport default grepServerFacet;\n"],"mappings":"2LAKa,GAAA,+CAAkBA,CAAAA,CAAAA,mBAAAA,CAAmB,CAChD,KAAMC,EAAAA,eACN,aAAgB,CAAE,MAAO,CAACC,EAAAA,uBAAuB,CAAC,CAAE,EACtD,CAAC"}
@@ -0,0 +1,5 @@
1
+ //#region src/extensions/server.d.ts
2
+ export declare const grepServerFacet: import("@agimon-ai/doompi-core/server-facet").DoomServerFacet;
3
+ //#endregion
4
+ export { grepServerFacet as default };
5
+ //# sourceMappingURL=server.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.cts","names":[],"sources":["../../src/extensions/server.ts"],"mappings":";qBAKa,+DAAe"}
@@ -0,0 +1,5 @@
1
+ //#region src/extensions/server.d.ts
2
+ export declare const grepServerFacet: import("@agimon-ai/doompi-core/server-facet").DoomServerFacet;
3
+ //#endregion
4
+ export { grepServerFacet as default };
5
+ //# sourceMappingURL=server.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../src/extensions/server.ts"],"mappings":";qBAKa,+DAAe"}
@@ -0,0 +1,2 @@
1
+ import{createHeadlessGrepTool as e}from"../services/headlessGrep/index.mjs";import{PACKAGE_SOURCE as t}from"../constants/package.mjs";import{defineServerPlugin as n}from"@agimon-ai/doompi-core/server-facet";const r=n({name:t,session:()=>({tools:[e()]})});export{r as default,r as grepServerFacet};
2
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../../src/extensions/server.ts"],"sourcesContent":["import { defineServerPlugin } from '@agimon-ai/doompi-core/server-facet';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { createHeadlessGrepTool } from '../services/headlessGrep';\n\nexport const grepServerFacet = defineServerPlugin({\n name: PACKAGE_SOURCE,\n session: () => ({ tools: [createHeadlessGrepTool()] }),\n});\nexport default grepServerFacet;\n"],"mappings":"+MAKA,MAAa,EAAkB,EAAmB,CAChD,KAAM,EACN,aAAgB,CAAE,MAAO,CAAC,EAAuB,CAAC,CAAE,EACtD,CAAC"}
package/dist/index.cjs CHANGED
@@ -1 +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;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./schemas/grepTool.cjs"),t=require("./tools/piGrep.cjs"),n=require("./services/headlessGrep/index.cjs");exports.GrepParamsSchema=e.GrepParamsSchema,exports.createHashlineGrepTool=t.createHashlineGrepTool,exports.createHeadlessGrepTool=n.createHeadlessGrepTool;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { activateDoomPiGrepExtension, installDoomPiGrepRuntime } from "./adapters/pi/extension.cjs";
2
1
  import { GrepParams, GrepParamsSchema } from "./schemas/grepTool.cjs";
3
- import { registerHashlineGrepTool } from "./adapters/pi/grepTool.cjs";
4
- export { type GrepParams, GrepParamsSchema, activateDoomPiGrepExtension, installDoomPiGrepRuntime, registerHashlineGrepTool };
2
+ import { createHashlineGrepTool } from "./tools/piGrep.cjs";
3
+ import { createHeadlessGrepTool } from "./services/headlessGrep/index.cjs";
4
+ export { type GrepParams, GrepParamsSchema, createHashlineGrepTool, createHeadlessGrepTool };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { activateDoomPiGrepExtension, installDoomPiGrepRuntime } from "./adapters/pi/extension.mjs";
2
1
  import { GrepParams, GrepParamsSchema } from "./schemas/grepTool.mjs";
3
- import { registerHashlineGrepTool } from "./adapters/pi/grepTool.mjs";
4
- export { type GrepParams, GrepParamsSchema, activateDoomPiGrepExtension, installDoomPiGrepRuntime, registerHashlineGrepTool };
2
+ import { createHashlineGrepTool } from "./tools/piGrep.mjs";
3
+ import { createHeadlessGrepTool } from "./services/headlessGrep/index.mjs";
4
+ export { type GrepParams, GrepParamsSchema, createHashlineGrepTool, createHeadlessGrepTool };
package/dist/index.mjs CHANGED
@@ -1 +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};
1
+ import{GrepParamsSchema as e}from"./schemas/grepTool.mjs";import{createHashlineGrepTool as t}from"./tools/piGrep.mjs";import{createHeadlessGrepTool as n}from"./services/headlessGrep/index.mjs";export{e as GrepParamsSchema,t as createHashlineGrepTool,n as createHeadlessGrepTool};
@@ -0,0 +1,2 @@
1
+ const e=(0,require("@agimon-ai/doompi-core/api-contracts").defineApiContract)({version:1,http:[],sockets:[],dynamic:[]});exports.apiContracts=e,exports.default=e;
2
+ //# sourceMappingURL=apiContracts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/api-contracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"AAGA,MAAa,GAAA,gDAAeA,CAAAA,CAAAA,kBAAAA,CAAkB,CAAE,QAAS,EAAG,KAAM,CAAC,EAAG,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,CAAC"}
@@ -0,0 +1,53 @@
1
+ //#region src/schemas/apiContracts.d.ts
2
+ /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
3
+ export declare const apiContracts: {
4
+ version: 1;
5
+ protocols?: Record<string, string> | undefined;
6
+ schemas?: Record<string, boolean | object> | undefined;
7
+ http: {
8
+ id: string;
9
+ scope: "global" | "session" | "workspace";
10
+ basePath?: string | undefined;
11
+ path: string;
12
+ method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
13
+ description: string;
14
+ availability?: string | undefined;
15
+ authentication: "device" | "none" | "owner";
16
+ parameters?: {
17
+ name: string;
18
+ in: "header" | "path" | "query";
19
+ required: boolean;
20
+ schema: boolean | object;
21
+ }[] | undefined;
22
+ body?: {
23
+ contentType: string;
24
+ contentTypes?: string[] | undefined;
25
+ required: boolean;
26
+ schema: boolean | object;
27
+ } | undefined;
28
+ responses: Record<string, {
29
+ description: string;
30
+ contentType?: string | undefined;
31
+ schema?: boolean | object | undefined;
32
+ events?: Record<string, boolean | object> | undefined;
33
+ }>;
34
+ }[];
35
+ sockets: {
36
+ id: string;
37
+ scope: "global" | "session" | "workspace";
38
+ description: string;
39
+ availability?: string | undefined;
40
+ service: string;
41
+ member: string;
42
+ direction: "client-to-server" | "server-to-client";
43
+ kind: "channel" | "method" | "state";
44
+ input: boolean | object;
45
+ output?: boolean | object | undefined;
46
+ errors?: boolean | object | undefined;
47
+ }[];
48
+ dynamic: string[];
49
+ gaps?: string[] | undefined;
50
+ };
51
+ //#endregion
52
+ export { apiContracts as default };
53
+ //# sourceMappingURL=apiContracts.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.d.cts","names":[],"sources":["../../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
@@ -0,0 +1,53 @@
1
+ //#region src/schemas/apiContracts.d.ts
2
+ /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
3
+ export declare const apiContracts: {
4
+ version: 1;
5
+ protocols?: Record<string, string> | undefined;
6
+ schemas?: Record<string, boolean | object> | undefined;
7
+ http: {
8
+ id: string;
9
+ scope: "global" | "session" | "workspace";
10
+ basePath?: string | undefined;
11
+ path: string;
12
+ method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
13
+ description: string;
14
+ availability?: string | undefined;
15
+ authentication: "device" | "none" | "owner";
16
+ parameters?: {
17
+ name: string;
18
+ in: "header" | "path" | "query";
19
+ required: boolean;
20
+ schema: boolean | object;
21
+ }[] | undefined;
22
+ body?: {
23
+ contentType: string;
24
+ contentTypes?: string[] | undefined;
25
+ required: boolean;
26
+ schema: boolean | object;
27
+ } | undefined;
28
+ responses: Record<string, {
29
+ description: string;
30
+ contentType?: string | undefined;
31
+ schema?: boolean | object | undefined;
32
+ events?: Record<string, boolean | object> | undefined;
33
+ }>;
34
+ }[];
35
+ sockets: {
36
+ id: string;
37
+ scope: "global" | "session" | "workspace";
38
+ description: string;
39
+ availability?: string | undefined;
40
+ service: string;
41
+ member: string;
42
+ direction: "client-to-server" | "server-to-client";
43
+ kind: "channel" | "method" | "state";
44
+ input: boolean | object;
45
+ output?: boolean | object | undefined;
46
+ errors?: boolean | object | undefined;
47
+ }[];
48
+ dynamic: string[];
49
+ gaps?: string[] | undefined;
50
+ };
51
+ //#endregion
52
+ export { apiContracts as default };
53
+ //# sourceMappingURL=apiContracts.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
@@ -0,0 +1,2 @@
1
+ import{defineApiContract as e}from"@agimon-ai/doompi-core/api-contracts";const t=e({version:1,http:[],sockets:[],dynamic:[]});export{t as apiContracts,t as default};
2
+ //# sourceMappingURL=apiContracts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/api-contracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"yEAGA,MAAa,EAAe,EAAkB,CAAE,QAAS,EAAG,KAAM,CAAC,EAAG,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ let e=require("@agimon-ai/doompi-hashline/files"),t=require("node:path"),n=require("@agimon-ai/doompi-hashline");const r=/:(\d+): /gu,i=/-(\d+)- /gu;async function a(t,r,i,a,c,u,d){let f=t.content.find(e=>e.type===`text`);if(!f||f.text===`No matches found`)return t;let p=f.text.lastIndexOf(`
2
+
3
+ [`),m=p===-1?f.text:f.text.slice(0,p),h=p===-1?``:f.text.slice(p),g=(0,e.resolveInputPath)(r.path??`.`,i),_=await u.stat(g);l(a);let v=await s(m,g,_.isDirectory(),a,u);if(v.length===0)return t;let y=o(v,g,_.isDirectory(),i),b=[],x=0,S=t.details?.linesTruncated??!1;for(let t of y.values()){l(a);let r=await c(t.absolutePath);if(l(a),!r){b.push(t.nativeRows.join(`
4
+ `));continue}let i;try{i=await u.readFile(t.absolutePath)}catch{b.push(t.nativeRows.join(`
5
+ `));continue}l(a);let o=(0,n.splitLines)((0,e.decodeUtf8)(i,t.path)),s=[(0,n.formatFileHeader)(t.path,(0,e.computeFileTag)(i))];for(let[e,r]of[...t.rows].sort(([e],[t])=>e-t)){let t=o[e-1];if(t===void 0)continue;let i=d.truncateLine(t);i.wasTruncated&&(S=!0),s.push((0,n.formatTaggedLine)(i.text,e,r?`>> `:` `,t))}s.length>1?(b.push(s.join(`
6
+ `)),x++):b.push(t.nativeRows.join(`
7
+ `))}if(b.length===0||x===0)return t;let C=d.truncateHead(b.join(`
8
+ `),{maxLines:2**53-1}),w=C.truncated?`\n\n[${d.formatSize(d.maxBytes)} tagged output limit reached]`:``,T={...t.details,...C.truncated?{truncation:C}:{},...S?{linesTruncated:!0}:{}};return l(a),{...t,content:[{type:`text`,text:`${C.content}${h}${w}`}],details:Object.keys(T).length>0?T:void 0}}function o(n,r,i,a){let o=new Map;for(let s of n){let n=i?(0,t.resolve)(r,s.path):r,c=o.get(n);c||(c={path:(0,e.displayPath)(n,a),absolutePath:n,nativeRows:[],rows:new Map},o.set(n,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}async function s(e,n,r,i,a){let o=new Map,s=[];for(let u of e.split(`
9
+ `)){l(i);let e;for(let d of c(u)){if(!r){d.path===(0,t.basename)(n)&&s.push({...d,native:u});break}let c=(0,t.resolve)(n,d.path),f=o.get(c);f===void 0&&(f=await a.stat(c).then(e=>e.isFile()).catch(()=>!1),l(i),o.set(c,f)),f&&(e={...d,native:u})}e&&s.push(e)}return s}function c(e){let t=[];for(let n of e.matchAll(r))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(i))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 l(e){if(e?.aborted)throw Error(`Operation aborted`)}exports.assertNotAborted=l,exports.groupGrepRows=o,exports.tagGrepResult=a;
10
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["resolveInputPath","splitLines","decodeUtf8","formatFileHeader","computeFileTag","formatTaggedLine","resolve","displayPath","basename"],"sources":["../../../src/services/grepTool/index.ts"],"sourcesContent":["import { basename, resolve } from 'node:path';\n\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport { computeFileTag, decodeUtf8, displayPath, resolveInputPath } from '@agimon-ai/doompi-hashline/files';\n\nimport type { GrepParams } from '../../schemas/grepTool';\n\nconst MATCH_DELIMITER = /:(\\d+): /gu;\nconst CONTEXT_DELIMITER = /-(\\d+)- /gu;\nconst NO_MATCHES = 'No matches found';\n\nexport interface GrepRow {\n readonly path: string;\n readonly line: number;\n readonly match: boolean;\n readonly native?: string;\n}\n\nexport interface GrepGroup {\n readonly path: string;\n readonly absolutePath: string;\n readonly nativeRows: string[];\n readonly rows: Map<number, boolean>;\n}\n\nexport interface GrepResult {\n content: Array<{ type: 'text'; text: string }>;\n details?: {\n readonly linesTruncated?: boolean;\n readonly truncation?: GrepTruncation;\n readonly [key: string]: unknown;\n };\n}\n\nexport interface GrepFileStats {\n isDirectory(): boolean;\n isFile(): boolean;\n}\n\nexport interface GrepFileSystem {\n stat(path: string): Promise<GrepFileStats>;\n readFile(path: string): Promise<Uint8Array>;\n}\n\nexport interface GrepTruncation {\n readonly content: string;\n readonly truncated: boolean;\n readonly truncatedBy: 'lines' | 'bytes' | null;\n readonly outputLines: number;\n}\n\nexport interface GrepOutputOperations {\n readonly maxBytes: number;\n formatSize(bytes: number): string;\n truncateHead(content: string, options: { readonly maxLines?: number }): GrepTruncation;\n truncateLine(line: string): { readonly text: string; readonly wasTruncated: boolean };\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\nexport async function tagGrepResult(\n nativeResult: GrepResult,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: (path: string) => Promise<boolean>,\n filesystem: GrepFileSystem,\n outputOperations: GrepOutputOperations,\n): Promise<GrepResult> {\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 filesystem.stat(searchPath);\n assertNotAborted(signal);\n const rows = await parseValidatedGrepRows(rowsText, searchPath, searchStats.isDirectory(), signal, filesystem);\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: Uint8Array;\n try {\n bytes = await filesystem.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 = outputOperations.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 = outputOperations.truncateHead(blocks.join('\\n'), { maxLines: Number.MAX_SAFE_INTEGER });\n const extraNotice = truncation.truncated\n ? `\\n\\n[${outputOperations.formatSize(outputOperations.maxBytes)} tagged output limit reached]`\n : '';\n const details = {\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 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\nasync function parseValidatedGrepRows(\n rowsText: string,\n searchPath: string,\n directory: boolean,\n signal: AbortSignal | undefined,\n filesystem: GrepFileSystem,\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)) rows.push({ ...candidate, native: value });\n break;\n }\n const absolutePath = resolve(searchPath, candidate.path);\n let exists = pathCache.get(absolutePath);\n if (exists === undefined) {\n exists = await filesystem\n .stat(absolutePath)\n .then((value) => value.isFile())\n .catch(() => false);\n assertNotAborted(signal);\n pathCache.set(absolutePath, exists);\n }\n if (exists) resolvedCandidate = { ...candidate, native: value };\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 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
+ import "../../schemas/grepTool.cjs";
@@ -0,0 +1 @@
1
+ import "../../schemas/grepTool.mjs";
@@ -0,0 +1,10 @@
1
+ import{computeFileTag as e,decodeUtf8 as t,displayPath as n,resolveInputPath as r}from"@agimon-ai/doompi-hashline/files";import{basename as i,resolve as a}from"node:path";import{formatFileHeader as o,formatTaggedLine as s,splitLines as c}from"@agimon-ai/doompi-hashline";const l=/:(\d+): /gu,u=/-(\d+)- /gu;async function d(n,i,a,l,u,d,m){let g=n.content.find(e=>e.type===`text`);if(!g||g.text===`No matches found`)return n;let _=g.text.lastIndexOf(`
2
+
3
+ [`),v=_===-1?g.text:g.text.slice(0,_),y=_===-1?``:g.text.slice(_),b=r(i.path??`.`,a),x=await d.stat(b);h(l);let S=await p(v,b,x.isDirectory(),l,d);if(S.length===0)return n;let C=f(S,b,x.isDirectory(),a),w=[],T=0,E=n.details?.linesTruncated??!1;for(let n of C.values()){h(l);let r=await u(n.absolutePath);if(h(l),!r){w.push(n.nativeRows.join(`
4
+ `));continue}let i;try{i=await d.readFile(n.absolutePath)}catch{w.push(n.nativeRows.join(`
5
+ `));continue}h(l);let a=c(t(i,n.path)),f=[o(n.path,e(i))];for(let[e,t]of[...n.rows].sort(([e],[t])=>e-t)){let n=a[e-1];if(n===void 0)continue;let r=m.truncateLine(n);r.wasTruncated&&(E=!0),f.push(s(r.text,e,t?`>> `:` `,n))}f.length>1?(w.push(f.join(`
6
+ `)),T++):w.push(n.nativeRows.join(`
7
+ `))}if(w.length===0||T===0)return n;let D=m.truncateHead(w.join(`
8
+ `),{maxLines:2**53-1}),O=D.truncated?`\n\n[${m.formatSize(m.maxBytes)} tagged output limit reached]`:``,k={...n.details,...D.truncated?{truncation:D}:{},...E?{linesTruncated:!0}:{}};return h(l),{...n,content:[{type:`text`,text:`${D.content}${y}${O}`}],details:Object.keys(k).length>0?k:void 0}}function f(e,t,r,i){let o=new Map;for(let s of e){let e=r?a(t,s.path):t,c=o.get(e);c||(c={path:n(e,i),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}async function p(e,t,n,r,o){let s=new Map,c=[];for(let l of e.split(`
9
+ `)){h(r);let e;for(let u of m(l)){if(!n){u.path===i(t)&&c.push({...u,native:l});break}let d=a(t,u.path),f=s.get(d);f===void 0&&(f=await o.stat(d).then(e=>e.isFile()).catch(()=>!1),h(r),s.set(d,f)),f&&(e={...u,native:l})}e&&c.push(e)}return c}function m(e){let t=[];for(let n of e.matchAll(l))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(u))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 h(e){if(e?.aborted)throw Error(`Operation aborted`)}export{h as assertNotAborted,f as groupGrepRows,d as tagGrepResult};
10
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/grepTool/index.ts"],"sourcesContent":["import { basename, resolve } from 'node:path';\n\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport { computeFileTag, decodeUtf8, displayPath, resolveInputPath } from '@agimon-ai/doompi-hashline/files';\n\nimport type { GrepParams } from '../../schemas/grepTool';\n\nconst MATCH_DELIMITER = /:(\\d+): /gu;\nconst CONTEXT_DELIMITER = /-(\\d+)- /gu;\nconst NO_MATCHES = 'No matches found';\n\nexport interface GrepRow {\n readonly path: string;\n readonly line: number;\n readonly match: boolean;\n readonly native?: string;\n}\n\nexport interface GrepGroup {\n readonly path: string;\n readonly absolutePath: string;\n readonly nativeRows: string[];\n readonly rows: Map<number, boolean>;\n}\n\nexport interface GrepResult {\n content: Array<{ type: 'text'; text: string }>;\n details?: {\n readonly linesTruncated?: boolean;\n readonly truncation?: GrepTruncation;\n readonly [key: string]: unknown;\n };\n}\n\nexport interface GrepFileStats {\n isDirectory(): boolean;\n isFile(): boolean;\n}\n\nexport interface GrepFileSystem {\n stat(path: string): Promise<GrepFileStats>;\n readFile(path: string): Promise<Uint8Array>;\n}\n\nexport interface GrepTruncation {\n readonly content: string;\n readonly truncated: boolean;\n readonly truncatedBy: 'lines' | 'bytes' | null;\n readonly outputLines: number;\n}\n\nexport interface GrepOutputOperations {\n readonly maxBytes: number;\n formatSize(bytes: number): string;\n truncateHead(content: string, options: { readonly maxLines?: number }): GrepTruncation;\n truncateLine(line: string): { readonly text: string; readonly wasTruncated: boolean };\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\nexport async function tagGrepResult(\n nativeResult: GrepResult,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: (path: string) => Promise<boolean>,\n filesystem: GrepFileSystem,\n outputOperations: GrepOutputOperations,\n): Promise<GrepResult> {\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 filesystem.stat(searchPath);\n assertNotAborted(signal);\n const rows = await parseValidatedGrepRows(rowsText, searchPath, searchStats.isDirectory(), signal, filesystem);\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: Uint8Array;\n try {\n bytes = await filesystem.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 = outputOperations.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 = outputOperations.truncateHead(blocks.join('\\n'), { maxLines: Number.MAX_SAFE_INTEGER });\n const extraNotice = truncation.truncated\n ? `\\n\\n[${outputOperations.formatSize(outputOperations.maxBytes)} tagged output limit reached]`\n : '';\n const details = {\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 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\nasync function parseValidatedGrepRows(\n rowsText: string,\n searchPath: string,\n directory: boolean,\n signal: AbortSignal | undefined,\n filesystem: GrepFileSystem,\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)) rows.push({ ...candidate, native: value });\n break;\n }\n const absolutePath = resolve(searchPath, candidate.path);\n let exists = pathCache.get(absolutePath);\n if (exists === undefined) {\n exists = await filesystem\n .stat(absolutePath)\n .then((value) => value.isFile())\n .catch(() => false);\n assertNotAborted(signal);\n pathCache.set(absolutePath, exists);\n }\n if (exists) resolvedCandidate = { ...candidate, native: value };\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 assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ const e=require("../../schemas/grepTool.cjs"),t=require("../grepTool/index.cjs");let n=require("node:fs/promises"),r=require("@agimon-ai/doompi-hashline/files"),i=require("@earendil-works/pi-coding-agent"),a=require("node:path"),o=require("node:child_process");const s={stat:e=>(0,n.stat)(e),readFile:e=>(0,n.readFile)(e)},c={maxBytes:i.DEFAULT_MAX_BYTES,formatSize:i.formatSize,truncateHead:i.truncateHead,truncateLine:i.truncateLine};function l(){return{name:`grep`,label:`grep`,description:`Search file contents using ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Respects .gitignore.`,promptSnippet:`Search file contents and return editable hashline anchors`,parameters:e.GrepParamsSchema,executionMode:`parallel`,execute:async(e,n,i,a,o)=>{let l=n,d=await u(l,o.cwd,i);return t.tagGrepResult(d,l,o.cwd,i,r.isWritableFile,s,c)}}}async function u(e,t,n){let i=(0,r.resolveInputPath)(e.path??`.`,t),o=(0,a.relative)(t,i)||`.`,s=[`--color`,`never`,`--no-heading`,`--with-filename`,`--line-number`];e.ignoreCase===!0&&s.push(`--ignore-case`),e.literal===!0&&s.push(`--fixed-strings`),e.context!==void 0&&s.push(`--context`,String(e.context)),e.glob!==void 0&&s.push(`--glob`,e.glob),s.push(`--`,e.pattern,o);let c=await f(s,t,n);return c.trim()===``?{content:[{type:`text`,text:`No matches found`}]}:{content:[{type:`text`,text:d(c,e.limit)}]}}function d(e,t){if(t===void 0)return e.trimEnd();let n=0,r=e.trimEnd().split(`
2
+ `),i=[];for(let e of r)/:(\d+):/u.test(e)&&(n++,n>t)||i.push(e);return i.join(`
3
+ `)}function f(e,t,n){return new Promise((r,i)=>{let a=(0,o.spawn)(`rg`,e,{cwd:t,stdio:[`ignore`,`pipe`,`pipe`]}),s=``,c=``;a.stdout.on(`data`,e=>{s+=e.toString()}),a.stderr.on(`data`,e=>{c+=e.toString()});let l=()=>{a.kill(`SIGTERM`),i(Error(`Operation aborted`))};if(n?.aborted){l();return}n?.addEventListener(`abort`,l,{once:!0}),a.once(`error`,e=>{n?.removeEventListener(`abort`,l),i(Error(`Could not start ripgrep: ${e.message}`,{cause:e}))}),a.once(`close`,e=>{if(n?.removeEventListener(`abort`,l),e===0||e===1){r(s);return}i(Error(c.trim()||`ripgrep exited with code ${e??`unknown`}`))})})}exports.createHeadlessGrepTool=l;
4
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["stat","readFile","DEFAULT_MAX_BYTES","GrepParamsSchema","tagServiceGrepResult","isWritableFile","resolveInputPath","relative","spawn"],"sources":["../../../src/services/headlessGrep/index.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { readFile, stat } from 'node:fs/promises';\nimport { relative } from 'node:path';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { resolveInputPath, isWritableFile } from '@agimon-ai/doompi-hashline/files';\nimport { DEFAULT_MAX_BYTES, formatSize, truncateHead, truncateLine } from '@earendil-works/pi-coding-agent';\n\nimport { GrepParamsSchema, type GrepParams } from '../../schemas/grepTool';\nimport {\n type GrepFileSystem,\n type GrepOutputOperations,\n type GrepResult,\n tagGrepResult as tagServiceGrepResult,\n} from '../grepTool';\n\nconst fileSystem: GrepFileSystem = {\n stat: (path) => stat(path),\n readFile: (path) => readFile(path),\n};\n\nconst outputOperations: GrepOutputOperations = {\n maxBytes: DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n};\n\nexport function createHeadlessGrepTool(): DoomHeadlessTool<typeof GrepParamsSchema> {\n return {\n name: 'grep',\n label: 'grep',\n description:\n 'Search file contents using ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Respects .gitignore.',\n promptSnippet: 'Search file contents and return editable hashline anchors',\n parameters: GrepParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: GrepParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => {\n const input = params as GrepParams;\n const result = await runRipgrep(input, context.cwd, signal);\n return tagServiceGrepResult(result, input, context.cwd, signal, isWritableFile, fileSystem, outputOperations);\n },\n };\n}\n\nasync function runRipgrep(params: GrepParams, cwd: string, signal: AbortSignal | undefined): Promise<GrepResult> {\n const target = resolveInputPath(params.path ?? '.', cwd);\n const targetArg = relative(cwd, target) || '.';\n const args = ['--color', 'never', '--no-heading', '--with-filename', '--line-number'];\n if (params.ignoreCase === true) args.push('--ignore-case');\n if (params.literal === true) args.push('--fixed-strings');\n if (params.context !== undefined) args.push('--context', String(params.context));\n if (params.glob !== undefined) args.push('--glob', params.glob);\n args.push('--', params.pattern, targetArg);\n\n const output = await spawnRipgrep(args, cwd, signal);\n if (output.trim() === '') return { content: [{ type: 'text', text: 'No matches found' }] };\n return { content: [{ type: 'text', text: limitMatches(output, params.limit) }] };\n}\n\nfunction limitMatches(output: string, limit: number | undefined): string {\n if (limit === undefined) return output.trimEnd();\n let matches = 0;\n const lines = output.trimEnd().split('\\n');\n const selected: string[] = [];\n for (const line of lines) {\n if (/:(\\d+):/u.test(line)) {\n matches++;\n if (matches > limit) continue;\n }\n selected.push(line);\n }\n return selected.join('\\n');\n}\n\nfunction spawnRipgrep(args: readonly string[], cwd: string, signal: AbortSignal | undefined): Promise<string> {\n return new Promise((resolveOutput, reject) => {\n const child = spawn('rg', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n const abort = (): void => {\n child.kill('SIGTERM');\n reject(new Error('Operation aborted'));\n };\n if (signal?.aborted) {\n abort();\n return;\n }\n signal?.addEventListener('abort', abort, { once: true });\n child.once('error', (error) => {\n signal?.removeEventListener('abort', abort);\n reject(new Error(`Could not start ripgrep: ${error.message}`, { cause: error }));\n });\n child.once('close', (code) => {\n signal?.removeEventListener('abort', abort);\n if (code === 0 || code === 1) {\n resolveOutput(stdout);\n return;\n }\n reject(new Error(stderr.trim() || `ripgrep exited with code ${code ?? 'unknown'}`));\n });\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { GrepParamsSchema } from "../../schemas/grepTool.cjs";
2
+ import { DoomHeadlessTool } from "@agimon-ai/doompi-core/headless";
3
+ //#region src/services/headlessGrep/index.d.ts
4
+ export declare function createHeadlessGrepTool(): DoomHeadlessTool<typeof GrepParamsSchema>;
5
+ //#endregion
6
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/services/headlessGrep/index.ts"],"mappings":";;;wBAgCgB,0BAA0B,wBAAwB"}
@@ -0,0 +1,6 @@
1
+ import { GrepParamsSchema } from "../../schemas/grepTool.mjs";
2
+ import { DoomHeadlessTool } from "@agimon-ai/doompi-core/headless";
3
+ //#region src/services/headlessGrep/index.d.ts
4
+ export declare function createHeadlessGrepTool(): DoomHeadlessTool<typeof GrepParamsSchema>;
5
+ //#endregion
6
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/headlessGrep/index.ts"],"mappings":";;;wBAgCgB,0BAA0B,wBAAwB"}
@@ -0,0 +1,4 @@
1
+ import{GrepParamsSchema as e}from"../../schemas/grepTool.mjs";import{tagGrepResult as t}from"../grepTool/index.mjs";import{readFile as n,stat as r}from"node:fs/promises";import{isWritableFile as i,resolveInputPath as a}from"@agimon-ai/doompi-hashline/files";import{DEFAULT_MAX_BYTES as o,formatSize as s,truncateHead as c,truncateLine as l}from"@earendil-works/pi-coding-agent";import{relative as u}from"node:path";import{spawn as d}from"node:child_process";const f={stat:e=>r(e),readFile:e=>n(e)},p={maxBytes:o,formatSize:s,truncateHead:c,truncateLine:l};function m(){return{name:`grep`,label:`grep`,description:`Search file contents using ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Respects .gitignore.`,promptSnippet:`Search file contents and return editable hashline anchors`,parameters:e,executionMode:`parallel`,execute:async(e,n,r,a,o)=>{let s=n,c=await h(s,o.cwd,r);return t(c,s,o.cwd,r,i,f,p)}}}async function h(e,t,n){let r=a(e.path??`.`,t),i=u(t,r)||`.`,o=[`--color`,`never`,`--no-heading`,`--with-filename`,`--line-number`];e.ignoreCase===!0&&o.push(`--ignore-case`),e.literal===!0&&o.push(`--fixed-strings`),e.context!==void 0&&o.push(`--context`,String(e.context)),e.glob!==void 0&&o.push(`--glob`,e.glob),o.push(`--`,e.pattern,i);let s=await _(o,t,n);return s.trim()===``?{content:[{type:`text`,text:`No matches found`}]}:{content:[{type:`text`,text:g(s,e.limit)}]}}function g(e,t){if(t===void 0)return e.trimEnd();let n=0,r=e.trimEnd().split(`
2
+ `),i=[];for(let e of r)/:(\d+):/u.test(e)&&(n++,n>t)||i.push(e);return i.join(`
3
+ `)}function _(e,t,n){return new Promise((r,i)=>{let a=d(`rg`,e,{cwd:t,stdio:[`ignore`,`pipe`,`pipe`]}),o=``,s=``;a.stdout.on(`data`,e=>{o+=e.toString()}),a.stderr.on(`data`,e=>{s+=e.toString()});let c=()=>{a.kill(`SIGTERM`),i(Error(`Operation aborted`))};if(n?.aborted){c();return}n?.addEventListener(`abort`,c,{once:!0}),a.once(`error`,e=>{n?.removeEventListener(`abort`,c),i(Error(`Could not start ripgrep: ${e.message}`,{cause:e}))}),a.once(`close`,e=>{if(n?.removeEventListener(`abort`,c),e===0||e===1){r(o);return}i(Error(s.trim()||`ripgrep exited with code ${e??`unknown`}`))})})}export{m as createHeadlessGrepTool};
4
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["tagServiceGrepResult"],"sources":["../../../src/services/headlessGrep/index.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { readFile, stat } from 'node:fs/promises';\nimport { relative } from 'node:path';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { resolveInputPath, isWritableFile } from '@agimon-ai/doompi-hashline/files';\nimport { DEFAULT_MAX_BYTES, formatSize, truncateHead, truncateLine } from '@earendil-works/pi-coding-agent';\n\nimport { GrepParamsSchema, type GrepParams } from '../../schemas/grepTool';\nimport {\n type GrepFileSystem,\n type GrepOutputOperations,\n type GrepResult,\n tagGrepResult as tagServiceGrepResult,\n} from '../grepTool';\n\nconst fileSystem: GrepFileSystem = {\n stat: (path) => stat(path),\n readFile: (path) => readFile(path),\n};\n\nconst outputOperations: GrepOutputOperations = {\n maxBytes: DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n};\n\nexport function createHeadlessGrepTool(): DoomHeadlessTool<typeof GrepParamsSchema> {\n return {\n name: 'grep',\n label: 'grep',\n description:\n 'Search file contents using ripgrep semantics, then add exact-byte file tags and stable line anchors for writable matches. Respects .gitignore.',\n promptSnippet: 'Search file contents and return editable hashline anchors',\n parameters: GrepParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: GrepParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => {\n const input = params as GrepParams;\n const result = await runRipgrep(input, context.cwd, signal);\n return tagServiceGrepResult(result, input, context.cwd, signal, isWritableFile, fileSystem, outputOperations);\n },\n };\n}\n\nasync function runRipgrep(params: GrepParams, cwd: string, signal: AbortSignal | undefined): Promise<GrepResult> {\n const target = resolveInputPath(params.path ?? '.', cwd);\n const targetArg = relative(cwd, target) || '.';\n const args = ['--color', 'never', '--no-heading', '--with-filename', '--line-number'];\n if (params.ignoreCase === true) args.push('--ignore-case');\n if (params.literal === true) args.push('--fixed-strings');\n if (params.context !== undefined) args.push('--context', String(params.context));\n if (params.glob !== undefined) args.push('--glob', params.glob);\n args.push('--', params.pattern, targetArg);\n\n const output = await spawnRipgrep(args, cwd, signal);\n if (output.trim() === '') return { content: [{ type: 'text', text: 'No matches found' }] };\n return { content: [{ type: 'text', text: limitMatches(output, params.limit) }] };\n}\n\nfunction limitMatches(output: string, limit: number | undefined): string {\n if (limit === undefined) return output.trimEnd();\n let matches = 0;\n const lines = output.trimEnd().split('\\n');\n const selected: string[] = [];\n for (const line of lines) {\n if (/:(\\d+):/u.test(line)) {\n matches++;\n if (matches > limit) continue;\n }\n selected.push(line);\n }\n return selected.join('\\n');\n}\n\nfunction spawnRipgrep(args: readonly string[], cwd: string, signal: AbortSignal | undefined): Promise<string> {\n return new Promise((resolveOutput, reject) => {\n const child = spawn('rg', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n const abort = (): void => {\n child.kill('SIGTERM');\n reject(new Error('Operation aborted'));\n };\n if (signal?.aborted) {\n abort();\n return;\n }\n signal?.addEventListener('abort', abort, { once: true });\n child.once('error', (error) => {\n signal?.removeEventListener('abort', abort);\n reject(new Error(`Could not start ripgrep: ${error.message}`, { cause: error }));\n });\n child.once('close', (code) => {\n signal?.removeEventListener('abort', abort);\n if (code === 0 || code === 1) {\n resolveOutput(stdout);\n return;\n }\n reject(new Error(stderr.trim() || `ripgrep exited with code ${code ?? 'unknown'}`));\n });\n });\n}\n"],"mappings":"0cAoBA,MAAM,EAA6B,CACjC,KAAO,GAAS,EAAK,CAAI,EACzB,SAAW,GAAS,EAAS,CAAI,CACnC,EAEM,EAAyC,CAC7C,SAAU,EACV,aACA,eACA,cACF,EAEA,SAAgB,GAAoE,CAClF,MAAO,CACL,KAAM,OACN,MAAO,OACP,YACE,iJACF,cAAe,4DACf,WAAY,EACZ,cAAe,WACf,QAAS,MACP,EACA,EACA,EACA,EACA,IACG,CACH,IAAM,EAAQ,EACR,EAAS,MAAM,EAAW,EAAO,EAAQ,IAAK,CAAM,EAC1D,OAAOA,EAAqB,EAAQ,EAAO,EAAQ,IAAK,EAAQ,EAAgB,EAAY,CAAgB,CAC9G,CACF,CACF,CAEA,eAAe,EAAW,EAAoB,EAAa,EAAsD,CAC/G,IAAM,EAAS,EAAiB,EAAO,MAAQ,IAAK,CAAG,EACjD,EAAY,EAAS,EAAK,CAAM,GAAK,IACrC,EAAO,CAAC,UAAW,QAAS,eAAgB,kBAAmB,eAAe,EAChF,EAAO,aAAe,IAAM,EAAK,KAAK,eAAe,EACrD,EAAO,UAAY,IAAM,EAAK,KAAK,iBAAiB,EACpD,EAAO,UAAY,IAAA,IAAW,EAAK,KAAK,YAAa,OAAO,EAAO,OAAO,CAAC,EAC3E,EAAO,OAAS,IAAA,IAAW,EAAK,KAAK,SAAU,EAAO,IAAI,EAC9D,EAAK,KAAK,KAAM,EAAO,QAAS,CAAS,EAEzC,IAAM,EAAS,MAAM,EAAa,EAAM,EAAK,CAAM,EAEnD,OADI,EAAO,KAAK,IAAM,GAAW,CAAE,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,kBAAmB,CAAC,CAAE,EAClF,CAAE,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAa,EAAQ,EAAO,KAAK,CAAE,CAAC,CAAE,CACjF,CAEA,SAAS,EAAa,EAAgB,EAAmC,CACvE,GAAI,IAAU,IAAA,GAAW,OAAO,EAAO,QAAQ,EAC/C,IAAI,EAAU,EACR,EAAQ,EAAO,QAAQ,CAAC,CAAC,MAAM;CAAI,EACnC,EAAqB,CAAC,EAC5B,IAAK,IAAM,KAAQ,EACb,WAAW,KAAK,CAAI,IACtB,IACI,EAAU,IAEhB,EAAS,KAAK,CAAI,EAEpB,OAAO,EAAS,KAAK;CAAI,CAC3B,CAEA,SAAS,EAAa,EAAyB,EAAa,EAAkD,CAC5G,OAAO,IAAI,SAAS,EAAe,IAAW,CAC5C,IAAM,EAAQ,EAAM,KAAM,EAAM,CAAE,MAAK,MAAO,CAAC,SAAU,OAAQ,MAAM,CAAE,CAAC,EACtE,EAAS,GACT,EAAS,GACb,EAAM,OAAO,GAAG,OAAS,GAAkB,CACzC,GAAU,EAAM,SAAS,CAC3B,CAAC,EACD,EAAM,OAAO,GAAG,OAAS,GAAkB,CACzC,GAAU,EAAM,SAAS,CAC3B,CAAC,EACD,IAAM,MAAoB,CACxB,EAAM,KAAK,SAAS,EACpB,EAAW,MAAM,mBAAmB,CAAC,CACvC,EACA,GAAI,GAAQ,QAAS,CACnB,EAAM,EACN,MACF,CACA,GAAQ,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EACvD,EAAM,KAAK,QAAU,GAAU,CAC7B,GAAQ,oBAAoB,QAAS,CAAK,EAC1C,EAAW,MAAM,4BAA4B,EAAM,UAAW,CAAE,MAAO,CAAM,CAAC,CAAC,CACjF,CAAC,EACD,EAAM,KAAK,QAAU,GAAS,CAE5B,GADA,GAAQ,oBAAoB,QAAS,CAAK,EACtC,IAAS,GAAK,IAAS,EAAG,CAC5B,EAAc,CAAM,EACpB,MACF,CACA,EAAW,MAAM,EAAO,KAAK,GAAK,4BAA4B,GAAQ,WAAW,CAAC,CACpF,CAAC,CACH,CAAC,CACH"}
@@ -0,0 +1,2 @@
1
+ const e=require("../schemas/grepTool.cjs"),t=require("../services/grepTool/index.cjs");let n=require("node:fs/promises"),r=require("@agimon-ai/doompi-hashline/files"),i=require("@agimon-ai/doompi-ui/hashlineRendering"),a=require("@earendil-works/pi-coding-agent");const o={stat:e=>(0,n.stat)(e),readFile:e=>(0,n.readFile)(e)},s={maxBytes:a.DEFAULT_MAX_BYTES,formatSize:a.formatSize,truncateHead:a.truncateHead,truncateLine:a.truncateLine};async function c(e,n,i,a,c=r.isWritableFile){return t.tagGrepResult(e,n,i,a,c,o,s)}function l(n=r.isWritableFile){return{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,r,i,o,s){let l=r,u=await(0,a.createGrepToolDefinition)(s.cwd).execute(e,l,i,o,s);return t.assertNotAborted(i),c(u,l,s.cwd,i,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,i.renderHashlineCall)(`grep`,n.pattern,r,t)},renderResult(e,t,n,r){return(0,i.renderHashlineResult)(e,t,n,r,`grep`)}}}exports.createHashlineGrepTool=l,exports.tagGrepResult=c;
2
+ //# sourceMappingURL=piGrep.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piGrep.cjs","names":["stat","readFile","DEFAULT_MAX_BYTES","isWritableFile","tagServiceGrepResult","GrepParamsSchema","createGrepToolDefinition","renderHashlineCall","renderHashlineResult"],"sources":["../../src/tools/piGrep.ts"],"sourcesContent":["import { readFile, stat } from 'node:fs/promises';\n\nimport { isWritableFile } from '@agimon-ai/doompi-hashline/files';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n createGrepToolDefinition,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { GrepParamsSchema, type GrepParams } from '../schemas/grepTool';\nimport {\n assertNotAborted,\n type GrepFileSystem,\n type GrepOutputOperations,\n type GrepResult,\n tagGrepResult as tagServiceGrepResult,\n} from '../services/grepTool';\n\nconst fileSystem: GrepFileSystem = {\n stat: (path) => stat(path),\n readFile: (path) => readFile(path),\n};\n\nconst outputOperations: GrepOutputOperations = {\n maxBytes: DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n};\n\nexport async function tagGrepResult(\n nativeResult: GrepResult,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: WritableCheck = isWritableFile,\n): Promise<GrepResult> {\n return tagServiceGrepResult(nativeResult, params, cwd, signal, writable, fileSystem, outputOperations);\n}\n\nexport { groupGrepRows, parseGrepRow } from '../services/grepTool';\nexport type { GrepGroup, GrepRow } from '../services/grepTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\n/** Register only the snapshot-bound replacement for Pi's grep tool. */\nexport function createHashlineGrepTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof GrepParamsSchema> {\n return {\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(\n nativeResult as GrepResult,\n input,\n ctx.cwd,\n signal,\n writable,\n ) as unknown as AgentToolResult<unknown>;\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"],"mappings":"wQAuBA,MAAM,EAA6B,CACjC,KAAO,IAAA,EAASA,EAAAA,KAAAA,CAAK,CAAI,EACzB,SAAW,IAAA,EAASC,EAAAA,SAAAA,CAAS,CAAI,CACnC,EAEM,EAAyC,CAC7C,SAAUC,EAAAA,kBACV,WAAA,EAAA,WACA,aAAA,EAAA,aACA,aAAA,EAAA,YACF,EAEA,eAAsB,EACpB,EACA,EACA,EACA,EACA,EAA0BC,EAAAA,eACL,CACrB,OAAOC,EAAAA,cAAqB,EAAc,EAAQ,EAAK,EAAQ,EAAU,EAAY,CAAgB,CACvG,CAQA,SAAgB,EACd,EAA0BD,EAAAA,eACe,CACzC,MAAO,CACL,KAAM,OACN,MAAO,OACP,YACE,6MACF,cAAe,4DACf,WAAYE,EAAAA,iBACZ,cAAe,WACf,YAAa,OACb,MAAM,QAAQ,EAAY,EAAQ,EAAQ,EAAU,EAAK,CACvD,IAAM,EAAQ,EAER,EAAe,MAAA,EADFC,EAAAA,yBAAAA,CAAyB,EAAI,GACZ,CAAC,CAAC,QAAQ,EAAY,EAAO,EAAQ,EAAU,CAAG,EAEtF,OADA,EAAA,iBAAiB,CAAM,EAChB,EACL,EACA,EACA,EAAI,IACJ,EACA,CACF,CACF,EACA,WAAW,EAAM,EAAO,CACtB,IAAM,EAAQ,EACR,EAAU,CACd,EAAM,MAAQ,IACd,EAAM,KACN,EAAM,aAAe,GAAO,cAAgB,IAAA,GAC5C,EAAM,QAAU,IAAA,GAAY,IAAA,GAAY,GAAG,EAAM,MAAM,SACzD,CAAC,CAAC,OAAQ,GAA2B,IAAU,IAAA,EAAS,EACxD,OAAA,EAAOC,EAAAA,mBAAAA,CAAmB,OAAQ,EAAM,QAAS,EAAS,CAAK,CACjE,EACA,aAAa,EAAQ,EAAS,EAAO,EAAS,CAC5C,OAAA,EAAOC,EAAAA,qBAAAA,CAAqB,EAAQ,EAAS,EAAO,EAAS,MAAM,CACrE,CACF,CACF"}
@@ -0,0 +1,9 @@
1
+ import { GrepParamsSchema } from "../schemas/grepTool.cjs";
2
+ import "../services/grepTool/index.cjs";
3
+ import { ToolDefinition } from "@earendil-works/pi-coding-agent";
4
+ //#region src/tools/piGrep.d.ts
5
+ type WritableCheck = (path: string) => Promise<boolean>;
6
+ /** Register only the snapshot-bound replacement for Pi's grep tool. */
7
+ export declare function createHashlineGrepTool(writable?: WritableCheck): ToolDefinition<typeof GrepParamsSchema>;
8
+ //#endregion
9
+ //# sourceMappingURL=piGrep.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piGrep.d.cts","names":[],"sources":["../../src/tools/piGrep.ts"],"mappings":";;;;KAgDK,iBAAiB,iBAAiB;;wBAGvB,uBACd,WAAU,gBACT,sBAAsB"}
@@ -0,0 +1,9 @@
1
+ import { GrepParamsSchema } from "../schemas/grepTool.mjs";
2
+ import "../services/grepTool/index.mjs";
3
+ import { ToolDefinition } from "@earendil-works/pi-coding-agent";
4
+ //#region src/tools/piGrep.d.ts
5
+ type WritableCheck = (path: string) => Promise<boolean>;
6
+ /** Register only the snapshot-bound replacement for Pi's grep tool. */
7
+ export declare function createHashlineGrepTool(writable?: WritableCheck): ToolDefinition<typeof GrepParamsSchema>;
8
+ //#endregion
9
+ //# sourceMappingURL=piGrep.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piGrep.d.mts","names":[],"sources":["../../src/tools/piGrep.ts"],"mappings":";;;;KAgDK,iBAAiB,iBAAiB;;wBAGvB,uBACd,WAAU,gBACT,sBAAsB"}
@@ -0,0 +1,2 @@
1
+ import{GrepParamsSchema as e}from"../schemas/grepTool.mjs";import{assertNotAborted as t,tagGrepResult as n}from"../services/grepTool/index.mjs";import{readFile as r,stat as i}from"node:fs/promises";import{isWritableFile as a}from"@agimon-ai/doompi-hashline/files";import{renderHashlineCall as o,renderHashlineResult as s}from"@agimon-ai/doompi-ui/hashlineRendering";import{DEFAULT_MAX_BYTES as c,createGrepToolDefinition as l,formatSize as u,truncateHead as d,truncateLine as f}from"@earendil-works/pi-coding-agent";const p={stat:e=>i(e),readFile:e=>r(e)},m={maxBytes:c,formatSize:u,truncateHead:d,truncateLine:f};async function h(e,t,r,i,o=a){return n(e,t,r,i,o,p,m)}function g(n=a){return{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,r,i,a,o){let s=r,c=await l(o.cwd).execute(e,s,i,a,o);return t(i),h(c,s,o.cwd,i,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 o(`grep`,n.pattern,r,t)},renderResult(e,t,n,r){return s(e,t,n,r,`grep`)}}}export{g as createHashlineGrepTool,h as tagGrepResult};
2
+ //# sourceMappingURL=piGrep.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piGrep.mjs","names":["tagServiceGrepResult"],"sources":["../../src/tools/piGrep.ts"],"sourcesContent":["import { readFile, stat } from 'node:fs/promises';\n\nimport { isWritableFile } from '@agimon-ai/doompi-hashline/files';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n createGrepToolDefinition,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { GrepParamsSchema, type GrepParams } from '../schemas/grepTool';\nimport {\n assertNotAborted,\n type GrepFileSystem,\n type GrepOutputOperations,\n type GrepResult,\n tagGrepResult as tagServiceGrepResult,\n} from '../services/grepTool';\n\nconst fileSystem: GrepFileSystem = {\n stat: (path) => stat(path),\n readFile: (path) => readFile(path),\n};\n\nconst outputOperations: GrepOutputOperations = {\n maxBytes: DEFAULT_MAX_BYTES,\n formatSize,\n truncateHead,\n truncateLine,\n};\n\nexport async function tagGrepResult(\n nativeResult: GrepResult,\n params: GrepParams,\n cwd: string,\n signal: AbortSignal | undefined,\n writable: WritableCheck = isWritableFile,\n): Promise<GrepResult> {\n return tagServiceGrepResult(nativeResult, params, cwd, signal, writable, fileSystem, outputOperations);\n}\n\nexport { groupGrepRows, parseGrepRow } from '../services/grepTool';\nexport type { GrepGroup, GrepRow } from '../services/grepTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\n/** Register only the snapshot-bound replacement for Pi's grep tool. */\nexport function createHashlineGrepTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof GrepParamsSchema> {\n return {\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(\n nativeResult as GrepResult,\n input,\n ctx.cwd,\n signal,\n writable,\n ) as unknown as AgentToolResult<unknown>;\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"],"mappings":"ogBAuBA,MAAM,EAA6B,CACjC,KAAO,GAAS,EAAK,CAAI,EACzB,SAAW,GAAS,EAAS,CAAI,CACnC,EAEM,EAAyC,CAC7C,SAAU,EACV,aACA,eACA,cACF,EAEA,eAAsB,EACpB,EACA,EACA,EACA,EACA,EAA0B,EACL,CACrB,OAAOA,EAAqB,EAAc,EAAQ,EAAK,EAAQ,EAAU,EAAY,CAAgB,CACvG,CAQA,SAAgB,EACd,EAA0B,EACe,CACzC,MAAO,CACL,KAAM,OACN,MAAO,OACP,YACE,6MACF,cAAe,4DACf,WAAY,EACZ,cAAe,WACf,YAAa,OACb,MAAM,QAAQ,EAAY,EAAQ,EAAQ,EAAU,EAAK,CACvD,IAAM,EAAQ,EAER,EAAe,MADF,EAAyB,EAAI,GACZ,CAAC,CAAC,QAAQ,EAAY,EAAO,EAAQ,EAAU,CAAG,EAEtF,OADA,EAAiB,CAAM,EAChB,EACL,EACA,EACA,EAAI,IACJ,EACA,CACF,CACF,EACA,WAAW,EAAM,EAAO,CACtB,IAAM,EAAQ,EACR,EAAU,CACd,EAAM,MAAQ,IACd,EAAM,KACN,EAAM,aAAe,GAAO,cAAgB,IAAA,GAC5C,EAAM,QAAU,IAAA,GAAY,IAAA,GAAY,GAAG,EAAM,MAAM,SACzD,CAAC,CAAC,OAAQ,GAA2B,IAAU,IAAA,EAAS,EACxD,OAAO,EAAmB,OAAQ,EAAM,QAAS,EAAS,CAAK,CACjE,EACA,aAAa,EAAQ,EAAS,EAAO,EAAS,CAC5C,OAAO,EAAqB,EAAQ,EAAS,EAAO,EAAS,MAAM,CACrE,CACF,CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-grep",
3
- "version": "0.0.1-alpha.41",
3
+ "version": "0.0.1-alpha.43",
4
4
  "description": "Snapshot-bound hashline grep for Pi and DoomPi.",
5
5
  "keywords": [
6
6
  "ai",
@@ -27,7 +27,7 @@
27
27
  "files": [
28
28
  "dist",
29
29
  "src/web",
30
- "src/exports/webClient.ts",
30
+ "src/extensions/web.ts",
31
31
  "!src/web/**/*.stories.tsx"
32
32
  ],
33
33
  "type": "module",
@@ -45,6 +45,11 @@
45
45
  "import": "./dist/extensions/pi.mjs",
46
46
  "require": "./dist/extensions/pi.cjs"
47
47
  },
48
+ "./extensions/server": {
49
+ "types": "./dist/extensions/server.d.mts",
50
+ "import": "./dist/extensions/server.mjs",
51
+ "require": "./dist/extensions/server.cjs"
52
+ },
48
53
  "./package.json": "./package.json"
49
54
  },
50
55
  "publishConfig": {
@@ -53,11 +58,10 @@
53
58
  "dependencies": {
54
59
  "@deepseek-ai/cordis": "4.0.2",
55
60
  "typebox": "1.3.25",
56
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.68",
57
- "@agimon-ai/doompi-hashline": "0.0.1-alpha.39",
58
- "@agimon-ai/doompi-ui": "0.0.1-alpha.69",
59
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.28",
60
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.31"
61
+ "@agimon-ai/doompi-core": "0.0.1-alpha.71",
62
+ "@agimon-ai/doompi-hashline": "0.0.1-alpha.40",
63
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.71",
64
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.29"
61
65
  },
62
66
  "devDependencies": {
63
67
  "@earendil-works/pi-coding-agent": "0.85.1",
@@ -89,10 +93,24 @@
89
93
  "engines": {
90
94
  "node": ">=22.19.0"
91
95
  },
96
+ "doompiServer": {
97
+ "entry": "./src/extensions/server.ts",
98
+ "dist": "./dist/extensions/server.mjs",
99
+ "scopes": [
100
+ "session"
101
+ ],
102
+ "contracts": {
103
+ "entry": "./src/exports/apiContracts.ts",
104
+ "dist": "./dist/api-contracts.mjs"
105
+ }
106
+ },
92
107
  "doompiWeb": {
93
108
  "pluginId": "grep",
94
109
  "channels": [],
95
- "client": "./src/exports/webClient.ts"
110
+ "client": "./src/extensions/web.ts",
111
+ "scopes": [
112
+ "session"
113
+ ]
96
114
  },
97
115
  "pi": {
98
116
  "extensions": [
@@ -0,0 +1,14 @@
1
+ import { defineWebPlugin } from '@agimon-ai/doompi-core/web';
2
+
3
+ import { GrepToolMessage } from '../web/components/GrepToolMessage';
4
+
5
+ /**
6
+ * This package's cockpit presence: the grep tool's timeline card, the web
7
+ * half of the TUI's renderCall and renderResult for hashline searches.
8
+ */
9
+ export const webPlugin = defineWebPlugin({
10
+ id: 'grep',
11
+ session: {
12
+ toolRenderers: [{ tools: ['grep'], message: GrepToolMessage }],
13
+ },
14
+ });
@@ -1,3 +1,4 @@
1
+ import type { ToolMessageRenderProps } from '@agimon-ai/doompi-core/web';
1
2
  import {
2
3
  HashlineLines,
3
4
  hashlineBody,
@@ -8,8 +9,8 @@ import {
8
9
  resultTextLines,
9
10
  toolTone,
10
11
  } from '@agimon-ai/doompi-web-components';
11
- import type { ToolMessageRenderProps } from '@agimon-ai/doompi-web-contracts';
12
- import { grepCallView } from '../lib/grepToolView.ts';
12
+
13
+ import { grepCallView } from '../lib/grepToolView';
13
14
 
14
15
  /**
15
16
  * The grep tool's timeline item, the web half of its renderCall and
@@ -19,5 +19,5 @@
19
19
  "forceConsistentCasingInFileNames": true,
20
20
  "types": ["node"]
21
21
  },
22
- "include": [".", "../types", "../exports/webClient.ts"]
22
+ "include": [".", "../types", "../extensions/web.ts"]
23
23
  }
@@ -1,2 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,10 +0,0 @@
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
- export declare function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void;
6
- /** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
7
- export declare function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void>;
8
- //#endregion
9
- export { activateDoomPiGrepExtension as default };
10
- //# sourceMappingURL=extension.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;wBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;wBAkBxC,4BAA4B,IAAI,eAAe"}
@@ -1,10 +0,0 @@
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
- export declare function installDoomPiGrepRuntime(cordis: Context, pi: ExtensionAPI): void;
6
- /** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
7
- export declare function activateDoomPiGrepExtension(pi: ExtensionAPI): Promise<void>;
8
- //#endregion
9
- export { activateDoomPiGrepExtension as default };
10
- //# sourceMappingURL=extension.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;wBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;wBAkBxC,4BAA4B,IAAI,eAAe"}
@@ -1,2 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,10 +0,0 @@
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
@@ -1 +0,0 @@
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":"8RAsBA,MAAM,EAAkB,aAClB,EAAoB,aAoB1B,SAAgB,EACd,EACA,EAA0BA,EAAAA,eACpB,CACN,EAAG,aAAa,CACd,KAAM,OACN,MAAO,OACP,YACE,6MACF,cAAe,4DACf,WAAYC,EAAAA,iBACZ,cAAe,WACf,YAAa,OACb,MAAM,QAAQ,EAAY,EAAQ,EAAQ,EAAU,EAAK,CACvD,IAAM,EAAQ,EAER,EAAe,MAAA,EADFC,EAAAA,yBAAAA,CAAyB,EAAI,GACZ,CAAC,CAAC,QAAQ,EAAY,EAAO,EAAQ,EAAU,CAAG,EAEtF,OADA,EAAiB,CAAM,EAChB,EAAc,EAAc,EAAO,EAAI,IAAK,EAAQ,CAAQ,CACrE,EACA,WAAW,EAAM,EAAO,CACtB,IAAM,EAAQ,EACR,EAAU,CACd,EAAM,MAAQ,IACd,EAAM,KACN,EAAM,aAAe,GAAO,cAAgB,IAAA,GAC5C,EAAM,QAAU,IAAA,GAAY,IAAA,GAAY,GAAG,EAAM,MAAM,SACzD,CAAC,CAAC,OAAQ,GAA2B,IAAU,IAAA,EAAS,EACxD,OAAA,EAAOC,EAAAA,mBAAAA,CAAmB,OAAQ,EAAM,QAAS,EAAS,CAAK,CACjE,EACA,aAAa,EAAQ,EAAS,EAAO,EAAS,CAC5C,OAAA,EAAOC,EAAAA,qBAAAA,CAAqB,EAAQ,EAAS,EAAO,EAAS,MAAM,CACrE,CACF,CAAC,CACH,CAEA,eAAsB,EACpB,EACA,EACA,EACA,EACA,EAA0BJ,EAAAA,eACI,CAC9B,IAAM,EAAW,EAAa,QAAQ,KAAM,GAAS,EAAK,OAAS,MAAM,EACzE,GAAI,CAAC,GAAY,EAAS,OAAS,mBAAY,OAAO,EAEtD,IAAM,EAAc,EAAS,KAAK,YAAY;;EAAO,EAC/C,EAAW,IAAgB,GAAK,EAAS,KAAO,EAAS,KAAK,MAAM,EAAG,CAAW,EAClF,EAAS,IAAgB,GAAK,GAAK,EAAS,KAAK,MAAM,CAAW,EAClE,GAAA,EAAaK,EAAAA,iBAAAA,CAAiB,EAAO,MAAQ,IAAK,CAAG,EACrD,EAAc,MAAA,EAAMC,EAAAA,KAAAA,CAAK,CAAU,EACzC,EAAiB,CAAM,EACvB,IAAM,EAAO,MAAM,EAAuB,EAAU,EAAY,EAAY,YAAY,EAAG,CAAM,EACjG,GAAI,EAAK,SAAW,EAAG,OAAO,EAE9B,IAAM,EAAS,EAAc,EAAM,EAAY,EAAY,YAAY,EAAG,CAAG,EACvE,EAAmB,CAAC,EACtB,EAAc,EACd,EAAiB,EAAa,SAAS,gBAAkB,GAE7D,IAAK,IAAM,KAAS,EAAO,OAAO,EAAG,CACnC,EAAiB,CAAM,EACvB,IAAM,EAAU,MAAM,EAAS,EAAM,YAAY,EAEjD,GADA,EAAiB,CAAM,EACnB,CAAC,EAAS,CACZ,EAAO,KAAK,EAAM,WAAW,KAAK;CAAI,CAAC,EACvC,QACF,CACA,IAAI,EACJ,GAAI,CACF,EAAQ,MAAA,EAAMC,EAAAA,SAAAA,CAAS,EAAM,YAAY,CAC3C,MAAQ,CACN,EAAO,KAAK,EAAM,WAAW,KAAK;CAAI,CAAC,EACvC,QACF,CACA,EAAiB,CAAM,EACvB,IAAM,GAAA,EAAQC,EAAAA,WAAAA,EAAAA,EAAWC,EAAAA,WAAAA,CAAW,EAAO,EAAM,IAAI,CAAC,EAChD,EAAS,EAAA,EAACC,EAAAA,iBAAAA,CAAiB,EAAM,MAAA,EAAMC,EAAAA,eAAAA,CAAe,CAAK,CAAC,CAAC,EACnE,IAAK,GAAM,CAAC,EAAY,IAAY,CAAC,GAAG,EAAM,IAAI,CAAC,CAAC,MAAM,CAAC,GAAO,CAAC,KAAW,EAAO,CAAK,EAAG,CAC3F,IAAM,EAAO,EAAM,EAAa,GAChC,GAAI,IAAS,IAAA,GAAW,SACxB,IAAM,GAAA,EAAUC,EAAAA,aAAAA,CAAa,CAAI,EAC7B,EAAQ,eAAc,EAAiB,IAC3C,EAAO,MAAA,EAAKC,EAAAA,iBAAAA,CAAiB,EAAQ,KAAM,EAAY,EAAU,MAAQ,MAAO,CAAI,CAAC,CACvF,CACI,EAAO,OAAS,GAClB,EAAO,KAAK,EAAO,KAAK;CAAI,CAAC,EAC7B,KAEA,EAAO,KAAK,EAAM,WAAW,KAAK;CAAI,CAAC,CAE3C,CAEA,GAAI,EAAO,SAAW,GAAK,IAAgB,EAAG,OAAO,EACrD,IAAM,GAAA,EAAaC,EAAAA,aAAAA,CAAa,EAAO,KAAK;CAAI,EAAG,CAAE,gBAAkC,CAAC,EAClF,EAAc,EAAW,UAAY,SAAA,EAAQC,EAAAA,WAAAA,CAAWC,EAAAA,iBAAiB,EAAE,+BAAiC,GAC5G,EAA2B,CAC/B,GAAG,EAAa,QAChB,GAAI,EAAW,UAAY,CAAE,YAAW,EAAI,CAAC,EAC7C,GAAI,EAAiB,CAAE,eAAgB,EAAK,EAAI,CAAC,CACnD,EAEA,OADA,EAAiB,CAAM,EAChB,CACL,GAAG,EACH,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,GAAG,EAAW,UAAU,IAAS,GAAc,CAAC,EAChF,QAAS,OAAO,KAAK,CAAO,CAAC,CAAC,OAAS,EAAI,EAAU,IAAA,EACvD,CACF,CAQA,eAAe,EACb,EACA,EACA,EACA,EACoB,CACpB,IAAM,EAAY,IAAI,IAChB,EAAkB,CAAC,EACzB,IAAK,IAAM,KAAS,EAAS,MAAM;CAAI,EAAG,CACxC,EAAiB,CAAM,EACvB,IAAI,EACJ,IAAK,IAAM,KAAa,EAAkB,CAAK,EAAG,CAChD,GAAI,CAAC,EAAW,CACd,GAAI,EAAU,QAAA,EAASC,EAAAA,SAAAA,CAAS,CAAU,EAAG,CAC3C,EAAK,KAAK,CAAE,GAAG,EAAW,OAAQ,CAAM,CAAC,EACzC,KACF,CACA,QACF,CACA,IAAM,GAAA,EAAeC,EAAAA,QAAAA,CAAQ,EAAY,EAAU,IAAI,EACnD,EAAS,EAAU,IAAI,CAAY,EACnC,IAAW,IAAA,KACb,EAAS,MAAA,EAAMZ,EAAAA,KAAAA,CAAK,CAAY,CAAC,CAC9B,KAAM,GAAU,EAAM,OAAO,CAAC,CAAC,CAC/B,UAAY,EAAK,EACpB,EAAiB,CAAM,EACvB,EAAU,IAAI,EAAc,CAAM,GAEhC,IAGF,EAAoB,CAAE,GAAG,EAAW,OAAQ,CAAM,EAEtD,CACI,GAAmB,EAAK,KAAK,CAAiB,CACpD,CACA,OAAO,CACT,CAEA,SAAS,EAAkB,EAA0B,CACnD,IAAM,EAAuE,CAAC,EAC9E,IAAK,IAAM,KAAS,EAAM,SAAS,CAAe,EAChD,EAAW,KAAK,CACd,MAAO,EAAM,MACb,IAAK,CAAE,KAAM,EAAM,MAAM,EAAG,EAAM,KAAK,EAAG,KAAM,OAAO,SAAS,EAAM,IAAM,GAAI,EAAE,EAAG,MAAO,EAAK,CACnG,CAAC,EAEH,IAAK,IAAM,KAAS,EAAM,SAAS,CAAiB,EAClD,EAAW,KAAK,CACd,MAAO,EAAM,MACb,IAAK,CAAE,KAAM,EAAM,MAAM,EAAG,EAAM,KAAK,EAAG,KAAM,OAAO,SAAS,EAAM,IAAM,GAAI,EAAE,EAAG,MAAO,EAAM,CACpG,CAAC,EAEH,OAAO,EAAW,MAAM,EAAM,IAAU,EAAK,MAAQ,EAAM,KAAK,CAAC,CAAC,KAAK,CAAE,SAAU,CAAG,CACxF,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACwB,CACxB,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAe,GAAA,EAAYY,EAAAA,QAAAA,CAAQ,EAAY,EAAI,IAAI,EAAI,EAC7D,EAAQ,EAAO,IAAI,CAAY,EAC9B,IACH,EAAQ,CAAE,MAAA,EAAMC,EAAAA,YAAAA,CAAY,EAAc,CAAG,EAAG,eAAc,WAAY,CAAC,EAAG,KAAM,IAAI,GAAM,EAC9F,EAAO,IAAI,EAAc,CAAK,GAE5B,EAAI,SAAW,IAAA,IAAW,EAAM,WAAW,KAAK,EAAI,MAAM,EAC9D,EAAM,KAAK,IAAI,EAAI,KAAM,EAAI,OAAS,EAAM,KAAK,IAAI,EAAI,IAAI,IAAM,EAAI,CACzE,CACA,OAAO,CACT,CAEA,SAAS,EAAiB,EAAuC,CAC/D,GAAI,GAAQ,QAAS,MAAU,MAAM,mBAAmB,CAC1D"}
@@ -1,8 +0,0 @@
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
- export declare function registerHashlineGrepTool(pi: Pick<ExtensionAPI, 'registerTool'>, writable?: WritableCheck): void;
7
- //#endregion
8
- //# sourceMappingURL=grepTool.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"grepTool.d.cts","names":[],"sources":["../../../src/adapters/pi/grepTool.ts"],"mappings":";;;KAwCK,iBAAiB,iBAAiB;;wBAGvB,yBACd,IAAI,KAAK,+BACT,WAAU"}
@@ -1,8 +0,0 @@
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
- export declare function registerHashlineGrepTool(pi: Pick<ExtensionAPI, 'registerTool'>, writable?: WritableCheck): void;
7
- //#endregion
8
- //# sourceMappingURL=grepTool.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"grepTool.d.mts","names":[],"sources":["../../../src/adapters/pi/grepTool.ts"],"mappings":";;;KAwCK,iBAAiB,iBAAiB;;wBAGvB,yBACd,IAAI,KAAK,+BACT,WAAU"}
@@ -1,10 +0,0 @@
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
@@ -1 +0,0 @@
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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"}
@@ -1 +0,0 @@
1
- export { webPlugin } from '../web/index.ts';
package/src/web/index.ts DELETED
@@ -1,11 +0,0 @@
1
- import { defineWebPlugin } from '@agimon-ai/doompi-web-contracts';
2
- import { GrepToolMessage } from './components/GrepToolMessage.tsx';
3
-
4
- /**
5
- * This package's cockpit presence: the grep tool's timeline card, the web
6
- * half of the TUI's renderCall and renderResult for hashline searches.
7
- */
8
- export const webPlugin = defineWebPlugin({
9
- id: 'grep',
10
- toolRenderers: [{ tools: ['grep'], message: GrepToolMessage }],
11
- });