@lambdacurry/arbor 0.20.31 → 0.20.32
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 +361 -4
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -31,6 +31,19 @@ var CONTRIBUTION_TYPES = [
|
|
|
31
31
|
"decision"
|
|
32
32
|
];
|
|
33
33
|
var STAMP_FACETS = ["quality", "impact", "fit", "originality"];
|
|
34
|
+
// ../core/src/feedback/constants.ts
|
|
35
|
+
var ARBOR_FEEDBACK_TYPES = [
|
|
36
|
+
"comment",
|
|
37
|
+
"question",
|
|
38
|
+
"assertion",
|
|
39
|
+
"evidence",
|
|
40
|
+
"critique",
|
|
41
|
+
"proposal",
|
|
42
|
+
"risk",
|
|
43
|
+
"correction"
|
|
44
|
+
];
|
|
45
|
+
var ARBOR_FEEDBACK_CAPABILITIES = ["moderate", "review_private"];
|
|
46
|
+
var ARBOR_FEEDBACK_STATUSES = ["new", "reviewed", "linked", "resolved"];
|
|
34
47
|
// ../core/src/errors/contract.ts
|
|
35
48
|
var ERROR_REASONS = new Set([
|
|
36
49
|
"validation.missing_field",
|
|
@@ -1706,7 +1719,8 @@ var orgs = sqliteTable("orgs", {
|
|
|
1706
1719
|
createdAt: ts("created_at").notNull(),
|
|
1707
1720
|
status: text("status").$type().notNull().default("active"),
|
|
1708
1721
|
lockedAt: ts("locked_at"),
|
|
1709
|
-
lockedReason: text("locked_reason")
|
|
1722
|
+
lockedReason: text("locked_reason"),
|
|
1723
|
+
systemKind: text("system_kind").unique()
|
|
1710
1724
|
});
|
|
1711
1725
|
var profiles = sqliteTable("profiles", {
|
|
1712
1726
|
id: text("id").primaryKey(),
|
|
@@ -1755,8 +1769,12 @@ var spaces = sqliteTable("spaces", {
|
|
|
1755
1769
|
contributionLanes: text("contribution_lanes", { mode: "json" }).$type().notNull().default([]),
|
|
1756
1770
|
defaultReviewDimensions: text("default_review_dimensions", { mode: "json" }).$type().notNull().default([]),
|
|
1757
1771
|
stage: text("stage").$type().notNull().default("exploration"),
|
|
1772
|
+
systemKind: text("system_kind"),
|
|
1758
1773
|
createdAt: ts("created_at").notNull()
|
|
1759
|
-
}, (t) => ({
|
|
1774
|
+
}, (t) => ({
|
|
1775
|
+
orgIdx: index("spaces_org_idx").on(t.orgId),
|
|
1776
|
+
systemKindUq: uniqueIndex("spaces_system_kind_uq").on(t.systemKind)
|
|
1777
|
+
}));
|
|
1760
1778
|
var spaceMemberships = sqliteTable("space_memberships", {
|
|
1761
1779
|
id: text("id").primaryKey(),
|
|
1762
1780
|
spaceId: text("space_id").notNull().references(() => spaces.id),
|
|
@@ -1815,6 +1833,7 @@ var topics = sqliteTable("topics", {
|
|
|
1815
1833
|
purpose: text("purpose"),
|
|
1816
1834
|
guidance: text("guidance", { mode: "json" }).$type().notNull().default([]),
|
|
1817
1835
|
contributionLanes: text("contribution_lanes", { mode: "json" }).$type().notNull().default([]),
|
|
1836
|
+
archivedAt: ts("archived_at"),
|
|
1818
1837
|
createdAt: ts("created_at").notNull()
|
|
1819
1838
|
}, (t) => ({ spaceIdx: index("topics_space_idx").on(t.spaceId) }));
|
|
1820
1839
|
var initiatives = sqliteTable("initiatives", {
|
|
@@ -2557,6 +2576,93 @@ var inboxItems = sqliteTable("inbox_items", {
|
|
|
2557
2576
|
targetIdx: index("inbox_target_idx").on(t.targetProfileId, t.status),
|
|
2558
2577
|
dedupeIdx: index("inbox_dedupe_idx").on(t.dedupeKey)
|
|
2559
2578
|
}));
|
|
2579
|
+
var arborFeedback = sqliteTable("arbor_feedback", {
|
|
2580
|
+
id: text("id").primaryKey(),
|
|
2581
|
+
reporterProfileId: text("reporter_profile_id").notNull().references(() => profiles.id),
|
|
2582
|
+
reporterOrgId: text("reporter_org_id").notNull().references(() => orgs.id),
|
|
2583
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2584
|
+
computerSessionId: text("computer_session_id").references(() => computerSessions.id),
|
|
2585
|
+
type: text("type").$type().notNull(),
|
|
2586
|
+
body: text("body").notNull(),
|
|
2587
|
+
summary: text("summary"),
|
|
2588
|
+
confidence: integer("confidence"),
|
|
2589
|
+
idempotencyKey: text("idempotency_key"),
|
|
2590
|
+
idempotencyFingerprint: text("idempotency_fingerprint"),
|
|
2591
|
+
source: text("source", { mode: "json" }).$type().notNull(),
|
|
2592
|
+
status: text("status").$type().notNull().default("new"),
|
|
2593
|
+
reviewedAt: ts("reviewed_at"),
|
|
2594
|
+
reviewedByProfileId: text("reviewed_by_profile_id").references(() => profiles.id),
|
|
2595
|
+
resolvedAt: ts("resolved_at"),
|
|
2596
|
+
resolvedByProfileId: text("resolved_by_profile_id").references(() => profiles.id),
|
|
2597
|
+
createdAt: ts("created_at").notNull(),
|
|
2598
|
+
updatedAt: ts("updated_at").notNull()
|
|
2599
|
+
}, (t) => ({
|
|
2600
|
+
reporterReplayUq: uniqueIndex("arbor_feedback_reporter_replay_uq").on(t.reporterProfileId, t.idempotencyKey),
|
|
2601
|
+
statusCreatedIdx: index("arbor_feedback_status_created_idx").on(t.status, t.createdAt),
|
|
2602
|
+
orgCreatedIdx: index("arbor_feedback_org_created_idx").on(t.reporterOrgId, t.createdAt)
|
|
2603
|
+
}));
|
|
2604
|
+
var arborFeedbackAssociations = sqliteTable("arbor_feedback_associations", {
|
|
2605
|
+
id: text("id").primaryKey(),
|
|
2606
|
+
feedbackId: text("feedback_id").notNull().references(() => arborFeedback.id),
|
|
2607
|
+
targetType: text("target_type").$type().notNull(),
|
|
2608
|
+
topicId: text("topic_id").references(() => topics.id),
|
|
2609
|
+
threadId: text("thread_id").references(() => threads.id),
|
|
2610
|
+
createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
|
|
2611
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2612
|
+
createdAt: ts("created_at").notNull()
|
|
2613
|
+
}, (t) => ({
|
|
2614
|
+
targetShape: check("arbor_feedback_associations_target_shape", sql`(${t.targetType} = 'topic' and ${t.topicId} is not null and ${t.threadId} is null) or (${t.targetType} = 'thread' and ${t.threadId} is not null and ${t.topicId} is null)`),
|
|
2615
|
+
feedbackTopicUq: uniqueIndex("arbor_feedback_associations_feedback_topic_uq").on(t.feedbackId, t.topicId).where(sql`${t.topicId} is not null`),
|
|
2616
|
+
feedbackThreadUq: uniqueIndex("arbor_feedback_associations_feedback_thread_uq").on(t.feedbackId, t.threadId).where(sql`${t.threadId} is not null`),
|
|
2617
|
+
feedbackIdx: index("arbor_feedback_associations_feedback_idx").on(t.feedbackId),
|
|
2618
|
+
threadIdx: index("arbor_feedback_associations_thread_idx").on(t.threadId)
|
|
2619
|
+
}));
|
|
2620
|
+
var arborFeedbackGrants = sqliteTable("arbor_feedback_grants", {
|
|
2621
|
+
id: text("id").primaryKey(),
|
|
2622
|
+
profileId: text("profile_id").notNull().references(() => profiles.id),
|
|
2623
|
+
capability: text("capability").$type().notNull(),
|
|
2624
|
+
grantedByProfileId: text("granted_by_profile_id").notNull().references(() => profiles.id),
|
|
2625
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2626
|
+
createdAt: ts("created_at").notNull()
|
|
2627
|
+
}, (t) => ({
|
|
2628
|
+
profileCapabilityUq: uniqueIndex("arbor_feedback_grants_profile_capability_uq").on(t.profileId, t.capability),
|
|
2629
|
+
capabilityIdx: index("arbor_feedback_grants_capability_idx").on(t.capability, t.profileId)
|
|
2630
|
+
}));
|
|
2631
|
+
var arborFeedbackPublications = sqliteTable("arbor_feedback_publications", {
|
|
2632
|
+
id: text("id").primaryKey(),
|
|
2633
|
+
feedbackId: text("feedback_id").notNull().references(() => arborFeedback.id),
|
|
2634
|
+
contributionId: text("contribution_id").notNull().references(() => contributions.id),
|
|
2635
|
+
createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
|
|
2636
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2637
|
+
createdAt: ts("created_at").notNull()
|
|
2638
|
+
}, (t) => ({
|
|
2639
|
+
pairUq: uniqueIndex("arbor_feedback_publications_pair_uq").on(t.feedbackId, t.contributionId),
|
|
2640
|
+
feedbackIdx: index("arbor_feedback_publications_feedback_idx").on(t.feedbackId),
|
|
2641
|
+
contributionIdx: index("arbor_feedback_publications_contribution_idx").on(t.contributionId)
|
|
2642
|
+
}));
|
|
2643
|
+
var arborFeedbackThreadMerges = sqliteTable("arbor_feedback_thread_merges", {
|
|
2644
|
+
sourceThreadId: text("source_thread_id").primaryKey().references(() => threads.id),
|
|
2645
|
+
targetThreadId: text("target_thread_id").notNull().references(() => threads.id),
|
|
2646
|
+
mergedByProfileId: text("merged_by_profile_id").notNull().references(() => profiles.id),
|
|
2647
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2648
|
+
reason: text("reason"),
|
|
2649
|
+
createdAt: ts("created_at").notNull()
|
|
2650
|
+
}, (t) => ({
|
|
2651
|
+
notSelf: check("arbor_feedback_thread_merges_not_self", sql`${t.sourceThreadId} <> ${t.targetThreadId}`),
|
|
2652
|
+
targetIdx: index("arbor_feedback_thread_merges_target_idx").on(t.targetThreadId)
|
|
2653
|
+
}));
|
|
2654
|
+
var arborFeedbackAuditEvents = sqliteTable("arbor_feedback_audit_events", {
|
|
2655
|
+
id: text("id").primaryKey(),
|
|
2656
|
+
feedbackId: text("feedback_id").references(() => arborFeedback.id),
|
|
2657
|
+
action: text("action").$type().notNull(),
|
|
2658
|
+
actorProfileId: text("actor_profile_id").notNull().references(() => profiles.id),
|
|
2659
|
+
executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
|
|
2660
|
+
metadata: text("metadata", { mode: "json" }).$type().notNull(),
|
|
2661
|
+
createdAt: ts("created_at").notNull()
|
|
2662
|
+
}, (t) => ({
|
|
2663
|
+
feedbackCreatedIdx: index("arbor_feedback_audit_feedback_created_idx").on(t.feedbackId, t.createdAt),
|
|
2664
|
+
actionCreatedIdx: index("arbor_feedback_audit_action_created_idx").on(t.action, t.createdAt)
|
|
2665
|
+
}));
|
|
2560
2666
|
var events = sqliteTable("events", {
|
|
2561
2667
|
id: text("id").primaryKey(),
|
|
2562
2668
|
type: text("type").notNull(),
|
|
@@ -2743,6 +2849,7 @@ var INDEX_ON = new Set([
|
|
|
2743
2849
|
"artifact.edited",
|
|
2744
2850
|
"review.added",
|
|
2745
2851
|
"thread.created",
|
|
2852
|
+
"thread.edited",
|
|
2746
2853
|
"topic.created",
|
|
2747
2854
|
"topic.edited",
|
|
2748
2855
|
"contribution.restored"
|
|
@@ -17579,6 +17686,44 @@ var MCP_OUTPUT_SCHEMAS = {
|
|
|
17579
17686
|
deployment: exports_external.looseObject({ id: exports_external.string(), sourceRevision: exports_external.string().nullable(), deployedAt: timestamp }).nullable()
|
|
17580
17687
|
}),
|
|
17581
17688
|
recall: exports_external.object({ result: exports_external.array(recallHit) }),
|
|
17689
|
+
feedback_tree: exports_external.looseObject({
|
|
17690
|
+
scope: exports_external.literal("global"),
|
|
17691
|
+
forum: exports_external.looseObject({ title: exports_external.string(), purpose: nullableString }),
|
|
17692
|
+
topics: exports_external.array(jsonObject),
|
|
17693
|
+
privacy: exports_external.string()
|
|
17694
|
+
}),
|
|
17695
|
+
feedback_recall: exports_external.looseObject({
|
|
17696
|
+
query: exports_external.string(),
|
|
17697
|
+
topicId: nullableString,
|
|
17698
|
+
hits: exports_external.array(jsonObject),
|
|
17699
|
+
privacy: exports_external.string()
|
|
17700
|
+
}),
|
|
17701
|
+
feedback_thread_get: exports_external.looseObject({
|
|
17702
|
+
requestedThreadId: id,
|
|
17703
|
+
canonicalThreadId: id,
|
|
17704
|
+
thread: jsonObject,
|
|
17705
|
+
topic: jsonObject,
|
|
17706
|
+
contributions: exports_external.array(jsonObject),
|
|
17707
|
+
mergedFrom: exports_external.array(jsonObject),
|
|
17708
|
+
redirects: exports_external.array(jsonObject),
|
|
17709
|
+
privacy: exports_external.string()
|
|
17710
|
+
}),
|
|
17711
|
+
contribute_arbor_feedback: exports_external.looseObject({
|
|
17712
|
+
feedbackId: id,
|
|
17713
|
+
type: exports_external.string(),
|
|
17714
|
+
status: exports_external.string(),
|
|
17715
|
+
private: exports_external.literal(true),
|
|
17716
|
+
replayed: exports_external.boolean(),
|
|
17717
|
+
association: jsonObject.nullable(),
|
|
17718
|
+
message: exports_external.string()
|
|
17719
|
+
}),
|
|
17720
|
+
admin_feedback_capability: jsonObject,
|
|
17721
|
+
admin_feedback_evidence: jsonObject,
|
|
17722
|
+
admin_feedback_topic: jsonObject,
|
|
17723
|
+
admin_feedback_thread: jsonObject,
|
|
17724
|
+
admin_feedback_publish: jsonObject,
|
|
17725
|
+
admin_feedback_edit: jsonObject,
|
|
17726
|
+
admin_feedback_curate: jsonObject,
|
|
17582
17727
|
contribute: exports_external.looseObject({
|
|
17583
17728
|
contributionId: id,
|
|
17584
17729
|
replayed: exports_external.boolean(),
|
|
@@ -18427,6 +18572,17 @@ var destructiveOpenWorld = {
|
|
|
18427
18572
|
var MCP_TOOL_ANNOTATIONS = {
|
|
18428
18573
|
server_info: readOnly,
|
|
18429
18574
|
recall: readOnly,
|
|
18575
|
+
feedback_tree: readOnly,
|
|
18576
|
+
feedback_recall: readOnly,
|
|
18577
|
+
feedback_thread_get: readOnly,
|
|
18578
|
+
contribute_arbor_feedback: additive,
|
|
18579
|
+
admin_feedback_capability: destructiveIdempotent,
|
|
18580
|
+
admin_feedback_evidence: destructive,
|
|
18581
|
+
admin_feedback_topic: destructive,
|
|
18582
|
+
admin_feedback_thread: destructive,
|
|
18583
|
+
admin_feedback_publish: additive,
|
|
18584
|
+
admin_feedback_edit: destructive,
|
|
18585
|
+
admin_feedback_curate: destructive,
|
|
18430
18586
|
contribute: additive,
|
|
18431
18587
|
edit: additive,
|
|
18432
18588
|
stamp: additive,
|
|
@@ -18538,6 +18694,8 @@ var CONTRIBUTION_ADD_LINK_RELS = [
|
|
|
18538
18694
|
];
|
|
18539
18695
|
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:
|
|
18540
18696
|
|
|
18697
|
+
Meaningful friction with Arbor itself can be privately contributed through \`contribute_arbor_feedback\`; the raw body is never posted into the current Thread or the shared Arbor Feedback forum. Browse the curated shared forum with \`feedback_tree\` → \`feedback_recall\` → \`feedback_thread_get\`.
|
|
18698
|
+
|
|
18541
18699
|
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: use \`tree\` to choose the room, then scope \`recall\` with \`space\`/\`topic\`/\`thread\` before deeper reads. 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 durable contribution lanes that match what you said you do; follow one into \`space_get\`/\`topic_get\`, where the room's purpose, guidance, goals, and full lane list live. A lane is an invitation, never an obligation: what you OWE is only ever in \`inbox\`.
|
|
18542
18700
|
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.
|
|
18543
18701
|
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).
|
|
@@ -18659,6 +18817,173 @@ var ACTION_DEFINITIONS = [
|
|
|
18659
18817
|
toolset: "loop",
|
|
18660
18818
|
run: forward("knowledge.recall")
|
|
18661
18819
|
},
|
|
18820
|
+
{
|
|
18821
|
+
name: "feedback_tree",
|
|
18822
|
+
title: "Browse the shared Arbor Feedback forum",
|
|
18823
|
+
description: "READ ONLY: Browse the global curated Arbor Feedback forum by Topic and optional Thread roster; the global scope is implied and no Space id is required. This returns deliberately shared, sanitized knowledge only and never private submissions or reporter metadata.",
|
|
18824
|
+
inputSchema: {
|
|
18825
|
+
depth: exports_external.enum(["topics", "threads"]).optional().describe("topics (default) or threads to include each Topic's shared Thread roster"),
|
|
18826
|
+
includeArchived: exports_external.boolean().optional().describe("include archived Topics/Threads for historical moderation or lookup (default false)")
|
|
18827
|
+
},
|
|
18828
|
+
surfaces: ["mcp", "cli"],
|
|
18829
|
+
toolset: "feedback",
|
|
18830
|
+
run: forward("feedback.tree")
|
|
18831
|
+
},
|
|
18832
|
+
{
|
|
18833
|
+
name: "feedback_recall",
|
|
18834
|
+
title: "Find known Arbor feedback",
|
|
18835
|
+
description: "READ ONLY: Search the global shared Arbor Feedback forum for sanitized issues, workarounds, and decisions; scope to a Topic after feedback_tree when useful. Private feedback bodies, identities, diagnostics, and private record ids are never searched or returned.",
|
|
18836
|
+
inputSchema: {
|
|
18837
|
+
query: exports_external.string().min(1).describe("the Arbor friction, issue, workaround, or idea to find"),
|
|
18838
|
+
topicId: exports_external.string().optional().describe("optional shared Feedback Topic id from feedback_tree"),
|
|
18839
|
+
topK: exports_external.number().int().min(1).max(50).optional().describe("results to return (default 10)")
|
|
18840
|
+
},
|
|
18841
|
+
surfaces: ["mcp", "cli"],
|
|
18842
|
+
toolset: "feedback",
|
|
18843
|
+
run: forward("feedback.recall")
|
|
18844
|
+
},
|
|
18845
|
+
{
|
|
18846
|
+
name: "feedback_thread_get",
|
|
18847
|
+
title: "Read a shared Arbor Feedback thread",
|
|
18848
|
+
description: "READ ONLY: Read one curated shared Arbor Feedback Thread, following a merge redirect to its canonical destination while preserving shared provenance. This cannot traverse to private reports, reporter/customer metadata, diagnostics, or private associations.",
|
|
18849
|
+
inputSchema: {
|
|
18850
|
+
threadId: exports_external.string().describe("the shared Feedback Thread id, thr_…")
|
|
18851
|
+
},
|
|
18852
|
+
surfaces: ["mcp", "cli"],
|
|
18853
|
+
toolset: "feedback",
|
|
18854
|
+
run: forward("feedback.thread_get")
|
|
18855
|
+
},
|
|
18856
|
+
{
|
|
18857
|
+
name: "contribute_arbor_feedback",
|
|
18858
|
+
title: "Privately contribute feedback about Arbor",
|
|
18859
|
+
description: "Privately contribute feedback about using Arbor, including friction, evidence, critiques, questions, risks, or improvement proposals. The submitted body is not posted into the current Thread or shared Arbor Feedback forum; optional Topic/Thread ids only associate the private evidence with sanitized shared knowledge.",
|
|
18860
|
+
inputSchema: {
|
|
18861
|
+
type: exports_external.enum(ARBOR_FEEDBACK_TYPES).optional().describe("the contribution move (default comment); decision is reserved for shared forum curation"),
|
|
18862
|
+
body: exports_external.string().min(1).describe("the private feedback body"),
|
|
18863
|
+
summary: exports_external.string().max(500).optional().describe("optional private gist, at most 500 characters"),
|
|
18864
|
+
confidence: exports_external.number().int().min(0).max(100).optional().describe("optional 0–100 confidence"),
|
|
18865
|
+
idempotencyKey: exports_external.string().min(1).max(200).optional().describe("stable key for this ONE private submission; safe retries return the same receipt"),
|
|
18866
|
+
threadId: exports_external.string().optional().describe("optional shared Feedback Thread this private evidence relates to; not a write destination"),
|
|
18867
|
+
topicId: exports_external.string().optional().describe("optional shared Feedback Topic this private evidence relates to; not a write destination"),
|
|
18868
|
+
computerSessionId: exports_external.string().optional().describe("optional Arbor Computer session you own; only its id is attached, never shell output or files")
|
|
18869
|
+
},
|
|
18870
|
+
surfaces: ["mcp", "cli"],
|
|
18871
|
+
toolset: "feedback",
|
|
18872
|
+
run: forward("feedback.contribute")
|
|
18873
|
+
},
|
|
18874
|
+
{
|
|
18875
|
+
name: "admin_feedback_capability",
|
|
18876
|
+
title: "Manage Arbor Feedback capabilities",
|
|
18877
|
+
description: "Privileged: list or set explicit shared-moderation and private-review grants. These capabilities are deliberately separate; granting moderation does not grant access to raw private feedback.",
|
|
18878
|
+
inputSchema: {
|
|
18879
|
+
verb: exports_external.enum(["list", "set"]).describe("list grants, or set one profile capability"),
|
|
18880
|
+
profileId: exports_external.string().optional().describe("set: the profile receiving or losing the grant"),
|
|
18881
|
+
capability: exports_external.enum(ARBOR_FEEDBACK_CAPABILITIES).optional().describe("set: moderate shared forum or review_private raw evidence"),
|
|
18882
|
+
enabled: exports_external.boolean().optional().describe("set: true to grant; false to revoke")
|
|
18883
|
+
},
|
|
18884
|
+
surfaces: ["mcp", "cli"],
|
|
18885
|
+
toolset: "admin",
|
|
18886
|
+
run: dispatch({ list: "feedback_admin.grants", set: "feedback_admin.grant" })
|
|
18887
|
+
},
|
|
18888
|
+
{
|
|
18889
|
+
name: "admin_feedback_evidence",
|
|
18890
|
+
title: "Review private Arbor feedback evidence",
|
|
18891
|
+
description: "Privileged private-review surface: list/get private reports, associate or disassociate them with shared Topics/Threads, and mark review state. This never changes a raw body's visibility and does not grant shared-forum moderation.",
|
|
18892
|
+
inputSchema: {
|
|
18893
|
+
verb: exports_external.enum(["list", "get", "associate", "disassociate", "status"]).describe("the private-evidence review action"),
|
|
18894
|
+
feedbackId: exports_external.string().optional().describe("get/associate/disassociate/status: private feedback id"),
|
|
18895
|
+
associationId: exports_external.string().optional().describe("disassociate: association id to remove"),
|
|
18896
|
+
topicId: exports_external.string().optional().describe("associate: shared Feedback Topic id"),
|
|
18897
|
+
threadId: exports_external.string().optional().describe("associate: shared Feedback Thread id"),
|
|
18898
|
+
status: exports_external.enum(ARBOR_FEEDBACK_STATUSES).optional().describe("list filter or status: new, reviewed, linked, or resolved"),
|
|
18899
|
+
limit: exports_external.number().int().min(1).max(100).optional().describe("list: rows to return (default 50)")
|
|
18900
|
+
},
|
|
18901
|
+
surfaces: ["mcp", "cli"],
|
|
18902
|
+
toolset: "admin",
|
|
18903
|
+
run: dispatch({
|
|
18904
|
+
list: "feedback_admin.list",
|
|
18905
|
+
get: "feedback_admin.get",
|
|
18906
|
+
associate: "feedback_admin.link",
|
|
18907
|
+
disassociate: "feedback_admin.unlink",
|
|
18908
|
+
status: "feedback_admin.status"
|
|
18909
|
+
})
|
|
18910
|
+
},
|
|
18911
|
+
{
|
|
18912
|
+
name: "admin_feedback_topic",
|
|
18913
|
+
title: "Maintain shared Feedback Topics",
|
|
18914
|
+
description: "Privileged shared-forum moderation: create, update, archive, or restore one global Feedback Topic without database intervention. This capability does not expose private evidence.",
|
|
18915
|
+
inputSchema: {
|
|
18916
|
+
action: exports_external.enum(["create", "update", "archive", "restore"]),
|
|
18917
|
+
topicId: exports_external.string().optional().describe("update/archive/restore: shared Feedback Topic id"),
|
|
18918
|
+
title: exports_external.string().min(1).optional().describe("create/update: Topic title"),
|
|
18919
|
+
purpose: exports_external.string().optional().describe("create/update: Topic purpose")
|
|
18920
|
+
},
|
|
18921
|
+
surfaces: ["mcp", "cli"],
|
|
18922
|
+
toolset: "admin",
|
|
18923
|
+
run: forward("feedback_admin.topic")
|
|
18924
|
+
},
|
|
18925
|
+
{
|
|
18926
|
+
name: "admin_feedback_thread",
|
|
18927
|
+
title: "Maintain and merge shared Feedback Threads",
|
|
18928
|
+
description: "Privileged shared-forum moderation: create/update/move/transition/archive/restore Threads or merge a duplicate into a canonical destination with redirect and provenance. Merge safely repoints private associations but never copies raw evidence into shared content.",
|
|
18929
|
+
inputSchema: {
|
|
18930
|
+
action: exports_external.enum(["create", "update", "move", "transition", "archive", "restore", "merge"]).describe("the Thread lifecycle or merge action"),
|
|
18931
|
+
threadId: exports_external.string().optional().describe("update/move/transition/archive/restore: Thread id"),
|
|
18932
|
+
sourceThreadId: exports_external.string().optional().describe("merge: duplicate source Thread id"),
|
|
18933
|
+
targetThreadId: exports_external.string().optional().describe("merge: canonical destination Thread id"),
|
|
18934
|
+
topicId: exports_external.string().optional().describe("create/move/update: destination Feedback Topic id"),
|
|
18935
|
+
title: exports_external.string().min(1).optional().describe("create/update: Thread title"),
|
|
18936
|
+
objective: exports_external.string().min(1).optional().describe("create/update: Thread objective"),
|
|
18937
|
+
status: exports_external.enum(["active", "needs-review", "stuck", "standing", "resolved", "archived"]).optional().describe("transition/update: target Thread status"),
|
|
18938
|
+
reason: exports_external.string().optional().describe("merge: concise auditable rationale")
|
|
18939
|
+
},
|
|
18940
|
+
surfaces: ["mcp", "cli"],
|
|
18941
|
+
toolset: "admin",
|
|
18942
|
+
run: forward("feedback_admin.thread")
|
|
18943
|
+
},
|
|
18944
|
+
{
|
|
18945
|
+
name: "admin_feedback_publish",
|
|
18946
|
+
title: "Publish sanitized shared Feedback content",
|
|
18947
|
+
description: "Privileged: author a new sanitized shared contribution in a Feedback Thread, optionally recording that private evidence informed it. The body must be separately authored; Arbor refuses an exact raw-body copy and never flips private visibility.",
|
|
18948
|
+
inputSchema: {
|
|
18949
|
+
threadId: exports_external.string().describe("shared Feedback Thread id or merged source redirect"),
|
|
18950
|
+
type: exports_external.enum(CONTRIBUTION_TYPES).describe("shared contribution type, including maintainer decision"),
|
|
18951
|
+
body: exports_external.string().min(1).describe("deliberately sanitized shared body"),
|
|
18952
|
+
summary: exports_external.string().max(500).optional().describe("optional shared gist"),
|
|
18953
|
+
confidence: exports_external.number().int().min(0).max(100).optional(),
|
|
18954
|
+
idempotencyKey: exports_external.string().min(1).max(200).optional(),
|
|
18955
|
+
feedbackId: exports_external.string().optional().describe("optional private evidence id; additionally requires review_private")
|
|
18956
|
+
},
|
|
18957
|
+
surfaces: ["mcp", "cli"],
|
|
18958
|
+
toolset: "admin",
|
|
18959
|
+
run: forward("feedback_admin.publish")
|
|
18960
|
+
},
|
|
18961
|
+
{
|
|
18962
|
+
name: "admin_feedback_edit",
|
|
18963
|
+
title: "Edit sanitized shared Feedback content",
|
|
18964
|
+
description: "Privileged shared-forum moderation: correct a shared Feedback contribution's body, summary, or type while preserving normal Arbor audit history. This cannot target private feedback records.",
|
|
18965
|
+
inputSchema: {
|
|
18966
|
+
contributionId: exports_external.string().describe("shared Feedback contribution id"),
|
|
18967
|
+
body: exports_external.string().min(1).optional().describe("replacement sanitized body"),
|
|
18968
|
+
summary: exports_external.string().max(500).nullable().optional().describe("replacement gist; null/empty clears"),
|
|
18969
|
+
type: exports_external.enum(CONTRIBUTION_TYPES).optional().describe("replacement shared contribution type")
|
|
18970
|
+
},
|
|
18971
|
+
surfaces: ["mcp", "cli"],
|
|
18972
|
+
toolset: "admin",
|
|
18973
|
+
run: forward("feedback_admin.edit")
|
|
18974
|
+
},
|
|
18975
|
+
{
|
|
18976
|
+
name: "admin_feedback_curate",
|
|
18977
|
+
title: "Curate shared Feedback content",
|
|
18978
|
+
description: "Privileged shared-forum moderation: soft-delete or restore a sanitized shared contribution. This capability remains independent of private-feedback review access.",
|
|
18979
|
+
inputSchema: {
|
|
18980
|
+
verb: exports_external.enum(["delete", "restore"]),
|
|
18981
|
+
contributionId: exports_external.string().describe("shared Feedback contribution id")
|
|
18982
|
+
},
|
|
18983
|
+
surfaces: ["mcp", "cli"],
|
|
18984
|
+
toolset: "admin",
|
|
18985
|
+
run: dispatch({ delete: "feedback_admin.remove", restore: "feedback_admin.restore" })
|
|
18986
|
+
},
|
|
18662
18987
|
{
|
|
18663
18988
|
name: "contribute",
|
|
18664
18989
|
title: "Contribute to a thread",
|
|
@@ -21170,13 +21495,27 @@ function buildInput(inputSchema, flags, command) {
|
|
|
21170
21495
|
}
|
|
21171
21496
|
|
|
21172
21497
|
// src/commands.ts
|
|
21498
|
+
var COMMAND_WORD_OVERRIDES = {
|
|
21499
|
+
contribute_arbor_feedback: "feedback",
|
|
21500
|
+
feedback_recall: "feedback find",
|
|
21501
|
+
feedback_thread_get: "feedback thread"
|
|
21502
|
+
};
|
|
21173
21503
|
function commandWords(action) {
|
|
21174
|
-
return action.name.replace(/_/g, " ");
|
|
21504
|
+
return COMMAND_WORD_OVERRIDES[action.name] ?? action.name.replace(/_/g, " ");
|
|
21175
21505
|
}
|
|
21176
21506
|
var CLI_ACTIONS = ACTIONS.filter((a) => a.surfaces.includes("cli") || a.surfaces.includes("computer-cli"));
|
|
21177
21507
|
var BY_COMMAND = new Map(CLI_ACTIONS.map((a) => [commandWords(a), a]));
|
|
21178
21508
|
var MAX_WORDS = Math.max(1, ...CLI_ACTIONS.map((a) => commandWords(a).split(" ").length));
|
|
21179
21509
|
var POSITIONAL_FIELDS = {
|
|
21510
|
+
contribute_arbor_feedback: ["body"],
|
|
21511
|
+
feedback_recall: ["query"],
|
|
21512
|
+
feedback_thread_get: ["threadId"],
|
|
21513
|
+
admin_feedback_capability: ["verb"],
|
|
21514
|
+
admin_feedback_evidence: ["verb"],
|
|
21515
|
+
admin_feedback_topic: ["action"],
|
|
21516
|
+
admin_feedback_thread: ["action"],
|
|
21517
|
+
admin_feedback_edit: ["contributionId"],
|
|
21518
|
+
admin_feedback_curate: ["verb", "contributionId"],
|
|
21180
21519
|
app_fetch: ["appId", "path"],
|
|
21181
21520
|
app_request: ["appId", "path"],
|
|
21182
21521
|
computer_run_start: ["computerSessionId", "mode"],
|
|
@@ -21344,8 +21683,26 @@ function applyPositionals(action, extras, flags) {
|
|
|
21344
21683
|
flags[target.flag] = value;
|
|
21345
21684
|
}
|
|
21346
21685
|
}
|
|
21686
|
+
function resolveCommand(positionals, flags) {
|
|
21687
|
+
const normalized = positionals.map((word) => word.replace(/_/g, " "));
|
|
21688
|
+
const feedbackInputFlags = new Set([
|
|
21689
|
+
"type",
|
|
21690
|
+
"body",
|
|
21691
|
+
"body-file",
|
|
21692
|
+
"summary",
|
|
21693
|
+
"summary-file",
|
|
21694
|
+
"confidence",
|
|
21695
|
+
"idempotency-key",
|
|
21696
|
+
"thread-id",
|
|
21697
|
+
"topic-id",
|
|
21698
|
+
"computer-session-id"
|
|
21699
|
+
]);
|
|
21700
|
+
const explicitFeedbackInput = Object.keys(flags).some((flag) => feedbackInputFlags.has(flag));
|
|
21701
|
+
const bareFeedbackTree = normalized.length === 1 && normalized[0] === "feedback" && !explicitFeedbackInput;
|
|
21702
|
+
return bareFeedbackTree ? { action: CLI_ACTIONS.find((action) => action.name === "feedback_tree"), words: 1 } : matchCommand(positionals);
|
|
21703
|
+
}
|
|
21347
21704
|
async function runObjectVerb(positionals, flags, ctx) {
|
|
21348
|
-
const match =
|
|
21705
|
+
const match = resolveCommand(positionals, flags);
|
|
21349
21706
|
if (!match) {
|
|
21350
21707
|
const typed = positionals.join(" ") || "(none)";
|
|
21351
21708
|
throw new UsageError(`unknown command: ${typed} — ${suggestCommand(positionals)}`);
|
package/package.json
CHANGED