@agimon-ai/doompi-git 0.0.1-alpha.3 → 0.0.1-alpha.31

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 (180) hide show
  1. package/README.md +12 -0
  2. package/dist/apiContracts.cjs +198 -0
  3. package/dist/apiContracts.cjs.map +1 -0
  4. package/dist/apiContracts.d.mts +53 -0
  5. package/dist/apiContracts.d.mts.map +1 -0
  6. package/dist/apiContracts.mjs +193 -0
  7. package/dist/apiContracts.mjs.map +1 -0
  8. package/dist/extensions/pi.cjs +105 -1
  9. package/dist/extensions/pi.cjs.map +1 -0
  10. package/dist/extensions/pi.d.mts +6 -2
  11. package/dist/extensions/pi.d.mts.map +1 -0
  12. package/dist/extensions/pi.mjs +100 -1
  13. package/dist/extensions/pi.mjs.map +1 -0
  14. package/dist/extensions/server.cjs +588 -0
  15. package/dist/extensions/server.cjs.map +1 -0
  16. package/dist/extensions/server.d.mts +5 -0
  17. package/dist/extensions/server.d.mts.map +1 -0
  18. package/dist/extensions/server.mjs +583 -0
  19. package/dist/extensions/server.mjs.map +1 -0
  20. package/dist/extensions/web.mjs +911 -0
  21. package/dist/extensions/web.mjs.map +1 -0
  22. package/dist/gitDependencies-CJFmhrG1.mjs +22 -0
  23. package/dist/gitDependencies-CJFmhrG1.mjs.map +1 -0
  24. package/dist/gitDependencies-CWsygnLQ.cjs +33 -0
  25. package/dist/gitDependencies-CWsygnLQ.cjs.map +1 -0
  26. package/dist/index-D79MSCee.d.mts +145 -0
  27. package/dist/index-D79MSCee.d.mts.map +1 -0
  28. package/dist/index.cjs +4 -1
  29. package/dist/index.d.mts +2 -5
  30. package/dist/index.mjs +2 -1
  31. package/dist/runWorktree-BdK3oRtX.mjs +298 -0
  32. package/dist/runWorktree-BdK3oRtX.mjs.map +1 -0
  33. package/dist/runWorktree-D0bsyYc0.cjs +351 -0
  34. package/dist/runWorktree-D0bsyYc0.cjs.map +1 -0
  35. package/dist/worktreeOperations-CijBzYEf.mjs +1163 -0
  36. package/dist/worktreeOperations-CijBzYEf.mjs.map +1 -0
  37. package/dist/worktreeOperations-FJDk44Zt.cjs +1253 -0
  38. package/dist/worktreeOperations-FJDk44Zt.cjs.map +1 -0
  39. package/llms.txt +4 -0
  40. package/package.json +54 -39
  41. package/src/prompts/doompi-use-git/SKILL.md +26 -3
  42. package/dist/_virtual/_rolldown/runtime.cjs +0 -1
  43. package/dist/adapters/channel/worktreeChannel.cjs +0 -2
  44. package/dist/adapters/channel/worktreeChannel.cjs.map +0 -1
  45. package/dist/adapters/channel/worktreeChannel.d.cts +0 -40
  46. package/dist/adapters/channel/worktreeChannel.d.cts.map +0 -1
  47. package/dist/adapters/channel/worktreeChannel.d.mts +0 -40
  48. package/dist/adapters/channel/worktreeChannel.d.mts.map +0 -1
  49. package/dist/adapters/channel/worktreeChannel.mjs +0 -2
  50. package/dist/adapters/channel/worktreeChannel.mjs.map +0 -1
  51. package/dist/adapters/filesystem/atomicJson.cjs +0 -2
  52. package/dist/adapters/filesystem/atomicJson.cjs.map +0 -1
  53. package/dist/adapters/filesystem/atomicJson.mjs +0 -2
  54. package/dist/adapters/filesystem/atomicJson.mjs.map +0 -1
  55. package/dist/adapters/filesystem/paths.cjs +0 -2
  56. package/dist/adapters/filesystem/paths.cjs.map +0 -1
  57. package/dist/adapters/filesystem/paths.mjs +0 -2
  58. package/dist/adapters/filesystem/paths.mjs.map +0 -1
  59. package/dist/adapters/hub/hubClient.cjs +0 -2
  60. package/dist/adapters/hub/hubClient.cjs.map +0 -1
  61. package/dist/adapters/hub/hubClient.d.cts +0 -1
  62. package/dist/adapters/hub/hubClient.d.mts +0 -1
  63. package/dist/adapters/hub/hubClient.mjs +0 -2
  64. package/dist/adapters/hub/hubClient.mjs.map +0 -1
  65. package/dist/adapters/pi/extension.cjs +0 -2
  66. package/dist/adapters/pi/extension.cjs.map +0 -1
  67. package/dist/adapters/pi/extension.d.cts +0 -9
  68. package/dist/adapters/pi/extension.d.cts.map +0 -1
  69. package/dist/adapters/pi/extension.d.mts +0 -9
  70. package/dist/adapters/pi/extension.d.mts.map +0 -1
  71. package/dist/adapters/pi/extension.mjs +0 -2
  72. package/dist/adapters/pi/extension.mjs.map +0 -1
  73. package/dist/adapters/pi/extensions/runWorktreeTool.cjs +0 -15
  74. package/dist/adapters/pi/extensions/runWorktreeTool.cjs.map +0 -1
  75. package/dist/adapters/pi/extensions/runWorktreeTool.mjs +0 -15
  76. package/dist/adapters/pi/extensions/runWorktreeTool.mjs.map +0 -1
  77. package/dist/adapters/web/worktreesChannel.cjs +0 -2
  78. package/dist/adapters/web/worktreesChannel.cjs.map +0 -1
  79. package/dist/adapters/web/worktreesChannel.d.cts +0 -21
  80. package/dist/adapters/web/worktreesChannel.d.cts.map +0 -1
  81. package/dist/adapters/web/worktreesChannel.d.mts +0 -21
  82. package/dist/adapters/web/worktreesChannel.d.mts.map +0 -1
  83. package/dist/adapters/web/worktreesChannel.mjs +0 -2
  84. package/dist/adapters/web/worktreesChannel.mjs.map +0 -1
  85. package/dist/adapters/worktree/dependencyInstall.cjs +0 -2
  86. package/dist/adapters/worktree/dependencyInstall.cjs.map +0 -1
  87. package/dist/adapters/worktree/dependencyInstall.mjs +0 -2
  88. package/dist/adapters/worktree/dependencyInstall.mjs.map +0 -1
  89. package/dist/adapters/worktree/gitCli.cjs +0 -4
  90. package/dist/adapters/worktree/gitCli.cjs.map +0 -1
  91. package/dist/adapters/worktree/gitCli.mjs +0 -4
  92. package/dist/adapters/worktree/gitCli.mjs.map +0 -1
  93. package/dist/adapters/worktree/repositoryIdentity.cjs +0 -2
  94. package/dist/adapters/worktree/repositoryIdentity.cjs.map +0 -1
  95. package/dist/adapters/worktree/repositoryIdentity.mjs +0 -2
  96. package/dist/adapters/worktree/repositoryIdentity.mjs.map +0 -1
  97. package/dist/adapters/worktree/worktreeOperations.cjs +0 -2
  98. package/dist/adapters/worktree/worktreeOperations.cjs.map +0 -1
  99. package/dist/adapters/worktree/worktreeOperations.d.cts +0 -32
  100. package/dist/adapters/worktree/worktreeOperations.d.cts.map +0 -1
  101. package/dist/adapters/worktree/worktreeOperations.d.mts +0 -32
  102. package/dist/adapters/worktree/worktreeOperations.d.mts.map +0 -1
  103. package/dist/adapters/worktree/worktreeOperations.mjs +0 -2
  104. package/dist/adapters/worktree/worktreeOperations.mjs.map +0 -1
  105. package/dist/adapters/worktree/worktreeRegistry.cjs +0 -2
  106. package/dist/adapters/worktree/worktreeRegistry.cjs.map +0 -1
  107. package/dist/adapters/worktree/worktreeRegistry.mjs +0 -2
  108. package/dist/adapters/worktree/worktreeRegistry.mjs.map +0 -1
  109. package/dist/commands/doomGitCommand.cjs +0 -2
  110. package/dist/commands/doomGitCommand.cjs.map +0 -1
  111. package/dist/commands/doomGitCommand.mjs +0 -2
  112. package/dist/commands/doomGitCommand.mjs.map +0 -1
  113. package/dist/container/index.cjs +0 -2
  114. package/dist/container/index.cjs.map +0 -1
  115. package/dist/container/index.d.cts +0 -6
  116. package/dist/container/index.d.cts.map +0 -1
  117. package/dist/container/index.d.mts +0 -6
  118. package/dist/container/index.d.mts.map +0 -1
  119. package/dist/container/index.mjs +0 -2
  120. package/dist/container/index.mjs.map +0 -1
  121. package/dist/extensions/pi.d.cts +0 -2
  122. package/dist/hubApi.cjs +0 -2
  123. package/dist/hubApi.cjs.map +0 -1
  124. package/dist/hubApi.d.cts +0 -6
  125. package/dist/hubApi.d.cts.map +0 -1
  126. package/dist/hubApi.d.mts +0 -6
  127. package/dist/hubApi.d.mts.map +0 -1
  128. package/dist/hubApi.mjs +0 -2
  129. package/dist/hubApi.mjs.map +0 -1
  130. package/dist/index.d.cts +0 -5
  131. package/dist/schemas/runWorktreeTool.cjs +0 -2
  132. package/dist/schemas/runWorktreeTool.cjs.map +0 -1
  133. package/dist/schemas/runWorktreeTool.mjs +0 -2
  134. package/dist/schemas/runWorktreeTool.mjs.map +0 -1
  135. package/dist/services/extensionService.cjs +0 -2
  136. package/dist/services/extensionService.cjs.map +0 -1
  137. package/dist/services/extensionService.d.cts +0 -8
  138. package/dist/services/extensionService.d.cts.map +0 -1
  139. package/dist/services/extensionService.d.mts +0 -8
  140. package/dist/services/extensionService.d.mts.map +0 -1
  141. package/dist/services/extensionService.mjs +0 -2
  142. package/dist/services/extensionService.mjs.map +0 -1
  143. package/dist/services/support/errors.cjs +0 -2
  144. package/dist/services/support/errors.cjs.map +0 -1
  145. package/dist/services/support/errors.mjs +0 -2
  146. package/dist/services/support/errors.mjs.map +0 -1
  147. package/dist/services/worktreeNaming.cjs +0 -2
  148. package/dist/services/worktreeNaming.cjs.map +0 -1
  149. package/dist/services/worktreeNaming.d.cts +0 -27
  150. package/dist/services/worktreeNaming.d.cts.map +0 -1
  151. package/dist/services/worktreeNaming.d.mts +0 -27
  152. package/dist/services/worktreeNaming.d.mts.map +0 -1
  153. package/dist/services/worktreeNaming.mjs +0 -2
  154. package/dist/services/worktreeNaming.mjs.map +0 -1
  155. package/dist/types/extension.d.cts +0 -17
  156. package/dist/types/extension.d.cts.map +0 -1
  157. package/dist/types/extension.d.mts +0 -17
  158. package/dist/types/extension.d.mts.map +0 -1
  159. package/dist/types/webWorktrees.cjs +0 -2
  160. package/dist/types/webWorktrees.cjs.map +0 -1
  161. package/dist/types/webWorktrees.mjs +0 -2
  162. package/dist/types/webWorktrees.mjs.map +0 -1
  163. package/dist/types/worktreeRegistry.d.cts +0 -41
  164. package/dist/types/worktreeRegistry.d.cts.map +0 -1
  165. package/dist/types/worktreeRegistry.d.mts +0 -41
  166. package/dist/types/worktreeRegistry.d.mts.map +0 -1
  167. package/dist/webHub.cjs +0 -1
  168. package/dist/webHub.d.cts +0 -2
  169. package/dist/webHub.d.mts +0 -2
  170. package/dist/webHub.mjs +0 -1
  171. package/src/exports/webClient.ts +0 -1
  172. package/src/types/webWorktrees.ts +0 -55
  173. package/src/types/worktreeRegistry.ts +0 -69
  174. package/src/web/components/RunWorktreeToolMessage.tsx +0 -37
  175. package/src/web/components/WorktreesActivitySection.tsx +0 -64
  176. package/src/web/components/WorktreesPanel.tsx +0 -125
  177. package/src/web/components/toolRenderers.ts +0 -7
  178. package/src/web/index.ts +0 -30
  179. package/src/web/stores/worktreesActivityStore.ts +0 -124
  180. package/src/web/tsconfig.json +0 -22
@@ -0,0 +1,588 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ const require_worktreeOperations = require("../worktreeOperations-FJDk44Zt.cjs");
6
+ const require_runWorktree = require("../runWorktree-D0bsyYc0.cjs");
7
+ let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
8
+ let _agimon_ai_doompi_core_serverFacet = require("@agimon-ai/doompi-core/serverFacet");
9
+ let _agimon_ai_doompi_session = require("@agimon-ai/doompi-session");
10
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts
11
+ function progressResult(action, label) {
12
+ return {
13
+ content: [{
14
+ type: "text",
15
+ text: label
16
+ }],
17
+ details: { action }
18
+ };
19
+ }
20
+ function createGitSession({ context, host: serverHost }) {
21
+ if (serverHost.context.directEvents === void 0) throw new Error("Git headless facet requires the session direct event bus.");
22
+ if (serverHost.context.sessionId === void 0) throw new Error("Git headless facet requires a session identity.");
23
+ const sessionId = serverHost.context.sessionId;
24
+ const directEvents = serverHost.context.directEvents;
25
+ const messageInbox = require_worktreeOperations.createWorktreeMessageInbox(directEvents, sessionId);
26
+ const operations = require_worktreeOperations.createWorktreeOperations({
27
+ git: require_worktreeOperations.createWorktreeGit(),
28
+ sessionService: serverHost.context.sessionService,
29
+ messageInbox,
30
+ sessionDelivery: () => (0, _agimon_ai_doompi_session.readDoomSessionDelivery)(context)
31
+ });
32
+ return {
33
+ value: {
34
+ resources: [{
35
+ when: {
36
+ state: { "minor-mode": "help" },
37
+ attribution: {
38
+ kind: "minor",
39
+ mode: "help"
40
+ }
41
+ },
42
+ name: "doompi-git",
43
+ kind: "context",
44
+ read: () => (0, _agimon_ai_doompi_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "llms.txt")
45
+ }, {
46
+ name: "doompi-use-git",
47
+ kind: "skill",
48
+ read: () => (0, _agimon_ai_doompi_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/doompi-use-git/SKILL.md")
49
+ }],
50
+ tool: {
51
+ name: require_runWorktree.RUN_WORKTREE_TOOL_NAME,
52
+ label: "Worktree",
53
+ description: require_runWorktree.RUN_WORKTREE_DESCRIPTION,
54
+ parameters: require_runWorktree.RunWorktreeToolSchema,
55
+ promptSnippet: "Create and manage Git worktree sessions",
56
+ executionMode: "serial",
57
+ async execute(_toolCallId, parameters, signal, onUpdate, execution) {
58
+ const params = require_runWorktree.validateParams(parameters);
59
+ return require_runWorktree.executeRunWorktreeTool(params, operations, execution, {
60
+ ...signal === void 0 ? {} : { signal },
61
+ onProgress: (label) => onUpdate?.(progressResult(params.action, label))
62
+ });
63
+ }
64
+ }
65
+ },
66
+ onDispose: () => messageInbox.close()
67
+ };
68
+ }
69
+ const root = (0, _agimon_ai_doompi_core_extensionFile.defineRoot)(createGitSession);
70
+ //#endregion
71
+ //#region src/extensions/workspaces/sessions/(backend)/root.server.ts
72
+ var root_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoot)(root);
73
+ //#endregion
74
+ //#region src/services/newSessionRequest/index.ts
75
+ const MAX_NAME_LENGTH = 120;
76
+ /** Trimmed text, undefined when absent or blank, false when not text at all. */
77
+ function optionalText(value) {
78
+ if (value === void 0) return void 0;
79
+ if (typeof value !== "string") return false;
80
+ const trimmed = value.trim();
81
+ return trimmed === "" ? void 0 : trimmed;
82
+ }
83
+ /**
84
+ * Validates a new-session dialog request for a worktree session. Every ref is
85
+ * checked here, before it can reach git as a positional argument.
86
+ */
87
+ function newSessionRequest(body) {
88
+ if (typeof body !== "object" || body === null || Array.isArray(body)) return { error: "A request body is required." };
89
+ const record = body;
90
+ const branch = optionalText(record.branch);
91
+ if (branch === void 0 || branch === false || !require_worktreeOperations.validRefName(branch)) return { error: "A valid branch name is required." };
92
+ const name = optionalText(record.name);
93
+ if (name === false || name !== void 0 && name.length > MAX_NAME_LENGTH) return { error: `The session name must be text of up to ${String(MAX_NAME_LENGTH)} characters.` };
94
+ const named = name === void 0 ? {} : { name };
95
+ if (record.mode === "existing-branch") {
96
+ const remote = optionalText(record.remote);
97
+ if (remote === false || remote !== void 0 && !require_worktreeOperations.validRefName(remote)) return { error: "That remote name is not valid." };
98
+ return {
99
+ mode: "existing-branch",
100
+ branch,
101
+ ...remote === void 0 ? {} : { remote },
102
+ ...named
103
+ };
104
+ }
105
+ if (record.mode === "new-branch") {
106
+ const baseRef = optionalText(record.baseRef);
107
+ if (baseRef === false || baseRef !== void 0 && !require_worktreeOperations.validRefName(baseRef)) return { error: "That base branch is not valid." };
108
+ return {
109
+ mode: "new-branch",
110
+ branch,
111
+ ...baseRef === void 0 ? {} : { baseRef },
112
+ ...named
113
+ };
114
+ }
115
+ return { error: "The mode must be existing-branch or new-branch." };
116
+ }
117
+ //#endregion
118
+ //#region src/extensions/(backend)/api/_lib/route.server.ts
119
+ /**
120
+ * The worktree surface the cockpit panel calls.
121
+ *
122
+ * Hub-scoped because worktrees are a property of a repository, not of one
123
+ * session: the panel lists and creates them whether or not the session that
124
+ * made them is focused, and a session-scoped API would disappear with it.
125
+ *
126
+ * The panel names a repository by the hub's opaque id and never by path.
127
+ * `resolveRepository` turns that into an admitted root, so a browser cannot
128
+ * point this at a directory the cockpit was never given.
129
+ */
130
+ function badRequest(message) {
131
+ return Response.json({ error: message }, { status: 400 });
132
+ }
133
+ function failed(error) {
134
+ if (error instanceof require_worktreeOperations.DoomGitExpectedError) return Response.json({
135
+ error: error.message,
136
+ code: error.code
137
+ }, { status: error.retryable ? 503 : 409 });
138
+ return Response.json({ error: "The worktree operation failed." }, { status: 500 });
139
+ }
140
+ //#endregion
141
+ //#region src/extensions/(backend)/api/route.server.ts
142
+ var route_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoute)({
143
+ basePath: "git",
144
+ start(context) {
145
+ if (context.directEvents === void 0) throw new Error("Git hub API requires the direct event bus.");
146
+ const directEvents = context.directEvents;
147
+ const publishLifecycle = (sessionId, repositoryRoot) => {
148
+ directEvents.publish(require_worktreeOperations.GIT_WORKTREE_LIFECYCLE_EVENT, sessionId, {
149
+ version: 1,
150
+ repositoryRoot
151
+ });
152
+ };
153
+ const git = require_worktreeOperations.createWorktreeGit();
154
+ const operations = require_worktreeOperations.createWorktreeOperations({
155
+ git,
156
+ sessionService: context.sessionService,
157
+ ...context.homeDirectory === void 0 ? {} : { homeDir: context.homeDirectory }
158
+ });
159
+ /**
160
+ * The new-session dialog's routes: the workspace's branches, and a top-level
161
+ * worktree session on one. Workspace-mounted only, and always rooted at the
162
+ * mount's own workspace, so a request can never name another directory.
163
+ */
164
+ const newSession = async (request, url) => {
165
+ const isBranches = request.method === "GET" && url.pathname === "/branches";
166
+ const isCreate = request.method === "POST" && url.pathname === "/sessions";
167
+ if (!isBranches && !isCreate) return void 0;
168
+ const workspaceRoot = context.scope === "workspace" ? context.workspaceRoot : void 0;
169
+ if (workspaceRoot === void 0) return Response.json({ error: "This route belongs to a workspace." }, { status: 404 });
170
+ if (isBranches) {
171
+ const repositoryRoot = await git.repositoryRoot(workspaceRoot);
172
+ const branches = repositoryRoot === void 0 ? {
173
+ repository: false,
174
+ local: [],
175
+ remote: []
176
+ } : {
177
+ repository: true,
178
+ ...await git.listBranches(repositoryRoot)
179
+ };
180
+ return Response.json(branches);
181
+ }
182
+ const parsed = newSessionRequest(await request.json().catch(() => void 0));
183
+ if ("error" in parsed) return badRequest(parsed.error);
184
+ const record = await operations.spawn({ cwd: workspaceRoot }, {
185
+ branch: parsed.branch,
186
+ checkout: parsed.mode === "existing-branch" ? "existing" : "new",
187
+ ...parsed.mode === "existing-branch" && parsed.remote !== void 0 ? { remote: parsed.remote } : {},
188
+ ...parsed.mode === "new-branch" && parsed.baseRef !== void 0 ? { baseRef: parsed.baseRef } : {},
189
+ ...parsed.name === void 0 ? {} : { name: parsed.name }
190
+ });
191
+ publishLifecycle(record.sessionId, record.repositoryRoot);
192
+ const created = {
193
+ sessionId: record.sessionId,
194
+ worktreeId: record.id
195
+ };
196
+ return Response.json(created, { status: 201 });
197
+ };
198
+ /** The admitted root for a request, or a response explaining why not. */
199
+ const rootOf = (url) => {
200
+ const repositoryId = url.searchParams.get("repositoryId");
201
+ if (repositoryId === null || repositoryId === "") return badRequest("A repositoryId is required.");
202
+ const root = context.resolveRepository?.(repositoryId);
203
+ if (root === void 0) return badRequest("That repository is not admitted to this cockpit.");
204
+ return root;
205
+ };
206
+ return {
207
+ async fetch(request) {
208
+ const url = new URL(request.url);
209
+ try {
210
+ const answered = await newSession(request, url);
211
+ if (answered !== void 0) return answered;
212
+ } catch (error) {
213
+ context.onNotice(`new-session request failed: ${error.name}`);
214
+ return failed(error);
215
+ }
216
+ const root = rootOf(url);
217
+ if (root instanceof Response) return root;
218
+ const callerContext = {
219
+ cwd: root,
220
+ sessionId: url.searchParams.get("sessionId") ?? ""
221
+ };
222
+ if ((request.method === "POST" && url.pathname === "/worktrees" || request.method === "DELETE" && /^\/worktrees\/[^/]+$/u.test(url.pathname)) && callerContext.sessionId === "") return badRequest("A sessionId is required for worktree mutations.");
223
+ try {
224
+ if (request.method === "GET" && url.pathname === "/worktrees") return Response.json({ worktrees: await operations.list(callerContext) });
225
+ if (request.method === "POST" && url.pathname === "/worktrees") {
226
+ const body = await request.json();
227
+ if (typeof body.branch !== "string" || body.branch.trim() === "") return badRequest("A branch is required.");
228
+ const record = await operations.spawn(callerContext, {
229
+ branch: body.branch,
230
+ ...body.baseRef === void 0 ? {} : { baseRef: body.baseRef },
231
+ ...body.name === void 0 ? {} : { name: body.name }
232
+ });
233
+ publishLifecycle(callerContext.sessionId, record.repositoryRoot);
234
+ return Response.json({ worktree: record }, { status: 201 });
235
+ }
236
+ const closing = /^\/worktrees\/([^/]+)$/u.exec(url.pathname);
237
+ if (request.method === "DELETE" && closing) {
238
+ const record = await operations.close(callerContext, decodeURIComponent(String(closing[1])), url.searchParams.get("force") === "true");
239
+ publishLifecycle(callerContext.sessionId, record.repositoryRoot);
240
+ return Response.json({ worktree: record });
241
+ }
242
+ return Response.json({ error: "No such worktree route." }, { status: 404 });
243
+ } catch (error) {
244
+ context.onNotice(`worktree request failed: ${error.name}`);
245
+ return failed(error);
246
+ }
247
+ },
248
+ close() {}
249
+ };
250
+ }
251
+ });
252
+ //#endregion
253
+ //#region src/types/webWorktrees.ts
254
+ /**
255
+ * The cockpit's view of this session's worktrees.
256
+ *
257
+ * DESIGN PATTERNS:
258
+ * - Declarations only. The channel frame type is a constant so the hub and the
259
+ * page cannot drift apart on a string.
260
+ * - A view is the subset of a record the dock needs, not the record. The
261
+ * registry may hold paths and provenance the page has no business rendering.
262
+ *
263
+ * AVOID:
264
+ * - Adding behaviour here. This file is imported by browser code, so it must
265
+ * stay free of node builtins.
266
+ */
267
+ /** The data channel carrying one session's worktrees to the page. */
268
+ const GIT_WORKTREES_TYPE = "git_worktrees";
269
+ //#endregion
270
+ //#region src/extensions/(backend)/channel/_lib/git-worktrees.server.ts
271
+ function payloadOf(state) {
272
+ return {
273
+ worktrees: state.worktrees,
274
+ ...state.pending === void 0 ? {} : { pending: state.pending },
275
+ ...state.error === void 0 ? {} : { error: state.error },
276
+ ...state.errorTarget === void 0 ? {} : { errorTarget: state.errorTarget }
277
+ };
278
+ }
279
+ /** Worktrees visible to this session, using the hub's live session table for ownership. */
280
+ function viewsFor(scope, deps) {
281
+ try {
282
+ return require_worktreeOperations.createWorktreeRegistry(require_worktreeOperations.registryFile(scope.cwd, deps.homeDir)).list().flatMap((record) => {
283
+ if (record.parentSessionId === void 0 && record.sessionId !== scope.sessionId) return [];
284
+ const owned = record.parentSessionId === void 0 || record.parentSessionId === scope.sessionId;
285
+ const unowned = !owned && !deps.sessionService.isLive(record.parentSessionId);
286
+ if (!owned && !unowned) return [];
287
+ return [{
288
+ id: record.id,
289
+ branch: record.branch,
290
+ path: record.path,
291
+ sessionId: record.status === "orphaned" ? null : record.sessionId,
292
+ orphaned: record.status === "orphaned",
293
+ unowned
294
+ }];
295
+ });
296
+ } catch {
297
+ return [];
298
+ }
299
+ }
300
+ function sameList(left, right) {
301
+ if (left.length !== right.length) return false;
302
+ return left.every((entry, index) => {
303
+ const other = right[index];
304
+ return other !== void 0 && entry.id === other.id && entry.branch === other.branch && entry.sessionId === other.sessionId && entry.orphaned === other.orphaned && entry.unowned === other.unowned;
305
+ });
306
+ }
307
+ function errorTargetFor(command) {
308
+ return command.action === "create" ? { action: "create" } : {
309
+ action: "close",
310
+ id: command.id
311
+ };
312
+ }
313
+ /** A command the page sent, or undefined when the frame was not one. */
314
+ function parseCommand(payload) {
315
+ if (typeof payload !== "object" || payload === null) return void 0;
316
+ const value = payload;
317
+ if (value.action === "create") {
318
+ if (typeof value.branch !== "string" || value.branch.trim() === "") return void 0;
319
+ if (value.reservationId !== void 0 && (typeof value.reservationId !== "string" || !/^[A-Za-z0-9_-]+$/u.test(value.reservationId))) return void 0;
320
+ return {
321
+ action: "create",
322
+ branch: value.branch.trim(),
323
+ ...typeof value.baseRef === "string" && value.baseRef.trim() !== "" ? { baseRef: value.baseRef.trim() } : {},
324
+ ...typeof value.reservationId === "string" ? { reservationId: value.reservationId } : {}
325
+ };
326
+ }
327
+ if (value.action === "close") {
328
+ if (typeof value.id !== "string" || value.id === "") return void 0;
329
+ return {
330
+ action: "close",
331
+ id: value.id,
332
+ ...value.force === true ? { force: true } : {}
333
+ };
334
+ }
335
+ }
336
+ /**
337
+ * What the reader is told when a command fails.
338
+ *
339
+ * An expected failure explains itself. Anything else is summarised, never
340
+ * echoed: a git error can carry a remote URL with a token in it.
341
+ */
342
+ function failureText(error) {
343
+ return error instanceof require_worktreeOperations.DoomGitExpectedError ? error.message : "The worktree operation failed.";
344
+ }
345
+ /** Starts one direct-event subscription per managed session. */
346
+ function createWorktreesChannel(options = {}) {
347
+ let receiveCommand;
348
+ return {
349
+ frameType: GIT_WORKTREES_TYPE,
350
+ start(host) {
351
+ const sessionService = host.sessionService;
352
+ if (sessionService === void 0) throw new require_worktreeOperations.HubUnavailableError("The cockpit session service is unavailable. Start the cockpit and try again.");
353
+ const worktrees = options.operations ?? require_worktreeOperations.createWorktreeOperations({
354
+ git: require_worktreeOperations.createWorktreeGit(),
355
+ sessionService
356
+ });
357
+ /** Announces a successful mutation to this session's lifecycle subscribers. */
358
+ const publishLifecycle = (scope, repositoryRoot) => {
359
+ host.directEvents.publish(require_worktreeOperations.GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, {
360
+ version: 1,
361
+ repositoryRoot
362
+ });
363
+ };
364
+ const unregisterWorktreeProvisioner = sessionService.registerReservedWorktreeProvisioner?.(async ({ reservationId, parentSessionId, signal }) => {
365
+ const parent = host.sessions().find((scope) => scope.sessionId === parentSessionId);
366
+ if (parent === void 0) throw new Error("The conversation parent session is unavailable.");
367
+ const branch = `doompi/conversation-${reservationId.slice(0, 12)}`;
368
+ const record = await worktrees.spawn({
369
+ cwd: parent.cwd,
370
+ sessionId: parent.sessionId
371
+ }, {
372
+ branch,
373
+ name: `conversation ${reservationId.slice(0, 8)}`,
374
+ reservationId
375
+ }, { signal });
376
+ const reservations = sessionService.reservations;
377
+ if (reservations === void 0) throw new Error("Conversation reservations are unavailable.");
378
+ const session = await reservations.complete(reservationId, parentSessionId);
379
+ publishLifecycle(parent, record.repositoryRoot);
380
+ return session;
381
+ });
382
+ const views = {
383
+ homeDir: options.homeDir,
384
+ sessionService
385
+ };
386
+ const latest = /* @__PURE__ */ new Map();
387
+ const subscriptions = /* @__PURE__ */ new Map();
388
+ const busy = /* @__PURE__ */ new Set();
389
+ const generations = /* @__PURE__ */ new Map();
390
+ const newGeneration = (sessionId) => {
391
+ const generation = Symbol(sessionId);
392
+ generations.set(sessionId, generation);
393
+ return generation;
394
+ };
395
+ /** Republishes a session, skipping a frame that would say nothing new. */
396
+ const publish = (scope, force) => {
397
+ const previous = latest.get(scope.sessionId);
398
+ const next = {
399
+ worktrees: viewsFor(scope, views),
400
+ pending: previous?.pending,
401
+ error: previous?.error,
402
+ errorTarget: previous?.errorTarget
403
+ };
404
+ if (!force && previous !== void 0 && sameList(previous.worktrees, next.worktrees) && previous.pending === next.pending && previous.error === next.error && previous.errorTarget === next.errorTarget) return;
405
+ latest.set(scope.sessionId, next);
406
+ host.publish(scope.sessionId, payloadOf(next));
407
+ };
408
+ const mark = (scope, pending, error, errorTarget) => {
409
+ const previous = latest.get(scope.sessionId);
410
+ latest.set(scope.sessionId, {
411
+ worktrees: previous?.worktrees ?? viewsFor(scope, views),
412
+ pending,
413
+ error,
414
+ errorTarget
415
+ });
416
+ publish(scope, true);
417
+ };
418
+ const run = async (scope, command, generation) => {
419
+ const context = {
420
+ cwd: scope.cwd,
421
+ sessionId: scope.sessionId
422
+ };
423
+ const markCurrent = (pending, error, errorTarget) => {
424
+ if (generations.get(scope.sessionId) !== generation) return;
425
+ mark(scope, pending, error, errorTarget);
426
+ };
427
+ if (command.action === "create") {
428
+ markCurrent(`creating ${command.branch}…`, void 0, void 0);
429
+ const record = await worktrees.spawn(context, {
430
+ branch: command.branch,
431
+ ...command.baseRef === void 0 ? {} : { baseRef: command.baseRef },
432
+ ...command.reservationId === void 0 ? {} : { reservationId: command.reservationId }
433
+ }, { onProgress: (label) => markCurrent(label, void 0, void 0) });
434
+ if (generations.get(scope.sessionId) !== generation) return;
435
+ publishLifecycle(scope, record.repositoryRoot);
436
+ return;
437
+ }
438
+ markCurrent(`closing ${command.id}…`, void 0, void 0);
439
+ const record = await worktrees.close(context, command.id, command.force ?? false);
440
+ if (generations.get(scope.sessionId) !== generation) return;
441
+ publishLifecycle(scope, record.repositoryRoot);
442
+ };
443
+ const source = {
444
+ payloadFor(scope) {
445
+ const state = latest.get(scope.sessionId);
446
+ return state === void 0 ? void 0 : payloadOf(state);
447
+ },
448
+ sessionAdded(scope) {
449
+ newGeneration(scope.sessionId);
450
+ publish(scope, false);
451
+ const unsubscribe = host.directEvents.subscribe(require_worktreeOperations.GIT_WORKTREE_LIFECYCLE_EVENT, scope.sessionId, (payload) => {
452
+ if (!require_worktreeOperations.isWorktreeLifecycleEvent(payload)) return;
453
+ let sameRepository = false;
454
+ try {
455
+ sameRepository = require_worktreeOperations.registryFile(scope.cwd, options.homeDir) === require_worktreeOperations.registryFile(payload.repositoryRoot, options.homeDir);
456
+ } catch {
457
+ sameRepository = false;
458
+ }
459
+ if (sameRepository) publish(scope, false);
460
+ });
461
+ subscriptions.set(scope.sessionId, unsubscribe);
462
+ },
463
+ sessionRemoved(sessionId) {
464
+ newGeneration(sessionId);
465
+ subscriptions.get(sessionId)?.();
466
+ subscriptions.delete(sessionId);
467
+ latest.delete(sessionId);
468
+ busy.delete(sessionId);
469
+ },
470
+ close() {
471
+ unregisterWorktreeProvisioner?.();
472
+ for (const unsubscribe of subscriptions.values()) unsubscribe();
473
+ subscriptions.clear();
474
+ latest.clear();
475
+ busy.clear();
476
+ generations.clear();
477
+ }
478
+ };
479
+ receiveCommand = (scope, payload) => {
480
+ const command = parseCommand(payload);
481
+ if (command === void 0) return;
482
+ if (busy.has(scope.sessionId)) return;
483
+ const generation = generations.get(scope.sessionId);
484
+ if (generation === void 0) return;
485
+ busy.add(scope.sessionId);
486
+ run(scope, command, generation).then(() => {
487
+ if (generations.get(scope.sessionId) !== generation) return;
488
+ mark(scope, void 0, void 0, void 0);
489
+ }).catch((error) => {
490
+ if (generations.get(scope.sessionId) !== generation) return;
491
+ host.onNotice(`worktree command failed for ${scope.sessionId} (${failureText(error)})`);
492
+ mark(scope, void 0, failureText(error), errorTargetFor(command));
493
+ }).finally(() => {
494
+ if (generations.get(scope.sessionId) === generation) busy.delete(scope.sessionId);
495
+ });
496
+ };
497
+ return source;
498
+ },
499
+ receive(scope, payload) {
500
+ receiveCommand?.(scope, payload);
501
+ }
502
+ };
503
+ }
504
+ //#endregion
505
+ //#region src/extensions/(backend)/channel/git-worktrees.server.ts
506
+ var git_worktrees_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineChannel)(createWorktreesChannel);
507
+ //#endregion
508
+ //#region src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.ts
509
+ var doompiGit_server_default$1 = (context) => context.root.resources[0];
510
+ //#endregion
511
+ //#region src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.ts
512
+ var doompiGit_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)(doompiGit_server_default$1);
513
+ //#endregion
514
+ //#region src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.ts
515
+ var doompiGitReadme_server_default$1 = (context) => context.root.resources[2];
516
+ //#endregion
517
+ //#region src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.ts
518
+ var doompiGitReadme_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)(doompiGitReadme_server_default$1);
519
+ //#endregion
520
+ //#region src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.ts
521
+ var doompiUseGit_server_default$1 = (context) => context.root.resources[1];
522
+ //#endregion
523
+ //#region src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.ts
524
+ var doompiUseGit_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)(doompiUseGit_server_default$1);
525
+ //#endregion
526
+ //#region src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.ts
527
+ var runWorktree_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineServerTool)((context) => context.root.tool);
528
+ //#endregion
529
+ //#region generated/server.ts
530
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
531
+ const via = (identity, value) => value === void 0 ? void 0 : {
532
+ ...identity,
533
+ ...value
534
+ };
535
+ const facet = (0, _agimon_ai_doompi_core_serverFacet.defineServerPlugin)({
536
+ name: "@agimon-ai/doompi-git",
537
+ global: (context) => ({
538
+ get api() {
539
+ return [at(route_server_default, context)];
540
+ },
541
+ get channels() {
542
+ return [() => via({ frameType: "git_worktrees" }, git_worktrees_server_default())];
543
+ }
544
+ }),
545
+ workspace: (context) => ({
546
+ get api() {
547
+ return [at(route_server_default, context)];
548
+ },
549
+ get channels() {
550
+ return [() => via({ frameType: "git_worktrees" }, git_worktrees_server_default())];
551
+ }
552
+ }),
553
+ session: async (context) => {
554
+ const scopeSession = await root_server_default(context);
555
+ const contextSession = {
556
+ ...context,
557
+ root: scopeSession.value
558
+ };
559
+ return {
560
+ ...(0, _agimon_ai_doompi_core_extensionFile.composeRootHooks)(scopeSession),
561
+ get api() {
562
+ return [at(route_server_default, context)];
563
+ },
564
+ get channels() {
565
+ return [() => via({ frameType: "git_worktrees" }, git_worktrees_server_default())];
566
+ },
567
+ get resources() {
568
+ return [
569
+ at(doompiGit_server_default, contextSession),
570
+ at(doompiGitReadme_server_default, contextSession),
571
+ at(doompiUseGit_server_default, contextSession)
572
+ ];
573
+ },
574
+ get tools() {
575
+ return [via({ name: "run_worktree" }, at(runWorktree_server_default, contextSession))];
576
+ },
577
+ services: [...scopeSession.services ?? []],
578
+ get activities() {
579
+ return [...scopeSession.activities ?? []];
580
+ }
581
+ };
582
+ }
583
+ });
584
+ //#endregion
585
+ exports.default = facet;
586
+ exports.facet = facet;
587
+
588
+ //# sourceMappingURL=server.cjs.map