@productbrain/mcp 0.0.1-beta.42 → 0.0.1-beta.43
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-X7DON33G.js → chunk-AWDD44CN.js} +214 -88
- package/dist/chunk-AWDD44CN.js.map +1 -0
- package/dist/{chunk-6R67YS23.js → chunk-BIDMZOLE.js} +77 -2
- package/dist/chunk-BIDMZOLE.js.map +1 -0
- package/dist/{chunk-4YKORBQX.js → chunk-PQP27A3R.js} +4 -3
- package/dist/chunk-PQP27A3R.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/http.js +3 -3
- package/dist/index.js +3 -3
- package/dist/{setup-EN4T5LIB.js → setup-QT5KCX5Q.js} +20 -90
- package/dist/setup-QT5KCX5Q.js.map +1 -0
- package/dist/{smart-capture-TD5M4WFE.js → smart-capture-W2IALMJ5.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-4YKORBQX.js.map +0 -1
- package/dist/chunk-6R67YS23.js.map +0 -1
- package/dist/chunk-X7DON33G.js.map +0 -1
- package/dist/setup-EN4T5LIB.js.map +0 -1
- /package/dist/{smart-capture-TD5M4WFE.js.map → smart-capture-W2IALMJ5.js.map} +0 -0
|
@@ -25,43 +25,51 @@ import {
|
|
|
25
25
|
startAgentSession,
|
|
26
26
|
trackWriteTool,
|
|
27
27
|
translateStaleToolNames
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-PQP27A3R.js";
|
|
29
29
|
import {
|
|
30
30
|
trackQualityCheck,
|
|
31
31
|
trackQualityVerdict
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-BIDMZOLE.js";
|
|
33
33
|
|
|
34
34
|
// src/server.ts
|
|
35
35
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
36
36
|
|
|
37
37
|
// src/tools/knowledge.ts
|
|
38
38
|
import { z } from "zod";
|
|
39
|
-
var
|
|
39
|
+
var WORKFLOW_STATUS_VALUES = [
|
|
40
|
+
// Generic / governed collections
|
|
40
41
|
"open",
|
|
41
42
|
"pending",
|
|
42
|
-
"decided",
|
|
43
43
|
"proposed",
|
|
44
44
|
"accepted",
|
|
45
45
|
"needs-amendment",
|
|
46
46
|
"withdrawn",
|
|
47
47
|
"review",
|
|
48
48
|
"in-progress",
|
|
49
|
+
"decided",
|
|
49
50
|
"conflict",
|
|
50
51
|
"processing",
|
|
51
52
|
"closed",
|
|
53
|
+
// Bets lifecycle
|
|
52
54
|
"shaped",
|
|
53
55
|
"bet",
|
|
54
56
|
"building",
|
|
55
|
-
"shipped"
|
|
56
|
-
|
|
57
|
+
"shipped",
|
|
58
|
+
// Assumptions lifecycle
|
|
59
|
+
"untested",
|
|
60
|
+
"testing",
|
|
61
|
+
"validated",
|
|
62
|
+
"invalidated"
|
|
63
|
+
];
|
|
64
|
+
var LEGACY_WORKFLOW_STATUSES = new Set(WORKFLOW_STATUS_VALUES);
|
|
57
65
|
var updateEntrySchema = z.object({
|
|
58
66
|
entryId: z.string().describe("Entry ID to update, e.g. 'T-SUPPLIER', 'BR-001'"),
|
|
59
67
|
name: z.string().optional().describe("New display name"),
|
|
60
68
|
status: z.union([
|
|
61
69
|
z.enum(["draft", "active", "deprecated", "archived"]),
|
|
62
|
-
z.enum(
|
|
70
|
+
z.enum(WORKFLOW_STATUS_VALUES)
|
|
63
71
|
]).optional().describe("Lifecycle status: draft | active | deprecated | archived. **Workflow values (open, pending, decided\u2026) are deprecated here \u2014 use `workflowStatus` instead. Passing a workflow value as `status` will be auto-routed with a warning until 2026-09-03, then hard-errored.**"),
|
|
64
|
-
workflowStatus: z.enum(
|
|
72
|
+
workflowStatus: z.enum(WORKFLOW_STATUS_VALUES).optional().describe("Collection workflow state. Each collection restricts which values are valid (e.g. bets: 'shaped' | 'bet' | 'building' | 'shipped'; assumptions: 'untested' | 'testing' | 'validated' | 'invalidated'; decisions: 'pending' | 'decided'; tensions: 'open' | 'processing' | 'decided' | 'closed'). The backend will reject values invalid for the target collection."),
|
|
65
73
|
data: z.record(z.unknown()).optional().describe("Fields to update (merged with existing data)"),
|
|
66
74
|
order: z.number().optional().describe("New sort order"),
|
|
67
75
|
canonicalKey: z.string().optional().describe("Semantic type (e.g. 'decision', 'tension'). Only changeable on draft/uncommitted entries."),
|
|
@@ -195,7 +203,7 @@ ${formatted}` }]
|
|
|
195
203
|
},
|
|
196
204
|
async ({ entryId }) => {
|
|
197
205
|
requireWriteAccess();
|
|
198
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
206
|
+
const { runContradictionCheck } = await import("./smart-capture-W2IALMJ5.js");
|
|
199
207
|
const entry = await mcpQuery("chain.getEntry", { entryId });
|
|
200
208
|
if (!entry) {
|
|
201
209
|
return {
|
|
@@ -3669,11 +3677,15 @@ function generateBuildContract(ctx) {
|
|
|
3669
3677
|
|
|
3670
3678
|
// src/tools/facilitate-validation.ts
|
|
3671
3679
|
function computeCommitBlockers(opts) {
|
|
3672
|
-
const { betEntryId, relations, betData, sessionDrafts } = opts;
|
|
3680
|
+
const { betEntryId, betDocId, relations, hasStrategyLink, betData, sessionDrafts } = opts;
|
|
3673
3681
|
const blockers = [];
|
|
3674
3682
|
const str = (key) => (betData[key] ?? "").trim();
|
|
3675
|
-
const
|
|
3676
|
-
|
|
3683
|
+
const hasDirectionalCommitsTo = relations.some((r) => {
|
|
3684
|
+
if (r.type !== "commits_to") return false;
|
|
3685
|
+
return r.fromId === betDocId && r.toId !== betDocId;
|
|
3686
|
+
});
|
|
3687
|
+
const strategyLinked = hasStrategyLink ?? hasDirectionalCommitsTo;
|
|
3688
|
+
if (!strategyLinked) {
|
|
3677
3689
|
blockers.push({
|
|
3678
3690
|
entryId: betEntryId,
|
|
3679
3691
|
blocker: "Missing strategy link",
|
|
@@ -4470,6 +4482,7 @@ async function handleRespond(args) {
|
|
|
4470
4482
|
if (captureReady) {
|
|
4471
4483
|
commitBlockers = computeCommitBlockers({
|
|
4472
4484
|
betEntryId: betId,
|
|
4485
|
+
betDocId: refreshedBet?._id ?? betEntry._id,
|
|
4473
4486
|
relations: refreshedConstellation.relations,
|
|
4474
4487
|
betData: refreshedData,
|
|
4475
4488
|
sessionDrafts
|
|
@@ -4609,6 +4622,7 @@ async function handleScore(args) {
|
|
|
4609
4622
|
}
|
|
4610
4623
|
const commitBlockers = computeCommitBlockers({
|
|
4611
4624
|
betEntryId: betId,
|
|
4625
|
+
betDocId: betEntry._id,
|
|
4612
4626
|
relations: constellation.relations,
|
|
4613
4627
|
betData,
|
|
4614
4628
|
sessionDrafts
|
|
@@ -4768,10 +4782,27 @@ async function handleCommitConstellation(args) {
|
|
|
4768
4782
|
const relations = await mcpQuery("chain.listEntryRelations", {
|
|
4769
4783
|
entryId: betId
|
|
4770
4784
|
});
|
|
4785
|
+
const hasStrategyLink = await (async () => {
|
|
4786
|
+
const relatedDocIds = /* @__PURE__ */ new Set();
|
|
4787
|
+
for (const rel of relations) {
|
|
4788
|
+
if (rel.fromId === betEntry._id && rel.toId) relatedDocIds.add(rel.toId);
|
|
4789
|
+
if (rel.toId === betEntry._id && rel.fromId) relatedDocIds.add(rel.fromId);
|
|
4790
|
+
}
|
|
4791
|
+
for (const docId of relatedDocIds) {
|
|
4792
|
+
try {
|
|
4793
|
+
const related = await mcpQuery("chain.getEntry", { id: docId });
|
|
4794
|
+
if (related?.collectionSlug === "strategy") return true;
|
|
4795
|
+
} catch {
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
return false;
|
|
4799
|
+
})();
|
|
4771
4800
|
const sessionDrafts = await loadSessionDrafts(betId, betEntry._id);
|
|
4772
4801
|
const commitBlockerItems = computeCommitBlockers({
|
|
4773
4802
|
betEntryId: betId,
|
|
4803
|
+
betDocId: betEntry._id,
|
|
4774
4804
|
relations,
|
|
4805
|
+
hasStrategyLink,
|
|
4775
4806
|
betData,
|
|
4776
4807
|
sessionDrafts
|
|
4777
4808
|
});
|
|
@@ -4793,6 +4824,7 @@ async function handleCommitConstellation(args) {
|
|
|
4793
4824
|
blockers: commitBlockerItems,
|
|
4794
4825
|
committedIds: [],
|
|
4795
4826
|
alreadyCommittedIds: [],
|
|
4827
|
+
proposedIds: [],
|
|
4796
4828
|
failedIds: [],
|
|
4797
4829
|
conflictIds: [],
|
|
4798
4830
|
totalRelations: relations.length
|
|
@@ -4801,7 +4833,7 @@ async function handleCommitConstellation(args) {
|
|
|
4801
4833
|
}
|
|
4802
4834
|
let contradictionWarnings = [];
|
|
4803
4835
|
try {
|
|
4804
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
4836
|
+
const { runContradictionCheck } = await import("./smart-capture-W2IALMJ5.js");
|
|
4805
4837
|
const descField = betData.problem ?? betData.description ?? "";
|
|
4806
4838
|
contradictionWarnings = await runContradictionCheck(
|
|
4807
4839
|
betEntry.name ?? betId,
|
|
@@ -4836,15 +4868,30 @@ No constellation entries were committed.`
|
|
|
4836
4868
|
isError: true
|
|
4837
4869
|
};
|
|
4838
4870
|
}
|
|
4871
|
+
result = {
|
|
4872
|
+
...result,
|
|
4873
|
+
committedIds: result.committedIds ?? [],
|
|
4874
|
+
alreadyCommittedIds: result.alreadyCommittedIds ?? [],
|
|
4875
|
+
proposedIds: result.proposedIds ?? [],
|
|
4876
|
+
failedIds: result.failedIds ?? [],
|
|
4877
|
+
conflictIds: result.conflictIds ?? []
|
|
4878
|
+
};
|
|
4839
4879
|
for (const entryId of result.committedIds) {
|
|
4840
|
-
|
|
4880
|
+
try {
|
|
4881
|
+
const committedEntry = await mcpQuery("chain.getEntry", { entryId });
|
|
4882
|
+
const docId = committedEntry?._id;
|
|
4883
|
+
if (typeof docId === "string" && docId.length > 0) {
|
|
4884
|
+
await recordSessionActivity({ entryModified: docId });
|
|
4885
|
+
}
|
|
4886
|
+
} catch {
|
|
4887
|
+
}
|
|
4841
4888
|
}
|
|
4842
4889
|
const lines = [];
|
|
4843
4890
|
const hasIssues = result.failedIds.length > 0 || result.conflictIds.length > 0;
|
|
4844
4891
|
if (result.proposalCreated) {
|
|
4845
4892
|
const linkedCount = result.committedIds.filter((id) => id !== betId).length;
|
|
4846
4893
|
lines.push(
|
|
4847
|
-
`# Proposal created`,
|
|
4894
|
+
hasIssues ? `# Proposal created with issues` : `# Proposal created`,
|
|
4848
4895
|
"",
|
|
4849
4896
|
`Workspace uses consent-based governance. \`${betId}\` was submitted as a proposal \u2014 it will be committed when approved.`,
|
|
4850
4897
|
`**${linkedCount} linked entries** were committed directly (proposals apply to the bet only).`
|
|
@@ -4866,6 +4913,9 @@ No constellation entries were committed.`
|
|
|
4866
4913
|
if (result.alreadyCommittedIds.length > 0) {
|
|
4867
4914
|
lines.push("", `**Already committed:** ${result.alreadyCommittedIds.join(", ")}`);
|
|
4868
4915
|
}
|
|
4916
|
+
if (result.proposedIds.length > 0) {
|
|
4917
|
+
lines.push("", `**Proposed (not yet committed):** ${result.proposedIds.join(", ")}`);
|
|
4918
|
+
}
|
|
4869
4919
|
if (result.conflictIds.length > 0) {
|
|
4870
4920
|
lines.push("", `**${result.conflictIds.length} conflicts:**`);
|
|
4871
4921
|
for (const c of result.conflictIds) {
|
|
@@ -5337,10 +5387,10 @@ function formatRecoveryBlock(block) {
|
|
|
5337
5387
|
const lines = [
|
|
5338
5388
|
"## Previous Session Recovery",
|
|
5339
5389
|
"",
|
|
5340
|
-
`
|
|
5390
|
+
`Previous session \u2014 ${block.date}, ${block.duration}, status: ${block.status}`,
|
|
5341
5391
|
`Created (${block.created.length + (block.createdOverflow ?? 0)}): ${fmt(block.created, block.createdOverflow)}`,
|
|
5342
5392
|
`Modified (${block.modified.length + (block.modifiedOverflow ?? 0)}): ${fmt(block.modified, block.modifiedOverflow)}`,
|
|
5343
|
-
`
|
|
5393
|
+
`Items pending review (${block.draftsNeedingAttention.length + (block.draftsOverflow ?? 0)}): ${fmt(block.draftsNeedingAttention, block.draftsOverflow)}`,
|
|
5344
5394
|
`Relations created: ${block.relationsCreated}`,
|
|
5345
5395
|
""
|
|
5346
5396
|
];
|
|
@@ -5363,7 +5413,7 @@ function buildPlannedWorkSection(work, priorSessions, recoveryBlock) {
|
|
|
5363
5413
|
}
|
|
5364
5414
|
if (work.uncommittedDrafts.length > 0) {
|
|
5365
5415
|
const count = work.uncommittedDrafts.length;
|
|
5366
|
-
const label = count === 1 ? "1
|
|
5416
|
+
const label = count === 1 ? "1 item pending" : `${count} items pending`;
|
|
5367
5417
|
const topNames = work.uncommittedDrafts.slice(0, 3).map((d) => d.name).join(", ");
|
|
5368
5418
|
lines.push(`- **${label}** \u2014 ${topNames}${count > 3 ? ", ..." : ""}`);
|
|
5369
5419
|
}
|
|
@@ -5583,7 +5633,7 @@ function extractionToBatchEntries(extracted) {
|
|
|
5583
5633
|
}
|
|
5584
5634
|
function getInterviewInstructions(workspaceName) {
|
|
5585
5635
|
return {
|
|
5586
|
-
systemPrompt: `You are activating the **${workspaceName}** Product Brain. Ask 1\u20132 focused questions, then extract structured knowledge and feed it to batch-capture. Everything
|
|
5636
|
+
systemPrompt: `You are activating the **${workspaceName}** Product Brain. Ask 1\u20132 focused questions, then extract structured knowledge and feed it to batch-capture. Everything stays pending \u2014 the user confirms before anything is committed.`,
|
|
5587
5637
|
question1: `**Q1 \u2014 What are you building and for whom?** Describe your product in 1\u20132 sentences and who it's for. (This becomes your Product Vision and primary Audience.)`,
|
|
5588
5638
|
question2: `**Q2 (optional) \u2014 What's your tech stack or key domain terms?** Name a few core technologies or terms your team uses. (These become Architecture + Glossary entries.)`,
|
|
5589
5639
|
extractionGuidance: `After the user answers, extract:
|
|
@@ -5613,7 +5663,7 @@ function buildInterviewResponse(workspaceName) {
|
|
|
5613
5663
|
"",
|
|
5614
5664
|
instructions.systemPrompt,
|
|
5615
5665
|
"",
|
|
5616
|
-
"I'll ask you 1\u20132 questions. Your answers become the first entries in your knowledge graph \u2014 all
|
|
5666
|
+
"I'll ask you 1\u20132 questions. Your answers become the first entries in your knowledge graph \u2014 all pending until you confirm.",
|
|
5617
5667
|
"",
|
|
5618
5668
|
`**${instructions.question1}**`,
|
|
5619
5669
|
"",
|
|
@@ -5621,7 +5671,7 @@ function buildInterviewResponse(workspaceName) {
|
|
|
5621
5671
|
"",
|
|
5622
5672
|
`> ${instructions.scanOffer}`,
|
|
5623
5673
|
"",
|
|
5624
|
-
|
|
5674
|
+
"_Everything stays pending until you confirm._"
|
|
5625
5675
|
].join("\n");
|
|
5626
5676
|
}
|
|
5627
5677
|
|
|
@@ -5668,27 +5718,42 @@ function registerStartTools(server) {
|
|
|
5668
5718
|
errors.push("Readiness check unavailable \u2014 showing workspace summary.");
|
|
5669
5719
|
}
|
|
5670
5720
|
if (stage === "blank" && preset) {
|
|
5671
|
-
|
|
5721
|
+
const result = await seedPreset(wsCtx, preset, agentSessionId);
|
|
5722
|
+
return {
|
|
5723
|
+
content: [{ type: "text", text: result.text }],
|
|
5724
|
+
structuredContent: result.structuredContent
|
|
5725
|
+
};
|
|
5672
5726
|
}
|
|
5673
5727
|
if (stage === "blank") {
|
|
5674
|
-
|
|
5728
|
+
const scanResult = buildProjectScanResponse(wsCtx);
|
|
5729
|
+
return {
|
|
5730
|
+
content: [{ type: "text", text: scanResult.text }],
|
|
5731
|
+
structuredContent: scanResult.structuredContent
|
|
5732
|
+
};
|
|
5675
5733
|
}
|
|
5676
5734
|
if (stage === "seeded") {
|
|
5677
|
-
const
|
|
5735
|
+
const result = await buildSeededResponse(wsCtx, readiness, agentSessionId);
|
|
5678
5736
|
void mcpMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
5679
5737
|
});
|
|
5680
|
-
return {
|
|
5738
|
+
return {
|
|
5739
|
+
content: [{ type: "text", text: result.text }],
|
|
5740
|
+
structuredContent: result.structuredContent
|
|
5741
|
+
};
|
|
5681
5742
|
}
|
|
5682
5743
|
if (stage === "grounded" || stage === "connected") {
|
|
5683
5744
|
void mcpMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
5684
5745
|
});
|
|
5685
5746
|
}
|
|
5686
|
-
|
|
5747
|
+
const orientResult = await buildOrientResponse(wsCtx, agentSessionId, errors);
|
|
5748
|
+
return {
|
|
5749
|
+
content: [{ type: "text", text: orientResult.text }],
|
|
5750
|
+
structuredContent: orientResult.structuredContent
|
|
5751
|
+
};
|
|
5687
5752
|
}
|
|
5688
5753
|
);
|
|
5689
5754
|
}
|
|
5690
5755
|
function buildProjectScanResponse(wsCtx) {
|
|
5691
|
-
|
|
5756
|
+
const text = [
|
|
5692
5757
|
`# Welcome to ${wsCtx.workspaceName}`,
|
|
5693
5758
|
"",
|
|
5694
5759
|
"Your workspace is fresh. Let me get oriented in your codebase.",
|
|
@@ -5718,56 +5783,72 @@ function buildProjectScanResponse(wsCtx) {
|
|
|
5718
5783
|
"",
|
|
5719
5784
|
"_Prefer 5 specific entries over 8 generic ones. Skip anything that would apply to any codebase._"
|
|
5720
5785
|
].join("\n");
|
|
5786
|
+
return {
|
|
5787
|
+
text,
|
|
5788
|
+
structuredContent: {
|
|
5789
|
+
stage: "blank",
|
|
5790
|
+
oriented: false,
|
|
5791
|
+
orientationStatus: "no_session"
|
|
5792
|
+
}
|
|
5793
|
+
};
|
|
5721
5794
|
}
|
|
5722
5795
|
async function buildSeededResponse(wsCtx, readiness, agentSessionId) {
|
|
5796
|
+
const stage = readiness?.stage ?? "seeded";
|
|
5797
|
+
const score = readiness?.score;
|
|
5798
|
+
const gaps = readiness?.gaps ?? [];
|
|
5723
5799
|
const lines = [
|
|
5724
5800
|
`# ${wsCtx.workspaceName}`,
|
|
5725
5801
|
"_Picking up where you left off._",
|
|
5726
5802
|
""
|
|
5727
5803
|
];
|
|
5728
|
-
const stage = readiness?.stage ?? "seeded";
|
|
5729
|
-
const score = readiness?.score;
|
|
5730
|
-
if (score !== void 0) {
|
|
5731
|
-
lines.push(`**Brain stage: ${stage}.** Readiness score: ${score}/100.`);
|
|
5732
|
-
lines.push("");
|
|
5733
|
-
}
|
|
5734
|
-
const gaps = readiness?.gaps ?? [];
|
|
5735
5804
|
if (gaps.length > 0) {
|
|
5736
|
-
lines.push("
|
|
5737
|
-
for (const gap of gaps.slice(0, 3)) {
|
|
5738
|
-
const cta = gap.capabilityGuidance ?? gap.guidance ?? `Capture ${gap.label.toLowerCase()} to unlock this.`;
|
|
5739
|
-
lines.push(`**${gap.label}** \u2014 ${cta}`);
|
|
5740
|
-
}
|
|
5805
|
+
lines.push("Here are the most impactful gaps to fill next:");
|
|
5741
5806
|
lines.push("");
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5807
|
+
const topGaps = gaps.slice(0, 3);
|
|
5808
|
+
for (let i = 0; i < topGaps.length; i++) {
|
|
5809
|
+
const gap = topGaps[i];
|
|
5810
|
+
const cta = gap.capabilityGuidance ?? gap.guidance ?? `Describe your ${gap.label.toLowerCase()}.`;
|
|
5811
|
+
lines.push(`${i + 1}. **${gap.label}** \u2014 ${cta}`);
|
|
5745
5812
|
}
|
|
5746
|
-
} else {
|
|
5747
|
-
lines.push("No gaps detected \u2014 workspace is filling up nicely.");
|
|
5748
5813
|
lines.push("");
|
|
5814
|
+
lines.push("Pick any to start \u2014 or begin with **#1** and I'll guide you through it.");
|
|
5815
|
+
} else {
|
|
5816
|
+
lines.push("No gaps detected \u2014 your workspace is filling up nicely. What would you like to work on?");
|
|
5749
5817
|
}
|
|
5750
|
-
|
|
5751
|
-
|
|
5818
|
+
let oriented = false;
|
|
5819
|
+
let orientationStatus = "no_session";
|
|
5752
5820
|
if (agentSessionId) {
|
|
5753
5821
|
try {
|
|
5754
5822
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5755
5823
|
setSessionOriented(true);
|
|
5756
|
-
|
|
5757
|
-
|
|
5824
|
+
oriented = true;
|
|
5825
|
+
orientationStatus = "complete";
|
|
5758
5826
|
} catch {
|
|
5759
|
-
|
|
5760
|
-
lines.push("_Warning: Could not mark session as oriented._");
|
|
5827
|
+
orientationStatus = "failed";
|
|
5761
5828
|
}
|
|
5762
5829
|
}
|
|
5763
|
-
return
|
|
5830
|
+
return {
|
|
5831
|
+
text: lines.join("\n"),
|
|
5832
|
+
structuredContent: {
|
|
5833
|
+
stage,
|
|
5834
|
+
readinessScore: score ?? null,
|
|
5835
|
+
totalGaps: gaps.length,
|
|
5836
|
+
topGapLabels: gaps.slice(0, 3).map((g) => g.label),
|
|
5837
|
+
oriented,
|
|
5838
|
+
orientationStatus,
|
|
5839
|
+
...agentSessionId ? { sessionId: agentSessionId } : {}
|
|
5840
|
+
}
|
|
5841
|
+
};
|
|
5764
5842
|
}
|
|
5765
5843
|
async function seedPreset(wsCtx, presetId, agentSessionId) {
|
|
5766
5844
|
const preset = getPreset(presetId);
|
|
5767
5845
|
if (!preset) {
|
|
5768
|
-
return
|
|
5846
|
+
return {
|
|
5847
|
+
text: `Preset "${presetId}" not found.
|
|
5769
5848
|
|
|
5770
|
-
Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}
|
|
5849
|
+
Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`,
|
|
5850
|
+
structuredContent: { stage: "blank", error: "preset_not_found", preset: presetId }
|
|
5851
|
+
};
|
|
5771
5852
|
}
|
|
5772
5853
|
const seeded = [];
|
|
5773
5854
|
const skipped = [];
|
|
@@ -5787,11 +5868,16 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`;
|
|
|
5787
5868
|
skipped.push(`${col.name} (already exists)`);
|
|
5788
5869
|
}
|
|
5789
5870
|
}
|
|
5871
|
+
let oriented = false;
|
|
5872
|
+
let orientationStatus = "no_session";
|
|
5790
5873
|
if (agentSessionId) {
|
|
5791
5874
|
try {
|
|
5792
5875
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5793
5876
|
setSessionOriented(true);
|
|
5877
|
+
oriented = true;
|
|
5878
|
+
orientationStatus = "complete";
|
|
5794
5879
|
} catch {
|
|
5880
|
+
orientationStatus = "failed";
|
|
5795
5881
|
}
|
|
5796
5882
|
}
|
|
5797
5883
|
const lines = [
|
|
@@ -5813,12 +5899,20 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`;
|
|
|
5813
5899
|
"",
|
|
5814
5900
|
buildInterviewResponse(wsCtx.workspaceName),
|
|
5815
5901
|
"",
|
|
5816
|
-
"_You can also customize your
|
|
5817
|
-
"",
|
|
5818
|
-
"---",
|
|
5819
|
-
"Orientation complete. Write tools are available."
|
|
5902
|
+
"_You can also customize your collections anytime \u2014 just ask._"
|
|
5820
5903
|
);
|
|
5821
|
-
return
|
|
5904
|
+
return {
|
|
5905
|
+
text: lines.join("\n"),
|
|
5906
|
+
structuredContent: {
|
|
5907
|
+
stage: "blank",
|
|
5908
|
+
preset: presetId,
|
|
5909
|
+
seededCollections: seeded,
|
|
5910
|
+
skippedCollections: skipped,
|
|
5911
|
+
oriented,
|
|
5912
|
+
orientationStatus,
|
|
5913
|
+
...agentSessionId ? { sessionId: agentSessionId } : {}
|
|
5914
|
+
}
|
|
5915
|
+
};
|
|
5822
5916
|
}
|
|
5823
5917
|
function computeWorkspaceAge(createdAt) {
|
|
5824
5918
|
if (!createdAt) return { ageDays: 0, isNeglected: false };
|
|
@@ -5869,7 +5963,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5869
5963
|
const isHighReadiness = readiness !== null && readiness.score >= 50;
|
|
5870
5964
|
const stage = readiness?.stage ?? null;
|
|
5871
5965
|
lines.push(`# ${wsCtx.workspaceName}`);
|
|
5872
|
-
lines.push(
|
|
5966
|
+
lines.push("_Product Brain is ready._");
|
|
5873
5967
|
lines.push("");
|
|
5874
5968
|
if (isLowReadiness && isNeglected) {
|
|
5875
5969
|
const stageNote = stage ? ` and is still at the **${stage}** stage` : "";
|
|
@@ -5877,7 +5971,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5877
5971
|
lines.push("Let's close the gaps \u2014 or if the current structure doesn't fit, we can reshape it.");
|
|
5878
5972
|
lines.push("");
|
|
5879
5973
|
} else if (isLowReadiness) {
|
|
5880
|
-
|
|
5974
|
+
lines.push("Let's get your workspace active.");
|
|
5881
5975
|
lines.push("");
|
|
5882
5976
|
}
|
|
5883
5977
|
if (isLowReadiness) {
|
|
@@ -5888,21 +5982,17 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5888
5982
|
lines.push("");
|
|
5889
5983
|
lines.push(nextAction.cta);
|
|
5890
5984
|
lines.push("");
|
|
5891
|
-
lines.push(
|
|
5985
|
+
lines.push("_Everything I capture stays pending until you confirm._");
|
|
5892
5986
|
lines.push("");
|
|
5893
5987
|
const remainingGaps = (readiness.gaps ?? []).length - 1;
|
|
5894
5988
|
if (remainingGaps > 0 || openTensions.length > 0) {
|
|
5895
|
-
lines.push(`_${remainingGaps > 0 ? `${remainingGaps} more
|
|
5989
|
+
lines.push(`_${remainingGaps > 0 ? `${remainingGaps} more area${remainingGaps === 1 ? "" : "s"} to cover` : ""}${remainingGaps > 0 && openTensions.length > 0 ? " and " : ""}${openTensions.length > 0 ? `${openTensions.length} open tension${openTensions.length === 1 ? "" : "s"}` : ""} \u2014 ask for full status to see everything._`);
|
|
5896
5990
|
lines.push("");
|
|
5897
5991
|
}
|
|
5898
5992
|
}
|
|
5899
|
-
lines.push("_Need a collection that doesn't exist yet (e.g. audiences, personas, metrics)?_");
|
|
5900
|
-
lines.push("_Use `collections action=create` to add it, or ask me to propose collections for your domain._");
|
|
5993
|
+
lines.push("_Need a collection that doesn't exist yet (e.g. audiences, personas, metrics)? Just ask \u2014 I'll set it up._");
|
|
5901
5994
|
lines.push("");
|
|
5902
5995
|
} else if (isHighReadiness) {
|
|
5903
|
-
if (readiness) {
|
|
5904
|
-
lines.push(`**Brain stage: ${stage}.**`);
|
|
5905
|
-
}
|
|
5906
5996
|
let wsPrinciples = [];
|
|
5907
5997
|
let wsStandards = [];
|
|
5908
5998
|
let wsBusinessRules = [];
|
|
@@ -6004,7 +6094,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6004
6094
|
lines.push("");
|
|
6005
6095
|
lines.push("## Your workspace is activated");
|
|
6006
6096
|
lines.push(
|
|
6007
|
-
`**${committed.length}
|
|
6097
|
+
`**${committed.length} entries** across **${committedCollections.size} collections** \u2014 your knowledge graph is alive.`
|
|
6008
6098
|
);
|
|
6009
6099
|
lines.push("");
|
|
6010
6100
|
lines.push(
|
|
@@ -6015,7 +6105,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6015
6105
|
lines.push(`**View in Studio:** \`/w/${wsCtx.workspaceSlug}/studio\``);
|
|
6016
6106
|
lines.push("");
|
|
6017
6107
|
}
|
|
6018
|
-
lines.push(
|
|
6108
|
+
lines.push("_Tip: Ask me to suggest connections between entries to unlock deeper context._");
|
|
6019
6109
|
lines.push("");
|
|
6020
6110
|
}
|
|
6021
6111
|
} catch {
|
|
@@ -6028,23 +6118,30 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6028
6118
|
for (const err of errors) lines.push(`- ${err}`);
|
|
6029
6119
|
lines.push("");
|
|
6030
6120
|
}
|
|
6121
|
+
let oriented = false;
|
|
6122
|
+
let orientationStatus = "no_session";
|
|
6031
6123
|
if (agentSessionId) {
|
|
6032
6124
|
try {
|
|
6033
6125
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
6034
6126
|
setSessionOriented(true);
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
`Orientation complete. Session ${agentSessionId}. Write tools available.`
|
|
6038
|
-
);
|
|
6127
|
+
oriented = true;
|
|
6128
|
+
orientationStatus = "complete";
|
|
6039
6129
|
} catch {
|
|
6040
|
-
|
|
6041
|
-
lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
|
|
6130
|
+
orientationStatus = "failed";
|
|
6042
6131
|
}
|
|
6043
|
-
} else {
|
|
6044
|
-
lines.push("---");
|
|
6045
|
-
lines.push("_No active agent session. Call `session action=start` to begin a tracked session._");
|
|
6046
6132
|
}
|
|
6047
|
-
return
|
|
6133
|
+
return {
|
|
6134
|
+
text: lines.join("\n"),
|
|
6135
|
+
structuredContent: {
|
|
6136
|
+
stage,
|
|
6137
|
+
readinessScore: readiness?.score ?? null,
|
|
6138
|
+
totalGaps: readiness?.gaps?.length ?? 0,
|
|
6139
|
+
openTensions: openTensions.length,
|
|
6140
|
+
oriented,
|
|
6141
|
+
orientationStatus,
|
|
6142
|
+
...agentSessionId ? { sessionId: agentSessionId } : {}
|
|
6143
|
+
}
|
|
6144
|
+
};
|
|
6048
6145
|
}
|
|
6049
6146
|
|
|
6050
6147
|
// src/tools/usage.ts
|
|
@@ -8063,6 +8160,34 @@ function registerHealthTools(server) {
|
|
|
8063
8160
|
} catch (e) {
|
|
8064
8161
|
errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
|
|
8065
8162
|
}
|
|
8163
|
+
if (readiness?.stage === "blank") {
|
|
8164
|
+
const scanLines = [
|
|
8165
|
+
`# Welcome to ${wsCtx?.workspaceName ?? "your workspace"}`,
|
|
8166
|
+
"",
|
|
8167
|
+
"Your workspace is fresh \u2014 let's set it up.",
|
|
8168
|
+
"",
|
|
8169
|
+
"**Recommended:** call the `start` tool instead of `orient` for the best first-run experience.",
|
|
8170
|
+
"It will guide you through scanning your codebase and capturing initial knowledge.",
|
|
8171
|
+
"",
|
|
8172
|
+
"Or tell me about your product and I'll start capturing knowledge directly."
|
|
8173
|
+
];
|
|
8174
|
+
if (agentSessionId) {
|
|
8175
|
+
try {
|
|
8176
|
+
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
8177
|
+
setSessionOriented(true);
|
|
8178
|
+
} catch {
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
return {
|
|
8182
|
+
content: [{ type: "text", text: scanLines.join("\n") }],
|
|
8183
|
+
structuredContent: {
|
|
8184
|
+
stage: "blank",
|
|
8185
|
+
readinessScore: readiness?.score ?? 0,
|
|
8186
|
+
oriented: true,
|
|
8187
|
+
redirectHint: "Use the `start` tool for the full guided setup experience."
|
|
8188
|
+
}
|
|
8189
|
+
};
|
|
8190
|
+
}
|
|
8066
8191
|
const lines = [];
|
|
8067
8192
|
const isLowReadiness = readiness && readiness.score < 50;
|
|
8068
8193
|
if (wsCtx) {
|
|
@@ -9172,18 +9297,20 @@ You are a **coached shaping facilitator** powered by the \`facilitate\` tool. Yo
|
|
|
9172
9297
|
|
|
9173
9298
|
## Your Role (DEC-56 Boundary)
|
|
9174
9299
|
|
|
9175
|
-
The **server judges** \u2014 it scores input against
|
|
9300
|
+
The **server judges** \u2014 it scores input against 7 rubric dimensions, detects overlap with existing Chain entries, and checks alignment with governance. The server returns structured coaching responses.
|
|
9176
9301
|
**You coach** \u2014 you interpret the structured response, synthesize it naturally, decide tone, follow up on weak areas, and push back when the shaping isn't sharp enough.
|
|
9177
9302
|
The \`coaching.suggestedQuestion\` is a suggestion, not a script \u2014 rephrase or skip based on conversation flow.
|
|
9178
9303
|
|
|
9179
|
-
## Rubric Dimensions (
|
|
9304
|
+
## Rubric Dimensions (7 scoring criteria)
|
|
9180
9305
|
|
|
9181
9306
|
Each scored 0-10 by the server:
|
|
9182
9307
|
1. **Problem Clarity** \u2014 workaround described, who affected, frequency/severity, differentiated from existing tensions
|
|
9183
9308
|
2. **Appetite Definition** \u2014 time constraint explicit, scope bounded, trade-offs acknowledged
|
|
9184
9309
|
3. **Element Decomposition** \u2014 breadboard-level pieces identified, independently describable, no implementation leaks
|
|
9185
|
-
4. **
|
|
9186
|
-
5. **
|
|
9310
|
+
4. **Architecture Fit** \u2014 layer boundaries and dependency implications are explicit, aligned with existing system constraints
|
|
9311
|
+
5. **Risk Coverage** \u2014 rabbit holes named, mitigations or acceptances, codebase-level risks
|
|
9312
|
+
6. **Boundary Specification** \u2014 explicit no-gos, each prevents scope creep in a specific direction
|
|
9313
|
+
7. **Done-When Quality** \u2014 testable completion outcomes, measurable verification criteria, and clear acceptance conditions
|
|
9187
9314
|
|
|
9188
9315
|
## How to Use the Facilitate Tool
|
|
9189
9316
|
|
|
@@ -9620,8 +9747,8 @@ var INSTRUCTIONS = [
|
|
|
9620
9747
|
"",
|
|
9621
9748
|
"## Workflow",
|
|
9622
9749
|
"",
|
|
9623
|
-
" 1. Start: call `
|
|
9624
|
-
" 2.
|
|
9750
|
+
" 1. Start: call `start` to begin \u2014 it starts a session automatically, detects your workspace stage, and returns the right guidance. Fresh workspaces get a guided setup; active workspaces get a standup briefing.",
|
|
9751
|
+
" 2. Re-orient: call `orient` mid-session for task-scoped context or a compact status refresh.",
|
|
9625
9752
|
" 3. Discover: use `entries action=search` to find entries, or `entries action=list` to browse.",
|
|
9626
9753
|
' 4. Drill in: use `entries action=get entryId="..."` for full details \u2014 data, labels, relations, history.',
|
|
9627
9754
|
" 5. Context: use `context action=gather` with an entryId or a task description.",
|
|
@@ -9632,8 +9759,7 @@ var INSTRUCTIONS = [
|
|
|
9632
9759
|
" 10. Close: call `session action=close` when done \u2014 records session activity. Auto-nudges if wrapup was skipped.",
|
|
9633
9760
|
"",
|
|
9634
9761
|
"Write tools (capture, update-entry, relations, commit-entry) require:",
|
|
9635
|
-
" -
|
|
9636
|
-
" - Completed orientation (call orient)",
|
|
9762
|
+
" - Call `start` to begin (starts session + loads context). Call `orient` mid-session for a refresh.",
|
|
9637
9763
|
" - A readwrite API key scope",
|
|
9638
9764
|
"",
|
|
9639
9765
|
"Commit-on-confirm: always capture as draft first and show the user what was captured.",
|
|
@@ -9693,4 +9819,4 @@ export {
|
|
|
9693
9819
|
SERVER_VERSION,
|
|
9694
9820
|
createProductBrainServer
|
|
9695
9821
|
};
|
|
9696
|
-
//# sourceMappingURL=chunk-
|
|
9822
|
+
//# sourceMappingURL=chunk-AWDD44CN.js.map
|