paseo-plugin-zcode-provider 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/NOTICE.md +29 -0
- package/README.md +112 -2
- package/client/account.tsx +827 -0
- package/client/diagnostics.tsx +379 -0
- package/client/runtime.tsx +296 -0
- package/client/settings.tsx +84 -0
- package/client/value.tsx +20 -0
- package/icon.svg +1 -0
- package/index.client.tsx +22 -0
- package/index.server.ts +39 -0
- package/package.json +77 -4
- package/paseo-plugin.json +6 -0
- package/server/account.ts +781 -0
- package/server/attachments.ts +150 -0
- package/server/build-info.ts +2 -0
- package/server/conversation.ts +319 -0
- package/server/diagnostics.ts +252 -0
- package/server/discovery/discover.ts +225 -0
- package/server/discovery/manifest.ts +36 -0
- package/server/discovery/types.ts +30 -0
- package/server/errors.ts +36 -0
- package/server/host/bridge.ts +490 -0
- package/server/host/schemas.ts +119 -0
- package/server/logger.ts +19 -0
- package/server/mapping.ts +270 -0
- package/server/models.ts +68 -0
- package/server/persistence.ts +146 -0
- package/server/presentation.ts +470 -0
- package/server/provider-status.ts +81 -0
- package/server/provider.ts +838 -0
- package/server/runtime/managed.ts +501 -0
- package/server/runtime/pins.ts +72 -0
- package/server/runtime-setup.ts +77 -0
- package/server/session-types.ts +49 -0
- package/server/session.ts +866 -0
- package/server/status.ts +89 -0
- package/server/timeline.ts +18 -0
- package/server/usage.ts +362 -0
- package/server/vendor/zcode/LICENSE +202 -0
- package/server/vendor/zcode/NOTICE.md +70 -0
- package/server/vendor/zcode/THIRD-PARTY-NOTICES.md +37 -0
- package/server/vendor/zcode/packages/model-option-map/src/compiler.ts +92 -0
- package/server/vendor/zcode/packages/model-option-map/src/evaluator.ts +214 -0
- package/server/vendor/zcode/packages/model-option-map/src/index.ts +5 -0
- package/server/vendor/zcode/packages/model-option-map/src/merge-patch.ts +97 -0
- package/server/vendor/zcode/packages/model-option-map/src/option-maps.ts +42 -0
- package/server/vendor/zcode/packages/model-option-map/src/parser.ts +240 -0
- package/server/vendor/zcode/packages/model-option-map/src/tokenizer.ts +141 -0
- package/server/vendor/zcode/packages/model-option-map/src/types.ts +36 -0
- package/server/vendor/zcode/packages/rpc/src/buffer.ts +88 -0
- package/server/vendor/zcode/packages/rpc/src/channelClient.ts +275 -0
- package/server/vendor/zcode/packages/rpc/src/channelServer.ts +283 -0
- package/server/vendor/zcode/packages/rpc/src/channels.shared.ts +66 -0
- package/server/vendor/zcode/packages/rpc/src/channels.ts +4 -0
- package/server/vendor/zcode/packages/rpc/src/delayedChannel.ts +17 -0
- package/server/vendor/zcode/packages/rpc/src/foundation.ts +260 -0
- package/server/vendor/zcode/packages/rpc/src/protocol.ts +397 -0
- package/server/vendor/zcode/packages/rpc/src/proxy-channel.ts +213 -0
- package/server/vendor/zcode/packages/rpc/src/serialization.ts +291 -0
- package/server/vendor/zcode/packages/shared/src/account-provider-state.ts +13 -0
- package/server/vendor/zcode/packages/shared/src/background-bash-output.ts +24 -0
- package/server/vendor/zcode/packages/shared/src/background-task-controls.ts +404 -0
- package/server/vendor/zcode/packages/shared/src/bash-output-display.ts +11 -0
- package/server/vendor/zcode/packages/shared/src/bots.ts +558 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/backend.ts +80 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/command-metadata.ts +170 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/commands.ts +588 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/result.ts +130 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/snapshot.ts +77 -0
- package/server/vendor/zcode/packages/shared/src/command-types.ts +96 -0
- package/server/vendor/zcode/packages/shared/src/config-schema.ts +8 -0
- package/server/vendor/zcode/packages/shared/src/cuaAccessibilitySettings.ts +41 -0
- package/server/vendor/zcode/packages/shared/src/database-startup.ts +178 -0
- package/server/vendor/zcode/packages/shared/src/env.ts +63 -0
- package/server/vendor/zcode/packages/shared/src/execution-output-preview.ts +14 -0
- package/server/vendor/zcode/packages/shared/src/localTtft.ts +192 -0
- package/server/vendor/zcode/packages/shared/src/model-config.ts +123 -0
- package/server/vendor/zcode/packages/shared/src/model-execution.ts +23 -0
- package/server/vendor/zcode/packages/shared/src/model-provider-family.ts +171 -0
- package/server/vendor/zcode/packages/shared/src/model-provider-types.ts +81 -0
- package/server/vendor/zcode/packages/shared/src/model-selection.ts +60 -0
- package/server/vendor/zcode/packages/shared/src/oauth.ts +203 -0
- package/server/vendor/zcode/packages/shared/src/official-mcp-auth.ts +272 -0
- package/server/vendor/zcode/packages/shared/src/official-mcp-tool-error.ts +68 -0
- package/server/vendor/zcode/packages/shared/src/process-diagnostic.ts +42 -0
- package/server/vendor/zcode/packages/shared/src/protocol.ts +369 -0
- package/server/vendor/zcode/packages/shared/src/provider-family-connection-selection.ts +32 -0
- package/server/vendor/zcode/packages/shared/src/remoteAssetInstallMode.ts +11 -0
- package/server/vendor/zcode/packages/shared/src/remoteResourcePackages.ts +91 -0
- package/server/vendor/zcode/packages/shared/src/runtimeEnv.ts +315 -0
- package/server/vendor/zcode/packages/shared/src/settings-source.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/usage-quota.ts +74 -0
- package/server/vendor/zcode/packages/shared/src/usage-stats.ts +462 -0
- package/server/vendor/zcode/packages/shared/src/validationAppSettings.ts +562 -0
- package/server/vendor/zcode/packages/shared/src/workspacePurpose.ts +2 -0
- package/server/vendor/zcode/packages/shared/src/wslUserValidation.ts +33 -0
- package/server/vendor/zcode/packages/shared/src/zcode-agent-policy.ts +25 -0
- package/server/vendor/zcode/packages/shared/src/zcode-media-policy.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol/index.ts +3720 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-legacy-types.ts +529 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/apply.ts +218 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/attachment-ref.ts +14 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/command.ts +482 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/core.ts +100 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/create-workflow-display.ts +156 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/cuaPermission.ts +41 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/delta.ts +147 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/input-intent.ts +69 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/rows.ts +432 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/session-config.ts +43 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index-workflow-activity.ts +195 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index.ts +85 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-import.ts +38 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-ref.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/snapshot.ts +509 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/submission.ts +5 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/toolDisplay.ts +264 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/transport.ts +1152 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-assembler.ts +574 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-binary.ts +65 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-codec.ts +240 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-fault.ts +39 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire.ts +159 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-artifacts.ts +291 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-observation-display.ts +281 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-row-meta.ts +163 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-run-settings-command.ts +62 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs-delta.ts +517 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs.ts +512 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-config.ts +81 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-hook-review.ts +210 -0
- package/server/vendor/zcode/packages/shared/src/zcode-task-mode-schema.ts +6 -0
- package/server/vendor/zcode/packages/shared/src/zcode-task-types-core.ts +1187 -0
- package/server/vendor/zcode/packages/shared/src/zcodeEndpoint.ts +296 -0
- package/server/vendor/zcode/provenance.json +405 -0
- package/shared/account.ts +201 -0
- package/shared/diagnostics.ts +52 -0
- package/shared/runtime-setup.ts +73 -0
- package/vendor/acp-registry/LICENSE +176 -0
- package/vendor/paseo/LICENSE +211 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { createWriteStream } from "node:fs";
|
|
4
|
+
import {
|
|
5
|
+
access,
|
|
6
|
+
mkdir,
|
|
7
|
+
mkdtemp,
|
|
8
|
+
readFile,
|
|
9
|
+
readdir,
|
|
10
|
+
rename,
|
|
11
|
+
rm,
|
|
12
|
+
stat,
|
|
13
|
+
writeFile,
|
|
14
|
+
} from "node:fs/promises";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
17
|
+
import { Readable, Transform } from "node:stream";
|
|
18
|
+
import { pipeline } from "node:stream/promises";
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
import { AdapterError } from "../errors.js";
|
|
21
|
+
import {
|
|
22
|
+
MANAGED_NODE_ARCHIVES,
|
|
23
|
+
MANAGED_NODE_VERSION,
|
|
24
|
+
MANAGED_ZCODE_ARCHIVE,
|
|
25
|
+
MANAGED_ZCODE_VERSION,
|
|
26
|
+
managedPlatform,
|
|
27
|
+
type ManagedPlatform,
|
|
28
|
+
type PinnedArchive,
|
|
29
|
+
} from "./pins.js";
|
|
30
|
+
|
|
31
|
+
export type ManagedComponentId = "node" | "zcode";
|
|
32
|
+
|
|
33
|
+
export interface ManagedComponent {
|
|
34
|
+
readonly id: ManagedComponentId;
|
|
35
|
+
readonly version: string;
|
|
36
|
+
readonly archive: PinnedArchive;
|
|
37
|
+
/** Final directory; it exists only after a verified, complete install. */
|
|
38
|
+
readonly directory: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ManagedLayout {
|
|
42
|
+
readonly root: string;
|
|
43
|
+
readonly platform: ManagedPlatform;
|
|
44
|
+
readonly node: ManagedComponent & { readonly executable: string };
|
|
45
|
+
readonly zcode: ManagedComponent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Files the provider launches or must ship with the redistributed runtime.
|
|
49
|
+
export const MANAGED_ZCODE_FILES = [
|
|
50
|
+
"package.json",
|
|
51
|
+
"bin/zcode.mjs",
|
|
52
|
+
"server/remote/zcode-server.cjs",
|
|
53
|
+
"agent/zcode.cjs",
|
|
54
|
+
"agent/provider/zcode-builtin.json",
|
|
55
|
+
"LICENSE",
|
|
56
|
+
"NOTICE.md",
|
|
57
|
+
"THIRD-PARTY-NOTICES.md",
|
|
58
|
+
] as const;
|
|
59
|
+
|
|
60
|
+
const MARKER = ".paseo-managed.json";
|
|
61
|
+
const markerSchema = z
|
|
62
|
+
.object({ version: z.string(), archiveSha256: z.string() })
|
|
63
|
+
.strict();
|
|
64
|
+
|
|
65
|
+
// Outside the plugin checkout so plugin updates do not download the runtime
|
|
66
|
+
// again. Each OS uses its per-user data convention: Windows' non-roaming
|
|
67
|
+
// %LOCALAPPDATA%, otherwise ~/.local/share. An absolute XDG_DATA_HOME is an
|
|
68
|
+
// explicit override everywhere (CI isolates with it); relative values are
|
|
69
|
+
// ignored as the XDG specification requires.
|
|
70
|
+
export function managedRuntimeRoot(
|
|
71
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
72
|
+
platform: NodeJS.Platform = process.platform,
|
|
73
|
+
): string {
|
|
74
|
+
const absolute = (value: string | undefined) =>
|
|
75
|
+
value !== undefined && isAbsolute(value) ? value : undefined;
|
|
76
|
+
const base =
|
|
77
|
+
absolute(environment.XDG_DATA_HOME) ??
|
|
78
|
+
(platform === "win32"
|
|
79
|
+
? (absolute(environment.LOCALAPPDATA) ??
|
|
80
|
+
join(homedir(), "AppData", "Local"))
|
|
81
|
+
: join(homedir(), ".local", "share"));
|
|
82
|
+
return join(base, "paseo-plugin-zcode-provider", "runtimes");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function managedLayout(
|
|
86
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
87
|
+
platform: ManagedPlatform | undefined = managedPlatform(),
|
|
88
|
+
): ManagedLayout | undefined {
|
|
89
|
+
if (platform === undefined) return undefined;
|
|
90
|
+
const root = managedRuntimeRoot(environment);
|
|
91
|
+
const nodeDirectory = join(root, `node-v${MANAGED_NODE_VERSION}-${platform}`);
|
|
92
|
+
return {
|
|
93
|
+
root,
|
|
94
|
+
platform,
|
|
95
|
+
node: {
|
|
96
|
+
id: "node",
|
|
97
|
+
version: MANAGED_NODE_VERSION,
|
|
98
|
+
archive: MANAGED_NODE_ARCHIVES[platform],
|
|
99
|
+
directory: nodeDirectory,
|
|
100
|
+
executable: platform.startsWith("win-")
|
|
101
|
+
? join(nodeDirectory, "node.exe")
|
|
102
|
+
: join(nodeDirectory, "bin", "node"),
|
|
103
|
+
},
|
|
104
|
+
zcode: {
|
|
105
|
+
id: "zcode",
|
|
106
|
+
version: MANAGED_ZCODE_VERSION,
|
|
107
|
+
archive: MANAGED_ZCODE_ARCHIVE,
|
|
108
|
+
directory: join(
|
|
109
|
+
root,
|
|
110
|
+
`zcode-${MANAGED_ZCODE_VERSION}-${MANAGED_ZCODE_ARCHIVE.sha256.slice(0, 12)}`,
|
|
111
|
+
),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function isInstalled(
|
|
117
|
+
component: ManagedComponent,
|
|
118
|
+
): Promise<boolean> {
|
|
119
|
+
try {
|
|
120
|
+
const marker = markerSchema.parse(
|
|
121
|
+
JSON.parse(await readFile(join(component.directory, MARKER), "utf8")),
|
|
122
|
+
);
|
|
123
|
+
return (
|
|
124
|
+
marker.version === component.version &&
|
|
125
|
+
marker.archiveSha256 === component.archive.sha256
|
|
126
|
+
);
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Paths for discovery when both pinned components are installed. */
|
|
133
|
+
export async function resolveManagedRuntime(
|
|
134
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
135
|
+
): Promise<{ installRoot: string; executable: string } | undefined> {
|
|
136
|
+
const layout = managedLayout(environment);
|
|
137
|
+
if (
|
|
138
|
+
layout === undefined ||
|
|
139
|
+
!(await isInstalled(layout.node)) ||
|
|
140
|
+
!(await isInstalled(layout.zcode))
|
|
141
|
+
)
|
|
142
|
+
return undefined;
|
|
143
|
+
return {
|
|
144
|
+
installRoot: layout.zcode.directory,
|
|
145
|
+
executable: layout.node.executable,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface SetupProgress {
|
|
150
|
+
readonly component: ManagedComponentId;
|
|
151
|
+
readonly phase: "download" | "extract" | "verify";
|
|
152
|
+
readonly receivedBytes: number;
|
|
153
|
+
readonly totalBytes: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export type SetupState =
|
|
157
|
+
| { readonly state: "idle" }
|
|
158
|
+
| ({ readonly state: "running" } & SetupProgress)
|
|
159
|
+
| { readonly state: "succeeded" }
|
|
160
|
+
| {
|
|
161
|
+
readonly state: "failed";
|
|
162
|
+
readonly code: string;
|
|
163
|
+
readonly message: string;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export interface InstallerDependencies {
|
|
167
|
+
/** Replaces the pinned layout; tests use it to install local archives. */
|
|
168
|
+
readonly layout?: ManagedLayout;
|
|
169
|
+
readonly fetch?: typeof fetch;
|
|
170
|
+
readonly extract?: (archive: string, destination: string) => Promise<void>;
|
|
171
|
+
readonly nodeVersion?: (executable: string) => Promise<string>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function execute(file: string, args: string[]): Promise<string> {
|
|
175
|
+
return new Promise((resolve, reject) =>
|
|
176
|
+
execFile(
|
|
177
|
+
file,
|
|
178
|
+
args,
|
|
179
|
+
{ timeout: 300_000, maxBuffer: 1024 * 1024, windowsHide: true },
|
|
180
|
+
(error, stdout) => (error ? reject(error) : resolve(stdout.trim())),
|
|
181
|
+
),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// System tar reads .tar.gz everywhere and .zip on Windows. Windows uses its own
|
|
186
|
+
// bsdtar by path: a Git-for-Windows GNU tar on PATH cannot read zip archives.
|
|
187
|
+
export function extractWithSystemTar(
|
|
188
|
+
archive: string,
|
|
189
|
+
destination: string,
|
|
190
|
+
): Promise<void> {
|
|
191
|
+
const tar =
|
|
192
|
+
process.platform === "win32"
|
|
193
|
+
? join(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe")
|
|
194
|
+
: "tar";
|
|
195
|
+
return execute(tar, ["-xf", archive, "-C", destination]).then(() => {});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const setupFailure = (message: string, cause?: unknown) =>
|
|
199
|
+
new AdapterError("RUNTIME_SETUP_FAILED", message, {}, { cause });
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Installs the pinned Node.js and ZCode runtime. One job runs at a time per
|
|
203
|
+
* plugin process; a lock directory also guards other processes sharing the root.
|
|
204
|
+
*/
|
|
205
|
+
export class ManagedRuntimeInstaller {
|
|
206
|
+
private current: SetupState = { state: "idle" };
|
|
207
|
+
private job: Promise<void> | undefined;
|
|
208
|
+
private readonly fetchImpl: typeof fetch;
|
|
209
|
+
private readonly extract: (
|
|
210
|
+
archive: string,
|
|
211
|
+
destination: string,
|
|
212
|
+
) => Promise<void>;
|
|
213
|
+
private readonly nodeVersion: (executable: string) => Promise<string>;
|
|
214
|
+
private readonly fixedLayout: ManagedLayout | undefined;
|
|
215
|
+
|
|
216
|
+
constructor(
|
|
217
|
+
private readonly environment: NodeJS.ProcessEnv = process.env,
|
|
218
|
+
// null disables managed setup; tests use it for unsupported hosts.
|
|
219
|
+
private readonly platform: ManagedPlatform | null = managedPlatform() ??
|
|
220
|
+
null,
|
|
221
|
+
dependencies: InstallerDependencies = {},
|
|
222
|
+
) {
|
|
223
|
+
this.fixedLayout = dependencies.layout;
|
|
224
|
+
this.fetchImpl = dependencies.fetch ?? fetch;
|
|
225
|
+
this.extract = dependencies.extract ?? extractWithSystemTar;
|
|
226
|
+
this.nodeVersion =
|
|
227
|
+
dependencies.nodeVersion ??
|
|
228
|
+
((executable) => execute(executable, ["--version"]));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
layout(): ManagedLayout | undefined {
|
|
232
|
+
if (this.fixedLayout !== undefined) return this.fixedLayout;
|
|
233
|
+
return this.platform === null
|
|
234
|
+
? undefined
|
|
235
|
+
: managedLayout(this.environment, this.platform);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
state(): SetupState {
|
|
239
|
+
return this.current;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Starts setup unless it is already running; returns whether it started. */
|
|
243
|
+
start(): boolean {
|
|
244
|
+
if (this.job !== undefined) return false;
|
|
245
|
+
this.current = {
|
|
246
|
+
state: "running",
|
|
247
|
+
component: "node",
|
|
248
|
+
phase: "download",
|
|
249
|
+
receivedBytes: 0,
|
|
250
|
+
totalBytes: this.layout()?.node.archive.size ?? 0,
|
|
251
|
+
};
|
|
252
|
+
this.job = this.install()
|
|
253
|
+
.then(
|
|
254
|
+
() => {
|
|
255
|
+
this.current = { state: "succeeded" };
|
|
256
|
+
},
|
|
257
|
+
(error: unknown) => {
|
|
258
|
+
this.current = {
|
|
259
|
+
state: "failed",
|
|
260
|
+
code:
|
|
261
|
+
error instanceof AdapterError
|
|
262
|
+
? error.code
|
|
263
|
+
: "RUNTIME_SETUP_FAILED",
|
|
264
|
+
message:
|
|
265
|
+
error instanceof AdapterError
|
|
266
|
+
? error.message
|
|
267
|
+
: "ZCode runtime setup failed",
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
)
|
|
271
|
+
.finally(() => {
|
|
272
|
+
this.job = undefined;
|
|
273
|
+
});
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Resolves when the current job, if any, has finished. */
|
|
278
|
+
async settled(): Promise<void> {
|
|
279
|
+
await this.job;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async remove(): Promise<void> {
|
|
283
|
+
const layout = this.layout();
|
|
284
|
+
if (this.job !== undefined)
|
|
285
|
+
throw setupFailure("ZCode runtime setup is still running");
|
|
286
|
+
const root = layout?.root ?? managedRuntimeRoot(this.environment);
|
|
287
|
+
try {
|
|
288
|
+
await rm(root, { recursive: true, force: true });
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw setupFailure(
|
|
291
|
+
"The managed runtime could not be removed. Stop running ZCode sessions and try again.",
|
|
292
|
+
error,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
this.current = { state: "idle" };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private async install(): Promise<void> {
|
|
299
|
+
const layout = this.layout();
|
|
300
|
+
if (layout === undefined)
|
|
301
|
+
throw new AdapterError(
|
|
302
|
+
"UNSUPPORTED_PLATFORM",
|
|
303
|
+
"Managed ZCode setup is not available on this platform",
|
|
304
|
+
);
|
|
305
|
+
if (!/^[0-9a-f]{64}$/u.test(layout.zcode.archive.sha256))
|
|
306
|
+
throw setupFailure("This plugin build has no pinned ZCode runtime");
|
|
307
|
+
await mkdir(layout.root, { recursive: true });
|
|
308
|
+
const lock = await acquireLock(join(layout.root, ".lock"));
|
|
309
|
+
try {
|
|
310
|
+
await this.installComponent(layout, layout.node, async (directory) => {
|
|
311
|
+
const executable = join(
|
|
312
|
+
directory,
|
|
313
|
+
relative(layout.node.directory, layout.node.executable),
|
|
314
|
+
);
|
|
315
|
+
if ((await this.nodeVersion(executable)) !== `v${layout.node.version}`)
|
|
316
|
+
throw setupFailure("The downloaded Node.js failed its version check");
|
|
317
|
+
});
|
|
318
|
+
await this.installComponent(layout, layout.zcode, async (directory) => {
|
|
319
|
+
for (const file of MANAGED_ZCODE_FILES)
|
|
320
|
+
await access(join(directory, file)).catch((error) => {
|
|
321
|
+
throw setupFailure(
|
|
322
|
+
`The ZCode runtime archive is missing ${file}`,
|
|
323
|
+
error,
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
await this.removeStaleVersions(layout);
|
|
328
|
+
} finally {
|
|
329
|
+
await rm(lock, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
private async installComponent(
|
|
334
|
+
layout: ManagedLayout,
|
|
335
|
+
component: ManagedComponent,
|
|
336
|
+
verify: (directory: string) => Promise<void>,
|
|
337
|
+
): Promise<void> {
|
|
338
|
+
if (await isInstalled(component)) return;
|
|
339
|
+
const stagingRoot = join(layout.root, ".staging");
|
|
340
|
+
await mkdir(stagingRoot, { recursive: true });
|
|
341
|
+
const staging = await mkdtemp(join(stagingRoot, `${component.id}-`));
|
|
342
|
+
try {
|
|
343
|
+
const archive = join(
|
|
344
|
+
staging,
|
|
345
|
+
component.archive.url.endsWith(".zip") ? "archive.zip" : "archive.tgz",
|
|
346
|
+
);
|
|
347
|
+
await this.download(component, archive);
|
|
348
|
+
this.progress(component, "extract");
|
|
349
|
+
const extracted = join(staging, "extracted");
|
|
350
|
+
await mkdir(extracted);
|
|
351
|
+
await this.extract(archive, extracted).catch((error) => {
|
|
352
|
+
throw setupFailure(
|
|
353
|
+
`The ${label(component)} archive could not be extracted`,
|
|
354
|
+
error,
|
|
355
|
+
);
|
|
356
|
+
});
|
|
357
|
+
const entries = await readdir(extracted);
|
|
358
|
+
if (entries.length !== 1)
|
|
359
|
+
throw setupFailure(
|
|
360
|
+
`The ${label(component)} archive has an unexpected layout`,
|
|
361
|
+
);
|
|
362
|
+
const top = join(extracted, entries[0]!);
|
|
363
|
+
if (!(await stat(top)).isDirectory())
|
|
364
|
+
throw setupFailure(
|
|
365
|
+
`The ${label(component)} archive has an unexpected layout`,
|
|
366
|
+
);
|
|
367
|
+
this.progress(component, "verify");
|
|
368
|
+
await verify(top);
|
|
369
|
+
await writeFile(
|
|
370
|
+
join(top, MARKER),
|
|
371
|
+
JSON.stringify({
|
|
372
|
+
version: component.version,
|
|
373
|
+
archiveSha256: component.archive.sha256,
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
// A directory without a valid marker is an interrupted earlier attempt.
|
|
377
|
+
await rm(component.directory, { recursive: true, force: true });
|
|
378
|
+
await rename(top, component.directory);
|
|
379
|
+
} finally {
|
|
380
|
+
await rm(staging, { recursive: true, force: true });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private async download(
|
|
385
|
+
component: ManagedComponent,
|
|
386
|
+
destination: string,
|
|
387
|
+
): Promise<void> {
|
|
388
|
+
const { url, sha256, size } = component.archive;
|
|
389
|
+
let response: Response;
|
|
390
|
+
try {
|
|
391
|
+
response = await this.fetchImpl(url, { redirect: "follow" });
|
|
392
|
+
} catch (error) {
|
|
393
|
+
throw setupFailure(
|
|
394
|
+
`Cannot download ${label(component)} from ${url}`,
|
|
395
|
+
error,
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (!response.ok || response.body === null)
|
|
399
|
+
throw setupFailure(
|
|
400
|
+
`Download of ${label(component)} failed with HTTP ${response.status}`,
|
|
401
|
+
);
|
|
402
|
+
const hash = createHash("sha256");
|
|
403
|
+
let received = 0;
|
|
404
|
+
this.progress(component, "download", received);
|
|
405
|
+
const meter = new Transform({
|
|
406
|
+
transform: (chunk: Buffer, _encoding, callback) => {
|
|
407
|
+
hash.update(chunk);
|
|
408
|
+
received += chunk.length;
|
|
409
|
+
if (received > size)
|
|
410
|
+
return callback(
|
|
411
|
+
setupFailure(`${label(component)} is larger than the pinned size`),
|
|
412
|
+
);
|
|
413
|
+
this.progress(component, "download", received);
|
|
414
|
+
callback(null, chunk);
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
try {
|
|
418
|
+
await pipeline(
|
|
419
|
+
Readable.fromWeb(
|
|
420
|
+
response.body as import("node:stream/web").ReadableStream,
|
|
421
|
+
),
|
|
422
|
+
meter,
|
|
423
|
+
createWriteStream(destination, { flags: "wx" }),
|
|
424
|
+
);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (error instanceof AdapterError) throw error;
|
|
427
|
+
throw setupFailure(
|
|
428
|
+
`Download of ${label(component)} was interrupted`,
|
|
429
|
+
error,
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
if (hash.digest("hex") !== sha256)
|
|
433
|
+
throw setupFailure(
|
|
434
|
+
`${label(component)} does not match its pinned SHA-256`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private progress(
|
|
439
|
+
component: ManagedComponent,
|
|
440
|
+
phase: SetupProgress["phase"],
|
|
441
|
+
receivedBytes = component.archive.size,
|
|
442
|
+
): void {
|
|
443
|
+
this.current = {
|
|
444
|
+
state: "running",
|
|
445
|
+
component: component.id,
|
|
446
|
+
phase,
|
|
447
|
+
receivedBytes,
|
|
448
|
+
totalBytes: component.archive.size,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private async removeStaleVersions(layout: ManagedLayout): Promise<void> {
|
|
453
|
+
const keep = new Set([layout.node.directory, layout.zcode.directory]);
|
|
454
|
+
for (const entry of await readdir(layout.root)) {
|
|
455
|
+
const path = join(layout.root, entry);
|
|
456
|
+
if (
|
|
457
|
+
!keep.has(path) &&
|
|
458
|
+
(entry === ".staging" || /^(node-v|zcode-)/u.test(entry))
|
|
459
|
+
)
|
|
460
|
+
await rm(path, { recursive: true, force: true }).catch(() => {});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// A crashed setup leaves its lock behind; reclaim it only when its owner is gone.
|
|
466
|
+
async function acquireLock(lock: string): Promise<string> {
|
|
467
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
468
|
+
try {
|
|
469
|
+
await mkdir(lock);
|
|
470
|
+
await writeFile(join(lock, "owner"), String(process.pid));
|
|
471
|
+
return lock;
|
|
472
|
+
} catch (error) {
|
|
473
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST")
|
|
474
|
+
throw setupFailure(
|
|
475
|
+
"Cannot create the managed runtime directory",
|
|
476
|
+
error,
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
const owner = Number(
|
|
480
|
+
await readFile(join(lock, "owner"), "utf8").catch(() => ""),
|
|
481
|
+
);
|
|
482
|
+
if (Number.isSafeInteger(owner) && owner > 0 && processExists(owner))
|
|
483
|
+
throw setupFailure("Another ZCode runtime setup is running");
|
|
484
|
+
await rm(lock, { recursive: true, force: true });
|
|
485
|
+
}
|
|
486
|
+
throw setupFailure("Another ZCode runtime setup is running");
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function processExists(pid: number): boolean {
|
|
490
|
+
try {
|
|
491
|
+
process.kill(pid, 0);
|
|
492
|
+
return true;
|
|
493
|
+
} catch (error) {
|
|
494
|
+
return (error as NodeJS.ErrnoException).code === "EPERM";
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const label = (component: ManagedComponent) =>
|
|
499
|
+
component.id === "node"
|
|
500
|
+
? `Node.js ${component.version}`
|
|
501
|
+
: `ZCode runtime ${component.version}`;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Fixed downloads for the managed runtime (ADR 15). Clients can only ask the
|
|
2
|
+
// server to install these exact artifacts; they never supply URLs or versions.
|
|
3
|
+
export type ManagedPlatform =
|
|
4
|
+
| "darwin-arm64"
|
|
5
|
+
| "linux-x64"
|
|
6
|
+
| "linux-arm64"
|
|
7
|
+
| "win-x64"
|
|
8
|
+
| "win-arm64";
|
|
9
|
+
|
|
10
|
+
export interface PinnedArchive {
|
|
11
|
+
readonly url: string;
|
|
12
|
+
readonly sha256: string;
|
|
13
|
+
readonly size: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const MANAGED_NODE_VERSION = "24.21.0";
|
|
17
|
+
|
|
18
|
+
// Checksums come from nodejs.org SHASUMS256.txt, whose signature was verified
|
|
19
|
+
// against the nodejs/release-keys active keyring when the version was pinned.
|
|
20
|
+
const nodeArchive = (file: string, sha256: string, size: number) => ({
|
|
21
|
+
url: `https://nodejs.org/dist/v${MANAGED_NODE_VERSION}/${file}`,
|
|
22
|
+
sha256,
|
|
23
|
+
size,
|
|
24
|
+
});
|
|
25
|
+
export const MANAGED_NODE_ARCHIVES: Readonly<
|
|
26
|
+
Record<ManagedPlatform, PinnedArchive>
|
|
27
|
+
> = {
|
|
28
|
+
"darwin-arm64": nodeArchive(
|
|
29
|
+
`node-v${MANAGED_NODE_VERSION}-darwin-arm64.tar.gz`,
|
|
30
|
+
"bed7eea5325e1108f32ce5228ddd6a5f0f08a499ee42aa7442aea583702f6057",
|
|
31
|
+
52_909_993,
|
|
32
|
+
),
|
|
33
|
+
"linux-x64": nodeArchive(
|
|
34
|
+
`node-v${MANAGED_NODE_VERSION}-linux-x64.tar.gz`,
|
|
35
|
+
"6e1db87ef58b8819e5d5402eff1536491b18edd8eb7bee5ef7897876e88dc5ff",
|
|
36
|
+
58_088_022,
|
|
37
|
+
),
|
|
38
|
+
"linux-arm64": nodeArchive(
|
|
39
|
+
`node-v${MANAGED_NODE_VERSION}-linux-arm64.tar.gz`,
|
|
40
|
+
"724282c3b43aec998aa9527380465b45d229e021b58035f5f4f63095eabfe5d5",
|
|
41
|
+
57_824_078,
|
|
42
|
+
),
|
|
43
|
+
"win-x64": nodeArchive(
|
|
44
|
+
`node-v${MANAGED_NODE_VERSION}-win-x64.zip`,
|
|
45
|
+
"158f7685b44de51f6c0df1d153526cbcd3e1bc739a8dfc607721cef75de9e541",
|
|
46
|
+
37_618_919,
|
|
47
|
+
),
|
|
48
|
+
"win-arm64": nodeArchive(
|
|
49
|
+
`node-v${MANAGED_NODE_VERSION}-win-arm64.zip`,
|
|
50
|
+
"8779b1bde1d39f8d420e3b57aa657b39891af434d3de44a919044cec06785921",
|
|
51
|
+
33_679_608,
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Published by .github/workflows/zcode-runtime-release.yml from the pinned
|
|
56
|
+
// unmodified source. The same archive serves every managed platform.
|
|
57
|
+
export const MANAGED_ZCODE_VERSION = "3.14.3";
|
|
58
|
+
export const MANAGED_ZCODE_ARCHIVE: PinnedArchive = {
|
|
59
|
+
url: `https://github.com/supermomonga/paseo-plugin-zcode-provider/releases/download/zcode-runtime-v${MANAGED_ZCODE_VERSION}/zcode-runtime-${MANAGED_ZCODE_VERSION}.tar.gz`,
|
|
60
|
+
sha256: "a2af414592362d226f92c105d91211e5c4f138cf985b0c86da0eb9163cb9aee7",
|
|
61
|
+
size: 79_887_659,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export function managedPlatform(
|
|
65
|
+
platform: NodeJS.Platform = process.platform,
|
|
66
|
+
arch: string = process.arch,
|
|
67
|
+
): ManagedPlatform | undefined {
|
|
68
|
+
const key = `${platform === "win32" ? "win" : platform}-${arch}`;
|
|
69
|
+
return Object.hasOwn(MANAGED_NODE_ARCHIVES, key)
|
|
70
|
+
? (key as ManagedPlatform)
|
|
71
|
+
: undefined;
|
|
72
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { RuntimeSetupStatus } from "../shared/runtime-setup.js";
|
|
2
|
+
import { AdapterError } from "./errors.js";
|
|
3
|
+
import {
|
|
4
|
+
isInstalled,
|
|
5
|
+
managedRuntimeRoot,
|
|
6
|
+
ManagedRuntimeInstaller,
|
|
7
|
+
type ManagedComponent,
|
|
8
|
+
} from "./runtime/managed.js";
|
|
9
|
+
|
|
10
|
+
const LICENSES = {
|
|
11
|
+
node: "Node.js license (MIT) with bundled third-party notices",
|
|
12
|
+
zcode:
|
|
13
|
+
"Unofficial build of ZCode (Apache-2.0); third-party terms in THIRD-PARTY-NOTICES.md",
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export function createRuntimeSetupHandlers(
|
|
17
|
+
installer: ManagedRuntimeInstaller,
|
|
18
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
19
|
+
) {
|
|
20
|
+
const component = async (
|
|
21
|
+
entry: ManagedComponent,
|
|
22
|
+
): Promise<RuntimeSetupStatus["components"][number]> => ({
|
|
23
|
+
id: entry.id,
|
|
24
|
+
name: entry.id === "node" ? "Node.js" : "ZCode runtime",
|
|
25
|
+
version: entry.version,
|
|
26
|
+
url: entry.archive.url,
|
|
27
|
+
sha256: entry.archive.sha256,
|
|
28
|
+
sizeBytes: entry.archive.size,
|
|
29
|
+
license: LICENSES[entry.id],
|
|
30
|
+
installed: await isInstalled(entry),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
async status(): Promise<RuntimeSetupStatus> {
|
|
35
|
+
const layout = installer.layout();
|
|
36
|
+
const override = Boolean(
|
|
37
|
+
environment.PASEO_ZCODE_RUNTIME || environment.PASEO_ZCODE_NODE,
|
|
38
|
+
);
|
|
39
|
+
const base = {
|
|
40
|
+
platform: `${process.platform}-${process.arch}`,
|
|
41
|
+
override,
|
|
42
|
+
job: installer.state(),
|
|
43
|
+
};
|
|
44
|
+
if (layout === undefined)
|
|
45
|
+
return {
|
|
46
|
+
...base,
|
|
47
|
+
supported: false,
|
|
48
|
+
directory: managedRuntimeRoot(environment),
|
|
49
|
+
components: [],
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
...base,
|
|
53
|
+
supported: true,
|
|
54
|
+
directory: layout.root,
|
|
55
|
+
components: [
|
|
56
|
+
await component(layout.node),
|
|
57
|
+
await component(layout.zcode),
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
install: async () => ({ started: installer.start() }),
|
|
62
|
+
async remove() {
|
|
63
|
+
try {
|
|
64
|
+
await installer.remove();
|
|
65
|
+
return { status: "removed" as const };
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
status: "failed" as const,
|
|
69
|
+
message:
|
|
70
|
+
error instanceof AdapterError
|
|
71
|
+
? error.message
|
|
72
|
+
: "The managed runtime could not be removed",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProviderContent,
|
|
3
|
+
ProviderPermissionRequest,
|
|
4
|
+
ProviderPermissionResponse,
|
|
5
|
+
ProviderTimelineItem,
|
|
6
|
+
ProviderUsage,
|
|
7
|
+
} from "@getpaseo/plugin/server/provider";
|
|
8
|
+
|
|
9
|
+
export type NativePromptInput = string | ProviderContent[];
|
|
10
|
+
export type NativeTimelineItem = ProviderTimelineItem;
|
|
11
|
+
export interface NativeTimelineEntry {
|
|
12
|
+
item: NativeTimelineItem;
|
|
13
|
+
timestamp?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type NativeSessionEvent =
|
|
17
|
+
| {
|
|
18
|
+
type: "prompt_accepted";
|
|
19
|
+
clientMessageId: string;
|
|
20
|
+
turnId: string;
|
|
21
|
+
delivery: "turn" | "steer";
|
|
22
|
+
}
|
|
23
|
+
| ({ type: "timeline"; turnId?: string } & NativeTimelineEntry)
|
|
24
|
+
| { type: "usage_updated"; usage: ProviderUsage; turnId?: string }
|
|
25
|
+
| {
|
|
26
|
+
type: "turn_started" | "turn_completed" | "turn_canceled";
|
|
27
|
+
turnId: string;
|
|
28
|
+
usage?: ProviderUsage;
|
|
29
|
+
reason?: string;
|
|
30
|
+
}
|
|
31
|
+
| {
|
|
32
|
+
type: "turn_failed" | "runtime_failed";
|
|
33
|
+
turnId?: string;
|
|
34
|
+
error: string;
|
|
35
|
+
code?: string;
|
|
36
|
+
diagnostic?: string;
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
type: "permission_requested";
|
|
40
|
+
request: ProviderPermissionRequest;
|
|
41
|
+
turnId?: string;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
type: "permission_resolved";
|
|
45
|
+
requestId: string;
|
|
46
|
+
resolution: ProviderPermissionResponse;
|
|
47
|
+
turnId?: string;
|
|
48
|
+
}
|
|
49
|
+
| { type: "config_changed" };
|