@productbrain/mcp 0.0.1-beta.9650 → 0.0.1-beta.9674

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.
@@ -43,7 +43,7 @@ import {
43
43
  trackQualityVerdict,
44
44
  trackSessionCaptureRate,
45
45
  trackZeroCaptureAuditFired
46
- } from "./chunk-GLXQMNAS.js";
46
+ } from "./chunk-ZKRYGHNU.js";
47
47
 
48
48
  // src/server.ts
49
49
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -939,7 +939,8 @@ function buildCaptureForRealNextAction(payload) {
939
939
  autoCommit,
940
940
  sourceRef,
941
941
  sourceExcerpt,
942
- ownerRoleEntryId
942
+ ownerRoleEntryId,
943
+ team
943
944
  } = payload;
944
945
  return [{
945
946
  tool: "capture",
@@ -955,7 +956,8 @@ function buildCaptureForRealNextAction(payload) {
955
956
  ...autoCommit !== void 0 ? { autoCommit } : {},
956
957
  ...sourceRef ? { sourceRef } : {},
957
958
  ...sourceExcerpt ? { sourceExcerpt } : {},
958
- ...ownerRoleEntryId ? { ownerRoleEntryId } : {}
959
+ ...ownerRoleEntryId ? { ownerRoleEntryId } : {},
960
+ ...team ? { team } : {}
959
961
  }
960
962
  }];
961
963
  }
@@ -1194,10 +1196,10 @@ var captureSchema = z4.object({
1194
1196
  sourceExcerpt: z4.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data."),
1195
1197
  // WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
1196
1198
  preview: z4.boolean().optional().describe("If true, validates the capture without writing. Returns what would happen. Default false."),
1197
- // WP-513: explicit role to create AS OWNER of (rung 2 only). WP-753 O1b (DEC-1715):
1198
- // ownerTeamEntryId is deleted — the server takes the team you hold the role in (root first, else the shallowest),
1199
- // and an unnamed create resolves a default owner itself instead of landing ownerless.
1200
- ownerRoleEntryId: z4.string().max(200).optional().describe("Owning role entry ID/ref (rung 2); you must hold it, and its team is the one you hold it in (root first, else the shallowest).")
1199
+ // WP-513 / WP-753 O1b (DEC-1715): explicit owning role (rung 2); its team is the one you hold it in. Unnamed: a default owner.
1200
+ ownerRoleEntryId: z4.string().max(200).optional().describe("Owning role entry ID/ref (rung 2); you must hold it, and its team is the one you hold it in (root first, else the shallowest)."),
1201
+ // TASK-681 (DEC-1976, DEC-1977): where a new role or team sits, forwarded as createEntry's teamRef; the kernel places it.
1202
+ team: z4.string().max(200).optional().describe("For a role: the team it is born in. For a team: its parent team. Entry ID or ref; defaults to the root team.")
1201
1203
  });
1202
1204
  var captureClassifierSchema = z4.object({
1203
1205
  enabled: z4.boolean(),
@@ -1507,9 +1509,9 @@ var captureCompoundSchema = z4.object({
1507
1509
  preview: z4.boolean().optional().describe("If true, validates without writing."),
1508
1510
  suggestOnly: z4.never({ invalid_type_error: SUGGEST_ONLY_REMOVED }).optional().describe(SUGGEST_ONLY_REMOVED),
1509
1511
  // TASK-608: refused, never stripped into a write.
1510
- // WP-513: explicit role to create AS OWNER of (rung 2 only). WP-753 O1b: ownerTeamEntryId
1511
- // deleted — team is the one you hold the role in (root first, else the shallowest).
1512
- ownerRoleEntryId: z4.string().max(200).optional().describe("Owning role (rung-2); you must hold it; its team is the one you hold it in (root first, else the shallowest).")
1512
+ // WP-513 / WP-753 O1b: explicit owning role (rung 2); its team is the one you hold it in. TASK-681: `team` places a new role or team.
1513
+ ownerRoleEntryId: z4.string().max(200).optional().describe("Owning role (rung-2); you must hold it; its team is the one you hold it in (root first, else the shallowest)."),
1514
+ team: z4.string().max(200).optional().describe("For a role: the team it is born in. For a team: its parent team. Entry ID or ref; defaults to the root team.")
1513
1515
  });
1514
1516
  var captureSingleVariant = captureSchema.extend({ action: z4.literal("capture") });
1515
1517
  var captureActionUnion = z4.discriminatedUnion("action", [
@@ -1551,7 +1553,7 @@ All other collections get an ENT-{random} ID and sensible defaults.
1551
1553
  })
1552
1554
  );
1553
1555
  }
1554
- async function handleCapture(server, { collection, name, description, context, canonicalKey, data: userData, why, links, sourceRef, sourceExcerpt, preview, ownerRoleEntryId }) {
1556
+ async function handleCapture(server, { collection, name, description, context, canonicalKey, data: userData, why, links, sourceRef, sourceExcerpt, preview, ownerRoleEntryId, team }) {
1555
1557
  requireWriteAccess();
1556
1558
  const timingStart = Date.now();
1557
1559
  const wsCtx = await getWorkspaceContext();
@@ -1701,8 +1703,9 @@ async function handleCapture(server, { collection, name, description, context, c
1701
1703
  ...sourceRef ? { sourceRef } : {},
1702
1704
  ...sourceExcerpt ? { sourceExcerpt } : {},
1703
1705
  ...preview ? { preview: true } : {},
1704
- // WP-513: explicit rung-2 owner override. WP-753 O1b: team derives server-side.
1706
+ // WP-513: explicit rung-2 owner override (WP-753 O1b: its team derives server-side). TASK-681: `team` places a role or team.
1705
1707
  ...ownerRoleEntryId ? { ownerRoleEntryId } : {},
1708
+ ...team ? { teamRef: team } : {},
1706
1709
  // WP-475 E1 (Codex P2 — CLI parity): user links are known UPFRONT, so the
1707
1710
  // post-relations re-evaluation below owns the single LLM run — defer the
1708
1711
  // create-time LLM schedule (deterministic, mirrors `pb capture --link`).
@@ -1752,7 +1755,8 @@ async function handleCapture(server, { collection, name, description, context, c
1752
1755
  links,
1753
1756
  sourceRef,
1754
1757
  sourceExcerpt,
1755
- ownerRoleEntryId
1758
+ ownerRoleEntryId,
1759
+ team
1756
1760
  })
1757
1761
  );
1758
1762
  if (result2.contract) {
@@ -4049,7 +4053,7 @@ async function handleDelete(from, to, type) {
4049
4053
  }
4050
4054
 
4051
4055
  // src/tools/context.ts
4052
- import { z as z16 } from "zod/v3";
4056
+ import { z as z17 } from "zod/v3";
4053
4057
 
4054
4058
  // src/tools/documents.ts
4055
4059
  import { z as z13 } from "zod/v3";
@@ -4130,7 +4134,7 @@ This row pre-dates snapshot capture (legacy backfill), so no summary is availabl
4130
4134
  }
4131
4135
 
4132
4136
  // src/tools/contextLookups.ts
4133
- import { z as z15 } from "zod/v3";
4137
+ import { z as z16 } from "zod/v3";
4134
4138
 
4135
4139
  // src/tools/graph.ts
4136
4140
  import { z as z14 } from "zod/v3";
@@ -4250,45 +4254,198 @@ async function handleFind(entryId, direction) {
4250
4254
  };
4251
4255
  }
4252
4256
 
4257
+ // src/tools/people.ts
4258
+ import { z as z15 } from "zod/v3";
4259
+
4260
+ // src/lib/seatSentence.ts
4261
+ function formatSeatSentence(action, reply, clean) {
4262
+ if (reply.outcome === "refused") {
4263
+ return `Refused: ${reply.refusal?.reason ?? reply.refusal?.code ?? "not allowed"}${reply.refusal?.requiredAction ? ` ${reply.refusal.requiredAction}` : ""}`;
4264
+ }
4265
+ const who = `${clean(reply.person ?? "")}${reply.personStatus && reply.personStatus !== "active" ? ` (${clean(reply.personStatus)})` : ""}`;
4266
+ const roleLabel2 = `${clean(reply.roleName ?? "")} (${reply.role ?? ""})`;
4267
+ const teamLabel = clean(reply.teamName ?? "");
4268
+ if (action === "seat") {
4269
+ const id = reply.personId ? ` [${reply.personId}]` : "";
4270
+ return `${reply.created ? "Seated" : "Confirmed"} ${who}${id} as ${roleLabel2} in ${teamLabel}.`;
4271
+ }
4272
+ return reply.removed ? `Unseated ${who} from ${roleLabel2} in ${teamLabel}.` : `${who} did not hold ${roleLabel2} in ${teamLabel}; nothing changed.`;
4273
+ }
4274
+ function formatInviteSentence(reply, clean) {
4275
+ const who = `${clean(reply.person)} [${reply.personId}]`;
4276
+ 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.`;
4277
+ }
4278
+
4279
+ // src/tools/people.ts
4280
+ var PEOPLE_ACTIONS = ["invite", "remove"];
4281
+ var peopleSchema = z15.object({
4282
+ action: z15.enum(PEOPLE_ACTIONS).describe("'invite': send a login link by email. 'remove': take a person out of a team."),
4283
+ email: z15.string().max(320).optional().describe("'invite': where the login link goes. Required for 'invite'."),
4284
+ person: z15.string().max(320).optional().describe(
4285
+ "'invite': a placeholder's person id, instead of newPersonName. 'remove': the person, by person id or exact email."
4286
+ ),
4287
+ newPersonName: z15.string().max(120).optional().describe("'invite': the name of a new person to invite, instead of person."),
4288
+ teamId: z15.string().max(200).optional().describe("'remove': the team, by chain id or entry id. Required for 'remove'.")
4289
+ });
4290
+ var inviteVariant = z15.object({
4291
+ action: z15.literal("invite"),
4292
+ email: z15.string().max(320),
4293
+ person: z15.string().max(320).optional(),
4294
+ newPersonName: z15.string().max(120).optional()
4295
+ });
4296
+ var removeVariant = z15.object({
4297
+ action: z15.literal("remove"),
4298
+ person: z15.string().max(320),
4299
+ teamId: z15.string().max(200)
4300
+ });
4301
+ var peopleActionUnion = z15.discriminatedUnion("action", [inviteVariant, removeVariant]);
4302
+ var PEOPLE_ACTION_SPECS = {
4303
+ invite: { params: ["email", "person", "newPersonName"], description: "email is required, plus exactly one of person (a placeholder's id) or newPersonName." },
4304
+ remove: { params: ["person", "teamId"], description: "person and teamId are required." }
4305
+ };
4306
+ async function handlePeopleInvite(email, person, newPersonName) {
4307
+ const params = { email, person, newPersonName };
4308
+ try {
4309
+ requireWriteAccess();
4310
+ const result2 = await kernelMutation("people.invite", {
4311
+ email,
4312
+ targetPersonId: person,
4313
+ displayName: newPersonName,
4314
+ sessionId: getAgentSessionId()
4315
+ });
4316
+ const message = formatInviteSentence(result2, sanitizeSingleLineField);
4317
+ return successResult(message, message, result2);
4318
+ } catch (err) {
4319
+ return peopleErrorResult(err, "invite", params);
4320
+ }
4321
+ }
4322
+ async function handlePeopleRemove(person, teamId) {
4323
+ try {
4324
+ requireWriteAccess();
4325
+ const result2 = await kernelMutation("organisation.removeMembership", {
4326
+ targetPersonRef: person,
4327
+ teamRef: teamId,
4328
+ sessionId: getAgentSessionId()
4329
+ });
4330
+ if (result2.outcome === "refused") {
4331
+ const { reason, requiredAction } = result2.refusal;
4332
+ const message2 = `Refused: ${reason}${requiredAction ? ` ${requiredAction}` : ""}`;
4333
+ return failureResult(
4334
+ message2,
4335
+ "PERMISSION_DENIED",
4336
+ message2,
4337
+ requiredAction ?? "Ask the team's Team Lead to remove them.",
4338
+ void 0,
4339
+ result2
4340
+ );
4341
+ }
4342
+ const who = sanitizeSingleLineField(result2.person);
4343
+ const message = result2.removed ? `Removed ${who} from ${result2.team}.` : `${who} was not assigned to ${result2.team}; nothing changed.`;
4344
+ return successResult(message, message, result2);
4345
+ } catch (err) {
4346
+ return peopleErrorResult(err, "remove", { person, teamId });
4347
+ }
4348
+ }
4349
+ async function handlePeopleList() {
4350
+ try {
4351
+ const { people, truncated } = await kernelQuery("people.list", {});
4352
+ const lines = people.map((p) => `${sanitizeSingleLineField(p.displayName)} <${p.email ? sanitizeSingleLineField(p.email) : "no email"}> \xB7 ${p.status} \xB7 ${p.role}`);
4353
+ if (people.length === 0) lines.push("No people in this workspace.");
4354
+ if (truncated) lines.push("List cut at 200 live people; the full list is on Settings, Members in the web app.");
4355
+ const text = lines.join("\n");
4356
+ return successResult(text, text, { people, truncated, total: people.length });
4357
+ } catch (err) {
4358
+ const classified = classifyError(err);
4359
+ return failureResult(
4360
+ classified.message,
4361
+ classified.code,
4362
+ classified.message,
4363
+ classified.recovery ?? "Check the workspace key, then call context action=people again.",
4364
+ classified.availableActions,
4365
+ classified.diagnostics
4366
+ );
4367
+ }
4368
+ }
4369
+ function peopleErrorResult(err, action, params) {
4370
+ const classified = classifyError(err);
4371
+ const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
4372
+ const fallbackActions = retryIsFutile(classified.code) ? void 0 : [{ tool: "people", description: `Retry ${action}`, parameters: { action, ...definedParams } }];
4373
+ return failureResult(
4374
+ classified.message,
4375
+ classified.code,
4376
+ classified.message,
4377
+ classified.recovery ?? `Fix the input the message names and call action='${action}' again.`,
4378
+ classified.availableActions ?? fallbackActions,
4379
+ classified.diagnostics
4380
+ );
4381
+ }
4382
+ function registerPeopleTools(server) {
4383
+ const peopleHandlers = {
4384
+ invite: (data) => handlePeopleInvite(data.email, data.person, data.newPersonName),
4385
+ remove: (data) => handlePeopleRemove(data.person, data.teamId)
4386
+ };
4387
+ server.registerTool(
4388
+ "people",
4389
+ {
4390
+ title: "People",
4391
+ description: "People in the workspace. Two actions:\n\n- **invite**: send a login link to `email`. Give `person` (a placeholder's id, as `role action=seat` printed it) to invite that person in place: they keep every role they hold. Or give `newPersonName` to invite someone new. A person who already has a login or an invite is refused. Needs a workspace owner or admin.\n- **remove**: take `person` out of the team `teamId`; every role they hold there goes with it. To take one role, use `role action=unseat`. Needs the team's Team Lead.",
4392
+ inputSchema: peopleSchema,
4393
+ // TASK-677 (DEC-1981, DEC-74): invite emails an address outside the workspace (open world);
4394
+ // remove deletes a membership row and every role on it (destructive); neither is idempotent.
4395
+ annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: true }
4396
+ },
4397
+ thinWrapper(async (args) => {
4398
+ const parsed = parseOrFail(peopleSchema, args);
4399
+ if (!parsed.ok) return parsed.result;
4400
+ const { action } = parsed.data;
4401
+ return runWithToolContext(
4402
+ { tool: "people", action },
4403
+ () => dispatchDiscriminated("people", peopleActionUnion, parsed.data, PEOPLE_ACTION_SPECS, peopleHandlers)
4404
+ );
4405
+ })
4406
+ );
4407
+ }
4408
+
4253
4409
  // src/tools/contextLookups.ts
4254
- var LOOKUP_ACTIONS = ["get", "batch", "history", "list", "search", "find"];
4255
- var statusFilterSchema = z15.union([z15.string().max(200), z15.array(z15.enum(ENTRY_STATUS_READ_WORDS)).max(5)]);
4256
- var LOOKUP_ACTION_DESCRIBE = "'get': one entry in full by ID. 'batch': up to 20 entries by ID. 'history': audit trail for an entry. 'list': browse entries with filters (accepted by default). 'search': full-text search across entries. 'find': an entry's direct relations (direction: incoming|outgoing|both, default both). ";
4257
- var LOOKUP_TOOL_LINES = "- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **history**: Audit trail for an entry.\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n- **find**: An entry's direct relations, incoming and outgoing. NOT full-text search (use search).\n";
4410
+ var LOOKUP_ACTIONS = ["get", "batch", "history", "list", "search", "find", "people"];
4411
+ var statusFilterSchema = z16.union([z16.string().max(200), z16.array(z16.enum(ENTRY_STATUS_READ_WORDS)).max(5)]);
4412
+ var LOOKUP_ACTION_DESCRIBE = "'get': one entry in full by ID. 'batch': up to 20 entries by ID. 'history': audit trail for an entry. 'list': browse entries with filters (accepted by default). 'search': full-text search across entries. 'find': an entry's direct relations (direction: incoming|outgoing|both, default both). 'people': the workspace's members with name, email and status. ";
4413
+ var LOOKUP_TOOL_LINES = "- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **history**: Audit trail for an entry.\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n- **find**: An entry's direct relations, incoming and outgoing. NOT full-text search (use search).\n- **people**: The workspace's members: name, email, status, role. Max 200.\n";
4258
4414
  var lookupParams = {
4259
- entryIds: z15.array(z15.string().max(200)).min(1).max(20).optional().describe("For 'batch': entry IDs, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
4260
- collection: z15.string().max(200).optional().describe("For 'list'/'search': collection slug, e.g. 'glossary', 'tracking-events'."),
4261
- query: z15.string().min(2).max(500).optional().describe("For 'search': search text (min 2 characters)."),
4415
+ entryIds: z16.array(z16.string().max(200)).min(1).max(20).optional().describe("For 'batch': entry IDs, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
4416
+ collection: z16.string().max(200).optional().describe("For 'list'/'search': collection slug, e.g. 'glossary', 'tracking-events'."),
4417
+ query: z16.string().min(2).max(500).optional().describe("For 'search': search text (min 2 characters)."),
4262
4418
  // 'active'/'accepted'/'current' are the same trust level (DEC-1575/DEC-1788) — all enumerated, never one substituted.
4263
4419
  status: statusFilterSchema.optional().describe(
4264
4420
  `For 'list': defaults to accepted entries (active/accepted/current); use status='draft' to discover drafts. One lifecycle or category value (${ENTRY_STATUS_READ_WORDS.join("|")}). For 'search': one value OR an array of up to 5 (e.g. ['active','accepted']).`
4265
4421
  ),
4266
- tag: z15.string().max(200).optional().describe("For 'list': filter by internal tag."),
4267
- label: z15.string().max(200).optional().describe("For 'list': filter by label slug \u2014 matches entries across all collections.")
4422
+ tag: z16.string().max(200).optional().describe("For 'list': filter by internal tag."),
4423
+ label: z16.string().max(200).optional().describe("For 'list': filter by label slug \u2014 matches entries across all collections.")
4268
4424
  };
4269
4425
  var lookupVariants = [
4270
- z15.object({ action: z15.literal("get"), entryId: z15.string().max(200) }),
4271
- z15.object({ action: z15.literal("batch"), entryIds: z15.array(z15.string().max(200)).min(1).max(20) }),
4272
- z15.object({ action: z15.literal("history"), entryId: z15.string().max(200) }),
4273
- z15.object({
4274
- action: z15.literal("list"),
4275
- collection: z15.string().max(200).optional(),
4276
- status: z15.string().max(200).optional(),
4426
+ z16.object({ action: z16.literal("get"), entryId: z16.string().max(200) }),
4427
+ z16.object({ action: z16.literal("batch"), entryIds: z16.array(z16.string().max(200)).min(1).max(20) }),
4428
+ z16.object({ action: z16.literal("history"), entryId: z16.string().max(200) }),
4429
+ z16.object({
4430
+ action: z16.literal("list"),
4431
+ collection: z16.string().max(200).optional(),
4432
+ status: z16.string().max(200).optional(),
4277
4433
  // one status word; the flat union serves search
4278
- tag: z15.string().max(200).optional(),
4279
- label: z15.string().max(200).optional()
4434
+ tag: z16.string().max(200).optional(),
4435
+ label: z16.string().max(200).optional()
4280
4436
  }),
4281
- z15.object({
4282
- action: z15.literal("search"),
4283
- query: z15.string().min(2).max(500),
4284
- collection: z15.string().max(200).optional(),
4437
+ z16.object({
4438
+ action: z16.literal("search"),
4439
+ query: z16.string().min(2).max(500),
4440
+ collection: z16.string().max(200).optional(),
4285
4441
  status: statusFilterSchema.optional()
4286
4442
  }),
4287
- z15.object({
4288
- action: z15.literal("find"),
4289
- entryId: z15.string().max(200),
4290
- direction: z15.enum(["incoming", "outgoing", "both"]).optional().default("both")
4291
- })
4443
+ z16.object({
4444
+ action: z16.literal("find"),
4445
+ entryId: z16.string().max(200),
4446
+ direction: z16.enum(["incoming", "outgoing", "both"]).optional().default("both")
4447
+ }),
4448
+ z16.object({ action: z16.literal("people") })
4292
4449
  ];
4293
4450
  var LOOKUP_ACTION_SPECS = {
4294
4451
  get: { params: ["entryId"], description: "entryId is required." },
@@ -4296,7 +4453,8 @@ var LOOKUP_ACTION_SPECS = {
4296
4453
  history: { params: ["entryId"], description: "entryId is required." },
4297
4454
  list: { params: ["collection", "status", "tag", "label"], description: "Browse accepted entries by default; status='draft' lists drafts; status is one word. All params optional." },
4298
4455
  search: { params: ["query", "collection", "status"], description: "Full-text search; query is required (min 2 chars)." },
4299
- find: { params: ["entryId", "direction"], description: "entryId is required." }
4456
+ find: { params: ["entryId", "direction"], description: "entryId is required." },
4457
+ people: { params: [], description: "No params." }
4300
4458
  };
4301
4459
  function lookupHandlers(server) {
4302
4460
  return {
@@ -4306,7 +4464,8 @@ function lookupHandlers(server) {
4306
4464
  list: (data) => handleList(data.collection, data.status, data.tag, data.label),
4307
4465
  search: (data) => handleSearch(server, data.query, data.collection, data.status),
4308
4466
  // logs progress to the client
4309
- find: (data) => handleFind(data.entryId, data.direction ?? "both")
4467
+ find: (data) => handleFind(data.entryId, data.direction ?? "both"),
4468
+ people: () => handlePeopleList()
4310
4469
  };
4311
4470
  }
4312
4471
 
@@ -4322,90 +4481,90 @@ function epistemicCollectionHint(collectionName) {
4322
4481
  return "";
4323
4482
  }
4324
4483
  var CONTEXT_ACTIONS = [...LOOKUP_ACTIONS, "gather", "build", "neighborhood", "changes", "chain", "cross-cut", "incremental", "brief", "last-verified-brief"];
4325
- var contextSchema = z16.object({
4484
+ var contextSchema = z17.object({
4326
4485
  // provenance: neighborhood BET-142; changes/chain/cross-cut/incremental/brief BET-239 (E4, E6)
4327
- action: z16.enum(CONTEXT_ACTIONS).describe(
4486
+ action: z17.enum(CONTEXT_ACTIONS).describe(
4328
4487
  LOOKUP_ACTION_DESCRIBE + "'gather': assemble knowledge context (entry graph, task auto-load, journey mode, or graph mode). 'build': structured build spec for an entry. 'neighborhood': typed graph neighborhood for an entry \u2014 blocking chain, dependencies, parent context, tensions, staleness. 'changes': entries modified and relations created since a timestamp. Requires 'since' parameter. 'chain': directed traversal along one relation type to depth 4. Requires entryId. Optional: direction, relationType, maxHops (1-4). 'cross-cut': structural aggregation \u2014 all relations of a given type grouped by source collection. Requires 'relationType' parameter. 'incremental': delta since last brief run for a skill. Requires 'skill' parameter. Returns only entries changed since the skill's last brief. 'brief': compound intelligence query. Requires 'briefType' parameter: 'steering' (changes + structure + delta + readiness), 'confidence' (changes + active bets \u2014 use the pb CLI's `tensions list` for tensions), or 'delta' (changes + relations since timestamp). Optional 'since' for delta type. 'last-verified-brief': fetch the most recent verified brief snapshot for a (templateId, scopeKey) pair (absorbs documents action=get-last-verified-brief). Requires templateId and scopeKey."
4329
4488
  ),
4330
- entryId: z16.string().max(200).optional().describe("For 'get'/'history'/'find'/'build'/'neighborhood'/'chain': entry ID, e.g. '<PREFIX>-<n>'. For 'gather': optional (entry-graph mode)."),
4489
+ entryId: z17.string().max(200).optional().describe("For 'get'/'history'/'find'/'build'/'neighborhood'/'chain': entry ID, e.g. '<PREFIX>-<n>'. For 'gather': optional (entry-graph mode)."),
4331
4490
  ...lookupParams,
4332
- mapEntryId: z16.string().max(200).optional().describe(
4491
+ mapEntryId: z17.string().max(200).optional().describe(
4333
4492
  "For 'gather': journey map entry ID for journey-aware context. Returns context organised by journey stage. Takes precedence over entryId when both are supplied. Example: '<PREFIX>-<n>'."
4334
4493
  ),
4335
- task: z16.string().max(2e3).optional().describe("For 'gather': natural-language task description for loading task-relevant governance, binding constraints, and supporting context."),
4336
- since: z16.string().max(200).optional().describe(
4494
+ task: z17.string().max(2e3).optional().describe("For 'gather': natural-language task description for loading task-relevant governance, binding constraints, and supporting context."),
4495
+ since: z17.string().max(200).optional().describe(
4337
4496
  "For 'changes': ISO 8601 timestamp \u2014 returns entries/relations modified since this time. For 'brief' briefType='delta': optional custom timestamp. Example: '2026-03-24T00:00:00Z'."
4338
4497
  ),
4339
- direction: z16.enum(["outgoing", "incoming", "both"]).optional().describe("For 'chain': 'outgoing' follows relations from source, 'incoming' to source (default outgoing). For 'find': incoming|outgoing|both (default both)."),
4340
- relationType: z16.string().max(200).optional().describe(
4498
+ direction: z17.enum(["outgoing", "incoming", "both"]).optional().describe("For 'chain': 'outgoing' follows relations from source, 'incoming' to source (default outgoing). For 'find': incoming|outgoing|both (default both)."),
4499
+ relationType: z17.string().max(200).optional().describe(
4341
4500
  "Relation type filter. For 'chain': optional filter to traverse only this relation type. For 'cross-cut': required \u2014 scans all relations of this type across the workspace. Examples: 'part_of', 'informs', 'governs', 'depends_on'."
4342
4501
  ),
4343
- mode: z16.enum(["search", "graph"]).default("search").optional().describe("For gather: 'search' (default) or 'graph' (enhanced with provenance paths). Ignored when mapEntryId is provided."),
4344
- maxHops: z16.number().min(1).max(4).default(2).describe("Relation traversal depth (1=direct only, 2=default, 3=wide net, 4=deep chain walk)"),
4345
- maxResults: z16.number().min(1).max(25).default(10).optional().describe("Max entries to return in gather task mode (default 10)"),
4346
- strategy: z16.enum(["hybrid", "keyword"]).default("keyword").optional().describe("Seed strategy for task-based gather: 'keyword' (FTS only, default) or 'hybrid' (vector + FTS). Only affects task mode."),
4347
- skill: z16.string().max(200).optional().describe(
4502
+ mode: z17.enum(["search", "graph"]).default("search").optional().describe("For gather: 'search' (default) or 'graph' (enhanced with provenance paths). Ignored when mapEntryId is provided."),
4503
+ maxHops: z17.number().min(1).max(4).default(2).describe("Relation traversal depth (1=direct only, 2=default, 3=wide net, 4=deep chain walk)"),
4504
+ maxResults: z17.number().min(1).max(25).default(10).optional().describe("Max entries to return in gather task mode (default 10)"),
4505
+ strategy: z17.enum(["hybrid", "keyword"]).default("keyword").optional().describe("Seed strategy for task-based gather: 'keyword' (FTS only, default) or 'hybrid' (vector + FTS). Only affects task mode."),
4506
+ skill: z17.string().max(200).optional().describe(
4348
4507
  "Skill name for 'incremental' action \u2014 identifies which skill's brief history to compare against. Examples: 'preflight', 'shaping', 'review'. Required when action is 'incremental'."
4349
4508
  ),
4350
- briefType: z16.enum(["steering", "confidence", "delta"]).optional().describe(
4509
+ briefType: z17.enum(["steering", "confidence", "delta"]).optional().describe(
4351
4510
  "Compound query type for 'brief' action. 'steering': 7d changes + structural aggregation (part_of, depends_on, constrains) + incremental delta + workspace readiness. 'confidence': 7d changes + active bets summary (tensions: use the pb CLI's `tensions list`, not this action). 'delta': changes + relations since a custom timestamp (use 'since' param). Required when action is 'brief'."
4352
4511
  ),
4353
- templateId: z16.string().max(200).optional().describe(
4512
+ templateId: z17.string().max(200).optional().describe(
4354
4513
  "For 'last-verified-brief': brief template identifier \u2014 currently 'steering-brief' is the only registered template."
4355
4514
  ),
4356
- scopeKey: z16.string().max(200).optional().describe(
4515
+ scopeKey: z17.string().max(200).optional().describe(
4357
4516
  "For 'last-verified-brief': canonical scope key \u2014 'workspace:<workspaceId>' or 'initiative:<INI-ID>'."
4358
4517
  )
4359
4518
  });
4360
- var contextGatherVariant = z16.object({
4361
- action: z16.literal("gather"),
4362
- entryId: z16.string().max(200).optional(),
4363
- mapEntryId: z16.string().max(200).optional(),
4364
- task: z16.string().max(2e3).optional(),
4365
- mode: z16.enum(["search", "graph"]).optional().default("search"),
4366
- maxHops: z16.number().min(1).max(4).optional().default(2),
4367
- maxResults: z16.number().min(1).max(25).optional().default(10),
4368
- strategy: z16.enum(["hybrid", "keyword"]).optional().default("keyword")
4519
+ var contextGatherVariant = z17.object({
4520
+ action: z17.literal("gather"),
4521
+ entryId: z17.string().max(200).optional(),
4522
+ mapEntryId: z17.string().max(200).optional(),
4523
+ task: z17.string().max(2e3).optional(),
4524
+ mode: z17.enum(["search", "graph"]).optional().default("search"),
4525
+ maxHops: z17.number().min(1).max(4).optional().default(2),
4526
+ maxResults: z17.number().min(1).max(25).optional().default(10),
4527
+ strategy: z17.enum(["hybrid", "keyword"]).optional().default("keyword")
4369
4528
  });
4370
- var contextBuildVariant = z16.object({
4371
- action: z16.literal("build"),
4372
- entryId: z16.string().max(200),
4373
- maxHops: z16.number().min(1).max(4).optional().default(2)
4529
+ var contextBuildVariant = z17.object({
4530
+ action: z17.literal("build"),
4531
+ entryId: z17.string().max(200),
4532
+ maxHops: z17.number().min(1).max(4).optional().default(2)
4374
4533
  });
4375
- var contextNeighborhoodVariant = z16.object({
4376
- action: z16.literal("neighborhood"),
4377
- entryId: z16.string().max(200)
4534
+ var contextNeighborhoodVariant = z17.object({
4535
+ action: z17.literal("neighborhood"),
4536
+ entryId: z17.string().max(200)
4378
4537
  });
4379
- var contextChangesVariant = z16.object({
4380
- action: z16.literal("changes"),
4381
- since: z16.string().max(200)
4538
+ var contextChangesVariant = z17.object({
4539
+ action: z17.literal("changes"),
4540
+ since: z17.string().max(200)
4382
4541
  });
4383
- var contextChainVariant = z16.object({
4384
- action: z16.literal("chain"),
4385
- entryId: z16.string().max(200),
4386
- direction: z16.enum(["outgoing", "incoming"]).optional().default("outgoing"),
4387
- maxHops: z16.number().min(1).max(4).optional().default(2),
4388
- relationType: z16.string().max(200).optional()
4542
+ var contextChainVariant = z17.object({
4543
+ action: z17.literal("chain"),
4544
+ entryId: z17.string().max(200),
4545
+ direction: z17.enum(["outgoing", "incoming"]).optional().default("outgoing"),
4546
+ maxHops: z17.number().min(1).max(4).optional().default(2),
4547
+ relationType: z17.string().max(200).optional()
4389
4548
  });
4390
- var contextCrossCutVariant = z16.object({
4391
- action: z16.literal("cross-cut"),
4392
- relationType: z16.string().max(200)
4549
+ var contextCrossCutVariant = z17.object({
4550
+ action: z17.literal("cross-cut"),
4551
+ relationType: z17.string().max(200)
4393
4552
  });
4394
- var contextIncrementalVariant = z16.object({
4395
- action: z16.literal("incremental"),
4396
- skill: z16.string().max(200)
4553
+ var contextIncrementalVariant = z17.object({
4554
+ action: z17.literal("incremental"),
4555
+ skill: z17.string().max(200)
4397
4556
  });
4398
- var contextBriefVariant = z16.object({
4399
- action: z16.literal("brief"),
4400
- briefType: z16.enum(["steering", "confidence", "delta"]),
4401
- since: z16.string().max(200).optional()
4557
+ var contextBriefVariant = z17.object({
4558
+ action: z17.literal("brief"),
4559
+ briefType: z17.enum(["steering", "confidence", "delta"]),
4560
+ since: z17.string().max(200).optional()
4402
4561
  });
4403
- var contextLastVerifiedBriefVariant = z16.object({
4404
- action: z16.literal("last-verified-brief"),
4405
- templateId: z16.string().max(200),
4406
- scopeKey: z16.string().max(200)
4562
+ var contextLastVerifiedBriefVariant = z17.object({
4563
+ action: z17.literal("last-verified-brief"),
4564
+ templateId: z17.string().max(200),
4565
+ scopeKey: z17.string().max(200)
4407
4566
  });
4408
- var contextActionUnion = z16.discriminatedUnion("action", [
4567
+ var contextActionUnion = z17.discriminatedUnion("action", [
4409
4568
  ...lookupVariants,
4410
4569
  contextGatherVariant,
4411
4570
  contextBuildVariant,
@@ -5403,7 +5562,7 @@ function formatTimeAgo(ms) {
5403
5562
  }
5404
5563
 
5405
5564
  // src/tools/collections.ts
5406
- import { z as z18 } from "zod/v3";
5565
+ import { z as z19 } from "zod/v3";
5407
5566
 
5408
5567
  // src/lib/bodyTemplate.ts
5409
5568
  function readBodyTemplateGuidance(bodyTemplate) {
@@ -5413,17 +5572,17 @@ ${entry.guidance}`).join("\n\n");
5413
5572
  }
5414
5573
 
5415
5574
  // src/tools/labels.ts
5416
- import { z as z17 } from "zod/v3";
5417
- var labelsSchema = z17.object({
5418
- action: z17.enum(["list", "create", "update", "delete", "apply", "remove"]).describe("Action: list all labels, create/update/delete a label, or apply/remove a label on an entry"),
5419
- slug: z17.string().max(200).optional().describe("Label slug (required for create/update/delete/apply/remove)"),
5420
- name: z17.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Display name (required for create)"),
5421
- color: z17.string().max(50).optional().describe("Hex color, e.g. '#ef4444'"),
5422
- description: z17.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional().describe("What this label means"),
5423
- parentSlug: z17.string().max(200).optional().describe("Parent group slug for label hierarchy"),
5424
- isGroup: z17.boolean().optional().describe("True if this is a group container, not a taggable label"),
5425
- order: z17.number().optional().describe("Sort order within its group"),
5426
- entryId: z17.string().max(200).optional().describe("Entry ID for apply/remove actions")
5575
+ import { z as z18 } from "zod/v3";
5576
+ var labelsSchema = z18.object({
5577
+ action: z18.enum(["list", "create", "update", "delete", "apply", "remove"]).describe("Action: list all labels, create/update/delete a label, or apply/remove a label on an entry"),
5578
+ slug: z18.string().max(200).optional().describe("Label slug (required for create/update/delete/apply/remove)"),
5579
+ name: z18.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Display name (required for create)"),
5580
+ color: z18.string().max(50).optional().describe("Hex color, e.g. '#ef4444'"),
5581
+ description: z18.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional().describe("What this label means"),
5582
+ parentSlug: z18.string().max(200).optional().describe("Parent group slug for label hierarchy"),
5583
+ isGroup: z18.boolean().optional().describe("True if this is a group container, not a taggable label"),
5584
+ order: z18.number().optional().describe("Sort order within its group"),
5585
+ entryId: z18.string().max(200).optional().describe("Entry ID for apply/remove actions")
5427
5586
  });
5428
5587
  async function handleLabelsList() {
5429
5588
  const labels = await kernelQuery("chain.listLabels");
@@ -5528,108 +5687,108 @@ var COLLECTIONS_ACTIONS = [
5528
5687
  "label-remove"
5529
5688
  ];
5530
5689
  var STATUS_CATEGORIES2 = ["draft", "current", "past", "discarded"];
5531
- var statusListEntrySchema = z18.object({ label: z18.string().max(200), category: z18.enum(STATUS_CATEGORIES2), archiveDefault: z18.boolean().optional(), resolveDefault: z18.boolean().optional() });
5532
- var qualityCriterionSchema = z18.object({
5533
- field: z18.string().max(200).describe("Entry data field key this criterion applies to, e.g. 'description', 'owner'"),
5690
+ var statusListEntrySchema = z19.object({ label: z19.string().max(200), category: z19.enum(STATUS_CATEGORIES2), archiveDefault: z19.boolean().optional(), resolveDefault: z19.boolean().optional() });
5691
+ var qualityCriterionSchema = z19.object({
5692
+ field: z19.string().max(200).describe("Entry data field key this criterion applies to, e.g. 'description', 'owner'"),
5534
5693
  // WP-480 S1: `max_length` — must mirror the Convex rule union, or the tool rejects a
5535
5694
  // valid criterion before the request ever reaches the server.
5536
- rule: z18.enum(["required", "min_length", "max_length", "pattern"]).describe("'required': field must be non-empty (blocks accept). 'min_length': minimum string length (warns). 'max_length': maximum string length (warns). 'pattern': regex match (warns)."),
5537
- value: z18.string().max(500).optional().describe("For min_length/max_length: the length bound as a string integer. For pattern: the regex string. Unused for 'required'.")
5695
+ rule: z19.enum(["required", "min_length", "max_length", "pattern"]).describe("'required': field must be non-empty (blocks accept). 'min_length': minimum string length (warns). 'max_length': maximum string length (warns). 'pattern': regex match (warns)."),
5696
+ value: z19.string().max(500).optional().describe("For min_length/max_length: the length bound as a string integer. For pattern: the regex string. Unused for 'required'.")
5538
5697
  });
5539
- var fieldSchema = z18.object({
5540
- key: z18.string().max(200).describe("Field key, e.g. 'description', 'severity', 'status'"),
5541
- label: z18.string().max(200).describe("Display label, e.g. 'Description', 'Severity'"),
5542
- type: z18.string().max(50).describe("Field type: 'string', 'select', 'array', 'number', 'boolean'"),
5543
- required: z18.boolean().optional().describe("Whether this field is required"),
5544
- options: z18.array(z18.string().max(200)).max(200).optional().describe("Options for 'select' type fields"),
5545
- searchable: z18.boolean().optional().describe("Whether this field is included in full-text search"),
5546
- displayHint: z18.enum(["hero", "badge", "meta", "section", "hidden", "inline-meta"]).optional().describe("V2 rendering hint: how the field should be displayed in Cortex"),
5547
- zone: z18.enum(["header", "body", "meta"]).optional().describe("V2 layout zone: where the field appears in the entry view"),
5548
- colorMap: z18.record(z18.string().max(50)).optional().describe("V2 value-to-semantic-color mapping, e.g. { critical: 'danger', low: 'success' }"),
5549
- accentSource: z18.boolean().optional().describe("When true, this field's colorMap value drives the card-level accent styling"),
5550
- iconMap: z18.record(z18.string(), z18.string().max(50)).optional().describe("Maps field values to icons (emoji/symbol), prepended to badge text"),
5551
- helpText: z18.string().max(2e3).optional().describe("Help text shown in admin field editors"),
5552
- optionDescriptions: z18.record(z18.string().max(500)).optional().describe("Per-option guidance for select fields"),
5553
- semanticRole: z18.enum(["problem", "appetite", "elements", "architecture", "done_when", "risks", "exclusions"]).optional().describe("Semantic role for schema-driven consumers \u2014 enables field-key-independent validation and rendering"),
5554
- maxLength: z18.number().optional().describe("Maximum character length for field values. Three-tier resolution: explicit > displayHint > type fallback."),
5555
- minLength: z18.number().optional().describe("Minimum character length for field values. Only explicit \u2014 no defaults.")
5698
+ var fieldSchema = z19.object({
5699
+ key: z19.string().max(200).describe("Field key, e.g. 'description', 'severity', 'status'"),
5700
+ label: z19.string().max(200).describe("Display label, e.g. 'Description', 'Severity'"),
5701
+ type: z19.string().max(50).describe("Field type: 'string', 'select', 'array', 'number', 'boolean'"),
5702
+ required: z19.boolean().optional().describe("Whether this field is required"),
5703
+ options: z19.array(z19.string().max(200)).max(200).optional().describe("Options for 'select' type fields"),
5704
+ searchable: z19.boolean().optional().describe("Whether this field is included in full-text search"),
5705
+ displayHint: z19.enum(["hero", "badge", "meta", "section", "hidden", "inline-meta"]).optional().describe("V2 rendering hint: how the field should be displayed in Cortex"),
5706
+ zone: z19.enum(["header", "body", "meta"]).optional().describe("V2 layout zone: where the field appears in the entry view"),
5707
+ colorMap: z19.record(z19.string().max(50)).optional().describe("V2 value-to-semantic-color mapping, e.g. { critical: 'danger', low: 'success' }"),
5708
+ accentSource: z19.boolean().optional().describe("When true, this field's colorMap value drives the card-level accent styling"),
5709
+ iconMap: z19.record(z19.string(), z19.string().max(50)).optional().describe("Maps field values to icons (emoji/symbol), prepended to badge text"),
5710
+ helpText: z19.string().max(2e3).optional().describe("Help text shown in admin field editors"),
5711
+ optionDescriptions: z19.record(z19.string().max(500)).optional().describe("Per-option guidance for select fields"),
5712
+ semanticRole: z19.enum(["problem", "appetite", "elements", "architecture", "done_when", "risks", "exclusions"]).optional().describe("Semantic role for schema-driven consumers \u2014 enables field-key-independent validation and rendering"),
5713
+ maxLength: z19.number().optional().describe("Maximum character length for field values. Three-tier resolution: explicit > displayHint > type fallback."),
5714
+ minLength: z19.number().optional().describe("Minimum character length for field values. Only explicit \u2014 no defaults.")
5556
5715
  });
5557
- var collectionsSchema = z18.object({
5558
- action: z18.enum(COLLECTIONS_ACTIONS).describe(
5716
+ var collectionsSchema = z19.object({
5717
+ action: z19.enum(COLLECTIONS_ACTIONS).describe(
5559
5718
  "'list': browse all collections. 'update': update an existing collection. 'describe': full documentation for one collection \u2014 fields, option guides, usage guidance, examples. 'audit': health report for all collections \u2014 missing classification, displayHint coverage, and field schema gaps. 'export': full system_collection_definitions export with classification metadata (thinkingLayer, classificationPriority, classificationCheck, classificationSignals, governanceRole, governanceFunction, timelineRole, canBeElementOf, descriptionFieldKey). Admin only. 'label-list'/'label-create'/'label-update'/'label-delete'/'label-apply'/'label-remove': manage workspace labels (absorbs the `labels` tool). Creating a new collection is not offered here \u2014 ask a platform admin to provision it, or enable the module ontology pack that owns the drawer."
5560
5719
  ),
5561
- slug: z18.string().max(200).optional().describe("URL-safe identifier for create/update, e.g. 'glossary', 'tech-debt'. For label-*: label slug."),
5562
- name: z18.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("For label-*: the label's name. For update: refused (the catalog's)."),
5563
- description: z18.string().max(2e4).optional().describe("For label-*: what the label means (max 2,000 chars). For update: refused (the catalog's)."),
5564
- purpose: z18.string().max(2e3).optional().describe("Why this collection exists \u2014 strategic reason"),
5565
- icon: z18.string().max(50).optional().describe("For update: always refused \u2014 a collection's icon comes from the platform catalog."),
5566
- navGroup: z18.enum(["daily", "strategic", "governance", "reference", "collections"]).optional().describe("Sidebar placement: 'daily', 'strategic', 'governance', 'reference', 'collections'"),
5567
- fields: z18.array(fieldSchema).max(200).optional().describe("Field definitions for create, or replacement schema for update (replaces all fields)"),
5568
- axis: z18.enum(["work", "none", "pending"]).optional().describe("REQUIRED for create: 'work' (needs stageLabelMap + validWorkflowStatuses), 'none', or 'pending'. For update: always refused \u2014 a collection's axis comes from the platform catalog."),
5569
- stageLabelMap: z18.record(z18.string(), z18.enum(["open", "in_progress", "done", "stopped", "tag"])).optional().describe("Required when axis is 'work': maps each valid workflowStatus to a canonical stage."),
5570
- defaultCanonicalKey: z18.string().max(200).optional().describe("The canonical_key entries in this collection default to (e.g. 'decision', 'insight'). Consumers read from collection doc; code map is fallback."),
5571
- defaultWorkflowStatus: z18.string().max(200).optional().describe("Default workflowStatus for new entries. For update: always refused \u2014 the status words come from the platform catalog."),
5572
- validWorkflowStatuses: z18.array(z18.string().max(200)).max(50).optional().describe("The allowed workflowStatus values for entries in this collection. For update: always refused \u2014 the status words come from the platform catalog."),
5720
+ slug: z19.string().max(200).optional().describe("URL-safe identifier for create/update, e.g. 'glossary', 'tech-debt'. For label-*: label slug."),
5721
+ name: z19.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("For label-*: the label's name. For update: refused (the catalog's)."),
5722
+ description: z19.string().max(2e4).optional().describe("For label-*: what the label means (max 2,000 chars). For update: refused (the catalog's)."),
5723
+ purpose: z19.string().max(2e3).optional().describe("Why this collection exists \u2014 strategic reason"),
5724
+ icon: z19.string().max(50).optional().describe("For update: always refused \u2014 a collection's icon comes from the platform catalog."),
5725
+ navGroup: z19.enum(["daily", "strategic", "governance", "reference", "collections"]).optional().describe("Sidebar placement: 'daily', 'strategic', 'governance', 'reference', 'collections'"),
5726
+ fields: z19.array(fieldSchema).max(200).optional().describe("Field definitions for create, or replacement schema for update (replaces all fields)"),
5727
+ axis: z19.enum(["work", "none", "pending"]).optional().describe("REQUIRED for create: 'work' (needs stageLabelMap + validWorkflowStatuses), 'none', or 'pending'. For update: always refused \u2014 a collection's axis comes from the platform catalog."),
5728
+ stageLabelMap: z19.record(z19.string(), z19.enum(["open", "in_progress", "done", "stopped", "tag"])).optional().describe("Required when axis is 'work': maps each valid workflowStatus to a canonical stage."),
5729
+ defaultCanonicalKey: z19.string().max(200).optional().describe("The canonical_key entries in this collection default to (e.g. 'decision', 'insight'). Consumers read from collection doc; code map is fallback."),
5730
+ defaultWorkflowStatus: z19.string().max(200).optional().describe("Default workflowStatus for new entries. For update: always refused \u2014 the status words come from the platform catalog."),
5731
+ validWorkflowStatuses: z19.array(z19.string().max(200)).max(50).optional().describe("The allowed workflowStatus values for entries in this collection. For update: always refused \u2014 the status words come from the platform catalog."),
5573
5732
  // ENT-65, FEAT-200
5574
- classificationCheck: z18.string().max(500).optional().describe("LLM decision-tree check for this collection (3\u2013500 chars). Guides the classifier in routing entries here."),
5575
- classificationPriority: z18.number().optional().describe("Classifier priority (1\u20139, lower = higher priority). Used with classificationCheck to order the decision tree."),
5576
- qualityCriteria: z18.array(qualityCriterionSchema).max(50).optional().describe("Per-collection accept gate rules. 'required' rule hard-blocks accepts on empty fields; 'min_length'/'pattern' rules warn. Pass an empty array to clear all criteria."),
5577
- statusList: z18.array(statusListEntrySchema).max(50).optional().describe("Ordered status vocabulary: {label, category, archiveDefault?}[]. For update: always refused \u2014 the status words come from the platform catalog."),
5733
+ classificationCheck: z19.string().max(500).optional().describe("LLM decision-tree check for this collection (3\u2013500 chars). Guides the classifier in routing entries here."),
5734
+ classificationPriority: z19.number().optional().describe("Classifier priority (1\u20139, lower = higher priority). Used with classificationCheck to order the decision tree."),
5735
+ qualityCriteria: z19.array(qualityCriterionSchema).max(50).optional().describe("Per-collection accept gate rules. 'required' rule hard-blocks accepts on empty fields; 'min_length'/'pattern' rules warn. Pass an empty array to clear all criteria."),
5736
+ statusList: z19.array(statusListEntrySchema).max(50).optional().describe("Ordered status vocabulary: {label, category, archiveDefault?}[]. For update: always refused \u2014 the status words come from the platform catalog."),
5578
5737
  // For label-*
5579
- color: z18.string().max(50).optional().describe("For label-create/label-update: hex color, e.g. '#ef4444'."),
5580
- parentSlug: z18.string().max(200).optional().describe("For label-create: parent group slug for label hierarchy."),
5581
- isGroup: z18.boolean().optional().describe("For label-create/label-update: true if this is a group container, not a taggable label."),
5582
- order: z18.number().optional().describe("For label-create/label-update: sort order within its group."),
5583
- entryId: z18.string().max(200).optional().describe("For label-apply/label-remove: entry ID.")
5738
+ color: z19.string().max(50).optional().describe("For label-create/label-update: hex color, e.g. '#ef4444'."),
5739
+ parentSlug: z19.string().max(200).optional().describe("For label-create: parent group slug for label hierarchy."),
5740
+ isGroup: z19.boolean().optional().describe("For label-create/label-update: true if this is a group container, not a taggable label."),
5741
+ order: z19.number().optional().describe("For label-create/label-update: sort order within its group."),
5742
+ entryId: z19.string().max(200).optional().describe("For label-apply/label-remove: entry ID.")
5584
5743
  });
5585
- var collectionsListVariant = z18.object({ action: z18.literal("list") });
5586
- var collectionsDescribeVariant = z18.object({ action: z18.literal("describe"), slug: z18.string().max(200) });
5587
- var collectionsUpdateVariant = z18.object({
5588
- action: z18.literal("update"),
5589
- slug: z18.string().max(200),
5590
- name: z18.string().max(ENTRY_NAME_MAX_CHARS).optional(),
5591
- description: z18.string().max(2e4).optional(),
5592
- purpose: z18.string().max(2e3).optional(),
5593
- icon: z18.string().max(50).optional(),
5594
- navGroup: z18.enum(["daily", "strategic", "governance", "reference", "collections"]).optional(),
5595
- fields: z18.array(fieldSchema).optional(),
5596
- axis: z18.enum(["work", "none", "pending"]).optional(),
5597
- stageLabelMap: z18.record(z18.string(), z18.enum(["open", "in_progress", "done", "stopped", "tag"])).optional(),
5744
+ var collectionsListVariant = z19.object({ action: z19.literal("list") });
5745
+ var collectionsDescribeVariant = z19.object({ action: z19.literal("describe"), slug: z19.string().max(200) });
5746
+ var collectionsUpdateVariant = z19.object({
5747
+ action: z19.literal("update"),
5748
+ slug: z19.string().max(200),
5749
+ name: z19.string().max(ENTRY_NAME_MAX_CHARS).optional(),
5750
+ description: z19.string().max(2e4).optional(),
5751
+ purpose: z19.string().max(2e3).optional(),
5752
+ icon: z19.string().max(50).optional(),
5753
+ navGroup: z19.enum(["daily", "strategic", "governance", "reference", "collections"]).optional(),
5754
+ fields: z19.array(fieldSchema).optional(),
5755
+ axis: z19.enum(["work", "none", "pending"]).optional(),
5756
+ stageLabelMap: z19.record(z19.string(), z19.enum(["open", "in_progress", "done", "stopped", "tag"])).optional(),
5598
5757
  // WP-640 SWEEP (P1): axis/stageLabelMap repair legacy custom collections — see collections.ts's updateCollection.
5599
- defaultCanonicalKey: z18.string().max(200).optional(),
5600
- defaultWorkflowStatus: z18.string().max(200).optional(),
5601
- validWorkflowStatuses: z18.array(z18.string().max(200)).optional(),
5602
- classificationCheck: z18.string().max(500).optional(),
5603
- classificationPriority: z18.number().optional(),
5604
- qualityCriteria: z18.array(qualityCriterionSchema).optional(),
5605
- statusList: z18.array(statusListEntrySchema).optional()
5758
+ defaultCanonicalKey: z19.string().max(200).optional(),
5759
+ defaultWorkflowStatus: z19.string().max(200).optional(),
5760
+ validWorkflowStatuses: z19.array(z19.string().max(200)).optional(),
5761
+ classificationCheck: z19.string().max(500).optional(),
5762
+ classificationPriority: z19.number().optional(),
5763
+ qualityCriteria: z19.array(qualityCriterionSchema).optional(),
5764
+ statusList: z19.array(statusListEntrySchema).optional()
5606
5765
  });
5607
- var collectionsAuditVariant = z18.object({ action: z18.literal("audit") });
5608
- var collectionsExportVariant = z18.object({ action: z18.literal("export") });
5609
- var collectionsLabelListVariant = z18.object({ action: z18.literal("label-list") });
5610
- var collectionsLabelCreateVariant = z18.object({
5611
- action: z18.literal("label-create"),
5612
- slug: z18.string().max(200),
5613
- name: z18.string().max(ENTRY_NAME_MAX_CHARS),
5614
- color: z18.string().max(50).optional(),
5615
- description: z18.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
5616
- parentSlug: z18.string().max(200).optional(),
5617
- isGroup: z18.boolean().optional(),
5618
- order: z18.number().optional()
5766
+ var collectionsAuditVariant = z19.object({ action: z19.literal("audit") });
5767
+ var collectionsExportVariant = z19.object({ action: z19.literal("export") });
5768
+ var collectionsLabelListVariant = z19.object({ action: z19.literal("label-list") });
5769
+ var collectionsLabelCreateVariant = z19.object({
5770
+ action: z19.literal("label-create"),
5771
+ slug: z19.string().max(200),
5772
+ name: z19.string().max(ENTRY_NAME_MAX_CHARS),
5773
+ color: z19.string().max(50).optional(),
5774
+ description: z19.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
5775
+ parentSlug: z19.string().max(200).optional(),
5776
+ isGroup: z19.boolean().optional(),
5777
+ order: z19.number().optional()
5619
5778
  });
5620
- var collectionsLabelUpdateVariant = z18.object({
5621
- action: z18.literal("label-update"),
5622
- slug: z18.string().max(200),
5623
- name: z18.string().max(ENTRY_NAME_MAX_CHARS).optional(),
5624
- color: z18.string().max(50).optional(),
5625
- description: z18.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
5626
- isGroup: z18.boolean().optional(),
5627
- order: z18.number().optional()
5779
+ var collectionsLabelUpdateVariant = z19.object({
5780
+ action: z19.literal("label-update"),
5781
+ slug: z19.string().max(200),
5782
+ name: z19.string().max(ENTRY_NAME_MAX_CHARS).optional(),
5783
+ color: z19.string().max(50).optional(),
5784
+ description: z19.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
5785
+ isGroup: z19.boolean().optional(),
5786
+ order: z19.number().optional()
5628
5787
  });
5629
- var collectionsLabelDeleteVariant = z18.object({ action: z18.literal("label-delete"), slug: z18.string().max(200) });
5630
- var collectionsLabelApplyVariant = z18.object({ action: z18.literal("label-apply"), slug: z18.string().max(200), entryId: z18.string().max(200) });
5631
- var collectionsLabelRemoveVariant = z18.object({ action: z18.literal("label-remove"), slug: z18.string().max(200), entryId: z18.string().max(200) });
5632
- var collectionsActionUnion = z18.discriminatedUnion("action", [
5788
+ var collectionsLabelDeleteVariant = z19.object({ action: z19.literal("label-delete"), slug: z19.string().max(200) });
5789
+ var collectionsLabelApplyVariant = z19.object({ action: z19.literal("label-apply"), slug: z19.string().max(200), entryId: z19.string().max(200) });
5790
+ var collectionsLabelRemoveVariant = z19.object({ action: z19.literal("label-remove"), slug: z19.string().max(200), entryId: z19.string().max(200) });
5791
+ var collectionsActionUnion = z19.discriminatedUnion("action", [
5633
5792
  collectionsListVariant,
5634
5793
  collectionsDescribeVariant,
5635
5794
  collectionsUpdateVariant,
@@ -5937,7 +6096,7 @@ async function handleExport() {
5937
6096
  }
5938
6097
 
5939
6098
  // src/tools/orient.ts
5940
- import { z as z19 } from "zod/v3";
6099
+ import { z as z20 } from "zod/v3";
5941
6100
 
5942
6101
  // src/tools/planned-work.ts
5943
6102
  var MORE_DRAFTS_LINE = "_More drafts exist than shown. `context action=list status=draft` lists more, but that list is capped as well; page with limit/cursor once context list supports it._";
@@ -7008,25 +7167,25 @@ async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapsho
7008
7167
  }
7009
7168
  }
7010
7169
  var ORIENT_ACTIONS = ["task"];
7011
- var orientSchema = z19.object({
7012
- action: z19.enum(ORIENT_ACTIONS).optional().default("task").describe(
7170
+ var orientSchema = z20.object({
7171
+ action: z20.enum(ORIENT_ACTIONS).optional().default("task").describe(
7013
7172
  "'task': task-grounded context loader, the only action."
7014
7173
  ),
7015
- mode: z19.enum(["full", "brief"]).optional().default("full").describe("For 'task': full = full context (default). brief = compact summary for mid-session re-orientation. Prefer using the `tier` param for depth control."),
7016
- tier: z19.enum(["summary", "standard", "full"]).optional().describe(
7174
+ mode: z20.enum(["full", "brief"]).optional().default("full").describe("For 'task': full = full context (default). brief = compact summary for mid-session re-orientation. Prefer using the `tier` param for depth control."),
7175
+ tier: z20.enum(["summary", "standard", "full"]).optional().describe(
7017
7176
  "For 'task': payload depth. Defaults to summary (~10 KB) when task is provided; standard (~256 KB) when task is absent. Pass summary, standard, or full to override."
7018
7177
  ),
7019
- task: z19.string().max(2e3).optional().describe(
7178
+ task: z20.string().max(2e3).optional().describe(
7020
7179
  "For 'task': natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task."
7021
7180
  ),
7022
7181
  // D1d (WP-754/TASK-204): matches the server's StartupResolutionSignals shape; domain resolution (original purpose) is deleted, sole survivor is `context.served` telemetry.
7023
- startupSignals: z19.object({
7024
- changedPaths: z19.array(z19.string()).max(25).optional().describe("Paths changed in the current working tree, if known (e.g. from a prior git status/diff tool call)."),
7025
- reviewedArtifactRefs: z19.array(z19.string()).max(25).optional().describe("Chain entry IDs the caller has already reviewed this session, if tracked."),
7026
- branchName: z19.string().max(120).optional().describe("Current git branch name, if known."),
7027
- worktreeName: z19.string().max(120).optional().describe("Current worktree/directory name, if known.")
7182
+ startupSignals: z20.object({
7183
+ changedPaths: z20.array(z20.string()).max(25).optional().describe("Paths changed in the current working tree, if known (e.g. from a prior git status/diff tool call)."),
7184
+ reviewedArtifactRefs: z20.array(z20.string()).max(25).optional().describe("Chain entry IDs the caller has already reviewed this session, if tracked."),
7185
+ branchName: z20.string().max(120).optional().describe("Current git branch name, if known."),
7186
+ worktreeName: z20.string().max(120).optional().describe("Current worktree/directory name, if known.")
7028
7187
  }).optional().describe("For 'task': best-effort startup signals \u2014 changedPaths/reviewedArtifactRefs/branchName/worktreeName. All optional; omit fields you don't know."),
7029
- invocationPath: z19.enum(["session-start", "session-close", "manual-orient", "handshake", "unknown"]).optional().describe("For 'task': how this orient was invoked. Defaults to 'manual-orient' (the direct `orient task=...` call shape) when omitted.")
7188
+ invocationPath: z20.enum(["session-start", "session-close", "manual-orient", "handshake", "unknown"]).optional().describe("For 'task': how this orient was invoked. Defaults to 'manual-orient' (the direct `orient task=...` call shape) when omitted.")
7030
7189
  });
7031
7190
  function taskGroundingWarningLines(task, hasTaskGrounding = false) {
7032
7191
  if (hasTaskGrounding) return [];
@@ -7700,7 +7859,7 @@ async function _handleOrient({ mode = "full", tier, task, startupSignals, invoca
7700
7859
  }
7701
7860
 
7702
7861
  // src/tools/workflows.ts
7703
- import { z as z20 } from "zod/v3";
7862
+ import { z as z21 } from "zod/v3";
7704
7863
 
7705
7864
  // src/workflows/descriptor.ts
7706
7865
  function cloneWorkflowQuestion(question) {
@@ -8545,73 +8704,73 @@ function workflowRunOutputToText(output) {
8545
8704
 
8546
8705
  // src/tools/workflows.ts
8547
8706
  var WORKFLOWS_ACTIONS = ["list", "start", "checkpoint", "get-run"];
8548
- var jsonValueSchema = z20.lazy(
8549
- () => z20.union([
8550
- z20.string(),
8551
- z20.number(),
8552
- z20.boolean(),
8553
- z20.null(),
8554
- z20.array(jsonValueSchema),
8555
- z20.record(jsonValueSchema)
8707
+ var jsonValueSchema = z21.lazy(
8708
+ () => z21.union([
8709
+ z21.string(),
8710
+ z21.number(),
8711
+ z21.boolean(),
8712
+ z21.null(),
8713
+ z21.array(jsonValueSchema),
8714
+ z21.record(jsonValueSchema)
8556
8715
  ])
8557
8716
  );
8558
- var workflowRunOutputInputSchema = z20.union([
8559
- z20.object({
8560
- format: z20.literal("freetext"),
8561
- value: z20.string()
8717
+ var workflowRunOutputInputSchema = z21.union([
8718
+ z21.object({
8719
+ format: z21.literal("freetext"),
8720
+ value: z21.string()
8562
8721
  }),
8563
- z20.object({
8564
- format: z20.literal("list"),
8565
- value: z20.array(z20.string())
8722
+ z21.object({
8723
+ format: z21.literal("list"),
8724
+ value: z21.array(z21.string())
8566
8725
  }),
8567
- z20.object({
8568
- format: z20.literal("choice"),
8569
- value: z20.union([z20.string(), z20.array(z20.string())])
8726
+ z21.object({
8727
+ format: z21.literal("choice"),
8728
+ value: z21.union([z21.string(), z21.array(z21.string())])
8570
8729
  }),
8571
- z20.object({
8572
- format: z20.literal("structured"),
8730
+ z21.object({
8731
+ format: z21.literal("structured"),
8573
8732
  value: jsonValueSchema
8574
8733
  })
8575
8734
  ]);
8576
- var workflowsSchema = z20.object({
8577
- action: z20.enum(WORKFLOWS_ACTIONS).describe(
8735
+ var workflowsSchema = z21.object({
8736
+ action: z21.enum(WORKFLOWS_ACTIONS).describe(
8578
8737
  "'list': browse available workflows. 'start': start or resume a workflow \u2014 returns first (or current) round and next-step checkpoint call. 'checkpoint': record round output or final summary. 'get-run': inspect a persisted workflow run."
8579
8738
  ),
8580
- workflowId: z20.string().max(200).optional().describe("Workflow ID for start, checkpoint, or get-run, e.g. 'retro', 'implementation-review'"),
8581
- runId: z20.string().max(200).optional().describe("Workflow run ID: for get-run, which run to load; for checkpoint, target this run (avoids session drift \u2014 pass runId from get-run)."),
8582
- roundId: z20.string().max(200).optional().describe("Round ID for checkpoint, e.g. 'what-went-well'"),
8583
- output: z20.union([z20.string(), workflowRunOutputInputSchema]).optional().describe("The round's output \u2014 either legacy synthesized text or a typed workflow run payload."),
8584
- isFinal: z20.boolean().optional().describe("If true, finalize an existing durable workflow run from its terminal round and create the summary chain entry."),
8585
- restart: z20.boolean().optional().describe("If true, start a new durable run from the workflow's first round in the current session."),
8586
- summaryName: z20.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Optional name for final chain entry. If omitted, the workflow summary template is used."),
8587
- summaryDescription: z20.string().max(ENTRY_BODY_MAX_CHARS).optional().describe("Optional override for the final chain entry description. Defaults to the final round output text."),
8588
- summaryEntryId: z20.string().max(200).optional().describe("Link an existing entry as the run's summary instead of creating one. Used by facilitated workflows (e.g. shape) where the primary record is created by the specialized tool."),
8739
+ workflowId: z21.string().max(200).optional().describe("Workflow ID for start, checkpoint, or get-run, e.g. 'retro', 'implementation-review'"),
8740
+ runId: z21.string().max(200).optional().describe("Workflow run ID: for get-run, which run to load; for checkpoint, target this run (avoids session drift \u2014 pass runId from get-run)."),
8741
+ roundId: z21.string().max(200).optional().describe("Round ID for checkpoint, e.g. 'what-went-well'"),
8742
+ output: z21.union([z21.string(), workflowRunOutputInputSchema]).optional().describe("The round's output \u2014 either legacy synthesized text or a typed workflow run payload."),
8743
+ isFinal: z21.boolean().optional().describe("If true, finalize an existing durable workflow run from its terminal round and create the summary chain entry."),
8744
+ restart: z21.boolean().optional().describe("If true, start a new durable run from the workflow's first round in the current session."),
8745
+ summaryName: z21.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Optional name for final chain entry. If omitted, the workflow summary template is used."),
8746
+ summaryDescription: z21.string().max(ENTRY_BODY_MAX_CHARS).optional().describe("Optional override for the final chain entry description. Defaults to the final round output text."),
8747
+ summaryEntryId: z21.string().max(200).optional().describe("Link an existing entry as the run's summary instead of creating one. Used by facilitated workflows (e.g. shape) where the primary record is created by the specialized tool."),
8589
8748
  // WP-513: team+role to create the finalize summary AS OWNER of (rung 2 only).
8590
- ownerTeamEntryId: z20.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning team (rung-2)."),
8591
- ownerRoleEntryId: z20.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning role (rung-2).")
8749
+ ownerTeamEntryId: z21.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning team (rung-2)."),
8750
+ ownerRoleEntryId: z21.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning role (rung-2).")
8592
8751
  });
8593
- var workflowsListVariant = z20.object({ action: z20.literal("list") });
8594
- var workflowsGetRunVariant = z20.object({
8595
- action: z20.literal("get-run"),
8596
- runId: z20.string().max(200).optional(),
8597
- workflowId: z20.string().max(200).optional()
8752
+ var workflowsListVariant = z21.object({ action: z21.literal("list") });
8753
+ var workflowsGetRunVariant = z21.object({
8754
+ action: z21.literal("get-run"),
8755
+ runId: z21.string().max(200).optional(),
8756
+ workflowId: z21.string().max(200).optional()
8598
8757
  });
8599
- var workflowsStartVariant = z20.object({ action: z20.literal("start"), workflowId: z20.string().max(200) });
8600
- var workflowsCheckpointVariant = z20.object({
8601
- action: z20.literal("checkpoint"),
8602
- workflowId: z20.string().max(200),
8603
- roundId: z20.string().max(200),
8604
- output: z20.union([z20.string(), workflowRunOutputInputSchema]),
8605
- isFinal: z20.boolean().optional(),
8606
- restart: z20.boolean().optional(),
8607
- summaryName: z20.string().max(ENTRY_NAME_MAX_CHARS).optional(),
8608
- summaryDescription: z20.string().max(ENTRY_BODY_MAX_CHARS).optional(),
8609
- summaryEntryId: z20.string().max(200).optional(),
8610
- runId: z20.string().max(200).optional(),
8611
- ownerTeamEntryId: z20.string().max(200).optional(),
8612
- ownerRoleEntryId: z20.string().max(200).optional()
8758
+ var workflowsStartVariant = z21.object({ action: z21.literal("start"), workflowId: z21.string().max(200) });
8759
+ var workflowsCheckpointVariant = z21.object({
8760
+ action: z21.literal("checkpoint"),
8761
+ workflowId: z21.string().max(200),
8762
+ roundId: z21.string().max(200),
8763
+ output: z21.union([z21.string(), workflowRunOutputInputSchema]),
8764
+ isFinal: z21.boolean().optional(),
8765
+ restart: z21.boolean().optional(),
8766
+ summaryName: z21.string().max(ENTRY_NAME_MAX_CHARS).optional(),
8767
+ summaryDescription: z21.string().max(ENTRY_BODY_MAX_CHARS).optional(),
8768
+ summaryEntryId: z21.string().max(200).optional(),
8769
+ runId: z21.string().max(200).optional(),
8770
+ ownerTeamEntryId: z21.string().max(200).optional(),
8771
+ ownerRoleEntryId: z21.string().max(200).optional()
8613
8772
  });
8614
- var workflowsActionUnion = z20.discriminatedUnion("action", [
8773
+ var workflowsActionUnion = z21.discriminatedUnion("action", [
8615
8774
  workflowsListVariant,
8616
8775
  workflowsGetRunVariant,
8617
8776
  workflowsStartVariant,
@@ -9340,7 +9499,7 @@ function parseListOutput(output) {
9340
9499
  }
9341
9500
 
9342
9501
  // src/tools/quality.ts
9343
- import { z as z21 } from "zod/v3";
9502
+ import { z as z22 } from "zod/v3";
9344
9503
 
9345
9504
  // src/lib/spineVerdictRead.ts
9346
9505
  function isRecord(value) {
@@ -9505,36 +9664,36 @@ async function handleSpineCheck(story, refresh = false) {
9505
9664
 
9506
9665
  // src/tools/quality.ts
9507
9666
  var QUALITY_ACTIONS = ["check", "re-evaluate", "verify-chain", "spine-check"];
9508
- var qualitySchema = z21.object({
9509
- action: z21.enum(QUALITY_ACTIONS).describe(
9667
+ var qualitySchema = z22.object({
9668
+ action: z22.enum(QUALITY_ACTIONS).describe(
9510
9669
  "'check': read the entry's server quality verdict (tier + criteria). 're-evaluate': trigger fresh evaluation. 'verify-chain': verify entries against the codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. 'spine-check': structural completeness of the purpose+vision+strategy spine \u2014 story:true also runs the on-demand one-story judgment."
9511
9670
  ),
9512
- entryId: z21.string().max(200).optional().describe("For 'check'/'re-evaluate': entry ID, e.g. 'TEN-graph-db', '<PREFIX>-<n>'."),
9513
- context: z21.enum(["capture", "commit", "review"]).default("review").optional().describe("For re-evaluate: evaluation context"),
9514
- collection: z21.string().max(200).optional().describe("For 'verify-chain': collection slug to verify (default: glossary)."),
9515
- mode: z21.enum(["report", "fix"]).optional().describe("For 'verify-chain': 'report' = read-only trust report (default). 'fix' = also update drifted codeMapping statuses."),
9516
- story: z21.boolean().optional().describe("For 'spine-check': also run the on-demand one-story LLM judgment (never scheduled; result labelled [unvalidated])."),
9517
- refresh: z21.boolean().optional().describe(
9671
+ entryId: z22.string().max(200).optional().describe("For 'check'/'re-evaluate': entry ID, e.g. 'TEN-graph-db', '<PREFIX>-<n>'."),
9672
+ context: z22.enum(["capture", "commit", "review"]).default("review").optional().describe("For re-evaluate: evaluation context"),
9673
+ collection: z22.string().max(200).optional().describe("For 'verify-chain': collection slug to verify (default: glossary)."),
9674
+ mode: z22.enum(["report", "fix"]).optional().describe("For 'verify-chain': 'report' = read-only trust report (default). 'fix' = also update drifted codeMapping statuses."),
9675
+ story: z22.boolean().optional().describe("For 'spine-check': also run the on-demand one-story LLM judgment (never scheduled; result labelled [unvalidated])."),
9676
+ refresh: z22.boolean().optional().describe(
9518
9677
  "For 'spine-check': force a new run even if a fresh verdict already exists. Default false \u2014 a plain call NEVER re-triggers work just to read the last result; it auto-schedules only when no run is already in flight AND the stored verdict is absent/stale/missing the requested story pass."
9519
9678
  )
9520
9679
  });
9521
- var qualityCheckVariant = z21.object({ action: z21.literal("check"), entryId: z21.string().max(200) });
9522
- var qualityReEvaluateVariant = z21.object({
9523
- action: z21.literal("re-evaluate"),
9524
- entryId: z21.string().max(200),
9525
- context: z21.enum(["capture", "commit", "review"]).optional().default("review")
9680
+ var qualityCheckVariant = z22.object({ action: z22.literal("check"), entryId: z22.string().max(200) });
9681
+ var qualityReEvaluateVariant = z22.object({
9682
+ action: z22.literal("re-evaluate"),
9683
+ entryId: z22.string().max(200),
9684
+ context: z22.enum(["capture", "commit", "review"]).optional().default("review")
9526
9685
  });
9527
- var qualityVerifyChainVariant = z21.object({
9528
- action: z21.literal("verify-chain"),
9529
- collection: z21.string().max(200).optional().default("glossary"),
9530
- mode: z21.enum(["report", "fix"]).optional().default("report")
9686
+ var qualityVerifyChainVariant = z22.object({
9687
+ action: z22.literal("verify-chain"),
9688
+ collection: z22.string().max(200).optional().default("glossary"),
9689
+ mode: z22.enum(["report", "fix"]).optional().default("report")
9531
9690
  });
9532
- var qualitySpineCheckVariant = z21.object({
9533
- action: z21.literal("spine-check"),
9534
- story: z21.boolean().optional().default(false),
9535
- refresh: z21.boolean().optional().default(false)
9691
+ var qualitySpineCheckVariant = z22.object({
9692
+ action: z22.literal("spine-check"),
9693
+ story: z22.boolean().optional().default(false),
9694
+ refresh: z22.boolean().optional().default(false)
9536
9695
  });
9537
- var qualityActionUnion = z21.discriminatedUnion("action", [
9696
+ var qualityActionUnion = z22.discriminatedUnion("action", [
9538
9697
  qualityCheckVariant,
9539
9698
  qualityReEvaluateVariant,
9540
9699
  qualityVerifyChainVariant,
@@ -9546,43 +9705,43 @@ var QUALITY_ACTION_SPECS = {
9546
9705
  "verify-chain": { params: ["collection", "mode"], description: "All params optional; collection defaults to 'glossary'." },
9547
9706
  "spine-check": { params: ["story", "refresh"], description: "All params optional; story and refresh default to false \u2014 a plain call never re-triggers work, it just reads back the latest verdict (auto-refreshing only when stale/absent)." }
9548
9707
  };
9549
- var qualityCheckOutputSchema = z21.object({
9550
- entryId: z21.string(),
9708
+ var qualityCheckOutputSchema = z22.object({
9709
+ entryId: z22.string(),
9551
9710
  /** WP-480 S1: false = the ID does not resolve to an entry (typo/deleted) — distinct from "no verdict yet". */
9552
- entryFound: z21.boolean().optional(),
9553
- hasVerdict: z21.boolean(),
9711
+ entryFound: z22.boolean().optional(),
9712
+ hasVerdict: z22.boolean(),
9554
9713
  /** WP-480 S1: the verdict was judged against content the entry no longer has — re-evaluate for a current one. */
9555
- stale: z21.boolean().optional(),
9556
- tier: z21.string().optional(),
9557
- passed: z21.boolean().optional(),
9558
- criteria: z21.array(z21.object({
9559
- id: z21.string(),
9560
- passed: z21.boolean(),
9561
- hint: z21.string().optional()
9714
+ stale: z22.boolean().optional(),
9715
+ tier: z22.string().optional(),
9716
+ passed: z22.boolean().optional(),
9717
+ criteria: z22.array(z22.object({
9718
+ id: z22.string(),
9719
+ passed: z22.boolean(),
9720
+ hint: z22.string().optional()
9562
9721
  }))
9563
9722
  });
9564
- var qualityReevaluateOutputSchema = z21.object({
9565
- entryId: z21.string(),
9566
- context: z21.string(),
9567
- score: z21.number(),
9568
- maxScore: z21.number(),
9569
- improved: z21.boolean()
9723
+ var qualityReevaluateOutputSchema = z22.object({
9724
+ entryId: z22.string(),
9725
+ context: z22.string(),
9726
+ score: z22.number(),
9727
+ maxScore: z22.number(),
9728
+ improved: z22.boolean()
9570
9729
  });
9571
- var qualitySpineCheckOutputSchema = z21.object({
9572
- hasVerdict: z21.boolean(),
9573
- noSpineEntries: z21.boolean().optional(),
9574
- structuralPassed: z21.boolean().optional(),
9575
- storyPassed: z21.boolean().nullable().optional(),
9576
- stale: z21.boolean().optional(),
9730
+ var qualitySpineCheckOutputSchema = z22.object({
9731
+ hasVerdict: z22.boolean(),
9732
+ noSpineEntries: z22.boolean().optional(),
9733
+ structuralPassed: z22.boolean().optional(),
9734
+ storyPassed: z22.boolean().nullable().optional(),
9735
+ stale: z22.boolean().optional(),
9577
9736
  // TASK-156: a capped membership scan must stay distinguishable from a complete one, and a
9578
9737
  // malformed verdict needs its own discriminator — both were silently stripped before this.
9579
- staleMemberIds: z21.array(z21.string()).optional(),
9580
- membershipTruncated: z21.boolean().optional(),
9738
+ staleMemberIds: z22.array(z22.string()).optional(),
9739
+ membershipTruncated: z22.boolean().optional(),
9581
9740
  // PRRT_kwDORS4ils6i_PVS: a KNOWN relations-fingerprint mismatch, distinct from "unknown" —
9582
9741
  // without this, a detected topology change and an unverifiable legacy fingerprint were
9583
9742
  // indistinguishable in structured output.
9584
- relationsChanged: z21.boolean().optional(),
9585
- malformed: z21.boolean().optional()
9743
+ relationsChanged: z22.boolean().optional(),
9744
+ malformed: z22.boolean().optional()
9586
9745
  });
9587
9746
  function registerQualityTools(server) {
9588
9747
  const qualityHandlers = {
@@ -9738,10 +9897,10 @@ async function handleReEvaluate(entryId, context) {
9738
9897
  }
9739
9898
 
9740
9899
  // src/tools/session.ts
9741
- import { z as z24 } from "zod/v3";
9900
+ import { z as z25 } from "zod/v3";
9742
9901
 
9743
9902
  // src/tools/wrapup.ts
9744
- import { z as z22 } from "zod/v3";
9903
+ import { z as z23 } from "zod/v3";
9745
9904
 
9746
9905
  // src/lib/compose-wrapup-view.ts
9747
9906
  function toComposed(e) {
@@ -10029,8 +10188,8 @@ async function runWrapupCommitAll(data) {
10029
10188
  overflowUnscanned
10030
10189
  };
10031
10190
  }
10032
- var wrapupSchema = z22.object({
10033
- action: z22.enum(["review", "commit-all"]).optional().describe(
10191
+ var wrapupSchema = z23.object({
10192
+ action: z23.enum(["review", "commit-all"]).optional().describe(
10034
10193
  "Action to perform. 'review' (default) shows the wrapup summary. 'commit-all' accepts all uncommitted drafts; it writes no relations."
10035
10194
  )
10036
10195
  });
@@ -10123,26 +10282,26 @@ ${text}` : text;
10123
10282
  }
10124
10283
 
10125
10284
  // src/tools/facilitate.ts
10126
- import { z as z23 } from "zod/v3";
10285
+ import { z as z24 } from "zod/v3";
10127
10286
  var FACILITATE_ACTIONS = ["resume", "commit-constellation"];
10128
- var coherencyAcknowledgementSchema = z23.object({
10129
- response: z23.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
10130
- entryId: z23.string().max(200).optional().describe("Entry the acknowledgement links to (e.g. the strategic spine entry)."),
10131
- reason: z23.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
10132
- subjectEntryId: z23.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
10287
+ var coherencyAcknowledgementSchema = z24.object({
10288
+ response: z24.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
10289
+ entryId: z24.string().max(200).optional().describe("Entry the acknowledgement links to (e.g. the strategic spine entry)."),
10290
+ reason: z24.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
10291
+ subjectEntryId: z24.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
10133
10292
  });
10134
- var facilitateSchema = z23.object({
10135
- action: z23.enum(FACILITATE_ACTIONS).describe(
10293
+ var facilitateSchema = z24.object({
10294
+ action: z24.enum(FACILITATE_ACTIONS).describe(
10136
10295
  "'resume': load session state from an existing bet entry. 'commit-constellation': atomically accept a bet and all its linked draft entries in one call. Requires betEntryId."
10137
10296
  ),
10138
- betEntryId: z23.string().max(200).optional().describe("Bet entry ID. Required for both actions."),
10139
- operationId: z23.string().max(200).optional().describe("Optional idempotency key for commit-constellation retries."),
10297
+ betEntryId: z24.string().max(200).optional().describe("Bet entry ID. Required for both actions."),
10298
+ operationId: z24.string().max(200).optional().describe("Optional idempotency key for commit-constellation retries."),
10140
10299
  // WP-465 slice ⑤: coherency retry controls for a COHERENCY_REFUSED constellation hold.
10141
10300
  // Forwarded verbatim to agentKnowledge.facilitateEnvelope (validation lives at the gate).
10142
- coherencyAcknowledgements: z23.array(coherencyAcknowledgementSchema).max(20).optional().describe(
10301
+ coherencyAcknowledgements: z24.array(coherencyAcknowledgementSchema).max(20).optional().describe(
10143
10302
  "Per-offender acknowledgements to retry a constellation held under standard/strict coherency mode. Each: {subjectEntryId, response: 'linked' | 'accepted-fix' | 'diverged', entryId?, reason?}."
10144
10303
  ),
10145
- steeringOverrideReason: z23.string().max(2e3).optional().describe(
10304
+ steeringOverrideReason: z24.string().max(2e3).optional().describe(
10146
10305
  "Typed override reason (>= 12 chars) to push a constellation past a coherency hold instead of acknowledging."
10147
10306
  )
10148
10307
  });
@@ -10487,44 +10646,44 @@ var SESSION_ACTIONS = [
10487
10646
  "resume",
10488
10647
  "commit-constellation"
10489
10648
  ];
10490
- var coherencyAcknowledgementFlatSchema2 = z24.object({
10491
- response: z24.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
10492
- entryId: z24.string().max(200).optional().describe("Entry the acknowledgement links to."),
10493
- reason: z24.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
10494
- subjectEntryId: z24.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
10649
+ var coherencyAcknowledgementFlatSchema2 = z25.object({
10650
+ response: z25.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
10651
+ entryId: z25.string().max(200).optional().describe("Entry the acknowledgement links to."),
10652
+ reason: z25.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
10653
+ subjectEntryId: z25.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
10495
10654
  });
10496
- var sessionSchema = z24.object({
10497
- action: z24.enum(SESSION_ACTIONS).describe(
10655
+ var sessionSchema = z25.object({
10656
+ action: z25.enum(SESSION_ACTIONS).describe(
10498
10657
  "'start': begin a tracked session. 'close': end the session and record activity. 'status': check current session state. 'wrapup-review': review uncommitted drafts before closing (absorbs session-wrapup action=review). 'wrapup-commit': accept all uncommitted drafts (absorbs session-wrapup action=commit-all). 'resume': load session state from an existing bet entry (absorbs facilitate action=resume). 'commit-constellation': atomically accept a bet and its linked drafts (absorbs facilitate action=commit-constellation)."
10499
10658
  ),
10500
- betEntryId: z24.string().max(200).optional().describe("For 'resume'/'commit-constellation': bet entry ID. Required for both."),
10501
- operationId: z24.string().max(200).optional().describe("For 'commit-constellation': optional idempotency key for retries."),
10502
- coherencyAcknowledgements: z24.array(coherencyAcknowledgementFlatSchema2).max(20).optional().describe(
10659
+ betEntryId: z25.string().max(200).optional().describe("For 'resume'/'commit-constellation': bet entry ID. Required for both."),
10660
+ operationId: z25.string().max(200).optional().describe("For 'commit-constellation': optional idempotency key for retries."),
10661
+ coherencyAcknowledgements: z25.array(coherencyAcknowledgementFlatSchema2).max(20).optional().describe(
10503
10662
  "For 'commit-constellation': per-offender acknowledgements to retry a constellation held under standard/strict coherency mode."
10504
10663
  ),
10505
- steeringOverrideReason: z24.string().max(2e3).optional().describe(
10664
+ steeringOverrideReason: z25.string().max(2e3).optional().describe(
10506
10665
  "For 'commit-constellation': typed override reason (>= 12 chars) to push past a coherency hold instead of acknowledging."
10507
10666
  ),
10508
10667
  // DEC-1715 (WP-753 O1a)
10509
- role: z24.string().max(200).optional().describe(
10668
+ role: z25.string().max(200).optional().describe(
10510
10669
  "For 'start': role to act as this session, by the '<PREFIX>-<n>' id a start reply prints beside the role name \u2014 only needed if you hold more than one; the error lists your roles if omitted."
10511
10670
  )
10512
10671
  });
10513
- var sessionStartVariant = z24.object({
10514
- action: z24.literal("start"),
10672
+ var sessionStartVariant = z25.object({
10673
+ action: z25.literal("start"),
10515
10674
  // DEC-1715 (WP-753 O1a): the role to act as this session — only needed when the person holds
10516
10675
  // more than one role; the server refuses and lists the choices when it's required and omitted.
10517
- role: z24.string().max(200).optional().describe(
10676
+ role: z25.string().max(200).optional().describe(
10518
10677
  "Role to act as this session, by the '<PREFIX>-<n>' id a start reply prints beside the role name \u2014 only needed if you hold more than one; the error lists your roles if omitted."
10519
10678
  )
10520
10679
  });
10521
- var sessionCloseVariant = z24.object({ action: z24.literal("close") });
10522
- var sessionStatusVariant = z24.object({ action: z24.literal("status") });
10523
- var sessionWrapupReviewVariant = z24.object({ action: z24.literal("wrapup-review") });
10524
- var sessionWrapupCommitVariant = z24.object({ action: z24.literal("wrapup-commit") });
10525
- var sessionResumeVariant = facilitateSchema.omit({ action: true }).extend({ action: z24.literal("resume") });
10526
- var sessionCommitConstellationVariant = facilitateSchema.omit({ action: true }).extend({ action: z24.literal("commit-constellation") });
10527
- var sessionActionUnion = z24.discriminatedUnion("action", [
10680
+ var sessionCloseVariant = z25.object({ action: z25.literal("close") });
10681
+ var sessionStatusVariant = z25.object({ action: z25.literal("status") });
10682
+ var sessionWrapupReviewVariant = z25.object({ action: z25.literal("wrapup-review") });
10683
+ var sessionWrapupCommitVariant = z25.object({ action: z25.literal("wrapup-commit") });
10684
+ var sessionResumeVariant = facilitateSchema.omit({ action: true }).extend({ action: z25.literal("resume") });
10685
+ var sessionCommitConstellationVariant = facilitateSchema.omit({ action: true }).extend({ action: z25.literal("commit-constellation") });
10686
+ var sessionActionUnion = z25.discriminatedUnion("action", [
10528
10687
  sessionStartVariant,
10529
10688
  sessionCloseVariant,
10530
10689
  sessionStatusVariant,
@@ -10775,10 +10934,10 @@ async function handleStatus() {
10775
10934
  }
10776
10935
 
10777
10936
  // src/tools/workspace.ts
10778
- import { z as z27 } from "zod/v3";
10937
+ import { z as z28 } from "zod/v3";
10779
10938
 
10780
10939
  // src/tools/health.ts
10781
- import { z as z25 } from "zod/v3";
10940
+ import { z as z26 } from "zod/v3";
10782
10941
 
10783
10942
  // src/lib/auditView.ts
10784
10943
  async function buildTenantAuditView(limit) {
@@ -11122,60 +11281,60 @@ ${logLines.join("\n")}${seamSummaryText}` }],
11122
11281
  };
11123
11282
  }
11124
11283
  var HEALTH_ACTIONS = ["check", "whoami", "status", "audit", "self-test"];
11125
- var healthSchema = z25.object({
11126
- action: z25.enum(HEALTH_ACTIONS).describe(
11284
+ var healthSchema = z26.object({
11285
+ action: z26.enum(HEALTH_ACTIONS).describe(
11127
11286
  "'check': connectivity and workspace stats. 'whoami': session identity. 'status': workspace readiness. 'audit': session audit log. 'self-test': validate all tool schemas."
11128
11287
  ),
11129
- limit: z25.number().min(1).max(50).default(20).optional().describe("For audit: how many recent calls to show (max 50)")
11288
+ limit: z26.number().min(1).max(50).default(20).optional().describe("For audit: how many recent calls to show (max 50)")
11130
11289
  });
11131
- var healthCheckOutputSchema = z25.object({
11132
- healthy: z25.boolean(),
11133
- collections: z25.number(),
11134
- entries: z25.number(),
11135
- latencyMs: z25.number(),
11136
- workspace: z25.string()
11290
+ var healthCheckOutputSchema = z26.object({
11291
+ healthy: z26.boolean(),
11292
+ collections: z26.number(),
11293
+ entries: z26.number(),
11294
+ latencyMs: z26.number(),
11295
+ workspace: z26.string()
11137
11296
  });
11138
- var organisationHealthSchema = z25.object({
11139
- reviewed: z25.number(),
11140
- agreements: z25.number(),
11141
- disagreements: z25.number(),
11142
- abstentions: z25.number(),
11143
- agreementRate: z25.number(),
11144
- flags: z25.array(z25.object({ collection: z25.string(), count: z25.number(), suggestedCollection: z25.string() }))
11297
+ var organisationHealthSchema = z26.object({
11298
+ reviewed: z26.number(),
11299
+ agreements: z26.number(),
11300
+ disagreements: z26.number(),
11301
+ abstentions: z26.number(),
11302
+ agreementRate: z26.number(),
11303
+ flags: z26.array(z26.object({ collection: z26.string(), count: z26.number(), suggestedCollection: z26.string() }))
11145
11304
  });
11146
- var healthStatusOutputSchema = z25.object({
11147
- sampleTruncated: z25.boolean().nullable().optional(),
11148
- activeEntries: z25.number(),
11149
- totalRelations: z25.number(),
11150
- orphanedEntries: z25.number(),
11151
- checks: z25.array(z25.object({ label: z25.string(), passed: z25.boolean(), current: z25.number(), required: z25.number() })),
11152
- gaps: z25.array(z25.object({ id: z25.string(), label: z25.string(), guidance: z25.string() })),
11305
+ var healthStatusOutputSchema = z26.object({
11306
+ sampleTruncated: z26.boolean().nullable().optional(),
11307
+ activeEntries: z26.number(),
11308
+ totalRelations: z26.number(),
11309
+ orphanedEntries: z26.number(),
11310
+ checks: z26.array(z26.object({ label: z26.string(), passed: z26.boolean(), current: z26.number(), required: z26.number() })),
11311
+ gaps: z26.array(z26.object({ id: z26.string(), label: z26.string(), guidance: z26.string() })),
11153
11312
  organisationHealth: organisationHealthSchema.optional()
11154
11313
  });
11155
- var healthAuditOutputSchema = z25.object({
11156
- totalCalls: z25.number(),
11157
- calls: z25.array(z25.object({
11158
- tool: z25.string(),
11159
- action: z25.string().optional(),
11160
- timestamp: z25.string(),
11161
- durationMs: z25.number().optional()
11314
+ var healthAuditOutputSchema = z26.object({
11315
+ totalCalls: z26.number(),
11316
+ calls: z26.array(z26.object({
11317
+ tool: z26.string(),
11318
+ action: z26.string().optional(),
11319
+ timestamp: z26.string(),
11320
+ durationMs: z26.number().optional()
11162
11321
  }))
11163
11322
  });
11164
- var healthWhoamiOutputSchema = z25.object({
11165
- workspaceId: z25.string(),
11166
- workspaceName: z25.string(),
11167
- scope: z25.string(),
11168
- sessionId: z25.union([z25.string(), z25.null()]),
11169
- oriented: z25.boolean()
11323
+ var healthWhoamiOutputSchema = z26.object({
11324
+ workspaceId: z26.string(),
11325
+ workspaceName: z26.string(),
11326
+ scope: z26.string(),
11327
+ sessionId: z26.union([z26.string(), z26.null()]),
11328
+ oriented: z26.boolean()
11170
11329
  });
11171
- var selfTestOutputSchema = z25.object({
11172
- passed: z25.number(),
11173
- failed: z25.number(),
11174
- total: z25.number(),
11175
- results: z25.array(z25.object({
11176
- tool: z25.string(),
11177
- valid: z25.boolean(),
11178
- error: z25.string().optional()
11330
+ var selfTestOutputSchema = z26.object({
11331
+ passed: z26.number(),
11332
+ failed: z26.number(),
11333
+ total: z26.number(),
11334
+ results: z26.array(z26.object({
11335
+ tool: z26.string(),
11336
+ valid: z26.boolean(),
11337
+ error: z26.string().optional()
11179
11338
  }))
11180
11339
  });
11181
11340
  function handleSelfTest(server) {
@@ -11226,9 +11385,9 @@ function handleSelfTest(server) {
11226
11385
  }
11227
11386
 
11228
11387
  // src/tools/usage.ts
11229
- import { z as z26 } from "zod/v3";
11230
- var usageSummarySchema = z26.object({
11231
- periodDays: z26.number().min(1).max(90).optional().describe("Number of days to look back (default 30, max 90)")
11388
+ import { z as z27 } from "zod/v3";
11389
+ var usageSummarySchema = z27.object({
11390
+ periodDays: z27.number().min(1).max(90).optional().describe("Number of days to look back (default 30, max 90)")
11232
11391
  });
11233
11392
  async function handleUsageSummary(periodDays) {
11234
11393
  const ws = await getWorkspaceContext();
@@ -11298,20 +11457,20 @@ var WORKSPACE_ACTIONS = [
11298
11457
  "self-test",
11299
11458
  "usage"
11300
11459
  ];
11301
- var workspaceSchema = z27.object({
11302
- action: z27.enum(WORKSPACE_ACTIONS).describe(
11460
+ var workspaceSchema = z28.object({
11461
+ action: z28.enum(WORKSPACE_ACTIONS).describe(
11303
11462
  "'check': connectivity and workspace stats (absorbs health action=check). 'whoami': session identity (absorbs health action=whoami). 'status': workspace readiness (absorbs health action=status). 'audit': session audit log (absorbs health action=audit). 'self-test': validate all tool schemas (absorbs health action=self-test). 'usage': LLM usage and cost summary (absorbs get-usage-summary)."
11304
11463
  ),
11305
- limit: z27.number().min(1).max(50).optional().describe("For 'audit': how many recent calls to show (max 50, default 20)."),
11306
- periodDays: z27.number().min(1).max(90).optional().describe("For 'usage': number of days to look back (default 30, max 90).")
11464
+ limit: z28.number().min(1).max(50).optional().describe("For 'audit': how many recent calls to show (max 50, default 20)."),
11465
+ periodDays: z28.number().min(1).max(90).optional().describe("For 'usage': number of days to look back (default 30, max 90).")
11307
11466
  });
11308
- var workspaceCheckVariant = z27.object({ action: z27.literal("check") });
11309
- var workspaceWhoamiVariant = z27.object({ action: z27.literal("whoami") });
11310
- var workspaceStatusVariant = z27.object({ action: z27.literal("status") });
11311
- var workspaceAuditVariant = z27.object({ action: z27.literal("audit"), limit: z27.number().min(1).max(50).optional().default(20) });
11312
- var workspaceSelfTestVariant = z27.object({ action: z27.literal("self-test") });
11313
- var workspaceUsageVariant = z27.object({ action: z27.literal("usage"), periodDays: z27.number().min(1).max(90).optional() });
11314
- var workspaceActionUnion = z27.discriminatedUnion("action", [
11467
+ var workspaceCheckVariant = z28.object({ action: z28.literal("check") });
11468
+ var workspaceWhoamiVariant = z28.object({ action: z28.literal("whoami") });
11469
+ var workspaceStatusVariant = z28.object({ action: z28.literal("status") });
11470
+ var workspaceAuditVariant = z28.object({ action: z28.literal("audit"), limit: z28.number().min(1).max(50).optional().default(20) });
11471
+ var workspaceSelfTestVariant = z28.object({ action: z28.literal("self-test") });
11472
+ var workspaceUsageVariant = z28.object({ action: z28.literal("usage"), periodDays: z28.number().min(1).max(90).optional() });
11473
+ var workspaceActionUnion = z28.discriminatedUnion("action", [
11315
11474
  workspaceCheckVariant,
11316
11475
  workspaceWhoamiVariant,
11317
11476
  workspaceStatusVariant,
@@ -11357,7 +11516,7 @@ function registerWorkspaceTools(server) {
11357
11516
  }
11358
11517
 
11359
11518
  // src/tools/feedback.ts
11360
- import { z as z28 } from "zod/v3";
11519
+ import { z as z29 } from "zod/v3";
11361
11520
 
11362
11521
  // src/lib/productFeedbackConstants.ts
11363
11522
  var PRODUCT_FEEDBACK_CATEGORIES = ["bug", "friction", "idea", "praise", "other"];
@@ -11368,37 +11527,37 @@ var VENDOR_SETTABLE_STATUSES = PRODUCT_FEEDBACK_STATUSES.filter(
11368
11527
 
11369
11528
  // src/tools/feedback.ts
11370
11529
  var actions = ["submit", "list", "queue", "note", "group", "status"];
11371
- var category = z28.enum(PRODUCT_FEEDBACK_CATEGORIES);
11372
- var status = z28.enum(PRODUCT_FEEDBACK_STATUSES);
11373
- var vendorStatus = z28.enum(VENDOR_SETTABLE_STATUSES);
11530
+ var category = z29.enum(PRODUCT_FEEDBACK_CATEGORIES);
11531
+ var status = z29.enum(PRODUCT_FEEDBACK_STATUSES);
11532
+ var vendorStatus = z29.enum(VENDOR_SETTABLE_STATUSES);
11374
11533
  var MESSAGE_DISPLAY_LIMIT = 1e3;
11375
11534
  var FULL_MESSAGE_MAX_LIMIT = 5;
11376
- var feedbackSchema = z28.object({
11377
- action: z28.enum(actions).describe("submit requires message; list returns your own workspace's feedback (all statuses); queue is the vendor triage queue (system admins only) and accepts filters; note requires feedbackId+note; group requires feedbackIds+groupId (null clears); status requires feedbackId+status."),
11378
- message: z28.string().max(1e4).optional().describe("Required for submit: the product feedback text (max 10,000 characters)."),
11535
+ var feedbackSchema = z29.object({
11536
+ action: z29.enum(actions).describe("submit requires message; list returns your own workspace's feedback (all statuses); queue is the vendor triage queue (system admins only) and accepts filters; note requires feedbackId+note; group requires feedbackIds+groupId (null clears); status requires feedbackId+status."),
11537
+ message: z29.string().max(1e4).optional().describe("Required for submit: the product feedback text (max 10,000 characters)."),
11379
11538
  category: category.optional().describe("Submit/queue category; submit defaults to other."),
11380
- command: z28.string().max(1e3).optional().describe("Optional submit command context; argument values are scrubbed server-side."),
11381
- route: z28.string().max(500).optional().describe("Optional submit route context."),
11382
- client: z28.string().max(100).optional().describe("Optional submit client label."),
11383
- feedbackId: z28.string().max(200).optional().describe("Required for note/status: target feedback ID."),
11384
- feedbackIds: z28.array(z28.string().max(200)).max(100).optional().describe("Required for group: 1\u2013100 target feedback IDs."),
11385
- note: z28.string().max(4e3).optional().describe("Required for note: replacement triage note (max 4,000 characters)."),
11539
+ command: z29.string().max(1e3).optional().describe("Optional submit command context; argument values are scrubbed server-side."),
11540
+ route: z29.string().max(500).optional().describe("Optional submit route context."),
11541
+ client: z29.string().max(100).optional().describe("Optional submit client label."),
11542
+ feedbackId: z29.string().max(200).optional().describe("Required for note/status: target feedback ID."),
11543
+ feedbackIds: z29.array(z29.string().max(200)).max(100).optional().describe("Required for group: 1\u2013100 target feedback IDs."),
11544
+ note: z29.string().max(4e3).optional().describe("Required for note: replacement triage note (max 4,000 characters)."),
11386
11545
  status: status.optional().describe("list/queue filter (any status, including 'screening'); the status action's required target value excludes 'screening' (system-only)."),
11387
- groupId: z28.string().min(1).max(200).nullable().optional().describe("Group filter, or required group destination; null explicitly clears grouping."),
11388
- workspaceId: z28.string().max(200).optional().describe("Queue-only filter (vendor cross-workspace triage); omitted means all workspaces. Has no effect on list \u2014 your own workspace is always injected server-side."),
11389
- since: z28.number().optional().describe("Queue-only lower createdAt window bound (inclusive) in epoch milliseconds."),
11390
- before: z28.number().optional().describe("Queue-only upper createdAt window bound (exclusive) in epoch milliseconds. A time-window FILTER, not the pager \u2014 use cursor to page."),
11391
- limit: z28.number().int().min(1).max(100).optional().describe("list/queue row limit, default 50, maximum 100."),
11392
- cursor: z28.string().max(2e3).optional().describe("Opaque pagination cursor from a previous list/queue response (continueCursor); omit for the first page."),
11393
- full: z28.boolean().optional().describe(`list/queue only: return untruncated messages; allowed only when limit <= ${FULL_MESSAGE_MAX_LIMIT}.`)
11546
+ groupId: z29.string().min(1).max(200).nullable().optional().describe("Group filter, or required group destination; null explicitly clears grouping."),
11547
+ workspaceId: z29.string().max(200).optional().describe("Queue-only filter (vendor cross-workspace triage); omitted means all workspaces. Has no effect on list \u2014 your own workspace is always injected server-side."),
11548
+ since: z29.number().optional().describe("Queue-only lower createdAt window bound (inclusive) in epoch milliseconds."),
11549
+ before: z29.number().optional().describe("Queue-only upper createdAt window bound (exclusive) in epoch milliseconds. A time-window FILTER, not the pager \u2014 use cursor to page."),
11550
+ limit: z29.number().int().min(1).max(100).optional().describe("list/queue row limit, default 50, maximum 100."),
11551
+ cursor: z29.string().max(2e3).optional().describe("Opaque pagination cursor from a previous list/queue response (continueCursor); omit for the first page."),
11552
+ full: z29.boolean().optional().describe(`list/queue only: return untruncated messages; allowed only when limit <= ${FULL_MESSAGE_MAX_LIMIT}.`)
11394
11553
  });
11395
- var union = z28.discriminatedUnion("action", [
11396
- z28.object({ action: z28.literal("submit"), message: z28.string().min(1).max(1e4), category: category.optional(), command: z28.string().max(1e3).optional(), route: z28.string().max(500).optional(), client: z28.string().max(100).optional() }),
11397
- z28.object({ action: z28.literal("list"), status: status.optional(), limit: z28.number().int().min(1).max(100).optional(), cursor: z28.string().max(2e3).optional(), full: z28.boolean().optional() }),
11398
- z28.object({ action: z28.literal("queue"), status: status.optional(), category: category.optional(), groupId: z28.string().min(1).max(200).optional(), workspaceId: z28.string().max(200).optional(), since: z28.number().optional(), before: z28.number().optional(), limit: z28.number().int().min(1).max(100).optional(), cursor: z28.string().max(2e3).optional(), full: z28.boolean().optional() }),
11399
- z28.object({ action: z28.literal("note"), feedbackId: z28.string().min(1).max(200), note: z28.string().max(4e3) }),
11400
- z28.object({ action: z28.literal("group"), feedbackIds: z28.array(z28.string().min(1).max(200)).min(1).max(100), groupId: z28.string().min(1).max(200).nullable() }),
11401
- z28.object({ action: z28.literal("status"), feedbackId: z28.string().min(1).max(200), status: vendorStatus })
11554
+ var union = z29.discriminatedUnion("action", [
11555
+ z29.object({ action: z29.literal("submit"), message: z29.string().min(1).max(1e4), category: category.optional(), command: z29.string().max(1e3).optional(), route: z29.string().max(500).optional(), client: z29.string().max(100).optional() }),
11556
+ z29.object({ action: z29.literal("list"), status: status.optional(), limit: z29.number().int().min(1).max(100).optional(), cursor: z29.string().max(2e3).optional(), full: z29.boolean().optional() }),
11557
+ z29.object({ action: z29.literal("queue"), status: status.optional(), category: category.optional(), groupId: z29.string().min(1).max(200).optional(), workspaceId: z29.string().max(200).optional(), since: z29.number().optional(), before: z29.number().optional(), limit: z29.number().int().min(1).max(100).optional(), cursor: z29.string().max(2e3).optional(), full: z29.boolean().optional() }),
11558
+ z29.object({ action: z29.literal("note"), feedbackId: z29.string().min(1).max(200), note: z29.string().max(4e3) }),
11559
+ z29.object({ action: z29.literal("group"), feedbackIds: z29.array(z29.string().min(1).max(200)).min(1).max(100), groupId: z29.string().min(1).max(200).nullable() }),
11560
+ z29.object({ action: z29.literal("status"), feedbackId: z29.string().min(1).max(200), status: vendorStatus })
11402
11561
  ]);
11403
11562
  var specs = {
11404
11563
  submit: { params: ["message", "category", "command", "route", "client"], description: "message is required; category defaults to other." },
@@ -11525,34 +11684,34 @@ function registerFeedbackTool(server) {
11525
11684
  }
11526
11685
 
11527
11686
  // src/tools/shape.ts
11528
- import { z as z29 } from "zod/v3";
11687
+ import { z as z30 } from "zod/v3";
11529
11688
  var SHAPE_ACTIONS = ["list", "show", "agree", "dismiss"];
11530
11689
  var LIST_DISPOSITIONS = ["pending", "agreed", "dismissed", "expired"];
11531
11690
  var LIST_OUTCOMES = ["not_candidate", "atomic", "compound", "unavailable"];
11532
- var shapeSchema = z29.object({
11533
- action: z29.enum(SHAPE_ACTIONS).describe(
11691
+ var shapeSchema = z30.object({
11692
+ action: z30.enum(SHAPE_ACTIONS).describe(
11534
11693
  "'list': list shape advisories for this workspace, latest per subject. 'show': show one shape advisory by id. 'agree': agree with a compound advisory's split verdict. 'dismiss': dismiss a compound advisory's split verdict."
11535
11694
  ),
11536
- disposition: z29.enum(LIST_DISPOSITIONS).optional().describe(
11695
+ disposition: z30.enum(LIST_DISPOSITIONS).optional().describe(
11537
11696
  "For 'list': filter by disposition. Omitting both disposition and outcome defaults to the actionable set (disposition:pending, outcome:compound)."
11538
11697
  ),
11539
- outcome: z29.enum(LIST_OUTCOMES).optional().describe(
11698
+ outcome: z30.enum(LIST_OUTCOMES).optional().describe(
11540
11699
  "For 'list': filter by outcome. Omitting both disposition and outcome defaults to the actionable set (disposition:pending, outcome:compound)."
11541
11700
  ),
11542
- limit: z29.number().min(1).max(200).optional().describe("For 'list': max rows (default 50, max 200)."),
11543
- rowId: z29.string().max(200).optional().describe("For 'show'/'agree'/'dismiss': the advisory row id."),
11544
- reason: z29.string().max(1e3).optional().describe("For 'agree'/'dismiss': optional reason (capped at 1000 chars).")
11701
+ limit: z30.number().min(1).max(200).optional().describe("For 'list': max rows (default 50, max 200)."),
11702
+ rowId: z30.string().max(200).optional().describe("For 'show'/'agree'/'dismiss': the advisory row id."),
11703
+ reason: z30.string().max(1e3).optional().describe("For 'agree'/'dismiss': optional reason (capped at 1000 chars).")
11545
11704
  });
11546
- var shapeListVariant = z29.object({
11547
- action: z29.literal("list"),
11548
- disposition: z29.enum(LIST_DISPOSITIONS).optional(),
11549
- outcome: z29.enum(LIST_OUTCOMES).optional(),
11550
- limit: z29.number().min(1).max(200).optional()
11705
+ var shapeListVariant = z30.object({
11706
+ action: z30.literal("list"),
11707
+ disposition: z30.enum(LIST_DISPOSITIONS).optional(),
11708
+ outcome: z30.enum(LIST_OUTCOMES).optional(),
11709
+ limit: z30.number().min(1).max(200).optional()
11551
11710
  });
11552
- var shapeShowVariant = z29.object({ action: z29.literal("show"), rowId: z29.string().max(200) });
11553
- var shapeAgreeVariant = z29.object({ action: z29.literal("agree"), rowId: z29.string().max(200), reason: z29.string().max(1e3).optional() });
11554
- var shapeDismissVariant = z29.object({ action: z29.literal("dismiss"), rowId: z29.string().max(200), reason: z29.string().max(1e3).optional() });
11555
- var shapeActionUnion = z29.discriminatedUnion("action", [
11711
+ var shapeShowVariant = z30.object({ action: z30.literal("show"), rowId: z30.string().max(200) });
11712
+ var shapeAgreeVariant = z30.object({ action: z30.literal("agree"), rowId: z30.string().max(200), reason: z30.string().max(1e3).optional() });
11713
+ var shapeDismissVariant = z30.object({ action: z30.literal("dismiss"), rowId: z30.string().max(200), reason: z30.string().max(1e3).optional() });
11714
+ var shapeActionUnion = z30.discriminatedUnion("action", [
11556
11715
  shapeListVariant,
11557
11716
  shapeShowVariant,
11558
11717
  shapeAgreeVariant,
@@ -11698,26 +11857,26 @@ function registerShapeTools(server) {
11698
11857
  }
11699
11858
 
11700
11859
  // src/tools/question.ts
11701
- import { z as z30 } from "zod/v3";
11860
+ import { z as z31 } from "zod/v3";
11702
11861
  var QUESTION_ACTIONS = ["create", "assign", "answer", "force-close", "list"];
11703
- var questionSchema = z30.object({
11704
- action: z30.enum(QUESTION_ACTIONS).describe(
11862
+ var questionSchema = z31.object({
11863
+ action: z31.enum(QUESTION_ACTIONS).describe(
11705
11864
  "'create': create a new routed question from text \u2014 the dedicated birth action; every question is born escalated to the team lead (generic entry creation and move-and-retype also pair a routing facet). 'assign': reassign ownership to a role (toRole required \u2014 no bare self-confirm, no toPerson). 'answer': close the loop \u2014 writes the answer on the question and moves it to answered; --entry links an existing decision instead. 'force-close': Team-Lead-only escape hatch \u2014 reason required. 'list': the ack-gate read model \u2014 what you owe (or, with mine:true, every question you asked, including closed ones)."
11706
11865
  ),
11707
- entryId: z30.string().max(200).optional().describe("Target question's id (human TEN-nnn form or a raw entry id). Required for every action except 'create'/'list'."),
11708
- text: z30.string().max(5e3).optional().describe("'create': the question text. 'answer': the answer text (mutually exclusive with answerEntryId, max 2000 chars)."),
11709
- blocks: z30.array(z30.string().max(200)).max(50).optional().describe("'create': entry ids this question is blocking (repeatable)."),
11710
- toRole: z30.string().max(200).optional().describe("'assign': reassign to this role (human ROL-nnn form or a raw entry id) \u2014 required."),
11711
- reason: z30.string().max(2e3).optional().describe("'force-close': required reason."),
11712
- answerEntryId: z30.string().max(200).optional().describe("'answer': point at an already-written entry instead of supplying text (mutually exclusive with text)."),
11713
- mine: z30.boolean().optional().describe("'list': true for arm C (every question YOU asked, every status). Omit/false for the ack-gate view (what you owe).")
11866
+ entryId: z31.string().max(200).optional().describe("Target question's id (human TEN-nnn form or a raw entry id). Required for every action except 'create'/'list'."),
11867
+ text: z31.string().max(5e3).optional().describe("'create': the question text. 'answer': the answer text (mutually exclusive with answerEntryId, max 2000 chars)."),
11868
+ blocks: z31.array(z31.string().max(200)).max(50).optional().describe("'create': entry ids this question is blocking (repeatable)."),
11869
+ toRole: z31.string().max(200).optional().describe("'assign': reassign to this role (human ROL-nnn form or a raw entry id) \u2014 required."),
11870
+ reason: z31.string().max(2e3).optional().describe("'force-close': required reason."),
11871
+ answerEntryId: z31.string().max(200).optional().describe("'answer': point at an already-written entry instead of supplying text (mutually exclusive with text)."),
11872
+ mine: z31.boolean().optional().describe("'list': true for arm C (every question YOU asked, every status). Omit/false for the ack-gate view (what you owe).")
11714
11873
  });
11715
- var createVariant = z30.object({ action: z30.literal("create"), text: z30.string().min(1).max(5e3), blocks: z30.array(z30.string().max(200)).max(50).optional() });
11716
- var assignVariant = z30.object({ action: z30.literal("assign"), entryId: z30.string().max(200), toRole: z30.string().max(200).min(1) });
11717
- var answerVariant = z30.object({ action: z30.literal("answer"), entryId: z30.string().max(200), text: z30.string().max(2e3).optional(), answerEntryId: z30.string().max(200).optional() });
11718
- var forceCloseVariant = z30.object({ action: z30.literal("force-close"), entryId: z30.string().max(200), reason: z30.string().min(1).max(2e3) });
11719
- var listVariant = z30.object({ action: z30.literal("list"), mine: z30.boolean().optional() });
11720
- var questionActionUnion = z30.discriminatedUnion("action", [
11874
+ var createVariant = z31.object({ action: z31.literal("create"), text: z31.string().min(1).max(5e3), blocks: z31.array(z31.string().max(200)).max(50).optional() });
11875
+ var assignVariant = z31.object({ action: z31.literal("assign"), entryId: z31.string().max(200), toRole: z31.string().max(200).min(1) });
11876
+ var answerVariant = z31.object({ action: z31.literal("answer"), entryId: z31.string().max(200), text: z31.string().max(2e3).optional(), answerEntryId: z31.string().max(200).optional() });
11877
+ var forceCloseVariant = z31.object({ action: z31.literal("force-close"), entryId: z31.string().max(200), reason: z31.string().min(1).max(2e3) });
11878
+ var listVariant = z31.object({ action: z31.literal("list"), mine: z31.boolean().optional() });
11879
+ var questionActionUnion = z31.discriminatedUnion("action", [
11721
11880
  createVariant,
11722
11881
  assignVariant,
11723
11882
  answerVariant,
@@ -11871,68 +12030,47 @@ function registerQuestionTools(server) {
11871
12030
  }
11872
12031
 
11873
12032
  // src/tools/role.ts
11874
- import { z as z31 } from "zod/v3";
11875
-
11876
- // src/lib/seatSentence.ts
11877
- function formatSeatSentence(action, reply, clean) {
11878
- if (reply.outcome === "refused") {
11879
- return `Refused: ${reply.refusal?.reason ?? reply.refusal?.code ?? "not allowed"}${reply.refusal?.requiredAction ? ` ${reply.refusal.requiredAction}` : ""}`;
11880
- }
11881
- const who = `${clean(reply.person ?? "")}${reply.personStatus && reply.personStatus !== "active" ? ` (${clean(reply.personStatus)})` : ""}`;
11882
- const roleLabel2 = `${clean(reply.roleName ?? "")} (${reply.role ?? ""})`;
11883
- const teamLabel = clean(reply.teamName ?? "");
11884
- if (action === "seat") {
11885
- const id = reply.personId ? ` [${reply.personId}]` : "";
11886
- return `${reply.created ? "Seated" : "Confirmed"} ${who}${id} as ${roleLabel2} in ${teamLabel}.`;
11887
- }
11888
- return reply.removed ? `Unseated ${who} from ${roleLabel2} in ${teamLabel}.` : `${who} did not hold ${roleLabel2} in ${teamLabel}; nothing changed.`;
11889
- }
11890
- function formatInviteSentence(reply, clean) {
11891
- const who = `${clean(reply.person)} [${reply.personId}]`;
11892
- 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.`;
11893
- }
11894
-
11895
- // src/tools/role.ts
12033
+ import { z as z32 } from "zod/v3";
11896
12034
  var ROLE_ACTIONS = ["accountable", "seat", "unseat"];
11897
- var roleSchema = z31.object({
11898
- action: z31.enum(ROLE_ACTIONS).describe(
12035
+ var roleSchema = z32.object({
12036
+ action: z32.enum(ROLE_ACTIONS).describe(
11899
12037
  "'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."
11900
12038
  ),
11901
- roleId: z31.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."),
11902
- canonicalKey: z31.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
11903
- limit: z31.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
11904
- cursor: z31.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor."),
11905
- person: z31.string().max(200).optional().describe(
12039
+ 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."),
12040
+ canonicalKey: z32.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
12041
+ limit: z32.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
12042
+ cursor: z32.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor."),
12043
+ person: z32.string().max(200).optional().describe(
11906
12044
  "'seat' / 'unseat': an existing person, by person id or exact email. For 'seat', give this or newPersonName, not both."
11907
12045
  ),
11908
- newPersonName: z31.string().max(120).optional().describe(
12046
+ newPersonName: z32.string().max(120).optional().describe(
11909
12047
  "'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."
11910
12048
  ),
11911
- teamId: z31.string().max(200).optional().describe(
12049
+ teamId: z32.string().max(200).optional().describe(
11912
12050
  "'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."
11913
12051
  )
11914
12052
  });
11915
- var accountableVariant = z31.object({
11916
- action: z31.literal("accountable"),
11917
- roleId: z31.string().max(200),
11918
- canonicalKey: z31.string().max(200).optional(),
11919
- limit: z31.number().int().positive().max(200).optional(),
11920
- cursor: z31.number().optional()
12053
+ var accountableVariant = z32.object({
12054
+ action: z32.literal("accountable"),
12055
+ roleId: z32.string().max(200),
12056
+ canonicalKey: z32.string().max(200).optional(),
12057
+ limit: z32.number().int().positive().max(200).optional(),
12058
+ cursor: z32.number().optional()
11921
12059
  });
11922
- var seatVariant = z31.object({
11923
- action: z31.literal("seat"),
11924
- roleId: z31.string().max(200),
11925
- person: z31.string().max(200).optional(),
11926
- newPersonName: z31.string().max(120).optional(),
11927
- teamId: z31.string().max(200).optional()
12060
+ var seatVariant = z32.object({
12061
+ action: z32.literal("seat"),
12062
+ roleId: z32.string().max(200),
12063
+ person: z32.string().max(200).optional(),
12064
+ newPersonName: z32.string().max(120).optional(),
12065
+ teamId: z32.string().max(200).optional()
11928
12066
  });
11929
- var unseatVariant = z31.object({
11930
- action: z31.literal("unseat"),
11931
- roleId: z31.string().max(200),
11932
- person: z31.string().max(200),
11933
- teamId: z31.string().max(200).optional()
12067
+ var unseatVariant = z32.object({
12068
+ action: z32.literal("unseat"),
12069
+ roleId: z32.string().max(200),
12070
+ person: z32.string().max(200),
12071
+ teamId: z32.string().max(200).optional()
11934
12072
  });
11935
- var roleActionUnion = z31.discriminatedUnion("action", [accountableVariant, seatVariant, unseatVariant]);
12073
+ var roleActionUnion = z32.discriminatedUnion("action", [accountableVariant, seatVariant, unseatVariant]);
11936
12074
  var ROLE_ACTION_SPECS = {
11937
12075
  accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." },
11938
12076
  seat: { params: ["roleId", "person", "newPersonName", "teamId"], description: "roleId is required, plus exactly one of person or newPersonName; teamId only for Team Lead." },
@@ -12059,117 +12197,6 @@ function registerRoleTools(server) {
12059
12197
  );
12060
12198
  }
12061
12199
 
12062
- // src/tools/people.ts
12063
- import { z as z32 } from "zod/v3";
12064
- var PEOPLE_ACTIONS = ["invite", "remove"];
12065
- var peopleSchema = z32.object({
12066
- action: z32.enum(PEOPLE_ACTIONS).describe("'invite': send a login link by email. 'remove': take a person out of a team."),
12067
- email: z32.string().max(320).optional().describe("'invite': where the login link goes. Required for 'invite'."),
12068
- person: z32.string().max(320).optional().describe(
12069
- "'invite': a placeholder's person id, instead of newPersonName. 'remove': the person, by person id or exact email."
12070
- ),
12071
- newPersonName: z32.string().max(120).optional().describe("'invite': the name of a new person to invite, instead of person."),
12072
- teamId: z32.string().max(200).optional().describe("'remove': the team, by chain id or entry id. Required for 'remove'.")
12073
- });
12074
- var inviteVariant = z32.object({
12075
- action: z32.literal("invite"),
12076
- email: z32.string().max(320),
12077
- person: z32.string().max(320).optional(),
12078
- newPersonName: z32.string().max(120).optional()
12079
- });
12080
- var removeVariant = z32.object({
12081
- action: z32.literal("remove"),
12082
- person: z32.string().max(320),
12083
- teamId: z32.string().max(200)
12084
- });
12085
- var peopleActionUnion = z32.discriminatedUnion("action", [inviteVariant, removeVariant]);
12086
- var PEOPLE_ACTION_SPECS = {
12087
- invite: { params: ["email", "person", "newPersonName"], description: "email is required, plus exactly one of person (a placeholder's id) or newPersonName." },
12088
- remove: { params: ["person", "teamId"], description: "person and teamId are required." }
12089
- };
12090
- async function handlePeopleInvite(email, person, newPersonName) {
12091
- const params = { email, person, newPersonName };
12092
- try {
12093
- requireWriteAccess();
12094
- const result2 = await kernelMutation("people.invite", {
12095
- email,
12096
- targetPersonId: person,
12097
- displayName: newPersonName,
12098
- sessionId: getAgentSessionId()
12099
- });
12100
- const message = formatInviteSentence(result2, sanitizeSingleLineField);
12101
- return successResult(message, message, result2);
12102
- } catch (err) {
12103
- return peopleErrorResult(err, "invite", params);
12104
- }
12105
- }
12106
- async function handlePeopleRemove(person, teamId) {
12107
- try {
12108
- requireWriteAccess();
12109
- const result2 = await kernelMutation("organisation.removeMembership", {
12110
- targetPersonRef: person,
12111
- teamRef: teamId,
12112
- sessionId: getAgentSessionId()
12113
- });
12114
- if (result2.outcome === "refused") {
12115
- const { reason, requiredAction } = result2.refusal;
12116
- const message2 = `Refused: ${reason}${requiredAction ? ` ${requiredAction}` : ""}`;
12117
- return failureResult(
12118
- message2,
12119
- "PERMISSION_DENIED",
12120
- message2,
12121
- requiredAction ?? "Ask the team's Team Lead to remove them.",
12122
- void 0,
12123
- result2
12124
- );
12125
- }
12126
- const who = sanitizeSingleLineField(result2.person);
12127
- const message = result2.removed ? `Removed ${who} from ${result2.team}.` : `${who} was not assigned to ${result2.team}; nothing changed.`;
12128
- return successResult(message, message, result2);
12129
- } catch (err) {
12130
- return peopleErrorResult(err, "remove", { person, teamId });
12131
- }
12132
- }
12133
- function peopleErrorResult(err, action, params) {
12134
- const classified = classifyError(err);
12135
- const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
12136
- const fallbackActions = retryIsFutile(classified.code) ? void 0 : [{ tool: "people", description: `Retry ${action}`, parameters: { action, ...definedParams } }];
12137
- return failureResult(
12138
- classified.message,
12139
- classified.code,
12140
- classified.message,
12141
- classified.recovery ?? `Fix the input the message names and call action='${action}' again.`,
12142
- classified.availableActions ?? fallbackActions,
12143
- classified.diagnostics
12144
- );
12145
- }
12146
- function registerPeopleTools(server) {
12147
- const peopleHandlers = {
12148
- invite: (data) => handlePeopleInvite(data.email, data.person, data.newPersonName),
12149
- remove: (data) => handlePeopleRemove(data.person, data.teamId)
12150
- };
12151
- server.registerTool(
12152
- "people",
12153
- {
12154
- title: "People",
12155
- description: "People in the workspace. Two actions:\n\n- **invite**: send a login link to `email`. Give `person` (a placeholder's id, as `role action=seat` printed it) to invite that person in place: they keep every role they hold. Or give `newPersonName` to invite someone new. A person who already has a login or an invite is refused. Needs a workspace owner or admin.\n- **remove**: take `person` out of the team `teamId`; every role they hold there goes with it. To take one role, use `role action=unseat`. Needs the team's Team Lead.",
12156
- inputSchema: peopleSchema,
12157
- // TASK-677 (DEC-1981, DEC-74): invite emails an address outside the workspace (open world);
12158
- // remove deletes a membership row and every role on it (destructive); neither is idempotent.
12159
- annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: true }
12160
- },
12161
- thinWrapper(async (args) => {
12162
- const parsed = parseOrFail(peopleSchema, args);
12163
- if (!parsed.ok) return parsed.result;
12164
- const { action } = parsed.data;
12165
- return runWithToolContext(
12166
- { tool: "people", action },
12167
- () => dispatchDiscriminated("people", peopleActionUnion, parsed.data, PEOPLE_ACTION_SPECS, peopleHandlers)
12168
- );
12169
- })
12170
- );
12171
- }
12172
-
12173
12200
  // src/tools/outcome.ts
12174
12201
  import { z as z33 } from "zod/v3";
12175
12202
  var OUTCOME_ACTIONS = ["record", "list", "show"];
@@ -13038,4 +13065,4 @@ export {
13038
13065
  createProductBrainServer,
13039
13066
  initFeatureFlags
13040
13067
  };
13041
- //# sourceMappingURL=chunk-LLNKILES.js.map
13068
+ //# sourceMappingURL=chunk-ETBTCCMU.js.map