@keystrokehq/cli 0.0.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/AGENTS-blurb.md +123 -0
- package/LICENSE +42 -0
- package/README.md +177 -0
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/bin/keystroke.mjs +107 -0
- package/dist/_manifest-JSRE3H8k.mjs +385 -0
- package/dist/agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs +2344 -0
- package/dist/agent-manifest-CDnbkR2f.mjs +245 -0
- package/dist/agents-CZJGxVqV.mjs +228 -0
- package/dist/api-keys-D2lgguuY.mjs +40 -0
- package/dist/auth-DN2VusyU.mjs +59 -0
- package/dist/auth.handler-CT1BQUvu.mjs +340 -0
- package/dist/browser-qwFrUH82.mjs +24 -0
- package/dist/build-agents-BmM_AsSd-BGi9wtzt.mjs +514 -0
- package/dist/build-metadata-BWS7uhd_-DR8gJjTX.mjs +1422 -0
- package/dist/build-progress-DgYKb4hB.mjs +183 -0
- package/dist/build-tasks-CdihpudT-D5r5HUHe.mjs +91 -0
- package/dist/build-workflows-CfxBnIWh-CdYPv8w2.mjs +370 -0
- package/dist/build.handler-4799CjWH.mjs +36 -0
- package/dist/chunk-CH6r78ws.mjs +37 -0
- package/dist/clear-cache.handler-B9tqSoSM.mjs +11 -0
- package/dist/clear.handler-BTIXXPTJ.mjs +42 -0
- package/dist/clear.handler-BydlX-zE.mjs +11 -0
- package/dist/commander-DfTVqQ-3.mjs +133 -0
- package/dist/concurrency-gXn9Rw8x-DNl2YtrS.mjs +20 -0
- package/dist/connect-BUXkeH0F.mjs +43 -0
- package/dist/connect.handler-CYel9cy6.mjs +430 -0
- package/dist/constants-CPpPdSNg.mjs +8 -0
- package/dist/context-T7HZuB97.mjs +138 -0
- package/dist/credential-env-map-CI8yWHVy.mjs +28 -0
- package/dist/credential-schema-mismatch-BKo5PjcQ.mjs +76 -0
- package/dist/credentials-CvmjU0lK.mjs +171 -0
- package/dist/credentials-OfVHOtG3.mjs +151216 -0
- package/dist/current-deployment-workflow-poHt27i3.mjs +94 -0
- package/dist/current.handler-B8zKzfPp.mjs +21 -0
- package/dist/delete.handler-bAu1iXVQ.mjs +17 -0
- package/dist/deploy-7Jjls436.mjs +26 -0
- package/dist/deploy-BOPIpRWm.mjs +74 -0
- package/dist/deploy-progress-BmGUNFKg.mjs +70 -0
- package/dist/deploy.handler-BAzgiNhd.mjs +370 -0
- package/dist/detect-env-access-CwkOYeYM-D_BCZqV6.mjs +209 -0
- package/dist/diff-utils-NEfcjqxt.mjs +185 -0
- package/dist/diff.handler-Du7SY8K4.mjs +47 -0
- package/dist/dist-BkJUoBiG.mjs +1116 -0
- package/dist/dist-CUK7yBM0.mjs +308 -0
- package/dist/env-91KwMKov.mjs +140 -0
- package/dist/env.handler-BAzBuMzQ.mjs +277 -0
- package/dist/error-boundary-VL-JLfIa.mjs +34 -0
- package/dist/file-metadata-D1vm-XY2.mjs +191 -0
- package/dist/get-intrinsic-zLxwtrLK.mjs +658 -0
- package/dist/import-module-CV84H5fZ-B_CBCmb4.mjs +1747 -0
- package/dist/init-DpMCotSK.mjs +45 -0
- package/dist/init.handler-CPRnif52.mjs +585 -0
- package/dist/inspect.handler-DT_cD036.mjs +146 -0
- package/dist/integration-catalog-Bt-L3GjF.mjs +104 -0
- package/dist/integrations-DlatPK4W.mjs +79 -0
- package/dist/keystroke.d.mts +3 -0
- package/dist/keystroke.mjs +707 -0
- package/dist/layout-CbMtQ2tm.mjs +67 -0
- package/dist/list-enrichment-y-cwizLr.mjs +189 -0
- package/dist/list.handler-BTWvCyjA.mjs +52 -0
- package/dist/list.handler-CWF_Dj15.mjs +24 -0
- package/dist/list.handler-CZ6G2x_G.mjs +75 -0
- package/dist/list.handler-DWaQkJaR.mjs +51 -0
- package/dist/list.handler-DqbFcBW7.mjs +180 -0
- package/dist/list.handler-lq3ZGAn4.mjs +104 -0
- package/dist/logs-BEg9L5l8.mjs +28 -0
- package/dist/logs.handler-6hoMBzqw.mjs +35 -0
- package/dist/logs.handler-BD_dXiL1.mjs +231 -0
- package/dist/metadata-layout-GUYIUo0i-_aG2zjue.mjs +5877 -0
- package/dist/normalize-path-CojS-CgQ-DLCOvnD1.mjs +20 -0
- package/dist/options-CeaTcFxP.mjs +43 -0
- package/dist/org-xLzBtt2_.mjs +41 -0
- package/dist/output-DM4b7KgY.mjs +72 -0
- package/dist/oxc-B3KI3rf_-n9d1hKNq.mjs +119 -0
- package/dist/paused.handler-BMFm9Cff.mjs +94 -0
- package/dist/project-config-D1qsQlO7.mjs +107 -0
- package/dist/projects-CHkRE9rS.mjs +1574 -0
- package/dist/projects-Cjb7sovS.mjs +30 -0
- package/dist/read-credential-keys-77a91T8M-KA0Iw0Z1.mjs +9 -0
- package/dist/register.handler-BPCdor1_.mjs +86 -0
- package/dist/requirements.handler-DPXdSks3.mjs +201 -0
- package/dist/resolve-project-DDJ29sCF.mjs +35 -0
- package/dist/rolldown-runtime-twds-ZHy-BWWzu8VG.mjs +15 -0
- package/dist/run-polling-CAgFRdK3.mjs +20 -0
- package/dist/runs-D9hNLb9A.mjs +259 -0
- package/dist/schedule-BXx3uXwr.mjs +1142 -0
- package/dist/schema-17qMfNyI.mjs +18 -0
- package/dist/schema-display-CgmeKigW.mjs +130 -0
- package/dist/schemas-CDib1RhE.mjs +125 -0
- package/dist/skills-sync.handler-DIy8GR16.mjs +34 -0
- package/dist/skills.command-CrjI2dN9.mjs +35 -0
- package/dist/skills.handler-Bz8bJKql.mjs +9 -0
- package/dist/source-analysis-Cj-ADyu--BJQcFPCG.mjs +144 -0
- package/dist/spinner-progress-DMVwgqO9.mjs +173 -0
- package/dist/src-C0X6u_Mw.mjs +1340 -0
- package/dist/src-eHwu-Gfw.mjs +369 -0
- package/dist/status.handler-BO4nwvWn.mjs +101 -0
- package/dist/switch.handler-D_9213Vf.mjs +51 -0
- package/dist/sync-BL_Mo5st.mjs +39 -0
- package/dist/sync-keystroke-agent-skills-Kx_H7UTd.mjs +70 -0
- package/dist/sync.handler-BUFPdzWz.mjs +82 -0
- package/dist/task-B2sZMaZu.mjs +8 -0
- package/dist/task-target-build-CBeCKbu2.mjs +432 -0
- package/dist/task-target-deploy-C5X-USeR.mjs +4 -0
- package/dist/task-target-deploy-CA6elFpF-BEr4gkol.mjs +271 -0
- package/dist/task-target-deploy-runner.d.mts +3 -0
- package/dist/task-target-deploy-runner.mjs +202 -0
- package/dist/test-BHTgR3UA.mjs +698 -0
- package/dist/test.handler-BcPQ8b74.mjs +13 -0
- package/dist/trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs +239 -0
- package/dist/trigger-manifest-CY7brZeg.mjs +30 -0
- package/dist/try-deploy.handler-DqybNhXx.mjs +490 -0
- package/dist/upload-CkU--iDC.mjs +207 -0
- package/dist/upload.handler-DCtiznQp.mjs +441 -0
- package/dist/utils-CywxCDM7.mjs +14 -0
- package/dist/validate.handler-DOcTaJL0.mjs +280 -0
- package/dist/workflow-build-DBQaBfnn.mjs +1819 -0
- package/dist/workflow-bundler-BPiqVscj-X1PFFAuP.mjs +167 -0
- package/dist/workflows-g9z87AJJ.mjs +799 -0
- package/dist/writer-BG8poUm3-BbXlU2kI.mjs +426 -0
- package/package.json +87 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { n as readOptionalJsonSchemaKeys, t as manifestToDeclaredCredentialRequirement } from "./_manifest-JSRE3H8k.mjs";
|
|
4
|
+
import { t as AgentVersionManifestSchema } from "./agent-manifest-CDnbkR2f.mjs";
|
|
5
|
+
import { i as createAgentSandboxPackage, n as AGENT_VM_PI_SKILLS_ROOT, r as AGENT_VM_TOOLS_RUNTIME_RELATIVE_PATH, t as AGENT_VM_HOST_CALL_RELATIVE_PATH } from "./agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs";
|
|
6
|
+
import { t as readCredentialKeysFromSchemaObject } from "./read-credential-keys-77a91T8M-KA0Iw0Z1.mjs";
|
|
7
|
+
import { t as bundleSandboxAgentTarget } from "./workflow-bundler-BPiqVscj-X1PFFAuP.mjs";
|
|
8
|
+
import { builtinModules } from "node:module";
|
|
9
|
+
import { lstat, readFile, readdir, realpath } from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import * as crypto from "node:crypto";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { performance } from "node:perf_hooks";
|
|
14
|
+
//#region ../../packages/workflow-core/src/sandbox/host-call-stub-source.ts
|
|
15
|
+
const HOST_CALL_STUB_SOURCE = [
|
|
16
|
+
"const __pendingHostCalls = new Map();",
|
|
17
|
+
"let __hostCallCounter = 0;",
|
|
18
|
+
"const __DEFAULT_HOST_CALL_STUB_TIMEOUT_MS = 6 * 60 * 1000;",
|
|
19
|
+
"const __HOST_CALL_NOTIFY_PREFIX = \"__keystroke_host_call__:\";",
|
|
20
|
+
"const __pi = globalThis.pi;",
|
|
21
|
+
"const __onCommand =",
|
|
22
|
+
" __pi && typeof __pi.onCommand === \"function\" ? __pi.onCommand.bind(__pi) : null;",
|
|
23
|
+
"const __emitHostCallEvent =",
|
|
24
|
+
" __pi && typeof __pi.emit === \"function\"",
|
|
25
|
+
" ? (event) => __pi.emit(event)",
|
|
26
|
+
" : (event, ui) => {",
|
|
27
|
+
" if (!ui || typeof ui.notify !== \"function\") {",
|
|
28
|
+
" throw new Error(\"Host call transport is unavailable\");",
|
|
29
|
+
" }",
|
|
30
|
+
" ui.notify(`${__HOST_CALL_NOTIFY_PREFIX}${JSON.stringify(event)}`);",
|
|
31
|
+
" };",
|
|
32
|
+
"const __supportsHostCallResponses = __onCommand !== null;",
|
|
33
|
+
"",
|
|
34
|
+
"export async function __keystrokeHostCall(toolCallId, payload, opts = {}) {",
|
|
35
|
+
" const id = `hc_${++__hostCallCounter}`;",
|
|
36
|
+
" const timeoutMs = opts.timeoutMs ?? __DEFAULT_HOST_CALL_STUB_TIMEOUT_MS;",
|
|
37
|
+
" const traceContext = opts.traceparent",
|
|
38
|
+
" ? { traceparent: opts.traceparent, tracestate: opts.tracestate ?? undefined }",
|
|
39
|
+
" : null;",
|
|
40
|
+
"",
|
|
41
|
+
" return new Promise((resolve, reject) => {",
|
|
42
|
+
" if (!__supportsHostCallResponses) {",
|
|
43
|
+
" try {",
|
|
44
|
+
" __emitHostCallEvent({",
|
|
45
|
+
" type: 'host_call_request',",
|
|
46
|
+
" id,",
|
|
47
|
+
" toolCallId,",
|
|
48
|
+
" traceContext,",
|
|
49
|
+
" payload,",
|
|
50
|
+
" }, opts.ui);",
|
|
51
|
+
" resolve(toFireAndForgetReceipt(payload));",
|
|
52
|
+
" } catch (error) {",
|
|
53
|
+
" reject(error);",
|
|
54
|
+
" }",
|
|
55
|
+
" return;",
|
|
56
|
+
" }",
|
|
57
|
+
"",
|
|
58
|
+
" const timer = setTimeout(() => {",
|
|
59
|
+
" __pendingHostCalls.delete(id);",
|
|
60
|
+
" reject(new HostCallStubTimeoutError(id, timeoutMs));",
|
|
61
|
+
" }, timeoutMs);",
|
|
62
|
+
" __pendingHostCalls.set(id, {",
|
|
63
|
+
" resolve: (value) => {",
|
|
64
|
+
" clearTimeout(timer);",
|
|
65
|
+
" resolve(value);",
|
|
66
|
+
" },",
|
|
67
|
+
" reject: (error) => {",
|
|
68
|
+
" clearTimeout(timer);",
|
|
69
|
+
" reject(error);",
|
|
70
|
+
" },",
|
|
71
|
+
" });",
|
|
72
|
+
"",
|
|
73
|
+
" try {",
|
|
74
|
+
" __emitHostCallEvent({",
|
|
75
|
+
" type: 'host_call_request',",
|
|
76
|
+
" id,",
|
|
77
|
+
" toolCallId,",
|
|
78
|
+
" traceContext,",
|
|
79
|
+
" payload,",
|
|
80
|
+
" }, opts.ui);",
|
|
81
|
+
" } catch (error) {",
|
|
82
|
+
" __pendingHostCalls.delete(id);",
|
|
83
|
+
" clearTimeout(timer);",
|
|
84
|
+
" reject(error);",
|
|
85
|
+
" }",
|
|
86
|
+
" });",
|
|
87
|
+
"}",
|
|
88
|
+
"",
|
|
89
|
+
"if (__supportsHostCallResponses) {",
|
|
90
|
+
"__onCommand('host_call_response', (cmd) => {",
|
|
91
|
+
" const pending = __pendingHostCalls.get(cmd.id);",
|
|
92
|
+
" if (!pending) return;",
|
|
93
|
+
" __pendingHostCalls.delete(cmd.id);",
|
|
94
|
+
"",
|
|
95
|
+
" switch (cmd.result.status) {",
|
|
96
|
+
" case 'completed':",
|
|
97
|
+
" return pending.resolve({ kind: 'completed', output: cmd.result.output });",
|
|
98
|
+
" case 'failed':",
|
|
99
|
+
" return pending.reject(asError(cmd.result.error));",
|
|
100
|
+
" case 'cancelled':",
|
|
101
|
+
" return pending.reject(new HostCallCancelledError());",
|
|
102
|
+
" case 'timeout':",
|
|
103
|
+
" return pending.reject(new HostCallTimeoutError());",
|
|
104
|
+
" case 'yield':",
|
|
105
|
+
" return pending.resolve({ kind: 'yield', receipt: cmd.result.yieldReceipt });",
|
|
106
|
+
" case 'cred-wait':",
|
|
107
|
+
" return pending.resolve({ kind: 'cred-wait', envelope: cmd.result.envelope });",
|
|
108
|
+
" }",
|
|
109
|
+
"});",
|
|
110
|
+
"}",
|
|
111
|
+
"",
|
|
112
|
+
"function toFireAndForgetReceipt(payload) {",
|
|
113
|
+
" if (payload && payload.kind === \"child-workflow\") {",
|
|
114
|
+
" return {",
|
|
115
|
+
" kind: \"yield\",",
|
|
116
|
+
" receipt: {",
|
|
117
|
+
" pending: true,",
|
|
118
|
+
" kind: \"workflow\",",
|
|
119
|
+
" reason: \"Workflow tool started and will continue asynchronously.\",",
|
|
120
|
+
" _instruction:",
|
|
121
|
+
" \"Tell the user the workflow is still running in the background, then end your turn. The platform will resume when it completes.\",",
|
|
122
|
+
" },",
|
|
123
|
+
" };",
|
|
124
|
+
" }",
|
|
125
|
+
"",
|
|
126
|
+
" return {",
|
|
127
|
+
" kind: \"yield\",",
|
|
128
|
+
" receipt: {",
|
|
129
|
+
" pending: true,",
|
|
130
|
+
" kind: payload && payload.kind ? payload.kind : \"host-call\",",
|
|
131
|
+
" reason: \"Host call started and will continue asynchronously.\",",
|
|
132
|
+
" },",
|
|
133
|
+
" };",
|
|
134
|
+
"}",
|
|
135
|
+
"",
|
|
136
|
+
"class HostCallCancelledError extends Error {",
|
|
137
|
+
" constructor() {",
|
|
138
|
+
" super('Host call cancelled');",
|
|
139
|
+
" this.name = 'HostCallCancelledError';",
|
|
140
|
+
" }",
|
|
141
|
+
"}",
|
|
142
|
+
"",
|
|
143
|
+
"class HostCallTimeoutError extends Error {",
|
|
144
|
+
" constructor() {",
|
|
145
|
+
" super('Host call timed out');",
|
|
146
|
+
" this.name = 'HostCallTimeoutError';",
|
|
147
|
+
" }",
|
|
148
|
+
"}",
|
|
149
|
+
"",
|
|
150
|
+
"class HostCallStubTimeoutError extends Error {",
|
|
151
|
+
" constructor(id, timeoutMs) {",
|
|
152
|
+
" super(`Host call ${id} did not receive a host response within ${timeoutMs}ms`);",
|
|
153
|
+
" this.name = 'HostCallStubTimeoutError';",
|
|
154
|
+
" this.hostCallId = id;",
|
|
155
|
+
" this.timeoutMs = timeoutMs;",
|
|
156
|
+
" }",
|
|
157
|
+
"}",
|
|
158
|
+
"",
|
|
159
|
+
"function asError(envelope) {",
|
|
160
|
+
" const error = new Error(envelope.message);",
|
|
161
|
+
" error.name = envelope.name;",
|
|
162
|
+
" error.code = envelope.code;",
|
|
163
|
+
" error.category = envelope.category;",
|
|
164
|
+
" error.details = envelope.details;",
|
|
165
|
+
" return error;",
|
|
166
|
+
"}"
|
|
167
|
+
].join("\n");
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region ../../packages/workflow-builder/dist/build-agents-BmM_AsSd.mjs
|
|
170
|
+
const STAGED_LOCAL_SOURCES_PREFIX = ".keystroke/staged-local-sources";
|
|
171
|
+
function normalizeRelativeSandboxPath(targetPath) {
|
|
172
|
+
const normalized = path.posix.normalize(targetPath);
|
|
173
|
+
if (normalized.length === 0 || normalized === "." || normalized === ".." || normalized.startsWith("../") || path.posix.isAbsolute(normalized)) throw new Error(`Sandbox bootstrap path must stay relative to the sandbox root: ${targetPath}`);
|
|
174
|
+
return normalized;
|
|
175
|
+
}
|
|
176
|
+
function resolveLocalSourceTarget(sourcePath) {
|
|
177
|
+
return normalizeRelativeSandboxPath(path.posix.join(STAGED_LOCAL_SOURCES_PREFIX, path.posix.basename(sourcePath)));
|
|
178
|
+
}
|
|
179
|
+
function toBootstrapMode(mode) {
|
|
180
|
+
const normalizedMode = mode & 511;
|
|
181
|
+
return normalizedMode > 0 ? normalizedMode : void 0;
|
|
182
|
+
}
|
|
183
|
+
function resolveLocalFilesystemPath(projectRoot, sourcePath) {
|
|
184
|
+
const normalizedSourcePath = sourcePath.startsWith("file://") ? sourcePath.slice(7) : sourcePath;
|
|
185
|
+
return path.isAbsolute(normalizedSourcePath) ? normalizedSourcePath : path.resolve(projectRoot, normalizedSourcePath);
|
|
186
|
+
}
|
|
187
|
+
async function collectBootstrapFilesFromPath(params) {
|
|
188
|
+
const stats = await lstat(params.absolutePath).catch((error) => {
|
|
189
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
190
|
+
throw error;
|
|
191
|
+
});
|
|
192
|
+
if (!stats) return [];
|
|
193
|
+
if (stats.isSymbolicLink()) {
|
|
194
|
+
const resolvedPath = await realpath(params.absolutePath).catch((error) => {
|
|
195
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
196
|
+
throw error;
|
|
197
|
+
});
|
|
198
|
+
if (!resolvedPath) return [];
|
|
199
|
+
return collectBootstrapFilesFromPath({
|
|
200
|
+
absolutePath: resolvedPath,
|
|
201
|
+
targetPath: params.targetPath
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (stats.isDirectory()) {
|
|
205
|
+
const entries = await readdir(params.absolutePath, { withFileTypes: true }).catch((error) => {
|
|
206
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
207
|
+
throw error;
|
|
208
|
+
});
|
|
209
|
+
if (!entries) return [];
|
|
210
|
+
const sortedEntries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
|
|
211
|
+
const nested = [];
|
|
212
|
+
for (const entry of sortedEntries) nested.push(await collectBootstrapFilesFromPath({
|
|
213
|
+
absolutePath: path.join(params.absolutePath, entry.name),
|
|
214
|
+
targetPath: normalizeRelativeSandboxPath(path.posix.join(params.targetPath, entry.name))
|
|
215
|
+
}));
|
|
216
|
+
return nested.flat();
|
|
217
|
+
}
|
|
218
|
+
if (stats.isFile()) {
|
|
219
|
+
const content = await readFile(params.absolutePath).catch((error) => {
|
|
220
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
221
|
+
throw error;
|
|
222
|
+
});
|
|
223
|
+
if (!content) return [];
|
|
224
|
+
return [{
|
|
225
|
+
path: params.targetPath,
|
|
226
|
+
content,
|
|
227
|
+
mode: toBootstrapMode(stats.mode),
|
|
228
|
+
restoreBehavior: "overwrite"
|
|
229
|
+
}];
|
|
230
|
+
}
|
|
231
|
+
throw new Error(`Unsupported sandbox file source type at ${params.absolutePath}`);
|
|
232
|
+
}
|
|
233
|
+
async function resolveSkillSourceDirectory(projectRoot, skillPath) {
|
|
234
|
+
const absolutePath = resolveLocalFilesystemPath(projectRoot, skillPath);
|
|
235
|
+
const stats = await lstat(absolutePath).catch((error) => {
|
|
236
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
237
|
+
throw error;
|
|
238
|
+
});
|
|
239
|
+
if (!stats) throw new Error(`Skill source path not found: ${skillPath}`);
|
|
240
|
+
if (stats.isSymbolicLink()) {
|
|
241
|
+
const resolvedPath = await realpath(absolutePath).catch((error) => {
|
|
242
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
243
|
+
throw error;
|
|
244
|
+
});
|
|
245
|
+
if (!resolvedPath) throw new Error(`Skill source path not found: ${skillPath}`);
|
|
246
|
+
return resolveSkillSourceDirectory(projectRoot, resolvedPath);
|
|
247
|
+
}
|
|
248
|
+
if (!stats.isDirectory()) throw new Error(`Skill source path must point to a directory containing SKILL.md: ${skillPath}`);
|
|
249
|
+
const skillManifestStats = await lstat(path.join(absolutePath, "SKILL.md")).catch((error) => {
|
|
250
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
251
|
+
throw error;
|
|
252
|
+
});
|
|
253
|
+
if (!skillManifestStats || !skillManifestStats.isFile()) throw new Error(`Skill source directory must contain SKILL.md: ${skillPath}`);
|
|
254
|
+
return absolutePath;
|
|
255
|
+
}
|
|
256
|
+
function resolveSkillSourceTarget(absolutePath) {
|
|
257
|
+
const skillDirName = path.basename(path.resolve(absolutePath));
|
|
258
|
+
const relativeSkillsRoot = path.posix.relative("/home/user", AGENT_VM_PI_SKILLS_ROOT);
|
|
259
|
+
return normalizeRelativeSandboxPath(path.posix.join(relativeSkillsRoot, skillDirName));
|
|
260
|
+
}
|
|
261
|
+
async function collectSandboxSourceFiles(projectRoot, source) {
|
|
262
|
+
if (source.type === "local") return collectBootstrapFilesFromPath({
|
|
263
|
+
absolutePath: resolveLocalFilesystemPath(projectRoot, source.path),
|
|
264
|
+
targetPath: resolveLocalSourceTarget(source.path)
|
|
265
|
+
});
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
async function collectSkillSourceFiles(projectRoot, skill) {
|
|
269
|
+
const absolutePath = await resolveSkillSourceDirectory(projectRoot, skill.path);
|
|
270
|
+
return collectBootstrapFilesFromPath({
|
|
271
|
+
absolutePath,
|
|
272
|
+
targetPath: resolveSkillSourceTarget(absolutePath)
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async function buildAgentSandboxPackage(params) {
|
|
276
|
+
const sourceFiles = await Promise.all((params.agentManifest.sandbox?.fileSources ?? []).map((source) => collectSandboxSourceFiles(params.projectRoot, source)));
|
|
277
|
+
const skillFiles = await Promise.all((params.agentManifest.skills ?? []).map((skill) => collectSkillSourceFiles(params.projectRoot, skill)));
|
|
278
|
+
const bootstrapFiles = [
|
|
279
|
+
{
|
|
280
|
+
path: AGENT_VM_TOOLS_RUNTIME_RELATIVE_PATH,
|
|
281
|
+
content: params.bundleCode,
|
|
282
|
+
restoreBehavior: "overwrite"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
path: AGENT_VM_HOST_CALL_RELATIVE_PATH,
|
|
286
|
+
content: HOST_CALL_STUB_SOURCE,
|
|
287
|
+
restoreBehavior: "overwrite"
|
|
288
|
+
},
|
|
289
|
+
...sourceFiles.flat(),
|
|
290
|
+
...skillFiles.flat()
|
|
291
|
+
];
|
|
292
|
+
const packageBuffer = await createAgentSandboxPackage(bootstrapFiles);
|
|
293
|
+
return {
|
|
294
|
+
bootstrapFiles,
|
|
295
|
+
packageBuffer,
|
|
296
|
+
packageHash: createHash("sha256").update(packageBuffer).digest("hex"),
|
|
297
|
+
packageSize: packageBuffer.byteLength
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function schemaFingerprintForManifestCredentialSet(credentialSet) {
|
|
301
|
+
const { schemaFingerprint } = manifestToDeclaredCredentialRequirement(credentialSet);
|
|
302
|
+
if (!schemaFingerprint) throw new Error(`Cannot compute schema fingerprint for credential set "${credentialSet.resolvedCredentialSetId}"`);
|
|
303
|
+
return schemaFingerprint;
|
|
304
|
+
}
|
|
305
|
+
function createSessionRuntimePlacement() {
|
|
306
|
+
return {
|
|
307
|
+
cwd: "/home/user",
|
|
308
|
+
piRoot: "/home/user/.pi"
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Builds the sandbox block carried on the deployment manifest. Includes the
|
|
313
|
+
* inputs the executor's bootstrap + runtime stages read:
|
|
314
|
+
* - `setupCommands` (top-level) — runs once, marker-gated, cacheable.
|
|
315
|
+
* - `runtime.runCommands` — runs every boot.
|
|
316
|
+
* - `runtime.{workdir, env}` — VM placement and env.
|
|
317
|
+
* - `fileSources` — local sources baked into the bundle, git sources
|
|
318
|
+
* cloned in-VM during bootstrap.
|
|
319
|
+
*/
|
|
320
|
+
function createSandboxBlock(agentManifest) {
|
|
321
|
+
const sandbox = agentManifest.sandbox;
|
|
322
|
+
if (!sandbox) return void 0;
|
|
323
|
+
const setupCommands = sandbox.setupCommands ? [...sandbox.setupCommands] : [];
|
|
324
|
+
const fileSources = sandbox.fileSources ? [...sandbox.fileSources] : [];
|
|
325
|
+
return {
|
|
326
|
+
...sandbox.runtime ? { runtime: {
|
|
327
|
+
runCommands: sandbox.runtime.runCommands ?? [],
|
|
328
|
+
env: sandbox.runtime.env ?? {},
|
|
329
|
+
...sandbox.runtime.workdir ? { workdir: sandbox.runtime.workdir } : {}
|
|
330
|
+
} } : {},
|
|
331
|
+
...setupCommands.length > 0 ? { setupCommands } : {},
|
|
332
|
+
...fileSources.length > 0 ? { fileSources } : {}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function createResolvedMcpServers(agentManifest) {
|
|
336
|
+
if (agentManifest.mcpServers.length === 0) return;
|
|
337
|
+
return agentManifest.mcpServers.map((server) => {
|
|
338
|
+
if (server.credentialSets.length > 0 && !server.credentialInjection) throw new Error(`MCP server "${server.id}" must define credentialInjection to be deployable in Pi sessions.`);
|
|
339
|
+
return {
|
|
340
|
+
id: server.id,
|
|
341
|
+
name: server.name,
|
|
342
|
+
...server.description ? { description: server.description } : {},
|
|
343
|
+
transport: server.transport,
|
|
344
|
+
credentialSets: server.credentialSets.map((credentialSet) => ({
|
|
345
|
+
id: credentialSet.id,
|
|
346
|
+
resolvedId: credentialSet.resolvedCredentialSetId,
|
|
347
|
+
credentialKeys: readCredentialKeysFromSchemaObject(credentialSet.auth),
|
|
348
|
+
schemaFingerprint: schemaFingerprintForManifestCredentialSet(credentialSet)
|
|
349
|
+
})),
|
|
350
|
+
...server.credentialInjection ? { credentialInjection: server.credentialInjection } : {}
|
|
351
|
+
};
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
function createAgentVersionManifest(discoveredWorkflow, agentManifest, toolEnrichments, bundle) {
|
|
355
|
+
const bundleHash = crypto.createHash("sha256").update(bundle.code).digest("hex");
|
|
356
|
+
const sandboxBlock = createSandboxBlock(agentManifest);
|
|
357
|
+
const runtimeCredentialSets = agentManifest.credentialSets ?? [];
|
|
358
|
+
return AgentVersionManifestSchema.parse({
|
|
359
|
+
agentId: agentManifest.authoredAgentId,
|
|
360
|
+
authoredAgentId: agentManifest.authoredAgentId,
|
|
361
|
+
agentName: agentManifest.name,
|
|
362
|
+
displayName: agentManifest.name,
|
|
363
|
+
runtimeKind: agentManifest.runtimeKind,
|
|
364
|
+
exportName: discoveredWorkflow.exportName,
|
|
365
|
+
mode: "sandbox",
|
|
366
|
+
bundleHash,
|
|
367
|
+
bundleSize: bundle.size,
|
|
368
|
+
runtime: {
|
|
369
|
+
mode: "pi_session",
|
|
370
|
+
placement: createSessionRuntimePlacement()
|
|
371
|
+
},
|
|
372
|
+
...sandboxBlock ? { sandbox: sandboxBlock } : {},
|
|
373
|
+
...agentManifest.systemPrompt !== void 0 ? { systemPrompt: agentManifest.systemPrompt } : {},
|
|
374
|
+
...agentManifest.model !== void 0 ? { model: agentManifest.model } : {},
|
|
375
|
+
...agentManifest.thinkingLevel !== void 0 ? { thinkingLevel: agentManifest.thinkingLevel } : {},
|
|
376
|
+
...agentManifest.maxSteps !== void 0 ? { maxSteps: agentManifest.maxSteps } : {},
|
|
377
|
+
enableMemory: agentManifest.enableMemory,
|
|
378
|
+
enableDatabase: agentManifest.enableDatabase,
|
|
379
|
+
...agentManifest.input !== void 0 ? { inputSchema: agentManifest.input } : {},
|
|
380
|
+
...agentManifest.output !== void 0 ? { outputSchema: agentManifest.output } : {},
|
|
381
|
+
...agentManifest.tools.length > 0 ? { tools: agentManifest.tools.map((tool) => {
|
|
382
|
+
const enrichment = toolEnrichments[tool.id];
|
|
383
|
+
const credentialSets = enrichment?.credentialSets ?? (tool.credentialSets && tool.credentialSets.length > 0 ? tool.credentialSets : void 0);
|
|
384
|
+
return {
|
|
385
|
+
toolName: tool.id,
|
|
386
|
+
...tool.description ? { description: tool.description } : {},
|
|
387
|
+
sourceKind: tool.sourceKind,
|
|
388
|
+
...tool.authoredOperationId ? { authoredOperationId: tool.authoredOperationId } : {},
|
|
389
|
+
...tool.authoredWorkflowId ? { authoredWorkflowId: tool.authoredWorkflowId } : {},
|
|
390
|
+
...enrichment?.dispatch ? { dispatch: enrichment.dispatch } : {},
|
|
391
|
+
...enrichment?.invocation ? { invocation: enrichment.invocation } : {},
|
|
392
|
+
...tool.largeResultMode ? { largeResultMode: tool.largeResultMode } : {},
|
|
393
|
+
...tool.midSessionSnapshot !== void 0 ? { midSessionSnapshot: tool.midSessionSnapshot } : {},
|
|
394
|
+
...enrichment?.suspensions ? { suspensions: enrichment.suspensions } : {},
|
|
395
|
+
...credentialSets ? { credentialSets } : {},
|
|
396
|
+
...enrichment?.outputSchemaIsTabular !== void 0 ? { outputSchemaIsTabular: enrichment.outputSchemaIsTabular } : {}
|
|
397
|
+
};
|
|
398
|
+
}) } : {},
|
|
399
|
+
...runtimeCredentialSets.length > 0 ? { credentialSets: runtimeCredentialSets.map((credentialSet) => {
|
|
400
|
+
const optionalCredentialKeys = readOptionalJsonSchemaKeys(credentialSet.auth);
|
|
401
|
+
return {
|
|
402
|
+
resolvedId: credentialSet.resolvedCredentialSetId,
|
|
403
|
+
credentialKeys: readCredentialKeysFromSchemaObject(credentialSet.auth),
|
|
404
|
+
schemaFingerprint: schemaFingerprintForManifestCredentialSet(credentialSet),
|
|
405
|
+
...optionalCredentialKeys.length > 0 ? { optionalCredentialKeys } : {},
|
|
406
|
+
...credentialSet.proxy ? { proxy: credentialSet.proxy } : {},
|
|
407
|
+
...credentialSet.needsRawSecret === true ? { needsRawSecret: true } : {}
|
|
408
|
+
};
|
|
409
|
+
}) } : {},
|
|
410
|
+
...agentManifest.mcpServers.length > 0 ? { mcpServers: createResolvedMcpServers(agentManifest) } : {},
|
|
411
|
+
...agentManifest.messaging && agentManifest.messaging.length > 0 ? { messaging: agentManifest.messaging.map((gateway) => ({
|
|
412
|
+
id: gateway.id,
|
|
413
|
+
name: gateway.name,
|
|
414
|
+
provider: gateway.provider,
|
|
415
|
+
mode: gateway.mode,
|
|
416
|
+
credentialSet: {
|
|
417
|
+
resolvedId: gateway.credentialSet.resolvedCredentialSetId,
|
|
418
|
+
credentialKeys: readCredentialKeysFromSchemaObject(gateway.credentialSet.auth),
|
|
419
|
+
schemaFingerprint: schemaFingerprintForManifestCredentialSet(gateway.credentialSet)
|
|
420
|
+
},
|
|
421
|
+
...gateway.appRef ? { appRef: gateway.appRef } : {}
|
|
422
|
+
})) } : {}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
async function buildAgentArtifact(options) {
|
|
426
|
+
const totalStartedAt = performance.now();
|
|
427
|
+
const { manifest: authoredAgentManifest } = options.agentMetadata;
|
|
428
|
+
const bundle = await bundleSandboxAgentTarget({
|
|
429
|
+
filePath: options.discoveredWorkflow.resolvedFilePath,
|
|
430
|
+
localExportName: options.discoveredWorkflow.localExportName,
|
|
431
|
+
projectRoot: options.projectRoot,
|
|
432
|
+
external: [
|
|
433
|
+
/^node:/,
|
|
434
|
+
...builtinModules,
|
|
435
|
+
/^@swc\//,
|
|
436
|
+
/\.node$/
|
|
437
|
+
],
|
|
438
|
+
sourceMap: options.sourceMaps
|
|
439
|
+
});
|
|
440
|
+
const sandboxPackage = await buildAgentSandboxPackage({
|
|
441
|
+
agentManifest: authoredAgentManifest,
|
|
442
|
+
bundleCode: bundle.code,
|
|
443
|
+
projectRoot: options.projectRoot
|
|
444
|
+
});
|
|
445
|
+
const bundleMs = performance.now() - totalStartedAt - options.agentMetadata.timing.importMs;
|
|
446
|
+
const versionManifest = createAgentVersionManifest(options.discoveredWorkflow, authoredAgentManifest, options.agentMetadata.toolEnrichments, {
|
|
447
|
+
code: bundle.code,
|
|
448
|
+
size: bundle.size
|
|
449
|
+
});
|
|
450
|
+
return {
|
|
451
|
+
agent: {
|
|
452
|
+
bindingKey: options.discoveredWorkflow.bindingKey,
|
|
453
|
+
exportFilePath: options.discoveredWorkflow.exportFilePath,
|
|
454
|
+
resolvedFilePath: options.discoveredWorkflow.resolvedFilePath,
|
|
455
|
+
exportName: options.discoveredWorkflow.exportName,
|
|
456
|
+
localExportName: options.discoveredWorkflow.localExportName,
|
|
457
|
+
agentId: versionManifest.agentId,
|
|
458
|
+
agentName: versionManifest.agentName
|
|
459
|
+
},
|
|
460
|
+
manifest: versionManifest,
|
|
461
|
+
bundle: {
|
|
462
|
+
code: bundle.code,
|
|
463
|
+
sourceMap: bundle.sourceMap,
|
|
464
|
+
hash: bundle.hash,
|
|
465
|
+
...bundle.sourceMapHash ? { sourceMapHash: bundle.sourceMapHash } : {},
|
|
466
|
+
localDependencies: bundle.localDependencies,
|
|
467
|
+
externalImports: bundle.externalImports,
|
|
468
|
+
size: bundle.size
|
|
469
|
+
},
|
|
470
|
+
sandboxPackage: {
|
|
471
|
+
buffer: sandboxPackage.packageBuffer,
|
|
472
|
+
size: sandboxPackage.packageSize,
|
|
473
|
+
hash: sandboxPackage.packageHash
|
|
474
|
+
},
|
|
475
|
+
timing: {
|
|
476
|
+
importMs: options.agentMetadata.timing.importMs,
|
|
477
|
+
manifestMs: options.agentMetadata.timing.manifestMs,
|
|
478
|
+
bundleMs,
|
|
479
|
+
totalMs: performance.now() - totalStartedAt
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
async function buildAgentArtifacts(options) {
|
|
484
|
+
const agentArtifacts = [];
|
|
485
|
+
const failures = [];
|
|
486
|
+
for (const entry of options.entries) try {
|
|
487
|
+
agentArtifacts.push(await buildAgentArtifact({
|
|
488
|
+
discoveredWorkflow: entry.discoveredWorkflow,
|
|
489
|
+
agentMetadata: entry.agentMetadata,
|
|
490
|
+
projectRoot: options.projectRoot
|
|
491
|
+
}));
|
|
492
|
+
} catch (error) {
|
|
493
|
+
failures.push({
|
|
494
|
+
kind: "agent",
|
|
495
|
+
agent: {
|
|
496
|
+
bindingKey: entry.discoveredWorkflow.bindingKey,
|
|
497
|
+
exportFilePath: entry.discoveredWorkflow.exportFilePath,
|
|
498
|
+
resolvedFilePath: entry.discoveredWorkflow.resolvedFilePath,
|
|
499
|
+
exportName: entry.discoveredWorkflow.exportName,
|
|
500
|
+
localExportName: entry.discoveredWorkflow.localExportName,
|
|
501
|
+
agentId: entry.discoveredWorkflow.exportName,
|
|
502
|
+
agentName: entry.discoveredWorkflow.exportName
|
|
503
|
+
},
|
|
504
|
+
phase: "bundle",
|
|
505
|
+
error: `Agent bundle failed: ${error instanceof Error ? error.message : String(error)}`
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
agentArtifacts,
|
|
510
|
+
failures
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
//#endregion
|
|
514
|
+
export { buildAgentArtifacts };
|