@cabane/companion 0.6.192 → 0.6.194
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/dist/cli.js +303 -179
- package/dist/runtime.js +166 -90
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7560,6 +7560,7 @@ function parseRunnerInput(env, stdin) {
|
|
|
7560
7560
|
baseUrl: required(env, RUNNER_ENV.url),
|
|
7561
7561
|
credential: credentials.credential,
|
|
7562
7562
|
...credentials.secrets ? { secrets: credentials.secrets } : {},
|
|
7563
|
+
...credentials.grants ? { grants: credentials.grants } : {},
|
|
7563
7564
|
dispatch,
|
|
7564
7565
|
turnId: required(env, RUNNER_ENV.turnId),
|
|
7565
7566
|
resumed: env[RUNNER_ENV.resumed] === "1",
|
|
@@ -7579,7 +7580,8 @@ function runnerEnv(input) {
|
|
|
7579
7580
|
function runnerStdin(input) {
|
|
7580
7581
|
return `${JSON.stringify({
|
|
7581
7582
|
credential: input.credential,
|
|
7582
|
-
...input.secrets ? { secrets: input.secrets } : {}
|
|
7583
|
+
...input.secrets ? { secrets: input.secrets } : {},
|
|
7584
|
+
...input.grants ? { grants: input.grants } : {}
|
|
7583
7585
|
})}
|
|
7584
7586
|
`;
|
|
7585
7587
|
}
|
|
@@ -7684,7 +7686,8 @@ var init_protocol = __esm({
|
|
|
7684
7686
|
});
|
|
7685
7687
|
credentialsSchema = z14.object({
|
|
7686
7688
|
credential: z14.string().startsWith("cabrn_"),
|
|
7687
|
-
secrets: z14.record(z14.string(), z14.string()).optional()
|
|
7689
|
+
secrets: z14.record(z14.string(), z14.string()).optional(),
|
|
7690
|
+
grants: z14.record(z14.string(), z14.record(z14.string(), z14.string())).optional()
|
|
7688
7691
|
});
|
|
7689
7692
|
}
|
|
7690
7693
|
});
|
|
@@ -7811,7 +7814,12 @@ async function mintForRunner(opts, payload, handleOpts, signal, log2) {
|
|
|
7811
7814
|
// The one turn the credential will operate: this run's.
|
|
7812
7815
|
turnId: handleOpts.turnId
|
|
7813
7816
|
});
|
|
7814
|
-
return {
|
|
7817
|
+
return {
|
|
7818
|
+
ok: true,
|
|
7819
|
+
credential: minted.credential,
|
|
7820
|
+
runnerId: minted.runnerId,
|
|
7821
|
+
deviceGrants: minted.deviceGrants ?? []
|
|
7822
|
+
};
|
|
7815
7823
|
} catch (err) {
|
|
7816
7824
|
if (signal.aborted) return { ok: false, reason: "cancelled" };
|
|
7817
7825
|
const status2 = err instanceof ApiError ? err.status : 0;
|
|
@@ -7906,10 +7914,12 @@ async function runTurnInRunner(opts, launch, duties, payload, handleOpts) {
|
|
|
7906
7914
|
try {
|
|
7907
7915
|
const boxed = launch.boxed === true;
|
|
7908
7916
|
const env = runnerExecEnv(launch.env ?? process.env, boxed);
|
|
7917
|
+
const grants = minted.deviceGrants.length > 0 ? launch.grants?.(minted.deviceGrants) ?? {} : {};
|
|
7909
7918
|
const input = {
|
|
7910
7919
|
baseUrl: opts.baseUrl,
|
|
7911
7920
|
credential: minted.credential,
|
|
7912
7921
|
...boxed ? { secrets: launch.secrets?.() ?? {} } : {},
|
|
7922
|
+
...Object.keys(grants).length > 0 ? { grants } : {},
|
|
7913
7923
|
dispatch: payload,
|
|
7914
7924
|
turnId,
|
|
7915
7925
|
resumed: handleOpts.resumed,
|
|
@@ -8072,11 +8082,101 @@ var init_launch = __esm({
|
|
|
8072
8082
|
}
|
|
8073
8083
|
});
|
|
8074
8084
|
|
|
8085
|
+
// src/grants.ts
|
|
8086
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
8087
|
+
import { join as join14 } from "path";
|
|
8088
|
+
import { z as z15 } from "zod";
|
|
8089
|
+
function allowedGrantVariable(name) {
|
|
8090
|
+
return name.length <= 100 && VARIABLE_NAME_RE.test(name) && !name.startsWith("CABANE_");
|
|
8091
|
+
}
|
|
8092
|
+
function environmentSafe(value) {
|
|
8093
|
+
return !value.includes("\0");
|
|
8094
|
+
}
|
|
8095
|
+
function grantsPath() {
|
|
8096
|
+
return join14(cabaneDir(), "grants.json");
|
|
8097
|
+
}
|
|
8098
|
+
function readGrants(keys, report) {
|
|
8099
|
+
if (keys.length === 0) return {};
|
|
8100
|
+
const file = loadGrantsFile(report);
|
|
8101
|
+
const out = {};
|
|
8102
|
+
for (const key of keys) {
|
|
8103
|
+
if (!allowedGrantVariable(key) || !Object.hasOwn(file, key)) continue;
|
|
8104
|
+
const entry = {};
|
|
8105
|
+
for (const [variable, value] of Object.entries(file[key])) {
|
|
8106
|
+
if (allowedGrantVariable(variable) && environmentSafe(value)) entry[variable] = value;
|
|
8107
|
+
else report.refusedVariable(key, variable);
|
|
8108
|
+
}
|
|
8109
|
+
out[key] = entry;
|
|
8110
|
+
}
|
|
8111
|
+
return out;
|
|
8112
|
+
}
|
|
8113
|
+
function loadGrantsFile(report) {
|
|
8114
|
+
const path = grantsPath();
|
|
8115
|
+
if (!existsSync9(path)) return {};
|
|
8116
|
+
let raw;
|
|
8117
|
+
try {
|
|
8118
|
+
raw = readFileSync7(path, "utf8");
|
|
8119
|
+
} catch (err) {
|
|
8120
|
+
const code = err.code ?? "unknown error";
|
|
8121
|
+
report.unreadable(`couldn't read ${path}: ${code}`);
|
|
8122
|
+
return {};
|
|
8123
|
+
}
|
|
8124
|
+
if (raw.trim().length === 0) return {};
|
|
8125
|
+
let parsed;
|
|
8126
|
+
try {
|
|
8127
|
+
parsed = JSON.parse(raw);
|
|
8128
|
+
} catch {
|
|
8129
|
+
report.unreadable(`${path} is not valid JSON.`);
|
|
8130
|
+
return {};
|
|
8131
|
+
}
|
|
8132
|
+
const result = grantsFileSchema.safeParse(parsed);
|
|
8133
|
+
if (!result.success) {
|
|
8134
|
+
report.unreadable(
|
|
8135
|
+
`${path} must map a secret's variable name to an object of "VARIABLE": "value" pairs (e.g. { "HAS_PROD_ACCESS": { "RENDER_API_KEY": "rnd_\u2026" } }).`
|
|
8136
|
+
);
|
|
8137
|
+
return {};
|
|
8138
|
+
}
|
|
8139
|
+
return result.data;
|
|
8140
|
+
}
|
|
8141
|
+
function harnessSecretEnv(parts) {
|
|
8142
|
+
const env = {};
|
|
8143
|
+
const dropped = [];
|
|
8144
|
+
for (const [name, value] of Object.entries({
|
|
8145
|
+
...parts.deviceDefaults,
|
|
8146
|
+
...parts.granted,
|
|
8147
|
+
...parts.issued
|
|
8148
|
+
})) {
|
|
8149
|
+
if (environmentSafe(value)) env[name] = value;
|
|
8150
|
+
else dropped.push(name);
|
|
8151
|
+
}
|
|
8152
|
+
return { env, dropped };
|
|
8153
|
+
}
|
|
8154
|
+
function grantEnv(sent, issuedBySecret, issued) {
|
|
8155
|
+
const env = {};
|
|
8156
|
+
for (const [key, entry] of Object.entries(sent ?? {})) {
|
|
8157
|
+
if (!Object.hasOwn(issuedBySecret, key)) continue;
|
|
8158
|
+
for (const [variable, value] of Object.entries(entry)) {
|
|
8159
|
+
if (Object.hasOwn(issued, variable) || Object.hasOwn(env, variable)) continue;
|
|
8160
|
+
env[variable] = value;
|
|
8161
|
+
}
|
|
8162
|
+
}
|
|
8163
|
+
return env;
|
|
8164
|
+
}
|
|
8165
|
+
var VARIABLE_NAME_RE, grantsFileSchema;
|
|
8166
|
+
var init_grants = __esm({
|
|
8167
|
+
"src/grants.ts"() {
|
|
8168
|
+
"use strict";
|
|
8169
|
+
init_config();
|
|
8170
|
+
VARIABLE_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
8171
|
+
grantsFileSchema = z15.record(z15.string(), z15.record(z15.string(), z15.string()));
|
|
8172
|
+
}
|
|
8173
|
+
});
|
|
8174
|
+
|
|
8075
8175
|
// src/work-dir.ts
|
|
8076
8176
|
import { statSync as statSync3 } from "fs";
|
|
8077
|
-
import { join as
|
|
8177
|
+
import { join as join15 } from "path";
|
|
8078
8178
|
function pairDirectory(root, pair) {
|
|
8079
|
-
return
|
|
8179
|
+
return join15(root, pair.workspaceSlug, pair.agentUsername, pair.conversationId);
|
|
8080
8180
|
}
|
|
8081
8181
|
function chooseStandingDirectory(named, pairDir, isDirectory = directoryExists) {
|
|
8082
8182
|
const skipped = [];
|
|
@@ -8101,7 +8201,7 @@ var init_work_dir = __esm({
|
|
|
8101
8201
|
|
|
8102
8202
|
// src/turn-control-tools.ts
|
|
8103
8203
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
8104
|
-
import { z as
|
|
8204
|
+
import { z as z16 } from "zod";
|
|
8105
8205
|
function createSkipState() {
|
|
8106
8206
|
return { skipped: false, reason: null };
|
|
8107
8207
|
}
|
|
@@ -8152,7 +8252,7 @@ function createTurnControlMcpServer(acts, skipState) {
|
|
|
8152
8252
|
SKIP_TURN_TOOL,
|
|
8153
8253
|
TURN_CONTROL_TOOL_DESCRIPTIONS.skip_turn,
|
|
8154
8254
|
{
|
|
8155
|
-
reason:
|
|
8255
|
+
reason: z16.string().min(1).max(MAX_SKIP_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.skip_turn.reason)
|
|
8156
8256
|
},
|
|
8157
8257
|
async (args) => {
|
|
8158
8258
|
skipState.skipped = true;
|
|
@@ -8168,22 +8268,22 @@ function createTurnControlMcpServer(acts, skipState) {
|
|
|
8168
8268
|
ASK_TOOL,
|
|
8169
8269
|
TURN_CONTROL_TOOL_DESCRIPTIONS.ask,
|
|
8170
8270
|
{
|
|
8171
|
-
targetUserId:
|
|
8172
|
-
question:
|
|
8173
|
-
headline:
|
|
8174
|
-
options:
|
|
8175
|
-
questions:
|
|
8176
|
-
|
|
8177
|
-
headline:
|
|
8178
|
-
body:
|
|
8179
|
-
options:
|
|
8180
|
-
|
|
8271
|
+
targetUserId: z16.string().regex(ASK_TARGET_PATTERN, { error: ASK_TARGET_INVALID }).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.targetUserId),
|
|
8272
|
+
question: z16.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.question),
|
|
8273
|
+
headline: z16.string().min(1).max(MAX_ASK_HEADLINE_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.headline),
|
|
8274
|
+
options: z16.array(z16.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.options),
|
|
8275
|
+
questions: z16.array(
|
|
8276
|
+
z16.object({
|
|
8277
|
+
headline: z16.string().min(1).max(MAX_ASK_HEADLINE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.headline"]),
|
|
8278
|
+
body: z16.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.body"]),
|
|
8279
|
+
options: z16.array(
|
|
8280
|
+
z16.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)
|
|
8181
8281
|
).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.options"])
|
|
8182
8282
|
})
|
|
8183
8283
|
).min(1).max(MAX_ASK_ITEMS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.questions),
|
|
8184
|
-
replaces:
|
|
8185
|
-
askId:
|
|
8186
|
-
reason:
|
|
8284
|
+
replaces: z16.object({
|
|
8285
|
+
askId: z16.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.askId"]),
|
|
8286
|
+
reason: z16.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.reason"])
|
|
8187
8287
|
}).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.replaces)
|
|
8188
8288
|
},
|
|
8189
8289
|
async (args) => {
|
|
@@ -8224,9 +8324,9 @@ function createTurnControlMcpServer(acts, skipState) {
|
|
|
8224
8324
|
WAKE_ME_TOOL,
|
|
8225
8325
|
TURN_CONTROL_TOOL_DESCRIPTIONS.wake_me,
|
|
8226
8326
|
{
|
|
8227
|
-
afterSeconds:
|
|
8228
|
-
at:
|
|
8229
|
-
note:
|
|
8327
|
+
afterSeconds: z16.number().int().positive().optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.afterSeconds),
|
|
8328
|
+
at: z16.string().datetime({ offset: true }).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.at),
|
|
8329
|
+
note: z16.string().min(1).max(MAX_WAKE_NOTE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.note)
|
|
8230
8330
|
},
|
|
8231
8331
|
async (args) => {
|
|
8232
8332
|
const hasAfter = args.afterSeconds !== void 0;
|
|
@@ -8260,8 +8360,8 @@ function createTurnControlMcpServer(acts, skipState) {
|
|
|
8260
8360
|
WITHDRAW_ASK_TOOL,
|
|
8261
8361
|
TURN_CONTROL_TOOL_DESCRIPTIONS.withdraw_ask,
|
|
8262
8362
|
{
|
|
8263
|
-
askId:
|
|
8264
|
-
reason:
|
|
8363
|
+
askId: z16.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.askId),
|
|
8364
|
+
reason: z16.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.reason)
|
|
8265
8365
|
},
|
|
8266
8366
|
async (args) => performAct(acts, {
|
|
8267
8367
|
kind: "withdraw_ask",
|
|
@@ -8359,10 +8459,10 @@ var init_build_options = __esm({
|
|
|
8359
8459
|
// src/codex-config.ts
|
|
8360
8460
|
import { readFile as readFile2 } from "fs/promises";
|
|
8361
8461
|
import { homedir as homedir7 } from "os";
|
|
8362
|
-
import { join as
|
|
8462
|
+
import { join as join16 } from "path";
|
|
8363
8463
|
import { parse } from "smol-toml";
|
|
8364
8464
|
function codexConfigPath(env = process.env, home = homedir7()) {
|
|
8365
|
-
return
|
|
8465
|
+
return join16(env.CODEX_HOME || join16(home, ".codex"), "config.toml");
|
|
8366
8466
|
}
|
|
8367
8467
|
async function readCodexConfigSetsSandboxMode(path = codexConfigPath()) {
|
|
8368
8468
|
let text;
|
|
@@ -8389,13 +8489,13 @@ var init_codex_config = __esm({
|
|
|
8389
8489
|
// src/codex-images.ts
|
|
8390
8490
|
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
8391
8491
|
import { tmpdir } from "os";
|
|
8392
|
-
import { join as
|
|
8492
|
+
import { join as join17 } from "path";
|
|
8393
8493
|
function createCodexImagePreparer(opts) {
|
|
8394
8494
|
const doFetch = opts.fetch ?? fetch;
|
|
8395
8495
|
const timeoutMs = opts.timeoutMs ?? FETCH_TIMEOUT_MS;
|
|
8396
8496
|
return async (urls, signal) => {
|
|
8397
8497
|
signal.throwIfAborted();
|
|
8398
|
-
const dir2 = await mkdtemp(
|
|
8498
|
+
const dir2 = await mkdtemp(join17(tmpdir(), `cabane-codex-images-${opts.turnId}-`));
|
|
8399
8499
|
const cleanup = async () => {
|
|
8400
8500
|
try {
|
|
8401
8501
|
await rm(dir2, { recursive: true, force: true });
|
|
@@ -8416,7 +8516,7 @@ function createCodexImagePreparer(opts) {
|
|
|
8416
8516
|
const ext = EXTENSIONS[type];
|
|
8417
8517
|
if (!ext) throw new Error(`not a vision image type: ${type || "none"}`);
|
|
8418
8518
|
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
8419
|
-
const path =
|
|
8519
|
+
const path = join17(dir2, `image-${index + 1}.${ext}`);
|
|
8420
8520
|
await writeFile(path, bytes, { mode: 384 });
|
|
8421
8521
|
return path;
|
|
8422
8522
|
} catch (err) {
|
|
@@ -8458,9 +8558,9 @@ var init_codex_images = __esm({
|
|
|
8458
8558
|
import { createReadStream } from "fs";
|
|
8459
8559
|
import { readdir } from "fs/promises";
|
|
8460
8560
|
import { homedir as homedir8 } from "os";
|
|
8461
|
-
import { join as
|
|
8561
|
+
import { join as join18 } from "path";
|
|
8462
8562
|
import { createInterface as createInterface2 } from "readline";
|
|
8463
|
-
function createCodexCompactionCounter(codexHome = process.env.CODEX_HOME ||
|
|
8563
|
+
function createCodexCompactionCounter(codexHome = process.env.CODEX_HOME || join18(homedir8(), ".codex")) {
|
|
8464
8564
|
return async (threadId) => {
|
|
8465
8565
|
try {
|
|
8466
8566
|
const rollout = await findRollout(codexHome, threadId);
|
|
@@ -8477,7 +8577,7 @@ async function findRollout(codexHome, threadId) {
|
|
|
8477
8577
|
const suffix = `-${threadId}.jsonl`;
|
|
8478
8578
|
for (const offset of [0, -DAY_MS, DAY_MS]) {
|
|
8479
8579
|
const day = new Date(createdAt + offset);
|
|
8480
|
-
const dir2 =
|
|
8580
|
+
const dir2 = join18(
|
|
8481
8581
|
codexHome,
|
|
8482
8582
|
"sessions",
|
|
8483
8583
|
String(day.getUTCFullYear()),
|
|
@@ -8491,7 +8591,7 @@ async function findRollout(codexHome, threadId) {
|
|
|
8491
8591
|
continue;
|
|
8492
8592
|
}
|
|
8493
8593
|
const name = names.find((n) => n.startsWith("rollout-") && n.endsWith(suffix));
|
|
8494
|
-
if (name) return
|
|
8594
|
+
if (name) return join18(dir2, name);
|
|
8495
8595
|
}
|
|
8496
8596
|
return null;
|
|
8497
8597
|
}
|
|
@@ -8623,22 +8723,22 @@ var init_prepare_failure = __esm({
|
|
|
8623
8723
|
});
|
|
8624
8724
|
|
|
8625
8725
|
// src/prepared.ts
|
|
8626
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
8627
|
-
import { join as
|
|
8726
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync8, rmSync as rmSync5, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "fs";
|
|
8727
|
+
import { join as join19 } from "path";
|
|
8628
8728
|
function dirFor(workspaceId) {
|
|
8629
|
-
return
|
|
8729
|
+
return join19(cabaneDir(), "prepared", encodeURIComponent(workspaceId));
|
|
8630
8730
|
}
|
|
8631
8731
|
function conversationDir(workspaceId, conversationId) {
|
|
8632
|
-
return
|
|
8732
|
+
return join19(dirFor(workspaceId), encodeURIComponent(conversationId));
|
|
8633
8733
|
}
|
|
8634
8734
|
function pathFor2(workspaceId, conversationId, agentId) {
|
|
8635
|
-
return
|
|
8735
|
+
return join19(conversationDir(workspaceId, conversationId), `${encodeURIComponent(agentId)}.json`);
|
|
8636
8736
|
}
|
|
8637
8737
|
function readPrepared(workspaceId, conversationId, agentId) {
|
|
8638
8738
|
const path = pathFor2(workspaceId, conversationId, agentId);
|
|
8639
|
-
if (!
|
|
8739
|
+
if (!existsSync10(path)) return null;
|
|
8640
8740
|
try {
|
|
8641
|
-
const parsed = JSON.parse(
|
|
8741
|
+
const parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
8642
8742
|
if (parsed && typeof parsed.cwd === "string" && parsed.cwd.length > 0) {
|
|
8643
8743
|
return {
|
|
8644
8744
|
cwd: parsed.cwd,
|
|
@@ -8669,18 +8769,18 @@ var init_prepared = __esm({
|
|
|
8669
8769
|
});
|
|
8670
8770
|
|
|
8671
8771
|
// src/secrets.ts
|
|
8672
|
-
import { existsSync as
|
|
8673
|
-
import { join as
|
|
8674
|
-
import { z as
|
|
8772
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
8773
|
+
import { join as join20 } from "path";
|
|
8774
|
+
import { z as z17 } from "zod";
|
|
8675
8775
|
function secretsPath() {
|
|
8676
|
-
return
|
|
8776
|
+
return join20(cabaneDir(), "secrets.json");
|
|
8677
8777
|
}
|
|
8678
8778
|
function loadSecretValues() {
|
|
8679
8779
|
const path = secretsPath();
|
|
8680
|
-
if (!
|
|
8780
|
+
if (!existsSync11(path)) return {};
|
|
8681
8781
|
let raw;
|
|
8682
8782
|
try {
|
|
8683
|
-
raw =
|
|
8783
|
+
raw = readFileSync9(path, "utf8");
|
|
8684
8784
|
} catch (err) {
|
|
8685
8785
|
throw new ConfigError(
|
|
8686
8786
|
`couldn't read ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -8798,7 +8898,7 @@ var init_secrets = __esm({
|
|
|
8798
8898
|
init_config();
|
|
8799
8899
|
init_errors();
|
|
8800
8900
|
PLACEHOLDER_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
8801
|
-
secretStoreSchema =
|
|
8901
|
+
secretStoreSchema = z17.record(z17.string(), z17.string());
|
|
8802
8902
|
SECRET_ENV_NAME = /^CABANE_MCP_(\d+)$/;
|
|
8803
8903
|
}
|
|
8804
8904
|
});
|
|
@@ -8830,9 +8930,9 @@ var init_turn_env = __esm({
|
|
|
8830
8930
|
|
|
8831
8931
|
// src/transcript-writer.ts
|
|
8832
8932
|
import { appendFileSync, chmodSync as chmodSync4, copyFileSync, mkdirSync as mkdirSync8, readdirSync, rmSync as rmSync6 } from "fs";
|
|
8833
|
-
import { basename as basename3, dirname as dirname7, join as
|
|
8933
|
+
import { basename as basename3, dirname as dirname7, join as join21 } from "path";
|
|
8834
8934
|
function transcriptsDir() {
|
|
8835
|
-
return
|
|
8935
|
+
return join21(cabaneDir(), "transcripts");
|
|
8836
8936
|
}
|
|
8837
8937
|
function fileName(meta) {
|
|
8838
8938
|
const d = new Date(meta.ts);
|
|
@@ -8858,7 +8958,7 @@ function pruneOld(dir2, retain) {
|
|
|
8858
8958
|
const drop = files.sort().slice(0, files.length - retain);
|
|
8859
8959
|
for (const f of drop) {
|
|
8860
8960
|
try {
|
|
8861
|
-
rmSync6(
|
|
8961
|
+
rmSync6(join21(dir2, f), { force: true });
|
|
8862
8962
|
} catch {
|
|
8863
8963
|
}
|
|
8864
8964
|
}
|
|
@@ -8876,7 +8976,7 @@ var init_transcript_writer = __esm({
|
|
|
8876
8976
|
onWarn;
|
|
8877
8977
|
constructor(dir2, meta, onWarn) {
|
|
8878
8978
|
this.onWarn = onWarn;
|
|
8879
|
-
this.path =
|
|
8979
|
+
this.path = join21(dir2, fileName(meta));
|
|
8880
8980
|
try {
|
|
8881
8981
|
mkdirSync8(dir2, { recursive: true });
|
|
8882
8982
|
try {
|
|
@@ -8905,10 +9005,10 @@ var init_transcript_writer = __esm({
|
|
|
8905
9005
|
preserveAnomaly() {
|
|
8906
9006
|
if (this.broken) return;
|
|
8907
9007
|
try {
|
|
8908
|
-
const dir2 =
|
|
9008
|
+
const dir2 = join21(dirname7(this.path), "anomalies");
|
|
8909
9009
|
mkdirSync8(dir2, { recursive: true, mode: 448 });
|
|
8910
9010
|
chmodSync4(dir2, 448);
|
|
8911
|
-
const target =
|
|
9011
|
+
const target = join21(dir2, basename3(this.path));
|
|
8912
9012
|
copyFileSync(this.path, target);
|
|
8913
9013
|
chmodSync4(target, 384);
|
|
8914
9014
|
pruneOld(dir2, ANOMALY_RETAIN);
|
|
@@ -9204,6 +9304,7 @@ var init_turn_execution = __esm({
|
|
|
9204
9304
|
init_cabane_command();
|
|
9205
9305
|
init_boot_id();
|
|
9206
9306
|
init_src();
|
|
9307
|
+
init_grants();
|
|
9207
9308
|
init_work_dir();
|
|
9208
9309
|
init_build_options();
|
|
9209
9310
|
init_bundled_binaries();
|
|
@@ -9575,7 +9676,19 @@ var init_turn_execution = __esm({
|
|
|
9575
9676
|
throw this.concluded(reason, reason);
|
|
9576
9677
|
}
|
|
9577
9678
|
this.resolvedMcpServers = resolvedMcpServers;
|
|
9578
|
-
|
|
9679
|
+
const granted = grantEnv(this.opts.deviceGrants, this.turnContext.secretEnv ?? {}, secretEnv);
|
|
9680
|
+
const harness = harnessSecretEnv({
|
|
9681
|
+
deviceDefaults: harnessLoginEnv(secretStore, this.turnContext.runtime),
|
|
9682
|
+
granted,
|
|
9683
|
+
issued: secretEnv
|
|
9684
|
+
});
|
|
9685
|
+
if (harness.dropped.length > 0) {
|
|
9686
|
+
turnLog.warn(
|
|
9687
|
+
{ variables: harness.dropped },
|
|
9688
|
+
"Left out a secret value this turn: it contains a NUL character, which no environment can hold."
|
|
9689
|
+
);
|
|
9690
|
+
}
|
|
9691
|
+
this.secretEnv = harness.env;
|
|
9579
9692
|
this.secretStore = secretStore;
|
|
9580
9693
|
}
|
|
9581
9694
|
async prepareEnvironment() {
|
|
@@ -10346,11 +10459,11 @@ var init_turn_execution = __esm({
|
|
|
10346
10459
|
|
|
10347
10460
|
// src/dispatcher.ts
|
|
10348
10461
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
10349
|
-
import { existsSync as
|
|
10350
|
-
import { join as
|
|
10462
|
+
import { existsSync as existsSync12, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
10463
|
+
import { join as join22 } from "path";
|
|
10351
10464
|
function checkoutState(cwd) {
|
|
10352
10465
|
if (!cwd) return { ok: false, reason: "no working directory was resolved for this turn" };
|
|
10353
|
-
if (!
|
|
10466
|
+
if (!existsSync12(cwd)) return { ok: false, reason: `the working directory is gone (${cwd})` };
|
|
10354
10467
|
let entries;
|
|
10355
10468
|
try {
|
|
10356
10469
|
entries = readdirSync2(cwd);
|
|
@@ -10360,15 +10473,15 @@ function checkoutState(cwd) {
|
|
|
10360
10473
|
if (entries.length === 0) {
|
|
10361
10474
|
return { ok: false, reason: `${cwd} is empty \u2014 a recreated shell, not a prepared directory` };
|
|
10362
10475
|
}
|
|
10363
|
-
const gitPath =
|
|
10364
|
-
if (!
|
|
10476
|
+
const gitPath = join22(cwd, ".git");
|
|
10477
|
+
if (!existsSync12(gitPath)) return { ok: true, reason: "usable" };
|
|
10365
10478
|
let stat;
|
|
10366
10479
|
try {
|
|
10367
10480
|
stat = statSync4(gitPath);
|
|
10368
10481
|
} catch (error) {
|
|
10369
10482
|
return { ok: false, reason: `${gitPath} is unreadable (${error.message})` };
|
|
10370
10483
|
}
|
|
10371
|
-
if (stat.isDirectory() && !
|
|
10484
|
+
if (stat.isDirectory() && !existsSync12(join22(gitPath, "HEAD")))
|
|
10372
10485
|
return { ok: false, reason: `${gitPath} has no HEAD \u2014 an empty shell, not a checkout` };
|
|
10373
10486
|
return { ok: true, reason: "usable" };
|
|
10374
10487
|
}
|
|
@@ -10476,15 +10589,15 @@ var init_dispatcher = __esm({
|
|
|
10476
10589
|
|
|
10477
10590
|
// src/outbox.ts
|
|
10478
10591
|
import {
|
|
10479
|
-
existsSync as
|
|
10592
|
+
existsSync as existsSync14,
|
|
10480
10593
|
mkdirSync as mkdirSync10,
|
|
10481
10594
|
readdirSync as readdirSync3,
|
|
10482
|
-
readFileSync as
|
|
10595
|
+
readFileSync as readFileSync11,
|
|
10483
10596
|
renameSync as renameSync5,
|
|
10484
10597
|
rmSync as rmSync7,
|
|
10485
10598
|
writeFileSync as writeFileSync6
|
|
10486
10599
|
} from "fs";
|
|
10487
|
-
import { join as
|
|
10600
|
+
import { join as join23 } from "path";
|
|
10488
10601
|
var MAX_ENTRIES, MAX_AGE_MS, Outbox;
|
|
10489
10602
|
var init_outbox = __esm({
|
|
10490
10603
|
"src/outbox.ts"() {
|
|
@@ -10502,10 +10615,10 @@ var init_outbox = __esm({
|
|
|
10502
10615
|
// Resolved lazily (per call) so tests that swap HOME between
|
|
10503
10616
|
// cases route writes at the right tmpdir.
|
|
10504
10617
|
dir() {
|
|
10505
|
-
return
|
|
10618
|
+
return join23(cabaneDir(), "outbox", encodeURIComponent(this.workspaceId));
|
|
10506
10619
|
}
|
|
10507
10620
|
fileFor(turnId, seq) {
|
|
10508
|
-
return
|
|
10621
|
+
return join23(this.dir(), `${encodeURIComponent(turnId)}__${seq}.json`);
|
|
10509
10622
|
}
|
|
10510
10623
|
// Persist a commit for later draining. Atomic (temp file + rename) so a
|
|
10511
10624
|
// concurrent `list()` never reads a half-written entry, then enforces the
|
|
@@ -10537,7 +10650,7 @@ var init_outbox = __esm({
|
|
|
10537
10650
|
// wedging the drain.
|
|
10538
10651
|
list() {
|
|
10539
10652
|
const dir2 = this.dir();
|
|
10540
|
-
if (!
|
|
10653
|
+
if (!existsSync14(dir2)) return [];
|
|
10541
10654
|
let names;
|
|
10542
10655
|
try {
|
|
10543
10656
|
names = readdirSync3(dir2);
|
|
@@ -10547,9 +10660,9 @@ var init_outbox = __esm({
|
|
|
10547
10660
|
const entries = [];
|
|
10548
10661
|
for (const name of names) {
|
|
10549
10662
|
if (!name.endsWith(".json")) continue;
|
|
10550
|
-
const full =
|
|
10663
|
+
const full = join23(dir2, name);
|
|
10551
10664
|
try {
|
|
10552
|
-
const parsed = JSON.parse(
|
|
10665
|
+
const parsed = JSON.parse(readFileSync11(full, "utf8"));
|
|
10553
10666
|
if (parsed && typeof parsed.turnId === "string" && typeof parsed.seq === "number" && typeof parsed.path === "string") {
|
|
10554
10667
|
entries.push(parsed);
|
|
10555
10668
|
} else {
|
|
@@ -10583,7 +10696,7 @@ var init_outbox = __esm({
|
|
|
10583
10696
|
// different: it is positive evidence that nothing was ever queued here.
|
|
10584
10697
|
maxSeqForTurn(turnId) {
|
|
10585
10698
|
const dir2 = this.dir();
|
|
10586
|
-
if (!
|
|
10699
|
+
if (!existsSync14(dir2)) return 0;
|
|
10587
10700
|
const names = readdirSync3(dir2);
|
|
10588
10701
|
const prefix = `${encodeURIComponent(turnId)}__`;
|
|
10589
10702
|
let max = 0;
|
|
@@ -10603,7 +10716,7 @@ var init_outbox = __esm({
|
|
|
10603
10716
|
}
|
|
10604
10717
|
size() {
|
|
10605
10718
|
const dir2 = this.dir();
|
|
10606
|
-
if (!
|
|
10719
|
+
if (!existsSync14(dir2)) return 0;
|
|
10607
10720
|
try {
|
|
10608
10721
|
return readdirSync3(dir2).filter((n) => n.endsWith(".json")).length;
|
|
10609
10722
|
} catch {
|
|
@@ -10654,7 +10767,7 @@ var init_outbox = __esm({
|
|
|
10654
10767
|
|
|
10655
10768
|
// src/runner/exec-shim.ts
|
|
10656
10769
|
import { chmodSync as chmodSync6, mkdirSync as mkdirSync18, mkdtempSync, rmSync as rmSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
10657
|
-
import { join as
|
|
10770
|
+
import { join as join33 } from "path";
|
|
10658
10771
|
function shellQuote(value) {
|
|
10659
10772
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
10660
10773
|
}
|
|
@@ -10664,10 +10777,10 @@ function createShimDir() {
|
|
|
10664
10777
|
return {
|
|
10665
10778
|
write(argv) {
|
|
10666
10779
|
if (!dir2) {
|
|
10667
|
-
mkdirSync18(
|
|
10668
|
-
dir2 = mkdtempSync(
|
|
10780
|
+
mkdirSync18(join33(cabaneDir(), "runner"), { recursive: true });
|
|
10781
|
+
dir2 = mkdtempSync(join33(cabaneDir(), "runner", "turn-"));
|
|
10669
10782
|
}
|
|
10670
|
-
const path =
|
|
10783
|
+
const path = join33(dir2, `exec-${++count}`);
|
|
10671
10784
|
writeFileSync11(path, `#!/bin/sh
|
|
10672
10785
|
exec ${argv.map(shellQuote).join(" ")} "$@"
|
|
10673
10786
|
`);
|
|
@@ -10815,6 +10928,8 @@ function runnerTurnOptions(input, log2, emit, extras = {}) {
|
|
|
10815
10928
|
// The launcher's copy of the device's secrets, when it sent one: a runner
|
|
10816
10929
|
// in a box has no `secrets.json` to read.
|
|
10817
10930
|
...input.secrets ? { secretStore: makeStore(input.secrets) } : {},
|
|
10931
|
+
// The grants-file entries the launcher read for this dispatch's turn.
|
|
10932
|
+
...input.grants ? { deviceGrants: input.grants } : {},
|
|
10818
10933
|
log: log2,
|
|
10819
10934
|
...queryFn ? { queryFn } : {},
|
|
10820
10935
|
...spec.opencodeServerUrl ? { opencodeServerUrl: spec.opencodeServerUrl } : {},
|
|
@@ -12905,7 +13020,7 @@ var ConnectorHealthStore = class {
|
|
|
12905
13020
|
init_dispatcher();
|
|
12906
13021
|
|
|
12907
13022
|
// src/host-report.ts
|
|
12908
|
-
import { existsSync as
|
|
13023
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
12909
13024
|
import { userInfo as userInfo2 } from "os";
|
|
12910
13025
|
function inContainer(signals) {
|
|
12911
13026
|
if (signals.dockerenv) return true;
|
|
@@ -12916,11 +13031,11 @@ function inContainer(signals) {
|
|
|
12916
13031
|
function readContainerSignals() {
|
|
12917
13032
|
let cgroup = null;
|
|
12918
13033
|
try {
|
|
12919
|
-
cgroup =
|
|
13034
|
+
cgroup = readFileSync10("/proc/1/cgroup", "utf8");
|
|
12920
13035
|
} catch {
|
|
12921
13036
|
cgroup = null;
|
|
12922
13037
|
}
|
|
12923
|
-
return { dockerenv:
|
|
13038
|
+
return { dockerenv: existsSync13("/.dockerenv"), cgroup, env: process.env };
|
|
12924
13039
|
}
|
|
12925
13040
|
function osUser() {
|
|
12926
13041
|
try {
|
|
@@ -13207,6 +13322,7 @@ var DispatchClaims = class {
|
|
|
13207
13322
|
init_outbox();
|
|
13208
13323
|
init_run_config();
|
|
13209
13324
|
init_secrets();
|
|
13325
|
+
init_grants();
|
|
13210
13326
|
|
|
13211
13327
|
// src/sse.ts
|
|
13212
13328
|
init_errors();
|
|
@@ -13332,20 +13448,20 @@ init_transcript_writer();
|
|
|
13332
13448
|
|
|
13333
13449
|
// src/updater.ts
|
|
13334
13450
|
import { spawn as spawn6 } from "child_process";
|
|
13335
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
13336
|
-
import { dirname as dirname11, join as
|
|
13451
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync16, mkdirSync as mkdirSync14, renameSync as renameSync9, rmSync as rmSync10 } from "fs";
|
|
13452
|
+
import { dirname as dirname11, join as join27 } from "path";
|
|
13337
13453
|
|
|
13338
13454
|
// src/boot-rule.ts
|
|
13339
13455
|
import {
|
|
13340
13456
|
mkdirSync as mkdirSync11,
|
|
13341
|
-
readFileSync as
|
|
13457
|
+
readFileSync as readFileSync12,
|
|
13342
13458
|
realpathSync as realpathSync4,
|
|
13343
13459
|
renameSync as renameSync6,
|
|
13344
13460
|
rmSync as rmSync8,
|
|
13345
13461
|
symlinkSync,
|
|
13346
13462
|
writeFileSync as writeFileSync7
|
|
13347
13463
|
} from "fs";
|
|
13348
|
-
import { dirname as dirname8, join as
|
|
13464
|
+
import { dirname as dirname8, join as join24 } from "path";
|
|
13349
13465
|
var UNCONFIRMED_WINDOW_MS = 10 * 6e4;
|
|
13350
13466
|
var MAX_STAGE_ATTEMPTS = 3;
|
|
13351
13467
|
function superseded(pending, ...running) {
|
|
@@ -13369,42 +13485,42 @@ function rolledBackState(state, pending, reason, now) {
|
|
|
13369
13485
|
// src/install-layout.ts
|
|
13370
13486
|
init_config();
|
|
13371
13487
|
import {
|
|
13372
|
-
existsSync as
|
|
13488
|
+
existsSync as existsSync15,
|
|
13373
13489
|
lstatSync,
|
|
13374
13490
|
mkdirSync as mkdirSync12,
|
|
13375
|
-
readFileSync as
|
|
13491
|
+
readFileSync as readFileSync13,
|
|
13376
13492
|
readdirSync as readdirSync4,
|
|
13377
13493
|
realpathSync as realpathSync5,
|
|
13378
13494
|
renameSync as renameSync7,
|
|
13379
13495
|
rmSync as rmSync9,
|
|
13380
13496
|
symlinkSync as symlinkSync2
|
|
13381
13497
|
} from "fs";
|
|
13382
|
-
import { dirname as dirname9, join as
|
|
13498
|
+
import { dirname as dirname9, join as join25 } from "path";
|
|
13383
13499
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13384
13500
|
function versionsDir() {
|
|
13385
|
-
return
|
|
13501
|
+
return join25(cabaneDir(), "versions");
|
|
13386
13502
|
}
|
|
13387
13503
|
function currentLink() {
|
|
13388
|
-
return
|
|
13504
|
+
return join25(cabaneDir(), "current");
|
|
13389
13505
|
}
|
|
13390
13506
|
function bootGuardPath() {
|
|
13391
|
-
return
|
|
13507
|
+
return join25(cabaneDir(), "boot-guard.mjs");
|
|
13392
13508
|
}
|
|
13393
13509
|
function pinnedNodeDir() {
|
|
13394
|
-
return
|
|
13510
|
+
return join25(cabaneDir(), "node");
|
|
13395
13511
|
}
|
|
13396
13512
|
function pinnedNodePath() {
|
|
13397
|
-
return
|
|
13513
|
+
return join25(pinnedNodeDir(), "bin", "node");
|
|
13398
13514
|
}
|
|
13399
13515
|
function versionPackageRoot(version) {
|
|
13400
|
-
return
|
|
13516
|
+
return join25(versionsDir(), version, "node_modules", "@cabane", "companion");
|
|
13401
13517
|
}
|
|
13402
13518
|
function ownPackageRoot(moduleUrl = import.meta.url) {
|
|
13403
13519
|
return dirname9(dirname9(fileURLToPath5(moduleUrl)));
|
|
13404
13520
|
}
|
|
13405
13521
|
function packageVersion(root) {
|
|
13406
13522
|
try {
|
|
13407
|
-
const pkg2 = JSON.parse(
|
|
13523
|
+
const pkg2 = JSON.parse(readFileSync13(join25(root, "package.json"), "utf8"));
|
|
13408
13524
|
return typeof pkg2.version === "string" ? pkg2.version : null;
|
|
13409
13525
|
} catch {
|
|
13410
13526
|
return null;
|
|
@@ -13413,7 +13529,7 @@ function packageVersion(root) {
|
|
|
13413
13529
|
function currentRoot() {
|
|
13414
13530
|
try {
|
|
13415
13531
|
const root = realpathSync5(currentLink());
|
|
13416
|
-
return
|
|
13532
|
+
return existsSync15(join25(root, "dist", "cli.js")) ? root : null;
|
|
13417
13533
|
} catch {
|
|
13418
13534
|
return null;
|
|
13419
13535
|
}
|
|
@@ -13432,11 +13548,11 @@ function pointCurrentAt(root) {
|
|
|
13432
13548
|
}
|
|
13433
13549
|
function pruneVersions(keep) {
|
|
13434
13550
|
const dir2 = versionsDir();
|
|
13435
|
-
if (!
|
|
13551
|
+
if (!existsSync15(dir2)) return [];
|
|
13436
13552
|
const removed = [];
|
|
13437
13553
|
for (const name of readdirSync4(dir2)) {
|
|
13438
13554
|
if (keep.includes(name)) continue;
|
|
13439
|
-
rmSync9(
|
|
13555
|
+
rmSync9(join25(dir2, name), { recursive: true, force: true });
|
|
13440
13556
|
removed.push(name);
|
|
13441
13557
|
}
|
|
13442
13558
|
return removed;
|
|
@@ -13455,36 +13571,36 @@ function compareVersions(a, b) {
|
|
|
13455
13571
|
|
|
13456
13572
|
// src/update-state.ts
|
|
13457
13573
|
init_config();
|
|
13458
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
13459
|
-
import { dirname as dirname10, join as
|
|
13460
|
-
import { z as
|
|
13461
|
-
var resultSchema =
|
|
13462
|
-
kind:
|
|
13463
|
-
from:
|
|
13464
|
-
to:
|
|
13465
|
-
at:
|
|
13466
|
-
reason:
|
|
13574
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
13575
|
+
import { dirname as dirname10, join as join26 } from "path";
|
|
13576
|
+
import { z as z18 } from "zod";
|
|
13577
|
+
var resultSchema = z18.object({
|
|
13578
|
+
kind: z18.enum(["updated", "rolled_back", "failed"]),
|
|
13579
|
+
from: z18.string(),
|
|
13580
|
+
to: z18.string(),
|
|
13581
|
+
at: z18.string(),
|
|
13582
|
+
reason: z18.string().optional()
|
|
13467
13583
|
});
|
|
13468
|
-
var pendingSchema =
|
|
13469
|
-
from:
|
|
13584
|
+
var pendingSchema = z18.object({
|
|
13585
|
+
from: z18.string(),
|
|
13470
13586
|
// The package root `current` pointed at before the swap, so a rollback can point it back.
|
|
13471
|
-
fromRoot:
|
|
13472
|
-
to:
|
|
13473
|
-
at:
|
|
13474
|
-
boots:
|
|
13587
|
+
fromRoot: z18.string(),
|
|
13588
|
+
to: z18.string(),
|
|
13589
|
+
at: z18.string(),
|
|
13590
|
+
boots: z18.number().int().nonnegative()
|
|
13475
13591
|
});
|
|
13476
|
-
var stateSchema =
|
|
13477
|
-
server:
|
|
13592
|
+
var stateSchema = z18.object({
|
|
13593
|
+
server: z18.object({ latest: z18.string(), minimum: z18.string(), at: z18.string() }).optional(),
|
|
13478
13594
|
pending: pendingSchema.optional(),
|
|
13479
13595
|
lastResult: resultSchema.optional(),
|
|
13480
|
-
failed:
|
|
13596
|
+
failed: z18.object({ version: z18.string(), attempts: z18.number().int(), at: z18.string() }).optional()
|
|
13481
13597
|
});
|
|
13482
13598
|
function updateStatePath(dir2 = cabaneDir()) {
|
|
13483
|
-
return
|
|
13599
|
+
return join26(dir2, "update.json");
|
|
13484
13600
|
}
|
|
13485
13601
|
function readUpdateState(path = updateStatePath()) {
|
|
13486
13602
|
try {
|
|
13487
|
-
const parsed = stateSchema.safeParse(JSON.parse(
|
|
13603
|
+
const parsed = stateSchema.safeParse(JSON.parse(readFileSync14(path, "utf8")));
|
|
13488
13604
|
return parsed.success ? parsed.data : {};
|
|
13489
13605
|
} catch {
|
|
13490
13606
|
return {};
|
|
@@ -13525,12 +13641,12 @@ function versionToStage(input) {
|
|
|
13525
13641
|
return latest;
|
|
13526
13642
|
}
|
|
13527
13643
|
function rollBack(pending, reason, now = /* @__PURE__ */ new Date()) {
|
|
13528
|
-
if (
|
|
13644
|
+
if (existsSync16(pending.fromRoot)) pointCurrentAt(pending.fromRoot);
|
|
13529
13645
|
return updateUpdateState((state) => rolledBackState(state, pending, reason, now));
|
|
13530
13646
|
}
|
|
13531
13647
|
function writeBootGuard(root = ownPackageRoot()) {
|
|
13532
|
-
const built =
|
|
13533
|
-
if (!
|
|
13648
|
+
const built = join27(root, "dist", "boot-guard.js");
|
|
13649
|
+
if (!existsSync16(built)) return false;
|
|
13534
13650
|
const target = bootGuardPath();
|
|
13535
13651
|
mkdirSync14(dirname11(target), { recursive: true });
|
|
13536
13652
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
@@ -13569,17 +13685,17 @@ var runProcess = (command, args, opts = {}) => new Promise((resolve2) => {
|
|
|
13569
13685
|
async function stageVersion(version, harnesses, deps = {}) {
|
|
13570
13686
|
const run = deps.run ?? runProcess;
|
|
13571
13687
|
const node = deps.execPath ?? process.execPath;
|
|
13572
|
-
const target =
|
|
13688
|
+
const target = join27(versionsDir(), version);
|
|
13573
13689
|
const placed = versionPackageRoot(version);
|
|
13574
|
-
if (
|
|
13690
|
+
if (existsSync16(placed)) {
|
|
13575
13691
|
if (!await verifyInstall(placed, version, harnesses, { run, execPath: node }))
|
|
13576
13692
|
return { ok: true, root: placed };
|
|
13577
13693
|
}
|
|
13578
|
-
const npm =
|
|
13579
|
-
if (!
|
|
13694
|
+
const npm = join27(dirname11(node), "npm");
|
|
13695
|
+
if (!existsSync16(npm))
|
|
13580
13696
|
return { ok: false, reason: `there is no npm beside Node at ${dirname11(node)}` };
|
|
13581
13697
|
mkdirSync14(versionsDir(), { recursive: true });
|
|
13582
|
-
const staging =
|
|
13698
|
+
const staging = join27(versionsDir(), `.${version}.staging-${process.pid}`);
|
|
13583
13699
|
rmSync10(staging, { recursive: true, force: true });
|
|
13584
13700
|
const installed = await run(
|
|
13585
13701
|
npm,
|
|
@@ -13608,7 +13724,7 @@ async function stageVersion(version, harnesses, deps = {}) {
|
|
|
13608
13724
|
return { ok: false, reason: `version ${version} isn't published yet`, unpublished: true };
|
|
13609
13725
|
return { ok: false, reason: `npm couldn't install it: ${lastLine(installed.stderr)}` };
|
|
13610
13726
|
}
|
|
13611
|
-
const root =
|
|
13727
|
+
const root = join27(staging, "node_modules", "@cabane", "companion");
|
|
13612
13728
|
const verdict = await verifyInstall(root, version, harnesses, { run, execPath: node });
|
|
13613
13729
|
if (verdict) {
|
|
13614
13730
|
rmSync10(staging, { recursive: true, force: true });
|
|
@@ -13620,7 +13736,7 @@ async function stageVersion(version, harnesses, deps = {}) {
|
|
|
13620
13736
|
}
|
|
13621
13737
|
async function verifyInstall(root, version, harnesses, deps) {
|
|
13622
13738
|
if (packageVersion(root) !== version) return `the installed package isn't version ${version}`;
|
|
13623
|
-
const answered = await deps.run(deps.execPath, [
|
|
13739
|
+
const answered = await deps.run(deps.execPath, [join27(root, "dist", "bin.js"), "--version"], {
|
|
13624
13740
|
timeoutMs: 6e4,
|
|
13625
13741
|
env: { ...process.env, CABANE_LAUNCH_SELF: "1" }
|
|
13626
13742
|
});
|
|
@@ -13628,7 +13744,7 @@ async function verifyInstall(root, version, harnesses, deps) {
|
|
|
13628
13744
|
return `it doesn't start: ${lastLine(answered.stderr) || "no version printed"}`;
|
|
13629
13745
|
}
|
|
13630
13746
|
if (harnesses.length === 0) return null;
|
|
13631
|
-
const probed = await deps.run(deps.execPath, [
|
|
13747
|
+
const probed = await deps.run(deps.execPath, [join27(root, "dist", "postinstall.js"), "--json"], {
|
|
13632
13748
|
timeoutMs: 6e4
|
|
13633
13749
|
});
|
|
13634
13750
|
let resolutions = {};
|
|
@@ -14625,6 +14741,14 @@ var CompanionSupervisor = class {
|
|
|
14625
14741
|
(m) => this.log.warn({ err: m }, "Could not read the secrets file for a boxed turn.")
|
|
14626
14742
|
)
|
|
14627
14743
|
} : {},
|
|
14744
|
+
// Read per dispatch, for the secret variables its mint named and no others.
|
|
14745
|
+
grants: (keys) => readGrants(keys, {
|
|
14746
|
+
refusedVariable: (key, variable) => this.log.warn(
|
|
14747
|
+
{ key, variable },
|
|
14748
|
+
"Skipped a variable in ~/.cabane/grants.json: its name must use capital letters, digits and underscores, not starting with CABANE_, and its value cannot contain a NUL character."
|
|
14749
|
+
),
|
|
14750
|
+
unreadable: (message2) => this.log.warn({ err: message2 }, "Could not read the grants file.")
|
|
14751
|
+
}),
|
|
14628
14752
|
...this.runnerEnv ? { env: this.runnerEnv } : {},
|
|
14629
14753
|
reportRunnerGone: (report) => this.reportRunnerGone(report),
|
|
14630
14754
|
connectorHealth: this.connectorHealth,
|
|
@@ -15317,10 +15441,10 @@ function handleUncaught(log2, err, origin) {
|
|
|
15317
15441
|
|
|
15318
15442
|
// src/crash-marker.ts
|
|
15319
15443
|
init_config();
|
|
15320
|
-
import { existsSync as
|
|
15321
|
-
import { join as
|
|
15444
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync15, readFileSync as readFileSync15, rmSync as rmSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
15445
|
+
import { join as join28 } from "path";
|
|
15322
15446
|
function crashMarkerPath() {
|
|
15323
|
-
return
|
|
15447
|
+
return join28(cabaneDir(), "last-error.json");
|
|
15324
15448
|
}
|
|
15325
15449
|
function recordCrash(rec2) {
|
|
15326
15450
|
try {
|
|
@@ -15332,7 +15456,7 @@ function recordCrash(rec2) {
|
|
|
15332
15456
|
function clearCrash() {
|
|
15333
15457
|
try {
|
|
15334
15458
|
const path = crashMarkerPath();
|
|
15335
|
-
if (
|
|
15459
|
+
if (existsSync17(path)) rmSync11(path, { force: true });
|
|
15336
15460
|
} catch {
|
|
15337
15461
|
}
|
|
15338
15462
|
}
|
|
@@ -15340,8 +15464,8 @@ function clearCrash() {
|
|
|
15340
15464
|
// src/stray-companion.ts
|
|
15341
15465
|
init_config();
|
|
15342
15466
|
import { spawnSync } from "child_process";
|
|
15343
|
-
import { readFileSync as
|
|
15344
|
-
import { join as
|
|
15467
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
15468
|
+
import { join as join29 } from "path";
|
|
15345
15469
|
var COMPANION_ENTRY = /@cabane\/companion\/|cabane-companion|(^|[\s/])cabane\s|\.cabane\/(versions|current|boot-guard)/;
|
|
15346
15470
|
var START = /\sstart(\s|$)/;
|
|
15347
15471
|
function companionStarts(psOutput) {
|
|
@@ -15358,7 +15482,7 @@ function companionStarts(psOutput) {
|
|
|
15358
15482
|
}
|
|
15359
15483
|
function stateDirOf(env) {
|
|
15360
15484
|
const home = env.CABANE_COMPANION_HOME || env.HOME;
|
|
15361
|
-
return home ?
|
|
15485
|
+
return home ? join29(home, ".cabane") : null;
|
|
15362
15486
|
}
|
|
15363
15487
|
function envFromPsE(output, command) {
|
|
15364
15488
|
const line = output.replace(/\n$/, "");
|
|
@@ -15373,7 +15497,7 @@ function envFromPsE(output, command) {
|
|
|
15373
15497
|
function envFromProc(pid) {
|
|
15374
15498
|
try {
|
|
15375
15499
|
const env = {};
|
|
15376
|
-
for (const entry of
|
|
15500
|
+
for (const entry of readFileSync16(`/proc/${pid}/environ`, "utf8").split("\0")) {
|
|
15377
15501
|
const eq = entry.indexOf("=");
|
|
15378
15502
|
if (eq > 0) env[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
15379
15503
|
}
|
|
@@ -15625,15 +15749,15 @@ import { createHash as createHash3 } from "crypto";
|
|
|
15625
15749
|
import {
|
|
15626
15750
|
chmodSync as chmodSync5,
|
|
15627
15751
|
cpSync,
|
|
15628
|
-
existsSync as
|
|
15752
|
+
existsSync as existsSync18,
|
|
15629
15753
|
mkdirSync as mkdirSync16,
|
|
15630
|
-
readFileSync as
|
|
15754
|
+
readFileSync as readFileSync17,
|
|
15631
15755
|
renameSync as renameSync10,
|
|
15632
15756
|
rmSync as rmSync12,
|
|
15633
15757
|
writeFileSync as writeFileSync10
|
|
15634
15758
|
} from "fs";
|
|
15635
15759
|
import { homedir as homedir9, userInfo as userInfo3 } from "os";
|
|
15636
|
-
import { dirname as dirname12, join as
|
|
15760
|
+
import { dirname as dirname12, join as join30, sep as sep3 } from "path";
|
|
15637
15761
|
function servicePlatform(platform = process.platform) {
|
|
15638
15762
|
if (platform === "linux") return "systemd";
|
|
15639
15763
|
if (platform === "darwin") return "launchd";
|
|
@@ -15648,18 +15772,18 @@ function launchdLabel(env = process.env) {
|
|
|
15648
15772
|
return serviceName(env).replace(/^cabane-companion/, "ai.cabane.companion").replace("-", ".");
|
|
15649
15773
|
}
|
|
15650
15774
|
function serviceNode(execPath = process.execPath) {
|
|
15651
|
-
return
|
|
15775
|
+
return existsSync18(pinnedNodePath()) ? pinnedNodePath() : execPath;
|
|
15652
15776
|
}
|
|
15653
15777
|
function servicePaths(platform, env = process.env, home = homedir9(), node = serviceNode()) {
|
|
15654
|
-
const unitFile = platform === "systemd" ?
|
|
15655
|
-
env.XDG_CONFIG_HOME ||
|
|
15778
|
+
const unitFile = platform === "systemd" ? join30(
|
|
15779
|
+
env.XDG_CONFIG_HOME || join30(home, ".config"),
|
|
15656
15780
|
"systemd",
|
|
15657
15781
|
"user",
|
|
15658
15782
|
`${serviceName(env)}.service`
|
|
15659
|
-
) :
|
|
15783
|
+
) : join30(home, "Library", "LaunchAgents", `${launchdLabel(env)}.plist`);
|
|
15660
15784
|
return {
|
|
15661
15785
|
unitFile,
|
|
15662
|
-
envFile:
|
|
15786
|
+
envFile: join30(cabaneDir(), "service.env"),
|
|
15663
15787
|
node,
|
|
15664
15788
|
entry: bootGuardPath()
|
|
15665
15789
|
};
|
|
@@ -15726,7 +15850,7 @@ function renderLaunchdPlist(paths, env = process.env, servicePath) {
|
|
|
15726
15850
|
" <key>ThrottleInterval</key><integer>5</integer>",
|
|
15727
15851
|
// The companion writes its own log; the console copy would only grow a second one.
|
|
15728
15852
|
" <key>StandardOutPath</key><string>/dev/null</string>",
|
|
15729
|
-
` <key>StandardErrorPath</key><string>${xml(
|
|
15853
|
+
` <key>StandardErrorPath</key><string>${xml(join30(cabaneDir(), "service-error.log"))}</string>`,
|
|
15730
15854
|
"</dict>",
|
|
15731
15855
|
"</plist>",
|
|
15732
15856
|
""
|
|
@@ -15782,7 +15906,7 @@ async function installService(deps = {}) {
|
|
|
15782
15906
|
const paths = servicePaths(platform, env, deps.home, node);
|
|
15783
15907
|
const servicePath = await loginShellPath(run, env);
|
|
15784
15908
|
mkdirSync16(dirname12(paths.envFile), { recursive: true });
|
|
15785
|
-
const existing =
|
|
15909
|
+
const existing = existsSync18(paths.envFile) ? readFileSync17(paths.envFile, "utf8") : "";
|
|
15786
15910
|
writeFileSync10(paths.envFile, withServicePath(existing, servicePath), { mode: 384 });
|
|
15787
15911
|
chmodSync5(paths.envFile, 384);
|
|
15788
15912
|
mkdirSync16(dirname12(paths.unitFile), { recursive: true });
|
|
@@ -15838,7 +15962,7 @@ async function uninstallService(deps = {}) {
|
|
|
15838
15962
|
const platform = servicePlatform(deps.platform);
|
|
15839
15963
|
if (!platform) return { ok: true, lines: [] };
|
|
15840
15964
|
const paths = servicePaths(platform, env, deps.home);
|
|
15841
|
-
if (!
|
|
15965
|
+
if (!existsSync18(paths.unitFile)) return { ok: true, lines: ["No Cabane service is installed."] };
|
|
15842
15966
|
await removeUnit(platform, paths, env, run);
|
|
15843
15967
|
return { ok: true, lines: [] };
|
|
15844
15968
|
}
|
|
@@ -15865,16 +15989,16 @@ async function seedManagedInstall(deps) {
|
|
|
15865
15989
|
return { ok: true, root: own };
|
|
15866
15990
|
}
|
|
15867
15991
|
const target = versionPackageRoot(version);
|
|
15868
|
-
if (!
|
|
15869
|
-
const staging =
|
|
15992
|
+
if (!existsSync18(target)) {
|
|
15993
|
+
const staging = join30(versionsDir(), `.${version}.seed-${process.pid}`);
|
|
15870
15994
|
rmSync12(staging, { recursive: true, force: true });
|
|
15871
15995
|
try {
|
|
15872
|
-
cpSync(own,
|
|
15996
|
+
cpSync(own, join30(staging, "node_modules", "@cabane", "companion"), {
|
|
15873
15997
|
recursive: true,
|
|
15874
15998
|
verbatimSymlinks: true
|
|
15875
15999
|
});
|
|
15876
|
-
rmSync12(
|
|
15877
|
-
renameSync10(staging,
|
|
16000
|
+
rmSync12(join30(versionsDir(), version), { recursive: true, force: true });
|
|
16001
|
+
renameSync10(staging, join30(versionsDir(), version));
|
|
15878
16002
|
} catch (err) {
|
|
15879
16003
|
rmSync12(staging, { recursive: true, force: true });
|
|
15880
16004
|
return {
|
|
@@ -15885,7 +16009,7 @@ async function seedManagedInstall(deps) {
|
|
|
15885
16009
|
}
|
|
15886
16010
|
const unrunnable = await verifyInstall(target, version, [], deps);
|
|
15887
16011
|
if (unrunnable) {
|
|
15888
|
-
rmSync12(
|
|
16012
|
+
rmSync12(join30(versionsDir(), version), { recursive: true, force: true });
|
|
15889
16013
|
return { ok: false, reason: `The copy of Cabane for the service can't run: ${unrunnable}.` };
|
|
15890
16014
|
}
|
|
15891
16015
|
pointCurrentAt(target);
|
|
@@ -15897,7 +16021,7 @@ function tildeDir() {
|
|
|
15897
16021
|
function unitNode(platform, unitFile) {
|
|
15898
16022
|
let text;
|
|
15899
16023
|
try {
|
|
15900
|
-
text =
|
|
16024
|
+
text = readFileSync17(unitFile, "utf8");
|
|
15901
16025
|
} catch {
|
|
15902
16026
|
return null;
|
|
15903
16027
|
}
|
|
@@ -15919,9 +16043,9 @@ async function serviceState(deps = {}) {
|
|
|
15919
16043
|
};
|
|
15920
16044
|
if (!platform) return none;
|
|
15921
16045
|
const paths = servicePaths(platform, env, deps.home);
|
|
15922
|
-
if (!
|
|
16046
|
+
if (!existsSync18(paths.unitFile)) return none;
|
|
15923
16047
|
const node = unitNode(platform, paths.unitFile);
|
|
15924
|
-
const nodeOk = node === null ||
|
|
16048
|
+
const nodeOk = node === null || existsSync18(node);
|
|
15925
16049
|
if (platform === "systemd") {
|
|
15926
16050
|
const r2 = await run(
|
|
15927
16051
|
"systemctl",
|
|
@@ -15953,7 +16077,7 @@ async function serviceState(deps = {}) {
|
|
|
15953
16077
|
function serviceInstalled(deps = {}) {
|
|
15954
16078
|
const platform = servicePlatform(deps.platform);
|
|
15955
16079
|
if (!platform) return false;
|
|
15956
|
-
return
|
|
16080
|
+
return existsSync18(servicePaths(platform, deps.env ?? process.env, deps.home).unitFile);
|
|
15957
16081
|
}
|
|
15958
16082
|
function writeAtomic(path, content) {
|
|
15959
16083
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
@@ -15967,12 +16091,12 @@ function userName() {
|
|
|
15967
16091
|
return process.env.USER ?? "";
|
|
15968
16092
|
}
|
|
15969
16093
|
}
|
|
15970
|
-
function rewriteScriptWrappers(dir2 =
|
|
16094
|
+
function rewriteScriptWrappers(dir2 = join30(cabaneDir(), "bin")) {
|
|
15971
16095
|
for (const name of ["cabane", "cabane-companion"]) {
|
|
15972
|
-
const path =
|
|
16096
|
+
const path = join30(dir2, name);
|
|
15973
16097
|
let text;
|
|
15974
16098
|
try {
|
|
15975
|
-
text =
|
|
16099
|
+
text = readFileSync17(path, "utf8");
|
|
15976
16100
|
} catch {
|
|
15977
16101
|
continue;
|
|
15978
16102
|
}
|
|
@@ -16641,7 +16765,7 @@ function writeCompletedPairing(raw) {
|
|
|
16641
16765
|
}
|
|
16642
16766
|
|
|
16643
16767
|
// src/cli.ts
|
|
16644
|
-
import { readFileSync as
|
|
16768
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
16645
16769
|
|
|
16646
16770
|
// src/commands/logs.ts
|
|
16647
16771
|
init_cabane_command();
|
|
@@ -16726,9 +16850,9 @@ async function logs(opts = {}) {
|
|
|
16726
16850
|
init_cabane_command();
|
|
16727
16851
|
init_install_kind();
|
|
16728
16852
|
init_cabane_command();
|
|
16729
|
-
import { readdirSync as readdirSync5, realpathSync as realpathSync6, existsSync as
|
|
16853
|
+
import { readdirSync as readdirSync5, realpathSync as realpathSync6, existsSync as existsSync19 } from "fs";
|
|
16730
16854
|
import { homedir as homedir10 } from "os";
|
|
16731
|
-
import { dirname as dirname13, join as
|
|
16855
|
+
import { dirname as dirname13, join as join31 } from "path";
|
|
16732
16856
|
init_config();
|
|
16733
16857
|
init_secrets();
|
|
16734
16858
|
init_term();
|
|
@@ -17014,7 +17138,7 @@ function versionLine() {
|
|
|
17014
17138
|
const install = companionInstall();
|
|
17015
17139
|
const own = installedCommandPath({ install });
|
|
17016
17140
|
if (install === "script") {
|
|
17017
|
-
return `Cabane ${COMPANION_VERSION} \xB7 installed by the install script (${tildePath(
|
|
17141
|
+
return `Cabane ${COMPANION_VERSION} \xB7 installed by the install script (${tildePath(join31(homedir10(), ".cabane"))})`;
|
|
17018
17142
|
}
|
|
17019
17143
|
if (own)
|
|
17020
17144
|
return `Cabane ${COMPANION_VERSION} \xB7 installed with npm (${tildePath(dirname13(dirname13(own)))})`;
|
|
@@ -17040,7 +17164,7 @@ function otherInstall(install, own) {
|
|
|
17040
17164
|
}
|
|
17041
17165
|
};
|
|
17042
17166
|
if (install === "npm") {
|
|
17043
|
-
const script =
|
|
17167
|
+
const script = join31(
|
|
17044
17168
|
homedir10(),
|
|
17045
17169
|
".cabane",
|
|
17046
17170
|
"node",
|
|
@@ -17049,11 +17173,11 @@ function otherInstall(install, own) {
|
|
|
17049
17173
|
"@cabane",
|
|
17050
17174
|
"companion"
|
|
17051
17175
|
);
|
|
17052
|
-
return
|
|
17176
|
+
return existsSync19(script) ? join31(homedir10(), ".cabane") : null;
|
|
17053
17177
|
}
|
|
17054
17178
|
const found = firstOnPath("cabane-companion", process.env.PATH);
|
|
17055
17179
|
if (!found) return null;
|
|
17056
|
-
const ownAlias = own ? real(
|
|
17180
|
+
const ownAlias = own ? real(join31(dirname13(own), "cabane-companion")) : null;
|
|
17057
17181
|
return real(found) === ownAlias ? null : dirname13(found);
|
|
17058
17182
|
}
|
|
17059
17183
|
function runningMode(running, service2) {
|
|
@@ -17259,8 +17383,8 @@ init_cabane_command();
|
|
|
17259
17383
|
init_errors();
|
|
17260
17384
|
init_src();
|
|
17261
17385
|
init_transcript_writer();
|
|
17262
|
-
import { existsSync as
|
|
17263
|
-
import { basename as basename4, isAbsolute as isAbsolute2, join as
|
|
17386
|
+
import { existsSync as existsSync20, readFileSync as readFileSync18, readdirSync as readdirSync6 } from "fs";
|
|
17387
|
+
import { basename as basename4, isAbsolute as isAbsolute2, join as join32 } from "path";
|
|
17264
17388
|
async function transcript(opts = {}) {
|
|
17265
17389
|
const dir2 = transcriptsDir();
|
|
17266
17390
|
if (opts.follow) {
|
|
@@ -17277,7 +17401,7 @@ async function transcript(opts = {}) {
|
|
|
17277
17401
|
process.stdout.write(emptyMessage(dir2));
|
|
17278
17402
|
return;
|
|
17279
17403
|
}
|
|
17280
|
-
process.stdout.write(renderFile(
|
|
17404
|
+
process.stdout.write(renderFile(join32(dir2, newest)) + "\n");
|
|
17281
17405
|
return;
|
|
17282
17406
|
}
|
|
17283
17407
|
printList(dir2);
|
|
@@ -17360,7 +17484,7 @@ function isComplete(content) {
|
|
|
17360
17484
|
async function followTranscripts(dir2) {
|
|
17361
17485
|
const follower = new TranscriptFollower({
|
|
17362
17486
|
listFiles: () => listFiles(dir2),
|
|
17363
|
-
read: (f) =>
|
|
17487
|
+
read: (f) => readFileSync18(join32(dir2, f), "utf8"),
|
|
17364
17488
|
write: (s) => process.stdout.write(s),
|
|
17365
17489
|
// CSI: cursor up `n` lines, then erase from cursor to end of screen.
|
|
17366
17490
|
clearLines: (n) => process.stdout.write(`\x1B[${n}A\x1B[0J`),
|
|
@@ -17396,7 +17520,7 @@ function listTranscriptFiles(dir2) {
|
|
|
17396
17520
|
if (!entry.isDirectory() || entry.name === "anomalies") continue;
|
|
17397
17521
|
let inner;
|
|
17398
17522
|
try {
|
|
17399
|
-
inner = readdirSync6(
|
|
17523
|
+
inner = readdirSync6(join32(dir2, entry.name));
|
|
17400
17524
|
} catch {
|
|
17401
17525
|
continue;
|
|
17402
17526
|
}
|
|
@@ -17415,7 +17539,7 @@ function printList(dir2) {
|
|
|
17415
17539
|
|
|
17416
17540
|
`);
|
|
17417
17541
|
for (const f of files.slice(0, 20)) {
|
|
17418
|
-
const { meta, outcome } = peek(
|
|
17542
|
+
const { meta, outcome } = peek(join32(dir2, f));
|
|
17419
17543
|
const when = fmtTime(rec(meta)?.ts);
|
|
17420
17544
|
const ws = str2(rec(meta)?.workspaceSlug);
|
|
17421
17545
|
const o = rec(outcome);
|
|
@@ -17437,7 +17561,7 @@ function peek(path) {
|
|
|
17437
17561
|
let meta;
|
|
17438
17562
|
let outcome;
|
|
17439
17563
|
try {
|
|
17440
|
-
for (const line of
|
|
17564
|
+
for (const line of readFileSync18(path, "utf8").split("\n")) {
|
|
17441
17565
|
if (!line.trim()) continue;
|
|
17442
17566
|
const o = safeParse(line);
|
|
17443
17567
|
const t = str2(rec(o)?.type);
|
|
@@ -17450,14 +17574,14 @@ function peek(path) {
|
|
|
17450
17574
|
}
|
|
17451
17575
|
function resolveTarget(dir2, target) {
|
|
17452
17576
|
if (isAbsolute2(target) || target.includes("/")) {
|
|
17453
|
-
if (
|
|
17454
|
-
if (!isAbsolute2(target) &&
|
|
17577
|
+
if (existsSync20(target)) return target;
|
|
17578
|
+
if (!isAbsolute2(target) && existsSync20(join32(dir2, target))) return join32(dir2, target);
|
|
17455
17579
|
throw new CompanionError(`no transcript at ${target}.`);
|
|
17456
17580
|
}
|
|
17457
|
-
const exact =
|
|
17458
|
-
if (
|
|
17581
|
+
const exact = join32(dir2, target);
|
|
17582
|
+
if (existsSync20(exact)) return exact;
|
|
17459
17583
|
const matches = listFiles(dir2).filter((f) => f.includes(target));
|
|
17460
|
-
if (matches.length === 1) return
|
|
17584
|
+
if (matches.length === 1) return join32(dir2, matches[0]);
|
|
17461
17585
|
if (matches.length === 0) {
|
|
17462
17586
|
throw new CompanionError(
|
|
17463
17587
|
`no transcript matching "${target}" in ${dir2}. Run \`${cabane("transcript")}\` to list them.`
|
|
@@ -17471,7 +17595,7 @@ function resolveTarget(dir2, target) {
|
|
|
17471
17595
|
function renderFile(path) {
|
|
17472
17596
|
let content;
|
|
17473
17597
|
try {
|
|
17474
|
-
content =
|
|
17598
|
+
content = readFileSync18(path, "utf8");
|
|
17475
17599
|
} catch (err) {
|
|
17476
17600
|
throw new CompanionError(
|
|
17477
17601
|
`couldn't read ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -17644,7 +17768,7 @@ program.command("setup [code]").description("set up this device: find your agent
|
|
|
17644
17768
|
});
|
|
17645
17769
|
});
|
|
17646
17770
|
program.command("write-paired-config", { hidden: true }).description("persist an already-completed device enrollment payload from stdin.").action(() => {
|
|
17647
|
-
writeCompletedPairing(
|
|
17771
|
+
writeCompletedPairing(readFileSync19(0, "utf8"));
|
|
17648
17772
|
});
|
|
17649
17773
|
program.command("start").description("run Cabane on this device in the background.").option("--foreground", "run attached in this terminal (for terminals and supervisors)").option("--daemon", "run in the background (the default; kept for compatibility)").addOption(new Option("--server <url>").hideHelp()).addOption(
|
|
17650
17774
|
new Option("--log-level <level>", "info (default), warn, or debug").choices([
|