@lambdacurry/arbor 0.21.9 → 0.21.10
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 +104 -20
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -18365,7 +18365,9 @@ var MCP_OUTPUT_SCHEMAS = {
|
|
|
18365
18365
|
exitCode: exports_external.number().optional(),
|
|
18366
18366
|
processId: exports_external.string().optional(),
|
|
18367
18367
|
status: exports_external.string().optional(),
|
|
18368
|
-
cwd: exports_external.string().optional()
|
|
18368
|
+
cwd: exports_external.string().optional(),
|
|
18369
|
+
execution: exports_external.enum(["completed", "running"]).optional(),
|
|
18370
|
+
nextAction: exports_external.literal("computer_process_read").optional()
|
|
18369
18371
|
}),
|
|
18370
18372
|
computer_process_read: exports_external.looseObject({
|
|
18371
18373
|
status: exports_external.string(),
|
|
@@ -18682,6 +18684,8 @@ var OUTPUT_SHAPERS = {
|
|
|
18682
18684
|
["exitCode", result.exitCode],
|
|
18683
18685
|
["processId", result.processId],
|
|
18684
18686
|
["status", result.status],
|
|
18687
|
+
["execution", result.execution],
|
|
18688
|
+
["nextAction", result.nextAction],
|
|
18685
18689
|
["cwd", input.cwd === undefined ? result.cwd : undefined]
|
|
18686
18690
|
]),
|
|
18687
18691
|
computer_process_read: (result) => defined([
|
|
@@ -18906,7 +18910,9 @@ Arbor's MCP is the collaboration and durable-knowledge surface. Configure, autho
|
|
|
18906
18910
|
8. DURABLE OUTPUT IS AN ARTIFACT, NOT A LONG CONTRIBUTION (AD-201). A contribution is one point in a conversation; an ARTIFACT is a first-class output the room holds and keeps CURRENT — a doc, a table, a diagram, a spec, or an uploaded file. When your point is really a deliverable the team will read or UPDATE later — a table of options, a reference doc, a plan, a rubric — make it an artifact (\`artifact\` verb=create with kind doc/table/diagram/html + \`source\`, or promote a file) instead of pasting it into prose. Text-kind artifacts are LIVING: \`artifact_get\` it, then \`artifact\` verb=edit naming the \`baseVersion\` you read — patches apply exact-match and atomically, one version per call, every version attributed. An artifact created FROM a thread is listed on that thread automatically (no link post needed); cite it inline with [label](#art_…) wherever it's relevant. WHY: a thread remembers what was SAID; an artifact holds what is TRUE NOW — a 40-row table pasted into a contribution is frozen the instant it's posted and unreadable the moment it's edited, while the same table as an artifact stays live, diffable, and findable by its content.
|
|
18907
18911
|
|
|
18908
18912
|
Run \`arbor help\` (or read the MCP tool list) for the exact command/flags — those stay generated from the live action surface, so they're always current.`;
|
|
18909
|
-
var COMPUTER_ORIENTATION = `
|
|
18913
|
+
var COMPUTER_ORIENTATION = `Long Computer work returns a handle — do not hold one tool call for a full test or build. \`computer_exec\` runs a command; if the result is still running, take \`processId\` and poll \`computer_process_read\`. Do not chain \`pnpm test && pnpm build\` in one exec; split steps or pass \`background:true\`. The CLI waits on the same handle unless \`--no-wait\`.
|
|
18914
|
+
|
|
18915
|
+
Arbor Computer is the complete software execution platform attached to Arbor's durable collaboration graph. It configures project environments, executes and verifies work, packages and releases Apps, and preserves reviewable evidence; it does not schedule agents or replace Arbor collaboration.
|
|
18910
18916
|
|
|
18911
18917
|
${ARBOR_FEEDBACK_GUIDANCE}
|
|
18912
18918
|
|
|
@@ -19612,14 +19618,14 @@ var ACTION_DEFINITIONS = [
|
|
|
19612
19618
|
{
|
|
19613
19619
|
name: "computer_exec",
|
|
19614
19620
|
title: "Run a command",
|
|
19615
|
-
description: "Run one bounded shell operation in a parent Computer or Run with ambient GitHub authorization for connected humans.
|
|
19621
|
+
description: "Run one bounded shell operation in a parent Computer or Run with ambient GitHub authorization for connected humans. A long command returns processId if still running — poll computer_process_read (background:true skips the wait; timeout kills the process); after a missed isolated response use computer_run_receipt.operations[].operationId with computer_process_read instead of repeating the mutation.",
|
|
19616
19622
|
inputSchema: {
|
|
19617
19623
|
computerSessionId: exports_external.string().optional().describe("the computerSessionId returned by computer_open, cms_…; required unless runId is supplied"),
|
|
19618
19624
|
command: exports_external.string().min(1).describe("the shell command to run"),
|
|
19619
19625
|
runId: exports_external.string().optional().describe("route this command according to this Run execution placement, run_… (from computer_run_start)"),
|
|
19620
19626
|
cwd: exports_external.string().optional().describe("working directory under /workspace, or under the run; omit to use defaultCwd"),
|
|
19621
|
-
timeout: exports_external.number().int().min(1000).max(1800000).optional().describe("
|
|
19622
|
-
background: exports_external.boolean().optional().describe("start
|
|
19627
|
+
timeout: exports_external.number().int().min(1000).max(1800000).optional().describe("process kill deadline in milliseconds, from 1,000 through 1,800,000 — not the RPC hold"),
|
|
19628
|
+
background: exports_external.boolean().optional().describe("start the process and return immediately without the short RPC wait"),
|
|
19623
19629
|
activityLabel: exports_external.string().min(1).max(COMPUTER_RUN_ACTIVITY_LABEL_MAX).optional().describe("short human-readable label for run-scoped background work; Arbor records this label instead of the raw command or output"),
|
|
19624
19630
|
activityKind: exports_external.literal("verification").optional().describe("mark a labeled run-scoped background command as a verification check; its provider-observed terminal result is recorded as verification.finished"),
|
|
19625
19631
|
strict: exports_external.boolean().optional().describe("fail on the first unhandled command or pipeline failure; defaults to true, set false only for intentional best-effort execution")
|
|
@@ -21633,7 +21639,8 @@ var GLOBAL_BOOLEAN_FLAGS = new Set([
|
|
|
21633
21639
|
"json",
|
|
21634
21640
|
"quiet",
|
|
21635
21641
|
"no-quiet",
|
|
21636
|
-
"help"
|
|
21642
|
+
"help",
|
|
21643
|
+
"no-wait"
|
|
21637
21644
|
]);
|
|
21638
21645
|
var RESERVED_FLAGS = new Set([
|
|
21639
21646
|
...GLOBAL_BOOLEAN_FLAGS,
|
|
@@ -21725,6 +21732,66 @@ function emitDual(data, human, action, ctx) {
|
|
|
21725
21732
|
process.stdout.write(human);
|
|
21726
21733
|
}
|
|
21727
21734
|
|
|
21735
|
+
// src/computer-exec-wait.ts
|
|
21736
|
+
var DEFAULT_PROCESS_DEADLINE_MS = 1800000;
|
|
21737
|
+
var POLL_MS = 400;
|
|
21738
|
+
var processRead = ACTIONS.find((action) => action.name === "computer_process_read");
|
|
21739
|
+
function record3(value) {
|
|
21740
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
21741
|
+
}
|
|
21742
|
+
function isRunning(value) {
|
|
21743
|
+
const status = typeof value.status === "string" ? value.status.toLowerCase() : "";
|
|
21744
|
+
if (value.done === false)
|
|
21745
|
+
return true;
|
|
21746
|
+
if (status === "running" || status === "started" || status === "starting")
|
|
21747
|
+
return true;
|
|
21748
|
+
if (value.done === true)
|
|
21749
|
+
return false;
|
|
21750
|
+
if (status === "completed" || status === "exited" || status === "failed" || status === "cancelled" || status === "terminated" || status === "killed" || status === "unknown") {
|
|
21751
|
+
return false;
|
|
21752
|
+
}
|
|
21753
|
+
if (typeof value.exitCode === "number")
|
|
21754
|
+
return false;
|
|
21755
|
+
return typeof value.processId === "string";
|
|
21756
|
+
}
|
|
21757
|
+
function sleep(ms) {
|
|
21758
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
21759
|
+
}
|
|
21760
|
+
function isComputerExecHandle(value) {
|
|
21761
|
+
const rec = record3(value);
|
|
21762
|
+
return Boolean(rec && typeof rec.processId === "string" && isRunning(rec));
|
|
21763
|
+
}
|
|
21764
|
+
async function waitForComputerExec(executor, input, value, ctx) {
|
|
21765
|
+
if (!processRead || !isComputerExecHandle(value))
|
|
21766
|
+
return value;
|
|
21767
|
+
let latest = value;
|
|
21768
|
+
let cursor = typeof latest.nextCursor === "string" && latest.nextCursor ? latest.nextCursor : undefined;
|
|
21769
|
+
const deadline = Date.now() + (typeof input.timeout === "number" && Number.isFinite(input.timeout) ? input.timeout : DEFAULT_PROCESS_DEADLINE_MS);
|
|
21770
|
+
advise(`Process ${String(latest.processId)} is still running; polling computer_process_read.
|
|
21771
|
+
`, ctx);
|
|
21772
|
+
while (isRunning(latest) && Date.now() < deadline) {
|
|
21773
|
+
await sleep(POLL_MS);
|
|
21774
|
+
const read = record3(await processRead.run(executor, {
|
|
21775
|
+
processId: latest.processId,
|
|
21776
|
+
...cursor ? { cursor } : {},
|
|
21777
|
+
...typeof input.runId === "string" ? { runId: input.runId } : {},
|
|
21778
|
+
...typeof input.computerSessionId === "string" ? { computerSessionId: input.computerSessionId } : {}
|
|
21779
|
+
}));
|
|
21780
|
+
if (!read) {
|
|
21781
|
+
throw new Error("computer_process_read returned an empty result");
|
|
21782
|
+
}
|
|
21783
|
+
latest = read;
|
|
21784
|
+
if (typeof read.nextCursor === "string" && read.nextCursor)
|
|
21785
|
+
cursor = read.nextCursor;
|
|
21786
|
+
const stdout = typeof latest.stdout === "string" ? latest.stdout : "";
|
|
21787
|
+
if (stdout)
|
|
21788
|
+
advise(stdout, ctx);
|
|
21789
|
+
if (latest.recovery)
|
|
21790
|
+
break;
|
|
21791
|
+
}
|
|
21792
|
+
return latest;
|
|
21793
|
+
}
|
|
21794
|
+
|
|
21728
21795
|
// src/schema.ts
|
|
21729
21796
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
21730
21797
|
function kebab(field) {
|
|
@@ -22067,11 +22134,14 @@ Bare arguments fill ${explicitPositionals.map((spec) => `--${spec.flag}`).join("
|
|
|
22067
22134
|
|
|
22068
22135
|
Alias: \`arbor ${alias2}\` (the tool-name form) resolves to this same command.` : "";
|
|
22069
22136
|
const heading = `${commandWords(action)}${alias2 ? ` (alias: ${alias2})` : ""}`;
|
|
22137
|
+
const waitLines = action.name === "computer_exec" ? [
|
|
22138
|
+
" --no-wait [<boolean>] [optional] — return a running processId immediately instead of polling computer_process_read"
|
|
22139
|
+
] : [];
|
|
22070
22140
|
return `${heading} — ${action.description}
|
|
22071
22141
|
|
|
22072
|
-
${usage}
|
|
22142
|
+
${usage}${waitLines.length > 0 ? " [--no-wait]" : ""}
|
|
22073
22143
|
|
|
22074
|
-
${lines.join(`
|
|
22144
|
+
${[...lines, ...waitLines].join(`
|
|
22075
22145
|
`)}${primaryNote}${explicitNote}${aliasNote}
|
|
22076
22146
|
`;
|
|
22077
22147
|
}
|
|
@@ -22080,13 +22150,24 @@ function commandCatalog() {
|
|
|
22080
22150
|
command: commandWords(action),
|
|
22081
22151
|
name: action.name,
|
|
22082
22152
|
description: action.description,
|
|
22083
|
-
flags:
|
|
22084
|
-
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
|
|
22088
|
-
|
|
22089
|
-
|
|
22153
|
+
flags: [
|
|
22154
|
+
...flagsForSchema(action.inputSchema).map((f) => ({
|
|
22155
|
+
flag: f.flag,
|
|
22156
|
+
kind: f.kind,
|
|
22157
|
+
required: f.required,
|
|
22158
|
+
acceptsFile: f.kind === "string",
|
|
22159
|
+
description: f.description
|
|
22160
|
+
})),
|
|
22161
|
+
...action.name === "computer_exec" ? [
|
|
22162
|
+
{
|
|
22163
|
+
flag: "no-wait",
|
|
22164
|
+
kind: "boolean",
|
|
22165
|
+
required: false,
|
|
22166
|
+
acceptsFile: false,
|
|
22167
|
+
description: "return a running processId immediately instead of polling computer_process_read"
|
|
22168
|
+
}
|
|
22169
|
+
] : []
|
|
22170
|
+
]
|
|
22090
22171
|
}));
|
|
22091
22172
|
}
|
|
22092
22173
|
function applyPositionals(action, extras, flags) {
|
|
@@ -22165,13 +22246,16 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
22165
22246
|
advise(`Agent registered. Save its apiKey now — it is shown only once:
|
|
22166
22247
|
`, ctx);
|
|
22167
22248
|
}
|
|
22168
|
-
|
|
22249
|
+
let value = await action.run(httpExecutor, input);
|
|
22250
|
+
if (action.name === "computer_exec" && !truthyFlag(flags["no-wait"])) {
|
|
22251
|
+
value = await waitForComputerExec(httpExecutor, input, value, ctx);
|
|
22252
|
+
}
|
|
22169
22253
|
emitData(shapeActionOutput(action.name, value, input), action.name, ctx);
|
|
22170
22254
|
}
|
|
22171
22255
|
|
|
22172
22256
|
// src/connect.ts
|
|
22173
22257
|
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
22174
|
-
var
|
|
22258
|
+
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
22175
22259
|
function bareConnectUrl(apiUrl, returnedUrl) {
|
|
22176
22260
|
const fallback = `${apiUrl.replace(/\/$/, "")}/connect`;
|
|
22177
22261
|
if (!returnedUrl)
|
|
@@ -22215,7 +22299,7 @@ async function connect(opts) {
|
|
|
22215
22299
|
if (Date.now() > deadline) {
|
|
22216
22300
|
throw new Error("pairing timed out — ask for a new pairing key and run `arbor connect` again");
|
|
22217
22301
|
}
|
|
22218
|
-
await
|
|
22302
|
+
await sleep2(pollIntervalMs);
|
|
22219
22303
|
const tokRes = await fetch(`${apiUrl}/api/agent/connect/token`, {
|
|
22220
22304
|
method: "POST",
|
|
22221
22305
|
headers,
|
|
@@ -22241,7 +22325,7 @@ async function connect(opts) {
|
|
|
22241
22325
|
// src/login.ts
|
|
22242
22326
|
var CLIENT_ID = "arbor-cli";
|
|
22243
22327
|
var GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
22244
|
-
var
|
|
22328
|
+
var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
22245
22329
|
async function login(opts) {
|
|
22246
22330
|
const apiUrl = opts.url ?? loadConfig().apiUrl;
|
|
22247
22331
|
const codeRes = await fetch(`${apiUrl}/api/auth/device/code`, {
|
|
@@ -22266,7 +22350,7 @@ async function login(opts) {
|
|
|
22266
22350
|
for (;; ) {
|
|
22267
22351
|
if (Date.now() > deadline)
|
|
22268
22352
|
throw new Error("login timed out — run `arbor login` again");
|
|
22269
|
-
await
|
|
22353
|
+
await sleep3(interval);
|
|
22270
22354
|
const tokRes = await fetch(`${apiUrl}/api/auth/device/token`, {
|
|
22271
22355
|
method: "POST",
|
|
22272
22356
|
headers: { "content-type": "application/json" },
|
package/package.json
CHANGED