@lambdacurry/arbor 0.8.2 → 0.8.3
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 +27 -8
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -1594,9 +1594,13 @@ var requests = sqliteTable("requests", {
|
|
|
1594
1594
|
audience: text("audience", { mode: "json" }).$type().notNull(),
|
|
1595
1595
|
completionPolicy: text("completion_policy", { mode: "json" }).$type().notNull(),
|
|
1596
1596
|
status: text("status").$type().notNull().default("open"),
|
|
1597
|
+
opensAt: ts("opens_at"),
|
|
1597
1598
|
expiresAt: ts("expires_at"),
|
|
1598
1599
|
createdAt: ts("created_at").notNull()
|
|
1599
|
-
}, (t) => ({
|
|
1600
|
+
}, (t) => ({
|
|
1601
|
+
threadIdx: index("requests_thread_idx").on(t.threadId),
|
|
1602
|
+
statusOpensIdx: index("requests_status_opens_idx").on(t.status, t.opensAt)
|
|
1603
|
+
}));
|
|
1600
1604
|
var inboxItems = sqliteTable("inbox_items", {
|
|
1601
1605
|
id: text("id").primaryKey(),
|
|
1602
1606
|
targetProfileId: text("target_profile_id").notNull().references(() => profiles.id),
|
|
@@ -16042,7 +16046,7 @@ config(en_default());
|
|
|
16042
16046
|
// ../actions/src/index.ts
|
|
16043
16047
|
var ORIENTATION = `Arbor is your team's deliberation room and shared memory — people and agents settle typed work here, and Arbor remembers what's decided. To work well:
|
|
16044
16048
|
|
|
16045
|
-
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. 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. 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.
|
|
16049
|
+
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. 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.
|
|
16046
16050
|
2. CONTRIBUTE typed points — but ADD ONLY WHAT'S ADDITIVE (AD-205). Ask what the most additive move is, not whether to say something: if your reaction to a point already on the record fits in one line — agree OR disagree — STAMP it (vouch, or push back with a one-line why), don't restate it; if you'd only echo consensus, reviewing IS the contribution and staying out is fine. When you DO contribute, it's ONE point, with the type that names your move (proposal / critique / question / evidence / risk / correction / assertion / decision). Markdown welcome; put references IN your prose (a URL or [label](#con_…) becomes a navigable reference). Prose refs are CITATIONS — they never move your contribution in the thread, so cite freely; to REPLY under a specific contribution, pass links: [{rel: 'inReplyTo', targetId}] (AD-196). WHY: a thread where every agent restates the consensus is noise — the record is strongest when each point appears ONCE and gets vouched (or contested) with a stamp, not re-said; and one typed point is reviewable on its own, so a synthesis citing five points should read as the most top-level thing in the thread, not as a reply to the first one it mentions.
|
|
16047
16051
|
3. ANSWER through requests. When \`inbox\` or a thread shows an open request you can meet, answer THROUGH it — \`respond\` to it, or \`stamp\` the contribution a review request is about — so it completes and the requester is notified. WHY: a plain reply that merely happens to answer leaves their request hanging (the most common failure).
|
|
16048
16052
|
4. REVIEW honestly; promote the standout, sparingly. \`stamp\` to vouch or push back with a one-line why (you can't stamp your own work — request a review via \`request\`). PROMOTE a contribution/artifact only when it's the standout the org should find FIRST (the \uD83C\uDF96️). One deliberate exception (AD-200): in a STANDING thread, periodically promoting a distilling synthesis IS the job — it's how an open-forever lane compresses for newcomers and recall, not applause inflation; promoting your own synthesis there is fine (only stamps bar self-review). WHY: promotion is curation, not applause — and it's about an OUTPUT, never a whole thread (a thread RESOLVES; it is never "promoted").
|
|
@@ -16094,7 +16098,7 @@ var ACTIONS = [
|
|
|
16094
16098
|
threadId: exports_external.string().describe("the thread id, e.g. thr_…"),
|
|
16095
16099
|
type: exports_external.enum(CONTRIBUTION_TYPES).describe("the contribution type (AD-066 taxonomy)"),
|
|
16096
16100
|
body: exports_external.string().min(1).describe("the contribution text"),
|
|
16097
|
-
summary: exports_external.string().max(
|
|
16101
|
+
summary: exports_external.string().max(500).optional().describe("optional gist, 1-2 short sentences — HARD LIMIT 500 characters (the request is rejected past it, so keep well under). Becomes the recall snippet AND sharpens recall for long contributions (it's prepended to the embedded text); write one when the body is long"),
|
|
16098
16102
|
confidence: exports_external.number().int().min(0).max(100).optional().describe("optional 0–100 confidence"),
|
|
16099
16103
|
mentions: exports_external.array(exports_external.object({
|
|
16100
16104
|
kind: exports_external.enum(["person", "contribution", "artifact"]),
|
|
@@ -16114,7 +16118,7 @@ var ACTIONS = [
|
|
|
16114
16118
|
inputSchema: {
|
|
16115
16119
|
contributionId: exports_external.string().describe("your contribution's id, con_…"),
|
|
16116
16120
|
body: exports_external.string().min(1).describe("the replacement markdown body"),
|
|
16117
|
-
summary: exports_external.string().max(
|
|
16121
|
+
summary: exports_external.string().max(500).optional().describe("optional gist, 1-2 short sentences (HARD LIMIT 500 characters) — omit to leave unchanged, empty string to clear")
|
|
16118
16122
|
},
|
|
16119
16123
|
surfaces: ["mcp", "cli"],
|
|
16120
16124
|
toolset: "loop",
|
|
@@ -16337,7 +16341,7 @@ var ACTIONS = [
|
|
|
16337
16341
|
{
|
|
16338
16342
|
name: "request",
|
|
16339
16343
|
title: "Request a contribution or review",
|
|
16340
|
-
description:
|
|
16344
|
+
description: 'Request input on a thread (AD-161). OMIT `aboutContributionId` to ask for a CONTRIBUTION — evidence, a proposal, or a decision you need — answered via `respond`. PASS it to ask for a REVIEW of that contribution — answered ONLY by a `stamp`, so never wrap a decision as a review. Name targets (an inbox item each) or leave it open; completion is software-computed (first | quorum | all-targets | deadline | explicit); every request expires (default 14 days). SEND LATER: pass `opensAt` (ISO) or `opensIn` ("2h", "3d", "1w") to schedule the request — it stays dormant (no inbox delivery, no notification) until that time, then opens normally; default expiry runs 14 days from OPEN. Reschedule via the CLI `reschedule_request` (or cancel + re-request), retire with `cancel_request`.',
|
|
16341
16345
|
inputSchema: {
|
|
16342
16346
|
threadId: exports_external.string().describe("the thread the request is in, thr_…"),
|
|
16343
16347
|
requestedAction: exports_external.string().optional().describe("a one-line 'what you're requesting'"),
|
|
@@ -16346,12 +16350,27 @@ var ACTIONS = [
|
|
|
16346
16350
|
targetProfileIds: exports_external.array(exports_external.string()).optional().describe("targeted recipients (omit → open board)"),
|
|
16347
16351
|
completion: exports_external.enum(["first", "quorum", "all-targets", "deadline", "explicit"]),
|
|
16348
16352
|
quorumN: exports_external.number().int().min(1).optional().describe("required when completion=quorum"),
|
|
16349
|
-
expiresAt: exports_external.string().optional().describe("ISO-8601 deadline (default: 14 days from creation, AD-167)")
|
|
16353
|
+
expiresAt: exports_external.string().optional().describe("ISO-8601 deadline (default: 14 days from creation — or from opensAt when scheduled, AD-167/SFR-360)"),
|
|
16354
|
+
opensAt: exports_external.string().optional().describe("SEND LATER (SFR-360): ISO-8601 instant to open at — the request stays dormant until then. Must be future and before expiresAt"),
|
|
16355
|
+
opensIn: exports_external.string().optional().describe('SEND LATER sugar: a duration from now — "30m", "2h", "3d", "1w". opensAt wins if both')
|
|
16350
16356
|
},
|
|
16351
16357
|
surfaces: ["mcp", "cli"],
|
|
16352
16358
|
toolset: "loop",
|
|
16353
16359
|
run: forward("request.create")
|
|
16354
16360
|
},
|
|
16361
|
+
{
|
|
16362
|
+
name: "reschedule_request",
|
|
16363
|
+
title: "Reschedule a scheduled request",
|
|
16364
|
+
description: 'Move a SCHEDULED request\'s open time (SFR-360) — yours only (or org owner). Takes `opensAt` (ISO) or `opensIn` ("2h", "3d", "1w") like `request`. Only works while the request is still dormant; once it opens it\'s live and can\'t be rescheduled. A default expiry moves with the new open time; an explicit one stays.',
|
|
16365
|
+
inputSchema: {
|
|
16366
|
+
requestId: exports_external.string().describe("the scheduled request, req_…"),
|
|
16367
|
+
opensAt: exports_external.string().optional().describe("new ISO-8601 open instant"),
|
|
16368
|
+
opensIn: exports_external.string().optional().describe('new open time as a duration from now — "2h", "3d", "1w"')
|
|
16369
|
+
},
|
|
16370
|
+
surfaces: ["cli"],
|
|
16371
|
+
toolset: "loop",
|
|
16372
|
+
run: forward("request.reschedule")
|
|
16373
|
+
},
|
|
16355
16374
|
{
|
|
16356
16375
|
name: "respond",
|
|
16357
16376
|
title: "Respond to a request",
|
|
@@ -16381,7 +16400,7 @@ var ACTIONS = [
|
|
|
16381
16400
|
{
|
|
16382
16401
|
name: "cancel_request",
|
|
16383
16402
|
title: "Cancel a request",
|
|
16384
|
-
description: "Cancel an OPEN request you raised (or any
|
|
16403
|
+
description: "Cancel an OPEN or SCHEDULED request you raised (or any such request, if you're the org owner) — it moves to a terminal `cancelled` state and any inbox items it fanned out are SILENTLY withdrawn (they leave recipients' inboxes, no notification). Use this when a request is no longer needed. A completed/expired one can't be cancelled. Returns `status: cancelled` (success) + `withdrawn`: how many recipients' inbox items were retracted — `0` just means it hadn't reached anyone yet (a scheduled request always withdraws 0), NOT a failure.",
|
|
16385
16404
|
inputSchema: {
|
|
16386
16405
|
requestId: exports_external.string().describe("the open request to cancel, req_…")
|
|
16387
16406
|
},
|
|
@@ -17697,7 +17716,7 @@ async function renderMe(ctx, action) {
|
|
|
17697
17716
|
` : "") + spaceLines;
|
|
17698
17717
|
emitDual(me, human, action, ctx);
|
|
17699
17718
|
}
|
|
17700
|
-
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\` (
|
|
17719
|
+
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.`;
|
|
17701
17720
|
function renderOrient(ctx) {
|
|
17702
17721
|
emitDual({ orientation: ORIENTATION, cliNote: CLI_NOTE }, `${ORIENTATION}
|
|
17703
17722
|
|
package/package.json
CHANGED