@productbrain/mcp 0.0.1-beta.43 → 0.0.1-beta.45
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-AWDD44CN.js → chunk-ADLZPAEI.js} +417 -281
- package/dist/chunk-ADLZPAEI.js.map +1 -0
- package/dist/{chunk-PQP27A3R.js → chunk-CYECJTRI.js} +54 -2
- package/dist/chunk-CYECJTRI.js.map +1 -0
- package/dist/{chunk-BIDMZOLE.js → chunk-MRIO53BY.js} +1 -1
- package/dist/{chunk-BIDMZOLE.js.map → chunk-MRIO53BY.js.map} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/http.js +3 -3
- package/dist/index.js +3 -3
- package/dist/{setup-QT5KCX5Q.js → setup-LSCFKMW7.js} +2 -2
- package/dist/{smart-capture-W2IALMJ5.js → smart-capture-XBOUPHFI.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-AWDD44CN.js.map +0 -1
- package/dist/chunk-PQP27A3R.js.map +0 -1
- /package/dist/{setup-QT5KCX5Q.js.map → setup-LSCFKMW7.js.map} +0 -0
- /package/dist/{smart-capture-W2IALMJ5.js.map → smart-capture-XBOUPHFI.js.map} +0 -0
|
@@ -25,11 +25,11 @@ import {
|
|
|
25
25
|
startAgentSession,
|
|
26
26
|
trackWriteTool,
|
|
27
27
|
translateStaleToolNames
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-CYECJTRI.js";
|
|
29
29
|
import {
|
|
30
30
|
trackQualityCheck,
|
|
31
31
|
trackQualityVerdict
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-MRIO53BY.js";
|
|
33
33
|
|
|
34
34
|
// src/server.ts
|
|
35
35
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -59,7 +59,10 @@ var WORKFLOW_STATUS_VALUES = [
|
|
|
59
59
|
"untested",
|
|
60
60
|
"testing",
|
|
61
61
|
"validated",
|
|
62
|
-
"invalidated"
|
|
62
|
+
"invalidated",
|
|
63
|
+
// Insights lifecycle
|
|
64
|
+
"hypothesis",
|
|
65
|
+
"evidenced"
|
|
63
66
|
];
|
|
64
67
|
var LEGACY_WORKFLOW_STATUSES = new Set(WORKFLOW_STATUS_VALUES);
|
|
65
68
|
var updateEntrySchema = z.object({
|
|
@@ -203,7 +206,7 @@ ${formatted}` }]
|
|
|
203
206
|
},
|
|
204
207
|
async ({ entryId }) => {
|
|
205
208
|
requireWriteAccess();
|
|
206
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
209
|
+
const { runContradictionCheck } = await import("./smart-capture-XBOUPHFI.js");
|
|
207
210
|
const entry = await mcpQuery("chain.getEntry", { entryId });
|
|
208
211
|
if (!entry) {
|
|
209
212
|
return {
|
|
@@ -3724,10 +3727,11 @@ function computeCommitBlockers(opts) {
|
|
|
3724
3727
|
}
|
|
3725
3728
|
for (const draft of sessionDrafts) {
|
|
3726
3729
|
if (!draft.name || draft.name.trim().length === 0) {
|
|
3730
|
+
const draftRef = draft.entryId && draft.entryId.trim().length > 0 ? draft.entryId : "<draftId>";
|
|
3727
3731
|
blockers.push({
|
|
3728
3732
|
entryId: betEntryId,
|
|
3729
3733
|
blocker: `Draft constellation entry is missing a name`,
|
|
3730
|
-
fix: `update-entry entryId="
|
|
3734
|
+
fix: `update-entry entryId="${draftRef}" name="<name>"`
|
|
3731
3735
|
});
|
|
3732
3736
|
}
|
|
3733
3737
|
}
|
|
@@ -3778,7 +3782,7 @@ var captureItemSchema = z12.object({
|
|
|
3778
3782
|
});
|
|
3779
3783
|
var facilitateSchema = z12.object({
|
|
3780
3784
|
action: z12.enum(FACILITATE_ACTIONS).describe(
|
|
3781
|
-
"'start':
|
|
3785
|
+
"'start': begin shaping session context (entry created on first respond). 'respond': process user input, score, capture, return coaching. 'score': return current scorecard without advancing. 'resume': reconstruct session from existing bet entry. 'commit-constellation': atomically commit a bet and all its linked draft entries in one call. Requires betEntryId."
|
|
3782
3786
|
),
|
|
3783
3787
|
sessionType: z12.enum(["shape"]).default("shape").optional().describe("Session type. Only 'shape' in v1."),
|
|
3784
3788
|
betEntryId: z12.string().optional().describe("Bet entry ID. Required for resume/score. For respond: omit on first call after start (entry created automatically); required for subsequent calls."),
|
|
@@ -3797,7 +3801,7 @@ function registerFacilitateTools(server) {
|
|
|
3797
3801
|
"facilitate",
|
|
3798
3802
|
{
|
|
3799
3803
|
title: "Facilitate \u2014 Coached Shaping",
|
|
3800
|
-
description: "Server-controlled coached shaping session with real-time Chain capture.\n\n- **start**:
|
|
3804
|
+
description: "Server-controlled coached shaping session with real-time Chain capture.\n\n- **start**: Begin a coached session context only. No bet entry is created yet.\n- **first respond**: Call respond with `betName` to create the draft bet and capture initial problem context.\n- **respond**: Process user input \u2014 scores against 7 shaping rubrics (problem, appetite, elements, architecture, risks, boundaries, done-when), searches for overlap, captures to Chain, returns structured coaching response with phase tracking.\n- **score**: Return the current scorecard without advancing the session.\n- **resume**: Reconstruct session state from an existing bet entry on the Chain.\n- **commit-constellation**: Atomically commit a bet and all its linked draft entries (features, tensions, decisions) in one call. Validates strategy link and required fields before committing anything. Replaces 9-13 sequential commit-entry calls.\n\nThe structured response separates judgment (server) from coaching (agent) per DEC-56. Read the phase, scorecard, and coaching fields to determine what to say next. When captureReady is true, buildContract is auto-generated from Chain governance.",
|
|
3801
3805
|
inputSchema: facilitateSchema,
|
|
3802
3806
|
annotations: {
|
|
3803
3807
|
readOnlyHint: false,
|
|
@@ -3989,8 +3993,12 @@ async function loadConstellationState(betEntryId, betInternalId) {
|
|
|
3989
3993
|
const elementCount = relations.filter(
|
|
3990
3994
|
(r) => r.type === "part_of" && r.toId === internalId
|
|
3991
3995
|
).length;
|
|
3992
|
-
const riskCount = relations.filter(
|
|
3993
|
-
|
|
3996
|
+
const riskCount = relations.filter(
|
|
3997
|
+
(r) => r.type === "constrains" && r.toId === internalId
|
|
3998
|
+
).length;
|
|
3999
|
+
const decisionCount = relations.filter(
|
|
4000
|
+
(r) => r.type === "informs" && r.toId === internalId
|
|
4001
|
+
).length;
|
|
3994
4002
|
return { relations, elementCount, riskCount, decisionCount };
|
|
3995
4003
|
} catch {
|
|
3996
4004
|
return { relations: [], elementCount: 0, riskCount: 0, decisionCount: 0 };
|
|
@@ -4173,208 +4181,166 @@ async function handleStart2(args) {
|
|
|
4173
4181
|
structuredContent: response
|
|
4174
4182
|
};
|
|
4175
4183
|
}
|
|
4176
|
-
async function
|
|
4177
|
-
|
|
4178
|
-
const { userInput, betEntryId: argBetId, dimension: argDimension, capture: rawCapture, source: argSource, betName: argBetName } = args;
|
|
4179
|
-
const source = argSource ?? "user";
|
|
4180
|
-
const captureItems = rawCapture ? Array.isArray(rawCapture) ? rawCapture : [rawCapture] : [];
|
|
4181
|
-
if (!userInput) {
|
|
4182
|
-
return {
|
|
4183
|
-
content: [{ type: "text", text: "`userInput` is required for respond action." }]
|
|
4184
|
-
};
|
|
4185
|
-
}
|
|
4184
|
+
async function processCaptures(opts) {
|
|
4185
|
+
const { captureItems, betEntryId, betDocId, betData } = opts;
|
|
4186
4186
|
const captureErrors = [];
|
|
4187
4187
|
const entriesCreated = [];
|
|
4188
4188
|
let relationsCreated = 0;
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4189
|
+
const capAgentId = getAgentSessionId();
|
|
4190
|
+
const collectionMap = {
|
|
4191
|
+
element: { slug: "features", dataField: "description", relationType: "part_of" },
|
|
4192
|
+
risk: { slug: "tensions", dataField: "description", relationType: "constrains" },
|
|
4193
|
+
decision: { slug: "decisions", dataField: "rationale", relationType: "informs" }
|
|
4194
|
+
};
|
|
4195
|
+
let runningBetData = { ...betData };
|
|
4196
|
+
for (const item of captureItems) {
|
|
4197
|
+
if (item.type === "noGo") {
|
|
4198
|
+
const updatedNoGos = appendNoGo(
|
|
4199
|
+
runningBetData.noGos,
|
|
4200
|
+
{ title: item.name, explanation: item.description }
|
|
4201
|
+
);
|
|
4202
|
+
runningBetData.noGos = updatedNoGos;
|
|
4203
|
+
try {
|
|
4204
|
+
await mcpMutation("chain.updateEntry", {
|
|
4205
|
+
entryId: betEntryId,
|
|
4206
|
+
data: { noGos: updatedNoGos },
|
|
4207
|
+
changeNote: `Added no-go: ${item.name}`
|
|
4208
|
+
});
|
|
4209
|
+
await recordSessionActivity({ entryModified: betDocId });
|
|
4210
|
+
} catch (updErr) {
|
|
4211
|
+
captureErrors.push({
|
|
4212
|
+
operation: "update",
|
|
4213
|
+
detail: `noGos field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
continue;
|
|
4217
|
+
}
|
|
4218
|
+
const mapping = collectionMap[item.type];
|
|
4219
|
+
if (!mapping) continue;
|
|
4220
|
+
let capturedEntryId = null;
|
|
4193
4221
|
try {
|
|
4194
4222
|
const result = await mcpMutation(
|
|
4195
4223
|
"chain.createEntry",
|
|
4196
4224
|
{
|
|
4197
|
-
collectionSlug:
|
|
4198
|
-
name:
|
|
4225
|
+
collectionSlug: mapping.slug,
|
|
4226
|
+
name: item.name,
|
|
4199
4227
|
status: "draft",
|
|
4200
|
-
data: {
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
elements: "",
|
|
4204
|
-
rabbitHoles: "",
|
|
4205
|
-
noGos: "",
|
|
4206
|
-
architecture: "",
|
|
4207
|
-
buildContract: "",
|
|
4208
|
-
description: `Shaping session for: ${betName2}`,
|
|
4209
|
-
status: "shaping",
|
|
4210
|
-
shapingSessionActive: true
|
|
4211
|
-
},
|
|
4212
|
-
createdBy: agentId ? `agent:${agentId}` : "facilitate",
|
|
4213
|
-
sessionId: agentId ?? void 0
|
|
4228
|
+
data: { [mapping.dataField]: item.description },
|
|
4229
|
+
createdBy: capAgentId ? `agent:${capAgentId}` : "facilitate",
|
|
4230
|
+
sessionId: capAgentId ?? void 0
|
|
4214
4231
|
}
|
|
4215
4232
|
);
|
|
4216
|
-
|
|
4233
|
+
capturedEntryId = result.entryId;
|
|
4234
|
+
entriesCreated.push(result.entryId);
|
|
4217
4235
|
await recordSessionActivity({ entryCreated: result.docId });
|
|
4218
|
-
} catch (
|
|
4219
|
-
const msg =
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
const [betEntry, constellation, chainSurfaced] = await Promise.all([
|
|
4227
|
-
loadBetEntry(betId),
|
|
4228
|
-
loadConstellationState(betId),
|
|
4229
|
-
searchChain(userInput, { maxResults: 8 })
|
|
4230
|
-
]);
|
|
4231
|
-
if (!betEntry) {
|
|
4232
|
-
return {
|
|
4233
|
-
content: [{ type: "text", text: `Bet \`${betId}\` not found. Use start to create a session.` }]
|
|
4234
|
-
};
|
|
4235
|
-
}
|
|
4236
|
-
const betData = betEntry.data ?? {};
|
|
4237
|
-
if (captureItems.length > 0) {
|
|
4238
|
-
const capAgentId = getAgentSessionId();
|
|
4239
|
-
const collectionMap = {
|
|
4240
|
-
element: { slug: "features", dataField: "description", relationType: "part_of" },
|
|
4241
|
-
risk: { slug: "tensions", dataField: "description", relationType: "constrains" },
|
|
4242
|
-
decision: { slug: "decisions", dataField: "rationale", relationType: "informs" }
|
|
4243
|
-
};
|
|
4244
|
-
let runningBetData = { ...betData };
|
|
4245
|
-
for (const item of captureItems) {
|
|
4246
|
-
if (item.type === "noGo") {
|
|
4247
|
-
const updatedNoGos = appendNoGo(
|
|
4248
|
-
runningBetData.noGos,
|
|
4249
|
-
{ title: item.name, explanation: item.description }
|
|
4236
|
+
} catch (createErr) {
|
|
4237
|
+
const msg = createErr instanceof Error ? createErr.message : String(createErr);
|
|
4238
|
+
if (msg.includes("Duplicate entry") || msg.includes("already exists")) {
|
|
4239
|
+
const fallback = await findAndLinkExisting(
|
|
4240
|
+
item.name,
|
|
4241
|
+
mapping.slug,
|
|
4242
|
+
betEntryId,
|
|
4243
|
+
mapping.relationType
|
|
4250
4244
|
);
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
data: { noGos: updatedNoGos },
|
|
4256
|
-
changeNote: `Added no-go: ${item.name}`
|
|
4257
|
-
});
|
|
4258
|
-
await recordSessionActivity({ entryModified: betEntry._id });
|
|
4259
|
-
} catch (updErr) {
|
|
4245
|
+
if (fallback) {
|
|
4246
|
+
capturedEntryId = fallback.entryId;
|
|
4247
|
+
entriesCreated.push(fallback.entryId);
|
|
4248
|
+
if (fallback.linked) relationsCreated++;
|
|
4260
4249
|
captureErrors.push({
|
|
4261
|
-
operation: "
|
|
4262
|
-
detail: `
|
|
4250
|
+
operation: "info",
|
|
4251
|
+
detail: `Linked existing ${mapping.slug} entry \`${fallback.entryId}\` instead of creating duplicate.`
|
|
4263
4252
|
});
|
|
4264
|
-
}
|
|
4265
|
-
continue;
|
|
4266
|
-
}
|
|
4267
|
-
const mapping = collectionMap[item.type];
|
|
4268
|
-
if (!mapping) continue;
|
|
4269
|
-
let capturedEntryId = null;
|
|
4270
|
-
try {
|
|
4271
|
-
const result = await mcpMutation(
|
|
4272
|
-
"chain.createEntry",
|
|
4273
|
-
{
|
|
4274
|
-
collectionSlug: mapping.slug,
|
|
4275
|
-
name: item.name,
|
|
4276
|
-
status: "draft",
|
|
4277
|
-
data: { [mapping.dataField]: item.description },
|
|
4278
|
-
createdBy: capAgentId ? `agent:${capAgentId}` : "facilitate",
|
|
4279
|
-
sessionId: capAgentId ?? void 0
|
|
4280
|
-
}
|
|
4281
|
-
);
|
|
4282
|
-
capturedEntryId = result.entryId;
|
|
4283
|
-
entriesCreated.push(result.entryId);
|
|
4284
|
-
await recordSessionActivity({ entryCreated: result.docId });
|
|
4285
|
-
} catch (createErr) {
|
|
4286
|
-
const msg = createErr instanceof Error ? createErr.message : String(createErr);
|
|
4287
|
-
if (msg.includes("Duplicate entry") || msg.includes("already exists")) {
|
|
4288
|
-
const fallback = await findAndLinkExisting(
|
|
4289
|
-
item.name,
|
|
4290
|
-
mapping.slug,
|
|
4291
|
-
betId,
|
|
4292
|
-
mapping.relationType
|
|
4293
|
-
);
|
|
4294
|
-
if (fallback) {
|
|
4295
|
-
capturedEntryId = fallback.entryId;
|
|
4296
|
-
entriesCreated.push(fallback.entryId);
|
|
4297
|
-
if (fallback.linked) relationsCreated++;
|
|
4298
|
-
captureErrors.push({
|
|
4299
|
-
operation: "info",
|
|
4300
|
-
detail: `Linked existing ${mapping.slug} entry \`${fallback.entryId}\` instead of creating duplicate.`
|
|
4301
|
-
});
|
|
4302
|
-
} else {
|
|
4303
|
-
captureErrors.push({ operation: "capture", detail: `${item.type}: ${msg}` });
|
|
4304
|
-
}
|
|
4305
4253
|
} else {
|
|
4306
4254
|
captureErrors.push({ operation: "capture", detail: `${item.type}: ${msg}` });
|
|
4307
4255
|
}
|
|
4256
|
+
} else {
|
|
4257
|
+
captureErrors.push({ operation: "capture", detail: `${item.type}: ${msg}` });
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
if (!capturedEntryId) continue;
|
|
4261
|
+
try {
|
|
4262
|
+
await mcpMutation("chain.createEntryRelation", {
|
|
4263
|
+
fromEntryId: capturedEntryId,
|
|
4264
|
+
toEntryId: betEntryId,
|
|
4265
|
+
type: mapping.relationType
|
|
4266
|
+
});
|
|
4267
|
+
relationsCreated++;
|
|
4268
|
+
await recordSessionActivity({ relationCreated: true });
|
|
4269
|
+
} catch (relErr) {
|
|
4270
|
+
const msg = relErr instanceof Error ? relErr.message : String(relErr);
|
|
4271
|
+
if (!msg.includes("already exists") && !msg.includes("Duplicate")) {
|
|
4272
|
+
captureErrors.push({
|
|
4273
|
+
operation: "relation",
|
|
4274
|
+
detail: `${mapping.relationType} from ${capturedEntryId} to ${betEntryId}: ${msg}`
|
|
4275
|
+
});
|
|
4308
4276
|
}
|
|
4309
|
-
|
|
4277
|
+
}
|
|
4278
|
+
if (item.type === "element") {
|
|
4279
|
+
const updatedElements = appendElement(
|
|
4280
|
+
runningBetData.elements,
|
|
4281
|
+
{ name: item.name, description: item.description, entryId: capturedEntryId }
|
|
4282
|
+
);
|
|
4283
|
+
runningBetData.elements = updatedElements;
|
|
4310
4284
|
try {
|
|
4311
|
-
await mcpMutation("chain.
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4285
|
+
await mcpMutation("chain.updateEntry", {
|
|
4286
|
+
entryId: betEntryId,
|
|
4287
|
+
data: { elements: updatedElements },
|
|
4288
|
+
changeNote: `Added element: ${item.name}`
|
|
4289
|
+
});
|
|
4290
|
+
await recordSessionActivity({ entryModified: betDocId });
|
|
4291
|
+
} catch (updErr) {
|
|
4292
|
+
captureErrors.push({
|
|
4293
|
+
operation: "update",
|
|
4294
|
+
detail: `elements field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
|
|
4315
4295
|
});
|
|
4316
|
-
relationsCreated++;
|
|
4317
|
-
await recordSessionActivity({ relationCreated: true });
|
|
4318
|
-
} catch (relErr) {
|
|
4319
|
-
const msg = relErr instanceof Error ? relErr.message : String(relErr);
|
|
4320
|
-
if (!msg.includes("already exists") && !msg.includes("Duplicate")) {
|
|
4321
|
-
captureErrors.push({
|
|
4322
|
-
operation: "relation",
|
|
4323
|
-
detail: `${mapping.relationType} from ${capturedEntryId} to ${betId}: ${msg}`
|
|
4324
|
-
});
|
|
4325
|
-
}
|
|
4326
4296
|
}
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
}
|
|
4346
|
-
} else if (item.type === "risk") {
|
|
4347
|
-
const updatedRisks = appendRabbitHole(
|
|
4348
|
-
runningBetData.rabbitHoles,
|
|
4349
|
-
{ name: item.name, description: item.description, theme: item.theme, entryId: capturedEntryId }
|
|
4350
|
-
);
|
|
4351
|
-
runningBetData.rabbitHoles = updatedRisks;
|
|
4352
|
-
try {
|
|
4353
|
-
await mcpMutation("chain.updateEntry", {
|
|
4354
|
-
entryId: betId,
|
|
4355
|
-
data: { rabbitHoles: updatedRisks },
|
|
4356
|
-
changeNote: `Added risk: ${item.name}`
|
|
4357
|
-
});
|
|
4358
|
-
await recordSessionActivity({ entryModified: betEntry._id });
|
|
4359
|
-
} catch (updErr) {
|
|
4360
|
-
captureErrors.push({
|
|
4361
|
-
operation: "update",
|
|
4362
|
-
detail: `rabbitHoles field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
|
|
4363
|
-
});
|
|
4364
|
-
}
|
|
4297
|
+
} else if (item.type === "risk") {
|
|
4298
|
+
const updatedRisks = appendRabbitHole(
|
|
4299
|
+
runningBetData.rabbitHoles,
|
|
4300
|
+
{ name: item.name, description: item.description, theme: item.theme, entryId: capturedEntryId }
|
|
4301
|
+
);
|
|
4302
|
+
runningBetData.rabbitHoles = updatedRisks;
|
|
4303
|
+
try {
|
|
4304
|
+
await mcpMutation("chain.updateEntry", {
|
|
4305
|
+
entryId: betEntryId,
|
|
4306
|
+
data: { rabbitHoles: updatedRisks },
|
|
4307
|
+
changeNote: `Added risk: ${item.name}`
|
|
4308
|
+
});
|
|
4309
|
+
await recordSessionActivity({ entryModified: betDocId });
|
|
4310
|
+
} catch (updErr) {
|
|
4311
|
+
captureErrors.push({
|
|
4312
|
+
operation: "update",
|
|
4313
|
+
detail: `rabbitHoles field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
|
|
4314
|
+
});
|
|
4365
4315
|
}
|
|
4366
4316
|
}
|
|
4367
4317
|
}
|
|
4368
|
-
|
|
4318
|
+
return { entriesCreated, relationsCreated, captureErrors };
|
|
4319
|
+
}
|
|
4320
|
+
async function computeAndUpdateScores(opts) {
|
|
4321
|
+
const {
|
|
4322
|
+
betEntryId,
|
|
4323
|
+
betDocId,
|
|
4324
|
+
betData,
|
|
4325
|
+
betEntry,
|
|
4326
|
+
userInput,
|
|
4327
|
+
argDimension,
|
|
4328
|
+
source,
|
|
4329
|
+
captureItems,
|
|
4330
|
+
chainSurfaced,
|
|
4331
|
+
constellation
|
|
4332
|
+
} = opts;
|
|
4333
|
+
const captureErrors = [];
|
|
4334
|
+
const refreshedBet = await loadBetEntry(betEntryId);
|
|
4369
4335
|
const refreshedData = refreshedBet?.data ?? betData;
|
|
4370
|
-
const refreshedConstellation = captureItems.length > 0 ? await loadConstellationState(
|
|
4371
|
-
const sessionDrafts = await loadSessionDrafts(
|
|
4336
|
+
const refreshedConstellation = captureItems.length > 0 ? await loadConstellationState(betEntryId, refreshedBet?._id ?? betEntry._id) : constellation;
|
|
4337
|
+
const sessionDrafts = await loadSessionDrafts(betEntryId, refreshedBet?._id ?? betEntry._id);
|
|
4372
4338
|
const constellationEntryIds = sessionDrafts.map((d) => d.entryId);
|
|
4373
4339
|
const alreadyCheckedOverlap = typeof refreshedData._overlapIds === "string";
|
|
4374
4340
|
let overlap = [];
|
|
4375
4341
|
if (!alreadyCheckedOverlap && captureItems.length === 0) {
|
|
4376
4342
|
const problemText = refreshedData.problem ?? userInput;
|
|
4377
|
-
const overlapResults = await searchChain(problemText, { maxResults: 5, excludeIds: [
|
|
4343
|
+
const overlapResults = await searchChain(problemText, { maxResults: 5, excludeIds: [betEntryId, ...constellationEntryIds] });
|
|
4378
4344
|
overlap = overlapResults.map((r) => ({
|
|
4379
4345
|
entryId: r.entryId,
|
|
4380
4346
|
similarity: "text_match",
|
|
@@ -4428,7 +4394,7 @@ async function handleRespond(args) {
|
|
|
4428
4394
|
}
|
|
4429
4395
|
if (Object.keys(fieldUpdates).length > 0) {
|
|
4430
4396
|
await mcpMutation("chain.updateEntry", {
|
|
4431
|
-
entryId:
|
|
4397
|
+
entryId: betEntryId,
|
|
4432
4398
|
data: fieldUpdates,
|
|
4433
4399
|
changeNote: `Updated ${Object.keys(fieldUpdates).join(", ")} from shaping session`
|
|
4434
4400
|
});
|
|
@@ -4451,12 +4417,10 @@ async function handleRespond(args) {
|
|
|
4451
4417
|
const observation = dimensionResult.satisfied.length > 0 ? `${DIMENSION_LABELS[activeDimension]}: ${dimensionResult.satisfied.join("; ")}` : `${DIMENSION_LABELS[activeDimension]}: needs more detail`;
|
|
4452
4418
|
const pushback = captureItems.length === 0 && overlap.length > 0 ? `${overlap[0].summary} already exists on the Chain. How does your bet differ?` : dimensionResult.missing.length > 0 ? dimensionResult.missing[0] : "";
|
|
4453
4419
|
const suggestedQuestion = dimensionResult.missing.length > 1 ? dimensionResult.missing[1] : dimensionResult.missing.length > 0 ? dimensionResult.missing[0] : `${DIMENSION_LABELS[nextDimension]} is next \u2014 ready to move on?`;
|
|
4454
|
-
const wsCtx = await getWorkspaceContext();
|
|
4455
|
-
const studioUrl = buildStudioUrl(wsCtx.workspaceSlug, betId);
|
|
4456
4420
|
let buildContract;
|
|
4457
4421
|
if (captureReady) {
|
|
4458
4422
|
const contractCtx = {
|
|
4459
|
-
betEntryId
|
|
4423
|
+
betEntryId,
|
|
4460
4424
|
governanceEntries: chainSurfaced.filter((e) => ["principles", "standards", "business-rules"].includes(e.collection)).map((e) => ({ entryId: e.entryId, name: e.name, collection: e.collection })),
|
|
4461
4425
|
relatedDecisions: chainSurfaced.filter((e) => e.collection === "decisions").map((e) => ({ entryId: e.entryId, name: e.name })),
|
|
4462
4426
|
relatedTensions: chainSurfaced.filter((e) => e.collection === "tensions").map((e) => ({ entryId: e.entryId, name: e.name }))
|
|
@@ -4465,7 +4429,7 @@ async function handleRespond(args) {
|
|
|
4465
4429
|
if (refreshedData.buildContract !== buildContract) {
|
|
4466
4430
|
try {
|
|
4467
4431
|
await mcpMutation("chain.updateEntry", {
|
|
4468
|
-
entryId:
|
|
4432
|
+
entryId: betEntryId,
|
|
4469
4433
|
data: { buildContract },
|
|
4470
4434
|
changeNote: "Updated build contract from shaping session"
|
|
4471
4435
|
});
|
|
@@ -4481,7 +4445,7 @@ async function handleRespond(args) {
|
|
|
4481
4445
|
let commitBlockers;
|
|
4482
4446
|
if (captureReady) {
|
|
4483
4447
|
commitBlockers = computeCommitBlockers({
|
|
4484
|
-
betEntryId
|
|
4448
|
+
betEntryId,
|
|
4485
4449
|
betDocId: refreshedBet?._id ?? betEntry._id,
|
|
4486
4450
|
relations: refreshedConstellation.relations,
|
|
4487
4451
|
betData: refreshedData,
|
|
@@ -4489,11 +4453,59 @@ async function handleRespond(args) {
|
|
|
4489
4453
|
});
|
|
4490
4454
|
if (commitBlockers.length === 0) commitBlockers = void 0;
|
|
4491
4455
|
}
|
|
4456
|
+
return {
|
|
4457
|
+
scorecard,
|
|
4458
|
+
scorecardCriteria,
|
|
4459
|
+
phase,
|
|
4460
|
+
activeDimension,
|
|
4461
|
+
nextDimension,
|
|
4462
|
+
dimensionResult,
|
|
4463
|
+
overlap,
|
|
4464
|
+
sessionDrafts,
|
|
4465
|
+
alignment,
|
|
4466
|
+
coaching: { observation, pushback, suggestedQuestion, captureReady },
|
|
4467
|
+
completed,
|
|
4468
|
+
isSmallBatch,
|
|
4469
|
+
refreshedData,
|
|
4470
|
+
scoringCtx,
|
|
4471
|
+
captureErrors,
|
|
4472
|
+
buildContract,
|
|
4473
|
+
commitBlockers
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
4476
|
+
function assembleResponse(opts) {
|
|
4477
|
+
const {
|
|
4478
|
+
betEntryId,
|
|
4479
|
+
betName,
|
|
4480
|
+
workspaceSlug,
|
|
4481
|
+
scorecard,
|
|
4482
|
+
scorecardCriteria,
|
|
4483
|
+
phase,
|
|
4484
|
+
activeDimension,
|
|
4485
|
+
nextDimension,
|
|
4486
|
+
dimensionResult,
|
|
4487
|
+
coaching,
|
|
4488
|
+
overlap,
|
|
4489
|
+
sessionDrafts,
|
|
4490
|
+
alignment,
|
|
4491
|
+
chainSurfaced,
|
|
4492
|
+
scoringCtx,
|
|
4493
|
+
isSmallBatch,
|
|
4494
|
+
completed,
|
|
4495
|
+
refreshedData,
|
|
4496
|
+
buildContract,
|
|
4497
|
+
commitBlockers,
|
|
4498
|
+
entriesCreated,
|
|
4499
|
+
relationsCreated,
|
|
4500
|
+
captureErrors,
|
|
4501
|
+
captureItems
|
|
4502
|
+
} = opts;
|
|
4503
|
+
const studioUrl = buildStudioUrl(workspaceSlug, betEntryId);
|
|
4492
4504
|
const suggested = suggestCaptures(scoringCtx, activeDimension);
|
|
4493
4505
|
const betProblem = refreshedData.problem ?? "";
|
|
4494
|
-
const
|
|
4506
|
+
const responseBetName = refreshedData.description ?? betName;
|
|
4495
4507
|
const elementNames = (refreshedData.elements ?? "").match(/###\s*Element\s*\d+:\s*(.+)/gi)?.map((h) => h.replace(/###\s*Element\s*\d+:\s*/i, "").trim()) ?? [];
|
|
4496
|
-
const investigationBrief = buildInvestigationBrief(phase,
|
|
4508
|
+
const investigationBrief = buildInvestigationBrief(phase, responseBetName, betEntryId, betProblem, elementNames) ?? void 0;
|
|
4497
4509
|
const response = {
|
|
4498
4510
|
version: 2,
|
|
4499
4511
|
phase,
|
|
@@ -4505,15 +4517,15 @@ async function handleRespond(args) {
|
|
|
4505
4517
|
suggestedCaptures: suggested,
|
|
4506
4518
|
sessionDrafts,
|
|
4507
4519
|
coaching: {
|
|
4508
|
-
observation,
|
|
4520
|
+
observation: coaching.observation,
|
|
4509
4521
|
missing: dimensionResult.missing,
|
|
4510
|
-
pushback,
|
|
4511
|
-
suggestedQuestion,
|
|
4512
|
-
captureReady,
|
|
4522
|
+
pushback: coaching.pushback,
|
|
4523
|
+
suggestedQuestion: coaching.suggestedQuestion,
|
|
4524
|
+
captureReady: coaching.captureReady,
|
|
4513
4525
|
nextDimension
|
|
4514
4526
|
},
|
|
4515
4527
|
captured: {
|
|
4516
|
-
betEntryId
|
|
4528
|
+
betEntryId,
|
|
4517
4529
|
studioUrl,
|
|
4518
4530
|
entriesCreated,
|
|
4519
4531
|
relationsCreated
|
|
@@ -4525,6 +4537,7 @@ async function handleRespond(args) {
|
|
|
4525
4537
|
suggestedOrder: activeDimensions(isSmallBatch)
|
|
4526
4538
|
},
|
|
4527
4539
|
buildContract,
|
|
4540
|
+
directive: buildDirective(scorecard, phase, betEntryId, coaching.captureReady, activeDimension, nextDimension) || void 0,
|
|
4528
4541
|
investigationBrief,
|
|
4529
4542
|
commitBlockers,
|
|
4530
4543
|
scorecardCriteria
|
|
@@ -4536,39 +4549,141 @@ async function handleRespond(args) {
|
|
|
4536
4549
|
};
|
|
4537
4550
|
const expectedCaptureType = STRUCTURED_DIMS[activeDimension];
|
|
4538
4551
|
const dataLossWarning = expectedCaptureType && captureItems.length === 0 ? `**WARNING:** You discussed ${activeDimension} but did not use the \`capture\` parameter \u2014 nothing was saved to the bet. Re-send with \`capture={type:"${expectedCaptureType}", name:"...", description:"..."}\` to persist this.` : "";
|
|
4539
|
-
const directive = buildDirective(scorecard, phase, betId, captureReady, activeDimension, nextDimension);
|
|
4540
4552
|
const summaryParts = [
|
|
4541
4553
|
`# ${PHASE_LABELS[phase]} \u2014 ${DIMENSION_LABELS[activeDimension]}`,
|
|
4542
4554
|
"",
|
|
4543
4555
|
dataLossWarning,
|
|
4544
4556
|
`**Score:** ${DIMENSION_LABELS[activeDimension]}: ${scorecard[activeDimension]}/10 \u2014 ${formatCriteriaLine(dimensionResult.criteria)}`,
|
|
4545
4557
|
`**Phase:** ${PHASE_LABELS[phase]}`,
|
|
4546
|
-
observation,
|
|
4547
|
-
pushback ? `**Pushback:** ${pushback}` : "",
|
|
4548
|
-
`**Next:** ${suggestedQuestion}`,
|
|
4549
|
-
captureReady ? "\n**Capture ready** \u2014 the bet has enough shape to finalize." : "",
|
|
4558
|
+
coaching.observation,
|
|
4559
|
+
coaching.pushback ? `**Pushback:** ${coaching.pushback}` : "",
|
|
4560
|
+
`**Next:** ${coaching.suggestedQuestion}`,
|
|
4561
|
+
coaching.captureReady ? "\n**Capture ready** \u2014 the bet has enough shape to finalize." : "",
|
|
4550
4562
|
commitBlockers?.length ? `
|
|
4551
4563
|
\u26A0 **Commit blockers (${commitBlockers.length}):** ${commitBlockers.map((b) => `${b.blocker} \u2192 \`${b.fix}\``).join("; ")}` : "",
|
|
4552
4564
|
entriesCreated.length > 0 ? `**Captured:** ${entriesCreated.join(", ")}` : "",
|
|
4553
4565
|
suggested.length > 0 ? `**Suggest capturing:** ${suggested.map((s) => `${s.type}: "${s.name}"`).join("; ")}` : "",
|
|
4554
4566
|
sessionDrafts.length > 0 ? `**Session drafts (${sessionDrafts.length}):** ${sessionDrafts.map((d) => `\`${d.entryId}\` ${d.name}`).join(", ")}` : "",
|
|
4555
|
-
captureErrors.length > 0 ? `**Warnings:** ${captureErrors.map((e) => e.detail).join("; ")}` : ""
|
|
4556
|
-
directive ? `
|
|
4557
|
-
---
|
|
4558
|
-
## Agent Directive
|
|
4559
|
-
${directive}` : "",
|
|
4560
|
-
investigationBrief ? `
|
|
4561
|
-
## Investigation Brief
|
|
4562
|
-
${investigationBrief.tasks.map((t) => `- **${t.target}:** ${t.query} \u2014 ${t.purpose}`).join("\n")}
|
|
4563
|
-
|
|
4564
|
-
**Proposal guidance:** ${investigationBrief.proposalGuidance}
|
|
4565
|
-
**Reaction prompt:** ${investigationBrief.reactionPrompt}` : ""
|
|
4567
|
+
captureErrors.length > 0 ? `**Warnings:** ${captureErrors.map((e) => e.detail).join("; ")}` : ""
|
|
4566
4568
|
];
|
|
4567
4569
|
return {
|
|
4568
4570
|
content: [{ type: "text", text: summaryParts.filter(Boolean).join("\n") }],
|
|
4569
4571
|
structuredContent: response
|
|
4570
4572
|
};
|
|
4571
4573
|
}
|
|
4574
|
+
async function handleRespond(args) {
|
|
4575
|
+
requireWriteAccess();
|
|
4576
|
+
const { userInput, betEntryId: argBetId, dimension: argDimension, capture: rawCapture, source: argSource, betName: argBetName } = args;
|
|
4577
|
+
const source = argSource ?? "user";
|
|
4578
|
+
const captureItems = rawCapture ? Array.isArray(rawCapture) ? rawCapture : [rawCapture] : [];
|
|
4579
|
+
if (!userInput) {
|
|
4580
|
+
return {
|
|
4581
|
+
content: [{ type: "text", text: "`userInput` is required for respond action." }]
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4584
|
+
let betId = argBetId;
|
|
4585
|
+
if (!betId) {
|
|
4586
|
+
const betName = argBetName ?? "Untitled Bet (Shaping)";
|
|
4587
|
+
const agentId = getAgentSessionId();
|
|
4588
|
+
try {
|
|
4589
|
+
const result = await mcpMutation(
|
|
4590
|
+
"chain.createEntry",
|
|
4591
|
+
{
|
|
4592
|
+
collectionSlug: "bets",
|
|
4593
|
+
name: betName,
|
|
4594
|
+
status: "draft",
|
|
4595
|
+
data: {
|
|
4596
|
+
problem: userInput,
|
|
4597
|
+
appetite: "",
|
|
4598
|
+
elements: "",
|
|
4599
|
+
rabbitHoles: "",
|
|
4600
|
+
noGos: "",
|
|
4601
|
+
architecture: "",
|
|
4602
|
+
buildContract: "",
|
|
4603
|
+
description: `Shaping session for: ${betName}`,
|
|
4604
|
+
status: "shaping",
|
|
4605
|
+
shapingSessionActive: true
|
|
4606
|
+
},
|
|
4607
|
+
createdBy: agentId ? `agent:${agentId}` : "facilitate",
|
|
4608
|
+
sessionId: agentId ?? void 0
|
|
4609
|
+
}
|
|
4610
|
+
);
|
|
4611
|
+
betId = result.entryId;
|
|
4612
|
+
await recordSessionActivity({ entryCreated: result.docId });
|
|
4613
|
+
} catch (err) {
|
|
4614
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4615
|
+
return {
|
|
4616
|
+
content: [{ type: "text", text: `Failed to create bet entry: ${msg}` }],
|
|
4617
|
+
isError: true
|
|
4618
|
+
};
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
const [betEntry, constellation, chainSurfaced] = await Promise.all([
|
|
4622
|
+
loadBetEntry(betId),
|
|
4623
|
+
loadConstellationState(betId),
|
|
4624
|
+
searchChain(userInput, { maxResults: 8 })
|
|
4625
|
+
]);
|
|
4626
|
+
if (!betEntry) {
|
|
4627
|
+
return {
|
|
4628
|
+
content: [{ type: "text", text: `Bet \`${betId}\` not found. Use start to create a session.` }]
|
|
4629
|
+
};
|
|
4630
|
+
}
|
|
4631
|
+
const betData = betEntry.data ?? {};
|
|
4632
|
+
let entriesCreated = [];
|
|
4633
|
+
let relationsCreated = 0;
|
|
4634
|
+
const captureErrors = [];
|
|
4635
|
+
if (captureItems.length > 0) {
|
|
4636
|
+
const capResult = await processCaptures({
|
|
4637
|
+
captureItems,
|
|
4638
|
+
betEntryId: betId,
|
|
4639
|
+
betDocId: betEntry._id,
|
|
4640
|
+
betData
|
|
4641
|
+
});
|
|
4642
|
+
entriesCreated = capResult.entriesCreated;
|
|
4643
|
+
relationsCreated = capResult.relationsCreated;
|
|
4644
|
+
captureErrors.push(...capResult.captureErrors);
|
|
4645
|
+
}
|
|
4646
|
+
const scoreResult = await computeAndUpdateScores({
|
|
4647
|
+
betEntryId: betId,
|
|
4648
|
+
betDocId: betEntry._id,
|
|
4649
|
+
betData,
|
|
4650
|
+
betEntry,
|
|
4651
|
+
userInput,
|
|
4652
|
+
argDimension,
|
|
4653
|
+
source,
|
|
4654
|
+
captureItems,
|
|
4655
|
+
chainSurfaced,
|
|
4656
|
+
constellation
|
|
4657
|
+
});
|
|
4658
|
+
captureErrors.push(...scoreResult.captureErrors);
|
|
4659
|
+
const wsCtx = await getWorkspaceContext();
|
|
4660
|
+
return assembleResponse({
|
|
4661
|
+
betEntryId: betId,
|
|
4662
|
+
betName: betEntry.name,
|
|
4663
|
+
workspaceSlug: wsCtx.workspaceSlug,
|
|
4664
|
+
scorecard: scoreResult.scorecard,
|
|
4665
|
+
scorecardCriteria: scoreResult.scorecardCriteria,
|
|
4666
|
+
phase: scoreResult.phase,
|
|
4667
|
+
activeDimension: scoreResult.activeDimension,
|
|
4668
|
+
nextDimension: scoreResult.nextDimension,
|
|
4669
|
+
dimensionResult: scoreResult.dimensionResult,
|
|
4670
|
+
coaching: scoreResult.coaching,
|
|
4671
|
+
overlap: scoreResult.overlap,
|
|
4672
|
+
sessionDrafts: scoreResult.sessionDrafts,
|
|
4673
|
+
alignment: scoreResult.alignment,
|
|
4674
|
+
chainSurfaced,
|
|
4675
|
+
scoringCtx: scoreResult.scoringCtx,
|
|
4676
|
+
isSmallBatch: scoreResult.isSmallBatch,
|
|
4677
|
+
completed: scoreResult.completed,
|
|
4678
|
+
refreshedData: scoreResult.refreshedData,
|
|
4679
|
+
buildContract: scoreResult.buildContract,
|
|
4680
|
+
commitBlockers: scoreResult.commitBlockers,
|
|
4681
|
+
entriesCreated,
|
|
4682
|
+
relationsCreated,
|
|
4683
|
+
captureErrors,
|
|
4684
|
+
captureItems
|
|
4685
|
+
});
|
|
4686
|
+
}
|
|
4572
4687
|
async function handleScore(args) {
|
|
4573
4688
|
const betId = args.betEntryId;
|
|
4574
4689
|
if (!betId) {
|
|
@@ -4833,7 +4948,7 @@ async function handleCommitConstellation(args) {
|
|
|
4833
4948
|
}
|
|
4834
4949
|
let contradictionWarnings = [];
|
|
4835
4950
|
try {
|
|
4836
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
4951
|
+
const { runContradictionCheck } = await import("./smart-capture-XBOUPHFI.js");
|
|
4837
4952
|
const descField = betData.problem ?? betData.description ?? "";
|
|
4838
4953
|
contradictionWarnings = await runContradictionCheck(
|
|
4839
4954
|
betEntry.name ?? betId,
|
|
@@ -5676,6 +5791,16 @@ function buildInterviewResponse(workspaceName) {
|
|
|
5676
5791
|
}
|
|
5677
5792
|
|
|
5678
5793
|
// src/tools/start.ts
|
|
5794
|
+
async function tryMarkOriented(agentSessionId) {
|
|
5795
|
+
if (!agentSessionId) return { oriented: false, orientationStatus: "no_session" };
|
|
5796
|
+
try {
|
|
5797
|
+
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5798
|
+
setSessionOriented(true);
|
|
5799
|
+
return { oriented: true, orientationStatus: "complete" };
|
|
5800
|
+
} catch {
|
|
5801
|
+
return { oriented: false, orientationStatus: "failed" };
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5679
5804
|
var startSchema = z15.object({
|
|
5680
5805
|
preset: z15.string().optional().describe(
|
|
5681
5806
|
"Collection preset ID to seed (e.g. 'software-product', 'content-business', 'agency', 'saas-api', 'general'). Only used for fresh workspaces. If omitted on a fresh workspace, returns the preset menu."
|
|
@@ -5725,10 +5850,16 @@ function registerStartTools(server) {
|
|
|
5725
5850
|
};
|
|
5726
5851
|
}
|
|
5727
5852
|
if (stage === "blank") {
|
|
5728
|
-
const
|
|
5853
|
+
const { oriented, orientationStatus } = await tryMarkOriented(agentSessionId);
|
|
5854
|
+
const blankResult = buildBlankResponse(wsCtx);
|
|
5729
5855
|
return {
|
|
5730
|
-
content: [{ type: "text", text:
|
|
5731
|
-
structuredContent:
|
|
5856
|
+
content: [{ type: "text", text: blankResult.text }],
|
|
5857
|
+
structuredContent: {
|
|
5858
|
+
...blankResult.structuredContent,
|
|
5859
|
+
oriented,
|
|
5860
|
+
orientationStatus,
|
|
5861
|
+
...agentSessionId ? { sessionId: agentSessionId } : {}
|
|
5862
|
+
}
|
|
5732
5863
|
};
|
|
5733
5864
|
}
|
|
5734
5865
|
if (stage === "seeded") {
|
|
@@ -5752,44 +5883,71 @@ function registerStartTools(server) {
|
|
|
5752
5883
|
}
|
|
5753
5884
|
);
|
|
5754
5885
|
}
|
|
5755
|
-
function
|
|
5886
|
+
function buildBlankResponse(wsCtx) {
|
|
5887
|
+
const instructions = getInterviewInstructions(wsCtx.workspaceName);
|
|
5756
5888
|
const text = [
|
|
5757
5889
|
`# Welcome to ${wsCtx.workspaceName}`,
|
|
5758
5890
|
"",
|
|
5759
|
-
"Your workspace is fresh. Let
|
|
5891
|
+
"Your workspace is fresh. Let's set it up.",
|
|
5892
|
+
"",
|
|
5893
|
+
"## How would you like to start?",
|
|
5894
|
+
"",
|
|
5895
|
+
"Present these options to the user:",
|
|
5896
|
+
"",
|
|
5897
|
+
"**1. Tell me about your product** _(recommended)_",
|
|
5898
|
+
"Ask the user:",
|
|
5899
|
+
`> ${instructions.question1}`,
|
|
5900
|
+
"",
|
|
5901
|
+
"_A sentence or two is enough. This becomes the foundation \u2014 vision and audience \u2014 that makes everything else more relevant._",
|
|
5902
|
+
"",
|
|
5903
|
+
"**2. Scan my codebase**",
|
|
5904
|
+
"Skip the questions and jump straight to reading the project files.",
|
|
5905
|
+
"",
|
|
5906
|
+
"**3. Use a preset**",
|
|
5907
|
+
`Seed collections for a domain. Available: software-product, content-business, agency, saas-api, general.`,
|
|
5908
|
+
"",
|
|
5909
|
+
"---",
|
|
5910
|
+
"",
|
|
5911
|
+
"## Path 1: Interview first (default if user just starts talking)",
|
|
5912
|
+
"",
|
|
5913
|
+
instructions.systemPrompt,
|
|
5914
|
+
"",
|
|
5915
|
+
"After the user answers Q1, extract:",
|
|
5916
|
+
instructions.extractionGuidance,
|
|
5917
|
+
"",
|
|
5918
|
+
instructions.captureInstructions,
|
|
5919
|
+
"Use `autoCommit: false` for all captures \u2014 user confirms before anything is committed.",
|
|
5920
|
+
"",
|
|
5921
|
+
"**Then offer the codebase scan with context:**",
|
|
5922
|
+
`"Now that I know what you're building, I can scan your project files and find technical decisions, features, and conventions that are relevant to **your** product. Want me to?"`,
|
|
5923
|
+
"",
|
|
5924
|
+
"If they say yes, scan README.md, package.json/pyproject.toml/Cargo.toml, and top-level source dirs.",
|
|
5925
|
+
"Infer entries WITH the product context you now have. Present as a numbered list for confirmation.",
|
|
5926
|
+
"Capture confirmed entries with `autoCommit: false`.",
|
|
5927
|
+
"",
|
|
5928
|
+
"## Path 2: Scan first",
|
|
5760
5929
|
"",
|
|
5761
|
-
"
|
|
5762
|
-
"1.
|
|
5763
|
-
"2.
|
|
5930
|
+
"Read these files:",
|
|
5931
|
+
"1. README.md (or equivalent top-level docs)",
|
|
5932
|
+
"2. package.json / pyproject.toml / Cargo.toml (project manifest)",
|
|
5764
5933
|
"3. Top-level source directories and their purpose",
|
|
5765
5934
|
"",
|
|
5766
|
-
"
|
|
5767
|
-
"
|
|
5768
|
-
"- **Key technical decisions** already made (framework, DB, architecture)",
|
|
5769
|
-
"- **Core features** the codebase reveals",
|
|
5770
|
-
"- **Conventions** you notice (naming, patterns, standards)",
|
|
5935
|
+
"Infer 5\u20138 product knowledge entries (product name, tech decisions, features, conventions).",
|
|
5936
|
+
"Present as a numbered list. Ask which to keep. Capture confirmed entries with `autoCommit: false`.",
|
|
5771
5937
|
"",
|
|
5772
|
-
"
|
|
5773
|
-
"```",
|
|
5774
|
-
"1. [Entry name]: [1-sentence description]",
|
|
5775
|
-
"2. ...",
|
|
5776
|
-
"```",
|
|
5938
|
+
"**If the codebase is sparse** (no README, empty project): fall back to Path 1 (ask the user about their product).",
|
|
5777
5939
|
"",
|
|
5778
|
-
|
|
5940
|
+
"_Prefer 5 specific entries over 8 generic ones. Skip anything that would apply to any codebase._",
|
|
5779
5941
|
"",
|
|
5780
|
-
"
|
|
5942
|
+
"## Path 3: Preset",
|
|
5781
5943
|
"",
|
|
5782
|
-
|
|
5944
|
+
"If the user picks a preset, call `start` again with `preset: '<chosen-preset>'`.",
|
|
5783
5945
|
"",
|
|
5784
|
-
|
|
5946
|
+
instructions.qualityNote
|
|
5785
5947
|
].join("\n");
|
|
5786
5948
|
return {
|
|
5787
5949
|
text,
|
|
5788
|
-
structuredContent: {
|
|
5789
|
-
stage: "blank",
|
|
5790
|
-
oriented: false,
|
|
5791
|
-
orientationStatus: "no_session"
|
|
5792
|
-
}
|
|
5950
|
+
structuredContent: { stage: "blank" }
|
|
5793
5951
|
};
|
|
5794
5952
|
}
|
|
5795
5953
|
async function buildSeededResponse(wsCtx, readiness, agentSessionId) {
|
|
@@ -5815,18 +5973,7 @@ async function buildSeededResponse(wsCtx, readiness, agentSessionId) {
|
|
|
5815
5973
|
} else {
|
|
5816
5974
|
lines.push("No gaps detected \u2014 your workspace is filling up nicely. What would you like to work on?");
|
|
5817
5975
|
}
|
|
5818
|
-
|
|
5819
|
-
let orientationStatus = "no_session";
|
|
5820
|
-
if (agentSessionId) {
|
|
5821
|
-
try {
|
|
5822
|
-
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5823
|
-
setSessionOriented(true);
|
|
5824
|
-
oriented = true;
|
|
5825
|
-
orientationStatus = "complete";
|
|
5826
|
-
} catch {
|
|
5827
|
-
orientationStatus = "failed";
|
|
5828
|
-
}
|
|
5829
|
-
}
|
|
5976
|
+
const { oriented, orientationStatus } = await tryMarkOriented(agentSessionId);
|
|
5830
5977
|
return {
|
|
5831
5978
|
text: lines.join("\n"),
|
|
5832
5979
|
structuredContent: {
|
|
@@ -5868,18 +6015,7 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`,
|
|
|
5868
6015
|
skipped.push(`${col.name} (already exists)`);
|
|
5869
6016
|
}
|
|
5870
6017
|
}
|
|
5871
|
-
|
|
5872
|
-
let orientationStatus = "no_session";
|
|
5873
|
-
if (agentSessionId) {
|
|
5874
|
-
try {
|
|
5875
|
-
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
5876
|
-
setSessionOriented(true);
|
|
5877
|
-
oriented = true;
|
|
5878
|
-
orientationStatus = "complete";
|
|
5879
|
-
} catch {
|
|
5880
|
-
orientationStatus = "failed";
|
|
5881
|
-
}
|
|
5882
|
-
}
|
|
6018
|
+
const { oriented, orientationStatus } = await tryMarkOriented(agentSessionId);
|
|
5883
6019
|
const lines = [
|
|
5884
6020
|
`# ${wsCtx.workspaceName} is ready`,
|
|
5885
6021
|
"",
|
|
@@ -6118,18 +6254,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors) {
|
|
|
6118
6254
|
for (const err of errors) lines.push(`- ${err}`);
|
|
6119
6255
|
lines.push("");
|
|
6120
6256
|
}
|
|
6121
|
-
|
|
6122
|
-
let orientationStatus = "no_session";
|
|
6123
|
-
if (agentSessionId) {
|
|
6124
|
-
try {
|
|
6125
|
-
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
6126
|
-
setSessionOriented(true);
|
|
6127
|
-
oriented = true;
|
|
6128
|
-
orientationStatus = "complete";
|
|
6129
|
-
} catch {
|
|
6130
|
-
orientationStatus = "failed";
|
|
6131
|
-
}
|
|
6132
|
-
}
|
|
6257
|
+
const { oriented, orientationStatus } = await tryMarkOriented(agentSessionId);
|
|
6133
6258
|
return {
|
|
6134
6259
|
text: lines.join("\n"),
|
|
6135
6260
|
structuredContent: {
|
|
@@ -8167,15 +8292,20 @@ function registerHealthTools(server) {
|
|
|
8167
8292
|
"Your workspace is fresh \u2014 let's set it up.",
|
|
8168
8293
|
"",
|
|
8169
8294
|
"**Recommended:** call the `start` tool instead of `orient` for the best first-run experience.",
|
|
8170
|
-
"It will guide you through
|
|
8295
|
+
"It will guide you through setting up your workspace \u2014 you can tell me about your product, scan your codebase, or use a preset.",
|
|
8171
8296
|
"",
|
|
8172
8297
|
"Or tell me about your product and I'll start capturing knowledge directly."
|
|
8173
8298
|
];
|
|
8299
|
+
let oriented = false;
|
|
8300
|
+
let orientationStatus = "no_session";
|
|
8174
8301
|
if (agentSessionId) {
|
|
8175
8302
|
try {
|
|
8176
8303
|
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
8177
8304
|
setSessionOriented(true);
|
|
8305
|
+
oriented = true;
|
|
8306
|
+
orientationStatus = "complete";
|
|
8178
8307
|
} catch {
|
|
8308
|
+
orientationStatus = "failed";
|
|
8179
8309
|
}
|
|
8180
8310
|
}
|
|
8181
8311
|
return {
|
|
@@ -8183,7 +8313,8 @@ function registerHealthTools(server) {
|
|
|
8183
8313
|
structuredContent: {
|
|
8184
8314
|
stage: "blank",
|
|
8185
8315
|
readinessScore: readiness?.score ?? 0,
|
|
8186
|
-
oriented
|
|
8316
|
+
oriented,
|
|
8317
|
+
orientationStatus,
|
|
8187
8318
|
redirectHint: "Use the `start` tool for the full guided setup experience."
|
|
8188
8319
|
}
|
|
8189
8320
|
};
|
|
@@ -9320,9 +9451,14 @@ Each scored 0-10 by the server:
|
|
|
9320
9451
|
|
|
9321
9452
|
### Session Flow
|
|
9322
9453
|
1. **Start:** \`facilitate action=start betName="${idea}"\`
|
|
9323
|
-
|
|
9454
|
+
Starts shaping context only (no entry is created yet).
|
|
9455
|
+
|
|
9456
|
+
2. **First respond:** \`facilitate action=respond betName="${idea}" userInput="<user's input>"\`
|
|
9457
|
+
This creates the draft bet and captures the initial problem context.
|
|
9458
|
+
|
|
9459
|
+
Save \`captured.betEntryId\` from the response and reuse it for every subsequent call.
|
|
9324
9460
|
|
|
9325
|
-
|
|
9461
|
+
3. **Respond (repeat):** \`facilitate action=respond betEntryId="..." userInput="<user's input>"\`
|
|
9326
9462
|
Optionally add \`dimension="problem_clarity"\` to target a specific dimension.
|
|
9327
9463
|
|
|
9328
9464
|
**CRITICAL \u2014 Capture is REQUIRED for structured items:**
|
|
@@ -9332,10 +9468,10 @@ Each scored 0-10 by the server:
|
|
|
9332
9468
|
- No-gos: \`capture={type:"noGo", name:"...", description:"..."}\`
|
|
9333
9469
|
Each element, risk, and no-go needs its own \`respond\` call with \`capture\`.
|
|
9334
9470
|
|
|
9335
|
-
|
|
9471
|
+
4. **Score (anytime):** \`facilitate action=score betEntryId="..."\`
|
|
9336
9472
|
Check the scorecard without advancing.
|
|
9337
9473
|
|
|
9338
|
-
|
|
9474
|
+
5. **Resume:** \`facilitate action=resume betEntryId="..."\`
|
|
9339
9475
|
Reconstruct session from Chain state if returning to an existing bet.
|
|
9340
9476
|
|
|
9341
9477
|
### Reading the Response
|
|
@@ -9819,4 +9955,4 @@ export {
|
|
|
9819
9955
|
SERVER_VERSION,
|
|
9820
9956
|
createProductBrainServer
|
|
9821
9957
|
};
|
|
9822
|
-
//# sourceMappingURL=chunk-
|
|
9958
|
+
//# sourceMappingURL=chunk-ADLZPAEI.js.map
|