@agimon-ai/doompi-file-edit 0.0.1-alpha.80 → 0.0.1-alpha.81

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 (243) hide show
  1. package/dist/{src/schemas/apiContracts.cjs → apiContracts.cjs} +9 -7
  2. package/dist/apiContracts.cjs.map +1 -0
  3. package/dist/{src/schemas/apiContracts.d.mts.map → apiContracts.d.mts.map} +1 -1
  4. package/dist/{src/schemas/apiContracts.mjs → apiContracts.mjs} +2 -2
  5. package/dist/apiContracts.mjs.map +1 -0
  6. package/dist/extensions/pi.cjs +309 -14
  7. package/dist/extensions/pi.cjs.map +1 -1
  8. package/dist/extensions/pi.d.mts +1 -1
  9. package/dist/extensions/pi.d.mts.map +1 -1
  10. package/dist/extensions/pi.mjs +298 -7
  11. package/dist/extensions/pi.mjs.map +1 -1
  12. package/dist/extensions/server.cjs +610 -15
  13. package/dist/extensions/server.cjs.map +1 -1
  14. package/dist/extensions/server.d.mts +1 -1
  15. package/dist/extensions/server.d.mts.map +1 -1
  16. package/dist/extensions/server.mjs +599 -7
  17. package/dist/extensions/server.mjs.map +1 -1
  18. package/dist/fileEditDependencies-CAnZUtLx.mjs +491 -0
  19. package/dist/fileEditDependencies-CAnZUtLx.mjs.map +1 -0
  20. package/dist/fileEditDependencies-C_9BS-aJ.cjs +500 -0
  21. package/dist/fileEditDependencies-C_9BS-aJ.cjs.map +1 -0
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.d.mts +311 -4
  24. package/dist/index.d.mts.map +1 -0
  25. package/dist/index.mjs +1 -1
  26. package/dist/treeManifest-BzCs3h_c.mjs +1042 -0
  27. package/dist/treeManifest-BzCs3h_c.mjs.map +1 -0
  28. package/dist/treeManifest-CtKbEtkE.cjs +1157 -0
  29. package/dist/treeManifest-CtKbEtkE.cjs.map +1 -0
  30. package/dist/{src/services/doomIgnore/index.mjs → webFiles-Bxs3fiqe.mjs} +8 -2
  31. package/dist/webFiles-Bxs3fiqe.mjs.map +1 -0
  32. package/dist/{src/services/doomIgnore/index.cjs → webFiles-gkmgR3MY.cjs} +33 -5
  33. package/dist/webFiles-gkmgR3MY.cjs.map +1 -0
  34. package/package.json +18 -18
  35. package/dist/_virtual/_rolldown/runtime.cjs +0 -23
  36. package/dist/api-contracts.cjs +0 -7
  37. package/dist/api-contracts.d.cts +0 -2
  38. package/dist/api-contracts.d.mts +0 -2
  39. package/dist/api-contracts.mjs +0 -2
  40. package/dist/extensions/pi.d.cts +0 -5
  41. package/dist/extensions/pi.d.cts.map +0 -1
  42. package/dist/extensions/server.d.cts +0 -5
  43. package/dist/extensions/server.d.cts.map +0 -1
  44. package/dist/index.d.cts +0 -4
  45. package/dist/src/constants/package.cjs +0 -10
  46. package/dist/src/constants/package.cjs.map +0 -1
  47. package/dist/src/constants/package.mjs +0 -8
  48. package/dist/src/constants/package.mjs.map +0 -1
  49. package/dist/src/extensions/(backend)/channel/fileEdits.server.cjs +0 -9
  50. package/dist/src/extensions/(backend)/channel/fileEdits.server.cjs.map +0 -1
  51. package/dist/src/extensions/(backend)/channel/fileEdits.server.mjs +0 -10
  52. package/dist/src/extensions/(backend)/channel/fileEdits.server.mjs.map +0 -1
  53. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/piRoot.cjs +0 -15
  54. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/piRoot.cjs.map +0 -1
  55. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/piRoot.mjs +0 -15
  56. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/piRoot.mjs.map +0 -1
  57. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.cjs +0 -13
  58. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.cjs.map +0 -1
  59. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.mjs +0 -13
  60. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.mjs.map +0 -1
  61. package/dist/src/extensions/workspaces/sessions/(backend)/api/file-edits/route.server.cjs +0 -15
  62. package/dist/src/extensions/workspaces/sessions/(backend)/api/file-edits/route.server.cjs.map +0 -1
  63. package/dist/src/extensions/workspaces/sessions/(backend)/api/file-edits/route.server.mjs +0 -16
  64. package/dist/src/extensions/workspaces/sessions/(backend)/api/file-edits/route.server.mjs.map +0 -1
  65. package/dist/src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.cjs +0 -6
  66. package/dist/src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.cjs.map +0 -1
  67. package/dist/src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.mjs +0 -7
  68. package/dist/src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.mjs.map +0 -1
  69. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.cjs +0 -6
  70. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.cjs.map +0 -1
  71. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.mjs +0 -7
  72. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.mjs.map +0 -1
  73. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.cjs +0 -6
  74. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.cjs.map +0 -1
  75. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.mjs +0 -7
  76. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.mjs.map +0 -1
  77. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.cjs +0 -6
  78. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.cjs.map +0 -1
  79. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.mjs +0 -7
  80. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.mjs.map +0 -1
  81. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.cjs +0 -6
  82. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.cjs.map +0 -1
  83. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.mjs +0 -7
  84. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.mjs.map +0 -1
  85. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.server.cjs +0 -6
  86. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.server.cjs.map +0 -1
  87. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.server.mjs +0 -7
  88. package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.server.mjs.map +0 -1
  89. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs +0 -7
  90. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs.map +0 -1
  91. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs +0 -8
  92. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs.map +0 -1
  93. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs +0 -7
  94. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs.map +0 -1
  95. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs +0 -8
  96. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs.map +0 -1
  97. package/dist/src/schemas/apiContracts.cjs.map +0 -1
  98. package/dist/src/schemas/apiContracts.d.cts +0 -53
  99. package/dist/src/schemas/apiContracts.d.cts.map +0 -1
  100. package/dist/src/schemas/apiContracts.mjs.map +0 -1
  101. package/dist/src/services/commandLine/index.cjs +0 -39
  102. package/dist/src/services/commandLine/index.cjs.map +0 -1
  103. package/dist/src/services/commandLine/index.mjs +0 -37
  104. package/dist/src/services/commandLine/index.mjs.map +0 -1
  105. package/dist/src/services/doomIgnore/index.cjs.map +0 -1
  106. package/dist/src/services/doomIgnore/index.mjs.map +0 -1
  107. package/dist/src/services/editTracker/index.cjs +0 -250
  108. package/dist/src/services/editTracker/index.cjs.map +0 -1
  109. package/dist/src/services/editTracker/index.mjs +0 -248
  110. package/dist/src/services/editTracker/index.mjs.map +0 -1
  111. package/dist/src/services/editorConfigService/index.cjs +0 -42
  112. package/dist/src/services/editorConfigService/index.cjs.map +0 -1
  113. package/dist/src/services/editorConfigService/index.mjs +0 -38
  114. package/dist/src/services/editorConfigService/index.mjs.map +0 -1
  115. package/dist/src/services/editorLauncher/index.cjs +0 -92
  116. package/dist/src/services/editorLauncher/index.cjs.map +0 -1
  117. package/dist/src/services/editorLauncher/index.mjs +0 -88
  118. package/dist/src/services/editorLauncher/index.mjs.map +0 -1
  119. package/dist/src/services/fileChanges/index.cjs +0 -143
  120. package/dist/src/services/fileChanges/index.cjs.map +0 -1
  121. package/dist/src/services/fileChanges/index.mjs +0 -136
  122. package/dist/src/services/fileChanges/index.mjs.map +0 -1
  123. package/dist/src/services/fileEditPaths/index.cjs +0 -89
  124. package/dist/src/services/fileEditPaths/index.cjs.map +0 -1
  125. package/dist/src/services/fileEditPaths/index.mjs +0 -85
  126. package/dist/src/services/fileEditPaths/index.mjs.map +0 -1
  127. package/dist/src/services/fileEditRuntime/index.cjs +0 -194
  128. package/dist/src/services/fileEditRuntime/index.cjs.map +0 -1
  129. package/dist/src/services/fileEditRuntime/index.mjs +0 -190
  130. package/dist/src/services/fileEditRuntime/index.mjs.map +0 -1
  131. package/dist/src/services/fileEditSession/index.cjs +0 -110
  132. package/dist/src/services/fileEditSession/index.cjs.map +0 -1
  133. package/dist/src/services/fileEditSession/index.mjs +0 -107
  134. package/dist/src/services/fileEditSession/index.mjs.map +0 -1
  135. package/dist/src/services/fileEditsApi/index.cjs +0 -313
  136. package/dist/src/services/fileEditsApi/index.cjs.map +0 -1
  137. package/dist/src/services/fileEditsApi/index.mjs +0 -308
  138. package/dist/src/services/fileEditsApi/index.mjs.map +0 -1
  139. package/dist/src/services/gitDiffService/index.cjs +0 -114
  140. package/dist/src/services/gitDiffService/index.cjs.map +0 -1
  141. package/dist/src/services/gitDiffService/index.mjs +0 -110
  142. package/dist/src/services/gitDiffService/index.mjs.map +0 -1
  143. package/dist/src/services/gitStatus/index.cjs +0 -94
  144. package/dist/src/services/gitStatus/index.cjs.map +0 -1
  145. package/dist/src/services/gitStatus/index.mjs +0 -92
  146. package/dist/src/services/gitStatus/index.mjs.map +0 -1
  147. package/dist/src/services/lineDiff/index.cjs +0 -206
  148. package/dist/src/services/lineDiff/index.cjs.map +0 -1
  149. package/dist/src/services/lineDiff/index.mjs +0 -205
  150. package/dist/src/services/lineDiff/index.mjs.map +0 -1
  151. package/dist/src/services/sessionStateSweep/index.cjs +0 -89
  152. package/dist/src/services/sessionStateSweep/index.cjs.map +0 -1
  153. package/dist/src/services/sessionStateSweep/index.mjs +0 -85
  154. package/dist/src/services/sessionStateSweep/index.mjs.map +0 -1
  155. package/dist/src/services/snapshotStore/index.cjs +0 -87
  156. package/dist/src/services/snapshotStore/index.cjs.map +0 -1
  157. package/dist/src/services/snapshotStore/index.mjs +0 -83
  158. package/dist/src/services/snapshotStore/index.mjs.map +0 -1
  159. package/dist/src/services/timelineStore/index.cjs +0 -99
  160. package/dist/src/services/timelineStore/index.cjs.map +0 -1
  161. package/dist/src/services/timelineStore/index.mjs +0 -97
  162. package/dist/src/services/timelineStore/index.mjs.map +0 -1
  163. package/dist/src/services/treeManifest/index.cjs +0 -148
  164. package/dist/src/services/treeManifest/index.cjs.map +0 -1
  165. package/dist/src/services/treeManifest/index.mjs +0 -143
  166. package/dist/src/services/treeManifest/index.mjs.map +0 -1
  167. package/dist/src/services/webFilesChannel/index.cjs +0 -109
  168. package/dist/src/services/webFilesChannel/index.cjs.map +0 -1
  169. package/dist/src/services/webFilesChannel/index.mjs +0 -105
  170. package/dist/src/services/webFilesChannel/index.mjs.map +0 -1
  171. package/dist/src/tui/fileEditDependencies.cjs +0 -43
  172. package/dist/src/tui/fileEditDependencies.cjs.map +0 -1
  173. package/dist/src/tui/fileEditDependencies.d.cts +0 -12
  174. package/dist/src/tui/fileEditDependencies.d.cts.map +0 -1
  175. package/dist/src/tui/fileEditDependencies.d.mts +0 -12
  176. package/dist/src/tui/fileEditDependencies.d.mts.map +0 -1
  177. package/dist/src/tui/fileEditDependencies.mjs +0 -43
  178. package/dist/src/tui/fileEditDependencies.mjs.map +0 -1
  179. package/dist/src/tui/fileEditOverlay.cjs +0 -144
  180. package/dist/src/tui/fileEditOverlay.cjs.map +0 -1
  181. package/dist/src/tui/fileEditOverlay.mjs +0 -142
  182. package/dist/src/tui/fileEditOverlay.mjs.map +0 -1
  183. package/dist/src/tui/fileEditWorkflow.cjs +0 -68
  184. package/dist/src/tui/fileEditWorkflow.cjs.map +0 -1
  185. package/dist/src/tui/fileEditWorkflow.mjs +0 -68
  186. package/dist/src/tui/fileEditWorkflow.mjs.map +0 -1
  187. package/dist/src/types/apiRoutes.cjs +0 -56
  188. package/dist/src/types/apiRoutes.cjs.map +0 -1
  189. package/dist/src/types/apiRoutes.mjs +0 -56
  190. package/dist/src/types/apiRoutes.mjs.map +0 -1
  191. package/dist/src/types/domain.d.cts +0 -91
  192. package/dist/src/types/domain.d.cts.map +0 -1
  193. package/dist/src/types/domain.d.mts +0 -91
  194. package/dist/src/types/domain.d.mts.map +0 -1
  195. package/dist/src/types/editTracker.d.cts +0 -29
  196. package/dist/src/types/editTracker.d.cts.map +0 -1
  197. package/dist/src/types/editTracker.d.mts +0 -29
  198. package/dist/src/types/editTracker.d.mts.map +0 -1
  199. package/dist/src/types/editorConfigService.d.cts +0 -11
  200. package/dist/src/types/editorConfigService.d.cts.map +0 -1
  201. package/dist/src/types/editorConfigService.d.mts +0 -11
  202. package/dist/src/types/editorConfigService.d.mts.map +0 -1
  203. package/dist/src/types/editorLauncher.d.cts +0 -17
  204. package/dist/src/types/editorLauncher.d.cts.map +0 -1
  205. package/dist/src/types/editorLauncher.d.mts +0 -17
  206. package/dist/src/types/editorLauncher.d.mts.map +0 -1
  207. package/dist/src/types/fileEditPaths.d.cts +0 -20
  208. package/dist/src/types/fileEditPaths.d.cts.map +0 -1
  209. package/dist/src/types/fileEditPaths.d.mts +0 -20
  210. package/dist/src/types/fileEditPaths.d.mts.map +0 -1
  211. package/dist/src/types/fileEditWorkflow.d.cts +0 -7
  212. package/dist/src/types/fileEditWorkflow.d.cts.map +0 -1
  213. package/dist/src/types/fileEditWorkflow.d.mts +0 -7
  214. package/dist/src/types/fileEditWorkflow.d.mts.map +0 -1
  215. package/dist/src/types/fileEditsApi.cjs +0 -25
  216. package/dist/src/types/fileEditsApi.cjs.map +0 -1
  217. package/dist/src/types/fileEditsApi.mjs +0 -24
  218. package/dist/src/types/fileEditsApi.mjs.map +0 -1
  219. package/dist/src/types/gitDiffService.d.cts +0 -7
  220. package/dist/src/types/gitDiffService.d.cts.map +0 -1
  221. package/dist/src/types/gitDiffService.d.mts +0 -7
  222. package/dist/src/types/gitDiffService.d.mts.map +0 -1
  223. package/dist/src/types/index.d.cts +0 -24
  224. package/dist/src/types/index.d.cts.map +0 -1
  225. package/dist/src/types/index.d.mts +0 -24
  226. package/dist/src/types/index.d.mts.map +0 -1
  227. package/dist/src/types/snapshotStore.d.cts +0 -35
  228. package/dist/src/types/snapshotStore.d.cts.map +0 -1
  229. package/dist/src/types/snapshotStore.d.mts +0 -35
  230. package/dist/src/types/snapshotStore.d.mts.map +0 -1
  231. package/dist/src/types/timelineStore.d.cts +0 -12
  232. package/dist/src/types/timelineStore.d.cts.map +0 -1
  233. package/dist/src/types/timelineStore.d.mts +0 -12
  234. package/dist/src/types/timelineStore.d.mts.map +0 -1
  235. package/dist/src/types/treeManifest.d.cts +0 -70
  236. package/dist/src/types/treeManifest.d.cts.map +0 -1
  237. package/dist/src/types/treeManifest.d.mts +0 -70
  238. package/dist/src/types/treeManifest.d.mts.map +0 -1
  239. package/dist/src/types/webFiles.cjs +0 -10
  240. package/dist/src/types/webFiles.cjs.map +0 -1
  241. package/dist/src/types/webFiles.mjs +0 -9
  242. package/dist/src/types/webFiles.mjs.map +0 -1
  243. /package/dist/{src/schemas/apiContracts.d.mts → apiContracts.d.mts} +0 -0
@@ -1,4 +1,8 @@
1
- let _agimon_ai_doompi_core_api_contracts = require("@agimon-ai/doompi-core/api-contracts");
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let _agimon_ai_doompi_core_apiContracts = require("@agimon-ai/doompi-core/apiContracts");
2
6
  let typebox = require("typebox");
3
7
  //#region src/schemas/apiContracts.ts
4
8
  const S = typebox.Type.String();
@@ -63,7 +67,7 @@ const query = [{
63
67
  required: true,
64
68
  schema: typebox.Type.String({ minLength: 1 })
65
69
  }];
66
- const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)({
70
+ const apiContracts = (0, _agimon_ai_doompi_core_apiContracts.defineApiContract)({
67
71
  version: 1,
68
72
  dynamic: [],
69
73
  http: [
@@ -76,7 +80,7 @@ const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)
76
80
  authentication: "owner",
77
81
  description: "Read recorded changes and current file content.",
78
82
  parameters: query,
79
- responses: (0, _agimon_ai_doompi_core_api_contracts.jsonApiResponses)(FileDetailSchema)
83
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(FileDetailSchema)
80
84
  },
81
85
  {
82
86
  id: "files.preview",
@@ -87,7 +91,7 @@ const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)
87
91
  authentication: "owner",
88
92
  description: "Read a file contained in the session directory.",
89
93
  parameters: query,
90
- responses: (0, _agimon_ai_doompi_core_api_contracts.jsonApiResponses)(typebox.Type.Object({
94
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({
91
95
  path: S,
92
96
  relPath: S,
93
97
  working: Working
@@ -110,7 +114,7 @@ const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)
110
114
  content: S
111
115
  })
112
116
  },
113
- responses: (0, _agimon_ai_doompi_core_api_contracts.jsonApiResponses)(typebox.Type.Object({ hash: S }))
117
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({ hash: S }))
114
118
  },
115
119
  {
116
120
  id: "files.delete",
@@ -146,8 +150,6 @@ const apiContracts = (0, _agimon_ai_doompi_core_api_contracts.defineApiContract)
146
150
  }))
147
151
  });
148
152
  //#endregion
149
- exports.FileDetailSchema = FileDetailSchema;
150
- exports.FilesPayloadSchema = FilesPayloadSchema;
151
153
  exports.apiContracts = apiContracts;
152
154
  exports.default = apiContracts;
153
155
 
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.cjs","names":["Type","defineApiContract","jsonApiResponses"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/doompi-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst S = Type.String();\nconst N = Type.Number();\nconst B = Type.Boolean();\nconst O = Type.Optional;\nconst literals = <T extends string>(values: T[]) => Type.Union(values.map((value) => Type.Literal(value)));\nconst Tool = literals(['edit', 'write', 'bash', 'user']);\nconst Hunk = Type.Object({\n start: N,\n rows: Type.Array(Type.Object({ marker: literals(['+', '-', ' ']), line: N, content: S })),\n});\nconst Diff = { additions: N, removals: N, hunks: O(Type.Array(Hunk)), note: O(S) };\nconst Working = Type.Object({ content: S, hash: S, unavailable: B, reason: O(S) });\nexport const FileDetailSchema = Type.Object({\n path: S,\n relPath: S,\n versions: Type.Array(Type.Object({ index: N, tool: Tool, at: N, origin: literals(['tool', 'scan']), ...Diff })),\n cumulative: Type.Object(Diff),\n working: Working,\n});\nexport const FilesPayloadSchema = Type.Object({\n items: Type.Array(Type.Object({ path: S, relPath: S, tool: Tool, at: N, count: N, diffable: B })),\n});\nconst query = [{ name: 'path', in: 'query' as const, required: true, schema: Type.String({ minLength: 1 }) }];\nexport const apiContracts = defineApiContract({\n version: 1,\n dynamic: [],\n http: [\n {\n id: 'files.detail',\n scope: 'session',\n basePath: 'file-edits',\n path: '/detail',\n method: 'GET',\n authentication: 'owner',\n description: 'Read recorded changes and current file content.',\n parameters: query,\n responses: jsonApiResponses(FileDetailSchema),\n },\n {\n id: 'files.preview',\n scope: 'session',\n basePath: 'file-edits',\n path: '/preview',\n method: 'GET',\n authentication: 'owner',\n description: 'Read a file contained in the session directory.',\n parameters: query,\n responses: jsonApiResponses(Type.Object({ path: S, relPath: S, working: Working })),\n },\n {\n id: 'files.save',\n scope: 'session',\n basePath: 'file-edits',\n path: '/content',\n method: 'PUT',\n authentication: 'owner',\n description: 'Save a recorded file if its hash still matches.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ path: S, expectedHash: S, content: S }),\n },\n responses: jsonApiResponses(Type.Object({ hash: S })),\n },\n {\n id: 'files.delete',\n scope: 'session',\n basePath: 'file-edits',\n path: '/content',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Delete a recorded file.',\n parameters: query,\n responses: {\n '204': { description: 'File deleted or already absent.' },\n '404': { description: 'Unrecorded file.', schema: Type.Object({ error: S }) },\n '409': { description: 'Deletion failed.', schema: Type.Object({ error: S }) },\n },\n },\n ],\n sockets: (['global', 'workspace'] as const).map((scope) => ({\n id: 'files.channel',\n scope,\n service: 'doompi.hub.v1',\n member: 'file_edits',\n kind: 'channel',\n direction: 'server-to-client',\n description: 'File edits channel payload in the hub frame payload property.',\n input: FilesPayloadSchema,\n })),\n});\nexport default apiContracts;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../../../src/schemas/apiContracts.ts"],"mappings":";;qBA0Ba"}
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";;qBA0Ba"}
@@ -1,4 +1,4 @@
1
- import { defineApiContract, jsonApiResponses } from "@agimon-ai/doompi-core/api-contracts";
1
+ import { defineApiContract, jsonApiResponses } from "@agimon-ai/doompi-core/apiContracts";
2
2
  import { Type } from "typebox";
3
3
  //#region src/schemas/apiContracts.ts
4
4
  const S = Type.String();
@@ -146,6 +146,6 @@ const apiContracts = defineApiContract({
146
146
  }))
147
147
  });
148
148
  //#endregion
149
- export { FileDetailSchema, FilesPayloadSchema, apiContracts, apiContracts as default };
149
+ export { apiContracts, apiContracts as default };
150
150
 
151
151
  //# sourceMappingURL=apiContracts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/doompi-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst S = Type.String();\nconst N = Type.Number();\nconst B = Type.Boolean();\nconst O = Type.Optional;\nconst literals = <T extends string>(values: T[]) => Type.Union(values.map((value) => Type.Literal(value)));\nconst Tool = literals(['edit', 'write', 'bash', 'user']);\nconst Hunk = Type.Object({\n start: N,\n rows: Type.Array(Type.Object({ marker: literals(['+', '-', ' ']), line: N, content: S })),\n});\nconst Diff = { additions: N, removals: N, hunks: O(Type.Array(Hunk)), note: O(S) };\nconst Working = Type.Object({ content: S, hash: S, unavailable: B, reason: O(S) });\nexport const FileDetailSchema = Type.Object({\n path: S,\n relPath: S,\n versions: Type.Array(Type.Object({ index: N, tool: Tool, at: N, origin: literals(['tool', 'scan']), ...Diff })),\n cumulative: Type.Object(Diff),\n working: Working,\n});\nexport const FilesPayloadSchema = Type.Object({\n items: Type.Array(Type.Object({ path: S, relPath: S, tool: Tool, at: N, count: N, diffable: B })),\n});\nconst query = [{ name: 'path', in: 'query' as const, required: true, schema: Type.String({ minLength: 1 }) }];\nexport const apiContracts = defineApiContract({\n version: 1,\n dynamic: [],\n http: [\n {\n id: 'files.detail',\n scope: 'session',\n basePath: 'file-edits',\n path: '/detail',\n method: 'GET',\n authentication: 'owner',\n description: 'Read recorded changes and current file content.',\n parameters: query,\n responses: jsonApiResponses(FileDetailSchema),\n },\n {\n id: 'files.preview',\n scope: 'session',\n basePath: 'file-edits',\n path: '/preview',\n method: 'GET',\n authentication: 'owner',\n description: 'Read a file contained in the session directory.',\n parameters: query,\n responses: jsonApiResponses(Type.Object({ path: S, relPath: S, working: Working })),\n },\n {\n id: 'files.save',\n scope: 'session',\n basePath: 'file-edits',\n path: '/content',\n method: 'PUT',\n authentication: 'owner',\n description: 'Save a recorded file if its hash still matches.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ path: S, expectedHash: S, content: S }),\n },\n responses: jsonApiResponses(Type.Object({ hash: S })),\n },\n {\n id: 'files.delete',\n scope: 'session',\n basePath: 'file-edits',\n path: '/content',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Delete a recorded file.',\n parameters: query,\n responses: {\n '204': { description: 'File deleted or already absent.' },\n '404': { description: 'Unrecorded file.', schema: Type.Object({ error: S }) },\n '409': { description: 'Deletion failed.', schema: Type.Object({ error: S }) },\n },\n },\n ],\n sockets: (['global', 'workspace'] as const).map((scope) => ({\n id: 'files.channel',\n scope,\n service: 'doompi.hub.v1',\n member: 'file_edits',\n kind: 'channel',\n direction: 'server-to-client',\n description: 'File edits channel payload in the hub frame payload property.',\n input: FilesPayloadSchema,\n })),\n});\nexport default apiContracts;\n"],"mappings":"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"}
@@ -2,34 +2,329 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_root_cli = require("../src/extensions/workspaces/sessions/(backend)/root.cli.cjs");
6
- const require_file_edits_cli = require("../src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.cjs");
7
- const require_session_start_cli = require("../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.cjs");
8
- const require_tool_execution_end_cli = require("../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.cjs");
9
- const require_tool_execution_start_cli = require("../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.cjs");
10
- let _agimon_ai_doompi_core_pi_extension = require("@agimon-ai/doompi-core/pi-extension");
11
- let _agimon_ai_doompi_core_extension_file = require("@agimon-ai/doompi-core/extension-file");
5
+ const require_treeManifest = require("../treeManifest-CtKbEtkE.cjs");
6
+ const require_fileEditDependencies = require("../fileEditDependencies-C_9BS-aJ.cjs");
7
+ const require_webFiles = require("../webFiles-gkmgR3MY.cjs");
8
+ let node_fs_promises = require("node:fs/promises");
9
+ node_fs_promises = require_treeManifest.__toESM(node_fs_promises, 1);
10
+ let node_path = require("node:path");
11
+ node_path = require_treeManifest.__toESM(node_path, 1);
12
+ let node_fs = require("node:fs");
13
+ node_fs = require_treeManifest.__toESM(node_fs, 1);
14
+ let _agimon_ai_doompi_core_childProcess = require("@agimon-ai/doompi-core/childProcess");
15
+ let _agimon_ai_doompi_core_piExtension = require("@agimon-ai/doompi-core/piExtension");
16
+ let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
17
+ let _agimon_ai_doompi_core_uiHub = require("@agimon-ai/doompi-core/uiHub");
18
+ let _agimon_ai_doompi_telemetry = require("@agimon-ai/doompi-telemetry");
19
+ //#region src/constants/package.ts
20
+ const FILES_COMMAND = "file-edits";
21
+ const PACKAGE_SOURCE = "@agimon-ai/doompi-file-edit";
22
+ const DOOM_IGNORE_FILE = ".doomignore";
23
+ //#endregion
24
+ //#region src/services/sessionStateSweep/index.ts
25
+ /**
26
+ * Remove the state sessions left behind when they never got to clean up.
27
+ *
28
+ * A session clears its own timeline and snapshots on shutdown, which covers the
29
+ * ordinary case and nothing else: a killed process, a crash, or a machine that
30
+ * lost power leaves both behind, and nothing ever looked at the directory
31
+ * again. One week of that filled a real checkout with hundreds of megabytes.
32
+ *
33
+ * Age is the only signal used, because it is the only one that is true from
34
+ * another process. A running session appends as it works, so its timeline is
35
+ * recent; a dead one stops moving at the moment it died.
36
+ */
37
+ /**
38
+ * How long state may sit untouched before a later session removes it.
39
+ *
40
+ * Generous on purpose. The cost of waiting is disk, and the cost of being wrong
41
+ * is deleting a live session's history, so this is set far beyond any plausible
42
+ * gap between two appends rather than close to it.
43
+ */
44
+ const STATE_MAX_AGE_MS = 6048e5;
45
+ const TIMELINE_SUFFIX = ".jsonl";
46
+ const SNAPSHOTS_SUFFIX = ".blobs";
47
+ async function remove(target) {
48
+ await node_fs_promises.default.rm(target, {
49
+ recursive: true,
50
+ force: true
51
+ });
52
+ }
53
+ /** The most recent time anything under this session's state moved. */
54
+ async function lastTouched(paths) {
55
+ let newest;
56
+ for (const target of paths) try {
57
+ const stat = await node_fs_promises.default.stat(target);
58
+ if (newest === void 0 || stat.mtimeMs > newest) newest = stat.mtimeMs;
59
+ } catch {}
60
+ return newest;
61
+ }
62
+ /** How many sessions' worth of state was removed. */
63
+ async function sweepSessionState(options) {
64
+ const { directory, keep, removeDirectory = false, now = Date.now(), maxAgeMs = STATE_MAX_AGE_MS } = options;
65
+ let entries;
66
+ try {
67
+ entries = await node_fs_promises.default.readdir(directory);
68
+ } catch {
69
+ return 0;
70
+ }
71
+ const floor = now - maxAgeMs;
72
+ const timelines = new Set(entries.filter((entry) => entry.endsWith(TIMELINE_SUFFIX)));
73
+ let removed = 0;
74
+ for (const entry of timelines) {
75
+ const timelinePath = node_path.default.join(directory, entry);
76
+ if (keep !== void 0 && timelinePath === keep) continue;
77
+ const snapshotsPath = `${timelinePath.slice(0, -6)}${SNAPSHOTS_SUFFIX}`;
78
+ const lockPath = `${timelinePath}.lock`;
79
+ const touched = await lastTouched([
80
+ timelinePath,
81
+ snapshotsPath,
82
+ lockPath
83
+ ]);
84
+ if (touched === void 0 || touched >= floor) continue;
85
+ await remove(snapshotsPath);
86
+ await remove(timelinePath);
87
+ await remove(lockPath);
88
+ removed += 1;
89
+ }
90
+ for (const entry of entries) {
91
+ if (!entry.endsWith(SNAPSHOTS_SUFFIX)) continue;
92
+ if (timelines.has(`${entry.slice(0, -6)}${TIMELINE_SUFFIX}`)) continue;
93
+ const orphan = node_path.default.join(directory, entry);
94
+ const touched = await lastTouched([orphan]);
95
+ if (touched === void 0 || touched >= floor) continue;
96
+ await remove(orphan);
97
+ }
98
+ if (removeDirectory) try {
99
+ await node_fs_promises.default.rmdir(directory);
100
+ } catch {}
101
+ return removed;
102
+ }
103
+ //#endregion
104
+ //#region src/services/fileEditRuntime/index.ts
105
+ /**
106
+ * The project's ignore rules as a test over absolute paths, or nothing when the
107
+ * file is absent, empty, or unreadable.
108
+ *
109
+ * Read once per session, like the exclude list it is passed beside. The web
110
+ * reader re-reads the same file per request, so a mid-session edit reaches the
111
+ * list before it reaches the recorder; that is a pre-existing difference and
112
+ * not one this read introduces.
113
+ */
114
+ function readDoomIgnore(cwd) {
115
+ let content;
116
+ try {
117
+ content = node_fs.default.readFileSync(node_path.default.join(cwd, DOOM_IGNORE_FILE), "utf8");
118
+ } catch {
119
+ return;
120
+ }
121
+ const matcher = require_webFiles.createDoomIgnoreMatcher(content);
122
+ if (matcher === void 0) return void 0;
123
+ return (filePath) => matcher(node_path.default.relative(cwd, filePath));
124
+ }
125
+ const FILE_EDIT_LEADER_CONTRIBUTION = {
126
+ source: PACKAGE_SOURCE,
127
+ bindings: [{
128
+ id: "editor.files",
129
+ path: [{
130
+ key: "e",
131
+ label: "extension",
132
+ detail: "tools, skills and config",
133
+ order: 50
134
+ }, {
135
+ key: "f",
136
+ label: "files",
137
+ detail: "session edits"
138
+ }],
139
+ command: { name: FILES_COMMAND }
140
+ }]
141
+ };
142
+ function createFileEditRuntime(dependencies) {
143
+ const { paths, timeline, snapshots, editTracker: tracker, workflow } = dependencies;
144
+ const telemetry = (0, _agimon_ai_doompi_telemetry.createDoomTelemetry)({
145
+ serviceName: "doom-file-edit",
146
+ packageName: PACKAGE_SOURCE,
147
+ env: process.env,
148
+ enableLogs: true,
149
+ enableTraces: true
150
+ });
151
+ const toolStartedAt = /* @__PURE__ */ new Map();
152
+ let active = true;
153
+ let sessionGeneration = 0;
154
+ let sessionContext;
155
+ /**
156
+ * Publishes the count the cockpit's activity group keys off. The group is
157
+ * hidden until this status exists, so it is written on every append rather
158
+ * than only when the count changes.
159
+ */
160
+ const publishStatus = async () => {
161
+ if (!active || !sessionContext?.hasUI) return;
162
+ const entries = await timeline.list();
163
+ sessionContext.ui.setStatus(require_webFiles.filesStatusKey, entries.length === 0 ? "" : `${entries.length} ${entries.length === 1 ? "file" : "files"}`);
164
+ };
165
+ const dispose = async () => {
166
+ active = false;
167
+ sessionGeneration += 1;
168
+ toolStartedAt.clear();
169
+ await tracker.flush();
170
+ tracker.reset();
171
+ const closing = sessionContext;
172
+ sessionContext = void 0;
173
+ try {
174
+ if (!process.env[_agimon_ai_doompi_core_childProcess.SUBAGENT_CHILD_ENV]) {
175
+ await timeline.clear();
176
+ await snapshots.clear();
177
+ }
178
+ if (closing?.hasUI) closing.ui.setStatus(require_webFiles.filesStatusKey, void 0);
179
+ await telemetry.recordEvent("doom_file_edit.timeline_finished", { outcome: "closed" });
180
+ } finally {
181
+ await telemetry.shutdown();
182
+ }
183
+ };
184
+ /**
185
+ * Clears state no session will claim again. Never awaited and never allowed
186
+ * to throw: a sweep that cannot run is not a reason to fail a session.
187
+ */
188
+ const sweepAbandonedState = async (cwd, keep) => {
189
+ try {
190
+ await sweepSessionState({
191
+ directory: paths.stateDirectory(),
192
+ keep
193
+ });
194
+ const legacy = paths.legacyStateDirectory(cwd);
195
+ if (legacy === void 0 || legacy === paths.stateDirectory()) return;
196
+ await sweepSessionState({
197
+ directory: legacy,
198
+ removeDirectory: true
199
+ });
200
+ } catch {}
201
+ };
202
+ return {
203
+ onDispose: dispose,
204
+ services: [(cordis) => {
205
+ cordis.inject([_agimon_ai_doompi_core_uiHub.DOOM_UI_HUB_SERVICE], (uiContext) => {
206
+ const contribution = (0, _agimon_ai_doompi_core_uiHub.requireDoomUiHub)(uiContext).registerLeader(FILE_EDIT_LEADER_CONTRIBUTION);
207
+ return () => contribution.dispose();
208
+ });
209
+ }],
210
+ commands: [[FILES_COMMAND, {
211
+ description: "Review files edited in this session",
212
+ handler: async (_args, ctx) => {
213
+ if (!active) return;
214
+ if (!ctx.hasUI) {
215
+ ctx.ui.notify("/file-edits requires interactive mode", "error");
216
+ return;
217
+ }
218
+ await workflow.open(ctx);
219
+ }
220
+ }]],
221
+ events: {
222
+ session_start: (_event, ctx) => {
223
+ if (!active) return;
224
+ sessionGeneration += 1;
225
+ toolStartedAt.clear();
226
+ sessionContext = ctx;
227
+ const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());
228
+ const timelinePath = paths.timelinePath(ctx.cwd, sessionKey);
229
+ const snapshotsPath = paths.snapshotsPath(ctx.cwd, sessionKey);
230
+ timeline.initialize(timelinePath);
231
+ snapshots.initialize(snapshotsPath);
232
+ sweepAbandonedState(ctx.cwd, timelinePath);
233
+ const isIgnored = readDoomIgnore(ctx.cwd);
234
+ tracker.reset({
235
+ exclude: [
236
+ timelinePath,
237
+ `${timelinePath}.lock`,
238
+ snapshotsPath
239
+ ],
240
+ ...isIgnored === void 0 ? {} : { isIgnored }
241
+ });
242
+ publishStatus();
243
+ telemetry.recordEvent("doom_file_edit.timeline_started", { outcome: "initialized" });
244
+ },
245
+ tool_execution_start: async (event, ctx) => {
246
+ if (!active) return;
247
+ const ownGeneration = sessionGeneration;
248
+ toolStartedAt.set(event.toolCallId, Date.now());
249
+ const hookStartedAt = Date.now();
250
+ await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);
251
+ const hookMs = Date.now() - hookStartedAt;
252
+ if (!active || ownGeneration !== sessionGeneration) {
253
+ toolStartedAt.delete(event.toolCallId);
254
+ return;
255
+ }
256
+ telemetry.recordEvent("doom_file_edit.edit_started", {
257
+ "tool.name": event.toolName,
258
+ hook_ms: hookMs
259
+ });
260
+ },
261
+ tool_execution_end: async (event, ctx) => {
262
+ if (!active) return;
263
+ const startedAt = toolStartedAt.get(event.toolCallId);
264
+ toolStartedAt.delete(event.toolCallId);
265
+ const hookStartedAt = Date.now();
266
+ await tracker.end(event.toolCallId, event.isError, ctx.cwd);
267
+ if (!active) return;
268
+ await publishStatus();
269
+ const hookMs = Date.now() - hookStartedAt;
270
+ telemetry.recordEvent("doom_file_edit.edit_finished", {
271
+ "tool.name": event.toolName,
272
+ "tool.result.error": event.isError,
273
+ ...startedAt === void 0 ? {} : { duration_ms: Date.now() - startedAt },
274
+ hook_ms: hookMs,
275
+ outcome: event.isError ? "failed" : "completed"
276
+ });
277
+ }
278
+ }
279
+ };
280
+ }
281
+ //#endregion
282
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts
283
+ const createFileEditPiRoot = () => {
284
+ const runtime = createFileEditRuntime(require_fileEditDependencies.createFileEditDependencies());
285
+ return {
286
+ value: runtime,
287
+ services: runtime.services,
288
+ onDispose: runtime.onDispose
289
+ };
290
+ };
291
+ //#endregion
292
+ //#region src/extensions/workspaces/sessions/(backend)/root.cli.ts
293
+ var root_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoot)(createFileEditPiRoot);
294
+ //#endregion
295
+ //#region src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.ts
296
+ var file_edits_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoutedContribution)((context) => [context.root.commands[0]], { cardinality: "many" });
297
+ //#endregion
298
+ //#region src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.ts
299
+ var session_start_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliHook)((context) => context.root.events.session_start);
300
+ //#endregion
301
+ //#region src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.ts
302
+ var tool_execution_end_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliHook)((context) => context.root.events.tool_execution_end);
303
+ //#endregion
304
+ //#region src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.ts
305
+ var tool_execution_start_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliHook)((context) => context.root.events.tool_execution_start);
306
+ //#endregion
12
307
  //#region generated/pi.ts
13
308
  const at = (value, context) => typeof value === "function" ? value(context) : value;
14
309
  const many = (value, context) => {
15
310
  const resolved = typeof value === "function" ? value(context) : value;
16
311
  return Array.isArray(resolved) ? resolved : [resolved];
17
312
  };
18
- const extension = (0, _agimon_ai_doompi_core_pi_extension.definePiExtension)("@agimon-ai/doompi-file-edit", async (context) => {
19
- const scopeSession = await require_root_cli.default(context);
313
+ const extension = (0, _agimon_ai_doompi_core_piExtension.definePiExtension)("@agimon-ai/doompi-file-edit", async (context) => {
314
+ const scopeSession = await root_cli_default(context);
20
315
  const contextSession = {
21
316
  ...context,
22
317
  root: scopeSession.value
23
318
  };
24
319
  return {
25
- ...(0, _agimon_ai_doompi_core_extension_file.composeRootHooks)(scopeSession),
320
+ ...(0, _agimon_ai_doompi_core_extensionFile.composeRootHooks)(scopeSession),
26
321
  get commands() {
27
- return [...many(require_file_edits_cli.default, contextSession)];
322
+ return [...many(file_edits_cli_default, contextSession)];
28
323
  },
29
324
  events: {
30
- session_start: at(require_session_start_cli.default, contextSession),
31
- tool_execution_end: at(require_tool_execution_end_cli.default, contextSession),
32
- tool_execution_start: at(require_tool_execution_start_cli.default, contextSession)
325
+ session_start: at(session_start_cli_default, contextSession),
326
+ tool_execution_end: at(tool_execution_end_cli_default, contextSession),
327
+ tool_execution_start: at(tool_execution_start_cli_default, contextSession)
33
328
  },
34
329
  services: [...scopeSession.services ?? []]
35
330
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pi.cjs","names":["definePiExtension","rootSession","composeRootHooks","commandFileEdits","hookSessionStart","hookToolExecutionEnd","hookToolExecutionStart"],"sources":["../../generated/pi.ts"],"sourcesContent":["// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/pi-extension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extension-file';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandFileEdits from '../src/extensions/workspaces/sessions/(backend)/command/file-edits.cli';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli';\nimport hookToolExecutionEnd from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli';\nimport hookToolExecutionStart from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandFileEdits> | OptionsOf<typeof hookSessionStart> | OptionsOf<typeof hookToolExecutionEnd> | OptionsOf<typeof hookToolExecutionStart>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-file-edit', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandFileEdits, contextSession)]; },\n events: {\n session_start: at(hookSessionStart, contextSession) as NonNullable<PiPluginContributions['events']>['session_start'],\n tool_execution_end: at(hookToolExecutionEnd, contextSession) as NonNullable<PiPluginContributions['events']>['tool_execution_end'],\n tool_execution_start: at(hookToolExecutionStart, contextSession) as NonNullable<PiPluginContributions['events']>['tool_execution_start'],\n },\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAM,QAAc,OAA6C,YAA6B;CAC5F,MAAM,WAAW,OAAO,UAAU,aAAc,MAA4B,OAAO,IAAI;CACvF,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAa;AAC5D;AAEA,MAAa,aAAA,GAAYA,oCAAAA,kBAAAA,CAAoC,+BAA+B,OAAO,YAAY;CAC7G,MAAM,eAAe,MAAMC,iBAAAA,QAAY,OAAO;CAC9C,MAAM,iBAAiB;EAAE,GAAG;EAAS,MAAM,aAAa;CAAM;CAC9D,OAAO;EACL,IAAA,GAAGC,sCAAAA,iBAAAA,CAAiB,YAAY;EAChC,IAAI,WAA8C;GAAE,OAAO,CAAC,GAAG,KAAKC,uBAAAA,SAAkB,cAAc,CAAC;EAAG;EACxG,QAAQ;GACN,eAAe,GAAGC,0BAAAA,SAAkB,cAAc;GAClD,oBAAoB,GAAGC,+BAAAA,SAAsB,cAAc;GAC3D,sBAAsB,GAAGC,iCAAAA,SAAwB,cAAc;EACjE;EACA,UAAU,CAAC,GAAI,aAAa,YAAY,CAAC,CAAE;CAC7C;AACF,CAAC"}
1
+ {"version":3,"file":"pi.cjs","names":["fs","path","fs","path","createDoomIgnoreMatcher","createDoomTelemetry","filesStatusKey","SUBAGENT_CHILD_ENV","DOOM_UI_HUB_SERVICE","requireDoomUiHub","createFileEditDependencies","defineRoot","defineRoutedContribution","defineCliHook","defineCliHook","defineCliHook","definePiExtension","rootSession","composeRootHooks","commandFileEdits","hookSessionStart","hookToolExecutionEnd","hookToolExecutionStart"],"sources":["../../src/constants/package.ts","../../src/services/sessionStateSweep/index.ts","../../src/services/fileEditRuntime/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/piRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/file-edits.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli.ts","../../generated/pi.ts"],"sourcesContent":["export const FILES_COMMAND = 'file-edits';\nexport const PACKAGE_SOURCE = '@agimon-ai/doompi-file-edit';\nexport const DOOM_IGNORE_FILE = '.doomignore';\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/**\n * Remove the state sessions left behind when they never got to clean up.\n *\n * A session clears its own timeline and snapshots on shutdown, which covers the\n * ordinary case and nothing else: a killed process, a crash, or a machine that\n * lost power leaves both behind, and nothing ever looked at the directory\n * again. One week of that filled a real checkout with hundreds of megabytes.\n *\n * Age is the only signal used, because it is the only one that is true from\n * another process. A running session appends as it works, so its timeline is\n * recent; a dead one stops moving at the moment it died.\n */\n\n/**\n * How long state may sit untouched before a later session removes it.\n *\n * Generous on purpose. The cost of waiting is disk, and the cost of being wrong\n * is deleting a live session's history, so this is set far beyond any plausible\n * gap between two appends rather than close to it.\n */\nexport const STATE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\nconst TIMELINE_SUFFIX = '.jsonl';\nconst SNAPSHOTS_SUFFIX = '.blobs';\n\nexport interface SweepSessionStateOptions {\n directory: string;\n /** The caller's own timeline, which is never a candidate however it looks. */\n keep?: string;\n /** Remove the directory itself once nothing is left in it. */\n removeDirectory?: boolean;\n now?: number;\n maxAgeMs?: number;\n}\n\nasync function remove(target: string): Promise<void> {\n await fs.rm(target, { recursive: true, force: true });\n}\n\n/** The most recent time anything under this session's state moved. */\nasync function lastTouched(paths: readonly string[]): Promise<number | undefined> {\n let newest: number | undefined;\n for (const target of paths) {\n try {\n const stat = await fs.stat(target);\n if (newest === undefined || stat.mtimeMs > newest) newest = stat.mtimeMs;\n } catch {\n // Not there is not a reason to keep the rest.\n }\n }\n return newest;\n}\n\n/** How many sessions' worth of state was removed. */\nexport async function sweepSessionState(options: SweepSessionStateOptions): Promise<number> {\n const { directory, keep, removeDirectory = false, now = Date.now(), maxAgeMs = STATE_MAX_AGE_MS } = options;\n let entries: string[];\n try {\n entries = await fs.readdir(directory);\n } catch {\n return 0;\n }\n const floor = now - maxAgeMs;\n const timelines = new Set(entries.filter((entry) => entry.endsWith(TIMELINE_SUFFIX)));\n let removed = 0;\n\n for (const entry of timelines) {\n const timelinePath = path.join(directory, entry);\n if (keep !== undefined && timelinePath === keep) continue;\n const snapshotsPath = `${timelinePath.slice(0, -TIMELINE_SUFFIX.length)}${SNAPSHOTS_SUFFIX}`;\n const lockPath = `${timelinePath}.lock`;\n const touched = await lastTouched([timelinePath, snapshotsPath, lockPath]);\n if (touched === undefined || touched >= floor) continue;\n // Content first. A crash between the two leaves a timeline whose snapshots\n // are gone, which reads as a session whose diffs expired. The other order\n // leaves a blob tree nothing will ever name again, which is the shape of\n // the leak this exists to clear.\n await remove(snapshotsPath);\n await remove(timelinePath);\n await remove(lockPath);\n removed += 1;\n }\n\n // A blob tree whose timeline is already gone is exactly what a half-finished\n // cleanup leaves, and nothing else will ever look for it.\n for (const entry of entries) {\n if (!entry.endsWith(SNAPSHOTS_SUFFIX)) continue;\n if (timelines.has(`${entry.slice(0, -SNAPSHOTS_SUFFIX.length)}${TIMELINE_SUFFIX}`)) continue;\n const orphan = path.join(directory, entry);\n const touched = await lastTouched([orphan]);\n if (touched === undefined || touched >= floor) continue;\n await remove(orphan);\n }\n\n if (removeDirectory) {\n try {\n await fs.rmdir(directory);\n } catch {\n // Still holding something, so it is not this sweep's to remove.\n }\n }\n return removed;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { SUBAGENT_CHILD_ENV } from '@agimon-ai/doompi-core/childProcess';\nimport type { LeaderContribution } from '@agimon-ai/doompi-core/leader';\nimport type { PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { FILES_COMMAND, PACKAGE_SOURCE, DOOM_IGNORE_FILE } from '../../constants/package';\nimport { createDoomIgnoreMatcher } from '../../services/doomIgnore';\nimport { sweepSessionState } from '../../services/sessionStateSweep';\nimport type { FileEditDependencies } from '../../types';\nimport { filesStatusKey } from '../../types/webFiles';\n/**\n * The project's ignore rules as a test over absolute paths, or nothing when the\n * file is absent, empty, or unreadable.\n *\n * Read once per session, like the exclude list it is passed beside. The web\n * reader re-reads the same file per request, so a mid-session edit reaches the\n * list before it reaches the recorder; that is a pre-existing difference and\n * not one this read introduces.\n */\nfunction readDoomIgnore(cwd: string): ((filePath: string) => boolean) | undefined {\n let content: string;\n try {\n content = fs.readFileSync(path.join(cwd, DOOM_IGNORE_FILE), 'utf8');\n } catch {\n return undefined;\n }\n const matcher = createDoomIgnoreMatcher(content);\n if (matcher === undefined) return undefined;\n return (filePath: string): boolean => matcher(path.relative(cwd, filePath));\n}\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', detail: 'tools, skills and config', order: 50 },\n { key: 'f', label: 'files', detail: 'session edits' },\n ],\n command: { name: FILES_COMMAND },\n },\n ],\n} as const satisfies LeaderContribution;\nexport function createFileEditRuntime(dependencies: FileEditDependencies): PiPluginContributions {\n const { paths, timeline, snapshots, editTracker: tracker, workflow } = dependencies;\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 let sessionContext: ExtensionContext | undefined;\n\n /**\n * Publishes the count the cockpit's activity group keys off. The group is\n * hidden until this status exists, so it is written on every append rather\n * than only when the count changes.\n */\n const publishStatus = async (): Promise<void> => {\n if (!active || !sessionContext?.hasUI) return;\n const entries = await timeline.list();\n sessionContext.ui.setStatus(\n filesStatusKey,\n entries.length === 0 ? '' : `${entries.length} ${entries.length === 1 ? 'file' : 'files'}`,\n );\n };\n\n const dispose = async () => {\n active = false;\n sessionGeneration += 1;\n toolStartedAt.clear();\n // A scan deferred by the last bash call would otherwise append after the\n // clear below and leave a timeline no session owns.\n await tracker.flush();\n tracker.reset();\n const closing = sessionContext;\n sessionContext = undefined;\n try {\n if (!process.env[SUBAGENT_CHILD_ENV]) {\n await timeline.clear();\n // The snapshots exist only to diff this session, so they go with it\n // rather than accumulating a copy of the tree on every run.\n await snapshots.clear();\n }\n if (closing?.hasUI) closing.ui.setStatus(filesStatusKey, undefined);\n await telemetry.recordEvent('doom_file_edit.timeline_finished', { outcome: 'closed' });\n } finally {\n await telemetry.shutdown();\n }\n };\n\n /**\n * Clears state no session will claim again. Never awaited and never allowed\n * to throw: a sweep that cannot run is not a reason to fail a session.\n */\n const sweepAbandonedState = async (cwd: string, keep: string): Promise<void> => {\n try {\n await sweepSessionState({ directory: paths.stateDirectory(), keep });\n const legacy = paths.legacyStateDirectory(cwd);\n if (legacy === undefined || legacy === paths.stateDirectory()) return;\n // Same age rule, so a build still running against the old location is\n // not robbed of the session it is in the middle of.\n await sweepSessionState({ directory: legacy, removeDirectory: true });\n } catch {\n // Nothing here is worth interrupting a session that is starting.\n }\n };\n return {\n onDispose: dispose,\n services: [\n (cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerLeader(FILE_EDIT_LEADER_CONTRIBUTION);\n return () => contribution.dispose();\n });\n },\n ],\n commands: [\n [\n FILES_COMMAND,\n {\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 ],\n events: {\n session_start: (_event, ctx) => {\n if (!active) return;\n sessionGeneration += 1;\n toolStartedAt.clear();\n sessionContext = ctx;\n const sessionKey = paths.sessionKey(ctx.sessionManager.getSessionId());\n const timelinePath = paths.timelinePath(ctx.cwd, sessionKey);\n const snapshotsPath = paths.snapshotsPath(ctx.cwd, sessionKey);\n timeline.initialize(timelinePath);\n snapshots.initialize(snapshotsPath);\n // Inside a git worktree these land under the repository's own git\n // directory, which can sit inside the tree the tracker walks. Naming them\n // here is what stops the package's bookkeeping reading as session edits.\n // Whatever earlier sessions were killed before they could clean up, plus\n // anything an older build left in the repository's own git directory.\n void sweepAbandonedState(ctx.cwd, timelinePath);\n const isIgnored = readDoomIgnore(ctx.cwd);\n tracker.reset({\n exclude: [timelinePath, `${timelinePath}.lock`, snapshotsPath],\n ...(isIgnored === undefined ? {} : { isIgnored }),\n });\n // A resumed session already has a timeline, so the group must show its\n // count from the first paint rather than waiting for the next edit.\n void publishStatus();\n void telemetry.recordEvent('doom_file_edit.timeline_started', { outcome: 'initialized' });\n },\n tool_execution_start: async (event, ctx) => {\n if (!active) return;\n const ownGeneration = sessionGeneration;\n toolStartedAt.set(event.toolCallId, Date.now());\n const hookStartedAt = Date.now();\n await tracker.start(event.toolCallId, event.toolName, event.args, ctx.cwd);\n const hookMs = Date.now() - hookStartedAt;\n if (!active || ownGeneration !== sessionGeneration) {\n toolStartedAt.delete(event.toolCallId);\n return;\n }\n void telemetry.recordEvent('doom_file_edit.edit_started', {\n 'tool.name': event.toolName,\n hook_ms: hookMs,\n });\n },\n tool_execution_end: async (event, ctx) => {\n if (!active) return;\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n // Measured separately from the tool's own duration: this is the part of\n // the wait that belongs to this package rather than to the tool.\n const hookStartedAt = Date.now();\n await tracker.end(event.toolCallId, event.isError, ctx.cwd);\n if (!active) return;\n await publishStatus();\n const hookMs = Date.now() - hookStartedAt;\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 hook_ms: hookMs,\n outcome: event.isError ? 'failed' : 'completed',\n });\n },\n },\n };\n}\n","import { createFileEditRuntime } from '../../../../../services/fileEditRuntime';\nimport { createFileEditDependencies } from '../../../../../tui/fileEditDependencies';\nexport const createFileEditPiRoot = () => {\n const runtime = createFileEditRuntime(createFileEditDependencies());\n return { value: runtime, services: runtime.services, onDispose: runtime.onDispose };\n};\nexport type FileEditPiScope = Awaited<ReturnType<typeof createFileEditPiRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createFileEditPiRoot } from './_lib/piRoot';\n\nexport default defineRoot(createFileEditPiRoot);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { FileEditPiScope } from '../_lib/piRoot';\nexport default defineRoutedContribution(\n (context: WithRoot<PiPluginContext<unknown>, FileEditPiScope>) => [context.root.commands![0]!] as const,\n { cardinality: 'many' },\n);\n","import { defineCliHook, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { FileEditPiScope } from '../_lib/piRoot';\nexport default defineCliHook(\n (context: WithRoot<PiPluginContext<unknown>, FileEditPiScope>) => context.root.events!.session_start!,\n);\n","import { defineCliHook, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { FileEditPiScope } from '../_lib/piRoot';\nexport default defineCliHook(\n (context: WithRoot<PiPluginContext<unknown>, FileEditPiScope>) => context.root.events!.tool_execution_end!,\n);\n","import { defineCliHook, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { FileEditPiScope } from '../_lib/piRoot';\nexport default defineCliHook(\n (context: WithRoot<PiPluginContext<unknown>, FileEditPiScope>) => context.root.events!.tool_execution_start!,\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandFileEdits from '../src/extensions/workspaces/sessions/(backend)/command/file-edits.cli';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli';\nimport hookToolExecutionEnd from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.cli';\nimport hookToolExecutionStart from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-start.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandFileEdits> | OptionsOf<typeof hookSessionStart> | OptionsOf<typeof hookToolExecutionEnd> | OptionsOf<typeof hookToolExecutionStart>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-file-edit', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return [...many(commandFileEdits, contextSession)]; },\n events: {\n session_start: at(hookSessionStart, contextSession) as NonNullable<PiPluginContributions['events']>['session_start'],\n tool_execution_end: at(hookToolExecutionEnd, contextSession) as NonNullable<PiPluginContributions['events']>['tool_execution_end'],\n tool_execution_start: at(hookToolExecutionStart, contextSession) as NonNullable<PiPluginContributions['events']>['tool_execution_start'],\n },\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region generated/pi.d.ts
2
- export declare const extension: import("@agimon-ai/doompi-core/runtime-pi-extension").DefinedPiExtension<undefined>;
2
+ export declare const extension: import("@agimon-ai/doompi-core/runtimePiExtension").DefinedPiExtension<undefined>;
3
3
  //#endregion
4
4
  export { extension as default };
5
5
  //# sourceMappingURL=pi.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.mts","names":[],"sources":["../../generated/pi.ts"],"mappings":";qBAyBa,iEAAS"}
1
+ {"version":3,"file":"pi.d.mts","names":[],"sources":["../../generated/pi.ts"],"mappings":";qBAyBa,+DAAS"}