@productbrain/mcp 0.0.1-beta.4276 → 0.0.1-beta.4282

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.
@@ -9518,7 +9518,7 @@ function registerOrientTool(server) {
9518
9518
  "orient",
9519
9519
  {
9520
9520
  title: "Orient",
9521
- description: "Workspace orientation and session bootstrapping. Three actions:\n\n- **start**: Universal opener (absorbs `start_pb`) \u2014 say 'Start PB' to begin every session. Stage-aware: fresh workspaces (blank/seeded) get the SKILL-pb-setup body verbatim; active workspaces (grounded/connected) get a standup briefing. Orients the CURRENT session \u2014 it does not create one; for writes, call `session action=start` first.\n- **task**: Task-grounded context loader (the original `orient` behavior). Use after `action=start` to load governance and context for a specific task. Completing orientation unlocks write tools.\n- **record-activation**: Chat-only activation receipt writer (absorbs `record_activation`) \u2014 closes the install-to-activation arc for chat-only surfaces.\n\n**tier** (action=task): Controls payload depth.\n- `summary` (~10 KB) \u2014 compact, calibrated for task-scoped retrieval.\n- `standard` (~256 KB) \u2014 rich, suited to workspace standups.\n- `full` \u2014 complete payload, no cap (use with deliberation).\n\nDefaults: `summary` when `task` is provided; `standard` when `task` is absent. Explicit `tier` always wins.\n\n**mode** (action=task): `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally.\n\n**scope** (action=task): Optional domain scope filtering governance to entries relevant for the specified domain.",
9521
+ description: "Workspace orientation and session bootstrapping. Three actions:\n\n- **start**: Universal opener (absorbs `start_pb`) \u2014 say 'Start PB' to begin every session. Stage-aware: fresh workspaces (blank/seeded) get the SKILL-pb-setup body verbatim; active workspaces (grounded/connected) get a standup briefing. Orients the CURRENT session \u2014 it does not create one; for writes, call `session action=start` first.\n- **task**: Task-grounded context loader (the original `orient` behavior). Use after `action=start` to load governance and context for a specific task. Completing orientation unlocks write tools.\n- **record-activation**: Chat-only activation receipt writer (absorbs `record_activation`) \u2014 closes the install-to-activation arc for chat-only surfaces.\n\n**tier** (action=task): Controls payload depth.\n- `summary` (~10 KB) \u2014 compact, calibrated for task-scoped retrieval.\n- `standard` (~256 KB) \u2014 rich, suited to workspace standups.\n- `full` \u2014 complete payload, no cap, except strategicContext vision/purpose (always server-bounded to ~200 chars + an ellipsis marker \u2014 no uncapped path at any tier). Use with deliberation.\n\nDefaults: `summary` when `task` is provided; `standard` when `task` is absent. Explicit `tier` always wins.\n\n**mode** (action=task): `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally.\n\n**scope** (action=task): Optional domain scope filtering governance to entries relevant for the specified domain.",
9522
9522
  inputSchema: orientSchema,
9523
9523
  // Mixed read/write noun (§3 R3): 'start'/'record-activation' write session state.
9524
9524
  annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false }
@@ -9847,9 +9847,7 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9847
9847
  ...orientView?.taskAlignment ? { taskAlignment: orientView.taskAlignment } : {},
9848
9848
  ...orientView?.degradedPreloads?.length ? { degradedPreloads: orientView.degradedPreloads } : {},
9849
9849
  // WP-621 S1
9850
- // WP-582 B2 round 1 (Codex P2 review, PR #532, T1): omit when `undefined` (old
9851
- // deploy, field never served); keep an explicit `null` for the documented no-row
9852
- // arm — the two states must stay distinguishable to a structuredContent consumer.
9850
+ // WP-582 B2 round 1 (Codex P2 review, PR #532, T1): omit when `undefined` (old deploy, never served); keep explicit `null` for the documented no-row arm — the two states must stay distinguishable to consumers.
9853
9851
  ...orientView?.directionLine !== void 0 ? { directionLine: orientView.directionLine } : {},
9854
9852
  ...orientView?.verdictAskLine !== void 0 ? { verdictAskLine: orientView.verdictAskLine } : {},
9855
9853
  ...orientView?.spineLine !== void 0 ? { spineLine: orientView.spineLine } : {},
@@ -9857,8 +9855,7 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9857
9855
  // PR #538 late review (P2)
9858
9856
  ...orientView?.fetchFailed !== void 0 ? { fetchFailed: orientView.fetchFailed } : {},
9859
9857
  // PR #539 review fix
9860
- // RCRT miss-alarm: machine-readable verdict for structuredContent
9861
- // consumers (parity with the rendered prose alarm).
9858
+ // RCRT miss-alarm: machine-readable verdict for structuredContent consumers (parity with the rendered prose alarm).
9862
9859
  ...orientView?.retrievalMiss ? { retrievalMiss: orientView.retrievalMiss } : {},
9863
9860
  orientationStatus: orientationStatus2,
9864
9861
  nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
@@ -9886,6 +9883,9 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9886
9883
  }
9887
9884
  let fullCoherenceSnapshot;
9888
9885
  if (isLowReadiness) {
9886
+ const scLR = !task ? orientView?.strategicContext : void 0;
9887
+ const scLRLines = scLR ? [scLR.vision && `**Vision:** ${scLR.vision}`, scLR.purpose && `**Purpose:** ${scLR.purpose}`].filter((l) => Boolean(l)) : [];
9888
+ if (scLRLines.length > 0) lines.push("## Strategic Context", ...scLRLines, "");
9889
9889
  const captureBehaviorNote = (readiness?.governanceMode ?? wsCtx?.governanceMode ?? "open") === "open" ? "_In Open mode, captures are accepted automatically unless you ask me to keep them as drafts._" : "_Everything stays as a draft until you confirm._";
9890
9890
  const gaps = readiness.gaps ?? [];
9891
9891
  if (gaps.length > 0) {
@@ -9935,12 +9935,8 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9935
9935
  lines.push("## Strategic Context");
9936
9936
  if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
9937
9937
  if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
9938
- if (sc.productAreaCount != null && sc.productAreaCount > 0) {
9939
- lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
9940
- }
9941
- if (sc.playingFieldCount != null && sc.playingFieldCount > 0) {
9942
- lines.push(`**Playing field (${sc.playingFieldCount}):** ${(sc.playingField ?? []).join(", ")}`);
9943
- }
9938
+ if (sc.productAreaCount != null && sc.productAreaCount > 0) lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
9939
+ if (sc.playingFieldCount != null && sc.playingFieldCount > 0) lines.push(`**Playing field (${sc.playingFieldCount}):** ${(sc.playingField ?? []).join(", ")}`);
9944
9940
  const currentWP = sc.currentWorkPackage;
9945
9941
  const wpSingularFull = getCollectionLabel("work_package", "singular", vocabCtx);
9946
9942
  const wpPluralFull = getCollectionLabel("work_package", "plural", vocabCtx);
@@ -15888,6 +15884,15 @@ function registerShapeTools(server) {
15888
15884
 
15889
15885
  // src/tools/question.ts
15890
15886
  import { z as z34 } from "zod/v3";
15887
+
15888
+ // src/lib/strip.ts
15889
+ var ANSI_AND_CONTROL_RE2 = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*\x07|\x1b[^[\]0-9;A-Za-z]?|[\x00-\x08\x0b-\x1f\x7f]/g;
15890
+ function stripControlChars(str) {
15891
+ if (!str) return str;
15892
+ return str.replace(ANSI_AND_CONTROL_RE2, "");
15893
+ }
15894
+
15895
+ // src/tools/question.ts
15891
15896
  var QUESTION_ACTIONS = ["create", "adopt", "assign", "snooze", "decline", "answer", "force-close", "list"];
15892
15897
  var questionSchema = z34.object({
15893
15898
  action: z34.enum(QUESTION_ACTIONS).describe(
@@ -15942,7 +15947,7 @@ async function displayName(id) {
15942
15947
  if (!id) return void 0;
15943
15948
  try {
15944
15949
  const entry = await kernelQuery("chain.getEntry", { id });
15945
- return entry?.name;
15950
+ return entry?.name ? stripControlChars(entry.name) : void 0;
15946
15951
  } catch {
15947
15952
  return void 0;
15948
15953
  }
@@ -15998,7 +16003,7 @@ async function handleQuestionAssign(entryId, toRole, toPerson) {
15998
16003
  const isReassign = Boolean(toRole || toPerson);
15999
16004
  let message;
16000
16005
  if (isReassign) {
16001
- const who = toPerson ? result2.ownerPersonName ?? result2.ownerPersonId ?? "the target" : await displayName(result2.ownerRoleId) ?? result2.ownerRoleId ?? "the target";
16006
+ const who = toPerson ? stripControlChars(result2.ownerPersonName ?? "") || result2.ownerPersonId || "the target" : await displayName(result2.ownerRoleId) ?? result2.ownerRoleId ?? "the target";
16002
16007
  message = `${entryId} reassigned to ${who}. They'll see it at their next session.`;
16003
16008
  } else {
16004
16009
  message = `${entryId} is yours now.`;
@@ -16066,7 +16071,7 @@ async function handleQuestionAnswer(entryId, text, answerEntryId) {
16066
16071
  const resolvedEntryId = await resolveEntryRef(entryId, "Entry");
16067
16072
  const resolvedAnswerEntryId = answerEntryId ? await resolveEntryRef(answerEntryId, "Answer entry") : void 0;
16068
16073
  const result2 = await kernelMutation("question.answer", { entryId: resolvedEntryId, text, answerEntryId: resolvedAnswerEntryId });
16069
- const askerName = result2.askerName ?? "The asker";
16074
+ const askerName = (result2.askerName ? stripControlChars(result2.askerName) : "") || "The asker";
16070
16075
  const pendingNote = result2.answerPending ? " The answer is a draft awaiting accept." : "";
16071
16076
  const message = result2.idempotent ? result2.processedVia === "declined" || result2.processedVia === "force_closed" ? `${entryId} is already processed (${result2.processedVia === "declined" ? "declined" : "force-closed"}) \u2014 no change.` : `${entryId} is already answered \u2014 no change.` : `Answered. ${askerName} will see the outcome at their next session (and in pb question list --mine).${pendingNote}`;
16072
16077
  return successResult(message, message, result2);
@@ -16094,8 +16099,8 @@ async function handleQuestionList(mine) {
16094
16099
  return successResult(message2, message2, { ...result2, action: "list" });
16095
16100
  }
16096
16101
  const lines = rows.map((r) => {
16097
- const outcomeSuffix = mine && r.outcome ? ` \u2014 ${r.outcome}` : "";
16098
- return `[${r.entryId}] ${r.question} \u2014 ${r.stateLabel} \u2014 ${r.why} \u2014 ${r.domain} \u2014 ${r.withLabel} \u2014 ${r.ageDays}d${outcomeSuffix}`;
16102
+ const outcomeSuffix = mine && r.outcome ? ` \u2014 ${stripControlChars(r.outcome)}` : "";
16103
+ return `[${stripControlChars(r.entryId)}] ${stripControlChars(r.question)} \u2014 ${stripControlChars(r.stateLabel)} \u2014 ${stripControlChars(r.why)} \u2014 ${stripControlChars(r.domain)} \u2014 ${stripControlChars(r.withLabel)} \u2014 ${r.ageDays}d${outcomeSuffix}`;
16099
16104
  });
16100
16105
  const truncationNote = result2.truncated ? `
16101
16106
  (${mine ? "showing your most recent questions only \u2014 older ones exist but are not shown" : "this list may be incomplete \u2014 some obligations may not be shown"})` : "";
@@ -17082,4 +17087,4 @@ export {
17082
17087
  createProductBrainServer,
17083
17088
  initFeatureFlags
17084
17089
  };
17085
- //# sourceMappingURL=chunk-WGTVDUBC.js.map
17090
+ //# sourceMappingURL=chunk-MEQC3IGR.js.map