@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.
- package/README.md +12 -0
- package/dist/apiContracts.cjs +198 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +193 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/extensions/pi.cjs +105 -1
- package/dist/extensions/pi.cjs.map +1 -0
- package/dist/extensions/pi.d.mts +6 -2
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +100 -1
- package/dist/extensions/pi.mjs.map +1 -0
- package/dist/extensions/server.cjs +588 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +583 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +911 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/gitDependencies-CJFmhrG1.mjs +22 -0
- package/dist/gitDependencies-CJFmhrG1.mjs.map +1 -0
- package/dist/gitDependencies-CWsygnLQ.cjs +33 -0
- package/dist/gitDependencies-CWsygnLQ.cjs.map +1 -0
- package/dist/index-D79MSCee.d.mts +145 -0
- package/dist/index-D79MSCee.d.mts.map +1 -0
- package/dist/index.cjs +4 -1
- package/dist/index.d.mts +2 -5
- package/dist/index.mjs +2 -1
- package/dist/runWorktree-BdK3oRtX.mjs +298 -0
- package/dist/runWorktree-BdK3oRtX.mjs.map +1 -0
- package/dist/runWorktree-D0bsyYc0.cjs +351 -0
- package/dist/runWorktree-D0bsyYc0.cjs.map +1 -0
- package/dist/worktreeOperations-CijBzYEf.mjs +1163 -0
- package/dist/worktreeOperations-CijBzYEf.mjs.map +1 -0
- package/dist/worktreeOperations-FJDk44Zt.cjs +1253 -0
- package/dist/worktreeOperations-FJDk44Zt.cjs.map +1 -0
- package/llms.txt +4 -0
- package/package.json +54 -39
- package/src/prompts/doompi-use-git/SKILL.md +26 -3
- package/dist/_virtual/_rolldown/runtime.cjs +0 -1
- package/dist/adapters/channel/worktreeChannel.cjs +0 -2
- package/dist/adapters/channel/worktreeChannel.cjs.map +0 -1
- package/dist/adapters/channel/worktreeChannel.d.cts +0 -40
- package/dist/adapters/channel/worktreeChannel.d.cts.map +0 -1
- package/dist/adapters/channel/worktreeChannel.d.mts +0 -40
- package/dist/adapters/channel/worktreeChannel.d.mts.map +0 -1
- package/dist/adapters/channel/worktreeChannel.mjs +0 -2
- package/dist/adapters/channel/worktreeChannel.mjs.map +0 -1
- package/dist/adapters/filesystem/atomicJson.cjs +0 -2
- package/dist/adapters/filesystem/atomicJson.cjs.map +0 -1
- package/dist/adapters/filesystem/atomicJson.mjs +0 -2
- package/dist/adapters/filesystem/atomicJson.mjs.map +0 -1
- package/dist/adapters/filesystem/paths.cjs +0 -2
- package/dist/adapters/filesystem/paths.cjs.map +0 -1
- package/dist/adapters/filesystem/paths.mjs +0 -2
- package/dist/adapters/filesystem/paths.mjs.map +0 -1
- package/dist/adapters/hub/hubClient.cjs +0 -2
- package/dist/adapters/hub/hubClient.cjs.map +0 -1
- package/dist/adapters/hub/hubClient.d.cts +0 -1
- package/dist/adapters/hub/hubClient.d.mts +0 -1
- package/dist/adapters/hub/hubClient.mjs +0 -2
- package/dist/adapters/hub/hubClient.mjs.map +0 -1
- package/dist/adapters/pi/extension.cjs +0 -2
- package/dist/adapters/pi/extension.cjs.map +0 -1
- package/dist/adapters/pi/extension.d.cts +0 -9
- package/dist/adapters/pi/extension.d.cts.map +0 -1
- package/dist/adapters/pi/extension.d.mts +0 -9
- package/dist/adapters/pi/extension.d.mts.map +0 -1
- package/dist/adapters/pi/extension.mjs +0 -2
- package/dist/adapters/pi/extension.mjs.map +0 -1
- package/dist/adapters/pi/extensions/runWorktreeTool.cjs +0 -15
- package/dist/adapters/pi/extensions/runWorktreeTool.cjs.map +0 -1
- package/dist/adapters/pi/extensions/runWorktreeTool.mjs +0 -15
- package/dist/adapters/pi/extensions/runWorktreeTool.mjs.map +0 -1
- package/dist/adapters/web/worktreesChannel.cjs +0 -2
- package/dist/adapters/web/worktreesChannel.cjs.map +0 -1
- package/dist/adapters/web/worktreesChannel.d.cts +0 -21
- package/dist/adapters/web/worktreesChannel.d.cts.map +0 -1
- package/dist/adapters/web/worktreesChannel.d.mts +0 -21
- package/dist/adapters/web/worktreesChannel.d.mts.map +0 -1
- package/dist/adapters/web/worktreesChannel.mjs +0 -2
- package/dist/adapters/web/worktreesChannel.mjs.map +0 -1
- package/dist/adapters/worktree/dependencyInstall.cjs +0 -2
- package/dist/adapters/worktree/dependencyInstall.cjs.map +0 -1
- package/dist/adapters/worktree/dependencyInstall.mjs +0 -2
- package/dist/adapters/worktree/dependencyInstall.mjs.map +0 -1
- package/dist/adapters/worktree/gitCli.cjs +0 -4
- package/dist/adapters/worktree/gitCli.cjs.map +0 -1
- package/dist/adapters/worktree/gitCli.mjs +0 -4
- package/dist/adapters/worktree/gitCli.mjs.map +0 -1
- package/dist/adapters/worktree/repositoryIdentity.cjs +0 -2
- package/dist/adapters/worktree/repositoryIdentity.cjs.map +0 -1
- package/dist/adapters/worktree/repositoryIdentity.mjs +0 -2
- package/dist/adapters/worktree/repositoryIdentity.mjs.map +0 -1
- package/dist/adapters/worktree/worktreeOperations.cjs +0 -2
- package/dist/adapters/worktree/worktreeOperations.cjs.map +0 -1
- package/dist/adapters/worktree/worktreeOperations.d.cts +0 -32
- package/dist/adapters/worktree/worktreeOperations.d.cts.map +0 -1
- package/dist/adapters/worktree/worktreeOperations.d.mts +0 -32
- package/dist/adapters/worktree/worktreeOperations.d.mts.map +0 -1
- package/dist/adapters/worktree/worktreeOperations.mjs +0 -2
- package/dist/adapters/worktree/worktreeOperations.mjs.map +0 -1
- package/dist/adapters/worktree/worktreeRegistry.cjs +0 -2
- package/dist/adapters/worktree/worktreeRegistry.cjs.map +0 -1
- package/dist/adapters/worktree/worktreeRegistry.mjs +0 -2
- package/dist/adapters/worktree/worktreeRegistry.mjs.map +0 -1
- package/dist/commands/doomGitCommand.cjs +0 -2
- package/dist/commands/doomGitCommand.cjs.map +0 -1
- package/dist/commands/doomGitCommand.mjs +0 -2
- package/dist/commands/doomGitCommand.mjs.map +0 -1
- package/dist/container/index.cjs +0 -2
- package/dist/container/index.cjs.map +0 -1
- package/dist/container/index.d.cts +0 -6
- package/dist/container/index.d.cts.map +0 -1
- package/dist/container/index.d.mts +0 -6
- package/dist/container/index.d.mts.map +0 -1
- package/dist/container/index.mjs +0 -2
- package/dist/container/index.mjs.map +0 -1
- package/dist/extensions/pi.d.cts +0 -2
- package/dist/hubApi.cjs +0 -2
- package/dist/hubApi.cjs.map +0 -1
- package/dist/hubApi.d.cts +0 -6
- package/dist/hubApi.d.cts.map +0 -1
- package/dist/hubApi.d.mts +0 -6
- package/dist/hubApi.d.mts.map +0 -1
- package/dist/hubApi.mjs +0 -2
- package/dist/hubApi.mjs.map +0 -1
- package/dist/index.d.cts +0 -5
- package/dist/schemas/runWorktreeTool.cjs +0 -2
- package/dist/schemas/runWorktreeTool.cjs.map +0 -1
- package/dist/schemas/runWorktreeTool.mjs +0 -2
- package/dist/schemas/runWorktreeTool.mjs.map +0 -1
- package/dist/services/extensionService.cjs +0 -2
- package/dist/services/extensionService.cjs.map +0 -1
- package/dist/services/extensionService.d.cts +0 -8
- package/dist/services/extensionService.d.cts.map +0 -1
- package/dist/services/extensionService.d.mts +0 -8
- package/dist/services/extensionService.d.mts.map +0 -1
- package/dist/services/extensionService.mjs +0 -2
- package/dist/services/extensionService.mjs.map +0 -1
- package/dist/services/support/errors.cjs +0 -2
- package/dist/services/support/errors.cjs.map +0 -1
- package/dist/services/support/errors.mjs +0 -2
- package/dist/services/support/errors.mjs.map +0 -1
- package/dist/services/worktreeNaming.cjs +0 -2
- package/dist/services/worktreeNaming.cjs.map +0 -1
- package/dist/services/worktreeNaming.d.cts +0 -27
- package/dist/services/worktreeNaming.d.cts.map +0 -1
- package/dist/services/worktreeNaming.d.mts +0 -27
- package/dist/services/worktreeNaming.d.mts.map +0 -1
- package/dist/services/worktreeNaming.mjs +0 -2
- package/dist/services/worktreeNaming.mjs.map +0 -1
- package/dist/types/extension.d.cts +0 -17
- package/dist/types/extension.d.cts.map +0 -1
- package/dist/types/extension.d.mts +0 -17
- package/dist/types/extension.d.mts.map +0 -1
- package/dist/types/webWorktrees.cjs +0 -2
- package/dist/types/webWorktrees.cjs.map +0 -1
- package/dist/types/webWorktrees.mjs +0 -2
- package/dist/types/webWorktrees.mjs.map +0 -1
- package/dist/types/worktreeRegistry.d.cts +0 -41
- package/dist/types/worktreeRegistry.d.cts.map +0 -1
- package/dist/types/worktreeRegistry.d.mts +0 -41
- package/dist/types/worktreeRegistry.d.mts.map +0 -1
- package/dist/webHub.cjs +0 -1
- package/dist/webHub.d.cts +0 -2
- package/dist/webHub.d.mts +0 -2
- package/dist/webHub.mjs +0 -1
- package/src/exports/webClient.ts +0 -1
- package/src/types/webWorktrees.ts +0 -55
- package/src/types/worktreeRegistry.ts +0 -69
- package/src/web/components/RunWorktreeToolMessage.tsx +0 -37
- package/src/web/components/WorktreesActivitySection.tsx +0 -64
- package/src/web/components/WorktreesPanel.tsx +0 -125
- package/src/web/components/toolRenderers.ts +0 -7
- package/src/web/index.ts +0 -30
- package/src/web/stores/worktreesActivityStore.ts +0 -124
- 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
|