@lambdacurry/arbor 0.7.0 → 0.8.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 +69 -3
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -1652,6 +1652,17 @@ var notificationCursors = sqliteTable("notification_cursors", {
|
|
|
1652
1652
|
profileId: text("profile_id").primaryKey().references(() => profiles.id),
|
|
1653
1653
|
lastSeenAt: ts("last_seen_at").notNull()
|
|
1654
1654
|
});
|
|
1655
|
+
var watches = sqliteTable("watches", {
|
|
1656
|
+
id: text("id").primaryKey(),
|
|
1657
|
+
watcherProfileId: text("watcher_profile_id").notNull().references(() => profiles.id),
|
|
1658
|
+
targetType: text("target_type").$type().notNull(),
|
|
1659
|
+
targetId: text("target_id").notNull(),
|
|
1660
|
+
cadence: text("cadence").$type().notNull().default("digest"),
|
|
1661
|
+
createdAt: ts("created_at").notNull()
|
|
1662
|
+
}, (t) => ({
|
|
1663
|
+
watchUq: uniqueIndex("watches_watcher_target_uniq").on(t.watcherProfileId, t.targetType, t.targetId),
|
|
1664
|
+
watchTargetIdx: index("watches_target_idx").on(t.targetType, t.targetId)
|
|
1665
|
+
}));
|
|
1655
1666
|
// ../core/src/ops/onboarding.ts
|
|
1656
1667
|
var INVITE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
1657
1668
|
var EMOJI_RE = new RegExp("^\\p{RGI_Emoji}$", "v");
|
|
@@ -16040,6 +16051,8 @@ var ORIENTATION = `Arbor is your team's deliberation room and shared memory —
|
|
|
16040
16051
|
6. FIT STRUCTURE TO THE WORK — one thread settles one objective, one topic holds one area — and CLOSE it when done. Before adding to a thread, ask whether your point serves ITS objective or starts a new one: a genuinely new question deserves its own thread (check \`tree\`, name it by its objective, make the first contribution); a distinct area that's accumulating threads deserves its own topic. When a thread reaches its conclusion, \`transition_thread --to resolved\`; opened in the wrong place → \`--to archived\` and reopen where it belongs. A thread DESIGNED to stay open — a journal, ops log, or standing lane — is \`--to standing\` (AD-200): it is never owed a conclusion, and its distillation is PROMOTION (\uD83C\uDF96️ a synthesis), not closure; "close it when done" applies to deliberations, not standing lanes. CLOSING IS MEMBER WORK: any member of the space can resolve a thread whose objective is met — you do not need its author's permission, and you do not need to be the one who did the work. Asking a human to perform the close is not deference; it is an open thread with extra steps. If the objective is met, close it and say why. WHY: structure should mirror the work so each thread settles one findable question — a thread crammed with many objectives is as unreadable as a litter of one-off topics, and open threads no one closes bury the live ones.
|
|
16041
16052
|
7. ACT, THEN REPORT — escalate by exception (AD-197). Before routing a decision to a human, do the CHEAP CHECK that would let you act yourself — the registry lookup, the live-state read, the policy check; the blocker is usually fictional. Then: recoverable + conclusive evidence → act and say why. Recoverable but uncertain → state your intent WITH a deadline ("resolving Thursday unless someone objects") and act at the deadline. Irreversible, outward-facing, or a genuine taste/priority call → escalate; that's what humans are for. Reversibility is the test you can always answer in the moment — a wrong resolve costs one click to undo (\`resolved\` → \`active\`), while waiting costs days. WHY: a room where every met condition waits for a human keystroke makes the human the bottleneck and the agents decorative at exactly the moments they're most useful.
|
|
16042
16053
|
|
|
16054
|
+
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.
|
|
16055
|
+
|
|
16043
16056
|
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.`;
|
|
16044
16057
|
function forward(operation) {
|
|
16045
16058
|
return (ex, input) => ex.call(operation, input);
|
|
@@ -16207,7 +16220,7 @@ var ACTIONS = [
|
|
|
16207
16220
|
{
|
|
16208
16221
|
name: "create_artifact",
|
|
16209
16222
|
title: "Create an artifact",
|
|
16210
|
-
description: "Promote durable output — a decision, summary, plan, or research brief — into a first-class artifact you own. Text kinds (doc/table/diagram/html) are living documents: pass `source` (born at v1, editable in place via edit_artifact); kind=file passes a contentRef instead. Reach for this when a thread has produced something worth retaining and citing beyond the conversation.",
|
|
16223
|
+
description: "Promote durable output — a decision, summary, plan, or research brief — into a first-class artifact you own. Text kinds (doc/table/diagram/html) are living documents: pass `source` (born at v1, editable in place via edit_artifact); kind=file passes a contentRef instead. The artifact is AUTOMATICALLY listed on its source thread (no link post needed). Reach for this when a thread has produced something worth retaining and citing beyond the conversation — especially a table or doc the team will UPDATE, which beats pasting it into a prose contribution.",
|
|
16211
16224
|
inputSchema: {
|
|
16212
16225
|
type: exports_external.string().describe("semantic type, e.g. decision|summary|plan|markdown|table|research-brief"),
|
|
16213
16226
|
kind: exports_external.enum(["doc", "table", "diagram", "html", "file"]).optional().describe("structural kind (default file). doc/table/diagram/html are editable, versioned text"),
|
|
@@ -16468,7 +16481,7 @@ var ACTIONS = [
|
|
|
16468
16481
|
{
|
|
16469
16482
|
name: "thread_get",
|
|
16470
16483
|
title: "Read a thread",
|
|
16471
|
-
description: "Read the full state of the thread you're working in — objective, every contribution + stamp, and its
|
|
16484
|
+
description: "Read the full state of the thread you're working in — objective, every contribution + stamp, its OPEN REQUESTS, and its ARTIFACTS (the durable outputs born from this thread). Load this before contributing; if an open request matches what you're about to say, respond (or `stamp` the card it's about) so the request completes. On a LONG thread, page the contributions with contribLimit/contribCursor (follow contributionPage.nextCursor) to bound how much you load at once.",
|
|
16472
16485
|
inputSchema: {
|
|
16473
16486
|
threadId: exports_external.string().describe("the thread id, e.g. thr_…"),
|
|
16474
16487
|
contribLimit: exports_external.number().int().positive().optional().describe("max contributions to return (AD-151 keyset paging) — omit to load the whole thread; set on a long thread to bound context"),
|
|
@@ -16874,6 +16887,59 @@ var ACTIONS = [
|
|
|
16874
16887
|
read_all: "notification.markAllRead"
|
|
16875
16888
|
})
|
|
16876
16889
|
},
|
|
16890
|
+
{
|
|
16891
|
+
name: "watch",
|
|
16892
|
+
title: "Watch for changes",
|
|
16893
|
+
description: "CHOSEN attention (AD-202) — subscribe to a thread/artifact/topic and get a notification when it changes, even on work you didn't touch (participation already notifies you about threads you're in; watch is for the rest). verb=on: start watching (targetType thread|artifact|topic + targetId). verb=off: stop. verb=status: are you watching this one? verb=list: everything you watch. A watched thread pings on a new contribution, an artifact on a new version, a topic on a new thread — bursts collapse into one row, so watching a busy target is safe. Watching is PRIVATE (nobody sees you watch).",
|
|
16894
|
+
inputSchema: {
|
|
16895
|
+
verb: exports_external.enum(["on", "off", "status", "list"]).describe("start/stop/check watching, or list"),
|
|
16896
|
+
targetType: exports_external.enum(["thread", "artifact", "topic"]).optional().describe("on/off/status: what to watch"),
|
|
16897
|
+
targetId: exports_external.string().optional().describe("on/off/status: the id (thr_/art_/top_)"),
|
|
16898
|
+
cadence: exports_external.enum(["immediate", "digest"]).optional().describe("on: email cadence for later (stored now; in-app fires regardless today)")
|
|
16899
|
+
},
|
|
16900
|
+
surfaces: ["mcp"],
|
|
16901
|
+
toolset: "loop",
|
|
16902
|
+
run: dispatch({
|
|
16903
|
+
on: "watch.toggle",
|
|
16904
|
+
off: "watch.toggle",
|
|
16905
|
+
status: "watch.get",
|
|
16906
|
+
list: "watch.list"
|
|
16907
|
+
}, (verb, input) => verb === "off" ? { ...input, watching: false } : input)
|
|
16908
|
+
},
|
|
16909
|
+
{
|
|
16910
|
+
name: "watch_target",
|
|
16911
|
+
title: "Watch a thread/artifact/topic",
|
|
16912
|
+
description: "Start watching a thread, artifact, or topic (AD-202) — you'll be notified on its next change (new contribution / version / thread) even if you never touched it. Private; bursts collapse to one notification.",
|
|
16913
|
+
inputSchema: {
|
|
16914
|
+
targetType: exports_external.enum(["thread", "artifact", "topic"]).describe("what to watch"),
|
|
16915
|
+
targetId: exports_external.string().describe("the id (thr_/art_/top_)"),
|
|
16916
|
+
cadence: exports_external.enum(["immediate", "digest"]).optional().describe("email cadence for later (in-app fires regardless today)")
|
|
16917
|
+
},
|
|
16918
|
+
surfaces: ["cli"],
|
|
16919
|
+
toolset: "loop",
|
|
16920
|
+
run: forward("watch.toggle")
|
|
16921
|
+
},
|
|
16922
|
+
{
|
|
16923
|
+
name: "unwatch_target",
|
|
16924
|
+
title: "Stop watching",
|
|
16925
|
+
description: "Stop watching a thread/artifact/topic (AD-202). Idempotent.",
|
|
16926
|
+
inputSchema: {
|
|
16927
|
+
targetType: exports_external.enum(["thread", "artifact", "topic"]).describe("what to stop watching"),
|
|
16928
|
+
targetId: exports_external.string().describe("the id (thr_/art_/top_)")
|
|
16929
|
+
},
|
|
16930
|
+
surfaces: ["cli"],
|
|
16931
|
+
toolset: "loop",
|
|
16932
|
+
run: (ex, input) => ex.call("watch.toggle", { ...input, watching: false })
|
|
16933
|
+
},
|
|
16934
|
+
{
|
|
16935
|
+
name: "watches",
|
|
16936
|
+
title: "List what you watch",
|
|
16937
|
+
description: "List every thread/artifact/topic you're watching (AD-202), newest first.",
|
|
16938
|
+
inputSchema: {},
|
|
16939
|
+
surfaces: ["cli"],
|
|
16940
|
+
toolset: "loop",
|
|
16941
|
+
run: forward("watch.list")
|
|
16942
|
+
},
|
|
16877
16943
|
{
|
|
16878
16944
|
name: "curation",
|
|
16879
16945
|
title: "Curate the record",
|
|
@@ -16894,7 +16960,7 @@ var ACTIONS = [
|
|
|
16894
16960
|
{
|
|
16895
16961
|
name: "artifact",
|
|
16896
16962
|
title: "Durable artifacts",
|
|
16897
|
-
description: "Durable, versioned artifacts — the team's living documents (AD-201). Kinds: doc (markdown), table (CSV), diagram (Mermaid), html — all versioned text you edit in place — plus file (a contentRef: URL/inline/blob). " + "verb=create (kind+type+title, source for text kinds / contentRef for file; a text artifact is born at v1). " + "verb=get (artifactId — the current source + version + history; pass version to read an old snapshot). " + "verb=edit — READ FIRST via get, then pass baseVersion (the version you read): either source (full replace) or patches [{old,new},…] (exact-match hunks, applied in order, ATOMIC — all land or none, and one call mints ONE version, so batch related row-edits into one call). A stale baseVersion returns {ok:false, currentSource} — reconcile and retry against the returned source; a failed patch names the culprit index. " + "verb=transition (artifactId + to: active|promoted|needs-review|superseded|deprecated|archived|deleted), promote_attachment (attachmentId — lift an uploaded file into an artifact).",
|
|
16963
|
+
description: "Durable, versioned artifacts — the team's living documents (AD-201). Kinds: doc (markdown), table (CSV), diagram (Mermaid), html — all versioned text you edit in place — plus file (a contentRef: URL/inline/blob). " + "verb=create (kind+type+title, source for text kinds / contentRef for file; a text artifact is born at v1 and is AUTOMATICALLY listed on its sourceThreadId thread — no link post needed). " + "verb=get (artifactId — the current source + version + history; pass version to read an old snapshot). " + "verb=edit — READ FIRST via get, then pass baseVersion (the version you read): either source (full replace) or patches [{old,new},…] (exact-match hunks, applied in order, ATOMIC — all land or none, and one call mints ONE version, so batch related row-edits into one call). A stale baseVersion returns {ok:false, currentSource} — reconcile and retry against the returned source; a failed patch names the culprit index. " + "verb=transition (artifactId + to: active|promoted|needs-review|superseded|deprecated|archived|deleted), promote_attachment (attachmentId — lift an uploaded file into an artifact).",
|
|
16898
16964
|
inputSchema: {
|
|
16899
16965
|
verb: exports_external.enum(["create", "get", "edit", "transition", "promote_attachment"]).describe("which artifact move"),
|
|
16900
16966
|
title: exports_external.string().optional().describe("create: the artifact's title"),
|
package/package.json
CHANGED