@productbrain/mcp 0.0.1-beta.10528 → 0.0.1-beta.10538

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.
@@ -45,7 +45,7 @@ import {
45
45
  trackQualityVerdict,
46
46
  trackSessionCaptureRate,
47
47
  trackZeroCaptureAuditFired
48
- } from "./chunk-VQ6P44A3.js";
48
+ } from "./chunk-XZMCPLDR.js";
49
49
 
50
50
  // src/server.ts
51
51
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -4294,6 +4294,25 @@ function formatInviteSentence(reply, clean) {
4294
4294
  const who = `${clean(reply.person)} [${reply.personId}]`;
4295
4295
  return reply.inPlace ? `Invited ${who} at ${clean(reply.email)}; they keep every role they already hold.` : `Invited ${who} at ${clean(reply.email)} as a new person.`;
4296
4296
  }
4297
+ var ORGANISATION_VALIDATION_REFUSALS = /* @__PURE__ */ new Set([
4298
+ "duplicate_membership",
4299
+ "last_team_lead",
4300
+ "child_team_invalid",
4301
+ "parent_team_invalid",
4302
+ "existing_parent_invalid",
4303
+ "hierarchy_ambiguous",
4304
+ "self_parent",
4305
+ "hierarchy_cycle",
4306
+ "hierarchy_too_deep",
4307
+ "hierarchy_too_large",
4308
+ "hierarchy_repair_required",
4309
+ "archived_parent_authority_invalid",
4310
+ "role_still_held",
4311
+ "move_not_needed",
4312
+ "no_pending_move",
4313
+ "why_required",
4314
+ "role_unplaced"
4315
+ ]);
4297
4316
 
4298
4317
  // src/tools/people.ts
4299
4318
  var PEOPLE_ACTIONS = ["invite", "remove"];
@@ -11970,10 +11989,10 @@ function registerQuestionTools(server) {
11970
11989
 
11971
11990
  // src/tools/role.ts
11972
11991
  import { z as z32 } from "zod/v3";
11973
- var ROLE_ACTIONS = ["accountable", "seat", "unseat"];
11992
+ var ROLE_ACTIONS = ["accountable", "seat", "unseat", "release_move", "accept_move", "refuse_move"];
11974
11993
  var roleSchema = z32.object({
11975
11994
  action: z32.enum(ROLE_ACTIONS).describe(
11976
- "'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage. 'seat': put a person in this role. 'unseat': take this role from a person."
11995
+ "'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage. 'seat': put a person in this role. 'unseat': take this role from a person. 'release_move' / 'accept_move' / 'refuse_move': move a role or team to a team with another Team Lead."
11977
11996
  ),
11978
11997
  roleId: z32.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."),
11979
11998
  canonicalKey: z32.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
@@ -11986,8 +12005,10 @@ var roleSchema = z32.object({
11986
12005
  "'seat': the name of a person who has no login yet; a placeholder person is created once and reused for the same exact name. Refused when the name belongs to someone with an account."
11987
12006
  ),
11988
12007
  teamId: z32.string().max(200).optional().describe(
11989
- "'seat' / 'unseat': the team, by chain id or entry id. Only needed for Team Lead, which lives in every team; any other role is seated in its home team."
11990
- )
12008
+ "'seat' / 'unseat': the team, by chain id or entry id. Only needed for Team Lead, which lives in every team; any other role is seated in its home team. 'release_move': the team it moves to."
12009
+ ),
12010
+ childId: z32.string().max(200).optional().describe("'release_move' / 'accept_move' / 'refuse_move': the role or team that moves, by chain id or entry id."),
12011
+ why: z32.string().max(1e3).optional().describe("'refuse_move': why the move is refused; it becomes a tension for the old team's Team Lead.")
11991
12012
  });
11992
12013
  var accountableVariant = z32.object({
11993
12014
  action: z32.literal("accountable"),
@@ -12009,11 +12030,24 @@ var unseatVariant = z32.object({
12009
12030
  person: z32.string().max(200),
12010
12031
  teamId: z32.string().max(200).optional()
12011
12032
  });
12012
- var roleActionUnion = z32.discriminatedUnion("action", [accountableVariant, seatVariant, unseatVariant]);
12033
+ var releaseMoveVariant = z32.object({ action: z32.literal("release_move"), childId: z32.string().max(200), teamId: z32.string().max(200) });
12034
+ var acceptMoveVariant = z32.object({ action: z32.literal("accept_move"), childId: z32.string().max(200) });
12035
+ var refuseMoveVariant = z32.object({ action: z32.literal("refuse_move"), childId: z32.string().max(200), why: z32.string().max(1e3) });
12036
+ var roleActionUnion = z32.discriminatedUnion("action", [
12037
+ accountableVariant,
12038
+ seatVariant,
12039
+ unseatVariant,
12040
+ releaseMoveVariant,
12041
+ acceptMoveVariant,
12042
+ refuseMoveVariant
12043
+ ]);
12013
12044
  var ROLE_ACTION_SPECS = {
12014
12045
  accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." },
12015
12046
  seat: { params: ["roleId", "person", "newPersonName", "teamId"], description: "roleId is required, plus exactly one of person or newPersonName; teamId only for Team Lead." },
12016
- unseat: { params: ["roleId", "person", "teamId"], description: "roleId and person are required; teamId only for Team Lead." }
12047
+ unseat: { params: ["roleId", "person", "teamId"], description: "roleId and person are required; teamId only for Team Lead." },
12048
+ release_move: { params: ["childId", "teamId"], description: "childId and teamId (the team it moves to) are required." },
12049
+ accept_move: { params: ["childId"], description: "childId is required." },
12050
+ refuse_move: { params: ["childId", "why"], description: "childId and why are required." }
12017
12051
  };
12018
12052
  function formatHolders(result2) {
12019
12053
  if (result2.holders.length === 0) return [` holders: none${result2.holdersTruncated ? " found, but the membership scan is incomplete" : ""}`];
@@ -12094,6 +12128,29 @@ function handleRoleSeat(roleId, person, newPersonName, teamId) {
12094
12128
  function handleRoleUnseat(roleId, person, teamId) {
12095
12129
  return runSeatAction("unseat", "organisation.unseatFromRole", { roleId, person, teamId });
12096
12130
  }
12131
+ function callMove(action, params, sessionId) {
12132
+ if (action === "release_move") {
12133
+ return kernelMutation("organisation.hierarchy.release", { childRef: params.childId, toParentRef: params.teamId, sessionId });
12134
+ }
12135
+ if (action === "accept_move") return kernelMutation("organisation.hierarchy.accept", { childRef: params.childId, sessionId });
12136
+ return kernelMutation("organisation.hierarchy.refuse", { childRef: params.childId, why: params.why, sessionId });
12137
+ }
12138
+ async function handleMove(action, params) {
12139
+ try {
12140
+ requireWriteAccess();
12141
+ const raw = await callMove(action, params, getAgentSessionId());
12142
+ if (raw.outcome === "refused") {
12143
+ const recovery = authorityRecovery(raw.refusal) ?? "Ask the Team Lead the refusal names.";
12144
+ const message2 = `Refused: ${sanitizeSingleLineField(raw.refusal.reason)} ${recovery}`;
12145
+ const code = ORGANISATION_VALIDATION_REFUSALS.has(raw.refusal.code) ? "VALIDATION_ERROR" : "PERMISSION_DENIED";
12146
+ return failureResult(message2, code, message2, recovery, void 0, raw);
12147
+ }
12148
+ const message = raw.replaced ? `${raw.line} It replaces the release toward ${sanitizeSingleLineField(raw.replaced)}.` : raw.line;
12149
+ return successResult(message, message, raw);
12150
+ } catch (err) {
12151
+ return roleErrorResult(err, action, params);
12152
+ }
12153
+ }
12097
12154
  function roleErrorResult(err, action, params = {}) {
12098
12155
  const classified = classifyError(err);
12099
12156
  const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
@@ -12111,13 +12168,16 @@ function registerRoleTools(server) {
12111
12168
  const roleHandlers = {
12112
12169
  accountable: (data) => handleRoleAccountable(data.roleId, data.canonicalKey, data.limit, data.cursor),
12113
12170
  seat: (data) => handleRoleSeat(data.roleId, data.person, data.newPersonName, data.teamId),
12114
- unseat: (data) => handleRoleUnseat(data.roleId, data.person, data.teamId)
12171
+ unseat: (data) => handleRoleUnseat(data.roleId, data.person, data.teamId),
12172
+ release_move: (data) => handleMove("release_move", data),
12173
+ accept_move: (data) => handleMove("accept_move", data),
12174
+ refuse_move: (data) => handleMove("refuse_move", data)
12115
12175
  };
12116
12176
  server.registerTool(
12117
12177
  "role",
12118
12178
  {
12119
12179
  title: "Role",
12120
- description: "Workspace roles \u2014 who is accountable for what, and who holds it. Three actions:\n\n- **accountable**: what this role owns (`explicit` \u2014 the canonical ownership row for objective/key_result/tension, data.ownerRoleId for domain), reports on (`reporting`, data.reporterRoleId \u2014 key results only, a separate fact from ownership), and \u2014 always `not-computed` today, never faked as empty \u2014 inherits via Team-Lead vacancy coverage. Also lists `holders`.\n- **seat**: put a person in this role, by person id or email, or by `newPersonName` for someone with no login yet (a placeholder person, created once per exact name). The role's home team is used; name `teamId` only for Team Lead. A held role refuses a second holder and names the holder; the person keeps their other roles in the team. Needs the team's Team Lead.\n- **unseat**: take this role from a person; their other roles in the team stay. The last active Team Lead of a team is refused. Invite a person, or take them out of a team, with the `people` tool.",
12180
+ description: "Workspace roles \u2014 who is accountable for what, who holds it, and where it sits. Six actions:\n\n- **accountable**: what this role owns (`explicit` \u2014 the canonical ownership row for objective/key_result/tension, data.ownerRoleId for domain), reports on (`reporting`, data.reporterRoleId \u2014 key results only, a separate fact from ownership), and \u2014 always `not-computed` today, never faked as empty \u2014 inherits via Team-Lead vacancy coverage. Also lists `holders`.\n- **seat**: put a person in this role, by person id or email, or by `newPersonName` for someone with no login yet (a placeholder person, created once per exact name). The role's home team is used; name `teamId` only for Team Lead. A held role refuses a second holder and names the holder; the person keeps their other roles in the team. Needs the team's Team Lead.\n- **unseat**: take this role from a person; their other roles in the team stay. The last active Team Lead of a team is refused. Invite a person, or take them out of a team, with the `people` tool.\n- **release_move** / **accept_move** / **refuse_move**: move a role or team (`childId`) to a team whose Team Lead is another seat. Acting as Team Lead of its current team, release it toward `teamId`; acting as Team Lead of that team, accept it, or refuse it with `why` (it stays, and a tension goes to its current team's Team Lead).",
12121
12181
  inputSchema: roleSchema,
12122
12182
  // The hints describe the whole tool, so they say the most it can do: unseat removes a role and can
12123
12183
  // delete a membership row (destructive), and a repeated seat still writes history and audit rows
@@ -12765,4 +12825,4 @@ export {
12765
12825
  createProductBrainServer,
12766
12826
  initFeatureFlags
12767
12827
  };
12768
- //# sourceMappingURL=chunk-DX2W5QVT.js.map
12828
+ //# sourceMappingURL=chunk-EIYC3GYH.js.map