@byok-sdk/client 0.6.0 → 0.6.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 +91 -1
- package/dist/adapters/index.js +183 -34
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/pi/events.d.ts +1 -1
- package/dist/adapters/pi/mcp-config.d.ts +1 -0
- package/dist/adapters/pi/mcp-extension.js +25 -0
- package/dist/adapters/pi/mcp-extension.js.map +1 -0
- package/dist/adapters/pi/permission-mapping.d.ts +1 -1
- package/dist/adapters/pi/pi-adapter.d.ts +5 -0
- package/dist/adapters/pi/resolve-extensions.d.ts +11 -0
- package/dist/agent-home.d.ts +106 -0
- package/dist/bin/byok-agent.js +12892 -9473
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/bin/commands/toolsets.d.ts +8 -0
- package/dist/bin/format.d.ts +3 -0
- package/dist/daemon/agent-content-audit-store.d.ts +35 -0
- package/dist/daemon/agent-content-read.d.ts +169 -0
- package/dist/daemon/agent-egress-controller.d.ts +76 -0
- package/dist/daemon/agent-egress-policy.d.ts +36 -0
- package/dist/daemon/agent-egress-sanitizer.d.ts +38 -0
- package/dist/daemon/agent-egress-spool.d.ts +116 -0
- package/dist/daemon/agent-session-handoff-store.d.ts +82 -0
- package/dist/daemon/blob-client.d.ts +6 -2
- package/dist/daemon/connection-manager.d.ts +2 -2
- package/dist/daemon/control-protocol.d.ts +9 -0
- package/dist/daemon/create-daemon.d.ts +78 -3
- package/dist/daemon/long-poll-transport.d.ts +60 -0
- package/dist/daemon/presence-publisher.d.ts +2 -2
- package/dist/daemon/task-runner.d.ts +53 -4
- package/dist/daemon/toolset-registry.d.ts +30 -0
- package/dist/daemon/url.d.ts +21 -0
- package/dist/daemon/ws-transport.d.ts +30 -5
- package/dist/index.d.ts +12 -2
- package/dist/index.js +8646 -5272
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +44 -0
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -14,7 +14,11 @@ the separately installed `byok-pi-provider-launcher`, the local non-secret
|
|
|
14
14
|
profile database path, and a stable Pi session directory. The client passes
|
|
15
15
|
only those paths plus provider/model ids; the launcher alone reads the OS
|
|
16
16
|
credential when required and spawns Pi. Both custody paths must be absolute;
|
|
17
|
-
missing launcher configuration fails closed.
|
|
17
|
+
missing launcher configuration fails closed. A macOS host running under an
|
|
18
|
+
isolated `HOME` can additionally set `piByokLauncher.macosKeychainPath` to one
|
|
19
|
+
absolute keychain file. The client projects it as the launcher's reserved
|
|
20
|
+
`--macos-keychain-path` flag; it does not search a second credential authority
|
|
21
|
+
or widen the Pi child environment.
|
|
18
22
|
|
|
19
23
|
Claude Code and Codex remain user-installed runtimes and use their own login
|
|
20
24
|
state. Hosts that only need runtime detection/composition can import the
|
|
@@ -81,6 +85,92 @@ createDaemon({
|
|
|
81
85
|
The value is intentionally host-owned and has no SDK default because it is a
|
|
82
86
|
deployment/read-model policy, not a frozen protocol limit.
|
|
83
87
|
|
|
88
|
+
## Durable Agent homes
|
|
89
|
+
|
|
90
|
+
An Agent-capable daemon receives one absolute branded storage root. The SDK,
|
|
91
|
+
not the host, composes `agents/<agentId>`, validates canonical containment,
|
|
92
|
+
creates missing `MEMORY.md` and `notes/` without overwriting existing bytes,
|
|
93
|
+
and binds the resulting Agent home as runtime cwd.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { createAgentHomeProjection, createDaemon } from '@byok-sdk/client';
|
|
97
|
+
|
|
98
|
+
createDaemon({
|
|
99
|
+
// ...normal device and transport configuration
|
|
100
|
+
agentHome: {
|
|
101
|
+
hostStorageRoot: '/Users/alice/.salesko',
|
|
102
|
+
projection: createAgentHomeProjection(async ({ agentRef, cwd }) => {
|
|
103
|
+
// Host code receives the canonical home. It supplies redacted profile
|
|
104
|
+
// content but never joins `agents/<agentId>` and never writes secrets.
|
|
105
|
+
await profileProjection.write({ agentRef, canonicalAgentHome: cwd });
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Startup materializes and write-probes the canonical root before publishing
|
|
112
|
+
`agent-home-contract`. `agentHome` and `gitWorkspace` are mutually exclusive;
|
|
113
|
+
strict Agent execution has one workspace authority and never falls back to a
|
|
114
|
+
task-scoped Git workspace.
|
|
115
|
+
|
|
116
|
+
Successful startup with this configuration advertises `agent-home-contract`. Agent offers are distinct
|
|
117
|
+
from legacy task offers and fail closed when identity, profile revision,
|
|
118
|
+
session/runtime/cwd evidence, or the one-writer lease does not match. Agent
|
|
119
|
+
files other than the SDK-reserved `.byok` namespace are opaque; there is no
|
|
120
|
+
required `artifacts/` directory and the client does not parse or index their
|
|
121
|
+
contents.
|
|
122
|
+
|
|
123
|
+
## Agent egress and explicit content reads
|
|
124
|
+
|
|
125
|
+
`agentEgress` is consumed configuration, not a profile projection. The host
|
|
126
|
+
must select one exact policy revision and an authenticated tenant id. Omitting
|
|
127
|
+
contentful mode keeps runtime activity metadata/status-only; enabling it is an
|
|
128
|
+
explicit product decision and requires the server capability. Reliable events
|
|
129
|
+
are fsynced under the canonical Agent home and retire only after an exact ack.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
createDaemon({
|
|
133
|
+
// ...normal device, transport and agentHome configuration
|
|
134
|
+
agentEgress: {
|
|
135
|
+
tenantId: 'tenant-authority-from-salesko',
|
|
136
|
+
policy: {
|
|
137
|
+
policyRevision: 'salesko-agent-egress-r1',
|
|
138
|
+
activity: { mode: 'metadata-status', delivery: 'latest-value' },
|
|
139
|
+
reliable: {
|
|
140
|
+
maxPendingEventsPerAgent: 256,
|
|
141
|
+
maxPendingBytesPerAgent: 4 * 1024 * 1024,
|
|
142
|
+
maxPendingBytesPerTenant: 16 * 1024 * 1024,
|
|
143
|
+
},
|
|
144
|
+
transfers: {
|
|
145
|
+
workspace: { maxBytes: 1024 * 1024, allowedMimeTypes: ['text/plain'] },
|
|
146
|
+
transcript: 'disabled',
|
|
147
|
+
artifact: 'disabled',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
contentRead: {
|
|
151
|
+
workspace: {
|
|
152
|
+
root: { kind: 'agent-home' },
|
|
153
|
+
maxTextBytes: 1024 * 1024,
|
|
154
|
+
textMimeTypes: ['text/plain'],
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Each content surface requires both the matching non-disabled wire policy and
|
|
162
|
+
its local supplement. The local supplement can only narrow root, text, MIME,
|
|
163
|
+
size and sensitive-name behavior; it cannot enable a wire-disabled surface.
|
|
164
|
+
The SDK derives `agents/<agentId>`, `.byok/egress`, runtime-session evidence and
|
|
165
|
+
the per-Agent content-read audit path. Salesko must not compose those paths.
|
|
166
|
+
Tenant/device identity comes from authenticated host state; a request cannot
|
|
167
|
+
override it. Transcript reads additionally require the exact persisted
|
|
168
|
+
AgentRef/session/runtime/cwd handoff. Allowed content is uploaded through the
|
|
169
|
+
authenticated blob channel. The content-free receipt is fsynced into the
|
|
170
|
+
Agent-local reliable spool with stable event/cursor identity before send and
|
|
171
|
+
retires only after an exact ack; an allowed receipt carries the exact
|
|
172
|
+
`BlobRef`. No API recursively mirrors an Agent home.
|
|
173
|
+
|
|
84
174
|
For a concrete private host composition, see the
|
|
85
175
|
[`examples/salesko-connector-broker`](../../examples/salesko-connector-broker)
|
|
86
176
|
reference. It keeps `@byok-sdk/client` credential-blind while combining
|
package/dist/adapters/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFile, spawn } from 'child_process';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
2
|
import { promises, existsSync, readFileSync, realpathSync } from 'fs';
|
|
4
|
-
import path3 from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
3
|
import os from 'os';
|
|
4
|
+
import path5, { isAbsolute } from 'path';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
7
|
import 'readline';
|
|
8
8
|
|
|
9
9
|
// src/runtime-failure.ts
|
|
@@ -95,9 +95,12 @@ var SteerUnsupportedError = class extends Error {
|
|
|
95
95
|
this.runtimeId = runtimeId;
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
|
+
|
|
99
|
+
// src/adapters/pi/mcp-config.ts
|
|
100
|
+
var BYOK_PI_MCP_CONFIG_PATH = "BYOK_PI_MCP_CONFIG_PATH";
|
|
98
101
|
var PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
99
102
|
function readPackageJson(dir) {
|
|
100
|
-
const candidate =
|
|
103
|
+
const candidate = path5.join(dir, "package.json");
|
|
101
104
|
if (!existsSync(candidate)) return void 0;
|
|
102
105
|
try {
|
|
103
106
|
return JSON.parse(readFileSync(candidate, "utf8"));
|
|
@@ -112,17 +115,17 @@ function resolvePiBin() {
|
|
|
112
115
|
}
|
|
113
116
|
try {
|
|
114
117
|
const mainEntryUrl = import.meta.resolve(PI_PACKAGE_NAME);
|
|
115
|
-
let dir =
|
|
118
|
+
let dir = path5.dirname(fileURLToPath(mainEntryUrl));
|
|
116
119
|
for (let depth = 0; depth < 6; depth++) {
|
|
117
120
|
const pkg = readPackageJson(dir);
|
|
118
121
|
if (pkg?.name === PI_PACKAGE_NAME) {
|
|
119
122
|
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.pi;
|
|
120
123
|
if (binRel) {
|
|
121
|
-
return { command:
|
|
124
|
+
return { command: path5.join(dir, binRel), source: "package" };
|
|
122
125
|
}
|
|
123
126
|
break;
|
|
124
127
|
}
|
|
125
|
-
const parent =
|
|
128
|
+
const parent = path5.dirname(dir);
|
|
126
129
|
if (parent === dir) break;
|
|
127
130
|
dir = parent;
|
|
128
131
|
}
|
|
@@ -136,6 +139,13 @@ function resolvePiBin() {
|
|
|
136
139
|
`Required ${PI_PACKAGE_NAME} does not expose the pi CLI; reinstall the pinned dependency or set BYOK_PI_BIN to a Node 22.22+ pi sidecar`
|
|
137
140
|
);
|
|
138
141
|
}
|
|
142
|
+
function resolvePiExtensions() {
|
|
143
|
+
const clientManifest = fileURLToPath(import.meta.resolve("@byok-sdk/client/package.json"));
|
|
144
|
+
return {
|
|
145
|
+
webAccess: fileURLToPath(import.meta.resolve("pi-web-access/index.ts")),
|
|
146
|
+
mcpAdapter: path5.join(path5.dirname(clientManifest), "dist", "adapters", "pi", "mcp-extension.js")
|
|
147
|
+
};
|
|
148
|
+
}
|
|
139
149
|
|
|
140
150
|
// src/adapters/pi/permission-mapping.ts
|
|
141
151
|
var READONLY_TOOLS = ["read", "grep", "find", "ls"];
|
|
@@ -888,9 +898,73 @@ var DETECT_TIMEOUT_MS = 5e3;
|
|
|
888
898
|
function errorMessage(err) {
|
|
889
899
|
return err instanceof Error ? err.message : String(err);
|
|
890
900
|
}
|
|
901
|
+
async function cleanupMcpConfigDir(dir) {
|
|
902
|
+
if (!dir) return;
|
|
903
|
+
try {
|
|
904
|
+
await promises.rm(dir, { recursive: true, force: true });
|
|
905
|
+
} catch (cause) {
|
|
906
|
+
throw new RuntimeDisposalFailure({
|
|
907
|
+
stage: "cleanup",
|
|
908
|
+
reason: "pi task-scoped MCP configuration could not be removed"
|
|
909
|
+
}, { cause });
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function validatePiByokLauncherConfig(launcher) {
|
|
913
|
+
if (launcher === void 0) return;
|
|
914
|
+
for (const [field, value] of [
|
|
915
|
+
["command", launcher.command],
|
|
916
|
+
["profileDbPath", launcher.profileDbPath],
|
|
917
|
+
["sessionDir", launcher.sessionDir]
|
|
918
|
+
]) {
|
|
919
|
+
if (value.trim().length === 0 || /[\u0000\r\n]/u.test(value)) {
|
|
920
|
+
throw new Error(`DaemonConfig.piByokLauncher.${field} must be a non-empty single-line string`);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (!isAbsolute(launcher.profileDbPath) || !isAbsolute(launcher.sessionDir)) {
|
|
924
|
+
throw new Error(
|
|
925
|
+
"DaemonConfig.piByokLauncher profileDbPath and sessionDir must be absolute paths"
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
if (launcher.macosKeychainPath !== void 0 && (launcher.macosKeychainPath.trim().length === 0 || /[\u0000\r\n]/u.test(launcher.macosKeychainPath))) {
|
|
929
|
+
throw new Error(
|
|
930
|
+
"DaemonConfig.piByokLauncher.macosKeychainPath must be a non-empty single-line string"
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
if (launcher.macosKeychainPath !== void 0 && !isAbsolute(launcher.macosKeychainPath)) {
|
|
934
|
+
throw new Error(
|
|
935
|
+
"DaemonConfig.piByokLauncher.macosKeychainPath must be an absolute path"
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
if (launcher.secretServicePrefix !== void 0 && (launcher.secretServicePrefix.trim().length === 0 || /[\u0000\r\n]/u.test(launcher.secretServicePrefix))) {
|
|
939
|
+
throw new Error(
|
|
940
|
+
"DaemonConfig.piByokLauncher.secretServicePrefix must be a non-empty single-line string"
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
const reserved = /* @__PURE__ */ new Set([
|
|
944
|
+
"--",
|
|
945
|
+
"--pi-bin",
|
|
946
|
+
"--profile-db",
|
|
947
|
+
"--session-dir",
|
|
948
|
+
"--macos-keychain-path",
|
|
949
|
+
"--secret-service-prefix",
|
|
950
|
+
"--provider",
|
|
951
|
+
"--model"
|
|
952
|
+
]);
|
|
953
|
+
const conflicting = launcher.args?.find((arg) => reserved.has(arg));
|
|
954
|
+
if (conflicting !== void 0) {
|
|
955
|
+
throw new Error(
|
|
956
|
+
`DaemonConfig.piByokLauncher.args must not override reserved launcher argument ${conflicting}`
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
const invalidArg = launcher.args?.find((arg) => arg.length === 0 || /[\u0000\r\n]/u.test(arg));
|
|
960
|
+
if (invalidArg !== void 0) {
|
|
961
|
+
throw new Error("DaemonConfig.piByokLauncher.args must contain only non-empty single-line strings");
|
|
962
|
+
}
|
|
963
|
+
}
|
|
891
964
|
var PiAdapter = class {
|
|
892
965
|
constructor(options = {}) {
|
|
893
966
|
this.options = options;
|
|
967
|
+
validatePiByokLauncherConfig(options.byokLauncher);
|
|
894
968
|
}
|
|
895
969
|
options;
|
|
896
970
|
descriptor = freezeRuntimeAdapterDescriptor({
|
|
@@ -899,6 +973,7 @@ var PiAdapter = class {
|
|
|
899
973
|
capabilities: {
|
|
900
974
|
steer: true,
|
|
901
975
|
resume: true,
|
|
976
|
+
mcpToolsets: true,
|
|
902
977
|
approvalInteractive: false,
|
|
903
978
|
permissionModes: ["auto", "readonly"]
|
|
904
979
|
},
|
|
@@ -920,7 +995,15 @@ var PiAdapter = class {
|
|
|
920
995
|
if (!mapping.ok) {
|
|
921
996
|
return { kind: "reject", reason: mapping.reason ?? "policy rejected by pi adapter", retryable: false };
|
|
922
997
|
}
|
|
998
|
+
if (input.requiredToolsetIds.length > 0 && input.policy.mode !== "auto") {
|
|
999
|
+
return {
|
|
1000
|
+
kind: "reject",
|
|
1001
|
+
reason: 'pi MCP toolsets require permission mode "auto" because pi-mcp-adapter exposes one proxy across read and mutation tools',
|
|
1002
|
+
retryable: false
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
923
1005
|
const bin = this.resolveBin();
|
|
1006
|
+
const extensions = (this.options.resolveExtensions ?? resolvePiExtensions)();
|
|
924
1007
|
const selection = input.offer.dispatchSelection;
|
|
925
1008
|
const pinnedSelection = selection === void 0 ? void 0 : Object.freeze({ ...selection });
|
|
926
1009
|
let command = bin.command;
|
|
@@ -942,6 +1025,7 @@ var PiAdapter = class {
|
|
|
942
1025
|
launcher.profileDbPath,
|
|
943
1026
|
"--session-dir",
|
|
944
1027
|
launcher.sessionDir,
|
|
1028
|
+
...launcher.macosKeychainPath !== void 0 ? ["--macos-keychain-path", launcher.macosKeychainPath] : [],
|
|
945
1029
|
...launcher.secretServicePrefix ? ["--secret-service-prefix", launcher.secretServicePrefix] : [],
|
|
946
1030
|
"--provider",
|
|
947
1031
|
pinnedSelection.providerId,
|
|
@@ -971,18 +1055,48 @@ var PiAdapter = class {
|
|
|
971
1055
|
});
|
|
972
1056
|
}
|
|
973
1057
|
const resumeSessionId = startInput.manifest.sessionRef;
|
|
974
|
-
const
|
|
1058
|
+
const manifestCwd = startInput.manifest.cwd;
|
|
1059
|
+
if (manifestCwd === void 0) {
|
|
1060
|
+
throw new RuntimeExecutionFailure({
|
|
1061
|
+
phase: "start",
|
|
1062
|
+
category: "authority",
|
|
1063
|
+
retry: "non-retryable",
|
|
1064
|
+
reason: "prepared pi operation received a manifest without a sealed cwd"
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
let mcpConfigDir;
|
|
1068
|
+
let runtimeEnv = manifestSelection === void 0 ? startInput.env : withoutProviderCredentials(startInput.env);
|
|
1069
|
+
const taskMcpServers = startInput.mcpServers ?? {};
|
|
1070
|
+
const hasMcpServers = Object.keys(taskMcpServers).length > 0;
|
|
1071
|
+
if (hasMcpServers) {
|
|
1072
|
+
mcpConfigDir = await promises.mkdtemp(path5.join(os.tmpdir(), "byok-pi-mcp-"));
|
|
1073
|
+
await promises.chmod(mcpConfigDir, 448).catch(() => {
|
|
1074
|
+
});
|
|
1075
|
+
const mcpConfigPath = path5.join(mcpConfigDir, "mcp-config.json");
|
|
1076
|
+
await promises.writeFile(mcpConfigPath, JSON.stringify({ mcpServers: taskMcpServers }), { mode: 384 });
|
|
1077
|
+
runtimeEnv = { ...runtimeEnv, [BYOK_PI_MCP_CONFIG_PATH]: mcpConfigPath };
|
|
1078
|
+
}
|
|
1079
|
+
const piArgs = [
|
|
1080
|
+
"--mode",
|
|
1081
|
+
"rpc",
|
|
1082
|
+
"--extension",
|
|
1083
|
+
extensions.webAccess,
|
|
1084
|
+
...hasMcpServers ? ["--extension", extensions.mcpAdapter] : [],
|
|
1085
|
+
...resumeSessionId ? ["--session", resumeSessionId] : [],
|
|
1086
|
+
...mapping.args
|
|
1087
|
+
];
|
|
975
1088
|
const args = launcherArgs === void 0 ? piArgs : [...launcherArgs, "--", ...piArgs];
|
|
976
1089
|
let rpc;
|
|
977
1090
|
try {
|
|
978
1091
|
rpc = new PiRpcClient({
|
|
979
1092
|
command,
|
|
980
1093
|
args,
|
|
981
|
-
cwd:
|
|
982
|
-
env:
|
|
1094
|
+
cwd: manifestCwd,
|
|
1095
|
+
env: runtimeEnv,
|
|
983
1096
|
spawnFn: this.options.spawnFn
|
|
984
1097
|
});
|
|
985
1098
|
} catch (cause) {
|
|
1099
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
986
1100
|
throw new RuntimeExecutionFailure({
|
|
987
1101
|
phase: "start",
|
|
988
1102
|
category: "infrastructure",
|
|
@@ -995,6 +1109,7 @@ var PiAdapter = class {
|
|
|
995
1109
|
response = await rpc.send({ type: "prompt", message: startInput.instruction });
|
|
996
1110
|
} catch (cause) {
|
|
997
1111
|
rpc.kill();
|
|
1112
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
998
1113
|
throw new RuntimeExecutionFailure({
|
|
999
1114
|
phase: "start",
|
|
1000
1115
|
category: "infrastructure",
|
|
@@ -1004,6 +1119,7 @@ var PiAdapter = class {
|
|
|
1004
1119
|
}
|
|
1005
1120
|
if (response.success === false) {
|
|
1006
1121
|
rpc.kill();
|
|
1122
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
1007
1123
|
throw new RuntimeExecutionFailure({
|
|
1008
1124
|
phase: "start",
|
|
1009
1125
|
category: "semantic",
|
|
@@ -1016,10 +1132,12 @@ var PiAdapter = class {
|
|
|
1016
1132
|
sessionRef = await resolveAuthoritativeSessionId(rpc);
|
|
1017
1133
|
} catch (err) {
|
|
1018
1134
|
rpc.kill();
|
|
1135
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
1019
1136
|
throw err;
|
|
1020
1137
|
}
|
|
1021
1138
|
if (resumeSessionId !== void 0 && sessionRef !== resumeSessionId) {
|
|
1022
1139
|
rpc.kill();
|
|
1140
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
1023
1141
|
throw new RuntimeExecutionFailure({
|
|
1024
1142
|
phase: "start",
|
|
1025
1143
|
category: "authority",
|
|
@@ -1027,7 +1145,7 @@ var PiAdapter = class {
|
|
|
1027
1145
|
reason: "pi resumed a different authoritative session than requested"
|
|
1028
1146
|
});
|
|
1029
1147
|
}
|
|
1030
|
-
return new PiSession(sessionRef, rpc, manifestSelection);
|
|
1148
|
+
return new PiSession(sessionRef, rpc, manifestSelection, mcpConfigDir);
|
|
1031
1149
|
}
|
|
1032
1150
|
}
|
|
1033
1151
|
};
|
|
@@ -1076,14 +1194,17 @@ async function resolveAuthoritativeSessionId(rpc) {
|
|
|
1076
1194
|
});
|
|
1077
1195
|
}
|
|
1078
1196
|
var PiSession = class {
|
|
1079
|
-
constructor(sessionRef, rpc, selection) {
|
|
1197
|
+
constructor(sessionRef, rpc, selection, mcpConfigDir) {
|
|
1080
1198
|
this.sessionRef = sessionRef;
|
|
1081
1199
|
this.rpc = rpc;
|
|
1082
1200
|
this.selection = selection;
|
|
1201
|
+
this.mcpConfigDir = mcpConfigDir;
|
|
1083
1202
|
}
|
|
1084
1203
|
sessionRef;
|
|
1085
1204
|
rpc;
|
|
1086
1205
|
selection;
|
|
1206
|
+
mcpConfigDir;
|
|
1207
|
+
closeAttempt;
|
|
1087
1208
|
get events() {
|
|
1088
1209
|
const rpc = this.rpc;
|
|
1089
1210
|
return {
|
|
@@ -1152,7 +1273,17 @@ var PiSession = class {
|
|
|
1152
1273
|
await this.rpc.send({ type: "abort" });
|
|
1153
1274
|
}
|
|
1154
1275
|
async close() {
|
|
1155
|
-
|
|
1276
|
+
if (!this.closeAttempt) {
|
|
1277
|
+
const attempt = (async () => {
|
|
1278
|
+
await this.rpc.dispose();
|
|
1279
|
+
await cleanupMcpConfigDir(this.mcpConfigDir);
|
|
1280
|
+
})();
|
|
1281
|
+
this.closeAttempt = attempt.catch((error) => {
|
|
1282
|
+
this.closeAttempt = void 0;
|
|
1283
|
+
throw error;
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
await this.closeAttempt;
|
|
1156
1287
|
}
|
|
1157
1288
|
async resolveApproval() {
|
|
1158
1289
|
throw new Error("pi adapter does not support approval resume: pi never emits needs_approval in M0/M1");
|
|
@@ -1172,7 +1303,7 @@ function resolveApprovalMcpBin() {
|
|
|
1172
1303
|
if (override) {
|
|
1173
1304
|
return { command: override, args: [], source: "env" };
|
|
1174
1305
|
}
|
|
1175
|
-
const distBin =
|
|
1306
|
+
const distBin = path5.join(path5.dirname(fileURLToPath(import.meta.url)), "bin", "byok-approval-mcp.js");
|
|
1176
1307
|
return { command: process.execPath, args: [distBin], source: "dist" };
|
|
1177
1308
|
}
|
|
1178
1309
|
|
|
@@ -1263,7 +1394,7 @@ var EXTENSION_CONTENT_TYPES = {
|
|
|
1263
1394
|
".yml": "application/yaml"
|
|
1264
1395
|
};
|
|
1265
1396
|
function guessContentType(filePath) {
|
|
1266
|
-
const ext =
|
|
1397
|
+
const ext = path5.extname(filePath).toLowerCase();
|
|
1267
1398
|
return EXTENSION_CONTENT_TYPES[ext] ?? "application/octet-stream";
|
|
1268
1399
|
}
|
|
1269
1400
|
function mapAssistant(msg, correlation) {
|
|
@@ -1347,11 +1478,11 @@ function tryBuildArtifactEvent(msg, workspaceDir) {
|
|
|
1347
1478
|
const filePath = toolUseResult && typeof toolUseResult.filePath === "string" ? toolUseResult.filePath : void 0;
|
|
1348
1479
|
if (!filePath) return void 0;
|
|
1349
1480
|
const realWorkspaceDir = tryRealpath(workspaceDir) ?? workspaceDir;
|
|
1350
|
-
const fileDir =
|
|
1481
|
+
const fileDir = path5.dirname(filePath);
|
|
1351
1482
|
const realFileDir = tryRealpath(fileDir) ?? fileDir;
|
|
1352
|
-
const realFilePath =
|
|
1353
|
-
const relative =
|
|
1354
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
1483
|
+
const realFilePath = path5.join(realFileDir, path5.basename(filePath));
|
|
1484
|
+
const relative = path5.relative(realWorkspaceDir, realFilePath);
|
|
1485
|
+
if (relative === "" || relative.startsWith("..") || path5.isAbsolute(relative)) {
|
|
1355
1486
|
return void 0;
|
|
1356
1487
|
}
|
|
1357
1488
|
return { type: "artifact", name: relative, contentType: guessContentType(filePath) };
|
|
@@ -1637,7 +1768,7 @@ var DETECT_TIMEOUT_MS2 = 5e3;
|
|
|
1637
1768
|
function errorMessage2(err) {
|
|
1638
1769
|
return err instanceof Error ? err.message : String(err);
|
|
1639
1770
|
}
|
|
1640
|
-
async function
|
|
1771
|
+
async function cleanupMcpConfigDir2(dir) {
|
|
1641
1772
|
if (!dir) return;
|
|
1642
1773
|
try {
|
|
1643
1774
|
await promises.rm(dir, { recursive: true, force: true });
|
|
@@ -1745,10 +1876,10 @@ var ClaudeAdapter = class {
|
|
|
1745
1876
|
});
|
|
1746
1877
|
}
|
|
1747
1878
|
if (needsMcpConfig) {
|
|
1748
|
-
mcpConfigDir = await promises.mkdtemp(
|
|
1879
|
+
mcpConfigDir = await promises.mkdtemp(path5.join(os.tmpdir(), "byok-mcp-"));
|
|
1749
1880
|
await promises.chmod(mcpConfigDir, 448).catch(() => {
|
|
1750
1881
|
});
|
|
1751
|
-
const mcpConfigPath =
|
|
1882
|
+
const mcpConfigPath = path5.join(mcpConfigDir, "mcp-config.json");
|
|
1752
1883
|
const mcpServers = { ...taskMcpServers };
|
|
1753
1884
|
if (mapping.needsApprovalMcp) {
|
|
1754
1885
|
const approvalChannel = startInput.approvalChannel;
|
|
@@ -1807,6 +1938,15 @@ var ClaudeAdapter = class {
|
|
|
1807
1938
|
reason: "prepared claude operation received a manifest with different runtime selection"
|
|
1808
1939
|
});
|
|
1809
1940
|
}
|
|
1941
|
+
const manifestCwd = startInput.manifest.cwd;
|
|
1942
|
+
if (manifestCwd === void 0) {
|
|
1943
|
+
throw new RuntimeExecutionFailure({
|
|
1944
|
+
phase: "start",
|
|
1945
|
+
category: "authority",
|
|
1946
|
+
retry: "non-retryable",
|
|
1947
|
+
reason: "prepared claude operation received a manifest without a sealed cwd"
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1810
1950
|
const args = [
|
|
1811
1951
|
"-p",
|
|
1812
1952
|
"--input-format",
|
|
@@ -1827,12 +1967,12 @@ var ClaudeAdapter = class {
|
|
|
1827
1967
|
client = new ClaudeProcessClient({
|
|
1828
1968
|
command: bin.command,
|
|
1829
1969
|
args,
|
|
1830
|
-
cwd:
|
|
1970
|
+
cwd: manifestCwd,
|
|
1831
1971
|
env: withoutProviderCredentials(startInput.env),
|
|
1832
1972
|
spawnFn: this.options.spawnFn
|
|
1833
1973
|
});
|
|
1834
1974
|
} catch (cause) {
|
|
1835
|
-
await
|
|
1975
|
+
await cleanupMcpConfigDir2(mcpConfigDir);
|
|
1836
1976
|
throw new RuntimeExecutionFailure({
|
|
1837
1977
|
phase: "start",
|
|
1838
1978
|
category: "infrastructure",
|
|
@@ -1844,7 +1984,7 @@ var ClaudeAdapter = class {
|
|
|
1844
1984
|
client.writeUserMessage(startInput.instruction);
|
|
1845
1985
|
} catch (cause) {
|
|
1846
1986
|
client.kill();
|
|
1847
|
-
await
|
|
1987
|
+
await cleanupMcpConfigDir2(mcpConfigDir);
|
|
1848
1988
|
throw new RuntimeExecutionFailure({
|
|
1849
1989
|
phase: "start",
|
|
1850
1990
|
category: "infrastructure",
|
|
@@ -1857,7 +1997,7 @@ var ClaudeAdapter = class {
|
|
|
1857
1997
|
sessionRef = await client.waitForInit();
|
|
1858
1998
|
} catch (err) {
|
|
1859
1999
|
client.kill();
|
|
1860
|
-
await
|
|
2000
|
+
await cleanupMcpConfigDir2(mcpConfigDir);
|
|
1861
2001
|
if (isRuntimeExecutionFailure(err)) throw err;
|
|
1862
2002
|
throw new RuntimeExecutionFailure({
|
|
1863
2003
|
phase: "start",
|
|
@@ -1868,7 +2008,7 @@ var ClaudeAdapter = class {
|
|
|
1868
2008
|
}
|
|
1869
2009
|
if (resumeSessionId !== void 0 && sessionRef !== resumeSessionId) {
|
|
1870
2010
|
client.kill();
|
|
1871
|
-
await
|
|
2011
|
+
await cleanupMcpConfigDir2(mcpConfigDir);
|
|
1872
2012
|
throw new RuntimeExecutionFailure({
|
|
1873
2013
|
phase: "start",
|
|
1874
2014
|
category: "authority",
|
|
@@ -1879,7 +2019,7 @@ var ClaudeAdapter = class {
|
|
|
1879
2019
|
return new ClaudeSession(
|
|
1880
2020
|
sessionRef,
|
|
1881
2021
|
client,
|
|
1882
|
-
|
|
2022
|
+
manifestCwd,
|
|
1883
2023
|
startInput.approvalChannel,
|
|
1884
2024
|
mcpConfigDir,
|
|
1885
2025
|
manifestModelId
|
|
@@ -2042,7 +2182,7 @@ var ClaudeSession = class {
|
|
|
2042
2182
|
if (!this.closeAttempt) {
|
|
2043
2183
|
const attempt = (async () => {
|
|
2044
2184
|
await this.client.dispose();
|
|
2045
|
-
await
|
|
2185
|
+
await cleanupMcpConfigDir2(this.mcpConfigDir);
|
|
2046
2186
|
})();
|
|
2047
2187
|
this.closeAttempt = attempt.catch((error) => {
|
|
2048
2188
|
this.closeAttempt = void 0;
|
|
@@ -2225,8 +2365,8 @@ function extractArtifactEvents(changes, workspaceDir) {
|
|
|
2225
2365
|
const absolutePath = typeof change.path === "string" ? change.path : void 0;
|
|
2226
2366
|
const kind = typeof change.kind === "string" ? change.kind : void 0;
|
|
2227
2367
|
if (!absolutePath || kind === "delete") continue;
|
|
2228
|
-
const relative =
|
|
2229
|
-
if (relative.length === 0 || relative.startsWith("..") ||
|
|
2368
|
+
const relative = path5.relative(workspaceDir, absolutePath);
|
|
2369
|
+
if (relative.length === 0 || relative.startsWith("..") || path5.isAbsolute(relative)) continue;
|
|
2230
2370
|
events.push({ type: "artifact", name: relative, contentType: guessContentType2(relative) });
|
|
2231
2371
|
}
|
|
2232
2372
|
return events;
|
|
@@ -2247,7 +2387,7 @@ var CONTENT_TYPE_BY_EXTENSION = {
|
|
|
2247
2387
|
".csv": "text/csv"
|
|
2248
2388
|
};
|
|
2249
2389
|
function guessContentType2(relativePath) {
|
|
2250
|
-
return CONTENT_TYPE_BY_EXTENSION[
|
|
2390
|
+
return CONTENT_TYPE_BY_EXTENSION[path5.extname(relativePath).toLowerCase()] ?? "application/octet-stream";
|
|
2251
2391
|
}
|
|
2252
2392
|
function extractErrorMessage(rawError) {
|
|
2253
2393
|
if (typeof rawError === "string") return rawError;
|
|
@@ -2497,9 +2637,18 @@ ${withStreams.stderr ?? ""}`);
|
|
|
2497
2637
|
const queue = new AsyncQueue();
|
|
2498
2638
|
const terminal = {};
|
|
2499
2639
|
const recordUnmapped = makeUnmappedFrameRecorder(/* @__PURE__ */ new Map());
|
|
2640
|
+
const manifestCwd = startInput.manifest.cwd;
|
|
2641
|
+
if (manifestCwd === void 0) {
|
|
2642
|
+
throw new RuntimeExecutionFailure({
|
|
2643
|
+
phase: "start",
|
|
2644
|
+
category: "authority",
|
|
2645
|
+
retry: "non-retryable",
|
|
2646
|
+
reason: "prepared codex operation received a manifest without a sealed cwd"
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2500
2649
|
let workspaceDir;
|
|
2501
2650
|
try {
|
|
2502
|
-
workspaceDir = await resolveRealWorkspaceDir(
|
|
2651
|
+
workspaceDir = await resolveRealWorkspaceDir(manifestCwd);
|
|
2503
2652
|
} catch (cause) {
|
|
2504
2653
|
throw new RuntimeExecutionFailure({
|
|
2505
2654
|
phase: "start",
|
|
@@ -2534,7 +2683,7 @@ ${withStreams.stderr ?? ""}`);
|
|
|
2534
2683
|
instruction: startInput.instruction,
|
|
2535
2684
|
modelId: manifestModelId,
|
|
2536
2685
|
policyArgs: [...policyArgs],
|
|
2537
|
-
cwd:
|
|
2686
|
+
cwd: manifestCwd,
|
|
2538
2687
|
env: runtimeEnv,
|
|
2539
2688
|
spawnFn: this.options.spawnFn,
|
|
2540
2689
|
workspaceDir,
|