@agimon-ai/doompi-edit 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +97 -0
- package/dist/adapters/pi/editTool.cjs +9 -0
- package/dist/adapters/pi/editTool.cjs.map +1 -0
- package/dist/adapters/pi/editTool.d.cts +14 -0
- package/dist/adapters/pi/editTool.d.cts.map +1 -0
- package/dist/adapters/pi/editTool.d.mts +14 -0
- package/dist/adapters/pi/editTool.d.mts.map +1 -0
- package/dist/adapters/pi/editTool.mjs +9 -0
- package/dist/adapters/pi/editTool.mjs.map +1 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/pi/extension.d.cts +10 -0
- package/dist/adapters/pi/extension.d.cts.map +1 -0
- package/dist/adapters/pi/extension.d.mts +10 -0
- package/dist/adapters/pi/extension.d.mts.map +1 -0
- package/dist/adapters/pi/extension.mjs +2 -0
- package/dist/adapters/pi/extension.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +1 -0
- package/dist/schemas/editTool.cjs +2 -0
- package/dist/schemas/editTool.cjs.map +1 -0
- package/dist/schemas/editTool.d.cts +21 -0
- package/dist/schemas/editTool.d.cts.map +1 -0
- package/dist/schemas/editTool.d.mts +21 -0
- package/dist/schemas/editTool.d.mts.map +1 -0
- package/dist/schemas/editTool.mjs +2 -0
- package/dist/schemas/editTool.mjs.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vuong Ngo
|
|
4
|
+
Copyright (c) 2026 pulseaiclub
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @agimon-ai/doompi-edit
|
|
2
|
+
|
|
3
|
+
Snapshot-bound hashline edit tool for Pi and DoomPi.
|
|
4
|
+
|
|
5
|
+
Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
|
|
6
|
+
|
|
7
|
+
The package replaces only Pi's `edit` registration. It consumes the exact file tags and stable
|
|
8
|
+
three-letter anchors produced by `@agimon-ai/doompi-read`, `@agimon-ai/doompi-grep`, or another
|
|
9
|
+
compatible hashline producer. Stale or ambiguous mutations fail before any file is changed.
|
|
10
|
+
|
|
11
|
+
> **Alpha:** tool and protocol contracts may change between releases.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Node.js 22.19.0 or newer
|
|
16
|
+
- Pi 0.84.2 and Pi TUI 0.84.2
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pi install npm:@agimon-ai/doompi-edit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Pi discovers `@agimon-ai/doompi-edit/extensions/pi` from the package manifest.
|
|
25
|
+
|
|
26
|
+
Standalone Pi also needs `@agimon-ai/doompi-read`, `@agimon-ai/doompi-grep`, or another compatible
|
|
27
|
+
producer for the file tags and anchors consumed by this tool.
|
|
28
|
+
|
|
29
|
+
If `@agimon-ai/doompi-ui` is also installed directly in standalone Pi, list
|
|
30
|
+
`@agimon-ai/doompi-edit` first when its `edit` tool should win. DoomPi's default distribution
|
|
31
|
+
installs `@agimon-ai/doompi-read`, `@agimon-ai/doompi-grep`, and `@agimon-ai/doompi-edit` together.
|
|
32
|
+
|
|
33
|
+
## Tool protocol
|
|
34
|
+
|
|
35
|
+
Compatible read and grep results start with a file header followed by tagged lines:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
@file src/example.ts#A1b2C3d4
|
|
39
|
+
1#abc|const value = 1;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The shared protocol is implemented by `@agimon-ai/doompi-hashline`. The eight-character file tag is
|
|
43
|
+
the base64url SHA-256 prefix of the exact file bytes. The three-letter line anchor is a
|
|
44
|
+
whitespace-insensitive FNV-1a64 tag.
|
|
45
|
+
|
|
46
|
+
`edit` accepts:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"path": "src/example.ts",
|
|
51
|
+
"hash": "A1b2C3d4",
|
|
52
|
+
"edits": [
|
|
53
|
+
{
|
|
54
|
+
"from": "1#abc",
|
|
55
|
+
"to": "1#abc",
|
|
56
|
+
"content": "const value = 2;"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
All anchors refer to the original snapshot. Ranges are inclusive. Omit `content` to delete a range.
|
|
63
|
+
Exact duplicate edits are applied once, but any other overlapping ranges are rejected before
|
|
64
|
+
mutation.
|
|
65
|
+
|
|
66
|
+
Pass exactly one anchor in each `from` and `to` value, for example `5#abc`. Anchors copied with a
|
|
67
|
+
`>`, `+`, or `-` display prefix are accepted, as are uppercase anchor letters, whitespace around
|
|
68
|
+
the separator, and the legacy `5:abc` separator. Pasted multiline blocks are rejected.
|
|
69
|
+
|
|
70
|
+
## Attribution
|
|
71
|
+
|
|
72
|
+
The hashline protocol and FNV anchor approach are adapted from
|
|
73
|
+
[Phi's writetool](https://github.com/pulseaiclub/phi/tree/main/internal/tools/writetool), licensed
|
|
74
|
+
under MIT by pulseaiclub. DoomPi uses an exact-byte SHA-256 file tag as an intentional compatibility
|
|
75
|
+
boundary.
|
|
76
|
+
|
|
77
|
+
## Public API
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { EditParamsSchema, executeHashlineEdit, registerHashlineEditTool } from '@agimon-ai/doompi-edit';
|
|
81
|
+
import type { EditParams, HashlineRange } from '@agimon-ai/doompi-edit';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Development
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pnpm build
|
|
88
|
+
pnpm typecheck
|
|
89
|
+
pnpm test
|
|
90
|
+
pnpm lint
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Maintained by [Agimon](https://agimon.ai/about).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const e=require("../../schemas/editTool.cjs");let t=require("node:fs"),n=require("node:fs/promises"),r=require("@agimon-ai/doompi-hashline"),i=require("@agimon-ai/doompi-hashline/files"),a=require("@agimon-ai/doompi-ui/hashlineRendering"),o=require("@earendil-works/pi-coding-agent");const s=Buffer.from([239,187,191]);function c(t){t.registerTool({name:`edit`,label:`edit`,description:`Edit one file using its exact snapshot hash and inclusive anchors such as 5#abc from read or grep. Each from and to value must contain one anchor, not a pasted block. All ranges refer to the original snapshot. Empty or omitted content deletes a range.`,promptSnippet:`Edit files with snapshot-bound hashline ranges`,promptGuidelines:[`Copy path, hash, and anchors from the latest compatible read or grep result. Re-read after every successful edit.`,`Pass one anchor such as 5#abc in each from and to value. Do not paste tagged lines or multiline blocks.`,`Put multiple disjoint changes to one file in one edit call. All anchors must describe the original snapshot.`,`Omit content or pass an empty string to delete an inclusive range. Merge overlapping ranges before calling edit.`],parameters:e.EditParamsSchema,executionMode:`parallel`,renderShell:`self`,async execute(e,t,n,r,i){return l(t,i.cwd,n)},renderCall(e,t){let n=e,r=n.edits.length;return(0,a.renderHashlineCall)(`edit`,n.path,[`${r} ${r===1?`range`:`ranges`}`],t)},renderResult(e,t,n,r){let i=r.args;return(0,a.renderHashlineEditResult)(i.path,e,t,n,r)}})}async function l(e,a,c){let l=(0,i.resolveInputPath)(e.path,a),f=(0,r.normalizeFileTag)(e.hash);return(0,o.withFileMutationQueue)(l,async()=>{u(c),await(0,n.access)(l,t.constants.R_OK|t.constants.W_OK);let p=await(0,n.readFile)(l);u(c);let m=(0,i.computeFileTag)(p);if(m!==f)throw Error(`Stale file hash ${f}. Current hash is ${m}. Re-read the file and retry.`);let h=p.subarray(0,s.length).equals(s),g=(0,i.decodeUtf8)(p,e.path),_=(0,r.stripBom)(g),v=(0,r.normalizeToLf)(_),y=(0,r.applyHashlineEdits)(v,e.edits),b=d(_,y.edits);if((0,r.normalizeToLf)(b)!==y.content)throw Error(`Could not preserve the file line endings safely. The file was not changed.`);let x=(0,o.generateDiffString)(v,y.content),S=(0,o.generateUnifiedPatch)((0,i.displayPath)(l,a),v,y.content),C={diff:x.diff,patch:S,firstChangedLine:x.firstChangedLine};if(u(c),!(await(0,n.readFile)(l)).equals(p))throw Error(`The file changed while the edit was being prepared. Re-read it and retry.`);if(u(c),y.content!==v){let e=Buffer.from(`${h?``:``}${b}`,`utf8`);await(0,n.writeFile)(l,e)}let w=y.edits.length,T=w===1?`range`:`ranges`;return{content:[{type:`text`,text:`${y.content===v?`No changes needed in ${e.path}.`:`Edited ${e.path} (${w} ${T}).`} Re-read before editing it again.`}],details:C}})}function u(e){if(e?.aborted)throw Error(`Operation aborted`)}function d(e,t){let n=f(e),r=n.find(e=>e.ending!==``)?.ending??`
|
|
2
|
+
`;for(let e of[...t].reverse()){let t=e.from.line-1,i=e.to.line-e.from.line+1,a=n.slice(t,t+i),o=a.at(-1)?.ending??``,s=a.find(e=>e.ending!==``)?.ending??r,c=p(e.content);if(c.length===0&&a.at(-1)?.ending===``&&t>0){let e=n[t-1];e&&(n[t-1]={...e,ending:``})}let l=c.map((e,t)=>({text:e,ending:t===c.length-1?o:s}));n.splice(t,i,...l)}return n.map(e=>`${e.text}${e.ending}`).join(``)}function f(e){let t=[],n=0;for(let r=0;r<e.length;r+=1){let i=e[r];if(i!==`\r`&&i!==`
|
|
3
|
+
`)continue;let a=i===`\r`&&e[r+1]===`
|
|
4
|
+
`?`\r
|
|
5
|
+
`:i;t.push({text:e.slice(n,r),ending:a}),a===`\r
|
|
6
|
+
`&&(r+=1),n=r+1}return t.push({text:e.slice(n),ending:``}),t}function p(e){if(e===null||e===``)return[];let t=(0,r.normalizeToLf)(e),n=t.endsWith(`
|
|
7
|
+
`)?t.slice(0,-1):t;return n===``?[]:n.split(`
|
|
8
|
+
`)}exports.executeHashlineEdit=l,exports.registerHashlineEditTool=c;
|
|
9
|
+
//# sourceMappingURL=editTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.cjs","names":["EditParamsSchema","renderHashlineCall","renderHashlineEditResult","resolveInputPath","normalizeFileTag","withFileMutationQueue","access","constants","readFile","computeFileTag","decodeUtf8","stripBom","normalizeToLf","applyHashlineEdits","generateDiffString","generateUnifiedPatch","displayPath","writeFile"],"sources":["../../../src/adapters/pi/editTool.ts"],"sourcesContent":["import { constants } from 'node:fs';\nimport { access, readFile, writeFile } from 'node:fs/promises';\nimport {\n applyHashlineEdits,\n normalizeFileTag,\n normalizeToLf,\n stripBom,\n type PreparedHashlineEdit,\n} from '@agimon-ai/doompi-hashline';\nimport { computeFileTag, decodeUtf8, displayPath, resolveInputPath } from '@agimon-ai/doompi-hashline/files';\nimport { renderHashlineCall, renderHashlineEditResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n generateDiffString,\n generateUnifiedPatch,\n withFileMutationQueue,\n type EditToolDetails,\n type ExtensionAPI,\n} from '@earendil-works/pi-coding-agent';\nimport { EditParamsSchema, type EditParams } from '../../schemas/editTool.ts';\n\nconst UTF8_BOM = Buffer.from([0xef, 0xbb, 0xbf]);\n\nexport function registerHashlineEditTool(pi: Pick<ExtensionAPI, 'registerTool'>): void {\n pi.registerTool({\n name: 'edit',\n label: 'edit',\n description:\n 'Edit one file using its exact snapshot hash and inclusive anchors such as 5#abc from read or grep. Each from and to value must contain one anchor, not a pasted block. All ranges refer to the original snapshot. Empty or omitted content deletes a range.',\n promptSnippet: 'Edit files with snapshot-bound hashline ranges',\n promptGuidelines: [\n 'Copy path, hash, and anchors from the latest compatible read or grep result. Re-read after every successful edit.',\n 'Pass one anchor such as 5#abc in each from and to value. Do not paste tagged lines or multiline blocks.',\n 'Put multiple disjoint changes to one file in one edit call. All anchors must describe the original snapshot.',\n 'Omit content or pass an empty string to delete an inclusive range. Merge overlapping ranges before calling edit.',\n ],\n parameters: EditParamsSchema,\n executionMode: 'parallel',\n renderShell: 'self',\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return executeHashlineEdit(params as EditParams, ctx.cwd, signal);\n },\n renderCall(args, theme) {\n const input = args as EditParams;\n const count = input.edits.length;\n return renderHashlineCall('edit', input.path, [`${count} ${count === 1 ? 'range' : 'ranges'}`], theme);\n },\n renderResult(result, options, theme, context) {\n const input = context.args as EditParams;\n return renderHashlineEditResult(input.path, result, options, theme, context);\n },\n });\n}\n\nexport async function executeHashlineEdit(\n params: EditParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<{ content: [{ type: 'text'; text: string }]; details: EditToolDetails }> {\n const absolutePath = resolveInputPath(params.path, cwd);\n const expectedHash = normalizeFileTag(params.hash);\n return withFileMutationQueue(absolutePath, async () => {\n assertNotAborted(signal);\n await access(absolutePath, constants.R_OK | constants.W_OK);\n const beforeBytes = await readFile(absolutePath);\n assertNotAborted(signal);\n\n const actualHash = computeFileTag(beforeBytes);\n if (actualHash !== expectedHash) {\n throw new Error(`Stale file hash ${expectedHash}. Current hash is ${actualHash}. Re-read the file and retry.`);\n }\n\n const hasBom = beforeBytes.subarray(0, UTF8_BOM.length).equals(UTF8_BOM);\n const decoded = decodeUtf8(beforeBytes, params.path);\n const withoutBom = stripBom(decoded);\n const before = normalizeToLf(withoutBom);\n const applied = applyHashlineEdits(before, params.edits);\n const editedText = restoreOriginalLineEndings(withoutBom, applied.edits);\n if (normalizeToLf(editedText) !== applied.content) {\n throw new Error('Could not preserve the file line endings safely. The file was not changed.');\n }\n const diff = generateDiffString(before, applied.content);\n const patch = generateUnifiedPatch(displayPath(absolutePath, cwd), before, applied.content);\n const details: EditToolDetails = { diff: diff.diff, patch, firstChangedLine: diff.firstChangedLine };\n\n assertNotAborted(signal);\n const currentBytes = await readFile(absolutePath);\n if (!currentBytes.equals(beforeBytes)) {\n throw new Error('The file changed while the edit was being prepared. Re-read it and retry.');\n }\n assertNotAborted(signal);\n\n if (applied.content !== before) {\n const output = Buffer.from(`${hasBom ? '\\ufeff' : ''}${editedText}`, 'utf8');\n await writeFile(absolutePath, output);\n }\n\n const count = applied.edits.length;\n const noun = count === 1 ? 'range' : 'ranges';\n const message =\n applied.content === before ? `No changes needed in ${params.path}.` : `Edited ${params.path} (${count} ${noun}).`;\n return { content: [{ type: 'text', text: `${message} Re-read before editing it again.` }], details };\n });\n}\n\ninterface LineToken {\n readonly text: string;\n readonly ending: '\\r\\n' | '\\n' | '\\r' | '';\n}\n\nfunction assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nfunction restoreOriginalLineEndings(original: string, edits: readonly PreparedHashlineEdit[]): string {\n const tokens = tokenizeLines(original);\n const defaultEnding = tokens.find((token) => token.ending !== '')?.ending ?? '\\n';\n for (const edit of [...edits].reverse()) {\n const start = edit.from.line - 1;\n const count = edit.to.line - edit.from.line + 1;\n const removed = tokens.slice(start, start + count);\n const inheritedEnding = removed.at(-1)?.ending ?? '';\n const internalEnding = removed.find((token) => token.ending !== '')?.ending ?? defaultEnding;\n const lines = replacementLines(edit.content);\n if (lines.length === 0 && removed.at(-1)?.ending === '' && start > 0) {\n const previous = tokens[start - 1];\n if (previous) tokens[start - 1] = { ...previous, ending: '' };\n }\n const replacements = lines.map<LineToken>((text, index) => ({\n text,\n ending: index === lines.length - 1 ? inheritedEnding : internalEnding,\n }));\n tokens.splice(start, count, ...replacements);\n }\n return tokens.map((token) => `${token.text}${token.ending}`).join('');\n}\n\nfunction tokenizeLines(content: string): LineToken[] {\n const tokens: LineToken[] = [];\n let start = 0;\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index];\n if (character !== '\\r' && character !== '\\n') continue;\n const ending = character === '\\r' && content[index + 1] === '\\n' ? '\\r\\n' : character;\n tokens.push({ text: content.slice(start, index), ending });\n if (ending === '\\r\\n') index += 1;\n start = index + 1;\n }\n tokens.push({ text: content.slice(start), ending: '' });\n return tokens;\n}\n\nfunction replacementLines(content: string | null): string[] {\n if (content === null || content === '') return [];\n const normalized = normalizeToLf(content);\n const trimmed = normalized.endsWith('\\n') ? normalized.slice(0, -1) : normalized;\n return trimmed === '' ? [] : trimmed.split('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EditParams } from "../../schemas/editTool.cjs";
|
|
2
|
+
import { EditToolDetails, ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/editTool.d.ts
|
|
4
|
+
declare function registerHashlineEditTool(pi: Pick<ExtensionAPI, 'registerTool'>): void;
|
|
5
|
+
declare function executeHashlineEdit(params: EditParams, cwd: string, signal: AbortSignal | undefined): Promise<{
|
|
6
|
+
content: [{
|
|
7
|
+
type: 'text';
|
|
8
|
+
text: string;
|
|
9
|
+
}];
|
|
10
|
+
details: EditToolDetails;
|
|
11
|
+
}>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { executeHashlineEdit, registerHashlineEditTool };
|
|
14
|
+
//# sourceMappingURL=editTool.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.d.cts","names":[],"sources":["../../../src/adapters/pi/editTool.ts"],"mappings":";;;iBAsBgB,yBAAyB,IAAI,KAAK;iBA+B5B,oBACpB,QAAQ,YACR,aACA,QAAQ,0BACP;EAAU;IAAY;IAAc;;EAAiB,SAAS"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EditParams } from "../../schemas/editTool.mjs";
|
|
2
|
+
import { EditToolDetails, ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/editTool.d.ts
|
|
4
|
+
declare function registerHashlineEditTool(pi: Pick<ExtensionAPI, 'registerTool'>): void;
|
|
5
|
+
declare function executeHashlineEdit(params: EditParams, cwd: string, signal: AbortSignal | undefined): Promise<{
|
|
6
|
+
content: [{
|
|
7
|
+
type: 'text';
|
|
8
|
+
text: string;
|
|
9
|
+
}];
|
|
10
|
+
details: EditToolDetails;
|
|
11
|
+
}>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { executeHashlineEdit, registerHashlineEditTool };
|
|
14
|
+
//# sourceMappingURL=editTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.d.mts","names":[],"sources":["../../../src/adapters/pi/editTool.ts"],"mappings":";;;iBAsBgB,yBAAyB,IAAI,KAAK;iBA+B5B,oBACpB,QAAQ,YACR,aACA,QAAQ,0BACP;EAAU;IAAY;IAAc;;EAAiB,SAAS"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{EditParamsSchema as e}from"../../schemas/editTool.mjs";import{constants as t}from"node:fs";import{access as n,readFile as r,writeFile as i}from"node:fs/promises";import{applyHashlineEdits as a,normalizeFileTag as o,normalizeToLf as s,stripBom as c}from"@agimon-ai/doompi-hashline";import{computeFileTag as l,decodeUtf8 as u,displayPath as d,resolveInputPath as f}from"@agimon-ai/doompi-hashline/files";import{renderHashlineCall as p,renderHashlineEditResult as m}from"@agimon-ai/doompi-ui/hashlineRendering";import{generateDiffString as h,generateUnifiedPatch as g,withFileMutationQueue as _}from"@earendil-works/pi-coding-agent";const v=Buffer.from([239,187,191]);function y(t){t.registerTool({name:`edit`,label:`edit`,description:`Edit one file using its exact snapshot hash and inclusive anchors such as 5#abc from read or grep. Each from and to value must contain one anchor, not a pasted block. All ranges refer to the original snapshot. Empty or omitted content deletes a range.`,promptSnippet:`Edit files with snapshot-bound hashline ranges`,promptGuidelines:[`Copy path, hash, and anchors from the latest compatible read or grep result. Re-read after every successful edit.`,`Pass one anchor such as 5#abc in each from and to value. Do not paste tagged lines or multiline blocks.`,`Put multiple disjoint changes to one file in one edit call. All anchors must describe the original snapshot.`,`Omit content or pass an empty string to delete an inclusive range. Merge overlapping ranges before calling edit.`],parameters:e,executionMode:`parallel`,renderShell:`self`,async execute(e,t,n,r,i){return b(t,i.cwd,n)},renderCall(e,t){let n=e,r=n.edits.length;return p(`edit`,n.path,[`${r} ${r===1?`range`:`ranges`}`],t)},renderResult(e,t,n,r){let i=r.args;return m(i.path,e,t,n,r)}})}async function b(e,p,m){let y=f(e.path,p),b=o(e.hash);return _(y,async()=>{x(m),await n(y,t.R_OK|t.W_OK);let o=await r(y);x(m);let f=l(o);if(f!==b)throw Error(`Stale file hash ${b}. Current hash is ${f}. Re-read the file and retry.`);let _=o.subarray(0,v.length).equals(v),C=u(o,e.path),w=c(C),T=s(w),E=a(T,e.edits),D=S(w,E.edits);if(s(D)!==E.content)throw Error(`Could not preserve the file line endings safely. The file was not changed.`);let O=h(T,E.content),k=g(d(y,p),T,E.content),A={diff:O.diff,patch:k,firstChangedLine:O.firstChangedLine};if(x(m),!(await r(y)).equals(o))throw Error(`The file changed while the edit was being prepared. Re-read it and retry.`);if(x(m),E.content!==T){let e=Buffer.from(`${_?``:``}${D}`,`utf8`);await i(y,e)}let j=E.edits.length,M=j===1?`range`:`ranges`;return{content:[{type:`text`,text:`${E.content===T?`No changes needed in ${e.path}.`:`Edited ${e.path} (${j} ${M}).`} Re-read before editing it again.`}],details:A}})}function x(e){if(e?.aborted)throw Error(`Operation aborted`)}function S(e,t){let n=C(e),r=n.find(e=>e.ending!==``)?.ending??`
|
|
2
|
+
`;for(let e of[...t].reverse()){let t=e.from.line-1,i=e.to.line-e.from.line+1,a=n.slice(t,t+i),o=a.at(-1)?.ending??``,s=a.find(e=>e.ending!==``)?.ending??r,c=w(e.content);if(c.length===0&&a.at(-1)?.ending===``&&t>0){let e=n[t-1];e&&(n[t-1]={...e,ending:``})}let l=c.map((e,t)=>({text:e,ending:t===c.length-1?o:s}));n.splice(t,i,...l)}return n.map(e=>`${e.text}${e.ending}`).join(``)}function C(e){let t=[],n=0;for(let r=0;r<e.length;r+=1){let i=e[r];if(i!==`\r`&&i!==`
|
|
3
|
+
`)continue;let a=i===`\r`&&e[r+1]===`
|
|
4
|
+
`?`\r
|
|
5
|
+
`:i;t.push({text:e.slice(n,r),ending:a}),a===`\r
|
|
6
|
+
`&&(r+=1),n=r+1}return t.push({text:e.slice(n),ending:``}),t}function w(e){if(e===null||e===``)return[];let t=s(e),n=t.endsWith(`
|
|
7
|
+
`)?t.slice(0,-1):t;return n===``?[]:n.split(`
|
|
8
|
+
`)}export{b as executeHashlineEdit,y as registerHashlineEditTool};
|
|
9
|
+
//# sourceMappingURL=editTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.mjs","names":[],"sources":["../../../src/adapters/pi/editTool.ts"],"sourcesContent":["import { constants } from 'node:fs';\nimport { access, readFile, writeFile } from 'node:fs/promises';\nimport {\n applyHashlineEdits,\n normalizeFileTag,\n normalizeToLf,\n stripBom,\n type PreparedHashlineEdit,\n} from '@agimon-ai/doompi-hashline';\nimport { computeFileTag, decodeUtf8, displayPath, resolveInputPath } from '@agimon-ai/doompi-hashline/files';\nimport { renderHashlineCall, renderHashlineEditResult } from '@agimon-ai/doompi-ui/hashlineRendering';\nimport {\n generateDiffString,\n generateUnifiedPatch,\n withFileMutationQueue,\n type EditToolDetails,\n type ExtensionAPI,\n} from '@earendil-works/pi-coding-agent';\nimport { EditParamsSchema, type EditParams } from '../../schemas/editTool.ts';\n\nconst UTF8_BOM = Buffer.from([0xef, 0xbb, 0xbf]);\n\nexport function registerHashlineEditTool(pi: Pick<ExtensionAPI, 'registerTool'>): void {\n pi.registerTool({\n name: 'edit',\n label: 'edit',\n description:\n 'Edit one file using its exact snapshot hash and inclusive anchors such as 5#abc from read or grep. Each from and to value must contain one anchor, not a pasted block. All ranges refer to the original snapshot. Empty or omitted content deletes a range.',\n promptSnippet: 'Edit files with snapshot-bound hashline ranges',\n promptGuidelines: [\n 'Copy path, hash, and anchors from the latest compatible read or grep result. Re-read after every successful edit.',\n 'Pass one anchor such as 5#abc in each from and to value. Do not paste tagged lines or multiline blocks.',\n 'Put multiple disjoint changes to one file in one edit call. All anchors must describe the original snapshot.',\n 'Omit content or pass an empty string to delete an inclusive range. Merge overlapping ranges before calling edit.',\n ],\n parameters: EditParamsSchema,\n executionMode: 'parallel',\n renderShell: 'self',\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return executeHashlineEdit(params as EditParams, ctx.cwd, signal);\n },\n renderCall(args, theme) {\n const input = args as EditParams;\n const count = input.edits.length;\n return renderHashlineCall('edit', input.path, [`${count} ${count === 1 ? 'range' : 'ranges'}`], theme);\n },\n renderResult(result, options, theme, context) {\n const input = context.args as EditParams;\n return renderHashlineEditResult(input.path, result, options, theme, context);\n },\n });\n}\n\nexport async function executeHashlineEdit(\n params: EditParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<{ content: [{ type: 'text'; text: string }]; details: EditToolDetails }> {\n const absolutePath = resolveInputPath(params.path, cwd);\n const expectedHash = normalizeFileTag(params.hash);\n return withFileMutationQueue(absolutePath, async () => {\n assertNotAborted(signal);\n await access(absolutePath, constants.R_OK | constants.W_OK);\n const beforeBytes = await readFile(absolutePath);\n assertNotAborted(signal);\n\n const actualHash = computeFileTag(beforeBytes);\n if (actualHash !== expectedHash) {\n throw new Error(`Stale file hash ${expectedHash}. Current hash is ${actualHash}. Re-read the file and retry.`);\n }\n\n const hasBom = beforeBytes.subarray(0, UTF8_BOM.length).equals(UTF8_BOM);\n const decoded = decodeUtf8(beforeBytes, params.path);\n const withoutBom = stripBom(decoded);\n const before = normalizeToLf(withoutBom);\n const applied = applyHashlineEdits(before, params.edits);\n const editedText = restoreOriginalLineEndings(withoutBom, applied.edits);\n if (normalizeToLf(editedText) !== applied.content) {\n throw new Error('Could not preserve the file line endings safely. The file was not changed.');\n }\n const diff = generateDiffString(before, applied.content);\n const patch = generateUnifiedPatch(displayPath(absolutePath, cwd), before, applied.content);\n const details: EditToolDetails = { diff: diff.diff, patch, firstChangedLine: diff.firstChangedLine };\n\n assertNotAborted(signal);\n const currentBytes = await readFile(absolutePath);\n if (!currentBytes.equals(beforeBytes)) {\n throw new Error('The file changed while the edit was being prepared. Re-read it and retry.');\n }\n assertNotAborted(signal);\n\n if (applied.content !== before) {\n const output = Buffer.from(`${hasBom ? '\\ufeff' : ''}${editedText}`, 'utf8');\n await writeFile(absolutePath, output);\n }\n\n const count = applied.edits.length;\n const noun = count === 1 ? 'range' : 'ranges';\n const message =\n applied.content === before ? `No changes needed in ${params.path}.` : `Edited ${params.path} (${count} ${noun}).`;\n return { content: [{ type: 'text', text: `${message} Re-read before editing it again.` }], details };\n });\n}\n\ninterface LineToken {\n readonly text: string;\n readonly ending: '\\r\\n' | '\\n' | '\\r' | '';\n}\n\nfunction assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nfunction restoreOriginalLineEndings(original: string, edits: readonly PreparedHashlineEdit[]): string {\n const tokens = tokenizeLines(original);\n const defaultEnding = tokens.find((token) => token.ending !== '')?.ending ?? '\\n';\n for (const edit of [...edits].reverse()) {\n const start = edit.from.line - 1;\n const count = edit.to.line - edit.from.line + 1;\n const removed = tokens.slice(start, start + count);\n const inheritedEnding = removed.at(-1)?.ending ?? '';\n const internalEnding = removed.find((token) => token.ending !== '')?.ending ?? defaultEnding;\n const lines = replacementLines(edit.content);\n if (lines.length === 0 && removed.at(-1)?.ending === '' && start > 0) {\n const previous = tokens[start - 1];\n if (previous) tokens[start - 1] = { ...previous, ending: '' };\n }\n const replacements = lines.map<LineToken>((text, index) => ({\n text,\n ending: index === lines.length - 1 ? inheritedEnding : internalEnding,\n }));\n tokens.splice(start, count, ...replacements);\n }\n return tokens.map((token) => `${token.text}${token.ending}`).join('');\n}\n\nfunction tokenizeLines(content: string): LineToken[] {\n const tokens: LineToken[] = [];\n let start = 0;\n for (let index = 0; index < content.length; index += 1) {\n const character = content[index];\n if (character !== '\\r' && character !== '\\n') continue;\n const ending = character === '\\r' && content[index + 1] === '\\n' ? '\\r\\n' : character;\n tokens.push({ text: content.slice(start, index), ending });\n if (ending === '\\r\\n') index += 1;\n start = index + 1;\n }\n tokens.push({ text: content.slice(start), ending: '' });\n return tokens;\n}\n\nfunction replacementLines(content: string | null): string[] {\n if (content === null || content === '') return [];\n const normalized = normalizeToLf(content);\n const trimmed = normalized.endsWith('\\n') ? normalized.slice(0, -1) : normalized;\n return trimmed === '' ? [] : trimmed.split('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./editTool.cjs");let t=require("@agimon-ai/doompi-extension-contracts/cordis-host"),n=require("@agimon-ai/doompi-extension-contracts/tool-overrides");const r=`@agimon-ai/doompi-edit`;function i(t,i){t.inject([n.DOOM_TOOL_OVERRIDES_SERVICE],t=>{let a=(0,n.requireDoomToolOverrides)(t).claim({source:r,tools:[`edit`]});if(a.granted){try{e.registerHashlineEditTool(i)}catch(e){throw a.dispose(),e}return()=>a.dispose()}})}async function a(e){let n=await(0,t.connectDoomCordisHost)(e,r),i=n.root.plugin(o,{pi:e});try{await i}catch(e){try{await i.dispose()}finally{await n.dispose()}throw e}let a;e.on(`session_shutdown`,()=>a??=(async()=>{try{await i.dispose()}finally{await n.dispose()}})())}function o(e,t){i(e,t.pi)}exports.activateDoomPiEditExtension=a,exports.default=a,exports.installDoomPiEditRuntime=i;
|
|
2
|
+
//# sourceMappingURL=extension.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["DOOM_TOOL_OVERRIDES_SERVICE","requireDoomToolOverrides","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_TOOL_OVERRIDES_SERVICE,\n requireDoomToolOverrides,\n} from '@agimon-ai/doompi-extension-contracts/tool-overrides';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerHashlineEditTool } from './editTool.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-edit';\n\n/** Install the hashline edit tool after claiming its shared Pi name. */\nexport function installDoomPiEditRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.inject([DOOM_TOOL_OVERRIDES_SERVICE], (overridesContext) => {\n const registration = requireDoomToolOverrides(overridesContext).claim({\n source: PACKAGE_SOURCE,\n tools: ['edit'],\n });\n if (!registration.granted) return;\n try {\n registerHashlineEditTool(pi);\n } catch (error) {\n registration.dispose();\n throw error;\n }\n return () => registration.dispose();\n });\n}\n\n/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */\nexport async function activateDoomPiEditExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiEditPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface DoomPiEditPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction doomPiEditPlugin(cordis: Context, config: DoomPiEditPluginConfig): void {\n installDoomPiEditRuntime(cordis, config.pi);\n}\n\nexport default activateDoomPiEditExtension;\n"],"mappings":"uKASA,MAAM,EAAiB,yBAGvB,SAAgB,EAAyB,EAAiB,EAAwB,CAChF,EAAO,OAAO,CAACA,EAAAA,2BAA2B,EAAI,GAAqB,CACjE,IAAM,GAAA,EAAeC,EAAAA,yBAAAA,CAAyB,CAAgB,CAAC,CAAC,MAAM,CACpE,OAAQ,EACR,MAAO,CAAC,MAAM,CAChB,CAAC,EACI,KAAa,QAClB,IAAI,CACF,EAAA,yBAAyB,CAAE,CAC7B,OAAS,EAAO,CAEd,MADA,EAAa,QAAQ,EACf,CACR,CACA,UAAa,EAAa,QAAQ,CADlC,CAEF,CAAC,CACH,CAGA,eAAsB,EAA4B,EAAiC,CACjF,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAkB,CAAE,IAAG,CAAC,EAC7D,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAiB,EAAiB,EAAsC,CAC/E,EAAyB,EAAQ,EAAO,EAAE,CAC5C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/** Install the hashline edit tool after claiming its shared Pi name. */
|
|
5
|
+
declare function installDoomPiEditRuntime(cordis: Context, pi: ExtensionAPI): void;
|
|
6
|
+
/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
|
|
7
|
+
declare function activateDoomPiEditExtension(pi: ExtensionAPI): Promise<void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { activateDoomPiEditExtension, activateDoomPiEditExtension as default, installDoomPiEditRuntime };
|
|
10
|
+
//# sourceMappingURL=extension.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;iBAkBxC,4BAA4B,IAAI,eAAe"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
//#region src/adapters/pi/extension.d.ts
|
|
4
|
+
/** Install the hashline edit tool after claiming its shared Pi name. */
|
|
5
|
+
declare function installDoomPiEditRuntime(cordis: Context, pi: ExtensionAPI): void;
|
|
6
|
+
/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */
|
|
7
|
+
declare function activateDoomPiEditExtension(pi: ExtensionAPI): Promise<void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { activateDoomPiEditExtension, activateDoomPiEditExtension as default, installDoomPiEditRuntime };
|
|
10
|
+
//# sourceMappingURL=extension.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAYgB,yBAAyB,QAAQ,SAAS,IAAI;;iBAkBxC,4BAA4B,IAAI,eAAe"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{registerHashlineEditTool as e}from"./editTool.mjs";import{connectDoomCordisHost as t}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_TOOL_OVERRIDES_SERVICE as n,requireDoomToolOverrides as r}from"@agimon-ai/doompi-extension-contracts/tool-overrides";const i=`@agimon-ai/doompi-edit`;function a(t,a){t.inject([n],t=>{let n=r(t).claim({source:i,tools:[`edit`]});if(n.granted){try{e(a)}catch(e){throw n.dispose(),e}return()=>n.dispose()}})}async function o(e){let n=await t(e,i),r=n.root.plugin(s,{pi:e});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let a;e.on(`session_shutdown`,()=>a??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}function s(e,t){a(e,t.pi)}export{o as activateDoomPiEditExtension,o as default,a as installDoomPiEditRuntime};
|
|
2
|
+
//# sourceMappingURL=extension.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n DOOM_TOOL_OVERRIDES_SERVICE,\n requireDoomToolOverrides,\n} from '@agimon-ai/doompi-extension-contracts/tool-overrides';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerHashlineEditTool } from './editTool.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-edit';\n\n/** Install the hashline edit tool after claiming its shared Pi name. */\nexport function installDoomPiEditRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.inject([DOOM_TOOL_OVERRIDES_SERVICE], (overridesContext) => {\n const registration = requireDoomToolOverrides(overridesContext).claim({\n source: PACKAGE_SOURCE,\n tools: ['edit'],\n });\n if (!registration.granted) return;\n try {\n registerHashlineEditTool(pi);\n } catch (error) {\n registration.dispose();\n throw error;\n }\n return () => registration.dispose();\n });\n}\n\n/** Connect the package's standard Pi entry to DoomPi's shared Cordis host. */\nexport async function activateDoomPiEditExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiEditPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface DoomPiEditPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction doomPiEditPlugin(cordis: Context, config: DoomPiEditPluginConfig): void {\n installDoomPiEditRuntime(cordis, config.pi);\n}\n\nexport default activateDoomPiEditExtension;\n"],"mappings":"qRASA,MAAM,EAAiB,yBAGvB,SAAgB,EAAyB,EAAiB,EAAwB,CAChF,EAAO,OAAO,CAAC,CAA2B,EAAI,GAAqB,CACjE,IAAM,EAAe,EAAyB,CAAgB,CAAC,CAAC,MAAM,CACpE,OAAQ,EACR,MAAO,CAAC,MAAM,CAChB,CAAC,EACI,KAAa,QAClB,IAAI,CACF,EAAyB,CAAE,CAC7B,OAAS,EAAO,CAEd,MADA,EAAa,QAAQ,EACf,CACR,CACA,UAAa,EAAa,QAAQ,CADlC,CAEF,CAAC,CACH,CAGA,eAAsB,EAA4B,EAAiC,CACjF,IAAM,EAAa,MAAM,EAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAkB,CAAE,IAAG,CAAC,EAC7D,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAiB,EAAiB,EAAsC,CAC/E,EAAyB,EAAQ,EAAO,EAAE,CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../adapters/pi/extension.cjs");module.exports=e.activateDoomPiEditExtension;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{activateDoomPiEditExtension as e}from"../adapters/pi/extension.mjs";export{e as default};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./schemas/editTool.cjs"),t=require("./adapters/pi/editTool.cjs"),n=require("./adapters/pi/extension.cjs");exports.EditParamsSchema=e.EditParamsSchema,exports.HashlineRangeSchema=e.HashlineRangeSchema,exports.activateDoomPiEditExtension=n.activateDoomPiEditExtension,exports.executeHashlineEdit=t.executeHashlineEdit,exports.installDoomPiEditRuntime=n.installDoomPiEditRuntime,exports.registerHashlineEditTool=t.registerHashlineEditTool;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { activateDoomPiEditExtension, installDoomPiEditRuntime } from "./adapters/pi/extension.cjs";
|
|
2
|
+
import { EditParams, EditParamsSchema, HashlineRange, HashlineRangeSchema } from "./schemas/editTool.cjs";
|
|
3
|
+
import { executeHashlineEdit, registerHashlineEditTool } from "./adapters/pi/editTool.cjs";
|
|
4
|
+
export { type EditParams, EditParamsSchema, type HashlineRange, HashlineRangeSchema, activateDoomPiEditExtension, executeHashlineEdit, installDoomPiEditRuntime, registerHashlineEditTool };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { activateDoomPiEditExtension, installDoomPiEditRuntime } from "./adapters/pi/extension.mjs";
|
|
2
|
+
import { EditParams, EditParamsSchema, HashlineRange, HashlineRangeSchema } from "./schemas/editTool.mjs";
|
|
3
|
+
import { executeHashlineEdit, registerHashlineEditTool } from "./adapters/pi/editTool.mjs";
|
|
4
|
+
export { type EditParams, EditParamsSchema, type HashlineRange, HashlineRangeSchema, activateDoomPiEditExtension, executeHashlineEdit, installDoomPiEditRuntime, registerHashlineEditTool };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{EditParamsSchema as e,HashlineRangeSchema as t}from"./schemas/editTool.mjs";import{executeHashlineEdit as n,registerHashlineEditTool as r}from"./adapters/pi/editTool.mjs";import{activateDoomPiEditExtension as i,installDoomPiEditRuntime as a}from"./adapters/pi/extension.mjs";export{e as EditParamsSchema,t as HashlineRangeSchema,i as activateDoomPiEditExtension,n as executeHashlineEdit,a as installDoomPiEditRuntime,r as registerHashlineEditTool};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("typebox");const t=e.Type.Object({from:e.Type.String({description:`One inclusive starting anchor, for example 5#abc. Do not paste multiple lines.`}),to:e.Type.String({description:`One inclusive ending anchor, for example 8#def. Do not paste multiple lines.`}),content:e.Type.Optional(e.Type.Union([e.Type.String({description:`Replacement content. Empty content deletes the selected lines.`}),e.Type.Null({description:`Delete the selected lines.`})]))}),n=e.Type.Object({path:e.Type.String({description:`Path to the file returned by a compatible hashline read or grep tool.`}),hash:e.Type.String({description:`Eight-character exact-byte file tag returned by read or grep.`}),edits:e.Type.Array(t,{minItems:1,description:`Non-overlapping inclusive ranges from the same original snapshot.`})});exports.EditParamsSchema=n,exports.HashlineRangeSchema=t;
|
|
2
|
+
//# sourceMappingURL=editTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.cjs","names":["Type"],"sources":["../../src/schemas/editTool.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const HashlineRangeSchema = Type.Object({\n from: Type.String({ description: 'One inclusive starting anchor, for example 5#abc. Do not paste multiple lines.' }),\n to: Type.String({ description: 'One inclusive ending anchor, for example 8#def. Do not paste multiple lines.' }),\n content: Type.Optional(\n Type.Union([\n Type.String({ description: 'Replacement content. Empty content deletes the selected lines.' }),\n Type.Null({ description: 'Delete the selected lines.' }),\n ]),\n ),\n});\n\nexport const EditParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file returned by a compatible hashline read or grep tool.' }),\n hash: Type.String({ description: 'Eight-character exact-byte file tag returned by read or grep.' }),\n edits: Type.Array(HashlineRangeSchema, {\n minItems: 1,\n description: 'Non-overlapping inclusive ranges from the same original snapshot.',\n }),\n});\n\nexport type HashlineRange = Static<typeof HashlineRangeSchema>;\nexport type EditParams = Static<typeof EditParamsSchema>;\n"],"mappings":"yBAEA,MAAa,EAAsBA,EAAAA,KAAK,OAAO,CAC7C,KAAMA,EAAAA,KAAK,OAAO,CAAE,YAAa,gFAAiF,CAAC,EACnH,GAAIA,EAAAA,KAAK,OAAO,CAAE,YAAa,8EAA+E,CAAC,EAC/G,QAASA,EAAAA,KAAK,SACZA,EAAAA,KAAK,MAAM,CACTA,EAAAA,KAAK,OAAO,CAAE,YAAa,gEAAiE,CAAC,EAC7FA,EAAAA,KAAK,KAAK,CAAE,YAAa,4BAA6B,CAAC,CACzD,CAAC,CACH,CACF,CAAC,EAEY,EAAmBA,EAAAA,KAAK,OAAO,CAC1C,KAAMA,EAAAA,KAAK,OAAO,CAAE,YAAa,uEAAwE,CAAC,EAC1G,KAAMA,EAAAA,KAAK,OAAO,CAAE,YAAa,+DAAgE,CAAC,EAClG,MAAOA,EAAAA,KAAK,MAAM,EAAqB,CACrC,SAAU,EACV,YAAa,mEACf,CAAC,CACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Static, Type } from "typebox";
|
|
2
|
+
//#region src/schemas/editTool.d.ts
|
|
3
|
+
declare const HashlineRangeSchema: Type.TObject<{
|
|
4
|
+
from: Type.TString;
|
|
5
|
+
to: Type.TString;
|
|
6
|
+
content: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
7
|
+
}>;
|
|
8
|
+
declare const EditParamsSchema: Type.TObject<{
|
|
9
|
+
path: Type.TString;
|
|
10
|
+
hash: Type.TString;
|
|
11
|
+
edits: Type.TArray<Type.TObject<{
|
|
12
|
+
from: Type.TString;
|
|
13
|
+
to: Type.TString;
|
|
14
|
+
content: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
15
|
+
}>>;
|
|
16
|
+
}>;
|
|
17
|
+
type HashlineRange = Static<typeof HashlineRangeSchema>;
|
|
18
|
+
type EditParams = Static<typeof EditParamsSchema>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { EditParams, EditParamsSchema, HashlineRange, HashlineRangeSchema };
|
|
21
|
+
//# sourceMappingURL=editTool.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.d.cts","names":[],"sources":["../../src/schemas/editTool.ts"],"mappings":";;cAEa,qBAAmB,KAAA;;;;;cAWnB,kBAAgB,KAAA;;;;;;;;;KASjB,gBAAgB,cAAc;KAC9B,aAAa,cAAc"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Static, Type } from "typebox";
|
|
2
|
+
//#region src/schemas/editTool.d.ts
|
|
3
|
+
declare const HashlineRangeSchema: Type.TObject<{
|
|
4
|
+
from: Type.TString;
|
|
5
|
+
to: Type.TString;
|
|
6
|
+
content: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
7
|
+
}>;
|
|
8
|
+
declare const EditParamsSchema: Type.TObject<{
|
|
9
|
+
path: Type.TString;
|
|
10
|
+
hash: Type.TString;
|
|
11
|
+
edits: Type.TArray<Type.TObject<{
|
|
12
|
+
from: Type.TString;
|
|
13
|
+
to: Type.TString;
|
|
14
|
+
content: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
15
|
+
}>>;
|
|
16
|
+
}>;
|
|
17
|
+
type HashlineRange = Static<typeof HashlineRangeSchema>;
|
|
18
|
+
type EditParams = Static<typeof EditParamsSchema>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { EditParams, EditParamsSchema, HashlineRange, HashlineRangeSchema };
|
|
21
|
+
//# sourceMappingURL=editTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.d.mts","names":[],"sources":["../../src/schemas/editTool.ts"],"mappings":";;cAEa,qBAAmB,KAAA;;;;;cAWnB,kBAAgB,KAAA;;;;;;;;;KASjB,gBAAgB,cAAc;KAC9B,aAAa,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Type as e}from"typebox";const t=e.Object({from:e.String({description:`One inclusive starting anchor, for example 5#abc. Do not paste multiple lines.`}),to:e.String({description:`One inclusive ending anchor, for example 8#def. Do not paste multiple lines.`}),content:e.Optional(e.Union([e.String({description:`Replacement content. Empty content deletes the selected lines.`}),e.Null({description:`Delete the selected lines.`})]))}),n=e.Object({path:e.String({description:`Path to the file returned by a compatible hashline read or grep tool.`}),hash:e.String({description:`Eight-character exact-byte file tag returned by read or grep.`}),edits:e.Array(t,{minItems:1,description:`Non-overlapping inclusive ranges from the same original snapshot.`})});export{n as EditParamsSchema,t as HashlineRangeSchema};
|
|
2
|
+
//# sourceMappingURL=editTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.mjs","names":[],"sources":["../../src/schemas/editTool.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const HashlineRangeSchema = Type.Object({\n from: Type.String({ description: 'One inclusive starting anchor, for example 5#abc. Do not paste multiple lines.' }),\n to: Type.String({ description: 'One inclusive ending anchor, for example 8#def. Do not paste multiple lines.' }),\n content: Type.Optional(\n Type.Union([\n Type.String({ description: 'Replacement content. Empty content deletes the selected lines.' }),\n Type.Null({ description: 'Delete the selected lines.' }),\n ]),\n ),\n});\n\nexport const EditParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file returned by a compatible hashline read or grep tool.' }),\n hash: Type.String({ description: 'Eight-character exact-byte file tag returned by read or grep.' }),\n edits: Type.Array(HashlineRangeSchema, {\n minItems: 1,\n description: 'Non-overlapping inclusive ranges from the same original snapshot.',\n }),\n});\n\nexport type HashlineRange = Static<typeof HashlineRangeSchema>;\nexport type EditParams = Static<typeof EditParamsSchema>;\n"],"mappings":"+BAEA,MAAa,EAAsB,EAAK,OAAO,CAC7C,KAAM,EAAK,OAAO,CAAE,YAAa,gFAAiF,CAAC,EACnH,GAAI,EAAK,OAAO,CAAE,YAAa,8EAA+E,CAAC,EAC/G,QAAS,EAAK,SACZ,EAAK,MAAM,CACT,EAAK,OAAO,CAAE,YAAa,gEAAiE,CAAC,EAC7F,EAAK,KAAK,CAAE,YAAa,4BAA6B,CAAC,CACzD,CAAC,CACH,CACF,CAAC,EAEY,EAAmB,EAAK,OAAO,CAC1C,KAAM,EAAK,OAAO,CAAE,YAAa,uEAAwE,CAAC,EAC1G,KAAM,EAAK,OAAO,CAAE,YAAa,+DAAgE,CAAC,EAClG,MAAO,EAAK,MAAM,EAAqB,CACrC,SAAU,EACV,YAAa,mEACf,CAAC,CACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agimon-ai/doompi-edit",
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
|
+
"description": "Snapshot-bound hashline edit tool for Pi and DoomPi.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"coding-agent",
|
|
8
|
+
"developer-tools",
|
|
9
|
+
"doompi",
|
|
10
|
+
"hashline",
|
|
11
|
+
"pi-coding-agent",
|
|
12
|
+
"pi-extension",
|
|
13
|
+
"pi-package"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://agimon.ai",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Vuong Ngo",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"types": "./dist/index.d.mts",
|
|
24
|
+
"jsnext:main": "./dist/index.mjs",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.mts",
|
|
28
|
+
"import": "./dist/index.mjs",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./extensions/pi": {
|
|
32
|
+
"types": "./dist/extensions/pi.d.mts",
|
|
33
|
+
"import": "./dist/extensions/pi.mjs",
|
|
34
|
+
"require": "./dist/extensions/pi.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
43
|
+
"typebox": "1.3.16",
|
|
44
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.29",
|
|
45
|
+
"@agimon-ai/doompi-hashline": "0.0.1-alpha.1",
|
|
46
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.29"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
50
|
+
"@earendil-works/pi-tui": "0.84.2",
|
|
51
|
+
"@types/node": "26.2.0",
|
|
52
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
53
|
+
"tsdown": "0.22.14",
|
|
54
|
+
"typescript": "7.0.2",
|
|
55
|
+
"vitest": "4.1.11"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
59
|
+
"@earendil-works/pi-tui": "0.84.2"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"@earendil-works/pi-coding-agent": {
|
|
63
|
+
"optional": true
|
|
64
|
+
},
|
|
65
|
+
"@earendil-works/pi-tui": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=22.19.0"
|
|
71
|
+
},
|
|
72
|
+
"pi": {
|
|
73
|
+
"extensions": [
|
|
74
|
+
"./dist/extensions/pi.mjs"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"build": "tsdown",
|
|
79
|
+
"test": "vitest --run",
|
|
80
|
+
"typecheck": "tsc --noEmit",
|
|
81
|
+
"lint": "oxlint . && oxfmt . --check",
|
|
82
|
+
"fixcode": "oxlint . --fix && oxfmt ."
|
|
83
|
+
}
|
|
84
|
+
}
|