@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.
@@ -25,11 +25,11 @@ import {
25
25
  startAgentSession,
26
26
  trackWriteTool,
27
27
  translateStaleToolNames
28
- } from "./chunk-PQP27A3R.js";
28
+ } from "./chunk-CYECJTRI.js";
29
29
  import {
30
30
  trackQualityCheck,
31
31
  trackQualityVerdict
32
- } from "./chunk-BIDMZOLE.js";
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-W2IALMJ5.js");
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="<draftId>" name="<name>"`
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': create draft bet and begin session. '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."
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**: Create a draft bet on the Chain and begin a coached session. Returns Studio URL, initial context, and first coaching prompt.\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.",
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((r) => r.type === "constrains").length;
3993
- const decisionCount = relations.filter((r) => r.type === "informs").length;
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 handleRespond(args) {
4177
- requireWriteAccess();
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
- let betId = argBetId;
4190
- if (!betId) {
4191
- const betName2 = argBetName ?? "Untitled Bet (Shaping)";
4192
- const agentId = getAgentSessionId();
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: "bets",
4198
- name: betName2,
4225
+ collectionSlug: mapping.slug,
4226
+ name: item.name,
4199
4227
  status: "draft",
4200
- data: {
4201
- problem: userInput,
4202
- appetite: "",
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
- betId = result.entryId;
4233
+ capturedEntryId = result.entryId;
4234
+ entriesCreated.push(result.entryId);
4217
4235
  await recordSessionActivity({ entryCreated: result.docId });
4218
- } catch (err) {
4219
- const msg = err instanceof Error ? err.message : String(err);
4220
- return {
4221
- content: [{ type: "text", text: `Failed to create bet entry: ${msg}` }],
4222
- isError: true
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
- runningBetData.noGos = updatedNoGos;
4252
- try {
4253
- await mcpMutation("chain.updateEntry", {
4254
- entryId: betId,
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: "update",
4262
- detail: `noGos field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
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
- if (!capturedEntryId) continue;
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.createEntryRelation", {
4312
- fromEntryId: capturedEntryId,
4313
- toEntryId: betId,
4314
- type: mapping.relationType
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
- if (item.type === "element") {
4328
- const updatedElements = appendElement(
4329
- runningBetData.elements,
4330
- { name: item.name, description: item.description, entryId: capturedEntryId }
4331
- );
4332
- runningBetData.elements = updatedElements;
4333
- try {
4334
- await mcpMutation("chain.updateEntry", {
4335
- entryId: betId,
4336
- data: { elements: updatedElements },
4337
- changeNote: `Added element: ${item.name}`
4338
- });
4339
- await recordSessionActivity({ entryModified: betEntry._id });
4340
- } catch (updErr) {
4341
- captureErrors.push({
4342
- operation: "update",
4343
- detail: `elements field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
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
- const refreshedBet = await loadBetEntry(betId);
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(betId, refreshedBet?._id ?? betEntry._id) : constellation;
4371
- const sessionDrafts = await loadSessionDrafts(betId, refreshedBet?._id ?? betEntry._id);
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: [betId, ...constellationEntryIds] });
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: betId,
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: betId,
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: betId,
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: betId,
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 betName = refreshedData.description ?? betEntry.name;
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, betName, betId, betProblem, elementNames) ?? void 0;
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: betId,
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-W2IALMJ5.js");
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 scanResult = buildProjectScanResponse(wsCtx);
5853
+ const { oriented, orientationStatus } = await tryMarkOriented(agentSessionId);
5854
+ const blankResult = buildBlankResponse(wsCtx);
5729
5855
  return {
5730
- content: [{ type: "text", text: scanResult.text }],
5731
- structuredContent: scanResult.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 buildProjectScanResponse(wsCtx) {
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 me get oriented in your codebase.",
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
- "**Please read these files and tell me what you find:**",
5762
- "1. `README.md` (or equivalent \u2014 top-level docs)",
5763
- "2. `package.json` / `pyproject.toml` / `Cargo.toml` (project manifest)",
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
- "From those, infer 5\u20138 product knowledge entries \u2014 things like:",
5767
- "- **Product name and what it does** (1\u20132 sentences)",
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
- "Present them as a numbered list:",
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
- `Then ask: **"Which of these are accurate? Reply with numbers to skip (e.g. 'skip 2, 4') or say 'all good' to capture everything."**`,
5940
+ "_Prefer 5 specific entries over 8 generic ones. Skip anything that would apply to any codebase._",
5779
5941
  "",
5780
- "Once confirmed, call `capture` for each entry with `autoCommit: false` \u2014 the user will review before anything hits the Chain.",
5942
+ "## Path 3: Preset",
5781
5943
  "",
5782
- '**If the codebase is sparse** (no README, empty project, monorepo root): say so and ask "Tell me about your product in a sentence \u2014 what does it do and who is it for?" instead.',
5944
+ "If the user picks a preset, call `start` again with `preset: '<chosen-preset>'`.",
5783
5945
  "",
5784
- "_Prefer 5 specific entries over 8 generic ones. Skip anything that would apply to any codebase._"
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
- let oriented = false;
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
- let oriented = false;
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
- let oriented = false;
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 scanning your codebase and capturing initial knowledge.",
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: true,
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
- Creates a draft bet on the Chain. Returns Studio URL and initial coaching prompt.
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
- 2. **Respond (repeat):** \`facilitate action=respond betEntryId="..." userInput="<user's input>"\`
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
- 3. **Score (anytime):** \`facilitate action=score betEntryId="..."\`
9471
+ 4. **Score (anytime):** \`facilitate action=score betEntryId="..."\`
9336
9472
  Check the scorecard without advancing.
9337
9473
 
9338
- 4. **Resume:** \`facilitate action=resume betEntryId="..."\`
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-AWDD44CN.js.map
9958
+ //# sourceMappingURL=chunk-ADLZPAEI.js.map