@lambdacurry/arbor 0.9.1 → 0.11.0
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 +60 -18
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -1767,7 +1767,8 @@ var INDEX_ON = new Set([
|
|
|
1767
1767
|
"artifact.edited",
|
|
1768
1768
|
"review.added",
|
|
1769
1769
|
"thread.created",
|
|
1770
|
-
"topic.created"
|
|
1770
|
+
"topic.created",
|
|
1771
|
+
"topic.edited"
|
|
1771
1772
|
]);
|
|
1772
1773
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
1773
1774
|
var exports_external = {};
|
|
@@ -16067,6 +16068,15 @@ var ORIENTATION = `Arbor is your team's deliberation room and shared memory —
|
|
|
16067
16068
|
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\` create with kind doc/table/diagram/html + \`source\`, or promote a file) instead of pasting it into prose. Text-kind artifacts are LIVING: \`get\` it, then \`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.
|
|
16068
16069
|
|
|
16069
16070
|
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.`;
|
|
16071
|
+
var PROSE_LISTS = exports_external.registry();
|
|
16072
|
+
function proseList(description) {
|
|
16073
|
+
const schema = exports_external.array(exports_external.string()).describe(description);
|
|
16074
|
+
PROSE_LISTS.add(schema, { literal: true });
|
|
16075
|
+
return schema;
|
|
16076
|
+
}
|
|
16077
|
+
function isProseList(schema) {
|
|
16078
|
+
return PROSE_LISTS.has(schema);
|
|
16079
|
+
}
|
|
16070
16080
|
function forward(operation) {
|
|
16071
16081
|
return (ex, input) => ex.call(operation, input);
|
|
16072
16082
|
}
|
|
@@ -16180,13 +16190,26 @@ var ACTIONS = [
|
|
|
16180
16190
|
toolset: "structure",
|
|
16181
16191
|
run: forward("topic.create")
|
|
16182
16192
|
},
|
|
16193
|
+
{
|
|
16194
|
+
name: "topic_update",
|
|
16195
|
+
title: "Edit a topic's title or purpose",
|
|
16196
|
+
description: "Edit a topic's TITLE and/or PURPOSE — the facts of what this area of work IS, distinct from its soft `guidance` (set_topic_guidance) and its lanes (set_topic_lanes). Patches ONLY the fields you pass. Whoever may open a topic in this space may correct one. Reach for this when a purpose has gone stale or wrong — a moved repo, a renamed area, a stub written at creation — so `topic_get` and recall read true; guidance is for norms, never for facts that rot.",
|
|
16197
|
+
inputSchema: {
|
|
16198
|
+
topicId: exports_external.string().describe("the topic to edit, top_…"),
|
|
16199
|
+
title: exports_external.string().min(1).optional().describe("a new title — an area of work, not a question"),
|
|
16200
|
+
purpose: exports_external.string().optional().describe("a new one-line purpose — what belongs here")
|
|
16201
|
+
},
|
|
16202
|
+
surfaces: ["mcp", "cli"],
|
|
16203
|
+
toolset: "spaces",
|
|
16204
|
+
run: forward("topic.setConfig")
|
|
16205
|
+
},
|
|
16183
16206
|
{
|
|
16184
16207
|
name: "set_topic_guidance",
|
|
16185
16208
|
title: "Set a topic's guidance",
|
|
16186
|
-
description: "Set a topic's SOFT guidance — the local how-we-work norms for this topic (culture/quality, AD-063), e.g. 'recall before re-deriving', 'one typed point per contribution'. Soft norms only; hard governance (permissions, rate, join) lives at the space. You READ guidance to learn the room's habits — it's distinct from `set_ways_to_help` (what's open on a thread) and `request` (obligations). Replaces the whole list; pass [] to clear.",
|
|
16209
|
+
description: "Set a topic's SOFT guidance — the local how-we-work norms for this topic (culture/quality, AD-063), e.g. 'recall before re-deriving', 'one typed point per contribution'. Soft norms only; hard governance (permissions, rate, join) lives at the space, and FACTS about the area (where its code lives, what it covers) belong in the topic's purpose — `topic_update`, not here. You READ guidance to learn the room's habits — it's distinct from `set_ways_to_help` (what's open on a thread) and `request` (obligations). Replaces the whole list; pass [] to clear.",
|
|
16187
16210
|
inputSchema: {
|
|
16188
16211
|
topicId: exports_external.string().describe("the topic, top_…"),
|
|
16189
|
-
guidance:
|
|
16212
|
+
guidance: proseList("the full guidance list — replaces the existing one; [] clears it")
|
|
16190
16213
|
},
|
|
16191
16214
|
surfaces: ["cli"],
|
|
16192
16215
|
toolset: "spaces",
|
|
@@ -16198,7 +16221,7 @@ var ACTIONS = [
|
|
|
16198
16221
|
description: "Set a SPACE's SOFT guidance — the how-we-work-here norms for the whole space (culture/quality, AD-062/063), e.g. 'recall before re-deriving', 'promote the standout, sparingly'. Soft norms only, read not enforced; hard governance (permissions, rate, join) is separate. Members READ it (via space_get) to learn how the room operates — it's broader than `set_topic_guidance` (one topic's habits) and distinct from `request` (obligations). Replaces the whole list; pass [] to clear.",
|
|
16199
16222
|
inputSchema: {
|
|
16200
16223
|
spaceId: exports_external.string().describe("the space, spc_…"),
|
|
16201
|
-
guidance:
|
|
16224
|
+
guidance: proseList("the full guidance list — replaces the existing one; [] clears it")
|
|
16202
16225
|
},
|
|
16203
16226
|
surfaces: ["cli"],
|
|
16204
16227
|
toolset: "spaces",
|
|
@@ -16210,7 +16233,7 @@ var ACTIONS = [
|
|
|
16210
16233
|
description: "Set a SPACE's DURABLE contribution lanes (AD-222) — the standing kinds of help this room wants, as short matchable labels ('security review', 'cold-start performance', 'onboarding copy'). This is the discovery surface: a member whose capabilities/charter share a word with a lane sees it quoted in their `tree` as `lanesForYou`, and reads the full list via `space_get`. Distinct from `set_space_guidance` (HOW we work here) and from a thread's ways-to-help (a temporary, thread-local ask). At most 6 lanes, 120 characters each — over the cap is rejected, never truncated. Replaces the whole list; pass [] to clear.",
|
|
16211
16234
|
inputSchema: {
|
|
16212
16235
|
spaceId: exports_external.string().describe("the space, spc_…"),
|
|
16213
|
-
contributionLanes:
|
|
16236
|
+
contributionLanes: proseList("the full lane list — replaces the existing one; [] clears it")
|
|
16214
16237
|
},
|
|
16215
16238
|
surfaces: ["cli"],
|
|
16216
16239
|
toolset: "spaces",
|
|
@@ -16222,7 +16245,7 @@ var ACTIONS = [
|
|
|
16222
16245
|
description: "Set a TOPIC's DURABLE contribution lanes (AD-222) — the same axis as `set_space_lanes`, narrowed to one area of work. Read back in full via `topic_get`; matched (at most two, verbatim) into `tree`. At most 6 lanes, 120 characters each — over the cap is rejected, never truncated. Replaces the whole list; pass [] to clear.",
|
|
16223
16246
|
inputSchema: {
|
|
16224
16247
|
topicId: exports_external.string().describe("the topic, top_…"),
|
|
16225
|
-
contributionLanes:
|
|
16248
|
+
contributionLanes: proseList("the full lane list — replaces the existing one; [] clears it")
|
|
16226
16249
|
},
|
|
16227
16250
|
surfaces: ["cli"],
|
|
16228
16251
|
toolset: "spaces",
|
|
@@ -16248,7 +16271,7 @@ var ACTIONS = [
|
|
|
16248
16271
|
description: "Set a thread's READ-ONLY 'ways to help' (AD-038) — a short, curated list of perspectives, skills, or concrete tasks orienting someone on how they could pitch in with THIS thread as it stands (e.g. 'a benchmark on cold-start latency'). It is thread-local and temporary: it is read inside `thread_get`, and it never rolls up into a space/topic orientation surface — a standing statement about what a room wants is a contribution LANE (`set_space_lanes`/`set_topic_lanes`, AD-222). Guidance you READ, NOT an obligation — that's `request`. Replaces the whole list; pass [] to clear.",
|
|
16249
16272
|
inputSchema: {
|
|
16250
16273
|
threadId: exports_external.string().describe("the thread, thr_…"),
|
|
16251
|
-
waysToHelp:
|
|
16274
|
+
waysToHelp: proseList("the full ways-to-help list — replaces the existing one; [] clears it")
|
|
16252
16275
|
},
|
|
16253
16276
|
surfaces: ["cli"],
|
|
16254
16277
|
toolset: "spaces",
|
|
@@ -17109,10 +17132,10 @@ var ACTIONS = [
|
|
|
17109
17132
|
charter: exports_external.string().optional().describe("space_charter: the text; empty string clears"),
|
|
17110
17133
|
profileId: exports_external.string().optional().describe("space_charter admin override: whose charter"),
|
|
17111
17134
|
topicId: exports_external.string().optional().describe("topic_guidance/topic_lanes: the topic, top_…"),
|
|
17112
|
-
guidance:
|
|
17113
|
-
contributionLanes:
|
|
17135
|
+
guidance: proseList("space_guidance/topic_guidance: full list, replaces; [] clears").optional(),
|
|
17136
|
+
contributionLanes: proseList("space_lanes/topic_lanes: full lane list, replaces; [] clears").optional(),
|
|
17114
17137
|
threadId: exports_external.string().optional().describe("ways_to_help: the thread, thr_…"),
|
|
17115
|
-
waysToHelp:
|
|
17138
|
+
waysToHelp: proseList("ways_to_help: full list, replaces; [] clears").optional()
|
|
17116
17139
|
},
|
|
17117
17140
|
surfaces: ["mcp"],
|
|
17118
17141
|
toolset: "spaces",
|
|
@@ -17456,7 +17479,8 @@ function flagsForSchema(inputSchema) {
|
|
|
17456
17479
|
flag: kebab(field),
|
|
17457
17480
|
kind: kindOf(inner),
|
|
17458
17481
|
required: !optional2,
|
|
17459
|
-
description: description(inner) ?? description(raw)
|
|
17482
|
+
description: description(inner) ?? description(raw),
|
|
17483
|
+
literal: isProseList(inner)
|
|
17460
17484
|
};
|
|
17461
17485
|
});
|
|
17462
17486
|
}
|
|
@@ -17512,7 +17536,7 @@ function buildInput(inputSchema, flags, command) {
|
|
|
17512
17536
|
throw new UsageError(`--${spec.flag} looks like JSON but failed to parse — check the quoting`);
|
|
17513
17537
|
}
|
|
17514
17538
|
}
|
|
17515
|
-
if (repeated) {
|
|
17539
|
+
if (repeated || spec.literal) {
|
|
17516
17540
|
if (text3)
|
|
17517
17541
|
out.push(text3);
|
|
17518
17542
|
} else {
|
|
@@ -17549,14 +17573,29 @@ var KNOWN_MISREACHES = [
|
|
|
17549
17573
|
{ tried: "spaces", use: "tree", why: "the tree lists spaces" },
|
|
17550
17574
|
{ tried: "space list", use: "tree", why: "the tree lists spaces" },
|
|
17551
17575
|
{ tried: "topics", use: "tree --depth topics", why: "topics are a tree depth" },
|
|
17552
|
-
{ tried: "search", use: "recall <query>", why: "recall is the search surface" }
|
|
17576
|
+
{ tried: "search", use: "recall <query>", why: "recall is the search surface" },
|
|
17577
|
+
{ tried: "update topic", use: "topic update --topic-id top_…", why: "this command is noun-verb" },
|
|
17578
|
+
{ tried: "update space", use: "space update --space-id spc_…", why: "this command is noun-verb" }
|
|
17553
17579
|
];
|
|
17580
|
+
function familyHelp(positionals) {
|
|
17581
|
+
if (positionals.length !== 1)
|
|
17582
|
+
return;
|
|
17583
|
+
const word = positionals[0].toLowerCase().replace(/_/g, " ");
|
|
17584
|
+
const members = CLI_ACTIONS.filter((a) => commandWords(a).split(" ").includes(word)).sort((a, b) => commandWords(a).localeCompare(commandWords(b)));
|
|
17585
|
+
if (members.length === 0)
|
|
17586
|
+
return;
|
|
17587
|
+
return `\`${word}\` commands — run \`arbor <command> --help\` for one command's exact flags.
|
|
17588
|
+
|
|
17589
|
+
` + `${members.map(helpLine).join(`
|
|
17590
|
+
`)}
|
|
17591
|
+
`;
|
|
17592
|
+
}
|
|
17554
17593
|
function suggestCommand(positionals) {
|
|
17555
|
-
const typed = positionals.join(" ").toLowerCase();
|
|
17594
|
+
const typed = positionals.join(" ").toLowerCase().replace(/_/g, " ");
|
|
17556
17595
|
const known = KNOWN_MISREACHES.find((m) => m.tried === typed);
|
|
17557
17596
|
if (known)
|
|
17558
17597
|
return `use \`arbor ${known.use}\` — ${known.why}`;
|
|
17559
|
-
const head =
|
|
17598
|
+
const head = typed.split(" ")[0];
|
|
17560
17599
|
if (head) {
|
|
17561
17600
|
const siblings = CLI_ACTIONS.map(commandWords).filter((c) => c === head || c.startsWith(`${head} `)).sort();
|
|
17562
17601
|
if (siblings.length > 0) {
|
|
@@ -17605,7 +17644,10 @@ function commandHelp(positionals) {
|
|
|
17605
17644
|
const req = f.required ? "required" : "optional";
|
|
17606
17645
|
const fileNote = f.kind === "string" ? ` (or --${f.flag}-file <path|->)` : "";
|
|
17607
17646
|
const desc = f.description ? ` — ${f.description}` : "";
|
|
17608
|
-
|
|
17647
|
+
const listNote = f.kind === "array" ? f.literal ? `
|
|
17648
|
+
list: repeat --${f.flag} per item; a single value is ONE item (commas kept literal)` : `
|
|
17649
|
+
list: repeat --${f.flag} per item, or one comma-separated value (--${f.flag} a,b,c)` : "";
|
|
17650
|
+
return ` --${f.flag} <${f.kind}> [${req}]${fileNote}${desc}${listNote}`;
|
|
17609
17651
|
});
|
|
17610
17652
|
const primaryNote = primary ? `
|
|
17611
17653
|
|
|
@@ -17840,7 +17882,7 @@ async function renderMe(ctx, action) {
|
|
|
17840
17882
|
` : "") + spaceLines;
|
|
17841
17883
|
emitDual(me, human, action, ctx);
|
|
17842
17884
|
}
|
|
17843
|
-
var CLI_NOTE = `On this CLI, before your first write: commands are NOUN-VERB (\`thread get\`, \`space get\`, not \`get thread\`). The underscore tool-names you see in MCP, recall, and docs (\`set_space_charter\`, \`transition_thread\`) work as CLI commands VERBATIM too — \`set_space_charter …\` and \`set space charter …\` are the same command, either form. A single-argument command also takes a bare positional — \`recall "your question"\`, \`thread get thr_…\` — so you don't have to name the obvious flag. Flag names are kebab-derived from the inputs (\`--thread-id\`, \`--request-id\`, \`--contribution-id\` — not \`--thread\`/\`--request\`), so check \`arbor help\` or \`arbor <command> --help\` (now focused on that command's flags) instead of guessing. Pass long/markdown bodies via \`--body-file -\` (stdin), never shell-quoted; a one-line \`--summary\` (1-2 short sentences, hard limit 500 chars) on a long contribution becomes its recall snippet. List inputs (
|
|
17885
|
+
var CLI_NOTE = `On this CLI, before your first write: commands are NOUN-VERB (\`thread get\`, \`space get\`, not \`get thread\`). The underscore tool-names you see in MCP, recall, and docs (\`set_space_charter\`, \`transition_thread\`) work as CLI commands VERBATIM too — \`set_space_charter …\` and \`set space charter …\` are the same command, either form. A single-argument command also takes a bare positional — \`recall "your question"\`, \`thread get thr_…\` — so you don't have to name the obvious flag. Flag names are kebab-derived from the inputs (\`--thread-id\`, \`--request-id\`, \`--contribution-id\` — not \`--thread\`/\`--request\`), so check \`arbor help\` or \`arbor <command> --help\` (now focused on that command's flags) instead of guessing. Pass long/markdown bodies via \`--body-file -\` (stdin), never shell-quoted; a one-line \`--summary\` (1-2 short sentences, hard limit 500 chars) on a long contribution becomes its recall snippet. List inputs always accept a REPEATED flag, one item each (\`--guidance "…" --guidance "…"\`) — the form that works everywhere. A single value additionally comma-splits for TOKEN lists (\`--capabilities a,b,c\`), but stays one literal item for PROSE lists (\`--guidance\`, \`--ways-to-help\`, \`--contribution-lanes\`) so a comma inside a sentence can't shred it; \`arbor <command> --help\` names which form each list flag takes. \`tree\` is a glanceable map (default depth \`topics\`); drill down with \`space get\`/\`topic get\`/\`thread get\` rather than expanding the whole tree. If \`inbox\` is empty, that's "nothing needs you" — but if you're unsure your auth resolved, \`whoami\` confirms it.`;
|
|
17844
17886
|
function renderOrient(ctx) {
|
|
17845
17887
|
emitDual({ orientation: ORIENTATION, cliNote: CLI_NOTE }, `${ORIENTATION}
|
|
17846
17888
|
|
|
@@ -17932,7 +17974,7 @@ async function main() {
|
|
|
17932
17974
|
return;
|
|
17933
17975
|
}
|
|
17934
17976
|
if (truthyFlag(flags.help)) {
|
|
17935
|
-
const focused = positionals.length > 0 ? commandHelp(positionals) : undefined;
|
|
17977
|
+
const focused = positionals.length > 0 ? commandHelp(positionals) ?? familyHelp(positionals) : undefined;
|
|
17936
17978
|
if (focused)
|
|
17937
17979
|
emitDual({ help: focused }, focused, "help", ctx);
|
|
17938
17980
|
else
|
package/package.json
CHANGED