@productbrain/mcp 0.0.1-beta.47 → 0.0.1-beta.49
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/{chunk-FYFF4QKF.js → chunk-ED3KCWZE.js} +455 -72
- package/dist/chunk-ED3KCWZE.js.map +1 -0
- package/dist/{chunk-FMEZXUP5.js → chunk-IGQLZI32.js} +2232 -1941
- package/dist/chunk-IGQLZI32.js.map +1 -0
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{smart-capture-XLBFE252.js → smart-capture-2IM2565I.js} +8 -2
- package/dist/views/src/entry-cards/index.html +227 -0
- package/dist/views/src/graph-constellation/index.html +254 -0
- package/package.json +3 -2
- package/dist/chunk-FMEZXUP5.js.map +0 -1
- package/dist/chunk-FYFF4QKF.js.map +0 -1
- /package/dist/{smart-capture-XLBFE252.js.map → smart-capture-2IM2565I.js.map} +0 -0
|
@@ -159,22 +159,27 @@ async function startAgentSession() {
|
|
|
159
159
|
workspaceId,
|
|
160
160
|
apiKeyId: s.apiKeyId
|
|
161
161
|
});
|
|
162
|
+
if (s.agentSessionId) {
|
|
163
|
+
resetTouchThrottle(s.agentSessionId);
|
|
164
|
+
}
|
|
162
165
|
s.agentSessionId = result.sessionId;
|
|
163
166
|
s.apiKeyScope = result.toolsScope;
|
|
164
167
|
s.sessionOriented = false;
|
|
165
168
|
s.sessionClosed = false;
|
|
166
|
-
resetTouchThrottle();
|
|
169
|
+
resetTouchThrottle(result.sessionId);
|
|
167
170
|
return result;
|
|
168
171
|
}
|
|
169
172
|
async function closeAgentSession() {
|
|
170
173
|
const s = state();
|
|
171
174
|
if (!s.agentSessionId) return;
|
|
175
|
+
const sessionId = s.agentSessionId;
|
|
172
176
|
try {
|
|
173
177
|
await mcpCall("agent.closeSession", {
|
|
174
|
-
sessionId
|
|
178
|
+
sessionId,
|
|
175
179
|
status: "closed"
|
|
176
180
|
});
|
|
177
181
|
} finally {
|
|
182
|
+
resetTouchThrottle(sessionId);
|
|
178
183
|
s.sessionClosed = true;
|
|
179
184
|
s.agentSessionId = null;
|
|
180
185
|
s.sessionOriented = false;
|
|
@@ -183,32 +188,40 @@ async function closeAgentSession() {
|
|
|
183
188
|
async function orphanAgentSession() {
|
|
184
189
|
const s = state();
|
|
185
190
|
if (!s.agentSessionId) return;
|
|
191
|
+
const sessionId = s.agentSessionId;
|
|
186
192
|
try {
|
|
187
193
|
await mcpCall("agent.closeSession", {
|
|
188
|
-
sessionId
|
|
194
|
+
sessionId,
|
|
189
195
|
status: "orphaned"
|
|
190
196
|
});
|
|
191
197
|
} catch {
|
|
192
198
|
} finally {
|
|
199
|
+
resetTouchThrottle(sessionId);
|
|
193
200
|
s.agentSessionId = null;
|
|
194
201
|
s.sessionOriented = false;
|
|
195
202
|
}
|
|
196
203
|
}
|
|
197
|
-
var
|
|
204
|
+
var _lastTouchAtBySession = /* @__PURE__ */ new Map();
|
|
198
205
|
var TOUCH_THROTTLE_MS = 5e3;
|
|
199
206
|
function touchSessionActivity() {
|
|
200
207
|
const s = state();
|
|
201
|
-
|
|
208
|
+
const sessionId = s.agentSessionId;
|
|
209
|
+
if (!sessionId) return;
|
|
202
210
|
const now = Date.now();
|
|
203
|
-
|
|
204
|
-
|
|
211
|
+
const lastTouchAt = _lastTouchAtBySession.get(sessionId) ?? 0;
|
|
212
|
+
if (now - lastTouchAt < TOUCH_THROTTLE_MS) return;
|
|
213
|
+
_lastTouchAtBySession.set(sessionId, now);
|
|
205
214
|
mcpCall("agent.touchSession", {
|
|
206
|
-
sessionId
|
|
215
|
+
sessionId
|
|
207
216
|
}).catch(() => {
|
|
208
217
|
});
|
|
209
218
|
}
|
|
210
|
-
function resetTouchThrottle() {
|
|
211
|
-
|
|
219
|
+
function resetTouchThrottle(sessionId) {
|
|
220
|
+
if (sessionId) {
|
|
221
|
+
_lastTouchAtBySession.delete(sessionId);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
_lastTouchAtBySession.clear();
|
|
212
225
|
}
|
|
213
226
|
async function recordSessionActivity(activity) {
|
|
214
227
|
const s = state();
|
|
@@ -302,7 +315,14 @@ async function mcpCall(fn, args = {}) {
|
|
|
302
315
|
setCached(fn, args, data);
|
|
303
316
|
}
|
|
304
317
|
const s = state();
|
|
305
|
-
const TOUCH_EXCLUDED = /* @__PURE__ */ new Set([
|
|
318
|
+
const TOUCH_EXCLUDED = /* @__PURE__ */ new Set([
|
|
319
|
+
"agent.touchSession",
|
|
320
|
+
"agent.startSession",
|
|
321
|
+
"agent.markOriented",
|
|
322
|
+
"agent.recordActivity",
|
|
323
|
+
"agent.recordWrapup",
|
|
324
|
+
"agent.closeSession"
|
|
325
|
+
]);
|
|
306
326
|
if (s.agentSessionId && !TOUCH_EXCLUDED.has(fn)) {
|
|
307
327
|
touchSessionActivity();
|
|
308
328
|
}
|
|
@@ -428,6 +448,58 @@ async function recoverSessionState() {
|
|
|
428
448
|
}
|
|
429
449
|
|
|
430
450
|
// src/tools/knowledge-helpers.ts
|
|
451
|
+
var EPISTEMIC_COLLECTIONS = /* @__PURE__ */ new Set(["insights", "assumptions"]);
|
|
452
|
+
function deriveEpistemicStatus(entry) {
|
|
453
|
+
const coll = entry.collectionName?.toLowerCase();
|
|
454
|
+
if (!coll || !EPISTEMIC_COLLECTIONS.has(coll)) return null;
|
|
455
|
+
const relations = entry.relations ?? [];
|
|
456
|
+
const hasValidates = relations.some(
|
|
457
|
+
(r) => r.type === "validates" && r.direction === "incoming"
|
|
458
|
+
);
|
|
459
|
+
const hasInvalidates = relations.some(
|
|
460
|
+
(r) => r.type === "invalidates" && r.direction === "incoming"
|
|
461
|
+
);
|
|
462
|
+
const evidenceCount = relations.filter(
|
|
463
|
+
(r) => (r.type === "validates" || r.type === "invalidates") && r.direction === "incoming"
|
|
464
|
+
).length;
|
|
465
|
+
if (coll === "assumptions") {
|
|
466
|
+
const ws2 = entry.workflowStatus;
|
|
467
|
+
if (ws2 === "invalidated" || hasInvalidates) {
|
|
468
|
+
return { level: "invalidated", reason: "Disproved by linked counter-evidence" };
|
|
469
|
+
}
|
|
470
|
+
if (ws2 === "validated" || hasValidates && ws2 !== "untested") {
|
|
471
|
+
return { level: "validated", reason: `${evidenceCount} evidence link${evidenceCount !== 1 ? "s" : ""}` };
|
|
472
|
+
}
|
|
473
|
+
if (ws2 === "testing") {
|
|
474
|
+
return { level: "testing", reason: "Experiment in progress" };
|
|
475
|
+
}
|
|
476
|
+
return { level: "untested", reason: "No evidence linked", action: 'Link evidence via `relations action=create type="validates"`' };
|
|
477
|
+
}
|
|
478
|
+
const ws = entry.workflowStatus;
|
|
479
|
+
if (ws === "validated" && hasValidates) {
|
|
480
|
+
return { level: "validated", reason: `${evidenceCount} evidence link${evidenceCount !== 1 ? "s" : ""}` };
|
|
481
|
+
}
|
|
482
|
+
if (ws === "evidenced" || hasValidates) {
|
|
483
|
+
return { level: "evidenced", reason: `${evidenceCount} evidence link${evidenceCount !== 1 ? "s" : ""}` };
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
level: "hypothesis",
|
|
487
|
+
reason: "No linked evidence",
|
|
488
|
+
action: 'Link proof via `relations action=create type="validates"`'
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function formatEpistemicLine(es) {
|
|
492
|
+
const icon = es.level === "validated" ? "\u2713" : es.level === "evidenced" ? "\u25CE" : es.level === "hypothesis" ? "\u25B3" : es.level === "untested" ? "?" : es.level === "testing" ? "\u25CE" : "\u2715";
|
|
493
|
+
const suffix = es.action ? ` ${es.action}` : "";
|
|
494
|
+
return `**Confidence:** ${icon} ${es.level} \u2014 ${es.reason}.${suffix}`;
|
|
495
|
+
}
|
|
496
|
+
function toEpistemicInput(entry) {
|
|
497
|
+
return {
|
|
498
|
+
collectionName: typeof entry.collectionName === "string" ? entry.collectionName : void 0,
|
|
499
|
+
workflowStatus: typeof entry.workflowStatus === "string" ? entry.workflowStatus : void 0,
|
|
500
|
+
relations: Array.isArray(entry.relations) ? entry.relations.map((r) => ({ type: r.type, direction: r.direction })) : void 0
|
|
501
|
+
};
|
|
502
|
+
}
|
|
431
503
|
function extractPreview(data, maxLen) {
|
|
432
504
|
if (!data || typeof data !== "object") return "";
|
|
433
505
|
const d = data;
|
|
@@ -546,11 +618,27 @@ async function isFeatureEnabled(flag, workspaceId, workspaceSlug) {
|
|
|
546
618
|
// src/tools/smart-capture-routing.ts
|
|
547
619
|
var CLASSIFIER_AUTO_ROUTE_THRESHOLD = 70;
|
|
548
620
|
var CLASSIFIER_AMBIGUITY_MARGIN = 15;
|
|
549
|
-
var
|
|
621
|
+
var CLASSIFIABLE_COLLECTIONS = [
|
|
622
|
+
"decisions",
|
|
623
|
+
"tensions",
|
|
624
|
+
"glossary",
|
|
625
|
+
"insights",
|
|
626
|
+
"bets",
|
|
627
|
+
"features",
|
|
628
|
+
"architecture",
|
|
629
|
+
"business-rules",
|
|
630
|
+
"tracking-events",
|
|
631
|
+
"landscape",
|
|
632
|
+
"standards",
|
|
633
|
+
"principles",
|
|
634
|
+
"assumptions"
|
|
635
|
+
];
|
|
636
|
+
var STARTER_COLLECTIONS = CLASSIFIABLE_COLLECTIONS;
|
|
550
637
|
var SIGNAL_WEIGHT = 10;
|
|
638
|
+
var MIN_SCORE_FLOOR = 10;
|
|
551
639
|
var MAX_MATCHES_PER_SIGNAL = 2;
|
|
552
640
|
var MAX_REASON_COUNT = 3;
|
|
553
|
-
var
|
|
641
|
+
var COLLECTION_SIGNALS = {
|
|
554
642
|
decisions: [
|
|
555
643
|
"decide",
|
|
556
644
|
"decision",
|
|
@@ -560,7 +648,15 @@ var STARTER_COLLECTION_SIGNALS = {
|
|
|
560
648
|
"resolved",
|
|
561
649
|
"we will",
|
|
562
650
|
"we should",
|
|
563
|
-
"approved"
|
|
651
|
+
"approved",
|
|
652
|
+
"replaces",
|
|
653
|
+
"instead of",
|
|
654
|
+
"go with",
|
|
655
|
+
"criteria",
|
|
656
|
+
"adopted",
|
|
657
|
+
"reposition",
|
|
658
|
+
"scoring framework",
|
|
659
|
+
"review"
|
|
564
660
|
],
|
|
565
661
|
tensions: [
|
|
566
662
|
"problem",
|
|
@@ -569,10 +665,20 @@ var STARTER_COLLECTION_SIGNALS = {
|
|
|
569
665
|
"blocker",
|
|
570
666
|
"friction",
|
|
571
667
|
"pain",
|
|
572
|
-
"risk",
|
|
573
|
-
"constraint",
|
|
574
668
|
"bottleneck",
|
|
575
|
-
"struggle"
|
|
669
|
+
"struggle",
|
|
670
|
+
"missing",
|
|
671
|
+
"breaks",
|
|
672
|
+
"regression",
|
|
673
|
+
"unclear",
|
|
674
|
+
"no way to",
|
|
675
|
+
"scope creep",
|
|
676
|
+
"coupled",
|
|
677
|
+
"trapped",
|
|
678
|
+
"ambiguous",
|
|
679
|
+
"no batch",
|
|
680
|
+
"undetectable",
|
|
681
|
+
"coordination gap"
|
|
576
682
|
],
|
|
577
683
|
glossary: [
|
|
578
684
|
"definition",
|
|
@@ -582,28 +688,151 @@ var STARTER_COLLECTION_SIGNALS = {
|
|
|
582
688
|
"refers to",
|
|
583
689
|
"is called",
|
|
584
690
|
"vocabulary",
|
|
585
|
-
"terminology"
|
|
691
|
+
"terminology",
|
|
692
|
+
"a governance mechanism",
|
|
693
|
+
"a workspace",
|
|
694
|
+
"a tracked",
|
|
695
|
+
"the atom",
|
|
696
|
+
"the action of",
|
|
697
|
+
"the versioned",
|
|
698
|
+
"a field on",
|
|
699
|
+
"one of the",
|
|
700
|
+
"a constraint on",
|
|
701
|
+
"a hard data",
|
|
702
|
+
"a single"
|
|
586
703
|
],
|
|
587
704
|
insights: [
|
|
588
705
|
"insight",
|
|
589
706
|
"learned",
|
|
590
707
|
"observed",
|
|
591
|
-
"pattern",
|
|
592
708
|
"trend",
|
|
593
|
-
"signal",
|
|
594
709
|
"found that",
|
|
595
|
-
"
|
|
710
|
+
"discovery",
|
|
711
|
+
"validates",
|
|
712
|
+
"saturates",
|
|
713
|
+
"convergence",
|
|
714
|
+
"signals from",
|
|
715
|
+
"converge",
|
|
716
|
+
"TAM"
|
|
596
717
|
],
|
|
597
718
|
bets: [
|
|
598
|
-
"bet",
|
|
599
719
|
"appetite",
|
|
600
|
-
"scope",
|
|
601
|
-
"elements",
|
|
602
720
|
"rabbit hole",
|
|
603
721
|
"no-go",
|
|
604
|
-
"shape",
|
|
605
|
-
"
|
|
606
|
-
"
|
|
722
|
+
"shape up",
|
|
723
|
+
"done when",
|
|
724
|
+
"shaping session",
|
|
725
|
+
"from static",
|
|
726
|
+
"from storage",
|
|
727
|
+
"from passive",
|
|
728
|
+
"the chain learns",
|
|
729
|
+
"stage-aware",
|
|
730
|
+
"commit friction",
|
|
731
|
+
"interactive knowledge",
|
|
732
|
+
"capture without",
|
|
733
|
+
"front door",
|
|
734
|
+
"response envelope",
|
|
735
|
+
"knowledge organisation",
|
|
736
|
+
"graveyard",
|
|
737
|
+
"remote MCP",
|
|
738
|
+
"coaching service"
|
|
739
|
+
],
|
|
740
|
+
features: [
|
|
741
|
+
"feature",
|
|
742
|
+
"capability",
|
|
743
|
+
"user can",
|
|
744
|
+
"navigation",
|
|
745
|
+
"palette",
|
|
746
|
+
"modal",
|
|
747
|
+
"smart capture",
|
|
748
|
+
"suggest-links",
|
|
749
|
+
"command palette",
|
|
750
|
+
"auto-commit",
|
|
751
|
+
"collection-optional",
|
|
752
|
+
"organisation intelligence",
|
|
753
|
+
"consolidation"
|
|
754
|
+
],
|
|
755
|
+
architecture: [
|
|
756
|
+
"architecture",
|
|
757
|
+
"layer",
|
|
758
|
+
"data model",
|
|
759
|
+
"infrastructure",
|
|
760
|
+
"system design",
|
|
761
|
+
"L1",
|
|
762
|
+
"L2",
|
|
763
|
+
"L3",
|
|
764
|
+
"L4",
|
|
765
|
+
"L5",
|
|
766
|
+
"L6",
|
|
767
|
+
"L7",
|
|
768
|
+
"guard infrastructure",
|
|
769
|
+
"data layer",
|
|
770
|
+
"intelligence layer",
|
|
771
|
+
"MCP layer",
|
|
772
|
+
"core layer"
|
|
773
|
+
],
|
|
774
|
+
"business-rules": [
|
|
775
|
+
"guard",
|
|
776
|
+
"enforce",
|
|
777
|
+
"integrity",
|
|
778
|
+
"prevents",
|
|
779
|
+
"excludes",
|
|
780
|
+
"permitted",
|
|
781
|
+
"policy",
|
|
782
|
+
"feature gate",
|
|
783
|
+
"must not",
|
|
784
|
+
"only permitted",
|
|
785
|
+
"closed enum",
|
|
786
|
+
"write guard",
|
|
787
|
+
"never imports",
|
|
788
|
+
"requires active session",
|
|
789
|
+
"readiness excludes"
|
|
790
|
+
],
|
|
791
|
+
"tracking-events": [
|
|
792
|
+
"track",
|
|
793
|
+
"tracking",
|
|
794
|
+
"analytics",
|
|
795
|
+
"trigger",
|
|
796
|
+
"posthog",
|
|
797
|
+
"instrument",
|
|
798
|
+
"fires when"
|
|
799
|
+
],
|
|
800
|
+
landscape: [
|
|
801
|
+
"competitor",
|
|
802
|
+
"alternative tool",
|
|
803
|
+
"alternative platform",
|
|
804
|
+
"competing product",
|
|
805
|
+
"landscape",
|
|
806
|
+
"comparison"
|
|
807
|
+
],
|
|
808
|
+
standards: [
|
|
809
|
+
"standard",
|
|
810
|
+
"convention",
|
|
811
|
+
"trunk-based",
|
|
812
|
+
"alignment-first",
|
|
813
|
+
"structured bet",
|
|
814
|
+
"system fixes",
|
|
815
|
+
"patches"
|
|
816
|
+
],
|
|
817
|
+
principles: [
|
|
818
|
+
"we believe",
|
|
819
|
+
"principle",
|
|
820
|
+
"compounds",
|
|
821
|
+
"philosophy",
|
|
822
|
+
"simplicity compounds",
|
|
823
|
+
"trust through",
|
|
824
|
+
"evidence over",
|
|
825
|
+
"compensate for",
|
|
826
|
+
"honest by default"
|
|
827
|
+
],
|
|
828
|
+
assumptions: [
|
|
829
|
+
"assume",
|
|
830
|
+
"assumption",
|
|
831
|
+
"hypothesis",
|
|
832
|
+
"untested",
|
|
833
|
+
"we think",
|
|
834
|
+
"we assume",
|
|
835
|
+
"needs validation"
|
|
607
836
|
]
|
|
608
837
|
};
|
|
609
838
|
function escapeRegExp(text) {
|
|
@@ -618,11 +847,12 @@ function countSignalMatches(text, signal) {
|
|
|
618
847
|
const matches = text.match(regex);
|
|
619
848
|
return matches?.length ?? 0;
|
|
620
849
|
}
|
|
621
|
-
|
|
622
|
-
|
|
850
|
+
var ENTRY_ID_PATTERN = /\b[A-Z]{2,}-\d+\b/g;
|
|
851
|
+
function classifyCollection(name, description) {
|
|
852
|
+
const text = `${name} ${description}`.replace(ENTRY_ID_PATTERN, "").toLowerCase();
|
|
623
853
|
const rawScores = [];
|
|
624
|
-
for (const collection of
|
|
625
|
-
const signals =
|
|
854
|
+
for (const collection of CLASSIFIABLE_COLLECTIONS) {
|
|
855
|
+
const signals = COLLECTION_SIGNALS[collection];
|
|
626
856
|
const reasons = [];
|
|
627
857
|
let score = 0;
|
|
628
858
|
for (const signal of signals) {
|
|
@@ -640,8 +870,9 @@ function classifyStarterCollection(name, description) {
|
|
|
640
870
|
rawScores.sort((a, b) => b.score - a.score);
|
|
641
871
|
const top = rawScores[0];
|
|
642
872
|
const second = rawScores[1];
|
|
643
|
-
if (!top || top.score
|
|
873
|
+
if (!top || top.score < MIN_SCORE_FLOOR) return null;
|
|
644
874
|
const margin = Math.max(0, top.score - (second?.score ?? 0));
|
|
875
|
+
if (margin === 0 && top.score <= MIN_SCORE_FLOOR) return null;
|
|
645
876
|
const baseConfidence = Math.min(90, top.score);
|
|
646
877
|
const confidence = Math.min(99, baseConfidence + Math.min(20, margin));
|
|
647
878
|
return {
|
|
@@ -665,6 +896,7 @@ function shouldAutoRouteClassification(result) {
|
|
|
665
896
|
function isClassificationAmbiguous(result) {
|
|
666
897
|
return result.scoreMargin < CLASSIFIER_AMBIGUITY_MARGIN;
|
|
667
898
|
}
|
|
899
|
+
var classifyStarterCollection = classifyCollection;
|
|
668
900
|
|
|
669
901
|
// src/envelope.ts
|
|
670
902
|
import { z } from "zod";
|
|
@@ -935,6 +1167,33 @@ var COMMON_CHECKS = {
|
|
|
935
1167
|
suggestion: () => "Classify this entry with a canonical type for better context assembly. Use update-entry to set canonicalKey."
|
|
936
1168
|
}
|
|
937
1169
|
};
|
|
1170
|
+
var STRATEGY_CATEGORY_INFERENCE_THRESHOLD = 2;
|
|
1171
|
+
var STRATEGY_CATEGORY_SIGNALS = [
|
|
1172
|
+
["business-model", [/pricing/, /revenue/, /unit economics/, /cost structure/, /monetiz/, /margin/, /per.?seat/, /subscription/, /freemium/]],
|
|
1173
|
+
["vision", [/vision/, /aspirational/, /future state/, /world where/]],
|
|
1174
|
+
["purpose", [/purpose/, /why we exist/, /mission/, /reason for being/]],
|
|
1175
|
+
["goal", [/goal/, /metric/, /target/, /kpi/, /okr/, /critical number/, /measur/]],
|
|
1176
|
+
["principle", [/we believe/, /guiding principle/, /core belief/, /philosophy/]],
|
|
1177
|
+
["product-area", [/product area/, /module/, /surface/, /capability area/]],
|
|
1178
|
+
["audience", [/audience/, /persona/, /user segment/, /icp/, /target market/]],
|
|
1179
|
+
["insight", [/insight/, /we learned/, /we observed/, /pattern/]],
|
|
1180
|
+
["opportunity", [/opportunity/, /whitespace/, /gap/, /underserved/]]
|
|
1181
|
+
];
|
|
1182
|
+
function inferStrategyCategory(name, description) {
|
|
1183
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
1184
|
+
let bestCategory = null;
|
|
1185
|
+
let bestScore = 0;
|
|
1186
|
+
for (const [cat, signals] of STRATEGY_CATEGORY_SIGNALS) {
|
|
1187
|
+
const score = signals.reduce((s, rx) => s + (rx.test(text) ? 1 : 0), 0);
|
|
1188
|
+
if (score > bestScore) {
|
|
1189
|
+
bestScore = score;
|
|
1190
|
+
bestCategory = cat;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (bestCategory && bestScore >= STRATEGY_CATEGORY_INFERENCE_THRESHOLD) return bestCategory;
|
|
1194
|
+
if (bestScore === 0) return "strategy";
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
938
1197
|
var PROFILES = /* @__PURE__ */ new Map([
|
|
939
1198
|
["tensions", {
|
|
940
1199
|
governedDraft: false,
|
|
@@ -1150,6 +1409,11 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
1150
1409
|
descriptionField: "description",
|
|
1151
1410
|
defaults: [],
|
|
1152
1411
|
recommendedRelationTypes: ["informs", "governs", "belongs_to", "related_to"],
|
|
1412
|
+
inferField: (ctx) => {
|
|
1413
|
+
if (ctx.data?.category) return {};
|
|
1414
|
+
const category = inferStrategyCategory(ctx.name, ctx.description);
|
|
1415
|
+
return category ? { category } : {};
|
|
1416
|
+
},
|
|
1153
1417
|
qualityChecks: [
|
|
1154
1418
|
COMMON_CHECKS.clearName,
|
|
1155
1419
|
COMMON_CHECKS.hasDescription,
|
|
@@ -1302,6 +1566,36 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
1302
1566
|
suggestion: () => "Describe how this assumption could be tested or validated."
|
|
1303
1567
|
}
|
|
1304
1568
|
]
|
|
1569
|
+
}],
|
|
1570
|
+
["architecture", {
|
|
1571
|
+
governedDraft: true,
|
|
1572
|
+
descriptionField: "description",
|
|
1573
|
+
defaults: [],
|
|
1574
|
+
recommendedRelationTypes: ["belongs_to", "depends_on", "governs", "references", "related_to"],
|
|
1575
|
+
qualityChecks: [
|
|
1576
|
+
COMMON_CHECKS.clearName,
|
|
1577
|
+
COMMON_CHECKS.hasDescription,
|
|
1578
|
+
COMMON_CHECKS.hasRelations,
|
|
1579
|
+
COMMON_CHECKS.hasType,
|
|
1580
|
+
{
|
|
1581
|
+
id: "has-layer",
|
|
1582
|
+
label: "Architecture layer identified",
|
|
1583
|
+
check: (ctx) => !!ctx.data?.layer && String(ctx.data.layer).length > 0,
|
|
1584
|
+
suggestion: () => "Specify which architecture layer this belongs to (L1-L7)."
|
|
1585
|
+
}
|
|
1586
|
+
]
|
|
1587
|
+
}],
|
|
1588
|
+
["landscape", {
|
|
1589
|
+
governedDraft: false,
|
|
1590
|
+
descriptionField: "description",
|
|
1591
|
+
defaults: [],
|
|
1592
|
+
recommendedRelationTypes: ["references", "related_to", "fills_slot"],
|
|
1593
|
+
qualityChecks: [
|
|
1594
|
+
COMMON_CHECKS.clearName,
|
|
1595
|
+
COMMON_CHECKS.hasDescription,
|
|
1596
|
+
COMMON_CHECKS.hasRelations,
|
|
1597
|
+
COMMON_CHECKS.hasType
|
|
1598
|
+
]
|
|
1305
1599
|
}]
|
|
1306
1600
|
]);
|
|
1307
1601
|
var FALLBACK_PROFILE = {
|
|
@@ -1466,7 +1760,8 @@ var GOVERNED_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
|
1466
1760
|
"principles",
|
|
1467
1761
|
"standards",
|
|
1468
1762
|
"strategy",
|
|
1469
|
-
"features"
|
|
1763
|
+
"features",
|
|
1764
|
+
"architecture"
|
|
1470
1765
|
]);
|
|
1471
1766
|
var AUTO_LINK_CONFIDENCE_THRESHOLD = 35;
|
|
1472
1767
|
var MAX_AUTO_LINKS = 5;
|
|
@@ -1497,18 +1792,20 @@ var batchCaptureSchema = z2.object({
|
|
|
1497
1792
|
var captureClassifierSchema = z2.object({
|
|
1498
1793
|
enabled: z2.boolean(),
|
|
1499
1794
|
autoRouted: z2.boolean(),
|
|
1795
|
+
agrees: z2.boolean(),
|
|
1796
|
+
abstained: z2.boolean(),
|
|
1500
1797
|
topConfidence: z2.number(),
|
|
1501
|
-
// Backward-compatible alias for topConfidence.
|
|
1502
1798
|
confidence: z2.number(),
|
|
1503
1799
|
reasons: z2.array(z2.string()),
|
|
1504
1800
|
candidates: z2.array(
|
|
1505
1801
|
z2.object({
|
|
1506
|
-
collection: z2.enum(
|
|
1802
|
+
collection: z2.enum(CLASSIFIABLE_COLLECTIONS),
|
|
1507
1803
|
signalScore: z2.number(),
|
|
1508
|
-
// Backward-compatible alias for signalScore.
|
|
1509
1804
|
confidence: z2.number()
|
|
1510
1805
|
})
|
|
1511
|
-
)
|
|
1806
|
+
),
|
|
1807
|
+
agentProvidedCollection: z2.string().optional(),
|
|
1808
|
+
overrideCommand: z2.string().optional()
|
|
1512
1809
|
});
|
|
1513
1810
|
function trackClassifierTelemetry(params) {
|
|
1514
1811
|
const telemetry = {
|
|
@@ -1550,12 +1847,12 @@ function buildClassifierUnknownResult() {
|
|
|
1550
1847
|
"Could not infer collection from input.",
|
|
1551
1848
|
"Provide collection explicitly, or rewrite with clearer intent.",
|
|
1552
1849
|
[{ tool: "collections", description: "List available collections", parameters: { action: "list" } }],
|
|
1553
|
-
{ classifier: { enabled: true, autoRouted: false, topConfidence: 0, confidence: 0, candidates: [] } }
|
|
1850
|
+
{ classifier: { enabled: true, autoRouted: false, agrees: false, abstained: true, topConfidence: 0, confidence: 0, reasons: [], candidates: [] } }
|
|
1554
1851
|
)
|
|
1555
1852
|
};
|
|
1556
1853
|
}
|
|
1557
1854
|
function buildProvisionedCollectionSuggestions(candidates) {
|
|
1558
|
-
return candidates.length ? candidates.map((c) => `- \`${c.collection}\` (${c.signalScore}% signal score)`).join("\n") : "- No provisioned
|
|
1855
|
+
return candidates.length ? candidates.map((c) => `- \`${c.collection}\` (${c.signalScore}% signal score)`).join("\n") : "- No provisioned collection candidates were inferred confidently.";
|
|
1559
1856
|
}
|
|
1560
1857
|
function buildUnsupportedProvisioningResult(classified, provisionedCandidates) {
|
|
1561
1858
|
const suggestions = buildProvisionedCollectionSuggestions(provisionedCandidates);
|
|
@@ -1579,6 +1876,8 @@ Correction path: rerun with explicit \`collection\`.`;
|
|
|
1579
1876
|
classifier: {
|
|
1580
1877
|
enabled: true,
|
|
1581
1878
|
autoRouted: false,
|
|
1879
|
+
agrees: false,
|
|
1880
|
+
abstained: false,
|
|
1582
1881
|
topConfidence: classified.topConfidence,
|
|
1583
1882
|
confidence: classified.confidence,
|
|
1584
1883
|
reasons: classified.reasons,
|
|
@@ -1612,17 +1911,17 @@ Correction path: if this was close, rerun with your chosen \`collection\`.`;
|
|
|
1612
1911
|
)
|
|
1613
1912
|
};
|
|
1614
1913
|
}
|
|
1615
|
-
async function
|
|
1914
|
+
async function getProvisionedCollectionCandidates(classified, supportedCollections) {
|
|
1616
1915
|
const allCollections = await mcpQuery("chain.listCollections");
|
|
1617
|
-
const
|
|
1916
|
+
const provisionedCollections = new Set(
|
|
1618
1917
|
(allCollections ?? []).map((collection) => collection.slug).filter(
|
|
1619
|
-
(slug) =>
|
|
1918
|
+
(slug) => supportedCollections.has(slug)
|
|
1620
1919
|
)
|
|
1621
1920
|
);
|
|
1622
1921
|
const provisionedCandidates = classified.candidates.filter(
|
|
1623
|
-
(candidate) =>
|
|
1922
|
+
(candidate) => provisionedCollections.has(candidate.collection)
|
|
1624
1923
|
);
|
|
1625
|
-
return {
|
|
1924
|
+
return { provisionedCollections, provisionedCandidates };
|
|
1626
1925
|
}
|
|
1627
1926
|
async function resolveCaptureCollection(params) {
|
|
1628
1927
|
const {
|
|
@@ -1630,17 +1929,60 @@ async function resolveCaptureCollection(params) {
|
|
|
1630
1929
|
name,
|
|
1631
1930
|
description,
|
|
1632
1931
|
classifierFlagOn,
|
|
1633
|
-
|
|
1932
|
+
supportedCollections,
|
|
1634
1933
|
workspaceId,
|
|
1635
1934
|
explicitCollectionProvided
|
|
1636
1935
|
} = params;
|
|
1637
1936
|
if (collection) {
|
|
1638
|
-
|
|
1937
|
+
const classified2 = classifyCollection(name, description);
|
|
1938
|
+
if (classified2) {
|
|
1939
|
+
const agrees = classified2.collection === collection;
|
|
1940
|
+
const classifierMeta2 = {
|
|
1941
|
+
enabled: true,
|
|
1942
|
+
autoRouted: false,
|
|
1943
|
+
agrees,
|
|
1944
|
+
abstained: false,
|
|
1945
|
+
topConfidence: classified2.topConfidence,
|
|
1946
|
+
confidence: classified2.confidence,
|
|
1947
|
+
reasons: classified2.reasons,
|
|
1948
|
+
candidates: classified2.candidates.slice(0, 3),
|
|
1949
|
+
agentProvidedCollection: collection,
|
|
1950
|
+
...!agrees && {
|
|
1951
|
+
overrideCommand: `capture collection="${classified2.collection}"`
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1954
|
+
if (!agrees) {
|
|
1955
|
+
trackClassifierTelemetry({
|
|
1956
|
+
workspaceId,
|
|
1957
|
+
predictedCollection: classified2.collection,
|
|
1958
|
+
confidence: classified2.confidence,
|
|
1959
|
+
autoRouted: false,
|
|
1960
|
+
reasonCategory: "low-confidence",
|
|
1961
|
+
explicitCollectionProvided: true,
|
|
1962
|
+
outcome: "fallback"
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
return { resolvedCollection: collection, classifierMeta: classifierMeta2 };
|
|
1966
|
+
}
|
|
1967
|
+
return {
|
|
1968
|
+
resolvedCollection: collection,
|
|
1969
|
+
classifierMeta: {
|
|
1970
|
+
enabled: true,
|
|
1971
|
+
autoRouted: false,
|
|
1972
|
+
agrees: false,
|
|
1973
|
+
abstained: true,
|
|
1974
|
+
topConfidence: 0,
|
|
1975
|
+
confidence: 0,
|
|
1976
|
+
reasons: [],
|
|
1977
|
+
candidates: [],
|
|
1978
|
+
agentProvidedCollection: collection
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1639
1981
|
}
|
|
1640
1982
|
if (!classifierFlagOn) {
|
|
1641
1983
|
return { earlyResult: buildCollectionRequiredResult() };
|
|
1642
1984
|
}
|
|
1643
|
-
const classified =
|
|
1985
|
+
const classified = classifyCollection(name, description);
|
|
1644
1986
|
if (!classified) {
|
|
1645
1987
|
trackClassifierTelemetry({
|
|
1646
1988
|
workspaceId,
|
|
@@ -1653,8 +1995,8 @@ async function resolveCaptureCollection(params) {
|
|
|
1653
1995
|
});
|
|
1654
1996
|
return { earlyResult: buildClassifierUnknownResult() };
|
|
1655
1997
|
}
|
|
1656
|
-
const {
|
|
1657
|
-
if (!
|
|
1998
|
+
const { provisionedCollections, provisionedCandidates } = await getProvisionedCollectionCandidates(classified, supportedCollections);
|
|
1999
|
+
if (!provisionedCollections.has(classified.collection)) {
|
|
1658
2000
|
trackClassifierTelemetry({
|
|
1659
2001
|
workspaceId,
|
|
1660
2002
|
predictedCollection: classified.collection,
|
|
@@ -1673,6 +2015,8 @@ async function resolveCaptureCollection(params) {
|
|
|
1673
2015
|
const classifierMeta = {
|
|
1674
2016
|
enabled: true,
|
|
1675
2017
|
autoRouted: autoRoute,
|
|
2018
|
+
agrees: true,
|
|
2019
|
+
abstained: false,
|
|
1676
2020
|
topConfidence: classified.topConfidence,
|
|
1677
2021
|
confidence: classified.confidence,
|
|
1678
2022
|
reasons: classified.reasons,
|
|
@@ -1711,7 +2055,7 @@ var captureSuccessOutputSchema = z2.object({
|
|
|
1711
2055
|
entryId: z2.string(),
|
|
1712
2056
|
collection: z2.string(),
|
|
1713
2057
|
name: z2.string(),
|
|
1714
|
-
status: z2.enum(["draft", "committed"]),
|
|
2058
|
+
status: z2.enum(["draft", "committed", "proposed"]),
|
|
1715
2059
|
qualityScore: z2.number(),
|
|
1716
2060
|
qualityVerdict: z2.record(z2.unknown()).optional(),
|
|
1717
2061
|
classifier: captureClassifierSchema.optional(),
|
|
@@ -1740,14 +2084,14 @@ var batchCaptureOutputSchema = z2.object({
|
|
|
1740
2084
|
})).optional()
|
|
1741
2085
|
});
|
|
1742
2086
|
function registerSmartCaptureTools(server) {
|
|
1743
|
-
const
|
|
1744
|
-
|
|
2087
|
+
const supportedCollections = new Set(
|
|
2088
|
+
CLASSIFIABLE_COLLECTIONS.filter((slug) => PROFILES.has(slug))
|
|
1745
2089
|
);
|
|
1746
2090
|
const captureTool = server.registerTool(
|
|
1747
2091
|
"capture",
|
|
1748
2092
|
{
|
|
1749
2093
|
title: "Capture",
|
|
1750
|
-
description: "The single tool for creating knowledge entries. Creates an entry, auto-links related entries, and returns a quality scorecard \u2014 all in one call. Provide a name and description; `collection` is optional when `capture-without-thinking` is enabled.\n\nSupported collections with smart profiles: tensions, business-rules, glossary, decisions, features, audiences, strategy, standards, maps, bets, insights, assumptions, principles, tracking-events.\nAll other collections get an ENT-{random} ID and sensible defaults.\n\n**Explicit data:** When you know the schema, pass `data: { field: value }` to set fields directly. Top-level `name` and `description` always win for those fields. `data` wins over inference for all other fields.\n\n**Compound capture:** Pass `links` to create relations in the same call (skips auto-link discovery). Pass `autoCommit: true` to promote the entry from draft to SSOT immediately after linking. Governed collections (glossary, business-rules, principles, standards, strategy, features) will warn but still commit \u2014 use only when you're certain.\n\nAlways creates as 'draft' unless `autoCommit` is true. Use `update-entry` for post-creation adjustments.",
|
|
2094
|
+
description: "The single tool for creating knowledge entries. Creates an entry, auto-links related entries, and returns a quality scorecard \u2014 all in one call. Provide a name and description; `collection` is optional when `capture-without-thinking` is enabled.\n\nSupported collections with smart profiles: tensions, business-rules, glossary, decisions, features, audiences, strategy, standards, maps, bets, insights, assumptions, principles, tracking-events.\nAll other collections get an ENT-{random} ID and sensible defaults.\n\n**Explicit data:** When you know the schema, pass `data: { field: value }` to set fields directly. Top-level `name` and `description` always win for those fields. `data` wins over inference for all other fields.\n\n**Compound capture:** Pass `links` to create relations in the same call (skips auto-link discovery). Pass `autoCommit: true` to promote the entry from draft to SSOT immediately after linking. Governed collections (glossary, business-rules, principles, standards, strategy, features, architecture) will warn but still commit \u2014 use only when you're certain.\n\nAlways creates as 'draft' unless `autoCommit` is true. Use `update-entry` for post-creation adjustments.",
|
|
1751
2095
|
inputSchema: captureSchema.shape,
|
|
1752
2096
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1753
2097
|
},
|
|
@@ -1765,7 +2109,7 @@ function registerSmartCaptureTools(server) {
|
|
|
1765
2109
|
name,
|
|
1766
2110
|
description,
|
|
1767
2111
|
classifierFlagOn,
|
|
1768
|
-
|
|
2112
|
+
supportedCollections,
|
|
1769
2113
|
workspaceId: wsCtx.workspaceId,
|
|
1770
2114
|
explicitCollectionProvided
|
|
1771
2115
|
});
|
|
@@ -1849,10 +2193,10 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
1849
2193
|
}
|
|
1850
2194
|
data[profile.descriptionField || "description"] = description;
|
|
1851
2195
|
const status = "draft";
|
|
2196
|
+
const agentId = getAgentSessionId();
|
|
1852
2197
|
let finalEntryId;
|
|
1853
2198
|
let internalId;
|
|
1854
2199
|
try {
|
|
1855
|
-
const agentId = getAgentSessionId();
|
|
1856
2200
|
const result = await mcpMutation("chain.createEntry", {
|
|
1857
2201
|
collectionSlug: resolvedCollection,
|
|
1858
2202
|
entryId: entryId ?? void 0,
|
|
@@ -1865,7 +2209,6 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
1865
2209
|
});
|
|
1866
2210
|
internalId = result.docId;
|
|
1867
2211
|
finalEntryId = result.entryId;
|
|
1868
|
-
await recordSessionActivity({ entryCreated: internalId });
|
|
1869
2212
|
} catch (error) {
|
|
1870
2213
|
const msg = error instanceof Error ? error.message : String(error);
|
|
1871
2214
|
if (msg.includes("Duplicate") || msg.includes("already exists")) {
|
|
@@ -1921,7 +2264,8 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
1921
2264
|
await mcpMutation("chain.createEntryRelation", {
|
|
1922
2265
|
fromEntryId: finalEntryId,
|
|
1923
2266
|
toEntryId: c.entryId,
|
|
1924
|
-
type: relationType
|
|
2267
|
+
type: relationType,
|
|
2268
|
+
sessionId: agentId ?? void 0
|
|
1925
2269
|
});
|
|
1926
2270
|
linksCreated.push({
|
|
1927
2271
|
targetEntryId: c.entryId,
|
|
@@ -1955,7 +2299,8 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
1955
2299
|
await mcpMutation("chain.createEntryRelation", {
|
|
1956
2300
|
fromEntryId: finalEntryId,
|
|
1957
2301
|
toEntryId: link.to,
|
|
1958
|
-
type: link.type
|
|
2302
|
+
type: link.type,
|
|
2303
|
+
sessionId: agentId ?? void 0
|
|
1959
2304
|
});
|
|
1960
2305
|
userLinkResults.push({ label: `\u2713 ${link.type} \u2192 ${link.to}`, ok: true });
|
|
1961
2306
|
linksCreated.push({
|
|
@@ -2036,9 +2381,15 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2036
2381
|
let commitError = null;
|
|
2037
2382
|
if (shouldAutoCommit && finalEntryId) {
|
|
2038
2383
|
try {
|
|
2039
|
-
await mcpMutation("chain.commitEntry", {
|
|
2040
|
-
|
|
2041
|
-
|
|
2384
|
+
const commitResult = await mcpMutation("chain.commitEntry", {
|
|
2385
|
+
entryId: finalEntryId,
|
|
2386
|
+
author: agentId ? `agent:${agentId}` : void 0,
|
|
2387
|
+
sessionId: agentId ?? void 0
|
|
2388
|
+
});
|
|
2389
|
+
finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
|
|
2390
|
+
if (finalStatus === "committed") {
|
|
2391
|
+
await recordSessionActivity({ entryModified: internalId });
|
|
2392
|
+
}
|
|
2042
2393
|
} catch (e) {
|
|
2043
2394
|
commitError = e instanceof Error ? e.message : "unknown error";
|
|
2044
2395
|
}
|
|
@@ -2048,14 +2399,29 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2048
2399
|
`**${name}** added to \`${resolvedCollection}\` as \`${finalStatus}\``,
|
|
2049
2400
|
`**Workspace:** ${wsCtx.workspaceSlug} (${wsCtx.workspaceId})`
|
|
2050
2401
|
];
|
|
2051
|
-
if (classifierMeta
|
|
2402
|
+
if (classifierMeta) {
|
|
2052
2403
|
lines.push("");
|
|
2053
|
-
lines.push("##
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2404
|
+
lines.push("## Classification");
|
|
2405
|
+
if (classifierMeta.abstained) {
|
|
2406
|
+
lines.push(`No classifier coverage for \`${resolvedCollection}\` \u2014 entry accepted as-is.`);
|
|
2407
|
+
} else if (classifierMeta.autoRouted) {
|
|
2408
|
+
lines.push(`Auto-routed to \`${resolvedCollection}\` (${classifierMeta.topConfidence}% confidence).`);
|
|
2409
|
+
if (classifierMeta.reasons.length > 0) {
|
|
2410
|
+
lines.push(`Reason: ${classifierMeta.reasons.join("; ")}.`);
|
|
2411
|
+
}
|
|
2412
|
+
lines.push(`Override: rerun with explicit \`collection\` if wrong.`);
|
|
2413
|
+
} else if (classifierMeta.agrees) {
|
|
2414
|
+
lines.push(`Classifier confirms \`${resolvedCollection}\` (${classifierMeta.topConfidence}% confidence).`);
|
|
2415
|
+
} else {
|
|
2416
|
+
const suggested = classifierMeta.candidates[0]?.collection ?? "unknown";
|
|
2417
|
+
lines.push(`Classifier suggests \`${suggested}\` (${classifierMeta.topConfidence}% confidence) \u2014 review classification.`);
|
|
2418
|
+
if (classifierMeta.reasons.length > 0) {
|
|
2419
|
+
lines.push(`Reason: ${classifierMeta.reasons.join("; ")}.`);
|
|
2420
|
+
}
|
|
2421
|
+
if (classifierMeta.overrideCommand) {
|
|
2422
|
+
lines.push(`Override: \`${classifierMeta.overrideCommand}\``);
|
|
2423
|
+
}
|
|
2057
2424
|
}
|
|
2058
|
-
lines.push("Correction path: rerun capture with explicit `collection` if this routing is wrong.");
|
|
2059
2425
|
}
|
|
2060
2426
|
const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://productbrain.io";
|
|
2061
2427
|
const studioUrl = resolvedCollection === "bets" ? `${appUrl.replace(/\/$/, "")}/w/${wsCtx.workspaceSlug}/studio/${internalId}` : void 0;
|
|
@@ -2088,6 +2454,10 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2088
2454
|
if (GOVERNED_COLLECTIONS.has(resolvedCollection)) {
|
|
2089
2455
|
lines.push(`_Note: \`${resolvedCollection}\` is a governed collection \u2014 ensure this entry has been reviewed._`);
|
|
2090
2456
|
}
|
|
2457
|
+
} else if (finalStatus === "proposed") {
|
|
2458
|
+
lines.push("");
|
|
2459
|
+
lines.push(`## Proposal created: ${finalEntryId}`);
|
|
2460
|
+
lines.push(`**${name}** requires consent before it can be committed, so a proposal was created instead of publishing directly.`);
|
|
2091
2461
|
} else if (commitError) {
|
|
2092
2462
|
lines.push("");
|
|
2093
2463
|
lines.push("## Commit failed");
|
|
@@ -2142,6 +2512,11 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2142
2512
|
if (failedChecks.length > 0) {
|
|
2143
2513
|
lines.push(`2. **Improve quality:** \`update-entry entryId="${eid}"\` \u2014 fill missing fields`);
|
|
2144
2514
|
}
|
|
2515
|
+
} else if (finalStatus === "proposed") {
|
|
2516
|
+
lines.push(`1. **Connect it:** \`graph action=suggest entryId="${eid}"\` \u2014 discover additional links to support the proposal`);
|
|
2517
|
+
if (failedChecks.length > 0) {
|
|
2518
|
+
lines.push(`2. **Improve quality:** \`update-entry entryId="${eid}"\` \u2014 strengthen the entry before approval`);
|
|
2519
|
+
}
|
|
2145
2520
|
} else {
|
|
2146
2521
|
if (userLinkResults.length === 0) {
|
|
2147
2522
|
lines.push(`1. **Connect it:** \`graph action=suggest entryId="${eid}"\` \u2014 discover what this should link to`);
|
|
@@ -2166,13 +2541,15 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2166
2541
|
const next = [];
|
|
2167
2542
|
if (finalStatus === "committed") {
|
|
2168
2543
|
next.push({ tool: "graph", description: "Discover connections", parameters: { action: "suggest", entryId: finalEntryId } });
|
|
2544
|
+
} else if (finalStatus === "proposed") {
|
|
2545
|
+
next.push({ tool: "graph", description: "Discover connections", parameters: { action: "suggest", entryId: finalEntryId } });
|
|
2169
2546
|
} else {
|
|
2170
2547
|
if (userLinkResults.length === 0) {
|
|
2171
2548
|
next.push({ tool: "graph", description: "Discover links", parameters: { action: "suggest", entryId: finalEntryId } });
|
|
2172
2549
|
}
|
|
2173
2550
|
next.push({ tool: "commit-entry", description: "Commit to Chain", parameters: { entryId: finalEntryId } });
|
|
2174
2551
|
}
|
|
2175
|
-
const summary = finalStatus === "committed" ? `Captured and committed ${finalEntryId} (${name}) to ${resolvedCollection}. Quality ${quality.score}/10.` : `Captured ${finalEntryId} (${name}) as draft in ${resolvedCollection}. Quality ${quality.score}/10.`;
|
|
2552
|
+
const summary = finalStatus === "committed" ? `Captured and committed ${finalEntryId} (${name}) to ${resolvedCollection}. Quality ${quality.score}/10.` : finalStatus === "proposed" ? `Captured ${finalEntryId} (${name}) in ${resolvedCollection} and created a proposal for commit. Quality ${quality.score}/10.` : `Captured ${finalEntryId} (${name}) as draft in ${resolvedCollection}. Quality ${quality.score}/10.`;
|
|
2176
2553
|
const toolResult = {
|
|
2177
2554
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
2178
2555
|
structuredContent: success(
|
|
@@ -2301,7 +2678,8 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2301
2678
|
await mcpMutation("chain.createEntryRelation", {
|
|
2302
2679
|
fromEntryId: finalEntryId,
|
|
2303
2680
|
toEntryId: c.entryId,
|
|
2304
|
-
type: relationType
|
|
2681
|
+
type: relationType,
|
|
2682
|
+
sessionId: agentId ?? void 0
|
|
2305
2683
|
});
|
|
2306
2684
|
autoLinkCount++;
|
|
2307
2685
|
} catch {
|
|
@@ -2311,7 +2689,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2311
2689
|
}
|
|
2312
2690
|
}
|
|
2313
2691
|
results.push({ name: entry.name, collection: entry.collection, entryId: finalEntryId, ok: true, autoLinks: autoLinkCount });
|
|
2314
|
-
await recordSessionActivity({ entryCreated: internalId });
|
|
2315
2692
|
} catch (error) {
|
|
2316
2693
|
const msg = error instanceof Error ? error.message : String(error);
|
|
2317
2694
|
results.push({ name: entry.name, collection: entry.collection, entryId: "", ok: false, autoLinks: 0, error: msg });
|
|
@@ -2613,15 +2990,20 @@ export {
|
|
|
2613
2990
|
requireActiveSession,
|
|
2614
2991
|
requireWriteAccess,
|
|
2615
2992
|
recoverSessionState,
|
|
2993
|
+
deriveEpistemicStatus,
|
|
2994
|
+
formatEpistemicLine,
|
|
2995
|
+
toEpistemicInput,
|
|
2616
2996
|
extractPreview,
|
|
2617
2997
|
translateStaleToolNames,
|
|
2618
2998
|
initToolSurface,
|
|
2619
2999
|
trackWriteTool,
|
|
2620
3000
|
initFeatureFlags,
|
|
2621
3001
|
CLASSIFIER_AUTO_ROUTE_THRESHOLD,
|
|
3002
|
+
CLASSIFIABLE_COLLECTIONS,
|
|
2622
3003
|
STARTER_COLLECTIONS,
|
|
2623
|
-
|
|
3004
|
+
classifyCollection,
|
|
2624
3005
|
isClassificationAmbiguous,
|
|
3006
|
+
classifyStarterCollection,
|
|
2625
3007
|
success,
|
|
2626
3008
|
failure,
|
|
2627
3009
|
parseOrFail,
|
|
@@ -2631,6 +3013,7 @@ export {
|
|
|
2631
3013
|
notFoundResult,
|
|
2632
3014
|
validationResult,
|
|
2633
3015
|
withEnvelope,
|
|
3016
|
+
inferStrategyCategory,
|
|
2634
3017
|
formatQualityReport,
|
|
2635
3018
|
checkEntryQuality,
|
|
2636
3019
|
captureSchema,
|
|
@@ -2643,4 +3026,4 @@ export {
|
|
|
2643
3026
|
formatRubricCoaching,
|
|
2644
3027
|
formatRubricVerdictSection
|
|
2645
3028
|
};
|
|
2646
|
-
//# sourceMappingURL=chunk-
|
|
3029
|
+
//# sourceMappingURL=chunk-ED3KCWZE.js.map
|