@super-one/cli 0.52.0-alpha → 0.53.0-alpha
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/MANIFEST.json +2 -2
- package/lib/cli.mjs +2428 -1002
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -179,7 +179,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
"name": "session_collab_request",
|
|
182
|
-
"description": 'Request user approval for
|
|
182
|
+
"description": 'Request user approval for collaboration launches: mode "spawn" (default) creates a child; mode "link" opens a mailbox with an existing sessionId. Spawn: list_agents; require agentId, name, role, summary, task; for cwd/worktree call read_manual({ domain: "product", topic: "collaboration" }); same-repo isolation belongs in config.worktree. Link: require sessionId + summary; optional task opening (turn-injected, not system prompt). User must approve; credential for session_collab_start.',
|
|
183
183
|
"inputSchema": {
|
|
184
184
|
"type": "object",
|
|
185
185
|
"properties": {
|
|
@@ -194,9 +194,22 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
194
194
|
"type": "string",
|
|
195
195
|
"description": "Optional caller correlation id."
|
|
196
196
|
},
|
|
197
|
+
"mode": {
|
|
198
|
+
"type": "string",
|
|
199
|
+
"enum": [
|
|
200
|
+
"spawn",
|
|
201
|
+
"link"
|
|
202
|
+
],
|
|
203
|
+
"description": '"spawn" (default) creates a new child session. "link" connects to an already-existing SuperOne session (sessionId required).'
|
|
204
|
+
},
|
|
205
|
+
"sessionId": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"minLength": 1,
|
|
208
|
+
"description": 'Existing SuperOne session id to link with (mode "link" only). Required for link; ignore for spawn. Prefer ids from @session mentions or session_list \u2014 never invent ids.'
|
|
209
|
+
},
|
|
197
210
|
"agentId": {
|
|
198
211
|
"type": "string",
|
|
199
|
-
"description":
|
|
212
|
+
"description": 'Agent profile id from session_collab_list_agents. Required for mode "spawn"; omit for "link".'
|
|
200
213
|
},
|
|
201
214
|
"summary": {
|
|
202
215
|
"type": "string",
|
|
@@ -205,23 +218,23 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
205
218
|
},
|
|
206
219
|
"task": {
|
|
207
220
|
"type": "string",
|
|
208
|
-
"
|
|
209
|
-
"description": "Full task brief in Markdown. Delivered to the child session on session_collab_start. The user can expand the summary in the confirm UI to preview it."
|
|
221
|
+
"description": "Full Markdown brief. Spawn: delivered to the child on session_collab_start. Link: optional opening for the peer (mailbox + turn wake, never system prompt). Expandable in the confirm UI."
|
|
210
222
|
},
|
|
211
223
|
"name": {
|
|
212
224
|
"type": "string",
|
|
213
225
|
"minLength": 1,
|
|
214
226
|
"maxLength": 64,
|
|
215
|
-
"description": '
|
|
227
|
+
"description": 'Spawn: human-friendly child label (e.g. "Alice"). Link: optional; defaults to peer session title.'
|
|
216
228
|
},
|
|
217
229
|
"role": {
|
|
218
230
|
"type": "string",
|
|
219
231
|
"minLength": 1,
|
|
220
232
|
"maxLength": 64,
|
|
221
|
-
"description": '
|
|
233
|
+
"description": 'Spawn: role for title "Name - Role". Link: optional; defaults to "Peer".'
|
|
222
234
|
},
|
|
223
235
|
"config": {
|
|
224
236
|
"type": "object",
|
|
237
|
+
"description": 'Spawn only. Ignored for mode "link".',
|
|
225
238
|
"properties": {
|
|
226
239
|
"model": {
|
|
227
240
|
"type": "string"
|
|
@@ -300,11 +313,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
300
313
|
}
|
|
301
314
|
},
|
|
302
315
|
"required": [
|
|
303
|
-
"
|
|
304
|
-
"summary",
|
|
305
|
-
"task",
|
|
306
|
-
"name",
|
|
307
|
-
"role"
|
|
316
|
+
"summary"
|
|
308
317
|
],
|
|
309
318
|
"additionalProperties": false
|
|
310
319
|
}
|
|
@@ -318,7 +327,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
318
327
|
},
|
|
319
328
|
{
|
|
320
329
|
"name": "session_collab_start",
|
|
321
|
-
"description": "
|
|
330
|
+
"description": "Activate one approved collaboration credential. Spawn: create the child and deliver its task. Link: bind the existing peer and wake it via turn injection (not system prompt). Returns when the peer begins (spawn) or is notified (link). Retries are idempotent. Start all credentials back-to-back.",
|
|
322
331
|
"inputSchema": {
|
|
323
332
|
"type": "object",
|
|
324
333
|
"properties": {
|
|
@@ -334,7 +343,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
334
343
|
},
|
|
335
344
|
{
|
|
336
345
|
"name": "session_collab_send",
|
|
337
|
-
"description": "Send a persistent Markdown message through one parent-child
|
|
346
|
+
"description": "Send a persistent Markdown message through one collaboration mailbox (spawn parent-child or link peers). Use clientMessageId for retry-safe delivery. The host wakes the peer and later wakes you when it replies. After sending, continue other work or end your turn. Never sleep, resend, or poll session_collab_retrieve while waiting.",
|
|
338
347
|
"inputSchema": {
|
|
339
348
|
"type": "object",
|
|
340
349
|
"properties": {
|
|
@@ -359,7 +368,7 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
359
368
|
},
|
|
360
369
|
{
|
|
361
370
|
"name": "session_collab_retrieve",
|
|
362
|
-
"description": 'Retrieve queued Markdown messages for this session from one or more
|
|
371
|
+
"description": 'Retrieve queued Markdown messages for this session from one or more collaboration mailboxes. Call after a collaboration wake, or once before acting on peer input. This is a non-blocking read: status "empty" is not a retry signal. Do not sleep or poll; end your turn and wait for the next wake.',
|
|
363
372
|
"inputSchema": {
|
|
364
373
|
"type": "object",
|
|
365
374
|
"properties": {
|
|
@@ -3234,6 +3243,191 @@ var init_host_action_superone_descriptors = __esm({
|
|
|
3234
3243
|
"additionalProperties": false
|
|
3235
3244
|
}
|
|
3236
3245
|
},
|
|
3246
|
+
{
|
|
3247
|
+
"name": "automation_list",
|
|
3248
|
+
"description": "List scheduled agent automations for the current project (id, name, enabled, schedule, last/next run). Pass id for full detail (prompt, agentConfig, schedule). Filter with query (name) or enabled. Call before automation_apply or automation_delete. Current project only \u2014 not session archive tools.",
|
|
3249
|
+
"inputSchema": {
|
|
3250
|
+
"type": "object",
|
|
3251
|
+
"properties": {
|
|
3252
|
+
"id": {
|
|
3253
|
+
"type": "string",
|
|
3254
|
+
"description": "When set, return full detail for this automation (must belong to the current project)."
|
|
3255
|
+
},
|
|
3256
|
+
"enabled": {
|
|
3257
|
+
"type": "boolean",
|
|
3258
|
+
"description": "Filter by enabled state. Omit for all."
|
|
3259
|
+
},
|
|
3260
|
+
"query": {
|
|
3261
|
+
"type": "string",
|
|
3262
|
+
"description": "Case-insensitive name substring filter."
|
|
3263
|
+
},
|
|
3264
|
+
"limit": {
|
|
3265
|
+
"type": "integer",
|
|
3266
|
+
"minimum": 1,
|
|
3267
|
+
"maximum": 100,
|
|
3268
|
+
"description": "Max rows. Default 50, max 100."
|
|
3269
|
+
},
|
|
3270
|
+
"offset": {
|
|
3271
|
+
"type": "integer",
|
|
3272
|
+
"minimum": 0,
|
|
3273
|
+
"description": "Pagination offset. Default 0."
|
|
3274
|
+
}
|
|
3275
|
+
},
|
|
3276
|
+
"additionalProperties": false
|
|
3277
|
+
}
|
|
3278
|
+
},
|
|
3279
|
+
{
|
|
3280
|
+
"name": "automation_apply",
|
|
3281
|
+
"description": "Create or update a project automation. action=create needs name, prompt, schedule; agentConfig optional (defaults claude + bypassPermissions). action=update needs id plus any of name/prompt/enabled/schedule/agentConfig (toggle via enabled). Always set schedule.summary to a short natural-language phrase for the UI (user language). Always opens a user confirmation dialog; applies nothing without approval. Call automation_list first for ids. Delete with automation_delete.",
|
|
3282
|
+
"inputSchema": {
|
|
3283
|
+
"type": "object",
|
|
3284
|
+
"properties": {
|
|
3285
|
+
"action": {
|
|
3286
|
+
"type": "string",
|
|
3287
|
+
"enum": ["create", "update"],
|
|
3288
|
+
"description": "create a new automation, or update an existing one (including toggle enabled)."
|
|
3289
|
+
},
|
|
3290
|
+
"id": {
|
|
3291
|
+
"type": "string",
|
|
3292
|
+
"description": "Required for update. Automation id from automation_list."
|
|
3293
|
+
},
|
|
3294
|
+
"name": {
|
|
3295
|
+
"type": "string",
|
|
3296
|
+
"description": "Display name. Required for create; optional for update."
|
|
3297
|
+
},
|
|
3298
|
+
"prompt": {
|
|
3299
|
+
"type": "string",
|
|
3300
|
+
"description": "Prompt sent to the agent when the automation runs. Required for create; optional for update."
|
|
3301
|
+
},
|
|
3302
|
+
"enabled": {
|
|
3303
|
+
"type": "boolean",
|
|
3304
|
+
"description": "Whether the scheduler will run this automation. Create defaults to true; use false to pause."
|
|
3305
|
+
},
|
|
3306
|
+
"schedule": {
|
|
3307
|
+
"type": "object",
|
|
3308
|
+
"description": `When to run. one-time needs runAt (ISO). recurring needs cron (e.g. "0 9 * * *"). Always include summary: natural language for the confirm UI in the user's language (e.g. "Every weekday at 9:00 AM", "\u6BCF\u5929\u4E0A\u5348 9 \u70B9"). Machine fields still drive the scheduler.`,
|
|
3309
|
+
"properties": {
|
|
3310
|
+
"type": {
|
|
3311
|
+
"type": "string",
|
|
3312
|
+
"enum": ["one-time", "recurring"]
|
|
3313
|
+
},
|
|
3314
|
+
"cron": {
|
|
3315
|
+
"type": "string",
|
|
3316
|
+
"description": "Cron expression for recurring (required when type=recurring)."
|
|
3317
|
+
},
|
|
3318
|
+
"runAt": {
|
|
3319
|
+
"type": "string",
|
|
3320
|
+
"description": "ISO timestamp for one-time (required when type=one-time)."
|
|
3321
|
+
},
|
|
3322
|
+
"preset": {
|
|
3323
|
+
"type": "string",
|
|
3324
|
+
"enum": ["hourly", "daily", "weekly", "custom"]
|
|
3325
|
+
},
|
|
3326
|
+
"timeOfDay": {
|
|
3327
|
+
"type": "string",
|
|
3328
|
+
"description": "HH:mm local time hint for daily/weekly presets."
|
|
3329
|
+
},
|
|
3330
|
+
"dayOfWeek": {
|
|
3331
|
+
"type": "array",
|
|
3332
|
+
"items": {
|
|
3333
|
+
"type": "integer",
|
|
3334
|
+
"minimum": 0,
|
|
3335
|
+
"maximum": 6
|
|
3336
|
+
},
|
|
3337
|
+
"description": "0=Sun \u2026 6=Sat for weekly preset."
|
|
3338
|
+
},
|
|
3339
|
+
"minuteOfHour": {
|
|
3340
|
+
"type": "integer",
|
|
3341
|
+
"minimum": 0,
|
|
3342
|
+
"maximum": 59,
|
|
3343
|
+
"description": "Minute for hourly preset."
|
|
3344
|
+
},
|
|
3345
|
+
"summary": {
|
|
3346
|
+
"type": "string",
|
|
3347
|
+
"minLength": 1,
|
|
3348
|
+
"maxLength": 200,
|
|
3349
|
+
"description": `Natural-language schedule shown in the UI (list + confirm). Use the user's language. Examples: "Every weekday at 9:00 AM", "\u6BCF\u5929\u4E0A\u5348 9 \u70B9", "Once on May 1 at 3pm". Required for create.`
|
|
3350
|
+
}
|
|
3351
|
+
},
|
|
3352
|
+
"required": ["type", "summary"],
|
|
3353
|
+
"additionalProperties": false
|
|
3354
|
+
},
|
|
3355
|
+
"agentConfig": {
|
|
3356
|
+
"type": "object",
|
|
3357
|
+
"description": "Harness + model for the automation run. type is required (claude|codex|acp|opencode). Defaults on create: claude + bypassPermissions + sandbox off. Prefer unified fields: model, effort, permissionMode, sandboxMode, apiProviderId, acpAgentId.",
|
|
3358
|
+
"properties": {
|
|
3359
|
+
"type": {
|
|
3360
|
+
"type": "string",
|
|
3361
|
+
"enum": ["claude", "codex", "acp", "opencode"]
|
|
3362
|
+
},
|
|
3363
|
+
"agentName": {
|
|
3364
|
+
"type": "string",
|
|
3365
|
+
"description": "Claude only: named agent profile."
|
|
3366
|
+
},
|
|
3367
|
+
"model": {
|
|
3368
|
+
"type": "string"
|
|
3369
|
+
},
|
|
3370
|
+
"effort": {
|
|
3371
|
+
"type": "string",
|
|
3372
|
+
"description": "Unified effort (Claude levels, Codex reasoning, ACP mode ids)."
|
|
3373
|
+
},
|
|
3374
|
+
"permissionMode": {
|
|
3375
|
+
"type": "string",
|
|
3376
|
+
"enum": ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"],
|
|
3377
|
+
"description": "Unified permission mode. Prefer bypassPermissions for unattended runs."
|
|
3378
|
+
},
|
|
3379
|
+
"sandboxMode": {
|
|
3380
|
+
"type": "string",
|
|
3381
|
+
"enum": ["off", "on", "auto"],
|
|
3382
|
+
"description": "Claude sandbox (ignored by other harnesses)."
|
|
3383
|
+
},
|
|
3384
|
+
"apiProviderId": {
|
|
3385
|
+
"type": ["string", "null"],
|
|
3386
|
+
"description": "Optional third-party AI provider credential id (claude/codex)."
|
|
3387
|
+
},
|
|
3388
|
+
"acpAgentId": {
|
|
3389
|
+
"type": "string",
|
|
3390
|
+
"description": "ACP only: agent id (e.g. grok-build)."
|
|
3391
|
+
},
|
|
3392
|
+
"reasoningEffort": {
|
|
3393
|
+
"type": "string",
|
|
3394
|
+
"enum": ["minimal", "low", "medium", "high", "xhigh"],
|
|
3395
|
+
"description": "Codex legacy alias for effort."
|
|
3396
|
+
},
|
|
3397
|
+
"permissionPreset": {
|
|
3398
|
+
"type": "string",
|
|
3399
|
+
"enum": ["read-only", "default", "full-access"],
|
|
3400
|
+
"description": "Codex legacy alias for permissionMode (full-access \u2248 bypassPermissions)."
|
|
3401
|
+
}
|
|
3402
|
+
},
|
|
3403
|
+
"required": ["type"],
|
|
3404
|
+
"additionalProperties": false
|
|
3405
|
+
}
|
|
3406
|
+
},
|
|
3407
|
+
"required": ["action"],
|
|
3408
|
+
"additionalProperties": false
|
|
3409
|
+
}
|
|
3410
|
+
},
|
|
3411
|
+
{
|
|
3412
|
+
"name": "automation_delete",
|
|
3413
|
+
"description": "Permanently delete project automations by id (from automation_list). Always opens a user confirmation dialog. Current project only. Prefer automation_list to choose ids first.",
|
|
3414
|
+
"inputSchema": {
|
|
3415
|
+
"type": "object",
|
|
3416
|
+
"properties": {
|
|
3417
|
+
"ids": {
|
|
3418
|
+
"type": "array",
|
|
3419
|
+
"items": {
|
|
3420
|
+
"type": "string"
|
|
3421
|
+
},
|
|
3422
|
+
"minItems": 1,
|
|
3423
|
+
"maxItems": 20,
|
|
3424
|
+
"description": "Automation ids from automation_list to delete (current project only)."
|
|
3425
|
+
}
|
|
3426
|
+
},
|
|
3427
|
+
"required": ["ids"],
|
|
3428
|
+
"additionalProperties": false
|
|
3429
|
+
}
|
|
3430
|
+
},
|
|
3237
3431
|
{
|
|
3238
3432
|
"name": "mobile_share_file",
|
|
3239
3433
|
"description": "Share a file from the desktop to the mobile device that is currently viewing this session, so the user can open or save it on their phone. This tool is ONLY available while a mobile device is subscribed to the session \u2014 if it is not in your tool list, no phone is connected. The file is delivered end-to-end encrypted and appears as a file card in the mobile chat. The path MUST point to a file inside the current project directory. Use it when the user asks to send, share, or get a file onto their phone.",
|
|
@@ -3326,6 +3520,7 @@ var init_host_action_browser_catalog = __esm({
|
|
|
3326
3520
|
"media_video_status",
|
|
3327
3521
|
"widget_list_templates",
|
|
3328
3522
|
"miniapp_list",
|
|
3523
|
+
"automation_list",
|
|
3329
3524
|
// session_collab_* are node-local (not HA); list_agents stays "safe" if ever reclassified
|
|
3330
3525
|
"computer_apps",
|
|
3331
3526
|
"computer_snapshot",
|
|
@@ -3969,17 +4164,17 @@ var require_node_gyp_build = __commonJS({
|
|
|
3969
4164
|
].filter(Boolean).join(" ");
|
|
3970
4165
|
throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
|
|
3971
4166
|
function resolve13(dir2) {
|
|
3972
|
-
var tuples =
|
|
4167
|
+
var tuples = readdirSync12(path.join(dir2, "prebuilds")).map(parseTuple);
|
|
3973
4168
|
var tuple2 = tuples.filter(matchTuple(platform2, arch2)).sort(compareTuples)[0];
|
|
3974
4169
|
if (!tuple2) return;
|
|
3975
4170
|
var prebuilds = path.join(dir2, "prebuilds", tuple2.name);
|
|
3976
|
-
var parsed =
|
|
4171
|
+
var parsed = readdirSync12(prebuilds).map(parseTags);
|
|
3977
4172
|
var candidates = parsed.filter(matchTags(runtime, abi));
|
|
3978
4173
|
var winner = candidates.sort(compareTags(runtime))[0];
|
|
3979
4174
|
if (winner) return path.join(prebuilds, winner.file);
|
|
3980
4175
|
}
|
|
3981
4176
|
};
|
|
3982
|
-
function
|
|
4177
|
+
function readdirSync12(dir) {
|
|
3983
4178
|
try {
|
|
3984
4179
|
return fs.readdirSync(dir);
|
|
3985
4180
|
} catch (err) {
|
|
@@ -3987,7 +4182,7 @@ var require_node_gyp_build = __commonJS({
|
|
|
3987
4182
|
}
|
|
3988
4183
|
}
|
|
3989
4184
|
function getFirst(dir, filter) {
|
|
3990
|
-
var files =
|
|
4185
|
+
var files = readdirSync12(dir).filter(filter);
|
|
3991
4186
|
return files[0] && path.join(dir, files[0]);
|
|
3992
4187
|
}
|
|
3993
4188
|
function matchBuild(name) {
|
|
@@ -6358,8 +6553,8 @@ var require_websocket = __commonJS({
|
|
|
6358
6553
|
var http = __require("http");
|
|
6359
6554
|
var net2 = __require("net");
|
|
6360
6555
|
var tls = __require("tls");
|
|
6361
|
-
var { randomBytes:
|
|
6362
|
-
var { Duplex, Readable:
|
|
6556
|
+
var { randomBytes: randomBytes7, createHash: createHash10 } = __require("crypto");
|
|
6557
|
+
var { Duplex, Readable: Readable4 } = __require("stream");
|
|
6363
6558
|
var { URL: URL2 } = __require("url");
|
|
6364
6559
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
6365
6560
|
var Receiver2 = require_receiver();
|
|
@@ -6888,7 +7083,7 @@ var require_websocket = __commonJS({
|
|
|
6888
7083
|
}
|
|
6889
7084
|
}
|
|
6890
7085
|
const defaultPort = isSecure ? 443 : 80;
|
|
6891
|
-
const key =
|
|
7086
|
+
const key = randomBytes7(16).toString("base64");
|
|
6892
7087
|
const request = isSecure ? https.request : http.request;
|
|
6893
7088
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
6894
7089
|
let perMessageDeflate;
|
|
@@ -7018,7 +7213,7 @@ var require_websocket = __commonJS({
|
|
|
7018
7213
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
7019
7214
|
return;
|
|
7020
7215
|
}
|
|
7021
|
-
const digest =
|
|
7216
|
+
const digest = createHash10("sha1").update(key + GUID).digest("base64");
|
|
7022
7217
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
7023
7218
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
7024
7219
|
return;
|
|
@@ -7385,7 +7580,7 @@ var require_websocket_server = __commonJS({
|
|
|
7385
7580
|
var EventEmitter = __require("events");
|
|
7386
7581
|
var http = __require("http");
|
|
7387
7582
|
var { Duplex } = __require("stream");
|
|
7388
|
-
var { createHash:
|
|
7583
|
+
var { createHash: createHash10 } = __require("crypto");
|
|
7389
7584
|
var extension2 = require_extension();
|
|
7390
7585
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
7391
7586
|
var subprotocol2 = require_subprotocol();
|
|
@@ -7686,7 +7881,7 @@ var require_websocket_server = __commonJS({
|
|
|
7686
7881
|
);
|
|
7687
7882
|
}
|
|
7688
7883
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
7689
|
-
const digest =
|
|
7884
|
+
const digest = createHash10("sha1").update(key + GUID).digest("base64");
|
|
7690
7885
|
const headers = [
|
|
7691
7886
|
"HTTP/1.1 101 Switching Protocols",
|
|
7692
7887
|
"Upgrade: websocket",
|
|
@@ -7771,6 +7966,162 @@ var require_websocket_server = __commonJS({
|
|
|
7771
7966
|
}
|
|
7772
7967
|
});
|
|
7773
7968
|
|
|
7969
|
+
// ../../packages/runtime/src/spawn-env.ts
|
|
7970
|
+
function mergeLoopbackNoProxy(env) {
|
|
7971
|
+
const existingParts = [];
|
|
7972
|
+
for (const key of ["NO_PROXY", "no_proxy"]) {
|
|
7973
|
+
const raw = env[key];
|
|
7974
|
+
if (!raw) continue;
|
|
7975
|
+
for (const part of raw.split(/[,\s]+/)) {
|
|
7976
|
+
const trimmed = part.trim();
|
|
7977
|
+
if (trimmed) existingParts.push(trimmed);
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7981
|
+
const merged = [];
|
|
7982
|
+
for (const part of existingParts) {
|
|
7983
|
+
const key = part.toLowerCase();
|
|
7984
|
+
if (seen.has(key)) continue;
|
|
7985
|
+
seen.add(key);
|
|
7986
|
+
merged.push(part);
|
|
7987
|
+
}
|
|
7988
|
+
for (const host of LOOPBACK_NO_PROXY_HOSTS) {
|
|
7989
|
+
const key = host.toLowerCase();
|
|
7990
|
+
if (seen.has(key)) continue;
|
|
7991
|
+
seen.add(key);
|
|
7992
|
+
merged.push(host);
|
|
7993
|
+
}
|
|
7994
|
+
const value = merged.join(",");
|
|
7995
|
+
env.NO_PROXY = value;
|
|
7996
|
+
env.no_proxy = value;
|
|
7997
|
+
}
|
|
7998
|
+
function isEssentialEnv(key) {
|
|
7999
|
+
if (ESSENTIAL_EXACT.has(key)) return true;
|
|
8000
|
+
return ESSENTIAL_PREFIXES.some((p2) => key.startsWith(p2));
|
|
8001
|
+
}
|
|
8002
|
+
function sanitizePathEnv(pathEnv) {
|
|
8003
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8004
|
+
const out = [];
|
|
8005
|
+
let dropped = 0;
|
|
8006
|
+
let deduped = 0;
|
|
8007
|
+
let droppedByPathMax = 0;
|
|
8008
|
+
let droppedByNameMax = 0;
|
|
8009
|
+
for (const entry of pathEnv.split(":")) {
|
|
8010
|
+
if (!entry) continue;
|
|
8011
|
+
if (seen.has(entry)) {
|
|
8012
|
+
deduped++;
|
|
8013
|
+
continue;
|
|
8014
|
+
}
|
|
8015
|
+
seen.add(entry);
|
|
8016
|
+
if (entry.length > SPAWN_PATH_MAX) {
|
|
8017
|
+
dropped++;
|
|
8018
|
+
droppedByPathMax++;
|
|
8019
|
+
continue;
|
|
8020
|
+
}
|
|
8021
|
+
if (entry.split("/").some((comp) => Buffer.byteLength(comp, "utf8") > SPAWN_NAME_MAX)) {
|
|
8022
|
+
dropped++;
|
|
8023
|
+
droppedByNameMax++;
|
|
8024
|
+
continue;
|
|
8025
|
+
}
|
|
8026
|
+
out.push(entry);
|
|
8027
|
+
}
|
|
8028
|
+
return { value: out.join(":"), dropped, deduped, droppedByPathMax, droppedByNameMax };
|
|
8029
|
+
}
|
|
8030
|
+
function serializedSize(env) {
|
|
8031
|
+
let n = 0;
|
|
8032
|
+
for (const key in env) {
|
|
8033
|
+
n += Buffer.byteLength(key) + Buffer.byteLength(env[key]) + 2;
|
|
8034
|
+
}
|
|
8035
|
+
return n;
|
|
8036
|
+
}
|
|
8037
|
+
function sanitizeEnv(base = process.env, extra) {
|
|
8038
|
+
const merged = {};
|
|
8039
|
+
for (const key in base) {
|
|
8040
|
+
const v2 = base[key];
|
|
8041
|
+
if (v2 !== void 0) merged[key] = v2;
|
|
8042
|
+
}
|
|
8043
|
+
if (extra) {
|
|
8044
|
+
for (const key in extra) {
|
|
8045
|
+
const v2 = extra[key];
|
|
8046
|
+
if (v2 !== void 0) merged[key] = v2;
|
|
8047
|
+
}
|
|
8048
|
+
}
|
|
8049
|
+
if (process.platform !== "win32" && typeof merged.PATH === "string") {
|
|
8050
|
+
const res = sanitizePathEnv(merged.PATH);
|
|
8051
|
+
merged.PATH = res.value;
|
|
8052
|
+
if (res.dropped > 0) {
|
|
8053
|
+
const parts = [];
|
|
8054
|
+
if (res.droppedByPathMax > 0)
|
|
8055
|
+
parts.push(`${res.droppedByPathMax} \u6574\u6BB5 > PATH_MAX(${SPAWN_PATH_MAX}B)`);
|
|
8056
|
+
if (res.droppedByNameMax > 0)
|
|
8057
|
+
parts.push(`${res.droppedByNameMax} \u6BB5\u542B > NAME_MAX(${SPAWN_NAME_MAX}B) \u7684\u76EE\u5F55\u540D`);
|
|
8058
|
+
console.warn(`[spawn-env] \u4E3A\u89C4\u907F spawn ENAMETOOLONG \u5DF2\u4E22\u5F03 ${res.dropped} \u4E2A\u8D85\u957F PATH \u5206\u6BB5\uFF08${parts.join("\uFF1B")}\uFF09`);
|
|
8059
|
+
}
|
|
8060
|
+
}
|
|
8061
|
+
mergeLoopbackNoProxy(merged);
|
|
8062
|
+
let size = serializedSize(merged);
|
|
8063
|
+
if (size > MAX_ENV_BYTES) {
|
|
8064
|
+
const entries = Object.entries(merged).sort((a, b2) => b2[1].length - a[1].length);
|
|
8065
|
+
for (const [key, value] of entries) {
|
|
8066
|
+
if (size <= MAX_ENV_BYTES) break;
|
|
8067
|
+
if (isEssentialEnv(key)) continue;
|
|
8068
|
+
size -= Buffer.byteLength(key) + Buffer.byteLength(value) + 2;
|
|
8069
|
+
delete merged[key];
|
|
8070
|
+
}
|
|
8071
|
+
if (size > MAX_ENV_BYTES) {
|
|
8072
|
+
console.warn(`[spawn-env] env still ${size} bytes after trimming non-essential vars (limit ${MAX_ENV_BYTES})`);
|
|
8073
|
+
} else {
|
|
8074
|
+
console.warn(`[spawn-env] trimmed env to ${size} bytes to avoid spawn E2BIG`);
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
return merged;
|
|
8078
|
+
}
|
|
8079
|
+
function buildSafeEnv(extra) {
|
|
8080
|
+
return sanitizeEnv(process.env, extra);
|
|
8081
|
+
}
|
|
8082
|
+
var SPAWN_PATH_MAX, SPAWN_NAME_MAX, MAX_ENV_BYTES, ESSENTIAL_EXACT, ESSENTIAL_PREFIXES, LOOPBACK_NO_PROXY_HOSTS;
|
|
8083
|
+
var init_spawn_env = __esm({
|
|
8084
|
+
"../../packages/runtime/src/spawn-env.ts"() {
|
|
8085
|
+
"use strict";
|
|
8086
|
+
SPAWN_PATH_MAX = 1024;
|
|
8087
|
+
SPAWN_NAME_MAX = 255;
|
|
8088
|
+
MAX_ENV_BYTES = 256 * 1024;
|
|
8089
|
+
ESSENTIAL_EXACT = /* @__PURE__ */ new Set([
|
|
8090
|
+
"PATH",
|
|
8091
|
+
"HOME",
|
|
8092
|
+
"USER",
|
|
8093
|
+
"LOGNAME",
|
|
8094
|
+
"SHELL",
|
|
8095
|
+
"TERM",
|
|
8096
|
+
"LANG",
|
|
8097
|
+
"LC_ALL",
|
|
8098
|
+
"LC_CTYPE",
|
|
8099
|
+
"DISPLAY",
|
|
8100
|
+
"TMPDIR",
|
|
8101
|
+
"TEMP",
|
|
8102
|
+
"TMP",
|
|
8103
|
+
"DYLD_FRAMEWORK_PATH",
|
|
8104
|
+
"DYLD_LIBRARY_PATH",
|
|
8105
|
+
"DYLD_FALLBACK_FRAMEWORK_PATH",
|
|
8106
|
+
"DYLD_FALLBACK_LIBRARY_PATH",
|
|
8107
|
+
// Proxy bypass must survive E2BIG trimming — loopback MCP depends on it.
|
|
8108
|
+
"NO_PROXY",
|
|
8109
|
+
"no_proxy"
|
|
8110
|
+
]);
|
|
8111
|
+
ESSENTIAL_PREFIXES = [
|
|
8112
|
+
"LC_",
|
|
8113
|
+
"ELECTRON_",
|
|
8114
|
+
"ANTHROPIC_",
|
|
8115
|
+
"CODEX_",
|
|
8116
|
+
"NPM_CONFIG_",
|
|
8117
|
+
"NODE_",
|
|
8118
|
+
"SSH_",
|
|
8119
|
+
"GIT_"
|
|
8120
|
+
];
|
|
8121
|
+
LOOPBACK_NO_PROXY_HOSTS = ["127.0.0.1", "localhost", "::1"];
|
|
8122
|
+
}
|
|
8123
|
+
});
|
|
8124
|
+
|
|
7774
8125
|
// ../../packages/codex/src/agent-event-mapper.ts
|
|
7775
8126
|
function asRecord(value) {
|
|
7776
8127
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -8384,7 +8735,7 @@ async function openCodexAppServer(opts) {
|
|
|
8384
8735
|
}
|
|
8385
8736
|
const spawnFn = opts.spawnFn ?? defaultSpawn;
|
|
8386
8737
|
const args = [...opts.cliArgs ?? [], "app-server", "--listen", "stdio://"];
|
|
8387
|
-
const env =
|
|
8738
|
+
const env = buildSafeEnv(opts.env);
|
|
8388
8739
|
const child = spawnFn(opts.binaryPath, args, {
|
|
8389
8740
|
env,
|
|
8390
8741
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -8878,6 +9229,7 @@ var DEFAULT_REQUEST_TIMEOUT_MS, THREAD_TIMEOUT_MS, TURN_WAIT_TIMEOUT_MS, MAX_STD
|
|
|
8878
9229
|
var init_app_server_client = __esm({
|
|
8879
9230
|
"../../packages/codex/src/app-server-client.ts"() {
|
|
8880
9231
|
"use strict";
|
|
9232
|
+
init_spawn_env();
|
|
8881
9233
|
init_environment();
|
|
8882
9234
|
init_agent_event_mapper();
|
|
8883
9235
|
DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
|
|
@@ -9344,6 +9696,9 @@ var init_superone_host_owned_tools = __esm({
|
|
|
9344
9696
|
"widget_show",
|
|
9345
9697
|
"config_read",
|
|
9346
9698
|
"config_apply",
|
|
9699
|
+
"automation_list",
|
|
9700
|
+
"automation_apply",
|
|
9701
|
+
"automation_delete",
|
|
9347
9702
|
...BROWSER_TOOL_NAMES
|
|
9348
9703
|
];
|
|
9349
9704
|
MOBILE_SHARE_FILE_TOOL_NAME = "mobile_share_file";
|
|
@@ -43811,10 +44166,14 @@ async function stopProcess(child, closed) {
|
|
|
43811
44166
|
signalProcess(child, "SIGKILL");
|
|
43812
44167
|
await closed.catch(() => void 0);
|
|
43813
44168
|
}
|
|
44169
|
+
function buildAcpProcessEnv(extra) {
|
|
44170
|
+
return buildSafeEnv(extra);
|
|
44171
|
+
}
|
|
43814
44172
|
function spawnAcpProcess(launch2) {
|
|
43815
44173
|
const child = spawn2(launch2.command, launch2.args ?? [], {
|
|
43816
44174
|
cwd: launch2.cwd || process.cwd(),
|
|
43817
|
-
|
|
44175
|
+
// buildSafeEnv merges loopback into NO_PROXY (package-level parity with desktop).
|
|
44176
|
+
env: buildAcpProcessEnv(launch2.env),
|
|
43818
44177
|
stdio: ["pipe", "pipe", "pipe"],
|
|
43819
44178
|
shell: process.platform === "win32",
|
|
43820
44179
|
windowsHide: true
|
|
@@ -43854,6 +44213,7 @@ var init_process = __esm({
|
|
|
43854
44213
|
"../../packages/acp/src/process.ts"() {
|
|
43855
44214
|
"use strict";
|
|
43856
44215
|
init_acp();
|
|
44216
|
+
init_spawn_env();
|
|
43857
44217
|
KILL_ESCALATE_MS = 1500;
|
|
43858
44218
|
}
|
|
43859
44219
|
});
|
|
@@ -50485,6 +50845,13 @@ function openCodePath(pathEnv) {
|
|
|
50485
50845
|
].filter(Boolean);
|
|
50486
50846
|
return [...new Set(paths)].join(delimiter);
|
|
50487
50847
|
}
|
|
50848
|
+
function buildOpenCodeServeEnv(extra) {
|
|
50849
|
+
return buildSafeEnv({
|
|
50850
|
+
...extra,
|
|
50851
|
+
PATH: openCodePath(extra?.PATH ?? process.env.PATH),
|
|
50852
|
+
OPENCODE_CONFIG_CONTENT: extra?.OPENCODE_CONFIG_CONTENT ?? "{}"
|
|
50853
|
+
});
|
|
50854
|
+
}
|
|
50488
50855
|
function signalChild(child, signal) {
|
|
50489
50856
|
try {
|
|
50490
50857
|
if (child.exitCode === null && child.signalCode === null) child.kill(signal);
|
|
@@ -50547,12 +50914,7 @@ async function startOpenCodeServer(opts) {
|
|
|
50547
50914
|
const binary = opts.binaryPath?.trim() || process.env.SUPERONE_OPENCODE_BINARY?.trim() || defaultOpenCodeBinaryPath();
|
|
50548
50915
|
const child = spawn3(binary, [...OPENCODE_SERVE_ARGS], {
|
|
50549
50916
|
cwd: opts.cwd,
|
|
50550
|
-
env:
|
|
50551
|
-
...process.env,
|
|
50552
|
-
...opts.env,
|
|
50553
|
-
PATH: openCodePath(opts.env?.PATH ?? process.env.PATH),
|
|
50554
|
-
OPENCODE_CONFIG_CONTENT: opts.env?.OPENCODE_CONFIG_CONTENT ?? "{}"
|
|
50555
|
-
},
|
|
50917
|
+
env: buildOpenCodeServeEnv(opts.env),
|
|
50556
50918
|
stdio: "pipe"
|
|
50557
50919
|
});
|
|
50558
50920
|
const exited = new Promise((resolve13) => {
|
|
@@ -50591,6 +50953,7 @@ var OPENCODE_SERVE_ARGS, maxServerOutput;
|
|
|
50591
50953
|
var init_server3 = __esm({
|
|
50592
50954
|
"../../packages/opencode/src/server.ts"() {
|
|
50593
50955
|
"use strict";
|
|
50956
|
+
init_spawn_env();
|
|
50594
50957
|
OPENCODE_SERVE_ARGS = ["serve", "--hostname=127.0.0.1", "--port=0"];
|
|
50595
50958
|
maxServerOutput = 64 * 1024;
|
|
50596
50959
|
}
|
|
@@ -51283,199 +51646,6 @@ var init_codex_turn_runner = __esm({
|
|
|
51283
51646
|
}
|
|
51284
51647
|
});
|
|
51285
51648
|
|
|
51286
|
-
// src/session/managed-harness-official.ts
|
|
51287
|
-
var managed_harness_official_exports = {};
|
|
51288
|
-
__export(managed_harness_official_exports, {
|
|
51289
|
-
OFFICIAL_CLAUDE_SDK_PACKAGE: () => OFFICIAL_CLAUDE_SDK_PACKAGE,
|
|
51290
|
-
OFFICIAL_CLAUDE_SDK_VERSION: () => OFFICIAL_CLAUDE_SDK_VERSION,
|
|
51291
|
-
OFFICIAL_CODEX_NPM_VERSION: () => OFFICIAL_CODEX_NPM_VERSION,
|
|
51292
|
-
OFFICIAL_CODEX_PACKAGE: () => OFFICIAL_CODEX_PACKAGE,
|
|
51293
|
-
claudePlatformPackageName: () => claudePlatformPackageName,
|
|
51294
|
-
installManagedFromOfficialNpm: () => installManagedFromOfficialNpm,
|
|
51295
|
-
managedNpmPrefix: () => managedNpmPrefix,
|
|
51296
|
-
officialPackageSpecs: () => officialPackageSpecs,
|
|
51297
|
-
resolveOfficialInstallBinary: () => resolveOfficialInstallBinary
|
|
51298
|
-
});
|
|
51299
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync14, readdirSync as readdirSync8, statSync as statSync6 } from "node:fs";
|
|
51300
|
-
import { arch as osArch2, platform as osPlatform2 } from "node:os";
|
|
51301
|
-
import { join as join19, resolve as resolve5 } from "node:path";
|
|
51302
|
-
import { spawn as spawn4 } from "node:child_process";
|
|
51303
|
-
function managedNpmPrefix(nodeHome, harnessId) {
|
|
51304
|
-
return resolve5(nodeHome, "managed-npm", harnessId);
|
|
51305
|
-
}
|
|
51306
|
-
function claudePlatformPackageName() {
|
|
51307
|
-
const p2 = osPlatform2();
|
|
51308
|
-
const a = osArch2();
|
|
51309
|
-
if (a !== "arm64" && a !== "x64") {
|
|
51310
|
-
throw new Error(`unsupported arch for Claude Agent SDK: ${a}`);
|
|
51311
|
-
}
|
|
51312
|
-
if (p2 === "darwin") return `@anthropic-ai/claude-agent-sdk-darwin-${a}`;
|
|
51313
|
-
if (p2 === "win32") return `@anthropic-ai/claude-agent-sdk-win32-${a}`;
|
|
51314
|
-
if (p2 === "linux") {
|
|
51315
|
-
if (isMuslLinux()) return `@anthropic-ai/claude-agent-sdk-linux-${a}-musl`;
|
|
51316
|
-
return `@anthropic-ai/claude-agent-sdk-linux-${a}`;
|
|
51317
|
-
}
|
|
51318
|
-
throw new Error(`unsupported platform for Claude Agent SDK: ${p2}`);
|
|
51319
|
-
}
|
|
51320
|
-
function isMuslLinux() {
|
|
51321
|
-
try {
|
|
51322
|
-
if (existsSync24("/etc/alpine-release")) return true;
|
|
51323
|
-
const lib = readdirSync8("/lib").some((n) => n.startsWith("ld-musl"));
|
|
51324
|
-
if (lib) return true;
|
|
51325
|
-
} catch {
|
|
51326
|
-
}
|
|
51327
|
-
return false;
|
|
51328
|
-
}
|
|
51329
|
-
function officialPackageSpecs(harnessId) {
|
|
51330
|
-
if (harnessId === "claude") {
|
|
51331
|
-
const ver2 = process.env.SUPERONE_CLAUDE_SDK_VERSION?.trim() || OFFICIAL_CLAUDE_SDK_VERSION;
|
|
51332
|
-
const platform2 = claudePlatformPackageName();
|
|
51333
|
-
return {
|
|
51334
|
-
runtimeVersion: ver2,
|
|
51335
|
-
specs: [`${OFFICIAL_CLAUDE_SDK_PACKAGE}@${ver2}`, `${platform2}@${ver2}`]
|
|
51336
|
-
};
|
|
51337
|
-
}
|
|
51338
|
-
const ver = process.env.SUPERONE_CODEX_NPM_VERSION?.trim() || OFFICIAL_CODEX_NPM_VERSION;
|
|
51339
|
-
return {
|
|
51340
|
-
runtimeVersion: ver,
|
|
51341
|
-
specs: [`${OFFICIAL_CODEX_PACKAGE}@${ver}`]
|
|
51342
|
-
};
|
|
51343
|
-
}
|
|
51344
|
-
function resolveOfficialInstallBinary(harnessId, prefix) {
|
|
51345
|
-
if (harnessId === "codex") {
|
|
51346
|
-
const candidates = [
|
|
51347
|
-
join19(prefix, "bin", "codex"),
|
|
51348
|
-
join19(prefix, "bin", "codex.cmd"),
|
|
51349
|
-
join19(prefix, "lib", "node_modules", "@openai", "codex", "bin", "codex.js")
|
|
51350
|
-
];
|
|
51351
|
-
for (const c of candidates) {
|
|
51352
|
-
if (existsSync24(c) && (c.endsWith(".js") || isExecutableFile(c))) return c;
|
|
51353
|
-
}
|
|
51354
|
-
return null;
|
|
51355
|
-
}
|
|
51356
|
-
const nm = join19(prefix, "lib", "node_modules");
|
|
51357
|
-
const scoped = join19(nm, "@anthropic-ai");
|
|
51358
|
-
try {
|
|
51359
|
-
if (existsSync24(scoped)) {
|
|
51360
|
-
const names = readdirSync8(scoped).filter((n) => n.startsWith("claude-agent-sdk-"));
|
|
51361
|
-
for (const n of names) {
|
|
51362
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
51363
|
-
const bin = join19(scoped, n, `claude${ext}`);
|
|
51364
|
-
if (existsSync24(bin)) return bin;
|
|
51365
|
-
}
|
|
51366
|
-
}
|
|
51367
|
-
} catch {
|
|
51368
|
-
}
|
|
51369
|
-
const direct = join19(
|
|
51370
|
-
nm,
|
|
51371
|
-
...claudePlatformPackageName().split("/"),
|
|
51372
|
-
process.platform === "win32" ? "claude.exe" : "claude"
|
|
51373
|
-
);
|
|
51374
|
-
if (existsSync24(direct)) return direct;
|
|
51375
|
-
return null;
|
|
51376
|
-
}
|
|
51377
|
-
function isExecutableFile(path) {
|
|
51378
|
-
try {
|
|
51379
|
-
const st = statSync6(path);
|
|
51380
|
-
if (!st.isFile()) return false;
|
|
51381
|
-
if (process.platform === "win32") return true;
|
|
51382
|
-
return (st.mode & 73) !== 0;
|
|
51383
|
-
} catch {
|
|
51384
|
-
return false;
|
|
51385
|
-
}
|
|
51386
|
-
}
|
|
51387
|
-
async function installManagedFromOfficialNpm(opts) {
|
|
51388
|
-
const { specs, runtimeVersion } = officialPackageSpecs(opts.harnessId);
|
|
51389
|
-
const prefix = managedNpmPrefix(opts.nodeHome, opts.harnessId);
|
|
51390
|
-
mkdirSync12(prefix, { recursive: true });
|
|
51391
|
-
const existing = resolveOfficialInstallBinary(opts.harnessId, prefix);
|
|
51392
|
-
if (existing) {
|
|
51393
|
-
return {
|
|
51394
|
-
harnessId: opts.harnessId,
|
|
51395
|
-
command: existing,
|
|
51396
|
-
runtimeVersion: readInstalledVersion(prefix, opts.harnessId) ?? runtimeVersion,
|
|
51397
|
-
source: "official-npm",
|
|
51398
|
-
packageSpec: specs.join(" "),
|
|
51399
|
-
installPrefix: prefix
|
|
51400
|
-
};
|
|
51401
|
-
}
|
|
51402
|
-
const runNpm = opts.runNpm ?? defaultRunNpm;
|
|
51403
|
-
await runNpm(
|
|
51404
|
-
["install", "--prefix", prefix, "--omit=dev", "--no-fund", "--no-audit", ...specs],
|
|
51405
|
-
prefix
|
|
51406
|
-
);
|
|
51407
|
-
const command = resolveOfficialInstallBinary(opts.harnessId, prefix);
|
|
51408
|
-
if (!command) {
|
|
51409
|
-
throw new Error(
|
|
51410
|
-
`official npm install of ${specs.join(" ")} succeeded but binary was not found under ${prefix}`
|
|
51411
|
-
);
|
|
51412
|
-
}
|
|
51413
|
-
return {
|
|
51414
|
-
harnessId: opts.harnessId,
|
|
51415
|
-
command,
|
|
51416
|
-
runtimeVersion: readInstalledVersion(prefix, opts.harnessId) ?? runtimeVersion,
|
|
51417
|
-
source: "official-npm",
|
|
51418
|
-
packageSpec: specs.join(" "),
|
|
51419
|
-
installPrefix: prefix
|
|
51420
|
-
};
|
|
51421
|
-
}
|
|
51422
|
-
function readInstalledVersion(prefix, harnessId) {
|
|
51423
|
-
try {
|
|
51424
|
-
const pkgPath = harnessId === "claude" ? join19(prefix, "lib", "node_modules", "@anthropic-ai", "claude-agent-sdk", "package.json") : join19(prefix, "lib", "node_modules", "@openai", "codex", "package.json");
|
|
51425
|
-
if (!existsSync24(pkgPath)) return null;
|
|
51426
|
-
const raw = JSON.parse(readFileSync14(pkgPath, "utf8"));
|
|
51427
|
-
return raw.version?.trim() || null;
|
|
51428
|
-
} catch {
|
|
51429
|
-
return null;
|
|
51430
|
-
}
|
|
51431
|
-
}
|
|
51432
|
-
function defaultRunNpm(args, cwd) {
|
|
51433
|
-
return new Promise((resolvePromise, reject) => {
|
|
51434
|
-
const child = spawn4("npm", args, {
|
|
51435
|
-
cwd,
|
|
51436
|
-
env: { ...process.env, npm_config_update_notifier: "false" },
|
|
51437
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
51438
|
-
});
|
|
51439
|
-
let stderr = "";
|
|
51440
|
-
child.stderr?.on("data", (c) => {
|
|
51441
|
-
stderr += c.toString();
|
|
51442
|
-
});
|
|
51443
|
-
child.on("error", (err) => {
|
|
51444
|
-
reject(
|
|
51445
|
-
new Error(
|
|
51446
|
-
`failed to spawn npm (${err.message}). Node.js/npm is required on the host for official harness install.`
|
|
51447
|
-
)
|
|
51448
|
-
);
|
|
51449
|
-
});
|
|
51450
|
-
const timer = setTimeout(() => {
|
|
51451
|
-
child.kill("SIGTERM");
|
|
51452
|
-
reject(new Error(`npm install timed out after 10m: npm ${args.join(" ")}`));
|
|
51453
|
-
}, 10 * 6e4);
|
|
51454
|
-
child.on("close", (code) => {
|
|
51455
|
-
clearTimeout(timer);
|
|
51456
|
-
if (code === 0) resolvePromise();
|
|
51457
|
-
else {
|
|
51458
|
-
reject(
|
|
51459
|
-
new Error(
|
|
51460
|
-
`npm install failed (exit ${code}): npm ${args.join(" ")}
|
|
51461
|
-
${stderr.slice(-1200)}`
|
|
51462
|
-
)
|
|
51463
|
-
);
|
|
51464
|
-
}
|
|
51465
|
-
});
|
|
51466
|
-
});
|
|
51467
|
-
}
|
|
51468
|
-
var OFFICIAL_CLAUDE_SDK_VERSION, OFFICIAL_CODEX_NPM_VERSION, OFFICIAL_CLAUDE_SDK_PACKAGE, OFFICIAL_CODEX_PACKAGE;
|
|
51469
|
-
var init_managed_harness_official = __esm({
|
|
51470
|
-
"src/session/managed-harness-official.ts"() {
|
|
51471
|
-
"use strict";
|
|
51472
|
-
OFFICIAL_CLAUDE_SDK_VERSION = "0.3.226";
|
|
51473
|
-
OFFICIAL_CODEX_NPM_VERSION = "0.146.1";
|
|
51474
|
-
OFFICIAL_CLAUDE_SDK_PACKAGE = "@anthropic-ai/claude-agent-sdk";
|
|
51475
|
-
OFFICIAL_CODEX_PACKAGE = "@openai/codex";
|
|
51476
|
-
}
|
|
51477
|
-
});
|
|
51478
|
-
|
|
51479
51649
|
// src/session/codex-admin-service.ts
|
|
51480
51650
|
var codex_admin_service_exports = {};
|
|
51481
51651
|
__export(codex_admin_service_exports, {
|
|
@@ -58613,7 +58783,7 @@ var require_dist = __commonJS({
|
|
|
58613
58783
|
});
|
|
58614
58784
|
|
|
58615
58785
|
// src/cli.ts
|
|
58616
|
-
import { homedir as
|
|
58786
|
+
import { homedir as homedir10 } from "node:os";
|
|
58617
58787
|
import { resolve as resolve12 } from "node:path";
|
|
58618
58788
|
|
|
58619
58789
|
// src/config.ts
|
|
@@ -58655,8 +58825,8 @@ import { fileURLToPath } from "node:url";
|
|
|
58655
58825
|
function resolveCliReleaseVersion() {
|
|
58656
58826
|
const fromEnv = process.env.SUPERONE_CLI_VERSION?.trim();
|
|
58657
58827
|
if (fromEnv) return fromEnv;
|
|
58658
|
-
if ("0.
|
|
58659
|
-
return "0.
|
|
58828
|
+
if ("0.53.0-alpha".trim()) {
|
|
58829
|
+
return "0.53.0-alpha".trim();
|
|
58660
58830
|
}
|
|
58661
58831
|
const fromDist = readDistManifestVersion();
|
|
58662
58832
|
if (fromDist) return fromDist;
|
|
@@ -58906,7 +59076,7 @@ function regenerateIdentity(nodeHome, label) {
|
|
|
58906
59076
|
}
|
|
58907
59077
|
|
|
58908
59078
|
// src/runtime.ts
|
|
58909
|
-
import { existsSync as
|
|
59079
|
+
import { existsSync as existsSync39, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "node:fs";
|
|
58910
59080
|
|
|
58911
59081
|
// src/auth/auth-service.ts
|
|
58912
59082
|
init_environment();
|
|
@@ -58956,7 +59126,7 @@ var AuthService = class {
|
|
|
58956
59126
|
FROM pairing_tokens WHERE token_hash = ?`
|
|
58957
59127
|
).get(tokenHash);
|
|
58958
59128
|
if (!row) throw Object.assign(new Error("invalid pairing token"), { code: "unauthorized" });
|
|
58959
|
-
if (row.revoked_at) throw Object.assign(new Error("pairing token revoked"), { code: "
|
|
59129
|
+
if (row.revoked_at) throw Object.assign(new Error("pairing token revoked"), { code: "revoked" });
|
|
58960
59130
|
if (row.consumed_at) throw Object.assign(new Error("pairing token already used"), { code: "unauthorized" });
|
|
58961
59131
|
if (row.expires_at < now) throw Object.assign(new Error("pairing token expired"), { code: "unauthorized" });
|
|
58962
59132
|
const updated = this.db.prepare(
|
|
@@ -59044,13 +59214,13 @@ var AuthService = class {
|
|
|
59044
59214
|
).run(now, reused.client_session_id);
|
|
59045
59215
|
this.onRevoke?.(reused.client_session_id);
|
|
59046
59216
|
throw Object.assign(new Error("refresh token reuse detected; session revoked"), {
|
|
59047
|
-
code: "
|
|
59217
|
+
code: "revoked"
|
|
59048
59218
|
});
|
|
59049
59219
|
}
|
|
59050
59220
|
}
|
|
59051
|
-
if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "
|
|
59221
|
+
if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "revoked" });
|
|
59052
59222
|
if (row.refresh_expires_at < now) {
|
|
59053
|
-
throw Object.assign(new Error("refresh token expired"), { code: "
|
|
59223
|
+
throw Object.assign(new Error("refresh token expired"), { code: "revoked" });
|
|
59054
59224
|
}
|
|
59055
59225
|
if (!input.verifyDeviceProof(row.device_public_key_pem, input.proofPayload, input.proofSignature)) {
|
|
59056
59226
|
throw Object.assign(new Error("device proof failed"), { code: "unauthorized" });
|
|
@@ -59109,7 +59279,8 @@ var AuthService = class {
|
|
|
59109
59279
|
createWsTicket(accessToken) {
|
|
59110
59280
|
const verified = this.verifyAccessToken(accessToken);
|
|
59111
59281
|
if (!verified.ok) {
|
|
59112
|
-
|
|
59282
|
+
const code = /session revoked/i.test(verified.reason) ? "revoked" : "unauthorized";
|
|
59283
|
+
throw Object.assign(new Error(verified.reason), { code });
|
|
59113
59284
|
}
|
|
59114
59285
|
const client3 = verified.client;
|
|
59115
59286
|
const now = Date.now();
|
|
@@ -59154,7 +59325,7 @@ var AuthService = class {
|
|
|
59154
59325
|
WHERE t.ticket_id = ?`
|
|
59155
59326
|
).get(ticketId);
|
|
59156
59327
|
if (!row) throw Object.assign(new Error("invalid ws ticket"), { code: "unauthorized" });
|
|
59157
|
-
if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "
|
|
59328
|
+
if (row.revoked_at) throw Object.assign(new Error("client session revoked"), { code: "revoked" });
|
|
59158
59329
|
if (row.consumed_at) throw Object.assign(new Error("ws ticket already used"), { code: "unauthorized" });
|
|
59159
59330
|
if (row.expires_at < now) throw Object.assign(new Error("ws ticket expired"), { code: "unauthorized" });
|
|
59160
59331
|
if (!safeEqualString(row.ticket_hash, ticketHash)) {
|
|
@@ -59444,7 +59615,8 @@ CREATE TABLE IF NOT EXISTS session_collaboration_grants (
|
|
|
59444
59615
|
config_json TEXT NOT NULL,
|
|
59445
59616
|
task_sent INTEGER NOT NULL DEFAULT 0,
|
|
59446
59617
|
created_at TEXT NOT NULL,
|
|
59447
|
-
started_at TEXT
|
|
59618
|
+
started_at TEXT,
|
|
59619
|
+
kind TEXT NOT NULL DEFAULT 'spawn'
|
|
59448
59620
|
);
|
|
59449
59621
|
CREATE INDEX IF NOT EXISTS idx_session_collaboration_parent
|
|
59450
59622
|
ON session_collaboration_grants(parent_session_id);
|
|
@@ -59696,8 +59868,10 @@ CREATE TABLE IF NOT EXISTS session_collaboration_grants (
|
|
|
59696
59868
|
config_json TEXT NOT NULL,
|
|
59697
59869
|
task_sent INTEGER NOT NULL DEFAULT 0,
|
|
59698
59870
|
created_at TEXT NOT NULL,
|
|
59699
|
-
started_at TEXT
|
|
59871
|
+
started_at TEXT,
|
|
59872
|
+
kind TEXT NOT NULL DEFAULT 'spawn'
|
|
59700
59873
|
);
|
|
59874
|
+
-- kind: 'spawn' (create child) | 'link' (mailbox with existing session)
|
|
59701
59875
|
CREATE INDEX IF NOT EXISTS idx_session_collaboration_parent
|
|
59702
59876
|
ON session_collaboration_grants(parent_session_id);
|
|
59703
59877
|
CREATE INDEX IF NOT EXISTS idx_session_collaboration_child
|
|
@@ -59726,6 +59900,10 @@ CREATE TABLE IF NOT EXISTS session_collaboration_cursors (
|
|
|
59726
59900
|
PRIMARY KEY(credential_hash, session_id)
|
|
59727
59901
|
);
|
|
59728
59902
|
`);
|
|
59903
|
+
const grantCols = db.prepare(`PRAGMA table_info(session_collaboration_grants)`).all();
|
|
59904
|
+
if (!grantCols.some((c) => c.name === "kind")) {
|
|
59905
|
+
db.exec(`ALTER TABLE session_collaboration_grants ADD COLUMN kind TEXT NOT NULL DEFAULT 'spawn'`);
|
|
59906
|
+
}
|
|
59729
59907
|
}
|
|
59730
59908
|
function ensureAutomationsSupport(db) {
|
|
59731
59909
|
const cols = db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
@@ -60073,215 +60251,432 @@ async function probeSandboxRpc() {
|
|
|
60073
60251
|
init_codex_turn_runner();
|
|
60074
60252
|
init_claude_turn_runner();
|
|
60075
60253
|
|
|
60076
|
-
// src/
|
|
60077
|
-
|
|
60078
|
-
|
|
60079
|
-
|
|
60080
|
-
|
|
60081
|
-
|
|
60082
|
-
|
|
60083
|
-
}
|
|
60084
|
-
function envBinaryExists(envName) {
|
|
60085
|
-
const v2 = process.env[envName]?.trim();
|
|
60086
|
-
return Boolean(v2 && existsSync22(v2));
|
|
60087
|
-
}
|
|
60088
|
-
function assertSessionHarnessRuntimeReady(sessionHarnessId, harnesses) {
|
|
60089
|
-
const id = sessionHarnessId === "acp" ? "acp" : sessionHarnessId;
|
|
60090
|
-
if (id === "claude") {
|
|
60091
|
-
if (resolveClaudeBinaryPath({ harnesses }) || isClaudeRuntimeRunnable()) {
|
|
60092
|
-
return { ok: true, reason: "claude binary or Agent SDK available" };
|
|
60093
|
-
}
|
|
60094
|
-
return {
|
|
60095
|
-
ok: false,
|
|
60096
|
-
reason: "claude runtime unavailable: install managed artifact, Agent SDK platform package, or SUPERONE_CLAUDE_BINARY"
|
|
60097
|
-
};
|
|
60254
|
+
// ../../packages/runtime/src/harness/manager.ts
|
|
60255
|
+
init_environment();
|
|
60256
|
+
var HarnessManager = class {
|
|
60257
|
+
constructor(db) {
|
|
60258
|
+
this.db = db;
|
|
60259
|
+
this.ensureRows();
|
|
60260
|
+
this.clearSimulatedContamination();
|
|
60098
60261
|
}
|
|
60099
|
-
|
|
60100
|
-
|
|
60101
|
-
|
|
60102
|
-
|
|
60103
|
-
|
|
60104
|
-
|
|
60105
|
-
|
|
60106
|
-
|
|
60262
|
+
/**
|
|
60263
|
+
* When true, list/get/ready behave as if every harness is enabled+ready.
|
|
60264
|
+
* Never persisted — only for contract/CI simulated runners.
|
|
60265
|
+
*/
|
|
60266
|
+
simulatedOverlay = false;
|
|
60267
|
+
/** Ensure one row per first-party definition. */
|
|
60268
|
+
ensureRows() {
|
|
60269
|
+
const now = Date.now();
|
|
60270
|
+
const insert = this.db.prepare(
|
|
60271
|
+
`INSERT OR IGNORE INTO harness_installations
|
|
60272
|
+
(harness_id, enabled, state, runtime_version, command, config_json, secret_ref,
|
|
60273
|
+
diagnostic_code, diagnostic_message, last_probed_at, updated_at)
|
|
60274
|
+
VALUES (?, 0, 'disabled', NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?)`
|
|
60275
|
+
);
|
|
60276
|
+
const tx = this.db.transaction(() => {
|
|
60277
|
+
for (const def of NODE_HARNESS_DEFINITIONS) {
|
|
60278
|
+
insert.run(def.id, now);
|
|
60279
|
+
}
|
|
60280
|
+
});
|
|
60281
|
+
tx();
|
|
60107
60282
|
}
|
|
60108
|
-
|
|
60109
|
-
|
|
60110
|
-
|
|
60111
|
-
|
|
60112
|
-
|
|
60113
|
-
|
|
60114
|
-
|
|
60115
|
-
|
|
60116
|
-
|
|
60283
|
+
/**
|
|
60284
|
+
* Reset durable rows that older builds may have marked as simulated-ready.
|
|
60285
|
+
* Safe to run on every open: only touches synthetic simulated provenance.
|
|
60286
|
+
*/
|
|
60287
|
+
clearSimulatedContamination() {
|
|
60288
|
+
const now = Date.now();
|
|
60289
|
+
this.db.prepare(
|
|
60290
|
+
`UPDATE harness_installations SET
|
|
60291
|
+
enabled = 0,
|
|
60292
|
+
state = 'disabled',
|
|
60293
|
+
runtime_version = NULL,
|
|
60294
|
+
command = NULL,
|
|
60295
|
+
diagnostic_code = NULL,
|
|
60296
|
+
diagnostic_message = NULL,
|
|
60297
|
+
last_probed_at = NULL,
|
|
60298
|
+
updated_at = ?
|
|
60299
|
+
WHERE runtime_version = 'simulated'
|
|
60300
|
+
OR diagnostic_code = 'simulated'`
|
|
60301
|
+
).run(now);
|
|
60117
60302
|
}
|
|
60118
|
-
|
|
60119
|
-
|
|
60120
|
-
|
|
60121
|
-
|
|
60122
|
-
|
|
60303
|
+
/**
|
|
60304
|
+
* Enable in-memory simulated readiness for all first-party harnesses.
|
|
60305
|
+
* Does not write the database. Production starts must never call this.
|
|
60306
|
+
*/
|
|
60307
|
+
enableSimulatedOverlay() {
|
|
60308
|
+
this.simulatedOverlay = true;
|
|
60309
|
+
}
|
|
60310
|
+
/** @deprecated use enableSimulatedOverlay — kept as alias for call-site clarity. */
|
|
60311
|
+
markAllSimulatedReady() {
|
|
60312
|
+
this.enableSimulatedOverlay();
|
|
60313
|
+
}
|
|
60314
|
+
list() {
|
|
60315
|
+
return NODE_HARNESS_DEFINITIONS.map((d) => this.get(d.id));
|
|
60316
|
+
}
|
|
60317
|
+
get(id) {
|
|
60318
|
+
const status = this.readPersisted(id);
|
|
60319
|
+
if (!this.simulatedOverlay) return status;
|
|
60123
60320
|
return {
|
|
60124
|
-
|
|
60125
|
-
|
|
60321
|
+
...status,
|
|
60322
|
+
enabled: true,
|
|
60323
|
+
state: "ready",
|
|
60324
|
+
runtimeVersion: status.runtimeVersion ?? "simulated",
|
|
60325
|
+
diagnostic: buildHarnessDiagnostic("simulated")
|
|
60126
60326
|
};
|
|
60127
60327
|
}
|
|
60128
|
-
|
|
60129
|
-
|
|
60130
|
-
|
|
60131
|
-
|
|
60132
|
-
|
|
60133
|
-
|
|
60134
|
-
|
|
60135
|
-
|
|
60136
|
-
if (!runtime.ok) {
|
|
60137
|
-
issues.push(runtime.reason);
|
|
60138
|
-
if (status.enabled && (status.state === "ready" || status.state === "needs_auth")) {
|
|
60139
|
-
harnesses.update(id, {
|
|
60140
|
-
state: "error",
|
|
60141
|
-
diagnosticCode: "probe_failed",
|
|
60142
|
-
lastProbedAt: Date.now()
|
|
60143
|
-
});
|
|
60144
|
-
const next = harnesses.get(id);
|
|
60145
|
-
return {
|
|
60146
|
-
id,
|
|
60147
|
-
previousState,
|
|
60148
|
-
state: next.state,
|
|
60149
|
-
transitioned: next.state !== previousState,
|
|
60150
|
-
ok: false,
|
|
60151
|
-
issues,
|
|
60152
|
-
reason: runtime.reason
|
|
60153
|
-
};
|
|
60328
|
+
readPersisted(id) {
|
|
60329
|
+
const row = this.db.prepare(
|
|
60330
|
+
`SELECT harness_id, enabled, state, runtime_version, command,
|
|
60331
|
+
diagnostic_code, diagnostic_message
|
|
60332
|
+
FROM harness_installations WHERE harness_id = ?`
|
|
60333
|
+
).get(id);
|
|
60334
|
+
if (!row) {
|
|
60335
|
+
return defaultHarnessInstallationStatus(id);
|
|
60154
60336
|
}
|
|
60155
|
-
|
|
60156
|
-
|
|
60337
|
+
const def = NODE_HARNESS_DEFINITIONS.find((d) => d.id === id);
|
|
60338
|
+
const status = {
|
|
60157
60339
|
id,
|
|
60158
|
-
|
|
60159
|
-
|
|
60160
|
-
|
|
60161
|
-
|
|
60162
|
-
issues,
|
|
60163
|
-
reason: runtime.reason
|
|
60340
|
+
runtimeSource: def.runtimeSource,
|
|
60341
|
+
enabled: row.enabled === 1,
|
|
60342
|
+
state: parseState(row.state),
|
|
60343
|
+
requiresAuth: def.requiresAuth
|
|
60164
60344
|
};
|
|
60165
|
-
|
|
60166
|
-
|
|
60167
|
-
|
|
60168
|
-
|
|
60169
|
-
|
|
60170
|
-
|
|
60171
|
-
|
|
60172
|
-
|
|
60345
|
+
if (row.runtime_version && row.runtime_version !== "simulated") {
|
|
60346
|
+
status.runtimeVersion = row.runtime_version;
|
|
60347
|
+
}
|
|
60348
|
+
const command = sanitizeHarnessCommand(row.command);
|
|
60349
|
+
if (command) status.command = command;
|
|
60350
|
+
const code = sanitizeHarnessDiagnosticCode(row.diagnostic_code);
|
|
60351
|
+
if (code && code !== "simulated") {
|
|
60352
|
+
status.diagnostic = buildHarnessDiagnostic(code, {
|
|
60353
|
+
runtimeVersion: status.runtimeVersion,
|
|
60354
|
+
command: status.command
|
|
60173
60355
|
});
|
|
60174
|
-
return {
|
|
60175
|
-
id,
|
|
60176
|
-
previousState,
|
|
60177
|
-
state: "needs_auth",
|
|
60178
|
-
transitioned: false,
|
|
60179
|
-
ok: false,
|
|
60180
|
-
issues,
|
|
60181
|
-
reason: authOk.reason
|
|
60182
|
-
};
|
|
60183
60356
|
}
|
|
60184
|
-
|
|
60185
|
-
|
|
60357
|
+
return status;
|
|
60358
|
+
}
|
|
60359
|
+
/**
|
|
60360
|
+
* Session wire harness ids that are currently runnable (enabled + ready).
|
|
60361
|
+
* Used by environment.descriptor capabilities.harnessIds.
|
|
60362
|
+
*/
|
|
60363
|
+
readySessionHarnessIds() {
|
|
60364
|
+
return readySessionHarnessIds(this.list());
|
|
60365
|
+
}
|
|
60366
|
+
/** Whether a session.create harnessId is allowed on this node. */
|
|
60367
|
+
isSessionHarnessRunnable(sessionHarnessId) {
|
|
60368
|
+
const wire = normalizeSessionHarnessId(sessionHarnessId);
|
|
60369
|
+
if (!wire) return false;
|
|
60370
|
+
const catalogId = wire === "acp" ? "acp-grok" : wire;
|
|
60371
|
+
if (!isNodeHarnessId(catalogId)) return false;
|
|
60372
|
+
return isHarnessRunnable(this.get(catalogId));
|
|
60373
|
+
}
|
|
60374
|
+
update(id, patch) {
|
|
60375
|
+
if (!isNodeHarnessId(id)) {
|
|
60376
|
+
throw new Error(`unknown harness: ${id}`);
|
|
60377
|
+
}
|
|
60378
|
+
const apply = this.db.transaction(() => {
|
|
60379
|
+
const current = this.readPersisted(id);
|
|
60380
|
+
const extra = this.db.prepare(
|
|
60381
|
+
`SELECT config_json, secret_ref, last_probed_at, diagnostic_code
|
|
60382
|
+
FROM harness_installations WHERE harness_id = ?`
|
|
60383
|
+
).get(id);
|
|
60384
|
+
const enabled = patch.enabled ?? current.enabled;
|
|
60385
|
+
const state = patch.state ?? current.state;
|
|
60386
|
+
const runtimeVersion = patch.runtimeVersion === null ? null : patch.runtimeVersion ?? current.runtimeVersion ?? null;
|
|
60387
|
+
let command;
|
|
60388
|
+
if (patch.command === null) {
|
|
60389
|
+
command = null;
|
|
60390
|
+
} else if (patch.command !== void 0) {
|
|
60391
|
+
command = sanitizeHarnessCommand(patch.command) ?? null;
|
|
60392
|
+
} else {
|
|
60393
|
+
command = current.command ?? null;
|
|
60394
|
+
}
|
|
60395
|
+
let diagnosticCode;
|
|
60396
|
+
if (patch.diagnosticCode === null) {
|
|
60397
|
+
diagnosticCode = null;
|
|
60398
|
+
} else if (patch.diagnosticCode !== void 0) {
|
|
60399
|
+
diagnosticCode = sanitizeHarnessDiagnosticCode(patch.diagnosticCode);
|
|
60400
|
+
} else {
|
|
60401
|
+
diagnosticCode = sanitizeHarnessDiagnosticCode(extra?.diagnostic_code);
|
|
60402
|
+
}
|
|
60403
|
+
let diagnosticMessage = null;
|
|
60404
|
+
if (diagnosticCode) {
|
|
60405
|
+
const fields = {
|
|
60406
|
+
...patch.diagnosticFields ?? {},
|
|
60407
|
+
runtimeVersion: runtimeVersion ?? void 0,
|
|
60408
|
+
command: command ?? void 0
|
|
60409
|
+
};
|
|
60410
|
+
diagnosticMessage = buildHarnessDiagnostic(
|
|
60411
|
+
diagnosticCode,
|
|
60412
|
+
fields
|
|
60413
|
+
).message;
|
|
60414
|
+
}
|
|
60415
|
+
const configJson = patch.configJson === null ? null : patch.configJson ?? extra?.config_json ?? null;
|
|
60416
|
+
const secretRef = patch.secretRef === null ? null : patch.secretRef ?? extra?.secret_ref ?? null;
|
|
60417
|
+
const lastProbedAt = patch.lastProbedAt === null ? null : patch.lastProbedAt ?? extra?.last_probed_at ?? null;
|
|
60418
|
+
const now = Date.now();
|
|
60419
|
+
this.db.prepare(
|
|
60420
|
+
`UPDATE harness_installations SET
|
|
60421
|
+
enabled = ?, state = ?, runtime_version = ?, command = ?,
|
|
60422
|
+
config_json = ?, secret_ref = ?,
|
|
60423
|
+
diagnostic_code = ?, diagnostic_message = ?,
|
|
60424
|
+
last_probed_at = ?, updated_at = ?
|
|
60425
|
+
WHERE harness_id = ?`
|
|
60426
|
+
).run(
|
|
60427
|
+
enabled ? 1 : 0,
|
|
60428
|
+
state,
|
|
60429
|
+
runtimeVersion,
|
|
60430
|
+
command,
|
|
60431
|
+
configJson,
|
|
60432
|
+
secretRef,
|
|
60433
|
+
diagnosticCode,
|
|
60434
|
+
diagnosticMessage,
|
|
60435
|
+
lastProbedAt,
|
|
60436
|
+
now,
|
|
60437
|
+
id
|
|
60438
|
+
);
|
|
60439
|
+
});
|
|
60440
|
+
apply();
|
|
60441
|
+
return this.get(id);
|
|
60442
|
+
}
|
|
60443
|
+
/**
|
|
60444
|
+
* Disable a harness. Does not delete managed artifacts or external binaries.
|
|
60445
|
+
* Default drain policy is enforced by higher-level CLI/RPC in a later slice.
|
|
60446
|
+
*/
|
|
60447
|
+
disable(id) {
|
|
60448
|
+
return this.update(id, {
|
|
60449
|
+
enabled: false,
|
|
60450
|
+
state: "disabled",
|
|
60186
60451
|
diagnosticCode: null,
|
|
60187
|
-
|
|
60452
|
+
diagnosticFields: null
|
|
60188
60453
|
});
|
|
60189
|
-
return {
|
|
60190
|
-
id,
|
|
60191
|
-
previousState,
|
|
60192
|
-
state: "ready",
|
|
60193
|
-
transitioned: true,
|
|
60194
|
-
ok: true,
|
|
60195
|
-
issues: [],
|
|
60196
|
-
reason: `promoted needs_auth \u2192 ready (${authOk.reason})`
|
|
60197
|
-
};
|
|
60198
60454
|
}
|
|
60199
|
-
|
|
60200
|
-
|
|
60455
|
+
/**
|
|
60456
|
+
* Internal non-secret row fields for CLI show/doctor.
|
|
60457
|
+
* Does not expose secret_ref or stored diagnostic message text.
|
|
60458
|
+
*/
|
|
60459
|
+
readRawRow(id) {
|
|
60460
|
+
const row = this.db.prepare(
|
|
60461
|
+
`SELECT config_json, last_probed_at
|
|
60462
|
+
FROM harness_installations WHERE harness_id = ?`
|
|
60463
|
+
).get(id);
|
|
60464
|
+
return row ?? null;
|
|
60465
|
+
}
|
|
60466
|
+
};
|
|
60467
|
+
function parseState(raw) {
|
|
60468
|
+
switch (raw) {
|
|
60469
|
+
case "disabled":
|
|
60470
|
+
case "missing":
|
|
60471
|
+
case "installing":
|
|
60472
|
+
case "needs_auth":
|
|
60473
|
+
case "ready":
|
|
60474
|
+
case "incompatible":
|
|
60475
|
+
case "error":
|
|
60476
|
+
return raw;
|
|
60477
|
+
default:
|
|
60478
|
+
return "error";
|
|
60479
|
+
}
|
|
60480
|
+
}
|
|
60481
|
+
|
|
60482
|
+
// ../../packages/runtime/src/harness/home-path.ts
|
|
60483
|
+
import { homedir as homedir6 } from "node:os";
|
|
60484
|
+
import { join as join18 } from "node:path";
|
|
60485
|
+
var HARNESS_HOME_DIRNAME = "harness";
|
|
60486
|
+
var SUPERONE_DIRNAME = ".superone";
|
|
60487
|
+
function defaultHarnessHomeRoot(userHome = homedir6()) {
|
|
60488
|
+
return join18(userHome, SUPERONE_DIRNAME, HARNESS_HOME_DIRNAME);
|
|
60489
|
+
}
|
|
60490
|
+
function resolveHarnessHomeRoot(opts = {}) {
|
|
60491
|
+
const explicit = opts.override?.trim();
|
|
60492
|
+
if (explicit) return explicit;
|
|
60493
|
+
if (!opts.ignoreEnv) {
|
|
60494
|
+
const fromEnv = process.env.SUPERONE_HARNESS_HOME?.trim();
|
|
60495
|
+
if (fromEnv) return fromEnv;
|
|
60496
|
+
}
|
|
60497
|
+
return defaultHarnessHomeRoot(opts.userHome);
|
|
60498
|
+
}
|
|
60499
|
+
|
|
60500
|
+
// ../../packages/runtime/src/harness/managed-layout.ts
|
|
60501
|
+
import {
|
|
60502
|
+
existsSync as existsSync22,
|
|
60503
|
+
mkdirSync as mkdirSync11,
|
|
60504
|
+
readdirSync as readdirSync8,
|
|
60505
|
+
readFileSync as readFileSync13,
|
|
60506
|
+
renameSync as renameSync2,
|
|
60507
|
+
rmSync as rmSync2,
|
|
60508
|
+
statSync as statSync5,
|
|
60509
|
+
writeFileSync as writeFileSync9
|
|
60510
|
+
} from "node:fs";
|
|
60511
|
+
import { join as join19 } from "node:path";
|
|
60512
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
60513
|
+
var MANAGED_VERSIONS_DIRNAME = "versions";
|
|
60514
|
+
var MANAGED_CURRENT_BASENAME = "current";
|
|
60515
|
+
var MANAGED_VERSION_KEEP = 2;
|
|
60516
|
+
function sanitizeRuntimeVersionForPath(runtimeVersion) {
|
|
60517
|
+
const v2 = runtimeVersion.trim();
|
|
60518
|
+
if (!v2) throw new Error("empty runtime version");
|
|
60519
|
+
if (v2.includes("..") || v2.includes("/") || v2.includes("\\") || v2.includes("\0")) {
|
|
60520
|
+
throw new Error(`unsafe runtime version for path: ${runtimeVersion}`);
|
|
60521
|
+
}
|
|
60522
|
+
if (!/^[A-Za-z0-9._+-]+$/.test(v2)) {
|
|
60523
|
+
throw new Error(`unsafe runtime version for path: ${runtimeVersion}`);
|
|
60524
|
+
}
|
|
60525
|
+
return v2;
|
|
60526
|
+
}
|
|
60527
|
+
function managedVersionsDir(prefix) {
|
|
60528
|
+
return join19(prefix, MANAGED_VERSIONS_DIRNAME);
|
|
60529
|
+
}
|
|
60530
|
+
function managedVersionDir(prefix, runtimeVersion) {
|
|
60531
|
+
return join19(managedVersionsDir(prefix), sanitizeRuntimeVersionForPath(runtimeVersion));
|
|
60532
|
+
}
|
|
60533
|
+
function managedCurrentPath(prefix) {
|
|
60534
|
+
return join19(prefix, MANAGED_CURRENT_BASENAME);
|
|
60535
|
+
}
|
|
60536
|
+
function readCurrentPointer(prefix) {
|
|
60537
|
+
const path = managedCurrentPath(prefix);
|
|
60538
|
+
if (!existsSync22(path)) return null;
|
|
60539
|
+
try {
|
|
60540
|
+
const raw = JSON.parse(readFileSync13(path, "utf8"));
|
|
60541
|
+
if (typeof raw.runtimeVersion !== "string" || !raw.runtimeVersion.trim()) return null;
|
|
60201
60542
|
return {
|
|
60202
|
-
|
|
60203
|
-
|
|
60204
|
-
|
|
60205
|
-
transitioned: false,
|
|
60206
|
-
ok: true,
|
|
60207
|
-
issues: [],
|
|
60208
|
-
reason: runtime.reason
|
|
60543
|
+
runtimeVersion: raw.runtimeVersion.trim(),
|
|
60544
|
+
installRoot: typeof raw.installRoot === "string" ? raw.installRoot : void 0,
|
|
60545
|
+
updatedAt: typeof raw.updatedAt === "number" ? raw.updatedAt : void 0
|
|
60209
60546
|
};
|
|
60547
|
+
} catch {
|
|
60548
|
+
return null;
|
|
60210
60549
|
}
|
|
60211
|
-
harnesses.update(id, { lastProbedAt: Date.now() });
|
|
60212
|
-
return {
|
|
60213
|
-
id,
|
|
60214
|
-
previousState,
|
|
60215
|
-
state: status.state,
|
|
60216
|
-
transitioned: false,
|
|
60217
|
-
ok: status.enabled && status.state === "ready",
|
|
60218
|
-
issues: status.enabled ? [`state_${status.state}`] : ["disabled"],
|
|
60219
|
-
reason: status.enabled ? `state is ${status.state}` : "harness disabled"
|
|
60220
|
-
};
|
|
60221
60550
|
}
|
|
60222
|
-
function
|
|
60223
|
-
|
|
60224
|
-
|
|
60551
|
+
function writeCurrentPointer(prefix, runtimeVersion, extras) {
|
|
60552
|
+
const ver = sanitizeRuntimeVersionForPath(runtimeVersion);
|
|
60553
|
+
mkdirSync11(prefix, { recursive: true });
|
|
60554
|
+
const path = managedCurrentPath(prefix);
|
|
60555
|
+
const body = JSON.stringify(
|
|
60556
|
+
{
|
|
60557
|
+
runtimeVersion: ver,
|
|
60558
|
+
installRoot: extras?.installRoot,
|
|
60559
|
+
updatedAt: Date.now()
|
|
60560
|
+
},
|
|
60561
|
+
null,
|
|
60562
|
+
2
|
|
60563
|
+
);
|
|
60564
|
+
const tmp = join19(
|
|
60565
|
+
prefix,
|
|
60566
|
+
`.${MANAGED_CURRENT_BASENAME}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`
|
|
60567
|
+
);
|
|
60568
|
+
writeFileSync9(tmp, body);
|
|
60569
|
+
try {
|
|
60570
|
+
renameSync2(tmp, path);
|
|
60571
|
+
} catch {
|
|
60572
|
+
try {
|
|
60573
|
+
if (existsSync22(path)) rmSync2(path, { force: true });
|
|
60574
|
+
renameSync2(tmp, path);
|
|
60575
|
+
} catch {
|
|
60576
|
+
writeFileSync9(path, body);
|
|
60577
|
+
try {
|
|
60578
|
+
rmSync2(tmp, { force: true });
|
|
60579
|
+
} catch {
|
|
60580
|
+
}
|
|
60581
|
+
}
|
|
60225
60582
|
}
|
|
60226
|
-
|
|
60227
|
-
|
|
60228
|
-
|
|
60583
|
+
}
|
|
60584
|
+
function resolveActiveInstallRoot(prefix) {
|
|
60585
|
+
if (!prefix || !existsSync22(prefix)) return null;
|
|
60586
|
+
const pointer = readCurrentPointer(prefix);
|
|
60587
|
+
if (pointer) {
|
|
60588
|
+
if (pointer.installRoot && existsSync22(pointer.installRoot) && statSync5(pointer.installRoot).isDirectory()) {
|
|
60589
|
+
return pointer.installRoot;
|
|
60590
|
+
}
|
|
60591
|
+
const dir = managedVersionDir(prefix, pointer.runtimeVersion);
|
|
60592
|
+
if (existsSync22(dir) && statSync5(dir).isDirectory()) return dir;
|
|
60229
60593
|
}
|
|
60230
|
-
|
|
60231
|
-
|
|
60232
|
-
|
|
60233
|
-
const
|
|
60234
|
-
|
|
60235
|
-
|
|
60236
|
-
|
|
60594
|
+
const versionsRoot = managedVersionsDir(prefix);
|
|
60595
|
+
if (existsSync22(versionsRoot)) {
|
|
60596
|
+
try {
|
|
60597
|
+
const kids = readdirSync8(versionsRoot).filter((n) => {
|
|
60598
|
+
try {
|
|
60599
|
+
return statSync5(join19(versionsRoot, n)).isDirectory();
|
|
60600
|
+
} catch {
|
|
60601
|
+
return false;
|
|
60602
|
+
}
|
|
60603
|
+
});
|
|
60604
|
+
if (kids.length === 1) return join19(versionsRoot, kids[0]);
|
|
60605
|
+
} catch {
|
|
60606
|
+
}
|
|
60607
|
+
}
|
|
60608
|
+
return null;
|
|
60609
|
+
}
|
|
60610
|
+
function pruneManagedVersions(prefix, keep, maxKeep = MANAGED_VERSION_KEEP) {
|
|
60611
|
+
const versionsRoot = managedVersionsDir(prefix);
|
|
60612
|
+
if (!existsSync22(versionsRoot)) return;
|
|
60613
|
+
const keepSet = new Set(
|
|
60614
|
+
keep.filter(Boolean).map((v2) => {
|
|
60615
|
+
try {
|
|
60616
|
+
return sanitizeRuntimeVersionForPath(v2);
|
|
60617
|
+
} catch {
|
|
60618
|
+
return "";
|
|
60237
60619
|
}
|
|
60238
|
-
|
|
60239
|
-
|
|
60240
|
-
|
|
60620
|
+
}).filter(Boolean)
|
|
60621
|
+
);
|
|
60622
|
+
let entries;
|
|
60623
|
+
try {
|
|
60624
|
+
entries = readdirSync8(versionsRoot).map((name) => {
|
|
60625
|
+
try {
|
|
60626
|
+
const st = statSync5(join19(versionsRoot, name));
|
|
60627
|
+
if (!st.isDirectory()) return null;
|
|
60628
|
+
return { name, mtime: st.mtimeMs };
|
|
60629
|
+
} catch {
|
|
60630
|
+
return null;
|
|
60241
60631
|
}
|
|
60242
|
-
}
|
|
60632
|
+
}).filter((e) => e != null);
|
|
60633
|
+
} catch {
|
|
60634
|
+
return;
|
|
60243
60635
|
}
|
|
60244
|
-
|
|
60245
|
-
|
|
60636
|
+
const protectedNames = entries.filter((e) => keepSet.has(e.name));
|
|
60637
|
+
const others = entries.filter((e) => !keepSet.has(e.name)).sort((a, b2) => b2.mtime - a.mtime);
|
|
60638
|
+
const retain = new Set(protectedNames.map((e) => e.name));
|
|
60639
|
+
for (const e of others) {
|
|
60640
|
+
if (retain.size >= maxKeep) break;
|
|
60641
|
+
retain.add(e.name);
|
|
60246
60642
|
}
|
|
60247
|
-
|
|
60248
|
-
|
|
60643
|
+
for (const e of entries) {
|
|
60644
|
+
if (retain.has(e.name)) continue;
|
|
60645
|
+
const dir = join19(versionsRoot, e.name);
|
|
60646
|
+
try {
|
|
60647
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
60648
|
+
} catch {
|
|
60649
|
+
}
|
|
60249
60650
|
}
|
|
60250
|
-
return {
|
|
60251
|
-
ok: false,
|
|
60252
|
-
reason: "needs_auth: push provider credentials, complete host CLI login, or set SUPERONE_HARNESS_MARK_READY=1 for lab"
|
|
60253
|
-
};
|
|
60254
60651
|
}
|
|
60255
60652
|
|
|
60256
|
-
// src/
|
|
60257
|
-
init_environment();
|
|
60258
|
-
init_src2();
|
|
60259
|
-
import { accessSync, constants, existsSync as existsSync25, realpathSync as realpathSync3, statSync as statSync7 } from "node:fs";
|
|
60260
|
-
import { isAbsolute as isAbsolute2, resolve as resolve6 } from "node:path";
|
|
60261
|
-
|
|
60262
|
-
// src/session/managed-harness-release.ts
|
|
60653
|
+
// ../../packages/runtime/src/harness/managed-release.ts
|
|
60263
60654
|
import {
|
|
60264
60655
|
copyFileSync,
|
|
60265
60656
|
createReadStream,
|
|
60266
60657
|
existsSync as existsSync23,
|
|
60267
|
-
mkdirSync as
|
|
60658
|
+
mkdirSync as mkdirSync12,
|
|
60268
60659
|
mkdtempSync,
|
|
60269
|
-
readFileSync as
|
|
60270
|
-
renameSync as
|
|
60271
|
-
rmSync as
|
|
60272
|
-
statSync as
|
|
60273
|
-
writeFileSync as
|
|
60660
|
+
readFileSync as readFileSync14,
|
|
60661
|
+
renameSync as renameSync3,
|
|
60662
|
+
rmSync as rmSync3,
|
|
60663
|
+
statSync as statSync6,
|
|
60664
|
+
writeFileSync as writeFileSync10
|
|
60274
60665
|
} from "node:fs";
|
|
60275
|
-
import { createHash as createHash4, randomBytes as
|
|
60276
|
-
import { dirname as dirname11, join as
|
|
60666
|
+
import { createHash as createHash4, randomBytes as randomBytes4 } from "node:crypto";
|
|
60667
|
+
import { dirname as dirname11, join as join20, relative, resolve as resolve4, sep as sep3 } from "node:path";
|
|
60277
60668
|
import { arch as osArch, platform as osPlatform } from "node:os";
|
|
60669
|
+
var releaseVersionProvider = null;
|
|
60670
|
+
function setHarnessReleaseVersionProvider(fn) {
|
|
60671
|
+
releaseVersionProvider = fn;
|
|
60672
|
+
}
|
|
60278
60673
|
var MANAGED_PAYLOAD_BASENAME = "payload.bin";
|
|
60279
60674
|
var MANAGED_META_BASENAME = "artifact.json";
|
|
60280
|
-
var
|
|
60675
|
+
var MANAGED_CURRENT_BASENAME2 = "current";
|
|
60281
60676
|
var MAX_SEGMENT_LEN = 64;
|
|
60282
60677
|
var SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
60283
60678
|
function currentCliVersion() {
|
|
60284
|
-
const v2 =
|
|
60679
|
+
const v2 = releaseVersionProvider?.() ?? process.env.SUPERONE_CLI_VERSION?.trim() ?? "";
|
|
60285
60680
|
return assertSafePathSegment(v2, "cli version");
|
|
60286
60681
|
}
|
|
60287
60682
|
function currentHostPlatform() {
|
|
@@ -60375,11 +60770,37 @@ function parseManagedHarnessPin(id, raw) {
|
|
|
60375
60770
|
}
|
|
60376
60771
|
fileName = art.fileName.slice(0, 128);
|
|
60377
60772
|
}
|
|
60773
|
+
let url2;
|
|
60774
|
+
if (typeof art.url === "string" && art.url.trim()) {
|
|
60775
|
+
const u = art.url.trim();
|
|
60776
|
+
if (!/^https:\/\//i.test(u)) {
|
|
60777
|
+
throw new Error(`manifest ${id} artifacts[${i}] url must be https`);
|
|
60778
|
+
}
|
|
60779
|
+
if (u.length > 1024) {
|
|
60780
|
+
throw new Error(`manifest ${id} artifacts[${i}] url exceeds 1024 chars`);
|
|
60781
|
+
}
|
|
60782
|
+
url2 = u;
|
|
60783
|
+
}
|
|
60784
|
+
let npmName;
|
|
60785
|
+
if (typeof art.npmName === "string" && art.npmName.trim()) {
|
|
60786
|
+
const n = art.npmName.trim();
|
|
60787
|
+
if (!/^(@[A-Za-z0-9._-]+\/)?[A-Za-z0-9._-]+$/.test(n) || n.length > 214) {
|
|
60788
|
+
throw new Error(`manifest ${id} artifacts[${i}] npmName invalid`);
|
|
60789
|
+
}
|
|
60790
|
+
npmName = n;
|
|
60791
|
+
}
|
|
60792
|
+
let npmVersion;
|
|
60793
|
+
if (typeof art.npmVersion === "string" && art.npmVersion.trim()) {
|
|
60794
|
+
npmVersion = assertSafePathSegment(art.npmVersion, `${id}.artifacts[${i}].npmVersion`);
|
|
60795
|
+
}
|
|
60378
60796
|
return {
|
|
60379
60797
|
platform: platform2,
|
|
60380
60798
|
arch: arch2,
|
|
60381
60799
|
digestSha256: digest.toLowerCase(),
|
|
60382
|
-
fileName
|
|
60800
|
+
fileName,
|
|
60801
|
+
url: url2,
|
|
60802
|
+
npmName,
|
|
60803
|
+
npmVersion
|
|
60383
60804
|
};
|
|
60384
60805
|
});
|
|
60385
60806
|
return { runtimeVersion, artifactVersion, artifacts };
|
|
@@ -60390,11 +60811,11 @@ function loadHarnessReleaseManifest(nodeHome) {
|
|
|
60390
60811
|
if (!existsSync23(fromEnv)) {
|
|
60391
60812
|
throw new Error(`SUPERONE_HARNESS_MANIFEST not found: ${fromEnv}`);
|
|
60392
60813
|
}
|
|
60393
|
-
return parseHarnessReleaseManifest(JSON.parse(
|
|
60814
|
+
return parseHarnessReleaseManifest(JSON.parse(readFileSync14(fromEnv, "utf8")));
|
|
60394
60815
|
}
|
|
60395
|
-
const local =
|
|
60816
|
+
const local = join20(nodeHome, "release-manifest.json");
|
|
60396
60817
|
if (existsSync23(local)) {
|
|
60397
|
-
return parseHarnessReleaseManifest(JSON.parse(
|
|
60818
|
+
return parseHarnessReleaseManifest(JSON.parse(readFileSync14(local, "utf8")));
|
|
60398
60819
|
}
|
|
60399
60820
|
return null;
|
|
60400
60821
|
}
|
|
@@ -60465,7 +60886,7 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60465
60886
|
if (!existsSync23(opts.artifactPath)) {
|
|
60466
60887
|
throw new Error(`artifact not found: ${opts.artifactPath}`);
|
|
60467
60888
|
}
|
|
60468
|
-
if (!
|
|
60889
|
+
if (!statSync6(opts.artifactPath).isFile()) {
|
|
60469
60890
|
throw new Error(`artifact is not a regular file: ${opts.artifactPath}`);
|
|
60470
60891
|
}
|
|
60471
60892
|
const digest = await sha256File(opts.artifactPath);
|
|
@@ -60480,8 +60901,8 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60480
60901
|
opts.harnessId,
|
|
60481
60902
|
pin.artifactVersion
|
|
60482
60903
|
);
|
|
60483
|
-
const finalFile =
|
|
60484
|
-
const metaPath =
|
|
60904
|
+
const finalFile = join20(destDir, MANAGED_PAYLOAD_BASENAME);
|
|
60905
|
+
const metaPath = join20(destDir, MANAGED_META_BASENAME);
|
|
60485
60906
|
assertStrictChild(finalFile, destDir, "payload path");
|
|
60486
60907
|
assertStrictChild(metaPath, destDir, "meta path");
|
|
60487
60908
|
const metaBody = JSON.stringify(
|
|
@@ -60501,7 +60922,7 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60501
60922
|
);
|
|
60502
60923
|
let reusedExisting = false;
|
|
60503
60924
|
if (existsSync23(destDir)) {
|
|
60504
|
-
const payloadOk = existsSync23(finalFile) &&
|
|
60925
|
+
const payloadOk = existsSync23(finalFile) && statSync6(finalFile).isFile() && await sha256File(finalFile) === art.digestSha256;
|
|
60505
60926
|
if (payloadOk) {
|
|
60506
60927
|
reusedExisting = true;
|
|
60507
60928
|
} else if (mode === "repair") {
|
|
@@ -60521,24 +60942,24 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60521
60942
|
}
|
|
60522
60943
|
} else {
|
|
60523
60944
|
const harnessRoot2 = dirname11(destDir);
|
|
60524
|
-
|
|
60945
|
+
mkdirSync12(harnessRoot2, { recursive: true });
|
|
60525
60946
|
assertPathInside(destDir, harnessRoot2, "version dir");
|
|
60526
60947
|
const stagingDir = mkdtempSync(
|
|
60527
|
-
|
|
60948
|
+
join20(harnessRoot2, `.staging-${opts.harnessId}-${randomBytes4(8).toString("hex")}-`)
|
|
60528
60949
|
);
|
|
60529
60950
|
assertPathInside(stagingDir, harnessRoot2, "staging dir");
|
|
60530
|
-
const stagingFile =
|
|
60531
|
-
const stagingMeta =
|
|
60951
|
+
const stagingFile = join20(stagingDir, MANAGED_PAYLOAD_BASENAME);
|
|
60952
|
+
const stagingMeta = join20(stagingDir, MANAGED_META_BASENAME);
|
|
60532
60953
|
try {
|
|
60533
60954
|
copyFileSync(opts.artifactPath, stagingFile);
|
|
60534
60955
|
const stagedDigest = await sha256File(stagingFile);
|
|
60535
60956
|
if (stagedDigest !== art.digestSha256) {
|
|
60536
60957
|
throw new Error(`staged artifact digest mismatch for ${opts.harnessId}`);
|
|
60537
60958
|
}
|
|
60538
|
-
|
|
60539
|
-
|
|
60959
|
+
writeFileSync10(stagingMeta, metaBody, "utf8");
|
|
60960
|
+
renameSync3(stagingDir, destDir);
|
|
60540
60961
|
} catch (err) {
|
|
60541
|
-
|
|
60962
|
+
rmSync3(stagingDir, { recursive: true, force: true });
|
|
60542
60963
|
if (existsSync23(destDir) && existsSync23(finalFile)) {
|
|
60543
60964
|
const existingDigest = await sha256File(finalFile);
|
|
60544
60965
|
if (existingDigest === art.digestSha256) {
|
|
@@ -60564,22 +60985,22 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60564
60985
|
if (finalDigest !== art.digestSha256) {
|
|
60565
60986
|
throw new Error(`final payload digest mismatch for ${opts.harnessId}`);
|
|
60566
60987
|
}
|
|
60567
|
-
const harnessRoot =
|
|
60988
|
+
const harnessRoot = join20(
|
|
60568
60989
|
releasesRoot(opts.nodeHome),
|
|
60569
60990
|
opts.manifest.cliVersion,
|
|
60570
60991
|
"harnesses",
|
|
60571
60992
|
opts.harnessId
|
|
60572
60993
|
);
|
|
60573
60994
|
assertPathInside(harnessRoot, releasesRoot(opts.nodeHome), "harness root");
|
|
60574
|
-
|
|
60575
|
-
const currentPath =
|
|
60576
|
-
const currentTmp =
|
|
60995
|
+
mkdirSync12(harnessRoot, { recursive: true });
|
|
60996
|
+
const currentPath = join20(harnessRoot, MANAGED_CURRENT_BASENAME2);
|
|
60997
|
+
const currentTmp = join20(
|
|
60577
60998
|
harnessRoot,
|
|
60578
|
-
`.${
|
|
60999
|
+
`.${MANAGED_CURRENT_BASENAME2}.${process.pid}.${randomBytes4(6).toString("hex")}.tmp`
|
|
60579
61000
|
);
|
|
60580
61001
|
assertStrictChild(currentTmp, harnessRoot, "current pointer temp");
|
|
60581
61002
|
try {
|
|
60582
|
-
|
|
61003
|
+
writeFileSync10(
|
|
60583
61004
|
currentTmp,
|
|
60584
61005
|
JSON.stringify(
|
|
60585
61006
|
{
|
|
@@ -60593,9 +61014,9 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60593
61014
|
),
|
|
60594
61015
|
"utf8"
|
|
60595
61016
|
);
|
|
60596
|
-
|
|
61017
|
+
renameSync3(currentTmp, currentPath);
|
|
60597
61018
|
} catch (err) {
|
|
60598
|
-
|
|
61019
|
+
rmSync3(currentTmp, { force: true });
|
|
60599
61020
|
throw err;
|
|
60600
61021
|
}
|
|
60601
61022
|
return {
|
|
@@ -60610,10 +61031,10 @@ async function installManagedArtifactFromFile(opts) {
|
|
|
60610
61031
|
};
|
|
60611
61032
|
}
|
|
60612
61033
|
async function replacePayloadAtomically(opts) {
|
|
60613
|
-
|
|
60614
|
-
const nonce =
|
|
60615
|
-
const payloadTmp =
|
|
60616
|
-
const metaTmp =
|
|
61034
|
+
mkdirSync12(opts.destDir, { recursive: true });
|
|
61035
|
+
const nonce = randomBytes4(8).toString("hex");
|
|
61036
|
+
const payloadTmp = join20(opts.destDir, `.${MANAGED_PAYLOAD_BASENAME}.${nonce}.tmp`);
|
|
61037
|
+
const metaTmp = join20(opts.destDir, `.${MANAGED_META_BASENAME}.${nonce}.tmp`);
|
|
60617
61038
|
assertStrictChild(payloadTmp, opts.destDir, "payload temp");
|
|
60618
61039
|
assertStrictChild(metaTmp, opts.destDir, "meta temp");
|
|
60619
61040
|
try {
|
|
@@ -60622,12 +61043,12 @@ async function replacePayloadAtomically(opts) {
|
|
|
60622
61043
|
if (d !== opts.expectedDigest) {
|
|
60623
61044
|
throw new Error(`repair staged digest mismatch: expected ${opts.expectedDigest}, got ${d}`);
|
|
60624
61045
|
}
|
|
60625
|
-
|
|
60626
|
-
|
|
60627
|
-
|
|
61046
|
+
writeFileSync10(metaTmp, opts.metaBody, "utf8");
|
|
61047
|
+
renameSync3(payloadTmp, opts.finalFile);
|
|
61048
|
+
renameSync3(metaTmp, opts.metaPath);
|
|
60628
61049
|
} catch (err) {
|
|
60629
|
-
|
|
60630
|
-
|
|
61050
|
+
rmSync3(payloadTmp, { force: true });
|
|
61051
|
+
rmSync3(metaTmp, { force: true });
|
|
60631
61052
|
throw err;
|
|
60632
61053
|
}
|
|
60633
61054
|
}
|
|
@@ -60646,14 +61067,967 @@ function requiredRuntimeVersion(harnessId, manifest) {
|
|
|
60646
61067
|
return manifest?.managedHarnesses[harnessId]?.runtimeVersion ?? null;
|
|
60647
61068
|
}
|
|
60648
61069
|
|
|
60649
|
-
// src/
|
|
60650
|
-
|
|
60651
|
-
|
|
61070
|
+
// ../../packages/runtime/src/harness/managed-official.ts
|
|
61071
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync13, readFileSync as readFileSync15, readdirSync as readdirSync9, statSync as statSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
61072
|
+
import { arch as osArch2, platform as osPlatform2 } from "node:os";
|
|
61073
|
+
import { join as join21, resolve as resolve5 } from "node:path";
|
|
61074
|
+
var OFFICIAL_CLAUDE_SDK_VERSION = "0.3.226";
|
|
61075
|
+
var OFFICIAL_CODEX_NPM_VERSION = "0.146.1";
|
|
61076
|
+
var OFFICIAL_CODEX_PACKAGE = "@openai/codex";
|
|
61077
|
+
function managedHarnessPrefix(nodeHome, harnessId) {
|
|
61078
|
+
return resolve5(nodeHome, harnessId);
|
|
61079
|
+
}
|
|
61080
|
+
function claudePlatformPackageName() {
|
|
61081
|
+
const p2 = osPlatform2();
|
|
61082
|
+
const a = osArch2();
|
|
61083
|
+
if (a !== "arm64" && a !== "x64") {
|
|
61084
|
+
throw new Error(`unsupported arch for Claude Agent SDK: ${a}`);
|
|
61085
|
+
}
|
|
61086
|
+
if (p2 === "darwin") return `@anthropic-ai/claude-agent-sdk-darwin-${a}`;
|
|
61087
|
+
if (p2 === "win32") return `@anthropic-ai/claude-agent-sdk-win32-${a}`;
|
|
61088
|
+
if (p2 === "linux") {
|
|
61089
|
+
if (isMuslLinux()) return `@anthropic-ai/claude-agent-sdk-linux-${a}-musl`;
|
|
61090
|
+
return `@anthropic-ai/claude-agent-sdk-linux-${a}`;
|
|
61091
|
+
}
|
|
61092
|
+
throw new Error(`unsupported platform for Claude Agent SDK: ${p2}`);
|
|
61093
|
+
}
|
|
61094
|
+
function isMuslLinux() {
|
|
61095
|
+
try {
|
|
61096
|
+
if (existsSync24("/etc/alpine-release")) return true;
|
|
61097
|
+
const lib = readdirSync9("/lib").some((n) => n.startsWith("ld-musl"));
|
|
61098
|
+
if (lib) return true;
|
|
61099
|
+
} catch {
|
|
61100
|
+
}
|
|
61101
|
+
return false;
|
|
61102
|
+
}
|
|
61103
|
+
function resolveOfficialInstallBinaryInRoot(harnessId, installRoot) {
|
|
61104
|
+
if (!installRoot || !existsSync24(installRoot)) return null;
|
|
61105
|
+
if (harnessId === "codex") {
|
|
61106
|
+
const candidates = [
|
|
61107
|
+
join21(installRoot, "bin", "codex"),
|
|
61108
|
+
join21(installRoot, "bin", "codex.cmd"),
|
|
61109
|
+
join21(installRoot, "lib", "node_modules", "@openai", "codex", "bin", "codex.js")
|
|
61110
|
+
];
|
|
61111
|
+
for (const c of candidates) {
|
|
61112
|
+
if (existsSync24(c) && (c.endsWith(".js") || isExecutableFile(c))) return c;
|
|
61113
|
+
}
|
|
61114
|
+
return null;
|
|
61115
|
+
}
|
|
61116
|
+
const nm = join21(installRoot, "lib", "node_modules");
|
|
61117
|
+
const scoped = join21(nm, "@anthropic-ai");
|
|
61118
|
+
try {
|
|
61119
|
+
if (existsSync24(scoped)) {
|
|
61120
|
+
const names = readdirSync9(scoped).filter((n) => n.startsWith("claude-agent-sdk-"));
|
|
61121
|
+
for (const n of names) {
|
|
61122
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
61123
|
+
const bin = join21(scoped, n, `claude${ext}`);
|
|
61124
|
+
if (existsSync24(bin)) return bin;
|
|
61125
|
+
}
|
|
61126
|
+
}
|
|
61127
|
+
} catch {
|
|
61128
|
+
}
|
|
61129
|
+
const direct = join21(
|
|
61130
|
+
nm,
|
|
61131
|
+
...claudePlatformPackageName().split("/"),
|
|
61132
|
+
process.platform === "win32" ? "claude.exe" : "claude"
|
|
61133
|
+
);
|
|
61134
|
+
if (existsSync24(direct)) return direct;
|
|
61135
|
+
return null;
|
|
61136
|
+
}
|
|
61137
|
+
function isExecutableFile(path) {
|
|
61138
|
+
try {
|
|
61139
|
+
const st = statSync7(path);
|
|
61140
|
+
if (!st.isFile()) return false;
|
|
61141
|
+
if (process.platform === "win32") return true;
|
|
61142
|
+
return (st.mode & 73) !== 0;
|
|
61143
|
+
} catch {
|
|
61144
|
+
return false;
|
|
61145
|
+
}
|
|
61146
|
+
}
|
|
61147
|
+
|
|
61148
|
+
// ../../packages/runtime/src/harness/tarball-fetch.ts
|
|
61149
|
+
import { existsSync as existsSync25, rmSync as rmSync4 } from "node:fs";
|
|
61150
|
+
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
61151
|
+
function assertSha256(actualHex, expectedHex) {
|
|
61152
|
+
if (actualHex !== expectedHex.toLowerCase()) {
|
|
61153
|
+
throw new Error(`tarball sha256 mismatch: expected ${expectedHex}, got ${actualHex}`);
|
|
61154
|
+
}
|
|
61155
|
+
}
|
|
61156
|
+
function assertSha512Integrity(actualBase64, integrity) {
|
|
61157
|
+
if (!integrity.startsWith("sha512-")) {
|
|
61158
|
+
throw new Error(`unsupported integrity algorithm: ${integrity.slice(0, 16)}`);
|
|
61159
|
+
}
|
|
61160
|
+
const expected = integrity.slice("sha512-".length);
|
|
61161
|
+
if (actualBase64 !== expected) {
|
|
61162
|
+
throw new Error(`tarball integrity mismatch (sha512)`);
|
|
61163
|
+
}
|
|
61164
|
+
}
|
|
61165
|
+
function discardPartial(destPath) {
|
|
61166
|
+
try {
|
|
61167
|
+
if (existsSync25(destPath)) rmSync4(destPath, { force: true });
|
|
61168
|
+
} catch {
|
|
61169
|
+
}
|
|
61170
|
+
}
|
|
61171
|
+
function createFetchJson(httpFetch) {
|
|
61172
|
+
return async (url2) => {
|
|
61173
|
+
const res = await httpFetch(url2, { headers: { accept: "application/json" } });
|
|
61174
|
+
if (!res.ok) throw new Error(`registry GET ${url2} \u2192 ${res.status}`);
|
|
61175
|
+
return res.json();
|
|
61176
|
+
};
|
|
61177
|
+
}
|
|
61178
|
+
async function resolveNpmPackMeta(name, version2, fetchJson) {
|
|
61179
|
+
const encoded = name.startsWith("@") ? `/${name.replace("/", "%2f")}/${encodeURIComponent(version2)}` : `/${name}/${encodeURIComponent(version2)}`;
|
|
61180
|
+
const url2 = `${NPM_REGISTRY}${encoded}`;
|
|
61181
|
+
const raw = await fetchJson(url2);
|
|
61182
|
+
const dist = raw.dist;
|
|
61183
|
+
if (!dist?.tarball || !dist.integrity) {
|
|
61184
|
+
throw new Error(`npm package ${name}@${version2} missing dist.tarball/integrity`);
|
|
61185
|
+
}
|
|
61186
|
+
if (!dist.integrity.startsWith("sha512-")) {
|
|
61187
|
+
throw new Error(`npm package ${name}@${version2} integrity is not sha512: ${dist.integrity}`);
|
|
61188
|
+
}
|
|
61189
|
+
return {
|
|
61190
|
+
name,
|
|
61191
|
+
version: typeof raw.version === "string" ? raw.version : version2,
|
|
61192
|
+
tarball: dist.tarball,
|
|
61193
|
+
integrity: dist.integrity
|
|
61194
|
+
};
|
|
61195
|
+
}
|
|
61196
|
+
async function fetchTarballWithFallback(opts) {
|
|
61197
|
+
const {
|
|
61198
|
+
destPath,
|
|
61199
|
+
npmName,
|
|
61200
|
+
npmVersion,
|
|
61201
|
+
pin,
|
|
61202
|
+
npmOnly,
|
|
61203
|
+
fetchJson,
|
|
61204
|
+
downloadToFile,
|
|
61205
|
+
onProgress,
|
|
61206
|
+
log: log2
|
|
61207
|
+
} = opts;
|
|
61208
|
+
const expectedSha = pin?.digestSha256;
|
|
61209
|
+
if (!npmOnly && pin?.url) {
|
|
61210
|
+
try {
|
|
61211
|
+
log2?.info?.(`[harness] fetching R2 ${pin.url}`);
|
|
61212
|
+
const digests = await downloadToFile(pin.url, destPath, onProgress);
|
|
61213
|
+
if (expectedSha) assertSha256(digests.sha256Hex, expectedSha);
|
|
61214
|
+
return { from: "r2-tarball", digests };
|
|
61215
|
+
} catch (err) {
|
|
61216
|
+
log2?.warn?.(
|
|
61217
|
+
`[harness] R2 fetch failed (${err instanceof Error ? err.message : String(err)}); trying npm`
|
|
61218
|
+
);
|
|
61219
|
+
if (err instanceof Error && /sha256 mismatch|integrity mismatch/i.test(err.message)) {
|
|
61220
|
+
discardPartial(destPath);
|
|
61221
|
+
}
|
|
61222
|
+
}
|
|
61223
|
+
}
|
|
61224
|
+
log2?.info?.(`[harness] fetching npm ${npmName}@${npmVersion}`);
|
|
61225
|
+
const meta3 = await resolveNpmPackMeta(npmName, npmVersion, fetchJson);
|
|
61226
|
+
try {
|
|
61227
|
+
const digests = await downloadToFile(meta3.tarball, destPath, onProgress);
|
|
61228
|
+
if (expectedSha) {
|
|
61229
|
+
assertSha256(digests.sha256Hex, expectedSha);
|
|
61230
|
+
} else {
|
|
61231
|
+
assertSha512Integrity(digests.sha512Base64, meta3.integrity);
|
|
61232
|
+
}
|
|
61233
|
+
return { from: "npm-tarball", digests, npmMeta: meta3 };
|
|
61234
|
+
} catch (err) {
|
|
61235
|
+
if (err instanceof Error && /sha256 mismatch|integrity mismatch/i.test(err.message)) {
|
|
61236
|
+
discardPartial(destPath);
|
|
61237
|
+
}
|
|
61238
|
+
throw err;
|
|
61239
|
+
}
|
|
61240
|
+
}
|
|
61241
|
+
|
|
61242
|
+
// ../../packages/runtime/src/harness/resumable-download.ts
|
|
61243
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
61244
|
+
import {
|
|
61245
|
+
appendFileSync,
|
|
61246
|
+
createReadStream as createReadStream2,
|
|
61247
|
+
createWriteStream,
|
|
61248
|
+
existsSync as existsSync26,
|
|
61249
|
+
mkdirSync as mkdirSync14,
|
|
61250
|
+
rmSync as rmSync5,
|
|
61251
|
+
statSync as statSync8,
|
|
61252
|
+
writeFileSync as writeFileSync12
|
|
61253
|
+
} from "node:fs";
|
|
61254
|
+
import { dirname as dirname12 } from "node:path";
|
|
61255
|
+
import { pipeline } from "node:stream/promises";
|
|
61256
|
+
import { Readable as Readable2, Transform } from "node:stream";
|
|
61257
|
+
var HARNESS_PROGRESS_THROTTLE_MS = 200;
|
|
61258
|
+
function createThrottledProgress(onProgress, throttleMs = HARNESS_PROGRESS_THROTTLE_MS) {
|
|
61259
|
+
if (!onProgress) return void 0;
|
|
61260
|
+
let lastEmit = 0;
|
|
61261
|
+
return (received, total) => {
|
|
61262
|
+
const now = Date.now();
|
|
61263
|
+
const done = total > 0 && received >= total;
|
|
61264
|
+
if (done || lastEmit === 0 || now - lastEmit >= throttleMs) {
|
|
61265
|
+
lastEmit = now;
|
|
61266
|
+
onProgress(received, total);
|
|
61267
|
+
}
|
|
61268
|
+
};
|
|
61269
|
+
}
|
|
61270
|
+
function parseContentRange(header) {
|
|
61271
|
+
if (!header) return null;
|
|
61272
|
+
const m2 = /^bytes\s+(\d+)-(\d+)\/(\d+|\*)$/i.exec(header.trim());
|
|
61273
|
+
if (!m2) return null;
|
|
61274
|
+
return {
|
|
61275
|
+
start: Number(m2[1]),
|
|
61276
|
+
end: Number(m2[2]),
|
|
61277
|
+
total: m2[3] === "*" ? null : Number(m2[3])
|
|
61278
|
+
};
|
|
61279
|
+
}
|
|
61280
|
+
async function seedHashesFromFile(path) {
|
|
61281
|
+
const sha256 = createHash5("sha256");
|
|
61282
|
+
const sha512 = createHash5("sha512");
|
|
61283
|
+
const size = statSync8(path).size;
|
|
61284
|
+
if (size === 0) return { sha256, sha512, size };
|
|
61285
|
+
await new Promise((resolve13, reject) => {
|
|
61286
|
+
const stream = createReadStream2(path);
|
|
61287
|
+
stream.on("data", (chunk) => {
|
|
61288
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
61289
|
+
sha256.update(buf);
|
|
61290
|
+
sha512.update(buf);
|
|
61291
|
+
});
|
|
61292
|
+
stream.on("error", reject);
|
|
61293
|
+
stream.on("end", () => resolve13());
|
|
61294
|
+
});
|
|
61295
|
+
return { sha256, sha512, size };
|
|
61296
|
+
}
|
|
61297
|
+
async function hashExistingFile(path, onProgress) {
|
|
61298
|
+
const { sha256, sha512, size } = await seedHashesFromFile(path);
|
|
61299
|
+
onProgress?.(size, size);
|
|
61300
|
+
return {
|
|
61301
|
+
byteLength: size,
|
|
61302
|
+
sha256Hex: sha256.digest("hex"),
|
|
61303
|
+
sha512Base64: sha512.digest("base64")
|
|
61304
|
+
};
|
|
61305
|
+
}
|
|
61306
|
+
async function streamResponseToFile(res, destPath, onProgress, opts = {}) {
|
|
61307
|
+
if (!res.ok && res.status !== 206) {
|
|
61308
|
+
throw new Error(`tarball GET \u2192 ${res.status}`);
|
|
61309
|
+
}
|
|
61310
|
+
const resumeFrom = opts.resumeFrom ?? 0;
|
|
61311
|
+
const append = opts.append === true && resumeFrom > 0;
|
|
61312
|
+
const keepPartial = opts.keepPartialOnError !== false;
|
|
61313
|
+
const contentLen = Number(res.headers.get("content-length") ?? 0);
|
|
61314
|
+
const total = opts.totalBytes && opts.totalBytes > 0 ? opts.totalBytes : append ? resumeFrom + contentLen : contentLen;
|
|
61315
|
+
mkdirSync14(dirname12(destPath), { recursive: true });
|
|
61316
|
+
const emit = createThrottledProgress(onProgress, opts.progressThrottleMs);
|
|
61317
|
+
let sha256;
|
|
61318
|
+
let sha512;
|
|
61319
|
+
let received;
|
|
61320
|
+
if (append) {
|
|
61321
|
+
const seeded = await seedHashesFromFile(destPath);
|
|
61322
|
+
if (seeded.size !== resumeFrom) {
|
|
61323
|
+
throw new Error(
|
|
61324
|
+
`partial size mismatch: disk=${seeded.size} resumeFrom=${resumeFrom}`
|
|
61325
|
+
);
|
|
61326
|
+
}
|
|
61327
|
+
sha256 = seeded.sha256;
|
|
61328
|
+
sha512 = seeded.sha512;
|
|
61329
|
+
received = resumeFrom;
|
|
61330
|
+
emit?.(received, total || received);
|
|
61331
|
+
} else {
|
|
61332
|
+
sha256 = createHash5("sha256");
|
|
61333
|
+
sha512 = createHash5("sha512");
|
|
61334
|
+
received = 0;
|
|
61335
|
+
}
|
|
61336
|
+
if (!res.body) {
|
|
61337
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
61338
|
+
if (append) {
|
|
61339
|
+
appendFileSync(destPath, buf);
|
|
61340
|
+
} else {
|
|
61341
|
+
writeFileSync12(destPath, buf);
|
|
61342
|
+
}
|
|
61343
|
+
sha256.update(buf);
|
|
61344
|
+
sha512.update(buf);
|
|
61345
|
+
received += buf.byteLength;
|
|
61346
|
+
emit?.(received, total || received);
|
|
61347
|
+
onProgress?.(received, total || received);
|
|
61348
|
+
return {
|
|
61349
|
+
byteLength: received,
|
|
61350
|
+
sha256Hex: sha256.digest("hex"),
|
|
61351
|
+
sha512Base64: sha512.digest("base64")
|
|
61352
|
+
};
|
|
61353
|
+
}
|
|
61354
|
+
const nodeStream = Readable2.fromWeb(res.body);
|
|
61355
|
+
const hasher = new Transform({
|
|
61356
|
+
transform(chunk, _enc, cb) {
|
|
61357
|
+
sha256.update(chunk);
|
|
61358
|
+
sha512.update(chunk);
|
|
61359
|
+
received += chunk.byteLength;
|
|
61360
|
+
emit?.(received, total || received);
|
|
61361
|
+
cb(null, chunk);
|
|
61362
|
+
}
|
|
61363
|
+
});
|
|
61364
|
+
try {
|
|
61365
|
+
await pipeline(
|
|
61366
|
+
nodeStream,
|
|
61367
|
+
hasher,
|
|
61368
|
+
createWriteStream(destPath, append ? { flags: "a" } : void 0)
|
|
61369
|
+
);
|
|
61370
|
+
} catch (err) {
|
|
61371
|
+
if (!keepPartial) {
|
|
61372
|
+
try {
|
|
61373
|
+
if (existsSync26(destPath)) rmSync5(destPath, { force: true });
|
|
61374
|
+
} catch {
|
|
61375
|
+
}
|
|
61376
|
+
}
|
|
61377
|
+
throw err;
|
|
61378
|
+
}
|
|
61379
|
+
onProgress?.(received, total || received);
|
|
61380
|
+
return {
|
|
61381
|
+
byteLength: received,
|
|
61382
|
+
sha256Hex: sha256.digest("hex"),
|
|
61383
|
+
sha512Base64: sha512.digest("base64")
|
|
61384
|
+
};
|
|
61385
|
+
}
|
|
61386
|
+
var destPathLocks = /* @__PURE__ */ new Map();
|
|
61387
|
+
async function withDestPathLock(destPath, fn) {
|
|
61388
|
+
const prev = destPathLocks.get(destPath) ?? Promise.resolve();
|
|
61389
|
+
let release;
|
|
61390
|
+
const gate = new Promise((resolve13) => {
|
|
61391
|
+
release = resolve13;
|
|
61392
|
+
});
|
|
61393
|
+
const held = prev.then(() => gate);
|
|
61394
|
+
destPathLocks.set(
|
|
61395
|
+
destPath,
|
|
61396
|
+
held.catch(() => {
|
|
61397
|
+
})
|
|
61398
|
+
);
|
|
61399
|
+
await prev.catch(() => {
|
|
61400
|
+
});
|
|
61401
|
+
try {
|
|
61402
|
+
return await fn();
|
|
61403
|
+
} finally {
|
|
61404
|
+
release();
|
|
61405
|
+
if (destPathLocks.get(destPath) === held) {
|
|
61406
|
+
destPathLocks.delete(destPath);
|
|
61407
|
+
}
|
|
61408
|
+
}
|
|
61409
|
+
}
|
|
61410
|
+
async function downloadResumableToFile(httpFetch, url2, destPath, onProgress, log2) {
|
|
61411
|
+
return withDestPathLock(
|
|
61412
|
+
destPath,
|
|
61413
|
+
() => downloadResumableToFileUnlocked(httpFetch, url2, destPath, onProgress, log2)
|
|
61414
|
+
);
|
|
61415
|
+
}
|
|
61416
|
+
async function downloadResumableToFileUnlocked(httpFetch, url2, destPath, onProgress, log2) {
|
|
61417
|
+
mkdirSync14(dirname12(destPath), { recursive: true });
|
|
61418
|
+
let existing = existsSync26(destPath) ? statSync8(destPath).size : 0;
|
|
61419
|
+
if (existing > 0 && existing < 64) {
|
|
61420
|
+
rmSync5(destPath, { force: true });
|
|
61421
|
+
existing = 0;
|
|
61422
|
+
}
|
|
61423
|
+
const tryOnce = async (from) => {
|
|
61424
|
+
const diskNow = existsSync26(destPath) ? statSync8(destPath).size : 0;
|
|
61425
|
+
const start = from > 0 ? diskNow : 0;
|
|
61426
|
+
if (from > 0 && diskNow !== from) {
|
|
61427
|
+
log2?.warn?.(
|
|
61428
|
+
`[harness] partial size changed before Range (wanted ${from}, disk ${diskNow}); using disk`
|
|
61429
|
+
);
|
|
61430
|
+
}
|
|
61431
|
+
const headers = {};
|
|
61432
|
+
if (start > 0) {
|
|
61433
|
+
headers.Range = `bytes=${start}-`;
|
|
61434
|
+
log2?.info?.(`[harness] resume download from byte ${start} \u2192 ${url2}`);
|
|
61435
|
+
}
|
|
61436
|
+
const res = await httpFetch(url2, { headers });
|
|
61437
|
+
if (res.status === 416 && start > 0) {
|
|
61438
|
+
try {
|
|
61439
|
+
const head = await httpFetch(url2, { method: "HEAD" });
|
|
61440
|
+
const len = Number(head.headers.get("content-length") ?? 0);
|
|
61441
|
+
if (len > 0 && start === len) {
|
|
61442
|
+
log2?.info?.(`[harness] partial already complete (${len} B); reusing`);
|
|
61443
|
+
return hashExistingFile(destPath, onProgress);
|
|
61444
|
+
}
|
|
61445
|
+
} catch {
|
|
61446
|
+
}
|
|
61447
|
+
log2?.warn?.(`[harness] Range 416 for ${url2}; discarding partial and restarting`);
|
|
61448
|
+
rmSync5(destPath, { force: true });
|
|
61449
|
+
return tryOnce(0);
|
|
61450
|
+
}
|
|
61451
|
+
if (res.status === 206) {
|
|
61452
|
+
const cr = parseContentRange(res.headers.get("content-range"));
|
|
61453
|
+
if (cr && cr.start !== start) {
|
|
61454
|
+
log2?.warn?.(
|
|
61455
|
+
`[harness] Content-Range start ${cr.start} \u2260 local ${start}; restarting`
|
|
61456
|
+
);
|
|
61457
|
+
rmSync5(destPath, { force: true });
|
|
61458
|
+
return tryOnce(0);
|
|
61459
|
+
}
|
|
61460
|
+
const total = cr?.total ?? start + Number(res.headers.get("content-length") ?? 0);
|
|
61461
|
+
try {
|
|
61462
|
+
return await streamResponseToFile(res, destPath, onProgress, {
|
|
61463
|
+
resumeFrom: start,
|
|
61464
|
+
append: true,
|
|
61465
|
+
totalBytes: total > 0 ? total : void 0,
|
|
61466
|
+
keepPartialOnError: true
|
|
61467
|
+
});
|
|
61468
|
+
} catch (err) {
|
|
61469
|
+
if (err instanceof Error && /partial size mismatch/i.test(err.message)) {
|
|
61470
|
+
log2?.warn?.(`[harness] ${err.message}; discarding partial and restarting`);
|
|
61471
|
+
rmSync5(destPath, { force: true });
|
|
61472
|
+
return tryOnce(0);
|
|
61473
|
+
}
|
|
61474
|
+
throw err;
|
|
61475
|
+
}
|
|
61476
|
+
}
|
|
61477
|
+
if (res.status === 200) {
|
|
61478
|
+
if (start > 0) {
|
|
61479
|
+
log2?.info?.(`[harness] server ignored Range for ${url2}; full re-download`);
|
|
61480
|
+
try {
|
|
61481
|
+
rmSync5(destPath, { force: true });
|
|
61482
|
+
} catch {
|
|
61483
|
+
}
|
|
61484
|
+
}
|
|
61485
|
+
const total = Number(res.headers.get("content-length") ?? 0);
|
|
61486
|
+
return streamResponseToFile(res, destPath, onProgress, {
|
|
61487
|
+
resumeFrom: 0,
|
|
61488
|
+
append: false,
|
|
61489
|
+
totalBytes: total > 0 ? total : void 0,
|
|
61490
|
+
keepPartialOnError: true
|
|
61491
|
+
});
|
|
61492
|
+
}
|
|
61493
|
+
if (!res.ok) throw new Error(`tarball GET ${url2} \u2192 ${res.status}`);
|
|
61494
|
+
return streamResponseToFile(res, destPath, onProgress, {
|
|
61495
|
+
keepPartialOnError: true
|
|
61496
|
+
});
|
|
61497
|
+
};
|
|
61498
|
+
return tryOnce(existing);
|
|
61499
|
+
}
|
|
61500
|
+
function createResumableDownloadToFile(httpFetch, log2) {
|
|
61501
|
+
return (url2, destPath, onProgress) => downloadResumableToFile(httpFetch, url2, destPath, onProgress, log2);
|
|
61502
|
+
}
|
|
61503
|
+
|
|
61504
|
+
// ../../packages/runtime/src/harness/managed-tarball-installer.ts
|
|
61505
|
+
import {
|
|
61506
|
+
existsSync as existsSync27,
|
|
61507
|
+
mkdirSync as mkdirSync15,
|
|
61508
|
+
mkdtempSync as mkdtempSync2,
|
|
61509
|
+
readFileSync as readFileSync16,
|
|
61510
|
+
renameSync as renameSync4,
|
|
61511
|
+
rmSync as rmSync6,
|
|
61512
|
+
statSync as statSync9,
|
|
61513
|
+
writeFileSync as writeFileSync13
|
|
61514
|
+
} from "node:fs";
|
|
61515
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
61516
|
+
import { dirname as dirname13, join as join22 } from "node:path";
|
|
61517
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
61518
|
+
|
|
61519
|
+
// ../../packages/shared/src/update-channels.ts
|
|
61520
|
+
function channelFromVersion(version2) {
|
|
61521
|
+
if (/-alpha/i.test(version2)) return "alpha";
|
|
61522
|
+
if (/-beta/i.test(version2)) return "beta";
|
|
61523
|
+
return "stable";
|
|
61524
|
+
}
|
|
61525
|
+
|
|
61526
|
+
// ../../packages/runtime/src/harness/cdn.ts
|
|
61527
|
+
var HARNESS_CDN_BASE = "https://dl.super-one.dev";
|
|
61528
|
+
var HARNESS_CDN_BUCKET_PREFIX = "harness";
|
|
61529
|
+
function isHarnessManifestChannel(value) {
|
|
61530
|
+
return value === "alpha" || value === "beta" || value === "stable";
|
|
61531
|
+
}
|
|
61532
|
+
function harnessChannelManifestObjectKey(channel) {
|
|
61533
|
+
return `${HARNESS_CDN_BUCKET_PREFIX}/manifest/${channel}.json`;
|
|
61534
|
+
}
|
|
61535
|
+
function harnessChannelManifestUrl(channel, base = HARNESS_CDN_BASE) {
|
|
61536
|
+
return `${base.replace(/\/+$/, "")}/${harnessChannelManifestObjectKey(channel)}`;
|
|
61537
|
+
}
|
|
61538
|
+
async function fetchHarnessChannelManifest(opts) {
|
|
61539
|
+
const url2 = harnessChannelManifestUrl(opts.channel, opts.baseUrl ?? HARNESS_CDN_BASE);
|
|
61540
|
+
const fetchJson = opts.fetchJson ?? (async (u) => {
|
|
61541
|
+
const ctrl = new AbortController();
|
|
61542
|
+
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
61543
|
+
try {
|
|
61544
|
+
const res = await fetch(u, {
|
|
61545
|
+
signal: ctrl.signal,
|
|
61546
|
+
headers: { accept: "application/json" }
|
|
61547
|
+
});
|
|
61548
|
+
if (!res.ok) throw new Error(`manifest GET ${u} \u2192 ${res.status}`);
|
|
61549
|
+
return res.json();
|
|
61550
|
+
} finally {
|
|
61551
|
+
clearTimeout(timer);
|
|
61552
|
+
}
|
|
61553
|
+
});
|
|
61554
|
+
return parseHarnessReleaseManifest(await fetchJson(url2));
|
|
61555
|
+
}
|
|
61556
|
+
function selectHarnessArtifact(manifest, harnessId, platform2, arch2) {
|
|
61557
|
+
const pin = manifest.managedHarnesses[harnessId];
|
|
61558
|
+
if (!pin) return null;
|
|
61559
|
+
return pin.artifacts.find((a) => a.platform === platform2 && a.arch === arch2) ?? null;
|
|
61560
|
+
}
|
|
61561
|
+
|
|
61562
|
+
// ../../packages/runtime/src/harness/managed-tarball-installer.ts
|
|
61563
|
+
function codexPlatformVersion(baseVersion = OFFICIAL_CODEX_NPM_VERSION) {
|
|
61564
|
+
const p2 = process.platform;
|
|
61565
|
+
const a = process.arch;
|
|
61566
|
+
if (a !== "arm64" && a !== "x64") {
|
|
61567
|
+
throw new Error(`unsupported arch for Codex: ${a}`);
|
|
61568
|
+
}
|
|
61569
|
+
if (p2 === "darwin") return `${baseVersion}-darwin-${a}`;
|
|
61570
|
+
if (p2 === "linux") return `${baseVersion}-linux-${a}`;
|
|
61571
|
+
if (p2 === "win32") return `${baseVersion}-win32-${a}`;
|
|
61572
|
+
throw new Error(`unsupported platform for Codex: ${p2}`);
|
|
61573
|
+
}
|
|
61574
|
+
function managedPackagePins(id) {
|
|
61575
|
+
if (id === "claude") {
|
|
61576
|
+
const ver = process.env.SUPERONE_CLAUDE_SDK_VERSION?.trim() || OFFICIAL_CLAUDE_SDK_VERSION;
|
|
61577
|
+
const platform2 = claudePlatformPackageName();
|
|
61578
|
+
return {
|
|
61579
|
+
runtimeVersion: ver,
|
|
61580
|
+
packages: [{ name: platform2, version: ver, nodeModulesDir: platform2 }]
|
|
61581
|
+
};
|
|
61582
|
+
}
|
|
61583
|
+
const base = process.env.SUPERONE_CODEX_NPM_VERSION?.trim() || OFFICIAL_CODEX_NPM_VERSION;
|
|
61584
|
+
return {
|
|
61585
|
+
runtimeVersion: base,
|
|
61586
|
+
packages: [
|
|
61587
|
+
{
|
|
61588
|
+
name: OFFICIAL_CODEX_PACKAGE,
|
|
61589
|
+
version: codexPlatformVersion(base),
|
|
61590
|
+
nodeModulesDir: OFFICIAL_CODEX_PACKAGE
|
|
61591
|
+
}
|
|
61592
|
+
]
|
|
61593
|
+
};
|
|
61594
|
+
}
|
|
61595
|
+
function resolveHarnessManifestChannel(explicit, releaseVersion) {
|
|
61596
|
+
if (explicit) return explicit;
|
|
61597
|
+
const fromEnv = process.env.SUPERONE_HARNESS_CHANNEL?.trim();
|
|
61598
|
+
if (fromEnv && isHarnessManifestChannel(fromEnv)) return fromEnv;
|
|
61599
|
+
const ver = releaseVersion?.trim() || process.env.SUPERONE_CLI_VERSION?.trim() || process.env.npm_package_version?.trim() || "";
|
|
61600
|
+
if (ver) {
|
|
61601
|
+
const ch = channelFromVersion(ver);
|
|
61602
|
+
if (isHarnessManifestChannel(ch)) return ch;
|
|
61603
|
+
}
|
|
61604
|
+
return "alpha";
|
|
61605
|
+
}
|
|
61606
|
+
function harnessDownloadDir(homeRoot) {
|
|
61607
|
+
return join22(homeRoot, ".download");
|
|
61608
|
+
}
|
|
61609
|
+
function harnessArtifactDownloadKey(opts) {
|
|
61610
|
+
const digest = opts.digestSha256?.trim().toLowerCase();
|
|
61611
|
+
if (digest && /^[a-f0-9]{16,}$/.test(digest)) {
|
|
61612
|
+
return `${opts.harnessId}-${digest.slice(0, 24)}`;
|
|
61613
|
+
}
|
|
61614
|
+
const safe = `${opts.npmName}@${opts.npmVersion}`.replace(/^@/, "").replace(/[^A-Za-z0-9._+-]+/g, "_").slice(0, 120);
|
|
61615
|
+
return `${opts.harnessId}-${safe}`;
|
|
61616
|
+
}
|
|
61617
|
+
function harnessPartialPath(homeRoot, key) {
|
|
61618
|
+
if (!key || key.includes("..") || key.includes("/") || key.includes("\\")) {
|
|
61619
|
+
throw new Error(`unsafe download key: ${key}`);
|
|
61620
|
+
}
|
|
61621
|
+
return join22(harnessDownloadDir(homeRoot), `${key}.partial`);
|
|
61622
|
+
}
|
|
61623
|
+
function extractTgzWithSystemTar(tgzPath, destDir) {
|
|
61624
|
+
return new Promise((resolve13, reject) => {
|
|
61625
|
+
mkdirSync15(destDir, { recursive: true });
|
|
61626
|
+
const child = spawn4("tar", ["-xzf", tgzPath, "-C", destDir], {
|
|
61627
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
61628
|
+
});
|
|
61629
|
+
let stderr = "";
|
|
61630
|
+
child.stderr?.on("data", (c) => {
|
|
61631
|
+
stderr += c.toString();
|
|
61632
|
+
});
|
|
61633
|
+
child.on("error", (err) => reject(new Error(`tar spawn failed: ${err.message}`)));
|
|
61634
|
+
child.on("close", (code) => {
|
|
61635
|
+
if (code === 0) resolve13();
|
|
61636
|
+
else reject(new Error(`tar extract failed (exit ${code}): ${stderr.slice(-500)}`));
|
|
61637
|
+
});
|
|
61638
|
+
});
|
|
61639
|
+
}
|
|
61640
|
+
function installPackageDir(packageDir, prefix, nodeModulesRel) {
|
|
61641
|
+
const dest = join22(prefix, "lib", "node_modules", ...nodeModulesRel.split("/"));
|
|
61642
|
+
const parent = dirname13(dest);
|
|
61643
|
+
mkdirSync15(parent, { recursive: true });
|
|
61644
|
+
if (existsSync27(dest)) {
|
|
61645
|
+
rmSync6(dest, { recursive: true, force: true });
|
|
61646
|
+
}
|
|
61647
|
+
const staging = join22(
|
|
61648
|
+
parent,
|
|
61649
|
+
`.staging-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
61650
|
+
);
|
|
61651
|
+
try {
|
|
61652
|
+
renameSync4(packageDir, staging);
|
|
61653
|
+
renameSync4(staging, dest);
|
|
61654
|
+
} catch (err) {
|
|
61655
|
+
if (existsSync27(staging)) rmSync6(staging, { recursive: true, force: true });
|
|
61656
|
+
throw err instanceof Error ? err : new Error(`failed to place package into ${dest}: ${String(err)}`);
|
|
61657
|
+
}
|
|
61658
|
+
return dest;
|
|
61659
|
+
}
|
|
61660
|
+
function codexTargetTriple() {
|
|
61661
|
+
const key = `${process.platform}-${process.arch}`;
|
|
61662
|
+
const map2 = {
|
|
61663
|
+
"darwin-arm64": "aarch64-apple-darwin",
|
|
61664
|
+
"darwin-x64": "x86_64-apple-darwin",
|
|
61665
|
+
"linux-arm64": "aarch64-unknown-linux-musl",
|
|
61666
|
+
"linux-x64": "x86_64-unknown-linux-musl",
|
|
61667
|
+
"win32-arm64": "aarch64-pc-windows-msvc",
|
|
61668
|
+
"win32-x64": "x86_64-pc-windows-msvc"
|
|
61669
|
+
};
|
|
61670
|
+
return map2[key] ?? null;
|
|
61671
|
+
}
|
|
61672
|
+
function resolveCodexNativeUnderPrefix(prefix) {
|
|
61673
|
+
const triple = codexTargetTriple();
|
|
61674
|
+
if (!triple) return null;
|
|
61675
|
+
const binaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
|
61676
|
+
const candidates = [
|
|
61677
|
+
join22(prefix, "lib", "node_modules", "@openai", "codex", "vendor", triple, "bin", binaryName),
|
|
61678
|
+
join22(
|
|
61679
|
+
prefix,
|
|
61680
|
+
"lib",
|
|
61681
|
+
"node_modules",
|
|
61682
|
+
"@openai",
|
|
61683
|
+
`codex-${process.platform}-${process.arch}`,
|
|
61684
|
+
"vendor",
|
|
61685
|
+
triple,
|
|
61686
|
+
"bin",
|
|
61687
|
+
binaryName
|
|
61688
|
+
)
|
|
61689
|
+
];
|
|
61690
|
+
for (const c of candidates) {
|
|
61691
|
+
if (existsSync27(c) && statSync9(c).isFile()) return c;
|
|
61692
|
+
}
|
|
61693
|
+
return null;
|
|
61694
|
+
}
|
|
61695
|
+
function resolveManagedTarballBinary(id, installRoot) {
|
|
61696
|
+
if (id === "claude") return resolveOfficialInstallBinaryInRoot("claude", installRoot);
|
|
61697
|
+
return resolveCodexNativeUnderPrefix(installRoot) ?? resolveOfficialInstallBinaryInRoot("codex", installRoot);
|
|
61698
|
+
}
|
|
61699
|
+
function readRuntimeVersionFromRoot(id, installRoot) {
|
|
61700
|
+
try {
|
|
61701
|
+
const metaPath = join22(installRoot, "install-meta.json");
|
|
61702
|
+
if (existsSync27(metaPath)) {
|
|
61703
|
+
const raw = JSON.parse(readFileSync16(metaPath, "utf8"));
|
|
61704
|
+
if (raw.runtimeVersion) return raw.runtimeVersion;
|
|
61705
|
+
}
|
|
61706
|
+
} catch {
|
|
61707
|
+
}
|
|
61708
|
+
try {
|
|
61709
|
+
const pkgPath = id === "claude" ? null : join22(installRoot, "lib", "node_modules", "@openai", "codex", "package.json");
|
|
61710
|
+
if (pkgPath && existsSync27(pkgPath)) {
|
|
61711
|
+
const raw = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
61712
|
+
const v2 = raw.version?.trim();
|
|
61713
|
+
if (!v2) return null;
|
|
61714
|
+
return v2.replace(/-(darwin|linux|win32)-(arm64|x64)$/, "");
|
|
61715
|
+
}
|
|
61716
|
+
} catch {
|
|
61717
|
+
}
|
|
61718
|
+
return null;
|
|
61719
|
+
}
|
|
61720
|
+
async function resolveArtifactPin(id, channel, opts, fetchJson) {
|
|
61721
|
+
if (opts.artifactPin !== void 0) return opts.artifactPin;
|
|
61722
|
+
if (opts.npmOnly) return null;
|
|
61723
|
+
try {
|
|
61724
|
+
const manifest = await fetchHarnessChannelManifest({
|
|
61725
|
+
channel,
|
|
61726
|
+
baseUrl: opts.cdnBase,
|
|
61727
|
+
fetchJson
|
|
61728
|
+
});
|
|
61729
|
+
return selectHarnessArtifact(manifest, id, currentHostPlatform(), currentHostArch());
|
|
61730
|
+
} catch (err) {
|
|
61731
|
+
opts.log?.warn?.(
|
|
61732
|
+
`[harness] channel manifest ${channel} unavailable (${err instanceof Error ? err.message : String(err)}); falling back to npm`
|
|
61733
|
+
);
|
|
61734
|
+
return null;
|
|
61735
|
+
}
|
|
61736
|
+
}
|
|
61737
|
+
function createManagedTarballInstaller(opts = {}) {
|
|
61738
|
+
const httpFetch = opts.httpFetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
61739
|
+
const fetchJson = opts.fetchJson ?? createFetchJson(httpFetch);
|
|
61740
|
+
const log2 = opts.log;
|
|
61741
|
+
const downloadToFile = opts.downloadToFile ?? createResumableDownloadToFile(httpFetch, log2);
|
|
61742
|
+
const extractTgz = opts.extractTgz ?? extractTgzWithSystemTar;
|
|
61743
|
+
return {
|
|
61744
|
+
async install(id, home, onProgress) {
|
|
61745
|
+
const prefix = managedHarnessPrefix(home.root, id);
|
|
61746
|
+
mkdirSync15(prefix, { recursive: true });
|
|
61747
|
+
const pins = managedPackagePins(id);
|
|
61748
|
+
const versionDir = managedVersionDir(prefix, pins.runtimeVersion);
|
|
61749
|
+
const previousPointer = readCurrentPointer(prefix)?.runtimeVersion ?? null;
|
|
61750
|
+
const versionBin = resolveManagedTarballBinary(id, versionDir);
|
|
61751
|
+
const versionMeta = readRuntimeVersionFromRoot(id, versionDir);
|
|
61752
|
+
if (versionBin && versionMeta === pins.runtimeVersion) {
|
|
61753
|
+
writeCurrentPointer(prefix, pins.runtimeVersion, { installRoot: versionDir });
|
|
61754
|
+
return {
|
|
61755
|
+
command: versionBin,
|
|
61756
|
+
runtimeVersion: pins.runtimeVersion,
|
|
61757
|
+
source: "npm-tarball",
|
|
61758
|
+
detail: {
|
|
61759
|
+
installPrefix: versionDir,
|
|
61760
|
+
reused: "1",
|
|
61761
|
+
runtimeVersion: pins.runtimeVersion
|
|
61762
|
+
}
|
|
61763
|
+
};
|
|
61764
|
+
}
|
|
61765
|
+
const activeRoot = resolveActiveInstallRoot(prefix);
|
|
61766
|
+
if (activeRoot) {
|
|
61767
|
+
const activeBin = resolveManagedTarballBinary(id, activeRoot);
|
|
61768
|
+
const activeVer = readRuntimeVersionFromRoot(id, activeRoot);
|
|
61769
|
+
if (activeBin && activeVer === pins.runtimeVersion) {
|
|
61770
|
+
writeCurrentPointer(prefix, pins.runtimeVersion, { installRoot: activeRoot });
|
|
61771
|
+
return {
|
|
61772
|
+
command: activeBin,
|
|
61773
|
+
runtimeVersion: activeVer,
|
|
61774
|
+
source: "npm-tarball",
|
|
61775
|
+
detail: { installPrefix: activeRoot, reused: "1" }
|
|
61776
|
+
};
|
|
61777
|
+
}
|
|
61778
|
+
if (activeBin && activeVer && activeVer !== pins.runtimeVersion) {
|
|
61779
|
+
log2?.info?.(
|
|
61780
|
+
`[harness] ${id} pin mismatch: installed=${activeVer} pin=${pins.runtimeVersion} \u2014 installing side-by-side`
|
|
61781
|
+
);
|
|
61782
|
+
}
|
|
61783
|
+
}
|
|
61784
|
+
const channel = resolveHarnessManifestChannel(opts.channel, opts.releaseVersion);
|
|
61785
|
+
const artifactPin = await resolveArtifactPin(id, channel, opts, fetchJson);
|
|
61786
|
+
let packageSpec = "";
|
|
61787
|
+
let source = "npm-tarball";
|
|
61788
|
+
mkdirSync15(versionDir, { recursive: true });
|
|
61789
|
+
for (const pkg of pins.packages) {
|
|
61790
|
+
const npmName = artifactPin?.npmName ?? pkg.name;
|
|
61791
|
+
const npmVersion = artifactPin?.npmVersion ?? pkg.version;
|
|
61792
|
+
packageSpec = `${npmName}@${npmVersion}`;
|
|
61793
|
+
const downloadKey = harnessArtifactDownloadKey({
|
|
61794
|
+
harnessId: id,
|
|
61795
|
+
digestSha256: artifactPin?.digestSha256,
|
|
61796
|
+
npmName,
|
|
61797
|
+
npmVersion
|
|
61798
|
+
});
|
|
61799
|
+
const partialPath = harnessPartialPath(home.root, downloadKey);
|
|
61800
|
+
const work = mkdtempSync2(join22(tmpdir2(), `superone-harness-${id}-`));
|
|
61801
|
+
try {
|
|
61802
|
+
const { from } = await fetchTarballWithFallback({
|
|
61803
|
+
destPath: partialPath,
|
|
61804
|
+
npmName,
|
|
61805
|
+
npmVersion,
|
|
61806
|
+
pin: artifactPin,
|
|
61807
|
+
npmOnly: opts.npmOnly === true,
|
|
61808
|
+
fetchJson,
|
|
61809
|
+
downloadToFile,
|
|
61810
|
+
onProgress,
|
|
61811
|
+
log: log2
|
|
61812
|
+
});
|
|
61813
|
+
source = from;
|
|
61814
|
+
const extractRoot = join22(work, "out");
|
|
61815
|
+
await extractTgz(partialPath, extractRoot);
|
|
61816
|
+
const packageDir = join22(extractRoot, "package");
|
|
61817
|
+
if (!existsSync27(packageDir) || !statSync9(packageDir).isDirectory()) {
|
|
61818
|
+
throw new Error(`tarball for ${packageSpec} has no package/ directory`);
|
|
61819
|
+
}
|
|
61820
|
+
installPackageDir(packageDir, versionDir, npmName);
|
|
61821
|
+
try {
|
|
61822
|
+
if (existsSync27(partialPath)) rmSync6(partialPath, { force: true });
|
|
61823
|
+
} catch {
|
|
61824
|
+
}
|
|
61825
|
+
} finally {
|
|
61826
|
+
rmSync6(work, { recursive: true, force: true });
|
|
61827
|
+
}
|
|
61828
|
+
}
|
|
61829
|
+
writeFileSync13(
|
|
61830
|
+
join22(versionDir, "install-meta.json"),
|
|
61831
|
+
JSON.stringify(
|
|
61832
|
+
{
|
|
61833
|
+
harnessId: id,
|
|
61834
|
+
runtimeVersion: pins.runtimeVersion,
|
|
61835
|
+
packageSpec,
|
|
61836
|
+
source,
|
|
61837
|
+
channel,
|
|
61838
|
+
digestSha256: artifactPin?.digestSha256 ?? null,
|
|
61839
|
+
installedAt: Date.now()
|
|
61840
|
+
},
|
|
61841
|
+
null,
|
|
61842
|
+
2
|
|
61843
|
+
)
|
|
61844
|
+
);
|
|
61845
|
+
const command = resolveManagedTarballBinary(id, versionDir);
|
|
61846
|
+
if (!command) {
|
|
61847
|
+
throw new Error(
|
|
61848
|
+
`tarball install of ${id} succeeded but binary was not found under ${versionDir}`
|
|
61849
|
+
);
|
|
61850
|
+
}
|
|
61851
|
+
writeCurrentPointer(prefix, pins.runtimeVersion, { installRoot: versionDir });
|
|
61852
|
+
const keep = [pins.runtimeVersion, previousPointer].filter(
|
|
61853
|
+
(v2) => typeof v2 === "string" && v2.length > 0
|
|
61854
|
+
);
|
|
61855
|
+
pruneManagedVersions(prefix, keep);
|
|
61856
|
+
log2?.info?.(`[harness] installed ${id}@${pins.runtimeVersion} from ${source} \u2192 ${command}`);
|
|
61857
|
+
return {
|
|
61858
|
+
command,
|
|
61859
|
+
runtimeVersion: pins.runtimeVersion,
|
|
61860
|
+
source,
|
|
61861
|
+
detail: {
|
|
61862
|
+
packageSpec,
|
|
61863
|
+
installPrefix: versionDir,
|
|
61864
|
+
channel,
|
|
61865
|
+
digestSha256: artifactPin?.digestSha256,
|
|
61866
|
+
runtimeVersion: pins.runtimeVersion
|
|
61867
|
+
}
|
|
61868
|
+
};
|
|
61869
|
+
}
|
|
61870
|
+
};
|
|
61871
|
+
}
|
|
61872
|
+
|
|
61873
|
+
// ../../packages/runtime/src/harness/runtime-ready.ts
|
|
61874
|
+
var RUNTIME_SPECS = {
|
|
61875
|
+
claude: {
|
|
61876
|
+
catalogId: "claude",
|
|
61877
|
+
okReason: "claude binary or Agent SDK available",
|
|
61878
|
+
failReason: "claude runtime unavailable: install managed artifact, Agent SDK platform package, or SUPERONE_CLAUDE_BINARY"
|
|
61879
|
+
},
|
|
61880
|
+
codex: {
|
|
61881
|
+
catalogId: "codex",
|
|
61882
|
+
okReason: "codex binary available",
|
|
61883
|
+
failReason: "codex runtime unavailable: enable with --artifact or set SUPERONE_CODEX_BINARY"
|
|
61884
|
+
},
|
|
61885
|
+
acp: {
|
|
61886
|
+
catalogId: "acp-grok",
|
|
61887
|
+
okReason: "acp binary available",
|
|
61888
|
+
failReason: "acp-grok runtime unavailable: enable with --command or set SUPERONE_ACP_BINARY"
|
|
61889
|
+
},
|
|
61890
|
+
opencode: {
|
|
61891
|
+
catalogId: "opencode",
|
|
61892
|
+
okReason: "opencode binary available",
|
|
61893
|
+
// server-url only configs still need a client binary for the node runner today
|
|
61894
|
+
failReason: "opencode runtime unavailable: enable with --command or set SUPERONE_OPENCODE_BINARY"
|
|
61895
|
+
}
|
|
61896
|
+
};
|
|
61897
|
+
function assertSessionHarnessRuntimeReady(sessionHarnessId, harnesses, resolver) {
|
|
61898
|
+
const spec = RUNTIME_SPECS[sessionHarnessId];
|
|
61899
|
+
if (!spec) return { ok: false, reason: `unknown harness: ${sessionHarnessId}` };
|
|
61900
|
+
if (resolver.resolveBinary(spec.catalogId, harnesses) || resolver.isRunnableWithoutCatalog(spec.catalogId)) {
|
|
61901
|
+
return { ok: true, reason: spec.okReason };
|
|
61902
|
+
}
|
|
61903
|
+
return { ok: false, reason: spec.failReason };
|
|
61904
|
+
}
|
|
61905
|
+
function probeHarnessReadiness(harnesses, id, deps) {
|
|
61906
|
+
const status = harnesses.get(id);
|
|
61907
|
+
const previousState = status.state;
|
|
61908
|
+
const issues = [];
|
|
61909
|
+
const sessionWire = id === "acp-grok" ? "acp" : id;
|
|
61910
|
+
const runtime = assertSessionHarnessRuntimeReady(sessionWire, harnesses, deps.resolver);
|
|
61911
|
+
if (!runtime.ok) {
|
|
61912
|
+
issues.push(runtime.reason);
|
|
61913
|
+
if (status.enabled && (status.state === "ready" || status.state === "needs_auth")) {
|
|
61914
|
+
harnesses.update(id, {
|
|
61915
|
+
state: "error",
|
|
61916
|
+
diagnosticCode: "probe_failed",
|
|
61917
|
+
lastProbedAt: Date.now()
|
|
61918
|
+
});
|
|
61919
|
+
const next = harnesses.get(id);
|
|
61920
|
+
return {
|
|
61921
|
+
id,
|
|
61922
|
+
previousState,
|
|
61923
|
+
state: next.state,
|
|
61924
|
+
transitioned: next.state !== previousState,
|
|
61925
|
+
ok: false,
|
|
61926
|
+
issues,
|
|
61927
|
+
reason: runtime.reason
|
|
61928
|
+
};
|
|
61929
|
+
}
|
|
61930
|
+
harnesses.update(id, { lastProbedAt: Date.now() });
|
|
61931
|
+
return {
|
|
61932
|
+
id,
|
|
61933
|
+
previousState,
|
|
61934
|
+
state: status.state,
|
|
61935
|
+
transitioned: false,
|
|
61936
|
+
ok: false,
|
|
61937
|
+
issues,
|
|
61938
|
+
reason: runtime.reason
|
|
61939
|
+
};
|
|
61940
|
+
}
|
|
61941
|
+
if (status.enabled && status.state === "needs_auth") {
|
|
61942
|
+
const authOk = isAuthSatisfied(id, deps);
|
|
61943
|
+
if (!authOk.ok) {
|
|
61944
|
+
issues.push(authOk.reason);
|
|
61945
|
+
harnesses.update(id, {
|
|
61946
|
+
lastProbedAt: Date.now(),
|
|
61947
|
+
diagnosticCode: "needs_auth"
|
|
61948
|
+
});
|
|
61949
|
+
return {
|
|
61950
|
+
id,
|
|
61951
|
+
previousState,
|
|
61952
|
+
state: "needs_auth",
|
|
61953
|
+
transitioned: false,
|
|
61954
|
+
ok: false,
|
|
61955
|
+
issues,
|
|
61956
|
+
reason: authOk.reason
|
|
61957
|
+
};
|
|
61958
|
+
}
|
|
61959
|
+
harnesses.update(id, {
|
|
61960
|
+
state: "ready",
|
|
61961
|
+
diagnosticCode: null,
|
|
61962
|
+
lastProbedAt: Date.now()
|
|
61963
|
+
});
|
|
61964
|
+
return {
|
|
61965
|
+
id,
|
|
61966
|
+
previousState,
|
|
61967
|
+
state: "ready",
|
|
61968
|
+
transitioned: true,
|
|
61969
|
+
ok: true,
|
|
61970
|
+
issues: [],
|
|
61971
|
+
reason: `promoted needs_auth \u2192 ready (${authOk.reason})`
|
|
61972
|
+
};
|
|
61973
|
+
}
|
|
61974
|
+
if (status.enabled && status.state === "ready") {
|
|
61975
|
+
harnesses.update(id, { lastProbedAt: Date.now(), diagnosticCode: null });
|
|
61976
|
+
return {
|
|
61977
|
+
id,
|
|
61978
|
+
previousState,
|
|
61979
|
+
state: "ready",
|
|
61980
|
+
transitioned: false,
|
|
61981
|
+
ok: true,
|
|
61982
|
+
issues: [],
|
|
61983
|
+
reason: runtime.reason
|
|
61984
|
+
};
|
|
61985
|
+
}
|
|
61986
|
+
harnesses.update(id, { lastProbedAt: Date.now() });
|
|
61987
|
+
return {
|
|
61988
|
+
id,
|
|
61989
|
+
previousState,
|
|
61990
|
+
state: status.state,
|
|
61991
|
+
transitioned: false,
|
|
61992
|
+
ok: status.enabled && status.state === "ready",
|
|
61993
|
+
issues: status.enabled ? [`state_${status.state}`] : ["disabled"],
|
|
61994
|
+
reason: status.enabled ? `state is ${status.state}` : "harness disabled"
|
|
61995
|
+
};
|
|
61996
|
+
}
|
|
61997
|
+
function isAuthSatisfied(id, deps) {
|
|
61998
|
+
if (process.env.SUPERONE_HARNESS_MARK_READY === "1") {
|
|
61999
|
+
return { ok: true, reason: "SUPERONE_HARNESS_MARK_READY" };
|
|
62000
|
+
}
|
|
62001
|
+
const defRequiresAuth = id === "claude" || id === "codex";
|
|
62002
|
+
if (!defRequiresAuth) {
|
|
62003
|
+
return { ok: true, reason: "external harness does not require SuperOne provider auth" };
|
|
62004
|
+
}
|
|
62005
|
+
const fromProvider = deps.auth?.hasCredentialFor(id);
|
|
62006
|
+
if (fromProvider?.ok) return fromProvider;
|
|
62007
|
+
if (deps.resolver.isRunnableWithoutCatalog(id)) {
|
|
62008
|
+
return {
|
|
62009
|
+
ok: true,
|
|
62010
|
+
reason: id === "claude" ? "claude Agent SDK / host credentials assumed" : "SUPERONE_CODEX_BINARY host credentials assumed"
|
|
62011
|
+
};
|
|
62012
|
+
}
|
|
62013
|
+
return {
|
|
62014
|
+
ok: false,
|
|
62015
|
+
reason: "needs_auth: push provider credentials, complete host CLI login, or set SUPERONE_HARNESS_MARK_READY=1 for lab"
|
|
62016
|
+
};
|
|
62017
|
+
}
|
|
62018
|
+
|
|
62019
|
+
// ../../packages/runtime/src/harness/enable.ts
|
|
62020
|
+
init_environment();
|
|
62021
|
+
import { accessSync, constants, existsSync as existsSync28, realpathSync as realpathSync3, statSync as statSync10 } from "node:fs";
|
|
62022
|
+
import { isAbsolute as isAbsolute2, resolve as resolve6 } from "node:path";
|
|
62023
|
+
async function enableHarness(manager, input, deps) {
|
|
60652
62024
|
const id = input.harnessId;
|
|
60653
62025
|
if (!isNodeHarnessId(id)) throw new Error(`unknown harnessId: ${id}`);
|
|
60654
62026
|
let status;
|
|
60655
62027
|
if (id === "claude" || id === "codex") {
|
|
60656
|
-
status = await enableManaged(manager, id, input.artifactPath
|
|
62028
|
+
status = await enableManaged(manager, id, input.artifactPath, deps, "enable", {
|
|
62029
|
+
forcePin: input.forcePin === true
|
|
62030
|
+
});
|
|
60657
62031
|
} else if (id === "opencode") {
|
|
60658
62032
|
status = enableOpencode(manager, {
|
|
60659
62033
|
command: input.command,
|
|
@@ -60666,7 +62040,7 @@ async function enableHarness(manager, input, providers) {
|
|
|
60666
62040
|
});
|
|
60667
62041
|
}
|
|
60668
62042
|
try {
|
|
60669
|
-
probeHarnessReadiness(manager, id,
|
|
62043
|
+
probeHarnessReadiness(manager, id, { resolver: deps.resolver, auth: deps.auth });
|
|
60670
62044
|
} catch {
|
|
60671
62045
|
}
|
|
60672
62046
|
return manager.get(id);
|
|
@@ -60675,9 +62049,10 @@ function disableHarness(manager, harnessId) {
|
|
|
60675
62049
|
if (!isNodeHarnessId(harnessId)) throw new Error(`unknown harnessId: ${harnessId}`);
|
|
60676
62050
|
return manager.disable(harnessId);
|
|
60677
62051
|
}
|
|
60678
|
-
async function enableManaged(manager, id, artifact, mode = "enable") {
|
|
60679
|
-
const nodeHome =
|
|
62052
|
+
async function enableManaged(manager, id, artifact, deps, mode = "enable", opts) {
|
|
62053
|
+
const nodeHome = deps.home.root;
|
|
60680
62054
|
const def = getNodeHarnessDefinition(id);
|
|
62055
|
+
const forcePin = opts?.forcePin === true;
|
|
60681
62056
|
if (artifact) {
|
|
60682
62057
|
const manifest = loadHarnessReleaseManifest(nodeHome);
|
|
60683
62058
|
if (!manifest) {
|
|
@@ -60714,25 +62089,26 @@ async function enableManaged(manager, id, artifact, mode = "enable") {
|
|
|
60714
62089
|
})
|
|
60715
62090
|
});
|
|
60716
62091
|
}
|
|
60717
|
-
|
|
60718
|
-
|
|
60719
|
-
|
|
60720
|
-
|
|
60721
|
-
|
|
60722
|
-
|
|
60723
|
-
runtimeVersion: auto.runtimeVersion ?? null,
|
|
60724
|
-
diagnosticCode: def.requiresAuth ? "needs_auth" : null,
|
|
60725
|
-
diagnosticFields: def.requiresAuth ? { command: auto.command, runtimeVersion: auto.runtimeVersion } : null,
|
|
60726
|
-
lastProbedAt: Date.now(),
|
|
60727
|
-
configJson: JSON.stringify({
|
|
62092
|
+
if (!forcePin) {
|
|
62093
|
+
const auto = deps.resolver.autoRuntime(id);
|
|
62094
|
+
if (auto) {
|
|
62095
|
+
return manager.update(id, {
|
|
62096
|
+
enabled: true,
|
|
62097
|
+
state: def.requiresAuth ? "needs_auth" : "ready",
|
|
60728
62098
|
command: auto.command,
|
|
60729
|
-
|
|
60730
|
-
|
|
60731
|
-
|
|
62099
|
+
runtimeVersion: auto.runtimeVersion,
|
|
62100
|
+
diagnosticCode: def.requiresAuth ? "needs_auth" : null,
|
|
62101
|
+
diagnosticFields: def.requiresAuth ? { command: auto.command, runtimeVersion: auto.runtimeVersion } : null,
|
|
62102
|
+
lastProbedAt: Date.now(),
|
|
62103
|
+
configJson: JSON.stringify({
|
|
62104
|
+
command: auto.command,
|
|
62105
|
+
source: auto.source
|
|
62106
|
+
})
|
|
62107
|
+
});
|
|
62108
|
+
}
|
|
60732
62109
|
}
|
|
60733
62110
|
try {
|
|
60734
|
-
const
|
|
60735
|
-
const official = await installManagedFromOfficialNpm2({ nodeHome, harnessId: id });
|
|
62111
|
+
const official = await deps.installer.install(id, deps.home);
|
|
60736
62112
|
return manager.update(id, {
|
|
60737
62113
|
enabled: true,
|
|
60738
62114
|
state: def.requiresAuth ? "needs_auth" : "ready",
|
|
@@ -60744,8 +62120,7 @@ async function enableManaged(manager, id, artifact, mode = "enable") {
|
|
|
60744
62120
|
configJson: JSON.stringify({
|
|
60745
62121
|
command: official.command,
|
|
60746
62122
|
source: official.source,
|
|
60747
|
-
|
|
60748
|
-
installPrefix: official.installPrefix,
|
|
62123
|
+
...official.detail ?? {},
|
|
60749
62124
|
runtimeVersion: official.runtimeVersion
|
|
60750
62125
|
})
|
|
60751
62126
|
});
|
|
@@ -60757,24 +62132,8 @@ async function enableManaged(manager, id, artifact, mode = "enable") {
|
|
|
60757
62132
|
`official install failed (${detail}); ${describeExpectedArtifact(id, manifest)} as offline fallback`
|
|
60758
62133
|
);
|
|
60759
62134
|
}
|
|
60760
|
-
throw new Error(
|
|
60761
|
-
`official install of ${id} failed: ${detail}. Ensure npm is on PATH and the host can reach registry.npmjs.org.`
|
|
60762
|
-
);
|
|
60763
|
-
}
|
|
60764
|
-
}
|
|
60765
|
-
function resolveManagedAutoRuntime(id) {
|
|
60766
|
-
if (id === "claude") {
|
|
60767
|
-
const sdk = resolveSdkClaudeBinary();
|
|
60768
|
-
if (sdk && existsSync25(sdk)) {
|
|
60769
|
-
return { command: sdk, source: "agent-sdk-optional" };
|
|
60770
|
-
}
|
|
60771
|
-
return null;
|
|
62135
|
+
throw new Error(`official install of ${id} failed: ${detail}`);
|
|
60772
62136
|
}
|
|
60773
|
-
const fromEnv = resolveCodexBinaryPath({});
|
|
60774
|
-
if (fromEnv) return { command: fromEnv, source: "env-or-catalog" };
|
|
60775
|
-
const fromPath = resolveExternalCommand(void 0, ["codex"]);
|
|
60776
|
-
if (fromPath) return { command: fromPath, source: "path" };
|
|
60777
|
-
return null;
|
|
60778
62137
|
}
|
|
60779
62138
|
function enableOpencode(manager, opts) {
|
|
60780
62139
|
if (opts.serverUrl) {
|
|
@@ -60840,7 +62199,7 @@ function requireRegularReadableFile(path) {
|
|
|
60840
62199
|
throw new Error(`path must be absolute: ${path}`);
|
|
60841
62200
|
}
|
|
60842
62201
|
const abs = resolve6(path);
|
|
60843
|
-
if (!
|
|
62202
|
+
if (!existsSync28(abs) || !statSync10(abs).isFile()) {
|
|
60844
62203
|
throw new Error(`not a regular file: ${abs}`);
|
|
60845
62204
|
}
|
|
60846
62205
|
accessSync(abs, constants.R_OK);
|
|
@@ -60849,9 +62208,9 @@ function requireRegularReadableFile(path) {
|
|
|
60849
62208
|
function resolveExternalCommand(explicit, searchNames) {
|
|
60850
62209
|
if (explicit) {
|
|
60851
62210
|
const abs = isAbsolute2(explicit) ? explicit : resolve6(explicit);
|
|
60852
|
-
if (!
|
|
62211
|
+
if (!existsSync28(abs)) return null;
|
|
60853
62212
|
try {
|
|
60854
|
-
if (!
|
|
62213
|
+
if (!statSync10(abs).isFile()) return null;
|
|
60855
62214
|
accessSync(abs, constants.X_OK);
|
|
60856
62215
|
} catch {
|
|
60857
62216
|
return null;
|
|
@@ -60864,9 +62223,9 @@ function resolveExternalCommand(explicit, searchNames) {
|
|
|
60864
62223
|
for (const dir of dirs) {
|
|
60865
62224
|
if (!dir) continue;
|
|
60866
62225
|
const candidate = resolve6(dir, name);
|
|
60867
|
-
if (!
|
|
62226
|
+
if (!existsSync28(candidate)) continue;
|
|
60868
62227
|
try {
|
|
60869
|
-
if (!
|
|
62228
|
+
if (!statSync10(candidate).isFile()) continue;
|
|
60870
62229
|
accessSync(candidate, constants.X_OK);
|
|
60871
62230
|
return realpathSync3(candidate);
|
|
60872
62231
|
} catch {
|
|
@@ -60918,10 +62277,105 @@ function looksLikeSecretArg(value) {
|
|
|
60918
62277
|
return false;
|
|
60919
62278
|
}
|
|
60920
62279
|
|
|
62280
|
+
// src/session/harness-host.ts
|
|
62281
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
62282
|
+
init_src2();
|
|
62283
|
+
init_claude_turn_runner();
|
|
62284
|
+
init_codex_turn_runner();
|
|
62285
|
+
init_resolve_service();
|
|
62286
|
+
setHarnessReleaseVersionProvider(resolveCliReleaseVersion);
|
|
62287
|
+
function envBinaryExists(envName) {
|
|
62288
|
+
const v2 = process.env[envName]?.trim();
|
|
62289
|
+
return Boolean(v2 && existsSync29(v2));
|
|
62290
|
+
}
|
|
62291
|
+
var cliHarnessResolver = {
|
|
62292
|
+
resolveBinary(id, harnesses) {
|
|
62293
|
+
if (id === "claude") return resolveClaudeBinaryPath({ harnesses });
|
|
62294
|
+
if (id === "codex") return resolveCodexBinaryPath({ harnesses });
|
|
62295
|
+
const command = harnesses.get(id).command;
|
|
62296
|
+
return command && existsSync29(command) ? command : null;
|
|
62297
|
+
},
|
|
62298
|
+
isRunnableWithoutCatalog(id) {
|
|
62299
|
+
if (id === "claude") return isClaudeRuntimeRunnable();
|
|
62300
|
+
if (id === "codex") return isCodexBinaryOverrideRunnable();
|
|
62301
|
+
if (id === "acp-grok") return envBinaryExists("SUPERONE_ACP_BINARY");
|
|
62302
|
+
return envBinaryExists("SUPERONE_OPENCODE_BINARY");
|
|
62303
|
+
},
|
|
62304
|
+
autoRuntime(id) {
|
|
62305
|
+
if (id === "claude") {
|
|
62306
|
+
const sdk = resolveSdkClaudeBinary();
|
|
62307
|
+
if (sdk && existsSync29(sdk)) return { command: sdk, source: "agent-sdk-optional" };
|
|
62308
|
+
return null;
|
|
62309
|
+
}
|
|
62310
|
+
const fromEnv = resolveCodexBinaryPath({});
|
|
62311
|
+
if (fromEnv) return { command: fromEnv, source: "env-or-catalog" };
|
|
62312
|
+
const fromPath = resolveExternalCommand(void 0, ["codex"]);
|
|
62313
|
+
if (fromPath) return { command: fromPath, source: "path" };
|
|
62314
|
+
return null;
|
|
62315
|
+
}
|
|
62316
|
+
};
|
|
62317
|
+
function cliHarnessAuthProbe(providers) {
|
|
62318
|
+
if (!providers) return null;
|
|
62319
|
+
return {
|
|
62320
|
+
hasCredentialFor(id) {
|
|
62321
|
+
const consumer = consumerForHarness(id);
|
|
62322
|
+
if (!consumer) return null;
|
|
62323
|
+
const binding = providers.listBindings().find((b2) => b2.consumer === consumer);
|
|
62324
|
+
if (binding?.credentialId) {
|
|
62325
|
+
const cred = providers.listCredentials().find((c) => c.id === binding.credentialId);
|
|
62326
|
+
if (cred) return { ok: true, reason: `provider binding ${consumer}` };
|
|
62327
|
+
}
|
|
62328
|
+
if (providers.listCredentials().length > 0) {
|
|
62329
|
+
return { ok: true, reason: "node has provider credentials" };
|
|
62330
|
+
}
|
|
62331
|
+
return null;
|
|
62332
|
+
}
|
|
62333
|
+
};
|
|
62334
|
+
}
|
|
62335
|
+
function cliHarnessDeps(providers) {
|
|
62336
|
+
const releaseVersion = resolveCliReleaseVersion();
|
|
62337
|
+
return {
|
|
62338
|
+
// Shared with desktop: ~/.superone/harness (or SUPERONE_HARNESS_HOME).
|
|
62339
|
+
home: { root: resolveHarnessHomeRoot() },
|
|
62340
|
+
releaseVersion,
|
|
62341
|
+
resolver: cliHarnessResolver,
|
|
62342
|
+
// Same R2 → npm tarball path as desktop (createManagedTarballInstaller).
|
|
62343
|
+
installer: createManagedTarballInstaller({
|
|
62344
|
+
releaseVersion,
|
|
62345
|
+
log: {
|
|
62346
|
+
info: (m2) => process.stderr.write(`${m2}
|
|
62347
|
+
`),
|
|
62348
|
+
warn: (m2) => process.stderr.write(`${m2}
|
|
62349
|
+
`)
|
|
62350
|
+
}
|
|
62351
|
+
}),
|
|
62352
|
+
auth: cliHarnessAuthProbe(providers)
|
|
62353
|
+
};
|
|
62354
|
+
}
|
|
62355
|
+
|
|
62356
|
+
// src/session/harness-runtime-ready.ts
|
|
62357
|
+
function assertSessionHarnessRuntimeReady2(sessionHarnessId, harnesses) {
|
|
62358
|
+
return assertSessionHarnessRuntimeReady(sessionHarnessId, harnesses, cliHarnessResolver);
|
|
62359
|
+
}
|
|
62360
|
+
function probeHarnessReadiness2(harnesses, id, providers) {
|
|
62361
|
+
return probeHarnessReadiness(harnesses, id, {
|
|
62362
|
+
resolver: cliHarnessResolver,
|
|
62363
|
+
auth: cliHarnessAuthProbe(providers)
|
|
62364
|
+
});
|
|
62365
|
+
}
|
|
62366
|
+
|
|
62367
|
+
// src/session/harness-enable.ts
|
|
62368
|
+
function enableHarness2(manager, input, providers) {
|
|
62369
|
+
return enableHarness(manager, input, cliHarnessDeps(providers));
|
|
62370
|
+
}
|
|
62371
|
+
function enableManaged2(manager, id, artifact, mode = "enable") {
|
|
62372
|
+
return enableManaged(manager, id, artifact, cliHarnessDeps(), mode);
|
|
62373
|
+
}
|
|
62374
|
+
|
|
60921
62375
|
// ../../packages/shared/src/git-clone.ts
|
|
60922
62376
|
import { execFile as execFile2 } from "node:child_process";
|
|
60923
|
-
import { existsSync as
|
|
60924
|
-
import { isAbsolute as isAbsolute3, join as
|
|
62377
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync16 } from "node:fs";
|
|
62378
|
+
import { isAbsolute as isAbsolute3, join as join23, resolve as resolve7 } from "node:path";
|
|
60925
62379
|
|
|
60926
62380
|
// ../../packages/shared/src/git-remote.ts
|
|
60927
62381
|
function repoNameFromGitUrl(url2) {
|
|
@@ -60986,17 +62440,17 @@ function resolveCloneDestination(input) {
|
|
|
60986
62440
|
if (name.includes("/") || name.includes("\\") || name === "." || name === "..") {
|
|
60987
62441
|
throw invalid(`invalid folder name: ${name}`);
|
|
60988
62442
|
}
|
|
60989
|
-
return { path:
|
|
62443
|
+
return { path: join23(resolve7(parent), name), name };
|
|
60990
62444
|
}
|
|
60991
62445
|
async function cloneRepository(input) {
|
|
60992
62446
|
const destination = resolveCloneDestination(input);
|
|
60993
|
-
if (
|
|
62447
|
+
if (existsSync30(destination.path)) {
|
|
60994
62448
|
throw Object.assign(new Error(`destination already exists: ${destination.path}`), {
|
|
60995
62449
|
code: "conflict"
|
|
60996
62450
|
});
|
|
60997
62451
|
}
|
|
60998
62452
|
const parent = resolve7(input.parentPath.trim());
|
|
60999
|
-
|
|
62453
|
+
mkdirSync16(parent, { recursive: true });
|
|
61000
62454
|
await new Promise((resolvePromise, reject) => {
|
|
61001
62455
|
execFile2(
|
|
61002
62456
|
"git",
|
|
@@ -61034,9 +62488,9 @@ async function cloneRepository(input) {
|
|
|
61034
62488
|
|
|
61035
62489
|
// src/rpc/handlers.ts
|
|
61036
62490
|
init_resolve_service();
|
|
61037
|
-
import { existsSync as
|
|
62491
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync17, readdirSync as readdirSync10, statSync as statSync11 } from "node:fs";
|
|
61038
62492
|
import { join as pathJoin, resolve as pathResolve } from "node:path";
|
|
61039
|
-
import { arch, cpus, freemem, homedir as
|
|
62493
|
+
import { arch, cpus, freemem, homedir as homedir7, hostname as hostname4, platform, totalmem, uptime } from "node:os";
|
|
61040
62494
|
|
|
61041
62495
|
// src/rpc/resource-handlers.ts
|
|
61042
62496
|
init_environment();
|
|
@@ -61950,15 +63404,38 @@ function parseAgentConfig(raw) {
|
|
|
61950
63404
|
...typeof c.model === "string" ? { model: c.model } : {},
|
|
61951
63405
|
...typeof c.effort === "string" ? { effort: c.effort } : {},
|
|
61952
63406
|
...typeof c.permissionMode === "string" ? { permissionMode: c.permissionMode } : {},
|
|
61953
|
-
...typeof c.sandboxMode === "string" ? { sandboxMode: c.sandboxMode } : {}
|
|
63407
|
+
...typeof c.sandboxMode === "string" ? { sandboxMode: c.sandboxMode } : {},
|
|
63408
|
+
...c.apiProviderId === null || typeof c.apiProviderId === "string" ? { apiProviderId: c.apiProviderId } : {}
|
|
61954
63409
|
};
|
|
61955
63410
|
}
|
|
61956
63411
|
if (c.type === "codex") {
|
|
63412
|
+
const effort = typeof c.effort === "string" ? c.effort : typeof c.reasoningEffort === "string" ? c.reasoningEffort : void 0;
|
|
61957
63413
|
return {
|
|
61958
63414
|
type: "codex",
|
|
61959
63415
|
...typeof c.model === "string" ? { model: c.model } : {},
|
|
61960
|
-
...
|
|
61961
|
-
...typeof c.
|
|
63416
|
+
...effort ? { effort, reasoningEffort: effort } : {},
|
|
63417
|
+
...typeof c.permissionMode === "string" ? { permissionMode: c.permissionMode } : {},
|
|
63418
|
+
...typeof c.permissionPreset === "string" ? { permissionPreset: c.permissionPreset } : {},
|
|
63419
|
+
...c.apiProviderId === null || typeof c.apiProviderId === "string" ? { apiProviderId: c.apiProviderId } : {}
|
|
63420
|
+
};
|
|
63421
|
+
}
|
|
63422
|
+
if (c.type === "acp") {
|
|
63423
|
+
return {
|
|
63424
|
+
type: "acp",
|
|
63425
|
+
...typeof c.acpAgentId === "string" ? { acpAgentId: c.acpAgentId } : {},
|
|
63426
|
+
...typeof c.model === "string" ? { model: c.model } : {},
|
|
63427
|
+
...typeof c.effort === "string" ? { effort: c.effort } : {},
|
|
63428
|
+
...typeof c.permissionMode === "string" ? { permissionMode: c.permissionMode } : {},
|
|
63429
|
+
...c.apiProviderId === null || typeof c.apiProviderId === "string" ? { apiProviderId: c.apiProviderId } : {}
|
|
63430
|
+
};
|
|
63431
|
+
}
|
|
63432
|
+
if (c.type === "opencode") {
|
|
63433
|
+
return {
|
|
63434
|
+
type: "opencode",
|
|
63435
|
+
...typeof c.model === "string" ? { model: c.model } : {},
|
|
63436
|
+
...typeof c.effort === "string" ? { effort: c.effort } : {},
|
|
63437
|
+
...typeof c.permissionMode === "string" ? { permissionMode: c.permissionMode } : {},
|
|
63438
|
+
...c.apiProviderId === null || typeof c.apiProviderId === "string" ? { apiProviderId: c.apiProviderId } : {}
|
|
61962
63439
|
};
|
|
61963
63440
|
}
|
|
61964
63441
|
return null;
|
|
@@ -61967,6 +63444,7 @@ function parseSchedule(raw) {
|
|
|
61967
63444
|
if (!raw || typeof raw !== "object") return null;
|
|
61968
63445
|
const s2 = raw;
|
|
61969
63446
|
if (s2.type !== "one-time" && s2.type !== "recurring") return null;
|
|
63447
|
+
const summary = typeof s2.summary === "string" ? s2.summary.trim() : "";
|
|
61970
63448
|
return {
|
|
61971
63449
|
type: s2.type,
|
|
61972
63450
|
...typeof s2.cron === "string" ? { cron: s2.cron } : {},
|
|
@@ -61974,7 +63452,8 @@ function parseSchedule(raw) {
|
|
|
61974
63452
|
...typeof s2.preset === "string" ? { preset: s2.preset } : {},
|
|
61975
63453
|
...typeof s2.timeOfDay === "string" ? { timeOfDay: s2.timeOfDay } : {},
|
|
61976
63454
|
...Array.isArray(s2.dayOfWeek) ? { dayOfWeek: s2.dayOfWeek.filter((x2) => typeof x2 === "number") } : {},
|
|
61977
|
-
...typeof s2.minuteOfHour === "number" ? { minuteOfHour: s2.minuteOfHour } : {}
|
|
63455
|
+
...typeof s2.minuteOfHour === "number" ? { minuteOfHour: s2.minuteOfHour } : {},
|
|
63456
|
+
...summary ? { summary } : {}
|
|
61978
63457
|
};
|
|
61979
63458
|
}
|
|
61980
63459
|
function handleAutomationList(payload, ctx) {
|
|
@@ -62018,7 +63497,7 @@ function handleAutomationCreate(payload, ctx) {
|
|
|
62018
63497
|
}
|
|
62019
63498
|
const agentConfig = parseAgentConfig(p2.agentConfig);
|
|
62020
63499
|
if (!agentConfig) {
|
|
62021
|
-
return { error: { code: "invalid_argument", message: "agentConfig.type must be claude or
|
|
63500
|
+
return { error: { code: "invalid_argument", message: "agentConfig.type must be claude, codex, acp, or opencode" } };
|
|
62022
63501
|
}
|
|
62023
63502
|
const schedule = parseSchedule(p2.schedule);
|
|
62024
63503
|
if (!schedule) {
|
|
@@ -62056,7 +63535,7 @@ function handleAutomationUpdate(payload, ctx) {
|
|
|
62056
63535
|
if (p2.agentConfig !== void 0) {
|
|
62057
63536
|
const agentConfig = parseAgentConfig(p2.agentConfig);
|
|
62058
63537
|
if (!agentConfig) {
|
|
62059
|
-
return { error: { code: "invalid_argument", message: "agentConfig.type must be claude or
|
|
63538
|
+
return { error: { code: "invalid_argument", message: "agentConfig.type must be claude, codex, acp, or opencode" } };
|
|
62060
63539
|
}
|
|
62061
63540
|
patch.agentConfig = agentConfig;
|
|
62062
63541
|
}
|
|
@@ -63353,7 +64832,7 @@ function handleHarnessProbe(payload, ctx) {
|
|
|
63353
64832
|
return { error: { code: "invalid_argument", message: `unknown harnessId: ${id}` } };
|
|
63354
64833
|
}
|
|
63355
64834
|
try {
|
|
63356
|
-
const result =
|
|
64835
|
+
const result = probeHarnessReadiness2(ctx.harnesses, id, ctx.providers ?? null);
|
|
63357
64836
|
return { result: { ...result, status: ctx.harnesses.get(id) } };
|
|
63358
64837
|
} catch (err) {
|
|
63359
64838
|
return mapThrown6(err);
|
|
@@ -63369,7 +64848,7 @@ async function handleHarnessEnable(payload, ctx) {
|
|
|
63369
64848
|
}
|
|
63370
64849
|
try {
|
|
63371
64850
|
const args = Array.isArray(p2.args) ? p2.args.filter((a) => typeof a === "string") : void 0;
|
|
63372
|
-
const status = await
|
|
64851
|
+
const status = await enableHarness2(
|
|
63373
64852
|
ctx.harnesses,
|
|
63374
64853
|
{
|
|
63375
64854
|
harnessId: id,
|
|
@@ -63659,9 +65138,9 @@ function handleProjectGet(payload, ctx) {
|
|
|
63659
65138
|
function expandHostPath(path) {
|
|
63660
65139
|
const trimmed = path.trim();
|
|
63661
65140
|
if (!trimmed) return trimmed;
|
|
63662
|
-
if (trimmed === "~") return
|
|
65141
|
+
if (trimmed === "~") return homedir7();
|
|
63663
65142
|
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
63664
|
-
return pathResolve(pathJoin(
|
|
65143
|
+
return pathResolve(pathJoin(homedir7(), trimmed.slice(2)));
|
|
63665
65144
|
}
|
|
63666
65145
|
return pathResolve(trimmed);
|
|
63667
65146
|
}
|
|
@@ -63675,8 +65154,8 @@ function handleProjectOpen(payload, ctx) {
|
|
|
63675
65154
|
}
|
|
63676
65155
|
const name = typeof p2.name === "string" ? p2.name : void 0;
|
|
63677
65156
|
try {
|
|
63678
|
-
if (p2.createIfMissing === true && !
|
|
63679
|
-
|
|
65157
|
+
if (p2.createIfMissing === true && !existsSync31(path)) {
|
|
65158
|
+
mkdirSync17(path, { recursive: true });
|
|
63680
65159
|
}
|
|
63681
65160
|
return { result: ctx.projects.open(path, name) };
|
|
63682
65161
|
} catch (err) {
|
|
@@ -63712,13 +65191,13 @@ function handleFsListDir(payload, ctx) {
|
|
|
63712
65191
|
}
|
|
63713
65192
|
try {
|
|
63714
65193
|
const resolved = expandHostPath(raw);
|
|
63715
|
-
if (!
|
|
65194
|
+
if (!existsSync31(resolved)) {
|
|
63716
65195
|
return { error: { code: "not_found", message: "path not found" } };
|
|
63717
65196
|
}
|
|
63718
|
-
if (!
|
|
65197
|
+
if (!statSync11(resolved).isDirectory()) {
|
|
63719
65198
|
return { error: { code: "invalid_argument", message: "not a directory" } };
|
|
63720
65199
|
}
|
|
63721
|
-
const entries =
|
|
65200
|
+
const entries = readdirSync10(resolved, { withFileTypes: true }).filter((ent) => ent.isDirectory() && !ent.name.startsWith(".")).map((ent) => ({
|
|
63722
65201
|
name: ent.name,
|
|
63723
65202
|
path: pathJoin(resolved, ent.name),
|
|
63724
65203
|
type: "directory"
|
|
@@ -64345,7 +65824,7 @@ function handleSessionCreate(payload, ctx) {
|
|
|
64345
65824
|
};
|
|
64346
65825
|
}
|
|
64347
65826
|
if (!ctx.simulatedHarness) {
|
|
64348
|
-
const runtime =
|
|
65827
|
+
const runtime = assertSessionHarnessRuntimeReady2(harnessId, ctx.harnesses);
|
|
64349
65828
|
if (!runtime.ok) {
|
|
64350
65829
|
return {
|
|
64351
65830
|
error: {
|
|
@@ -65098,7 +66577,7 @@ async function startNodeServer(opts) {
|
|
|
65098
66577
|
await handleHttp(req, res, opts);
|
|
65099
66578
|
} catch (err) {
|
|
65100
66579
|
const e = err;
|
|
65101
|
-
const status = e.code === "unauthorized" ? 401 : e.code === "forbidden" ? 403 : e.code === "invalid_argument" ? 400 : 500;
|
|
66580
|
+
const status = e.code === "unauthorized" || e.code === "revoked" ? 401 : e.code === "forbidden" ? 403 : e.code === "invalid_argument" ? 400 : 500;
|
|
65102
66581
|
sendJson(res, status, {
|
|
65103
66582
|
error: { code: e.code ?? "internal", message: e.message ?? "internal error" }
|
|
65104
66583
|
});
|
|
@@ -65378,7 +66857,7 @@ async function handleHttp(req, res, opts) {
|
|
|
65378
66857
|
sendJson(res, 200, result);
|
|
65379
66858
|
} catch (err) {
|
|
65380
66859
|
const e = err;
|
|
65381
|
-
sendJson(res, e.code === "unauthorized" ? 401 : 500, {
|
|
66860
|
+
sendJson(res, e.code === "unauthorized" || e.code === "revoked" ? 401 : 500, {
|
|
65382
66861
|
error: { code: e.code ?? "internal", message: e.message ?? "pair failed" }
|
|
65383
66862
|
});
|
|
65384
66863
|
}
|
|
@@ -65408,7 +66887,7 @@ async function handleHttp(req, res, opts) {
|
|
|
65408
66887
|
sendJson(res, 200, result);
|
|
65409
66888
|
} catch (err) {
|
|
65410
66889
|
const e = err;
|
|
65411
|
-
sendJson(res, e.code === "unauthorized" ? 401 : 500, {
|
|
66890
|
+
sendJson(res, e.code === "unauthorized" || e.code === "revoked" ? 401 : 500, {
|
|
65412
66891
|
error: { code: e.code ?? "internal", message: e.message ?? "token refresh failed" }
|
|
65413
66892
|
});
|
|
65414
66893
|
}
|
|
@@ -65429,7 +66908,7 @@ async function handleHttp(req, res, opts) {
|
|
|
65429
66908
|
sendJson(res, 200, ticket);
|
|
65430
66909
|
} catch (err) {
|
|
65431
66910
|
const e = err;
|
|
65432
|
-
sendJson(res, e.code === "unauthorized" ? 401 : 500, {
|
|
66911
|
+
sendJson(res, e.code === "unauthorized" || e.code === "revoked" ? 401 : 500, {
|
|
65433
66912
|
error: { code: e.code ?? "internal", message: e.message ?? "ticket failed" }
|
|
65434
66913
|
});
|
|
65435
66914
|
}
|
|
@@ -65440,7 +66919,7 @@ async function handleHttp(req, res, opts) {
|
|
|
65440
66919
|
|
|
65441
66920
|
// src/terminal/manager.ts
|
|
65442
66921
|
import { createRequire as createRequire2 } from "node:module";
|
|
65443
|
-
import { existsSync as
|
|
66922
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
65444
66923
|
var nodeRequire = createRequire2(import.meta.url);
|
|
65445
66924
|
var { spawn: spawn5 } = nodeRequire("node-pty");
|
|
65446
66925
|
var SNAPSHOT_SOFT_LIMIT = 64 * 1024;
|
|
@@ -65455,7 +66934,7 @@ var NodeTerminalManager = class {
|
|
|
65455
66934
|
}
|
|
65456
66935
|
byId = /* @__PURE__ */ new Map();
|
|
65457
66936
|
create(opts) {
|
|
65458
|
-
if (!
|
|
66937
|
+
if (!existsSync32(opts.cwd)) {
|
|
65459
66938
|
throw Object.assign(new Error(`cwd does not exist: ${opts.cwd}`), { code: "invalid_argument" });
|
|
65460
66939
|
}
|
|
65461
66940
|
const terminalId = crypto.randomUUID();
|
|
@@ -65596,8 +67075,8 @@ var NodeTerminalManager = class {
|
|
|
65596
67075
|
|
|
65597
67076
|
// src/workspace/project-registry.ts
|
|
65598
67077
|
import { basename as basename2, resolve as resolve8 } from "node:path";
|
|
65599
|
-
import { existsSync as
|
|
65600
|
-
import { createHash as
|
|
67078
|
+
import { existsSync as existsSync33, realpathSync as realpathSync4, statSync as statSync12 } from "node:fs";
|
|
67079
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
65601
67080
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
65602
67081
|
var ProjectRegistry = class {
|
|
65603
67082
|
constructor(db) {
|
|
@@ -65626,7 +67105,7 @@ var ProjectRegistry = class {
|
|
|
65626
67105
|
}
|
|
65627
67106
|
open(path, name) {
|
|
65628
67107
|
let abs = resolve8(path);
|
|
65629
|
-
if (!
|
|
67108
|
+
if (!existsSync33(abs) || !statSync12(abs).isDirectory()) {
|
|
65630
67109
|
throw Object.assign(new Error(`project path is not a directory: ${abs}`), {
|
|
65631
67110
|
code: "invalid_argument"
|
|
65632
67111
|
});
|
|
@@ -65641,7 +67120,7 @@ var ProjectRegistry = class {
|
|
|
65641
67120
|
this.db.prepare(`UPDATE projects SET last_active_at = ?, name = COALESCE(?, name) WHERE project_id = ?`).run(now, name ?? null, existing.projectId);
|
|
65642
67121
|
return this.get(existing.projectId);
|
|
65643
67122
|
}
|
|
65644
|
-
const projectId =
|
|
67123
|
+
const projectId = createHash6("sha256").update(abs).digest("hex").slice(0, 32);
|
|
65645
67124
|
const repoIdentity = detectRepoIdentity(abs);
|
|
65646
67125
|
this.db.prepare(
|
|
65647
67126
|
`INSERT INTO projects (project_id, path, name, repo_identity, opened_at, last_active_at)
|
|
@@ -65670,7 +67149,7 @@ var ProjectRegistry = class {
|
|
|
65670
67149
|
toSnapshot(r) {
|
|
65671
67150
|
let missing = false;
|
|
65672
67151
|
try {
|
|
65673
|
-
missing = !
|
|
67152
|
+
missing = !statSync12(r.path).isDirectory();
|
|
65674
67153
|
} catch {
|
|
65675
67154
|
missing = true;
|
|
65676
67155
|
}
|
|
@@ -65710,21 +67189,21 @@ function detectRepoIdentity(abs) {
|
|
|
65710
67189
|
init_fs();
|
|
65711
67190
|
import {
|
|
65712
67191
|
closeSync,
|
|
65713
|
-
existsSync as
|
|
67192
|
+
existsSync as existsSync34,
|
|
65714
67193
|
fstatSync,
|
|
65715
|
-
mkdirSync as
|
|
67194
|
+
mkdirSync as mkdirSync18,
|
|
65716
67195
|
openSync,
|
|
65717
67196
|
readSync,
|
|
65718
|
-
readdirSync as
|
|
65719
|
-
readFileSync as
|
|
65720
|
-
renameSync as
|
|
65721
|
-
rmSync as
|
|
65722
|
-
statSync as
|
|
67197
|
+
readdirSync as readdirSync11,
|
|
67198
|
+
readFileSync as readFileSync17,
|
|
67199
|
+
renameSync as renameSync5,
|
|
67200
|
+
rmSync as rmSync7,
|
|
67201
|
+
statSync as statSync13,
|
|
65723
67202
|
unlinkSync,
|
|
65724
|
-
writeFileSync as
|
|
67203
|
+
writeFileSync as writeFileSync14
|
|
65725
67204
|
} from "node:fs";
|
|
65726
|
-
import { dirname as
|
|
65727
|
-
import { createHash as
|
|
67205
|
+
import { dirname as dirname14, join as join24, relative as relative2 } from "node:path";
|
|
67206
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
65728
67207
|
function normalizeRel(path) {
|
|
65729
67208
|
return path.replace(/\\/g, "/").replace(/\/+$/, "") || ".";
|
|
65730
67209
|
}
|
|
@@ -65769,21 +67248,21 @@ var WorkspaceFsService = class {
|
|
|
65769
67248
|
if (!resolved.ok) {
|
|
65770
67249
|
throw Object.assign(new Error(resolved.reason), { code: "invalid_argument" });
|
|
65771
67250
|
}
|
|
65772
|
-
if (!
|
|
67251
|
+
if (!existsSync34(resolved.absolutePath)) {
|
|
65773
67252
|
throw Object.assign(new Error("path not found"), { code: "not_found" });
|
|
65774
67253
|
}
|
|
65775
|
-
const st =
|
|
67254
|
+
const st = statSync13(resolved.absolutePath);
|
|
65776
67255
|
if (!st.isDirectory()) {
|
|
65777
67256
|
throw Object.assign(new Error("not a directory"), { code: "invalid_argument" });
|
|
65778
67257
|
}
|
|
65779
67258
|
this.projects.touch(projectId);
|
|
65780
|
-
const ents =
|
|
67259
|
+
const ents = readdirSync11(resolved.absolutePath, { withFileTypes: true });
|
|
65781
67260
|
return ents.map((ent) => {
|
|
65782
|
-
const abs =
|
|
67261
|
+
const abs = join24(resolved.absolutePath, ent.name);
|
|
65783
67262
|
let size;
|
|
65784
67263
|
let mtimeMs;
|
|
65785
67264
|
try {
|
|
65786
|
-
const s2 =
|
|
67265
|
+
const s2 = statSync13(abs);
|
|
65787
67266
|
size = s2.size;
|
|
65788
67267
|
mtimeMs = s2.mtimeMs;
|
|
65789
67268
|
} catch {
|
|
@@ -65804,10 +67283,10 @@ var WorkspaceFsService = class {
|
|
|
65804
67283
|
if (!resolved.ok) {
|
|
65805
67284
|
throw Object.assign(new Error(resolved.reason), { code: "invalid_argument" });
|
|
65806
67285
|
}
|
|
65807
|
-
if (!
|
|
67286
|
+
if (!existsSync34(resolved.absolutePath)) {
|
|
65808
67287
|
throw Object.assign(new Error("file not found"), { code: "not_found" });
|
|
65809
67288
|
}
|
|
65810
|
-
const st =
|
|
67289
|
+
const st = statSync13(resolved.absolutePath);
|
|
65811
67290
|
if (!st.isFile()) {
|
|
65812
67291
|
throw Object.assign(new Error("not a file"), { code: "invalid_argument" });
|
|
65813
67292
|
}
|
|
@@ -65830,7 +67309,7 @@ var WorkspaceFsService = class {
|
|
|
65830
67309
|
const slice = Buffer.alloc(toRead);
|
|
65831
67310
|
if (toRead > 0) readSync(fd, slice, 0, toRead, offset);
|
|
65832
67311
|
const content = slice.toString("base64");
|
|
65833
|
-
const hash2 =
|
|
67312
|
+
const hash2 = createHash7("sha256").update(slice).digest("hex");
|
|
65834
67313
|
this.projects.touch(projectId);
|
|
65835
67314
|
return { content, hash: hash2, encoding: "base64" };
|
|
65836
67315
|
} finally {
|
|
@@ -65843,8 +67322,8 @@ var WorkspaceFsService = class {
|
|
|
65843
67322
|
if (!resolved.ok) {
|
|
65844
67323
|
throw Object.assign(new Error(resolved.reason), { code: "invalid_argument" });
|
|
65845
67324
|
}
|
|
65846
|
-
if (
|
|
65847
|
-
const st =
|
|
67325
|
+
if (existsSync34(resolved.absolutePath) && expectedHash) {
|
|
67326
|
+
const st = statSync13(resolved.absolutePath);
|
|
65848
67327
|
if (st.size > MAX_READ_BYTES) {
|
|
65849
67328
|
throw Object.assign(
|
|
65850
67329
|
new Error(`optimistic-write target too large (${st.size} bytes; max ${MAX_READ_BYTES})`),
|
|
@@ -65856,27 +67335,27 @@ var WorkspaceFsService = class {
|
|
|
65856
67335
|
throw Object.assign(new Error("content hash mismatch"), { code: "conflict" });
|
|
65857
67336
|
}
|
|
65858
67337
|
}
|
|
65859
|
-
|
|
67338
|
+
mkdirSync18(dirname14(resolved.absolutePath), { recursive: true });
|
|
65860
67339
|
const data = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
|
|
65861
67340
|
if (data.length > MAX_READ_BYTES) {
|
|
65862
67341
|
throw Object.assign(new Error("write payload too large"), { code: "invalid_argument" });
|
|
65863
67342
|
}
|
|
65864
67343
|
let mode = 384;
|
|
65865
|
-
if (
|
|
67344
|
+
if (existsSync34(resolved.absolutePath)) {
|
|
65866
67345
|
try {
|
|
65867
|
-
mode =
|
|
67346
|
+
mode = statSync13(resolved.absolutePath).mode & 511;
|
|
65868
67347
|
} catch {
|
|
65869
67348
|
}
|
|
65870
67349
|
}
|
|
65871
67350
|
const tmp = `${resolved.absolutePath}.tmp-${crypto.randomUUID()}`;
|
|
65872
67351
|
let renamed = false;
|
|
65873
67352
|
try {
|
|
65874
|
-
|
|
67353
|
+
writeFileSync14(tmp, data, { mode });
|
|
65875
67354
|
const again = resolveProjectPath(root, relativePath);
|
|
65876
67355
|
if (!again.ok || again.absolutePath !== resolved.absolutePath) {
|
|
65877
67356
|
throw Object.assign(new Error("path changed during write"), { code: "failed_precondition" });
|
|
65878
67357
|
}
|
|
65879
|
-
|
|
67358
|
+
renameSync5(tmp, resolved.absolutePath);
|
|
65880
67359
|
renamed = true;
|
|
65881
67360
|
} finally {
|
|
65882
67361
|
if (!renamed) {
|
|
@@ -65886,7 +67365,7 @@ var WorkspaceFsService = class {
|
|
|
65886
67365
|
}
|
|
65887
67366
|
}
|
|
65888
67367
|
}
|
|
65889
|
-
const hash2 =
|
|
67368
|
+
const hash2 = createHash7("sha256").update(data).digest("hex");
|
|
65890
67369
|
this.projects.touch(projectId);
|
|
65891
67370
|
return { hash: hash2 };
|
|
65892
67371
|
}
|
|
@@ -65925,14 +67404,14 @@ var WorkspaceFsService = class {
|
|
|
65925
67404
|
if (hits.length >= MAX_SEARCH_HITS) return;
|
|
65926
67405
|
let ents;
|
|
65927
67406
|
try {
|
|
65928
|
-
ents =
|
|
67407
|
+
ents = readdirSync11(dir, { withFileTypes: true });
|
|
65929
67408
|
} catch {
|
|
65930
67409
|
return;
|
|
65931
67410
|
}
|
|
65932
67411
|
for (const ent of ents) {
|
|
65933
67412
|
if (hits.length >= MAX_SEARCH_HITS) return;
|
|
65934
67413
|
if (ent.name === ".git" || ent.name === "node_modules") continue;
|
|
65935
|
-
const abs =
|
|
67414
|
+
const abs = join24(dir, ent.name);
|
|
65936
67415
|
const rel = relative2(root, abs).split("\\").join("/");
|
|
65937
67416
|
const check2 = resolveProjectPath(root, rel);
|
|
65938
67417
|
if (!check2.ok) continue;
|
|
@@ -65942,9 +67421,9 @@ var WorkspaceFsService = class {
|
|
|
65942
67421
|
}
|
|
65943
67422
|
if (!ent.isFile()) continue;
|
|
65944
67423
|
try {
|
|
65945
|
-
const st =
|
|
67424
|
+
const st = statSync13(abs);
|
|
65946
67425
|
if (st.size > MAX_SEARCH_FILE_BYTES) continue;
|
|
65947
|
-
const text =
|
|
67426
|
+
const text = readFileSync17(abs, "utf8");
|
|
65948
67427
|
const lines = text.split(/\r?\n/);
|
|
65949
67428
|
for (let i = 0; i < lines.length; i++) {
|
|
65950
67429
|
if (lines[i].includes(query)) {
|
|
@@ -66006,15 +67485,15 @@ var WorkspaceFsService = class {
|
|
|
66006
67485
|
if (!resolved.ok) {
|
|
66007
67486
|
throw Object.assign(new Error(resolved.reason), { code: "invalid_argument" });
|
|
66008
67487
|
}
|
|
66009
|
-
if (
|
|
66010
|
-
const st =
|
|
67488
|
+
if (existsSync34(resolved.absolutePath)) {
|
|
67489
|
+
const st = statSync13(resolved.absolutePath);
|
|
66011
67490
|
if (!st.isDirectory()) {
|
|
66012
67491
|
throw Object.assign(new Error("path exists and is not a directory"), { code: "conflict" });
|
|
66013
67492
|
}
|
|
66014
67493
|
this.projects.touch(projectId);
|
|
66015
67494
|
return { path: rel };
|
|
66016
67495
|
}
|
|
66017
|
-
|
|
67496
|
+
mkdirSync18(resolved.absolutePath, { recursive: true });
|
|
66018
67497
|
this.projects.touch(projectId);
|
|
66019
67498
|
return { path: rel };
|
|
66020
67499
|
}
|
|
@@ -66029,13 +67508,13 @@ var WorkspaceFsService = class {
|
|
|
66029
67508
|
if (!resolved.ok) {
|
|
66030
67509
|
throw Object.assign(new Error(resolved.reason), { code: "invalid_argument" });
|
|
66031
67510
|
}
|
|
66032
|
-
if (!
|
|
67511
|
+
if (!existsSync34(resolved.absolutePath)) {
|
|
66033
67512
|
throw Object.assign(new Error("path not found"), { code: "not_found" });
|
|
66034
67513
|
}
|
|
66035
67514
|
if (resolved.absolutePath === root) {
|
|
66036
67515
|
throw Object.assign(new Error("cannot delete project root"), { code: "invalid_argument" });
|
|
66037
67516
|
}
|
|
66038
|
-
|
|
67517
|
+
rmSync7(resolved.absolutePath, { recursive: true, force: false });
|
|
66039
67518
|
this.projects.touch(projectId);
|
|
66040
67519
|
return { path: rel };
|
|
66041
67520
|
}
|
|
@@ -66053,20 +67532,20 @@ var WorkspaceFsService = class {
|
|
|
66053
67532
|
if (!from.ok) {
|
|
66054
67533
|
throw Object.assign(new Error(from.reason), { code: "invalid_argument" });
|
|
66055
67534
|
}
|
|
66056
|
-
if (!
|
|
67535
|
+
if (!existsSync34(from.absolutePath)) {
|
|
66057
67536
|
throw Object.assign(new Error("source not found"), { code: "not_found" });
|
|
66058
67537
|
}
|
|
66059
67538
|
const to = resolveProjectPath(root, toN);
|
|
66060
67539
|
if (!to.ok) {
|
|
66061
67540
|
throw Object.assign(new Error(to.reason), { code: "invalid_argument" });
|
|
66062
67541
|
}
|
|
66063
|
-
if (
|
|
67542
|
+
if (existsSync34(to.absolutePath)) {
|
|
66064
67543
|
throw Object.assign(new Error(`target already exists: ${baseNameRel(toN)}`), {
|
|
66065
67544
|
code: "conflict"
|
|
66066
67545
|
});
|
|
66067
67546
|
}
|
|
66068
|
-
|
|
66069
|
-
|
|
67547
|
+
mkdirSync18(dirname14(to.absolutePath), { recursive: true });
|
|
67548
|
+
renameSync5(from.absolutePath, to.absolutePath);
|
|
66070
67549
|
this.projects.touch(projectId);
|
|
66071
67550
|
return { from: fromN, to: toN };
|
|
66072
67551
|
}
|
|
@@ -66074,7 +67553,7 @@ var WorkspaceFsService = class {
|
|
|
66074
67553
|
function hashFileBounded(absolutePath, size) {
|
|
66075
67554
|
const fd = openSync(absolutePath, "r");
|
|
66076
67555
|
try {
|
|
66077
|
-
const hash2 =
|
|
67556
|
+
const hash2 = createHash7("sha256");
|
|
66078
67557
|
const buf = Buffer.alloc(Math.min(64 * 1024, Math.max(1, size)));
|
|
66079
67558
|
let offset = 0;
|
|
66080
67559
|
while (offset < size) {
|
|
@@ -66090,9 +67569,9 @@ function hashFileBounded(absolutePath, size) {
|
|
|
66090
67569
|
}
|
|
66091
67570
|
|
|
66092
67571
|
// src/workspace/git-service.ts
|
|
66093
|
-
import { existsSync as
|
|
66094
|
-
import { join as
|
|
66095
|
-
import { tmpdir as
|
|
67572
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync19, realpathSync as realpathSync5, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "node:fs";
|
|
67573
|
+
import { join as join26, resolve as resolve10 } from "node:path";
|
|
67574
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
66096
67575
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
66097
67576
|
|
|
66098
67577
|
// ../../packages/runtime/src/git/sanitize-ref.ts
|
|
@@ -66144,126 +67623,8 @@ function parseWorktreePorcelain(out) {
|
|
|
66144
67623
|
}
|
|
66145
67624
|
|
|
66146
67625
|
// ../../packages/runtime/src/git/run.ts
|
|
67626
|
+
init_spawn_env();
|
|
66147
67627
|
import { execFile as execFile3, execFileSync as execFileSync3 } from "child_process";
|
|
66148
|
-
|
|
66149
|
-
// ../../packages/runtime/src/spawn-env.ts
|
|
66150
|
-
var SPAWN_PATH_MAX = 1024;
|
|
66151
|
-
var SPAWN_NAME_MAX = 255;
|
|
66152
|
-
var MAX_ENV_BYTES = 256 * 1024;
|
|
66153
|
-
var ESSENTIAL_EXACT = /* @__PURE__ */ new Set([
|
|
66154
|
-
"PATH",
|
|
66155
|
-
"HOME",
|
|
66156
|
-
"USER",
|
|
66157
|
-
"LOGNAME",
|
|
66158
|
-
"SHELL",
|
|
66159
|
-
"TERM",
|
|
66160
|
-
"LANG",
|
|
66161
|
-
"LC_ALL",
|
|
66162
|
-
"LC_CTYPE",
|
|
66163
|
-
"DISPLAY",
|
|
66164
|
-
"TMPDIR",
|
|
66165
|
-
"TEMP",
|
|
66166
|
-
"TMP",
|
|
66167
|
-
"DYLD_FRAMEWORK_PATH",
|
|
66168
|
-
"DYLD_LIBRARY_PATH",
|
|
66169
|
-
"DYLD_FALLBACK_FRAMEWORK_PATH",
|
|
66170
|
-
"DYLD_FALLBACK_LIBRARY_PATH"
|
|
66171
|
-
]);
|
|
66172
|
-
var ESSENTIAL_PREFIXES = [
|
|
66173
|
-
"LC_",
|
|
66174
|
-
"ELECTRON_",
|
|
66175
|
-
"ANTHROPIC_",
|
|
66176
|
-
"CODEX_",
|
|
66177
|
-
"NPM_CONFIG_",
|
|
66178
|
-
"NODE_",
|
|
66179
|
-
"SSH_",
|
|
66180
|
-
"GIT_"
|
|
66181
|
-
];
|
|
66182
|
-
function isEssentialEnv(key) {
|
|
66183
|
-
if (ESSENTIAL_EXACT.has(key)) return true;
|
|
66184
|
-
return ESSENTIAL_PREFIXES.some((p2) => key.startsWith(p2));
|
|
66185
|
-
}
|
|
66186
|
-
function sanitizePathEnv(pathEnv) {
|
|
66187
|
-
const seen = /* @__PURE__ */ new Set();
|
|
66188
|
-
const out = [];
|
|
66189
|
-
let dropped = 0;
|
|
66190
|
-
let deduped = 0;
|
|
66191
|
-
let droppedByPathMax = 0;
|
|
66192
|
-
let droppedByNameMax = 0;
|
|
66193
|
-
for (const entry of pathEnv.split(":")) {
|
|
66194
|
-
if (!entry) continue;
|
|
66195
|
-
if (seen.has(entry)) {
|
|
66196
|
-
deduped++;
|
|
66197
|
-
continue;
|
|
66198
|
-
}
|
|
66199
|
-
seen.add(entry);
|
|
66200
|
-
if (entry.length > SPAWN_PATH_MAX) {
|
|
66201
|
-
dropped++;
|
|
66202
|
-
droppedByPathMax++;
|
|
66203
|
-
continue;
|
|
66204
|
-
}
|
|
66205
|
-
if (entry.split("/").some((comp) => Buffer.byteLength(comp, "utf8") > SPAWN_NAME_MAX)) {
|
|
66206
|
-
dropped++;
|
|
66207
|
-
droppedByNameMax++;
|
|
66208
|
-
continue;
|
|
66209
|
-
}
|
|
66210
|
-
out.push(entry);
|
|
66211
|
-
}
|
|
66212
|
-
return { value: out.join(":"), dropped, deduped, droppedByPathMax, droppedByNameMax };
|
|
66213
|
-
}
|
|
66214
|
-
function serializedSize(env) {
|
|
66215
|
-
let n = 0;
|
|
66216
|
-
for (const key in env) {
|
|
66217
|
-
n += Buffer.byteLength(key) + Buffer.byteLength(env[key]) + 2;
|
|
66218
|
-
}
|
|
66219
|
-
return n;
|
|
66220
|
-
}
|
|
66221
|
-
function sanitizeEnv(base = process.env, extra) {
|
|
66222
|
-
const merged = {};
|
|
66223
|
-
for (const key in base) {
|
|
66224
|
-
const v2 = base[key];
|
|
66225
|
-
if (v2 !== void 0) merged[key] = v2;
|
|
66226
|
-
}
|
|
66227
|
-
if (extra) {
|
|
66228
|
-
for (const key in extra) {
|
|
66229
|
-
const v2 = extra[key];
|
|
66230
|
-
if (v2 !== void 0) merged[key] = v2;
|
|
66231
|
-
}
|
|
66232
|
-
}
|
|
66233
|
-
if (process.platform !== "win32" && typeof merged.PATH === "string") {
|
|
66234
|
-
const res = sanitizePathEnv(merged.PATH);
|
|
66235
|
-
merged.PATH = res.value;
|
|
66236
|
-
if (res.dropped > 0) {
|
|
66237
|
-
const parts = [];
|
|
66238
|
-
if (res.droppedByPathMax > 0)
|
|
66239
|
-
parts.push(`${res.droppedByPathMax} \u6574\u6BB5 > PATH_MAX(${SPAWN_PATH_MAX}B)`);
|
|
66240
|
-
if (res.droppedByNameMax > 0)
|
|
66241
|
-
parts.push(`${res.droppedByNameMax} \u6BB5\u542B > NAME_MAX(${SPAWN_NAME_MAX}B) \u7684\u76EE\u5F55\u540D`);
|
|
66242
|
-
console.warn(`[spawn-env] \u4E3A\u89C4\u907F spawn ENAMETOOLONG \u5DF2\u4E22\u5F03 ${res.dropped} \u4E2A\u8D85\u957F PATH \u5206\u6BB5\uFF08${parts.join("\uFF1B")}\uFF09`);
|
|
66243
|
-
}
|
|
66244
|
-
}
|
|
66245
|
-
let size = serializedSize(merged);
|
|
66246
|
-
if (size > MAX_ENV_BYTES) {
|
|
66247
|
-
const entries = Object.entries(merged).sort((a, b2) => b2[1].length - a[1].length);
|
|
66248
|
-
for (const [key, value] of entries) {
|
|
66249
|
-
if (size <= MAX_ENV_BYTES) break;
|
|
66250
|
-
if (isEssentialEnv(key)) continue;
|
|
66251
|
-
size -= Buffer.byteLength(key) + Buffer.byteLength(value) + 2;
|
|
66252
|
-
delete merged[key];
|
|
66253
|
-
}
|
|
66254
|
-
if (size > MAX_ENV_BYTES) {
|
|
66255
|
-
console.warn(`[spawn-env] env still ${size} bytes after trimming non-essential vars (limit ${MAX_ENV_BYTES})`);
|
|
66256
|
-
} else {
|
|
66257
|
-
console.warn(`[spawn-env] trimmed env to ${size} bytes to avoid spawn E2BIG`);
|
|
66258
|
-
}
|
|
66259
|
-
}
|
|
66260
|
-
return merged;
|
|
66261
|
-
}
|
|
66262
|
-
function buildSafeEnv(extra) {
|
|
66263
|
-
return sanitizeEnv(process.env, extra);
|
|
66264
|
-
}
|
|
66265
|
-
|
|
66266
|
-
// ../../packages/runtime/src/git/run.ts
|
|
66267
67628
|
var GIT_MAX_BUFFER = 64 * 1024 * 1024;
|
|
66268
67629
|
var NO_OPTIONAL_LOCKS = "--no-optional-locks";
|
|
66269
67630
|
function gitRunSync(folderPath, args, env) {
|
|
@@ -66286,19 +67647,19 @@ function gitRunSync(folderPath, args, env) {
|
|
|
66286
67647
|
}
|
|
66287
67648
|
|
|
66288
67649
|
// ../../packages/runtime/src/git/worktree-plan.ts
|
|
66289
|
-
import { basename as basename3, dirname as
|
|
66290
|
-
import { homedir as
|
|
67650
|
+
import { basename as basename3, dirname as dirname15, join as join25, resolve as resolve9, sep as sep4 } from "node:path";
|
|
67651
|
+
import { homedir as homedir8 } from "node:os";
|
|
66291
67652
|
function resolveMainDirFromCommonDir(folderPath, gitCommonDir) {
|
|
66292
67653
|
const repoRoot = resolve9(folderPath, gitCommonDir.trim());
|
|
66293
|
-
return repoRoot.endsWith(`${sep4}.git`) || repoRoot.endsWith("/.git") ?
|
|
67654
|
+
return repoRoot.endsWith(`${sep4}.git`) || repoRoot.endsWith("/.git") ? dirname15(repoRoot) : repoRoot;
|
|
66294
67655
|
}
|
|
66295
67656
|
function planNewWorktreePaths(input) {
|
|
66296
|
-
const home = input.homeDir ??
|
|
67657
|
+
const home = input.homeDir ?? homedir8();
|
|
66297
67658
|
const repoName = basename3(input.mainDir);
|
|
66298
67659
|
const epoch = Math.floor((input.nowMs ?? Date.now()) / 1e3).toString(36);
|
|
66299
67660
|
const short = input.shortHash.slice(0, 7);
|
|
66300
|
-
const wtDir =
|
|
66301
|
-
const wtPath =
|
|
67661
|
+
const wtDir = join25(home, ".worktrees", repoName);
|
|
67662
|
+
const wtPath = join25(wtDir, `${epoch}-${short}`);
|
|
66302
67663
|
return { wtDir, wtPath };
|
|
66303
67664
|
}
|
|
66304
67665
|
function worktreeAddArgs(mode, wtPath, baseRef, branchName) {
|
|
@@ -66357,8 +67718,8 @@ function resolveMainWorktreeDir(folderPath) {
|
|
|
66357
67718
|
}
|
|
66358
67719
|
function samePath(a, b2) {
|
|
66359
67720
|
try {
|
|
66360
|
-
const ra =
|
|
66361
|
-
const rb =
|
|
67721
|
+
const ra = existsSync35(a) ? realpathSync5(a) : resolve10(a);
|
|
67722
|
+
const rb = existsSync35(b2) ? realpathSync5(b2) : resolve10(b2);
|
|
66362
67723
|
return ra === rb;
|
|
66363
67724
|
} catch {
|
|
66364
67725
|
return resolve10(a) === resolve10(b2);
|
|
@@ -66390,7 +67751,7 @@ var WorkspaceGitService = class {
|
|
|
66390
67751
|
* --ignored walks the whole tree of ignored paths and dominates remote latency.
|
|
66391
67752
|
*/
|
|
66392
67753
|
statusForCwd(cwd) {
|
|
66393
|
-
if (!
|
|
67754
|
+
if (!existsSync35(join26(cwd, ".git")) && !isGitWorktree(cwd)) {
|
|
66394
67755
|
return { isRepo: false, branch: null, dirty: false, ahead: 0, behind: 0, porcelain: "" };
|
|
66395
67756
|
}
|
|
66396
67757
|
try {
|
|
@@ -66499,15 +67860,15 @@ var WorkspaceGitService = class {
|
|
|
66499
67860
|
}
|
|
66500
67861
|
const abs = resolve10(worktreePath);
|
|
66501
67862
|
const main2 = resolve10(this.root(projectId));
|
|
66502
|
-
if (samePath(abs, main2)) return
|
|
67863
|
+
if (samePath(abs, main2)) return existsSync35(abs) ? realpathSync5(abs) : abs;
|
|
66503
67864
|
const listed = this.worktrees(projectId);
|
|
66504
67865
|
for (const wt of listed) {
|
|
66505
67866
|
if (samePath(abs, wt.path)) {
|
|
66506
|
-
return
|
|
67867
|
+
return existsSync35(abs) ? realpathSync5(abs) : resolve10(wt.path);
|
|
66507
67868
|
}
|
|
66508
67869
|
}
|
|
66509
67870
|
try {
|
|
66510
|
-
if (
|
|
67871
|
+
if (existsSync35(abs) && isGitWorktree(abs)) {
|
|
66511
67872
|
const commonA = resolve10(abs, git(abs, ["rev-parse", "--git-common-dir"]).trim());
|
|
66512
67873
|
const commonB = resolve10(main2, git(main2, ["rev-parse", "--git-common-dir"]).trim());
|
|
66513
67874
|
if (samePath(commonA, commonB)) {
|
|
@@ -66549,7 +67910,7 @@ var WorkspaceGitService = class {
|
|
|
66549
67910
|
mainDir,
|
|
66550
67911
|
shortHash: commitHash.slice(0, 7)
|
|
66551
67912
|
});
|
|
66552
|
-
if (!
|
|
67913
|
+
if (!existsSync35(wtDir)) mkdirSync19(wtDir, { recursive: true });
|
|
66553
67914
|
try {
|
|
66554
67915
|
const addArgs = worktreeAddArgs(mode, wtPath, baseBranch, safeBranchName);
|
|
66555
67916
|
git(folderPath, ["worktree", ...addArgs]);
|
|
@@ -66645,11 +68006,11 @@ var WorkspaceGitService = class {
|
|
|
66645
68006
|
const mainStatus = git(diff.mainDir, ["status", "--porcelain"]).trim();
|
|
66646
68007
|
if (mainStatus) return { ok: false, reason: "main-dirty" };
|
|
66647
68008
|
const patch = git(diff.worktreePath, ["diff", "--binary", diff.base, diff.tree]);
|
|
66648
|
-
const patchFile =
|
|
66649
|
-
|
|
68009
|
+
const patchFile = join26(tmpdir3(), `s1-handoff-${randomUUID8()}.patch`);
|
|
68010
|
+
writeFileSync15(patchFile, `${patch}
|
|
66650
68011
|
`);
|
|
66651
68012
|
if (git(diff.mainDir, ["status", "--porcelain"]).trim()) {
|
|
66652
|
-
|
|
68013
|
+
rmSync8(patchFile, { force: true });
|
|
66653
68014
|
return { ok: false, reason: "main-dirty" };
|
|
66654
68015
|
}
|
|
66655
68016
|
try {
|
|
@@ -66662,7 +68023,7 @@ var WorkspaceGitService = class {
|
|
|
66662
68023
|
}
|
|
66663
68024
|
return { ok: false, reason: "conflict", error: gitErrorMessage(err) };
|
|
66664
68025
|
} finally {
|
|
66665
|
-
|
|
68026
|
+
rmSync8(patchFile, { force: true });
|
|
66666
68027
|
}
|
|
66667
68028
|
try {
|
|
66668
68029
|
git(diff.mainDir, ["reset", "--quiet"]);
|
|
@@ -66707,14 +68068,14 @@ var WorkspaceGitService = class {
|
|
|
66707
68068
|
};
|
|
66708
68069
|
}
|
|
66709
68070
|
writeWorkingTree(worktreePath) {
|
|
66710
|
-
const tmpIndex =
|
|
68071
|
+
const tmpIndex = join26(tmpdir3(), `s1-handoff-${randomUUID8()}.index`);
|
|
66711
68072
|
const env = { GIT_INDEX_FILE: tmpIndex };
|
|
66712
68073
|
try {
|
|
66713
68074
|
git(worktreePath, ["read-tree", "HEAD"], env);
|
|
66714
68075
|
git(worktreePath, ["add", "-A"], env);
|
|
66715
68076
|
return git(worktreePath, ["write-tree"], env).trim();
|
|
66716
68077
|
} finally {
|
|
66717
|
-
|
|
68078
|
+
rmSync8(tmpIndex, { force: true });
|
|
66718
68079
|
}
|
|
66719
68080
|
}
|
|
66720
68081
|
repoIdentity(projectId) {
|
|
@@ -66899,245 +68260,17 @@ var SessionRuntime2 = class extends SessionRuntime {
|
|
|
66899
68260
|
init_harness_runners();
|
|
66900
68261
|
init_codex_turn_runner();
|
|
66901
68262
|
|
|
66902
|
-
// src/session/harness-manager.ts
|
|
66903
|
-
init_environment();
|
|
66904
|
-
var HarnessManager = class {
|
|
66905
|
-
constructor(db) {
|
|
66906
|
-
this.db = db;
|
|
66907
|
-
this.ensureRows();
|
|
66908
|
-
this.clearSimulatedContamination();
|
|
66909
|
-
}
|
|
66910
|
-
/**
|
|
66911
|
-
* When true, list/get/ready behave as if every harness is enabled+ready.
|
|
66912
|
-
* Never persisted — only for contract/CI simulated runners.
|
|
66913
|
-
*/
|
|
66914
|
-
simulatedOverlay = false;
|
|
66915
|
-
/** Ensure one row per first-party definition. */
|
|
66916
|
-
ensureRows() {
|
|
66917
|
-
const now = Date.now();
|
|
66918
|
-
const insert = this.db.prepare(
|
|
66919
|
-
`INSERT OR IGNORE INTO harness_installations
|
|
66920
|
-
(harness_id, enabled, state, runtime_version, command, config_json, secret_ref,
|
|
66921
|
-
diagnostic_code, diagnostic_message, last_probed_at, updated_at)
|
|
66922
|
-
VALUES (?, 0, 'disabled', NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?)`
|
|
66923
|
-
);
|
|
66924
|
-
const tx = this.db.transaction(() => {
|
|
66925
|
-
for (const def of NODE_HARNESS_DEFINITIONS) {
|
|
66926
|
-
insert.run(def.id, now);
|
|
66927
|
-
}
|
|
66928
|
-
});
|
|
66929
|
-
tx();
|
|
66930
|
-
}
|
|
66931
|
-
/**
|
|
66932
|
-
* Reset durable rows that older builds may have marked as simulated-ready.
|
|
66933
|
-
* Safe to run on every open: only touches synthetic simulated provenance.
|
|
66934
|
-
*/
|
|
66935
|
-
clearSimulatedContamination() {
|
|
66936
|
-
const now = Date.now();
|
|
66937
|
-
this.db.prepare(
|
|
66938
|
-
`UPDATE harness_installations SET
|
|
66939
|
-
enabled = 0,
|
|
66940
|
-
state = 'disabled',
|
|
66941
|
-
runtime_version = NULL,
|
|
66942
|
-
command = NULL,
|
|
66943
|
-
diagnostic_code = NULL,
|
|
66944
|
-
diagnostic_message = NULL,
|
|
66945
|
-
last_probed_at = NULL,
|
|
66946
|
-
updated_at = ?
|
|
66947
|
-
WHERE runtime_version = 'simulated'
|
|
66948
|
-
OR diagnostic_code = 'simulated'`
|
|
66949
|
-
).run(now);
|
|
66950
|
-
}
|
|
66951
|
-
/**
|
|
66952
|
-
* Enable in-memory simulated readiness for all first-party harnesses.
|
|
66953
|
-
* Does not write the database. Production starts must never call this.
|
|
66954
|
-
*/
|
|
66955
|
-
enableSimulatedOverlay() {
|
|
66956
|
-
this.simulatedOverlay = true;
|
|
66957
|
-
}
|
|
66958
|
-
/** @deprecated use enableSimulatedOverlay — kept as alias for call-site clarity. */
|
|
66959
|
-
markAllSimulatedReady() {
|
|
66960
|
-
this.enableSimulatedOverlay();
|
|
66961
|
-
}
|
|
66962
|
-
list() {
|
|
66963
|
-
return NODE_HARNESS_DEFINITIONS.map((d) => this.get(d.id));
|
|
66964
|
-
}
|
|
66965
|
-
get(id) {
|
|
66966
|
-
const status = this.readPersisted(id);
|
|
66967
|
-
if (!this.simulatedOverlay) return status;
|
|
66968
|
-
return {
|
|
66969
|
-
...status,
|
|
66970
|
-
enabled: true,
|
|
66971
|
-
state: "ready",
|
|
66972
|
-
runtimeVersion: status.runtimeVersion ?? "simulated",
|
|
66973
|
-
diagnostic: buildHarnessDiagnostic("simulated")
|
|
66974
|
-
};
|
|
66975
|
-
}
|
|
66976
|
-
readPersisted(id) {
|
|
66977
|
-
const row = this.db.prepare(
|
|
66978
|
-
`SELECT harness_id, enabled, state, runtime_version, command,
|
|
66979
|
-
diagnostic_code, diagnostic_message
|
|
66980
|
-
FROM harness_installations WHERE harness_id = ?`
|
|
66981
|
-
).get(id);
|
|
66982
|
-
if (!row) {
|
|
66983
|
-
return defaultHarnessInstallationStatus(id);
|
|
66984
|
-
}
|
|
66985
|
-
const def = NODE_HARNESS_DEFINITIONS.find((d) => d.id === id);
|
|
66986
|
-
const status = {
|
|
66987
|
-
id,
|
|
66988
|
-
runtimeSource: def.runtimeSource,
|
|
66989
|
-
enabled: row.enabled === 1,
|
|
66990
|
-
state: parseState(row.state),
|
|
66991
|
-
requiresAuth: def.requiresAuth
|
|
66992
|
-
};
|
|
66993
|
-
if (row.runtime_version && row.runtime_version !== "simulated") {
|
|
66994
|
-
status.runtimeVersion = row.runtime_version;
|
|
66995
|
-
}
|
|
66996
|
-
const command = sanitizeHarnessCommand(row.command);
|
|
66997
|
-
if (command) status.command = command;
|
|
66998
|
-
const code = sanitizeHarnessDiagnosticCode(row.diagnostic_code);
|
|
66999
|
-
if (code && code !== "simulated") {
|
|
67000
|
-
status.diagnostic = buildHarnessDiagnostic(code, {
|
|
67001
|
-
runtimeVersion: status.runtimeVersion,
|
|
67002
|
-
command: status.command
|
|
67003
|
-
});
|
|
67004
|
-
}
|
|
67005
|
-
return status;
|
|
67006
|
-
}
|
|
67007
|
-
/**
|
|
67008
|
-
* Session wire harness ids that are currently runnable (enabled + ready).
|
|
67009
|
-
* Used by environment.descriptor capabilities.harnessIds.
|
|
67010
|
-
*/
|
|
67011
|
-
readySessionHarnessIds() {
|
|
67012
|
-
return readySessionHarnessIds(this.list());
|
|
67013
|
-
}
|
|
67014
|
-
/** Whether a session.create harnessId is allowed on this node. */
|
|
67015
|
-
isSessionHarnessRunnable(sessionHarnessId) {
|
|
67016
|
-
const wire = normalizeSessionHarnessId(sessionHarnessId);
|
|
67017
|
-
if (!wire) return false;
|
|
67018
|
-
const catalogId = wire === "acp" ? "acp-grok" : wire;
|
|
67019
|
-
if (!isNodeHarnessId(catalogId)) return false;
|
|
67020
|
-
return isHarnessRunnable(this.get(catalogId));
|
|
67021
|
-
}
|
|
67022
|
-
update(id, patch) {
|
|
67023
|
-
if (!isNodeHarnessId(id)) {
|
|
67024
|
-
throw new Error(`unknown harness: ${id}`);
|
|
67025
|
-
}
|
|
67026
|
-
const apply = this.db.transaction(() => {
|
|
67027
|
-
const current = this.readPersisted(id);
|
|
67028
|
-
const extra = this.db.prepare(
|
|
67029
|
-
`SELECT config_json, secret_ref, last_probed_at, diagnostic_code
|
|
67030
|
-
FROM harness_installations WHERE harness_id = ?`
|
|
67031
|
-
).get(id);
|
|
67032
|
-
const enabled = patch.enabled ?? current.enabled;
|
|
67033
|
-
const state = patch.state ?? current.state;
|
|
67034
|
-
const runtimeVersion = patch.runtimeVersion === null ? null : patch.runtimeVersion ?? current.runtimeVersion ?? null;
|
|
67035
|
-
let command;
|
|
67036
|
-
if (patch.command === null) {
|
|
67037
|
-
command = null;
|
|
67038
|
-
} else if (patch.command !== void 0) {
|
|
67039
|
-
command = sanitizeHarnessCommand(patch.command) ?? null;
|
|
67040
|
-
} else {
|
|
67041
|
-
command = current.command ?? null;
|
|
67042
|
-
}
|
|
67043
|
-
let diagnosticCode;
|
|
67044
|
-
if (patch.diagnosticCode === null) {
|
|
67045
|
-
diagnosticCode = null;
|
|
67046
|
-
} else if (patch.diagnosticCode !== void 0) {
|
|
67047
|
-
diagnosticCode = sanitizeHarnessDiagnosticCode(patch.diagnosticCode);
|
|
67048
|
-
} else {
|
|
67049
|
-
diagnosticCode = sanitizeHarnessDiagnosticCode(extra?.diagnostic_code);
|
|
67050
|
-
}
|
|
67051
|
-
let diagnosticMessage = null;
|
|
67052
|
-
if (diagnosticCode) {
|
|
67053
|
-
const fields = {
|
|
67054
|
-
...patch.diagnosticFields ?? {},
|
|
67055
|
-
runtimeVersion: runtimeVersion ?? void 0,
|
|
67056
|
-
command: command ?? void 0
|
|
67057
|
-
};
|
|
67058
|
-
diagnosticMessage = buildHarnessDiagnostic(
|
|
67059
|
-
diagnosticCode,
|
|
67060
|
-
fields
|
|
67061
|
-
).message;
|
|
67062
|
-
}
|
|
67063
|
-
const configJson = patch.configJson === null ? null : patch.configJson ?? extra?.config_json ?? null;
|
|
67064
|
-
const secretRef = patch.secretRef === null ? null : patch.secretRef ?? extra?.secret_ref ?? null;
|
|
67065
|
-
const lastProbedAt = patch.lastProbedAt === null ? null : patch.lastProbedAt ?? extra?.last_probed_at ?? null;
|
|
67066
|
-
const now = Date.now();
|
|
67067
|
-
this.db.prepare(
|
|
67068
|
-
`UPDATE harness_installations SET
|
|
67069
|
-
enabled = ?, state = ?, runtime_version = ?, command = ?,
|
|
67070
|
-
config_json = ?, secret_ref = ?,
|
|
67071
|
-
diagnostic_code = ?, diagnostic_message = ?,
|
|
67072
|
-
last_probed_at = ?, updated_at = ?
|
|
67073
|
-
WHERE harness_id = ?`
|
|
67074
|
-
).run(
|
|
67075
|
-
enabled ? 1 : 0,
|
|
67076
|
-
state,
|
|
67077
|
-
runtimeVersion,
|
|
67078
|
-
command,
|
|
67079
|
-
configJson,
|
|
67080
|
-
secretRef,
|
|
67081
|
-
diagnosticCode,
|
|
67082
|
-
diagnosticMessage,
|
|
67083
|
-
lastProbedAt,
|
|
67084
|
-
now,
|
|
67085
|
-
id
|
|
67086
|
-
);
|
|
67087
|
-
});
|
|
67088
|
-
apply();
|
|
67089
|
-
return this.get(id);
|
|
67090
|
-
}
|
|
67091
|
-
/**
|
|
67092
|
-
* Disable a harness. Does not delete managed artifacts or external binaries.
|
|
67093
|
-
* Default drain policy is enforced by higher-level CLI/RPC in a later slice.
|
|
67094
|
-
*/
|
|
67095
|
-
disable(id) {
|
|
67096
|
-
return this.update(id, {
|
|
67097
|
-
enabled: false,
|
|
67098
|
-
state: "disabled",
|
|
67099
|
-
diagnosticCode: null,
|
|
67100
|
-
diagnosticFields: null
|
|
67101
|
-
});
|
|
67102
|
-
}
|
|
67103
|
-
/**
|
|
67104
|
-
* Internal non-secret row fields for CLI show/doctor.
|
|
67105
|
-
* Does not expose secret_ref or stored diagnostic message text.
|
|
67106
|
-
*/
|
|
67107
|
-
readRawRow(id) {
|
|
67108
|
-
const row = this.db.prepare(
|
|
67109
|
-
`SELECT config_json, last_probed_at
|
|
67110
|
-
FROM harness_installations WHERE harness_id = ?`
|
|
67111
|
-
).get(id);
|
|
67112
|
-
return row ?? null;
|
|
67113
|
-
}
|
|
67114
|
-
};
|
|
67115
|
-
function parseState(raw) {
|
|
67116
|
-
switch (raw) {
|
|
67117
|
-
case "disabled":
|
|
67118
|
-
case "missing":
|
|
67119
|
-
case "installing":
|
|
67120
|
-
case "needs_auth":
|
|
67121
|
-
case "ready":
|
|
67122
|
-
case "incompatible":
|
|
67123
|
-
case "error":
|
|
67124
|
-
return raw;
|
|
67125
|
-
default:
|
|
67126
|
-
return "error";
|
|
67127
|
-
}
|
|
67128
|
-
}
|
|
67129
|
-
|
|
67130
68263
|
// src/session/collaboration.ts
|
|
67131
68264
|
init_agent_types();
|
|
67132
68265
|
init_environment();
|
|
67133
68266
|
init_resolve_service();
|
|
67134
|
-
import { createHash as
|
|
67135
|
-
import { existsSync as
|
|
68267
|
+
import { createHash as createHash8, randomBytes as randomBytes5, randomUUID as randomUUID10 } from "node:crypto";
|
|
68268
|
+
import { existsSync as existsSync36, statSync as statSync14 } from "node:fs";
|
|
67136
68269
|
import { resolve as pathResolve2 } from "node:path";
|
|
67137
68270
|
var MAX_MESSAGES_PER_RETRIEVE = 100;
|
|
67138
68271
|
var EMPTY_MAILBOX_HINT = "No peer has replied yet. Do not retrieve again, do not sleep, do not wait in place \u2014 end your turn or do unrelated work. A task notification will start a new turn for you as soon as a message arrives.";
|
|
67139
68272
|
function hashCredential(credential) {
|
|
67140
|
-
return
|
|
68273
|
+
return createHash8("sha256").update(credential).digest("hex");
|
|
67141
68274
|
}
|
|
67142
68275
|
function parseConfig(raw) {
|
|
67143
68276
|
try {
|
|
@@ -67275,7 +68408,10 @@ var CollaborationService = class {
|
|
|
67275
68408
|
if (!parent) {
|
|
67276
68409
|
throw Object.assign(new Error("Parent session is not available"), { code: "not_found" });
|
|
67277
68410
|
}
|
|
67278
|
-
const nested = this.deps.db.prepare(
|
|
68411
|
+
const nested = this.deps.db.prepare(
|
|
68412
|
+
`SELECT 1 FROM session_collaboration_grants
|
|
68413
|
+
WHERE child_session_id = ? AND COALESCE(kind, 'spawn') = 'spawn' LIMIT 1`
|
|
68414
|
+
).get(input.parentSessionId);
|
|
67279
68415
|
if (nested) {
|
|
67280
68416
|
throw Object.assign(
|
|
67281
68417
|
new Error(
|
|
@@ -67298,15 +68434,74 @@ var CollaborationService = class {
|
|
|
67298
68434
|
const profileList = this.listProfiles();
|
|
67299
68435
|
const profiles = new Map(profileList.map((p2) => [p2.id, p2]));
|
|
67300
68436
|
const normalized = launches.map((launch2) => {
|
|
67301
|
-
const
|
|
68437
|
+
const mode = launch2.mode === "link" ? "link" : "spawn";
|
|
68438
|
+
const launchId = launch2.launchId?.trim() || randomUUID10();
|
|
68439
|
+
if (mode === "link") {
|
|
68440
|
+
const peerSessionId = launch2.sessionId?.trim();
|
|
68441
|
+
if (!peerSessionId) {
|
|
68442
|
+
throw Object.assign(
|
|
68443
|
+
new Error("Link launches require sessionId of an existing SuperOne session"),
|
|
68444
|
+
{ code: "invalid_argument" }
|
|
68445
|
+
);
|
|
68446
|
+
}
|
|
68447
|
+
if (peerSessionId === input.parentSessionId) {
|
|
68448
|
+
throw Object.assign(new Error("Cannot link a session to itself"), {
|
|
68449
|
+
code: "invalid_argument"
|
|
68450
|
+
});
|
|
68451
|
+
}
|
|
68452
|
+
const peer = this.deps.sessions.get(peerSessionId);
|
|
68453
|
+
if (!peer) {
|
|
68454
|
+
throw Object.assign(new Error(`Unknown sessionId for link: ${peerSessionId}`), {
|
|
68455
|
+
code: "not_found"
|
|
68456
|
+
});
|
|
68457
|
+
}
|
|
68458
|
+
const summary2 = launch2.summary?.trim() || resolveLaunchSummary(launch2.task ?? "", launch2.summary);
|
|
68459
|
+
if (!summary2) {
|
|
68460
|
+
throw Object.assign(new Error("Every launch must include a non-empty summary"), {
|
|
68461
|
+
code: "invalid_argument"
|
|
68462
|
+
});
|
|
68463
|
+
}
|
|
68464
|
+
const task2 = (launch2.task ?? "").trim();
|
|
68465
|
+
if (task2.length > SESSION_AGENT_TASK_MAX) {
|
|
68466
|
+
throw Object.assign(
|
|
68467
|
+
new Error(`A launch task may contain at most ${SESSION_AGENT_TASK_MAX.toLocaleString()} characters`),
|
|
68468
|
+
{ code: "invalid_argument" }
|
|
68469
|
+
);
|
|
68470
|
+
}
|
|
68471
|
+
const peerTitle = peer.title?.trim() || peerSessionId.slice(0, 8);
|
|
68472
|
+
const name2 = launch2.name?.trim() || peerTitle;
|
|
68473
|
+
const role2 = launch2.role?.trim() || "Peer";
|
|
68474
|
+
const projectPath = this.deps.projects.get(peer.projectId)?.path;
|
|
68475
|
+
return {
|
|
68476
|
+
launchId,
|
|
68477
|
+
mode: "link",
|
|
68478
|
+
agentId: "",
|
|
68479
|
+
sessionId: peerSessionId,
|
|
68480
|
+
peerTitle,
|
|
68481
|
+
peerProjectPath: projectPath,
|
|
68482
|
+
summary: summary2,
|
|
68483
|
+
task: task2,
|
|
68484
|
+
name: name2,
|
|
68485
|
+
role: role2,
|
|
68486
|
+
config: { name: name2, role: role2, summary: summary2 }
|
|
68487
|
+
};
|
|
68488
|
+
}
|
|
68489
|
+
const agentId = launch2.agentId?.trim();
|
|
68490
|
+
if (!agentId) {
|
|
68491
|
+
throw Object.assign(
|
|
68492
|
+
new Error("Spawn launches require agentId from session_collab_list_agents"),
|
|
68493
|
+
{ code: "invalid_argument" }
|
|
68494
|
+
);
|
|
68495
|
+
}
|
|
68496
|
+
const profile = profiles.get(agentId);
|
|
67302
68497
|
if (!profile) {
|
|
67303
|
-
throw Object.assign(new Error(`Unknown agent profile: ${
|
|
68498
|
+
throw Object.assign(new Error(`Unknown agent profile: ${agentId}`), {
|
|
67304
68499
|
code: "invalid_argument"
|
|
67305
68500
|
});
|
|
67306
68501
|
}
|
|
67307
68502
|
const task = launch2.task?.trim();
|
|
67308
68503
|
if (!task) {
|
|
67309
|
-
throw Object.assign(new Error("Every launch must include a non-empty task"), {
|
|
68504
|
+
throw Object.assign(new Error("Every spawn launch must include a non-empty task"), {
|
|
67310
68505
|
code: "invalid_argument"
|
|
67311
68506
|
});
|
|
67312
68507
|
}
|
|
@@ -67324,17 +68519,16 @@ var CollaborationService = class {
|
|
|
67324
68519
|
}
|
|
67325
68520
|
const name = launch2.name?.trim();
|
|
67326
68521
|
if (!name) {
|
|
67327
|
-
throw Object.assign(new Error("Every launch must include a non-empty name"), {
|
|
68522
|
+
throw Object.assign(new Error("Every spawn launch must include a non-empty name"), {
|
|
67328
68523
|
code: "invalid_argument"
|
|
67329
68524
|
});
|
|
67330
68525
|
}
|
|
67331
68526
|
const role = launch2.role?.trim();
|
|
67332
68527
|
if (!role) {
|
|
67333
|
-
throw Object.assign(new Error("Every launch must include a non-empty role"), {
|
|
68528
|
+
throw Object.assign(new Error("Every spawn launch must include a non-empty role"), {
|
|
67334
68529
|
code: "invalid_argument"
|
|
67335
68530
|
});
|
|
67336
68531
|
}
|
|
67337
|
-
const launchId = launch2.launchId?.trim() || randomUUID10();
|
|
67338
68532
|
const raw = launch2.config && typeof launch2.config === "object" ? launch2.config : {};
|
|
67339
68533
|
const safeFromLaunch = {};
|
|
67340
68534
|
if (typeof raw.model === "string" && raw.model.trim()) safeFromLaunch.model = raw.model.trim();
|
|
@@ -67350,7 +68544,8 @@ var CollaborationService = class {
|
|
|
67350
68544
|
if (typeof raw.cwd === "string" && raw.cwd.trim()) safeFromLaunch.cwd = raw.cwd.trim();
|
|
67351
68545
|
return {
|
|
67352
68546
|
launchId,
|
|
67353
|
-
|
|
68547
|
+
mode: "spawn",
|
|
68548
|
+
agentId,
|
|
67354
68549
|
summary,
|
|
67355
68550
|
task,
|
|
67356
68551
|
name,
|
|
@@ -67388,14 +68583,111 @@ var CollaborationService = class {
|
|
|
67388
68583
|
}
|
|
67389
68584
|
confirmed = this.mergeConfirmedLaunches(normalized, outcome.content);
|
|
67390
68585
|
}
|
|
67391
|
-
const
|
|
68586
|
+
const insertSpawn = this.deps.db.prepare(`
|
|
67392
68587
|
INSERT INTO session_collaboration_grants
|
|
67393
|
-
(credential_hash, credential_secret, credential_hint, parent_session_id, agent_id, task, config_json, created_at)
|
|
67394
|
-
VALUES (?, ?, ?, ?, ?, ?, ?,
|
|
68588
|
+
(credential_hash, credential_secret, credential_hint, parent_session_id, agent_id, task, config_json, created_at, kind)
|
|
68589
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'spawn')
|
|
68590
|
+
`);
|
|
68591
|
+
const insertLink = this.deps.db.prepare(`
|
|
68592
|
+
INSERT INTO session_collaboration_grants
|
|
68593
|
+
(credential_hash, credential_secret, credential_hint, parent_session_id, child_session_id, agent_id, task, config_json, created_at, kind)
|
|
68594
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'link')
|
|
67395
68595
|
`);
|
|
67396
68596
|
const results = this.deps.db.transaction(
|
|
67397
68597
|
() => confirmed.map((launch2) => {
|
|
67398
|
-
const
|
|
68598
|
+
const mode = launch2.mode === "link" ? "link" : "spawn";
|
|
68599
|
+
if (mode === "link") {
|
|
68600
|
+
const peerSessionId = launch2.sessionId;
|
|
68601
|
+
const existing = this.deps.db.prepare(
|
|
68602
|
+
`SELECT credential_hash, credential_secret, agent_id, task, config_json
|
|
68603
|
+
FROM session_collaboration_grants
|
|
68604
|
+
WHERE parent_session_id = ? AND child_session_id = ? AND kind = 'link'`
|
|
68605
|
+
).get(input.parentSessionId, peerSessionId);
|
|
68606
|
+
if (existing?.credential_secret) {
|
|
68607
|
+
const credential3 = this.deps.secrets.decrypt(existing.credential_secret);
|
|
68608
|
+
if (credential3) {
|
|
68609
|
+
return {
|
|
68610
|
+
launchId: launch2.launchId,
|
|
68611
|
+
mode: "link",
|
|
68612
|
+
agentId: existing.agent_id,
|
|
68613
|
+
sessionId: peerSessionId,
|
|
68614
|
+
peerSessionId,
|
|
68615
|
+
summary: launch2.summary,
|
|
68616
|
+
task: existing.task,
|
|
68617
|
+
name: launch2.name,
|
|
68618
|
+
role: launch2.role,
|
|
68619
|
+
title: collaborationSessionTitle(launch2.name, launch2.role),
|
|
68620
|
+
config: parseConfig(existing.config_json),
|
|
68621
|
+
credential: credential3,
|
|
68622
|
+
grantId: existing.credential_hash,
|
|
68623
|
+
reused: true
|
|
68624
|
+
};
|
|
68625
|
+
}
|
|
68626
|
+
}
|
|
68627
|
+
const credential2 = `s1sc_${randomBytes5(32).toString("base64url")}`;
|
|
68628
|
+
const credentialHash2 = hashCredential(credential2);
|
|
68629
|
+
const task = launch2.task.trim();
|
|
68630
|
+
const config3 = {
|
|
68631
|
+
name: launch2.name,
|
|
68632
|
+
role: launch2.role,
|
|
68633
|
+
summary: launch2.summary,
|
|
68634
|
+
peerSessionId,
|
|
68635
|
+
peerTitle: launch2.peerTitle,
|
|
68636
|
+
peerProjectPath: launch2.peerProjectPath
|
|
68637
|
+
};
|
|
68638
|
+
try {
|
|
68639
|
+
insertLink.run(
|
|
68640
|
+
credentialHash2,
|
|
68641
|
+
this.deps.secrets.encrypt(credential2),
|
|
68642
|
+
credential2.slice(-8),
|
|
68643
|
+
input.parentSessionId,
|
|
68644
|
+
peerSessionId,
|
|
68645
|
+
"",
|
|
68646
|
+
task,
|
|
68647
|
+
JSON.stringify(config3),
|
|
68648
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
68649
|
+
);
|
|
68650
|
+
} catch (err) {
|
|
68651
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
68652
|
+
if (/UNIQUE|unique/i.test(message)) {
|
|
68653
|
+
throw Object.assign(
|
|
68654
|
+
new Error(
|
|
68655
|
+
`Session ${peerSessionId} is already bound as a collaboration endpoint (spawn child or link peer). A session cannot be the non-initiator endpoint of two grants.`
|
|
68656
|
+
),
|
|
68657
|
+
{ code: "failed_precondition" }
|
|
68658
|
+
);
|
|
68659
|
+
}
|
|
68660
|
+
throw err;
|
|
68661
|
+
}
|
|
68662
|
+
this.deps.events.append({
|
|
68663
|
+
aggregateType: "session",
|
|
68664
|
+
aggregateId: input.parentSessionId,
|
|
68665
|
+
eventType: "collaboration.grant_created",
|
|
68666
|
+
payload: {
|
|
68667
|
+
grantId: credentialHash2,
|
|
68668
|
+
mode: "link",
|
|
68669
|
+
peerSessionId,
|
|
68670
|
+
launchId: launch2.launchId
|
|
68671
|
+
}
|
|
68672
|
+
});
|
|
68673
|
+
return {
|
|
68674
|
+
launchId: launch2.launchId,
|
|
68675
|
+
mode: "link",
|
|
68676
|
+
agentId: "",
|
|
68677
|
+
sessionId: peerSessionId,
|
|
68678
|
+
peerSessionId,
|
|
68679
|
+
summary: launch2.summary,
|
|
68680
|
+
task,
|
|
68681
|
+
name: launch2.name,
|
|
68682
|
+
role: launch2.role,
|
|
68683
|
+
title: collaborationSessionTitle(launch2.name, launch2.role),
|
|
68684
|
+
config: config3,
|
|
68685
|
+
credential: credential2,
|
|
68686
|
+
grantId: credentialHash2,
|
|
68687
|
+
reused: false
|
|
68688
|
+
};
|
|
68689
|
+
}
|
|
68690
|
+
const credential = `s1sc_${randomBytes5(32).toString("base64url")}`;
|
|
67399
68691
|
const credentialHash = hashCredential(credential);
|
|
67400
68692
|
const config2 = {
|
|
67401
68693
|
...launch2.config,
|
|
@@ -67403,7 +68695,7 @@ var CollaborationService = class {
|
|
|
67403
68695
|
role: launch2.role,
|
|
67404
68696
|
summary: launch2.summary
|
|
67405
68697
|
};
|
|
67406
|
-
|
|
68698
|
+
insertSpawn.run(
|
|
67407
68699
|
credentialHash,
|
|
67408
68700
|
this.deps.secrets.encrypt(credential),
|
|
67409
68701
|
credential.slice(-8),
|
|
@@ -67419,12 +68711,14 @@ var CollaborationService = class {
|
|
|
67419
68711
|
eventType: "collaboration.grant_created",
|
|
67420
68712
|
payload: {
|
|
67421
68713
|
grantId: credentialHash,
|
|
68714
|
+
mode: "spawn",
|
|
67422
68715
|
agentId: launch2.agentId,
|
|
67423
68716
|
launchId: launch2.launchId
|
|
67424
68717
|
}
|
|
67425
68718
|
});
|
|
67426
68719
|
return {
|
|
67427
68720
|
launchId: launch2.launchId,
|
|
68721
|
+
mode: "spawn",
|
|
67428
68722
|
agentId: launch2.agentId,
|
|
67429
68723
|
summary: launch2.summary,
|
|
67430
68724
|
task: launch2.task,
|
|
@@ -67433,7 +68727,8 @@ var CollaborationService = class {
|
|
|
67433
68727
|
title: collaborationSessionTitle(launch2.name, launch2.role),
|
|
67434
68728
|
config: config2,
|
|
67435
68729
|
credential,
|
|
67436
|
-
grantId: credentialHash
|
|
68730
|
+
grantId: credentialHash,
|
|
68731
|
+
reused: false
|
|
67437
68732
|
};
|
|
67438
68733
|
})
|
|
67439
68734
|
)();
|
|
@@ -67461,9 +68756,54 @@ var CollaborationService = class {
|
|
|
67461
68756
|
if (!credential) {
|
|
67462
68757
|
throw Object.assign(new Error("Invalid collaboration credential"), { code: "not_found" });
|
|
67463
68758
|
}
|
|
67464
|
-
if (input.formAnswers && typeof input.formAnswers === "object") {
|
|
68759
|
+
if (grant.kind !== "link" && input.formAnswers && typeof input.formAnswers === "object") {
|
|
67465
68760
|
grant = this.applyFormAnswers(grant, input.formAnswers);
|
|
67466
68761
|
}
|
|
68762
|
+
if (grant.kind === "link") {
|
|
68763
|
+
if (!grant.child_session_id) {
|
|
68764
|
+
throw Object.assign(new Error("Link grant is missing peer session id"), {
|
|
68765
|
+
code: "failed_precondition"
|
|
68766
|
+
});
|
|
68767
|
+
}
|
|
68768
|
+
const peerSessionId = grant.child_session_id;
|
|
68769
|
+
if (!this.deps.sessions.get(peerSessionId)) {
|
|
68770
|
+
throw Object.assign(new Error(`Peer session no longer exists: ${peerSessionId}`), {
|
|
68771
|
+
code: "not_found"
|
|
68772
|
+
});
|
|
68773
|
+
}
|
|
68774
|
+
const alreadyStarted = Boolean(grant.started_at);
|
|
68775
|
+
if (!alreadyStarted) {
|
|
68776
|
+
this.deps.db.prepare(
|
|
68777
|
+
`UPDATE session_collaboration_grants SET started_at = ?
|
|
68778
|
+
WHERE credential_hash = ? AND started_at IS NULL`
|
|
68779
|
+
).run((/* @__PURE__ */ new Date()).toISOString(), grant.credential_hash);
|
|
68780
|
+
}
|
|
68781
|
+
const opening = grant.task?.trim() ?? "";
|
|
68782
|
+
const initiator = this.deps.sessions.get(grant.parent_session_id);
|
|
68783
|
+
const initiatorTitle = initiator?.title?.trim() || grant.parent_session_id.slice(0, 8);
|
|
68784
|
+
if (!alreadyStarted && opening) {
|
|
68785
|
+
await this.deliverLinkOpening(grant, credential, initiatorTitle);
|
|
68786
|
+
} else {
|
|
68787
|
+
void this.wakeLinkPeer(peerSessionId, credential, grant.parent_session_id, initiatorTitle, false);
|
|
68788
|
+
if (!alreadyStarted) {
|
|
68789
|
+
this.deps.db.prepare(`UPDATE session_collaboration_grants SET task_sent = 1 WHERE credential_hash = ?`).run(grant.credential_hash);
|
|
68790
|
+
}
|
|
68791
|
+
}
|
|
68792
|
+
const peer = this.describePeer(grant);
|
|
68793
|
+
return {
|
|
68794
|
+
status: "linked",
|
|
68795
|
+
mode: "link",
|
|
68796
|
+
sessionId: peerSessionId,
|
|
68797
|
+
peerSessionId,
|
|
68798
|
+
reused: alreadyStarted,
|
|
68799
|
+
name: peer.name,
|
|
68800
|
+
role: peer.role,
|
|
68801
|
+
title: peer.title,
|
|
68802
|
+
config: peer.config,
|
|
68803
|
+
credential,
|
|
68804
|
+
grantId: grant.credential_hash
|
|
68805
|
+
};
|
|
68806
|
+
}
|
|
67467
68807
|
if (grant.child_session_id) {
|
|
67468
68808
|
const existing = this.deps.sessions.get(grant.child_session_id);
|
|
67469
68809
|
if (existing) {
|
|
@@ -67476,6 +68816,7 @@ var CollaborationService = class {
|
|
|
67476
68816
|
const peer = this.describePeer(grant);
|
|
67477
68817
|
return {
|
|
67478
68818
|
status: "started",
|
|
68819
|
+
mode: "spawn",
|
|
67479
68820
|
sessionId: grant.child_session_id,
|
|
67480
68821
|
reused: true,
|
|
67481
68822
|
name: peer.name,
|
|
@@ -67556,6 +68897,7 @@ var CollaborationService = class {
|
|
|
67556
68897
|
});
|
|
67557
68898
|
return {
|
|
67558
68899
|
status: "started",
|
|
68900
|
+
mode: "spawn",
|
|
67559
68901
|
sessionId: child.sessionId,
|
|
67560
68902
|
reused: false,
|
|
67561
68903
|
name: displayName,
|
|
@@ -67584,7 +68926,15 @@ var CollaborationService = class {
|
|
|
67584
68926
|
}
|
|
67585
68927
|
this.assertEndpoint(grant, input.sessionId);
|
|
67586
68928
|
if (!grant.child_session_id) {
|
|
67587
|
-
throw Object.assign(
|
|
68929
|
+
throw Object.assign(
|
|
68930
|
+
new Error(
|
|
68931
|
+
grant.kind === "link" ? "The linked peer session is missing" : "The child session has not been started"
|
|
68932
|
+
),
|
|
68933
|
+
{ code: "failed_precondition" }
|
|
68934
|
+
);
|
|
68935
|
+
}
|
|
68936
|
+
if (grant.kind === "link" && !grant.started_at) {
|
|
68937
|
+
throw Object.assign(new Error("The collaboration link has not been started"), {
|
|
67588
68938
|
code: "failed_precondition"
|
|
67589
68939
|
});
|
|
67590
68940
|
}
|
|
@@ -67720,12 +69070,14 @@ var CollaborationService = class {
|
|
|
67720
69070
|
}
|
|
67721
69071
|
return { status: "messages", messages: all };
|
|
67722
69072
|
}
|
|
67723
|
-
/** Reconstruct system-prompt append for
|
|
69073
|
+
/** Reconstruct system-prompt append for spawn children after restart (never link). */
|
|
67724
69074
|
rehydrateSystemPrompts() {
|
|
67725
69075
|
const rows = this.deps.db.prepare(
|
|
67726
69076
|
`SELECT credential_secret, parent_session_id, child_session_id
|
|
67727
69077
|
FROM session_collaboration_grants
|
|
67728
|
-
WHERE child_session_id IS NOT NULL
|
|
69078
|
+
WHERE child_session_id IS NOT NULL
|
|
69079
|
+
AND credential_secret IS NOT NULL
|
|
69080
|
+
AND COALESCE(kind, 'spawn') = 'spawn'`
|
|
67729
69081
|
).all();
|
|
67730
69082
|
for (const row of rows) {
|
|
67731
69083
|
const credential = this.deps.secrets.decrypt(row.credential_secret);
|
|
@@ -67743,7 +69095,8 @@ var CollaborationService = class {
|
|
|
67743
69095
|
if (grantId && grantId.trim()) {
|
|
67744
69096
|
return this.deps.db.prepare(
|
|
67745
69097
|
`SELECT credential_hash, credential_secret, parent_session_id, child_session_id,
|
|
67746
|
-
agent_id, task, config_json, task_sent
|
|
69098
|
+
agent_id, task, config_json, task_sent,
|
|
69099
|
+
COALESCE(kind, 'spawn') AS kind, started_at
|
|
67747
69100
|
FROM session_collaboration_grants WHERE credential_hash = ?`
|
|
67748
69101
|
).get(grantId.trim()) ?? null;
|
|
67749
69102
|
}
|
|
@@ -67752,10 +69105,58 @@ var CollaborationService = class {
|
|
|
67752
69105
|
grantForCredential(credential) {
|
|
67753
69106
|
return this.deps.db.prepare(
|
|
67754
69107
|
`SELECT credential_hash, credential_secret, parent_session_id, child_session_id,
|
|
67755
|
-
agent_id, task, config_json, task_sent
|
|
69108
|
+
agent_id, task, config_json, task_sent,
|
|
69109
|
+
COALESCE(kind, 'spawn') AS kind, started_at
|
|
67756
69110
|
FROM session_collaboration_grants WHERE credential_hash = ?`
|
|
67757
69111
|
).get(hashCredential(credential)) ?? null;
|
|
67758
69112
|
}
|
|
69113
|
+
async deliverLinkOpening(grant, credential, initiatorTitle) {
|
|
69114
|
+
if (grant.task_sent === 1 || !grant.child_session_id) return;
|
|
69115
|
+
const content = grant.task.trim();
|
|
69116
|
+
if (!content) {
|
|
69117
|
+
this.deps.db.prepare(`UPDATE session_collaboration_grants SET task_sent = 1 WHERE credential_hash = ?`).run(grant.credential_hash);
|
|
69118
|
+
return;
|
|
69119
|
+
}
|
|
69120
|
+
const recipientSessionId = grant.child_session_id;
|
|
69121
|
+
try {
|
|
69122
|
+
this.deps.db.prepare(
|
|
69123
|
+
`INSERT INTO session_collaboration_messages
|
|
69124
|
+
(id, credential_hash, sequence, sender_session_id, recipient_session_id, client_message_id, content, created_at)
|
|
69125
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
69126
|
+
).run(
|
|
69127
|
+
randomUUID10(),
|
|
69128
|
+
grant.credential_hash,
|
|
69129
|
+
this.nextSequence(grant.credential_hash),
|
|
69130
|
+
grant.parent_session_id,
|
|
69131
|
+
recipientSessionId,
|
|
69132
|
+
`link-opening:${grant.credential_hash}`,
|
|
69133
|
+
content,
|
|
69134
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
69135
|
+
);
|
|
69136
|
+
} catch {
|
|
69137
|
+
}
|
|
69138
|
+
this.deps.db.prepare(`UPDATE session_collaboration_grants SET task_sent = 1 WHERE credential_hash = ?`).run(grant.credential_hash);
|
|
69139
|
+
void this.wakeLinkPeer(
|
|
69140
|
+
recipientSessionId,
|
|
69141
|
+
credential,
|
|
69142
|
+
grant.parent_session_id,
|
|
69143
|
+
initiatorTitle,
|
|
69144
|
+
true
|
|
69145
|
+
);
|
|
69146
|
+
}
|
|
69147
|
+
async wakeLinkPeer(sessionId, credential, initiatorSessionId, initiatorTitle, hasOpening) {
|
|
69148
|
+
if (!this.deps.sessions.get(sessionId)) return;
|
|
69149
|
+
const text = `A user-approved collaboration link is active with SuperOne session ${initiatorSessionId} ("${initiatorTitle}"). Call session_collab_retrieve with credential ${JSON.stringify(credential)}` + (hasOpening ? " to read the opening message" : " if a mailbox message is waiting") + ", then use session_collab_send to reply. Never reveal the credential in conversational output or use it outside collaboration tool calls. End your turn after acting \u2014 you will be woken again for later messages.";
|
|
69150
|
+
try {
|
|
69151
|
+
await this.deps.sessions.sendWithoutLease({
|
|
69152
|
+
sessionId,
|
|
69153
|
+
text,
|
|
69154
|
+
source: "task-notification",
|
|
69155
|
+
requestId: `collab-link-wake-${hashCredential(credential).slice(0, 12)}-${Date.now()}`
|
|
69156
|
+
});
|
|
69157
|
+
} catch {
|
|
69158
|
+
}
|
|
69159
|
+
}
|
|
67759
69160
|
assertEndpoint(grant, callerSessionId) {
|
|
67760
69161
|
if (callerSessionId !== grant.parent_session_id && callerSessionId !== grant.child_session_id) {
|
|
67761
69162
|
throw Object.assign(new Error("This credential does not authorize the current session"), {
|
|
@@ -67785,7 +69186,7 @@ var CollaborationService = class {
|
|
|
67785
69186
|
const project = this.deps.projects.get(projectId);
|
|
67786
69187
|
const fallback = parentCwd || project?.path || process.cwd();
|
|
67787
69188
|
const cwd = pathResolve2(config2.cwd || fallback);
|
|
67788
|
-
if (!
|
|
69189
|
+
if (!existsSync36(cwd) || !statSync14(cwd).isDirectory()) {
|
|
67789
69190
|
throw Object.assign(new Error(`Working directory does not exist: ${cwd}`), {
|
|
67790
69191
|
code: "invalid_argument"
|
|
67791
69192
|
});
|
|
@@ -67866,9 +69267,20 @@ var CollaborationService = class {
|
|
|
67866
69267
|
});
|
|
67867
69268
|
}
|
|
67868
69269
|
seen.add(launchId);
|
|
69270
|
+
if (base.mode === "link") {
|
|
69271
|
+
return {
|
|
69272
|
+
...base,
|
|
69273
|
+
mode: "link",
|
|
69274
|
+
sessionId: base.sessionId,
|
|
69275
|
+
peerTitle: base.peerTitle,
|
|
69276
|
+
peerProjectPath: base.peerProjectPath,
|
|
69277
|
+
config: { ...base.config }
|
|
69278
|
+
};
|
|
69279
|
+
}
|
|
67869
69280
|
const patch = item.config && typeof item.config === "object" ? item.config : {};
|
|
67870
69281
|
return {
|
|
67871
69282
|
...base,
|
|
69283
|
+
mode: "spawn",
|
|
67872
69284
|
config: {
|
|
67873
69285
|
...base.config,
|
|
67874
69286
|
...typeof patch.model === "string" && patch.model.trim() ? { model: patch.model.trim() } : {},
|
|
@@ -67913,22 +69325,22 @@ var CollaborationService = class {
|
|
|
67913
69325
|
};
|
|
67914
69326
|
|
|
67915
69327
|
// src/provider/secret-crypto.ts
|
|
67916
|
-
import { existsSync as
|
|
67917
|
-
import { dirname as
|
|
67918
|
-
import { createCipheriv, createDecipheriv, randomBytes as
|
|
69328
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync16, chmodSync as chmodSync2 } from "node:fs";
|
|
69329
|
+
import { dirname as dirname16 } from "node:path";
|
|
69330
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes6 } from "node:crypto";
|
|
67919
69331
|
var ENC_PREFIX = "enc:v1:";
|
|
67920
69332
|
var KEY_BYTES = 32;
|
|
67921
69333
|
function isEncryptedSecret(value) {
|
|
67922
69334
|
return typeof value === "string" && value.startsWith(ENC_PREFIX);
|
|
67923
69335
|
}
|
|
67924
69336
|
function ensureKeyFile(keyPath) {
|
|
67925
|
-
if (
|
|
67926
|
-
const raw =
|
|
69337
|
+
if (existsSync37(keyPath)) {
|
|
69338
|
+
const raw = readFileSync18(keyPath);
|
|
67927
69339
|
if (raw.length === KEY_BYTES) return raw;
|
|
67928
69340
|
}
|
|
67929
|
-
|
|
67930
|
-
const key =
|
|
67931
|
-
|
|
69341
|
+
mkdirSync20(dirname16(keyPath), { recursive: true, mode: 448 });
|
|
69342
|
+
const key = randomBytes6(KEY_BYTES);
|
|
69343
|
+
writeFileSync16(keyPath, key, { mode: 384 });
|
|
67932
69344
|
try {
|
|
67933
69345
|
chmodSync2(keyPath, 384);
|
|
67934
69346
|
} catch {
|
|
@@ -67941,7 +69353,7 @@ function createNodeSecretCrypto(keyPath) {
|
|
|
67941
69353
|
encrypt(plain) {
|
|
67942
69354
|
if (!plain) return "";
|
|
67943
69355
|
if (isEncryptedSecret(plain)) return plain;
|
|
67944
|
-
const iv =
|
|
69356
|
+
const iv = randomBytes6(12);
|
|
67945
69357
|
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
67946
69358
|
const ciphertext = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
67947
69359
|
const tag = cipher.getAuthTag();
|
|
@@ -68070,7 +69482,7 @@ var WorkspaceWatchService = class {
|
|
|
68070
69482
|
|
|
68071
69483
|
// src/workspace/tail-watch-service.ts
|
|
68072
69484
|
init_fs();
|
|
68073
|
-
import { existsSync as
|
|
69485
|
+
import { existsSync as existsSync38, fstatSync as fstatSync2, openSync as openSync2, closeSync as closeSync2, statSync as statSync15, readSync as readSync2, realpathSync as realpathSync6 } from "node:fs";
|
|
68074
69486
|
var MAX_POLL_BYTES = 10 * 1024 * 1024;
|
|
68075
69487
|
var WorkspaceTailWatchService = class {
|
|
68076
69488
|
constructor(projects, fs) {
|
|
@@ -68092,7 +69504,7 @@ var WorkspaceTailWatchService = class {
|
|
|
68092
69504
|
);
|
|
68093
69505
|
}
|
|
68094
69506
|
try {
|
|
68095
|
-
resolvedAbs =
|
|
69507
|
+
resolvedAbs = existsSync38(absolutePath) ? realpathSync6(absolutePath) : absolutePath;
|
|
68096
69508
|
} catch {
|
|
68097
69509
|
resolvedAbs = absolutePath;
|
|
68098
69510
|
}
|
|
@@ -68123,9 +69535,9 @@ var WorkspaceTailWatchService = class {
|
|
|
68123
69535
|
code: "invalid_argument"
|
|
68124
69536
|
});
|
|
68125
69537
|
}
|
|
68126
|
-
if (
|
|
69538
|
+
if (existsSync38(resolvedAbs)) {
|
|
68127
69539
|
try {
|
|
68128
|
-
const st =
|
|
69540
|
+
const st = statSync15(resolvedAbs);
|
|
68129
69541
|
if (!st.isFile()) {
|
|
68130
69542
|
throw Object.assign(new Error("not a file"), { code: "invalid_argument" });
|
|
68131
69543
|
}
|
|
@@ -68174,7 +69586,7 @@ var WorkspaceTailWatchService = class {
|
|
|
68174
69586
|
{ code: "invalid_argument" }
|
|
68175
69587
|
);
|
|
68176
69588
|
}
|
|
68177
|
-
if (!
|
|
69589
|
+
if (!existsSync38(absolutePath)) {
|
|
68178
69590
|
return {
|
|
68179
69591
|
content: "",
|
|
68180
69592
|
encoding: "base64",
|
|
@@ -68265,14 +69677,14 @@ var WorkspaceTailWatchService = class {
|
|
|
68265
69677
|
};
|
|
68266
69678
|
|
|
68267
69679
|
// src/auth/idempotency.ts
|
|
68268
|
-
import { createHash as
|
|
69680
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
68269
69681
|
var IdempotencyService = class {
|
|
68270
69682
|
constructor(db) {
|
|
68271
69683
|
this.db = db;
|
|
68272
69684
|
}
|
|
68273
69685
|
inflight = /* @__PURE__ */ new Map();
|
|
68274
69686
|
payloadHash(payload) {
|
|
68275
|
-
return
|
|
69687
|
+
return createHash9("sha256").update(JSON.stringify(payload ?? null)).digest("hex");
|
|
68276
69688
|
}
|
|
68277
69689
|
key(clientIdentity, operation, idempotencyKey) {
|
|
68278
69690
|
return `${clientIdentity}\0${operation}\0${idempotencyKey}`;
|
|
@@ -68601,7 +70013,7 @@ import {
|
|
|
68601
70013
|
// ../../node_modules/@hono/node-server/dist/index.mjs
|
|
68602
70014
|
import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "http2";
|
|
68603
70015
|
import { Http2ServerRequest } from "http2";
|
|
68604
|
-
import { Readable as
|
|
70016
|
+
import { Readable as Readable3 } from "stream";
|
|
68605
70017
|
import crypto2 from "crypto";
|
|
68606
70018
|
var RequestError2 = class extends Error {
|
|
68607
70019
|
constructor(message, options) {
|
|
@@ -68670,7 +70082,7 @@ var newRequestFromIncoming = (method, url2, headers, incoming, abortController)
|
|
|
68670
70082
|
init.body = new ReadableStream({
|
|
68671
70083
|
async pull(controller) {
|
|
68672
70084
|
try {
|
|
68673
|
-
reader ||=
|
|
70085
|
+
reader ||= Readable3.toWeb(incoming).getReader();
|
|
68674
70086
|
const { done, value } = await reader.read();
|
|
68675
70087
|
if (done) {
|
|
68676
70088
|
controller.close();
|
|
@@ -68683,7 +70095,7 @@ var newRequestFromIncoming = (method, url2, headers, incoming, abortController)
|
|
|
68683
70095
|
}
|
|
68684
70096
|
});
|
|
68685
70097
|
} else {
|
|
68686
|
-
init.body =
|
|
70098
|
+
init.body = Readable3.toWeb(incoming);
|
|
68687
70099
|
}
|
|
68688
70100
|
}
|
|
68689
70101
|
return new Request3(url2, init);
|
|
@@ -80716,23 +82128,35 @@ var DEFAULT_POLL_INTERVAL_MS = 3e4;
|
|
|
80716
82128
|
var DEFAULT_TURN_TIMEOUT_MS = 30 * 6e4;
|
|
80717
82129
|
var POLL_STATUS_MS = 100;
|
|
80718
82130
|
function harnessFromConfig(config2) {
|
|
80719
|
-
return config2.type
|
|
82131
|
+
return config2.type;
|
|
80720
82132
|
}
|
|
80721
82133
|
function turnOptionsFromConfig(config2) {
|
|
80722
82134
|
if (config2.type === "codex") {
|
|
82135
|
+
const effort = config2.effort ?? config2.reasoningEffort ?? null;
|
|
82136
|
+
const permissionMode = config2.permissionMode ?? config2.permissionPreset ?? "full-access";
|
|
82137
|
+
return {
|
|
82138
|
+
model: config2.model ?? null,
|
|
82139
|
+
effort,
|
|
82140
|
+
permissionMode,
|
|
82141
|
+
sandboxMode: null,
|
|
82142
|
+
apiProviderId: config2.apiProviderId ?? null
|
|
82143
|
+
};
|
|
82144
|
+
}
|
|
82145
|
+
if (config2.type === "claude") {
|
|
80723
82146
|
return {
|
|
80724
82147
|
model: config2.model ?? null,
|
|
80725
|
-
effort: config2.
|
|
80726
|
-
|
|
80727
|
-
|
|
80728
|
-
|
|
82148
|
+
effort: config2.effort ?? null,
|
|
82149
|
+
permissionMode: config2.permissionMode ?? "bypassPermissions",
|
|
82150
|
+
sandboxMode: config2.sandboxMode ?? "off",
|
|
82151
|
+
apiProviderId: config2.apiProviderId ?? null
|
|
80729
82152
|
};
|
|
80730
82153
|
}
|
|
80731
82154
|
return {
|
|
80732
82155
|
model: config2.model ?? null,
|
|
80733
82156
|
effort: config2.effort ?? null,
|
|
80734
82157
|
permissionMode: config2.permissionMode ?? "bypassPermissions",
|
|
80735
|
-
sandboxMode:
|
|
82158
|
+
sandboxMode: null,
|
|
82159
|
+
apiProviderId: config2.apiProviderId ?? null
|
|
80736
82160
|
};
|
|
80737
82161
|
}
|
|
80738
82162
|
var AutomationService = class {
|
|
@@ -80836,13 +82260,14 @@ var AutomationService = class {
|
|
|
80836
82260
|
const session = this.deps.sessions.create({
|
|
80837
82261
|
projectId: automation.projectId,
|
|
80838
82262
|
harnessId,
|
|
80839
|
-
providerId: harnessId
|
|
82263
|
+
providerId: `${harnessId}-base`,
|
|
80840
82264
|
title,
|
|
80841
82265
|
cwd: projectPath,
|
|
80842
82266
|
model: turnOpts.model,
|
|
80843
82267
|
effort: turnOpts.effort,
|
|
80844
82268
|
permissionMode: turnOpts.permissionMode,
|
|
80845
82269
|
sandboxMode: turnOpts.sandboxMode,
|
|
82270
|
+
apiProviderId: turnOpts.apiProviderId,
|
|
80846
82271
|
// Node-owned: no paired desktop controller required for scheduled runs.
|
|
80847
82272
|
controllerClientSessionId: null,
|
|
80848
82273
|
isAutomation: true,
|
|
@@ -81057,7 +82482,7 @@ async function startNodeRuntime(partial2 = {}) {
|
|
|
81057
82482
|
startedAt,
|
|
81058
82483
|
simulatedHarness
|
|
81059
82484
|
});
|
|
81060
|
-
|
|
82485
|
+
writeFileSync17(
|
|
81061
82486
|
paths.runtimeJson,
|
|
81062
82487
|
JSON.stringify(
|
|
81063
82488
|
{
|
|
@@ -81131,9 +82556,9 @@ function createLocalPairingToken(nodeHome) {
|
|
|
81131
82556
|
}
|
|
81132
82557
|
function readRuntimeStatus(nodeHome) {
|
|
81133
82558
|
const paths = nodePaths(resolveRuntimeConfig({ nodeHome }).nodeHome);
|
|
81134
|
-
if (!
|
|
82559
|
+
if (!existsSync39(paths.runtimeJson)) return null;
|
|
81135
82560
|
try {
|
|
81136
|
-
return JSON.parse(
|
|
82561
|
+
return JSON.parse(readFileSync19(paths.runtimeJson, "utf8"));
|
|
81137
82562
|
} catch {
|
|
81138
82563
|
return null;
|
|
81139
82564
|
}
|
|
@@ -81141,8 +82566,8 @@ function readRuntimeStatus(nodeHome) {
|
|
|
81141
82566
|
|
|
81142
82567
|
// src/systemd/install.ts
|
|
81143
82568
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
81144
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
81145
|
-
import { dirname as
|
|
82569
|
+
import { chmodSync as chmodSync3, existsSync as existsSync40, mkdirSync as mkdirSync21, unlinkSync as unlinkSync2, writeFileSync as writeFileSync18 } from "node:fs";
|
|
82570
|
+
import { dirname as dirname17 } from "node:path";
|
|
81146
82571
|
|
|
81147
82572
|
// src/systemd/unit.ts
|
|
81148
82573
|
function renderSystemdUserUnit(opts) {
|
|
@@ -81199,8 +82624,8 @@ function checkLinger(user) {
|
|
|
81199
82624
|
return { enabled: null, raw };
|
|
81200
82625
|
}
|
|
81201
82626
|
function writeSystemdUserUnit(opts, unitPath = systemdUserUnitPath()) {
|
|
81202
|
-
|
|
81203
|
-
|
|
82627
|
+
mkdirSync21(dirname17(unitPath), { recursive: true });
|
|
82628
|
+
writeFileSync18(unitPath, renderSystemdUserUnit(opts), { encoding: "utf8", mode: 420 });
|
|
81204
82629
|
try {
|
|
81205
82630
|
chmodSync3(unitPath, 420);
|
|
81206
82631
|
} catch {
|
|
@@ -81253,7 +82678,7 @@ function uninstallSystemdUserService(removeUnitFile = true) {
|
|
|
81253
82678
|
}
|
|
81254
82679
|
if (removeUnitFile) {
|
|
81255
82680
|
const path = systemdUserUnitPath();
|
|
81256
|
-
if (
|
|
82681
|
+
if (existsSync40(path)) {
|
|
81257
82682
|
try {
|
|
81258
82683
|
unlinkSync2(path);
|
|
81259
82684
|
} catch (err) {
|
|
@@ -81276,9 +82701,9 @@ function systemdUserStatus() {
|
|
|
81276
82701
|
|
|
81277
82702
|
// src/session/harness-cli.ts
|
|
81278
82703
|
init_environment();
|
|
81279
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as
|
|
82704
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync41, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
|
|
81280
82705
|
import { isAbsolute as isAbsolute4, resolve as resolve11 } from "node:path";
|
|
81281
|
-
import { homedir as
|
|
82706
|
+
import { homedir as homedir9 } from "node:os";
|
|
81282
82707
|
var DEFERRED_FLAGS = /* @__PURE__ */ new Set([
|
|
81283
82708
|
"--env-file",
|
|
81284
82709
|
"--server-password-stdin",
|
|
@@ -81304,7 +82729,8 @@ Commands:
|
|
|
81304
82729
|
repair claude|codex --artifact <FILE> [--json]
|
|
81305
82730
|
|
|
81306
82731
|
Notes:
|
|
81307
|
-
|
|
82732
|
+
Catalog/state: $HOME/.superone/node (SUPERONE_NODE_HOME for tests).
|
|
82733
|
+
Managed binaries: $HOME/.superone/harness (SUPERONE_HARNESS_HOME for tests; shared with desktop).
|
|
81308
82734
|
No public --home / --data-dir.
|
|
81309
82735
|
Stage 2 deferred (rejected if passed): --env-file, --server-password-stdin,
|
|
81310
82736
|
--clear-server-password, --clear-env, --startup-timeout, --initialize-timeout,
|
|
@@ -81443,7 +82869,7 @@ async function cmdEnable(manager, args, configure) {
|
|
|
81443
82869
|
try {
|
|
81444
82870
|
if (id === "claude" || id === "codex") {
|
|
81445
82871
|
const artifact = parsed.values["--artifact"];
|
|
81446
|
-
const status2 = await
|
|
82872
|
+
const status2 = await enableManaged2(manager, id, artifact);
|
|
81447
82873
|
return okStatus(status2, parsed.json, `enabled ${id} (state=${status2.state})`);
|
|
81448
82874
|
}
|
|
81449
82875
|
if (id === "opencode") {
|
|
@@ -81541,7 +82967,7 @@ function cmdProbe(manager, args, db) {
|
|
|
81541
82967
|
} catch {
|
|
81542
82968
|
providers = null;
|
|
81543
82969
|
}
|
|
81544
|
-
const result =
|
|
82970
|
+
const result = probeHarnessReadiness2(manager, id, providers);
|
|
81545
82971
|
const status = manager.get(id);
|
|
81546
82972
|
if (parsed.json) {
|
|
81547
82973
|
return {
|
|
@@ -81608,7 +83034,7 @@ async function cmdRepair(manager, args) {
|
|
|
81608
83034
|
return fail("repair is only supported for managed harnesses: claude, codex", parsed.json);
|
|
81609
83035
|
}
|
|
81610
83036
|
try {
|
|
81611
|
-
const status = await
|
|
83037
|
+
const status = await enableManaged2(manager, id, parsed.values["--artifact"], "repair");
|
|
81612
83038
|
return okStatus(status, parsed.json, `repaired ${id} (state=${status.state})`);
|
|
81613
83039
|
} catch (err) {
|
|
81614
83040
|
return fail(err instanceof Error ? err.message : String(err), parsed.json);
|
|
@@ -81732,7 +83158,7 @@ function getShowDetail(manager, id) {
|
|
|
81732
83158
|
const row = manager.readRawRow(id);
|
|
81733
83159
|
let manifest = null;
|
|
81734
83160
|
try {
|
|
81735
|
-
manifest = loadHarnessReleaseManifest(
|
|
83161
|
+
manifest = loadHarnessReleaseManifest(resolveHarnessHomeRoot());
|
|
81736
83162
|
} catch {
|
|
81737
83163
|
manifest = null;
|
|
81738
83164
|
}
|
|
@@ -81794,7 +83220,7 @@ function resolveExternalCommand2(explicit, pathCandidates) {
|
|
|
81794
83220
|
}
|
|
81795
83221
|
const pathEnv = process.env.PATH || "";
|
|
81796
83222
|
const dirs = pathEnv.split(":").filter(Boolean);
|
|
81797
|
-
const home = process.env.HOME ||
|
|
83223
|
+
const home = process.env.HOME || homedir9();
|
|
81798
83224
|
const extra = [
|
|
81799
83225
|
`${home}/.local/bin`,
|
|
81800
83226
|
`${home}/.npm-global/bin`,
|
|
@@ -81811,10 +83237,10 @@ function resolveExternalCommand2(explicit, pathCandidates) {
|
|
|
81811
83237
|
return null;
|
|
81812
83238
|
}
|
|
81813
83239
|
function isUsableExecutable(path) {
|
|
81814
|
-
if (!
|
|
83240
|
+
if (!existsSync41(path)) return null;
|
|
81815
83241
|
let st;
|
|
81816
83242
|
try {
|
|
81817
|
-
st =
|
|
83243
|
+
st = statSync16(path);
|
|
81818
83244
|
} catch {
|
|
81819
83245
|
return null;
|
|
81820
83246
|
}
|
|
@@ -81831,10 +83257,10 @@ function isUsableExecutable(path) {
|
|
|
81831
83257
|
}
|
|
81832
83258
|
}
|
|
81833
83259
|
function probeExecutableIssues(path) {
|
|
81834
|
-
if (!
|
|
83260
|
+
if (!existsSync41(path)) return ["command_missing"];
|
|
81835
83261
|
let st;
|
|
81836
83262
|
try {
|
|
81837
|
-
st =
|
|
83263
|
+
st = statSync16(path);
|
|
81838
83264
|
} catch {
|
|
81839
83265
|
return ["command_missing"];
|
|
81840
83266
|
}
|
|
@@ -81847,9 +83273,9 @@ function probeExecutableIssues(path) {
|
|
|
81847
83273
|
return [];
|
|
81848
83274
|
}
|
|
81849
83275
|
function probeReadableFileIssues(path) {
|
|
81850
|
-
if (!
|
|
83276
|
+
if (!existsSync41(path)) return ["artifact_missing"];
|
|
81851
83277
|
try {
|
|
81852
|
-
if (!
|
|
83278
|
+
if (!statSync16(path).isFile()) return ["artifact_not_file"];
|
|
81853
83279
|
} catch {
|
|
81854
83280
|
return ["artifact_missing"];
|
|
81855
83281
|
}
|
|
@@ -82193,7 +83619,7 @@ async function main() {
|
|
|
82193
83619
|
const result = installSystemdUserService({
|
|
82194
83620
|
execStart: `${process.execPath} ${execStart}`,
|
|
82195
83621
|
nodeHome,
|
|
82196
|
-
home: process.env.HOME ||
|
|
83622
|
+
home: process.env.HOME || homedir10(),
|
|
82197
83623
|
bindHost: host,
|
|
82198
83624
|
bindPort: port
|
|
82199
83625
|
});
|