@lambdacurry/arbor 0.10.0 → 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.
Files changed (2) hide show
  1. package/dist/arbor.js +25 -12
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -16068,6 +16068,15 @@ var ORIENTATION = `Arbor is your team's deliberation room and shared memory —
16068
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.
16069
16069
 
16070
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
+ }
16071
16080
  function forward(operation) {
16072
16081
  return (ex, input) => ex.call(operation, input);
16073
16082
  }
@@ -16200,7 +16209,7 @@ var ACTIONS = [
16200
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.",
16201
16210
  inputSchema: {
16202
16211
  topicId: exports_external.string().describe("the topic, top_…"),
16203
- guidance: exports_external.array(exports_external.string()).describe("the full guidance list — replaces the existing one; [] clears it")
16212
+ guidance: proseList("the full guidance list — replaces the existing one; [] clears it")
16204
16213
  },
16205
16214
  surfaces: ["cli"],
16206
16215
  toolset: "spaces",
@@ -16212,7 +16221,7 @@ var ACTIONS = [
16212
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.",
16213
16222
  inputSchema: {
16214
16223
  spaceId: exports_external.string().describe("the space, spc_…"),
16215
- guidance: exports_external.array(exports_external.string()).describe("the full guidance list — replaces the existing one; [] clears it")
16224
+ guidance: proseList("the full guidance list — replaces the existing one; [] clears it")
16216
16225
  },
16217
16226
  surfaces: ["cli"],
16218
16227
  toolset: "spaces",
@@ -16224,7 +16233,7 @@ var ACTIONS = [
16224
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.",
16225
16234
  inputSchema: {
16226
16235
  spaceId: exports_external.string().describe("the space, spc_…"),
16227
- contributionLanes: exports_external.array(exports_external.string()).describe("the full lane list — replaces the existing one; [] clears it")
16236
+ contributionLanes: proseList("the full lane list — replaces the existing one; [] clears it")
16228
16237
  },
16229
16238
  surfaces: ["cli"],
16230
16239
  toolset: "spaces",
@@ -16236,7 +16245,7 @@ var ACTIONS = [
16236
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.",
16237
16246
  inputSchema: {
16238
16247
  topicId: exports_external.string().describe("the topic, top_…"),
16239
- contributionLanes: exports_external.array(exports_external.string()).describe("the full lane list — replaces the existing one; [] clears it")
16248
+ contributionLanes: proseList("the full lane list — replaces the existing one; [] clears it")
16240
16249
  },
16241
16250
  surfaces: ["cli"],
16242
16251
  toolset: "spaces",
@@ -16262,7 +16271,7 @@ var ACTIONS = [
16262
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.",
16263
16272
  inputSchema: {
16264
16273
  threadId: exports_external.string().describe("the thread, thr_…"),
16265
- waysToHelp: exports_external.array(exports_external.string()).describe("the full ways-to-help list — replaces the existing one; [] clears it")
16274
+ waysToHelp: proseList("the full ways-to-help list — replaces the existing one; [] clears it")
16266
16275
  },
16267
16276
  surfaces: ["cli"],
16268
16277
  toolset: "spaces",
@@ -17123,10 +17132,10 @@ var ACTIONS = [
17123
17132
  charter: exports_external.string().optional().describe("space_charter: the text; empty string clears"),
17124
17133
  profileId: exports_external.string().optional().describe("space_charter admin override: whose charter"),
17125
17134
  topicId: exports_external.string().optional().describe("topic_guidance/topic_lanes: the topic, top_…"),
17126
- guidance: exports_external.array(exports_external.string()).optional().describe("space_guidance/topic_guidance: full list, replaces; [] clears"),
17127
- contributionLanes: exports_external.array(exports_external.string()).optional().describe("space_lanes/topic_lanes: full lane list, replaces; [] clears"),
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(),
17128
17137
  threadId: exports_external.string().optional().describe("ways_to_help: the thread, thr_…"),
17129
- waysToHelp: exports_external.array(exports_external.string()).optional().describe("ways_to_help: full list, replaces; [] clears")
17138
+ waysToHelp: proseList("ways_to_help: full list, replaces; [] clears").optional()
17130
17139
  },
17131
17140
  surfaces: ["mcp"],
17132
17141
  toolset: "spaces",
@@ -17470,7 +17479,8 @@ function flagsForSchema(inputSchema) {
17470
17479
  flag: kebab(field),
17471
17480
  kind: kindOf(inner),
17472
17481
  required: !optional2,
17473
- description: description(inner) ?? description(raw)
17482
+ description: description(inner) ?? description(raw),
17483
+ literal: isProseList(inner)
17474
17484
  };
17475
17485
  });
17476
17486
  }
@@ -17526,7 +17536,7 @@ function buildInput(inputSchema, flags, command) {
17526
17536
  throw new UsageError(`--${spec.flag} looks like JSON but failed to parse — check the quoting`);
17527
17537
  }
17528
17538
  }
17529
- if (repeated) {
17539
+ if (repeated || spec.literal) {
17530
17540
  if (text3)
17531
17541
  out.push(text3);
17532
17542
  } else {
@@ -17634,7 +17644,10 @@ function commandHelp(positionals) {
17634
17644
  const req = f.required ? "required" : "optional";
17635
17645
  const fileNote = f.kind === "string" ? ` (or --${f.flag}-file <path|->)` : "";
17636
17646
  const desc = f.description ? ` — ${f.description}` : "";
17637
- return ` --${f.flag} <${f.kind}> [${req}]${fileNote}${desc}`;
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}`;
17638
17651
  });
17639
17652
  const primaryNote = primary ? `
17640
17653
 
@@ -17869,7 +17882,7 @@ async function renderMe(ctx, action) {
17869
17882
  ` : "") + spaceLines;
17870
17883
  emitDual(me, human, action, ctx);
17871
17884
  }
17872
- 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 (e.g. \`--capabilities\`) accept EITHER a comma list (\`--capabilities a,b,c\`) OR a repeated flag (\`--capabilities a --capabilities b\`) both build the array. \`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.`;
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.`;
17873
17886
  function renderOrient(ctx) {
17874
17887
  emitDual({ orientation: ORIENTATION, cliNote: CLI_NOTE }, `${ORIENTATION}
17875
17888
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
5
5
  "keywords": [
6
6
  "agents",