@agimon-ai/doompi-file-edit 0.0.1-alpha.22 → 0.0.1-alpha.24

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 (136) hide show
  1. package/README.md +9 -6
  2. package/dist/adapters/EditTracker/EditTracker.cjs +2 -0
  3. package/dist/adapters/EditTracker/EditTracker.cjs.map +1 -0
  4. package/dist/adapters/EditTracker/EditTracker.mjs +2 -0
  5. package/dist/adapters/EditTracker/EditTracker.mjs.map +1 -0
  6. package/dist/adapters/EditorConfigService/EditorConfigService.cjs +2 -0
  7. package/dist/adapters/EditorConfigService/EditorConfigService.cjs.map +1 -0
  8. package/dist/adapters/EditorConfigService/EditorConfigService.mjs +2 -0
  9. package/dist/adapters/EditorConfigService/EditorConfigService.mjs.map +1 -0
  10. package/dist/adapters/EditorLauncher/EditorLauncher.cjs +2 -0
  11. package/dist/adapters/EditorLauncher/EditorLauncher.cjs.map +1 -0
  12. package/dist/adapters/EditorLauncher/EditorLauncher.mjs +2 -0
  13. package/dist/adapters/EditorLauncher/EditorLauncher.mjs.map +1 -0
  14. package/dist/adapters/FileEditPaths/FileEditPaths.cjs +2 -0
  15. package/dist/adapters/FileEditPaths/FileEditPaths.cjs.map +1 -0
  16. package/dist/adapters/FileEditPaths/FileEditPaths.mjs +2 -0
  17. package/dist/adapters/FileEditPaths/FileEditPaths.mjs.map +1 -0
  18. package/dist/adapters/GitDiffService/GitDiffService.cjs +5 -0
  19. package/dist/adapters/GitDiffService/GitDiffService.cjs.map +1 -0
  20. package/dist/adapters/GitDiffService/GitDiffService.mjs +5 -0
  21. package/dist/adapters/GitDiffService/GitDiffService.mjs.map +1 -0
  22. package/dist/adapters/TimelineStore/TimelineStore.cjs +3 -0
  23. package/dist/adapters/TimelineStore/TimelineStore.cjs.map +1 -0
  24. package/dist/adapters/TimelineStore/TimelineStore.mjs +3 -0
  25. package/dist/adapters/TimelineStore/TimelineStore.mjs.map +1 -0
  26. package/dist/adapters/pi/extension.cjs +1 -1
  27. package/dist/adapters/pi/extension.cjs.map +1 -1
  28. package/dist/adapters/pi/extension.d.cts +3 -1
  29. package/dist/adapters/pi/extension.d.cts.map +1 -1
  30. package/dist/adapters/pi/extension.d.mts +3 -1
  31. package/dist/adapters/pi/extension.d.mts.map +1 -1
  32. package/dist/adapters/pi/extension.mjs +1 -1
  33. package/dist/adapters/pi/extension.mjs.map +1 -1
  34. package/dist/container/index.cjs +1 -1
  35. package/dist/container/index.cjs.map +1 -1
  36. package/dist/container/index.d.cts +9 -3
  37. package/dist/container/index.d.cts.map +1 -1
  38. package/dist/container/index.d.mts +9 -3
  39. package/dist/container/index.d.mts.map +1 -1
  40. package/dist/container/index.mjs +1 -1
  41. package/dist/container/index.mjs.map +1 -1
  42. package/dist/index.cjs +1 -1
  43. package/dist/index.d.cts +3 -3
  44. package/dist/index.d.mts +3 -3
  45. package/dist/index.mjs +1 -1
  46. package/dist/tui/fileEditOverlay.cjs.map +1 -1
  47. package/dist/tui/fileEditOverlay.mjs.map +1 -1
  48. package/dist/tui/fileEditWorkflow.cjs +2 -0
  49. package/dist/tui/fileEditWorkflow.cjs.map +1 -0
  50. package/dist/tui/fileEditWorkflow.mjs +2 -0
  51. package/dist/tui/fileEditWorkflow.mjs.map +1 -0
  52. package/dist/{services/fileEdit → types}/domain.d.cts +1 -1
  53. package/dist/types/domain.d.cts.map +1 -0
  54. package/dist/{services/fileEdit → types}/domain.d.mts +1 -1
  55. package/dist/types/domain.d.mts.map +1 -0
  56. package/dist/types/editTracker.d.cts +8 -0
  57. package/dist/types/editTracker.d.cts.map +1 -0
  58. package/dist/types/editTracker.d.mts +8 -0
  59. package/dist/types/editTracker.d.mts.map +1 -0
  60. package/dist/types/editorConfigService.d.cts +12 -0
  61. package/dist/types/editorConfigService.d.cts.map +1 -0
  62. package/dist/types/editorConfigService.d.mts +12 -0
  63. package/dist/types/editorConfigService.d.mts.map +1 -0
  64. package/dist/types/editorLauncher.d.cts +18 -0
  65. package/dist/types/editorLauncher.d.cts.map +1 -0
  66. package/dist/types/editorLauncher.d.mts +18 -0
  67. package/dist/types/editorLauncher.d.mts.map +1 -0
  68. package/dist/types/fileEditPaths.d.cts +8 -0
  69. package/dist/types/fileEditPaths.d.cts.map +1 -0
  70. package/dist/types/fileEditPaths.d.mts +8 -0
  71. package/dist/types/fileEditPaths.d.mts.map +1 -0
  72. package/dist/types/fileEditWorkflow.d.cts +8 -0
  73. package/dist/types/fileEditWorkflow.d.cts.map +1 -0
  74. package/dist/types/fileEditWorkflow.d.mts +8 -0
  75. package/dist/types/fileEditWorkflow.d.mts.map +1 -0
  76. package/dist/types/gitDiffService.d.cts +8 -0
  77. package/dist/types/gitDiffService.d.cts.map +1 -0
  78. package/dist/types/gitDiffService.d.mts +8 -0
  79. package/dist/types/gitDiffService.d.mts.map +1 -0
  80. package/dist/types/index.d.cts +18 -10
  81. package/dist/types/index.d.cts.map +1 -1
  82. package/dist/types/index.d.mts +18 -10
  83. package/dist/types/index.d.mts.map +1 -1
  84. package/dist/types/timelineStore.d.cts +11 -0
  85. package/dist/types/timelineStore.d.cts.map +1 -0
  86. package/dist/types/timelineStore.d.mts +11 -0
  87. package/dist/types/timelineStore.d.mts.map +1 -0
  88. package/package.json +14 -15
  89. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.cjs +0 -1
  90. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.mjs +0 -1
  91. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.cjs +0 -1
  92. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.mjs +0 -1
  93. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.cjs +0 -1
  94. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.mjs +0 -1
  95. package/dist/extensions/doom.cjs +0 -2
  96. package/dist/extensions/doom.cjs.map +0 -1
  97. package/dist/extensions/doom.d.cts +0 -6
  98. package/dist/extensions/doom.d.cts.map +0 -1
  99. package/dist/extensions/doom.d.mts +0 -6
  100. package/dist/extensions/doom.d.mts.map +0 -1
  101. package/dist/extensions/doom.mjs +0 -2
  102. package/dist/extensions/doom.mjs.map +0 -1
  103. package/dist/services/EditTracker/EditTracker.cjs +0 -2
  104. package/dist/services/EditTracker/EditTracker.cjs.map +0 -1
  105. package/dist/services/EditTracker/EditTracker.mjs +0 -2
  106. package/dist/services/EditTracker/EditTracker.mjs.map +0 -1
  107. package/dist/services/EditorConfigService/EditorConfigService.cjs +0 -2
  108. package/dist/services/EditorConfigService/EditorConfigService.cjs.map +0 -1
  109. package/dist/services/EditorConfigService/EditorConfigService.mjs +0 -2
  110. package/dist/services/EditorConfigService/EditorConfigService.mjs.map +0 -1
  111. package/dist/services/EditorLauncher/EditorLauncher.cjs +0 -2
  112. package/dist/services/EditorLauncher/EditorLauncher.cjs.map +0 -1
  113. package/dist/services/EditorLauncher/EditorLauncher.mjs +0 -2
  114. package/dist/services/EditorLauncher/EditorLauncher.mjs.map +0 -1
  115. package/dist/services/FileEditPaths/FileEditPaths.cjs +0 -2
  116. package/dist/services/FileEditPaths/FileEditPaths.cjs.map +0 -1
  117. package/dist/services/FileEditPaths/FileEditPaths.mjs +0 -2
  118. package/dist/services/FileEditPaths/FileEditPaths.mjs.map +0 -1
  119. package/dist/services/FileEditWorkflow/FileEditWorkflow.cjs +0 -2
  120. package/dist/services/FileEditWorkflow/FileEditWorkflow.cjs.map +0 -1
  121. package/dist/services/FileEditWorkflow/FileEditWorkflow.mjs +0 -2
  122. package/dist/services/FileEditWorkflow/FileEditWorkflow.mjs.map +0 -1
  123. package/dist/services/GitDiffService/GitDiffService.cjs +0 -5
  124. package/dist/services/GitDiffService/GitDiffService.cjs.map +0 -1
  125. package/dist/services/GitDiffService/GitDiffService.mjs +0 -5
  126. package/dist/services/GitDiffService/GitDiffService.mjs.map +0 -1
  127. package/dist/services/TimelineStore/TimelineStore.cjs +0 -3
  128. package/dist/services/TimelineStore/TimelineStore.cjs.map +0 -1
  129. package/dist/services/TimelineStore/TimelineStore.mjs +0 -3
  130. package/dist/services/TimelineStore/TimelineStore.mjs.map +0 -1
  131. package/dist/services/fileEdit/domain.d.cts.map +0 -1
  132. package/dist/services/fileEdit/domain.d.mts.map +0 -1
  133. package/dist/types/index.cjs +0 -2
  134. package/dist/types/index.cjs.map +0 -1
  135. package/dist/types/index.mjs +0 -2
  136. package/dist/types/index.mjs.map +0 -1
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A session-scoped file-change timeline and external-editor launcher for Pi.
4
4
 
5
+ Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
6
+
5
7
  The package records files changed by successful `edit` and `write` calls and literal file paths detected in successful Bash changes. It presents the current session's work without relying on the transcript to remember every path.
6
8
 
7
9
  > **Alpha:** timeline and UI contracts may change between releases.
@@ -14,17 +16,16 @@ The package records files changed by successful `edit` and `write` calls and lit
14
16
 
15
17
  ## Install
16
18
 
17
- DoomPi loads the Doom adapter as core. For standalone Pi:
19
+ DoomPi includes File Edit in every composition. Standalone Pi loads the same standard factory:
18
20
 
19
21
  ```bash
20
22
  pi install npm:@agimon-ai/doompi-file-edit
21
23
  ```
22
24
 
23
- | Entry | Purpose |
24
- | --------------------------------------------- | -------------------------------------- |
25
- | `@agimon-ai/doompi-file-edit/extensions/doom` | DoomPi adapter and Leader contribution |
26
- | `@agimon-ai/doompi-file-edit/extensions/pi` | Standalone Pi adapter |
27
- | `@agimon-ai/doompi-file-edit` | Library API |
25
+ | Entry | Purpose |
26
+ | ------------------------------------------- | ------------------------------------------ |
27
+ | `@agimon-ai/doompi-file-edit/extensions/pi` | File-edit timeline and Leader contribution |
28
+ | `@agimon-ai/doompi-file-edit` | Library API |
28
29
 
29
30
  ## Open the timeline
30
31
 
@@ -75,6 +76,8 @@ pnpm test
75
76
  pnpm lint
76
77
  ```
77
78
 
79
+ Maintained by [Agimon](https://agimon.ai/about).
80
+
78
81
  ## License
79
82
 
80
83
  MIT
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs/promises");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);const r=`edit`,i=`write`,a=`bash`,o=new Set([`ENOENT`,`ENAMETOOLONG`]);function s(e,t){if(!e||typeof e!=`object`)return;let n=e[t];return typeof n==`string`?n:void 0}var c=class{timeline;pending=new Map;constructor(e){this.timeline=e}async start(e,t,o,c){if(t===r||t===i){let r=s(o,`path`);if(!r)return;let i=n.default.resolve(c,r);this.pending.set(e,{tool:t,paths:new Map([[i,await this.fingerprint(i)]])});return}if(t!==a)return;let l=s(o,`command`);if(!l)return;let u=new Map;for(let e of this.literalPaths(l,c))u.set(e,await this.fingerprint(e));this.pending.set(e,{tool:a,paths:u})}async end(e,t){let n=this.pending.get(e);if(this.pending.delete(e),!(!n||t))for(let[e,t]of n.paths){let a=await this.fingerprint(e);(n.tool===r||n.tool===i||JSON.stringify(t)!==JSON.stringify(a))&&await this.timeline.append({version:1,path:e,tool:n.tool,at:Date.now()})}}literalPaths(e,t){let r=(e.match(/"[^"]+"|'[^']+'|[^\s|;&<>]+/gu)??[]).map(e=>e.replace(/^['"]|['"]$/gu,``)).filter(e=>!e.startsWith(`-`)&&(e.includes(`/`)||/\.[a-z0-9_-]+$/iu.test(e))).map(e=>n.default.resolve(t,e));return[...new Set(r)]}async fingerprint(e){try{let n=await t.default.stat(e);return{exists:n.isFile(),size:n.size,modified:n.mtimeMs}}catch(e){if(e instanceof Error&&`code`in e&&typeof e.code==`string`&&o.has(e.code))return{exists:!1,size:0,modified:0};throw e}}};exports.EditTracker=c;
2
+ //# sourceMappingURL=EditTracker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditTracker.cjs","names":["path","fs"],"sources":["../../../src/adapters/EditTracker/EditTracker.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { FileEditTool } from '../../types/domain';\nimport type { ITimelineStore } from '../../types/timelineStore';\nimport type { IEditTracker } from '../../types/editTracker';\n\nconst EDIT_TOOL = 'edit';\nconst WRITE_TOOL = 'write';\nconst BASH_TOOL = 'bash';\nconst MISSING_PATH_ERROR_CODES = new Set(['ENOENT', 'ENAMETOOLONG']);\n\ninterface Fingerprint {\n exists: boolean;\n size: number;\n modified: number;\n}\n\ninterface PendingEdit {\n tool: FileEditTool;\n paths: Map<string, Fingerprint>;\n}\n\nfunction objectValue(value: unknown, key: string): string | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const found = (value as Record<string, unknown>)[key];\n return typeof found === 'string' ? found : undefined;\n}\n\nexport class EditTracker implements IEditTracker {\n private readonly pending = new Map<string, PendingEdit>();\n\n constructor(private readonly timeline: ITimelineStore) {}\n\n async start(id: string, tool: string, args: unknown, cwd: string): Promise<void> {\n if (tool === EDIT_TOOL || tool === WRITE_TOOL) {\n const supplied = objectValue(args, 'path');\n if (!supplied) return;\n const absolute = path.resolve(cwd, supplied);\n this.pending.set(id, { tool, paths: new Map([[absolute, await this.fingerprint(absolute)]]) });\n return;\n }\n if (tool !== BASH_TOOL) return;\n const command = objectValue(args, 'command');\n if (!command) return;\n const paths = new Map<string, Fingerprint>();\n for (const candidate of this.literalPaths(command, cwd)) paths.set(candidate, await this.fingerprint(candidate));\n this.pending.set(id, { tool: BASH_TOOL, paths });\n }\n\n async end(id: string, isError: boolean): Promise<void> {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (!pending || isError) return;\n for (const [filePath, before] of pending.paths) {\n const after = await this.fingerprint(filePath);\n const exactTool = pending.tool === EDIT_TOOL || pending.tool === WRITE_TOOL;\n if (exactTool || JSON.stringify(before) !== JSON.stringify(after)) {\n await this.timeline.append({ version: 1, path: filePath, tool: pending.tool, at: Date.now() });\n }\n }\n }\n\n private literalPaths(command: string, cwd: string): string[] {\n const tokens = command.match(/\"[^\"]+\"|'[^']+'|[^\\s|;&<>]+/gu) ?? [];\n const candidates = tokens\n .map((token) => token.replace(/^['\"]|['\"]$/gu, ''))\n .filter((token) => !token.startsWith('-') && (token.includes('/') || /\\.[a-z0-9_-]+$/iu.test(token)))\n .map((token) => path.resolve(cwd, token));\n return [...new Set(candidates)];\n }\n\n private async fingerprint(filePath: string): Promise<Fingerprint> {\n try {\n const stat = await fs.stat(filePath);\n return { exists: stat.isFile(), size: stat.size, modified: stat.mtimeMs };\n } catch (error) {\n if (\n error instanceof Error &&\n 'code' in error &&\n typeof error.code === 'string' &&\n MISSING_PATH_ERROR_CODES.has(error.code)\n ) {\n return { exists: false, size: 0, modified: 0 };\n }\n throw error;\n }\n }\n}\n"],"mappings":"uJAMA,MAAM,EAAY,OACZ,EAAa,QACb,EAAY,OACZ,EAA2B,IAAI,IAAI,CAAC,SAAU,cAAc,CAAC,EAanE,SAAS,EAAY,EAAgB,EAAiC,CACpE,GAAI,CAAC,GAAS,OAAO,GAAU,SAAU,OACzC,IAAM,EAAS,EAAkC,GACjD,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,EAC7C,CAEA,IAAa,EAAb,KAAiD,CAGlB,SAF7B,QAA2B,IAAI,IAE/B,YAAY,EAA2C,CAA1B,KAAA,SAAA,CAA2B,CAExD,MAAM,MAAM,EAAY,EAAc,EAAe,EAA4B,CAC/E,GAAI,IAAS,GAAa,IAAS,EAAY,CAC7C,IAAM,EAAW,EAAY,EAAM,MAAM,EACzC,GAAI,CAAC,EAAU,OACf,IAAM,EAAWA,EAAAA,QAAK,QAAQ,EAAK,CAAQ,EAC3C,KAAK,QAAQ,IAAI,EAAI,CAAE,OAAM,MAAO,IAAI,IAAI,CAAC,CAAC,EAAU,MAAM,KAAK,YAAY,CAAQ,CAAC,CAAC,CAAC,CAAE,CAAC,EAC7F,MACF,CACA,GAAI,IAAS,EAAW,OACxB,IAAM,EAAU,EAAY,EAAM,SAAS,EAC3C,GAAI,CAAC,EAAS,OACd,IAAM,EAAQ,IAAI,IAClB,IAAK,IAAM,KAAa,KAAK,aAAa,EAAS,CAAG,EAAG,EAAM,IAAI,EAAW,MAAM,KAAK,YAAY,CAAS,CAAC,EAC/G,KAAK,QAAQ,IAAI,EAAI,CAAE,KAAM,EAAW,OAAM,CAAC,CACjD,CAEA,MAAM,IAAI,EAAY,EAAiC,CACrD,IAAM,EAAU,KAAK,QAAQ,IAAI,CAAE,EACnC,QAAK,QAAQ,OAAO,CAAE,EAClB,GAAC,GAAW,GAChB,IAAK,GAAM,CAAC,EAAU,KAAW,EAAQ,MAAO,CAC9C,IAAM,EAAQ,MAAM,KAAK,YAAY,CAAQ,GAC3B,EAAQ,OAAS,GAAa,EAAQ,OAAS,GAChD,KAAK,UAAU,CAAM,IAAM,KAAK,UAAU,CAAK,IAC9D,MAAM,KAAK,SAAS,OAAO,CAAE,QAAS,EAAG,KAAM,EAAU,KAAM,EAAQ,KAAM,GAAI,KAAK,IAAI,CAAE,CAAC,CAEjG,CACF,CAEA,aAAqB,EAAiB,EAAuB,CAE3D,IAAM,GADS,EAAQ,MAAM,+BAA+B,GAAK,CAAC,EAAA,CAE/D,IAAK,GAAU,EAAM,QAAQ,gBAAiB,EAAE,CAAC,CAAC,CAClD,OAAQ,GAAU,CAAC,EAAM,WAAW,GAAG,IAAM,EAAM,SAAS,GAAG,GAAK,mBAAmB,KAAK,CAAK,EAAE,CAAC,CACpG,IAAK,GAAUA,EAAAA,QAAK,QAAQ,EAAK,CAAK,CAAC,EAC1C,MAAO,CAAC,GAAG,IAAI,IAAI,CAAU,CAAC,CAChC,CAEA,MAAc,YAAY,EAAwC,CAChE,GAAI,CACF,IAAM,EAAO,MAAMC,EAAAA,QAAG,KAAK,CAAQ,EACnC,MAAO,CAAE,OAAQ,EAAK,OAAO,EAAG,KAAM,EAAK,KAAM,SAAU,EAAK,OAAQ,CAC1E,OAAS,EAAO,CACd,GACE,aAAiB,OACjB,SAAU,GACV,OAAO,EAAM,MAAS,UACtB,EAAyB,IAAI,EAAM,IAAI,EAEvC,MAAO,CAAE,OAAQ,GAAO,KAAM,EAAG,SAAU,CAAE,EAE/C,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ import e from"node:fs/promises";import t from"node:path";const n=`edit`,r=`write`,i=`bash`,a=new Set([`ENOENT`,`ENAMETOOLONG`]);function o(e,t){if(!e||typeof e!=`object`)return;let n=e[t];return typeof n==`string`?n:void 0}var s=class{timeline;pending=new Map;constructor(e){this.timeline=e}async start(e,a,s,c){if(a===n||a===r){let n=o(s,`path`);if(!n)return;let r=t.resolve(c,n);this.pending.set(e,{tool:a,paths:new Map([[r,await this.fingerprint(r)]])});return}if(a!==i)return;let l=o(s,`command`);if(!l)return;let u=new Map;for(let e of this.literalPaths(l,c))u.set(e,await this.fingerprint(e));this.pending.set(e,{tool:i,paths:u})}async end(e,t){let i=this.pending.get(e);if(this.pending.delete(e),!(!i||t))for(let[e,t]of i.paths){let a=await this.fingerprint(e);(i.tool===n||i.tool===r||JSON.stringify(t)!==JSON.stringify(a))&&await this.timeline.append({version:1,path:e,tool:i.tool,at:Date.now()})}}literalPaths(e,n){let r=(e.match(/"[^"]+"|'[^']+'|[^\s|;&<>]+/gu)??[]).map(e=>e.replace(/^['"]|['"]$/gu,``)).filter(e=>!e.startsWith(`-`)&&(e.includes(`/`)||/\.[a-z0-9_-]+$/iu.test(e))).map(e=>t.resolve(n,e));return[...new Set(r)]}async fingerprint(t){try{let n=await e.stat(t);return{exists:n.isFile(),size:n.size,modified:n.mtimeMs}}catch(e){if(e instanceof Error&&`code`in e&&typeof e.code==`string`&&a.has(e.code))return{exists:!1,size:0,modified:0};throw e}}};export{s as EditTracker};
2
+ //# sourceMappingURL=EditTracker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditTracker.mjs","names":[],"sources":["../../../src/adapters/EditTracker/EditTracker.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { FileEditTool } from '../../types/domain';\nimport type { ITimelineStore } from '../../types/timelineStore';\nimport type { IEditTracker } from '../../types/editTracker';\n\nconst EDIT_TOOL = 'edit';\nconst WRITE_TOOL = 'write';\nconst BASH_TOOL = 'bash';\nconst MISSING_PATH_ERROR_CODES = new Set(['ENOENT', 'ENAMETOOLONG']);\n\ninterface Fingerprint {\n exists: boolean;\n size: number;\n modified: number;\n}\n\ninterface PendingEdit {\n tool: FileEditTool;\n paths: Map<string, Fingerprint>;\n}\n\nfunction objectValue(value: unknown, key: string): string | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const found = (value as Record<string, unknown>)[key];\n return typeof found === 'string' ? found : undefined;\n}\n\nexport class EditTracker implements IEditTracker {\n private readonly pending = new Map<string, PendingEdit>();\n\n constructor(private readonly timeline: ITimelineStore) {}\n\n async start(id: string, tool: string, args: unknown, cwd: string): Promise<void> {\n if (tool === EDIT_TOOL || tool === WRITE_TOOL) {\n const supplied = objectValue(args, 'path');\n if (!supplied) return;\n const absolute = path.resolve(cwd, supplied);\n this.pending.set(id, { tool, paths: new Map([[absolute, await this.fingerprint(absolute)]]) });\n return;\n }\n if (tool !== BASH_TOOL) return;\n const command = objectValue(args, 'command');\n if (!command) return;\n const paths = new Map<string, Fingerprint>();\n for (const candidate of this.literalPaths(command, cwd)) paths.set(candidate, await this.fingerprint(candidate));\n this.pending.set(id, { tool: BASH_TOOL, paths });\n }\n\n async end(id: string, isError: boolean): Promise<void> {\n const pending = this.pending.get(id);\n this.pending.delete(id);\n if (!pending || isError) return;\n for (const [filePath, before] of pending.paths) {\n const after = await this.fingerprint(filePath);\n const exactTool = pending.tool === EDIT_TOOL || pending.tool === WRITE_TOOL;\n if (exactTool || JSON.stringify(before) !== JSON.stringify(after)) {\n await this.timeline.append({ version: 1, path: filePath, tool: pending.tool, at: Date.now() });\n }\n }\n }\n\n private literalPaths(command: string, cwd: string): string[] {\n const tokens = command.match(/\"[^\"]+\"|'[^']+'|[^\\s|;&<>]+/gu) ?? [];\n const candidates = tokens\n .map((token) => token.replace(/^['\"]|['\"]$/gu, ''))\n .filter((token) => !token.startsWith('-') && (token.includes('/') || /\\.[a-z0-9_-]+$/iu.test(token)))\n .map((token) => path.resolve(cwd, token));\n return [...new Set(candidates)];\n }\n\n private async fingerprint(filePath: string): Promise<Fingerprint> {\n try {\n const stat = await fs.stat(filePath);\n return { exists: stat.isFile(), size: stat.size, modified: stat.mtimeMs };\n } catch (error) {\n if (\n error instanceof Error &&\n 'code' in error &&\n typeof error.code === 'string' &&\n MISSING_PATH_ERROR_CODES.has(error.code)\n ) {\n return { exists: false, size: 0, modified: 0 };\n }\n throw error;\n }\n }\n}\n"],"mappings":"yDAMA,MAAM,EAAY,OACZ,EAAa,QACb,EAAY,OACZ,EAA2B,IAAI,IAAI,CAAC,SAAU,cAAc,CAAC,EAanE,SAAS,EAAY,EAAgB,EAAiC,CACpE,GAAI,CAAC,GAAS,OAAO,GAAU,SAAU,OACzC,IAAM,EAAS,EAAkC,GACjD,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,EAC7C,CAEA,IAAa,EAAb,KAAiD,CAGlB,SAF7B,QAA2B,IAAI,IAE/B,YAAY,EAA2C,CAA1B,KAAA,SAAA,CAA2B,CAExD,MAAM,MAAM,EAAY,EAAc,EAAe,EAA4B,CAC/E,GAAI,IAAS,GAAa,IAAS,EAAY,CAC7C,IAAM,EAAW,EAAY,EAAM,MAAM,EACzC,GAAI,CAAC,EAAU,OACf,IAAM,EAAW,EAAK,QAAQ,EAAK,CAAQ,EAC3C,KAAK,QAAQ,IAAI,EAAI,CAAE,OAAM,MAAO,IAAI,IAAI,CAAC,CAAC,EAAU,MAAM,KAAK,YAAY,CAAQ,CAAC,CAAC,CAAC,CAAE,CAAC,EAC7F,MACF,CACA,GAAI,IAAS,EAAW,OACxB,IAAM,EAAU,EAAY,EAAM,SAAS,EAC3C,GAAI,CAAC,EAAS,OACd,IAAM,EAAQ,IAAI,IAClB,IAAK,IAAM,KAAa,KAAK,aAAa,EAAS,CAAG,EAAG,EAAM,IAAI,EAAW,MAAM,KAAK,YAAY,CAAS,CAAC,EAC/G,KAAK,QAAQ,IAAI,EAAI,CAAE,KAAM,EAAW,OAAM,CAAC,CACjD,CAEA,MAAM,IAAI,EAAY,EAAiC,CACrD,IAAM,EAAU,KAAK,QAAQ,IAAI,CAAE,EACnC,QAAK,QAAQ,OAAO,CAAE,EAClB,GAAC,GAAW,GAChB,IAAK,GAAM,CAAC,EAAU,KAAW,EAAQ,MAAO,CAC9C,IAAM,EAAQ,MAAM,KAAK,YAAY,CAAQ,GAC3B,EAAQ,OAAS,GAAa,EAAQ,OAAS,GAChD,KAAK,UAAU,CAAM,IAAM,KAAK,UAAU,CAAK,IAC9D,MAAM,KAAK,SAAS,OAAO,CAAE,QAAS,EAAG,KAAM,EAAU,KAAM,EAAQ,KAAM,GAAI,KAAK,IAAI,CAAE,CAAC,CAEjG,CACF,CAEA,aAAqB,EAAiB,EAAuB,CAE3D,IAAM,GADS,EAAQ,MAAM,+BAA+B,GAAK,CAAC,EAAA,CAE/D,IAAK,GAAU,EAAM,QAAQ,gBAAiB,EAAE,CAAC,CAAC,CAClD,OAAQ,GAAU,CAAC,EAAM,WAAW,GAAG,IAAM,EAAM,SAAS,GAAG,GAAK,mBAAmB,KAAK,CAAK,EAAE,CAAC,CACpG,IAAK,GAAU,EAAK,QAAQ,EAAK,CAAK,CAAC,EAC1C,MAAO,CAAC,GAAG,IAAI,IAAI,CAAU,CAAC,CAChC,CAEA,MAAc,YAAY,EAAwC,CAChE,GAAI,CACF,IAAM,EAAO,MAAM,EAAG,KAAK,CAAQ,EACnC,MAAO,CAAE,OAAQ,EAAK,OAAO,EAAG,KAAM,EAAK,KAAM,SAAU,EAAK,OAAQ,CAC1E,OAAS,EAAO,CACd,GACE,aAAiB,OACjB,SAAU,GACV,OAAO,EAAM,MAAS,UACtB,EAAyB,IAAI,EAAM,IAAI,EAEvC,MAAO,CAAE,OAAQ,GAAO,KAAM,EAAG,SAAU,CAAE,EAE/C,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs/promises");t=e.__toESM(t,1);let n=require("node:os");n=e.__toESM(n,1);let r=require("node:path");r=e.__toESM(r,1);let i=require("@agimon-ai/doompi-config");const a=/^\s*command:\s*(.+?)\s*$/mu;function o(){return process.env.PI_CODING_AGENT_DIR||r.default.join(n.default.homedir(),`.pi`,`agent`)}var s=class{path(){return(0,i.globalDoomConfigPath)()}packagePath(){return r.default.join(o(),`doom-file-edit`,`config.yaml`)}async command(){return await this.read(this.path())??await this.read(this.packagePath())}async read(e){try{let n=await t.default.readFile(e,`utf8`),r=/^editor:\s*\n((?:[ \t]+.*(?:\n|$))*)/mu.exec(n)?.[1];if(!r)return;let i=a.exec(r)?.[1]?.trim();if(!i)return;if(/^(?:[-+]?\d+(?:\.\d+)?|true|false|null)$/u.test(i))throw Error(`${e}: editor.command must be a string`);return i.replace(/^(?:"([\s\S]*)"|'([\s\S]*)')$/u,`$1$2`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}}};exports.EditorConfigService=s;
2
+ //# sourceMappingURL=EditorConfigService.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorConfigService.cjs","names":["path","os","globalDoomConfigPath","fs"],"sources":["../../../src/adapters/EditorConfigService/EditorConfigService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { globalDoomConfigPath } from '@agimon-ai/doompi-config';\nimport type { IEditorConfigService } from '../../types/editorConfigService';\n\nconst commandPattern = /^\\s*command:\\s*(.+?)\\s*$/mu;\n\nfunction agentDirectory(): string {\n return process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), '.pi', 'agent');\n}\n\nexport class EditorConfigService implements IEditorConfigService {\n path(): string {\n return globalDoomConfigPath();\n }\n\n packagePath(): string {\n return path.join(agentDirectory(), 'doom-file-edit', 'config.yaml');\n }\n\n async command(): Promise<string | undefined> {\n // Shared Doom config owns `editor:`; the package-scoped file is the\n // fallback for standalone installs that have no Doom config.\n return (await this.read(this.path())) ?? (await this.read(this.packagePath()));\n }\n\n private async read(filePath: string): Promise<string | undefined> {\n try {\n const content = await fs.readFile(filePath, 'utf8');\n const editorSection = /^editor:\\s*\\n((?:[ \\t]+.*(?:\\n|$))*)/mu.exec(content)?.[1];\n if (!editorSection) return undefined;\n const value = commandPattern.exec(editorSection)?.[1]?.trim();\n if (!value) return undefined;\n if (/^(?:[-+]?\\d+(?:\\.\\d+)?|true|false|null)$/u.test(value)) {\n throw new Error(`${filePath}: editor.command must be a string`);\n }\n return value.replace(/^(?:\"([\\s\\S]*)\"|'([\\s\\S]*)')$/u, '$1$2');\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return undefined;\n throw error;\n }\n }\n}\n"],"mappings":"2OAMA,MAAM,EAAiB,6BAEvB,SAAS,GAAyB,CAChC,OAAO,QAAQ,IAAI,qBAAuBA,EAAAA,QAAK,KAAKC,EAAAA,QAAG,QAAQ,EAAG,MAAO,OAAO,CAClF,CAEA,IAAa,EAAb,KAAiE,CAC/D,MAAe,CACb,OAAA,EAAOC,EAAAA,qBAAAA,CAAqB,CAC9B,CAEA,aAAsB,CACpB,OAAOF,EAAAA,QAAK,KAAK,EAAe,EAAG,iBAAkB,aAAa,CACpE,CAEA,MAAM,SAAuC,CAG3C,OAAQ,MAAM,KAAK,KAAK,KAAK,KAAK,CAAC,GAAO,MAAM,KAAK,KAAK,KAAK,YAAY,CAAC,CAC9E,CAEA,MAAc,KAAK,EAA+C,CAChE,GAAI,CACF,IAAM,EAAU,MAAMG,EAAAA,QAAG,SAAS,EAAU,MAAM,EAC5C,EAAgB,yCAAyC,KAAK,CAAO,CAAC,GAAG,GAC/E,GAAI,CAAC,EAAe,OACpB,IAAM,EAAQ,EAAe,KAAK,CAAa,CAAC,GAAG,EAAE,EAAE,KAAK,EAC5D,GAAI,CAAC,EAAO,OACZ,GAAI,4CAA4C,KAAK,CAAK,EACxD,MAAU,MAAM,GAAG,EAAS,kCAAkC,EAEhE,OAAO,EAAM,QAAQ,iCAAkC,MAAM,CAC/D,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,SAAU,OAC1E,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ import e from"node:fs/promises";import t from"node:os";import n from"node:path";import{globalDoomConfigPath as r}from"@agimon-ai/doompi-config";const i=/^\s*command:\s*(.+?)\s*$/mu;function a(){return process.env.PI_CODING_AGENT_DIR||n.join(t.homedir(),`.pi`,`agent`)}var o=class{path(){return r()}packagePath(){return n.join(a(),`doom-file-edit`,`config.yaml`)}async command(){return await this.read(this.path())??await this.read(this.packagePath())}async read(t){try{let n=await e.readFile(t,`utf8`),r=/^editor:\s*\n((?:[ \t]+.*(?:\n|$))*)/mu.exec(n)?.[1];if(!r)return;let a=i.exec(r)?.[1]?.trim();if(!a)return;if(/^(?:[-+]?\d+(?:\.\d+)?|true|false|null)$/u.test(a))throw Error(`${t}: editor.command must be a string`);return a.replace(/^(?:"([\s\S]*)"|'([\s\S]*)')$/u,`$1$2`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}}};export{o as EditorConfigService};
2
+ //# sourceMappingURL=EditorConfigService.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorConfigService.mjs","names":[],"sources":["../../../src/adapters/EditorConfigService/EditorConfigService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { globalDoomConfigPath } from '@agimon-ai/doompi-config';\nimport type { IEditorConfigService } from '../../types/editorConfigService';\n\nconst commandPattern = /^\\s*command:\\s*(.+?)\\s*$/mu;\n\nfunction agentDirectory(): string {\n return process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), '.pi', 'agent');\n}\n\nexport class EditorConfigService implements IEditorConfigService {\n path(): string {\n return globalDoomConfigPath();\n }\n\n packagePath(): string {\n return path.join(agentDirectory(), 'doom-file-edit', 'config.yaml');\n }\n\n async command(): Promise<string | undefined> {\n // Shared Doom config owns `editor:`; the package-scoped file is the\n // fallback for standalone installs that have no Doom config.\n return (await this.read(this.path())) ?? (await this.read(this.packagePath()));\n }\n\n private async read(filePath: string): Promise<string | undefined> {\n try {\n const content = await fs.readFile(filePath, 'utf8');\n const editorSection = /^editor:\\s*\\n((?:[ \\t]+.*(?:\\n|$))*)/mu.exec(content)?.[1];\n if (!editorSection) return undefined;\n const value = commandPattern.exec(editorSection)?.[1]?.trim();\n if (!value) return undefined;\n if (/^(?:[-+]?\\d+(?:\\.\\d+)?|true|false|null)$/u.test(value)) {\n throw new Error(`${filePath}: editor.command must be a string`);\n }\n return value.replace(/^(?:\"([\\s\\S]*)\"|'([\\s\\S]*)')$/u, '$1$2');\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return undefined;\n throw error;\n }\n }\n}\n"],"mappings":"gJAMA,MAAM,EAAiB,6BAEvB,SAAS,GAAyB,CAChC,OAAO,QAAQ,IAAI,qBAAuB,EAAK,KAAK,EAAG,QAAQ,EAAG,MAAO,OAAO,CAClF,CAEA,IAAa,EAAb,KAAiE,CAC/D,MAAe,CACb,OAAO,EAAqB,CAC9B,CAEA,aAAsB,CACpB,OAAO,EAAK,KAAK,EAAe,EAAG,iBAAkB,aAAa,CACpE,CAEA,MAAM,SAAuC,CAG3C,OAAQ,MAAM,KAAK,KAAK,KAAK,KAAK,CAAC,GAAO,MAAM,KAAK,KAAK,KAAK,YAAY,CAAC,CAC9E,CAEA,MAAc,KAAK,EAA+C,CAChE,GAAI,CACF,IAAM,EAAU,MAAM,EAAG,SAAS,EAAU,MAAM,EAC5C,EAAgB,yCAAyC,KAAK,CAAO,CAAC,GAAG,GAC/E,GAAI,CAAC,EAAe,OACpB,IAAM,EAAQ,EAAe,KAAK,CAAa,CAAC,GAAG,EAAE,EAAE,KAAK,EAC5D,GAAI,CAAC,EAAO,OACZ,GAAI,4CAA4C,KAAK,CAAK,EACxD,MAAU,MAAM,GAAG,EAAS,kCAAkC,EAEhE,OAAO,EAAM,QAAQ,iCAAkC,MAAM,CAC/D,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,SAAU,OAC1E,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../process/commandLine.cjs");let n=require("node:fs/promises");n=e.__toESM(n,1);let r=require("node:path");r=e.__toESM(r,1);let i=require("cross-spawn");i=e.__toESM(i,1);var a=class{config;constructor(e){this.config=e}async resolve(e=process.env,n=process.platform){let r=await this.config.command(),i=[...r?[{template:r,source:`configured`}]:[],...e.VISUAL?[{template:e.VISUAL,source:`VISUAL`}]:[],...e.EDITOR?[{template:e.EDITOR,source:`EDITOR`}]:[],{template:n===`win32`?`notepad {file}`:`nano {file}`,source:`fallback`}];for(let r of i){let i=t.splitCommandLine(r.template)[0];if(i&&await this.isExecutable(i,e,n))return r}}async launch(e,n,r){try{let a=await this.resolve();if(!a)return{success:!1,error:`No editor command could be resolved`};let[o,...s]=t.expandEditorTemplate(a.template,e,n);if(!o)return{success:!1,error:`Editor command must not be empty`};r.stop();try{await new Promise((e,t)=>{let n=(0,i.default)(o,s,{stdio:`inherit`,shell:!1});n.once(`error`,t),n.once(`exit`,()=>e())})}finally{r.start(),r.requestRender(!0)}return{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async isExecutable(e,t,i){let a=i===`win32`?(t.PATHEXT??`.EXE;.CMD;.BAT`).split(`;`):[``],o=r.default.isAbsolute(e)||e.includes(r.default.sep)?[``]:(t.PATH??``).split(r.default.delimiter);for(let t of o)for(let o of a){let a=t?r.default.join(t,`${e}${o}`):`${e}${o}`;try{return await n.default.access(a,i===`win32`?n.default.constants.F_OK:n.default.constants.X_OK),!0}catch(e){if(!(e instanceof Error&&`code`in e&&(e.code===`ENOENT`||e.code===`EACCES`)))throw e}}return!1}};exports.EditorLauncher=a;
2
+ //# sourceMappingURL=EditorLauncher.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorLauncher.cjs","names":["splitCommandLine","expandEditorTemplate","spawn","path","fs"],"sources":["../../../src/adapters/EditorLauncher/EditorLauncher.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport { expandEditorTemplate, splitCommandLine } from '../../adapters/process/commandLine.ts';\nimport type { IEditorConfigService } from '../../types/editorConfigService';\nimport type { ResolvedEditor } from '../../types/domain';\nimport type { EditorLaunchResult, EditorTui, IEditorLauncher } from '../../types/editorLauncher';\n\nexport class EditorLauncher implements IEditorLauncher {\n constructor(private readonly config: IEditorConfigService) {}\n\n async resolve(\n env: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n ): Promise<ResolvedEditor | undefined> {\n const configured = await this.config.command();\n const candidates: ResolvedEditor[] = [\n ...(configured ? [{ template: configured, source: 'configured' as const }] : []),\n ...(env.VISUAL ? [{ template: env.VISUAL, source: 'VISUAL' as const }] : []),\n ...(env.EDITOR ? [{ template: env.EDITOR, source: 'EDITOR' as const }] : []),\n { template: platform === 'win32' ? 'notepad {file}' : 'nano {file}', source: 'fallback' },\n ];\n for (const candidate of candidates) {\n const executable = splitCommandLine(candidate.template)[0];\n if (executable && (await this.isExecutable(executable, env, platform))) return candidate;\n }\n return undefined;\n }\n\n async launch(filePath: string, line: number, tui: EditorTui): Promise<EditorLaunchResult> {\n try {\n const editor = await this.resolve();\n if (!editor) return { success: false, error: 'No editor command could be resolved' };\n const [command, ...args] = expandEditorTemplate(editor.template, filePath, line);\n if (!command) return { success: false, error: 'Editor command must not be empty' };\n tui.stop();\n try {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { stdio: 'inherit', shell: false });\n child.once('error', reject);\n child.once('exit', () => resolve());\n });\n } finally {\n tui.start();\n tui.requestRender(true);\n }\n return { success: true };\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n }\n\n private async isExecutable(command: string, env: NodeJS.ProcessEnv, platform: NodeJS.Platform): Promise<boolean> {\n const extensions = platform === 'win32' ? (env.PATHEXT ?? '.EXE;.CMD;.BAT').split(';') : [''];\n const locations =\n path.isAbsolute(command) || command.includes(path.sep) ? [''] : (env.PATH ?? '').split(path.delimiter);\n for (const location of locations) {\n for (const extension of extensions) {\n const candidate = location ? path.join(location, `${command}${extension}`) : `${command}${extension}`;\n try {\n await fs.access(candidate, platform === 'win32' ? fs.constants.F_OK : fs.constants.X_OK);\n return true;\n } catch (error) {\n if (!(error instanceof Error && 'code' in error && (error.code === 'ENOENT' || error.code === 'EACCES')))\n throw error;\n }\n }\n }\n return false;\n }\n}\n"],"mappings":"6OAQA,IAAa,EAAb,KAAuD,CACxB,OAA7B,YAAY,EAA+C,CAA9B,KAAA,OAAA,CAA+B,CAE5D,MAAM,QACJ,EAAyB,QAAQ,IACjC,EAA4B,QAAQ,SACC,CACrC,IAAM,EAAa,MAAM,KAAK,OAAO,QAAQ,EACvC,EAA+B,CACnC,GAAI,EAAa,CAAC,CAAE,SAAU,EAAY,OAAQ,YAAsB,CAAC,EAAI,CAAC,EAC9E,GAAI,EAAI,OAAS,CAAC,CAAE,SAAU,EAAI,OAAQ,OAAQ,QAAkB,CAAC,EAAI,CAAC,EAC1E,GAAI,EAAI,OAAS,CAAC,CAAE,SAAU,EAAI,OAAQ,OAAQ,QAAkB,CAAC,EAAI,CAAC,EAC1E,CAAE,SAAU,IAAa,QAAU,iBAAmB,cAAe,OAAQ,UAAW,CAC1F,EACA,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAaA,EAAAA,iBAAiB,EAAU,QAAQ,CAAC,CAAC,GACxD,GAAI,GAAe,MAAM,KAAK,aAAa,EAAY,EAAK,CAAQ,EAAI,OAAO,CACjF,CAEF,CAEA,MAAM,OAAO,EAAkB,EAAc,EAA6C,CACxF,GAAI,CACF,IAAM,EAAS,MAAM,KAAK,QAAQ,EAClC,GAAI,CAAC,EAAQ,MAAO,CAAE,QAAS,GAAO,MAAO,qCAAsC,EACnF,GAAM,CAAC,EAAS,GAAG,GAAQC,EAAAA,qBAAqB,EAAO,SAAU,EAAU,CAAI,EAC/E,GAAI,CAAC,EAAS,MAAO,CAAE,QAAS,GAAO,MAAO,kCAAmC,EACjF,EAAI,KAAK,EACT,GAAI,CACF,MAAM,IAAI,SAAe,EAAS,IAAW,CAC3C,IAAM,GAAA,EAAQC,EAAAA,QAAAA,CAAM,EAAS,EAAM,CAAE,MAAO,UAAW,MAAO,EAAM,CAAC,EACrE,EAAM,KAAK,QAAS,CAAM,EAC1B,EAAM,KAAK,WAAc,EAAQ,CAAC,CACpC,CAAC,CACH,QAAU,CACR,EAAI,MAAM,EACV,EAAI,cAAc,EAAI,CACxB,CACA,MAAO,CAAE,QAAS,EAAK,CACzB,OAAS,EAAO,CACd,MAAO,CAAE,QAAS,GAAO,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAAE,CACzF,CACF,CAEA,MAAc,aAAa,EAAiB,EAAwB,EAA6C,CAC/G,IAAM,EAAa,IAAa,SAAW,EAAI,SAAW,iBAAA,CAAkB,MAAM,GAAG,EAAI,CAAC,EAAE,EACtF,EACJC,EAAAA,QAAK,WAAW,CAAO,GAAK,EAAQ,SAASA,EAAAA,QAAK,GAAG,EAAI,CAAC,EAAE,GAAK,EAAI,MAAQ,GAAA,CAAI,MAAMA,EAAAA,QAAK,SAAS,EACvG,IAAK,IAAM,KAAY,EACrB,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAY,EAAWA,EAAAA,QAAK,KAAK,EAAU,GAAG,IAAU,GAAW,EAAI,GAAG,IAAU,IAC1F,GAAI,CAEF,OADA,MAAMC,EAAAA,QAAG,OAAO,EAAW,IAAa,QAAUA,EAAAA,QAAG,UAAU,KAAOA,EAAAA,QAAG,UAAU,IAAI,EAChF,EACT,OAAS,EAAO,CACd,GAAI,EAAE,aAAiB,OAAS,SAAU,IAAU,EAAM,OAAS,UAAY,EAAM,OAAS,WAC5F,MAAM,CACV,CACF,CAEF,MAAO,EACT,CACF"}
@@ -0,0 +1,2 @@
1
+ import{expandEditorTemplate as e,splitCommandLine as t}from"../process/commandLine.mjs";import n from"node:fs/promises";import r from"node:path";import i from"cross-spawn";var a=class{config;constructor(e){this.config=e}async resolve(e=process.env,n=process.platform){let r=await this.config.command(),i=[...r?[{template:r,source:`configured`}]:[],...e.VISUAL?[{template:e.VISUAL,source:`VISUAL`}]:[],...e.EDITOR?[{template:e.EDITOR,source:`EDITOR`}]:[],{template:n===`win32`?`notepad {file}`:`nano {file}`,source:`fallback`}];for(let r of i){let i=t(r.template)[0];if(i&&await this.isExecutable(i,e,n))return r}}async launch(t,n,r){try{let a=await this.resolve();if(!a)return{success:!1,error:`No editor command could be resolved`};let[o,...s]=e(a.template,t,n);if(!o)return{success:!1,error:`Editor command must not be empty`};r.stop();try{await new Promise((e,t)=>{let n=i(o,s,{stdio:`inherit`,shell:!1});n.once(`error`,t),n.once(`exit`,()=>e())})}finally{r.start(),r.requestRender(!0)}return{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}async isExecutable(e,t,i){let a=i===`win32`?(t.PATHEXT??`.EXE;.CMD;.BAT`).split(`;`):[``],o=r.isAbsolute(e)||e.includes(r.sep)?[``]:(t.PATH??``).split(r.delimiter);for(let t of o)for(let o of a){let a=t?r.join(t,`${e}${o}`):`${e}${o}`;try{return await n.access(a,i===`win32`?n.constants.F_OK:n.constants.X_OK),!0}catch(e){if(!(e instanceof Error&&`code`in e&&(e.code===`ENOENT`||e.code===`EACCES`)))throw e}}return!1}};export{a as EditorLauncher};
2
+ //# sourceMappingURL=EditorLauncher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorLauncher.mjs","names":[],"sources":["../../../src/adapters/EditorLauncher/EditorLauncher.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport { expandEditorTemplate, splitCommandLine } from '../../adapters/process/commandLine.ts';\nimport type { IEditorConfigService } from '../../types/editorConfigService';\nimport type { ResolvedEditor } from '../../types/domain';\nimport type { EditorLaunchResult, EditorTui, IEditorLauncher } from '../../types/editorLauncher';\n\nexport class EditorLauncher implements IEditorLauncher {\n constructor(private readonly config: IEditorConfigService) {}\n\n async resolve(\n env: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n ): Promise<ResolvedEditor | undefined> {\n const configured = await this.config.command();\n const candidates: ResolvedEditor[] = [\n ...(configured ? [{ template: configured, source: 'configured' as const }] : []),\n ...(env.VISUAL ? [{ template: env.VISUAL, source: 'VISUAL' as const }] : []),\n ...(env.EDITOR ? [{ template: env.EDITOR, source: 'EDITOR' as const }] : []),\n { template: platform === 'win32' ? 'notepad {file}' : 'nano {file}', source: 'fallback' },\n ];\n for (const candidate of candidates) {\n const executable = splitCommandLine(candidate.template)[0];\n if (executable && (await this.isExecutable(executable, env, platform))) return candidate;\n }\n return undefined;\n }\n\n async launch(filePath: string, line: number, tui: EditorTui): Promise<EditorLaunchResult> {\n try {\n const editor = await this.resolve();\n if (!editor) return { success: false, error: 'No editor command could be resolved' };\n const [command, ...args] = expandEditorTemplate(editor.template, filePath, line);\n if (!command) return { success: false, error: 'Editor command must not be empty' };\n tui.stop();\n try {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { stdio: 'inherit', shell: false });\n child.once('error', reject);\n child.once('exit', () => resolve());\n });\n } finally {\n tui.start();\n tui.requestRender(true);\n }\n return { success: true };\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n }\n\n private async isExecutable(command: string, env: NodeJS.ProcessEnv, platform: NodeJS.Platform): Promise<boolean> {\n const extensions = platform === 'win32' ? (env.PATHEXT ?? '.EXE;.CMD;.BAT').split(';') : [''];\n const locations =\n path.isAbsolute(command) || command.includes(path.sep) ? [''] : (env.PATH ?? '').split(path.delimiter);\n for (const location of locations) {\n for (const extension of extensions) {\n const candidate = location ? path.join(location, `${command}${extension}`) : `${command}${extension}`;\n try {\n await fs.access(candidate, platform === 'win32' ? fs.constants.F_OK : fs.constants.X_OK);\n return true;\n } catch (error) {\n if (!(error instanceof Error && 'code' in error && (error.code === 'ENOENT' || error.code === 'EACCES')))\n throw error;\n }\n }\n }\n return false;\n }\n}\n"],"mappings":"4KAQA,IAAa,EAAb,KAAuD,CACxB,OAA7B,YAAY,EAA+C,CAA9B,KAAA,OAAA,CAA+B,CAE5D,MAAM,QACJ,EAAyB,QAAQ,IACjC,EAA4B,QAAQ,SACC,CACrC,IAAM,EAAa,MAAM,KAAK,OAAO,QAAQ,EACvC,EAA+B,CACnC,GAAI,EAAa,CAAC,CAAE,SAAU,EAAY,OAAQ,YAAsB,CAAC,EAAI,CAAC,EAC9E,GAAI,EAAI,OAAS,CAAC,CAAE,SAAU,EAAI,OAAQ,OAAQ,QAAkB,CAAC,EAAI,CAAC,EAC1E,GAAI,EAAI,OAAS,CAAC,CAAE,SAAU,EAAI,OAAQ,OAAQ,QAAkB,CAAC,EAAI,CAAC,EAC1E,CAAE,SAAU,IAAa,QAAU,iBAAmB,cAAe,OAAQ,UAAW,CAC1F,EACA,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAa,EAAiB,EAAU,QAAQ,CAAC,CAAC,GACxD,GAAI,GAAe,MAAM,KAAK,aAAa,EAAY,EAAK,CAAQ,EAAI,OAAO,CACjF,CAEF,CAEA,MAAM,OAAO,EAAkB,EAAc,EAA6C,CACxF,GAAI,CACF,IAAM,EAAS,MAAM,KAAK,QAAQ,EAClC,GAAI,CAAC,EAAQ,MAAO,CAAE,QAAS,GAAO,MAAO,qCAAsC,EACnF,GAAM,CAAC,EAAS,GAAG,GAAQ,EAAqB,EAAO,SAAU,EAAU,CAAI,EAC/E,GAAI,CAAC,EAAS,MAAO,CAAE,QAAS,GAAO,MAAO,kCAAmC,EACjF,EAAI,KAAK,EACT,GAAI,CACF,MAAM,IAAI,SAAe,EAAS,IAAW,CAC3C,IAAM,EAAQ,EAAM,EAAS,EAAM,CAAE,MAAO,UAAW,MAAO,EAAM,CAAC,EACrE,EAAM,KAAK,QAAS,CAAM,EAC1B,EAAM,KAAK,WAAc,EAAQ,CAAC,CACpC,CAAC,CACH,QAAU,CACR,EAAI,MAAM,EACV,EAAI,cAAc,EAAI,CACxB,CACA,MAAO,CAAE,QAAS,EAAK,CACzB,OAAS,EAAO,CACd,MAAO,CAAE,QAAS,GAAO,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAAE,CACzF,CACF,CAEA,MAAc,aAAa,EAAiB,EAAwB,EAA6C,CAC/G,IAAM,EAAa,IAAa,SAAW,EAAI,SAAW,iBAAA,CAAkB,MAAM,GAAG,EAAI,CAAC,EAAE,EACtF,EACJ,EAAK,WAAW,CAAO,GAAK,EAAQ,SAAS,EAAK,GAAG,EAAI,CAAC,EAAE,GAAK,EAAI,MAAQ,GAAA,CAAI,MAAM,EAAK,SAAS,EACvG,IAAK,IAAM,KAAY,EACrB,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAY,EAAW,EAAK,KAAK,EAAU,GAAG,IAAU,GAAW,EAAI,GAAG,IAAU,IAC1F,GAAI,CAEF,OADA,MAAM,EAAG,OAAO,EAAW,IAAa,QAAU,EAAG,UAAU,KAAO,EAAG,UAAU,IAAI,EAChF,EACT,OAAS,EAAO,CACd,GAAI,EAAE,aAAiB,OAAS,SAAU,IAAU,EAAM,OAAS,UAAY,EAAM,OAAS,WAC5F,MAAM,CACV,CACF,CAEF,MAAO,EACT,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("@agimon-ai/doompi-extension-contracts/child-process"),n=require("node:os");n=e.__toESM(n,1);let r=require("node:path");r=e.__toESM(r,1);let i=require("node:child_process"),a=require("node:crypto"),o=require("node:fs");o=e.__toESM(o,1);function s(e){return(0,a.createHash)(`sha256`).update(e).digest(`hex`).slice(0,16)}var c=class{sessionKey(e,n=process.env){if(n[t.SUBAGENT_CHILD_ENV]){let e=n[t.SUBAGENT_PARENT_SESSION_ENV];if(e)return e}return e}timelinePath(e,t){let i=this.gitCommonDirectory(e),a=s(o.default.realpathSync(e)),c=process.env.PI_CODING_AGENT_DIR||r.default.join(n.default.homedir(),`.pi`,`agent`),l=r.default.join(i??c,`doom-file-edit`);return o.default.mkdirSync(l,{recursive:!0}),r.default.join(l,`${a}-${s(t)}.jsonl`)}gitCommonDirectory(e){try{return(0,i.execFileSync)(`git`,[`rev-parse`,`--path-format=absolute`,`--git-common-dir`],{cwd:e,encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()||void 0}catch(e){if(e instanceof Error)return;throw e}}};exports.FileEditPaths=c;
2
+ //# sourceMappingURL=FileEditPaths.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileEditPaths.cjs","names":["createHash","SUBAGENT_CHILD_ENV","SUBAGENT_PARENT_SESSION_ENV","fs","path","os","execFileSync"],"sources":["../../../src/adapters/FileEditPaths/FileEditPaths.ts"],"sourcesContent":["import { execFileSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport type { IFileEditPaths } from '../../types/fileEditPaths';\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n}\n\nexport class FileEditPaths implements IFileEditPaths {\n sessionKey(sessionId: string, env: NodeJS.ProcessEnv = process.env): string {\n if (env[SUBAGENT_CHILD_ENV]) {\n const parent = env[SUBAGENT_PARENT_SESSION_ENV];\n if (parent) return parent;\n }\n return sessionId;\n }\n\n timelinePath(cwd: string, sessionKey: string): string {\n const commonDirectory = this.gitCommonDirectory(cwd);\n const worktree = hash(fs.realpathSync(cwd));\n const agentDirectory = process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), '.pi', 'agent');\n const directory = path.join(commonDirectory ?? agentDirectory, 'doom-file-edit');\n fs.mkdirSync(directory, { recursive: true });\n return path.join(directory, `${worktree}-${hash(sessionKey)}.jsonl`);\n }\n\n private gitCommonDirectory(cwd: string): string | undefined {\n try {\n const result = execFileSync('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return result || undefined;\n } catch (error) {\n if (error instanceof Error) return undefined;\n throw error;\n }\n }\n}\n"],"mappings":"kTAQA,SAAS,EAAK,EAAuB,CACnC,OAAA,EAAOA,EAAAA,WAAAA,CAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,EAAG,EAAE,CACrE,CAEA,IAAa,EAAb,KAAqD,CACnD,WAAW,EAAmB,EAAyB,QAAQ,IAAa,CAC1E,GAAI,EAAIC,EAAAA,oBAAqB,CAC3B,IAAM,EAAS,EAAIC,EAAAA,6BACnB,GAAI,EAAQ,OAAO,CACrB,CACA,OAAO,CACT,CAEA,aAAa,EAAa,EAA4B,CACpD,IAAM,EAAkB,KAAK,mBAAmB,CAAG,EAC7C,EAAW,EAAKC,EAAAA,QAAG,aAAa,CAAG,CAAC,EACpC,EAAiB,QAAQ,IAAI,qBAAuBC,EAAAA,QAAK,KAAKC,EAAAA,QAAG,QAAQ,EAAG,MAAO,OAAO,EAC1F,EAAYD,EAAAA,QAAK,KAAK,GAAmB,EAAgB,gBAAgB,EAE/E,OADA,EAAA,QAAG,UAAU,EAAW,CAAE,UAAW,EAAK,CAAC,EACpCA,EAAAA,QAAK,KAAK,EAAW,GAAG,EAAS,GAAG,EAAK,CAAU,EAAE,OAAO,CACrE,CAEA,mBAA2B,EAAiC,CAC1D,GAAI,CAMF,OAAA,EALeE,EAAAA,aAAAA,CAAa,MAAO,CAAC,YAAa,yBAA0B,kBAAkB,EAAG,CAC9F,MACA,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,CAAC,CAAC,KACS,GAAK,IAAA,EACnB,OAAS,EAAO,CACd,GAAI,aAAiB,MAAO,OAC5B,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ import{SUBAGENT_CHILD_ENV as e,SUBAGENT_PARENT_SESSION_ENV as t}from"@agimon-ai/doompi-extension-contracts/child-process";import n from"node:os";import r from"node:path";import{execFileSync as i}from"node:child_process";import{createHash as a}from"node:crypto";import o from"node:fs";function s(e){return a(`sha256`).update(e).digest(`hex`).slice(0,16)}var c=class{sessionKey(n,r=process.env){if(r[e]){let e=r[t];if(e)return e}return n}timelinePath(e,t){let i=this.gitCommonDirectory(e),a=s(o.realpathSync(e)),c=process.env.PI_CODING_AGENT_DIR||r.join(n.homedir(),`.pi`,`agent`),l=r.join(i??c,`doom-file-edit`);return o.mkdirSync(l,{recursive:!0}),r.join(l,`${a}-${s(t)}.jsonl`)}gitCommonDirectory(e){try{return i(`git`,[`rev-parse`,`--path-format=absolute`,`--git-common-dir`],{cwd:e,encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()||void 0}catch(e){if(e instanceof Error)return;throw e}}};export{c as FileEditPaths};
2
+ //# sourceMappingURL=FileEditPaths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileEditPaths.mjs","names":[],"sources":["../../../src/adapters/FileEditPaths/FileEditPaths.ts"],"sourcesContent":["import { execFileSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport type { IFileEditPaths } from '../../types/fileEditPaths';\n\nfunction hash(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 16);\n}\n\nexport class FileEditPaths implements IFileEditPaths {\n sessionKey(sessionId: string, env: NodeJS.ProcessEnv = process.env): string {\n if (env[SUBAGENT_CHILD_ENV]) {\n const parent = env[SUBAGENT_PARENT_SESSION_ENV];\n if (parent) return parent;\n }\n return sessionId;\n }\n\n timelinePath(cwd: string, sessionKey: string): string {\n const commonDirectory = this.gitCommonDirectory(cwd);\n const worktree = hash(fs.realpathSync(cwd));\n const agentDirectory = process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), '.pi', 'agent');\n const directory = path.join(commonDirectory ?? agentDirectory, 'doom-file-edit');\n fs.mkdirSync(directory, { recursive: true });\n return path.join(directory, `${worktree}-${hash(sessionKey)}.jsonl`);\n }\n\n private gitCommonDirectory(cwd: string): string | undefined {\n try {\n const result = execFileSync('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return result || undefined;\n } catch (error) {\n if (error instanceof Error) return undefined;\n throw error;\n }\n }\n}\n"],"mappings":"4RAQA,SAAS,EAAK,EAAuB,CACnC,OAAO,EAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,EAAG,EAAE,CACrE,CAEA,IAAa,EAAb,KAAqD,CACnD,WAAW,EAAmB,EAAyB,QAAQ,IAAa,CAC1E,GAAI,EAAI,GAAqB,CAC3B,IAAM,EAAS,EAAI,GACnB,GAAI,EAAQ,OAAO,CACrB,CACA,OAAO,CACT,CAEA,aAAa,EAAa,EAA4B,CACpD,IAAM,EAAkB,KAAK,mBAAmB,CAAG,EAC7C,EAAW,EAAK,EAAG,aAAa,CAAG,CAAC,EACpC,EAAiB,QAAQ,IAAI,qBAAuB,EAAK,KAAK,EAAG,QAAQ,EAAG,MAAO,OAAO,EAC1F,EAAY,EAAK,KAAK,GAAmB,EAAgB,gBAAgB,EAE/E,OADA,EAAG,UAAU,EAAW,CAAE,UAAW,EAAK,CAAC,EACpC,EAAK,KAAK,EAAW,GAAG,EAAS,GAAG,EAAK,CAAU,EAAE,OAAO,CACrE,CAEA,mBAA2B,EAAiC,CAC1D,GAAI,CAMF,OALe,EAAa,MAAO,CAAC,YAAa,yBAA0B,kBAAkB,EAAG,CAC9F,MACA,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,CAAC,CAAC,KACS,GAAK,IAAA,EACnB,OAAS,EAAO,CACd,GAAI,aAAiB,MAAO,OAC5B,MAAM,CACR,CACF,CACF"}
@@ -0,0 +1,5 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs/promises");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("node:child_process");const i=262144,a=8192;function o(e,t){let n=t||e.length>200,r=e.slice(0,200);return n&&r.push(`... diff truncated at 200 lines / ${i} bytes ...`),{lines:r,truncated:n}}function s(e,t,n,r){let s=r.byteLength>=i;if(r.subarray(0,a).includes(0))return{path:e,state:`binary`,lines:[`Binary file changed (${r.byteLength} bytes shown by git)`],additions:0,removals:0,tracked:n,truncated:s,suggestedLine:1};let c=o(r.subarray(0,i).toString(`utf8`).split(`
2
+ `),s),l=c.lines.filter(e=>e.startsWith(`+`)&&!e.startsWith(`+++`)).length,u=c.lines.filter(e=>e.startsWith(`-`)&&!e.startsWith(`---`)).length,d=c.lines.find(e=>e.startsWith(`@@`))?.match(/\+(\d+)/u);return{path:e,state:t,lines:c.lines,additions:l,removals:u,tracked:n,truncated:c.truncated,suggestedLine:Number(d?.[1]??1)}}var c=class{async diff(e,i){let a=n.default.resolve(e,i),o=n.default.relative(e,a),c=this.isTracked(e,o),l=!0;try{await t.default.access(a)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)l=!1;else throw e}if(!c&&!l)return s(a,`deleted`,!1,Buffer.from(`File no longer exists`));if(!c)return this.fullAdd(a);let u=(0,r.spawnSync)(`git`,[`diff`,`--no-ext-diff`,`--no-color`,`--unified=3`,`HEAD`,`--`,o],{cwd:e,encoding:`buffer`,maxBuffer:262144}).stdout??Buffer.alloc(0);return l&&/^(Binary files .* differ|GIT binary patch)$/mu.test(u.toString(`utf8`))?{path:a,state:`binary`,lines:[`Binary tracked file changed`],additions:0,removals:0,tracked:!0,truncated:!1,suggestedLine:1}:s(a,l?u.length>0?`modified`:`unchanged`:`deleted`,!0,u)}isTracked(e,t){return(0,r.spawnSync)(`git`,[`ls-files`,`--error-unmatch`,`--`,t],{cwd:e,stdio:`ignore`}).status===0}async fullAdd(e){let r=await t.default.open(e,`r`);try{let t=Buffer.alloc(i),{bytesRead:o}=await r.read(t,0,t.length,0),c=t.subarray(0,o);if(c.subarray(0,a).includes(0))return s(e,`binary`,!1,Buffer.from(`Binary untracked file (${o}+ bytes)`));let l=c.toString(`utf8`).split(`
3
+ `).map(e=>`+${e}`).join(`
4
+ `),u=`--- /dev/null\n+++ b/${n.default.basename(e)}\n@@ -0,0 +1 @@\n`;return s(e,`added`,!1,Buffer.from(u+l))}finally{await r.close()}}};exports.GitDiffService=c,exports.MAX_DIFF_BYTES=i;
5
+ //# sourceMappingURL=GitDiffService.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitDiffService.cjs","names":["path","fs","spawnSync"],"sources":["../../../src/adapters/GitDiffService/GitDiffService.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { FileDiff, FileEditState } from '../../types/domain';\nimport type { IGitDiffService } from '../../types/gitDiffService';\n\nexport const MAX_DIFF_LINES = 200;\nexport const MAX_DIFF_BYTES = 256 * 1024;\nconst BINARY_SAMPLE_BYTES = 8192;\n\nfunction capLines(lines: string[], byteTruncated: boolean): { lines: string[]; truncated: boolean } {\n const truncated = byteTruncated || lines.length > MAX_DIFF_LINES;\n const visible = lines.slice(0, MAX_DIFF_LINES);\n if (truncated) visible.push(`... diff truncated at ${MAX_DIFF_LINES} lines / ${MAX_DIFF_BYTES} bytes ...`);\n return { lines: visible, truncated };\n}\n\nfunction summarize(pathValue: string, state: FileEditState, tracked: boolean, raw: Buffer): FileDiff {\n const byteTruncated = raw.byteLength >= MAX_DIFF_BYTES;\n if (raw.subarray(0, BINARY_SAMPLE_BYTES).includes(0)) {\n return {\n path: pathValue,\n state: 'binary',\n lines: [`Binary file changed (${raw.byteLength} bytes shown by git)`],\n additions: 0,\n removals: 0,\n tracked,\n truncated: byteTruncated,\n suggestedLine: 1,\n };\n }\n const capped = capLines(raw.subarray(0, MAX_DIFF_BYTES).toString('utf8').split('\\n'), byteTruncated);\n const additions = capped.lines.filter((line) => line.startsWith('+') && !line.startsWith('+++')).length;\n const removals = capped.lines.filter((line) => line.startsWith('-') && !line.startsWith('---')).length;\n const hunk = capped.lines.find((line) => line.startsWith('@@'))?.match(/\\+(\\d+)/u);\n return {\n path: pathValue,\n state,\n lines: capped.lines,\n additions,\n removals,\n tracked,\n truncated: capped.truncated,\n suggestedLine: Number(hunk?.[1] ?? 1),\n };\n}\n\nexport class GitDiffService implements IGitDiffService {\n async diff(cwd: string, filePath: string): Promise<FileDiff> {\n const absolute = path.resolve(cwd, filePath);\n const relative = path.relative(cwd, absolute);\n const tracked = this.isTracked(cwd, relative);\n let exists = true;\n try {\n await fs.access(absolute);\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') exists = false;\n else throw error;\n }\n if (!tracked && !exists) return summarize(absolute, 'deleted', false, Buffer.from('File no longer exists'));\n if (!tracked) return this.fullAdd(absolute);\n const result = spawnSync('git', ['diff', '--no-ext-diff', '--no-color', '--unified=3', 'HEAD', '--', relative], {\n cwd,\n encoding: 'buffer',\n maxBuffer: MAX_DIFF_BYTES,\n });\n const output = result.stdout ?? Buffer.alloc(0);\n if (exists && /^(Binary files .* differ|GIT binary patch)$/mu.test(output.toString('utf8'))) {\n return {\n path: absolute,\n state: 'binary',\n lines: ['Binary tracked file changed'],\n additions: 0,\n removals: 0,\n tracked: true,\n truncated: false,\n suggestedLine: 1,\n };\n }\n const state: FileEditState = exists ? (output.length > 0 ? 'modified' : 'unchanged') : 'deleted';\n return summarize(absolute, state, true, output);\n }\n\n private isTracked(cwd: string, relative: string): boolean {\n return spawnSync('git', ['ls-files', '--error-unmatch', '--', relative], { cwd, stdio: 'ignore' }).status === 0;\n }\n\n private async fullAdd(filePath: string): Promise<FileDiff> {\n const handle = await fs.open(filePath, 'r');\n try {\n const buffer = Buffer.alloc(MAX_DIFF_BYTES);\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);\n const sample = buffer.subarray(0, bytesRead);\n if (sample.subarray(0, BINARY_SAMPLE_BYTES).includes(0)) {\n return summarize(filePath, 'binary', false, Buffer.from(`Binary untracked file (${bytesRead}+ bytes)`));\n }\n const body = sample\n .toString('utf8')\n .split('\\n')\n .map((line) => `+${line}`)\n .join('\\n');\n const header = `--- /dev/null\\n+++ b/${path.basename(filePath)}\\n@@ -0,0 +1 @@\\n`;\n return summarize(filePath, 'added', false, Buffer.from(header + body));\n } finally {\n await handle.close();\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import e from"node:fs/promises";import t from"node:path";import{spawnSync as n}from"node:child_process";const r=262144,i=8192;function a(e,t){let n=t||e.length>200,i=e.slice(0,200);return n&&i.push(`... diff truncated at 200 lines / ${r} bytes ...`),{lines:i,truncated:n}}function o(e,t,n,o){let s=o.byteLength>=r;if(o.subarray(0,i).includes(0))return{path:e,state:`binary`,lines:[`Binary file changed (${o.byteLength} bytes shown by git)`],additions:0,removals:0,tracked:n,truncated:s,suggestedLine:1};let c=a(o.subarray(0,r).toString(`utf8`).split(`
2
+ `),s),l=c.lines.filter(e=>e.startsWith(`+`)&&!e.startsWith(`+++`)).length,u=c.lines.filter(e=>e.startsWith(`-`)&&!e.startsWith(`---`)).length,d=c.lines.find(e=>e.startsWith(`@@`))?.match(/\+(\d+)/u);return{path:e,state:t,lines:c.lines,additions:l,removals:u,tracked:n,truncated:c.truncated,suggestedLine:Number(d?.[1]??1)}}var s=class{async diff(r,i){let a=t.resolve(r,i),s=t.relative(r,a),c=this.isTracked(r,s),l=!0;try{await e.access(a)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)l=!1;else throw e}if(!c&&!l)return o(a,`deleted`,!1,Buffer.from(`File no longer exists`));if(!c)return this.fullAdd(a);let u=n(`git`,[`diff`,`--no-ext-diff`,`--no-color`,`--unified=3`,`HEAD`,`--`,s],{cwd:r,encoding:`buffer`,maxBuffer:262144}).stdout??Buffer.alloc(0);return l&&/^(Binary files .* differ|GIT binary patch)$/mu.test(u.toString(`utf8`))?{path:a,state:`binary`,lines:[`Binary tracked file changed`],additions:0,removals:0,tracked:!0,truncated:!1,suggestedLine:1}:o(a,l?u.length>0?`modified`:`unchanged`:`deleted`,!0,u)}isTracked(e,t){return n(`git`,[`ls-files`,`--error-unmatch`,`--`,t],{cwd:e,stdio:`ignore`}).status===0}async fullAdd(n){let a=await e.open(n,`r`);try{let e=Buffer.alloc(r),{bytesRead:s}=await a.read(e,0,e.length,0),c=e.subarray(0,s);if(c.subarray(0,i).includes(0))return o(n,`binary`,!1,Buffer.from(`Binary untracked file (${s}+ bytes)`));let l=c.toString(`utf8`).split(`
3
+ `).map(e=>`+${e}`).join(`
4
+ `),u=`--- /dev/null\n+++ b/${t.basename(n)}\n@@ -0,0 +1 @@\n`;return o(n,`added`,!1,Buffer.from(u+l))}finally{await a.close()}}};export{s as GitDiffService,r as MAX_DIFF_BYTES};
5
+ //# sourceMappingURL=GitDiffService.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitDiffService.mjs","names":[],"sources":["../../../src/adapters/GitDiffService/GitDiffService.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { FileDiff, FileEditState } from '../../types/domain';\nimport type { IGitDiffService } from '../../types/gitDiffService';\n\nexport const MAX_DIFF_LINES = 200;\nexport const MAX_DIFF_BYTES = 256 * 1024;\nconst BINARY_SAMPLE_BYTES = 8192;\n\nfunction capLines(lines: string[], byteTruncated: boolean): { lines: string[]; truncated: boolean } {\n const truncated = byteTruncated || lines.length > MAX_DIFF_LINES;\n const visible = lines.slice(0, MAX_DIFF_LINES);\n if (truncated) visible.push(`... diff truncated at ${MAX_DIFF_LINES} lines / ${MAX_DIFF_BYTES} bytes ...`);\n return { lines: visible, truncated };\n}\n\nfunction summarize(pathValue: string, state: FileEditState, tracked: boolean, raw: Buffer): FileDiff {\n const byteTruncated = raw.byteLength >= MAX_DIFF_BYTES;\n if (raw.subarray(0, BINARY_SAMPLE_BYTES).includes(0)) {\n return {\n path: pathValue,\n state: 'binary',\n lines: [`Binary file changed (${raw.byteLength} bytes shown by git)`],\n additions: 0,\n removals: 0,\n tracked,\n truncated: byteTruncated,\n suggestedLine: 1,\n };\n }\n const capped = capLines(raw.subarray(0, MAX_DIFF_BYTES).toString('utf8').split('\\n'), byteTruncated);\n const additions = capped.lines.filter((line) => line.startsWith('+') && !line.startsWith('+++')).length;\n const removals = capped.lines.filter((line) => line.startsWith('-') && !line.startsWith('---')).length;\n const hunk = capped.lines.find((line) => line.startsWith('@@'))?.match(/\\+(\\d+)/u);\n return {\n path: pathValue,\n state,\n lines: capped.lines,\n additions,\n removals,\n tracked,\n truncated: capped.truncated,\n suggestedLine: Number(hunk?.[1] ?? 1),\n };\n}\n\nexport class GitDiffService implements IGitDiffService {\n async diff(cwd: string, filePath: string): Promise<FileDiff> {\n const absolute = path.resolve(cwd, filePath);\n const relative = path.relative(cwd, absolute);\n const tracked = this.isTracked(cwd, relative);\n let exists = true;\n try {\n await fs.access(absolute);\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') exists = false;\n else throw error;\n }\n if (!tracked && !exists) return summarize(absolute, 'deleted', false, Buffer.from('File no longer exists'));\n if (!tracked) return this.fullAdd(absolute);\n const result = spawnSync('git', ['diff', '--no-ext-diff', '--no-color', '--unified=3', 'HEAD', '--', relative], {\n cwd,\n encoding: 'buffer',\n maxBuffer: MAX_DIFF_BYTES,\n });\n const output = result.stdout ?? Buffer.alloc(0);\n if (exists && /^(Binary files .* differ|GIT binary patch)$/mu.test(output.toString('utf8'))) {\n return {\n path: absolute,\n state: 'binary',\n lines: ['Binary tracked file changed'],\n additions: 0,\n removals: 0,\n tracked: true,\n truncated: false,\n suggestedLine: 1,\n };\n }\n const state: FileEditState = exists ? (output.length > 0 ? 'modified' : 'unchanged') : 'deleted';\n return summarize(absolute, state, true, output);\n }\n\n private isTracked(cwd: string, relative: string): boolean {\n return spawnSync('git', ['ls-files', '--error-unmatch', '--', relative], { cwd, stdio: 'ignore' }).status === 0;\n }\n\n private async fullAdd(filePath: string): Promise<FileDiff> {\n const handle = await fs.open(filePath, 'r');\n try {\n const buffer = Buffer.alloc(MAX_DIFF_BYTES);\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);\n const sample = buffer.subarray(0, bytesRead);\n if (sample.subarray(0, BINARY_SAMPLE_BYTES).includes(0)) {\n return summarize(filePath, 'binary', false, Buffer.from(`Binary untracked file (${bytesRead}+ bytes)`));\n }\n const body = sample\n .toString('utf8')\n .split('\\n')\n .map((line) => `+${line}`)\n .join('\\n');\n const header = `--- /dev/null\\n+++ b/${path.basename(filePath)}\\n@@ -0,0 +1 @@\\n`;\n return summarize(filePath, 'added', false, Buffer.from(header + body));\n } finally {\n await handle.close();\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs/promises");t=e.__toESM(t,1);function n(e,t){return e instanceof Error&&`code`in e&&e.code===t}function r(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.version===1&&typeof t.path==`string`&&typeof t.at==`number`&&(t.tool===`edit`||t.tool===`write`||t.tool===`bash`)}var i=class{filePath;initialize(e){this.filePath=e}async append(e){await this.withLock(async()=>t.default.appendFile(this.requirePath(),`${JSON.stringify(e)}\n`,`utf8`))}async list(){let e;try{e=await t.default.readFile(this.requirePath(),`utf8`)}catch(e){if(n(e,`ENOENT`))return[];throw e}let i=new Map;for(let t of e.split(`
2
+ `)){if(!t)continue;let e;try{e=JSON.parse(t)}catch(e){console.warn(`Ignoring malformed file edit timeline line: ${e instanceof Error?e.message:String(e)}`);continue}if(!r(e))continue;let n=i.get(e.path);i.set(e.path,{path:e.path,tool:e.at>=(n?.at??0)?e.tool:n?.tool??e.tool,at:Math.max(e.at,n?.at??0),count:(n?.count??0)+1})}return[...i.values()].sort((e,t)=>t.at-e.at)}async clear(){try{await t.default.unlink(this.requirePath())}catch(e){if(!n(e,`ENOENT`))throw e}}requirePath(){if(!this.filePath)throw Error(`Timeline store is not initialized`);return this.filePath}async withLock(e){let r=`${this.requirePath()}.lock`;for(let i=0;i<100;i+=1)try{let i=await t.default.open(r,`wx`);try{return await e()}finally{await i.close();try{await t.default.unlink(r)}catch(e){n(e,`ENOENT`)||console.warn(`Could not remove timeline lock: ${String(e)}`)}}}catch(e){if(!n(e,`EEXIST`))throw e;await new Promise(e=>setTimeout(e,10))}throw Error(`Timed out acquiring timeline lock ${r}`)}};exports.TimelineStore=i;
3
+ //# sourceMappingURL=TimelineStore.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimelineStore.cjs","names":["fs"],"sources":["../../../src/adapters/TimelineStore/TimelineStore.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport type { FileEditEntry, TimelineEvent } from '../../types/domain';\nimport type { ITimelineStore } from '../../types/timelineStore';\n\nconst LOCK_RETRY_MS = 10;\nconst LOCK_RETRIES = 100;\n\nfunction hasCode(error: unknown, code: string): boolean {\n return error instanceof Error && 'code' in error && error.code === code;\n}\n\nfunction isTimelineEvent(value: unknown): value is TimelineEvent {\n if (!value || typeof value !== 'object') return false;\n const event = value as Partial<TimelineEvent>;\n return (\n event.version === 1 &&\n typeof event.path === 'string' &&\n typeof event.at === 'number' &&\n (event.tool === 'edit' || event.tool === 'write' || event.tool === 'bash')\n );\n}\n\nexport class TimelineStore implements ITimelineStore {\n private filePath: string | undefined;\n\n initialize(filePath: string): void {\n this.filePath = filePath;\n }\n\n async append(event: TimelineEvent): Promise<void> {\n await this.withLock(async () => fs.appendFile(this.requirePath(), `${JSON.stringify(event)}\\n`, 'utf8'));\n }\n\n async list(): Promise<FileEditEntry[]> {\n let content: string;\n try {\n content = await fs.readFile(this.requirePath(), 'utf8');\n } catch (error) {\n if (hasCode(error, 'ENOENT')) return [];\n throw error;\n }\n const folded = new Map<string, FileEditEntry>();\n for (const line of content.split('\\n')) {\n if (!line) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (error) {\n console.warn(\n `Ignoring malformed file edit timeline line: ${error instanceof Error ? error.message : String(error)}`,\n );\n continue;\n }\n if (!isTimelineEvent(parsed)) continue;\n const current = folded.get(parsed.path);\n folded.set(parsed.path, {\n path: parsed.path,\n tool: parsed.at >= (current?.at ?? 0) ? parsed.tool : (current?.tool ?? parsed.tool),\n at: Math.max(parsed.at, current?.at ?? 0),\n count: (current?.count ?? 0) + 1,\n });\n }\n return [...folded.values()].sort((left, right) => right.at - left.at);\n }\n\n async clear(): Promise<void> {\n try {\n await fs.unlink(this.requirePath());\n } catch (error) {\n if (!hasCode(error, 'ENOENT')) throw error;\n }\n }\n\n private requirePath(): string {\n if (!this.filePath) throw new Error('Timeline store is not initialized');\n return this.filePath;\n }\n\n private async withLock<T>(operation: () => Promise<T>): Promise<T> {\n const lockPath = `${this.requirePath()}.lock`;\n for (let attempt = 0; attempt < LOCK_RETRIES; attempt += 1) {\n try {\n const lock = await fs.open(lockPath, 'wx');\n try {\n return await operation();\n } finally {\n await lock.close();\n try {\n await fs.unlink(lockPath);\n } catch (error) {\n if (!hasCode(error, 'ENOENT')) console.warn(`Could not remove timeline lock: ${String(error)}`);\n }\n }\n } catch (error) {\n if (!hasCode(error, 'EEXIST')) throw error;\n await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));\n }\n }\n throw new Error(`Timed out acquiring timeline lock ${lockPath}`);\n }\n}\n"],"mappings":"2GAOA,SAAS,EAAQ,EAAgB,EAAuB,CACtD,OAAO,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,CACrE,CAEA,SAAS,EAAgB,EAAwC,CAC/D,GAAI,CAAC,GAAS,OAAO,GAAU,SAAU,MAAO,GAChD,IAAM,EAAQ,EACd,OACE,EAAM,UAAY,GAClB,OAAO,EAAM,MAAS,UACtB,OAAO,EAAM,IAAO,WACnB,EAAM,OAAS,QAAU,EAAM,OAAS,SAAW,EAAM,OAAS,OAEvE,CAEA,IAAa,EAAb,KAAqD,CACnD,SAEA,WAAW,EAAwB,CACjC,KAAK,SAAW,CAClB,CAEA,MAAM,OAAO,EAAqC,CAChD,MAAM,KAAK,SAAS,SAAYA,EAAAA,QAAG,WAAW,KAAK,YAAY,EAAG,GAAG,KAAK,UAAU,CAAK,EAAE,IAAK,MAAM,CAAC,CACzG,CAEA,MAAM,MAAiC,CACrC,IAAI,EACJ,GAAI,CACF,EAAU,MAAMA,EAAAA,QAAG,SAAS,KAAK,YAAY,EAAG,MAAM,CACxD,OAAS,EAAO,CACd,GAAI,EAAQ,EAAO,QAAQ,EAAG,MAAO,CAAC,EACtC,MAAM,CACR,CACA,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAQ,MAAM;CAAI,EAAG,CACtC,GAAI,CAAC,EAAM,SACX,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAI,CAC1B,OAAS,EAAO,CACd,QAAQ,KACN,+CAA+C,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,GACtG,EACA,QACF,CACA,GAAI,CAAC,EAAgB,CAAM,EAAG,SAC9B,IAAM,EAAU,EAAO,IAAI,EAAO,IAAI,EACtC,EAAO,IAAI,EAAO,KAAM,CACtB,KAAM,EAAO,KACb,KAAM,EAAO,KAAO,GAAS,IAAM,GAAK,EAAO,KAAQ,GAAS,MAAQ,EAAO,KAC/E,GAAI,KAAK,IAAI,EAAO,GAAI,GAAS,IAAM,CAAC,EACxC,OAAQ,GAAS,OAAS,GAAK,CACjC,CAAC,CACH,CACA,MAAO,CAAC,GAAG,EAAO,OAAO,CAAC,CAAC,CAAC,MAAM,EAAM,IAAU,EAAM,GAAK,EAAK,EAAE,CACtE,CAEA,MAAM,OAAuB,CAC3B,GAAI,CACF,MAAMA,EAAAA,QAAG,OAAO,KAAK,YAAY,CAAC,CACpC,OAAS,EAAO,CACd,GAAI,CAAC,EAAQ,EAAO,QAAQ,EAAG,MAAM,CACvC,CACF,CAEA,aAA8B,CAC5B,GAAI,CAAC,KAAK,SAAU,MAAU,MAAM,mCAAmC,EACvE,OAAO,KAAK,QACd,CAEA,MAAc,SAAY,EAAyC,CACjE,IAAM,EAAW,GAAG,KAAK,YAAY,EAAE,OACvC,IAAK,IAAI,EAAU,EAAG,EAAU,IAAc,GAAW,EACvD,GAAI,CACF,IAAM,EAAO,MAAMA,EAAAA,QAAG,KAAK,EAAU,IAAI,EACzC,GAAI,CACF,OAAO,MAAM,EAAU,CACzB,QAAU,CACR,MAAM,EAAK,MAAM,EACjB,GAAI,CACF,MAAMA,EAAAA,QAAG,OAAO,CAAQ,CAC1B,OAAS,EAAO,CACT,EAAQ,EAAO,QAAQ,GAAG,QAAQ,KAAK,mCAAmC,OAAO,CAAK,GAAG,CAChG,CACF,CACF,OAAS,EAAO,CACd,GAAI,CAAC,EAAQ,EAAO,QAAQ,EAAG,MAAM,EACrC,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,EAAa,CAAC,CACnE,CAEF,MAAU,MAAM,qCAAqC,GAAU,CACjE,CACF"}
@@ -0,0 +1,3 @@
1
+ import e from"node:fs/promises";function t(e,t){return e instanceof Error&&`code`in e&&e.code===t}function n(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.version===1&&typeof t.path==`string`&&typeof t.at==`number`&&(t.tool===`edit`||t.tool===`write`||t.tool===`bash`)}var r=class{filePath;initialize(e){this.filePath=e}async append(t){await this.withLock(async()=>e.appendFile(this.requirePath(),`${JSON.stringify(t)}\n`,`utf8`))}async list(){let r;try{r=await e.readFile(this.requirePath(),`utf8`)}catch(e){if(t(e,`ENOENT`))return[];throw e}let i=new Map;for(let e of r.split(`
2
+ `)){if(!e)continue;let t;try{t=JSON.parse(e)}catch(e){console.warn(`Ignoring malformed file edit timeline line: ${e instanceof Error?e.message:String(e)}`);continue}if(!n(t))continue;let r=i.get(t.path);i.set(t.path,{path:t.path,tool:t.at>=(r?.at??0)?t.tool:r?.tool??t.tool,at:Math.max(t.at,r?.at??0),count:(r?.count??0)+1})}return[...i.values()].sort((e,t)=>t.at-e.at)}async clear(){try{await e.unlink(this.requirePath())}catch(e){if(!t(e,`ENOENT`))throw e}}requirePath(){if(!this.filePath)throw Error(`Timeline store is not initialized`);return this.filePath}async withLock(n){let r=`${this.requirePath()}.lock`;for(let i=0;i<100;i+=1)try{let i=await e.open(r,`wx`);try{return await n()}finally{await i.close();try{await e.unlink(r)}catch(e){t(e,`ENOENT`)||console.warn(`Could not remove timeline lock: ${String(e)}`)}}}catch(e){if(!t(e,`EEXIST`))throw e;await new Promise(e=>setTimeout(e,10))}throw Error(`Timed out acquiring timeline lock ${r}`)}};export{r as TimelineStore};
3
+ //# sourceMappingURL=TimelineStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimelineStore.mjs","names":[],"sources":["../../../src/adapters/TimelineStore/TimelineStore.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport type { FileEditEntry, TimelineEvent } from '../../types/domain';\nimport type { ITimelineStore } from '../../types/timelineStore';\n\nconst LOCK_RETRY_MS = 10;\nconst LOCK_RETRIES = 100;\n\nfunction hasCode(error: unknown, code: string): boolean {\n return error instanceof Error && 'code' in error && error.code === code;\n}\n\nfunction isTimelineEvent(value: unknown): value is TimelineEvent {\n if (!value || typeof value !== 'object') return false;\n const event = value as Partial<TimelineEvent>;\n return (\n event.version === 1 &&\n typeof event.path === 'string' &&\n typeof event.at === 'number' &&\n (event.tool === 'edit' || event.tool === 'write' || event.tool === 'bash')\n );\n}\n\nexport class TimelineStore implements ITimelineStore {\n private filePath: string | undefined;\n\n initialize(filePath: string): void {\n this.filePath = filePath;\n }\n\n async append(event: TimelineEvent): Promise<void> {\n await this.withLock(async () => fs.appendFile(this.requirePath(), `${JSON.stringify(event)}\\n`, 'utf8'));\n }\n\n async list(): Promise<FileEditEntry[]> {\n let content: string;\n try {\n content = await fs.readFile(this.requirePath(), 'utf8');\n } catch (error) {\n if (hasCode(error, 'ENOENT')) return [];\n throw error;\n }\n const folded = new Map<string, FileEditEntry>();\n for (const line of content.split('\\n')) {\n if (!line) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (error) {\n console.warn(\n `Ignoring malformed file edit timeline line: ${error instanceof Error ? error.message : String(error)}`,\n );\n continue;\n }\n if (!isTimelineEvent(parsed)) continue;\n const current = folded.get(parsed.path);\n folded.set(parsed.path, {\n path: parsed.path,\n tool: parsed.at >= (current?.at ?? 0) ? parsed.tool : (current?.tool ?? parsed.tool),\n at: Math.max(parsed.at, current?.at ?? 0),\n count: (current?.count ?? 0) + 1,\n });\n }\n return [...folded.values()].sort((left, right) => right.at - left.at);\n }\n\n async clear(): Promise<void> {\n try {\n await fs.unlink(this.requirePath());\n } catch (error) {\n if (!hasCode(error, 'ENOENT')) throw error;\n }\n }\n\n private requirePath(): string {\n if (!this.filePath) throw new Error('Timeline store is not initialized');\n return this.filePath;\n }\n\n private async withLock<T>(operation: () => Promise<T>): Promise<T> {\n const lockPath = `${this.requirePath()}.lock`;\n for (let attempt = 0; attempt < LOCK_RETRIES; attempt += 1) {\n try {\n const lock = await fs.open(lockPath, 'wx');\n try {\n return await operation();\n } finally {\n await lock.close();\n try {\n await fs.unlink(lockPath);\n } catch (error) {\n if (!hasCode(error, 'ENOENT')) console.warn(`Could not remove timeline lock: ${String(error)}`);\n }\n }\n } catch (error) {\n if (!hasCode(error, 'EEXIST')) throw error;\n await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));\n }\n }\n throw new Error(`Timed out acquiring timeline lock ${lockPath}`);\n }\n}\n"],"mappings":"gCAOA,SAAS,EAAQ,EAAgB,EAAuB,CACtD,OAAO,aAAiB,OAAS,SAAU,GAAS,EAAM,OAAS,CACrE,CAEA,SAAS,EAAgB,EAAwC,CAC/D,GAAI,CAAC,GAAS,OAAO,GAAU,SAAU,MAAO,GAChD,IAAM,EAAQ,EACd,OACE,EAAM,UAAY,GAClB,OAAO,EAAM,MAAS,UACtB,OAAO,EAAM,IAAO,WACnB,EAAM,OAAS,QAAU,EAAM,OAAS,SAAW,EAAM,OAAS,OAEvE,CAEA,IAAa,EAAb,KAAqD,CACnD,SAEA,WAAW,EAAwB,CACjC,KAAK,SAAW,CAClB,CAEA,MAAM,OAAO,EAAqC,CAChD,MAAM,KAAK,SAAS,SAAY,EAAG,WAAW,KAAK,YAAY,EAAG,GAAG,KAAK,UAAU,CAAK,EAAE,IAAK,MAAM,CAAC,CACzG,CAEA,MAAM,MAAiC,CACrC,IAAI,EACJ,GAAI,CACF,EAAU,MAAM,EAAG,SAAS,KAAK,YAAY,EAAG,MAAM,CACxD,OAAS,EAAO,CACd,GAAI,EAAQ,EAAO,QAAQ,EAAG,MAAO,CAAC,EACtC,MAAM,CACR,CACA,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAQ,MAAM;CAAI,EAAG,CACtC,GAAI,CAAC,EAAM,SACX,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAI,CAC1B,OAAS,EAAO,CACd,QAAQ,KACN,+CAA+C,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,GACtG,EACA,QACF,CACA,GAAI,CAAC,EAAgB,CAAM,EAAG,SAC9B,IAAM,EAAU,EAAO,IAAI,EAAO,IAAI,EACtC,EAAO,IAAI,EAAO,KAAM,CACtB,KAAM,EAAO,KACb,KAAM,EAAO,KAAO,GAAS,IAAM,GAAK,EAAO,KAAQ,GAAS,MAAQ,EAAO,KAC/E,GAAI,KAAK,IAAI,EAAO,GAAI,GAAS,IAAM,CAAC,EACxC,OAAQ,GAAS,OAAS,GAAK,CACjC,CAAC,CACH,CACA,MAAO,CAAC,GAAG,EAAO,OAAO,CAAC,CAAC,CAAC,MAAM,EAAM,IAAU,EAAM,GAAK,EAAK,EAAE,CACtE,CAEA,MAAM,OAAuB,CAC3B,GAAI,CACF,MAAM,EAAG,OAAO,KAAK,YAAY,CAAC,CACpC,OAAS,EAAO,CACd,GAAI,CAAC,EAAQ,EAAO,QAAQ,EAAG,MAAM,CACvC,CACF,CAEA,aAA8B,CAC5B,GAAI,CAAC,KAAK,SAAU,MAAU,MAAM,mCAAmC,EACvE,OAAO,KAAK,QACd,CAEA,MAAc,SAAY,EAAyC,CACjE,IAAM,EAAW,GAAG,KAAK,YAAY,EAAE,OACvC,IAAK,IAAI,EAAU,EAAG,EAAU,IAAc,GAAW,EACvD,GAAI,CACF,IAAM,EAAO,MAAM,EAAG,KAAK,EAAU,IAAI,EACzC,GAAI,CACF,OAAO,MAAM,EAAU,CACzB,QAAU,CACR,MAAM,EAAK,MAAM,EACjB,GAAI,CACF,MAAM,EAAG,OAAO,CAAQ,CAC1B,OAAS,EAAO,CACT,EAAQ,EAAO,QAAQ,GAAG,QAAQ,KAAK,mCAAmC,OAAO,CAAK,GAAG,CAChG,CACF,CACF,OAAS,EAAO,CACd,GAAI,CAAC,EAAQ,EAAO,QAAQ,EAAG,MAAM,EACrC,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,EAAa,CAAC,CACnE,CAEF,MAAU,MAAM,qCAAqC,GAAU,CACjE,CACF"}
@@ -1,2 +1,2 @@
1
- const e=require("../../types/index.cjs"),t=require("../../container/index.cjs");let n=require("@agimon-ai/doompi-extension-contracts/child-process"),r=require("@agimon-ai/doompi-telemetry");const i=`file-edits`,a={source:`@agimon-ai/doompi-file-edit`,bindings:[{id:`editor.files`,path:[{key:`e`,label:`extension`,order:50},{key:`f`,label:`files`,detail:`session edits`}],command:{name:i}}]};function o(a){let o=t.createFileEditContainer(),s=o.get(e.FILE_EDIT_TYPES.Paths),c=o.get(e.FILE_EDIT_TYPES.TimelineStore),l=o.get(e.FILE_EDIT_TYPES.EditTracker),u=o.get(e.FILE_EDIT_TYPES.Workflow),d=(0,r.createDoomTelemetry)({serviceName:`doom-file-edit`,packageName:`@agimon-ai/doompi-file-edit`,env:process.env,enableLogs:!0,enableTraces:!0}),f=new Map;a.registerCommand(i,{description:`Review files edited in this session`,handler:async(e,t)=>{if(!t.hasUI){t.ui.notify(`/file-edits requires interactive mode`,`error`);return}await u.open(t)}}),a.on(`session_start`,async(e,t)=>{let n=s.sessionKey(t.sessionManager.getSessionId());c.initialize(s.timelinePath(t.cwd,n)),d.recordEvent(`doom_file_edit.timeline_started`,{outcome:`initialized`})}),a.on(`tool_execution_start`,async(e,t)=>{f.set(e.toolCallId,Date.now()),await l.start(e.toolCallId,e.toolName,e.args,t.cwd),d.recordEvent(`doom_file_edit.edit_started`,{"tool.name":e.toolName})}),a.on(`tool_execution_end`,async e=>{let t=f.get(e.toolCallId);f.delete(e.toolCallId),await l.end(e.toolCallId,e.isError),d.recordEvent(`doom_file_edit.edit_finished`,{"tool.name":e.toolName,"tool.result.error":e.isError,...t===void 0?{}:{duration_ms:Date.now()-t},outcome:e.isError?`failed`:`completed`})}),a.on(`session_shutdown`,async()=>{process.env[n.SUBAGENT_CHILD_ENV]||await c.clear(),await d.recordEvent(`doom_file_edit.timeline_finished`,{outcome:`closed`}),await d.shutdown()})}exports.FILE_EDIT_LEADER_CONTRIBUTION=a,exports.fileEditExtension=o;
1
+ const e=require("../../container/index.cjs");let t=require("@agimon-ai/doompi-extension-contracts/child-process"),n=require("@agimon-ai/doompi-telemetry"),r=require("@agimon-ai/doompi-ui/leader"),i=require("@deepseek-ai/cordis");const a=`file-edits`,o=`@agimon-ai/doompi-file-edit`,s={source:o,bindings:[{id:`editor.files`,path:[{key:`e`,label:`extension`,order:50},{key:`f`,label:`files`,detail:`session edits`}],command:{name:a}}]};function c(r,i){r.effect(function*(){let{paths:r,timeline:s,editTracker:c,workflow:l}=e.createFileEditContainer(),u=(0,n.createDoomTelemetry)({serviceName:`doom-file-edit`,packageName:o,env:process.env,enableLogs:!0,enableTraces:!0}),d=new Map,f=!0,p=0;yield async()=>{f=!1,p+=1,d.clear();try{process.env[t.SUBAGENT_CHILD_ENV]||await s.clear(),await u.recordEvent(`doom_file_edit.timeline_finished`,{outcome:`closed`})}finally{await u.shutdown()}},i.registerCommand(a,{description:`Review files edited in this session`,handler:async(e,t)=>{if(f){if(!t.hasUI){t.ui.notify(`/file-edits requires interactive mode`,`error`);return}await l.open(t)}}}),i.on(`session_start`,(e,t)=>{if(!f)return;p+=1,d.clear();let n=r.sessionKey(t.sessionManager.getSessionId());s.initialize(r.timelinePath(t.cwd,n)),u.recordEvent(`doom_file_edit.timeline_started`,{outcome:`initialized`})}),i.on(`tool_execution_start`,async(e,t)=>{if(!f)return;let n=p;if(d.set(e.toolCallId,Date.now()),await c.start(e.toolCallId,e.toolName,e.args,t.cwd),!f||n!==p){d.delete(e.toolCallId);return}u.recordEvent(`doom_file_edit.edit_started`,{"tool.name":e.toolName})}),i.on(`tool_execution_end`,async e=>{if(!f)return;let t=d.get(e.toolCallId);d.delete(e.toolCallId),await c.end(e.toolCallId,e.isError),f&&u.recordEvent(`doom_file_edit.edit_finished`,{"tool.name":e.toolName,"tool.result.error":e.isError,...t===void 0?{}:{duration_ms:Date.now()-t},outcome:e.isError?`failed`:`completed`})})},`${o}/runtime`)}async function l(e){let t=new i.Context,n,a=()=>(n??=t.fiber.dispose(),n);try{c(t,e),t.effect(()=>(0,r.registerDoomLeaderContribution)(e,s),`${o}/leader`)}catch(e){throw await a(),e}e.on(`session_shutdown`,a)}exports.FILE_EDIT_LEADER_CONTRIBUTION=s,exports.fileEditExtension=l,exports.installFileEditRuntime=c;
2
2
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["createFileEditContainer","FILE_EDIT_TYPES","createDoomTelemetry","SUBAGENT_CHILD_ENV"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { SUBAGENT_CHILD_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createFileEditContainer } from '../../container/index.ts';\nimport type { IEditTracker } from '../../services/EditTracker/types.ts';\nimport type { IFileEditPaths } from '../../services/FileEditPaths/types.ts';\nimport type { IFileEditWorkflow } from '../../services/FileEditWorkflow/types.ts';\nimport type { ITimelineStore } from '../../services/TimelineStore/types.ts';\nimport { FILE_EDIT_TYPES } from '../../types/index.ts';\n\nconst FILES_COMMAND = 'file-edits';\n\nexport const FILE_EDIT_LEADER_CONTRIBUTION = {\n source: '@agimon-ai/doompi-file-edit',\n bindings: [\n {\n id: 'editor.files',\n path: [\n { key: 'e', label: 'extension', order: 50 },\n { key: 'f', label: 'files', detail: 'session edits' },\n ],\n command: { name: FILES_COMMAND },\n },\n ],\n} as const;\n\nexport function fileEditExtension(pi: ExtensionAPI): void {\n const container = createFileEditContainer();\n const paths = container.get<IFileEditPaths>(FILE_EDIT_TYPES.Paths);\n const timeline = container.get<ITimelineStore>(FILE_EDIT_TYPES.TimelineStore);\n const tracker = container.get<IEditTracker>(FILE_EDIT_TYPES.EditTracker);\n const workflow = container.get<IFileEditWorkflow>(FILE_EDIT_TYPES.Workflow);\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: 'doom-file-edit',\n packageName: '@agimon-ai/doompi-file-edit',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const toolStartedAt = new Map<string, number>();\n\n pi.registerCommand(FILES_COMMAND, {\n description: 'Review files edited in this session',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify('/file-edits requires interactive mode', 'error');\n return;\n }\n await workflow.open(ctx);\n },\n });\n\n pi.on('session_start', async (_event, ctx) => {\n const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());\n timeline.initialize(paths.timelinePath(ctx.cwd, sessionKey));\n void telemetry.recordEvent('doom_file_edit.timeline_started', { outcome: 'initialized' });\n });\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);\n void telemetry.recordEvent('doom_file_edit.edit_started', { 'tool.name': event.toolName });\n });\n pi.on('tool_execution_end', async (event) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n await tracker.end(event.toolCallId, event.isError);\n void telemetry.recordEvent('doom_file_edit.edit_finished', {\n 'tool.name': event.toolName,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { duration_ms: Date.now() - startedAt }),\n outcome: event.isError ? 'failed' : 'completed',\n });\n });\n pi.on('session_shutdown', async () => {\n if (!process.env[SUBAGENT_CHILD_ENV]) await timeline.clear();\n await telemetry.recordEvent('doom_file_edit.timeline_finished', { outcome: 'closed' });\n await telemetry.shutdown();\n });\n}\n"],"mappings":"8LAUA,MAAM,EAAgB,aAET,EAAgC,CAC3C,OAAQ,8BACR,SAAU,CACR,CACE,GAAI,eACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,EAAG,EAC1C,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,eAAgB,CACtD,EACA,QAAS,CAAE,KAAM,CAAc,CACjC,CACF,CACF,EAEA,SAAgB,EAAkB,EAAwB,CACxD,IAAM,EAAYA,EAAAA,wBAAwB,EACpC,EAAQ,EAAU,IAAoBC,EAAAA,gBAAgB,KAAK,EAC3D,EAAW,EAAU,IAAoBA,EAAAA,gBAAgB,aAAa,EACtE,EAAU,EAAU,IAAkBA,EAAAA,gBAAgB,WAAW,EACjE,EAAW,EAAU,IAAuBA,EAAAA,gBAAgB,QAAQ,EACpE,GAAA,EAA2BC,EAAAA,oBAAAA,CAAoB,CACnD,YAAa,iBACb,YAAa,8BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAgB,IAAI,IAE1B,EAAG,gBAAgB,EAAe,CAChC,YAAa,sCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,wCAAyC,OAAO,EAC9D,MACF,CACA,MAAM,EAAS,KAAK,CAAG,CACzB,CACF,CAAC,EAED,EAAG,GAAG,gBAAiB,MAAO,EAAQ,IAAQ,CAC5C,IAAM,EAAa,EAAM,WAAW,EAAI,eAAe,aAAa,CAAC,EACrE,EAAS,WAAW,EAAM,aAAa,EAAI,IAAK,CAAU,CAAC,EAC3D,EAAe,YAAY,kCAAmC,CAAE,QAAS,aAAc,CAAC,CAC1F,CAAC,EACD,EAAG,GAAG,uBAAwB,MAAO,EAAO,IAAQ,CAClD,EAAc,IAAI,EAAM,WAAY,KAAK,IAAI,CAAC,EAC9C,MAAM,EAAQ,MAAM,EAAM,WAAY,EAAM,SAAU,EAAM,KAAM,EAAI,GAAG,EACzE,EAAe,YAAY,8BAA+B,CAAE,YAAa,EAAM,QAAS,CAAC,CAC3F,CAAC,EACD,EAAG,GAAG,qBAAsB,KAAO,IAAU,CAC3C,IAAM,EAAY,EAAc,IAAI,EAAM,UAAU,EACpD,EAAc,OAAO,EAAM,UAAU,EACrC,MAAM,EAAQ,IAAI,EAAM,WAAY,EAAM,OAAO,EACjD,EAAe,YAAY,+BAAgC,CACzD,YAAa,EAAM,SACnB,oBAAqB,EAAM,QAC3B,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,EACzE,QAAS,EAAM,QAAU,SAAW,WACtC,CAAC,CACH,CAAC,EACD,EAAG,GAAG,mBAAoB,SAAY,CAC/B,QAAQ,IAAIC,EAAAA,qBAAqB,MAAM,EAAS,MAAM,EAC3D,MAAM,EAAU,YAAY,mCAAoC,CAAE,QAAS,QAAS,CAAC,EACrF,MAAM,EAAU,SAAS,CAC3B,CAAC,CACH"}
1
+ {"version":3,"file":"extension.cjs","names":["createFileEditContainer","createDoomTelemetry","SUBAGENT_CHILD_ENV","Context","registerDoomLeaderContribution"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { SUBAGENT_CHILD_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { type DoomLeaderContribution, registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createFileEditContainer } from '../../container/index.ts';\n\nconst FILES_COMMAND = 'file-edits';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-file-edit';\n\nexport const FILE_EDIT_LEADER_CONTRIBUTION = {\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: 'editor.files',\n path: [\n { key: 'e', label: 'extension', order: 50 },\n { key: 'f', label: 'files', detail: 'session edits' },\n ],\n command: { name: FILES_COMMAND },\n },\n ],\n} as const;\n\n/** Install File Edit resources into one package-local Cordis root. */\nexport function installFileEditRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.effect(function* () {\n const { paths, timeline, editTracker: tracker, workflow } = createFileEditContainer();\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: 'doom-file-edit',\n packageName: PACKAGE_SOURCE,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n\n yield async () => {\n active = false;\n sessionGeneration += 1;\n toolStartedAt.clear();\n try {\n if (!process.env[SUBAGENT_CHILD_ENV]) await timeline.clear();\n await telemetry.recordEvent('doom_file_edit.timeline_finished', { outcome: 'closed' });\n } finally {\n await telemetry.shutdown();\n }\n };\n\n pi.registerCommand(FILES_COMMAND, {\n description: 'Review files edited in this session',\n handler: async (_args, ctx) => {\n if (!active) return;\n if (!ctx.hasUI) {\n ctx.ui.notify('/file-edits requires interactive mode', 'error');\n return;\n }\n await workflow.open(ctx);\n },\n });\n\n pi.on('session_start', (_event, ctx) => {\n if (!active) return;\n sessionGeneration += 1;\n toolStartedAt.clear();\n const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());\n timeline.initialize(paths.timelinePath(ctx.cwd, sessionKey));\n void telemetry.recordEvent('doom_file_edit.timeline_started', { outcome: 'initialized' });\n });\n pi.on('tool_execution_start', async (event, ctx) => {\n if (!active) return;\n const ownGeneration = sessionGeneration;\n toolStartedAt.set(event.toolCallId, Date.now());\n await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);\n if (!active || ownGeneration !== sessionGeneration) {\n toolStartedAt.delete(event.toolCallId);\n return;\n }\n void telemetry.recordEvent('doom_file_edit.edit_started', { 'tool.name': event.toolName });\n });\n pi.on('tool_execution_end', async (event) => {\n if (!active) return;\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n await tracker.end(event.toolCallId, event.isError);\n if (!active) return;\n void telemetry.recordEvent('doom_file_edit.edit_finished', {\n 'tool.name': event.toolName,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { duration_ms: Date.now() - startedAt }),\n outcome: event.isError ? 'failed' : 'completed',\n });\n });\n }, `${PACKAGE_SOURCE}/runtime`);\n}\n\n/** The package's single standard Pi factory. */\nexport async function fileEditExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n installFileEditRuntime(cordis, pi);\n cordis.effect(\n () => registerDoomLeaderContribution(pi, FILE_EDIT_LEADER_CONTRIBUTION satisfies DoomLeaderContribution),\n `${PACKAGE_SOURCE}/leader`,\n );\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on('session_shutdown', dispose);\n}\n"],"mappings":"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"}
@@ -1,6 +1,8 @@
1
+ import "@deepseek-ai/cordis";
1
2
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
3
  //#region src/adapters/pi/extension.d.ts
3
- declare function fileEditExtension(pi: ExtensionAPI): void;
4
+ /** The package's single standard Pi factory. */
5
+ declare function fileEditExtension(pi: ExtensionAPI): Promise<void>;
4
6
  //#endregion
5
7
  export { fileEditExtension };
6
8
  //# sourceMappingURL=extension.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;iBA0BgB,kBAAkB,IAAI"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmGsB,kBAAkB,IAAI,eAAe"}
@@ -1,6 +1,8 @@
1
+ import { Context } from "@deepseek-ai/cordis";
1
2
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
3
  //#region src/adapters/pi/extension.d.ts
3
- declare function fileEditExtension(pi: ExtensionAPI): void;
4
+ /** The package's single standard Pi factory. */
5
+ declare function fileEditExtension(pi: ExtensionAPI): Promise<void>;
4
6
  //#endregion
5
7
  export { fileEditExtension };
6
8
  //# sourceMappingURL=extension.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;iBA0BgB,kBAAkB,IAAI"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmGsB,kBAAkB,IAAI,eAAe"}
@@ -1,2 +1,2 @@
1
- import{FILE_EDIT_TYPES as e}from"../../types/index.mjs";import{createFileEditContainer as t}from"../../container/index.mjs";import{SUBAGENT_CHILD_ENV as n}from"@agimon-ai/doompi-extension-contracts/child-process";import{createDoomTelemetry as r}from"@agimon-ai/doompi-telemetry";const i=`file-edits`,a={source:`@agimon-ai/doompi-file-edit`,bindings:[{id:`editor.files`,path:[{key:`e`,label:`extension`,order:50},{key:`f`,label:`files`,detail:`session edits`}],command:{name:i}}]};function o(a){let o=t(),s=o.get(e.Paths),c=o.get(e.TimelineStore),l=o.get(e.EditTracker),u=o.get(e.Workflow),d=r({serviceName:`doom-file-edit`,packageName:`@agimon-ai/doompi-file-edit`,env:process.env,enableLogs:!0,enableTraces:!0}),f=new Map;a.registerCommand(i,{description:`Review files edited in this session`,handler:async(e,t)=>{if(!t.hasUI){t.ui.notify(`/file-edits requires interactive mode`,`error`);return}await u.open(t)}}),a.on(`session_start`,async(e,t)=>{let n=s.sessionKey(t.sessionManager.getSessionId());c.initialize(s.timelinePath(t.cwd,n)),d.recordEvent(`doom_file_edit.timeline_started`,{outcome:`initialized`})}),a.on(`tool_execution_start`,async(e,t)=>{f.set(e.toolCallId,Date.now()),await l.start(e.toolCallId,e.toolName,e.args,t.cwd),d.recordEvent(`doom_file_edit.edit_started`,{"tool.name":e.toolName})}),a.on(`tool_execution_end`,async e=>{let t=f.get(e.toolCallId);f.delete(e.toolCallId),await l.end(e.toolCallId,e.isError),d.recordEvent(`doom_file_edit.edit_finished`,{"tool.name":e.toolName,"tool.result.error":e.isError,...t===void 0?{}:{duration_ms:Date.now()-t},outcome:e.isError?`failed`:`completed`})}),a.on(`session_shutdown`,async()=>{process.env[n]||await c.clear(),await d.recordEvent(`doom_file_edit.timeline_finished`,{outcome:`closed`}),await d.shutdown()})}export{a as FILE_EDIT_LEADER_CONTRIBUTION,o as fileEditExtension};
1
+ import{createFileEditContainer as e}from"../../container/index.mjs";import{SUBAGENT_CHILD_ENV as t}from"@agimon-ai/doompi-extension-contracts/child-process";import{createDoomTelemetry as n}from"@agimon-ai/doompi-telemetry";import{registerDoomLeaderContribution as r}from"@agimon-ai/doompi-ui/leader";import{Context as i}from"@deepseek-ai/cordis";const a=`file-edits`,o=`@agimon-ai/doompi-file-edit`,s={source:o,bindings:[{id:`editor.files`,path:[{key:`e`,label:`extension`,order:50},{key:`f`,label:`files`,detail:`session edits`}],command:{name:a}}]};function c(r,i){r.effect(function*(){let{paths:r,timeline:s,editTracker:c,workflow:l}=e(),u=n({serviceName:`doom-file-edit`,packageName:o,env:process.env,enableLogs:!0,enableTraces:!0}),d=new Map,f=!0,p=0;yield async()=>{f=!1,p+=1,d.clear();try{process.env[t]||await s.clear(),await u.recordEvent(`doom_file_edit.timeline_finished`,{outcome:`closed`})}finally{await u.shutdown()}},i.registerCommand(a,{description:`Review files edited in this session`,handler:async(e,t)=>{if(f){if(!t.hasUI){t.ui.notify(`/file-edits requires interactive mode`,`error`);return}await l.open(t)}}}),i.on(`session_start`,(e,t)=>{if(!f)return;p+=1,d.clear();let n=r.sessionKey(t.sessionManager.getSessionId());s.initialize(r.timelinePath(t.cwd,n)),u.recordEvent(`doom_file_edit.timeline_started`,{outcome:`initialized`})}),i.on(`tool_execution_start`,async(e,t)=>{if(!f)return;let n=p;if(d.set(e.toolCallId,Date.now()),await c.start(e.toolCallId,e.toolName,e.args,t.cwd),!f||n!==p){d.delete(e.toolCallId);return}u.recordEvent(`doom_file_edit.edit_started`,{"tool.name":e.toolName})}),i.on(`tool_execution_end`,async e=>{if(!f)return;let t=d.get(e.toolCallId);d.delete(e.toolCallId),await c.end(e.toolCallId,e.isError),f&&u.recordEvent(`doom_file_edit.edit_finished`,{"tool.name":e.toolName,"tool.result.error":e.isError,...t===void 0?{}:{duration_ms:Date.now()-t},outcome:e.isError?`failed`:`completed`})})},`${o}/runtime`)}async function l(e){let t=new i,n,a=()=>(n??=t.fiber.dispose(),n);try{c(t,e),t.effect(()=>r(e,s),`${o}/leader`)}catch(e){throw await a(),e}e.on(`session_shutdown`,a)}export{s as FILE_EDIT_LEADER_CONTRIBUTION,l as fileEditExtension,c as installFileEditRuntime};
2
2
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { SUBAGENT_CHILD_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createFileEditContainer } from '../../container/index.ts';\nimport type { IEditTracker } from '../../services/EditTracker/types.ts';\nimport type { IFileEditPaths } from '../../services/FileEditPaths/types.ts';\nimport type { IFileEditWorkflow } from '../../services/FileEditWorkflow/types.ts';\nimport type { ITimelineStore } from '../../services/TimelineStore/types.ts';\nimport { FILE_EDIT_TYPES } from '../../types/index.ts';\n\nconst FILES_COMMAND = 'file-edits';\n\nexport const FILE_EDIT_LEADER_CONTRIBUTION = {\n source: '@agimon-ai/doompi-file-edit',\n bindings: [\n {\n id: 'editor.files',\n path: [\n { key: 'e', label: 'extension', order: 50 },\n { key: 'f', label: 'files', detail: 'session edits' },\n ],\n command: { name: FILES_COMMAND },\n },\n ],\n} as const;\n\nexport function fileEditExtension(pi: ExtensionAPI): void {\n const container = createFileEditContainer();\n const paths = container.get<IFileEditPaths>(FILE_EDIT_TYPES.Paths);\n const timeline = container.get<ITimelineStore>(FILE_EDIT_TYPES.TimelineStore);\n const tracker = container.get<IEditTracker>(FILE_EDIT_TYPES.EditTracker);\n const workflow = container.get<IFileEditWorkflow>(FILE_EDIT_TYPES.Workflow);\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: 'doom-file-edit',\n packageName: '@agimon-ai/doompi-file-edit',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const toolStartedAt = new Map<string, number>();\n\n pi.registerCommand(FILES_COMMAND, {\n description: 'Review files edited in this session',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify('/file-edits requires interactive mode', 'error');\n return;\n }\n await workflow.open(ctx);\n },\n });\n\n pi.on('session_start', async (_event, ctx) => {\n const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());\n timeline.initialize(paths.timelinePath(ctx.cwd, sessionKey));\n void telemetry.recordEvent('doom_file_edit.timeline_started', { outcome: 'initialized' });\n });\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);\n void telemetry.recordEvent('doom_file_edit.edit_started', { 'tool.name': event.toolName });\n });\n pi.on('tool_execution_end', async (event) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n await tracker.end(event.toolCallId, event.isError);\n void telemetry.recordEvent('doom_file_edit.edit_finished', {\n 'tool.name': event.toolName,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { duration_ms: Date.now() - startedAt }),\n outcome: event.isError ? 'failed' : 'completed',\n });\n });\n pi.on('session_shutdown', async () => {\n if (!process.env[SUBAGENT_CHILD_ENV]) await timeline.clear();\n await telemetry.recordEvent('doom_file_edit.timeline_finished', { outcome: 'closed' });\n await telemetry.shutdown();\n });\n}\n"],"mappings":"uRAUA,MAAM,EAAgB,aAET,EAAgC,CAC3C,OAAQ,8BACR,SAAU,CACR,CACE,GAAI,eACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,EAAG,EAC1C,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,eAAgB,CACtD,EACA,QAAS,CAAE,KAAM,CAAc,CACjC,CACF,CACF,EAEA,SAAgB,EAAkB,EAAwB,CACxD,IAAM,EAAY,EAAwB,EACpC,EAAQ,EAAU,IAAoB,EAAgB,KAAK,EAC3D,EAAW,EAAU,IAAoB,EAAgB,aAAa,EACtE,EAAU,EAAU,IAAkB,EAAgB,WAAW,EACjE,EAAW,EAAU,IAAuB,EAAgB,QAAQ,EACpE,EAA2B,EAAoB,CACnD,YAAa,iBACb,YAAa,8BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAgB,IAAI,IAE1B,EAAG,gBAAgB,EAAe,CAChC,YAAa,sCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,wCAAyC,OAAO,EAC9D,MACF,CACA,MAAM,EAAS,KAAK,CAAG,CACzB,CACF,CAAC,EAED,EAAG,GAAG,gBAAiB,MAAO,EAAQ,IAAQ,CAC5C,IAAM,EAAa,EAAM,WAAW,EAAI,eAAe,aAAa,CAAC,EACrE,EAAS,WAAW,EAAM,aAAa,EAAI,IAAK,CAAU,CAAC,EAC3D,EAAe,YAAY,kCAAmC,CAAE,QAAS,aAAc,CAAC,CAC1F,CAAC,EACD,EAAG,GAAG,uBAAwB,MAAO,EAAO,IAAQ,CAClD,EAAc,IAAI,EAAM,WAAY,KAAK,IAAI,CAAC,EAC9C,MAAM,EAAQ,MAAM,EAAM,WAAY,EAAM,SAAU,EAAM,KAAM,EAAI,GAAG,EACzE,EAAe,YAAY,8BAA+B,CAAE,YAAa,EAAM,QAAS,CAAC,CAC3F,CAAC,EACD,EAAG,GAAG,qBAAsB,KAAO,IAAU,CAC3C,IAAM,EAAY,EAAc,IAAI,EAAM,UAAU,EACpD,EAAc,OAAO,EAAM,UAAU,EACrC,MAAM,EAAQ,IAAI,EAAM,WAAY,EAAM,OAAO,EACjD,EAAe,YAAY,+BAAgC,CACzD,YAAa,EAAM,SACnB,oBAAqB,EAAM,QAC3B,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,EACzE,QAAS,EAAM,QAAU,SAAW,WACtC,CAAC,CACH,CAAC,EACD,EAAG,GAAG,mBAAoB,SAAY,CAC/B,QAAQ,IAAI,IAAqB,MAAM,EAAS,MAAM,EAC3D,MAAM,EAAU,YAAY,mCAAoC,CAAE,QAAS,QAAS,CAAC,EACrF,MAAM,EAAU,SAAS,CAC3B,CAAC,CACH"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { SUBAGENT_CHILD_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { type DoomLeaderContribution, registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createFileEditContainer } from '../../container/index.ts';\n\nconst FILES_COMMAND = 'file-edits';\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-file-edit';\n\nexport const FILE_EDIT_LEADER_CONTRIBUTION = {\n source: PACKAGE_SOURCE,\n bindings: [\n {\n id: 'editor.files',\n path: [\n { key: 'e', label: 'extension', order: 50 },\n { key: 'f', label: 'files', detail: 'session edits' },\n ],\n command: { name: FILES_COMMAND },\n },\n ],\n} as const;\n\n/** Install File Edit resources into one package-local Cordis root. */\nexport function installFileEditRuntime(cordis: Context, pi: ExtensionAPI): void {\n cordis.effect(function* () {\n const { paths, timeline, editTracker: tracker, workflow } = createFileEditContainer();\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: 'doom-file-edit',\n packageName: PACKAGE_SOURCE,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n\n yield async () => {\n active = false;\n sessionGeneration += 1;\n toolStartedAt.clear();\n try {\n if (!process.env[SUBAGENT_CHILD_ENV]) await timeline.clear();\n await telemetry.recordEvent('doom_file_edit.timeline_finished', { outcome: 'closed' });\n } finally {\n await telemetry.shutdown();\n }\n };\n\n pi.registerCommand(FILES_COMMAND, {\n description: 'Review files edited in this session',\n handler: async (_args, ctx) => {\n if (!active) return;\n if (!ctx.hasUI) {\n ctx.ui.notify('/file-edits requires interactive mode', 'error');\n return;\n }\n await workflow.open(ctx);\n },\n });\n\n pi.on('session_start', (_event, ctx) => {\n if (!active) return;\n sessionGeneration += 1;\n toolStartedAt.clear();\n const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());\n timeline.initialize(paths.timelinePath(ctx.cwd, sessionKey));\n void telemetry.recordEvent('doom_file_edit.timeline_started', { outcome: 'initialized' });\n });\n pi.on('tool_execution_start', async (event, ctx) => {\n if (!active) return;\n const ownGeneration = sessionGeneration;\n toolStartedAt.set(event.toolCallId, Date.now());\n await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);\n if (!active || ownGeneration !== sessionGeneration) {\n toolStartedAt.delete(event.toolCallId);\n return;\n }\n void telemetry.recordEvent('doom_file_edit.edit_started', { 'tool.name': event.toolName });\n });\n pi.on('tool_execution_end', async (event) => {\n if (!active) return;\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n await tracker.end(event.toolCallId, event.isError);\n if (!active) return;\n void telemetry.recordEvent('doom_file_edit.edit_finished', {\n 'tool.name': event.toolName,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { duration_ms: Date.now() - startedAt }),\n outcome: event.isError ? 'failed' : 'completed',\n });\n });\n }, `${PACKAGE_SOURCE}/runtime`);\n}\n\n/** The package's single standard Pi factory. */\nexport async function fileEditExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n installFileEditRuntime(cordis, pi);\n cordis.effect(\n () => registerDoomLeaderContribution(pi, FILE_EDIT_LEADER_CONTRIBUTION satisfies DoomLeaderContribution),\n `${PACKAGE_SOURCE}/leader`,\n );\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on('session_shutdown', dispose);\n}\n"],"mappings":"0VAOA,MAAM,EAAgB,aAChB,EAAiB,8BAEV,EAAgC,CAC3C,OAAQ,EACR,SAAU,CACR,CACE,GAAI,eACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,EAAG,EAC1C,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,eAAgB,CACtD,EACA,QAAS,CAAE,KAAM,CAAc,CACjC,CACF,CACF,EAGA,SAAgB,EAAuB,EAAiB,EAAwB,CAC9E,EAAO,OAAO,WAAa,CACzB,GAAM,CAAE,QAAO,WAAU,YAAa,EAAS,YAAa,EAAwB,EAC9E,EAA2B,EAAoB,CACnD,YAAa,iBACb,YAAa,EACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAgB,IAAI,IACtB,EAAS,GACT,EAAoB,EAExB,MAAM,SAAY,CAChB,EAAS,GACT,GAAqB,EACrB,EAAc,MAAM,EACpB,GAAI,CACG,QAAQ,IAAI,IAAqB,MAAM,EAAS,MAAM,EAC3D,MAAM,EAAU,YAAY,mCAAoC,CAAE,QAAS,QAAS,CAAC,CACvF,QAAU,CACR,MAAM,EAAU,SAAS,CAC3B,CACF,EAEA,EAAG,gBAAgB,EAAe,CAChC,YAAa,sCACb,QAAS,MAAO,EAAO,IAAQ,CACxB,KACL,IAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,wCAAyC,OAAO,EAC9D,MACF,CACA,MAAM,EAAS,KAAK,CAAG,CADvB,CAEF,CACF,CAAC,EAED,EAAG,GAAG,iBAAkB,EAAQ,IAAQ,CACtC,GAAI,CAAC,EAAQ,OACb,GAAqB,EACrB,EAAc,MAAM,EACpB,IAAM,EAAa,EAAM,WAAW,EAAI,eAAe,aAAa,CAAC,EACrE,EAAS,WAAW,EAAM,aAAa,EAAI,IAAK,CAAU,CAAC,EAC3D,EAAe,YAAY,kCAAmC,CAAE,QAAS,aAAc,CAAC,CAC1F,CAAC,EACD,EAAG,GAAG,uBAAwB,MAAO,EAAO,IAAQ,CAClD,GAAI,CAAC,EAAQ,OACb,IAAM,EAAgB,EAGtB,GAFA,EAAc,IAAI,EAAM,WAAY,KAAK,IAAI,CAAC,EAC9C,MAAM,EAAQ,MAAM,EAAM,WAAY,EAAM,SAAU,EAAM,KAAM,EAAI,GAAG,EACrE,CAAC,GAAU,IAAkB,EAAmB,CAClD,EAAc,OAAO,EAAM,UAAU,EACrC,MACF,CACA,EAAe,YAAY,8BAA+B,CAAE,YAAa,EAAM,QAAS,CAAC,CAC3F,CAAC,EACD,EAAG,GAAG,qBAAsB,KAAO,IAAU,CAC3C,GAAI,CAAC,EAAQ,OACb,IAAM,EAAY,EAAc,IAAI,EAAM,UAAU,EACpD,EAAc,OAAO,EAAM,UAAU,EACrC,MAAM,EAAQ,IAAI,EAAM,WAAY,EAAM,OAAO,EAC5C,GACL,EAAe,YAAY,+BAAgC,CACzD,YAAa,EAAM,SACnB,oBAAqB,EAAM,QAC3B,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,EACzE,QAAS,EAAM,QAAU,SAAW,WACtC,CAAC,CACH,CAAC,CACH,EAAG,GAAG,EAAe,SAAS,CAChC,CAGA,eAAsB,EAAkB,EAAiC,CACvE,IAAM,EAAS,IAAI,EACf,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAuB,EAAQ,CAAE,EACjC,EAAO,WACC,EAA+B,EAAI,CAA8D,EACvG,GAAG,EAAe,QACpB,CACF,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAoB,CAAO,CACnC"}
@@ -1,2 +1,2 @@
1
- const e=require("../services/EditorConfigService/EditorConfigService.cjs"),t=require("../types/index.cjs"),n=require("../services/EditorLauncher/EditorLauncher.cjs"),r=require("../services/EditTracker/EditTracker.cjs"),i=require("../services/FileEditPaths/FileEditPaths.cjs"),a=require("../services/FileEditWorkflow/FileEditWorkflow.cjs"),o=require("../services/GitDiffService/GitDiffService.cjs"),s=require("../services/TimelineStore/TimelineStore.cjs");let c=require("inversify");require("reflect-metadata/lite");function l(){let l=new c.Container;return l.bind(t.FILE_EDIT_TYPES.Paths).to(i.FileEditPaths).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.TimelineStore).to(s.TimelineStore).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.GitDiffService).to(o.GitDiffService).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.EditTracker).to(r.EditTracker).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.EditorConfigService).to(e.EditorConfigService).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.EditorLauncher).to(n.EditorLauncher).inSingletonScope(),l.bind(t.FILE_EDIT_TYPES.Workflow).to(a.FileEditWorkflow).inSingletonScope(),l}exports.createFileEditContainer=l;
1
+ const e=require("../adapters/EditorConfigService/EditorConfigService.cjs"),t=require("../adapters/EditorLauncher/EditorLauncher.cjs"),n=require("../adapters/EditTracker/EditTracker.cjs"),r=require("../adapters/FileEditPaths/FileEditPaths.cjs"),i=require("../tui/fileEditWorkflow.cjs"),a=require("../adapters/GitDiffService/GitDiffService.cjs"),o=require("../adapters/TimelineStore/TimelineStore.cjs");function s(s={}){let c=s.paths??new r.FileEditPaths,l=s.timeline??new o.TimelineStore,u=s.diffs??new a.GitDiffService,d=s.editorConfig??new e.EditorConfigService,f=s.editTracker??new n.EditTracker(l),p=s.editorLauncher??new t.EditorLauncher(d);return{paths:c,timeline:l,diffs:u,editorConfig:d,editTracker:f,editorLauncher:p,workflow:s.workflow??new i.FileEditWorkflow(l,u,d,p)}}exports.createFileEditContainer=s;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Container","FILE_EDIT_TYPES","FileEditPaths","TimelineStore","GitDiffService","EditTracker","EditorConfigService","EditorLauncher","FileEditWorkflow"],"sources":["../../src/container/index.ts"],"sourcesContent":["import { Container } from 'inversify';\nimport 'reflect-metadata/lite';\nimport { EditorConfigService } from '../services/EditorConfigService/EditorConfigService.ts';\nimport type { IEditorConfigService } from '../services/EditorConfigService/types.ts';\nimport { EditorLauncher } from '../services/EditorLauncher/EditorLauncher.ts';\nimport type { IEditorLauncher } from '../services/EditorLauncher/types.ts';\nimport { EditTracker } from '../services/EditTracker/EditTracker.ts';\nimport type { IEditTracker } from '../services/EditTracker/types.ts';\nimport { FileEditPaths } from '../services/FileEditPaths/FileEditPaths.ts';\nimport type { IFileEditPaths } from '../services/FileEditPaths/types.ts';\nimport { FileEditWorkflow } from '../services/FileEditWorkflow/FileEditWorkflow.ts';\nimport type { IFileEditWorkflow } from '../services/FileEditWorkflow/types.ts';\nimport { GitDiffService } from '../services/GitDiffService/GitDiffService.ts';\nimport type { IGitDiffService } from '../services/GitDiffService/types.ts';\nimport { TimelineStore } from '../services/TimelineStore/TimelineStore.ts';\nimport type { ITimelineStore } from '../services/TimelineStore/types.ts';\nimport { FILE_EDIT_TYPES } from '../types/index.ts';\n\nexport function createFileEditContainer(): Container {\n const container = new Container();\n container.bind<IFileEditPaths>(FILE_EDIT_TYPES.Paths).to(FileEditPaths).inSingletonScope();\n container.bind<ITimelineStore>(FILE_EDIT_TYPES.TimelineStore).to(TimelineStore).inSingletonScope();\n container.bind<IGitDiffService>(FILE_EDIT_TYPES.GitDiffService).to(GitDiffService).inSingletonScope();\n container.bind<IEditTracker>(FILE_EDIT_TYPES.EditTracker).to(EditTracker).inSingletonScope();\n container.bind<IEditorConfigService>(FILE_EDIT_TYPES.EditorConfigService).to(EditorConfigService).inSingletonScope();\n container.bind<IEditorLauncher>(FILE_EDIT_TYPES.EditorLauncher).to(EditorLauncher).inSingletonScope();\n container.bind<IFileEditWorkflow>(FILE_EDIT_TYPES.Workflow).to(FileEditWorkflow).inSingletonScope();\n return container;\n}\n"],"mappings":"mgBAkBA,SAAgB,GAAqC,CACnD,IAAM,EAAY,IAAIA,EAAAA,UAQtB,OAPA,EAAU,KAAqBC,EAAAA,gBAAgB,KAAK,CAAC,CAAC,GAAGC,EAAAA,aAAa,CAAC,CAAC,iBAAiB,EACzF,EAAU,KAAqBD,EAAAA,gBAAgB,aAAa,CAAC,CAAC,GAAGE,EAAAA,aAAa,CAAC,CAAC,iBAAiB,EACjG,EAAU,KAAsBF,EAAAA,gBAAgB,cAAc,CAAC,CAAC,GAAGG,EAAAA,cAAc,CAAC,CAAC,iBAAiB,EACpG,EAAU,KAAmBH,EAAAA,gBAAgB,WAAW,CAAC,CAAC,GAAGI,EAAAA,WAAW,CAAC,CAAC,iBAAiB,EAC3F,EAAU,KAA2BJ,EAAAA,gBAAgB,mBAAmB,CAAC,CAAC,GAAGK,EAAAA,mBAAmB,CAAC,CAAC,iBAAiB,EACnH,EAAU,KAAsBL,EAAAA,gBAAgB,cAAc,CAAC,CAAC,GAAGM,EAAAA,cAAc,CAAC,CAAC,iBAAiB,EACpG,EAAU,KAAwBN,EAAAA,gBAAgB,QAAQ,CAAC,CAAC,GAAGO,EAAAA,gBAAgB,CAAC,CAAC,iBAAiB,EAC3F,CACT"}
1
+ {"version":3,"file":"index.cjs","names":["FileEditPaths","TimelineStore","GitDiffService","EditorConfigService","EditTracker","EditorLauncher","FileEditWorkflow"],"sources":["../../src/container/index.ts"],"sourcesContent":["import { EditorConfigService } from '../adapters/EditorConfigService/EditorConfigService';\nimport { EditorLauncher } from '../adapters/EditorLauncher/EditorLauncher';\nimport { EditTracker } from '../adapters/EditTracker/EditTracker';\nimport { FileEditPaths } from '../adapters/FileEditPaths/FileEditPaths';\nimport { FileEditWorkflow } from '../tui/fileEditWorkflow';\nimport { GitDiffService } from '../adapters/GitDiffService/GitDiffService';\nimport { TimelineStore } from '../adapters/TimelineStore/TimelineStore';\nimport type { FileEditDependencies } from '../types';\n\n/**\n * Compose the file-edit runtime.\n *\n * Construction order is the dependency order, so the graph is readable top to\n * bottom and a cycle is a compile error rather than a resolution failure at\n * runtime. Pass overrides to substitute a double in tests.\n */\nexport function createFileEditContainer(overrides: Partial<FileEditDependencies> = {}): FileEditDependencies {\n const paths = overrides.paths ?? new FileEditPaths();\n const timeline = overrides.timeline ?? new TimelineStore();\n const diffs = overrides.diffs ?? new GitDiffService();\n const editorConfig = overrides.editorConfig ?? new EditorConfigService();\n const editTracker = overrides.editTracker ?? new EditTracker(timeline);\n const editorLauncher = overrides.editorLauncher ?? new EditorLauncher(editorConfig);\n const workflow = overrides.workflow ?? new FileEditWorkflow(timeline, diffs, editorConfig, editorLauncher);\n\n return { paths, timeline, diffs, editorConfig, editTracker, editorLauncher, workflow };\n}\n"],"mappings":"iZAgBA,SAAgB,EAAwB,EAA2C,CAAC,EAAyB,CAC3G,IAAM,EAAQ,EAAU,OAAS,IAAIA,EAAAA,cAC/B,EAAW,EAAU,UAAY,IAAIC,EAAAA,cACrC,EAAQ,EAAU,OAAS,IAAIC,EAAAA,eAC/B,EAAe,EAAU,cAAgB,IAAIC,EAAAA,oBAC7C,EAAc,EAAU,aAAe,IAAIC,EAAAA,YAAY,CAAQ,EAC/D,EAAiB,EAAU,gBAAkB,IAAIC,EAAAA,eAAe,CAAY,EAGlF,MAAO,CAAE,QAAO,WAAU,QAAO,eAAc,cAAa,iBAAgB,SAF3D,EAAU,UAAY,IAAIC,EAAAA,iBAAiB,EAAU,EAAO,EAAc,CAAc,CAEpB,CACvF"}
@@ -1,7 +1,13 @@
1
- import { Container } from "inversify";
2
- import "reflect-metadata/lite";
1
+ import { FileEditDependencies } from "../types/index.cjs";
3
2
  //#region src/container/index.d.ts
4
- declare function createFileEditContainer(): Container;
3
+ /**
4
+ * Compose the file-edit runtime.
5
+ *
6
+ * Construction order is the dependency order, so the graph is readable top to
7
+ * bottom and a cycle is a compile error rather than a resolution failure at
8
+ * runtime. Pass overrides to substitute a double in tests.
9
+ */
10
+ declare function createFileEditContainer(overrides?: Partial<FileEditDependencies>): FileEditDependencies;
5
11
  //#endregion
6
12
  export { createFileEditContainer };
7
13
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/container/index.ts"],"mappings":";;;iBAkBgB,2BAA2B"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/container/index.ts"],"mappings":";;;;;;;;;iBAgBgB,wBAAwB,YAAW,QAAQ,wBAA6B"}
@@ -1,7 +1,13 @@
1
- import { Container } from "inversify";
2
- import "reflect-metadata/lite";
1
+ import { FileEditDependencies } from "../types/index.mjs";
3
2
  //#region src/container/index.d.ts
4
- declare function createFileEditContainer(): Container;
3
+ /**
4
+ * Compose the file-edit runtime.
5
+ *
6
+ * Construction order is the dependency order, so the graph is readable top to
7
+ * bottom and a cycle is a compile error rather than a resolution failure at
8
+ * runtime. Pass overrides to substitute a double in tests.
9
+ */
10
+ declare function createFileEditContainer(overrides?: Partial<FileEditDependencies>): FileEditDependencies;
5
11
  //#endregion
6
12
  export { createFileEditContainer };
7
13
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/container/index.ts"],"mappings":";;;iBAkBgB,2BAA2B"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/container/index.ts"],"mappings":";;;;;;;;;iBAgBgB,wBAAwB,YAAW,QAAQ,wBAA6B"}
@@ -1,2 +1,2 @@
1
- import{EditorConfigService as e}from"../services/EditorConfigService/EditorConfigService.mjs";import{FILE_EDIT_TYPES as t}from"../types/index.mjs";import{EditorLauncher as n}from"../services/EditorLauncher/EditorLauncher.mjs";import{EditTracker as r}from"../services/EditTracker/EditTracker.mjs";import{FileEditPaths as i}from"../services/FileEditPaths/FileEditPaths.mjs";import{FileEditWorkflow as a}from"../services/FileEditWorkflow/FileEditWorkflow.mjs";import{GitDiffService as o}from"../services/GitDiffService/GitDiffService.mjs";import{TimelineStore as s}from"../services/TimelineStore/TimelineStore.mjs";import{Container as c}from"inversify";import"reflect-metadata/lite";function l(){let l=new c;return l.bind(t.Paths).to(i).inSingletonScope(),l.bind(t.TimelineStore).to(s).inSingletonScope(),l.bind(t.GitDiffService).to(o).inSingletonScope(),l.bind(t.EditTracker).to(r).inSingletonScope(),l.bind(t.EditorConfigService).to(e).inSingletonScope(),l.bind(t.EditorLauncher).to(n).inSingletonScope(),l.bind(t.Workflow).to(a).inSingletonScope(),l}export{l as createFileEditContainer};
1
+ import{EditorConfigService as e}from"../adapters/EditorConfigService/EditorConfigService.mjs";import{EditorLauncher as t}from"../adapters/EditorLauncher/EditorLauncher.mjs";import{EditTracker as n}from"../adapters/EditTracker/EditTracker.mjs";import{FileEditPaths as r}from"../adapters/FileEditPaths/FileEditPaths.mjs";import{FileEditWorkflow as i}from"../tui/fileEditWorkflow.mjs";import{GitDiffService as a}from"../adapters/GitDiffService/GitDiffService.mjs";import{TimelineStore as o}from"../adapters/TimelineStore/TimelineStore.mjs";function s(s={}){let c=s.paths??new r,l=s.timeline??new o,u=s.diffs??new a,d=s.editorConfig??new e,f=s.editTracker??new n(l),p=s.editorLauncher??new t(d);return{paths:c,timeline:l,diffs:u,editorConfig:d,editTracker:f,editorLauncher:p,workflow:s.workflow??new i(l,u,d,p)}}export{s as createFileEditContainer};
2
2
  //# sourceMappingURL=index.mjs.map