@jmfederico/pi-web 1.202608.0 → 1.202608.2
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 +4 -4
- package/dist/cli.js +287 -113
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/CodeViewer-BMWwxG7q.js +4 -0
- package/dist/client/assets/{TerminalPanel-fYrKc3jh.js → TerminalPanel-CacQDIYn.js} +6 -6
- package/dist/client/assets/index-DUW2xnoV.js +4279 -0
- package/dist/client/assets/vendor-editor-core-CXO8gGab.js +12 -0
- package/dist/client/assets/vendor-editor-languages-CpW4sJsX.js +46 -0
- package/dist/client/index.html +3 -3
- package/dist/config.js +110 -73
- package/dist/config.js.map +1 -1
- package/dist/docker/piWebDockerCommandPlan.js +4 -3
- package/dist/docker/piWebDockerCommandPlan.js.map +1 -1
- package/dist/environment.js +4 -0
- package/dist/environment.js.map +1 -0
- package/dist/nativeServices/installedServiceDefinitions.js +602 -0
- package/dist/nativeServices/installedServiceDefinitions.js.map +1 -0
- package/dist/nativeServices/serviceAction.js +174 -0
- package/dist/nativeServices/serviceAction.js.map +1 -0
- package/dist/nativeServices/serviceDoctor.js +374 -71
- package/dist/nativeServices/serviceDoctor.js.map +1 -1
- package/dist/nativeServices/servicePlan.js +1 -1
- package/dist/nativeServices/servicePlan.js.map +1 -1
- package/dist/{pi-web-plugins → pi-packages}/relays/markdownDocument.js +1 -1
- package/dist/pi-packages/relays/package.json +11 -0
- package/dist/{pi-web-plugins → pi-packages}/relays/pi-web-plugin.js +4 -4
- package/dist/pi-packages/relays/prompts/relay-worktree.md +157 -0
- package/dist/pi-packages/relays/prompts/relay.md +152 -0
- package/dist/{pi-web-plugins → pi-packages}/relays/relayDiscovery.js +1 -1
- package/dist/{pi-web-plugins → pi-packages}/relays/relaysPanelElement.js +1 -1
- package/dist/pi-packages/relays/skills/relay/SKILL.md +123 -0
- package/dist/pi-web-plugins/git/browser/git-contract.js +108 -0
- package/dist/pi-web-plugins/git/browser/git-panel.js +609 -0
- package/dist/pi-web-plugins/git/browser/gitFileList.js +43 -0
- package/dist/pi-web-plugins/git/browser/gitFileShared.js +16 -0
- package/dist/pi-web-plugins/git/browser/gitFileTree.js +81 -0
- package/dist/pi-web-plugins/git/browser/gitFileViewPreference.js +35 -0
- package/dist/pi-web-plugins/git/browser/gitRoute.js +42 -0
- package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +10 -0
- package/dist/pi-web-plugins/git/browser/unifiedDiff.js +301 -0
- package/dist/{server/git/gitService.js → pi-web-plugins/git/git-backend.js} +209 -60
- package/dist/pi-web-plugins/git/package.json +16 -0
- package/dist/pi-web-plugins/git/server-plugin.js +176 -0
- package/dist/pi-web-plugins/info/infoInternals.js +16 -2
- package/dist/pi-web-plugins/info/package.json +1 -1
- package/dist/pi-web-plugins/info/pi-web-plugin.js +2 -2
- package/dist/pi-web-plugins/updates/package.json +1 -1
- package/dist/pi-web-plugins/updates/pi-web-plugin.js +1 -1
- package/dist/pi-web-plugins/workspace-tasks/package.json +1 -1
- package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +3 -3
- package/dist/piWebVersionReport.js +63 -10
- package/dist/piWebVersionReport.js.map +1 -1
- package/dist/plugin-api.d.ts +33 -16
- package/dist/pluginRecoveryCli.js +172 -0
- package/dist/pluginRecoveryCli.js.map +1 -0
- package/dist/server/activity/workspaceActivityService.js +27 -19
- package/dist/server/activity/workspaceActivityService.js.map +1 -1
- package/dist/server/app.js +41 -15
- package/dist/server/app.js.map +1 -1
- package/dist/server/configRoutes.js +3 -21
- package/dist/server/configRoutes.js.map +1 -1
- package/dist/server/knownAutoInstallPiPackages.js +30 -0
- package/dist/server/knownAutoInstallPiPackages.js.map +1 -0
- package/dist/server/machines/machineClient.js +23 -4
- package/dist/server/machines/machineClient.js.map +1 -1
- package/dist/server/machines/machinePluginProxyRoutes.js +74 -17
- package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -1
- package/dist/server/machines/machineProxyRoutes.js +165 -8
- package/dist/server/machines/machineProxyRoutes.js.map +1 -1
- package/dist/server/machines/machineService.js +23 -0
- package/dist/server/machines/machineService.js.map +1 -1
- package/dist/server/piPackageIdentity.js +25 -0
- package/dist/server/piPackageIdentity.js.map +1 -0
- package/dist/server/piPackageService.js +69 -8
- package/dist/server/piPackageService.js.map +1 -1
- package/dist/server/piWebPluginCatalog.js +584 -0
- package/dist/server/piWebPluginCatalog.js.map +1 -0
- package/dist/server/piWebPluginLifecycle.js +162 -0
- package/dist/server/piWebPluginLifecycle.js.map +1 -0
- package/dist/server/piWebPluginService.js +159 -261
- package/dist/server/piWebPluginService.js.map +1 -1
- package/dist/server/piWebStatus.js +41 -9
- package/dist/server/piWebStatus.js.map +1 -1
- package/dist/server/plugins/pluginBackendProxyRoutes.js +69 -0
- package/dist/server/plugins/pluginBackendProxyRoutes.js.map +1 -0
- package/dist/server/plugins/serverPluginExec.js +184 -0
- package/dist/server/plugins/serverPluginExec.js.map +1 -0
- package/dist/server/plugins/serverPluginRuntime.js +480 -0
- package/dist/server/plugins/serverPluginRuntime.js.map +1 -0
- package/dist/server/projectTrustRoutes.js +80 -0
- package/dist/server/projectTrustRoutes.js.map +1 -0
- package/dist/server/projects/projectService.js +3 -1
- package/dist/server/projects/projectService.js.map +1 -1
- package/dist/server/realtime/sessionEventHub.js +26 -11
- package/dist/server/realtime/sessionEventHub.js.map +1 -1
- package/dist/server/requestCancellation.js +32 -0
- package/dist/server/requestCancellation.js.map +1 -0
- package/dist/server/sessiond/agentProcessEnvironment.js +29 -30
- package/dist/server/sessiond/agentProcessEnvironment.js.map +1 -1
- package/dist/server/sessiond/autoInstallPiPackages.js +63 -0
- package/dist/server/sessiond/autoInstallPiPackages.js.map +1 -0
- package/dist/server/sessiond/pluginBackendRoutes.js +64 -0
- package/dist/server/sessiond/pluginBackendRoutes.js.map +1 -0
- package/dist/server/sessiond/sessionDaemonShutdown.js +24 -0
- package/dist/server/sessiond/sessionDaemonShutdown.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +2 -2
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessiond/sessionServiceDependencies.js +2 -1
- package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -1
- package/dist/server/sessiond/sessiondStateOwnership.js +235 -0
- package/dist/server/sessiond/sessiondStateOwnership.js.map +1 -0
- package/dist/server/sessiond/workspaceCatalogRoutes.js +31 -0
- package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -0
- package/dist/server/sessiond/workspaceRemovalRoutes.js +41 -0
- package/dist/server/sessiond/workspaceRemovalRoutes.js.map +1 -0
- package/dist/server/sessiond.js +284 -98
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/authService.js +15 -54
- package/dist/server/sessions/authService.js.map +1 -1
- package/dist/server/sessions/dockerEnvironmentFacts.js +254 -0
- package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -0
- package/dist/server/sessions/modelCatalogRefresher.js +4 -3
- package/dist/server/sessions/modelCatalogRefresher.js.map +1 -1
- package/dist/server/sessions/piSessionManagerGateway.js +18 -67
- package/dist/server/sessions/piSessionManagerGateway.js.map +1 -1
- package/dist/server/sessions/piSessionService.js +495 -142
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionCommandService.js +24 -1
- package/dist/server/sessions/sessionCommandService.js.map +1 -1
- package/dist/server/sessions/sessionEnvironmentFacts.js +48 -0
- package/dist/server/sessions/sessionEnvironmentFacts.js.map +1 -0
- package/dist/server/sessions/sessionFileFormat.js +27 -0
- package/dist/server/sessions/sessionFileFormat.js.map +1 -0
- package/dist/server/sessions/sessionFileHeader.js +1 -14
- package/dist/server/sessions/sessionFileHeader.js.map +1 -1
- package/dist/server/sessions/sessionModelScope.js +160 -0
- package/dist/server/sessions/sessionModelScope.js.map +1 -0
- package/dist/server/sessions/sessionNameGenerator.js +6 -6
- package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
- package/dist/server/sessions/sessionRoutes.js +55 -0
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/sessions/sessionSummaryScanner.js +96 -224
- package/dist/server/sessions/sessionSummaryScanner.js.map +1 -1
- package/dist/server/sessions/spawnSubsessionTool.js +5 -9
- package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
- package/dist/server/sessions/spawnTargetResolver.js +1 -1
- package/dist/server/status/machineStatusRoutes.js +8 -0
- package/dist/server/status/machineStatusRoutes.js.map +1 -0
- package/dist/server/status/machineStatusService.js +181 -0
- package/dist/server/status/machineStatusService.js.map +1 -0
- package/dist/server/status/workspaceAttribution.js +87 -0
- package/dist/server/status/workspaceAttribution.js.map +1 -0
- package/dist/server/storage/piPackageDismissalStore.js +78 -0
- package/dist/server/storage/piPackageDismissalStore.js.map +1 -0
- package/dist/server/terminalProxyRoutes.js +2 -1
- package/dist/server/terminalProxyRoutes.js.map +1 -1
- package/dist/server/workspaceExplorerRoutes.js +20 -13
- package/dist/server/workspaceExplorerRoutes.js.map +1 -1
- package/dist/server/workspaces/fileContentService.js +18 -9
- package/dist/server/workspaces/fileContentService.js.map +1 -1
- package/dist/server/workspaces/filePreviewResponseHeaders.js +18 -0
- package/dist/server/workspaces/filePreviewResponseHeaders.js.map +1 -0
- package/dist/server/workspaces/filePreviewResponsePolicy.js +55 -0
- package/dist/server/workspaces/filePreviewResponsePolicy.js.map +1 -0
- package/dist/server/workspaces/filePreviewService.js +81 -0
- package/dist/server/workspaces/filePreviewService.js.map +1 -0
- package/dist/server/workspaces/projectWorkspaceCwds.js +0 -5
- package/dist/server/workspaces/projectWorkspaceCwds.js.map +1 -1
- package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +402 -0
- package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -0
- package/dist/server/workspaces/workspaceCatalog.js +47 -0
- package/dist/server/workspaces/workspaceCatalog.js.map +1 -0
- package/dist/server/workspaces/workspaceContext.js +1 -3
- package/dist/server/workspaces/workspaceContext.js.map +1 -1
- package/dist/server/workspaces/workspaceDeletionRoutes.js +35 -125
- package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -1
- package/dist/server/workspaces/workspaceProviderRegistry.js +651 -0
- package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -0
- package/dist/server/workspaces/workspaceRemovalService.js +256 -0
- package/dist/server/workspaces/workspaceRemovalService.js.map +1 -0
- package/dist/server/workspaces/workspaceRouteErrors.js +7 -0
- package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -0
- package/dist/server/workspaces/worktreePreRemoveHook.js +39 -0
- package/dist/server/workspaces/worktreePreRemoveHook.js.map +1 -0
- package/dist/server-plugin-api.d.ts +140 -0
- package/dist/server-plugin-api.js +2 -0
- package/dist/server-plugin-api.js.map +1 -0
- package/dist/serverPluginRecovery.js +138 -0
- package/dist/serverPluginRecovery.js.map +1 -0
- package/dist/sessiond/activeAgentProfile.js +3 -22
- package/dist/sessiond/activeAgentProfile.js.map +1 -1
- package/dist/sessiond/config.js +11 -0
- package/dist/sessiond/config.js.map +1 -1
- package/dist/sessiond/sessionDaemonClient.js +11 -9
- package/dist/sessiond/sessionDaemonClient.js.map +1 -1
- package/dist/shared/activeAgentProfile.js +2 -41
- package/dist/shared/activeAgentProfile.js.map +1 -1
- package/dist/shared/activity.js +0 -3
- package/dist/shared/activity.js.map +1 -1
- package/dist/shared/apiTypes.js +7 -5
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/capabilities.js +8 -6
- package/dist/shared/capabilities.js.map +1 -1
- package/dist/shared/federatedRoutes.js +36 -5
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/dist/shared/machinePluginIds.js +4 -2
- package/dist/shared/machinePluginIds.js.map +1 -1
- package/dist/shared/machineStatus.js +94 -0
- package/dist/shared/machineStatus.js.map +1 -0
- package/dist/shared/piWebStatusParsing.js +33 -0
- package/dist/shared/piWebStatusParsing.js.map +1 -1
- package/dist/shared/pluginApiTypes.d.ts +150 -0
- package/dist/shared/pluginApiTypes.js +3 -0
- package/dist/shared/pluginApiTypes.js.map +1 -0
- package/dist/shared/pluginBackendProtocol.js +110 -0
- package/dist/shared/pluginBackendProtocol.js.map +1 -0
- package/dist/shared/pluginIds.js +5 -0
- package/dist/shared/pluginIds.js.map +1 -1
- package/dist/shared/pluginRecoveryCommands.js +14 -0
- package/dist/shared/pluginRecoveryCommands.js.map +1 -0
- package/dist/shared/workspaceFiles.js +41 -2
- package/dist/shared/workspaceFiles.js.map +1 -1
- package/dist/shared/workspaceRemovalProtocol.js +24 -0
- package/dist/shared/workspaceRemovalProtocol.js.map +1 -0
- package/docs/config.md +105 -52
- package/docs/plugins.md +403 -146
- package/examples/workspace-provider-plugin/README.md +52 -0
- package/examples/workspace-provider-plugin/package.json +25 -0
- package/examples/workspace-provider-plugin/src/browser/index.ts +69 -0
- package/examples/workspace-provider-plugin/src/server.ts +64 -0
- package/examples/workspace-provider-plugin/tsconfig.json +21 -0
- package/package.json +30 -11
- package/server-plugin-api.d.ts +1 -0
- package/dist/client/assets/CodeViewer-D91Sp61M.js +0 -4
- package/dist/client/assets/UnifiedDiffViewer-BafLWGtF.js +0 -39
- package/dist/client/assets/index-CA8q9_o7.js +0 -4025
- package/dist/client/assets/vendor-editor-core-vUi74DnD.js +0 -12
- package/dist/client/assets/vendor-editor-languages-DoaXUodB.js +0 -46
- package/dist/pi-web-plugins/relays/package.json +0 -9
- package/dist/plugin-api/unstable.d.ts +0 -22
- package/dist/server/activity/workspaceActivityRoutes.js +0 -4
- package/dist/server/activity/workspaceActivityRoutes.js.map +0 -1
- package/dist/server/git/gitService.js.map +0 -1
- package/dist/server/gitRoutes.js +0 -23
- package/dist/server/gitRoutes.js.map +0 -1
- package/dist/server/sessions/parentSessionLocator.js +0 -75
- package/dist/server/sessions/parentSessionLocator.js.map +0 -1
- package/dist/server/workspaces/gitWorktreeDiscovery.js +0 -43
- package/dist/server/workspaces/gitWorktreeDiscovery.js.map +0 -1
- package/dist/server/workspaces/imagePreviewService.js +0 -40
- package/dist/server/workspaces/imagePreviewService.js.map +0 -1
- package/dist/server/workspaces/workspaceService.js +0 -52
- package/dist/server/workspaces/workspaceService.js.map +0 -1
- package/dist/shared/apiTypes.d.ts +0 -1217
- package/dist/shared/thinkingLevels.d.ts +0 -27
- package/plugin-api/unstable.d.ts +0 -1
- /package/dist/{pi-web-plugins → pi-packages}/relays/vendor/README.md +0 -0
- /package/dist/{pi-web-plugins → pi-packages}/relays/vendor/marked.esm.js +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { deleteWorkspaceFile, moveWorkspaceFile, readWorkspaceFile, writeWorkspaceFile } from "./workspaces/fileContentService.js";
|
|
2
2
|
import { isAbsoluteishFileSuggestionQuery, listFileSuggestions, listPathSuggestions } from "./workspaces/fileSuggestions.js";
|
|
3
3
|
import { listWorkspaceTree } from "./workspaces/fileTreeService.js";
|
|
4
|
-
import {
|
|
4
|
+
import { readWorkspaceFilePreview } from "./workspaces/filePreviewService.js";
|
|
5
|
+
import { workspaceFilePreviewResponsePolicy } from "./workspaces/filePreviewResponsePolicy.js";
|
|
6
|
+
import { applyWorkspaceFilePreviewErrorResponsePolicy } from "./workspaces/filePreviewResponseHeaders.js";
|
|
5
7
|
import { resolveWorkspaceContext } from "./workspaces/workspaceContext.js";
|
|
6
8
|
import { pathAccessForWorkspaceContext } from "./workspaces/effectivePathAccess.js";
|
|
9
|
+
import { sendWorkspaceRequestError } from "./workspaces/workspaceRouteErrors.js";
|
|
7
10
|
export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefix = "/api", options = {}) {
|
|
8
11
|
registerWorkspaceFileContentParsers(app);
|
|
9
12
|
app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/tree`, async (request, reply) => {
|
|
@@ -12,7 +15,7 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
12
15
|
return await listWorkspaceTree(context.root, request.query.path, await pathAccessForWorkspaceContext(context, options.config));
|
|
13
16
|
}
|
|
14
17
|
catch (error) {
|
|
15
|
-
return reply
|
|
18
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
16
19
|
}
|
|
17
20
|
});
|
|
18
21
|
app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/file`, async (request, reply) => {
|
|
@@ -21,7 +24,7 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
21
24
|
return await readWorkspaceFile(context.root, request.query.path, await pathAccessForWorkspaceContext(context, options.config));
|
|
22
25
|
}
|
|
23
26
|
catch (error) {
|
|
24
|
-
return reply
|
|
27
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
25
28
|
}
|
|
26
29
|
});
|
|
27
30
|
app.put(`${prefix}/projects/:projectId/workspaces/:workspaceId/file`, async (request, reply) => {
|
|
@@ -34,7 +37,7 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
34
37
|
return await writeWorkspaceFile(context.root, request.query.path, request.body, writeOptions);
|
|
35
38
|
}
|
|
36
39
|
catch (error) {
|
|
37
|
-
return reply
|
|
40
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
38
41
|
}
|
|
39
42
|
});
|
|
40
43
|
app.delete(`${prefix}/projects/:projectId/workspaces/:workspaceId/file`, async (request, reply) => {
|
|
@@ -43,7 +46,7 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
43
46
|
return await deleteWorkspaceFile(context.root, request.query.path);
|
|
44
47
|
}
|
|
45
48
|
catch (error) {
|
|
46
|
-
return reply
|
|
49
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
47
50
|
}
|
|
48
51
|
});
|
|
49
52
|
app.post(`${prefix}/projects/:projectId/workspaces/:workspaceId/file/move`, async (request, reply) => {
|
|
@@ -55,24 +58,28 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
55
58
|
});
|
|
56
59
|
}
|
|
57
60
|
catch (error) {
|
|
58
|
-
return reply
|
|
61
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
64
|
app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/file/preview`, async (request, reply) => {
|
|
62
65
|
try {
|
|
63
66
|
const context = await resolveWorkspaceContext(projects, workspaces, request.params.projectId, request.params.workspaceId);
|
|
64
|
-
const
|
|
67
|
+
const download = request.query.download === "1" || request.query.download === "true";
|
|
68
|
+
const preview = await readWorkspaceFilePreview(context.root, request.query.path, await pathAccessForWorkspaceContext(context, options.config), { download });
|
|
69
|
+
const policy = workspaceFilePreviewResponsePolicy(preview.path, { download });
|
|
65
70
|
return await reply
|
|
66
|
-
.
|
|
71
|
+
.header("Content-Type", policy.contentType)
|
|
67
72
|
.header("Cache-Control", "private, max-age=3600")
|
|
68
73
|
.header("Content-Length", String(preview.size))
|
|
69
|
-
.header("Content-
|
|
74
|
+
.header("Content-Disposition", policy.contentDisposition)
|
|
75
|
+
.header("Content-Security-Policy", policy.contentSecurityPolicy)
|
|
70
76
|
.header("Last-Modified", new Date(preview.modifiedAt).toUTCString())
|
|
71
|
-
.header("X-Content-Type-Options",
|
|
72
|
-
.send(preview.
|
|
77
|
+
.header("X-Content-Type-Options", policy.contentTypeOptions)
|
|
78
|
+
.send(preview.body);
|
|
73
79
|
}
|
|
74
80
|
catch (error) {
|
|
75
|
-
|
|
81
|
+
applyWorkspaceFilePreviewErrorResponsePolicy(reply);
|
|
82
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
76
83
|
}
|
|
77
84
|
});
|
|
78
85
|
app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/files`, async (request, reply) => {
|
|
@@ -85,7 +92,7 @@ export function registerWorkspaceExplorerRoutes(app, projects, workspaces, prefi
|
|
|
85
92
|
return await listFileSuggestions(context.root, query, { kind: request.query.kind, scope: request.query.scope, pathAccess });
|
|
86
93
|
}
|
|
87
94
|
catch (error) {
|
|
88
|
-
return reply
|
|
95
|
+
return sendWorkspaceRequestError(reply, error, 400);
|
|
89
96
|
}
|
|
90
97
|
});
|
|
91
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaceExplorerRoutes.js","sourceRoot":"","sources":["../../src/server/workspaceExplorerRoutes.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACnI,OAAO,EAAE,gCAAgC,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7H,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"workspaceExplorerRoutes.js","sourceRoot":"","sources":["../../src/server/workspaceExplorerRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { lstat, mkdir, open, realpath, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { classifyWorkspaceFile, MAX_WORKSPACE_FILE_CONTENT_BYTES } from "../../shared/workspaceFiles.js";
|
|
4
4
|
import { resolveWorkspacePathAccessTarget } from "./pathAccessPolicy.js";
|
|
5
5
|
import { ensureInside, isNodeErrorWithCode, resolveInsideWorkspace, resolveParentInsideWorkspace } from "./pathSafety.js";
|
|
6
|
-
const MAX_BYTES = 512 * 1024;
|
|
7
6
|
export async function readWorkspaceFile(rootPath, path, pathAccess) {
|
|
8
7
|
if (path === undefined || path === "")
|
|
9
8
|
throw new Error("path query parameter is required");
|
|
@@ -11,10 +10,14 @@ export async function readWorkspaceFile(rootPath, path, pathAccess) {
|
|
|
11
10
|
const s = await stat(target);
|
|
12
11
|
if (!s.isFile())
|
|
13
12
|
throw new Error("Path is not a file");
|
|
14
|
-
const bytesToRead = Math.min(s.size,
|
|
13
|
+
const bytesToRead = Math.min(s.size, MAX_WORKSPACE_FILE_CONTENT_BYTES);
|
|
15
14
|
const buffer = await readFilePrefix(target, bytesToRead);
|
|
16
|
-
const
|
|
17
|
-
const
|
|
15
|
+
const classification = classifyWorkspaceFile(displayPath);
|
|
16
|
+
const media = mediaForClassification(classification);
|
|
17
|
+
// Text-source formats (HTML, Markdown, SVG) retain capped literal UTF-8
|
|
18
|
+
// source for Raw mode. Raster image and PDF bytes stay out of JSON and are
|
|
19
|
+
// served only by the preview response.
|
|
20
|
+
const binary = classification?.source === "stream" || (classification === undefined && isProbablyBinary(buffer));
|
|
18
21
|
return {
|
|
19
22
|
path: displayPath,
|
|
20
23
|
...languageForPath(displayPath),
|
|
@@ -23,7 +26,7 @@ export async function readWorkspaceFile(rootPath, path, pathAccess) {
|
|
|
23
26
|
size: s.size,
|
|
24
27
|
modifiedAt: s.mtime.toISOString(),
|
|
25
28
|
content: binary ? "" : buffer.toString("utf8"),
|
|
26
|
-
truncated: s.size >
|
|
29
|
+
truncated: s.size > MAX_WORKSPACE_FILE_CONTENT_BYTES,
|
|
27
30
|
binary,
|
|
28
31
|
};
|
|
29
32
|
}
|
|
@@ -162,7 +165,9 @@ function languageForPath(path) {
|
|
|
162
165
|
jsx: "javascript",
|
|
163
166
|
json: "json",
|
|
164
167
|
md: "markdown",
|
|
168
|
+
markdown: "markdown",
|
|
165
169
|
css: "css",
|
|
170
|
+
htm: "html",
|
|
166
171
|
html: "html",
|
|
167
172
|
py: "python",
|
|
168
173
|
rs: "rust",
|
|
@@ -174,8 +179,12 @@ function languageForPath(path) {
|
|
|
174
179
|
const language = ext === undefined ? undefined : languages[ext];
|
|
175
180
|
return language === undefined ? {} : { language };
|
|
176
181
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
function mediaForClassification(classification) {
|
|
183
|
+
if (classification === undefined)
|
|
184
|
+
return {};
|
|
185
|
+
return {
|
|
186
|
+
mediaType: classification.mediaType,
|
|
187
|
+
...("previewMimeType" in classification ? { mimeType: classification.previewMimeType } : {}),
|
|
188
|
+
};
|
|
180
189
|
}
|
|
181
190
|
//# sourceMappingURL=fileContentService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileContentService.js","sourceRoot":"","sources":["../../../src/server/workspaces/fileContentService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fileContentService.js","sourceRoot":"","sources":["../../../src/server/workspaces/fileContentService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { workspaceFilePreviewErrorResponsePolicy } from "./filePreviewResponsePolicy.js";
|
|
2
|
+
/** Writes a preview response policy onto a reply, so local and proxied previews emit the identical contract. */
|
|
3
|
+
export function applyWorkspaceFilePreviewResponsePolicy(reply, policy) {
|
|
4
|
+
return reply
|
|
5
|
+
.header("Content-Type", policy.contentType)
|
|
6
|
+
.header("Content-Disposition", policy.contentDisposition)
|
|
7
|
+
.header("Content-Security-Policy", policy.contentSecurityPolicy)
|
|
8
|
+
.header("X-Content-Type-Options", policy.contentTypeOptions);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Hardens a failed preview response. Preview URLs are navigated directly by the
|
|
12
|
+
* browser, so an error body carrying attacker-influenced path text must never be
|
|
13
|
+
* sniffable into active content, on either the local or the remote route.
|
|
14
|
+
*/
|
|
15
|
+
export function applyWorkspaceFilePreviewErrorResponsePolicy(reply) {
|
|
16
|
+
return applyWorkspaceFilePreviewResponsePolicy(reply, workspaceFilePreviewErrorResponsePolicy());
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=filePreviewResponseHeaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filePreviewResponseHeaders.js","sourceRoot":"","sources":["../../../src/server/workspaces/filePreviewResponseHeaders.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uCAAuC,EAA2C,MAAM,gCAAgC,CAAC;AAElI,gHAAgH;AAChH,MAAM,UAAU,uCAAuC,CAAC,KAAmB,EAAE,MAA0C;IACrH,OAAO,KAAK;SACT,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,WAAW,CAAC;SAC1C,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,kBAAkB,CAAC;SACxD,MAAM,CAAC,yBAAyB,EAAE,MAAM,CAAC,qBAAqB,CAAC;SAC/D,MAAM,CAAC,wBAAwB,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4CAA4C,CAAC,KAAmB;IAC9E,OAAO,uCAAuC,CAAC,KAAK,EAAE,uCAAuC,EAAE,CAAC,CAAC;AACnG,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { classifyWorkspaceFile, workspaceFileName } from "../../shared/workspaceFiles.js";
|
|
2
|
+
const IMAGE_CONTENT_SECURITY_POLICY = "sandbox; default-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; script-src 'none'; connect-src 'none'; img-src data: blob:; media-src 'none'; font-src 'none'; style-src 'unsafe-inline'; worker-src 'none'; frame-ancestors 'self'";
|
|
3
|
+
const HTML_CONTENT_SECURITY_POLICY = "sandbox; default-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; script-src 'none'; connect-src 'none'; img-src data:; media-src 'none'; font-src 'none'; style-src 'unsafe-inline'; worker-src 'none'; frame-ancestors 'self'";
|
|
4
|
+
// Native PDF viewers refuse to run in any sandboxed context, so this policy
|
|
5
|
+
// deliberately omits the `sandbox` directive and the embedding frame omits the
|
|
6
|
+
// sandbox attribute. Isolation comes from the response itself: `application/pdf`
|
|
7
|
+
// plus `nosniff` means these bytes can only reach the browser's PDF handler and
|
|
8
|
+
// can never become an active same-origin document, while `default-src 'none'`
|
|
9
|
+
// denies scripts, navigation helpers, and every subresource except the
|
|
10
|
+
// same-origin plugin document (`object-src 'self'`) that the viewer embeds.
|
|
11
|
+
const PDF_CONTENT_SECURITY_POLICY = "default-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; object-src 'self'; script-src 'none'; connect-src 'none'; img-src 'none'; media-src 'none'; font-src 'none'; style-src 'none'; worker-src 'none'; frame-ancestors 'self'";
|
|
12
|
+
const DOWNLOAD_CONTENT_SECURITY_POLICY = "sandbox; default-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; script-src 'none'; connect-src 'none'; img-src 'none'; media-src 'none'; font-src 'none'; style-src 'none'; worker-src 'none'; frame-ancestors 'none'";
|
|
13
|
+
const ERROR_CONTENT_SECURITY_POLICY = "sandbox; default-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; object-src 'none'; script-src 'none'; connect-src 'none'; img-src 'none'; media-src 'none'; font-src 'none'; style-src 'none'; worker-src 'none'; frame-ancestors 'self'";
|
|
14
|
+
export function workspaceFilePreviewResponsePolicy(path, options = {}) {
|
|
15
|
+
const filename = workspaceFileName(path);
|
|
16
|
+
if (filename === "")
|
|
17
|
+
throw new Error("Workspace file path must include a filename");
|
|
18
|
+
if (options.download === true) {
|
|
19
|
+
return responsePolicy("application/octet-stream", "attachment", filename, DOWNLOAD_CONTENT_SECURITY_POLICY);
|
|
20
|
+
}
|
|
21
|
+
const classification = classifyWorkspaceFile(path);
|
|
22
|
+
if (classification === undefined || !("previewMimeType" in classification)) {
|
|
23
|
+
throw new Error("Inline preview is not supported for this file type");
|
|
24
|
+
}
|
|
25
|
+
const contentSecurityPolicy = classification.mediaType === "image"
|
|
26
|
+
? IMAGE_CONTENT_SECURITY_POLICY
|
|
27
|
+
: classification.mediaType === "html"
|
|
28
|
+
? HTML_CONTENT_SECURITY_POLICY
|
|
29
|
+
: PDF_CONTENT_SECURITY_POLICY;
|
|
30
|
+
return responsePolicy(classification.previewMimeType, "inline", filename, contentSecurityPolicy);
|
|
31
|
+
}
|
|
32
|
+
function responsePolicy(contentType, disposition, filename, contentSecurityPolicy) {
|
|
33
|
+
return {
|
|
34
|
+
contentType,
|
|
35
|
+
contentDisposition: contentDisposition(disposition, filename),
|
|
36
|
+
contentSecurityPolicy,
|
|
37
|
+
contentTypeOptions: "nosniff",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function workspaceFilePreviewErrorResponsePolicy() {
|
|
41
|
+
return {
|
|
42
|
+
contentType: "application/json; charset=utf-8",
|
|
43
|
+
contentDisposition: "inline",
|
|
44
|
+
contentSecurityPolicy: ERROR_CONTENT_SECURITY_POLICY,
|
|
45
|
+
contentTypeOptions: "nosniff",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function contentDisposition(disposition, filename) {
|
|
49
|
+
const asciiFallback = filename.replace(/[^\x20-\x7e]|["\\]/gu, "_");
|
|
50
|
+
return `${disposition}; filename="${asciiFallback}"; filename*=UTF-8''${encodeRfc5987Value(filename)}`;
|
|
51
|
+
}
|
|
52
|
+
function encodeRfc5987Value(value) {
|
|
53
|
+
return encodeURIComponent(value).replace(/['()*]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=filePreviewResponsePolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filePreviewResponsePolicy.js","sourceRoot":"","sources":["../../../src/server/workspaces/filePreviewResponsePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAS1F,MAAM,6BAA6B,GAAG,4QAA4Q,CAAC;AACnT,MAAM,4BAA4B,GAAG,sQAAsQ,CAAC;AAC5S,4EAA4E;AAC5E,+EAA+E;AAC/E,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,uEAAuE;AACvE,4EAA4E;AAC5E,MAAM,2BAA2B,GAAG,qPAAqP,CAAC;AAC1R,MAAM,gCAAgC,GAAG,8PAA8P,CAAC;AACxS,MAAM,6BAA6B,GAAG,8PAA8P,CAAC;AAErS,MAAM,UAAU,kCAAkC,CAAC,IAAY,EAAE,UAAkC,EAAE;IACnG,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACpF,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,cAAc,CAAC,0BAA0B,EAAE,YAAY,EAAE,QAAQ,EAAE,gCAAgC,CAAC,CAAC;IAC9G,CAAC;IAED,MAAM,cAAc,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,cAAc,KAAK,SAAS,IAAI,CAAC,CAAC,iBAAiB,IAAI,cAAc,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,qBAAqB,GAAG,cAAc,CAAC,SAAS,KAAK,OAAO;QAChE,CAAC,CAAC,6BAA6B;QAC/B,CAAC,CAAC,cAAc,CAAC,SAAS,KAAK,MAAM;YACnC,CAAC,CAAC,4BAA4B;YAC9B,CAAC,CAAC,2BAA2B,CAAC;IAClC,OAAO,cAAc,CAAC,cAAc,CAAC,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;AACnG,CAAC;AAED,SAAS,cAAc,CAAC,WAAmB,EAAE,WAAoC,EAAE,QAAgB,EAAE,qBAA6B;IAChI,OAAO;QACL,WAAW;QACX,kBAAkB,EAAE,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC;QAC7D,qBAAqB;QACrB,kBAAkB,EAAE,SAAS;KAC9B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uCAAuC;IACrD,OAAO;QACL,WAAW,EAAE,iCAAiC;QAC9C,kBAAkB,EAAE,QAAQ;QAC5B,qBAAqB,EAAE,6BAA6B;QACpD,kBAAkB,EAAE,SAAS;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAoC,EAAE,QAAgB;IAChF,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IACpE,OAAO,GAAG,WAAW,eAAe,aAAa,uBAAuB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AACzG,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAChI,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { open } from "node:fs/promises";
|
|
2
|
+
import { pipeline, Transform } from "node:stream";
|
|
3
|
+
import { classifyWorkspaceFile, MAX_INLINE_PREVIEW_BYTES, MAX_INLINE_PREVIEW_LABEL, workspaceFileName } from "../../shared/workspaceFiles.js";
|
|
4
|
+
import { resolveWorkspacePathAccessTarget } from "./pathAccessPolicy.js";
|
|
5
|
+
export async function readWorkspaceFilePreview(rootPath, path, pathAccess, options = {}) {
|
|
6
|
+
if (path === undefined || path === "")
|
|
7
|
+
throw new Error("path query parameter is required");
|
|
8
|
+
const { target, displayPath } = await resolveWorkspacePathAccessTarget(rootPath, path, pathAccess);
|
|
9
|
+
// Serve only from this descriptor. Path resolution is a snapshot: a rename,
|
|
10
|
+
// symlink swap, or resize after validation must not be able to change which
|
|
11
|
+
// bytes this response carries, how many of them it carries, or whether they
|
|
12
|
+
// are still inside the workspace or an allowed root.
|
|
13
|
+
const handle = await open(target, "r");
|
|
14
|
+
let streamOwnsHandle = false;
|
|
15
|
+
try {
|
|
16
|
+
const stats = await handle.stat();
|
|
17
|
+
if (!stats.isFile())
|
|
18
|
+
throw new Error("Path is not a file");
|
|
19
|
+
const metadata = { path: displayPath, filename: workspaceFileName(displayPath), modifiedAt: stats.mtime.toISOString() };
|
|
20
|
+
// Download mode serves any file as an opaque octet-stream attachment. No
|
|
21
|
+
// size cap: the response is streamed, and the browser writes it straight to
|
|
22
|
+
// disk. The stream still cannot exceed the validated size.
|
|
23
|
+
if (options.download === true) {
|
|
24
|
+
if (stats.size === 0)
|
|
25
|
+
return { ...metadata, size: 0, body: Buffer.alloc(0) };
|
|
26
|
+
streamOwnsHandle = true;
|
|
27
|
+
return { ...metadata, size: stats.size, body: validatedFileStream(handle, stats.size) };
|
|
28
|
+
}
|
|
29
|
+
const classification = classifyWorkspaceFile(displayPath);
|
|
30
|
+
if (classification === undefined || !("previewMimeType" in classification))
|
|
31
|
+
throw new Error("Inline preview is not supported for this file type");
|
|
32
|
+
if (stats.size > MAX_INLINE_PREVIEW_BYTES)
|
|
33
|
+
throw new Error(`File is too large to preview (limit ${MAX_INLINE_PREVIEW_LABEL})`);
|
|
34
|
+
const body = await readValidatedSnapshot(handle, stats.size);
|
|
35
|
+
return { ...metadata, mediaType: classification.mediaType, size: body.byteLength, body };
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
if (!streamOwnsHandle)
|
|
39
|
+
await handle.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read exactly the validated number of bytes. Growth after validation is
|
|
44
|
+
* ignored, and a file that shrank fails the request before any header is sent
|
|
45
|
+
* instead of desynchronizing the advertised length.
|
|
46
|
+
*/
|
|
47
|
+
async function readValidatedSnapshot(handle, size) {
|
|
48
|
+
if (size === 0)
|
|
49
|
+
return Buffer.alloc(0);
|
|
50
|
+
const buffer = Buffer.alloc(size);
|
|
51
|
+
let offset = 0;
|
|
52
|
+
while (offset < size) {
|
|
53
|
+
const { bytesRead } = await handle.read(buffer, offset, size - offset, offset);
|
|
54
|
+
if (bytesRead === 0)
|
|
55
|
+
throw new Error("File changed while it was being read");
|
|
56
|
+
offset += bytesRead;
|
|
57
|
+
}
|
|
58
|
+
return buffer;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stream the validated byte range from the open descriptor. Extra bytes written
|
|
62
|
+
* after validation are never sent, and a short read fails the response instead
|
|
63
|
+
* of silently truncating an advertised `Content-Length`.
|
|
64
|
+
*/
|
|
65
|
+
function validatedFileStream(handle, size) {
|
|
66
|
+
const source = handle.createReadStream({ start: 0, end: size - 1, autoClose: true });
|
|
67
|
+
let streamed = 0;
|
|
68
|
+
const exactLength = new Transform({
|
|
69
|
+
transform(chunk, _encoding, done) {
|
|
70
|
+
streamed += chunk.byteLength;
|
|
71
|
+
done(null, chunk);
|
|
72
|
+
},
|
|
73
|
+
flush(done) {
|
|
74
|
+
done(streamed === size ? null : new Error("File changed while it was being read"));
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
// The callback keeps a teardown failure from becoming an unhandled error; the
|
|
78
|
+
// returned stream still emits it, which fails the in-flight response.
|
|
79
|
+
return pipeline(source, exactLength, () => { });
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=filePreviewService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filePreviewService.js","sourceRoot":"","sources":["../../../src/server/workspaces/filePreviewService.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,9 +14,4 @@ export class RegisteredProjectWorkspaceCwds {
|
|
|
14
14
|
return undefined;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
/** Workspace paths of `cwd`'s project other than `cwd` itself. */
|
|
18
|
-
export async function siblingWorkspaceCwds(locator, cwd) {
|
|
19
|
-
const paths = await locator.forCwd(cwd);
|
|
20
|
-
return (paths ?? []).filter((path) => !cwdPathsEqual(path, cwd));
|
|
21
|
-
}
|
|
22
17
|
//# sourceMappingURL=projectWorkspaceCwds.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectWorkspaceCwds.js","sourceRoot":"","sources":["../../../src/server/workspaces/projectWorkspaceCwds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAgCvD,MAAM,OAAO,8BAA8B;IACzC,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC5D,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QACnE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF
|
|
1
|
+
{"version":3,"file":"projectWorkspaceCwds.js","sourceRoot":"","sources":["../../../src/server/workspaces/projectWorkspaceCwds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAgCvD,MAAM,OAAO,8BAA8B;IACzC,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC5D,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QACnE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|