@aiworker/web 1.22.2 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +7 -0
- package/dist/assets/{CodeMirrorCommentWidgets-CSICpWQD.js → CodeMirrorCommentWidgets-teB3HmBT.js} +1 -1
- package/dist/assets/DiffView-DC9RX3MF.js +4 -0
- package/dist/assets/{DirtyBranchSwitchDialog-C22HdWj4.js → DirtyBranchSwitchDialog-DwPkzXsS.js} +1 -1
- package/dist/assets/FilesView-BFZkuu4O.js +13 -0
- package/dist/assets/{GitView-VQQkYuUw.js → GitView-B_x52MHY.js} +4 -4
- package/dist/assets/{JsonTreeView-6lrhwD3q.js → JsonTreeView-cmAzUTiw.js} +1 -1
- package/dist/assets/{LinearIssuesView-Ba6Q9569.js → LinearIssuesView-Dehh5afm.js} +1 -1
- package/dist/assets/MarkdownImageGallery-DgNOqqhE.js +1 -0
- package/dist/assets/MarkdownRendererImpl-DusmMZ_p.js +12 -0
- package/dist/assets/OnboardingScreen-B8fm1H4m.js +1 -0
- package/dist/assets/{PatchDiff-BzcZPlOq.js → PatchDiff-BVr7gJU0.js} +1 -1
- package/dist/assets/PierreDiffViewer-DzLt-nel.js +161 -0
- package/dist/assets/PlanView-BmQUYT_z.js +5 -0
- package/dist/assets/SettingsView-ChWmAcZT.js +28 -0
- package/dist/assets/{SettingsWindow-DDQYaKWQ.js → SettingsWindow-Dy3M6ZB9.js} +1 -1
- package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
- package/dist/assets/{ToolOutputDialog-iYF8Y2bz.js → ToolOutputDialog-cTl_eLIH.js} +5 -5
- package/dist/assets/{ToolPartDiffPreview-CdjbOVMM.js → ToolPartDiffPreview-C_3iYNJQ.js} +1 -1
- package/dist/assets/{VirtualizedFileDiff-fFFm2QgH.js → VirtualizedFileDiff-CAWthkoy.js} +4 -4
- package/dist/assets/WalkthroughView-C7AHOpCA.js +4 -0
- package/dist/assets/{computeVirtualFileMetrics-CzgLum_K.js → computeVirtualFileMetrics-BkiDSlTW.js} +2 -2
- package/dist/assets/contextPanelEmbeddedChat-BdA6bdky.js +1 -0
- package/dist/assets/de-DJsQr-p7.js +10 -0
- package/dist/assets/es-BuYMlA9g.js +16 -0
- package/dist/assets/fr-ePDay33C.js +14 -0
- package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
- package/dist/assets/index-BD8ILbxF.js +40 -0
- package/dist/assets/{index-Bl3LSbjn.js → index-n6O3hklM.js} +1 -1
- package/dist/assets/index-zhgg-SDz.css +1 -0
- package/dist/assets/{isDiffPlainText-Dx-dB_8l.js → isDiffPlainText-GMdPz-71.js} +1 -1
- package/dist/assets/{isFilePlainText-CWFPwmnU.js → isFilePlainText-BVuH1zH9.js} +1 -1
- package/dist/assets/ja-BzR9xOY_.js +16 -0
- package/dist/assets/ko-BEjHAm14.js +16 -0
- package/dist/assets/main-BydQ1tr_.js +930 -0
- package/dist/assets/{main-DnBAoktx.js → main-D3ZDQglc.js} +2 -2
- package/dist/assets/markdownCore-Cb2MdZnV.js +5 -0
- package/dist/assets/{miniChat-BKyvLseN.js → miniChat-d01k801U.js} +2 -2
- package/dist/assets/{mobile-DKjeFgMN.js → mobile-D7VV-Ufz.js} +2 -2
- package/dist/assets/patchFileDiff-CdztVMz0.js +13 -0
- package/dist/assets/pl-rQmpxNIF.js +16 -0
- package/dist/assets/pt-BR-CorbsSW-.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-BGG9UIlh.js +2 -0
- package/dist/assets/renderMobileApp-BRP3J1iv.js +25 -0
- package/dist/assets/runtimeEndpointReset-BhT_-c52.js +41 -0
- package/dist/assets/scheduledTasksApi-BEuUF_cj.js +1 -0
- package/dist/assets/{shikiHighlight-TEQCmzW8.js → shikiHighlight-BzXUjlby.js} +1 -1
- package/dist/assets/surface-COKb77Ua.js +1 -0
- package/dist/assets/tr-CoAMXPtI.js +7 -0
- package/dist/assets/uk-YlAX0rRU.js +16 -0
- package/dist/assets/{useAppFontEffects-D7sNpuL2.js → useAppFontEffects-Cwyhjfl5.js} +141 -140
- package/dist/assets/useGitComparison-BCZVefdE.js +1 -0
- package/dist/assets/useInlineCommentController-DDkpBEU8.js +2 -0
- package/dist/assets/useRootScrollLock-CwjoWuC4.js +1 -0
- package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-BY_5qla_.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-data-Dp3KMRQG.js → vendor-codemirror-language-data-Cb1YnICj.js} +2 -2
- package/dist/assets/vendor-legendapp-list-BuBPBC3R.js +1 -0
- package/dist/assets/vendor-zod-B6551dwG.js +39 -0
- package/dist/assets/{web-components-_mNEMjFY.js → web-components-LV3vjTxy.js} +1 -1
- package/dist/assets/zh-CN-DDYg0Jl7.js +16 -0
- package/dist/assets/zh-TW-CQKaCayr.js +16 -0
- package/dist/index.html +5 -43
- package/dist/mini-chat.html +4 -4
- package/dist/mobile.html +4 -4
- package/package.json +2 -3
- package/server/index.d.ts +15 -0
- package/server/index.js +48 -22
- package/server/lib/agent-memory/runtime.js +7 -2
- package/server/lib/agent-memory/runtime.test.js +22 -0
- package/server/lib/data-dir-migration.js +40 -0
- package/server/lib/data-dir-migration.test.js +59 -0
- package/server/lib/event-stream/DOCUMENTATION.md +3 -0
- package/server/lib/event-stream/global-hub.js +29 -4
- package/server/lib/event-stream/global-hub.test.js +22 -0
- package/server/lib/event-stream/global-ws-bridge.js +15 -18
- package/server/lib/event-stream/protocol.js +21 -7
- package/server/lib/event-stream/runtime.js +9 -6
- package/server/lib/event-stream/runtime.test.js +72 -12
- package/server/lib/fs/DOCUMENTATION.md +3 -0
- package/server/lib/fs/routes.js +31 -0
- package/server/lib/fs/routes.test.js +110 -1
- package/server/lib/git/DOCUMENTATION.md +39 -6
- package/server/lib/git/routes.js +45 -12
- package/server/lib/git/routes.test.js +78 -0
- package/server/lib/git/service.js +343 -202
- package/server/lib/git/service.test.js +496 -25
- package/server/lib/github/DOCUMENTATION.md +5 -0
- package/server/lib/github/routes.js +2 -2
- package/server/lib/inherited-env.js +16 -9
- package/server/lib/inherited-env.test.js +8 -9
- package/server/lib/message-queue/DOCUMENTATION.md +11 -1
- package/server/lib/message-queue/runtime.js +13 -0
- package/server/lib/message-queue/runtime.test.js +31 -1
- package/server/lib/network-defaults.js +23 -0
- package/server/lib/network-defaults.test.js +52 -0
- package/server/lib/notifications/DOCUMENTATION.md +1 -1
- package/server/lib/notifications/emitter-runtime.js +4 -3
- package/server/lib/opencode/DOCUMENTATION.md +35 -5
- package/server/lib/opencode/bootstrap-runtime.js +2 -0
- package/server/lib/opencode/env-runtime.js +5 -1
- package/server/lib/opencode/env-runtime.test.js +72 -0
- package/server/lib/opencode/feature-routes-runtime.js +17 -1
- package/server/lib/opencode/lifecycle.js +4 -3
- package/server/lib/opencode/lifecycle.test.js +29 -0
- package/server/lib/opencode/managed-plugin-config.js +1 -1
- package/server/lib/opencode/openchamber-routes.js +64 -4
- package/server/lib/opencode/openchamber-routes.test.js +128 -1
- package/server/lib/opencode/proxy.js +33 -0
- package/server/lib/opencode/routes.js +5 -3
- package/server/lib/opencode/settings-files.js +214 -0
- package/server/lib/opencode/settings-helpers.js +88 -41
- package/server/lib/opencode/settings-helpers.test.js +176 -1
- package/server/lib/opencode/settings-registry.json +750 -0
- package/server/lib/opencode/settings-runtime.js +175 -27
- package/server/lib/opencode/settings-runtime.test.js +321 -7
- package/server/lib/project-context/DOCUMENTATION.md +38 -4
- package/server/lib/project-context/routes.http.test.js +18 -0
- package/server/lib/project-context/routes.js +15 -0
- package/server/lib/project-context/runtime.js +256 -25
- package/server/lib/project-context/runtime.test.js +160 -3
- package/server/lib/projects/DOCUMENTATION.md +77 -0
- package/server/lib/projects/project-config.js +179 -17
- package/server/lib/projects/project-config.test.js +97 -0
- package/server/lib/projects/project-id.js +43 -0
- package/server/lib/projects/project-setup.js +409 -0
- package/server/lib/projects/project-setup.test.js +557 -0
- package/server/lib/projects/routes.js +59 -0
- package/server/lib/quota/DOCUMENTATION.md +31 -1
- package/server/lib/quota/providers/cline-pass.js +125 -0
- package/server/lib/quota/providers/cline-pass.test.js +103 -0
- package/server/lib/quota/providers/index.js +7 -0
- package/server/lib/quota/providers/neuralwatt.js +3 -6
- package/server/lib/quota/providers/neuralwatt.test.js +7 -7
- package/server/lib/quota/providers/ollama-cloud.js +31 -0
- package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
- package/server/lib/quota/providers/opencode-go.js +1 -1
- package/server/lib/quota/providers/opencode-go.test.js +26 -1
- package/server/lib/quota/providers/openrouter.js +119 -24
- package/server/lib/quota/providers/openrouter.test.js +330 -0
- package/server/lib/relay/DOCUMENTATION.md +75 -0
- package/server/lib/relay/cross-compat.test.js +26 -0
- package/server/lib/relay/downstream-scheduler.js +154 -0
- package/server/lib/relay/downstream-scheduler.test.js +162 -0
- package/server/lib/relay/e2ee.js +10 -8
- package/server/lib/relay/flow-control.test.js +177 -0
- package/server/lib/relay/host-client.js +44 -8
- package/server/lib/relay/host-client.test.js +14 -0
- package/server/lib/relay/tunnel-codec.js +9 -0
- package/server/lib/relay/tunnel-host.js +66 -17
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +9 -1
- package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +28 -0
- package/server/lib/scheduled-tasks/runtime.js +12 -2
- package/server/lib/scheduled-tasks/runtime.test.js +53 -0
- package/server/lib/session-assist/DOCUMENTATION.md +131 -66
- package/server/lib/session-assist/context.js +127 -0
- package/server/lib/session-assist/context.test.js +132 -0
- package/server/lib/session-assist/prompt.js +54 -0
- package/server/lib/session-assist/runtime.js +117 -267
- package/server/lib/session-assist/runtime.test.js +203 -0
- package/server/lib/session-goal/runtime.js +4 -9
- package/server/lib/small-model/DOCUMENTATION.md +3 -2
- package/server/lib/small-model/call.js +9 -4
- package/server/lib/small-model/call.test.js +29 -0
- package/server/lib/small-model/index.js +5 -10
- package/server/lib/small-model/runtime-providers.js +15 -7
- package/server/lib/small-model/runtime-providers.test.js +7 -1
- package/server/lib/terminal/DOCUMENTATION.md +4 -4
- package/server/lib/terminal/runtime.js +11 -6
- package/server/lib/terminal/runtime.test.js +20 -13
- package/server/lib/walkthrough/DOCUMENTATION.md +49 -20
- package/server/lib/walkthrough/model-settings.js +8 -12
- package/server/lib/walkthrough/pr-source.test.js +21 -0
- package/server/lib/walkthrough/prompt.js +3 -1
- package/server/lib/walkthrough/pull-request.js +7 -4
- package/server/lib/walkthrough/pull-request.test.js +16 -0
- package/server/lib/walkthrough/routes.js +19 -0
- package/server/lib/walkthrough/routes.test.js +26 -0
- package/server/lib/walkthrough/sources.js +36 -4
- package/server/opencode-worktree-readiness.test.js +130 -0
- package/dist/assets/DiffView-hDBKesA_.js +0 -4
- package/dist/assets/FilesView-CdWzeOp9.js +0 -17
- package/dist/assets/MarkdownImageGallery-Czv_mhvS.js +0 -1
- package/dist/assets/MarkdownRendererImpl-BrMcswiy.js +0 -12
- package/dist/assets/OnboardingScreen-ChxQoAkx.js +0 -1
- package/dist/assets/PierreDiffViewer-BchBtZlp.js +0 -157
- package/dist/assets/PlanView-DyDt_nZ_.js +0 -5
- package/dist/assets/SettingsView-BKf5xBsP.js +0 -28
- package/dist/assets/WalkthroughView-DOeCsMju.js +0 -4
- package/dist/assets/contextPanelEmbeddedChat-C0ZLAepL.js +0 -1
- package/dist/assets/de-B5JaA3SA.js +0 -10
- package/dist/assets/es-EPIH88ii.js +0 -16
- package/dist/assets/fr-CAMfxUdZ.js +0 -14
- package/dist/assets/index-DF5kMP-i.js +0 -39
- package/dist/assets/index-Dl3xbAB_.css +0 -1
- package/dist/assets/ja-CifOE1VN.js +0 -16
- package/dist/assets/ko-BBDyAyYQ.js +0 -16
- package/dist/assets/main-MhSaOZoB.js +0 -930
- package/dist/assets/markdownCore-BrBwOOMn.js +0 -3
- package/dist/assets/patchFileDiff-o8ms1me8.js +0 -10
- package/dist/assets/pl-DgEHYfFM.js +0 -16
- package/dist/assets/pt-BR-DuWHojUw.js +0 -16
- package/dist/assets/renderElectronMiniChatApp-CDgBwwCS.js +0 -2
- package/dist/assets/renderMobileApp-DJIKIK1r.js +0 -25
- package/dist/assets/runtimeEndpointReset-CYJ9O_xX.js +0 -17
- package/dist/assets/scheduledTasksApi-D8yamh1b.js +0 -1
- package/dist/assets/tr-D5m2yIWL.js +0 -7
- package/dist/assets/uk-D_q60oog.js +0 -16
- package/dist/assets/useInlineCommentController-Brz_cLcQ.js +0 -2
- package/dist/assets/useRootScrollLock-lXEnWlaU.js +0 -1
- package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
- package/dist/assets/vendor-legendapp-list-gg7YLRW7.js +0 -1
- package/dist/assets/vendor-zod-CK21ihK-.js +0 -39
- package/dist/assets/zh-CN-D8QvsVeg.js +0 -16
- package/dist/assets/zh-TW-B9t7rQQO.js +0 -16
- package/server/lib/mcp-reconnect/DOCUMENTATION.md +0 -55
- package/server/lib/mcp-reconnect/runtime.js +0 -122
- package/server/lib/mcp-reconnect/runtime.test.js +0 -140
package/server/lib/git/routes.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
export function registerGitRoutes(app) {
|
|
1
|
+
export function registerGitRoutes(app, { emitWorktreeChanged } = {}) {
|
|
2
2
|
let gitLibraries = null;
|
|
3
3
|
const getGitLibraries = async () => {
|
|
4
4
|
if (!gitLibraries) {
|
|
5
5
|
gitLibraries = await import('./index.js');
|
|
6
|
+
if (emitWorktreeChanged) {
|
|
7
|
+
gitLibraries.subscribeWorktreeTopologyChanges(emitWorktreeChanged);
|
|
8
|
+
}
|
|
6
9
|
}
|
|
7
10
|
return gitLibraries;
|
|
8
11
|
};
|
|
9
12
|
|
|
10
|
-
const resolveDirectoryQuery = (value) => {
|
|
13
|
+
const resolveDirectoryQuery = (value, preserveWhitespace = false) => {
|
|
11
14
|
const raw = Array.isArray(value) ? value[0] : value;
|
|
12
15
|
if (typeof raw !== 'string') {
|
|
13
16
|
return null;
|
|
14
17
|
}
|
|
15
|
-
const
|
|
16
|
-
return
|
|
18
|
+
const normalized = preserveWhitespace ? raw : raw.trim();
|
|
19
|
+
return normalized || null;
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
const extractGitErrorText = (error) => {
|
|
@@ -220,7 +223,7 @@ export function registerGitRoutes(app) {
|
|
|
220
223
|
});
|
|
221
224
|
|
|
222
225
|
app.get('/api/git/status', async (req, res) => {
|
|
223
|
-
const { getStatus, isGitRepository } = await getGitLibraries();
|
|
226
|
+
const { getStatus, isGitRepository, observeWorktreeTopology } = await getGitLibraries();
|
|
224
227
|
|
|
225
228
|
try {
|
|
226
229
|
const directory = resolveDirectoryQuery(req.query.directory);
|
|
@@ -233,6 +236,11 @@ export function registerGitRoutes(app) {
|
|
|
233
236
|
return res.json(nonRepoStatusPayload());
|
|
234
237
|
}
|
|
235
238
|
|
|
239
|
+
// Clients ask for status while they work in a repository, so this is
|
|
240
|
+
// where an externally added or removed worktree gets noticed. It runs
|
|
241
|
+
// beside the status call and never delays or fails the response.
|
|
242
|
+
void observeWorktreeTopology(directory);
|
|
243
|
+
|
|
236
244
|
const mode = req.query.mode === 'light' ? 'light' : undefined;
|
|
237
245
|
const status = await getStatus(directory, { mode });
|
|
238
246
|
res.json(status);
|
|
@@ -417,6 +425,7 @@ export function registerGitRoutes(app) {
|
|
|
417
425
|
const diff = await getRangeDiff(directory, {
|
|
418
426
|
base,
|
|
419
427
|
head,
|
|
428
|
+
includeWorkingTree: req.query.includeWorkingTree === 'true',
|
|
420
429
|
path: pathParam,
|
|
421
430
|
contextLines: Number.isFinite(context) ? context : 3,
|
|
422
431
|
});
|
|
@@ -463,7 +472,7 @@ export function registerGitRoutes(app) {
|
|
|
463
472
|
return res.status(400).json({ error: 'base and head parameters are required' });
|
|
464
473
|
}
|
|
465
474
|
|
|
466
|
-
const files = await getRangeFiles(directory, { base, head });
|
|
475
|
+
const files = await getRangeFiles(directory, { base, head, includeWorkingTree: req.query.includeWorkingTree === 'true' });
|
|
467
476
|
res.json({ files });
|
|
468
477
|
} catch (error) {
|
|
469
478
|
console.error('Failed to get git range files:', error);
|
|
@@ -1077,7 +1086,7 @@ export function registerGitRoutes(app) {
|
|
|
1077
1086
|
});
|
|
1078
1087
|
|
|
1079
1088
|
app.get('/api/git/worktrees', async (req, res) => {
|
|
1080
|
-
const { getWorktrees } = await getGitLibraries();
|
|
1089
|
+
const { getWorktrees, observeWorktreeTopology } = await getGitLibraries();
|
|
1081
1090
|
try {
|
|
1082
1091
|
const directory = req.query.directory;
|
|
1083
1092
|
if (!directory) {
|
|
@@ -1085,13 +1094,18 @@ export function registerGitRoutes(app) {
|
|
|
1085
1094
|
}
|
|
1086
1095
|
|
|
1087
1096
|
const worktrees = await getWorktrees(directory);
|
|
1097
|
+
// A repository always lists at least its primary worktree; an empty
|
|
1098
|
+
// list means "not a repository" and has no topology to track.
|
|
1099
|
+
if (worktrees.length > 0) {
|
|
1100
|
+
void observeWorktreeTopology(directory);
|
|
1101
|
+
}
|
|
1088
1102
|
res.json(worktrees);
|
|
1089
1103
|
} catch (error) {
|
|
1090
|
-
//
|
|
1091
|
-
//
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
res.json(
|
|
1104
|
+
// A directory outside any repository still answers `[]` from getWorktrees.
|
|
1105
|
+
// Anything else is a real failure the client must not mistake for "no
|
|
1106
|
+
// worktrees", or it would drop the ones it already knows.
|
|
1107
|
+
console.error('Failed to get worktrees:', error);
|
|
1108
|
+
res.status(500).json({ error: error.message || 'Failed to get worktrees' });
|
|
1095
1109
|
}
|
|
1096
1110
|
});
|
|
1097
1111
|
|
|
@@ -1300,6 +1314,25 @@ export function registerGitRoutes(app) {
|
|
|
1300
1314
|
}
|
|
1301
1315
|
});
|
|
1302
1316
|
|
|
1317
|
+
app.get('/api/git/commit-diff', async (req, res) => {
|
|
1318
|
+
const { getCommitDiff } = await getGitLibraries();
|
|
1319
|
+
try {
|
|
1320
|
+
const directory = resolveDirectoryQuery(req.query.directory);
|
|
1321
|
+
const hash = resolveDirectoryQuery(req.query.hash);
|
|
1322
|
+
if (!directory || !hash) return res.status(400).json({ error: 'directory and hash are required' });
|
|
1323
|
+
const context = Number(req.query.context ?? 3);
|
|
1324
|
+
const diff = await getCommitDiff(directory, {
|
|
1325
|
+
hash,
|
|
1326
|
+
path: resolveDirectoryQuery(req.query.path, true) ?? undefined,
|
|
1327
|
+
previousPath: resolveDirectoryQuery(req.query.previousPath, true) ?? undefined,
|
|
1328
|
+
contextLines: Number.isFinite(context) ? context : 3,
|
|
1329
|
+
});
|
|
1330
|
+
res.json({ diff });
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
res.status(500).json({ error: error.message || 'Failed to get commit diff' });
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1303
1336
|
app.get('/api/git/commit-file-diff', async (req, res) => {
|
|
1304
1337
|
const { getCommitFileDiff } = await getGitLibraries();
|
|
1305
1338
|
try {
|
|
@@ -5,6 +5,9 @@ const gitLibraries = {
|
|
|
5
5
|
unstageFiles: vi.fn(),
|
|
6
6
|
isGitRepository: vi.fn(),
|
|
7
7
|
getStatus: vi.fn(),
|
|
8
|
+
getWorktrees: vi.fn(),
|
|
9
|
+
observeWorktreeTopology: vi.fn(),
|
|
10
|
+
subscribeWorktreeTopologyChanges: vi.fn(),
|
|
8
11
|
};
|
|
9
12
|
|
|
10
13
|
vi.mock('./index.js', () => ({
|
|
@@ -12,6 +15,9 @@ vi.mock('./index.js', () => ({
|
|
|
12
15
|
unstageFiles: gitLibraries.unstageFiles,
|
|
13
16
|
isGitRepository: gitLibraries.isGitRepository,
|
|
14
17
|
getStatus: gitLibraries.getStatus,
|
|
18
|
+
getWorktrees: gitLibraries.getWorktrees,
|
|
19
|
+
observeWorktreeTopology: gitLibraries.observeWorktreeTopology,
|
|
20
|
+
subscribeWorktreeTopologyChanges: gitLibraries.subscribeWorktreeTopologyChanges,
|
|
15
21
|
}));
|
|
16
22
|
|
|
17
23
|
const { registerGitRoutes } = await import('./routes.js');
|
|
@@ -141,6 +147,78 @@ describe('git routes index mutations', () => {
|
|
|
141
147
|
});
|
|
142
148
|
});
|
|
143
149
|
|
|
150
|
+
describe('git worktree topology routes', () => {
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
gitLibraries.isGitRepository.mockReset();
|
|
153
|
+
gitLibraries.getStatus.mockReset();
|
|
154
|
+
gitLibraries.getWorktrees.mockReset();
|
|
155
|
+
gitLibraries.observeWorktreeTopology.mockReset();
|
|
156
|
+
gitLibraries.subscribeWorktreeTopologyChanges.mockReset();
|
|
157
|
+
gitLibraries.observeWorktreeTopology.mockResolvedValue(undefined);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('observes the repository topology while serving status, never for non-repositories', async () => {
|
|
161
|
+
gitLibraries.isGitRepository.mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
|
162
|
+
gitLibraries.getStatus.mockResolvedValue({ current: 'main' });
|
|
163
|
+
const { app, getRoute } = createRouteRegistry();
|
|
164
|
+
registerGitRoutes(app);
|
|
165
|
+
const route = getRoute('GET', '/api/git/status');
|
|
166
|
+
|
|
167
|
+
const repoResponse = createMockResponse();
|
|
168
|
+
await route({ query: { directory: '/repo' } }, repoResponse);
|
|
169
|
+
expect(repoResponse.body).toEqual({ current: 'main' });
|
|
170
|
+
expect(gitLibraries.observeWorktreeTopology).toHaveBeenCalledWith('/repo');
|
|
171
|
+
|
|
172
|
+
await route({ query: { directory: '/plain-folder' } }, createMockResponse());
|
|
173
|
+
expect(gitLibraries.observeWorktreeTopology).toHaveBeenCalledTimes(1);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('observes topology after a repository listing and reports listing failures', async () => {
|
|
177
|
+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
178
|
+
gitLibraries.getWorktrees
|
|
179
|
+
.mockResolvedValueOnce([{ path: '/repo', branch: 'main' }])
|
|
180
|
+
.mockResolvedValueOnce([])
|
|
181
|
+
.mockRejectedValueOnce(new Error('git failed'));
|
|
182
|
+
const { app, getRoute } = createRouteRegistry();
|
|
183
|
+
registerGitRoutes(app);
|
|
184
|
+
const route = getRoute('GET', '/api/git/worktrees');
|
|
185
|
+
|
|
186
|
+
const listed = createMockResponse();
|
|
187
|
+
await route({ query: { directory: '/repo' } }, listed);
|
|
188
|
+
expect(listed.body).toEqual([{ path: '/repo', branch: 'main' }]);
|
|
189
|
+
expect(gitLibraries.observeWorktreeTopology).toHaveBeenCalledWith('/repo');
|
|
190
|
+
|
|
191
|
+
await route({ query: { directory: '/plain-folder' } }, createMockResponse());
|
|
192
|
+
expect(gitLibraries.observeWorktreeTopology).toHaveBeenCalledTimes(1);
|
|
193
|
+
|
|
194
|
+
const failed = createMockResponse();
|
|
195
|
+
await route({ query: { directory: '/repo' } }, failed);
|
|
196
|
+
expect(failed.statusCode).toBe(500);
|
|
197
|
+
expect(failed.body).toEqual({ error: 'git failed' });
|
|
198
|
+
errorSpy.mockRestore();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('forwards topology changes to the control event emitter once', async () => {
|
|
202
|
+
let listener = null;
|
|
203
|
+
gitLibraries.subscribeWorktreeTopologyChanges.mockImplementation((next) => {
|
|
204
|
+
listener = next;
|
|
205
|
+
return () => undefined;
|
|
206
|
+
});
|
|
207
|
+
gitLibraries.getWorktrees.mockResolvedValue([]);
|
|
208
|
+
const emitWorktreeChanged = vi.fn();
|
|
209
|
+
const { app, getRoute } = createRouteRegistry();
|
|
210
|
+
registerGitRoutes(app, { emitWorktreeChanged });
|
|
211
|
+
const route = getRoute('GET', '/api/git/worktrees');
|
|
212
|
+
|
|
213
|
+
await route({ query: { directory: '/repo' } }, createMockResponse());
|
|
214
|
+
await route({ query: { directory: '/repo' } }, createMockResponse());
|
|
215
|
+
expect(gitLibraries.subscribeWorktreeTopologyChanges).toHaveBeenCalledTimes(1);
|
|
216
|
+
|
|
217
|
+
listener({ directories: ['/repo'], at: 123 });
|
|
218
|
+
expect(emitWorktreeChanged).toHaveBeenCalledWith({ directories: ['/repo'], at: 123 });
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
144
222
|
describe('git routes status discovery', () => {
|
|
145
223
|
beforeEach(() => {
|
|
146
224
|
gitLibraries.isGitRepository.mockReset();
|