@lambdacurry/arbor 0.24.30 → 0.24.32
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/dist/arbor.js +84 -10
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -66,6 +66,9 @@ function parseErrorDetails(value) {
|
|
|
66
66
|
details.limit = raw.limit;
|
|
67
67
|
if (typeof raw.retryable === "boolean")
|
|
68
68
|
details.retryable = raw.retryable;
|
|
69
|
+
if (typeof raw.retryAfterMs === "number" && Number.isFinite(raw.retryAfterMs) && raw.retryAfterMs >= 0) {
|
|
70
|
+
details.retryAfterMs = raw.retryAfterMs;
|
|
71
|
+
}
|
|
69
72
|
if (typeof raw.phase === "string")
|
|
70
73
|
details.phase = raw.phase;
|
|
71
74
|
if (raw.provider && typeof raw.provider === "object" && !Array.isArray(raw.provider)) {
|
|
@@ -81,6 +84,19 @@ function parseErrorDetails(value) {
|
|
|
81
84
|
};
|
|
82
85
|
}
|
|
83
86
|
}
|
|
87
|
+
if (typeof raw.providerCode === "string")
|
|
88
|
+
details.providerCode = raw.providerCode;
|
|
89
|
+
if (raw.providerDetails && typeof raw.providerDetails === "object" && !Array.isArray(raw.providerDetails)) {
|
|
90
|
+
const scalars = Object.entries(raw.providerDetails).filter((entry) => typeof entry[1] === "string" || typeof entry[1] === "number" || typeof entry[1] === "boolean");
|
|
91
|
+
if (scalars.length > 0)
|
|
92
|
+
details.providerDetails = Object.fromEntries(scalars);
|
|
93
|
+
}
|
|
94
|
+
if (typeof raw.runStartId === "string")
|
|
95
|
+
details.runStartId = raw.runStartId;
|
|
96
|
+
if (typeof raw.runCreated === "boolean")
|
|
97
|
+
details.runCreated = raw.runCreated;
|
|
98
|
+
if (typeof raw.computerSessionId === "string")
|
|
99
|
+
details.computerSessionId = raw.computerSessionId;
|
|
84
100
|
if (typeof raw.runId === "string")
|
|
85
101
|
details.runId = raw.runId;
|
|
86
102
|
if (typeof raw.operationId === "string")
|
|
@@ -12241,7 +12257,9 @@ function buildOutputSchemas() {
|
|
|
12241
12257
|
runId: id,
|
|
12242
12258
|
runCreated: literal(false),
|
|
12243
12259
|
status: literal("provisioning"),
|
|
12244
|
-
phase: literal("run.admission")
|
|
12260
|
+
phase: literal("run.admission"),
|
|
12261
|
+
idempotencyKey: string2(),
|
|
12262
|
+
nextAction: literal("computer_run_start").describe("No Run exists yet (still provisioning, or stopped before one existed): retry computer_run_start with the same inputs and this idempotencyKey; it replays or resumes this start, never a second Run.")
|
|
12245
12263
|
})
|
|
12246
12264
|
])
|
|
12247
12265
|
}),
|
|
@@ -16749,7 +16767,7 @@ var ACTIONS = ACTION_DEFINITIONS.map((action) => {
|
|
|
16749
16767
|
});
|
|
16750
16768
|
|
|
16751
16769
|
// ../actions/src/retention-entry.ts
|
|
16752
|
-
var ARBOR_VERSION = "0.24.
|
|
16770
|
+
var ARBOR_VERSION = "0.24.32";
|
|
16753
16771
|
var historyPolicySchema = _enum(["full", "checkpoint"]).optional().describe("text Artifacts: future history retention policy; full retains every source snapshot, checkpoint keeps metadata for every revision and source only when explicitly retained");
|
|
16754
16772
|
var retainSourceSchema = boolean2().optional().describe("edit: in checkpoint mode, retain this newly minted content revision's source");
|
|
16755
16773
|
var checkpointSchema = boolean2().optional().describe("edit: retain the exact current version source without incrementing content version");
|
|
@@ -17157,7 +17175,7 @@ function dispositionFilename(value) {
|
|
|
17157
17175
|
// package.json
|
|
17158
17176
|
var package_default = {
|
|
17159
17177
|
name: "@lambdacurry/arbor",
|
|
17160
|
-
version: "0.24.
|
|
17178
|
+
version: "0.24.32",
|
|
17161
17179
|
description: "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
|
|
17162
17180
|
keywords: [
|
|
17163
17181
|
"agents",
|
|
@@ -17593,6 +17611,35 @@ async function waitForComputerExec(executor, input, value, ctx) {
|
|
|
17593
17611
|
return withContinuation(latest);
|
|
17594
17612
|
}
|
|
17595
17613
|
|
|
17614
|
+
// src/computer-run-start-wait.ts
|
|
17615
|
+
init_errors();
|
|
17616
|
+
var DEFAULT_SETUP_RETRY_AFTER_MS = 30000;
|
|
17617
|
+
function isSetupPendingRefusal(details) {
|
|
17618
|
+
return details?.retryable === true && details.suggestedAction === "computer_run_start" && details.phase === "computer.open";
|
|
17619
|
+
}
|
|
17620
|
+
function sleep2(ms) {
|
|
17621
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17622
|
+
}
|
|
17623
|
+
async function startComputerRunWithWait(action, executor, input, waitMs, ctx) {
|
|
17624
|
+
const deadline = Date.now() + waitMs;
|
|
17625
|
+
for (;; ) {
|
|
17626
|
+
try {
|
|
17627
|
+
return await action.run(executor, input);
|
|
17628
|
+
} catch (err) {
|
|
17629
|
+
const details = detailsForError(err);
|
|
17630
|
+
if (!isSetupPendingRefusal(details))
|
|
17631
|
+
throw err;
|
|
17632
|
+
const delay = typeof details?.retryAfterMs === "number" && details.retryAfterMs > 0 ? details.retryAfterMs : DEFAULT_SETUP_RETRY_AFTER_MS;
|
|
17633
|
+
const remaining = deadline - Date.now();
|
|
17634
|
+
if (delay > remaining)
|
|
17635
|
+
throw err;
|
|
17636
|
+
advise(`Computer setup is still running; retrying computer_run_start with the same idempotencyKey in ${Math.round(delay / 1000)}s (${Math.round(remaining / 1000)}s of --wait-ms left).
|
|
17637
|
+
`, ctx);
|
|
17638
|
+
await sleep2(delay);
|
|
17639
|
+
}
|
|
17640
|
+
}
|
|
17641
|
+
}
|
|
17642
|
+
|
|
17596
17643
|
// src/commands.ts
|
|
17597
17644
|
init_errors();
|
|
17598
17645
|
|
|
@@ -18163,7 +18210,7 @@ Aliases: ${aliases.map((alias) => `\`arbor ${alias}\``).join(", ")} (tool-name f
|
|
|
18163
18210
|
const heading = `${commandWords(action)}${aliases.length === 1 ? ` (alias: ${aliases[0]})` : aliases.length > 1 ? ` (aliases: ${aliases.join(", ")})` : ""}`;
|
|
18164
18211
|
const waitLines = action.name === "computer_exec" ? [
|
|
18165
18212
|
" --no-wait [<boolean>] [optional] — return a running processId immediately instead of polling computer_process_read (implied by --background); mutually exclusive with --wait-for-terminal-ms"
|
|
18166
|
-
] : [];
|
|
18213
|
+
] : action.name === "computer_run_start" ? [` --wait-ms <number> [optional] — ${WAIT_MS_DESCRIPTION}`] : [];
|
|
18167
18214
|
const notes = action.cliHelpNotes ? `
|
|
18168
18215
|
|
|
18169
18216
|
${action.cliHelpNotes}` : "";
|
|
@@ -18176,9 +18223,10 @@ ${lines.join(`
|
|
|
18176
18223
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
18177
18224
|
`;
|
|
18178
18225
|
}
|
|
18226
|
+
const waitUsage = action.name === "computer_exec" ? " [--no-wait]" : action.name === "computer_run_start" ? " [--wait-ms <number>]" : "";
|
|
18179
18227
|
return `${heading} — ${action.description}
|
|
18180
18228
|
|
|
18181
|
-
${usage}${
|
|
18229
|
+
${usage}${waitUsage}
|
|
18182
18230
|
|
|
18183
18231
|
${[...lines, ...waitLines].join(`
|
|
18184
18232
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
@@ -18205,6 +18253,15 @@ function commandCatalog(actions = CLI_ACTIONS) {
|
|
|
18205
18253
|
acceptsFile: false,
|
|
18206
18254
|
description: "return a running processId immediately instead of polling computer_process_read; mutually exclusive with --wait-for-terminal-ms"
|
|
18207
18255
|
}
|
|
18256
|
+
] : [],
|
|
18257
|
+
...action.name === "computer_run_start" ? [
|
|
18258
|
+
{
|
|
18259
|
+
flag: "wait-ms",
|
|
18260
|
+
kind: "number",
|
|
18261
|
+
required: false,
|
|
18262
|
+
acceptsFile: false,
|
|
18263
|
+
description: WAIT_MS_DESCRIPTION
|
|
18264
|
+
}
|
|
18208
18265
|
] : []
|
|
18209
18266
|
]
|
|
18210
18267
|
}));
|
|
@@ -18248,6 +18305,20 @@ function resolveCommand(positionals, flags) {
|
|
|
18248
18305
|
const bareFeedbackTree = normalized.length === 1 && normalized[0] === "feedback" && !explicitFeedbackInput;
|
|
18249
18306
|
return bareFeedbackTree ? { action: CLI_ACTIONS.find((action) => action.name === "feedback_tree"), words: 1 } : matchCommand(positionals);
|
|
18250
18307
|
}
|
|
18308
|
+
var WAIT_MS_DESCRIPTION = "CLI-only: while Arbor answers that Computer setup is still running (retryable, suggestedAction computer_run_start), wait each retryAfterMs and repeat this exact start with the same idempotencyKey for up to this many milliseconds; a terminal setup failure or any other error returns at once. Omit for one attempt";
|
|
18309
|
+
function parseWaitMs(value) {
|
|
18310
|
+
const raw = stringFlag(value, "wait-ms");
|
|
18311
|
+
if (raw === undefined)
|
|
18312
|
+
return;
|
|
18313
|
+
const ms = Number(raw);
|
|
18314
|
+
if (!Number.isInteger(ms) || ms < 0) {
|
|
18315
|
+
throw new UsageError(`--wait-ms expects a non-negative whole number of milliseconds, got "${raw}"`, {
|
|
18316
|
+
reason: "validation.invalid_value",
|
|
18317
|
+
field: "waitMs"
|
|
18318
|
+
});
|
|
18319
|
+
}
|
|
18320
|
+
return ms;
|
|
18321
|
+
}
|
|
18251
18322
|
async function runObjectVerb(positionals, flags, ctx) {
|
|
18252
18323
|
const match = resolveCommand(positionals, flags);
|
|
18253
18324
|
if (!match) {
|
|
@@ -18258,6 +18329,8 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18258
18329
|
const action = { ...match.action, inputSchema: canonicalInputShape(match.action) };
|
|
18259
18330
|
applyPositionals(action, positionals.slice(words), flags);
|
|
18260
18331
|
const accepted = acceptedFlags(action.inputSchema);
|
|
18332
|
+
if (action.name === "computer_run_start")
|
|
18333
|
+
accepted.add("wait-ms");
|
|
18261
18334
|
const unknown = Object.keys(flags).filter((f) => !accepted.has(f) && !RESERVED_FLAGS.has(f));
|
|
18262
18335
|
if (unknown.length > 0) {
|
|
18263
18336
|
const hints = unknown.map((f) => listFileHint(action, f)).filter(Boolean);
|
|
@@ -18287,6 +18360,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18287
18360
|
field: "waitForTerminalMs"
|
|
18288
18361
|
});
|
|
18289
18362
|
}
|
|
18363
|
+
const waitMs = action.name === "computer_run_start" ? parseWaitMs(flags["wait-ms"]) : undefined;
|
|
18290
18364
|
if (action.name === "app_request" && input.json !== undefined) {
|
|
18291
18365
|
if (input.body !== undefined) {
|
|
18292
18366
|
throw new UsageError("--json and --body are mutually exclusive", {
|
|
@@ -18307,7 +18381,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18307
18381
|
advise(`Agent registered. Save its apiKey now — it is shown only once:
|
|
18308
18382
|
`, ctx);
|
|
18309
18383
|
}
|
|
18310
|
-
let value = action.name === "attachment_upload" ? await uploadLocalAttachments(httpExecutor, input) : await action.run(httpExecutor, input);
|
|
18384
|
+
let value = action.name === "attachment_upload" ? await uploadLocalAttachments(httpExecutor, input) : waitMs !== undefined ? await startComputerRunWithWait(action, httpExecutor, input, waitMs, ctx) : await action.run(httpExecutor, input);
|
|
18311
18385
|
if (action.name === "computer_exec" && !truthyFlag(flags["no-wait"]) && input.waitForTerminalMs === undefined && input.background !== true) {
|
|
18312
18386
|
value = await waitForComputerExec(httpExecutor, input, value, ctx);
|
|
18313
18387
|
}
|
|
@@ -18320,7 +18394,7 @@ init_config();
|
|
|
18320
18394
|
// src/connect.ts
|
|
18321
18395
|
init_config();
|
|
18322
18396
|
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
18323
|
-
var
|
|
18397
|
+
var sleep3 = (ms) => new Promise((r) => globalThis.setTimeout(r, ms));
|
|
18324
18398
|
function bareConnectUrl(apiUrl, returnedUrl) {
|
|
18325
18399
|
const fallback = `${apiUrl.replace(/\/$/, "")}/connect`;
|
|
18326
18400
|
if (!returnedUrl)
|
|
@@ -18378,7 +18452,7 @@ async function connect2(opts) {
|
|
|
18378
18452
|
if (typeof globalThis.setTimeout !== "function") {
|
|
18379
18453
|
throw new Error("approval pending — approve it, then rerun the same `arbor connect` command to finish saving this agent's credential");
|
|
18380
18454
|
}
|
|
18381
|
-
await
|
|
18455
|
+
await sleep3(pollIntervalMs);
|
|
18382
18456
|
continue;
|
|
18383
18457
|
}
|
|
18384
18458
|
if (tok.status === "expired")
|
|
@@ -18398,7 +18472,7 @@ init_errors();
|
|
|
18398
18472
|
init_config();
|
|
18399
18473
|
var CLIENT_ID = "arbor-cli";
|
|
18400
18474
|
var GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
18401
|
-
var
|
|
18475
|
+
var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18402
18476
|
async function login(opts) {
|
|
18403
18477
|
const apiUrl = opts.url ?? loadConfig().apiUrl;
|
|
18404
18478
|
const codeRes = await fetch(`${apiUrl}/api/auth/device/code`, {
|
|
@@ -18423,7 +18497,7 @@ async function login(opts) {
|
|
|
18423
18497
|
for (;; ) {
|
|
18424
18498
|
if (Date.now() > deadline)
|
|
18425
18499
|
throw new Error("login timed out — run `arbor login` again");
|
|
18426
|
-
await
|
|
18500
|
+
await sleep4(interval);
|
|
18427
18501
|
const tokRes = await fetch(`${apiUrl}/api/auth/device/token`, {
|
|
18428
18502
|
method: "POST",
|
|
18429
18503
|
headers: { "content-type": "application/json" },
|
package/package.json
CHANGED