@hold-rein/plugins-code 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/plugin-id.d.ts +2 -0
  2. package/dist/plugin-id.d.ts.map +1 -0
  3. package/dist/server/tools/file-tools/delete-file-tool.d.ts +4 -0
  4. package/dist/server/tools/file-tools/delete-file-tool.d.ts.map +1 -0
  5. package/dist/server/tools/file-tools/edit-file-tool.d.ts +4 -0
  6. package/dist/server/tools/file-tools/edit-file-tool.d.ts.map +1 -0
  7. package/dist/server/tools/file-tools/find-files-tool.d.ts +4 -0
  8. package/dist/server/tools/file-tools/find-files-tool.d.ts.map +1 -0
  9. package/dist/server/tools/file-tools/grep-files-tool.d.ts +4 -0
  10. package/dist/server/tools/file-tools/grep-files-tool.d.ts.map +1 -0
  11. package/dist/server/tools/file-tools/index.d.ts +7 -0
  12. package/dist/server/tools/file-tools/index.d.ts.map +1 -0
  13. package/dist/server/tools/file-tools/path-utils.d.ts +3 -0
  14. package/dist/server/tools/file-tools/path-utils.d.ts.map +1 -0
  15. package/dist/server/tools/file-tools/read-file-tool.d.ts +4 -0
  16. package/dist/server/tools/file-tools/read-file-tool.d.ts.map +1 -0
  17. package/dist/server/tools/file-tools/truncate.d.ts +6 -0
  18. package/dist/server/tools/file-tools/truncate.d.ts.map +1 -0
  19. package/dist/server/tools/file-tools/write-file-tool.d.ts +4 -0
  20. package/dist/server/tools/file-tools/write-file-tool.d.ts.map +1 -0
  21. package/dist/server/tools/index.d.ts +2 -0
  22. package/dist/server/tools/index.d.ts.map +1 -0
  23. package/dist/server.cjs +18 -0
  24. package/dist/server.cjs.map +1 -0
  25. package/dist/server.d.ts +4 -0
  26. package/dist/server.d.ts.map +1 -0
  27. package/dist/server.js +465 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/style.css +1 -0
  30. package/dist/web/tools/file-tools/code-preview.d.ts +13 -0
  31. package/dist/web/tools/file-tools/code-preview.d.ts.map +1 -0
  32. package/dist/web/tools/file-tools/index.d.ts +15 -0
  33. package/dist/web/tools/file-tools/index.d.ts.map +1 -0
  34. package/dist/web/tools/file-tools/language.d.ts +2 -0
  35. package/dist/web/tools/file-tools/language.d.ts.map +1 -0
  36. package/dist/web/tools/file-tools/utils.d.ts +7 -0
  37. package/dist/web/tools/file-tools/utils.d.ts.map +1 -0
  38. package/dist/web/tools/index.d.ts +2 -0
  39. package/dist/web/tools/index.d.ts.map +1 -0
  40. package/dist/web/turn-footers/file-change-summary/index.d.ts +22 -0
  41. package/dist/web/turn-footers/file-change-summary/index.d.ts.map +1 -0
  42. package/dist/web/turn-footers/index.d.ts +2 -0
  43. package/dist/web/turn-footers/index.d.ts.map +1 -0
  44. package/dist/web.d.ts +4 -0
  45. package/dist/web.d.ts.map +1 -0
  46. package/dist/web.umd.cjs +9 -0
  47. package/dist/web.umd.cjs.map +1 -0
  48. package/package.json +60 -0
@@ -0,0 +1,2 @@
1
+ export declare const PLUGIN_ID = "__code__plugin";
2
+ //# sourceMappingURL=plugin-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-id.d.ts","sourceRoot":"","sources":["../src/plugin-id.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createDeleteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=delete-file-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-file-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/delete-file-tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAU7D,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CA+B/E"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createEditFileTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=edit-file-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/edit-file-tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAyC7D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CAiD7E"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createFindFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=find-files-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-files-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/find-files-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAuB7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CAgC9E"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createGrepFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=grep-files-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grep-files-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/grep-files-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AA4B7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CA+B9E"}
@@ -0,0 +1,7 @@
1
+ export { createDeleteFileTool } from "./delete-file-tool";
2
+ export { createEditFileTool } from "./edit-file-tool";
3
+ export { createFindFilesTool } from "./find-files-tool";
4
+ export { createGrepFilesTool } from "./grep-files-tool";
5
+ export { createReadFileTool } from "./read-file-tool";
6
+ export { createWriteFileTool } from "./write-file-tool";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function resolveToolPath(cwd: string, filePath: string): string;
2
+ export declare function normalizeTextLineEndings(text: string): string;
3
+ //# sourceMappingURL=path-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/path-utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createReadFileTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=read-file-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-file-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/read-file-tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAe7D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CAuC7E"}
@@ -0,0 +1,6 @@
1
+ export declare const DEFAULT_MAX_OUTPUT_LENGTH = 20000;
2
+ export declare function truncateText(text: string, maxLength?: number): {
3
+ text: string;
4
+ truncated: boolean;
5
+ };
6
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/truncate.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,SAA4B,GACpC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAStC"}
@@ -0,0 +1,4 @@
1
+ import type { ExecutionEnv } from "@earendil-works/pi-agent-core";
2
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
3
+ export declare function createWriteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool;
4
+ //# sourceMappingURL=write-file-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-file-tool.d.ts","sourceRoot":"","sources":["../../../../src/server/tools/file-tools/write-file-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAW7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAAC,UAAU,CAuC9E"}
@@ -0,0 +1,2 @@
1
+ export { createDeleteFileTool, createEditFileTool, createFindFilesTool, createGrepFilesTool, createReadFileTool, createWriteFileTool } from "./file-tools";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";const f=require("node:fs/promises"),a=require("@earendil-works/pi-ai"),u=require("node:path"),R=require("node:child_process");function w(e,n){return u.isAbsolute(n)?n:u.resolve(e,n)}function g(e){return e.replace(/\r\n/g,`
2
+ `).replace(/\r/g,`
3
+ `)}const I=a.Type.Object({path:a.Type.String({description:"Path to the file to delete."})});function C(e){return{name:"delete_file",label:"Delete File",description:"Delete a file from the workspace.",parameters:I,beforeExecute({event:n,requestApproval:o}){const t=n.input;return o(`Allowed to delete file: ${t.path??""}`)},async execute(n,o,t){const r=o;v(t);const i=w(e.cwd,r.path);return await f.unlink(i),v(t),{content:[{type:"text",text:`Successfully deleted ${r.path}.`}],details:{path:i}}}}}function v(e){if(e!=null&&e.aborted)throw new Error("Operation aborted")}const A=a.Type.Object({oldText:a.Type.String({description:"Exact original text. It must occur exactly once in the original file."}),newText:a.Type.String({description:"Replacement text."})}),D=a.Type.Object({path:a.Type.String({description:"Path to the file to edit."}),oldText:a.Type.Optional(a.Type.String({description:"Legacy single replacement original text."})),newText:a.Type.Optional(a.Type.String({description:"Legacy single replacement text."})),edits:a.Type.Optional(a.Type.Array(A,{description:"One or more exact text replacements matched against the original file."}))});function j(e){return{name:"edit_file",label:"Edit File",description:"Edit a file by replacing unique original text blocks. Returns only changed blocks and a compact diff.",parameters:D,beforeExecute({event:n,requestApproval:o}){const t=n.input;return o(`Allowed to edit file: ${t.path??""}`)},async execute(n,o,t){const r=o,i=M(r);T(t);const c=w(e.cwd,r.path),s=await f.readFile(c,"utf8");T(t);const l=s.includes(`\r
4
+ `)?`\r
5
+ `:`
6
+ `,d=g(s),h=N(d,i,r.path),m=k(d,h);T(t),await f.writeFile(c,B(m,l),"utf8"),T(t);const x=q(i);return{content:[{type:"text",text:[`Successfully replaced ${i.length} block(s) in ${r.path}.`,"",x].join(`
7
+ `)}],details:{path:c,replacements:i,diff:x}}}}}function M(e){const n=Array.isArray(e.edits)?[...e.edits]:[];if(typeof e.oldText=="string"&&typeof e.newText=="string"&&n.push({oldText:e.oldText,newText:e.newText}),n.length===0)throw new Error("edit_file requires oldText/newText or at least one edits entry.");return n.map((o,t)=>{if(!o.oldText)throw new Error(`edits[${t}].oldText must not be empty.`);return{oldText:g(o.oldText),newText:g(o.newText)}})}function N(e,n,o){const t=n.map((r,i)=>{const c=U(e,r.oldText);if(c.length===0)throw new Error(`Could not find edits[${i}] in ${o}. The oldText must match exactly.`);if(c.length>1)throw new Error(`Found ${c.length} occurrences of edits[${i}] in ${o}. Each oldText must be unique.`);const s=c[0];if(s===void 0)throw new Error(`Could not find edits[${i}] in ${o}.`);return{...r,index:s}});t.sort((r,i)=>r.index-i.index);for(let r=1;r<t.length;r++){const i=t[r-1],c=t[r];if(!(!i||!c)&&i.index+i.oldText.length>c.index)throw new Error("edit_file replacements must not overlap.")}return t}function U(e,n){const o=[];let t=e.indexOf(n);for(;t!==-1;)o.push(t),t=e.indexOf(n,t+n.length);return o}function k(e,n){let o=e;for(const t of[...n].reverse())o=o.slice(0,t.index)+t.newText+o.slice(t.index+t.oldText.length);if(o===e)throw new Error("No changes made. The replacements produced identical content.");return o}function q(e){return e.map((n,o)=>[`@@ replacement ${o+1} @@`,...n.oldText.split(`
8
+ `).map(t=>`-${t}`),...n.newText.split(`
9
+ `).map(t=>`+${t}`)].join(`
10
+ `)).join(`
11
+ `)}function B(e,n){return n===`\r
12
+ `?e.replace(/\n/g,`\r
13
+ `):e}function T(e){if(e!=null&&e.aborted)throw new Error("Operation aborted")}const G=2e4;function F(e,n=G){return e.length<=n?{text:e,truncated:!1}:{text:`${e.slice(0,n)}
14
+ [output truncated]`,truncated:!0}}const P=1e3,z=new Set([".git","node_modules","dist"]),W=a.Type.Object({pattern:a.Type.String({description:"Filename pattern. Supports * and ? wildcards. If it contains '/', it matches relative paths."}),path:a.Type.Optional(a.Type.String({description:"Directory to search. Defaults to cwd."})),limit:a.Type.Optional(a.Type.Number({description:`Maximum results. Default ${P}.`}))});function H(e){return{name:"find_files",label:"Find Files",description:"Find files by filename pattern. Returns paths relative to the search directory.",parameters:W,async execute(n,o,t){const r=o,i=w(e.cwd,r.path??"."),c=Math.max(1,r.limit??P),s=X(r.pattern),l=[];await _(i,i,s,l,c,t);const d=l.length>0?l.join(`
15
+ `):"No files found matching pattern",h=F(d);return{content:[{type:"text",text:h.text}],details:{path:i,pattern:r.pattern,resultCount:l.length,resultLimitReached:l.length>=c?c:void 0,truncated:h.truncated}}}}}async function _(e,n,o,t,r,i){if(O(i),t.length>=r)return;const c=await f.readdir(n,{withFileTypes:!0});for(const s of c){O(i);const l=u.join(n,s.name);if(s.isDirectory()){if(z.has(s.name)||await _(e,l,o,t,r,i),t.length>=r)return;continue}if(!s.isFile()&&!(await f.stat(l)).isFile())continue;const d=K(u.relative(e,l));if(o(d,s.name)&&(t.push(d),t.length>=r))return}}function X(e){const n=J(e),o=e.includes("/")||e.includes(u.sep);return(t,r)=>n.test(o?t:r)}function J(e){const n=e.split(u.sep).join("/").replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");return new RegExp(`^${n}$`)}function K(e){return e.split(u.sep).join("/")}function O(e){if(e!=null&&e.aborted)throw new Error("Operation aborted")}const S=100,Q=a.Type.Object({pattern:a.Type.String({description:"Text or regex pattern to search for."}),path:a.Type.Optional(a.Type.String({description:"Directory or file to search. Defaults to cwd."})),glob:a.Type.Optional(a.Type.String({description:"Limit matches by filename glob, e.g. *.ts."})),ignoreCase:a.Type.Optional(a.Type.Boolean({description:"Search case-insensitively."})),literal:a.Type.Optional(a.Type.Boolean({description:"Treat pattern as a literal string."})),limit:a.Type.Optional(a.Type.Number({description:`Maximum matches. Default ${S}.`}))});function V(e){return{name:"grep_files",label:"Grep Files",description:"Search file contents using grep. Returns matching file paths, line numbers, and matched lines.",parameters:Q,async execute(n,o,t){const r=o,i=w(e.cwd,r.path??"."),c=Math.max(1,r.limit??S),s=await Y(i,r,c,t),l=F(s.lines.join(`
16
+ `));return{content:[{type:"text",text:l.text||"No matches found"}],details:{path:i,pattern:r.pattern,matchCount:s.matchCount,matchLimitReached:s.matchLimitReached?c:void 0,truncated:l.truncated}}}}}function Y(e,n,o,t){return new Promise((r,i)=>{if(t!=null&&t.aborted){i(new Error("Operation aborted"));return}const c=["-R","-n","-I","--exclude-dir=.git","--exclude-dir=node_modules","--exclude-dir=dist"];n.ignoreCase&&c.push("-i"),n.literal&&c.push("-F"),n.glob&&c.push("--include",n.glob),c.push("--",n.pattern,e);const s=R.spawn("grep",c,{stdio:["ignore","pipe","pipe"]});let l="",d="",h=!1;const m=p=>{h||(h=!0,t==null||t.removeEventListener("abort",x),p())},x=()=>{s.kill(),m(()=>i(new Error("Operation aborted")))};t==null||t.addEventListener("abort",x,{once:!0}),s.stdout.on("data",p=>{l+=p.toString("utf8")}),s.stderr.on("data",p=>{d+=p.toString("utf8")}),s.on("error",p=>{m(()=>i(new Error(`Failed to run grep: ${p.message}`)))}),s.on("close",p=>{if(p!==0&&p!==1){m(()=>i(new Error(d.trim()||`grep exited with ${p}`)));return}const $=l.split(/\r?\n/).filter(Boolean).map(L=>Z(e,L)),E=$.slice(0,o);m(()=>r({lines:E,matchCount:E.length,matchLimitReached:$.length>o}))})})}function Z(e,n){const o=n.indexOf(":");if(o===-1)return n;const t=n.indexOf(":",o+1);if(t===-1)return n;const r=n.slice(0,o),i=n.slice(o+1,t),c=n.slice(t+1);return`${ee(u.relative(e,r))||r}:${i}:${c}`}function ee(e){return e.split(u.sep).join("/")}const te=a.Type.Object({path:a.Type.String({description:"Path to the file to read."}),offset:a.Type.Optional(a.Type.Number({description:"Line number to start reading from, 1-indexed."})),limit:a.Type.Optional(a.Type.Number({description:"Maximum number of lines."}))});function ne(e){return{name:"read_file",label:"Read File",description:"Read a UTF-8 text file. Use offset and limit for large files.",parameters:te,async execute(n,o,t){const r=o;y(t);const i=w(e.cwd,r.path),c=await f.stat(i);if(y(t),!c.isFile())throw new Error(`Path is not a file: ${r.path}`);const s=await f.readFile(i,"utf8");y(t);const l=re(s,r.offset,r.limit),d=F(l);return{content:[{type:"text",text:d.text}],details:{path:i,bytes:Buffer.byteLength(s,"utf8"),range:r.offset!==void 0||r.limit!==void 0?{offset:r.offset??1,limit:r.limit}:void 0,truncated:d.truncated}}}}}function re(e,n,o){if(n===void 0&&o===void 0)return e;const t=e.split(/\r\n|\n|\r/),r=Math.max(0,(n??1)-1),i=o===void 0?t.length:r+Math.max(0,o);return t.slice(r,i).join(`
17
+ `)}function y(e){if(e!=null&&e.aborted)throw new Error("Operation aborted")}const oe=a.Type.Object({path:a.Type.String({description:"Path to the file to write."}),content:a.Type.String({description:"Full file content to write."})});function ie(e){return{name:"write_file",label:"Write File",description:"Create or overwrite a UTF-8 text file, creating parent directories as needed.",parameters:oe,beforeExecute({event:n,requestApproval:o}){const t=n.input;return o(`Allowed to write file: ${t.path??""}`)},async execute(n,o,t){const r=o;b(t);const i=w(e.cwd,r.path);return await f.mkdir(u.dirname(i),{recursive:!0}),b(t),await f.writeFile(i,r.content,"utf8"),b(t),{content:[{type:"text",text:`Successfully wrote ${Buffer.byteLength(r.content,"utf8")} bytes to ${r.path}.`}],details:{path:i,bytes:Buffer.byteLength(r.content,"utf8")}}}}}function b(e){if(e!=null&&e.aborted)throw new Error("Operation aborted")}const ae="__code__plugin",ce={id:ae,contributionResolver:e=>({tools:[ne(e.env),ie(e.env),C(e.env),V(e.env),H(e.env),j(e.env)]})};module.exports=ce;
18
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.cjs","sources":["../src/server/tools/file-tools/path-utils.ts","../src/server/tools/file-tools/delete-file-tool.ts","../src/server/tools/file-tools/edit-file-tool.ts","../src/server/tools/file-tools/truncate.ts","../src/server/tools/file-tools/find-files-tool.ts","../src/server/tools/file-tools/grep-files-tool.ts","../src/server/tools/file-tools/read-file-tool.ts","../src/server/tools/file-tools/write-file-tool.ts","../src/plugin-id.ts","../src/server.ts"],"sourcesContent":["import { isAbsolute, resolve } from \"node:path\";\n\nexport function resolveToolPath(cwd: string, filePath: string): string {\n return isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n}\n\nexport function normalizeTextLineEndings(text: string): string {\n return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n","import { unlink } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\n\nconst deleteFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to delete.\" })\n});\n\ntype DeleteFileParameters = Static<typeof deleteFileParameters>;\n\nexport function createDeleteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"delete_file\",\n label: \"Delete File\",\n description: \"Delete a file from the workspace.\",\n parameters: deleteFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<DeleteFileParameters>;\n return requestApproval(`Allowed to delete file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as DeleteFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n await unlink(absolutePath);\n throwIfAborted(signal);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully deleted ${params.path}.`\n }\n ],\n details: {\n path: absolutePath\n }\n };\n }\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { normalizeTextLineEndings, resolveToolPath } from \"./path-utils\";\n\nconst editReplacementParameters = Type.Object({\n oldText: Type.String({\n description:\n \"Exact original text. It must occur exactly once in the original file.\"\n }),\n newText: Type.String({ description: \"Replacement text.\" })\n});\n\nconst editFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to edit.\" }),\n oldText: Type.Optional(\n Type.String({\n description: \"Legacy single replacement original text.\"\n })\n ),\n newText: Type.Optional(\n Type.String({ description: \"Legacy single replacement text.\" })\n ),\n edits: Type.Optional(\n Type.Array(editReplacementParameters, {\n description:\n \"One or more exact text replacements matched against the original file.\"\n })\n )\n});\n\ntype EditFileParameters = Static<typeof editFileParameters>;\n\ninterface EditReplacement {\n oldText: string;\n newText: string;\n}\n\ninterface MatchedReplacement extends EditReplacement {\n index: number;\n}\n\nexport function createEditFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"edit_file\",\n label: \"Edit File\",\n description:\n \"Edit a file by replacing unique original text blocks. Returns only changed blocks and a compact diff.\",\n parameters: editFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<EditFileParameters>;\n return requestApproval(`Allowed to edit file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as EditFileParameters;\n const replacements = normalizeReplacements(params);\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n const rawContent = await readFile(absolutePath, \"utf8\");\n throwIfAborted(signal);\n\n const lineEnding = rawContent.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const content = normalizeTextLineEndings(rawContent);\n const matched = matchReplacements(content, replacements, params.path);\n const newContent = applyReplacements(content, matched);\n throwIfAborted(signal);\n\n await writeFile(absolutePath, restoreLineEndings(newContent, lineEnding), \"utf8\");\n throwIfAborted(signal);\n\n const diff = formatReplacementDiff(replacements);\n return {\n content: [\n {\n type: \"text\",\n text: [\n `Successfully replaced ${replacements.length} block(s) in ${params.path}.`,\n \"\",\n diff\n ].join(\"\\n\")\n }\n ],\n details: {\n path: absolutePath,\n replacements,\n diff\n }\n };\n }\n };\n}\n\nfunction normalizeReplacements(params: EditFileParameters): EditReplacement[] {\n const edits = Array.isArray(params.edits) ? [...params.edits] : [];\n if (typeof params.oldText === \"string\" && typeof params.newText === \"string\") {\n edits.push({ oldText: params.oldText, newText: params.newText });\n }\n\n if (edits.length === 0) {\n throw new Error(\"edit_file requires oldText/newText or at least one edits entry.\");\n }\n\n return edits.map((edit, index) => {\n if (!edit.oldText) {\n throw new Error(`edits[${index}].oldText must not be empty.`);\n }\n return {\n oldText: normalizeTextLineEndings(edit.oldText),\n newText: normalizeTextLineEndings(edit.newText)\n };\n });\n}\n\nfunction matchReplacements(\n content: string,\n replacements: EditReplacement[],\n path: string\n): MatchedReplacement[] {\n const matched = replacements.map((replacement, index) => {\n const occurrences = findOccurrences(content, replacement.oldText);\n if (occurrences.length === 0) {\n throw new Error(\n `Could not find edits[${index}] in ${path}. The oldText must match exactly.`\n );\n }\n if (occurrences.length > 1) {\n throw new Error(\n `Found ${occurrences.length} occurrences of edits[${index}] in ${path}. Each oldText must be unique.`\n );\n }\n const occurrenceIndex = occurrences[0];\n if (occurrenceIndex === undefined) {\n throw new Error(`Could not find edits[${index}] in ${path}.`);\n }\n return { ...replacement, index: occurrenceIndex };\n });\n\n matched.sort((a, b) => a.index - b.index);\n for (let i = 1; i < matched.length; i++) {\n const previous = matched[i - 1];\n const current = matched[i];\n if (!previous || !current) {\n continue;\n }\n if (previous.index + previous.oldText.length > current.index) {\n throw new Error(\"edit_file replacements must not overlap.\");\n }\n }\n\n return matched;\n}\n\nfunction findOccurrences(content: string, search: string): number[] {\n const indexes: number[] = [];\n let index = content.indexOf(search);\n while (index !== -1) {\n indexes.push(index);\n index = content.indexOf(search, index + search.length);\n }\n return indexes;\n}\n\nfunction applyReplacements(\n content: string,\n replacements: MatchedReplacement[]\n): string {\n let nextContent = content;\n for (const replacement of [...replacements].reverse()) {\n nextContent =\n nextContent.slice(0, replacement.index) +\n replacement.newText +\n nextContent.slice(replacement.index + replacement.oldText.length);\n }\n if (nextContent === content) {\n throw new Error(\"No changes made. The replacements produced identical content.\");\n }\n return nextContent;\n}\n\nfunction formatReplacementDiff(replacements: EditReplacement[]): string {\n return replacements\n .map((replacement, index) =>\n [\n `@@ replacement ${index + 1} @@`,\n ...replacement.oldText.split(\"\\n\").map((line) => `-${line}`),\n ...replacement.newText.split(\"\\n\").map((line) => `+${line}`)\n ].join(\"\\n\")\n )\n .join(\"\\n\");\n}\n\nfunction restoreLineEndings(text: string, lineEnding: \"\\r\\n\" | \"\\n\"): string {\n return lineEnding === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","export const DEFAULT_MAX_OUTPUT_LENGTH = 20_000;\n\nexport function truncateText(\n text: string,\n maxLength = DEFAULT_MAX_OUTPUT_LENGTH\n): { text: string; truncated: boolean } {\n if (text.length <= maxLength) {\n return { text, truncated: false };\n }\n\n return {\n text: `${text.slice(0, maxLength)}\\n[output truncated]`,\n truncated: true\n };\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst DEFAULT_LIMIT = 1000;\nconst ignoredDirectories = new Set([\".git\", \"node_modules\", \"dist\"]);\n\nconst findFilesParameters = Type.Object({\n pattern: Type.String({\n description:\n \"Filename pattern. Supports * and ? wildcards. If it contains '/', it matches relative paths.\"\n }),\n path: Type.Optional(\n Type.String({ description: \"Directory to search. Defaults to cwd.\" })\n ),\n limit: Type.Optional(\n Type.Number({ description: `Maximum results. Default ${DEFAULT_LIMIT}.` })\n )\n});\n\ntype FindFilesParameters = Static<typeof findFilesParameters>;\n\nexport function createFindFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"find_files\",\n label: \"Find Files\",\n description:\n \"Find files by filename pattern. Returns paths relative to the search directory.\",\n parameters: findFilesParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as FindFilesParameters;\n const searchPath = resolveToolPath(env.cwd, params.path ?? \".\");\n const limit = Math.max(1, params.limit ?? DEFAULT_LIMIT);\n const matcher = createPatternMatcher(params.pattern);\n const results: string[] = [];\n\n await walkFiles(searchPath, searchPath, matcher, results, limit, signal);\n\n const text =\n results.length > 0 ? results.join(\"\\n\") : \"No files found matching pattern\";\n const truncated = truncateText(text);\n\n return {\n content: [{ type: \"text\", text: truncated.text }],\n details: {\n path: searchPath,\n pattern: params.pattern,\n resultCount: results.length,\n resultLimitReached: results.length >= limit ? limit : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nasync function walkFiles(\n root: string,\n current: string,\n matcher: (relativePath: string, basename: string) => boolean,\n results: string[],\n limit: number,\n signal: AbortSignal | undefined\n): Promise<void> {\n throwIfAborted(signal);\n if (results.length >= limit) {\n return;\n }\n\n const entries = await readdir(current, { withFileTypes: true });\n for (const entry of entries) {\n throwIfAborted(signal);\n const absolutePath = join(current, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoredDirectories.has(entry.name)) {\n await walkFiles(root, absolutePath, matcher, results, limit, signal);\n }\n if (results.length >= limit) {\n return;\n }\n continue;\n }\n\n if (!entry.isFile() && !(await stat(absolutePath)).isFile()) {\n continue;\n }\n\n const relativePath = toPosix(relative(root, absolutePath));\n if (matcher(relativePath, entry.name)) {\n results.push(relativePath);\n if (results.length >= limit) {\n return;\n }\n }\n }\n}\n\nfunction createPatternMatcher(\n pattern: string\n): (relativePath: string, basename: string) => boolean {\n const regex = wildcardToRegExp(pattern);\n const matchRelativePath = pattern.includes(\"/\") || pattern.includes(sep);\n return (relativePath, basename) =>\n regex.test(matchRelativePath ? relativePath : basename);\n}\n\nfunction wildcardToRegExp(pattern: string): RegExp {\n const source = pattern\n .split(sep)\n .join(\"/\")\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${source}$`);\n}\n\nfunction toPosix(value: string): string {\n return value.split(sep).join(\"/\");\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { relative, sep } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst DEFAULT_LIMIT = 100;\n\nconst grepFilesParameters = Type.Object({\n pattern: Type.String({ description: \"Text or regex pattern to search for.\" }),\n path: Type.Optional(\n Type.String({ description: \"Directory or file to search. Defaults to cwd.\" })\n ),\n glob: Type.Optional(\n Type.String({ description: \"Limit matches by filename glob, e.g. *.ts.\" })\n ),\n ignoreCase: Type.Optional(\n Type.Boolean({ description: \"Search case-insensitively.\" })\n ),\n literal: Type.Optional(\n Type.Boolean({ description: \"Treat pattern as a literal string.\" })\n ),\n limit: Type.Optional(\n Type.Number({ description: `Maximum matches. Default ${DEFAULT_LIMIT}.` })\n )\n});\n\ntype GrepFilesParameters = Static<typeof grepFilesParameters>;\n\nexport function createGrepFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"grep_files\",\n label: \"Grep Files\",\n description:\n \"Search file contents using grep. Returns matching file paths, line numbers, and matched lines.\",\n parameters: grepFilesParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as GrepFilesParameters;\n const searchPath = resolveToolPath(env.cwd, params.path ?? \".\");\n const limit = Math.max(1, params.limit ?? DEFAULT_LIMIT);\n const result = await runGrep(searchPath, params, limit, signal);\n const truncated = truncateText(result.lines.join(\"\\n\"));\n\n return {\n content: [\n {\n type: \"text\",\n text: truncated.text || \"No matches found\"\n }\n ],\n details: {\n path: searchPath,\n pattern: params.pattern,\n matchCount: result.matchCount,\n matchLimitReached: result.matchLimitReached ? limit : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nfunction runGrep(\n searchPath: string,\n params: GrepFilesParameters,\n limit: number,\n signal: AbortSignal | undefined\n): Promise<{ lines: string[]; matchCount: number; matchLimitReached: boolean }> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error(\"Operation aborted\"));\n return;\n }\n\n const args = [\n \"-R\",\n \"-n\",\n \"-I\",\n \"--exclude-dir=.git\",\n \"--exclude-dir=node_modules\",\n \"--exclude-dir=dist\"\n ];\n if (params.ignoreCase) {\n args.push(\"-i\");\n }\n if (params.literal) {\n args.push(\"-F\");\n }\n if (params.glob) {\n args.push(\"--include\", params.glob);\n }\n args.push(\"--\", params.pattern, searchPath);\n\n const child = spawn(\"grep\", args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n let settled = false;\n\n const settle = (callback: () => void): void => {\n if (settled) {\n return;\n }\n settled = true;\n signal?.removeEventListener(\"abort\", onAbort);\n callback();\n };\n\n const onAbort = (): void => {\n child.kill();\n settle(() => reject(new Error(\"Operation aborted\")));\n };\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"error\", (error) => {\n settle(() => reject(new Error(`Failed to run grep: ${error.message}`)));\n });\n child.on(\"close\", (code) => {\n if (code !== 0 && code !== 1) {\n settle(() => reject(new Error(stderr.trim() || `grep exited with ${code}`)));\n return;\n }\n\n const allLines = stdout\n .split(/\\r?\\n/)\n .filter(Boolean)\n .map((line) => formatGrepLine(searchPath, line));\n const lines = allLines.slice(0, limit);\n settle(() =>\n resolve({\n lines,\n matchCount: lines.length,\n matchLimitReached: allLines.length > limit\n })\n );\n });\n });\n}\n\nfunction formatGrepLine(searchPath: string, line: string): string {\n const firstColon = line.indexOf(\":\");\n if (firstColon === -1) {\n return line;\n }\n\n const secondColon = line.indexOf(\":\", firstColon + 1);\n if (secondColon === -1) {\n return line;\n }\n\n const rawPath = line.slice(0, firstColon);\n const lineNumber = line.slice(firstColon + 1, secondColon);\n const text = line.slice(secondColon + 1);\n const displayPath = toPosix(relative(searchPath, rawPath)) || rawPath;\n return `${displayPath}:${lineNumber}:${text}`;\n}\n\nfunction toPosix(value: string): string {\n return value.split(sep).join(\"/\");\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst readFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to read.\" }),\n offset: Type.Optional(\n Type.Number({ description: \"Line number to start reading from, 1-indexed.\" })\n ),\n limit: Type.Optional(Type.Number({ description: \"Maximum number of lines.\" }))\n});\n\ntype ReadFileParameters = Static<typeof readFileParameters>;\n\nexport function createReadFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"read_file\",\n label: \"Read File\",\n description:\n \"Read a UTF-8 text file. Use offset and limit for large files.\",\n parameters: readFileParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as ReadFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n const fileStat = await stat(absolutePath);\n throwIfAborted(signal);\n\n if (!fileStat.isFile()) {\n throw new Error(`Path is not a file: ${params.path}`);\n }\n\n const content = await readFile(absolutePath, \"utf8\");\n throwIfAborted(signal);\n\n const selected = selectLineRange(content, params.offset, params.limit);\n const truncated = truncateText(selected);\n\n return {\n content: [{ type: \"text\", text: truncated.text }],\n details: {\n path: absolutePath,\n bytes: Buffer.byteLength(content, \"utf8\"),\n range:\n params.offset !== undefined || params.limit !== undefined\n ? { offset: params.offset ?? 1, limit: params.limit }\n : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nfunction selectLineRange(\n content: string,\n offset: number | undefined,\n limit: number | undefined\n): string {\n if (offset === undefined && limit === undefined) {\n return content;\n }\n\n const lines = content.split(/\\r\\n|\\n|\\r/);\n const start = Math.max(0, (offset ?? 1) - 1);\n const end = limit === undefined ? lines.length : start + Math.max(0, limit);\n return lines.slice(start, end).join(\"\\n\");\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\n\nconst writeFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to write.\" }),\n content: Type.String({ description: \"Full file content to write.\" })\n});\n\ntype WriteFileParameters = Static<typeof writeFileParameters>;\n\nexport function createWriteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"write_file\",\n label: \"Write File\",\n description:\n \"Create or overwrite a UTF-8 text file, creating parent directories as needed.\",\n parameters: writeFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<WriteFileParameters>;\n return requestApproval(`Allowed to write file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as WriteFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n await mkdir(dirname(absolutePath), { recursive: true });\n throwIfAborted(signal);\n\n await writeFile(absolutePath, params.content, \"utf8\");\n throwIfAborted(signal);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully wrote ${Buffer.byteLength(\n params.content,\n \"utf8\"\n )} bytes to ${params.path}.`\n }\n ],\n details: {\n path: absolutePath,\n bytes: Buffer.byteLength(params.content, \"utf8\")\n }\n };\n }\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","export const PLUGIN_ID = \"__code__plugin\";\n","import type { ServerPlugin } from \"@hold-rein/plugin-server\";\nimport {\n createDeleteFileTool,\n createEditFileTool,\n createFindFilesTool,\n createGrepFilesTool,\n createReadFileTool,\n createWriteFileTool\n} from './server/tools'\n\nimport { PLUGIN_ID } from \"./plugin-id\";\n\nconst baseServerPlugin: ServerPlugin.Plugin = {\n id: PLUGIN_ID,\n contributionResolver: (context) => {\n return {\n tools: [\n createReadFileTool(context.env),\n createWriteFileTool(context.env),\n createDeleteFileTool(context.env),\n createGrepFilesTool(context.env),\n createFindFilesTool(context.env),\n createEditFileTool(context.env),\n ]\n }\n }\n};\n\nexport default baseServerPlugin;\n"],"names":["resolveToolPath","cwd","filePath","isAbsolute","resolve","normalizeTextLineEndings","text","deleteFileParameters","Type","createDeleteFileTool","env","event","requestApproval","params","_toolCallId","rawParams","signal","throwIfAborted","absolutePath","unlink","editReplacementParameters","editFileParameters","createEditFileTool","replacements","normalizeReplacements","rawContent","readFile","lineEnding","content","matched","matchReplacements","newContent","applyReplacements","writeFile","restoreLineEndings","diff","formatReplacementDiff","edits","edit","index","path","replacement","occurrences","findOccurrences","occurrenceIndex","a","b","i","previous","current","search","indexes","nextContent","line","DEFAULT_MAX_OUTPUT_LENGTH","truncateText","maxLength","DEFAULT_LIMIT","ignoredDirectories","findFilesParameters","createFindFilesTool","searchPath","limit","matcher","createPatternMatcher","results","walkFiles","truncated","root","entries","readdir","entry","join","stat","relativePath","toPosix","relative","pattern","regex","wildcardToRegExp","matchRelativePath","sep","basename","source","value","grepFilesParameters","createGrepFilesTool","result","runGrep","reject","args","child","spawn","stdout","stderr","settled","settle","callback","onAbort","chunk","error","code","allLines","formatGrepLine","lines","firstColon","secondColon","rawPath","lineNumber","readFileParameters","createReadFileTool","fileStat","selected","selectLineRange","offset","start","end","writeFileParameters","createWriteFileTool","mkdir","dirname","PLUGIN_ID","baseServerPlugin","context"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ServerPlugin } from "@hold-rein/plugin-server";
2
+ declare const baseServerPlugin: ServerPlugin.Plugin;
3
+ export default baseServerPlugin;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAY7D,QAAA,MAAM,gBAAgB,EAAE,YAAY,CAAC,MAcpC,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,465 @@
1
+ import { unlink as A, readFile as O, writeFile as P, readdir as D, stat as _, mkdir as j } from "node:fs/promises";
2
+ import { Type as a } from "@earendil-works/pi-ai";
3
+ import { isAbsolute as M, resolve as N, sep as w, join as U, relative as S, dirname as k } from "node:path";
4
+ import { spawn as B } from "node:child_process";
5
+ function h(e, n) {
6
+ return M(n) ? n : N(e, n);
7
+ }
8
+ function g(e) {
9
+ return e.replace(/\r\n/g, `
10
+ `).replace(/\r/g, `
11
+ `);
12
+ }
13
+ const G = a.Object({
14
+ path: a.String({ description: "Path to the file to delete." })
15
+ });
16
+ function q(e) {
17
+ return {
18
+ name: "delete_file",
19
+ label: "Delete File",
20
+ description: "Delete a file from the workspace.",
21
+ parameters: G,
22
+ beforeExecute({ event: n, requestApproval: o }) {
23
+ const t = n.input;
24
+ return o(`Allowed to delete file: ${t.path ?? ""}`);
25
+ },
26
+ async execute(n, o, t) {
27
+ const r = o;
28
+ E(t);
29
+ const i = h(e.cwd, r.path);
30
+ return await A(i), E(t), {
31
+ content: [
32
+ {
33
+ type: "text",
34
+ text: `Successfully deleted ${r.path}.`
35
+ }
36
+ ],
37
+ details: {
38
+ path: i
39
+ }
40
+ };
41
+ }
42
+ };
43
+ }
44
+ function E(e) {
45
+ if (e != null && e.aborted)
46
+ throw new Error("Operation aborted");
47
+ }
48
+ const z = a.Object({
49
+ oldText: a.String({
50
+ description: "Exact original text. It must occur exactly once in the original file."
51
+ }),
52
+ newText: a.String({ description: "Replacement text." })
53
+ }), W = a.Object({
54
+ path: a.String({ description: "Path to the file to edit." }),
55
+ oldText: a.Optional(
56
+ a.String({
57
+ description: "Legacy single replacement original text."
58
+ })
59
+ ),
60
+ newText: a.Optional(
61
+ a.String({ description: "Legacy single replacement text." })
62
+ ),
63
+ edits: a.Optional(
64
+ a.Array(z, {
65
+ description: "One or more exact text replacements matched against the original file."
66
+ })
67
+ )
68
+ });
69
+ function H(e) {
70
+ return {
71
+ name: "edit_file",
72
+ label: "Edit File",
73
+ description: "Edit a file by replacing unique original text blocks. Returns only changed blocks and a compact diff.",
74
+ parameters: W,
75
+ beforeExecute({ event: n, requestApproval: o }) {
76
+ const t = n.input;
77
+ return o(`Allowed to edit file: ${t.path ?? ""}`);
78
+ },
79
+ async execute(n, o, t) {
80
+ const r = o, i = X(r);
81
+ x(t);
82
+ const c = h(e.cwd, r.path), s = await O(c, "utf8");
83
+ x(t);
84
+ const l = s.includes(`\r
85
+ `) ? `\r
86
+ ` : `
87
+ `, d = g(s), p = J(d, i, r.path), f = Q(d, p);
88
+ x(t), await P(c, Y(f, l), "utf8"), x(t);
89
+ const m = V(i);
90
+ return {
91
+ content: [
92
+ {
93
+ type: "text",
94
+ text: [
95
+ `Successfully replaced ${i.length} block(s) in ${r.path}.`,
96
+ "",
97
+ m
98
+ ].join(`
99
+ `)
100
+ }
101
+ ],
102
+ details: {
103
+ path: c,
104
+ replacements: i,
105
+ diff: m
106
+ }
107
+ };
108
+ }
109
+ };
110
+ }
111
+ function X(e) {
112
+ const n = Array.isArray(e.edits) ? [...e.edits] : [];
113
+ if (typeof e.oldText == "string" && typeof e.newText == "string" && n.push({ oldText: e.oldText, newText: e.newText }), n.length === 0)
114
+ throw new Error("edit_file requires oldText/newText or at least one edits entry.");
115
+ return n.map((o, t) => {
116
+ if (!o.oldText)
117
+ throw new Error(`edits[${t}].oldText must not be empty.`);
118
+ return {
119
+ oldText: g(o.oldText),
120
+ newText: g(o.newText)
121
+ };
122
+ });
123
+ }
124
+ function J(e, n, o) {
125
+ const t = n.map((r, i) => {
126
+ const c = K(e, r.oldText);
127
+ if (c.length === 0)
128
+ throw new Error(
129
+ `Could not find edits[${i}] in ${o}. The oldText must match exactly.`
130
+ );
131
+ if (c.length > 1)
132
+ throw new Error(
133
+ `Found ${c.length} occurrences of edits[${i}] in ${o}. Each oldText must be unique.`
134
+ );
135
+ const s = c[0];
136
+ if (s === void 0)
137
+ throw new Error(`Could not find edits[${i}] in ${o}.`);
138
+ return { ...r, index: s };
139
+ });
140
+ t.sort((r, i) => r.index - i.index);
141
+ for (let r = 1; r < t.length; r++) {
142
+ const i = t[r - 1], c = t[r];
143
+ if (!(!i || !c) && i.index + i.oldText.length > c.index)
144
+ throw new Error("edit_file replacements must not overlap.");
145
+ }
146
+ return t;
147
+ }
148
+ function K(e, n) {
149
+ const o = [];
150
+ let t = e.indexOf(n);
151
+ for (; t !== -1; )
152
+ o.push(t), t = e.indexOf(n, t + n.length);
153
+ return o;
154
+ }
155
+ function Q(e, n) {
156
+ let o = e;
157
+ for (const t of [...n].reverse())
158
+ o = o.slice(0, t.index) + t.newText + o.slice(t.index + t.oldText.length);
159
+ if (o === e)
160
+ throw new Error("No changes made. The replacements produced identical content.");
161
+ return o;
162
+ }
163
+ function V(e) {
164
+ return e.map(
165
+ (n, o) => [
166
+ `@@ replacement ${o + 1} @@`,
167
+ ...n.oldText.split(`
168
+ `).map((t) => `-${t}`),
169
+ ...n.newText.split(`
170
+ `).map((t) => `+${t}`)
171
+ ].join(`
172
+ `)
173
+ ).join(`
174
+ `);
175
+ }
176
+ function Y(e, n) {
177
+ return n === `\r
178
+ ` ? e.replace(/\n/g, `\r
179
+ `) : e;
180
+ }
181
+ function x(e) {
182
+ if (e != null && e.aborted)
183
+ throw new Error("Operation aborted");
184
+ }
185
+ const Z = 2e4;
186
+ function y(e, n = Z) {
187
+ return e.length <= n ? { text: e, truncated: !1 } : {
188
+ text: `${e.slice(0, n)}
189
+ [output truncated]`,
190
+ truncated: !0
191
+ };
192
+ }
193
+ const L = 1e3, ee = /* @__PURE__ */ new Set([".git", "node_modules", "dist"]), te = a.Object({
194
+ pattern: a.String({
195
+ description: "Filename pattern. Supports * and ? wildcards. If it contains '/', it matches relative paths."
196
+ }),
197
+ path: a.Optional(
198
+ a.String({ description: "Directory to search. Defaults to cwd." })
199
+ ),
200
+ limit: a.Optional(
201
+ a.Number({ description: `Maximum results. Default ${L}.` })
202
+ )
203
+ });
204
+ function ne(e) {
205
+ return {
206
+ name: "find_files",
207
+ label: "Find Files",
208
+ description: "Find files by filename pattern. Returns paths relative to the search directory.",
209
+ parameters: te,
210
+ async execute(n, o, t) {
211
+ const r = o, i = h(e.cwd, r.path ?? "."), c = Math.max(1, r.limit ?? L), s = re(r.pattern), l = [];
212
+ await R(i, i, s, l, c, t);
213
+ const d = l.length > 0 ? l.join(`
214
+ `) : "No files found matching pattern", p = y(d);
215
+ return {
216
+ content: [{ type: "text", text: p.text }],
217
+ details: {
218
+ path: i,
219
+ pattern: r.pattern,
220
+ resultCount: l.length,
221
+ resultLimitReached: l.length >= c ? c : void 0,
222
+ truncated: p.truncated
223
+ }
224
+ };
225
+ }
226
+ };
227
+ }
228
+ async function R(e, n, o, t, r, i) {
229
+ if (v(i), t.length >= r)
230
+ return;
231
+ const c = await D(n, { withFileTypes: !0 });
232
+ for (const s of c) {
233
+ v(i);
234
+ const l = U(n, s.name);
235
+ if (s.isDirectory()) {
236
+ if (ee.has(s.name) || await R(e, l, o, t, r, i), t.length >= r)
237
+ return;
238
+ continue;
239
+ }
240
+ if (!s.isFile() && !(await _(l)).isFile())
241
+ continue;
242
+ const d = ie(S(e, l));
243
+ if (o(d, s.name) && (t.push(d), t.length >= r))
244
+ return;
245
+ }
246
+ }
247
+ function re(e) {
248
+ const n = oe(e), o = e.includes("/") || e.includes(w);
249
+ return (t, r) => n.test(o ? t : r);
250
+ }
251
+ function oe(e) {
252
+ const n = e.split(w).join("/").replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
253
+ return new RegExp(`^${n}$`);
254
+ }
255
+ function ie(e) {
256
+ return e.split(w).join("/");
257
+ }
258
+ function v(e) {
259
+ if (e != null && e.aborted)
260
+ throw new Error("Operation aborted");
261
+ }
262
+ const I = 100, ae = a.Object({
263
+ pattern: a.String({ description: "Text or regex pattern to search for." }),
264
+ path: a.Optional(
265
+ a.String({ description: "Directory or file to search. Defaults to cwd." })
266
+ ),
267
+ glob: a.Optional(
268
+ a.String({ description: "Limit matches by filename glob, e.g. *.ts." })
269
+ ),
270
+ ignoreCase: a.Optional(
271
+ a.Boolean({ description: "Search case-insensitively." })
272
+ ),
273
+ literal: a.Optional(
274
+ a.Boolean({ description: "Treat pattern as a literal string." })
275
+ ),
276
+ limit: a.Optional(
277
+ a.Number({ description: `Maximum matches. Default ${I}.` })
278
+ )
279
+ });
280
+ function ce(e) {
281
+ return {
282
+ name: "grep_files",
283
+ label: "Grep Files",
284
+ description: "Search file contents using grep. Returns matching file paths, line numbers, and matched lines.",
285
+ parameters: ae,
286
+ async execute(n, o, t) {
287
+ const r = o, i = h(e.cwd, r.path ?? "."), c = Math.max(1, r.limit ?? I), s = await se(i, r, c, t), l = y(s.lines.join(`
288
+ `));
289
+ return {
290
+ content: [
291
+ {
292
+ type: "text",
293
+ text: l.text || "No matches found"
294
+ }
295
+ ],
296
+ details: {
297
+ path: i,
298
+ pattern: r.pattern,
299
+ matchCount: s.matchCount,
300
+ matchLimitReached: s.matchLimitReached ? c : void 0,
301
+ truncated: l.truncated
302
+ }
303
+ };
304
+ }
305
+ };
306
+ }
307
+ function se(e, n, o, t) {
308
+ return new Promise((r, i) => {
309
+ if (t != null && t.aborted) {
310
+ i(new Error("Operation aborted"));
311
+ return;
312
+ }
313
+ const c = [
314
+ "-R",
315
+ "-n",
316
+ "-I",
317
+ "--exclude-dir=.git",
318
+ "--exclude-dir=node_modules",
319
+ "--exclude-dir=dist"
320
+ ];
321
+ n.ignoreCase && c.push("-i"), n.literal && c.push("-F"), n.glob && c.push("--include", n.glob), c.push("--", n.pattern, e);
322
+ const s = B("grep", c, { stdio: ["ignore", "pipe", "pipe"] });
323
+ let l = "", d = "", p = !1;
324
+ const f = (u) => {
325
+ p || (p = !0, t == null || t.removeEventListener("abort", m), u());
326
+ }, m = () => {
327
+ s.kill(), f(() => i(new Error("Operation aborted")));
328
+ };
329
+ t == null || t.addEventListener("abort", m, { once: !0 }), s.stdout.on("data", (u) => {
330
+ l += u.toString("utf8");
331
+ }), s.stderr.on("data", (u) => {
332
+ d += u.toString("utf8");
333
+ }), s.on("error", (u) => {
334
+ f(() => i(new Error(`Failed to run grep: ${u.message}`)));
335
+ }), s.on("close", (u) => {
336
+ if (u !== 0 && u !== 1) {
337
+ f(() => i(new Error(d.trim() || `grep exited with ${u}`)));
338
+ return;
339
+ }
340
+ const F = l.split(/\r?\n/).filter(Boolean).map((C) => le(e, C)), $ = F.slice(0, o);
341
+ f(
342
+ () => r({
343
+ lines: $,
344
+ matchCount: $.length,
345
+ matchLimitReached: F.length > o
346
+ })
347
+ );
348
+ });
349
+ });
350
+ }
351
+ function le(e, n) {
352
+ const o = n.indexOf(":");
353
+ if (o === -1)
354
+ return n;
355
+ const t = n.indexOf(":", o + 1);
356
+ if (t === -1)
357
+ return n;
358
+ const r = n.slice(0, o), i = n.slice(o + 1, t), c = n.slice(t + 1);
359
+ return `${de(S(e, r)) || r}:${i}:${c}`;
360
+ }
361
+ function de(e) {
362
+ return e.split(w).join("/");
363
+ }
364
+ const ue = a.Object({
365
+ path: a.String({ description: "Path to the file to read." }),
366
+ offset: a.Optional(
367
+ a.Number({ description: "Line number to start reading from, 1-indexed." })
368
+ ),
369
+ limit: a.Optional(a.Number({ description: "Maximum number of lines." }))
370
+ });
371
+ function pe(e) {
372
+ return {
373
+ name: "read_file",
374
+ label: "Read File",
375
+ description: "Read a UTF-8 text file. Use offset and limit for large files.",
376
+ parameters: ue,
377
+ async execute(n, o, t) {
378
+ const r = o;
379
+ b(t);
380
+ const i = h(e.cwd, r.path), c = await _(i);
381
+ if (b(t), !c.isFile())
382
+ throw new Error(`Path is not a file: ${r.path}`);
383
+ const s = await O(i, "utf8");
384
+ b(t);
385
+ const l = fe(s, r.offset, r.limit), d = y(l);
386
+ return {
387
+ content: [{ type: "text", text: d.text }],
388
+ details: {
389
+ path: i,
390
+ bytes: Buffer.byteLength(s, "utf8"),
391
+ range: r.offset !== void 0 || r.limit !== void 0 ? { offset: r.offset ?? 1, limit: r.limit } : void 0,
392
+ truncated: d.truncated
393
+ }
394
+ };
395
+ }
396
+ };
397
+ }
398
+ function fe(e, n, o) {
399
+ if (n === void 0 && o === void 0)
400
+ return e;
401
+ const t = e.split(/\r\n|\n|\r/), r = Math.max(0, (n ?? 1) - 1), i = o === void 0 ? t.length : r + Math.max(0, o);
402
+ return t.slice(r, i).join(`
403
+ `);
404
+ }
405
+ function b(e) {
406
+ if (e != null && e.aborted)
407
+ throw new Error("Operation aborted");
408
+ }
409
+ const he = a.Object({
410
+ path: a.String({ description: "Path to the file to write." }),
411
+ content: a.String({ description: "Full file content to write." })
412
+ });
413
+ function me(e) {
414
+ return {
415
+ name: "write_file",
416
+ label: "Write File",
417
+ description: "Create or overwrite a UTF-8 text file, creating parent directories as needed.",
418
+ parameters: he,
419
+ beforeExecute({ event: n, requestApproval: o }) {
420
+ const t = n.input;
421
+ return o(`Allowed to write file: ${t.path ?? ""}`);
422
+ },
423
+ async execute(n, o, t) {
424
+ const r = o;
425
+ T(t);
426
+ const i = h(e.cwd, r.path);
427
+ return await j(k(i), { recursive: !0 }), T(t), await P(i, r.content, "utf8"), T(t), {
428
+ content: [
429
+ {
430
+ type: "text",
431
+ text: `Successfully wrote ${Buffer.byteLength(
432
+ r.content,
433
+ "utf8"
434
+ )} bytes to ${r.path}.`
435
+ }
436
+ ],
437
+ details: {
438
+ path: i,
439
+ bytes: Buffer.byteLength(r.content, "utf8")
440
+ }
441
+ };
442
+ }
443
+ };
444
+ }
445
+ function T(e) {
446
+ if (e != null && e.aborted)
447
+ throw new Error("Operation aborted");
448
+ }
449
+ const xe = "__code__plugin", ye = {
450
+ id: xe,
451
+ contributionResolver: (e) => ({
452
+ tools: [
453
+ pe(e.env),
454
+ me(e.env),
455
+ q(e.env),
456
+ ce(e.env),
457
+ ne(e.env),
458
+ H(e.env)
459
+ ]
460
+ })
461
+ };
462
+ export {
463
+ ye as default
464
+ };
465
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sources":["../src/server/tools/file-tools/path-utils.ts","../src/server/tools/file-tools/delete-file-tool.ts","../src/server/tools/file-tools/edit-file-tool.ts","../src/server/tools/file-tools/truncate.ts","../src/server/tools/file-tools/find-files-tool.ts","../src/server/tools/file-tools/grep-files-tool.ts","../src/server/tools/file-tools/read-file-tool.ts","../src/server/tools/file-tools/write-file-tool.ts","../src/plugin-id.ts","../src/server.ts"],"sourcesContent":["import { isAbsolute, resolve } from \"node:path\";\n\nexport function resolveToolPath(cwd: string, filePath: string): string {\n return isAbsolute(filePath) ? filePath : resolve(cwd, filePath);\n}\n\nexport function normalizeTextLineEndings(text: string): string {\n return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n","import { unlink } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\n\nconst deleteFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to delete.\" })\n});\n\ntype DeleteFileParameters = Static<typeof deleteFileParameters>;\n\nexport function createDeleteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"delete_file\",\n label: \"Delete File\",\n description: \"Delete a file from the workspace.\",\n parameters: deleteFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<DeleteFileParameters>;\n return requestApproval(`Allowed to delete file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as DeleteFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n await unlink(absolutePath);\n throwIfAborted(signal);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully deleted ${params.path}.`\n }\n ],\n details: {\n path: absolutePath\n }\n };\n }\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { normalizeTextLineEndings, resolveToolPath } from \"./path-utils\";\n\nconst editReplacementParameters = Type.Object({\n oldText: Type.String({\n description:\n \"Exact original text. It must occur exactly once in the original file.\"\n }),\n newText: Type.String({ description: \"Replacement text.\" })\n});\n\nconst editFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to edit.\" }),\n oldText: Type.Optional(\n Type.String({\n description: \"Legacy single replacement original text.\"\n })\n ),\n newText: Type.Optional(\n Type.String({ description: \"Legacy single replacement text.\" })\n ),\n edits: Type.Optional(\n Type.Array(editReplacementParameters, {\n description:\n \"One or more exact text replacements matched against the original file.\"\n })\n )\n});\n\ntype EditFileParameters = Static<typeof editFileParameters>;\n\ninterface EditReplacement {\n oldText: string;\n newText: string;\n}\n\ninterface MatchedReplacement extends EditReplacement {\n index: number;\n}\n\nexport function createEditFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"edit_file\",\n label: \"Edit File\",\n description:\n \"Edit a file by replacing unique original text blocks. Returns only changed blocks and a compact diff.\",\n parameters: editFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<EditFileParameters>;\n return requestApproval(`Allowed to edit file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as EditFileParameters;\n const replacements = normalizeReplacements(params);\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n const rawContent = await readFile(absolutePath, \"utf8\");\n throwIfAborted(signal);\n\n const lineEnding = rawContent.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const content = normalizeTextLineEndings(rawContent);\n const matched = matchReplacements(content, replacements, params.path);\n const newContent = applyReplacements(content, matched);\n throwIfAborted(signal);\n\n await writeFile(absolutePath, restoreLineEndings(newContent, lineEnding), \"utf8\");\n throwIfAborted(signal);\n\n const diff = formatReplacementDiff(replacements);\n return {\n content: [\n {\n type: \"text\",\n text: [\n `Successfully replaced ${replacements.length} block(s) in ${params.path}.`,\n \"\",\n diff\n ].join(\"\\n\")\n }\n ],\n details: {\n path: absolutePath,\n replacements,\n diff\n }\n };\n }\n };\n}\n\nfunction normalizeReplacements(params: EditFileParameters): EditReplacement[] {\n const edits = Array.isArray(params.edits) ? [...params.edits] : [];\n if (typeof params.oldText === \"string\" && typeof params.newText === \"string\") {\n edits.push({ oldText: params.oldText, newText: params.newText });\n }\n\n if (edits.length === 0) {\n throw new Error(\"edit_file requires oldText/newText or at least one edits entry.\");\n }\n\n return edits.map((edit, index) => {\n if (!edit.oldText) {\n throw new Error(`edits[${index}].oldText must not be empty.`);\n }\n return {\n oldText: normalizeTextLineEndings(edit.oldText),\n newText: normalizeTextLineEndings(edit.newText)\n };\n });\n}\n\nfunction matchReplacements(\n content: string,\n replacements: EditReplacement[],\n path: string\n): MatchedReplacement[] {\n const matched = replacements.map((replacement, index) => {\n const occurrences = findOccurrences(content, replacement.oldText);\n if (occurrences.length === 0) {\n throw new Error(\n `Could not find edits[${index}] in ${path}. The oldText must match exactly.`\n );\n }\n if (occurrences.length > 1) {\n throw new Error(\n `Found ${occurrences.length} occurrences of edits[${index}] in ${path}. Each oldText must be unique.`\n );\n }\n const occurrenceIndex = occurrences[0];\n if (occurrenceIndex === undefined) {\n throw new Error(`Could not find edits[${index}] in ${path}.`);\n }\n return { ...replacement, index: occurrenceIndex };\n });\n\n matched.sort((a, b) => a.index - b.index);\n for (let i = 1; i < matched.length; i++) {\n const previous = matched[i - 1];\n const current = matched[i];\n if (!previous || !current) {\n continue;\n }\n if (previous.index + previous.oldText.length > current.index) {\n throw new Error(\"edit_file replacements must not overlap.\");\n }\n }\n\n return matched;\n}\n\nfunction findOccurrences(content: string, search: string): number[] {\n const indexes: number[] = [];\n let index = content.indexOf(search);\n while (index !== -1) {\n indexes.push(index);\n index = content.indexOf(search, index + search.length);\n }\n return indexes;\n}\n\nfunction applyReplacements(\n content: string,\n replacements: MatchedReplacement[]\n): string {\n let nextContent = content;\n for (const replacement of [...replacements].reverse()) {\n nextContent =\n nextContent.slice(0, replacement.index) +\n replacement.newText +\n nextContent.slice(replacement.index + replacement.oldText.length);\n }\n if (nextContent === content) {\n throw new Error(\"No changes made. The replacements produced identical content.\");\n }\n return nextContent;\n}\n\nfunction formatReplacementDiff(replacements: EditReplacement[]): string {\n return replacements\n .map((replacement, index) =>\n [\n `@@ replacement ${index + 1} @@`,\n ...replacement.oldText.split(\"\\n\").map((line) => `-${line}`),\n ...replacement.newText.split(\"\\n\").map((line) => `+${line}`)\n ].join(\"\\n\")\n )\n .join(\"\\n\");\n}\n\nfunction restoreLineEndings(text: string, lineEnding: \"\\r\\n\" | \"\\n\"): string {\n return lineEnding === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","export const DEFAULT_MAX_OUTPUT_LENGTH = 20_000;\n\nexport function truncateText(\n text: string,\n maxLength = DEFAULT_MAX_OUTPUT_LENGTH\n): { text: string; truncated: boolean } {\n if (text.length <= maxLength) {\n return { text, truncated: false };\n }\n\n return {\n text: `${text.slice(0, maxLength)}\\n[output truncated]`,\n truncated: true\n };\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst DEFAULT_LIMIT = 1000;\nconst ignoredDirectories = new Set([\".git\", \"node_modules\", \"dist\"]);\n\nconst findFilesParameters = Type.Object({\n pattern: Type.String({\n description:\n \"Filename pattern. Supports * and ? wildcards. If it contains '/', it matches relative paths.\"\n }),\n path: Type.Optional(\n Type.String({ description: \"Directory to search. Defaults to cwd.\" })\n ),\n limit: Type.Optional(\n Type.Number({ description: `Maximum results. Default ${DEFAULT_LIMIT}.` })\n )\n});\n\ntype FindFilesParameters = Static<typeof findFilesParameters>;\n\nexport function createFindFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"find_files\",\n label: \"Find Files\",\n description:\n \"Find files by filename pattern. Returns paths relative to the search directory.\",\n parameters: findFilesParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as FindFilesParameters;\n const searchPath = resolveToolPath(env.cwd, params.path ?? \".\");\n const limit = Math.max(1, params.limit ?? DEFAULT_LIMIT);\n const matcher = createPatternMatcher(params.pattern);\n const results: string[] = [];\n\n await walkFiles(searchPath, searchPath, matcher, results, limit, signal);\n\n const text =\n results.length > 0 ? results.join(\"\\n\") : \"No files found matching pattern\";\n const truncated = truncateText(text);\n\n return {\n content: [{ type: \"text\", text: truncated.text }],\n details: {\n path: searchPath,\n pattern: params.pattern,\n resultCount: results.length,\n resultLimitReached: results.length >= limit ? limit : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nasync function walkFiles(\n root: string,\n current: string,\n matcher: (relativePath: string, basename: string) => boolean,\n results: string[],\n limit: number,\n signal: AbortSignal | undefined\n): Promise<void> {\n throwIfAborted(signal);\n if (results.length >= limit) {\n return;\n }\n\n const entries = await readdir(current, { withFileTypes: true });\n for (const entry of entries) {\n throwIfAborted(signal);\n const absolutePath = join(current, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoredDirectories.has(entry.name)) {\n await walkFiles(root, absolutePath, matcher, results, limit, signal);\n }\n if (results.length >= limit) {\n return;\n }\n continue;\n }\n\n if (!entry.isFile() && !(await stat(absolutePath)).isFile()) {\n continue;\n }\n\n const relativePath = toPosix(relative(root, absolutePath));\n if (matcher(relativePath, entry.name)) {\n results.push(relativePath);\n if (results.length >= limit) {\n return;\n }\n }\n }\n}\n\nfunction createPatternMatcher(\n pattern: string\n): (relativePath: string, basename: string) => boolean {\n const regex = wildcardToRegExp(pattern);\n const matchRelativePath = pattern.includes(\"/\") || pattern.includes(sep);\n return (relativePath, basename) =>\n regex.test(matchRelativePath ? relativePath : basename);\n}\n\nfunction wildcardToRegExp(pattern: string): RegExp {\n const source = pattern\n .split(sep)\n .join(\"/\")\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${source}$`);\n}\n\nfunction toPosix(value: string): string {\n return value.split(sep).join(\"/\");\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { relative, sep } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst DEFAULT_LIMIT = 100;\n\nconst grepFilesParameters = Type.Object({\n pattern: Type.String({ description: \"Text or regex pattern to search for.\" }),\n path: Type.Optional(\n Type.String({ description: \"Directory or file to search. Defaults to cwd.\" })\n ),\n glob: Type.Optional(\n Type.String({ description: \"Limit matches by filename glob, e.g. *.ts.\" })\n ),\n ignoreCase: Type.Optional(\n Type.Boolean({ description: \"Search case-insensitively.\" })\n ),\n literal: Type.Optional(\n Type.Boolean({ description: \"Treat pattern as a literal string.\" })\n ),\n limit: Type.Optional(\n Type.Number({ description: `Maximum matches. Default ${DEFAULT_LIMIT}.` })\n )\n});\n\ntype GrepFilesParameters = Static<typeof grepFilesParameters>;\n\nexport function createGrepFilesTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"grep_files\",\n label: \"Grep Files\",\n description:\n \"Search file contents using grep. Returns matching file paths, line numbers, and matched lines.\",\n parameters: grepFilesParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as GrepFilesParameters;\n const searchPath = resolveToolPath(env.cwd, params.path ?? \".\");\n const limit = Math.max(1, params.limit ?? DEFAULT_LIMIT);\n const result = await runGrep(searchPath, params, limit, signal);\n const truncated = truncateText(result.lines.join(\"\\n\"));\n\n return {\n content: [\n {\n type: \"text\",\n text: truncated.text || \"No matches found\"\n }\n ],\n details: {\n path: searchPath,\n pattern: params.pattern,\n matchCount: result.matchCount,\n matchLimitReached: result.matchLimitReached ? limit : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nfunction runGrep(\n searchPath: string,\n params: GrepFilesParameters,\n limit: number,\n signal: AbortSignal | undefined\n): Promise<{ lines: string[]; matchCount: number; matchLimitReached: boolean }> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error(\"Operation aborted\"));\n return;\n }\n\n const args = [\n \"-R\",\n \"-n\",\n \"-I\",\n \"--exclude-dir=.git\",\n \"--exclude-dir=node_modules\",\n \"--exclude-dir=dist\"\n ];\n if (params.ignoreCase) {\n args.push(\"-i\");\n }\n if (params.literal) {\n args.push(\"-F\");\n }\n if (params.glob) {\n args.push(\"--include\", params.glob);\n }\n args.push(\"--\", params.pattern, searchPath);\n\n const child = spawn(\"grep\", args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n let settled = false;\n\n const settle = (callback: () => void): void => {\n if (settled) {\n return;\n }\n settled = true;\n signal?.removeEventListener(\"abort\", onAbort);\n callback();\n };\n\n const onAbort = (): void => {\n child.kill();\n settle(() => reject(new Error(\"Operation aborted\")));\n };\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"error\", (error) => {\n settle(() => reject(new Error(`Failed to run grep: ${error.message}`)));\n });\n child.on(\"close\", (code) => {\n if (code !== 0 && code !== 1) {\n settle(() => reject(new Error(stderr.trim() || `grep exited with ${code}`)));\n return;\n }\n\n const allLines = stdout\n .split(/\\r?\\n/)\n .filter(Boolean)\n .map((line) => formatGrepLine(searchPath, line));\n const lines = allLines.slice(0, limit);\n settle(() =>\n resolve({\n lines,\n matchCount: lines.length,\n matchLimitReached: allLines.length > limit\n })\n );\n });\n });\n}\n\nfunction formatGrepLine(searchPath: string, line: string): string {\n const firstColon = line.indexOf(\":\");\n if (firstColon === -1) {\n return line;\n }\n\n const secondColon = line.indexOf(\":\", firstColon + 1);\n if (secondColon === -1) {\n return line;\n }\n\n const rawPath = line.slice(0, firstColon);\n const lineNumber = line.slice(firstColon + 1, secondColon);\n const text = line.slice(secondColon + 1);\n const displayPath = toPosix(relative(searchPath, rawPath)) || rawPath;\n return `${displayPath}:${lineNumber}:${text}`;\n}\n\nfunction toPosix(value: string): string {\n return value.split(sep).join(\"/\");\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\nimport { truncateText } from \"./truncate\";\n\nconst readFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to read.\" }),\n offset: Type.Optional(\n Type.Number({ description: \"Line number to start reading from, 1-indexed.\" })\n ),\n limit: Type.Optional(Type.Number({ description: \"Maximum number of lines.\" }))\n});\n\ntype ReadFileParameters = Static<typeof readFileParameters>;\n\nexport function createReadFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"read_file\",\n label: \"Read File\",\n description:\n \"Read a UTF-8 text file. Use offset and limit for large files.\",\n parameters: readFileParameters,\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as ReadFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n const fileStat = await stat(absolutePath);\n throwIfAborted(signal);\n\n if (!fileStat.isFile()) {\n throw new Error(`Path is not a file: ${params.path}`);\n }\n\n const content = await readFile(absolutePath, \"utf8\");\n throwIfAborted(signal);\n\n const selected = selectLineRange(content, params.offset, params.limit);\n const truncated = truncateText(selected);\n\n return {\n content: [{ type: \"text\", text: truncated.text }],\n details: {\n path: absolutePath,\n bytes: Buffer.byteLength(content, \"utf8\"),\n range:\n params.offset !== undefined || params.limit !== undefined\n ? { offset: params.offset ?? 1, limit: params.limit }\n : undefined,\n truncated: truncated.truncated\n }\n };\n }\n };\n}\n\nfunction selectLineRange(\n content: string,\n offset: number | undefined,\n limit: number | undefined\n): string {\n if (offset === undefined && limit === undefined) {\n return content;\n }\n\n const lines = content.split(/\\r\\n|\\n|\\r/);\n const start = Math.max(0, (offset ?? 1) - 1);\n const end = limit === undefined ? lines.length : start + Math.max(0, limit);\n return lines.slice(start, end).join(\"\\n\");\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { ExecutionEnv } from \"@earendil-works/pi-agent-core\";\nimport { Type, type Static } from \"@earendil-works/pi-ai\";\nimport type { ServerPlugin } from \"@hold-rein/plugin-server\";\n\nimport { resolveToolPath } from \"./path-utils\";\n\nconst writeFileParameters = Type.Object({\n path: Type.String({ description: \"Path to the file to write.\" }),\n content: Type.String({ description: \"Full file content to write.\" })\n});\n\ntype WriteFileParameters = Static<typeof writeFileParameters>;\n\nexport function createWriteFileTool(env: ExecutionEnv): ServerPlugin.PluginTool {\n return {\n name: \"write_file\",\n label: \"Write File\",\n description:\n \"Create or overwrite a UTF-8 text file, creating parent directories as needed.\",\n parameters: writeFileParameters,\n beforeExecute({ event, requestApproval }) {\n const params = event.input as Partial<WriteFileParameters>;\n return requestApproval(`Allowed to write file: ${params.path ?? \"\"}`);\n },\n async execute(_toolCallId, rawParams, signal) {\n const params = rawParams as WriteFileParameters;\n throwIfAborted(signal);\n\n const absolutePath = resolveToolPath(env.cwd, params.path);\n await mkdir(dirname(absolutePath), { recursive: true });\n throwIfAborted(signal);\n\n await writeFile(absolutePath, params.content, \"utf8\");\n throwIfAborted(signal);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Successfully wrote ${Buffer.byteLength(\n params.content,\n \"utf8\"\n )} bytes to ${params.path}.`\n }\n ],\n details: {\n path: absolutePath,\n bytes: Buffer.byteLength(params.content, \"utf8\")\n }\n };\n }\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n}\n","export const PLUGIN_ID = \"__code__plugin\";\n","import type { ServerPlugin } from \"@hold-rein/plugin-server\";\nimport {\n createDeleteFileTool,\n createEditFileTool,\n createFindFilesTool,\n createGrepFilesTool,\n createReadFileTool,\n createWriteFileTool\n} from './server/tools'\n\nimport { PLUGIN_ID } from \"./plugin-id\";\n\nconst baseServerPlugin: ServerPlugin.Plugin = {\n id: PLUGIN_ID,\n contributionResolver: (context) => {\n return {\n tools: [\n createReadFileTool(context.env),\n createWriteFileTool(context.env),\n createDeleteFileTool(context.env),\n createGrepFilesTool(context.env),\n createFindFilesTool(context.env),\n createEditFileTool(context.env),\n ]\n }\n }\n};\n\nexport default baseServerPlugin;\n"],"names":["resolveToolPath","cwd","filePath","isAbsolute","resolve","normalizeTextLineEndings","text","deleteFileParameters","Type","createDeleteFileTool","env","event","requestApproval","params","_toolCallId","rawParams","signal","throwIfAborted","absolutePath","unlink","editReplacementParameters","editFileParameters","createEditFileTool","replacements","normalizeReplacements","rawContent","readFile","lineEnding","content","matched","matchReplacements","newContent","applyReplacements","writeFile","restoreLineEndings","diff","formatReplacementDiff","edits","edit","index","path","replacement","occurrences","findOccurrences","occurrenceIndex","a","b","i","previous","current","search","indexes","nextContent","line","DEFAULT_MAX_OUTPUT_LENGTH","truncateText","maxLength","DEFAULT_LIMIT","ignoredDirectories","findFilesParameters","createFindFilesTool","searchPath","limit","matcher","createPatternMatcher","results","walkFiles","truncated","root","entries","readdir","entry","join","stat","relativePath","toPosix","relative","pattern","regex","wildcardToRegExp","matchRelativePath","sep","basename","source","value","grepFilesParameters","createGrepFilesTool","result","runGrep","reject","args","child","spawn","stdout","stderr","settled","settle","callback","onAbort","chunk","error","code","allLines","formatGrepLine","lines","firstColon","secondColon","rawPath","lineNumber","readFileParameters","createReadFileTool","fileStat","selected","selectLineRange","offset","start","end","writeFileParameters","createWriteFileTool","mkdir","dirname","PLUGIN_ID","baseServerPlugin","context"],"mappings":"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"}
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .base-file-tool{display:grid;gap:10px}.base-file-tool__meta{color:var(--app-color-text-secondary, var(--app-color-text, currentColor));display:flex;flex-wrap:wrap;font-size:12px;gap:8px}.base-file-tool__chip{border:1px solid var(--app-color-border-secondary, currentColor);border-radius:6px;color:var(--app-color-text-secondary, var(--app-color-text, currentColor));padding:1px 7px}.base-file-tool__pre,.base-file-tool__list{background:var(--app-color-bg-container, transparent);border:1px solid var(--app-color-border-secondary, currentColor);border-radius:6px;color:var(--app-color-text, currentColor);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.55;margin:0;max-height:360px;overflow:auto;padding:10px;white-space:pre-wrap;word-break:break-word}.base-file-tool__list{display:grid;gap:4px;list-style:none}.base-file-tool__list-item{border-bottom:1px solid var(--app-color-border-secondary, currentColor);padding-bottom:4px}.base-file-tool__list-item:last-child{border-bottom:0;padding-bottom:0}.base-file-tool__editor{border:1px solid var(--app-color-border-secondary, currentColor);border-radius:6px;min-height:160px;overflow:hidden}.base-file-tool__empty{color:var(--app-color-text-secondary, var(--app-color-text, currentColor))}.base-file-change-summary{background:var(--app-color-bg-container, transparent);border:1px solid var(--app-color-border-secondary, currentColor);border-radius:8px;color:var(--app-color-text, currentColor);display:grid;gap:10px;padding:10px}.base-file-change-summary__title{background:var(--app-color-fill-secondary, transparent);border-radius:7px 7px 0 0;color:var(--app-color-text, currentColor);font-size:12px;font-weight:600;margin:-10px -10px 0;padding:12px 8px}.base-file-change-summary__list,.base-file-change-summary__item{display:grid;gap:6px}.base-file-change-summary__row{align-items:center;background:transparent;border:0;color:var(--app-color-text, currentColor);display:flex;font:inherit;gap:8px;min-width:0;padding:4px 0;text-align:left}button.base-file-change-summary__row{cursor:pointer}button.base-file-change-summary__row:hover{color:var(--app-color-primary, currentColor)}.base-file-change-summary__icon{color:var(--app-color-text-secondary, var(--app-color-text, currentColor));flex:0 0 auto}.base-file-change-summary__path{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}.base-file-change-summary__row--delete,.base-file-change-summary__row--delete .base-file-change-summary__icon{color:var(--app-color-danger, currentColor)}.base-file-change-summary__stats{align-items:center;display:inline-flex;flex:0 0 auto;font-size:12px;font-weight:600;gap:4px;margin-left:auto}.base-file-change-summary__stat--added{color:var(--app-color-success, currentColor)}.base-file-change-summary__stat--removed{color:var(--app-color-danger, currentColor)}.base-file-change-summary__preview{margin-left:22px}
@@ -0,0 +1,13 @@
1
+ interface CodePreviewProps {
2
+ content: string;
3
+ path: string | undefined;
4
+ }
5
+ interface DiffPreviewProps {
6
+ modified: string;
7
+ original: string;
8
+ path: string | undefined;
9
+ }
10
+ export declare function CodePreview({ content, path }: CodePreviewProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function DiffPreview({ modified, original, path }: DiffPreviewProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=code-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-preview.d.ts","sourceRoot":"","sources":["../../../../src/web/tools/file-tools/code-preview.tsx"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAsB9D;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CA+BzE"}
@@ -0,0 +1,15 @@
1
+ import type { WebPlugin } from "@hold-rein/plugin-web";
2
+ import "./file-tool-render.css";
3
+ export declare function ReadFileToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
4
+ export declare function WriteFileToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function DeleteFileToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function GrepFilesToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function FindFilesToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function EditFileToolRender(props: WebPlugin.ToolRenderProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare const readFileTool: WebPlugin.ToolRender;
10
+ export declare const writeFileTool: WebPlugin.ToolRender;
11
+ export declare const deleteFileTool: WebPlugin.ToolRender;
12
+ export declare const grepFilesTool: WebPlugin.ToolRender;
13
+ export declare const findFilesTool: WebPlugin.ToolRender;
14
+ export declare const editFileTool: WebPlugin.ToolRender;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/web/tools/file-tools/index.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAUvD,OAAO,wBAAwB,CAAC;AAOhC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CAiBlE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CAqBnE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CAkBpE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CAcnE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CAcnE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,2CA4BlE;AAqFD,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,UAGpC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,UAGrC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,SAAS,CAAC,UAGtC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,UAGrC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,UAGrC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,UAGpC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getLanguageFromPath(path: string | undefined): string;
2
+ //# sourceMappingURL=language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../../../../src/web/tools/file-tools/language.ts"],"names":[],"mappings":"AAwBA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOpE"}
@@ -0,0 +1,7 @@
1
+ import type { WebPlugin } from "@hold-rein/plugin-web";
2
+ export declare function getStringArg(args: Record<string, unknown>, key: string): string | undefined;
3
+ export declare function getTextResult(result: WebPlugin.ToolResultMessage | undefined): string;
4
+ export declare function splitResultLines(text: string): string[];
5
+ export declare function getWorkspaceRelativePath(path: string | undefined, workspacePath: string | undefined): string | undefined;
6
+ export declare function useMonacoTheme(): "vs" | "vs-dark";
7
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/web/tools/file-tools/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,iBAAiB,GAAG,SAAS,GAAG,MAAM,CASrF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC,MAAM,GAAG,SAAS,CAoBpB;AAED,wBAAgB,cAAc,IAAI,IAAI,GAAG,SAAS,CAsBjD"}
@@ -0,0 +1,2 @@
1
+ export * from './file-tools';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/web/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
@@ -0,0 +1,22 @@
1
+ import type { WebPlugin } from "@hold-rein/plugin-web";
2
+ import "./file-change-summary.css";
3
+ type FileOperation = "delete" | "edit" | "write";
4
+ interface CodeContent {
5
+ text: string;
6
+ type: "code";
7
+ }
8
+ interface DiffContent {
9
+ modified: string;
10
+ original: string;
11
+ type: "diff";
12
+ }
13
+ export interface FileChangeSummaryItem {
14
+ content?: CodeContent | DiffContent | undefined;
15
+ operation: FileOperation;
16
+ path: string;
17
+ }
18
+ export declare function FileChangeSummaryTurnFooter({ messages, workspacePath }: WebPlugin.TurnFooterRenderProps): import("react/jsx-runtime").JSX.Element | null;
19
+ export declare function getFileChangeSummaryItems(messages: readonly WebPlugin.AgentMessage[]): FileChangeSummaryItem[];
20
+ export declare const fileChangeSummaryTurnFooter: WebPlugin.TurnFooterRender;
21
+ export {};
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/web/turn-footers/file-change-summary/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAWvD,OAAO,2BAA2B,CAAC;AAEnC,KAAK,aAAa,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC;IAChD,SAAS,EAAE,aAAa,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAeD,wBAAgB,2BAA2B,CAAC,EAC1C,QAAQ,EACR,aAAa,EACd,EAAE,SAAS,CAAC,qBAAqB,kDA2DjC;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,SAAS,CAAC,YAAY,EAAE,GAC1C,qBAAqB,EAAE,CAyBzB;AAgBD,eAAO,MAAM,2BAA2B,EAAE,SAAS,CAAC,gBAGnD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./file-change-summary";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/web/turn-footers/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
package/dist/web.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { WebPlugin } from '@hold-rein/plugin-web';
2
+ declare const baseWebPlugin: WebPlugin.Plugin;
3
+ export default baseWebPlugin;
4
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAYtD,QAAA,MAAM,aAAa,EAAE,SAAS,CAAC,MAe9B,CAAA;AAED,eAAe,aAAa,CAAA"}
@@ -0,0 +1,9 @@
1
+ (function(t,c){typeof exports=="object"&&typeof module<"u"?module.exports=c(require("react/jsx-runtime"),require("@ant-design/icons"),require("@monaco-editor/react"),require("react")):typeof define=="function"&&define.amd?define(["react/jsx-runtime","@ant-design/icons","@monaco-editor/react","react"],c):(t=typeof globalThis<"u"?globalThis:t||self,t.HoldReinCodePlugin=c(t.jsxRuntime,t.icons,t.Editor,t.react))})(this,(function(t,c,_,f){"use strict";const P={c:"c",cpp:"cpp",cs:"csharp",css:"css",go:"go",html:"html",java:"java",js:"javascript",json:"json",jsx:"javascript",md:"markdown",py:"python",rs:"rust",sh:"shell",sql:"sql",ts:"typescript",tsx:"typescript",txt:"plaintext",xml:"xml",yaml:"yaml",yml:"yaml"};function y(e){var o;if(!e)return"plaintext";const n=(o=e.split(".").pop())==null?void 0:o.toLowerCase();return n?P[n]??"plaintext":"plaintext"}function s(e,n){const o=e[n];return typeof o=="string"?o:void 0}function u(e){return e?e.content.filter(n=>n.type==="text").map(n=>n.text).join(`
2
+ `):""}function x(e){return e.split(/\r?\n/).filter(Boolean)}function T(e,n){if(!e||!n)return e;const o=v(e),a=k(v(n));if(o===a)return".";const l=`${a}/`;return o.startsWith(l)?o.slice(l.length):e}function b(){const[e,n]=f.useState(()=>document.documentElement.dataset.themeMode==="dark"?"vs-dark":"vs");return f.useEffect(()=>{const o=new MutationObserver(()=>{n(document.documentElement.dataset.themeMode==="dark"?"vs-dark":"vs")});return o.observe(document.documentElement,{attributeFilter:["data-theme-mode"]}),()=>{o.disconnect()}},[]),e}function v(e){return e.replace(/\\/g,"/")}function k(e){return e.replace(/\/+$/g,"")}function p({content:e,path:n}){const o=b();return t.jsx("div",{className:"base-file-tool__editor",children:t.jsx(f.Suspense,{fallback:t.jsx("pre",{className:"base-file-tool__pre",children:e}),children:t.jsx(_,{height:Math.min(420,Math.max(160,e.split(`
3
+ `).length*20)),language:y(n),options:{lineNumbersMinChars:3,minimap:{enabled:!1},readOnly:!0,scrollBeyondLastLine:!1,wordWrap:"on"},theme:o,value:e})})})}function w({modified:e,original:n,path:o}){const a=b(),l=Math.min(420,Math.max(180,Math.max(n.split(`
4
+ `).length,e.split(`
5
+ `).length)*22));return t.jsx("div",{className:"base-file-tool__editor",children:t.jsx(f.Suspense,{fallback:t.jsx("pre",{className:"base-file-tool__pre",children:e}),children:t.jsx(_.DiffEditor,{height:l,language:y(o),modified:e,options:{lineNumbersMinChars:3,minimap:{enabled:!1},readOnly:!0,renderSideBySide:!1,scrollBeyondLastLine:!1,wordWrap:"on"},original:n,theme:a})})})}function S(e){const n=e.toolCall.arguments,o=s(n,"path"),a=u(e.result);return t.jsx(e.DefaultToolRender,{title:"读取文件",icon:t.jsx(c.ReadOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:o,workspacePath:e.workspacePath}),a?t.jsx(p,{content:a,path:o}):t.jsx("span",{className:"base-file-tool__empty",children:"等待读取结果"})]})})}function j(e){var r;const n=e.toolCall.arguments,o=s(n,"path"),a=s(n,"content")??"",l=(r=e.result)!=null&&r.isError?u(e.result):"";return t.jsx(e.DefaultToolRender,{title:"写入文件",icon:t.jsx(c.SaveOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:o,workspacePath:e.workspacePath}),a?t.jsx(p,{content:a,path:o}):t.jsx("span",{className:"base-file-tool__empty",children:"无写入内容"}),l?t.jsx("pre",{className:"base-file-tool__pre",children:l}):null]})})}function C(e){var l;const n=e.toolCall.arguments,o=s(n,"path"),a=(l=e.result)!=null&&l.isError?u(e.result):"";return t.jsx(e.DefaultToolRender,{title:"删除文件",icon:t.jsx(c.DeleteOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:o,workspacePath:e.workspacePath}),e.result?null:t.jsx("span",{className:"base-file-tool__empty",children:"等待删除结果"}),a?t.jsx("pre",{className:"base-file-tool__pre",children:a}):null]})})}function O(e){const n=e.toolCall.arguments,o=s(n,"pattern"),a=s(n,"path")??".",l=x(u(e.result));return t.jsx(e.DefaultToolRender,{title:"按内容查找",icon:t.jsx(c.SearchOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:a,pattern:o,workspacePath:e.workspacePath}),t.jsx(N,{emptyText:"等待 grep 结果",lines:l})]})})}function E(e){const n=e.toolCall.arguments,o=s(n,"pattern"),a=s(n,"path")??".",l=x(u(e.result));return t.jsx(e.DefaultToolRender,{title:"按文件名查找",icon:t.jsx(c.FileSearchOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:a,pattern:o,workspacePath:e.workspacePath}),t.jsx(N,{emptyText:"等待查找结果",lines:l})]})})}function D(e){var r;const n=e.toolCall.arguments,o=s(n,"path"),a=$(n),l=(r=e.result)!=null&&r.isError?u(e.result):"";return t.jsx(e.DefaultToolRender,{title:"编辑文件",icon:t.jsx(c.DiffOutlined,{}),children:t.jsxs("div",{className:"base-file-tool",children:[t.jsx(h,{path:o,workspacePath:e.workspacePath}),a.length?a.map((d,i)=>t.jsx(w,{modified:d.newText,original:d.oldText,path:o},`${i}-${d.oldText}`)):t.jsx("span",{className:"base-file-tool__empty",children:"无可预览的替换内容"}),l?t.jsx("pre",{className:"base-file-tool__pre",children:l}):null]})})}function h({path:e,pattern:n,workspacePath:o}){const a=T(e,o);return t.jsxs("div",{className:"base-file-tool__meta",children:[a?t.jsxs("span",{className:"base-file-tool__chip",children:[t.jsx(c.FileTextOutlined,{})," ",a]}):null,n?t.jsxs("span",{className:"base-file-tool__chip",children:["pattern: ",n]}):null]})}function N({emptyText:e,lines:n}){return n.length?t.jsx("ul",{className:"base-file-tool__list",children:n.map((o,a)=>t.jsx("li",{className:"base-file-tool__list-item",children:o},`${a}-${o}`))}):t.jsx("span",{className:"base-file-tool__empty",children:e})}function $(e){const n=s(e,"oldText"),o=s(e,"newText"),a=[];n!==void 0&&o!==void 0&&a.push({oldText:n,newText:o});const l=e.edits;if(!Array.isArray(l))return a;for(const r of l){if(!r||typeof r!="object")continue;const d=r;typeof d.oldText=="string"&&typeof d.newText=="string"&&a.push({oldText:d.oldText,newText:d.newText})}return a}const L={Render:S,toolName:"read_file"},M={Render:j,toolName:"write_file"},I={Render:C,toolName:"delete_file"},W={Render:O,toolName:"grep_files"},q={Render:E,toolName:"find_files"},B={Render:D,toolName:"edit_file"},A={delete:"删除",edit:"编辑",write:"新增"},z=["edit","write","delete"];function K({messages:e,workspacePath:n}){const o=f.useMemo(()=>G(e),[e]),[a,l]=f.useState(()=>new Set);if(!o.length)return null;const r=Y(o),d=z.filter(i=>r[i]>0).map(i=>`${A[i]}${r[i]}个文件`).join("、");return t.jsxs("section",{className:"base-file-change-summary",children:[t.jsx("div",{className:"base-file-change-summary__title",children:d}),t.jsx("div",{className:"base-file-change-summary__list",children:o.map((i,ne)=>{const g=`${i.operation}:${i.path}:${ne}`,oe=i.content!==void 0,F=a.has(g);return t.jsxs("div",{className:"base-file-change-summary__item",children:[t.jsx(J,{displayPath:T(i.path,n)??i.path,expanded:F,item:i,onToggle:oe?()=>{l(ae=>te(ae,g))}:void 0}),F&&i.content?t.jsx("div",{className:"base-file-change-summary__preview",children:t.jsx(Q,{item:i})}):null]},g)})})]})}function G(e){const n=[],o=U(e);for(const a of e)if(a.role==="assistant")for(const l of a.content){if(l.type!=="toolCall"||o.has(l.id))continue;const r=V(l);r&&n.push(r)}return n}function U(e){const n=new Set;for(const o of e)o.role==="toolResult"&&o.isError&&n.add(o.toolCallId);return n}const H={id:"file-change-summary",Render:K};function J({displayPath:e,expanded:n,item:o,onToggle:a}){const l=["base-file-change-summary__row",o.operation==="delete"?"base-file-change-summary__row--delete":""].filter(Boolean).join(" "),r=R(o),d=t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"base-file-change-summary__icon",children:ee(o.operation)}),t.jsx("span",{className:"base-file-change-summary__path",children:e}),r?t.jsx(Z,{stats:r}):null]});return a?t.jsx("button",{"aria-expanded":n,className:l,onClick:a,type:"button",children:d}):t.jsx("div",{className:l,children:d})}function Q({item:e}){var n,o;return((n=e.content)==null?void 0:n.type)==="code"?t.jsx(p,{content:e.content.text,path:e.path}):((o=e.content)==null?void 0:o.type)==="diff"?t.jsx(w,{modified:e.content.modified,original:e.content.original,path:e.path}):null}function V(e){const n=s(e.arguments,"path");if(!n)return;if(e.name==="write_file")return{content:{text:s(e.arguments,"content")??"",type:"code"},operation:"write",path:n};if(e.name==="delete_file")return{operation:"delete",path:n};if(e.name!=="edit_file")return;const o=X(e.arguments);return{content:{modified:o.map(a=>a.newText).join(`
6
+ `),original:o.map(a=>a.oldText).join(`
7
+ `),type:"diff"},operation:"edit",path:n}}function X(e){const n=[],o=s(e,"oldText"),a=s(e,"newText");if(o!==void 0&&a!==void 0&&n.push({newText:a,oldText:o}),!Array.isArray(e.edits))return n;for(const l of e.edits){if(!l||typeof l!="object")continue;const r=l;typeof r.newText=="string"&&typeof r.oldText=="string"&&n.push({newText:r.newText,oldText:r.oldText})}return n}function Y(e){return e.reduce((n,o)=>({...n,[o.operation]:n[o.operation]+1}),{delete:0,edit:0,write:0})}function Z({stats:e}){return t.jsxs("span",{"aria-label":`新增 ${e.added} 行,删除 ${e.removed} 行`,className:"base-file-change-summary__stats",children:[t.jsxs("span",{className:"base-file-change-summary__stat base-file-change-summary__stat--added",children:["+",e.added]}),e.removed>0?t.jsxs("span",{className:"base-file-change-summary__stat base-file-change-summary__stat--removed",children:["-",e.removed]}):null]})}function R(e){var n,o;if(((n=e.content)==null?void 0:n.type)==="code")return{added:m(e.content.text),removed:0};if(((o=e.content)==null?void 0:o.type)==="diff")return{added:m(e.content.modified),removed:m(e.content.original)}}function m(e){const n=e.replace(/\n$/,"");return n?n.split(`
8
+ `).length:0}function ee(e){return e==="edit"?t.jsx(c.DiffOutlined,{}):e==="write"?t.jsx(c.SaveOutlined,{}):t.jsx(c.DeleteOutlined,{})}function te(e,n){const o=new Set(e);return o.has(n)?o.delete(n):o.add(n),o}return{id:"__code__plugin",contributionResolver:{toolRenders:[L,M,I,W,q,B],turnFooterRenders:[H]}}}));
9
+ //# sourceMappingURL=web.umd.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.umd.cjs","sources":["../src/web/tools/file-tools/language.ts","../src/web/tools/file-tools/utils.ts","../src/web/tools/file-tools/code-preview.tsx","../src/web/tools/file-tools/index.tsx","../src/web/turn-footers/file-change-summary/index.tsx","../src/web.ts","../src/plugin-id.ts"],"sourcesContent":["const languageByExtension: Readonly<Record<string, string>> = {\n c: \"c\",\n cpp: \"cpp\",\n cs: \"csharp\",\n css: \"css\",\n go: \"go\",\n html: \"html\",\n java: \"java\",\n js: \"javascript\",\n json: \"json\",\n jsx: \"javascript\",\n md: \"markdown\",\n py: \"python\",\n rs: \"rust\",\n sh: \"shell\",\n sql: \"sql\",\n ts: \"typescript\",\n tsx: \"typescript\",\n txt: \"plaintext\",\n xml: \"xml\",\n yaml: \"yaml\",\n yml: \"yaml\"\n};\n\nexport function getLanguageFromPath(path: string | undefined): string {\n if (!path) {\n return \"plaintext\";\n }\n\n const extension = path.split(\".\").pop()?.toLowerCase();\n return extension ? languageByExtension[extension] ?? \"plaintext\" : \"plaintext\";\n}\n","import { useEffect, useState } from \"react\";\nimport type { WebPlugin } from \"@hold-rein/plugin-web\";\n\nexport function getStringArg(\n args: Record<string, unknown>,\n key: string\n): string | undefined {\n const value = args[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function getTextResult(result: WebPlugin.ToolResultMessage | undefined): string {\n if (!result) {\n return \"\";\n }\n\n return result.content\n .filter((item) => item.type === \"text\")\n .map((item) => item.text)\n .join(\"\\n\");\n}\n\nexport function splitResultLines(text: string): string[] {\n return text.split(/\\r?\\n/).filter(Boolean);\n}\n\nexport function getWorkspaceRelativePath(\n path: string | undefined,\n workspacePath: string | undefined\n): string | undefined {\n if (!path || !workspacePath) {\n return path;\n }\n\n const normalizedPath = normalizePath(path);\n const normalizedWorkspacePath = stripTrailingSeparators(\n normalizePath(workspacePath)\n );\n\n if (normalizedPath === normalizedWorkspacePath) {\n return \".\";\n }\n\n const workspacePrefix = `${normalizedWorkspacePath}/`;\n if (normalizedPath.startsWith(workspacePrefix)) {\n return normalizedPath.slice(workspacePrefix.length);\n }\n\n return path;\n}\n\nexport function useMonacoTheme(): \"vs\" | \"vs-dark\" {\n const [theme, setTheme] = useState<\"vs\" | \"vs-dark\">(() =>\n document.documentElement.dataset.themeMode === \"dark\" ? \"vs-dark\" : \"vs\"\n );\n\n useEffect(() => {\n const observer = new MutationObserver(() => {\n setTheme(\n document.documentElement.dataset.themeMode === \"dark\" ? \"vs-dark\" : \"vs\"\n );\n });\n\n observer.observe(document.documentElement, {\n attributeFilter: [\"data-theme-mode\"]\n });\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return theme;\n}\n\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, \"/\");\n}\n\nfunction stripTrailingSeparators(path: string): string {\n return path.replace(/\\/+$/g, \"\");\n}\n","import Editor, { DiffEditor } from \"@monaco-editor/react\";\nimport { Suspense } from \"react\";\n\nimport { getLanguageFromPath } from \"./language\";\nimport { useMonacoTheme } from \"./utils\";\n\ninterface CodePreviewProps {\n content: string;\n path: string | undefined;\n}\n\ninterface DiffPreviewProps {\n modified: string;\n original: string;\n path: string | undefined;\n}\n\nexport function CodePreview({ content, path }: CodePreviewProps) {\n const theme = useMonacoTheme();\n\n return (\n <div className=\"base-file-tool__editor\">\n <Suspense fallback={<pre className=\"base-file-tool__pre\">{content}</pre>}>\n <Editor\n height={Math.min(420, Math.max(160, content.split(\"\\n\").length * 20))}\n language={getLanguageFromPath(path)}\n options={{\n lineNumbersMinChars: 3,\n minimap: { enabled: false },\n readOnly: true,\n scrollBeyondLastLine: false,\n wordWrap: \"on\"\n }}\n theme={theme}\n value={content}\n />\n </Suspense>\n </div>\n );\n}\n\nexport function DiffPreview({ modified, original, path }: DiffPreviewProps) {\n const theme = useMonacoTheme();\n const height = Math.min(\n 420,\n Math.max(\n 180,\n Math.max(original.split(\"\\n\").length, modified.split(\"\\n\").length) * 22\n )\n );\n\n return (\n <div className=\"base-file-tool__editor\">\n <Suspense fallback={<pre className=\"base-file-tool__pre\">{modified}</pre>}>\n <DiffEditor\n height={height}\n language={getLanguageFromPath(path)}\n modified={modified}\n options={{\n lineNumbersMinChars: 3,\n minimap: { enabled: false },\n readOnly: true,\n renderSideBySide: false,\n scrollBeyondLastLine: false,\n wordWrap: \"on\"\n }}\n original={original}\n theme={theme}\n />\n </Suspense>\n </div>\n );\n}\n","import {\n DiffOutlined,\n DeleteOutlined,\n FileSearchOutlined,\n FileTextOutlined,\n ReadOutlined,\n SaveOutlined,\n SearchOutlined\n} from \"@ant-design/icons\";\nimport type { WebPlugin } from \"@hold-rein/plugin-web\";\n\nimport { CodePreview, DiffPreview } from \"./code-preview\";\nimport {\n getStringArg,\n getTextResult,\n getWorkspaceRelativePath,\n splitResultLines\n} from \"./utils\";\n\nimport \"./file-tool-render.css\";\n\ninterface EditReplacement {\n oldText: string;\n newText: string;\n}\n\nexport function ReadFileToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const path = getStringArg(args, \"path\");\n const output = getTextResult(props.result);\n\n return (\n <props.DefaultToolRender title=\"读取文件\" icon={<ReadOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} workspacePath={props.workspacePath} />\n {output ? (\n <CodePreview content={output} path={path} />\n ) : (\n <span className=\"base-file-tool__empty\">等待读取结果</span>\n )}\n </div>\n </props.DefaultToolRender>\n );\n}\n\nexport function WriteFileToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const path = getStringArg(args, \"path\");\n const content = getStringArg(args, \"content\") ?? \"\";\n const errorOutput = props.result?.isError ? getTextResult(props.result) : \"\";\n\n return (\n <props.DefaultToolRender title=\"写入文件\" icon={<SaveOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} workspacePath={props.workspacePath} />\n {content ? (\n <CodePreview content={content} path={path} />\n ) : (\n <span className=\"base-file-tool__empty\">无写入内容</span>\n )}\n {errorOutput ? (\n <pre className=\"base-file-tool__pre\">{errorOutput}</pre>\n ) : null}\n </div>\n </props.DefaultToolRender>\n );\n}\n\nexport function DeleteFileToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const path = getStringArg(args, \"path\");\n const errorOutput = props.result?.isError ? getTextResult(props.result) : \"\";\n\n return (\n <props.DefaultToolRender title=\"删除文件\" icon={<DeleteOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} workspacePath={props.workspacePath} />\n {!props.result ? (\n <span className=\"base-file-tool__empty\">等待删除结果</span>\n ) : null}\n {errorOutput ? (\n <pre className=\"base-file-tool__pre\">{errorOutput}</pre>\n ) : null}\n </div>\n </props.DefaultToolRender>\n );\n}\n\nexport function GrepFilesToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const pattern = getStringArg(args, \"pattern\");\n const path = getStringArg(args, \"path\") ?? \".\";\n const lines = splitResultLines(getTextResult(props.result));\n\n return (\n <props.DefaultToolRender title=\"按内容查找\" icon={<SearchOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} pattern={pattern} workspacePath={props.workspacePath} />\n <ResultList emptyText=\"等待 grep 结果\" lines={lines} />\n </div>\n </props.DefaultToolRender>\n );\n}\n\nexport function FindFilesToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const pattern = getStringArg(args, \"pattern\");\n const path = getStringArg(args, \"path\") ?? \".\";\n const lines = splitResultLines(getTextResult(props.result));\n\n return (\n <props.DefaultToolRender title=\"按文件名查找\" icon={<FileSearchOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} pattern={pattern} workspacePath={props.workspacePath} />\n <ResultList emptyText=\"等待查找结果\" lines={lines} />\n </div>\n </props.DefaultToolRender>\n );\n}\n\nexport function EditFileToolRender(props: WebPlugin.ToolRenderProps) {\n const args = props.toolCall.arguments;\n const path = getStringArg(args, \"path\");\n const replacements = getEditReplacements(args);\n const errorOutput = props.result?.isError ? getTextResult(props.result) : \"\";\n\n return (\n <props.DefaultToolRender title=\"编辑文件\" icon={<DiffOutlined />}>\n <div className=\"base-file-tool\">\n <ToolMeta path={path} workspacePath={props.workspacePath} />\n {replacements.length ? (\n replacements.map((replacement, index) => (\n <DiffPreview\n key={`${index}-${replacement.oldText}`}\n modified={replacement.newText}\n original={replacement.oldText}\n path={path}\n />\n ))\n ) : (\n <span className=\"base-file-tool__empty\">无可预览的替换内容</span>\n )}\n {errorOutput ? (\n <pre className=\"base-file-tool__pre\">{errorOutput}</pre>\n ) : null}\n </div>\n </props.DefaultToolRender>\n );\n}\n\nfunction ToolMeta({\n path,\n pattern,\n workspacePath\n}: {\n path: string | undefined;\n pattern?: string | undefined;\n workspacePath?: string | undefined;\n}) {\n const displayPath = getWorkspaceRelativePath(path, workspacePath);\n\n return (\n <div className=\"base-file-tool__meta\">\n {displayPath ? (\n <span className=\"base-file-tool__chip\">\n <FileTextOutlined /> {displayPath}\n </span>\n ) : null}\n {pattern ? (\n <span className=\"base-file-tool__chip\">pattern: {pattern}</span>\n ) : null}\n </div>\n );\n}\n\nfunction ResultList({\n emptyText,\n lines\n}: {\n emptyText: string;\n lines: string[];\n}) {\n if (!lines.length) {\n return <span className=\"base-file-tool__empty\">{emptyText}</span>;\n }\n\n return (\n <ul className=\"base-file-tool__list\">\n {lines.map((line, index) => (\n <li className=\"base-file-tool__list-item\" key={`${index}-${line}`}>\n {line}\n </li>\n ))}\n </ul>\n );\n}\n\nfunction getEditReplacements(\n args: Record<string, unknown>\n): EditReplacement[] {\n const oldText = getStringArg(args, \"oldText\");\n const newText = getStringArg(args, \"newText\");\n const replacements: EditReplacement[] = [];\n\n if (oldText !== undefined && newText !== undefined) {\n replacements.push({ oldText, newText });\n }\n\n const edits = args.edits;\n if (!Array.isArray(edits)) {\n return replacements;\n }\n\n for (const edit of edits) {\n if (!edit || typeof edit !== \"object\") {\n continue;\n }\n\n const candidate = edit as Record<string, unknown>;\n if (\n typeof candidate.oldText === \"string\" &&\n typeof candidate.newText === \"string\"\n ) {\n replacements.push({\n oldText: candidate.oldText,\n newText: candidate.newText\n });\n }\n }\n\n return replacements;\n}\n\nexport const readFileTool: WebPlugin.ToolRender = {\n Render: ReadFileToolRender,\n toolName: \"read_file\"\n};\n\nexport const writeFileTool: WebPlugin.ToolRender = {\n Render: WriteFileToolRender,\n toolName: \"write_file\"\n};\n\nexport const deleteFileTool: WebPlugin.ToolRender = {\n Render: DeleteFileToolRender,\n toolName: \"delete_file\"\n};\n\nexport const grepFilesTool: WebPlugin.ToolRender = {\n Render: GrepFilesToolRender,\n toolName: \"grep_files\"\n};\n\nexport const findFilesTool: WebPlugin.ToolRender = {\n Render: FindFilesToolRender,\n toolName: \"find_files\"\n};\n\nexport const editFileTool: WebPlugin.ToolRender = {\n Render: EditFileToolRender,\n toolName: \"edit_file\"\n};\n","import {\n DeleteOutlined,\n DiffOutlined,\n SaveOutlined\n} from \"@ant-design/icons\";\nimport { useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { WebPlugin } from \"@hold-rein/plugin-web\";\n\nimport {\n CodePreview,\n DiffPreview\n} from \"../../tools/file-tools/code-preview\";\nimport {\n getStringArg,\n getWorkspaceRelativePath\n} from \"../../tools/file-tools/utils\";\n\nimport \"./file-change-summary.css\";\n\ntype FileOperation = \"delete\" | \"edit\" | \"write\";\n\ninterface CodeContent {\n text: string;\n type: \"code\";\n}\n\ninterface DiffContent {\n modified: string;\n original: string;\n type: \"diff\";\n}\n\nexport interface FileChangeSummaryItem {\n content?: CodeContent | DiffContent | undefined;\n operation: FileOperation;\n path: string;\n}\n\ninterface EditReplacement {\n newText: string;\n oldText: string;\n}\n\nconst operationLabels: Record<FileOperation, string> = {\n delete: \"删除\",\n edit: \"编辑\",\n write: \"新增\"\n};\n\nconst operationOrder: readonly FileOperation[] = [\"edit\", \"write\", \"delete\"];\n\nexport function FileChangeSummaryTurnFooter({\n messages,\n workspacePath\n}: WebPlugin.TurnFooterRenderProps) {\n const items = useMemo(() => getFileChangeSummaryItems(messages), [messages]);\n const [expandedKeys, setExpandedKeys] = useState<ReadonlySet<string>>(\n () => new Set()\n );\n\n if (!items.length) {\n return null;\n }\n\n const counts = countOperations(items);\n const title = operationOrder\n .filter((operation) => counts[operation] > 0)\n .map(\n (operation) =>\n `${operationLabels[operation]}${counts[operation]}个文件`\n )\n .join(\"、\");\n\n return (\n <section className=\"base-file-change-summary\">\n <div className=\"base-file-change-summary__title\">\n {title}\n </div>\n <div className=\"base-file-change-summary__list\">\n {items.map((item, index) => {\n const itemKey = `${item.operation}:${item.path}:${index}`;\n const canExpand = item.content !== undefined;\n const isExpanded = expandedKeys.has(itemKey);\n\n return (\n <div className=\"base-file-change-summary__item\" key={itemKey}>\n <FileChangeRow\n displayPath={\n getWorkspaceRelativePath(item.path, workspacePath) ?? item.path\n }\n expanded={isExpanded}\n item={item}\n onToggle={\n canExpand\n ? () => {\n setExpandedKeys((current) =>\n toggleExpandedKey(current, itemKey)\n );\n }\n : undefined\n }\n />\n {isExpanded && item.content ? (\n <div className=\"base-file-change-summary__preview\">\n <FileChangePreview item={item} />\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n </section>\n );\n}\n\nexport function getFileChangeSummaryItems(\n messages: readonly WebPlugin.AgentMessage[]\n): FileChangeSummaryItem[] {\n const items: FileChangeSummaryItem[] = [];\n const failedToolCallIds = getFailedToolCallIds(messages);\n\n for (const message of messages) {\n if (message.role !== \"assistant\") {\n continue;\n }\n\n for (const block of message.content) {\n if (block.type !== \"toolCall\") {\n continue;\n }\n if (failedToolCallIds.has(block.id)) {\n continue;\n }\n\n const item = getFileChangeSummaryItem(block);\n if (item) {\n items.push(item);\n }\n }\n }\n\n return items;\n}\n\nfunction getFailedToolCallIds(\n messages: readonly WebPlugin.AgentMessage[]\n): ReadonlySet<string> {\n const failedToolCallIds = new Set<string>();\n\n for (const message of messages) {\n if (message.role === \"toolResult\" && message.isError) {\n failedToolCallIds.add(message.toolCallId);\n }\n }\n\n return failedToolCallIds;\n}\n\nexport const fileChangeSummaryTurnFooter: WebPlugin.TurnFooterRender = {\n id: \"file-change-summary\",\n Render: FileChangeSummaryTurnFooter\n};\n\nfunction FileChangeRow({\n displayPath,\n expanded,\n item,\n onToggle\n}: {\n displayPath: string;\n expanded: boolean;\n item: FileChangeSummaryItem;\n onToggle?: (() => void) | undefined;\n}) {\n const rowClassName = [\n \"base-file-change-summary__row\",\n item.operation === \"delete\" ? \"base-file-change-summary__row--delete\" : \"\"\n ]\n .filter(Boolean)\n .join(\" \");\n const stats = getLineStats(item);\n const content = (\n <>\n <span className=\"base-file-change-summary__icon\">\n {getOperationIcon(item.operation)}\n </span>\n <span className=\"base-file-change-summary__path\">{displayPath}</span>\n {stats ? <LineStats stats={stats} /> : null}\n </>\n );\n\n if (!onToggle) {\n return <div className={rowClassName}>{content}</div>;\n }\n\n return (\n <button\n aria-expanded={expanded}\n className={rowClassName}\n onClick={onToggle}\n type=\"button\"\n >\n {content}\n </button>\n );\n}\n\nfunction FileChangePreview({ item }: { item: FileChangeSummaryItem }) {\n if (item.content?.type === \"code\") {\n return <CodePreview content={item.content.text} path={item.path} />;\n }\n\n if (item.content?.type === \"diff\") {\n return (\n <DiffPreview\n modified={item.content.modified}\n original={item.content.original}\n path={item.path}\n />\n );\n }\n\n return null;\n}\n\nfunction getFileChangeSummaryItem(\n toolCall: WebPlugin.ToolCall\n): FileChangeSummaryItem | undefined {\n const path = getStringArg(toolCall.arguments, \"path\");\n if (!path) {\n return undefined;\n }\n\n if (toolCall.name === \"write_file\") {\n return {\n content: {\n text: getStringArg(toolCall.arguments, \"content\") ?? \"\",\n type: \"code\"\n },\n operation: \"write\",\n path\n };\n }\n\n if (toolCall.name === \"delete_file\") {\n return {\n operation: \"delete\",\n path\n };\n }\n\n if (toolCall.name !== \"edit_file\") {\n return undefined;\n }\n\n const replacements = getEditReplacements(toolCall.arguments);\n\n return {\n content: {\n modified: replacements.map((replacement) => replacement.newText).join(\"\\n\"),\n original: replacements.map((replacement) => replacement.oldText).join(\"\\n\"),\n type: \"diff\"\n },\n operation: \"edit\",\n path\n };\n}\n\nfunction getEditReplacements(\n args: Record<string, unknown>\n): EditReplacement[] {\n const replacements: EditReplacement[] = [];\n const oldText = getStringArg(args, \"oldText\");\n const newText = getStringArg(args, \"newText\");\n\n if (oldText !== undefined && newText !== undefined) {\n replacements.push({ newText, oldText });\n }\n\n if (!Array.isArray(args.edits)) {\n return replacements;\n }\n\n for (const edit of args.edits) {\n if (!edit || typeof edit !== \"object\") {\n continue;\n }\n\n const candidate = edit as Record<string, unknown>;\n if (\n typeof candidate.newText === \"string\" &&\n typeof candidate.oldText === \"string\"\n ) {\n replacements.push({\n newText: candidate.newText,\n oldText: candidate.oldText\n });\n }\n }\n\n return replacements;\n}\n\nfunction countOperations(\n items: readonly FileChangeSummaryItem[]\n): Record<FileOperation, number> {\n return items.reduce<Record<FileOperation, number>>(\n (counts, item) => ({\n ...counts,\n [item.operation]: counts[item.operation] + 1\n }),\n { delete: 0, edit: 0, write: 0 }\n );\n}\n\nfunction LineStats({\n stats\n}: {\n stats: { added: number; removed: number };\n}) {\n return (\n <span\n aria-label={`新增 ${stats.added} 行,删除 ${stats.removed} 行`}\n className=\"base-file-change-summary__stats\"\n >\n <span className=\"base-file-change-summary__stat base-file-change-summary__stat--added\">\n +{stats.added}\n </span>\n {stats.removed > 0 ? (\n <span className=\"base-file-change-summary__stat base-file-change-summary__stat--removed\">\n -{stats.removed}\n </span>\n ) : null}\n </span>\n );\n}\n\nfunction getLineStats(\n item: FileChangeSummaryItem\n): { added: number; removed: number } | undefined {\n if (item.content?.type === \"code\") {\n return { added: countTextLines(item.content.text), removed: 0 };\n }\n\n if (item.content?.type === \"diff\") {\n return {\n added: countTextLines(item.content.modified),\n removed: countTextLines(item.content.original)\n };\n }\n\n return undefined;\n}\n\nfunction countTextLines(text: string): number {\n const normalized = text.replace(/\\n$/, \"\");\n if (!normalized) {\n return 0;\n }\n return normalized.split(\"\\n\").length;\n}\n\nfunction getOperationIcon(operation: FileOperation): ReactNode {\n if (operation === \"edit\") {\n return <DiffOutlined />;\n }\n if (operation === \"write\") {\n return <SaveOutlined />;\n }\n return <DeleteOutlined />;\n}\n\nfunction toggleExpandedKey(\n current: ReadonlySet<string>,\n key: string\n): ReadonlySet<string> {\n const next = new Set(current);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n}\n","import type { WebPlugin } from '@hold-rein/plugin-web'\nimport {\n deleteFileTool,\n editFileTool,\n findFilesTool,\n grepFilesTool,\n readFileTool,\n writeFileTool,\n} from './web/tools'\nimport { fileChangeSummaryTurnFooter } from './web/turn-footers'\nimport { PLUGIN_ID } from \"./plugin-id\";\n\nconst baseWebPlugin: WebPlugin.Plugin = {\n id: PLUGIN_ID,\n contributionResolver: {\n toolRenders: [\n readFileTool,\n writeFileTool,\n deleteFileTool,\n grepFilesTool,\n findFilesTool,\n editFileTool\n ],\n turnFooterRenders: [\n fileChangeSummaryTurnFooter\n ]\n }\n}\n\nexport default baseWebPlugin\n","export const PLUGIN_ID = \"__code__plugin\";\n"],"names":["languageByExtension","getLanguageFromPath","path","extension","_a","getStringArg","args","key","value","getTextResult","result","item","splitResultLines","text","getWorkspaceRelativePath","workspacePath","normalizedPath","normalizePath","normalizedWorkspacePath","stripTrailingSeparators","workspacePrefix","useMonacoTheme","theme","setTheme","useState","useEffect","observer","CodePreview","content","jsx","Suspense","Editor","DiffPreview","modified","original","height","DiffEditor","ReadFileToolRender","props","output","ReadOutlined","jsxs","ToolMeta","WriteFileToolRender","errorOutput","SaveOutlined","DeleteFileToolRender","DeleteOutlined","GrepFilesToolRender","pattern","lines","SearchOutlined","ResultList","FindFilesToolRender","FileSearchOutlined","EditFileToolRender","replacements","getEditReplacements","DiffOutlined","replacement","index","displayPath","FileTextOutlined","emptyText","line","oldText","newText","edits","edit","candidate","readFileTool","writeFileTool","deleteFileTool","grepFilesTool","findFilesTool","editFileTool","operationLabels","operationOrder","FileChangeSummaryTurnFooter","messages","items","useMemo","getFileChangeSummaryItems","expandedKeys","setExpandedKeys","counts","countOperations","title","operation","itemKey","canExpand","isExpanded","FileChangeRow","current","toggleExpandedKey","FileChangePreview","failedToolCallIds","getFailedToolCallIds","message","block","getFileChangeSummaryItem","fileChangeSummaryTurnFooter","expanded","onToggle","rowClassName","stats","getLineStats","Fragment","getOperationIcon","LineStats","_b","toolCall","countTextLines","normalized","next"],"mappings":"mcAAA,MAAMA,EAAwD,CAC5D,EAAG,IACH,IAAK,MACL,GAAI,SACJ,IAAK,MACL,GAAI,KACJ,KAAM,OACN,KAAM,OACN,GAAI,aACJ,KAAM,OACN,IAAK,aACL,GAAI,WACJ,GAAI,SACJ,GAAI,OACJ,GAAI,QACJ,IAAK,MACL,GAAI,aACJ,IAAK,aACL,IAAK,YACL,IAAK,MACL,KAAM,OACN,IAAK,MACP,EAEO,SAASC,EAAoBC,EAAkC,OACpE,GAAI,CAACA,EACH,MAAO,YAGT,MAAMC,GAAYC,EAAAF,EAAK,MAAM,GAAG,EAAE,IAAA,IAAhB,YAAAE,EAAuB,cACzC,OAAOD,EAAYH,EAAoBG,CAAS,GAAK,YAAc,WACrE,CC5BO,SAASE,EACdC,EACAC,EACoB,CACpB,MAAMC,EAAQF,EAAKC,CAAG,EACtB,OAAO,OAAOC,GAAU,SAAWA,EAAQ,MAC7C,CAEO,SAASC,EAAcC,EAAyD,CACrF,OAAKA,EAIEA,EAAO,QACX,OAAQC,GAASA,EAAK,OAAS,MAAM,EACrC,IAAKA,GAASA,EAAK,IAAI,EACvB,KAAK;AAAA,CAAI,EANH,EAOX,CAEO,SAASC,EAAiBC,EAAwB,CACvD,OAAOA,EAAK,MAAM,OAAO,EAAE,OAAO,OAAO,CAC3C,CAEO,SAASC,EACdZ,EACAa,EACoB,CACpB,GAAI,CAACb,GAAQ,CAACa,EACZ,OAAOb,EAGT,MAAMc,EAAiBC,EAAcf,CAAI,EACnCgB,EAA0BC,EAC9BF,EAAcF,CAAa,CAAA,EAG7B,GAAIC,IAAmBE,EACrB,MAAO,IAGT,MAAME,EAAkB,GAAGF,CAAuB,IAClD,OAAIF,EAAe,WAAWI,CAAe,EACpCJ,EAAe,MAAMI,EAAgB,MAAM,EAG7ClB,CACT,CAEO,SAASmB,GAAmC,CACjD,KAAM,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAA2B,IACnD,SAAS,gBAAgB,QAAQ,YAAc,OAAS,UAAY,IAAA,EAGtEC,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAW,IAAI,iBAAiB,IAAM,CAC1CH,EACE,SAAS,gBAAgB,QAAQ,YAAc,OAAS,UAAY,IAAA,CAExE,CAAC,EAED,OAAAG,EAAS,QAAQ,SAAS,gBAAiB,CACzC,gBAAiB,CAAC,iBAAiB,CAAA,CACpC,EAEM,IAAM,CACXA,EAAS,WAAA,CACX,CACF,EAAG,CAAA,CAAE,EAEEJ,CACT,CAEA,SAASL,EAAcf,EAAsB,CAC3C,OAAOA,EAAK,QAAQ,MAAO,GAAG,CAChC,CAEA,SAASiB,EAAwBjB,EAAsB,CACrD,OAAOA,EAAK,QAAQ,QAAS,EAAE,CACjC,CChEO,SAASyB,EAAY,CAAE,QAAAC,EAAS,KAAA1B,GAA0B,CAC/D,MAAMoB,EAAQD,EAAA,EAEd,OACEQ,EAAAA,IAAC,MAAA,CAAI,UAAU,yBACb,SAAAA,EAAAA,IAACC,EAAAA,SAAA,CAAS,SAAUD,EAAAA,IAAC,MAAA,CAAI,UAAU,sBAAuB,SAAAD,CAAA,CAAQ,EAChE,SAAAC,EAAAA,IAACE,EAAA,CACC,OAAQ,KAAK,IAAI,IAAK,KAAK,IAAI,IAAKH,EAAQ,MAAM;AAAA,CAAI,EAAE,OAAS,EAAE,CAAC,EACpE,SAAU3B,EAAoBC,CAAI,EAClC,QAAS,CACP,oBAAqB,EACrB,QAAS,CAAE,QAAS,EAAA,EACpB,SAAU,GACV,qBAAsB,GACtB,SAAU,IAAA,EAEZ,MAAAoB,EACA,MAAOM,CAAA,CAAA,EAEX,CAAA,CACF,CAEJ,CAEO,SAASI,EAAY,CAAE,SAAAC,EAAU,SAAAC,EAAU,KAAAhC,GAA0B,CAC1E,MAAMoB,EAAQD,EAAA,EACRc,EAAS,KAAK,IAClB,IACA,KAAK,IACH,IACA,KAAK,IAAID,EAAS,MAAM;AAAA,CAAI,EAAE,OAAQD,EAAS,MAAM;AAAA,CAAI,EAAE,MAAM,EAAI,EAAA,CACvE,EAGF,OACEJ,EAAAA,IAAC,MAAA,CAAI,UAAU,yBACb,SAAAA,EAAAA,IAACC,EAAAA,SAAA,CAAS,SAAUD,EAAAA,IAAC,MAAA,CAAI,UAAU,sBAAuB,SAAAI,CAAA,CAAS,EACjE,SAAAJ,EAAAA,IAACO,EAAAA,WAAA,CACC,OAAAD,EACA,SAAUlC,EAAoBC,CAAI,EAClC,SAAA+B,EACA,QAAS,CACP,oBAAqB,EACrB,QAAS,CAAE,QAAS,EAAA,EACpB,SAAU,GACV,iBAAkB,GAClB,qBAAsB,GACtB,SAAU,IAAA,EAEZ,SAAAC,EACA,MAAAZ,CAAA,CAAA,EAEJ,CAAA,CACF,CAEJ,CC9CO,SAASe,EAAmBC,EAAkC,CACnE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBpC,EAAOG,EAAaC,EAAM,MAAM,EAChCiC,EAAS9B,EAAc6B,EAAM,MAAM,EAEzC,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,OAAO,KAAMT,EAAAA,IAACW,EAAAA,aAAA,CAAA,CAAa,EACxD,SAAAC,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,cAAeoC,EAAM,cAAe,EACzDC,EACCV,EAAAA,IAACF,EAAA,CAAY,QAASY,EAAQ,KAAArC,CAAA,CAAY,EAE1C2B,EAAAA,IAAC,OAAA,CAAK,UAAU,wBAAwB,SAAA,QAAA,CAAM,CAAA,CAAA,CAElD,CAAA,CACF,CAEJ,CAEO,SAASc,EAAoBL,EAAkC,OACpE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBpC,EAAOG,EAAaC,EAAM,MAAM,EAChCsB,EAAUvB,EAAaC,EAAM,SAAS,GAAK,GAC3CsC,GAAcxC,EAAAkC,EAAM,SAAN,MAAAlC,EAAc,QAAUK,EAAc6B,EAAM,MAAM,EAAI,GAE1E,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,OAAO,KAAMT,EAAAA,IAACgB,EAAAA,aAAA,CAAA,CAAa,EACxD,SAAAJ,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,cAAeoC,EAAM,cAAe,EACzDV,EACCC,EAAAA,IAACF,EAAA,CAAY,QAAAC,EAAkB,KAAA1B,CAAA,CAAY,EAE3C2B,MAAC,OAAA,CAAK,UAAU,wBAAwB,SAAA,OAAA,CAAK,EAE9Ce,EACCf,EAAAA,IAAC,MAAA,CAAI,UAAU,sBAAuB,WAAY,EAChD,IAAA,CAAA,CACN,CAAA,CACF,CAEJ,CAEO,SAASiB,EAAqBR,EAAkC,OACrE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBpC,EAAOG,EAAaC,EAAM,MAAM,EAChCsC,GAAcxC,EAAAkC,EAAM,SAAN,MAAAlC,EAAc,QAAUK,EAAc6B,EAAM,MAAM,EAAI,GAE1E,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,OAAO,KAAMT,EAAAA,IAACkB,EAAAA,eAAA,CAAA,CAAe,EAC1D,SAAAN,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,cAAeoC,EAAM,cAAe,EACxDA,EAAM,OAEJ,KADFT,EAAAA,IAAC,QAAK,UAAU,wBAAwB,kBAAM,EAE/Ce,EACCf,EAAAA,IAAC,MAAA,CAAI,UAAU,sBAAuB,WAAY,EAChD,IAAA,CAAA,CACN,CAAA,CACF,CAEJ,CAEO,SAASmB,EAAoBV,EAAkC,CACpE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBW,EAAU5C,EAAaC,EAAM,SAAS,EACtCJ,EAAOG,EAAaC,EAAM,MAAM,GAAK,IACrC4C,EAAQtC,EAAiBH,EAAc6B,EAAM,MAAM,CAAC,EAE1D,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,QAAQ,KAAMT,EAAAA,IAACsB,EAAAA,eAAA,CAAA,CAAe,EAC3D,SAAAV,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,QAAA+C,EAAkB,cAAeX,EAAM,cAAe,EAC5ET,EAAAA,IAACuB,EAAA,CAAW,UAAU,aAAa,MAAAF,CAAA,CAAc,CAAA,CAAA,CACnD,CAAA,CACF,CAEJ,CAEO,SAASG,EAAoBf,EAAkC,CACpE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBW,EAAU5C,EAAaC,EAAM,SAAS,EACtCJ,EAAOG,EAAaC,EAAM,MAAM,GAAK,IACrC4C,EAAQtC,EAAiBH,EAAc6B,EAAM,MAAM,CAAC,EAE1D,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,SAAS,KAAMT,EAAAA,IAACyB,EAAAA,mBAAA,CAAA,CAAmB,EAChE,SAAAb,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,QAAA+C,EAAkB,cAAeX,EAAM,cAAe,EAC5ET,EAAAA,IAACuB,EAAA,CAAW,UAAU,SAAS,MAAAF,CAAA,CAAc,CAAA,CAAA,CAC/C,CAAA,CACF,CAEJ,CAEO,SAASK,EAAmBjB,EAAkC,OACnE,MAAMhC,EAAOgC,EAAM,SAAS,UACtBpC,EAAOG,EAAaC,EAAM,MAAM,EAChCkD,EAAeC,EAAoBnD,CAAI,EACvCsC,GAAcxC,EAAAkC,EAAM,SAAN,MAAAlC,EAAc,QAAUK,EAAc6B,EAAM,MAAM,EAAI,GAE1E,OACET,EAAAA,IAACS,EAAM,kBAAN,CAAwB,MAAM,OAAO,KAAMT,EAAAA,IAAC6B,EAAAA,aAAA,CAAA,CAAa,EACxD,SAAAjB,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAZ,EAAAA,IAACa,EAAA,CAAS,KAAAxC,EAAY,cAAeoC,EAAM,cAAe,EACzDkB,EAAa,OACZA,EAAa,IAAI,CAACG,EAAaC,IAC7B/B,EAAAA,IAACG,EAAA,CAEC,SAAU2B,EAAY,QACtB,SAAUA,EAAY,QACtB,KAAAzD,CAAA,EAHK,GAAG0D,CAAK,IAAID,EAAY,OAAO,EAAA,CAKvC,EAED9B,EAAAA,IAAC,OAAA,CAAK,UAAU,wBAAwB,SAAA,YAAS,EAElDe,EACCf,EAAAA,IAAC,MAAA,CAAI,UAAU,sBAAuB,WAAY,EAChD,IAAA,CAAA,CACN,CAAA,CACF,CAEJ,CAEA,SAASa,EAAS,CAChB,KAAAxC,EACA,QAAA+C,EACA,cAAAlC,CACF,EAIG,CACD,MAAM8C,EAAc/C,EAAyBZ,EAAMa,CAAa,EAEhE,OACE0B,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACZ,SAAA,CAAAoB,EACCpB,EAAAA,KAAC,OAAA,CAAK,UAAU,uBACd,SAAA,CAAAZ,EAAAA,IAACiC,EAAAA,iBAAA,EAAiB,EAAE,IAAED,CAAA,CAAA,CACxB,EACE,KACHZ,EACCR,EAAAA,KAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,CAAA,YAAUQ,CAAA,CAAA,CAAQ,EACvD,IAAA,EACN,CAEJ,CAEA,SAASG,EAAW,CAClB,UAAAW,EACA,MAAAb,CACF,EAGG,CACD,OAAKA,EAAM,OAKTrB,MAAC,MAAG,UAAU,uBACX,WAAM,IAAI,CAACmC,EAAMJ,IAChB/B,EAAAA,IAAC,MAAG,UAAU,4BACX,YAD4C,GAAG+B,CAAK,IAAII,CAAI,EAE/D,CACD,CAAA,CACH,EAVOnC,EAAAA,IAAC,OAAA,CAAK,UAAU,wBAAyB,SAAAkC,EAAU,CAY9D,CAEA,SAASN,EACPnD,EACmB,CACnB,MAAM2D,EAAU5D,EAAaC,EAAM,SAAS,EACtC4D,EAAU7D,EAAaC,EAAM,SAAS,EACtCkD,EAAkC,CAAA,EAEpCS,IAAY,QAAaC,IAAY,QACvCV,EAAa,KAAK,CAAE,QAAAS,EAAS,QAAAC,CAAA,CAAS,EAGxC,MAAMC,EAAQ7D,EAAK,MACnB,GAAI,CAAC,MAAM,QAAQ6D,CAAK,EACtB,OAAOX,EAGT,UAAWY,KAAQD,EAAO,CACxB,GAAI,CAACC,GAAQ,OAAOA,GAAS,SAC3B,SAGF,MAAMC,EAAYD,EAEhB,OAAOC,EAAU,SAAY,UAC7B,OAAOA,EAAU,SAAY,UAE7Bb,EAAa,KAAK,CAChB,QAASa,EAAU,QACnB,QAASA,EAAU,OAAA,CACpB,CAEL,CAEA,OAAOb,CACT,CAEO,MAAMc,EAAqC,CAChD,OAAQjC,EACR,SAAU,WACZ,EAEakC,EAAsC,CACjD,OAAQ5B,EACR,SAAU,YACZ,EAEa6B,EAAuC,CAClD,OAAQ1B,EACR,SAAU,aACZ,EAEa2B,EAAsC,CACjD,OAAQzB,EACR,SAAU,YACZ,EAEa0B,EAAsC,CACjD,OAAQrB,EACR,SAAU,YACZ,EAEasB,EAAqC,CAChD,OAAQpB,EACR,SAAU,WACZ,ECzNMqB,EAAiD,CACrD,OAAQ,KACR,KAAM,KACN,MAAO,IACT,EAEMC,EAA2C,CAAC,OAAQ,QAAS,QAAQ,EAEpE,SAASC,EAA4B,CAC1C,SAAAC,EACA,cAAAhE,CACF,EAAoC,CAClC,MAAMiE,EAAQC,EAAAA,QAAQ,IAAMC,EAA0BH,CAAQ,EAAG,CAACA,CAAQ,CAAC,EACrE,CAACI,EAAcC,CAAe,EAAI5D,EAAAA,SACtC,QAAU,GAAI,EAGhB,GAAI,CAACwD,EAAM,OACT,OAAO,KAGT,MAAMK,EAASC,EAAgBN,CAAK,EAC9BO,EAAQV,EACX,OAAQW,GAAcH,EAAOG,CAAS,EAAI,CAAC,EAC3C,IACEA,GACC,GAAGZ,EAAgBY,CAAS,CAAC,GAAGH,EAAOG,CAAS,CAAC,KAAA,EAEpD,KAAK,GAAG,EAEX,OACE/C,EAAAA,KAAC,UAAA,CAAQ,UAAU,2BACjB,SAAA,CAAAZ,EAAAA,IAAC,MAAA,CAAI,UAAU,kCACZ,SAAA0D,EACH,EACA1D,MAAC,OAAI,UAAU,iCACZ,WAAM,IAAI,CAAClB,EAAMiD,KAAU,CAC1B,MAAM6B,EAAU,GAAG9E,EAAK,SAAS,IAAIA,EAAK,IAAI,IAAIiD,EAAK,GACjD8B,GAAY/E,EAAK,UAAY,OAC7BgF,EAAaR,EAAa,IAAIM,CAAO,EAE3C,OACEhD,EAAAA,KAAC,MAAA,CAAI,UAAU,iCACb,SAAA,CAAAZ,EAAAA,IAAC+D,EAAA,CACC,YACE9E,EAAyBH,EAAK,KAAMI,CAAa,GAAKJ,EAAK,KAE7D,SAAUgF,EACV,KAAAhF,EACA,SACE+E,GACI,IAAM,CACJN,EAAiBS,IACfC,GAAkBD,GAASJ,CAAO,CAAA,CAEtC,EACA,MAAA,CAAA,EAGPE,GAAchF,EAAK,QAClBkB,EAAAA,IAAC,MAAA,CAAI,UAAU,oCACb,SAAAA,EAAAA,IAACkE,EAAA,CAAkB,KAAApF,CAAA,CAAY,CAAA,CACjC,EACE,IAAA,CAAA,EArB+C8E,CAsBrD,CAEJ,CAAC,CAAA,CACH,CAAA,EACF,CAEJ,CAEO,SAASP,EACdH,EACyB,CACzB,MAAMC,EAAiC,CAAA,EACjCgB,EAAoBC,EAAqBlB,CAAQ,EAEvD,UAAWmB,KAAWnB,EACpB,GAAImB,EAAQ,OAAS,YAIrB,UAAWC,KAASD,EAAQ,QAAS,CAInC,GAHIC,EAAM,OAAS,YAGfH,EAAkB,IAAIG,EAAM,EAAE,EAChC,SAGF,MAAMxF,EAAOyF,EAAyBD,CAAK,EACvCxF,GACFqE,EAAM,KAAKrE,CAAI,CAEnB,CAGF,OAAOqE,CACT,CAEA,SAASiB,EACPlB,EACqB,CACrB,MAAMiB,MAAwB,IAE9B,UAAWE,KAAWnB,EAChBmB,EAAQ,OAAS,cAAgBA,EAAQ,SAC3CF,EAAkB,IAAIE,EAAQ,UAAU,EAI5C,OAAOF,CACT,CAEO,MAAMK,EAA0D,CACrE,GAAI,sBACJ,OAAQvB,CACV,EAEA,SAASc,EAAc,CACrB,YAAA/B,EACA,SAAAyC,EACA,KAAA3F,EACA,SAAA4F,CACF,EAKG,CACD,MAAMC,EAAe,CACnB,gCACA7F,EAAK,YAAc,SAAW,wCAA0C,EAAA,EAEvE,OAAO,OAAO,EACd,KAAK,GAAG,EACL8F,EAAQC,EAAa/F,CAAI,EACzBiB,EACJa,EAAAA,KAAAkE,EAAAA,SAAA,CACE,SAAA,CAAA9E,MAAC,QAAK,UAAU,iCACb,SAAA+E,GAAiBjG,EAAK,SAAS,EAClC,EACAkB,EAAAA,IAAC,OAAA,CAAK,UAAU,iCAAkC,SAAAgC,EAAY,EAC7D4C,EAAQ5E,EAAAA,IAACgF,EAAA,CAAU,MAAAJ,CAAA,CAAc,EAAK,IAAA,EACzC,EAGF,OAAKF,EAKH1E,EAAAA,IAAC,SAAA,CACC,gBAAeyE,EACf,UAAWE,EACX,QAASD,EACT,KAAK,SAEJ,SAAA3E,CAAA,CAAA,EAVIC,EAAAA,IAAC,MAAA,CAAI,UAAW2E,EAAe,SAAA5E,EAAQ,CAalD,CAEA,SAASmE,EAAkB,CAAE,KAAApF,GAAyC,SACpE,QAAIP,EAAAO,EAAK,UAAL,YAAAP,EAAc,QAAS,OAClByB,MAACF,GAAY,QAAShB,EAAK,QAAQ,KAAM,KAAMA,EAAK,KAAM,IAG/DmG,EAAAnG,EAAK,UAAL,YAAAmG,EAAc,QAAS,OAEvBjF,EAAAA,IAACG,EAAA,CACC,SAAUrB,EAAK,QAAQ,SACvB,SAAUA,EAAK,QAAQ,SACvB,KAAMA,EAAK,IAAA,CAAA,EAKV,IACT,CAEA,SAASyF,EACPW,EACmC,CACnC,MAAM7G,EAAOG,EAAa0G,EAAS,UAAW,MAAM,EACpD,GAAI,CAAC7G,EACH,OAGF,GAAI6G,EAAS,OAAS,aACpB,MAAO,CACL,QAAS,CACP,KAAM1G,EAAa0G,EAAS,UAAW,SAAS,GAAK,GACrD,KAAM,MAAA,EAER,UAAW,QACX,KAAA7G,CAAA,EAIJ,GAAI6G,EAAS,OAAS,cACpB,MAAO,CACL,UAAW,SACX,KAAA7G,CAAA,EAIJ,GAAI6G,EAAS,OAAS,YACpB,OAGF,MAAMvD,EAAeC,EAAoBsD,EAAS,SAAS,EAE3D,MAAO,CACL,QAAS,CACP,SAAUvD,EAAa,IAAKG,GAAgBA,EAAY,OAAO,EAAE,KAAK;AAAA,CAAI,EAC1E,SAAUH,EAAa,IAAKG,GAAgBA,EAAY,OAAO,EAAE,KAAK;AAAA,CAAI,EAC1E,KAAM,MAAA,EAER,UAAW,OACX,KAAAzD,CAAA,CAEJ,CAEA,SAASuD,EACPnD,EACmB,CACnB,MAAMkD,EAAkC,CAAA,EAClCS,EAAU5D,EAAaC,EAAM,SAAS,EACtC4D,EAAU7D,EAAaC,EAAM,SAAS,EAM5C,GAJI2D,IAAY,QAAaC,IAAY,QACvCV,EAAa,KAAK,CAAE,QAAAU,EAAS,QAAAD,CAAA,CAAS,EAGpC,CAAC,MAAM,QAAQ3D,EAAK,KAAK,EAC3B,OAAOkD,EAGT,UAAWY,KAAQ9D,EAAK,MAAO,CAC7B,GAAI,CAAC8D,GAAQ,OAAOA,GAAS,SAC3B,SAGF,MAAMC,EAAYD,EAEhB,OAAOC,EAAU,SAAY,UAC7B,OAAOA,EAAU,SAAY,UAE7Bb,EAAa,KAAK,CAChB,QAASa,EAAU,QACnB,QAASA,EAAU,OAAA,CACpB,CAEL,CAEA,OAAOb,CACT,CAEA,SAAS8B,EACPN,EAC+B,CAC/B,OAAOA,EAAM,OACX,CAACK,EAAQ1E,KAAU,CACjB,GAAG0E,EACH,CAAC1E,EAAK,SAAS,EAAG0E,EAAO1E,EAAK,SAAS,EAAI,CAAA,GAE7C,CAAE,OAAQ,EAAG,KAAM,EAAG,MAAO,CAAA,CAAE,CAEnC,CAEA,SAASkG,EAAU,CACjB,MAAAJ,CACF,EAEG,CACD,OACEhE,EAAAA,KAAC,OAAA,CACC,aAAY,MAAMgE,EAAM,KAAK,SAASA,EAAM,OAAO,KACnD,UAAU,kCAEV,SAAA,CAAAhE,EAAAA,KAAC,OAAA,CAAK,UAAU,uEAAuE,SAAA,CAAA,IACnFgE,EAAM,KAAA,EACV,EACCA,EAAM,QAAU,EACfhE,EAAAA,KAAC,OAAA,CAAK,UAAU,yEAAyE,SAAA,CAAA,IACrFgE,EAAM,OAAA,CAAA,CACV,EACE,IAAA,CAAA,CAAA,CAGV,CAEA,SAASC,EACP/F,EACgD,SAChD,KAAIP,EAAAO,EAAK,UAAL,YAAAP,EAAc,QAAS,OACzB,MAAO,CAAE,MAAO4G,EAAerG,EAAK,QAAQ,IAAI,EAAG,QAAS,CAAA,EAG9D,KAAImG,EAAAnG,EAAK,UAAL,YAAAmG,EAAc,QAAS,OACzB,MAAO,CACL,MAAOE,EAAerG,EAAK,QAAQ,QAAQ,EAC3C,QAASqG,EAAerG,EAAK,QAAQ,QAAQ,CAAA,CAKnD,CAEA,SAASqG,EAAenG,EAAsB,CAC5C,MAAMoG,EAAapG,EAAK,QAAQ,MAAO,EAAE,EACzC,OAAKoG,EAGEA,EAAW,MAAM;AAAA,CAAI,EAAE,OAFrB,CAGX,CAEA,SAASL,GAAiBpB,EAAqC,CAC7D,OAAIA,IAAc,aACR9B,EAAAA,aAAA,EAAa,EAEnB8B,IAAc,cACR3C,EAAAA,aAAA,EAAa,QAEfE,EAAAA,eAAA,EAAe,CACzB,CAEA,SAAS+C,GACPD,EACAtF,EACqB,CACrB,MAAM2G,EAAO,IAAI,IAAIrB,CAAO,EAC5B,OAAIqB,EAAK,IAAI3G,CAAG,EACd2G,EAAK,OAAO3G,CAAG,EAEf2G,EAAK,IAAI3G,CAAG,EAEP2G,CACT,OCpXwC,CACtC,GCbuB,iBDcvB,qBAAsB,CACpB,YAAa,CACX5C,EACAC,EACAC,EACAC,EACAC,EACAC,CAAA,EAEF,kBAAmB,CACjB0B,CAAA,CACF,CAEJ"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@hold-rein/plugins-code",
3
+ "version": "0.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/server.cjs",
7
+ "module": "./dist/server.js",
8
+ "types": "./dist/server.d.ts",
9
+ "exports": {
10
+ "./server": {
11
+ "types": "./dist/server.d.ts",
12
+ "import": "./dist/server.js",
13
+ "require": "./dist/server.cjs"
14
+ },
15
+ "./web": {
16
+ "types": "./dist/web.d.ts",
17
+ "style": "./dist/style.css",
18
+ "default": "./dist/web.umd.cjs",
19
+ "require": "./dist/web.umd.cjs"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "peerDependencies": {
29
+ "@earendil-works/pi-agent-core": "0.75.4",
30
+ "@earendil-works/pi-ai": "0.76.0",
31
+ "express": "5.2.1",
32
+ "@ant-design/icons": "6.2.5",
33
+ "@monaco-editor/react": "4.7.0",
34
+ "antd": "6.4.3",
35
+ "monaco-editor": "0.55.1",
36
+ "react": "19.2.6",
37
+ "react-dom": "19.2.6",
38
+ "@hold-rein/plugin-server": "^0.0.0",
39
+ "@hold-rein/plugin-web": "^0.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@earendil-works/pi-agent-core": "0.75.4",
43
+ "@earendil-works/pi-ai": "0.76.0",
44
+ "express": "5.2.1",
45
+ "vite": "6.3.5",
46
+ "@ant-design/icons": "6.2.5",
47
+ "@monaco-editor/react": "4.7.0",
48
+ "@types/react": "19.2.15",
49
+ "antd": "6.4.3",
50
+ "monaco-editor": "0.55.1",
51
+ "react": "19.2.6",
52
+ "react-dom": "19.2.6",
53
+ "@hold-rein/plugin-web": "^0.0.0",
54
+ "@hold-rein/plugin-server": "^0.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "vite build --config vite.config.ts && vite build --config vite.web.config.ts && tsc -p tsconfig.json --emitDeclarationOnly",
58
+ "typecheck": "tsc -p tsconfig.json --noEmit"
59
+ }
60
+ }