@productbrain/mcp 0.0.1-beta.41 → 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-5IH3KEAZ.js → chunk-AWDD44CN.js} +222 -90
- package/dist/chunk-AWDD44CN.js.map +1 -0
- package/dist/{chunk-P7ABQEFK.js → chunk-BIDMZOLE.js} +85 -3
- package/dist/chunk-BIDMZOLE.js.map +1 -0
- package/dist/{chunk-M264FY2V.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 +7 -4
- package/dist/index.js.map +1 -1
- package/dist/{setup-RSGAAKJB.js → setup-QT5KCX5Q.js} +20 -90
- package/dist/setup-QT5KCX5Q.js.map +1 -0
- package/dist/{smart-capture-GH4CXVVX.js → smart-capture-W2IALMJ5.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-5IH3KEAZ.js.map +0 -1
- package/dist/chunk-M264FY2V.js.map +0 -1
- package/dist/chunk-P7ABQEFK.js.map +0 -1
- package/dist/setup-RSGAAKJB.js.map +0 -1
- /package/dist/{smart-capture-GH4CXVVX.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",
|
|
@@ -4121,6 +4133,7 @@ async function handleStart2(args) {
|
|
|
4121
4133
|
const sc = orient?.strategicContext;
|
|
4122
4134
|
const parts = [];
|
|
4123
4135
|
if (sc?.vision) parts.push(`Vision: ${sc.vision}`);
|
|
4136
|
+
if (sc?.purpose) parts.push(`Purpose: ${sc.purpose}`);
|
|
4124
4137
|
if (sc?.activeBetCount) parts.push(`${sc.activeBetCount} active bet(s)`);
|
|
4125
4138
|
if (sc?.activeTensionCount) parts.push(`${sc.activeTensionCount} open tension(s)`);
|
|
4126
4139
|
if (orient?.activeBets?.length) {
|
|
@@ -4469,6 +4482,7 @@ async function handleRespond(args) {
|
|
|
4469
4482
|
if (captureReady) {
|
|
4470
4483
|
commitBlockers = computeCommitBlockers({
|
|
4471
4484
|
betEntryId: betId,
|
|
4485
|
+
betDocId: refreshedBet?._id ?? betEntry._id,
|
|
4472
4486
|
relations: refreshedConstellation.relations,
|
|
4473
4487
|
betData: refreshedData,
|
|
4474
4488
|
sessionDrafts
|
|
@@ -4608,6 +4622,7 @@ async function handleScore(args) {
|
|
|
4608
4622
|
}
|
|
4609
4623
|
const commitBlockers = computeCommitBlockers({
|
|
4610
4624
|
betEntryId: betId,
|
|
4625
|
+
betDocId: betEntry._id,
|
|
4611
4626
|
relations: constellation.relations,
|
|
4612
4627
|
betData,
|
|
4613
4628
|
sessionDrafts
|
|
@@ -4767,10 +4782,27 @@ async function handleCommitConstellation(args) {
|
|
|
4767
4782
|
const relations = await mcpQuery("chain.listEntryRelations", {
|
|
4768
4783
|
entryId: betId
|
|
4769
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
|
+
})();
|
|
4770
4800
|
const sessionDrafts = await loadSessionDrafts(betId, betEntry._id);
|
|
4771
4801
|
const commitBlockerItems = computeCommitBlockers({
|
|
4772
4802
|
betEntryId: betId,
|
|
4803
|
+
betDocId: betEntry._id,
|
|
4773
4804
|
relations,
|
|
4805
|
+
hasStrategyLink,
|
|
4774
4806
|
betData,
|
|
4775
4807
|
sessionDrafts
|
|
4776
4808
|
});
|
|
@@ -4792,6 +4824,7 @@ async function handleCommitConstellation(args) {
|
|
|
4792
4824
|
blockers: commitBlockerItems,
|
|
4793
4825
|
committedIds: [],
|
|
4794
4826
|
alreadyCommittedIds: [],
|
|
4827
|
+
proposedIds: [],
|
|
4795
4828
|
failedIds: [],
|
|
4796
4829
|
conflictIds: [],
|
|
4797
4830
|
totalRelations: relations.length
|
|
@@ -4800,7 +4833,7 @@ async function handleCommitConstellation(args) {
|
|
|
4800
4833
|
}
|
|
4801
4834
|
let contradictionWarnings = [];
|
|
4802
4835
|
try {
|
|
4803
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
4836
|
+
const { runContradictionCheck } = await import("./smart-capture-W2IALMJ5.js");
|
|
4804
4837
|
const descField = betData.problem ?? betData.description ?? "";
|
|
4805
4838
|
contradictionWarnings = await runContradictionCheck(
|
|
4806
4839
|
betEntry.name ?? betId,
|
|
@@ -4835,24 +4868,40 @@ No constellation entries were committed.`
|
|
|
4835
4868
|
isError: true
|
|
4836
4869
|
};
|
|
4837
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
|
+
};
|
|
4838
4879
|
for (const entryId of result.committedIds) {
|
|
4839
|
-
|
|
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
|
+
}
|
|
4840
4888
|
}
|
|
4841
4889
|
const lines = [];
|
|
4890
|
+
const hasIssues = result.failedIds.length > 0 || result.conflictIds.length > 0;
|
|
4842
4891
|
if (result.proposalCreated) {
|
|
4843
4892
|
const linkedCount = result.committedIds.filter((id) => id !== betId).length;
|
|
4844
4893
|
lines.push(
|
|
4845
|
-
`# Proposal created`,
|
|
4894
|
+
hasIssues ? `# Proposal created with issues` : `# Proposal created`,
|
|
4846
4895
|
"",
|
|
4847
4896
|
`Workspace uses consent-based governance. \`${betId}\` was submitted as a proposal \u2014 it will be committed when approved.`,
|
|
4848
4897
|
`**${linkedCount} linked entries** were committed directly (proposals apply to the bet only).`
|
|
4849
4898
|
);
|
|
4850
4899
|
} else {
|
|
4851
4900
|
lines.push(
|
|
4852
|
-
`# Published`,
|
|
4901
|
+
hasIssues ? `# Published with issues` : `# Published`,
|
|
4853
4902
|
"",
|
|
4854
4903
|
`**${result.committedIds.length} entries** committed to the Chain, **${result.totalRelations} connections** preserved.`,
|
|
4855
|
-
`\`${betId}\` and its full constellation are now source of truth.`
|
|
4904
|
+
hasIssues ? `\`${betId}\` was partially committed. Review conflicts/failed entries below before considering the constellation complete.` : `\`${betId}\` and its full constellation are now source of truth.`
|
|
4856
4905
|
);
|
|
4857
4906
|
}
|
|
4858
4907
|
if (contradictionWarnings.length > 0) {
|
|
@@ -4864,6 +4913,9 @@ No constellation entries were committed.`
|
|
|
4864
4913
|
if (result.alreadyCommittedIds.length > 0) {
|
|
4865
4914
|
lines.push("", `**Already committed:** ${result.alreadyCommittedIds.join(", ")}`);
|
|
4866
4915
|
}
|
|
4916
|
+
if (result.proposedIds.length > 0) {
|
|
4917
|
+
lines.push("", `**Proposed (not yet committed):** ${result.proposedIds.join(", ")}`);
|
|
4918
|
+
}
|
|
4867
4919
|
if (result.conflictIds.length > 0) {
|
|
4868
4920
|
lines.push("", `**${result.conflictIds.length} conflicts:**`);
|
|
4869
4921
|
for (const c of result.conflictIds) {
|
|
@@ -5335,10 +5387,10 @@ function formatRecoveryBlock(block) {
|
|
|
5335
5387
|
const lines = [
|
|
5336
5388
|
"## Previous Session Recovery",
|
|
5337
5389
|
"",
|
|
5338
|
-
`
|
|
5390
|
+
`Previous session \u2014 ${block.date}, ${block.duration}, status: ${block.status}`,
|
|
5339
5391
|
`Created (${block.created.length + (block.createdOverflow ?? 0)}): ${fmt(block.created, block.createdOverflow)}`,
|
|
5340
5392
|
`Modified (${block.modified.length + (block.modifiedOverflow ?? 0)}): ${fmt(block.modified, block.modifiedOverflow)}`,
|
|
5341
|
-
`
|
|
5393
|
+
`Items pending review (${block.draftsNeedingAttention.length + (block.draftsOverflow ?? 0)}): ${fmt(block.draftsNeedingAttention, block.draftsOverflow)}`,
|
|
5342
5394
|
`Relations created: ${block.relationsCreated}`,
|
|
5343
5395
|
""
|
|
5344
5396
|
];
|
|
@@ -5361,7 +5413,7 @@ function buildPlannedWorkSection(work, priorSessions, recoveryBlock) {
|
|
|
5361
5413
|
}
|
|
5362
5414
|
if (work.uncommittedDrafts.length > 0) {
|
|
5363
5415
|
const count = work.uncommittedDrafts.length;
|
|
5364
|
-
const label = count === 1 ? "1
|
|
5416
|
+
const label = count === 1 ? "1 item pending" : `${count} items pending`;
|
|
5365
5417
|
const topNames = work.uncommittedDrafts.slice(0, 3).map((d) => d.name).join(", ");
|
|
5366
5418
|
lines.push(`- **${label}** \u2014 ${topNames}${count > 3 ? ", ..." : ""}`);
|
|
5367
5419
|
}
|
|
@@ -5581,7 +5633,7 @@ function extractionToBatchEntries(extracted) {
|
|
|
5581
5633
|
}
|
|
5582
5634
|
function getInterviewInstructions(workspaceName) {
|
|
5583
5635
|
return {
|
|
5584
|
-
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.`,
|
|
5585
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.)`,
|
|
5586
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.)`,
|
|
5587
5639
|
extractionGuidance: `After the user answers, extract:
|
|
@@ -5611,7 +5663,7 @@ function buildInterviewResponse(workspaceName) {
|
|
|
5611
5663
|
"",
|
|
5612
5664
|
instructions.systemPrompt,
|
|
5613
5665
|
"",
|
|
5614
|
-
"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.",
|
|
5615
5667
|
"",
|
|
5616
5668
|
`**${instructions.question1}**`,
|
|
5617
5669
|
"",
|
|
@@ -5619,7 +5671,7 @@ function buildInterviewResponse(workspaceName) {
|
|
|
5619
5671
|
"",
|
|
5620
5672
|
`> ${instructions.scanOffer}`,
|
|
5621
5673
|
"",
|
|
5622
|
-
|
|
5674
|
+
"_Everything stays pending until you confirm._"
|
|
5623
5675
|
].join("\n");
|
|
5624
5676
|
}
|
|
5625
5677
|
|
|
@@ -5666,27 +5718,42 @@ function registerStartTools(server) {
|
|
|
5666
5718
|
errors.push("Readiness check unavailable \u2014 showing workspace summary.");
|
|
5667
5719
|
}
|
|
5668
5720
|
if (stage === "blank" && preset) {
|
|
5669
|
-
|
|
5721
|
+
const result = await seedPreset(wsCtx, preset, agentSessionId);
|
|
5722
|
+
return {
|
|
5723
|
+
content: [{ type: "text", text: result.text }],
|
|
5724
|
+
structuredContent: result.structuredContent
|
|
5725
|
+
};
|
|
5670
5726
|
}
|
|
5671
5727
|
if (stage === "blank") {
|
|
5672
|
-
|
|
5728
|
+
const scanResult = buildProjectScanResponse(wsCtx);
|
|
5729
|
+
return {
|
|
5730
|
+
content: [{ type: "text", text: scanResult.text }],
|
|
5731
|
+
structuredContent: scanResult.structuredContent
|
|
5732
|
+
};
|
|
5673
5733
|
}
|
|
5674
5734
|
if (stage === "seeded") {
|
|
5675
|
-
const
|
|
5735
|
+
const result = await buildSeededResponse(wsCtx, readiness, agentSessionId);
|
|
5676
5736
|
void mcpMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
5677
5737
|
});
|
|
5678
|
-
return {
|
|
5738
|
+
return {
|
|
5739
|
+
content: [{ type: "text", text: result.text }],
|
|
5740
|
+
structuredContent: result.structuredContent
|
|
5741
|
+
};
|
|
5679
5742
|
}
|
|
5680
5743
|
if (stage === "grounded" || stage === "connected") {
|
|
5681
5744
|
void mcpMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
5682
5745
|
});
|
|
5683
5746
|
}
|
|
5684
|
-
|
|
5747
|
+
const orientResult = await buildOrientResponse(wsCtx, agentSessionId, errors);
|
|
5748
|
+
return {
|
|
5749
|
+
content: [{ type: "text", text: orientResult.text }],
|
|
5750
|
+
structuredContent: orientResult.structuredContent
|
|
5751
|
+
};
|
|
5685
5752
|
}
|
|
5686
5753
|
);
|
|
5687
5754
|
}
|
|
5688
5755
|
function buildProjectScanResponse(wsCtx) {
|
|
5689
|
-
|
|
5756
|
+
const text = [
|
|
5690
5757
|
`# Welcome to ${wsCtx.workspaceName}`,
|
|
5691
5758
|
"",
|
|
5692
5759
|
"Your workspace is fresh. Let me get oriented in your codebase.",
|
|
@@ -5716,56 +5783,72 @@ function buildProjectScanResponse(wsCtx) {
|
|
|
5716
5783
|
"",
|
|
5717
5784
|
"_Prefer 5 specific entries over 8 generic ones. Skip anything that would apply to any codebase._"
|
|
5718
5785
|
].join("\n");
|
|
5786
|
+
return {
|
|
5787
|
+
text,
|
|
5788
|
+
structuredContent: {
|
|
5789
|
+
stage: "blank",
|
|
5790
|
+
oriented: false,
|
|
5791
|
+
orientationStatus: "no_session"
|
|
5792
|
+
}
|
|
5793
|
+
};
|
|
5719
5794
|
}
|
|
5720
5795
|
async function buildSeededResponse(wsCtx, readiness, agentSessionId) {
|
|
5796
|
+
const stage = readiness?.stage ?? "seeded";
|
|
5797
|
+
const score = readiness?.score;
|
|
5798
|
+
const gaps = readiness?.gaps ?? [];
|
|
5721
5799
|
const lines = [
|
|
5722
5800
|
`# ${wsCtx.workspaceName}`,
|
|
5723
5801
|
"_Picking up where you left off._",
|
|
5724
5802
|
""
|
|
5725
5803
|
];
|
|
5726
|
-
const stage = readiness?.stage ?? "seeded";
|
|
5727
|
-
const score = readiness?.score;
|
|
5728
|
-
if (score !== void 0) {
|
|
5729
|
-
lines.push(`**Brain stage: ${stage}.** Readiness score: ${score}/100.`);
|
|
5730
|
-
lines.push("");
|
|
5731
|
-
}
|
|
5732
|
-
const gaps = readiness?.gaps ?? [];
|
|
5733
5804
|
if (gaps.length > 0) {
|
|
5734
|
-
lines.push("
|
|
5735
|
-
for (const gap of gaps.slice(0, 3)) {
|
|
5736
|
-
const cta = gap.capabilityGuidance ?? gap.guidance ?? `Capture ${gap.label.toLowerCase()} to unlock this.`;
|
|
5737
|
-
lines.push(`**${gap.label}** \u2014 ${cta}`);
|
|
5738
|
-
}
|
|
5805
|
+
lines.push("Here are the most impactful gaps to fill next:");
|
|
5739
5806
|
lines.push("");
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
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}`);
|
|
5743
5812
|
}
|
|
5744
|
-
} else {
|
|
5745
|
-
lines.push("No gaps detected \u2014 workspace is filling up nicely.");
|
|
5746
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?");
|
|
5747
5817
|
}
|
|
5748
|
-
|
|
5749
|
-
|
|
5818
|
+
let oriented = false;
|
|
5819
|
+
let orientationStatus = "no_session";
|
|
5750
5820
|
if (agentSessionId) {
|
|
5751
5821
|
try {
|
|
5752
5822
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5753
5823
|
setSessionOriented(true);
|
|
5754
|
-
|
|
5755
|
-
|
|
5824
|
+
oriented = true;
|
|
5825
|
+
orientationStatus = "complete";
|
|
5756
5826
|
} catch {
|
|
5757
|
-
|
|
5758
|
-
lines.push("_Warning: Could not mark session as oriented._");
|
|
5827
|
+
orientationStatus = "failed";
|
|
5759
5828
|
}
|
|
5760
5829
|
}
|
|
5761
|
-
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
|
+
};
|
|
5762
5842
|
}
|
|
5763
5843
|
async function seedPreset(wsCtx, presetId, agentSessionId) {
|
|
5764
5844
|
const preset = getPreset(presetId);
|
|
5765
5845
|
if (!preset) {
|
|
5766
|
-
return
|
|
5846
|
+
return {
|
|
5847
|
+
text: `Preset "${presetId}" not found.
|
|
5767
5848
|
|
|
5768
|
-
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
|
+
};
|
|
5769
5852
|
}
|
|
5770
5853
|
const seeded = [];
|
|
5771
5854
|
const skipped = [];
|
|
@@ -5785,11 +5868,16 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`;
|
|
|
5785
5868
|
skipped.push(`${col.name} (already exists)`);
|
|
5786
5869
|
}
|
|
5787
5870
|
}
|
|
5871
|
+
let oriented = false;
|
|
5872
|
+
let orientationStatus = "no_session";
|
|
5788
5873
|
if (agentSessionId) {
|
|
5789
5874
|
try {
|
|
5790
5875
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5791
5876
|
setSessionOriented(true);
|
|
5877
|
+
oriented = true;
|
|
5878
|
+
orientationStatus = "complete";
|
|
5792
5879
|
} catch {
|
|
5880
|
+
orientationStatus = "failed";
|
|
5793
5881
|
}
|
|
5794
5882
|
}
|
|
5795
5883
|
const lines = [
|
|
@@ -5811,12 +5899,20 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`;
|
|
|
5811
5899
|
"",
|
|
5812
5900
|
buildInterviewResponse(wsCtx.workspaceName),
|
|
5813
5901
|
"",
|
|
5814
|
-
"_You can also customize your
|
|
5815
|
-
"",
|
|
5816
|
-
"---",
|
|
5817
|
-
"Orientation complete. Write tools are available."
|
|
5902
|
+
"_You can also customize your collections anytime \u2014 just ask._"
|
|
5818
5903
|
);
|
|
5819
|
-
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
|
+
};
|
|
5820
5916
|
}
|
|
5821
5917
|
function computeWorkspaceAge(createdAt) {
|
|
5822
5918
|
if (!createdAt) return { ageDays: 0, isNeglected: false };
|
|
@@ -5867,7 +5963,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5867
5963
|
const isHighReadiness = readiness !== null && readiness.score >= 50;
|
|
5868
5964
|
const stage = readiness?.stage ?? null;
|
|
5869
5965
|
lines.push(`# ${wsCtx.workspaceName}`);
|
|
5870
|
-
lines.push(
|
|
5966
|
+
lines.push("_Product Brain is ready._");
|
|
5871
5967
|
lines.push("");
|
|
5872
5968
|
if (isLowReadiness && isNeglected) {
|
|
5873
5969
|
const stageNote = stage ? ` and is still at the **${stage}** stage` : "";
|
|
@@ -5875,7 +5971,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5875
5971
|
lines.push("Let's close the gaps \u2014 or if the current structure doesn't fit, we can reshape it.");
|
|
5876
5972
|
lines.push("");
|
|
5877
5973
|
} else if (isLowReadiness) {
|
|
5878
|
-
|
|
5974
|
+
lines.push("Let's get your workspace active.");
|
|
5879
5975
|
lines.push("");
|
|
5880
5976
|
}
|
|
5881
5977
|
if (isLowReadiness) {
|
|
@@ -5886,21 +5982,17 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
5886
5982
|
lines.push("");
|
|
5887
5983
|
lines.push(nextAction.cta);
|
|
5888
5984
|
lines.push("");
|
|
5889
|
-
lines.push(
|
|
5985
|
+
lines.push("_Everything I capture stays pending until you confirm._");
|
|
5890
5986
|
lines.push("");
|
|
5891
5987
|
const remainingGaps = (readiness.gaps ?? []).length - 1;
|
|
5892
5988
|
if (remainingGaps > 0 || openTensions.length > 0) {
|
|
5893
|
-
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._`);
|
|
5894
5990
|
lines.push("");
|
|
5895
5991
|
}
|
|
5896
5992
|
}
|
|
5897
|
-
lines.push("_Need a collection that doesn't exist yet (e.g. audiences, personas, metrics)?_");
|
|
5898
|
-
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._");
|
|
5899
5994
|
lines.push("");
|
|
5900
5995
|
} else if (isHighReadiness) {
|
|
5901
|
-
if (readiness) {
|
|
5902
|
-
lines.push(`**Brain stage: ${stage}.**`);
|
|
5903
|
-
}
|
|
5904
5996
|
let wsPrinciples = [];
|
|
5905
5997
|
let wsStandards = [];
|
|
5906
5998
|
let wsBusinessRules = [];
|
|
@@ -6002,7 +6094,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6002
6094
|
lines.push("");
|
|
6003
6095
|
lines.push("## Your workspace is activated");
|
|
6004
6096
|
lines.push(
|
|
6005
|
-
`**${committed.length}
|
|
6097
|
+
`**${committed.length} entries** across **${committedCollections.size} collections** \u2014 your knowledge graph is alive.`
|
|
6006
6098
|
);
|
|
6007
6099
|
lines.push("");
|
|
6008
6100
|
lines.push(
|
|
@@ -6013,7 +6105,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6013
6105
|
lines.push(`**View in Studio:** \`/w/${wsCtx.workspaceSlug}/studio\``);
|
|
6014
6106
|
lines.push("");
|
|
6015
6107
|
}
|
|
6016
|
-
lines.push(
|
|
6108
|
+
lines.push("_Tip: Ask me to suggest connections between entries to unlock deeper context._");
|
|
6017
6109
|
lines.push("");
|
|
6018
6110
|
}
|
|
6019
6111
|
} catch {
|
|
@@ -6026,23 +6118,30 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6026
6118
|
for (const err of errors) lines.push(`- ${err}`);
|
|
6027
6119
|
lines.push("");
|
|
6028
6120
|
}
|
|
6121
|
+
let oriented = false;
|
|
6122
|
+
let orientationStatus = "no_session";
|
|
6029
6123
|
if (agentSessionId) {
|
|
6030
6124
|
try {
|
|
6031
6125
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
6032
6126
|
setSessionOriented(true);
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
`Orientation complete. Session ${agentSessionId}. Write tools available.`
|
|
6036
|
-
);
|
|
6127
|
+
oriented = true;
|
|
6128
|
+
orientationStatus = "complete";
|
|
6037
6129
|
} catch {
|
|
6038
|
-
|
|
6039
|
-
lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
|
|
6130
|
+
orientationStatus = "failed";
|
|
6040
6131
|
}
|
|
6041
|
-
} else {
|
|
6042
|
-
lines.push("---");
|
|
6043
|
-
lines.push("_No active agent session. Call `session action=start` to begin a tracked session._");
|
|
6044
6132
|
}
|
|
6045
|
-
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
|
+
};
|
|
6046
6145
|
}
|
|
6047
6146
|
|
|
6048
6147
|
// src/tools/usage.ts
|
|
@@ -8061,6 +8160,34 @@ function registerHealthTools(server) {
|
|
|
8061
8160
|
} catch (e) {
|
|
8062
8161
|
errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
|
|
8063
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
|
+
}
|
|
8064
8191
|
const lines = [];
|
|
8065
8192
|
const isLowReadiness = readiness && readiness.score < 50;
|
|
8066
8193
|
if (wsCtx) {
|
|
@@ -8077,6 +8204,7 @@ function registerHealthTools(server) {
|
|
|
8077
8204
|
if (orientEntries?.strategicContext) {
|
|
8078
8205
|
const sc = orientEntries.strategicContext;
|
|
8079
8206
|
if (sc.vision) lines.push(`Vision: ${sc.vision}`);
|
|
8207
|
+
if (sc.purpose) lines.push(`Purpose: ${sc.purpose}`);
|
|
8080
8208
|
if (sc.productAreaCount != null && sc.productAreaCount > 0) {
|
|
8081
8209
|
lines.push(`Product areas (${sc.productAreaCount}): ${(sc.productAreas ?? []).join(", ")}`);
|
|
8082
8210
|
}
|
|
@@ -8172,6 +8300,7 @@ function registerHealthTools(server) {
|
|
|
8172
8300
|
const sc = orientEntries.strategicContext;
|
|
8173
8301
|
lines.push("## Strategic Context");
|
|
8174
8302
|
if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
|
|
8303
|
+
if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
|
|
8175
8304
|
if (sc.productAreaCount != null && sc.productAreaCount > 0) {
|
|
8176
8305
|
lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
|
|
8177
8306
|
}
|
|
@@ -9122,6 +9251,8 @@ Description field: ${wf.kbOutputTemplate.descriptionField}
|
|
|
9122
9251
|
const orient = await mcpQuery("chain.getOrientEntries", {});
|
|
9123
9252
|
const sc = orient?.strategicContext;
|
|
9124
9253
|
if (sc?.vision) strategicContext += `**Vision:** ${sc.vision}
|
|
9254
|
+
`;
|
|
9255
|
+
if (sc?.purpose) strategicContext += `**Purpose:** ${sc.purpose}
|
|
9125
9256
|
`;
|
|
9126
9257
|
if (sc?.currentBet) strategicContext += `**Current bet:** ${sc.currentBet}
|
|
9127
9258
|
`;
|
|
@@ -9166,18 +9297,20 @@ You are a **coached shaping facilitator** powered by the \`facilitate\` tool. Yo
|
|
|
9166
9297
|
|
|
9167
9298
|
## Your Role (DEC-56 Boundary)
|
|
9168
9299
|
|
|
9169
|
-
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.
|
|
9170
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.
|
|
9171
9302
|
The \`coaching.suggestedQuestion\` is a suggestion, not a script \u2014 rephrase or skip based on conversation flow.
|
|
9172
9303
|
|
|
9173
|
-
## Rubric Dimensions (
|
|
9304
|
+
## Rubric Dimensions (7 scoring criteria)
|
|
9174
9305
|
|
|
9175
9306
|
Each scored 0-10 by the server:
|
|
9176
9307
|
1. **Problem Clarity** \u2014 workaround described, who affected, frequency/severity, differentiated from existing tensions
|
|
9177
9308
|
2. **Appetite Definition** \u2014 time constraint explicit, scope bounded, trade-offs acknowledged
|
|
9178
9309
|
3. **Element Decomposition** \u2014 breadboard-level pieces identified, independently describable, no implementation leaks
|
|
9179
|
-
4. **
|
|
9180
|
-
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
|
|
9181
9314
|
|
|
9182
9315
|
## How to Use the Facilitate Tool
|
|
9183
9316
|
|
|
@@ -9614,8 +9747,8 @@ var INSTRUCTIONS = [
|
|
|
9614
9747
|
"",
|
|
9615
9748
|
"## Workflow",
|
|
9616
9749
|
"",
|
|
9617
|
-
" 1. Start: call `
|
|
9618
|
-
" 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.",
|
|
9619
9752
|
" 3. Discover: use `entries action=search` to find entries, or `entries action=list` to browse.",
|
|
9620
9753
|
' 4. Drill in: use `entries action=get entryId="..."` for full details \u2014 data, labels, relations, history.',
|
|
9621
9754
|
" 5. Context: use `context action=gather` with an entryId or a task description.",
|
|
@@ -9626,8 +9759,7 @@ var INSTRUCTIONS = [
|
|
|
9626
9759
|
" 10. Close: call `session action=close` when done \u2014 records session activity. Auto-nudges if wrapup was skipped.",
|
|
9627
9760
|
"",
|
|
9628
9761
|
"Write tools (capture, update-entry, relations, commit-entry) require:",
|
|
9629
|
-
" -
|
|
9630
|
-
" - Completed orientation (call orient)",
|
|
9762
|
+
" - Call `start` to begin (starts session + loads context). Call `orient` mid-session for a refresh.",
|
|
9631
9763
|
" - A readwrite API key scope",
|
|
9632
9764
|
"",
|
|
9633
9765
|
"Commit-on-confirm: always capture as draft first and show the user what was captured.",
|
|
@@ -9687,4 +9819,4 @@ export {
|
|
|
9687
9819
|
SERVER_VERSION,
|
|
9688
9820
|
createProductBrainServer
|
|
9689
9821
|
};
|
|
9690
|
-
//# sourceMappingURL=chunk-
|
|
9822
|
+
//# sourceMappingURL=chunk-AWDD44CN.js.map
|