@productbrain/mcp 0.0.1-beta.5543 → 0.0.1-beta.5561

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.
@@ -802,7 +802,8 @@ var FIELD_TYPE_DEFAULTS = {
802
802
  "array": [],
803
803
  "json": null,
804
804
  "date": null,
805
- "person": null
805
+ "person": null,
806
+ "role": null
806
807
  };
807
808
 
808
809
  // src/lib/formatFieldGuidance.ts
@@ -15334,6 +15335,9 @@ function stripControlChars(str) {
15334
15335
  if (!str) return str;
15335
15336
  return str.replace(ANSI_AND_CONTROL_RE2, "");
15336
15337
  }
15338
+ function sanitizeSingleLineField(str) {
15339
+ return stripControlChars(str).replace(/\s+/g, " ").trim();
15340
+ }
15337
15341
 
15338
15342
  // src/tools/question.ts
15339
15343
  var QUESTION_ACTIONS = ["create", "adopt", "assign", "snooze", "decline", "answer", "force-close", "list"];
@@ -15598,6 +15602,93 @@ function registerQuestionTools(server) {
15598
15602
  );
15599
15603
  }
15600
15604
 
15605
+ // src/tools/role.ts
15606
+ import { z as z34 } from "zod/v3";
15607
+ var ROLE_ACTIONS = ["accountable"];
15608
+ var roleSchema = z34.object({
15609
+ action: z34.enum(ROLE_ACTIONS).describe("'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage."),
15610
+ roleId: z34.string().max(200).optional().describe("The role, by the human chain id `chain.getEntry` or `pb get` would print for it, or a raw entry id. Required for 'accountable'."),
15611
+ canonicalKey: z34.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
15612
+ limit: z34.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
15613
+ cursor: z34.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor.")
15614
+ });
15615
+ var accountableVariant = z34.object({
15616
+ action: z34.literal("accountable"),
15617
+ roleId: z34.string().max(200),
15618
+ canonicalKey: z34.string().max(200).optional(),
15619
+ limit: z34.number().int().positive().max(200).optional(),
15620
+ cursor: z34.number().optional()
15621
+ });
15622
+ var roleActionUnion = z34.discriminatedUnion("action", [accountableVariant]);
15623
+ var ROLE_ACTION_SPECS = {
15624
+ accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." }
15625
+ };
15626
+ function formatRow(row) {
15627
+ const id = row.entryId ?? row.id;
15628
+ return ` ${id} ${sanitizeSingleLineField(row.name)} [${row.canonicalKey ?? "?"}/${row.status}]`;
15629
+ }
15630
+ function formatSection(label, rows, truncated, cursorHint) {
15631
+ if (rows.length === 0) return [` ${label}: not recorded yet`];
15632
+ const lines = [` ${label}:`, ...rows.map(formatRow)];
15633
+ if (truncated) lines.push(` (more exist \u2014 ${cursorHint ?? "raise limit (capped at 200, no cursor for this list)"})`);
15634
+ return lines;
15635
+ }
15636
+ function formatRoleAccountable(result2) {
15637
+ const roleLabel = `${sanitizeSingleLineField(result2.role.name)} (${result2.role.entryId ?? result2.role.id})`;
15638
+ const explicitCursorHint = result2.nextCursor !== null ? `raise limit or continue with cursor ${result2.nextCursor}` : "raise limit";
15639
+ return [
15640
+ `${roleLabel} \u2014 accountability:`,
15641
+ ...formatSection("explicit (owns)", result2.explicit, result2.explicitTruncated, explicitCursorHint),
15642
+ ...formatSection("reporting (reports on)", result2.reporting, result2.reportingTruncated),
15643
+ ` inherited: not-computed \u2014 ${result2.inheritedNotComputedReason}`
15644
+ ].join("\n");
15645
+ }
15646
+ async function handleRoleAccountable(roleId, canonicalKey, limit, cursor) {
15647
+ try {
15648
+ const raw = await kernelQuery("chain.listByRole", { roleId, canonicalKey, limit, cursor });
15649
+ const result2 = raw;
15650
+ const message = formatRoleAccountable(result2);
15651
+ return successResult(message, message, result2);
15652
+ } catch (err) {
15653
+ return roleErrorResult(err, "accountable", { roleId, canonicalKey, limit, cursor });
15654
+ }
15655
+ }
15656
+ function roleErrorResult(err, action, params = {}) {
15657
+ const classified = classifyError(err);
15658
+ const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
15659
+ return failureResult(
15660
+ classified.message,
15661
+ classified.code,
15662
+ classified.message,
15663
+ classified.recovery ?? "Use action='accountable' with roleId set to a real role's chain id or entry id.",
15664
+ classified.availableActions ?? [{ tool: "role", description: `Retry ${action}`, parameters: { action, ...definedParams } }],
15665
+ classified.diagnostics
15666
+ );
15667
+ }
15668
+ function registerRoleTools(server) {
15669
+ const roleHandlers = {
15670
+ accountable: (data) => handleRoleAccountable(data.roleId, data.canonicalKey, data.limit, data.cursor)
15671
+ };
15672
+ server.registerTool(
15673
+ "role",
15674
+ {
15675
+ title: "Role",
15676
+ description: "Workspace roles \u2014 who is accountable for what. One action:\n\n- **accountable**: what this role owns (`explicit`, data.ownerRoleId), reports on (`reporting`, data.reporterRoleId \u2014 key results and tensions only, a separate fact from ownership), and \u2014 always `not-computed` today, never faked as empty \u2014 inherits via Team-Lead vacancy coverage.",
15677
+ inputSchema: roleSchema,
15678
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
15679
+ },
15680
+ thinWrapper(async (args) => {
15681
+ const parsed = parseOrFail(roleSchema, args);
15682
+ if (!parsed.ok) return parsed.result;
15683
+ const { action } = parsed.data;
15684
+ return runWithToolContext(
15685
+ { tool: "role", action },
15686
+ () => dispatchDiscriminated("role", roleActionUnion, parsed.data, ROLE_ACTION_SPECS, roleHandlers)
15687
+ );
15688
+ })
15689
+ );
15690
+ }
15691
+
15601
15692
  // src/resources/index.ts
15602
15693
  import { existsSync as existsSync3 } from "fs";
15603
15694
  import { dirname, join, resolve as resolve4 } from "path";
@@ -15607,7 +15698,7 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
15607
15698
  // src/resources/agentCheatsheet.ts
15608
15699
  var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
15609
15700
 
15610
- ## Core Tools (Serves 13 default compound tools; 2 more (chain, chain-review) behind PB_MODULES=gitchain \u2014 map retired, L29)
15701
+ ## Core Tools (Serves 14 default compound tools; 2 more (chain, chain-review) behind PB_MODULES=gitchain \u2014 map retired, L29)
15611
15702
  | Tool | Purpose | Key params |
15612
15703
  |---|---|---|
15613
15704
  | \`orient\` | Workspace context, governance, active work packages, session start | \`action\`: start, task, record-activation |
@@ -15623,6 +15714,7 @@ var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
15623
15714
  | \`feedback\` | Submit product feedback (any key, no session required); \`list\` reads back your own workspace's feedback (no gate); vendor triage: queue / note / group / status | \`action\`: submit, list, queue, note, group, status |
15624
15715
  | \`shape\` | Review / disposition write-shape (single-concern split) advisories | \`action\`: list, show, agree, dismiss |
15625
15716
  | \`question\` | Routed questions \u2014 create/adopt, own, snooze, decline, answer, force-close | \`action\`: create, adopt, assign, snooze, decline, answer, force-close |
15717
+ | \`role\` | What a role is accountable for \u2014 owns, reports on, and (not yet computed) inherits via Team-Lead vacancy coverage | \`action\`: accountable |
15626
15718
 
15627
15719
  ## Collection Prefixes
15628
15720
  GLO (glossary), BR (business-rules), PRI (principles), STD (standards),
@@ -16109,12 +16201,12 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
16109
16201
  }
16110
16202
 
16111
16203
  // src/prompts/index.ts
16112
- import { z as z34 } from "zod/v3";
16204
+ import { z as z35 } from "zod/v3";
16113
16205
  function registerPrompts(server) {
16114
16206
  server.prompt(
16115
16207
  "review-against-rules",
16116
16208
  "Review code or a design decision against all business rules for a given domain. Fetches the rules and asks you to do a structured compliance review.",
16117
- { domain: z34.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
16209
+ { domain: z35.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
16118
16210
  async ({ domain }) => {
16119
16211
  const entries = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
16120
16212
  const rules = entries.filter((e) => e.data?.domain === domain);
@@ -16167,7 +16259,7 @@ Provide a structured review with a compliance status for each rule (COMPLIANT /
16167
16259
  server.prompt(
16168
16260
  "name-check",
16169
16261
  "Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
16170
- { names: z34.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
16262
+ { names: z35.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
16171
16263
  async ({ names }) => {
16172
16264
  const terms = await kernelQuery("chain.listEntries", { collectionSlug: "glossary" });
16173
16265
  const glossaryContext = terms.map(
@@ -16203,7 +16295,7 @@ Format as a table: Name | Status | Canonical Form | Action Needed`
16203
16295
  server.prompt(
16204
16296
  "draft-decision-record",
16205
16297
  "Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
16206
- { context: z34.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
16298
+ { context: z35.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
16207
16299
  async ({ context }) => {
16208
16300
  const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
16209
16301
  const sorted = [...recentDecisions].sort((a, b) => (b.data?.date ?? "") > (a.data?.date ?? "") ? 1 : -1).slice(0, 5);
@@ -16241,8 +16333,8 @@ After drafting, I can log it using the capture tool with collection "decisions".
16241
16333
  "draft-rule-from-context",
16242
16334
  "Draft a new business rule from an observation or discovery made while coding. Fetches existing rules for the domain to ensure consistency.",
16243
16335
  {
16244
- observation: z34.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
16245
- domain: z34.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
16336
+ observation: z35.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
16337
+ domain: z35.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
16246
16338
  },
16247
16339
  async ({ observation, domain }) => {
16248
16340
  const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
@@ -16308,7 +16400,7 @@ var INSTRUCTIONS = [
16308
16400
  "- **Self-documenting**: orient and server instructions teach agents how PB works. Cursor rules supplement but don't replace.",
16309
16401
  "",
16310
16402
  "### Tool Rename Notice (WP-484 S3, one release)",
16311
- "Serves 13 default compound tools (WP-559 adds `shape` \u2014 review/disposition for write-shape advisories; WP-638 S3 adds `question` \u2014 routed-question routing/ownership/lifecycle); 2 more (chain, chain-review) behind PB_MODULES=gitchain.",
16403
+ "Serves 14 default compound tools (WP-559 adds `shape` \u2014 review/disposition for write-shape advisories; WP-638 S3 adds `question` \u2014 routed-question routing/ownership/lifecycle; WP-730 S2 adds `role` \u2014 role accountability); 2 more (chain, chain-review) behind PB_MODULES=gitchain.",
16312
16404
  "Old standalone names are gone \u2014 no alias window (ASM-43: zero external consumers). Map: `start_pb`\u2192`orient action=start`, `record_activation`\u2192`orient action=record-activation`, `session-wrapup`\u2192`session action=wrapup-review|wrapup-commit`, `facilitate`\u2192`session action=resume|commit-constellation`, `update-entry`\u2192`entries action=update`, `commit-entry`\u2192`entries action=commit`, `get-history`\u2192`entries action=history`, `move-entry`\u2192`entries action=move`, `verify-entry`\u2192`entries action=verify`, `graph`\u2192`relations action=find|suggest`, `documents`\u2192`context action=last-verified-brief`, `labels`\u2192`collections action=label-*`, `verify`\u2192`quality action=verify-chain`, `audit`\u2192`quality action=audit`, `health`\u2192`workspace action=check|whoami|status|self-test`, `get-usage-summary`\u2192`workspace action=usage`, `governance-proposals`\u2192`workspace action=proposals-*`, `skills`\u2192`workflows action=load-skill`, `chain-version`\u2192`chain action=version.*`, `chain-branch`\u2192`chain-review action=branch.*`.",
16313
16405
  "",
16314
16406
  "## Your Workspace Principles",
@@ -16380,6 +16472,7 @@ function createProductBrainServer() {
16380
16472
  registerFeedbackTool(server);
16381
16473
  registerShapeTools(server);
16382
16474
  registerQuestionTools(server);
16475
+ registerRoleTools(server);
16383
16476
  if (enabledModules.has("gitchain")) registerGitChainTools(server);
16384
16477
  registerResources(server);
16385
16478
  registerPrompts(server);
@@ -16519,4 +16612,4 @@ export {
16519
16612
  createProductBrainServer,
16520
16613
  initFeatureFlags
16521
16614
  };
16522
- //# sourceMappingURL=chunk-P4YFJRPQ.js.map
16615
+ //# sourceMappingURL=chunk-Y2JXPTBG.js.map