@jmfederico/pi-web 1.202607.3 → 1.202608.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/README.md +4 -4
- package/dist/cli.js +69 -7
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/{CodeViewer-CDVbMiN9.js → CodeViewer-mEiBZFA5.js} +2 -2
- package/dist/client/assets/{TerminalPanel-CTS1CgqF.js → TerminalPanel-O9381Eme.js} +6 -6
- package/dist/client/assets/index-uI2AGFUy.js +4091 -0
- package/dist/client/index.html +1 -1
- package/dist/config.js +109 -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/nativeServices/servicePlan.js +1 -1
- package/dist/nativeServices/servicePlan.js.map +1 -1
- 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 +1 -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/relays/package.json +1 -1
- package/dist/pi-web-plugins/relays/pi-web-plugin.js +3 -3
- package/dist/pi-web-plugins/relays/relayDiscovery.js +159 -27
- package/dist/pi-web-plugins/relays/relaysPanelElement.js +173 -16
- 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/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 +35 -37
- package/dist/server/app.js.map +1 -1
- package/dist/server/browserMessageProjection.js +0 -2
- package/dist/server/browserMessageProjection.js.map +1 -1
- package/dist/server/configRoutes.js +4 -31
- package/dist/server/configRoutes.js.map +1 -1
- 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 +167 -21
- package/dist/server/machines/machineProxyRoutes.js.map +1 -1
- package/dist/server/machines/machineService.js +22 -0
- package/dist/server/machines/machineService.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 +40 -45
- 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/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/agentHttpDispatcher.js +108 -0
- package/dist/server/sessiond/agentHttpDispatcher.js.map +1 -0
- package/dist/server/sessiond/agentProcessEnvironment.js +61 -0
- package/dist/server/sessiond/agentProcessEnvironment.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 +3 -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 +283 -96
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/askUserTool.js +0 -3
- package/dist/server/sessions/askUserTool.js.map +1 -1
- package/dist/server/sessions/authRoutes.js +0 -10
- package/dist/server/sessions/authRoutes.js.map +1 -1
- package/dist/server/sessions/authService.js +15 -78
- 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/messagePaging.js +2 -2
- package/dist/server/sessions/messagePaging.js.map +1 -1
- package/dist/server/sessions/modelCatalogRefresher.js +4 -3
- package/dist/server/sessions/modelCatalogRefresher.js.map +1 -1
- package/dist/server/sessions/oauthLoginFlowService.js +2 -5
- package/dist/server/sessions/oauthLoginFlowService.js.map +1 -1
- package/dist/server/sessions/pendingAskStore.js +0 -3
- package/dist/server/sessions/pendingAskStore.js.map +1 -1
- package/dist/server/sessions/piSessionManagerGateway.js +134 -3
- package/dist/server/sessions/piSessionManagerGateway.js.map +1 -1
- package/dist/server/sessions/piSessionService.js +318 -253
- 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 +82 -23
- package/dist/server/sessions/sessionFileHeader.js.map +1 -1
- package/dist/server/sessions/sessionRoutes.js +88 -56
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/sessions/sessionSummaryScanner.js +491 -0
- package/dist/server/sessions/sessionSummaryScanner.js.map +1 -0
- package/dist/server/sessions/spawnSessionTool.js +8 -1
- package/dist/server/sessions/spawnSessionTool.js.map +1 -1
- package/dist/server/sessions/spawnSubsessionTool.js +11 -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/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/effectivePathAccess.js +0 -19
- package/dist/server/workspaces/effectivePathAccess.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 +39 -103
- 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 +13 -2
- 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 -14
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/capabilities.js +8 -40
- package/dist/shared/capabilities.js.map +1 -1
- package/dist/shared/federatedRoutes.js +28 -8
- 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 +29 -0
- package/dist/shared/piWebStatusParsing.js.map +1 -1
- package/dist/shared/pluginApiTypes.d.ts +148 -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 +140 -47
- package/docs/plugins.md +386 -137
- 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 +32 -12
- package/server-plugin-api.d.ts +1 -0
- package/dist/client/assets/UnifiedDiffViewer-Cqke12ZX.js +0 -39
- package/dist/client/assets/index-LME0LfPb.js +0 -4068
- 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 -1234
- package/dist/shared/thinkingLevels.d.ts +0 -27
- package/plugin-api/unstable.d.ts +0 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# PI WEB dual-entry workspace-provider example
|
|
2
|
+
|
|
3
|
+
This standalone package is a copyable starting point for a trusted PI WEB plugin with both browser API v2 and server API v1 entries. It claims only projects that opt in with a marker file, publishes non-secret metadata to the browser, and demonstrates a browser request routed to the server provider that owns the workspace.
|
|
4
|
+
|
|
5
|
+
The example imports only the supported package declarations:
|
|
6
|
+
|
|
7
|
+
- `@jmfederico/pi-web/plugin-api`
|
|
8
|
+
- `@jmfederico/pi-web/server-plugin-api`
|
|
9
|
+
|
|
10
|
+
It requires PI WEB `1.202608.1` or newer, the first release that provides those entrypoints and browser API v2.
|
|
11
|
+
|
|
12
|
+
## Build and install
|
|
13
|
+
|
|
14
|
+
Copy `examples/workspace-provider-plugin/` out of the PI WEB repository or installed `@jmfederico/pi-web` package, then run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
mkdir -p ~/.pi-web/plugins
|
|
20
|
+
ln -s "$PWD" ~/.pi-web/plugins/example-workspaces
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If `PI_WEB_DATA_DIR` is set, link into `$PI_WEB_DATA_DIR/plugins` instead. The link name must be a valid plugin id and must not collide with another package.
|
|
24
|
+
|
|
25
|
+
Opt one registered PI WEB project into this example provider:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mkdir -p /absolute/path/to/project/.pi-web
|
|
29
|
+
touch /absolute/path/to/project/.pi-web/example-workspace-provider
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then restart the target session daemon and reload the browser:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
systemctl --user restart pi-web-sessiond
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Restarting `pi-web-sessiond.service` may interrupt active sessions and runtime ownership. A browser or web/API restart alone does not activate a server entry.
|
|
39
|
+
|
|
40
|
+
Open the opted-in project. The **Example Provider** panel displays the public marker metadata and its button calls the owning server provider's `summary` operation. Remove the marker and restart sessiond (or trigger a later workspace resolution) to stop claiming that project.
|
|
41
|
+
|
|
42
|
+
## Boundary demonstrated by the package
|
|
43
|
+
|
|
44
|
+
`package.json` declares:
|
|
45
|
+
|
|
46
|
+
- browser module `dist/browser/index.js` with `browserRoot: "dist/browser"`;
|
|
47
|
+
- server module `dist/server.js`, outside the browser root;
|
|
48
|
+
- `machineSpecific: true`, required for a dual browser/server entry.
|
|
49
|
+
|
|
50
|
+
Only files under `dist/browser/` can be served through this plugin's browser asset route. Source, package metadata, the server module, and dependencies remain outside that route. Keep secrets out of `publicMetadata`: it is visible to every browser script and API consumer.
|
|
51
|
+
|
|
52
|
+
The server provider intentionally does not advertise workspace removal. See the canonical plugin guide for removal-plan shell and completion semantics, package limits, federation behavior, and the complete API contract: <https://pi-web.dev/plugins>.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-web-example-workspace-provider",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@jmfederico/pi-web": "^1.202608.1",
|
|
11
|
+
"@types/node": "^24.13.3",
|
|
12
|
+
"typescript": "^6.0.3"
|
|
13
|
+
},
|
|
14
|
+
"piWeb": {
|
|
15
|
+
"plugins": [
|
|
16
|
+
{
|
|
17
|
+
"id": "example-workspaces",
|
|
18
|
+
"browserRoot": "dist/browser",
|
|
19
|
+
"module": "dist/browser/index.js",
|
|
20
|
+
"serverModule": "dist/server.js",
|
|
21
|
+
"machineSpecific": true
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { JsonObject, PiWebPlugin, WorkspacePanelContext } from "@jmfederico/pi-web/plugin-api";
|
|
2
|
+
|
|
3
|
+
const summaries = new Map<string, string>();
|
|
4
|
+
|
|
5
|
+
const plugin: PiWebPlugin = {
|
|
6
|
+
apiVersion: 2,
|
|
7
|
+
name: "Example Workspace Provider",
|
|
8
|
+
activate: ({ pluginId, runtimePluginId, html }) => ({
|
|
9
|
+
contributions: {
|
|
10
|
+
actions: [
|
|
11
|
+
{
|
|
12
|
+
id: "workspace.open",
|
|
13
|
+
title: "Open Example Workspace Provider",
|
|
14
|
+
enabled: ({ state }) => state.selectedWorkspace?.provider?.pluginId === pluginId,
|
|
15
|
+
run: ({ selectWorkspaceTool }) => {
|
|
16
|
+
selectWorkspaceTool(`${runtimePluginId}:workspace.example-provider`);
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
workspacePanels: [
|
|
21
|
+
{
|
|
22
|
+
id: "workspace.example-provider",
|
|
23
|
+
title: "Example Provider",
|
|
24
|
+
visible: ({ workspace }) => workspace.provider?.pluginId === pluginId,
|
|
25
|
+
render: (context) => {
|
|
26
|
+
const marker = stringMetadata(context.workspace.provider?.metadata, "marker") ?? "unknown";
|
|
27
|
+
const summary = summaries.get(workspaceKey(context)) ?? "Request a summary from the owning server plugin.";
|
|
28
|
+
return html`
|
|
29
|
+
<section class="toolbar"><strong>Example workspace provider</strong></section>
|
|
30
|
+
<section class="viewer">
|
|
31
|
+
<p>This workspace is owned by <code>${pluginId}</code>.</p>
|
|
32
|
+
<p class="muted">Claim marker: <code>${marker}</code></p>
|
|
33
|
+
<button
|
|
34
|
+
?disabled=${context.backend === undefined}
|
|
35
|
+
@click=${() => { void refreshSummary(context); }}
|
|
36
|
+
>Request backend summary</button>
|
|
37
|
+
<p aria-live="polite">${summary}</p>
|
|
38
|
+
</section>
|
|
39
|
+
`;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default plugin;
|
|
48
|
+
|
|
49
|
+
async function refreshSummary(context: WorkspacePanelContext): Promise<void> {
|
|
50
|
+
const key = workspaceKey(context);
|
|
51
|
+
try {
|
|
52
|
+
if (context.backend === undefined) throw new Error("The paired workspace backend is unavailable");
|
|
53
|
+
const result = await context.backend.request("summary", null);
|
|
54
|
+
if (typeof result !== "string") throw new Error("The workspace backend returned an invalid summary");
|
|
55
|
+
summaries.set(key, result);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
summaries.set(key, error instanceof Error ? error.message : String(error));
|
|
58
|
+
}
|
|
59
|
+
context.host.requestRender();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function workspaceKey(context: WorkspacePanelContext): string {
|
|
63
|
+
return `${context.machine.id}:${context.workspace.id}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function stringMetadata(metadata: JsonObject | undefined, key: string): string | undefined {
|
|
67
|
+
const value = metadata?.[key];
|
|
68
|
+
return typeof value === "string" ? value : undefined;
|
|
69
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type {
|
|
4
|
+
PiWebServerPlugin,
|
|
5
|
+
ProjectInput,
|
|
6
|
+
ProviderClaim,
|
|
7
|
+
ProviderRequestContext,
|
|
8
|
+
ProviderWorkspace,
|
|
9
|
+
WorkspaceProvider,
|
|
10
|
+
} from "@jmfederico/pi-web/server-plugin-api";
|
|
11
|
+
|
|
12
|
+
const markerPath = ".pi-web/example-workspace-provider";
|
|
13
|
+
|
|
14
|
+
const plugin: PiWebServerPlugin = {
|
|
15
|
+
apiVersion: 1,
|
|
16
|
+
name: "Example Workspace Provider",
|
|
17
|
+
activate({ pluginId, logger }) {
|
|
18
|
+
logger.info("Activating example workspace provider", { pluginId });
|
|
19
|
+
return { workspaceProvider: createWorkspaceProvider(pluginId) };
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default plugin;
|
|
24
|
+
|
|
25
|
+
function createWorkspaceProvider(pluginId: string): WorkspaceProvider {
|
|
26
|
+
return {
|
|
27
|
+
async probe(project: ProjectInput, signal: AbortSignal): Promise<ProviderClaim> {
|
|
28
|
+
signal.throwIfAborted();
|
|
29
|
+
try {
|
|
30
|
+
await access(join(project.path, markerPath));
|
|
31
|
+
signal.throwIfAborted();
|
|
32
|
+
return "claim";
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (isMissingFile(error)) return "pass";
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async list(project: ProjectInput, signal: AbortSignal): Promise<ProviderWorkspace[]> {
|
|
39
|
+
signal.throwIfAborted();
|
|
40
|
+
return [{
|
|
41
|
+
key: "main",
|
|
42
|
+
path: project.path,
|
|
43
|
+
label: project.name,
|
|
44
|
+
isMain: true,
|
|
45
|
+
// This object is visible to every browser script and API consumer.
|
|
46
|
+
publicMetadata: { kind: "example", marker: markerPath },
|
|
47
|
+
}];
|
|
48
|
+
},
|
|
49
|
+
request(context: ProviderRequestContext) {
|
|
50
|
+
context.signal.throwIfAborted();
|
|
51
|
+
if (context.operation !== "summary") {
|
|
52
|
+
throw new Error(`Unsupported example workspace operation: ${context.operation}`);
|
|
53
|
+
}
|
|
54
|
+
return Promise.resolve(`${pluginId} owns ${context.workspace.label} at ${context.workspace.path}`);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isMissingFile(error: unknown): boolean {
|
|
60
|
+
return typeof error === "object"
|
|
61
|
+
&& error !== null
|
|
62
|
+
&& "code" in error
|
|
63
|
+
&& Reflect.get(error, "code") === "ENOENT";
|
|
64
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022", "DOM"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"exactOptionalPropertyTypes": true,
|
|
12
|
+
"noUncheckedIndexedAccess": true,
|
|
13
|
+
"noImplicitReturns": true,
|
|
14
|
+
"noFallthroughCasesInSwitch": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"verbatimModuleSyntax": true,
|
|
17
|
+
"skipLibCheck": false,
|
|
18
|
+
"noEmitOnError": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*.ts"]
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jmfederico/pi-web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.202608.1",
|
|
4
4
|
"description": "Web UI for persistent Pi Coding Agent sessions in real workspaces.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Federico Jaramillo Martinez",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./plugin-api": {
|
|
10
|
+
"types": "./dist/plugin-api.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./server-plugin-api": {
|
|
13
|
+
"types": "./dist/server-plugin-api.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"typesVersions": {
|
|
17
|
+
"*": {
|
|
18
|
+
"plugin-api": [
|
|
19
|
+
"dist/plugin-api.d.ts"
|
|
20
|
+
],
|
|
21
|
+
"server-plugin-api": [
|
|
22
|
+
"dist/server-plugin-api.d.ts"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
8
26
|
"bin": {
|
|
9
27
|
"pi-web": "dist/cli.js",
|
|
10
28
|
"pi-web-server": "dist/server/index.js",
|
|
@@ -17,15 +35,16 @@
|
|
|
17
35
|
"README.md",
|
|
18
36
|
"LICENSE",
|
|
19
37
|
"extensions",
|
|
38
|
+
"examples/workspace-provider-plugin",
|
|
20
39
|
"docs/plugins.md",
|
|
21
40
|
"docs/config.md",
|
|
22
41
|
"docs/assets",
|
|
23
42
|
"plugin-api.d.ts",
|
|
24
|
-
"plugin-api
|
|
43
|
+
"server-plugin-api.d.ts"
|
|
25
44
|
],
|
|
26
45
|
"scripts": {
|
|
27
46
|
"dev": "bash -c 'trap \"kill 0\" EXIT; npm run dev:sessiond & npm run dev:web & npm run dev:client & wait'",
|
|
28
|
-
"dev:sessiond": "tsx watch src/server/sessiond.ts",
|
|
47
|
+
"dev:sessiond": "npm run build:plugins && tsx watch src/server/sessiond.ts",
|
|
29
48
|
"dev:web": "bash -c 'set -e; npm run build:plugins; trap \"kill 0\" EXIT; npm run dev:plugins & tsx watch src/server/index.ts & wait'",
|
|
30
49
|
"dev:server": "npm run dev:web",
|
|
31
50
|
"dev:client": "vite --host 0.0.0.0",
|
|
@@ -42,7 +61,7 @@
|
|
|
42
61
|
"verify": "npm run typecheck && npm run lint && npm run knip && npm test",
|
|
43
62
|
"verify:staged": "node scripts/verify-staged.mjs",
|
|
44
63
|
"start": "tsx src/server/index.ts",
|
|
45
|
-
"start:sessiond": "tsx src/server/sessiond.ts",
|
|
64
|
+
"start:sessiond": "npm run build:plugins && tsx src/server/sessiond.ts",
|
|
46
65
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
47
66
|
"prepack": "npm run build",
|
|
48
67
|
"pack:dry": "npm pack --dry-run",
|
|
@@ -69,7 +88,7 @@
|
|
|
69
88
|
"@codemirror/state": "^6.7.1",
|
|
70
89
|
"@codemirror/view": "^6.43.6",
|
|
71
90
|
"@fastify/compress": "^9.0.0",
|
|
72
|
-
"@fastify/static": "^
|
|
91
|
+
"@fastify/static": "^10.1.2",
|
|
73
92
|
"@fastify/websocket": "^11.3.0",
|
|
74
93
|
"@xterm/addon-fit": "^0.11.0",
|
|
75
94
|
"@xterm/xterm": "^6.0.0",
|
|
@@ -78,14 +97,15 @@
|
|
|
78
97
|
"lit": "^3.3.3",
|
|
79
98
|
"marked": "^18.0.6",
|
|
80
99
|
"node-pty": "^1.1.0",
|
|
81
|
-
"typebox": "1.3.
|
|
100
|
+
"typebox": "1.3.7",
|
|
101
|
+
"undici": "^8.5.0",
|
|
82
102
|
"ws": "^8.21.0"
|
|
83
103
|
},
|
|
84
104
|
"devDependencies": {
|
|
85
105
|
"@changesets/cli": "^2.31.0",
|
|
86
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
87
|
-
"@earendil-works/pi-ai": "^0.
|
|
88
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
106
|
+
"@earendil-works/pi-agent-core": "^0.84.1",
|
|
107
|
+
"@earendil-works/pi-ai": "^0.84.1",
|
|
108
|
+
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
89
109
|
"@eslint/js": "^10.0.1",
|
|
90
110
|
"@types/node": "^24.13.3",
|
|
91
111
|
"@types/ws": "^8.18.1",
|
|
@@ -115,9 +135,9 @@
|
|
|
115
135
|
"homepage": "https://pi-web.dev/",
|
|
116
136
|
"packageManager": "npm@11.11.0",
|
|
117
137
|
"peerDependencies": {
|
|
118
|
-
"@earendil-works/pi-agent-core": ">=0.
|
|
119
|
-
"@earendil-works/pi-ai": ">=0.
|
|
120
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
138
|
+
"@earendil-works/pi-agent-core": ">=0.84.0",
|
|
139
|
+
"@earendil-works/pi-ai": ">=0.84.0",
|
|
140
|
+
"@earendil-works/pi-coding-agent": ">=0.84.0"
|
|
121
141
|
},
|
|
122
142
|
"keywords": [
|
|
123
143
|
"pi-package",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dist/server-plugin-api.js";
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import{_ as e,a as t,f as n,g as r,m as i,p as a}from"./index-LME0LfPb.js";var o=class{diff(e,t,n={}){let r;typeof n==`function`?(r=n,n={}):`callback`in n&&(r=n.callback);let i=this.castInput(e,n),a=this.castInput(t,n),o=this.removeEmpty(this.tokenize(i,n)),s=this.removeEmpty(this.tokenize(a,n));return this.diffWithOptionsObj(o,s,n,r)}diffWithOptionsObj(e,t,n,r){let i=e=>{if(e=this.postProcess(e,n),r){setTimeout(function(){r(e)},0);return}else return e},a=t.length,o=e.length,s=1,c=a+o;n.maxEditLength!=null&&(c=Math.min(c,n.maxEditLength));let l=n.timeout??1/0,u=Date.now()+l,d=[{oldPos:-1,lastComponent:void 0}],f=this.extractCommon(d[0],t,e,0,n);if(d[0].oldPos+1>=o&&f+1>=a)return i(this.buildValues(d[0].lastComponent,t,e));let p=-1/0,m=1/0,h=()=>{for(let r=Math.max(p,-s);r<=Math.min(m,s);r+=2){let s,c=d[r-1],l=d[r+1];c&&(d[r-1]=void 0);let u=!1;if(l){let e=l.oldPos-r;u=l&&0<=e&&e<a}let h=c&&c.oldPos+1<o;if(!u&&!h){d[r]=void 0;continue}if(s=!h||u&&c.oldPos<l.oldPos?this.addToPath(l,!0,!1,0,n):this.addToPath(c,!1,!0,1,n),f=this.extractCommon(s,t,e,r,n),s.oldPos+1>=o&&f+1>=a)return i(this.buildValues(s.lastComponent,t,e))||!0;d[r]=s,s.oldPos+1>=o&&(m=Math.min(m,r-1)),f+1>=a&&(p=Math.max(p,r+1))}s++};if(r)(function e(){setTimeout(function(){if(s>c||Date.now()>u)return r(void 0);h()||e()},0)})();else for(;s<=c&&Date.now()<=u;){let e=h();if(e)return e}}addToPath(e,t,n,r,i){let a=e.lastComponent;return a&&!i.oneChangePerToken&&a.added===t&&a.removed===n?{oldPos:e.oldPos+r,lastComponent:{count:a.count+1,added:t,removed:n,previousComponent:a.previousComponent}}:{oldPos:e.oldPos+r,lastComponent:{count:1,added:t,removed:n,previousComponent:a}}}extractCommon(e,t,n,r,i){let a=t.length,o=n.length,s=e.oldPos,c=s-r,l=0;for(;c+1<a&&s+1<o&&this.equals(n[s+1],t[c+1],i);)c++,s++,l++,i.oneChangePerToken&&(e.lastComponent={count:1,previousComponent:e.lastComponent,added:!1,removed:!1});return l&&!i.oneChangePerToken&&(e.lastComponent={count:l,previousComponent:e.lastComponent,added:!1,removed:!1}),e.oldPos=s,c}equals(e,t,n){return n.comparator?n.comparator(e,t):e===t||!!n.ignoreCase&&e.toLowerCase()===t.toLowerCase()}removeEmpty(e){let t=[];for(let n=0;n<e.length;n++)e[n]&&t.push(e[n]);return t}castInput(e,t){return e}tokenize(e,t){return Array.from(e)}join(e){return e.join(``)}postProcess(e,t){return e}get useLongestToken(){return!1}buildValues(e,t,n){let r=[],i;for(;e;)r.push(e),i=e.previousComponent,delete e.previousComponent,e=i;r.reverse();let a=r.length,o=0,s=0,c=0;for(;o<a;o++){let e=r[o];if(e.removed)e.value=this.join(n.slice(c,c+e.count)),c+=e.count;else{if(!e.added&&this.useLongestToken){let r=t.slice(s,s+e.count);r=r.map(function(e,t){let r=n[c+t];return r.length>e.length?r:e}),e.value=this.join(r)}else e.value=this.join(t.slice(s,s+e.count));s+=e.count,e.added||(c+=e.count)}}return r}},s=new class extends o{};function c(e,t,n){return s.diff(e,t,n)}function l(e,t){let n;for(n=0;n<e.length&&n<t.length;n++)if(e[n]!=t[n])return e.slice(0,n);return e.slice(0,n)}function u(e,t){let n;if(!e||!t||e[e.length-1]!=t[t.length-1])return``;for(n=0;n<e.length&&n<t.length;n++)if(e[e.length-(n+1)]!=t[t.length-(n+1)])return e.slice(-n);return e.slice(-n)}function d(e,t,n){if(e.slice(0,t.length)!=t)throw Error(`string ${JSON.stringify(e)} doesn't start with prefix ${JSON.stringify(t)}; this is a bug`);return n+e.slice(t.length)}function f(e,t,n){if(!t)return e+n;if(e.slice(-t.length)!=t)throw Error(`string ${JSON.stringify(e)} doesn't end with suffix ${JSON.stringify(t)}; this is a bug`);return e.slice(0,-t.length)+n}function p(e,t){return d(e,t,``)}function m(e,t){return f(e,t,``)}function h(e,t){return t.slice(0,g(e,t))}function g(e,t){let n=0;e.length>t.length&&(n=e.length-t.length);let r=t.length;e.length<t.length&&(r=e.length);let i=Array(r),a=0;i[0]=0;for(let e=1;e<r;e++){for(t[e]==t[a]?i[e]=i[a]:i[e]=a;a>0&&t[e]!=t[a];)a=i[a];t[e]==t[a]&&a++}a=0;for(let r=n;r<e.length;r++){for(;a>0&&e[r]!=t[a];)a=i[a];e[r]==t[a]&&a++}return a}function _(e,t){let n=[];for(let r of Array.from(t.segment(e))){let e=r.segment;n.length&&/\s/.test(n[n.length-1])&&/\s/.test(e)?n[n.length-1]+=e:n.push(e)}return n}function v(e,t){if(t)return b(e,t)[1];let n;for(n=e.length-1;n>=0&&e[n].match(/\s/);n--);return e.substring(n+1)}function y(e,t){if(t)return b(e,t)[0];let n=e.match(/^\s*/);return n?n[0]:``}function b(e,t){if(!t)return[y(e),v(e)];if(t.resolvedOptions().granularity!=`word`)throw Error(`The segmenter passed must have a granularity of "word"`);let n=_(e,t),r=n[0],i=n[n.length-1];return[/\s/.test(r)?r:``,/\s/.test(i)?i:``]}var x=`a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}`,S=RegExp(`[${x}]+|\\s+|[^${x}]`,`ug`);new class extends o{equals(e,t,n){return n.ignoreCase&&(e=e.toLowerCase(),t=t.toLowerCase()),e.trim()===t.trim()}tokenize(e,t={}){let n;if(t.intlSegmenter){let r=t.intlSegmenter;if(r.resolvedOptions().granularity!=`word`)throw Error(`The segmenter passed must have a granularity of "word"`);n=_(e,r)}else n=e.match(S)||[];let r=[],i=null;return n.forEach(e=>{/\s/.test(e)?i==null?r.push(e):r.push(r.pop()+e):i!=null&&/\s/.test(i)?r[r.length-1]==i?r.push(r.pop()+e):r.push(i+e):r.push(e),i=e}),r}join(e){return e.map((e,t)=>t==0?e:e.replace(/^\s+/,``)).join(``)}postProcess(e,t){if(!e||t.oneChangePerToken)return e;let n=null,r=null,i=null;return e.forEach(e=>{e.added?r=e:e.removed?i=e:((r||i)&&C(n,i,r,e,t.intlSegmenter),n=e,r=null,i=null)}),(r||i)&&C(n,i,r,null,t.intlSegmenter),e}};function C(e,t,n,r,i){if(t&&n){let[a,o]=b(t.value,i),[s,c]=b(n.value,i);if(e){let r=l(a,s);e.value=f(e.value,s,r),t.value=p(t.value,r),n.value=p(n.value,r)}if(r){let e=u(o,c);r.value=d(r.value,c,e),t.value=m(t.value,e),n.value=m(n.value,e)}}else if(n){if(e){let e=y(n.value,i);n.value=n.value.substring(e.length)}if(r){let e=y(r.value,i);r.value=r.value.substring(e.length)}}else if(e&&r){let n=y(r.value,i),[a,o]=b(t.value,i),s=l(n,a);t.value=p(t.value,s);let c=u(p(n,s),o);t.value=m(t.value,c),r.value=d(r.value,n,c),e.value=f(e.value,n,n.slice(0,n.length-c.length))}else if(r){let e=y(r.value,i),n=h(v(t.value,i),e);t.value=m(t.value,n)}else if(e){let n=h(v(e.value,i),y(t.value,i));t.value=p(t.value,n)}}new class extends o{tokenize(e){let t=RegExp(`(\\r?\\n)|[${x}]+|[^\\S\\n\\r]+|[^${x}]`,`ug`);return e.match(t)||[]}},new class extends o{constructor(){super(...arguments),this.tokenize=w}equals(e,t,n){return n.ignoreWhitespace?((!n.newlineIsToken||!e.includes(`
|
|
2
|
-
`))&&(e=e.trim()),(!n.newlineIsToken||!t.includes(`
|
|
3
|
-
`))&&(t=t.trim())):n.ignoreNewlineAtEof&&!n.newlineIsToken&&(e.endsWith(`
|
|
4
|
-
`)&&(e=e.slice(0,-1)),t.endsWith(`
|
|
5
|
-
`)&&(t=t.slice(0,-1))),super.equals(e,t,n)}};function w(e,t){t.stripTrailingCr&&(e=e.replace(/\r\n/g,`
|
|
6
|
-
`));let n=[],r=e.split(/(\n|\r\n)/);r[r.length-1]||r.pop();for(let e=0;e<r.length;e++){let i=r[e];e%2&&!t.newlineIsToken?n[n.length-1]+=i:n.push(i)}return n}function T(e){return e==`.`||e==`!`||e==`?`}new class extends o{tokenize(e){let t=[],n=0;for(let r=0;r<e.length;r++){if(r==e.length-1){t.push(e.slice(n));break}if(T(e[r])&&e[r+1].match(/\s/)){for(t.push(e.slice(n,r+1)),r=n=r+1;e[r+1]?.match(/\s/);)r++;t.push(e.slice(n,r+1)),n=r+1}}return t}},new class extends o{tokenize(e){return e.split(/([{}:;,]|\s+)/)}},new class extends o{constructor(){super(...arguments),this.tokenize=w}get useLongestToken(){return!0}castInput(e,t){let{undefinedReplacement:n,stringifyReplacer:r=(e,t)=>t===void 0?n:t}=t;return typeof e==`string`?e:JSON.stringify(E(e,null,null,r),null,` `)}equals(e,t,n){return super.equals(e.replace(/,([\r\n])/g,`$1`),t.replace(/,([\r\n])/g,`$1`),n)}};function E(e,t,n,r,i){t||=[],n||=[],r&&(e=r(i===void 0?``:i,e));let a;for(a=0;a<t.length;a+=1)if(t[a]===e)return n[a];let o;if(Object.prototype.toString.call(e)===`[object Array]`){for(t.push(e),o=Array(e.length),n.push(o),a=0;a<e.length;a+=1)o[a]=E(e[a],t,n,r,String(a));return t.pop(),n.pop(),o}if(e&&e.toJSON&&(e=e.toJSON()),typeof e==`object`&&e){t.push(e),o={},n.push(o);let i=[],s;for(s in e)Object.prototype.hasOwnProperty.call(e,s)&&i.push(s);for(i.sort(),a=0;a<i.length;a+=1)s=i[a],o[s]=E(e[s],t,n,r,s);t.pop(),n.pop()}else o=e;return o}new class extends o{tokenize(e){return e.slice()}join(e){return e}removeEmpty(e){return e}};var D=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/,O=5e3,k=20,A=.2,j=.25;function M(e){let t=N(e);return I(t),t}function N(e){let t=P(e),n=[],r,i;for(let e of t){let t=D.exec(e);if(t!==null){r=Number(t[1]),i=Number(t[2]),n.push(F(`hunk`,``,e));continue}if(r!==void 0&&i!==void 0){if(e.startsWith(`+`)){n.push(F(`add`,`+`,e.slice(1),{newLineNumber:i})),i++;continue}if(e.startsWith(`-`)){n.push(F(`remove`,`-`,e.slice(1),{oldLineNumber:r})),r++;continue}if(e.startsWith(` `)){n.push(F(`context`,` `,e.slice(1),{oldLineNumber:r,newLineNumber:i})),r++,i++;continue}if(e.startsWith(`\\`)){n.push(F(`marker`,``,e));continue}}r=void 0,i=void 0,n.push(F(`meta`,``,e))}return n}function P(e){if(e===``)return[];let t=e.replace(/\r\n/g,`
|
|
7
|
-
`).replace(/\r/g,`
|
|
8
|
-
`).split(`
|
|
9
|
-
`);return t.at(-1)===``&&t.pop(),t}function F(e,t,n,r={}){return{kind:e,prefix:t,text:n,spans:n===``?[]:[{text:n,changed:!1}],...r}}function I(e){let t=0;for(;t<e.length;){if(e[t]?.kind!==`remove`){t++;continue}let n=t;for(;e[t]?.kind===`remove`;)t++;let r=t;for(;e[t]?.kind===`add`;)t++;r!==t&&L(e.slice(n,r),e.slice(r,t))}}function L(e,t){if(!(e.length+t.length>k))for(let n of R(e,t)){let e=U(n.removed.text,n.added.text);e!==void 0&&(n.removed.spans=e.removed,n.added.spans=e.added)}}function R(e,t){if(e.length===t.length)return e.map((e,n)=>({removed:e,added:t[n]})).filter(z);if(e.length===1)return B(e[0],t);if(t.length===1)return V(e,t[0]);let n=[],r=Math.min(e.length,t.length);for(let i=0;i<r;i++){let r=e[i],a=t[i];r===void 0||a===void 0||W(r.text,a.text)>=j&&n.push({removed:r,added:a})}return n}function z(e){return e.added!==void 0}function B(e,t){if(e===void 0)return[];let n=H(e.text,t);return n===void 0?[]:[{removed:e,added:n}]}function V(e,t){if(t===void 0)return[];let n=H(t.text,e);return n===void 0?[]:[{removed:n,added:t}]}function H(e,t){let n,r=j;for(let i of t){let t=W(e,i.text);t<=r||(n=i,r=t)}return n}function U(e,t){if(e===t||e.length>O||t.length>O)return;let n=c(e,t),r=G(n,e,t);if(Math.max(e.length,t.length)>=20&&r<A)return;let i=[],a=[];for(let e of n)e.value!==``&&(e.added?a.push({text:e.value,changed:!0}):e.removed?i.push({text:e.value,changed:!0}):(i.push({text:e.value,changed:!1}),a.push({text:e.value,changed:!1})));if(!(!i.some(e=>e.changed)&&!a.some(e=>e.changed)))return{removed:K(i),added:K(a)}}function W(e,t){return e===t?1:e.length>O||t.length>O?0:G(c(e,t),e,t)}function G(e,t,n){let r=Math.max(t.length,n.length);return r===0?1:e.reduce((e,t)=>t.added||t.removed?e:e+t.value.length,0)/r}function K(e){let t=[];for(let n of e){let e=t[t.length-1];e?.changed===n.changed?e.text+=n.text:t.push({...n})}return t}var q=class extends i{constructor(...e){super(...e),this.diff=``}render(){let e=M(this.diff);return e.length===0?r`<p class="empty">No diff.</p>`:r`
|
|
10
|
-
<div class="scroller">
|
|
11
|
-
<div class="diff-grid" role="table" aria-label="Unified diff">
|
|
12
|
-
${e.map(e=>this.renderLine(e))}
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
`}renderLine(e){let t=e.kind;return r`
|
|
16
|
-
<div class="line" role="row">
|
|
17
|
-
<span class=${`cell line-number old ${t}`} role="cell">${Y(e.oldLineNumber)}</span>
|
|
18
|
-
<span class=${`cell line-number new ${t}`} role="cell">${Y(e.newLineNumber)}</span>
|
|
19
|
-
<span class=${`cell prefix ${t}`} role="cell">${e.prefix}</span>
|
|
20
|
-
<span class=${`cell content ${t}`} role="cell">${J(e.spans)}</span>
|
|
21
|
-
</div>
|
|
22
|
-
`}static{this.styles=e`
|
|
23
|
-
:host { display: block; min-height: 0; height: 100%; color: var(--pi-text); background: var(--pi-bg); }
|
|
24
|
-
.empty { box-sizing: border-box; margin: 0; padding: 10px; color: var(--pi-muted); }
|
|
25
|
-
.scroller { height: 100%; min-height: 0; overflow: auto; background: var(--pi-bg); }
|
|
26
|
-
.diff-grid { display: grid; grid-template-columns: max-content max-content 2ch max-content; width: max-content; min-width: 100%; padding: 6px 0; font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; line-height: 1.45; }
|
|
27
|
-
.line { display: contents; }
|
|
28
|
-
.cell { min-height: 1.45em; white-space: pre; }
|
|
29
|
-
.line-number { min-width: 4ch; padding: 0 8px; border-right: 1px solid var(--pi-border-muted); color: var(--pi-dim); text-align: right; user-select: none; }
|
|
30
|
-
.prefix { padding: 0 4px; color: var(--pi-dim); text-align: center; user-select: none; }
|
|
31
|
-
.content { padding: 0 12px 0 4px; }
|
|
32
|
-
.meta { color: var(--pi-dim); }
|
|
33
|
-
.hunk { background: color-mix(in srgb, var(--pi-accent) 9%, transparent); color: var(--pi-accent); }
|
|
34
|
-
.add { background: color-mix(in srgb, var(--pi-success) 12%, transparent); }
|
|
35
|
-
.remove { background: color-mix(in srgb, var(--pi-danger) 12%, transparent); }
|
|
36
|
-
.marker { color: var(--pi-dim); }
|
|
37
|
-
.content.add .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-success) 36%, transparent); color: var(--pi-text); }
|
|
38
|
-
.content.remove .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-danger) 36%, transparent); color: var(--pi-text); }
|
|
39
|
-
`}};t([n()],q.prototype,`diff`,void 0),q=t([a(`unified-diff-viewer`)],q);function J(e){return e.map(e=>r`<span class=${e.changed?`inline-change`:``}>${e.text}</span>`)}function Y(e){return e===void 0?``:String(e)}export{q as UnifiedDiffViewer};
|