@lambdacurry/arbor 0.24.31 → 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 +81 -9
- 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")
|
|
@@ -16751,7 +16767,7 @@ var ACTIONS = ACTION_DEFINITIONS.map((action) => {
|
|
|
16751
16767
|
});
|
|
16752
16768
|
|
|
16753
16769
|
// ../actions/src/retention-entry.ts
|
|
16754
|
-
var ARBOR_VERSION = "0.24.
|
|
16770
|
+
var ARBOR_VERSION = "0.24.32";
|
|
16755
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");
|
|
16756
16772
|
var retainSourceSchema = boolean2().optional().describe("edit: in checkpoint mode, retain this newly minted content revision's source");
|
|
16757
16773
|
var checkpointSchema = boolean2().optional().describe("edit: retain the exact current version source without incrementing content version");
|
|
@@ -17159,7 +17175,7 @@ function dispositionFilename(value) {
|
|
|
17159
17175
|
// package.json
|
|
17160
17176
|
var package_default = {
|
|
17161
17177
|
name: "@lambdacurry/arbor",
|
|
17162
|
-
version: "0.24.
|
|
17178
|
+
version: "0.24.32",
|
|
17163
17179
|
description: "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
|
|
17164
17180
|
keywords: [
|
|
17165
17181
|
"agents",
|
|
@@ -17595,6 +17611,35 @@ async function waitForComputerExec(executor, input, value, ctx) {
|
|
|
17595
17611
|
return withContinuation(latest);
|
|
17596
17612
|
}
|
|
17597
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
|
+
|
|
17598
17643
|
// src/commands.ts
|
|
17599
17644
|
init_errors();
|
|
17600
17645
|
|
|
@@ -18165,7 +18210,7 @@ Aliases: ${aliases.map((alias) => `\`arbor ${alias}\``).join(", ")} (tool-name f
|
|
|
18165
18210
|
const heading = `${commandWords(action)}${aliases.length === 1 ? ` (alias: ${aliases[0]})` : aliases.length > 1 ? ` (aliases: ${aliases.join(", ")})` : ""}`;
|
|
18166
18211
|
const waitLines = action.name === "computer_exec" ? [
|
|
18167
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"
|
|
18168
|
-
] : [];
|
|
18213
|
+
] : action.name === "computer_run_start" ? [` --wait-ms <number> [optional] — ${WAIT_MS_DESCRIPTION}`] : [];
|
|
18169
18214
|
const notes = action.cliHelpNotes ? `
|
|
18170
18215
|
|
|
18171
18216
|
${action.cliHelpNotes}` : "";
|
|
@@ -18178,9 +18223,10 @@ ${lines.join(`
|
|
|
18178
18223
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
18179
18224
|
`;
|
|
18180
18225
|
}
|
|
18226
|
+
const waitUsage = action.name === "computer_exec" ? " [--no-wait]" : action.name === "computer_run_start" ? " [--wait-ms <number>]" : "";
|
|
18181
18227
|
return `${heading} — ${action.description}
|
|
18182
18228
|
|
|
18183
|
-
${usage}${
|
|
18229
|
+
${usage}${waitUsage}
|
|
18184
18230
|
|
|
18185
18231
|
${[...lines, ...waitLines].join(`
|
|
18186
18232
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
@@ -18207,6 +18253,15 @@ function commandCatalog(actions = CLI_ACTIONS) {
|
|
|
18207
18253
|
acceptsFile: false,
|
|
18208
18254
|
description: "return a running processId immediately instead of polling computer_process_read; mutually exclusive with --wait-for-terminal-ms"
|
|
18209
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
|
+
}
|
|
18210
18265
|
] : []
|
|
18211
18266
|
]
|
|
18212
18267
|
}));
|
|
@@ -18250,6 +18305,20 @@ function resolveCommand(positionals, flags) {
|
|
|
18250
18305
|
const bareFeedbackTree = normalized.length === 1 && normalized[0] === "feedback" && !explicitFeedbackInput;
|
|
18251
18306
|
return bareFeedbackTree ? { action: CLI_ACTIONS.find((action) => action.name === "feedback_tree"), words: 1 } : matchCommand(positionals);
|
|
18252
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
|
+
}
|
|
18253
18322
|
async function runObjectVerb(positionals, flags, ctx) {
|
|
18254
18323
|
const match = resolveCommand(positionals, flags);
|
|
18255
18324
|
if (!match) {
|
|
@@ -18260,6 +18329,8 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18260
18329
|
const action = { ...match.action, inputSchema: canonicalInputShape(match.action) };
|
|
18261
18330
|
applyPositionals(action, positionals.slice(words), flags);
|
|
18262
18331
|
const accepted = acceptedFlags(action.inputSchema);
|
|
18332
|
+
if (action.name === "computer_run_start")
|
|
18333
|
+
accepted.add("wait-ms");
|
|
18263
18334
|
const unknown = Object.keys(flags).filter((f) => !accepted.has(f) && !RESERVED_FLAGS.has(f));
|
|
18264
18335
|
if (unknown.length > 0) {
|
|
18265
18336
|
const hints = unknown.map((f) => listFileHint(action, f)).filter(Boolean);
|
|
@@ -18289,6 +18360,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18289
18360
|
field: "waitForTerminalMs"
|
|
18290
18361
|
});
|
|
18291
18362
|
}
|
|
18363
|
+
const waitMs = action.name === "computer_run_start" ? parseWaitMs(flags["wait-ms"]) : undefined;
|
|
18292
18364
|
if (action.name === "app_request" && input.json !== undefined) {
|
|
18293
18365
|
if (input.body !== undefined) {
|
|
18294
18366
|
throw new UsageError("--json and --body are mutually exclusive", {
|
|
@@ -18309,7 +18381,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18309
18381
|
advise(`Agent registered. Save its apiKey now — it is shown only once:
|
|
18310
18382
|
`, ctx);
|
|
18311
18383
|
}
|
|
18312
|
-
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);
|
|
18313
18385
|
if (action.name === "computer_exec" && !truthyFlag(flags["no-wait"]) && input.waitForTerminalMs === undefined && input.background !== true) {
|
|
18314
18386
|
value = await waitForComputerExec(httpExecutor, input, value, ctx);
|
|
18315
18387
|
}
|
|
@@ -18322,7 +18394,7 @@ init_config();
|
|
|
18322
18394
|
// src/connect.ts
|
|
18323
18395
|
init_config();
|
|
18324
18396
|
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
18325
|
-
var
|
|
18397
|
+
var sleep3 = (ms) => new Promise((r) => globalThis.setTimeout(r, ms));
|
|
18326
18398
|
function bareConnectUrl(apiUrl, returnedUrl) {
|
|
18327
18399
|
const fallback = `${apiUrl.replace(/\/$/, "")}/connect`;
|
|
18328
18400
|
if (!returnedUrl)
|
|
@@ -18380,7 +18452,7 @@ async function connect2(opts) {
|
|
|
18380
18452
|
if (typeof globalThis.setTimeout !== "function") {
|
|
18381
18453
|
throw new Error("approval pending — approve it, then rerun the same `arbor connect` command to finish saving this agent's credential");
|
|
18382
18454
|
}
|
|
18383
|
-
await
|
|
18455
|
+
await sleep3(pollIntervalMs);
|
|
18384
18456
|
continue;
|
|
18385
18457
|
}
|
|
18386
18458
|
if (tok.status === "expired")
|
|
@@ -18400,7 +18472,7 @@ init_errors();
|
|
|
18400
18472
|
init_config();
|
|
18401
18473
|
var CLIENT_ID = "arbor-cli";
|
|
18402
18474
|
var GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
18403
|
-
var
|
|
18475
|
+
var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18404
18476
|
async function login(opts) {
|
|
18405
18477
|
const apiUrl = opts.url ?? loadConfig().apiUrl;
|
|
18406
18478
|
const codeRes = await fetch(`${apiUrl}/api/auth/device/code`, {
|
|
@@ -18425,7 +18497,7 @@ async function login(opts) {
|
|
|
18425
18497
|
for (;; ) {
|
|
18426
18498
|
if (Date.now() > deadline)
|
|
18427
18499
|
throw new Error("login timed out — run `arbor login` again");
|
|
18428
|
-
await
|
|
18500
|
+
await sleep4(interval);
|
|
18429
18501
|
const tokRes = await fetch(`${apiUrl}/api/auth/device/token`, {
|
|
18430
18502
|
method: "POST",
|
|
18431
18503
|
headers: { "content-type": "application/json" },
|
package/package.json
CHANGED