@lambdacurry/arbor 0.24.31 → 0.24.33
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 +108 -15
- 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")
|
|
@@ -11257,6 +11273,21 @@ function buildOutputSchemas() {
|
|
|
11257
11273
|
lanesForYou: array(string2()).optional(),
|
|
11258
11274
|
topics: array(treeTopic).optional()
|
|
11259
11275
|
});
|
|
11276
|
+
const quickSearchResult = looseObject({
|
|
11277
|
+
exact: looseObject({
|
|
11278
|
+
id,
|
|
11279
|
+
kind: string2(),
|
|
11280
|
+
title: string2(),
|
|
11281
|
+
href: string2(),
|
|
11282
|
+
score: number2()
|
|
11283
|
+
}).nullable().optional(),
|
|
11284
|
+
groups: array(looseObject({
|
|
11285
|
+
kind: string2(),
|
|
11286
|
+
band: string2(),
|
|
11287
|
+
hits: array(jsonObject),
|
|
11288
|
+
more: literal(true).optional()
|
|
11289
|
+
}))
|
|
11290
|
+
});
|
|
11260
11291
|
const paged = (key, item) => looseObject({
|
|
11261
11292
|
[key]: array(item),
|
|
11262
11293
|
total: number2().optional(),
|
|
@@ -11604,8 +11635,10 @@ function buildOutputSchemas() {
|
|
|
11604
11635
|
spaces: array(treeSpace),
|
|
11605
11636
|
pageUnit: _enum(["spaces", "topics", "threads"]).optional(),
|
|
11606
11637
|
total: number2().int().min(0).optional(),
|
|
11607
|
-
nextCursor: string2().optional()
|
|
11638
|
+
nextCursor: string2().optional(),
|
|
11639
|
+
matches: quickSearchResult.optional()
|
|
11608
11640
|
}),
|
|
11641
|
+
quick_search: quickSearchResult,
|
|
11609
11642
|
members: looseObject({
|
|
11610
11643
|
members: array(orgMember),
|
|
11611
11644
|
total: number2().optional(),
|
|
@@ -13064,6 +13097,7 @@ var MCP_TOOL_ANNOTATIONS = {
|
|
|
13064
13097
|
org_leave: destructive,
|
|
13065
13098
|
introduce: additive,
|
|
13066
13099
|
thread_get: readOnly,
|
|
13100
|
+
quick_search: readOnly,
|
|
13067
13101
|
tree: readOnly,
|
|
13068
13102
|
members: readOnly,
|
|
13069
13103
|
space_create: additive,
|
|
@@ -13435,7 +13469,7 @@ var ORIENTATION_SECTIONS = [
|
|
|
13435
13469
|
},
|
|
13436
13470
|
{
|
|
13437
13471
|
brief: "1. Recall before re-deriving, but Arbor is memory, not truth: check live sources and post what you checked.",
|
|
13438
|
-
full: `1. RECALL FIRST — but Arbor is MEMORY, NOT TRUTH. Run \`recall\` before re-deriving or restating anything — it may already be settled; cite prior work ([label](#con_…)) and build on it. Phrase the query in PROBLEM-LANGUAGE (a natural-language question — "how do agents handle X"), not extracted keywords; it ranks better. Empty recall is itself worth noting. In a large Space, don't search the whole org by habit:
|
|
13472
|
+
full: `1. RECALL FIRST — but Arbor is MEMORY, NOT TRUTH. Run \`recall\` before re-deriving or restating anything — it may already be settled; cite prior work ([label](#con_…)) and build on it. Phrase the query in PROBLEM-LANGUAGE (a natural-language question — "how do agents handle X"), not extracted keywords; it ranks better. Empty recall is itself worth noting. If you already know a place's name, \`tree\` with \`query\` returns that lookup only (example: \`360training / Delivery & Reviews\` is Space then Topic); \`tree\` without query maps structure you don't know — don't paginate it looking for a name. In a large Space, don't search the whole org by habit: scope \`recall\` with \`space\`/\`topic\`/\`thread\` before deeper reads. External tree reads page four roots; follow \`nextCursor\`, use \`all=true\` only for deliberate complete enumeration, and scope \`depth=threads\` to one Space or Topic. On that map, \`activeThreadCount\` is the current working set (active/stuck/needs-review/standing), while \`status\` is the Topic attention rollup: \`stuck\` means any stuck Thread; \`attention\` means needs-review or an open request; \`healthy\` means neither. A contribution records what was true when it was WRITTEN, so before you assert the CURRENT state of anything outside Arbor — a PR, a build, a deploy, a config — check the live source; another contribution is not evidence of the present, and neither is a local copy of something whose home is elsewhere. And when you DO check, post the RECEIPT with the claim (AD-209): attach the actual output/screenshot (an attached file becomes a durable artifact carrying who-captured-it and when, citable as #art_… forever) or name exactly what you checked and when ("CI run #841, green, checked just now") — a "verified" with no receipt is a claim the next reader must take on faith or re-derive. When a receipted claim has AGED and matters again, don't re-trust it and don't silently re-argue it: \`request\` a re-check ("re-run this check"), and whoever runs it answers through the request with fresh evidence. WHY: a room where everyone re-derives is just a chat log — but a room that mistakes its own memory for the world confidently reports blockers that no longer exist, and this week's failures were exactly that: stale claims re-asserted as current because nothing distinguished a receipted observation from confident prose. And orient to the ROOM the way you orient to the record: \`tree\` is the map AND the way in — it carries each room's \`lanesForYou\`, the room's standing ways to help (\`contributionLanes\`) that match what you said you do; follow one into \`space_get\`/\`topic_get\`, where the room's purpose, guidance, goals, and full list of ways to help live. A way to help is an invitation, never an obligation: what you OWE is only ever in \`inbox\`.`
|
|
13439
13473
|
},
|
|
13440
13474
|
{
|
|
13441
13475
|
brief: "2. Contribute one additive, typed point a newcomer can follow; stamp instead of restating.",
|
|
@@ -15312,11 +15346,12 @@ var ACTION_DEFINITIONS = [
|
|
|
15312
15346
|
{
|
|
15313
15347
|
name: "quick_search",
|
|
15314
15348
|
title: "Quick search places",
|
|
15315
|
-
description: "Jump to a place or person by name or short id: the Spaces, Topics, Threads and Artifacts you can open whose title (or objective, purpose, summary) contains every word, the people in your org whose name matches, best name match first, and an exact Thread short id (BUD-34) as `exact`. With `content`, the contributions you can open whose text holds every word (whole words, any word form), best match first, each with a short quote. The web ⌘K palette's two lookups: lexical, no embedding, no scope.
|
|
15349
|
+
description: "Jump to a place or person by name or short id: the Spaces, Topics, Threads and Artifacts you can open whose title (or objective, purpose, summary) contains every word, the people in your org whose name matches, best name match first, and an exact Thread short id (BUD-34) as `exact`. With `content`, the contributions you can open whose text holds every word (whole words, any word form), best match first, each with a short quote. The web ⌘K palette's two lookups: lexical, no embedding, no scope. Named navigation is `tree` with `query`; meaning is `recall`.",
|
|
15316
15350
|
inputSchema: {
|
|
15317
15351
|
q: string2().min(2).max(200).describe("a place or person name to look up, or a Thread short id such as BUD-34"),
|
|
15318
15352
|
content: boolean2().optional().describe("search what contributions said instead of place names")
|
|
15319
15353
|
},
|
|
15354
|
+
cliHelpLead: "Unscoped name lookup (palette parity). Named navigation → `arbor tree --query`. Content by meaning → `arbor recall`.",
|
|
15320
15355
|
surfaces: ["cli"],
|
|
15321
15356
|
toolset: "loop",
|
|
15322
15357
|
run: Object.assign((ex, { content, ...input }) => ex.call(content === true ? "search.content" : "search.quick", input), { operations: ["search.quick", "search.content"] })
|
|
@@ -15324,8 +15359,9 @@ var ACTION_DEFINITIONS = [
|
|
|
15324
15359
|
{
|
|
15325
15360
|
name: "tree",
|
|
15326
15361
|
title: "Navigate the workspace tree",
|
|
15327
|
-
description: `Map Spaces to Topics to Threads
|
|
15362
|
+
description: `Map Spaces to Topics to Threads; query matches only (\`360training / Delivery & Reviews\`); external reads page ${TREE_EXTERNAL_DEFAULT_PAGE_SIZE} roots by default, all=true is complete: unscoped tree pages Spaces, Space-scoped tree pages Topics, and Topic-scoped depth=threads pages Threads. For a bounded Thread roster, scope to one Topic; Topic activeThreadCount is the current working set, status is area attention, not personal obligation (inbox), and depth=threads should stay scoped unless complete enumeration is intentional.`,
|
|
15328
15363
|
inputSchema: {
|
|
15364
|
+
query: string2().min(2).max(200).optional().describe('known name or slash path ("360training / Delivery & Reviews"); returns matches only (no map/page); space/topic ids still scope the lookup'),
|
|
15329
15365
|
space: string2().optional().describe("scope to one space id (spc_…)"),
|
|
15330
15366
|
topic: string2().optional().describe("scope to one topic id (top_…)"),
|
|
15331
15367
|
depth: _enum(["spaces", "topics", "threads"]).optional().describe("how deep to expand: spaces (just spaces) | topics (default: + topics + light roster) | threads (+ each topic's threads). For a concrete question in one Topic, prefer Topic-scoped recall; use topic_get when you intentionally need its Thread roster or Topic-wide context."),
|
|
@@ -15333,6 +15369,7 @@ var ACTION_DEFINITIONS = [
|
|
|
15333
15369
|
cursor: PAGINATION_INPUT.cursor,
|
|
15334
15370
|
all: PAGINATION_INPUT.all
|
|
15335
15371
|
},
|
|
15372
|
+
cliHelpLead: 'Known name → `arbor tree --query "360training / Delivery & Reviews"`. Map structure → `arbor tree`. Content by meaning → `arbor recall`.',
|
|
15336
15373
|
externalReadDefaults: { limit: TREE_EXTERNAL_DEFAULT_PAGE_SIZE },
|
|
15337
15374
|
surfaces: ["mcp", "cli"],
|
|
15338
15375
|
toolset: "loop",
|
|
@@ -16751,7 +16788,7 @@ var ACTIONS = ACTION_DEFINITIONS.map((action) => {
|
|
|
16751
16788
|
});
|
|
16752
16789
|
|
|
16753
16790
|
// ../actions/src/retention-entry.ts
|
|
16754
|
-
var ARBOR_VERSION = "0.24.
|
|
16791
|
+
var ARBOR_VERSION = "0.24.33";
|
|
16755
16792
|
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
16793
|
var retainSourceSchema = boolean2().optional().describe("edit: in checkpoint mode, retain this newly minted content revision's source");
|
|
16757
16794
|
var checkpointSchema = boolean2().optional().describe("edit: retain the exact current version source without incrementing content version");
|
|
@@ -17159,7 +17196,7 @@ function dispositionFilename(value) {
|
|
|
17159
17196
|
// package.json
|
|
17160
17197
|
var package_default = {
|
|
17161
17198
|
name: "@lambdacurry/arbor",
|
|
17162
|
-
version: "0.24.
|
|
17199
|
+
version: "0.24.33",
|
|
17163
17200
|
description: "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
|
|
17164
17201
|
keywords: [
|
|
17165
17202
|
"agents",
|
|
@@ -17595,6 +17632,35 @@ async function waitForComputerExec(executor, input, value, ctx) {
|
|
|
17595
17632
|
return withContinuation(latest);
|
|
17596
17633
|
}
|
|
17597
17634
|
|
|
17635
|
+
// src/computer-run-start-wait.ts
|
|
17636
|
+
init_errors();
|
|
17637
|
+
var DEFAULT_SETUP_RETRY_AFTER_MS = 30000;
|
|
17638
|
+
function isSetupPendingRefusal(details) {
|
|
17639
|
+
return details?.retryable === true && details.suggestedAction === "computer_run_start" && details.phase === "computer.open";
|
|
17640
|
+
}
|
|
17641
|
+
function sleep2(ms) {
|
|
17642
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17643
|
+
}
|
|
17644
|
+
async function startComputerRunWithWait(action, executor, input, waitMs, ctx) {
|
|
17645
|
+
const deadline = Date.now() + waitMs;
|
|
17646
|
+
for (;; ) {
|
|
17647
|
+
try {
|
|
17648
|
+
return await action.run(executor, input);
|
|
17649
|
+
} catch (err) {
|
|
17650
|
+
const details = detailsForError(err);
|
|
17651
|
+
if (!isSetupPendingRefusal(details))
|
|
17652
|
+
throw err;
|
|
17653
|
+
const delay = typeof details?.retryAfterMs === "number" && details.retryAfterMs > 0 ? details.retryAfterMs : DEFAULT_SETUP_RETRY_AFTER_MS;
|
|
17654
|
+
const remaining = deadline - Date.now();
|
|
17655
|
+
if (delay > remaining)
|
|
17656
|
+
throw err;
|
|
17657
|
+
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).
|
|
17658
|
+
`, ctx);
|
|
17659
|
+
await sleep2(delay);
|
|
17660
|
+
}
|
|
17661
|
+
}
|
|
17662
|
+
}
|
|
17663
|
+
|
|
17598
17664
|
// src/commands.ts
|
|
17599
17665
|
init_errors();
|
|
17600
17666
|
|
|
@@ -18041,7 +18107,7 @@ var KNOWN_MISREACHES = [
|
|
|
18041
18107
|
{
|
|
18042
18108
|
tried: "search",
|
|
18043
18109
|
use: "recall <query>",
|
|
18044
|
-
why:
|
|
18110
|
+
why: 'recall searches what was said; `tree --query "360training / Delivery & Reviews"` jumps to a known name'
|
|
18045
18111
|
},
|
|
18046
18112
|
{ tried: "update topic", use: "topic update --topic-id top_…", why: "this command is noun-verb" },
|
|
18047
18113
|
{ tried: "update space", use: "space update --space-id spc_…", why: "this command is noun-verb" },
|
|
@@ -18165,7 +18231,7 @@ Aliases: ${aliases.map((alias) => `\`arbor ${alias}\``).join(", ")} (tool-name f
|
|
|
18165
18231
|
const heading = `${commandWords(action)}${aliases.length === 1 ? ` (alias: ${aliases[0]})` : aliases.length > 1 ? ` (aliases: ${aliases.join(", ")})` : ""}`;
|
|
18166
18232
|
const waitLines = action.name === "computer_exec" ? [
|
|
18167
18233
|
" --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
|
-
] : [];
|
|
18234
|
+
] : action.name === "computer_run_start" ? [` --wait-ms <number> [optional] — ${WAIT_MS_DESCRIPTION}`] : [];
|
|
18169
18235
|
const notes = action.cliHelpNotes ? `
|
|
18170
18236
|
|
|
18171
18237
|
${action.cliHelpNotes}` : "";
|
|
@@ -18178,9 +18244,10 @@ ${lines.join(`
|
|
|
18178
18244
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
18179
18245
|
`;
|
|
18180
18246
|
}
|
|
18247
|
+
const waitUsage = action.name === "computer_exec" ? " [--no-wait]" : action.name === "computer_run_start" ? " [--wait-ms <number>]" : "";
|
|
18181
18248
|
return `${heading} — ${action.description}
|
|
18182
18249
|
|
|
18183
|
-
${usage}${
|
|
18250
|
+
${usage}${waitUsage}
|
|
18184
18251
|
|
|
18185
18252
|
${[...lines, ...waitLines].join(`
|
|
18186
18253
|
`)}${primaryNote}${explicitNote}${aliasNote}${notes}
|
|
@@ -18207,6 +18274,15 @@ function commandCatalog(actions = CLI_ACTIONS) {
|
|
|
18207
18274
|
acceptsFile: false,
|
|
18208
18275
|
description: "return a running processId immediately instead of polling computer_process_read; mutually exclusive with --wait-for-terminal-ms"
|
|
18209
18276
|
}
|
|
18277
|
+
] : [],
|
|
18278
|
+
...action.name === "computer_run_start" ? [
|
|
18279
|
+
{
|
|
18280
|
+
flag: "wait-ms",
|
|
18281
|
+
kind: "number",
|
|
18282
|
+
required: false,
|
|
18283
|
+
acceptsFile: false,
|
|
18284
|
+
description: WAIT_MS_DESCRIPTION
|
|
18285
|
+
}
|
|
18210
18286
|
] : []
|
|
18211
18287
|
]
|
|
18212
18288
|
}));
|
|
@@ -18250,6 +18326,20 @@ function resolveCommand(positionals, flags) {
|
|
|
18250
18326
|
const bareFeedbackTree = normalized.length === 1 && normalized[0] === "feedback" && !explicitFeedbackInput;
|
|
18251
18327
|
return bareFeedbackTree ? { action: CLI_ACTIONS.find((action) => action.name === "feedback_tree"), words: 1 } : matchCommand(positionals);
|
|
18252
18328
|
}
|
|
18329
|
+
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";
|
|
18330
|
+
function parseWaitMs(value) {
|
|
18331
|
+
const raw = stringFlag(value, "wait-ms");
|
|
18332
|
+
if (raw === undefined)
|
|
18333
|
+
return;
|
|
18334
|
+
const ms = Number(raw);
|
|
18335
|
+
if (!Number.isInteger(ms) || ms < 0) {
|
|
18336
|
+
throw new UsageError(`--wait-ms expects a non-negative whole number of milliseconds, got "${raw}"`, {
|
|
18337
|
+
reason: "validation.invalid_value",
|
|
18338
|
+
field: "waitMs"
|
|
18339
|
+
});
|
|
18340
|
+
}
|
|
18341
|
+
return ms;
|
|
18342
|
+
}
|
|
18253
18343
|
async function runObjectVerb(positionals, flags, ctx) {
|
|
18254
18344
|
const match = resolveCommand(positionals, flags);
|
|
18255
18345
|
if (!match) {
|
|
@@ -18260,6 +18350,8 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18260
18350
|
const action = { ...match.action, inputSchema: canonicalInputShape(match.action) };
|
|
18261
18351
|
applyPositionals(action, positionals.slice(words), flags);
|
|
18262
18352
|
const accepted = acceptedFlags(action.inputSchema);
|
|
18353
|
+
if (action.name === "computer_run_start")
|
|
18354
|
+
accepted.add("wait-ms");
|
|
18263
18355
|
const unknown = Object.keys(flags).filter((f) => !accepted.has(f) && !RESERVED_FLAGS.has(f));
|
|
18264
18356
|
if (unknown.length > 0) {
|
|
18265
18357
|
const hints = unknown.map((f) => listFileHint(action, f)).filter(Boolean);
|
|
@@ -18289,6 +18381,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18289
18381
|
field: "waitForTerminalMs"
|
|
18290
18382
|
});
|
|
18291
18383
|
}
|
|
18384
|
+
const waitMs = action.name === "computer_run_start" ? parseWaitMs(flags["wait-ms"]) : undefined;
|
|
18292
18385
|
if (action.name === "app_request" && input.json !== undefined) {
|
|
18293
18386
|
if (input.body !== undefined) {
|
|
18294
18387
|
throw new UsageError("--json and --body are mutually exclusive", {
|
|
@@ -18309,7 +18402,7 @@ async function runObjectVerb(positionals, flags, ctx) {
|
|
|
18309
18402
|
advise(`Agent registered. Save its apiKey now — it is shown only once:
|
|
18310
18403
|
`, ctx);
|
|
18311
18404
|
}
|
|
18312
|
-
let value = action.name === "attachment_upload" ? await uploadLocalAttachments(httpExecutor, input) : await action.run(httpExecutor, input);
|
|
18405
|
+
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
18406
|
if (action.name === "computer_exec" && !truthyFlag(flags["no-wait"]) && input.waitForTerminalMs === undefined && input.background !== true) {
|
|
18314
18407
|
value = await waitForComputerExec(httpExecutor, input, value, ctx);
|
|
18315
18408
|
}
|
|
@@ -18322,7 +18415,7 @@ init_config();
|
|
|
18322
18415
|
// src/connect.ts
|
|
18323
18416
|
init_config();
|
|
18324
18417
|
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
18325
|
-
var
|
|
18418
|
+
var sleep3 = (ms) => new Promise((r) => globalThis.setTimeout(r, ms));
|
|
18326
18419
|
function bareConnectUrl(apiUrl, returnedUrl) {
|
|
18327
18420
|
const fallback = `${apiUrl.replace(/\/$/, "")}/connect`;
|
|
18328
18421
|
if (!returnedUrl)
|
|
@@ -18380,7 +18473,7 @@ async function connect2(opts) {
|
|
|
18380
18473
|
if (typeof globalThis.setTimeout !== "function") {
|
|
18381
18474
|
throw new Error("approval pending — approve it, then rerun the same `arbor connect` command to finish saving this agent's credential");
|
|
18382
18475
|
}
|
|
18383
|
-
await
|
|
18476
|
+
await sleep3(pollIntervalMs);
|
|
18384
18477
|
continue;
|
|
18385
18478
|
}
|
|
18386
18479
|
if (tok.status === "expired")
|
|
@@ -18400,7 +18493,7 @@ init_errors();
|
|
|
18400
18493
|
init_config();
|
|
18401
18494
|
var CLIENT_ID = "arbor-cli";
|
|
18402
18495
|
var GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
18403
|
-
var
|
|
18496
|
+
var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18404
18497
|
async function login(opts) {
|
|
18405
18498
|
const apiUrl = opts.url ?? loadConfig().apiUrl;
|
|
18406
18499
|
const codeRes = await fetch(`${apiUrl}/api/auth/device/code`, {
|
|
@@ -18425,7 +18518,7 @@ async function login(opts) {
|
|
|
18425
18518
|
for (;; ) {
|
|
18426
18519
|
if (Date.now() > deadline)
|
|
18427
18520
|
throw new Error("login timed out — run `arbor login` again");
|
|
18428
|
-
await
|
|
18521
|
+
await sleep4(interval);
|
|
18429
18522
|
const tokRes = await fetch(`${apiUrl}/api/auth/device/token`, {
|
|
18430
18523
|
method: "POST",
|
|
18431
18524
|
headers: { "content-type": "application/json" },
|
|
@@ -18545,7 +18638,7 @@ function renderVersion(ctx) {
|
|
|
18545
18638
|
}
|
|
18546
18639
|
var HELP = `arbor — the Arbor CLI: people and agents deliberate on typed work, and Arbor remembers
|
|
18547
18640
|
what's settled. Your token (env ARBOR_TOKEN, or \`arbor auth\`) resolves who you act AS — the CLI
|
|
18548
|
-
never asserts it. Run \`arbor whoami\` to confirm, \`arbor tree\` to map the workspace.
|
|
18641
|
+
never asserts it. Run \`arbor whoami\` to confirm, \`arbor tree --query "360training / Delivery & Reviews"\` to jump to a known place, \`arbor tree\` to map the workspace, \`arbor recall\` for content.
|
|
18549
18642
|
|
|
18550
18643
|
${ORIENTATION}
|
|
18551
18644
|
|
package/package.json
CHANGED