@productbrain/mcp 0.0.1-beta.11368 → 0.0.1-beta.11378
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.
- package/dist/{chunk-3AMIZKIT.js → chunk-FYYPTIZM.js} +1042 -1024
- package/dist/chunk-FYYPTIZM.js.map +1 -0
- package/dist/http.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3AMIZKIT.js.map +0 -1
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
|
|
37
37
|
// src/server.ts
|
|
38
38
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
39
|
-
import { z as
|
|
39
|
+
import { z as z36 } from "zod/v3";
|
|
40
40
|
|
|
41
41
|
// src/lib/mcpGatewayClientMessages.ts
|
|
42
42
|
function agentSessionNotActiveMessage(status2) {
|
|
@@ -233,7 +233,7 @@ function resolveEffectiveCollection(result2, preview, fallbackCollection) {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
// src/tools/entries.ts
|
|
236
|
-
import { z as
|
|
236
|
+
import { z as z12 } from "zod/v3";
|
|
237
237
|
|
|
238
238
|
// src/tools/knowledge-helpers.ts
|
|
239
239
|
import { z as z2 } from "zod/v3";
|
|
@@ -565,6 +565,7 @@ function clearSessionGaps() {
|
|
|
565
565
|
}
|
|
566
566
|
|
|
567
567
|
// src/compound-tool.ts
|
|
568
|
+
import { z as z3 } from "zod/v3";
|
|
568
569
|
function backpressureResult(toolName, action, spec, detail) {
|
|
569
570
|
const paramList = spec.params.length > 0 ? spec.params.join(", ") : "(no params)";
|
|
570
571
|
const tip = `action '${action}' needs: ${paramList}. ${spec.description}`;
|
|
@@ -595,6 +596,14 @@ async function dispatchDiscriminated(toolName, union2, flatData, actionSpecs, ha
|
|
|
595
596
|
}
|
|
596
597
|
return handler(parsed.data);
|
|
597
598
|
}
|
|
599
|
+
function actionEnum(actions2, moved) {
|
|
600
|
+
return z3.enum(actions2, {
|
|
601
|
+
errorMap: (issue, ctx) => {
|
|
602
|
+
const received = issue.received;
|
|
603
|
+
return { message: typeof received === "string" && Object.hasOwn(moved, received) ? moved[received] : ctx.defaultError };
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
}
|
|
598
607
|
|
|
599
608
|
// src/lib/restsOn.ts
|
|
600
609
|
var RESTS_ON_SENTENCES = {
|
|
@@ -614,10 +623,10 @@ function restsOnLine(item) {
|
|
|
614
623
|
}
|
|
615
624
|
|
|
616
625
|
// src/tools/knowledge.ts
|
|
617
|
-
import { z as
|
|
626
|
+
import { z as z7 } from "zod/v3";
|
|
618
627
|
|
|
619
628
|
// src/tools/smart-capture.ts
|
|
620
|
-
import { z as
|
|
629
|
+
import { z as z5 } from "zod/v3";
|
|
621
630
|
|
|
622
631
|
// src/lib/statusCategories.ts
|
|
623
632
|
var STATUS_CATEGORIES = ["draft", "current", "past", "discarded"];
|
|
@@ -863,29 +872,29 @@ function formatRubricVerdictSection(verdict2) {
|
|
|
863
872
|
}
|
|
864
873
|
|
|
865
874
|
// src/lib/captureSinglePreviewOutput.ts
|
|
866
|
-
import { z as
|
|
867
|
-
var groundingDuplicateEntrySchema =
|
|
868
|
-
entryId:
|
|
869
|
-
name:
|
|
870
|
-
collectionSlug:
|
|
871
|
-
overlapRatio:
|
|
875
|
+
import { z as z4 } from "zod/v3";
|
|
876
|
+
var groundingDuplicateEntrySchema = z4.object({
|
|
877
|
+
entryId: z4.string(),
|
|
878
|
+
name: z4.string(),
|
|
879
|
+
collectionSlug: z4.string(),
|
|
880
|
+
overlapRatio: z4.number()
|
|
872
881
|
});
|
|
873
|
-
var groundingReportSchema =
|
|
882
|
+
var groundingReportSchema = z4.object({
|
|
874
883
|
// TASK-156: null preserves uncertainty for unavailable checks or an older server response.
|
|
875
|
-
scanTruncated:
|
|
876
|
-
duplicates:
|
|
884
|
+
scanTruncated: z4.boolean().nullable(),
|
|
885
|
+
duplicates: z4.array(groundingDuplicateEntrySchema)
|
|
877
886
|
});
|
|
878
|
-
var taskAlignmentSchema =
|
|
879
|
-
var captureSinglePreviewOutputSchema =
|
|
880
|
-
preflight:
|
|
881
|
-
entryId:
|
|
882
|
-
name:
|
|
883
|
-
collection:
|
|
884
|
-
outcome:
|
|
887
|
+
var taskAlignmentSchema = z4.record(z4.unknown());
|
|
888
|
+
var captureSinglePreviewOutputSchema = z4.object({
|
|
889
|
+
preflight: z4.custom().optional(),
|
|
890
|
+
entryId: z4.string(),
|
|
891
|
+
name: z4.string(),
|
|
892
|
+
collection: z4.string(),
|
|
893
|
+
outcome: z4.enum(["preview", "blocked"]),
|
|
885
894
|
// Present only when `outcome: "blocked"` AND the server supplied a reason.
|
|
886
|
-
blockingReason:
|
|
895
|
+
blockingReason: z4.string().optional(),
|
|
887
896
|
// Always present — `result.warnings ?? []`, never omitted.
|
|
888
|
-
warnings:
|
|
897
|
+
warnings: z4.array(z4.string()),
|
|
889
898
|
groundingReport: groundingReportSchema,
|
|
890
899
|
// TEN-2458: only present when the kernel computed a librarian verdict for this preview.
|
|
891
900
|
taskAlignment: taskAlignmentSchema.optional()
|
|
@@ -902,116 +911,116 @@ var RELATION_BATCH_MAX = 25;
|
|
|
902
911
|
var CAPTURE_LINK_OUTCOMES = ["written", "refused"];
|
|
903
912
|
var SPINE_FLOOR_SENTENCE = "kept as a draft; it can be accepted once its spine above is accepted \u2014 the promote door checks the whole spine and names the first missing rung.";
|
|
904
913
|
var SPINE_FLOOR_EXEMPT_SENTENCE = "kept as a draft, though this workspace is not yet enforcing the spine above it \u2014 it can be accepted as-is.";
|
|
905
|
-
var captureSchema =
|
|
906
|
-
collection:
|
|
907
|
-
name:
|
|
908
|
-
description:
|
|
909
|
-
context:
|
|
910
|
-
canonicalKey:
|
|
911
|
-
data:
|
|
912
|
-
why:
|
|
914
|
+
var captureSchema = z5.object({
|
|
915
|
+
collection: z5.string().optional().describe("Collection slug, e.g. 'tensions', 'rules', 'glossary', 'decisions'. Optional \u2014 the kernel classifies when omitted."),
|
|
916
|
+
name: z5.string().describe("Display name \u2014 be specific (e.g. 'Convex adjacency list won't scale for graph traversal')"),
|
|
917
|
+
description: z5.string().describe("Full context \u2014 what's happening, why it matters, what you observed"),
|
|
918
|
+
context: z5.string().optional().describe("Optional additional context (e.g. 'Observed during context gather calls taking 700ms+'); appended to the description, stored only when the description is."),
|
|
919
|
+
canonicalKey: z5.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'vision'). Auto-assigned from collection if omitted."),
|
|
920
|
+
data: z5.record(z5.unknown()).optional().describe("Explicit field values when you know the schema (e.g. canonical_key, cardinality_rule, required_fields). Merged with inferred values; user-provided wins."),
|
|
921
|
+
why: z5.string().optional().describe("Reasoning behind this entry \u2014 hard-required for purpose/vision/strategy/objective/decision/rule/key_result/product."),
|
|
913
922
|
// TASK-380: mirrors whyPolicy.ts
|
|
914
|
-
links:
|
|
915
|
-
to:
|
|
916
|
-
type:
|
|
923
|
+
links: z5.array(z5.object({
|
|
924
|
+
to: z5.string().describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
|
|
925
|
+
type: z5.string().describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
|
|
917
926
|
})).optional().describe("Links written with the entry in one transaction; each returns written or refused with a reason; a refused link fails nothing."),
|
|
918
|
-
sourceRef:
|
|
919
|
-
sourceExcerpt:
|
|
927
|
+
sourceRef: z5.string().optional().describe("URI or path of the source document backing this entry (e.g. 'meeting-2026-03-28.md', 'import://batch-5'). Stored as top-level entry field, not in data."),
|
|
928
|
+
sourceExcerpt: z5.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data."),
|
|
920
929
|
// WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
|
|
921
|
-
preview:
|
|
930
|
+
preview: z5.boolean().optional().describe("If true, validates the capture without writing. Returns what would happen. Default false."),
|
|
922
931
|
// 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.
|
|
923
|
-
ownerRoleEntryId:
|
|
932
|
+
ownerRoleEntryId: z5.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)."),
|
|
924
933
|
// TASK-681 (DEC-1976, DEC-1977): where a new role or team sits, forwarded as createEntry's teamRef; the kernel places it.
|
|
925
|
-
team:
|
|
934
|
+
team: z5.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.")
|
|
926
935
|
});
|
|
927
|
-
var captureClassifierSchema =
|
|
928
|
-
enabled:
|
|
929
|
-
autoRouted:
|
|
930
|
-
agrees:
|
|
931
|
-
abstained:
|
|
932
|
-
topConfidence:
|
|
933
|
-
confidence:
|
|
934
|
-
reasons:
|
|
935
|
-
candidates:
|
|
936
|
-
|
|
937
|
-
collection:
|
|
938
|
-
signalScore:
|
|
939
|
-
confidence:
|
|
936
|
+
var captureClassifierSchema = z5.object({
|
|
937
|
+
enabled: z5.boolean(),
|
|
938
|
+
autoRouted: z5.boolean(),
|
|
939
|
+
agrees: z5.boolean(),
|
|
940
|
+
abstained: z5.boolean(),
|
|
941
|
+
topConfidence: z5.number(),
|
|
942
|
+
confidence: z5.number(),
|
|
943
|
+
reasons: z5.array(z5.string()),
|
|
944
|
+
candidates: z5.array(
|
|
945
|
+
z5.object({
|
|
946
|
+
collection: z5.string(),
|
|
947
|
+
signalScore: z5.number().optional(),
|
|
948
|
+
confidence: z5.number(),
|
|
940
949
|
/** WP-316 S2: required-field cost — how many fields the agent must supply for this collection. */
|
|
941
|
-
requiredFieldCount:
|
|
950
|
+
requiredFieldCount: z5.number().optional()
|
|
942
951
|
})
|
|
943
952
|
),
|
|
944
|
-
agentProvidedCollection:
|
|
945
|
-
overrideCommand:
|
|
946
|
-
classifiedBy:
|
|
947
|
-
confidenceTier:
|
|
948
|
-
reasoning:
|
|
953
|
+
agentProvidedCollection: z5.string().optional(),
|
|
954
|
+
overrideCommand: z5.string().optional(),
|
|
955
|
+
classifiedBy: z5.string().optional(),
|
|
956
|
+
confidenceTier: z5.string().optional(),
|
|
957
|
+
reasoning: z5.string().optional()
|
|
949
958
|
});
|
|
950
|
-
var captureSuccessOutputSchema =
|
|
951
|
-
entryId:
|
|
952
|
-
collection:
|
|
953
|
-
name:
|
|
954
|
-
status:
|
|
959
|
+
var captureSuccessOutputSchema = z5.object({
|
|
960
|
+
entryId: z5.string(),
|
|
961
|
+
collection: z5.string(),
|
|
962
|
+
name: z5.string(),
|
|
963
|
+
status: z5.enum(["draft", "committed", "proposed", "draft_on_failure"]),
|
|
955
964
|
// WP-480 S1: `qualityScore` deleted (accepted breaking output change); the server verdict stays as `qualityVerdict`.
|
|
956
|
-
qualityVerdict:
|
|
957
|
-
qualityHints:
|
|
965
|
+
qualityVerdict: z5.record(z5.unknown()).optional(),
|
|
966
|
+
qualityHints: z5.array(z5.record(z5.unknown())).optional(),
|
|
958
967
|
groundingReport: captureSinglePreviewOutputSchema.shape.groundingReport.optional(),
|
|
959
968
|
classifier: captureClassifierSchema.optional(),
|
|
960
|
-
studioUrl:
|
|
969
|
+
studioUrl: z5.string().optional(),
|
|
961
970
|
// never set since TASK-964 (the chains-only Cortex link left with the retired drawer); kept, never narrowed (DEC-1831)
|
|
962
|
-
warnings:
|
|
963
|
-
normalization:
|
|
964
|
-
remapped:
|
|
965
|
-
rejected:
|
|
971
|
+
warnings: z5.array(z5.string()).optional(),
|
|
972
|
+
normalization: z5.object({
|
|
973
|
+
remapped: z5.record(z5.string()).optional(),
|
|
974
|
+
rejected: z5.array(z5.string()).optional()
|
|
966
975
|
}).optional(),
|
|
967
|
-
expectedFields:
|
|
968
|
-
key:
|
|
969
|
-
type:
|
|
970
|
-
required:
|
|
976
|
+
expectedFields: z5.array(z5.object({
|
|
977
|
+
key: z5.string(),
|
|
978
|
+
type: z5.string(),
|
|
979
|
+
required: z5.boolean().optional()
|
|
971
980
|
})).optional(),
|
|
972
981
|
// TASK-160: the server's birth-floor verdict must survive the strict output contract.
|
|
973
|
-
spineFloor:
|
|
982
|
+
spineFloor: z5.object({ relationType: z5.string(), parentKind: z5.string(), exempt: z5.boolean() }).optional(),
|
|
974
983
|
// WP-751 M3a-1b (TASK-189, DEC-1700): `coherencyRefusal` and `contradictionAdvisory` are deleted with the
|
|
975
984
|
// client-side auto-commit attempt that alone populated them (its gate refusal, the commit's advisory).
|
|
976
|
-
replayed:
|
|
985
|
+
replayed: z5.literal(true).optional(),
|
|
977
986
|
// TASK-898: a re-sent capture answered with the first capture's entry
|
|
978
987
|
// TASK-897: the kernel's outcome per link, on a create and on a replay.
|
|
979
|
-
links:
|
|
980
|
-
fallbackApplied:
|
|
988
|
+
links: z5.array(z5.object({ toEntryId: z5.string(), type: z5.string(), outcome: z5.enum(CAPTURE_LINK_OUTCOMES), reason: z5.string().optional(), line: z5.string() }).passthrough()).optional(),
|
|
989
|
+
fallbackApplied: z5.boolean().optional()
|
|
981
990
|
// never set since TASK-964 (the kernel classifies among live collections only); kept, never narrowed (DEC-1831)
|
|
982
991
|
}).strict();
|
|
983
|
-
var captureOutputSchema =
|
|
992
|
+
var captureOutputSchema = z5.union([
|
|
984
993
|
captureSuccessOutputSchema,
|
|
985
994
|
captureSinglePreviewOutputSchema
|
|
986
995
|
]);
|
|
987
996
|
var CAPTURE_ACTIONS = ["capture"];
|
|
988
997
|
var SUGGEST_ONLY_REMOVED = "suggestOnly was removed: call capture with preview: true to check a capture without writing.";
|
|
989
|
-
var captureCompoundSchema =
|
|
990
|
-
action:
|
|
991
|
-
collection:
|
|
992
|
-
name:
|
|
993
|
-
description:
|
|
994
|
-
context:
|
|
995
|
-
canonicalKey:
|
|
996
|
-
data:
|
|
997
|
-
why:
|
|
998
|
-
links:
|
|
999
|
-
to:
|
|
1000
|
-
type:
|
|
998
|
+
var captureCompoundSchema = z5.object({
|
|
999
|
+
action: z5.enum(CAPTURE_ACTIONS).optional().default("capture").describe("Create a single knowledge entry."),
|
|
1000
|
+
collection: z5.string().max(200).optional().describe("Collection slug, e.g. 'tensions', 'rules', 'glossary', 'decisions'. Optional \u2014 the kernel classifies when omitted."),
|
|
1001
|
+
name: z5.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Display name \u2014 required."),
|
|
1002
|
+
description: z5.string().max(ENTRY_BODY_MAX_CHARS).optional().describe("Full context, in Markdown \u2014 required."),
|
|
1003
|
+
context: z5.string().max(5e3).optional().describe("Optional additional context; appended to the description, so it is stored only when the description is (not when data carries the prose field)."),
|
|
1004
|
+
canonicalKey: z5.string().max(200).optional().describe("Semantic type (e.g. 'decision', 'tension', 'vision'). Auto-assigned from collection if omitted."),
|
|
1005
|
+
data: z5.record(z5.unknown()).optional().describe("Explicit field values; user-provided wins over inferred."),
|
|
1006
|
+
why: z5.string().max(ENTRY_BODY_MAX_CHARS).optional().describe("Why this entry exists."),
|
|
1007
|
+
links: z5.array(z5.object({
|
|
1008
|
+
to: z5.string().max(200).describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
|
|
1009
|
+
type: z5.string().max(200).describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
|
|
1001
1010
|
})).max(RELATION_BATCH_MAX).optional().describe("Links written with the entry in one transaction; each returns written or refused with a reason; a refused link fails nothing."),
|
|
1002
|
-
sourceRef:
|
|
1003
|
-
sourceExcerpt:
|
|
1004
|
-
preview:
|
|
1005
|
-
suggestOnly:
|
|
1011
|
+
sourceRef: z5.string().max(2e3).optional().describe("URI or path of the source document backing this entry."),
|
|
1012
|
+
sourceExcerpt: z5.string().max(SOURCE_EXCERPT_MAX_CHARS).optional().describe("Verbatim excerpt from the source backing this entry's claims."),
|
|
1013
|
+
preview: z5.boolean().optional().describe("If true, validates without writing."),
|
|
1014
|
+
suggestOnly: z5.never({ invalid_type_error: SUGGEST_ONLY_REMOVED }).optional().describe(SUGGEST_ONLY_REMOVED),
|
|
1006
1015
|
// TASK-608: refused, never stripped into a write.
|
|
1007
1016
|
// 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.
|
|
1008
|
-
ownerRoleEntryId:
|
|
1009
|
-
team:
|
|
1017
|
+
ownerRoleEntryId: z5.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)."),
|
|
1018
|
+
team: z5.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.")
|
|
1010
1019
|
});
|
|
1011
|
-
var captureSingleVariant = captureSchema.extend({ action:
|
|
1020
|
+
var captureSingleVariant = captureSchema.extend({ action: z5.literal("capture") });
|
|
1012
1021
|
var CAVEAT_JUDGE_LATE = "The duplicate check is still running; a close match it finds is added to this entry as a check.";
|
|
1013
1022
|
var CAVEAT_SCAN_CAPPED = "The duplicate check read a capped sample; more matching entries may exist. Review existing entries before creating another.";
|
|
1014
|
-
var captureActionUnion =
|
|
1023
|
+
var captureActionUnion = z5.discriminatedUnion("action", [
|
|
1015
1024
|
captureSingleVariant
|
|
1016
1025
|
]);
|
|
1017
1026
|
var CAPTURE_ACTION_SPECS = {
|
|
@@ -1530,9 +1539,9 @@ ${recovery}`,
|
|
|
1530
1539
|
}
|
|
1531
1540
|
|
|
1532
1541
|
// src/tools/knowledge/getHistory.ts
|
|
1533
|
-
import { z as
|
|
1534
|
-
var getHistorySchema =
|
|
1535
|
-
entryId:
|
|
1542
|
+
import { z as z6 } from "zod/v3";
|
|
1543
|
+
var getHistorySchema = z6.object({
|
|
1544
|
+
entryId: z6.string().describe("Entry ID, e.g. '<PREFIX>-<n>'")
|
|
1536
1545
|
});
|
|
1537
1546
|
async function handleGetHistory({ entryId }) {
|
|
1538
1547
|
const envelope = await kernelCallEnvelope("chain.listEntryHistory", { entryId });
|
|
@@ -1568,44 +1577,44 @@ ${cut}${formatted}` }],
|
|
|
1568
1577
|
}
|
|
1569
1578
|
|
|
1570
1579
|
// src/tools/knowledge.ts
|
|
1571
|
-
var updateEntrySchema =
|
|
1572
|
-
entryId:
|
|
1573
|
-
name:
|
|
1580
|
+
var updateEntrySchema = z7.object({
|
|
1581
|
+
entryId: z7.string().describe("Entry ID to update, e.g. '<PREFIX>-<n>'"),
|
|
1582
|
+
name: z7.string().optional().describe("New display name"),
|
|
1574
1583
|
// Chain-ID-leak guard (check:chain-id-leaks): the retired legacy-shim ticket number stays in
|
|
1575
1584
|
// the code comment above, never in this user-visible describe() string. T8 (TASK-393, WP-779): narrowed to generated ENTRY_STATUS_WRITE_WORDS.
|
|
1576
|
-
status:
|
|
1577
|
-
workflowStatus:
|
|
1578
|
-
data:
|
|
1579
|
-
order:
|
|
1580
|
-
canonicalKey:
|
|
1581
|
-
autoPublish:
|
|
1585
|
+
status: z7.enum(ENTRY_STATUS_WRITE_WORDS).optional().describe(`Lifecycle status: ${ENTRY_STATUS_WRITE_WORDS.join(" | ")}. 'accepted' is set via 'commit', never 'update'; 'active'/'deprecated' are legacy words and are refused here. Use \`workflowStatus\` for collection-specific workflow values \u2014 those are no longer accepted via \`status\`.`),
|
|
1586
|
+
workflowStatus: z7.string().optional().describe("Collection workflow state. Valid values are collection-specific and server-owned \u2014 discover them via `collections action=describe` for the target collection. The server rejects invalid values and returns the valid set in the error."),
|
|
1587
|
+
data: z7.record(z7.unknown()).optional().describe("Fields to update (merged with existing data)"),
|
|
1588
|
+
order: z7.number().optional().describe("New sort order"),
|
|
1589
|
+
canonicalKey: z7.string().optional().describe("Semantic type (e.g. 'decision', 'tension'). Only changeable on draft/uncommitted entries."),
|
|
1590
|
+
autoPublish: z7.boolean().optional().default(false).describe("Accepted for backward compatibility but IGNORED \u2014 draft vs. published is decided by the entry's own accepted/active status, never by this flag. Removal tracked as a follow-up."),
|
|
1582
1591
|
// DEC-1716
|
|
1583
|
-
changeReason:
|
|
1584
|
-
changeNote:
|
|
1585
|
-
sourceRef:
|
|
1586
|
-
sourceExcerpt:
|
|
1592
|
+
changeReason: z7.string().optional().describe("Change reason: required when this update changes a promise field (or the name of a collection that declares one) of an accepted entry \u2014 why what the entry promises is changing. Recorded on the history event and the version. Not the same as changeNote."),
|
|
1593
|
+
changeNote: z7.string().optional().describe("Strongly recommended: short human-readable rationale for WHY this change was made (e.g. 'Aligned description with F1-themed copy'). Surfaces in activity feed and pb get. If omitted, falls back to session purpose or auto-generated field summary."),
|
|
1594
|
+
sourceRef: z7.string().optional().describe("URI or path of the source document backing this entry. Write-once: can only be set if currently empty."),
|
|
1595
|
+
sourceExcerpt: z7.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Write-once: can only be set if currently empty."),
|
|
1587
1596
|
// WP-465 slice ⑤ — relay-only (TEN-2233): validation/min-length/recording live in Convex.
|
|
1588
|
-
steeringOverrideReason:
|
|
1589
|
-
qualityOverrideReason:
|
|
1597
|
+
steeringOverrideReason: z7.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block on a misaligned governance write \u2014 always recorded with author attribution."),
|
|
1598
|
+
qualityOverrideReason: z7.string().optional().describe("Why (\u226512 chars) to keep an accepted spine text its quality checklist failed \u2014 recorded as an override with who wrote it."),
|
|
1590
1599
|
// TASK-954
|
|
1591
|
-
coherencyAcknowledgement:
|
|
1592
|
-
response:
|
|
1593
|
-
entryId:
|
|
1594
|
-
reason:
|
|
1600
|
+
coherencyAcknowledgement: z7.object({
|
|
1601
|
+
response: z7.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
|
|
1602
|
+
entryId: z7.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
|
|
1603
|
+
reason: z7.string().optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
|
|
1595
1604
|
}).optional().describe("Explicit response to a coherency challenge (standard/strict workspace modes). One acknowledgement per challenge per entry per session.")
|
|
1596
1605
|
});
|
|
1597
|
-
var commitEntrySchema =
|
|
1598
|
-
entryId:
|
|
1606
|
+
var commitEntrySchema = z7.object({
|
|
1607
|
+
entryId: z7.string().describe("Entry ID to accept, e.g. 'TEN-abc123', '<PREFIX>-<n>'"),
|
|
1599
1608
|
// WP-316 S3: Preview gate — dry-run mode. Returns would-succeed result, no DB writes.
|
|
1600
|
-
preview:
|
|
1609
|
+
preview: z7.boolean().optional().describe("If true, validates the accept without writing. Returns what would happen. Default false."),
|
|
1601
1610
|
// WP-465 slice ⑤ — relay-only (TEN-2233): validation/recording live in Convex.
|
|
1602
|
-
steeringOverrideReason:
|
|
1603
|
-
qualityOverrideReason:
|
|
1611
|
+
steeringOverrideReason: z7.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block at the publish chokepoint \u2014 always recorded with author attribution."),
|
|
1612
|
+
qualityOverrideReason: z7.string().optional().describe("Why (\u226512 chars) to accept over a failing quality checklist \u2014 recorded as an override with who wrote it."),
|
|
1604
1613
|
// TASK-954
|
|
1605
|
-
coherencyAcknowledgement:
|
|
1606
|
-
response:
|
|
1607
|
-
entryId:
|
|
1608
|
-
reason:
|
|
1614
|
+
coherencyAcknowledgement: z7.object({
|
|
1615
|
+
response: z7.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
|
|
1616
|
+
entryId: z7.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
|
|
1617
|
+
reason: z7.string().optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
|
|
1609
1618
|
}).optional().describe("Explicit response to a coherency challenge (standard/strict workspace modes).")
|
|
1610
1619
|
});
|
|
1611
1620
|
async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, changeReason, sourceRef, sourceExcerpt, steeringOverrideReason, qualityOverrideReason, coherencyAcknowledgement }, toolName = "entries") {
|
|
@@ -1923,7 +1932,7 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
|
|
|
1923
1932
|
// src/tools/verify.ts
|
|
1924
1933
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
1925
1934
|
import { resolve as resolve2 } from "path";
|
|
1926
|
-
import { z as
|
|
1935
|
+
import { z as z8 } from "zod/v3";
|
|
1927
1936
|
|
|
1928
1937
|
// src/lib/resolve-project-root.ts
|
|
1929
1938
|
import { existsSync } from "fs";
|
|
@@ -2075,12 +2084,12 @@ function formatTrustReport(collection, entryCount, mappings, refs, fixes, mode2,
|
|
|
2075
2084
|
lines.push("", "---", `_Schema: ${schemaTableCount} tables parsed from convex/schema.ts. Project root: ${projectRoot}_`);
|
|
2076
2085
|
return lines.join("\n");
|
|
2077
2086
|
}
|
|
2078
|
-
var verifySchema =
|
|
2079
|
-
collection:
|
|
2080
|
-
mode:
|
|
2087
|
+
var verifySchema = z8.object({
|
|
2088
|
+
collection: z8.string().max(200).default("glossary").describe("Collection slug to verify (default: glossary)"),
|
|
2089
|
+
mode: z8.enum(["report", "fix"]).default("report").describe("'report' = read-only trust report. 'fix' = also update drifted codeMapping statuses.")
|
|
2081
2090
|
});
|
|
2082
|
-
var verifyEntrySchema =
|
|
2083
|
-
entryId:
|
|
2091
|
+
var verifyEntrySchema = z8.object({
|
|
2092
|
+
entryId: z8.string().max(200).describe("Human entry ID (e.g. '<PREFIX>-<n>') to mark as verified")
|
|
2084
2093
|
});
|
|
2085
2094
|
async function handleVerifyChain(server, { collection, mode: mode2 }) {
|
|
2086
2095
|
const projectRoot = resolveProjectRoot();
|
|
@@ -2297,9 +2306,9 @@ async function handleVerifyEntry({ entryId }) {
|
|
|
2297
2306
|
}
|
|
2298
2307
|
|
|
2299
2308
|
// src/tools/stillTrue.ts
|
|
2300
|
-
import { z as
|
|
2301
|
-
var stillTrueEntrySchema =
|
|
2302
|
-
entryId:
|
|
2309
|
+
import { z as z9 } from "zod/v3";
|
|
2310
|
+
var stillTrueEntrySchema = z9.object({
|
|
2311
|
+
entryId: z9.string().max(200).describe("Human entry ID (e.g. '<PREFIX>-<n>') to confirm is still true.")
|
|
2303
2312
|
});
|
|
2304
2313
|
async function handleStillTrueEntry({ entryId }) {
|
|
2305
2314
|
requireWriteAccess();
|
|
@@ -2313,14 +2322,14 @@ async function handleStillTrueEntry({ entryId }) {
|
|
|
2313
2322
|
}
|
|
2314
2323
|
|
|
2315
2324
|
// src/tools/entry-move.ts
|
|
2316
|
-
import { z as
|
|
2317
|
-
var moveEntrySchema =
|
|
2318
|
-
entryId:
|
|
2319
|
-
toCollection:
|
|
2325
|
+
import { z as z10 } from "zod/v3";
|
|
2326
|
+
var moveEntrySchema = z10.object({
|
|
2327
|
+
entryId: z10.string().describe("Entry ID to move, e.g. '<PREFIX>-<n>'"),
|
|
2328
|
+
toCollection: z10.string().describe("Target collection slug, e.g. 'decisions', 'architecture'"),
|
|
2320
2329
|
// WP-707 S2 (TASK-146): optional atomic move+RETYPE — validates and persists the entry's NEW
|
|
2321
2330
|
// canonicalKey and its destination collection in the SAME write (convex/agentKnowledge/
|
|
2322
2331
|
// moveToCollectionOperation.ts round 3, DEC-1622). Omit for a plain same-kind relocation.
|
|
2323
|
-
canonicalKey:
|
|
2332
|
+
canonicalKey: z10.string().optional().describe(
|
|
2324
2333
|
"Optional: also reclassify the entry to this canonical key atomically with the move (e.g. 'decision', 'objective'). Omit for a plain relocation."
|
|
2325
2334
|
)
|
|
2326
2335
|
});
|
|
@@ -2414,85 +2423,83 @@ function platformSearchLines(platform) {
|
|
|
2414
2423
|
}
|
|
2415
2424
|
|
|
2416
2425
|
// src/tools/entriesContract.ts
|
|
2417
|
-
import { z as
|
|
2426
|
+
import { z as z11 } from "zod/v3";
|
|
2418
2427
|
var ENTRIES_ACTIONS = [
|
|
2419
2428
|
"update",
|
|
2420
2429
|
"commit",
|
|
2421
2430
|
"move",
|
|
2422
2431
|
"verify",
|
|
2423
|
-
"preflight",
|
|
2424
2432
|
"still-true"
|
|
2425
2433
|
];
|
|
2426
|
-
var coherencyAcknowledgementFlatSchema =
|
|
2427
|
-
response:
|
|
2428
|
-
entryId:
|
|
2429
|
-
reason:
|
|
2434
|
+
var coherencyAcknowledgementFlatSchema = z11.object({
|
|
2435
|
+
response: z11.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
|
|
2436
|
+
entryId: z11.string().max(200).optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
|
|
2437
|
+
reason: z11.string().max(2e3).optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
|
|
2430
2438
|
});
|
|
2431
|
-
var
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2439
|
+
var ENTRIES_READS_MOVED = {
|
|
2440
|
+
preflight: "entries only writes. Check a collection's requirements with the read-only context tool: context action=preflight collection=..."
|
|
2441
|
+
};
|
|
2442
|
+
var entriesSchema = z11.object({
|
|
2443
|
+
action: actionEnum(ENTRIES_ACTIONS, ENTRIES_READS_MOVED).describe(
|
|
2444
|
+
"'update': change fields on an existing entry (draft by default). 'commit': accept a draft entry onto the Chain. 'move': relocate an entry to a different collection (pass `canonicalKey` too for an atomic move+retype). 'verify': mark an entry as verified (lightweight \u2014 no codebase scan; see `quality action=verify-chain` for that). 'still-true': confirm accuracy (the holder of the owning role, else the nearest seated Team Lead) \u2014 distinct from 'verify'; no content, version, or updatedAt change."
|
|
2436
2445
|
),
|
|
2437
|
-
entryId:
|
|
2446
|
+
entryId: z11.string().max(200).optional().describe(
|
|
2438
2447
|
"Entry ID, e.g. '<PREFIX>-<n>'. Required for: update, commit, move, verify, still-true."
|
|
2439
2448
|
),
|
|
2440
|
-
|
|
2441
|
-
status: z10.string().max(200).optional().describe(
|
|
2449
|
+
status: z11.string().max(200).optional().describe(
|
|
2442
2450
|
"For 'update': draft|archived ONLY \u2014 'accepted' is set via 'commit', never 'update'; 'active'/'deprecated' are legacy read-only words, refused on write. Workflow values use `workflowStatus` instead."
|
|
2443
2451
|
),
|
|
2444
|
-
name:
|
|
2445
|
-
workflowStatus:
|
|
2452
|
+
name: z11.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("For 'update': new display name."),
|
|
2453
|
+
workflowStatus: z11.string().max(200).optional().describe(
|
|
2446
2454
|
"For 'update': collection workflow state. Valid values are collection-specific and server-owned \u2014 discover via `collections action=describe`. Invalid values are rejected with the valid set."
|
|
2447
2455
|
),
|
|
2448
|
-
data:
|
|
2449
|
-
order:
|
|
2450
|
-
canonicalKey:
|
|
2451
|
-
"For 'update': semantic type (e.g. 'decision', 'tension'); only changeable on draft/uncommitted entries. For 'move': optional atomic move+retype target.
|
|
2456
|
+
data: z11.record(z11.unknown()).optional().describe("For 'update': fields to update (merged with existing data)."),
|
|
2457
|
+
order: z11.number().optional().describe("For 'update': new sort order."),
|
|
2458
|
+
canonicalKey: z11.string().max(200).optional().describe(
|
|
2459
|
+
"For 'update': semantic type (e.g. 'decision', 'tension'); only changeable on draft/uncommitted entries. For 'move': optional atomic move+retype target."
|
|
2452
2460
|
),
|
|
2453
2461
|
// DEC-1716: draft vs. published is decided by the entry's own accepted/active status, never this flag.
|
|
2454
|
-
autoPublish:
|
|
2462
|
+
autoPublish: z11.boolean().optional().default(false).describe(
|
|
2455
2463
|
"For 'update': accepted for backward compatibility but IGNORED \u2014 draft vs. published is decided by the entry's own accepted/active status, never by this flag."
|
|
2456
2464
|
),
|
|
2457
|
-
changeReason:
|
|
2465
|
+
changeReason: z11.string().max(2e3).optional().describe(
|
|
2458
2466
|
"For 'update': Change reason \u2014 required when the update changes a promise field of an accepted entry. Recorded on the history event and the version."
|
|
2459
2467
|
),
|
|
2460
|
-
changeNote:
|
|
2468
|
+
changeNote: z11.string().max(2e3).optional().describe(
|
|
2461
2469
|
"For 'update': short human-readable rationale for WHY this change was made. Surfaces in activity feed."
|
|
2462
2470
|
),
|
|
2463
|
-
sourceRef:
|
|
2471
|
+
sourceRef: z11.string().max(2e3).optional().describe(
|
|
2464
2472
|
"For 'update': URI or path of the source document backing this entry. Write-once."
|
|
2465
2473
|
),
|
|
2466
|
-
sourceExcerpt:
|
|
2474
|
+
sourceExcerpt: z11.string().max(SOURCE_EXCERPT_MAX_CHARS).optional().describe(
|
|
2467
2475
|
"For 'update': verbatim excerpt from the source backing this entry's claims. Write-once."
|
|
2468
2476
|
),
|
|
2469
|
-
steeringOverrideReason:
|
|
2477
|
+
steeringOverrideReason: z11.string().max(2e3).optional().describe(
|
|
2470
2478
|
"For 'update'/'commit': typed override (\u226512 chars) that clears a steering coherency block."
|
|
2471
2479
|
),
|
|
2472
|
-
qualityOverrideReason:
|
|
2480
|
+
qualityOverrideReason: z11.string().max(2e3).optional().describe(
|
|
2473
2481
|
"For 'update'/'commit': why (\u226512 chars) to keep a spine text its quality checklist failed; recorded as an override with who wrote it."
|
|
2474
2482
|
),
|
|
2475
2483
|
coherencyAcknowledgement: coherencyAcknowledgementFlatSchema.optional().describe(
|
|
2476
2484
|
"For 'update'/'commit': explicit response to a coherency challenge (standard/strict workspace modes)."
|
|
2477
2485
|
),
|
|
2478
|
-
preview:
|
|
2486
|
+
preview: z11.boolean().optional().describe(
|
|
2479
2487
|
"For 'commit': if true, validates the accept without writing \u2014 returns what would happen."
|
|
2480
2488
|
),
|
|
2481
|
-
toCollection:
|
|
2489
|
+
toCollection: z11.string().max(200).optional().describe("For 'move': target collection slug, e.g. 'decisions', 'architecture'.")
|
|
2482
2490
|
});
|
|
2483
|
-
var entriesUpdateVariant = updateEntrySchema.extend({ action:
|
|
2484
|
-
var entriesCommitVariant = commitEntrySchema.extend({ action:
|
|
2485
|
-
var entriesMoveVariant =
|
|
2486
|
-
action:
|
|
2487
|
-
entryId:
|
|
2488
|
-
toCollection:
|
|
2489
|
-
canonicalKey:
|
|
2491
|
+
var entriesUpdateVariant = updateEntrySchema.extend({ action: z11.literal("update") });
|
|
2492
|
+
var entriesCommitVariant = commitEntrySchema.extend({ action: z11.literal("commit") });
|
|
2493
|
+
var entriesMoveVariant = z11.object({
|
|
2494
|
+
action: z11.literal("move"),
|
|
2495
|
+
entryId: z11.string().max(200),
|
|
2496
|
+
toCollection: z11.string().max(200),
|
|
2497
|
+
canonicalKey: z11.string().max(200).optional()
|
|
2490
2498
|
// WP-707 S2: optional atomic move+RETYPE.
|
|
2491
2499
|
});
|
|
2492
|
-
var entriesVerifyVariant = verifyEntrySchema.extend({ action:
|
|
2493
|
-
var entriesStillTrueVariant = stillTrueEntrySchema.extend({ action:
|
|
2494
|
-
var entriesActionUnion =
|
|
2495
|
-
z10.object({ action: z10.literal("preflight"), collection: z10.string().max(200), canonicalKey: z10.string().max(200).optional(), links: preflightLinks }),
|
|
2500
|
+
var entriesVerifyVariant = verifyEntrySchema.extend({ action: z11.literal("verify") });
|
|
2501
|
+
var entriesStillTrueVariant = stillTrueEntrySchema.extend({ action: z11.literal("still-true") });
|
|
2502
|
+
var entriesActionUnion = z11.discriminatedUnion("action", [
|
|
2496
2503
|
entriesUpdateVariant,
|
|
2497
2504
|
entriesCommitVariant,
|
|
2498
2505
|
entriesMoveVariant,
|
|
@@ -2500,7 +2507,6 @@ var entriesActionUnion = z10.discriminatedUnion("action", [
|
|
|
2500
2507
|
entriesStillTrueVariant
|
|
2501
2508
|
]);
|
|
2502
2509
|
var ENTRIES_ACTION_SPECS = {
|
|
2503
|
-
preflight: { params: ["collection", "canonicalKey", "links"], description: "Inspect structure before composition; no writes or permission grant." },
|
|
2504
2510
|
update: { params: ["entryId", "name", "status", "workflowStatus", "data", "order", "canonicalKey", "autoPublish", "changeNote", "changeReason", "sourceRef", "sourceExcerpt", "steeringOverrideReason", "qualityOverrideReason", "coherencyAcknowledgement"], description: "entryId is required; every other field is optional." },
|
|
2505
2511
|
commit: { params: ["entryId", "preview", "steeringOverrideReason", "qualityOverrideReason", "coherencyAcknowledgement"], description: "entryId is required." },
|
|
2506
2512
|
move: { params: ["entryId", "toCollection", "canonicalKey"], description: "entryId and toCollection are required; canonicalKey is optional (atomic move+retype)." },
|
|
@@ -2562,16 +2568,16 @@ function renderVerificationLine(e) {
|
|
|
2562
2568
|
}
|
|
2563
2569
|
return `**Verification:** ${String(e.verificationStatus)}${who}`;
|
|
2564
2570
|
}
|
|
2565
|
-
var wqSchema =
|
|
2566
|
-
var entriesGetOutputSchema =
|
|
2567
|
-
entryId:
|
|
2568
|
-
name:
|
|
2569
|
-
collection:
|
|
2570
|
-
status:
|
|
2571
|
-
capturedAt:
|
|
2572
|
-
origin:
|
|
2573
|
-
originDetail:
|
|
2574
|
-
verificationStatus:
|
|
2571
|
+
var wqSchema = z12.enum(["rationale", "missing", "restated"]);
|
|
2572
|
+
var entriesGetOutputSchema = z12.object({
|
|
2573
|
+
entryId: z12.string(),
|
|
2574
|
+
name: z12.string(),
|
|
2575
|
+
collection: z12.string(),
|
|
2576
|
+
status: z12.string(),
|
|
2577
|
+
capturedAt: z12.number().optional(),
|
|
2578
|
+
origin: z12.string().optional(),
|
|
2579
|
+
originDetail: z12.string().optional(),
|
|
2580
|
+
verificationStatus: z12.string().optional(),
|
|
2575
2581
|
// Attestation-model finding (PR #341 review): the server's honest verifier label and
|
|
2576
2582
|
// derived attestation strength/basis — connectors NEVER re-derive strength (spec §5),
|
|
2577
2583
|
// they only render what chain.getEntry ships. Mirrors packages/cli EntryFromApi.
|
|
@@ -2580,80 +2586,76 @@ var entriesGetOutputSchema = z11.object({
|
|
|
2580
2586
|
// attestation.ts's AttestationStrength SSOT (allowlisted in Check D —
|
|
2581
2587
|
// scripts/check-collection-ssot.mjs's CHECK_D_ALLOWLIST — with the full
|
|
2582
2588
|
// reasoning for why this can't just import that module). Update both together.
|
|
2583
|
-
verifiedBy:
|
|
2584
|
-
attestation:
|
|
2585
|
-
strength:
|
|
2586
|
-
basis:
|
|
2589
|
+
verifiedBy: z12.string().optional(),
|
|
2590
|
+
attestation: z12.object({
|
|
2591
|
+
strength: z12.enum(["human-direct", "delegated", "system", "unattested"]),
|
|
2592
|
+
basis: z12.string().optional()
|
|
2587
2593
|
}).optional(),
|
|
2588
|
-
sourceRef:
|
|
2589
|
-
sourceExcerpt:
|
|
2590
|
-
why:
|
|
2594
|
+
sourceRef: z12.string().optional(),
|
|
2595
|
+
sourceExcerpt: z12.string().optional(),
|
|
2596
|
+
why: z12.string().optional(),
|
|
2591
2597
|
whyQuality: wqSchema.optional(),
|
|
2592
|
-
data:
|
|
2593
|
-
relations:
|
|
2594
|
-
entryId:
|
|
2595
|
-
name:
|
|
2596
|
-
type:
|
|
2597
|
-
direction:
|
|
2598
|
-
status:
|
|
2598
|
+
data: z12.record(z12.unknown()).optional(),
|
|
2599
|
+
relations: z12.array(z12.object({
|
|
2600
|
+
entryId: z12.string().optional(),
|
|
2601
|
+
name: z12.string(),
|
|
2602
|
+
type: z12.string(),
|
|
2603
|
+
direction: z12.string(),
|
|
2604
|
+
status: z12.string().optional()
|
|
2599
2605
|
})).optional(),
|
|
2600
|
-
labels:
|
|
2606
|
+
labels: z12.array(z12.string()).optional(),
|
|
2601
2607
|
owner: ownerOutputShape.optional()
|
|
2602
2608
|
}).passthrough();
|
|
2603
|
-
var entriesListOutputSchema =
|
|
2604
|
-
entries:
|
|
2605
|
-
entryId:
|
|
2606
|
-
name:
|
|
2607
|
-
collection:
|
|
2608
|
-
status:
|
|
2609
|
+
var entriesListOutputSchema = z12.object({
|
|
2610
|
+
entries: z12.array(z12.object({
|
|
2611
|
+
entryId: z12.string(),
|
|
2612
|
+
name: z12.string(),
|
|
2613
|
+
collection: z12.string(),
|
|
2614
|
+
status: z12.string()
|
|
2609
2615
|
})),
|
|
2610
|
-
total:
|
|
2616
|
+
total: z12.number()
|
|
2611
2617
|
});
|
|
2612
|
-
var entriesSearchOutputSchema =
|
|
2613
|
-
results:
|
|
2614
|
-
entryId:
|
|
2615
|
-
name:
|
|
2616
|
-
collection:
|
|
2617
|
-
status:
|
|
2618
|
-
score:
|
|
2618
|
+
var entriesSearchOutputSchema = z12.object({
|
|
2619
|
+
results: z12.array(z12.object({
|
|
2620
|
+
entryId: z12.string(),
|
|
2621
|
+
name: z12.string(),
|
|
2622
|
+
collection: z12.string(),
|
|
2623
|
+
status: z12.string(),
|
|
2624
|
+
score: z12.number().optional()
|
|
2619
2625
|
})),
|
|
2620
|
-
total:
|
|
2621
|
-
query:
|
|
2626
|
+
total: z12.number(),
|
|
2627
|
+
query: z12.string()
|
|
2622
2628
|
});
|
|
2623
|
-
var entriesBatchOutputSchema =
|
|
2624
|
-
entries:
|
|
2625
|
-
entryId:
|
|
2626
|
-
name:
|
|
2627
|
-
collection:
|
|
2628
|
-
status:
|
|
2629
|
-
capturedAt:
|
|
2630
|
-
origin:
|
|
2631
|
-
originDetail:
|
|
2632
|
-
verificationStatus:
|
|
2629
|
+
var entriesBatchOutputSchema = z12.object({
|
|
2630
|
+
entries: z12.array(z12.object({
|
|
2631
|
+
entryId: z12.string(),
|
|
2632
|
+
name: z12.string(),
|
|
2633
|
+
collection: z12.string(),
|
|
2634
|
+
status: z12.string(),
|
|
2635
|
+
capturedAt: z12.number().optional(),
|
|
2636
|
+
origin: z12.string().optional(),
|
|
2637
|
+
originDetail: z12.string().optional(),
|
|
2638
|
+
verificationStatus: z12.string().optional(),
|
|
2633
2639
|
// Attestation-model finding (PR #341 review): mirror entriesGetOutputSchema — batch
|
|
2634
2640
|
// entries now carry the same honest verifiedBy/attestation fields. Literal set is
|
|
2635
2641
|
// the same hand-kept SSOT mirror — see entriesGetOutputSchema's attestation
|
|
2636
2642
|
// comment above for the full Check D / kernel-import reasoning.
|
|
2637
|
-
verifiedBy:
|
|
2638
|
-
attestation:
|
|
2639
|
-
strength:
|
|
2640
|
-
basis:
|
|
2643
|
+
verifiedBy: z12.string().optional(),
|
|
2644
|
+
attestation: z12.object({
|
|
2645
|
+
strength: z12.enum(["human-direct", "delegated", "system", "unattested"]),
|
|
2646
|
+
basis: z12.string().optional()
|
|
2641
2647
|
}).optional(),
|
|
2642
|
-
sourceRef:
|
|
2643
|
-
sourceExcerpt:
|
|
2644
|
-
why:
|
|
2648
|
+
sourceRef: z12.string().optional(),
|
|
2649
|
+
sourceExcerpt: z12.string().optional(),
|
|
2650
|
+
why: z12.string().optional(),
|
|
2645
2651
|
// TEN-2191: mirrors entriesGetOutputSchema
|
|
2646
2652
|
whyQuality: wqSchema.optional(),
|
|
2647
|
-
data:
|
|
2653
|
+
data: z12.record(z12.unknown()).optional()
|
|
2648
2654
|
}).passthrough()),
|
|
2649
|
-
total:
|
|
2655
|
+
total: z12.number()
|
|
2650
2656
|
});
|
|
2651
2657
|
function registerEntriesTools(server) {
|
|
2652
2658
|
const entriesHandlers = {
|
|
2653
|
-
preflight: async (data) => {
|
|
2654
|
-
const result2 = await kernelQuery("chain.preflightEntry", { collectionSlug: data.collection, canonicalKey: data.canonicalKey, links: data.links });
|
|
2655
|
-
return { content: [{ type: "text", text: renderEntryPreflight(result2).join("\n") }], structuredContent: success("Structural requirements checked; nothing saved.", result2) };
|
|
2656
|
-
},
|
|
2657
2659
|
// update/commit reuse knowledge.ts's extracted handlers — "entries" routes
|
|
2658
2660
|
// `next` at itself (toolName="entries") instead of the legacy tool names.
|
|
2659
2661
|
update: (data) => handleUpdateEntry(data, "entries"),
|
|
@@ -2666,7 +2668,7 @@ function registerEntriesTools(server) {
|
|
|
2666
2668
|
"entries",
|
|
2667
2669
|
{
|
|
2668
2670
|
title: "Entries",
|
|
2669
|
-
description: 'Write entries on the Chain: the entry lifecycle after capture. Reads live on `context`.\n\n- **
|
|
2671
|
+
description: 'Write entries on the Chain: the entry lifecycle after capture. Reads live on `context`.\n\n- **update**: Change fields on an existing entry (publishes whenever the entry is not draft \u2014 includes archived, not just accepted/active; autoPublish is accepted but ignored).\n- **commit**: Accept a draft entry onto the Chain (SSOT). Runs the contradiction preflight first.\n- **move**: Relocate an entry to a different collection; pass canonicalKey too for an atomic move+retype.\n- **verify**: Mark verified (lightweight, no scan \u2014 see `quality action=verify-chain`).\n- **still-true**: confirm accuracy (the holder of the owning role; if that role is empty, the nearest seated Team Lead up the team tree).\n\nRead entries with the read-only `context` tool: `context action=get entryId="..."`, `context action=search query="..."`, `context action=preflight`.',
|
|
2670
2672
|
inputSchema: entriesSchema,
|
|
2671
2673
|
// DEC-1894 / DEC-74: every look-up lives on the read-only `context` tool, so this
|
|
2672
2674
|
// annotation tells hosts the truth about the writes left here.
|
|
@@ -2683,6 +2685,10 @@ function registerEntriesTools(server) {
|
|
|
2683
2685
|
})
|
|
2684
2686
|
);
|
|
2685
2687
|
}
|
|
2688
|
+
async function handleEntryPreflight(collection, canonicalKey, links) {
|
|
2689
|
+
const result2 = await kernelQuery("chain.preflightEntry", { collectionSlug: collection, canonicalKey, links });
|
|
2690
|
+
return { content: [{ type: "text", text: renderEntryPreflight(result2).join("\n") }], structuredContent: success("Structural requirements checked; nothing saved.", result2) };
|
|
2691
|
+
}
|
|
2686
2692
|
async function handleGet(entryId) {
|
|
2687
2693
|
const entry = await kernelQuery("chain.getEntry", { entryId });
|
|
2688
2694
|
if (!entry) {
|
|
@@ -3010,42 +3016,42 @@ ${footer}` }],
|
|
|
3010
3016
|
}
|
|
3011
3017
|
|
|
3012
3018
|
// src/tools/relations.ts
|
|
3013
|
-
import { z as
|
|
3019
|
+
import { z as z13 } from "zod/v3";
|
|
3014
3020
|
var RELATIONS_ACTIONS = ["create", "batch-create", "delete"];
|
|
3015
|
-
var relationItemSchema =
|
|
3016
|
-
from:
|
|
3017
|
-
to:
|
|
3018
|
-
type:
|
|
3021
|
+
var relationItemSchema = z13.object({
|
|
3022
|
+
from: z13.string().max(200),
|
|
3023
|
+
to: z13.string().max(200),
|
|
3024
|
+
type: z13.string().max(200)
|
|
3019
3025
|
});
|
|
3020
|
-
var relationsSchema =
|
|
3021
|
-
action:
|
|
3026
|
+
var relationsSchema = z13.object({
|
|
3027
|
+
action: z13.enum(RELATIONS_ACTIONS).describe(
|
|
3022
3028
|
"'create': link two entries. 'batch-create': create multiple relations (validates every item before writing any). 'delete': remove a relation."
|
|
3023
3029
|
),
|
|
3024
|
-
from:
|
|
3025
|
-
to:
|
|
3026
|
-
type:
|
|
3027
|
-
relations:
|
|
3030
|
+
from: z13.string().max(200).optional().describe("For 'create'/'delete': source entry ID."),
|
|
3031
|
+
to: z13.string().max(200).optional().describe("For 'create'/'delete': target entry ID."),
|
|
3032
|
+
type: z13.string().max(200).optional().describe("For 'create'/'delete': relation type."),
|
|
3033
|
+
relations: z13.array(relationItemSchema).min(1).max(RELATION_BATCH_MAX).optional().describe("For 'batch-create': array of {from, to, type}."),
|
|
3028
3034
|
// WP-316 S3: Preview gate — dry-run mode for action=create.
|
|
3029
|
-
preview:
|
|
3035
|
+
preview: z13.boolean().optional().describe("For 'create': if true, validates the relation without writing. Returns what would happen. Default false.")
|
|
3030
3036
|
});
|
|
3031
|
-
var relationsCreateVariant =
|
|
3032
|
-
action:
|
|
3033
|
-
from:
|
|
3034
|
-
to:
|
|
3035
|
-
type:
|
|
3036
|
-
preview:
|
|
3037
|
+
var relationsCreateVariant = z13.object({
|
|
3038
|
+
action: z13.literal("create"),
|
|
3039
|
+
from: z13.string().max(200),
|
|
3040
|
+
to: z13.string().max(200),
|
|
3041
|
+
type: z13.string().max(200),
|
|
3042
|
+
preview: z13.boolean().optional()
|
|
3037
3043
|
});
|
|
3038
|
-
var relationsBatchCreateVariant =
|
|
3039
|
-
action:
|
|
3040
|
-
relations:
|
|
3044
|
+
var relationsBatchCreateVariant = z13.object({
|
|
3045
|
+
action: z13.literal("batch-create"),
|
|
3046
|
+
relations: z13.array(relationItemSchema).min(1).max(RELATION_BATCH_MAX)
|
|
3041
3047
|
});
|
|
3042
|
-
var relationsDeleteVariant =
|
|
3043
|
-
action:
|
|
3044
|
-
from:
|
|
3045
|
-
to:
|
|
3046
|
-
type:
|
|
3048
|
+
var relationsDeleteVariant = z13.object({
|
|
3049
|
+
action: z13.literal("delete"),
|
|
3050
|
+
from: z13.string().max(200),
|
|
3051
|
+
to: z13.string().max(200),
|
|
3052
|
+
type: z13.string().max(200)
|
|
3047
3053
|
});
|
|
3048
|
-
var relationsActionUnion =
|
|
3054
|
+
var relationsActionUnion = z13.discriminatedUnion("action", [
|
|
3049
3055
|
relationsCreateVariant,
|
|
3050
3056
|
relationsBatchCreateVariant,
|
|
3051
3057
|
relationsDeleteVariant
|
|
@@ -3267,22 +3273,22 @@ async function handleDelete(from, to, type) {
|
|
|
3267
3273
|
}
|
|
3268
3274
|
|
|
3269
3275
|
// src/tools/context.ts
|
|
3270
|
-
import { z as
|
|
3276
|
+
import { z as z20 } from "zod/v3";
|
|
3271
3277
|
|
|
3272
3278
|
// src/lib/readinessNotices.ts
|
|
3273
3279
|
var READINESS_PROVISIONAL_LINE = "Readiness is provisional: its sample omitted accepted entries. Counts are lower bounds, apparent gaps may already be covered.";
|
|
3274
3280
|
|
|
3275
3281
|
// src/tools/documents.ts
|
|
3276
|
-
import { z as
|
|
3282
|
+
import { z as z14 } from "zod/v3";
|
|
3277
3283
|
var DOCUMENTS_ACTIONS = ["get-last-verified-brief"];
|
|
3278
|
-
var documentsSchema =
|
|
3279
|
-
action:
|
|
3284
|
+
var documentsSchema = z14.object({
|
|
3285
|
+
action: z14.enum(DOCUMENTS_ACTIONS).describe(
|
|
3280
3286
|
"'get-last-verified-brief': fetch the most recent verified brief snapshot for a (templateId, scopeKey) pair. Returns the verified summary so agents can build delta narratives ('since you last verified, X workstreams advanced')."
|
|
3281
3287
|
),
|
|
3282
|
-
templateId:
|
|
3288
|
+
templateId: z14.string().max(200).describe(
|
|
3283
3289
|
"Brief template identifier \u2014 currently 'steering-brief' is the only registered template."
|
|
3284
3290
|
),
|
|
3285
|
-
scopeKey:
|
|
3291
|
+
scopeKey: z14.string().max(200).describe(
|
|
3286
3292
|
"Canonical scope key. Use 'workspace:<workspaceId>' for the full workspace brief, or 'initiative:<INI-ID>' for an initiative-scoped brief. The same formula is applied at write time (chainwork/docKernel/scopeKey.ts), so passing the wrong shape returns exists:false."
|
|
3287
3293
|
)
|
|
3288
3294
|
});
|
|
@@ -3351,27 +3357,27 @@ This row pre-dates snapshot capture (legacy backfill), so no summary is availabl
|
|
|
3351
3357
|
}
|
|
3352
3358
|
|
|
3353
3359
|
// src/tools/contextLookups.ts
|
|
3354
|
-
import { z as
|
|
3360
|
+
import { z as z19 } from "zod/v3";
|
|
3355
3361
|
|
|
3356
3362
|
// src/tools/graph.ts
|
|
3357
|
-
import { z as
|
|
3363
|
+
import { z as z15 } from "zod/v3";
|
|
3358
3364
|
var GRAPH_ACTIONS = ["find"];
|
|
3359
|
-
var graphSchema =
|
|
3360
|
-
action:
|
|
3365
|
+
var graphSchema = z15.object({
|
|
3366
|
+
action: z15.enum(GRAPH_ACTIONS).describe(
|
|
3361
3367
|
"'find': traverse relations from an entry (graph walk)."
|
|
3362
3368
|
),
|
|
3363
|
-
entryId:
|
|
3364
|
-
direction:
|
|
3369
|
+
entryId: z15.string().max(200).describe("Entry ID, e.g. '<PREFIX>-<n>'"),
|
|
3370
|
+
direction: z15.enum(["incoming", "outgoing", "both"]).default("both").optional().describe("For find: 'incoming' = what references this, 'outgoing' = what this references")
|
|
3365
3371
|
});
|
|
3366
|
-
var graphFindOutputSchema =
|
|
3367
|
-
entryId:
|
|
3368
|
-
relations:
|
|
3369
|
-
entryId:
|
|
3370
|
-
name:
|
|
3371
|
-
type:
|
|
3372
|
-
direction:
|
|
3372
|
+
var graphFindOutputSchema = z15.object({
|
|
3373
|
+
entryId: z15.string(),
|
|
3374
|
+
relations: z15.array(z15.object({
|
|
3375
|
+
entryId: z15.string().optional(),
|
|
3376
|
+
name: z15.string(),
|
|
3377
|
+
type: z15.string(),
|
|
3378
|
+
direction: z15.enum(["outgoing", "incoming"])
|
|
3373
3379
|
})),
|
|
3374
|
-
total:
|
|
3380
|
+
total: z15.number()
|
|
3375
3381
|
});
|
|
3376
3382
|
async function handleFind(entryId, direction) {
|
|
3377
3383
|
const relations = await kernelQuery("chain.listEntryRelations", { entryId });
|
|
@@ -3472,7 +3478,7 @@ async function handleFind(entryId, direction) {
|
|
|
3472
3478
|
}
|
|
3473
3479
|
|
|
3474
3480
|
// src/tools/people.ts
|
|
3475
|
-
import { z as
|
|
3481
|
+
import { z as z16 } from "zod/v3";
|
|
3476
3482
|
|
|
3477
3483
|
// src/lib/seatSentence.ts
|
|
3478
3484
|
var PERSON_STATUS_WORDS = {
|
|
@@ -3528,27 +3534,27 @@ var ORGANISATION_VALIDATION_REFUSALS = /* @__PURE__ */ new Set([
|
|
|
3528
3534
|
|
|
3529
3535
|
// src/tools/people.ts
|
|
3530
3536
|
var PEOPLE_ACTIONS = ["invite", "remove"];
|
|
3531
|
-
var peopleSchema =
|
|
3532
|
-
action:
|
|
3533
|
-
email:
|
|
3534
|
-
person:
|
|
3537
|
+
var peopleSchema = z16.object({
|
|
3538
|
+
action: z16.enum(PEOPLE_ACTIONS).describe("'invite': send a login link by email. 'remove': take a person out of a team."),
|
|
3539
|
+
email: z16.string().max(320).optional().describe("'invite': where the login link goes. Required for 'invite'."),
|
|
3540
|
+
person: z16.string().max(320).optional().describe(
|
|
3535
3541
|
"'invite': a placeholder's person id, instead of newPersonName. 'remove': the person, by person id or exact email."
|
|
3536
3542
|
),
|
|
3537
|
-
newPersonName:
|
|
3538
|
-
teamId:
|
|
3543
|
+
newPersonName: z16.string().max(120).optional().describe("'invite': the name of a new person to invite, instead of person."),
|
|
3544
|
+
teamId: z16.string().max(200).optional().describe("'remove': the team, by chain id or entry id. Required for 'remove'.")
|
|
3539
3545
|
});
|
|
3540
|
-
var inviteVariant =
|
|
3541
|
-
action:
|
|
3542
|
-
email:
|
|
3543
|
-
person:
|
|
3544
|
-
newPersonName:
|
|
3546
|
+
var inviteVariant = z16.object({
|
|
3547
|
+
action: z16.literal("invite"),
|
|
3548
|
+
email: z16.string().max(320),
|
|
3549
|
+
person: z16.string().max(320).optional(),
|
|
3550
|
+
newPersonName: z16.string().max(120).optional()
|
|
3545
3551
|
});
|
|
3546
|
-
var removeVariant =
|
|
3547
|
-
action:
|
|
3548
|
-
person:
|
|
3549
|
-
teamId:
|
|
3552
|
+
var removeVariant = z16.object({
|
|
3553
|
+
action: z16.literal("remove"),
|
|
3554
|
+
person: z16.string().max(320),
|
|
3555
|
+
teamId: z16.string().max(200)
|
|
3550
3556
|
});
|
|
3551
|
-
var peopleActionUnion =
|
|
3557
|
+
var peopleActionUnion = z16.discriminatedUnion("action", [inviteVariant, removeVariant]);
|
|
3552
3558
|
var PEOPLE_ACTION_SPECS = {
|
|
3553
3559
|
invite: { params: ["email", "person", "newPersonName"], description: "email is required, plus exactly one of person (a placeholder's id) or newPersonName." },
|
|
3554
3560
|
remove: { params: ["person", "teamId"], description: "person and teamId are required." }
|
|
@@ -3658,7 +3664,7 @@ function registerPeopleTools(server) {
|
|
|
3658
3664
|
}
|
|
3659
3665
|
|
|
3660
3666
|
// src/tools/outcome.ts
|
|
3661
|
-
import { z as
|
|
3667
|
+
import { z as z17 } from "zod/v3";
|
|
3662
3668
|
|
|
3663
3669
|
// src/lib/outcomeObjectiveLines.ts
|
|
3664
3670
|
var LOOKUP_LINE = {
|
|
@@ -3687,40 +3693,39 @@ function formatOutcomeObjectiveLines(view, clean) {
|
|
|
3687
3693
|
var OUTCOME_ACTIONS = ["record"];
|
|
3688
3694
|
var OUTCOME_READS_MOVED = "outcome only records readings. Read with the read-only context tool: context action=outcome entryId=... (the derived view, its objective and sibling key results) or context action=readings entryId=... (the readings, newest first).";
|
|
3689
3695
|
var READING_KINDS = ["measurement", "estimate", "correction"];
|
|
3690
|
-
var outcomeSchema =
|
|
3691
|
-
|
|
3692
|
-
action: z16.enum(OUTCOME_ACTIONS, { errorMap: () => ({ message: OUTCOME_READS_MOVED }) }).describe(
|
|
3696
|
+
var outcomeSchema = z17.object({
|
|
3697
|
+
action: actionEnum(OUTCOME_ACTIONS, { list: OUTCOME_READS_MOVED, show: OUTCOME_READS_MOVED }).describe(
|
|
3693
3698
|
"'record': record a reading (evidence, not a verdict). Reads live on context: action=outcome and action=readings."
|
|
3694
3699
|
),
|
|
3695
|
-
entryId:
|
|
3700
|
+
entryId: z17.string().max(200).optional().describe("The key result (or other outcome-bearing) entry, by its chain id. Required."),
|
|
3696
3701
|
// PR #858 review round 3 (Codex P2, PRRT_kwDORS4ils6gXHj9): a JSON number that overflows to
|
|
3697
3702
|
// `Infinity` (e.g. `1e400`) parses fine in JS and passes a plain `z.number()`, but
|
|
3698
3703
|
// `callGateway()` serializes it with `JSON.stringify`, which turns `Infinity` into `null` —
|
|
3699
3704
|
// the backend's `v.number()` validator then rejects a call this tool's own schema accepted.
|
|
3700
3705
|
// `.finite()` rejects it here, matching the explicit finite-value checks the CLI/other outcome
|
|
3701
3706
|
// entry surfaces already use.
|
|
3702
|
-
value:
|
|
3703
|
-
valueText:
|
|
3704
|
-
asOf:
|
|
3705
|
-
kind:
|
|
3706
|
-
correctsReadingId:
|
|
3707
|
-
recordedByRoleId:
|
|
3708
|
-
note:
|
|
3709
|
-
source:
|
|
3707
|
+
value: z17.number().finite().optional().describe("'record': the measured value. Required for 'record'."),
|
|
3708
|
+
valueText: z17.string().max(500).optional().describe("'record': verbatim as-reported form when the source was not clean, e.g. '~62%'. Display only."),
|
|
3709
|
+
asOf: z17.string().max(64).optional().describe("'record': when the world was in this state, as a parseable date (default: now). Back-dating a backfill is legitimate \u2014 it shows up as asOf earlier than recordedAt."),
|
|
3710
|
+
kind: z17.enum(READING_KINDS).optional().describe("'record': measurement | estimate | correction (default: measurement)."),
|
|
3711
|
+
correctsReadingId: z17.string().max(200).optional().describe("'record': required with kind='correction' \u2014 the reading id this replaces. Refused if that row is already superseded."),
|
|
3712
|
+
recordedByRoleId: z17.string().max(200).optional().describe("'record': the accountable role (default: the entry's reporterRoleId, then its owning role)."),
|
|
3713
|
+
note: z17.string().max(2e3).optional().describe("'record': free-text note recorded with the reading."),
|
|
3714
|
+
source: z17.string().max(500).optional().describe("'record': where the number came from \u2014 a dashboard name, a query, a URL.")
|
|
3710
3715
|
});
|
|
3711
|
-
var recordVariant =
|
|
3712
|
-
action:
|
|
3713
|
-
entryId:
|
|
3714
|
-
value:
|
|
3715
|
-
valueText:
|
|
3716
|
-
asOf:
|
|
3717
|
-
kind:
|
|
3718
|
-
correctsReadingId:
|
|
3719
|
-
recordedByRoleId:
|
|
3720
|
-
note:
|
|
3721
|
-
source:
|
|
3716
|
+
var recordVariant = z17.object({
|
|
3717
|
+
action: z17.literal("record"),
|
|
3718
|
+
entryId: z17.string().max(200),
|
|
3719
|
+
value: z17.number().finite(),
|
|
3720
|
+
valueText: z17.string().max(500).optional(),
|
|
3721
|
+
asOf: z17.string().max(64).optional(),
|
|
3722
|
+
kind: z17.enum(READING_KINDS).optional(),
|
|
3723
|
+
correctsReadingId: z17.string().max(200).optional(),
|
|
3724
|
+
recordedByRoleId: z17.string().max(200).optional(),
|
|
3725
|
+
note: z17.string().max(2e3).optional(),
|
|
3726
|
+
source: z17.string().max(500).optional()
|
|
3722
3727
|
});
|
|
3723
|
-
var outcomeActionUnion =
|
|
3728
|
+
var outcomeActionUnion = z17.discriminatedUnion("action", [recordVariant]);
|
|
3724
3729
|
var OUTCOME_ACTION_SPECS = {
|
|
3725
3730
|
record: {
|
|
3726
3731
|
params: ["entryId", "value", "valueText", "asOf", "kind", "correctsReadingId", "recordedByRoleId", "note", "source"],
|
|
@@ -3915,49 +3920,276 @@ function registerOutcomeTools(server) {
|
|
|
3915
3920
|
);
|
|
3916
3921
|
}
|
|
3917
3922
|
|
|
3923
|
+
// src/tools/role.ts
|
|
3924
|
+
import { z as z18 } from "zod/v3";
|
|
3925
|
+
var ROLE_ACTIONS = ["seat", "unseat", "release_move", "accept_move", "refuse_move"];
|
|
3926
|
+
var ROLE_READS_MOVED = {
|
|
3927
|
+
accountable: "role only writes. Read what a role owns and who holds it with the read-only context tool: context action=accountable roleId=..."
|
|
3928
|
+
};
|
|
3929
|
+
var roleSchema = z18.object({
|
|
3930
|
+
action: actionEnum(ROLE_ACTIONS, ROLE_READS_MOVED).describe(
|
|
3931
|
+
"'seat': put a person in this role. 'unseat': take this role from a person. 'release_move' / 'accept_move' / 'refuse_move': move a role or team to a team with another Team Lead."
|
|
3932
|
+
),
|
|
3933
|
+
roleId: z18.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."),
|
|
3934
|
+
person: z18.string().max(200).optional().describe(
|
|
3935
|
+
"'seat' / 'unseat': an existing person, by person id or exact email. For 'seat', give this or newPersonName, not both."
|
|
3936
|
+
),
|
|
3937
|
+
newPersonName: z18.string().max(120).optional().describe(
|
|
3938
|
+
"'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."
|
|
3939
|
+
),
|
|
3940
|
+
teamId: z18.string().max(200).optional().describe(
|
|
3941
|
+
"'seat' / 'unseat': the team, by chain id or entry id. Only needed for Team Lead, which lives in every team; any other role is seated in its home team. 'release_move': the team it moves to."
|
|
3942
|
+
),
|
|
3943
|
+
onMyAuthority: z18.boolean().optional().describe(
|
|
3944
|
+
"'seat', Team Lead only: as the team's Team Lead, seat a second Team Lead who holds the seat on your authority until you unseat them."
|
|
3945
|
+
),
|
|
3946
|
+
childId: z18.string().max(200).optional().describe("'release_move' / 'accept_move' / 'refuse_move': the role or team that moves, by chain id or entry id."),
|
|
3947
|
+
why: z18.string().max(1e3).optional().describe("'refuse_move': why the move is refused; it becomes a tension for the old team's Team Lead.")
|
|
3948
|
+
});
|
|
3949
|
+
var seatVariant = z18.object({
|
|
3950
|
+
action: z18.literal("seat"),
|
|
3951
|
+
roleId: z18.string().max(200),
|
|
3952
|
+
person: z18.string().max(200).optional(),
|
|
3953
|
+
newPersonName: z18.string().max(120).optional(),
|
|
3954
|
+
teamId: z18.string().max(200).optional(),
|
|
3955
|
+
onMyAuthority: z18.boolean().optional()
|
|
3956
|
+
});
|
|
3957
|
+
var unseatVariant = z18.object({
|
|
3958
|
+
action: z18.literal("unseat"),
|
|
3959
|
+
roleId: z18.string().max(200),
|
|
3960
|
+
person: z18.string().max(200),
|
|
3961
|
+
teamId: z18.string().max(200).optional()
|
|
3962
|
+
});
|
|
3963
|
+
var releaseMoveVariant = z18.object({ action: z18.literal("release_move"), childId: z18.string().max(200), teamId: z18.string().max(200) });
|
|
3964
|
+
var acceptMoveVariant = z18.object({ action: z18.literal("accept_move"), childId: z18.string().max(200) });
|
|
3965
|
+
var refuseMoveVariant = z18.object({ action: z18.literal("refuse_move"), childId: z18.string().max(200), why: z18.string().max(1e3) });
|
|
3966
|
+
var roleActionUnion = z18.discriminatedUnion("action", [
|
|
3967
|
+
seatVariant,
|
|
3968
|
+
unseatVariant,
|
|
3969
|
+
releaseMoveVariant,
|
|
3970
|
+
acceptMoveVariant,
|
|
3971
|
+
refuseMoveVariant
|
|
3972
|
+
]);
|
|
3973
|
+
var ROLE_ACTION_SPECS = {
|
|
3974
|
+
seat: {
|
|
3975
|
+
params: ["roleId", "person", "newPersonName", "teamId", "onMyAuthority"],
|
|
3976
|
+
description: "roleId is required, plus exactly one of person or newPersonName; teamId and onMyAuthority only for Team Lead."
|
|
3977
|
+
},
|
|
3978
|
+
unseat: { params: ["roleId", "person", "teamId"], description: "roleId and person are required; teamId only for Team Lead." },
|
|
3979
|
+
release_move: { params: ["childId", "teamId"], description: "childId and teamId (the team it moves to) are required." },
|
|
3980
|
+
accept_move: { params: ["childId"], description: "childId is required." },
|
|
3981
|
+
refuse_move: { params: ["childId", "why"], description: "childId and why are required." }
|
|
3982
|
+
};
|
|
3983
|
+
function formatHolders(result2) {
|
|
3984
|
+
if (result2.holders.length === 0) return [` holders: none${result2.holdersTruncated ? " found, but the membership scan is incomplete" : ""}`];
|
|
3985
|
+
return [
|
|
3986
|
+
" holders:",
|
|
3987
|
+
...result2.holders.map((h) => {
|
|
3988
|
+
const word = personStatusTag(h.status);
|
|
3989
|
+
const tag = word ? ` (${word})` : "";
|
|
3990
|
+
const team = h.teamName ? ` in ${sanitizeSingleLineField(h.teamName)}` : "";
|
|
3991
|
+
return ` ${sanitizeSingleLineField(h.displayName)}${tag}${team}`;
|
|
3992
|
+
}),
|
|
3993
|
+
...result2.holdersTruncated ? [" (membership scan cut at 500 rows, more holders may exist)"] : []
|
|
3994
|
+
];
|
|
3995
|
+
}
|
|
3996
|
+
function formatRow(row) {
|
|
3997
|
+
const id = row.entryId ?? row.id;
|
|
3998
|
+
const statusDisplay = row.workflowStatus ? `${row.status} / ${sanitizeSingleLineField(row.workflowStatus)}` : row.status;
|
|
3999
|
+
const collectionSlug = row.collectionSlug ? sanitizeSingleLineField(row.collectionSlug) : "?";
|
|
4000
|
+
return ` ${id} ${sanitizeSingleLineField(row.name)} [${collectionSlug}/${statusDisplay}]`;
|
|
4001
|
+
}
|
|
4002
|
+
function formatSection(label, rows, truncated, cursorHint) {
|
|
4003
|
+
if (rows.length === 0 && !truncated) return [` ${label}: not recorded yet`];
|
|
4004
|
+
const lines = rows.length === 0 ? [` ${label}: not recorded yet, but the scan is incomplete`] : [` ${label}:`, ...rows.map(formatRow)];
|
|
4005
|
+
if (truncated) lines.push(` (scan incomplete, more may exist \u2014 ${cursorHint ?? "raise limit (capped at 200, no cursor for this list)"})`);
|
|
4006
|
+
return lines;
|
|
4007
|
+
}
|
|
4008
|
+
function formatRoleAccountable(result2) {
|
|
4009
|
+
const roleLabel2 = `${sanitizeSingleLineField(result2.role.name)} (${result2.role.entryId ?? result2.role.id})`;
|
|
4010
|
+
const explicitCursorHint = result2.nextCursor !== null ? `raise limit or continue with cursor ${result2.nextCursor}` : "raise limit";
|
|
4011
|
+
return [
|
|
4012
|
+
`${roleLabel2} \u2014 accountability:`,
|
|
4013
|
+
...formatHolders(result2),
|
|
4014
|
+
...formatSection("explicit (owns)", result2.explicit, result2.explicitTruncated, explicitCursorHint),
|
|
4015
|
+
...formatSection("reporting (reports on)", result2.reporting, result2.reportingTruncated),
|
|
4016
|
+
` inherited: not-computed \u2014 ${result2.inheritedNotComputedReason}`
|
|
4017
|
+
].join("\n");
|
|
4018
|
+
}
|
|
4019
|
+
async function handleRoleAccountable(roleId, canonicalKey, limit, cursor) {
|
|
4020
|
+
try {
|
|
4021
|
+
const raw = await kernelQuery("chain.listByRole", { roleId, canonicalKey, limit, cursor });
|
|
4022
|
+
const result2 = raw;
|
|
4023
|
+
const message = formatRoleAccountable(result2);
|
|
4024
|
+
return successResult(message, message, result2);
|
|
4025
|
+
} catch (err) {
|
|
4026
|
+
return roleErrorResult(err, "accountable", { roleId, canonicalKey, limit, cursor });
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
async function runSeatAction(action, fn, params) {
|
|
4030
|
+
try {
|
|
4031
|
+
requireWriteAccess();
|
|
4032
|
+
const sessionId = getAgentSessionId();
|
|
4033
|
+
const raw = await kernelMutation(fn, {
|
|
4034
|
+
roleRef: params.roleId,
|
|
4035
|
+
targetPersonRef: params.person,
|
|
4036
|
+
newPersonName: params.newPersonName,
|
|
4037
|
+
teamRef: params.teamId,
|
|
4038
|
+
sessionId,
|
|
4039
|
+
...params.onMyAuthority ? { onMyAuthority: true } : {}
|
|
4040
|
+
});
|
|
4041
|
+
const result2 = raw.refusal ? { ...raw, refusal: { ...raw.refusal, requiredAction: authorityRecovery(raw.refusal) } } : raw;
|
|
4042
|
+
const message = formatSeatSentence(action, result2, sanitizeSingleLineField);
|
|
4043
|
+
if (result2.outcome === "refused") {
|
|
4044
|
+
return failureResult(
|
|
4045
|
+
message,
|
|
4046
|
+
"PERMISSION_DENIED",
|
|
4047
|
+
message,
|
|
4048
|
+
result2.refusal?.requiredAction ?? "Ask the team's Team Lead to seat them.",
|
|
4049
|
+
void 0,
|
|
4050
|
+
result2
|
|
4051
|
+
);
|
|
4052
|
+
}
|
|
4053
|
+
return successResult(message, message, result2);
|
|
4054
|
+
} catch (err) {
|
|
4055
|
+
return roleErrorResult(err, action, params);
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
function handleRoleSeat(roleId, person, newPersonName, teamId, onMyAuthority) {
|
|
4059
|
+
return runSeatAction("seat", "organisation.seatInRole", { roleId, person, newPersonName, teamId, onMyAuthority });
|
|
4060
|
+
}
|
|
4061
|
+
function handleRoleUnseat(roleId, person, teamId) {
|
|
4062
|
+
return runSeatAction("unseat", "organisation.unseatFromRole", { roleId, person, teamId });
|
|
4063
|
+
}
|
|
4064
|
+
function callMove(action, params, sessionId) {
|
|
4065
|
+
if (action === "release_move") {
|
|
4066
|
+
return kernelMutation("organisation.hierarchy.release", { childRef: params.childId, toParentRef: params.teamId, sessionId });
|
|
4067
|
+
}
|
|
4068
|
+
if (action === "accept_move") return kernelMutation("organisation.hierarchy.accept", { childRef: params.childId, sessionId });
|
|
4069
|
+
return kernelMutation("organisation.hierarchy.refuse", { childRef: params.childId, why: params.why, sessionId });
|
|
4070
|
+
}
|
|
4071
|
+
async function handleMove(action, params) {
|
|
4072
|
+
try {
|
|
4073
|
+
requireWriteAccess();
|
|
4074
|
+
const raw = await callMove(action, params, getAgentSessionId());
|
|
4075
|
+
if (raw.outcome === "refused") {
|
|
4076
|
+
const recovery = authorityRecovery(raw.refusal) ?? "Ask the Team Lead the refusal names.";
|
|
4077
|
+
const message2 = `Refused: ${sanitizeSingleLineField(raw.refusal.reason)} ${recovery}`;
|
|
4078
|
+
const code = ORGANISATION_VALIDATION_REFUSALS.has(raw.refusal.code) ? "VALIDATION_ERROR" : "PERMISSION_DENIED";
|
|
4079
|
+
return failureResult(message2, code, message2, recovery, void 0, raw);
|
|
4080
|
+
}
|
|
4081
|
+
const message = raw.replaced ? `${raw.line} It replaces the release toward ${sanitizeSingleLineField(raw.replaced)}.` : raw.line;
|
|
4082
|
+
return successResult(message, message, raw);
|
|
4083
|
+
} catch (err) {
|
|
4084
|
+
return roleErrorResult(err, action, params);
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
function roleErrorResult(err, action, params = {}) {
|
|
4088
|
+
const classified = classifyError(err);
|
|
4089
|
+
const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
|
|
4090
|
+
const fallbackActions = retryIsFutile(classified.code) ? void 0 : [action === "accountable" ? { tool: "context", description: "Retry accountable", parameters: { action, ...definedParams } } : { tool: "role", description: `Retry ${action}`, parameters: { action, ...definedParams } }];
|
|
4091
|
+
return failureResult(
|
|
4092
|
+
classified.message,
|
|
4093
|
+
classified.code,
|
|
4094
|
+
classified.message,
|
|
4095
|
+
classified.recovery ?? (action === "accountable" ? "Use context action=accountable with roleId set to a real role's chain id or entry id." : `Fix the input the message names and call action='${action}' again.`),
|
|
4096
|
+
classified.availableActions ?? fallbackActions,
|
|
4097
|
+
classified.diagnostics
|
|
4098
|
+
);
|
|
4099
|
+
}
|
|
4100
|
+
function registerRoleTools(server) {
|
|
4101
|
+
const roleHandlers = {
|
|
4102
|
+
seat: (data) => handleRoleSeat(data.roleId, data.person, data.newPersonName, data.teamId, data.onMyAuthority),
|
|
4103
|
+
unseat: (data) => handleRoleUnseat(data.roleId, data.person, data.teamId),
|
|
4104
|
+
release_move: (data) => handleMove("release_move", data),
|
|
4105
|
+
accept_move: (data) => handleMove("accept_move", data),
|
|
4106
|
+
refuse_move: (data) => handleMove("refuse_move", data)
|
|
4107
|
+
};
|
|
4108
|
+
server.registerTool(
|
|
4109
|
+
"role",
|
|
4110
|
+
{
|
|
4111
|
+
title: "Role",
|
|
4112
|
+
description: "Workspace roles \u2014 who holds a role and where it sits. Five actions:\n\n- **seat**: put a person in this role, by person id or email, or by `newPersonName` for someone with no login yet (a placeholder person, created once per exact name). The role's home team is used; name `teamId` only for Team Lead. A held role refuses a second holder and names the holder; the person keeps their other roles in the team. Needs the team's Team Lead. With `onMyAuthority`, the team's Team Lead seats a second Team Lead on their own authority; unseating them revokes it.\n- **unseat**: take this role from a person; their other roles in the team stay. The last active Team Lead of a team is refused. Invite a person, or take them out of a team, with the `people` tool.\n- **release_move** / **accept_move** / **refuse_move**: move a role or team (`childId`) to a team whose Team Lead is another seat. Acting as Team Lead of its current team, release it toward `teamId`; acting as Team Lead of that team, accept it, or refuse it with `why` (it stays, and a tension goes to its current team's Team Lead).\n\nRead what a role owns with `context action=accountable`.",
|
|
4113
|
+
inputSchema: roleSchema,
|
|
4114
|
+
// The hints describe the whole tool, so they say the most it can do: unseat removes a role and can
|
|
4115
|
+
// delete a membership row (destructive), and a repeated seat still writes history and audit rows
|
|
4116
|
+
// (not idempotent); the one read moved to `context` (DEC-1894 step 2). Closed world: nothing here
|
|
4117
|
+
// reaches outside the workspace since invite moved to `people` (TASK-677, DEC-1981).
|
|
4118
|
+
annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: false }
|
|
4119
|
+
},
|
|
4120
|
+
thinWrapper(async (args) => {
|
|
4121
|
+
const parsed = parseOrFail(roleSchema, args);
|
|
4122
|
+
if (!parsed.ok) return parsed.result;
|
|
4123
|
+
const { action } = parsed.data;
|
|
4124
|
+
return runWithToolContext(
|
|
4125
|
+
{ tool: "role", action },
|
|
4126
|
+
() => dispatchDiscriminated("role", roleActionUnion, parsed.data, ROLE_ACTION_SPECS, roleHandlers)
|
|
4127
|
+
);
|
|
4128
|
+
})
|
|
4129
|
+
);
|
|
4130
|
+
}
|
|
4131
|
+
|
|
3918
4132
|
// src/tools/contextLookups.ts
|
|
3919
|
-
var LOOKUP_ACTIONS = ["get", "batch", "history", "list", "search", "find", "people", "outcome", "readings"];
|
|
3920
|
-
var statusFilterSchema =
|
|
3921
|
-
var
|
|
3922
|
-
var
|
|
4133
|
+
var LOOKUP_ACTIONS = ["get", "batch", "history", "list", "search", "find", "people", "outcome", "readings", "accountable", "preflight"];
|
|
4134
|
+
var statusFilterSchema = z19.union([z19.string().max(200), z19.array(z19.enum(ENTRY_STATUS_READ_WORDS)).max(5)]);
|
|
4135
|
+
var preflightLinks = z19.array(z19.object({ type: z19.string().max(200), entryId: z19.string().max(200) })).max(50).optional();
|
|
4136
|
+
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. 'outcome': a key result's derived view, its objective and sibling key results. 'readings': its readings, newest first. 'accountable': what a role owns and who holds it. 'preflight': a collection's requirements. ";
|
|
4137
|
+
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- **outcome**: A key result's derived view (current, progress, pace, staleness, recorded completion) with its objective and up to 5 sibling key results.\n- **readings**: A key result's readings, newest first; superseded rows are marked with their replacement. Record one with `outcome action=record`.\n- **accountable**: What a role owns, reports on, and who holds it.\n- **preflight**: What an entry in a collection needs before you compose it. Saves nothing.\n";
|
|
3923
4138
|
var lookupParams = {
|
|
3924
|
-
entryIds:
|
|
3925
|
-
collection:
|
|
3926
|
-
query:
|
|
4139
|
+
entryIds: z19.array(z19.string().max(200)).min(1).max(20).optional().describe("For 'batch': entry IDs, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
|
|
4140
|
+
collection: z19.string().max(200).optional().describe("For 'list'/'search': collection slug, e.g. 'glossary', 'tracking-events'. Required for 'preflight'."),
|
|
4141
|
+
query: z19.string().min(2).max(500).optional().describe("For 'search': search text (min 2 characters)."),
|
|
3927
4142
|
// 'active'/'accepted'/'current' are the same trust level (DEC-1575/DEC-1788) — all enumerated, never one substituted.
|
|
3928
4143
|
status: statusFilterSchema.optional().describe(
|
|
3929
4144
|
`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']).`
|
|
3930
4145
|
),
|
|
3931
|
-
tag:
|
|
3932
|
-
label:
|
|
3933
|
-
limit:
|
|
4146
|
+
tag: z19.string().max(200).optional().describe("For 'list': filter by internal tag."),
|
|
4147
|
+
label: z19.string().max(200).optional().describe("For 'list': filter by label slug \u2014 matches entries across all collections."),
|
|
4148
|
+
limit: z19.number().int().positive().max(200).optional().describe("For 'readings'/'accountable': max rows (default and maximum 200)."),
|
|
4149
|
+
roleId: z19.string().max(200).optional().describe("For 'accountable': the role's id (required)."),
|
|
4150
|
+
canonicalKey: z19.string().max(200).optional().describe("For 'accountable'/'preflight': one kind, e.g. tension."),
|
|
4151
|
+
cursor: z19.number().optional().describe("For 'accountable': nextCursor of an earlier page."),
|
|
4152
|
+
links: preflightLinks.describe("For 'preflight': proposed links.")
|
|
3934
4153
|
};
|
|
3935
4154
|
var lookupVariants = [
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
action:
|
|
3941
|
-
collection:
|
|
3942
|
-
status:
|
|
4155
|
+
z19.object({ action: z19.literal("get"), entryId: z19.string().max(200) }),
|
|
4156
|
+
z19.object({ action: z19.literal("batch"), entryIds: z19.array(z19.string().max(200)).min(1).max(20) }),
|
|
4157
|
+
z19.object({ action: z19.literal("history"), entryId: z19.string().max(200) }),
|
|
4158
|
+
z19.object({
|
|
4159
|
+
action: z19.literal("list"),
|
|
4160
|
+
collection: z19.string().max(200).optional(),
|
|
4161
|
+
status: z19.string().max(200).optional(),
|
|
3943
4162
|
// one status word; the flat union serves search
|
|
3944
|
-
tag:
|
|
3945
|
-
label:
|
|
4163
|
+
tag: z19.string().max(200).optional(),
|
|
4164
|
+
label: z19.string().max(200).optional()
|
|
3946
4165
|
}),
|
|
3947
|
-
|
|
3948
|
-
action:
|
|
3949
|
-
query:
|
|
3950
|
-
collection:
|
|
4166
|
+
z19.object({
|
|
4167
|
+
action: z19.literal("search"),
|
|
4168
|
+
query: z19.string().min(2).max(500),
|
|
4169
|
+
collection: z19.string().max(200).optional(),
|
|
3951
4170
|
status: statusFilterSchema.optional()
|
|
3952
4171
|
}),
|
|
3953
|
-
|
|
3954
|
-
action:
|
|
3955
|
-
entryId:
|
|
3956
|
-
direction:
|
|
4172
|
+
z19.object({
|
|
4173
|
+
action: z19.literal("find"),
|
|
4174
|
+
entryId: z19.string().max(200),
|
|
4175
|
+
direction: z19.enum(["incoming", "outgoing", "both"]).optional().default("both")
|
|
4176
|
+
}),
|
|
4177
|
+
z19.object({ action: z19.literal("people") }),
|
|
4178
|
+
z19.object({ action: z19.literal("outcome"), entryId: z19.string().max(200) }),
|
|
4179
|
+
z19.object({ action: z19.literal("readings"), entryId: z19.string().max(200), limit: z19.number().int().positive().max(200).optional() }),
|
|
4180
|
+
z19.object({
|
|
4181
|
+
action: z19.literal("accountable"),
|
|
4182
|
+
roleId: z19.string().max(200),
|
|
4183
|
+
canonicalKey: z19.string().max(200).optional(),
|
|
4184
|
+
limit: z19.number().int().positive().max(200).optional(),
|
|
4185
|
+
cursor: z19.number().optional()
|
|
3957
4186
|
}),
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
4187
|
+
z19.object({
|
|
4188
|
+
action: z19.literal("preflight"),
|
|
4189
|
+
collection: z19.string().max(200),
|
|
4190
|
+
canonicalKey: z19.string().max(200).optional(),
|
|
4191
|
+
links: preflightLinks
|
|
4192
|
+
})
|
|
3961
4193
|
];
|
|
3962
4194
|
var LOOKUP_ACTION_SPECS = {
|
|
3963
4195
|
get: { params: ["entryId"], description: "entryId is required." },
|
|
@@ -3968,7 +4200,9 @@ var LOOKUP_ACTION_SPECS = {
|
|
|
3968
4200
|
find: { params: ["entryId", "direction"], description: "entryId is required." },
|
|
3969
4201
|
people: { params: [], description: "No params." },
|
|
3970
4202
|
outcome: { params: ["entryId"], description: "entryId is required." },
|
|
3971
|
-
readings: { params: ["entryId", "limit"], description: "entryId is required; limit is optional." }
|
|
4203
|
+
readings: { params: ["entryId", "limit"], description: "entryId is required; limit is optional." },
|
|
4204
|
+
accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." },
|
|
4205
|
+
preflight: { params: ["collection", "canonicalKey", "links"], description: "collection is required; saves nothing." }
|
|
3972
4206
|
};
|
|
3973
4207
|
function lookupHandlers(server) {
|
|
3974
4208
|
return {
|
|
@@ -3982,7 +4216,10 @@ function lookupHandlers(server) {
|
|
|
3982
4216
|
people: () => handlePeopleList(),
|
|
3983
4217
|
outcome: (data) => handleOutcomeShow(data.entryId),
|
|
3984
4218
|
// DEC-1894 step 2 (TASK-817)
|
|
3985
|
-
readings: (data) => handleOutcomeList(data.entryId, data.limit)
|
|
4219
|
+
readings: (data) => handleOutcomeList(data.entryId, data.limit),
|
|
4220
|
+
accountable: (data) => handleRoleAccountable(data.roleId, data.canonicalKey, data.limit, data.cursor),
|
|
4221
|
+
// DEC-1894 step 2 (TASK-1004)
|
|
4222
|
+
preflight: (data) => handleEntryPreflight(data.collection, data.canonicalKey, data.links)
|
|
3986
4223
|
};
|
|
3987
4224
|
}
|
|
3988
4225
|
|
|
@@ -3998,90 +4235,90 @@ function epistemicCollectionHint(collectionName) {
|
|
|
3998
4235
|
return "";
|
|
3999
4236
|
}
|
|
4000
4237
|
var CONTEXT_ACTIONS = [...LOOKUP_ACTIONS, "gather", "build", "neighborhood", "changes", "chain", "cross-cut", "incremental", "brief", "last-verified-brief"];
|
|
4001
|
-
var contextSchema =
|
|
4238
|
+
var contextSchema = z20.object({
|
|
4002
4239
|
// provenance: neighborhood BET-142; changes/chain/cross-cut/incremental/brief BET-239 (E4, E6)
|
|
4003
|
-
action:
|
|
4240
|
+
action: z20.enum(CONTEXT_ACTIONS).describe(
|
|
4004
4241
|
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."
|
|
4005
4242
|
),
|
|
4006
|
-
entryId:
|
|
4243
|
+
entryId: z20.string().max(200).optional().describe("For 'get'/'history'/'find'/'outcome'/'readings'/'build'/'neighborhood'/'chain': entry ID. For 'gather': optional (entry-graph mode)."),
|
|
4007
4244
|
...lookupParams,
|
|
4008
|
-
mapEntryId:
|
|
4245
|
+
mapEntryId: z20.string().max(200).optional().describe(
|
|
4009
4246
|
"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>'."
|
|
4010
4247
|
),
|
|
4011
|
-
task:
|
|
4012
|
-
since:
|
|
4248
|
+
task: z20.string().max(2e3).optional().describe("For 'gather': natural-language task description for loading task-relevant governance, binding constraints, and supporting context."),
|
|
4249
|
+
since: z20.string().max(200).optional().describe(
|
|
4013
4250
|
"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'."
|
|
4014
4251
|
),
|
|
4015
|
-
direction:
|
|
4016
|
-
relationType:
|
|
4252
|
+
direction: z20.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)."),
|
|
4253
|
+
relationType: z20.string().max(200).optional().describe(
|
|
4017
4254
|
"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'."
|
|
4018
4255
|
),
|
|
4019
|
-
mode:
|
|
4020
|
-
maxHops:
|
|
4021
|
-
maxResults:
|
|
4022
|
-
strategy:
|
|
4023
|
-
skill:
|
|
4256
|
+
mode: z20.enum(["search", "graph"]).default("search").optional().describe("For gather: 'search' (default) or 'graph' (enhanced with provenance paths). Ignored when mapEntryId is provided."),
|
|
4257
|
+
maxHops: z20.number().min(1).max(4).default(2).describe("Relation traversal depth (1=direct only, 2=default, 3=wide net, 4=deep chain walk)"),
|
|
4258
|
+
maxResults: z20.number().min(1).max(25).default(10).optional().describe("Max entries to return in gather task mode (default 10)"),
|
|
4259
|
+
strategy: z20.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."),
|
|
4260
|
+
skill: z20.string().max(200).optional().describe(
|
|
4024
4261
|
"Skill name for 'incremental' action \u2014 identifies which skill's brief history to compare against. Examples: 'preflight', 'shaping', 'review'. Required when action is 'incremental'."
|
|
4025
4262
|
),
|
|
4026
|
-
briefType:
|
|
4263
|
+
briefType: z20.enum(["steering", "confidence", "delta"]).optional().describe(
|
|
4027
4264
|
"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'."
|
|
4028
4265
|
),
|
|
4029
|
-
templateId:
|
|
4266
|
+
templateId: z20.string().max(200).optional().describe(
|
|
4030
4267
|
"For 'last-verified-brief': brief template identifier \u2014 currently 'steering-brief' is the only registered template."
|
|
4031
4268
|
),
|
|
4032
|
-
scopeKey:
|
|
4269
|
+
scopeKey: z20.string().max(200).optional().describe(
|
|
4033
4270
|
"For 'last-verified-brief': canonical scope key \u2014 'workspace:<workspaceId>' or 'initiative:<INI-ID>'."
|
|
4034
4271
|
)
|
|
4035
4272
|
});
|
|
4036
|
-
var contextGatherVariant =
|
|
4037
|
-
action:
|
|
4038
|
-
entryId:
|
|
4039
|
-
mapEntryId:
|
|
4040
|
-
task:
|
|
4041
|
-
mode:
|
|
4042
|
-
maxHops:
|
|
4043
|
-
maxResults:
|
|
4044
|
-
strategy:
|
|
4273
|
+
var contextGatherVariant = z20.object({
|
|
4274
|
+
action: z20.literal("gather"),
|
|
4275
|
+
entryId: z20.string().max(200).optional(),
|
|
4276
|
+
mapEntryId: z20.string().max(200).optional(),
|
|
4277
|
+
task: z20.string().max(2e3).optional(),
|
|
4278
|
+
mode: z20.enum(["search", "graph"]).optional().default("search"),
|
|
4279
|
+
maxHops: z20.number().min(1).max(4).optional().default(2),
|
|
4280
|
+
maxResults: z20.number().min(1).max(25).optional().default(10),
|
|
4281
|
+
strategy: z20.enum(["hybrid", "keyword"]).optional().default("keyword")
|
|
4045
4282
|
});
|
|
4046
|
-
var contextBuildVariant =
|
|
4047
|
-
action:
|
|
4048
|
-
entryId:
|
|
4049
|
-
maxHops:
|
|
4283
|
+
var contextBuildVariant = z20.object({
|
|
4284
|
+
action: z20.literal("build"),
|
|
4285
|
+
entryId: z20.string().max(200),
|
|
4286
|
+
maxHops: z20.number().min(1).max(4).optional().default(2)
|
|
4050
4287
|
});
|
|
4051
|
-
var contextNeighborhoodVariant =
|
|
4052
|
-
action:
|
|
4053
|
-
entryId:
|
|
4288
|
+
var contextNeighborhoodVariant = z20.object({
|
|
4289
|
+
action: z20.literal("neighborhood"),
|
|
4290
|
+
entryId: z20.string().max(200)
|
|
4054
4291
|
});
|
|
4055
|
-
var contextChangesVariant =
|
|
4056
|
-
action:
|
|
4057
|
-
since:
|
|
4292
|
+
var contextChangesVariant = z20.object({
|
|
4293
|
+
action: z20.literal("changes"),
|
|
4294
|
+
since: z20.string().max(200)
|
|
4058
4295
|
});
|
|
4059
|
-
var contextChainVariant =
|
|
4060
|
-
action:
|
|
4061
|
-
entryId:
|
|
4062
|
-
direction:
|
|
4063
|
-
maxHops:
|
|
4064
|
-
relationType:
|
|
4296
|
+
var contextChainVariant = z20.object({
|
|
4297
|
+
action: z20.literal("chain"),
|
|
4298
|
+
entryId: z20.string().max(200),
|
|
4299
|
+
direction: z20.enum(["outgoing", "incoming"]).optional().default("outgoing"),
|
|
4300
|
+
maxHops: z20.number().min(1).max(4).optional().default(2),
|
|
4301
|
+
relationType: z20.string().max(200).optional()
|
|
4065
4302
|
});
|
|
4066
|
-
var contextCrossCutVariant =
|
|
4067
|
-
action:
|
|
4068
|
-
relationType:
|
|
4303
|
+
var contextCrossCutVariant = z20.object({
|
|
4304
|
+
action: z20.literal("cross-cut"),
|
|
4305
|
+
relationType: z20.string().max(200)
|
|
4069
4306
|
});
|
|
4070
|
-
var contextIncrementalVariant =
|
|
4071
|
-
action:
|
|
4072
|
-
skill:
|
|
4307
|
+
var contextIncrementalVariant = z20.object({
|
|
4308
|
+
action: z20.literal("incremental"),
|
|
4309
|
+
skill: z20.string().max(200)
|
|
4073
4310
|
});
|
|
4074
|
-
var contextBriefVariant =
|
|
4075
|
-
action:
|
|
4076
|
-
briefType:
|
|
4077
|
-
since:
|
|
4311
|
+
var contextBriefVariant = z20.object({
|
|
4312
|
+
action: z20.literal("brief"),
|
|
4313
|
+
briefType: z20.enum(["steering", "confidence", "delta"]),
|
|
4314
|
+
since: z20.string().max(200).optional()
|
|
4078
4315
|
});
|
|
4079
|
-
var contextLastVerifiedBriefVariant =
|
|
4080
|
-
action:
|
|
4081
|
-
templateId:
|
|
4082
|
-
scopeKey:
|
|
4316
|
+
var contextLastVerifiedBriefVariant = z20.object({
|
|
4317
|
+
action: z20.literal("last-verified-brief"),
|
|
4318
|
+
templateId: z20.string().max(200),
|
|
4319
|
+
scopeKey: z20.string().max(200)
|
|
4083
4320
|
});
|
|
4084
|
-
var contextActionUnion =
|
|
4321
|
+
var contextActionUnion = z20.discriminatedUnion("action", [
|
|
4085
4322
|
...lookupVariants,
|
|
4086
4323
|
contextGatherVariant,
|
|
4087
4324
|
contextBuildVariant,
|
|
@@ -5067,7 +5304,7 @@ function formatTimeAgo(ms) {
|
|
|
5067
5304
|
}
|
|
5068
5305
|
|
|
5069
5306
|
// src/tools/collections.ts
|
|
5070
|
-
import { z as
|
|
5307
|
+
import { z as z22 } from "zod/v3";
|
|
5071
5308
|
|
|
5072
5309
|
// src/lib/scopedCache.ts
|
|
5073
5310
|
var ScopedCache = class {
|
|
@@ -5129,17 +5366,17 @@ ${entry.guidance}`).join("\n\n");
|
|
|
5129
5366
|
}
|
|
5130
5367
|
|
|
5131
5368
|
// src/tools/labels.ts
|
|
5132
|
-
import { z as
|
|
5133
|
-
var labelsSchema =
|
|
5134
|
-
action:
|
|
5135
|
-
slug:
|
|
5136
|
-
name:
|
|
5137
|
-
color:
|
|
5138
|
-
description:
|
|
5139
|
-
parentSlug:
|
|
5140
|
-
isGroup:
|
|
5141
|
-
order:
|
|
5142
|
-
entryId:
|
|
5369
|
+
import { z as z21 } from "zod/v3";
|
|
5370
|
+
var labelsSchema = z21.object({
|
|
5371
|
+
action: z21.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"),
|
|
5372
|
+
slug: z21.string().max(200).optional().describe("Label slug (required for create/update/delete/apply/remove)"),
|
|
5373
|
+
name: z21.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Display name (required for create)"),
|
|
5374
|
+
color: z21.string().max(50).optional().describe("Hex color, e.g. '#ef4444'"),
|
|
5375
|
+
description: z21.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional().describe("What this label means"),
|
|
5376
|
+
parentSlug: z21.string().max(200).optional().describe("Parent group slug for label hierarchy"),
|
|
5377
|
+
isGroup: z21.boolean().optional().describe("True if this is a group container, not a taggable label"),
|
|
5378
|
+
order: z21.number().optional().describe("Sort order within its group"),
|
|
5379
|
+
entryId: z21.string().max(200).optional().describe("Entry ID for apply/remove actions")
|
|
5143
5380
|
});
|
|
5144
5381
|
async function handleLabelsList() {
|
|
5145
5382
|
const labels = await kernelQuery("chain.listLabels");
|
|
@@ -5244,108 +5481,108 @@ var COLLECTIONS_ACTIONS = [
|
|
|
5244
5481
|
"label-remove"
|
|
5245
5482
|
];
|
|
5246
5483
|
var STATUS_CATEGORIES2 = ["draft", "current", "past", "discarded"];
|
|
5247
|
-
var statusListEntrySchema =
|
|
5248
|
-
var qualityCriterionSchema =
|
|
5249
|
-
field:
|
|
5484
|
+
var statusListEntrySchema = z22.object({ label: z22.string().max(200), category: z22.enum(STATUS_CATEGORIES2), archiveDefault: z22.boolean().optional(), resolveDefault: z22.boolean().optional() });
|
|
5485
|
+
var qualityCriterionSchema = z22.object({
|
|
5486
|
+
field: z22.string().max(200).describe("Entry data field key this criterion applies to, e.g. 'description', 'owner'"),
|
|
5250
5487
|
// WP-480 S1: `max_length` — must mirror the Convex rule union, or the tool rejects a
|
|
5251
5488
|
// valid criterion before the request ever reaches the server.
|
|
5252
|
-
rule:
|
|
5253
|
-
value:
|
|
5489
|
+
rule: z22.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)."),
|
|
5490
|
+
value: z22.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'.")
|
|
5254
5491
|
});
|
|
5255
|
-
var fieldSchema =
|
|
5256
|
-
key:
|
|
5257
|
-
label:
|
|
5258
|
-
type:
|
|
5259
|
-
required:
|
|
5260
|
-
options:
|
|
5261
|
-
searchable:
|
|
5262
|
-
displayHint:
|
|
5263
|
-
zone:
|
|
5264
|
-
colorMap:
|
|
5265
|
-
accentSource:
|
|
5266
|
-
iconMap:
|
|
5267
|
-
helpText:
|
|
5268
|
-
optionDescriptions:
|
|
5269
|
-
semanticRole:
|
|
5270
|
-
maxLength:
|
|
5271
|
-
minLength:
|
|
5492
|
+
var fieldSchema = z22.object({
|
|
5493
|
+
key: z22.string().max(200).describe("Field key, e.g. 'description', 'severity', 'status'"),
|
|
5494
|
+
label: z22.string().max(200).describe("Display label, e.g. 'Description', 'Severity'"),
|
|
5495
|
+
type: z22.string().max(50).describe("Field type: 'string', 'select', 'array', 'number', 'boolean'"),
|
|
5496
|
+
required: z22.boolean().optional().describe("Whether this field is required"),
|
|
5497
|
+
options: z22.array(z22.string().max(200)).max(200).optional().describe("Options for 'select' type fields"),
|
|
5498
|
+
searchable: z22.boolean().optional().describe("Whether this field is included in full-text search"),
|
|
5499
|
+
displayHint: z22.enum(["hero", "badge", "meta", "section", "hidden", "inline-meta"]).optional().describe("V2 rendering hint: how the field should be displayed in Cortex"),
|
|
5500
|
+
zone: z22.enum(["header", "body", "meta"]).optional().describe("V2 layout zone: where the field appears in the entry view"),
|
|
5501
|
+
colorMap: z22.record(z22.string().max(50)).optional().describe("V2 value-to-semantic-color mapping, e.g. { critical: 'danger', low: 'success' }"),
|
|
5502
|
+
accentSource: z22.boolean().optional().describe("When true, this field's colorMap value drives the card-level accent styling"),
|
|
5503
|
+
iconMap: z22.record(z22.string(), z22.string().max(50)).optional().describe("Maps field values to icons (emoji/symbol), prepended to badge text"),
|
|
5504
|
+
helpText: z22.string().max(2e3).optional().describe("Help text shown in admin field editors"),
|
|
5505
|
+
optionDescriptions: z22.record(z22.string().max(500)).optional().describe("Per-option guidance for select fields"),
|
|
5506
|
+
semanticRole: z22.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"),
|
|
5507
|
+
maxLength: z22.number().optional().describe("Maximum character length for field values. Three-tier resolution: explicit > displayHint > type fallback."),
|
|
5508
|
+
minLength: z22.number().optional().describe("Minimum character length for field values. Only explicit \u2014 no defaults.")
|
|
5272
5509
|
});
|
|
5273
|
-
var collectionsSchema =
|
|
5274
|
-
action:
|
|
5510
|
+
var collectionsSchema = z22.object({
|
|
5511
|
+
action: z22.enum(COLLECTIONS_ACTIONS).describe(
|
|
5275
5512
|
"'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."
|
|
5276
5513
|
),
|
|
5277
|
-
slug:
|
|
5278
|
-
name:
|
|
5279
|
-
description:
|
|
5280
|
-
purpose:
|
|
5281
|
-
icon:
|
|
5282
|
-
navGroup:
|
|
5283
|
-
fields:
|
|
5284
|
-
axis:
|
|
5285
|
-
stageLabelMap:
|
|
5286
|
-
defaultCanonicalKey:
|
|
5287
|
-
defaultWorkflowStatus:
|
|
5288
|
-
validWorkflowStatuses:
|
|
5514
|
+
slug: z22.string().max(200).optional().describe("URL-safe identifier for create/update, e.g. 'glossary', 'tech-debt'. For label-*: label slug."),
|
|
5515
|
+
name: z22.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("For label-*: the label's name. For update: refused (the catalog's)."),
|
|
5516
|
+
description: z22.string().max(2e4).optional().describe("For label-*: what the label means (max 2,000 chars). For update: refused (the catalog's)."),
|
|
5517
|
+
purpose: z22.string().max(2e3).optional().describe("Why this collection exists \u2014 strategic reason"),
|
|
5518
|
+
icon: z22.string().max(50).optional().describe("For update: always refused \u2014 a collection's icon comes from the platform catalog."),
|
|
5519
|
+
navGroup: z22.enum(["daily", "strategic", "governance", "reference", "collections"]).optional().describe("Sidebar placement: 'daily', 'strategic', 'governance', 'reference', 'collections'"),
|
|
5520
|
+
fields: z22.array(fieldSchema).max(200).optional().describe("Field definitions for create, or replacement schema for update (replaces all fields)"),
|
|
5521
|
+
axis: z22.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."),
|
|
5522
|
+
stageLabelMap: z22.record(z22.string(), z22.enum(["open", "in_progress", "done", "stopped", "tag"])).optional().describe("Required when axis is 'work': maps each valid workflowStatus to a canonical stage."),
|
|
5523
|
+
defaultCanonicalKey: z22.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."),
|
|
5524
|
+
defaultWorkflowStatus: z22.string().max(200).optional().describe("Default workflowStatus for new entries. For update: always refused \u2014 the status words come from the platform catalog."),
|
|
5525
|
+
validWorkflowStatuses: z22.array(z22.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."),
|
|
5289
5526
|
// ENT-65, FEAT-200
|
|
5290
|
-
classificationCheck:
|
|
5291
|
-
classificationPriority:
|
|
5292
|
-
qualityCriteria:
|
|
5293
|
-
statusList:
|
|
5527
|
+
classificationCheck: z22.string().max(500).optional().describe("LLM decision-tree check for this collection (3\u2013500 chars). Guides the classifier in routing entries here."),
|
|
5528
|
+
classificationPriority: z22.number().optional().describe("Classifier priority (1\u20139, lower = higher priority). Used with classificationCheck to order the decision tree."),
|
|
5529
|
+
qualityCriteria: z22.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."),
|
|
5530
|
+
statusList: z22.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."),
|
|
5294
5531
|
// For label-*
|
|
5295
|
-
color:
|
|
5296
|
-
parentSlug:
|
|
5297
|
-
isGroup:
|
|
5298
|
-
order:
|
|
5299
|
-
entryId:
|
|
5532
|
+
color: z22.string().max(50).optional().describe("For label-create/label-update: hex color, e.g. '#ef4444'."),
|
|
5533
|
+
parentSlug: z22.string().max(200).optional().describe("For label-create: parent group slug for label hierarchy."),
|
|
5534
|
+
isGroup: z22.boolean().optional().describe("For label-create/label-update: true if this is a group container, not a taggable label."),
|
|
5535
|
+
order: z22.number().optional().describe("For label-create/label-update: sort order within its group."),
|
|
5536
|
+
entryId: z22.string().max(200).optional().describe("For label-apply/label-remove: entry ID.")
|
|
5300
5537
|
});
|
|
5301
|
-
var collectionsListVariant =
|
|
5302
|
-
var collectionsDescribeVariant =
|
|
5303
|
-
var collectionsUpdateVariant =
|
|
5304
|
-
action:
|
|
5305
|
-
slug:
|
|
5306
|
-
name:
|
|
5307
|
-
description:
|
|
5308
|
-
purpose:
|
|
5309
|
-
icon:
|
|
5310
|
-
navGroup:
|
|
5311
|
-
fields:
|
|
5312
|
-
axis:
|
|
5313
|
-
stageLabelMap:
|
|
5538
|
+
var collectionsListVariant = z22.object({ action: z22.literal("list") });
|
|
5539
|
+
var collectionsDescribeVariant = z22.object({ action: z22.literal("describe"), slug: z22.string().max(200) });
|
|
5540
|
+
var collectionsUpdateVariant = z22.object({
|
|
5541
|
+
action: z22.literal("update"),
|
|
5542
|
+
slug: z22.string().max(200),
|
|
5543
|
+
name: z22.string().max(ENTRY_NAME_MAX_CHARS).optional(),
|
|
5544
|
+
description: z22.string().max(2e4).optional(),
|
|
5545
|
+
purpose: z22.string().max(2e3).optional(),
|
|
5546
|
+
icon: z22.string().max(50).optional(),
|
|
5547
|
+
navGroup: z22.enum(["daily", "strategic", "governance", "reference", "collections"]).optional(),
|
|
5548
|
+
fields: z22.array(fieldSchema).optional(),
|
|
5549
|
+
axis: z22.enum(["work", "none", "pending"]).optional(),
|
|
5550
|
+
stageLabelMap: z22.record(z22.string(), z22.enum(["open", "in_progress", "done", "stopped", "tag"])).optional(),
|
|
5314
5551
|
// WP-640 SWEEP (P1): axis/stageLabelMap repair legacy custom collections — see collections.ts's updateCollection.
|
|
5315
|
-
defaultCanonicalKey:
|
|
5316
|
-
defaultWorkflowStatus:
|
|
5317
|
-
validWorkflowStatuses:
|
|
5318
|
-
classificationCheck:
|
|
5319
|
-
classificationPriority:
|
|
5320
|
-
qualityCriteria:
|
|
5321
|
-
statusList:
|
|
5552
|
+
defaultCanonicalKey: z22.string().max(200).optional(),
|
|
5553
|
+
defaultWorkflowStatus: z22.string().max(200).optional(),
|
|
5554
|
+
validWorkflowStatuses: z22.array(z22.string().max(200)).optional(),
|
|
5555
|
+
classificationCheck: z22.string().max(500).optional(),
|
|
5556
|
+
classificationPriority: z22.number().optional(),
|
|
5557
|
+
qualityCriteria: z22.array(qualityCriterionSchema).optional(),
|
|
5558
|
+
statusList: z22.array(statusListEntrySchema).optional()
|
|
5322
5559
|
});
|
|
5323
|
-
var collectionsAuditVariant =
|
|
5324
|
-
var collectionsExportVariant =
|
|
5325
|
-
var collectionsLabelListVariant =
|
|
5326
|
-
var collectionsLabelCreateVariant =
|
|
5327
|
-
action:
|
|
5328
|
-
slug:
|
|
5329
|
-
name:
|
|
5330
|
-
color:
|
|
5331
|
-
description:
|
|
5332
|
-
parentSlug:
|
|
5333
|
-
isGroup:
|
|
5334
|
-
order:
|
|
5560
|
+
var collectionsAuditVariant = z22.object({ action: z22.literal("audit") });
|
|
5561
|
+
var collectionsExportVariant = z22.object({ action: z22.literal("export") });
|
|
5562
|
+
var collectionsLabelListVariant = z22.object({ action: z22.literal("label-list") });
|
|
5563
|
+
var collectionsLabelCreateVariant = z22.object({
|
|
5564
|
+
action: z22.literal("label-create"),
|
|
5565
|
+
slug: z22.string().max(200),
|
|
5566
|
+
name: z22.string().max(ENTRY_NAME_MAX_CHARS),
|
|
5567
|
+
color: z22.string().max(50).optional(),
|
|
5568
|
+
description: z22.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
|
|
5569
|
+
parentSlug: z22.string().max(200).optional(),
|
|
5570
|
+
isGroup: z22.boolean().optional(),
|
|
5571
|
+
order: z22.number().optional()
|
|
5335
5572
|
});
|
|
5336
|
-
var collectionsLabelUpdateVariant =
|
|
5337
|
-
action:
|
|
5338
|
-
slug:
|
|
5339
|
-
name:
|
|
5340
|
-
color:
|
|
5341
|
-
description:
|
|
5342
|
-
isGroup:
|
|
5343
|
-
order:
|
|
5573
|
+
var collectionsLabelUpdateVariant = z22.object({
|
|
5574
|
+
action: z22.literal("label-update"),
|
|
5575
|
+
slug: z22.string().max(200),
|
|
5576
|
+
name: z22.string().max(ENTRY_NAME_MAX_CHARS).optional(),
|
|
5577
|
+
color: z22.string().max(50).optional(),
|
|
5578
|
+
description: z22.string().max(LABEL_DESCRIPTION_MAX_CHARS).optional(),
|
|
5579
|
+
isGroup: z22.boolean().optional(),
|
|
5580
|
+
order: z22.number().optional()
|
|
5344
5581
|
});
|
|
5345
|
-
var collectionsLabelDeleteVariant =
|
|
5346
|
-
var collectionsLabelApplyVariant =
|
|
5347
|
-
var collectionsLabelRemoveVariant =
|
|
5348
|
-
var collectionsActionUnion =
|
|
5582
|
+
var collectionsLabelDeleteVariant = z22.object({ action: z22.literal("label-delete"), slug: z22.string().max(200) });
|
|
5583
|
+
var collectionsLabelApplyVariant = z22.object({ action: z22.literal("label-apply"), slug: z22.string().max(200), entryId: z22.string().max(200) });
|
|
5584
|
+
var collectionsLabelRemoveVariant = z22.object({ action: z22.literal("label-remove"), slug: z22.string().max(200), entryId: z22.string().max(200) });
|
|
5585
|
+
var collectionsActionUnion = z22.discriminatedUnion("action", [
|
|
5349
5586
|
collectionsListVariant,
|
|
5350
5587
|
collectionsDescribeVariant,
|
|
5351
5588
|
collectionsUpdateVariant,
|
|
@@ -5652,7 +5889,7 @@ async function handleExport() {
|
|
|
5652
5889
|
}
|
|
5653
5890
|
|
|
5654
5891
|
// src/tools/orient.ts
|
|
5655
|
-
import { z as
|
|
5892
|
+
import { z as z23 } from "zod/v3";
|
|
5656
5893
|
|
|
5657
5894
|
// src/tools/planned-work.ts
|
|
5658
5895
|
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._";
|
|
@@ -6552,25 +6789,25 @@ async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapsho
|
|
|
6552
6789
|
}
|
|
6553
6790
|
}
|
|
6554
6791
|
var ORIENT_ACTIONS = ["task"];
|
|
6555
|
-
var orientSchema =
|
|
6556
|
-
action:
|
|
6792
|
+
var orientSchema = z23.object({
|
|
6793
|
+
action: z23.enum(ORIENT_ACTIONS).optional().default("task").describe(
|
|
6557
6794
|
"'task': task-grounded context loader, the only action."
|
|
6558
6795
|
),
|
|
6559
|
-
mode:
|
|
6560
|
-
tier:
|
|
6796
|
+
mode: z23.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."),
|
|
6797
|
+
tier: z23.enum(["summary", "standard", "full"]).optional().describe(
|
|
6561
6798
|
"For 'task': payload depth. Defaults to standard (~256 KB), with or without a task. Pass summary, standard, or full to override."
|
|
6562
6799
|
),
|
|
6563
|
-
task:
|
|
6800
|
+
task: z23.string().max(2e3).optional().describe(
|
|
6564
6801
|
"For 'task': natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task."
|
|
6565
6802
|
),
|
|
6566
6803
|
// D1d (WP-754/TASK-204): matches the server's StartupResolutionSignals shape; domain resolution (original purpose) is deleted, sole survivor is `context.served` telemetry.
|
|
6567
|
-
startupSignals:
|
|
6568
|
-
changedPaths:
|
|
6569
|
-
reviewedArtifactRefs:
|
|
6570
|
-
branchName:
|
|
6571
|
-
worktreeName:
|
|
6804
|
+
startupSignals: z23.object({
|
|
6805
|
+
changedPaths: z23.array(z23.string()).max(25).optional().describe("Paths changed in the current working tree, if known (e.g. from a prior git status/diff tool call)."),
|
|
6806
|
+
reviewedArtifactRefs: z23.array(z23.string()).max(25).optional().describe("Chain entry IDs the caller has already reviewed this session, if tracked."),
|
|
6807
|
+
branchName: z23.string().max(120).optional().describe("Current git branch name, if known."),
|
|
6808
|
+
worktreeName: z23.string().max(120).optional().describe("Current worktree/directory name, if known.")
|
|
6572
6809
|
}).optional().describe("For 'task': best-effort startup signals \u2014 changedPaths/reviewedArtifactRefs/branchName/worktreeName. All optional; omit fields you don't know."),
|
|
6573
|
-
invocationPath:
|
|
6810
|
+
invocationPath: z23.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.")
|
|
6574
6811
|
});
|
|
6575
6812
|
function taskGroundingWarningLines(task, hasTaskGrounding = false) {
|
|
6576
6813
|
if (hasTaskGrounding) return [];
|
|
@@ -7222,7 +7459,7 @@ async function _handleOrient({ mode: mode2 = "full", tier, task, startupSignals,
|
|
|
7222
7459
|
}
|
|
7223
7460
|
|
|
7224
7461
|
// src/tools/workflows.ts
|
|
7225
|
-
import { z as
|
|
7462
|
+
import { z as z24 } from "zod/v3";
|
|
7226
7463
|
|
|
7227
7464
|
// src/lib/resolveCollection.ts
|
|
7228
7465
|
async function resolveCollection(params) {
|
|
@@ -8081,73 +8318,73 @@ function workflowRunOutputToText(output) {
|
|
|
8081
8318
|
|
|
8082
8319
|
// src/tools/workflows.ts
|
|
8083
8320
|
var WORKFLOWS_ACTIONS = ["list", "start", "checkpoint", "get-run"];
|
|
8084
|
-
var jsonValueSchema =
|
|
8085
|
-
() =>
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8321
|
+
var jsonValueSchema = z24.lazy(
|
|
8322
|
+
() => z24.union([
|
|
8323
|
+
z24.string(),
|
|
8324
|
+
z24.number(),
|
|
8325
|
+
z24.boolean(),
|
|
8326
|
+
z24.null(),
|
|
8327
|
+
z24.array(jsonValueSchema),
|
|
8328
|
+
z24.record(jsonValueSchema)
|
|
8092
8329
|
])
|
|
8093
8330
|
);
|
|
8094
|
-
var workflowRunOutputInputSchema =
|
|
8095
|
-
|
|
8096
|
-
format:
|
|
8097
|
-
value:
|
|
8331
|
+
var workflowRunOutputInputSchema = z24.union([
|
|
8332
|
+
z24.object({
|
|
8333
|
+
format: z24.literal("freetext"),
|
|
8334
|
+
value: z24.string()
|
|
8098
8335
|
}),
|
|
8099
|
-
|
|
8100
|
-
format:
|
|
8101
|
-
value:
|
|
8336
|
+
z24.object({
|
|
8337
|
+
format: z24.literal("list"),
|
|
8338
|
+
value: z24.array(z24.string())
|
|
8102
8339
|
}),
|
|
8103
|
-
|
|
8104
|
-
format:
|
|
8105
|
-
value:
|
|
8340
|
+
z24.object({
|
|
8341
|
+
format: z24.literal("choice"),
|
|
8342
|
+
value: z24.union([z24.string(), z24.array(z24.string())])
|
|
8106
8343
|
}),
|
|
8107
|
-
|
|
8108
|
-
format:
|
|
8344
|
+
z24.object({
|
|
8345
|
+
format: z24.literal("structured"),
|
|
8109
8346
|
value: jsonValueSchema
|
|
8110
8347
|
})
|
|
8111
8348
|
]);
|
|
8112
|
-
var workflowsSchema =
|
|
8113
|
-
action:
|
|
8349
|
+
var workflowsSchema = z24.object({
|
|
8350
|
+
action: z24.enum(WORKFLOWS_ACTIONS).describe(
|
|
8114
8351
|
"'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."
|
|
8115
8352
|
),
|
|
8116
|
-
workflowId:
|
|
8117
|
-
runId:
|
|
8118
|
-
roundId:
|
|
8119
|
-
output:
|
|
8120
|
-
isFinal:
|
|
8121
|
-
restart:
|
|
8122
|
-
summaryName:
|
|
8123
|
-
summaryDescription:
|
|
8124
|
-
summaryEntryId:
|
|
8353
|
+
workflowId: z24.string().max(200).optional().describe("Workflow ID for start, checkpoint, or get-run, e.g. 'retro', 'implementation-review'"),
|
|
8354
|
+
runId: z24.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)."),
|
|
8355
|
+
roundId: z24.string().max(200).optional().describe("Round ID for checkpoint, e.g. 'what-went-well'"),
|
|
8356
|
+
output: z24.union([z24.string(), workflowRunOutputInputSchema]).optional().describe("The round's output \u2014 either legacy synthesized text or a typed workflow run payload."),
|
|
8357
|
+
isFinal: z24.boolean().optional().describe("If true, finalize an existing durable workflow run from its terminal round and create the summary chain entry."),
|
|
8358
|
+
restart: z24.boolean().optional().describe("If true, start a new durable run from the workflow's first round in the current session."),
|
|
8359
|
+
summaryName: z24.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("Optional name for final chain entry. If omitted, the workflow summary template is used."),
|
|
8360
|
+
summaryDescription: z24.string().max(ENTRY_BODY_MAX_CHARS).optional().describe("Optional override for the final chain entry description. Defaults to the final round output text."),
|
|
8361
|
+
summaryEntryId: z24.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."),
|
|
8125
8362
|
// WP-513: team+role to create the finalize summary AS OWNER of (rung 2 only).
|
|
8126
|
-
ownerTeamEntryId:
|
|
8127
|
-
ownerRoleEntryId:
|
|
8363
|
+
ownerTeamEntryId: z24.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning team (rung-2)."),
|
|
8364
|
+
ownerRoleEntryId: z24.string().max(200).optional().describe("For 'checkpoint' (isFinal): owning role (rung-2).")
|
|
8128
8365
|
});
|
|
8129
|
-
var workflowsListVariant =
|
|
8130
|
-
var workflowsGetRunVariant =
|
|
8131
|
-
action:
|
|
8132
|
-
runId:
|
|
8133
|
-
workflowId:
|
|
8366
|
+
var workflowsListVariant = z24.object({ action: z24.literal("list") });
|
|
8367
|
+
var workflowsGetRunVariant = z24.object({
|
|
8368
|
+
action: z24.literal("get-run"),
|
|
8369
|
+
runId: z24.string().max(200).optional(),
|
|
8370
|
+
workflowId: z24.string().max(200).optional()
|
|
8134
8371
|
});
|
|
8135
|
-
var workflowsStartVariant =
|
|
8136
|
-
var workflowsCheckpointVariant =
|
|
8137
|
-
action:
|
|
8138
|
-
workflowId:
|
|
8139
|
-
roundId:
|
|
8140
|
-
output:
|
|
8141
|
-
isFinal:
|
|
8142
|
-
restart:
|
|
8143
|
-
summaryName:
|
|
8144
|
-
summaryDescription:
|
|
8145
|
-
summaryEntryId:
|
|
8146
|
-
runId:
|
|
8147
|
-
ownerTeamEntryId:
|
|
8148
|
-
ownerRoleEntryId:
|
|
8372
|
+
var workflowsStartVariant = z24.object({ action: z24.literal("start"), workflowId: z24.string().max(200) });
|
|
8373
|
+
var workflowsCheckpointVariant = z24.object({
|
|
8374
|
+
action: z24.literal("checkpoint"),
|
|
8375
|
+
workflowId: z24.string().max(200),
|
|
8376
|
+
roundId: z24.string().max(200),
|
|
8377
|
+
output: z24.union([z24.string(), workflowRunOutputInputSchema]),
|
|
8378
|
+
isFinal: z24.boolean().optional(),
|
|
8379
|
+
restart: z24.boolean().optional(),
|
|
8380
|
+
summaryName: z24.string().max(ENTRY_NAME_MAX_CHARS).optional(),
|
|
8381
|
+
summaryDescription: z24.string().max(ENTRY_BODY_MAX_CHARS).optional(),
|
|
8382
|
+
summaryEntryId: z24.string().max(200).optional(),
|
|
8383
|
+
runId: z24.string().max(200).optional(),
|
|
8384
|
+
ownerTeamEntryId: z24.string().max(200).optional(),
|
|
8385
|
+
ownerRoleEntryId: z24.string().max(200).optional()
|
|
8149
8386
|
});
|
|
8150
|
-
var workflowsActionUnion =
|
|
8387
|
+
var workflowsActionUnion = z24.discriminatedUnion("action", [
|
|
8151
8388
|
workflowsListVariant,
|
|
8152
8389
|
workflowsGetRunVariant,
|
|
8153
8390
|
workflowsStartVariant,
|
|
@@ -8876,7 +9113,7 @@ function parseListOutput(output) {
|
|
|
8876
9113
|
}
|
|
8877
9114
|
|
|
8878
9115
|
// src/tools/quality.ts
|
|
8879
|
-
import { z as
|
|
9116
|
+
import { z as z25 } from "zod/v3";
|
|
8880
9117
|
|
|
8881
9118
|
// src/lib/spineVerdictRead.ts
|
|
8882
9119
|
function isRecord(value) {
|
|
@@ -9041,36 +9278,36 @@ async function handleSpineCheck(story, refresh = false) {
|
|
|
9041
9278
|
|
|
9042
9279
|
// src/tools/quality.ts
|
|
9043
9280
|
var QUALITY_ACTIONS = ["check", "re-evaluate", "verify-chain", "spine-check"];
|
|
9044
|
-
var qualitySchema =
|
|
9045
|
-
action:
|
|
9281
|
+
var qualitySchema = z25.object({
|
|
9282
|
+
action: z25.enum(QUALITY_ACTIONS).describe(
|
|
9046
9283
|
"'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."
|
|
9047
9284
|
),
|
|
9048
|
-
entryId:
|
|
9049
|
-
context:
|
|
9050
|
-
collection:
|
|
9051
|
-
mode:
|
|
9052
|
-
story:
|
|
9053
|
-
refresh:
|
|
9285
|
+
entryId: z25.string().max(200).optional().describe("For 'check'/'re-evaluate': entry ID, e.g. 'TEN-graph-db', '<PREFIX>-<n>'."),
|
|
9286
|
+
context: z25.enum(["capture", "commit", "review"]).default("review").optional().describe("For re-evaluate: evaluation context"),
|
|
9287
|
+
collection: z25.string().max(200).optional().describe("For 'verify-chain': collection slug to verify (default: glossary)."),
|
|
9288
|
+
mode: z25.enum(["report", "fix"]).optional().describe("For 'verify-chain': 'report' = read-only trust report (default). 'fix' = also update drifted codeMapping statuses."),
|
|
9289
|
+
story: z25.boolean().optional().describe("For 'spine-check': also run the on-demand one-story LLM judgment (never scheduled; result labelled [unvalidated])."),
|
|
9290
|
+
refresh: z25.boolean().optional().describe(
|
|
9054
9291
|
"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."
|
|
9055
9292
|
)
|
|
9056
9293
|
});
|
|
9057
|
-
var qualityCheckVariant =
|
|
9058
|
-
var qualityReEvaluateVariant =
|
|
9059
|
-
action:
|
|
9060
|
-
entryId:
|
|
9061
|
-
context:
|
|
9294
|
+
var qualityCheckVariant = z25.object({ action: z25.literal("check"), entryId: z25.string().max(200) });
|
|
9295
|
+
var qualityReEvaluateVariant = z25.object({
|
|
9296
|
+
action: z25.literal("re-evaluate"),
|
|
9297
|
+
entryId: z25.string().max(200),
|
|
9298
|
+
context: z25.enum(["capture", "commit", "review"]).optional().default("review")
|
|
9062
9299
|
});
|
|
9063
|
-
var qualityVerifyChainVariant =
|
|
9064
|
-
action:
|
|
9065
|
-
collection:
|
|
9066
|
-
mode:
|
|
9300
|
+
var qualityVerifyChainVariant = z25.object({
|
|
9301
|
+
action: z25.literal("verify-chain"),
|
|
9302
|
+
collection: z25.string().max(200).optional().default("glossary"),
|
|
9303
|
+
mode: z25.enum(["report", "fix"]).optional().default("report")
|
|
9067
9304
|
});
|
|
9068
|
-
var qualitySpineCheckVariant =
|
|
9069
|
-
action:
|
|
9070
|
-
story:
|
|
9071
|
-
refresh:
|
|
9305
|
+
var qualitySpineCheckVariant = z25.object({
|
|
9306
|
+
action: z25.literal("spine-check"),
|
|
9307
|
+
story: z25.boolean().optional().default(false),
|
|
9308
|
+
refresh: z25.boolean().optional().default(false)
|
|
9072
9309
|
});
|
|
9073
|
-
var qualityActionUnion =
|
|
9310
|
+
var qualityActionUnion = z25.discriminatedUnion("action", [
|
|
9074
9311
|
qualityCheckVariant,
|
|
9075
9312
|
qualityReEvaluateVariant,
|
|
9076
9313
|
qualityVerifyChainVariant,
|
|
@@ -9082,43 +9319,43 @@ var QUALITY_ACTION_SPECS = {
|
|
|
9082
9319
|
"verify-chain": { params: ["collection", "mode"], description: "All params optional; collection defaults to 'glossary'." },
|
|
9083
9320
|
"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)." }
|
|
9084
9321
|
};
|
|
9085
|
-
var qualityCheckOutputSchema =
|
|
9086
|
-
entryId:
|
|
9322
|
+
var qualityCheckOutputSchema = z25.object({
|
|
9323
|
+
entryId: z25.string(),
|
|
9087
9324
|
/** WP-480 S1: false = the ID does not resolve to an entry (typo/deleted) — distinct from "no verdict yet". */
|
|
9088
|
-
entryFound:
|
|
9089
|
-
hasVerdict:
|
|
9325
|
+
entryFound: z25.boolean().optional(),
|
|
9326
|
+
hasVerdict: z25.boolean(),
|
|
9090
9327
|
/** WP-480 S1: the verdict was judged against content the entry no longer has — re-evaluate for a current one. */
|
|
9091
|
-
stale:
|
|
9092
|
-
tier:
|
|
9093
|
-
passed:
|
|
9094
|
-
criteria:
|
|
9095
|
-
id:
|
|
9096
|
-
passed:
|
|
9097
|
-
hint:
|
|
9328
|
+
stale: z25.boolean().optional(),
|
|
9329
|
+
tier: z25.string().optional(),
|
|
9330
|
+
passed: z25.boolean().optional(),
|
|
9331
|
+
criteria: z25.array(z25.object({
|
|
9332
|
+
id: z25.string(),
|
|
9333
|
+
passed: z25.boolean(),
|
|
9334
|
+
hint: z25.string().optional()
|
|
9098
9335
|
}))
|
|
9099
9336
|
});
|
|
9100
|
-
var qualityReevaluateOutputSchema =
|
|
9101
|
-
entryId:
|
|
9102
|
-
context:
|
|
9103
|
-
score:
|
|
9104
|
-
maxScore:
|
|
9105
|
-
improved:
|
|
9337
|
+
var qualityReevaluateOutputSchema = z25.object({
|
|
9338
|
+
entryId: z25.string(),
|
|
9339
|
+
context: z25.string(),
|
|
9340
|
+
score: z25.number(),
|
|
9341
|
+
maxScore: z25.number(),
|
|
9342
|
+
improved: z25.boolean()
|
|
9106
9343
|
});
|
|
9107
|
-
var qualitySpineCheckOutputSchema =
|
|
9108
|
-
hasVerdict:
|
|
9109
|
-
noSpineEntries:
|
|
9110
|
-
structuralPassed:
|
|
9111
|
-
storyPassed:
|
|
9112
|
-
stale:
|
|
9344
|
+
var qualitySpineCheckOutputSchema = z25.object({
|
|
9345
|
+
hasVerdict: z25.boolean(),
|
|
9346
|
+
noSpineEntries: z25.boolean().optional(),
|
|
9347
|
+
structuralPassed: z25.boolean().optional(),
|
|
9348
|
+
storyPassed: z25.boolean().nullable().optional(),
|
|
9349
|
+
stale: z25.boolean().optional(),
|
|
9113
9350
|
// TASK-156: a capped membership scan must stay distinguishable from a complete one, and a
|
|
9114
9351
|
// malformed verdict needs its own discriminator — both were silently stripped before this.
|
|
9115
|
-
staleMemberIds:
|
|
9116
|
-
membershipTruncated:
|
|
9352
|
+
staleMemberIds: z25.array(z25.string()).optional(),
|
|
9353
|
+
membershipTruncated: z25.boolean().optional(),
|
|
9117
9354
|
// PRRT_kwDORS4ils6i_PVS: a KNOWN relations-fingerprint mismatch, distinct from "unknown" —
|
|
9118
9355
|
// without this, a detected topology change and an unverifiable legacy fingerprint were
|
|
9119
9356
|
// indistinguishable in structured output.
|
|
9120
|
-
relationsChanged:
|
|
9121
|
-
malformed:
|
|
9357
|
+
relationsChanged: z25.boolean().optional(),
|
|
9358
|
+
malformed: z25.boolean().optional()
|
|
9122
9359
|
});
|
|
9123
9360
|
function registerQualityTools(server) {
|
|
9124
9361
|
const qualityHandlers = {
|
|
@@ -9245,10 +9482,10 @@ async function handleReEvaluate(entryId, context) {
|
|
|
9245
9482
|
}
|
|
9246
9483
|
|
|
9247
9484
|
// src/tools/session.ts
|
|
9248
|
-
import { z as
|
|
9485
|
+
import { z as z28 } from "zod/v3";
|
|
9249
9486
|
|
|
9250
9487
|
// src/tools/wrapup.ts
|
|
9251
|
-
import { z as
|
|
9488
|
+
import { z as z26 } from "zod/v3";
|
|
9252
9489
|
|
|
9253
9490
|
// src/lib/compose-wrapup-view.ts
|
|
9254
9491
|
function toComposed(e) {
|
|
@@ -9530,8 +9767,8 @@ async function runWrapupCommitAll(data) {
|
|
|
9530
9767
|
overflowUnscanned
|
|
9531
9768
|
};
|
|
9532
9769
|
}
|
|
9533
|
-
var wrapupSchema =
|
|
9534
|
-
action:
|
|
9770
|
+
var wrapupSchema = z26.object({
|
|
9771
|
+
action: z26.enum(["review", "commit-all"]).optional().describe(
|
|
9535
9772
|
"Action to perform. 'review' (default) shows the wrapup summary. 'commit-all' accepts all uncommitted drafts; it writes no relations."
|
|
9536
9773
|
)
|
|
9537
9774
|
});
|
|
@@ -9624,26 +9861,26 @@ ${text}` : text;
|
|
|
9624
9861
|
}
|
|
9625
9862
|
|
|
9626
9863
|
// src/tools/facilitate.ts
|
|
9627
|
-
import { z as
|
|
9864
|
+
import { z as z27 } from "zod/v3";
|
|
9628
9865
|
var FACILITATE_ACTIONS = ["resume", "commit-constellation"];
|
|
9629
|
-
var coherencyAcknowledgementSchema =
|
|
9630
|
-
response:
|
|
9631
|
-
entryId:
|
|
9632
|
-
reason:
|
|
9633
|
-
subjectEntryId:
|
|
9866
|
+
var coherencyAcknowledgementSchema = z27.object({
|
|
9867
|
+
response: z27.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
|
|
9868
|
+
entryId: z27.string().max(200).optional().describe("Entry the acknowledgement links to (e.g. the strategic spine entry)."),
|
|
9869
|
+
reason: z27.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
|
|
9870
|
+
subjectEntryId: z27.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
|
|
9634
9871
|
});
|
|
9635
|
-
var facilitateSchema =
|
|
9636
|
-
action:
|
|
9872
|
+
var facilitateSchema = z27.object({
|
|
9873
|
+
action: z27.enum(FACILITATE_ACTIONS).describe(
|
|
9637
9874
|
"'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."
|
|
9638
9875
|
),
|
|
9639
|
-
betEntryId:
|
|
9640
|
-
operationId:
|
|
9876
|
+
betEntryId: z27.string().max(200).optional().describe("Bet entry ID. Required for both actions."),
|
|
9877
|
+
operationId: z27.string().max(200).optional().describe("Optional idempotency key for commit-constellation retries."),
|
|
9641
9878
|
// WP-465 slice ⑤: coherency retry controls for a COHERENCY_REFUSED constellation hold.
|
|
9642
9879
|
// Forwarded verbatim to agentKnowledge.facilitateEnvelope (validation lives at the gate).
|
|
9643
|
-
coherencyAcknowledgements:
|
|
9880
|
+
coherencyAcknowledgements: z27.array(coherencyAcknowledgementSchema).max(20).optional().describe(
|
|
9644
9881
|
"Per-offender acknowledgements to retry a constellation held under standard/strict coherency mode. Each: {subjectEntryId, response: 'linked' | 'accepted-fix' | 'diverged', entryId?, reason?}."
|
|
9645
9882
|
),
|
|
9646
|
-
steeringOverrideReason:
|
|
9883
|
+
steeringOverrideReason: z27.string().max(2e3).optional().describe(
|
|
9647
9884
|
"Typed override reason (>= 12 chars) to push a constellation past a coherency hold instead of acknowledging."
|
|
9648
9885
|
)
|
|
9649
9886
|
});
|
|
@@ -9988,49 +10225,49 @@ var SESSION_ACTIONS = [
|
|
|
9988
10225
|
"resume",
|
|
9989
10226
|
"commit-constellation"
|
|
9990
10227
|
];
|
|
9991
|
-
var coherencyAcknowledgementFlatSchema2 =
|
|
9992
|
-
response:
|
|
9993
|
-
entryId:
|
|
9994
|
-
reason:
|
|
9995
|
-
subjectEntryId:
|
|
10228
|
+
var coherencyAcknowledgementFlatSchema2 = z28.object({
|
|
10229
|
+
response: z28.string().max(200).describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
|
|
10230
|
+
entryId: z28.string().max(200).optional().describe("Entry the acknowledgement links to."),
|
|
10231
|
+
reason: z28.string().max(2e3).optional().describe("Free-text justification, required for a 'diverged' response."),
|
|
10232
|
+
subjectEntryId: z28.string().max(200).optional().describe("The refused entry this acknowledgement answers.")
|
|
9996
10233
|
});
|
|
9997
10234
|
var TEAM_PARAM_DESCRIPTION = "For 'start': the team the role is held in, by its 'TEAM-<n>' id \u2014 only needed with role, when you hold that role in more than one team; a refusal that names the way in prints it.";
|
|
9998
|
-
var sessionSchema =
|
|
9999
|
-
action:
|
|
10235
|
+
var sessionSchema = z28.object({
|
|
10236
|
+
action: z28.enum(SESSION_ACTIONS).describe(
|
|
10000
10237
|
"'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)."
|
|
10001
10238
|
),
|
|
10002
|
-
betEntryId:
|
|
10003
|
-
operationId:
|
|
10004
|
-
coherencyAcknowledgements:
|
|
10239
|
+
betEntryId: z28.string().max(200).optional().describe("For 'resume'/'commit-constellation': bet entry ID. Required for both."),
|
|
10240
|
+
operationId: z28.string().max(200).optional().describe("For 'commit-constellation': optional idempotency key for retries."),
|
|
10241
|
+
coherencyAcknowledgements: z28.array(coherencyAcknowledgementFlatSchema2).max(20).optional().describe(
|
|
10005
10242
|
"For 'commit-constellation': per-offender acknowledgements to retry a constellation held under standard/strict coherency mode."
|
|
10006
10243
|
),
|
|
10007
|
-
steeringOverrideReason:
|
|
10244
|
+
steeringOverrideReason: z28.string().max(2e3).optional().describe(
|
|
10008
10245
|
"For 'commit-constellation': typed override reason (>= 12 chars) to push past a coherency hold instead of acknowledging."
|
|
10009
10246
|
),
|
|
10010
10247
|
// DEC-1715 (WP-753 O1a)
|
|
10011
|
-
role:
|
|
10248
|
+
role: z28.string().max(200).optional().describe(
|
|
10012
10249
|
"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."
|
|
10013
10250
|
),
|
|
10014
|
-
team:
|
|
10251
|
+
team: z28.string().max(200).optional().describe(TEAM_PARAM_DESCRIPTION)
|
|
10015
10252
|
// TASK-801
|
|
10016
10253
|
});
|
|
10017
|
-
var sessionStartVariant =
|
|
10018
|
-
action:
|
|
10254
|
+
var sessionStartVariant = z28.object({
|
|
10255
|
+
action: z28.literal("start"),
|
|
10019
10256
|
// DEC-1715 (WP-753 O1a): the role to act as this session — only needed when the person holds
|
|
10020
10257
|
// more than one role; the server refuses and lists the choices when it's required and omitted.
|
|
10021
|
-
role:
|
|
10258
|
+
role: z28.string().max(200).optional().describe(
|
|
10022
10259
|
"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."
|
|
10023
10260
|
),
|
|
10024
|
-
team:
|
|
10261
|
+
team: z28.string().max(200).optional().describe(TEAM_PARAM_DESCRIPTION)
|
|
10025
10262
|
// TASK-801
|
|
10026
10263
|
});
|
|
10027
|
-
var sessionCloseVariant =
|
|
10028
|
-
var sessionStatusVariant =
|
|
10029
|
-
var sessionWrapupReviewVariant =
|
|
10030
|
-
var sessionWrapupCommitVariant =
|
|
10031
|
-
var sessionResumeVariant = facilitateSchema.omit({ action: true }).extend({ action:
|
|
10032
|
-
var sessionCommitConstellationVariant = facilitateSchema.omit({ action: true }).extend({ action:
|
|
10033
|
-
var sessionActionUnion =
|
|
10264
|
+
var sessionCloseVariant = z28.object({ action: z28.literal("close") });
|
|
10265
|
+
var sessionStatusVariant = z28.object({ action: z28.literal("status") });
|
|
10266
|
+
var sessionWrapupReviewVariant = z28.object({ action: z28.literal("wrapup-review") });
|
|
10267
|
+
var sessionWrapupCommitVariant = z28.object({ action: z28.literal("wrapup-commit") });
|
|
10268
|
+
var sessionResumeVariant = facilitateSchema.omit({ action: true }).extend({ action: z28.literal("resume") });
|
|
10269
|
+
var sessionCommitConstellationVariant = facilitateSchema.omit({ action: true }).extend({ action: z28.literal("commit-constellation") });
|
|
10270
|
+
var sessionActionUnion = z28.discriminatedUnion("action", [
|
|
10034
10271
|
sessionStartVariant,
|
|
10035
10272
|
sessionCloseVariant,
|
|
10036
10273
|
sessionStatusVariant,
|
|
@@ -10270,10 +10507,10 @@ async function handleStatus() {
|
|
|
10270
10507
|
}
|
|
10271
10508
|
|
|
10272
10509
|
// src/tools/workspace.ts
|
|
10273
|
-
import { z as
|
|
10510
|
+
import { z as z31 } from "zod/v3";
|
|
10274
10511
|
|
|
10275
10512
|
// src/tools/health.ts
|
|
10276
|
-
import { z as
|
|
10513
|
+
import { z as z29 } from "zod/v3";
|
|
10277
10514
|
|
|
10278
10515
|
// src/lib/auditView.ts
|
|
10279
10516
|
async function buildTenantAuditView(limit) {
|
|
@@ -10619,60 +10856,60 @@ ${logLines.join("\n")}${seamSummaryText}` }],
|
|
|
10619
10856
|
};
|
|
10620
10857
|
}
|
|
10621
10858
|
var HEALTH_ACTIONS = ["check", "whoami", "status", "audit", "self-test"];
|
|
10622
|
-
var healthSchema =
|
|
10623
|
-
action:
|
|
10859
|
+
var healthSchema = z29.object({
|
|
10860
|
+
action: z29.enum(HEALTH_ACTIONS).describe(
|
|
10624
10861
|
"'check': connectivity and workspace stats. 'whoami': session identity. 'status': workspace readiness. 'audit': session audit log. 'self-test': validate all tool schemas."
|
|
10625
10862
|
),
|
|
10626
|
-
limit:
|
|
10863
|
+
limit: z29.number().min(1).max(50).default(20).optional().describe("For audit: how many recent calls to show (max 50)")
|
|
10627
10864
|
});
|
|
10628
|
-
var healthCheckOutputSchema =
|
|
10629
|
-
healthy:
|
|
10630
|
-
collections:
|
|
10631
|
-
entries:
|
|
10632
|
-
latencyMs:
|
|
10633
|
-
workspace:
|
|
10865
|
+
var healthCheckOutputSchema = z29.object({
|
|
10866
|
+
healthy: z29.boolean(),
|
|
10867
|
+
collections: z29.number(),
|
|
10868
|
+
entries: z29.number(),
|
|
10869
|
+
latencyMs: z29.number(),
|
|
10870
|
+
workspace: z29.string()
|
|
10634
10871
|
});
|
|
10635
|
-
var organisationHealthSchema =
|
|
10636
|
-
reviewed:
|
|
10637
|
-
agreements:
|
|
10638
|
-
disagreements:
|
|
10639
|
-
abstentions:
|
|
10640
|
-
agreementRate:
|
|
10641
|
-
flags:
|
|
10872
|
+
var organisationHealthSchema = z29.object({
|
|
10873
|
+
reviewed: z29.number(),
|
|
10874
|
+
agreements: z29.number(),
|
|
10875
|
+
disagreements: z29.number(),
|
|
10876
|
+
abstentions: z29.number(),
|
|
10877
|
+
agreementRate: z29.number(),
|
|
10878
|
+
flags: z29.array(z29.object({ collection: z29.string(), count: z29.number(), suggestedCollection: z29.string() }))
|
|
10642
10879
|
});
|
|
10643
|
-
var healthStatusOutputSchema =
|
|
10644
|
-
sampleTruncated:
|
|
10645
|
-
activeEntries:
|
|
10646
|
-
totalRelations:
|
|
10647
|
-
orphanedEntries:
|
|
10648
|
-
checks:
|
|
10649
|
-
gaps:
|
|
10880
|
+
var healthStatusOutputSchema = z29.object({
|
|
10881
|
+
sampleTruncated: z29.boolean().nullable().optional(),
|
|
10882
|
+
activeEntries: z29.number(),
|
|
10883
|
+
totalRelations: z29.number(),
|
|
10884
|
+
orphanedEntries: z29.number(),
|
|
10885
|
+
checks: z29.array(z29.object({ label: z29.string(), passed: z29.boolean(), current: z29.number(), required: z29.number() })),
|
|
10886
|
+
gaps: z29.array(z29.object({ id: z29.string(), label: z29.string(), guidance: z29.string() })),
|
|
10650
10887
|
organisationHealth: organisationHealthSchema.optional()
|
|
10651
10888
|
});
|
|
10652
|
-
var healthAuditOutputSchema =
|
|
10653
|
-
totalCalls:
|
|
10654
|
-
calls:
|
|
10655
|
-
tool:
|
|
10656
|
-
action:
|
|
10657
|
-
timestamp:
|
|
10658
|
-
durationMs:
|
|
10889
|
+
var healthAuditOutputSchema = z29.object({
|
|
10890
|
+
totalCalls: z29.number(),
|
|
10891
|
+
calls: z29.array(z29.object({
|
|
10892
|
+
tool: z29.string(),
|
|
10893
|
+
action: z29.string().optional(),
|
|
10894
|
+
timestamp: z29.string(),
|
|
10895
|
+
durationMs: z29.number().optional()
|
|
10659
10896
|
}))
|
|
10660
10897
|
});
|
|
10661
|
-
var healthWhoamiOutputSchema =
|
|
10662
|
-
workspaceId:
|
|
10663
|
-
workspaceName:
|
|
10664
|
-
scope:
|
|
10665
|
-
sessionId:
|
|
10666
|
-
oriented:
|
|
10898
|
+
var healthWhoamiOutputSchema = z29.object({
|
|
10899
|
+
workspaceId: z29.string(),
|
|
10900
|
+
workspaceName: z29.string(),
|
|
10901
|
+
scope: z29.string(),
|
|
10902
|
+
sessionId: z29.union([z29.string(), z29.null()]),
|
|
10903
|
+
oriented: z29.boolean()
|
|
10667
10904
|
});
|
|
10668
|
-
var selfTestOutputSchema =
|
|
10669
|
-
passed:
|
|
10670
|
-
failed:
|
|
10671
|
-
total:
|
|
10672
|
-
results:
|
|
10673
|
-
tool:
|
|
10674
|
-
valid:
|
|
10675
|
-
error:
|
|
10905
|
+
var selfTestOutputSchema = z29.object({
|
|
10906
|
+
passed: z29.number(),
|
|
10907
|
+
failed: z29.number(),
|
|
10908
|
+
total: z29.number(),
|
|
10909
|
+
results: z29.array(z29.object({
|
|
10910
|
+
tool: z29.string(),
|
|
10911
|
+
valid: z29.boolean(),
|
|
10912
|
+
error: z29.string().optional()
|
|
10676
10913
|
}))
|
|
10677
10914
|
});
|
|
10678
10915
|
function handleSelfTest(server) {
|
|
@@ -10723,9 +10960,9 @@ function handleSelfTest(server) {
|
|
|
10723
10960
|
}
|
|
10724
10961
|
|
|
10725
10962
|
// src/tools/usage.ts
|
|
10726
|
-
import { z as
|
|
10727
|
-
var usageSummarySchema =
|
|
10728
|
-
periodDays:
|
|
10963
|
+
import { z as z30 } from "zod/v3";
|
|
10964
|
+
var usageSummarySchema = z30.object({
|
|
10965
|
+
periodDays: z30.number().min(1).max(90).optional().describe("Number of days to look back (default 30, max 90)")
|
|
10729
10966
|
});
|
|
10730
10967
|
async function handleUsageSummary(periodDays) {
|
|
10731
10968
|
const ws = await getWorkspaceContext();
|
|
@@ -10795,20 +11032,20 @@ var WORKSPACE_ACTIONS = [
|
|
|
10795
11032
|
"self-test",
|
|
10796
11033
|
"usage"
|
|
10797
11034
|
];
|
|
10798
|
-
var workspaceSchema =
|
|
10799
|
-
action:
|
|
11035
|
+
var workspaceSchema = z31.object({
|
|
11036
|
+
action: z31.enum(WORKSPACE_ACTIONS).describe(
|
|
10800
11037
|
"'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)."
|
|
10801
11038
|
),
|
|
10802
|
-
limit:
|
|
10803
|
-
periodDays:
|
|
11039
|
+
limit: z31.number().min(1).max(50).optional().describe("For 'audit': how many recent calls to show (max 50, default 20)."),
|
|
11040
|
+
periodDays: z31.number().min(1).max(90).optional().describe("For 'usage': number of days to look back (default 30, max 90).")
|
|
10804
11041
|
});
|
|
10805
|
-
var workspaceCheckVariant =
|
|
10806
|
-
var workspaceWhoamiVariant =
|
|
10807
|
-
var workspaceStatusVariant =
|
|
10808
|
-
var workspaceAuditVariant =
|
|
10809
|
-
var workspaceSelfTestVariant =
|
|
10810
|
-
var workspaceUsageVariant =
|
|
10811
|
-
var workspaceActionUnion =
|
|
11042
|
+
var workspaceCheckVariant = z31.object({ action: z31.literal("check") });
|
|
11043
|
+
var workspaceWhoamiVariant = z31.object({ action: z31.literal("whoami") });
|
|
11044
|
+
var workspaceStatusVariant = z31.object({ action: z31.literal("status") });
|
|
11045
|
+
var workspaceAuditVariant = z31.object({ action: z31.literal("audit"), limit: z31.number().min(1).max(50).optional().default(20) });
|
|
11046
|
+
var workspaceSelfTestVariant = z31.object({ action: z31.literal("self-test") });
|
|
11047
|
+
var workspaceUsageVariant = z31.object({ action: z31.literal("usage"), periodDays: z31.number().min(1).max(90).optional() });
|
|
11048
|
+
var workspaceActionUnion = z31.discriminatedUnion("action", [
|
|
10812
11049
|
workspaceCheckVariant,
|
|
10813
11050
|
workspaceWhoamiVariant,
|
|
10814
11051
|
workspaceStatusVariant,
|
|
@@ -10854,7 +11091,7 @@ function registerWorkspaceTools(server) {
|
|
|
10854
11091
|
}
|
|
10855
11092
|
|
|
10856
11093
|
// src/tools/feedback.ts
|
|
10857
|
-
import { z as
|
|
11094
|
+
import { z as z32 } from "zod/v3";
|
|
10858
11095
|
|
|
10859
11096
|
// src/lib/productFeedbackConstants.ts
|
|
10860
11097
|
var PRODUCT_FEEDBACK_CATEGORIES = ["bug", "friction", "idea", "praise", "other"];
|
|
@@ -10867,41 +11104,41 @@ var MAX_FEEDBACK_ANSWER_LENGTH = 240;
|
|
|
10867
11104
|
|
|
10868
11105
|
// src/tools/feedback.ts
|
|
10869
11106
|
var actions = ["submit", "list", "queue", "note", "group", "status"];
|
|
10870
|
-
var category =
|
|
10871
|
-
var status =
|
|
10872
|
-
var vendorStatus =
|
|
10873
|
-
var tensionId =
|
|
10874
|
-
var answer =
|
|
11107
|
+
var category = z32.enum(PRODUCT_FEEDBACK_CATEGORIES);
|
|
11108
|
+
var status = z32.enum(PRODUCT_FEEDBACK_STATUSES);
|
|
11109
|
+
var vendorStatus = z32.enum(VENDOR_SETTABLE_STATUSES);
|
|
11110
|
+
var tensionId = z32.string().regex(FEEDBACK_TENSION_ID_PATTERN);
|
|
11111
|
+
var answer = z32.string().trim().min(1).max(MAX_FEEDBACK_ANSWER_LENGTH);
|
|
10875
11112
|
var MESSAGE_DISPLAY_LIMIT = 1e3;
|
|
10876
11113
|
var FULL_MESSAGE_MAX_LIMIT = 5;
|
|
10877
|
-
var feedbackSchema =
|
|
10878
|
-
action:
|
|
10879
|
-
message:
|
|
11114
|
+
var feedbackSchema = z32.object({
|
|
11115
|
+
action: z32.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 and may carry tensionId and answer."),
|
|
11116
|
+
message: z32.string().max(1e4).optional().describe("Required for submit: the product feedback text (max 10,000 characters)."),
|
|
10880
11117
|
category: category.optional().describe("Submit/queue category; submit defaults to other."),
|
|
10881
|
-
command:
|
|
10882
|
-
route:
|
|
10883
|
-
client:
|
|
10884
|
-
feedbackId:
|
|
10885
|
-
feedbackIds:
|
|
10886
|
-
note:
|
|
11118
|
+
command: z32.string().max(1e3).optional().describe("Optional submit command context; argument values are scrubbed server-side."),
|
|
11119
|
+
route: z32.string().max(500).optional().describe("Optional submit route context."),
|
|
11120
|
+
client: z32.string().max(100).optional().describe("Optional submit client label."),
|
|
11121
|
+
feedbackId: z32.string().max(200).optional().describe("Required for note/status: target feedback ID."),
|
|
11122
|
+
feedbackIds: z32.array(z32.string().max(200)).max(100).optional().describe("Required for group: 1\u2013100 target feedback IDs."),
|
|
11123
|
+
note: z32.string().max(4e3).optional().describe("Required for note: replacement triage note (max 4,000 characters)."),
|
|
10887
11124
|
status: status.optional().describe("list/queue filter (any status, including 'screening'); the status action's required target value excludes 'screening' (system-only)."),
|
|
10888
11125
|
tensionId: tensionId.optional().describe("status only: the tension the report joined, its display id TEN- and a number (vendor-only, never shown to the reporter)."),
|
|
10889
11126
|
answer: answer.optional().describe(`status only: the one sentence the reporter reads under their report, dated (max ${MAX_FEEDBACK_ANSWER_LENGTH} characters).`),
|
|
10890
|
-
groupId:
|
|
10891
|
-
workspaceId:
|
|
10892
|
-
since:
|
|
10893
|
-
before:
|
|
10894
|
-
limit:
|
|
10895
|
-
cursor:
|
|
10896
|
-
full:
|
|
11127
|
+
groupId: z32.string().min(1).max(200).nullable().optional().describe("Group filter, or required group destination; null explicitly clears grouping."),
|
|
11128
|
+
workspaceId: z32.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."),
|
|
11129
|
+
since: z32.number().optional().describe("Queue-only lower createdAt window bound (inclusive) in epoch milliseconds."),
|
|
11130
|
+
before: z32.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."),
|
|
11131
|
+
limit: z32.number().int().min(1).max(100).optional().describe("list/queue row limit, default 50, maximum 100."),
|
|
11132
|
+
cursor: z32.string().max(2e3).optional().describe("Opaque pagination cursor from a previous list/queue response (continueCursor); omit for the first page."),
|
|
11133
|
+
full: z32.boolean().optional().describe(`list/queue only: return untruncated messages; allowed only when limit <= ${FULL_MESSAGE_MAX_LIMIT}.`)
|
|
10897
11134
|
});
|
|
10898
|
-
var union =
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
11135
|
+
var union = z32.discriminatedUnion("action", [
|
|
11136
|
+
z32.object({ action: z32.literal("submit"), message: z32.string().min(1).max(1e4), category: category.optional(), command: z32.string().max(1e3).optional(), route: z32.string().max(500).optional(), client: z32.string().max(100).optional() }),
|
|
11137
|
+
z32.object({ action: z32.literal("list"), status: status.optional(), limit: z32.number().int().min(1).max(100).optional(), cursor: z32.string().max(2e3).optional(), full: z32.boolean().optional() }),
|
|
11138
|
+
z32.object({ action: z32.literal("queue"), status: status.optional(), category: category.optional(), groupId: z32.string().min(1).max(200).optional(), workspaceId: z32.string().max(200).optional(), since: z32.number().optional(), before: z32.number().optional(), limit: z32.number().int().min(1).max(100).optional(), cursor: z32.string().max(2e3).optional(), full: z32.boolean().optional() }),
|
|
11139
|
+
z32.object({ action: z32.literal("note"), feedbackId: z32.string().min(1).max(200), note: z32.string().max(4e3) }),
|
|
11140
|
+
z32.object({ action: z32.literal("group"), feedbackIds: z32.array(z32.string().min(1).max(200)).min(1).max(100), groupId: z32.string().min(1).max(200).nullable() }),
|
|
11141
|
+
z32.object({ action: z32.literal("status"), feedbackId: z32.string().min(1).max(200), status: vendorStatus, tensionId: tensionId.optional(), answer: answer.optional() })
|
|
10905
11142
|
]);
|
|
10906
11143
|
var specs = {
|
|
10907
11144
|
submit: { params: ["message", "category", "command", "route", "client"], description: "message is required; category defaults to other." },
|
|
@@ -11030,19 +11267,19 @@ function registerFeedbackTool(server) {
|
|
|
11030
11267
|
}
|
|
11031
11268
|
|
|
11032
11269
|
// src/tools/conflicts.ts
|
|
11033
|
-
import { z as
|
|
11270
|
+
import { z as z33 } from "zod/v3";
|
|
11034
11271
|
var ACTIONS = ["list", "resolve"];
|
|
11035
|
-
var mode =
|
|
11036
|
-
var verdict =
|
|
11037
|
-
var conflictsSchema =
|
|
11038
|
-
action:
|
|
11272
|
+
var mode = z33.enum(["actionable", "all"]);
|
|
11273
|
+
var verdict = z33.enum(["real", "noise"]);
|
|
11274
|
+
var conflictsSchema = z33.object({
|
|
11275
|
+
action: z33.enum(ACTIONS),
|
|
11039
11276
|
mode: mode.optional().describe("list: all adds judged and snoozed rows."),
|
|
11040
|
-
issueId:
|
|
11277
|
+
issueId: z33.string().max(200).optional().describe("resolve: an id from list."),
|
|
11041
11278
|
verdict: verdict.optional().describe("resolve: real keeps the row open; noise closes it.")
|
|
11042
11279
|
});
|
|
11043
|
-
var conflictsActionUnion =
|
|
11044
|
-
|
|
11045
|
-
|
|
11280
|
+
var conflictsActionUnion = z33.discriminatedUnion("action", [
|
|
11281
|
+
z33.object({ action: z33.literal("list"), mode: mode.optional() }),
|
|
11282
|
+
z33.object({ action: z33.literal("resolve"), issueId: z33.string().min(1).max(200), verdict })
|
|
11046
11283
|
]);
|
|
11047
11284
|
var CONFLICTS_ACTION_SPECS = {
|
|
11048
11285
|
list: { params: ["mode"], description: "mode defaults to actionable." },
|
|
@@ -11085,26 +11322,26 @@ function registerConflictsTool(server) {
|
|
|
11085
11322
|
}
|
|
11086
11323
|
|
|
11087
11324
|
// src/tools/question.ts
|
|
11088
|
-
import { z as
|
|
11325
|
+
import { z as z34 } from "zod/v3";
|
|
11089
11326
|
var QUESTION_ACTIONS = ["create", "assign", "answer", "force-close", "list"];
|
|
11090
|
-
var questionSchema =
|
|
11091
|
-
action:
|
|
11327
|
+
var questionSchema = z34.object({
|
|
11328
|
+
action: z34.enum(QUESTION_ACTIONS).describe(
|
|
11092
11329
|
"'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)."
|
|
11093
11330
|
),
|
|
11094
|
-
entryId:
|
|
11095
|
-
text:
|
|
11096
|
-
blocks:
|
|
11097
|
-
toRole:
|
|
11098
|
-
reason:
|
|
11099
|
-
answerEntryId:
|
|
11100
|
-
mine:
|
|
11331
|
+
entryId: z34.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'."),
|
|
11332
|
+
text: z34.string().max(5e3).optional().describe("'create': the question text. 'answer': the answer text (mutually exclusive with answerEntryId, max 2000 chars)."),
|
|
11333
|
+
blocks: z34.array(z34.string().max(200)).max(50).optional().describe("'create': entry ids this question is blocking (repeatable)."),
|
|
11334
|
+
toRole: z34.string().max(200).optional().describe("'assign': reassign to this role (human ROL-nnn form or a raw entry id) \u2014 required."),
|
|
11335
|
+
reason: z34.string().max(2e3).optional().describe("'force-close': required reason."),
|
|
11336
|
+
answerEntryId: z34.string().max(200).optional().describe("'answer': point at an already-written entry instead of supplying text (mutually exclusive with text)."),
|
|
11337
|
+
mine: z34.boolean().optional().describe("'list': true for arm C (every question YOU asked, every status). Omit/false for the ack-gate view (what you owe).")
|
|
11101
11338
|
});
|
|
11102
|
-
var createVariant =
|
|
11103
|
-
var assignVariant =
|
|
11104
|
-
var answerVariant =
|
|
11105
|
-
var forceCloseVariant =
|
|
11106
|
-
var listVariant =
|
|
11107
|
-
var questionActionUnion =
|
|
11339
|
+
var createVariant = z34.object({ action: z34.literal("create"), text: z34.string().min(1).max(5e3), blocks: z34.array(z34.string().max(200)).max(50).optional() });
|
|
11340
|
+
var assignVariant = z34.object({ action: z34.literal("assign"), entryId: z34.string().max(200), toRole: z34.string().max(200).min(1) });
|
|
11341
|
+
var answerVariant = z34.object({ action: z34.literal("answer"), entryId: z34.string().max(200), text: z34.string().max(2e3).optional(), answerEntryId: z34.string().max(200).optional() });
|
|
11342
|
+
var forceCloseVariant = z34.object({ action: z34.literal("force-close"), entryId: z34.string().max(200), reason: z34.string().min(1).max(2e3) });
|
|
11343
|
+
var listVariant = z34.object({ action: z34.literal("list"), mine: z34.boolean().optional() });
|
|
11344
|
+
var questionActionUnion = z34.discriminatedUnion("action", [
|
|
11108
11345
|
createVariant,
|
|
11109
11346
|
assignVariant,
|
|
11110
11347
|
answerVariant,
|
|
@@ -11258,225 +11495,6 @@ function registerQuestionTools(server) {
|
|
|
11258
11495
|
);
|
|
11259
11496
|
}
|
|
11260
11497
|
|
|
11261
|
-
// src/tools/role.ts
|
|
11262
|
-
import { z as z33 } from "zod/v3";
|
|
11263
|
-
var ROLE_ACTIONS = ["accountable", "seat", "unseat", "release_move", "accept_move", "refuse_move"];
|
|
11264
|
-
var roleSchema = z33.object({
|
|
11265
|
-
action: z33.enum(ROLE_ACTIONS).describe(
|
|
11266
|
-
"'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage. 'seat': put a person in this role. 'unseat': take this role from a person. 'release_move' / 'accept_move' / 'refuse_move': move a role or team to a team with another Team Lead."
|
|
11267
|
-
),
|
|
11268
|
-
roleId: z33.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."),
|
|
11269
|
-
canonicalKey: z33.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
|
|
11270
|
-
limit: z33.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
|
|
11271
|
-
cursor: z33.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor."),
|
|
11272
|
-
person: z33.string().max(200).optional().describe(
|
|
11273
|
-
"'seat' / 'unseat': an existing person, by person id or exact email. For 'seat', give this or newPersonName, not both."
|
|
11274
|
-
),
|
|
11275
|
-
newPersonName: z33.string().max(120).optional().describe(
|
|
11276
|
-
"'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."
|
|
11277
|
-
),
|
|
11278
|
-
teamId: z33.string().max(200).optional().describe(
|
|
11279
|
-
"'seat' / 'unseat': the team, by chain id or entry id. Only needed for Team Lead, which lives in every team; any other role is seated in its home team. 'release_move': the team it moves to."
|
|
11280
|
-
),
|
|
11281
|
-
onMyAuthority: z33.boolean().optional().describe(
|
|
11282
|
-
"'seat', Team Lead only: as the team's Team Lead, seat a second Team Lead who holds the seat on your authority until you unseat them."
|
|
11283
|
-
),
|
|
11284
|
-
childId: z33.string().max(200).optional().describe("'release_move' / 'accept_move' / 'refuse_move': the role or team that moves, by chain id or entry id."),
|
|
11285
|
-
why: z33.string().max(1e3).optional().describe("'refuse_move': why the move is refused; it becomes a tension for the old team's Team Lead.")
|
|
11286
|
-
});
|
|
11287
|
-
var accountableVariant = z33.object({
|
|
11288
|
-
action: z33.literal("accountable"),
|
|
11289
|
-
roleId: z33.string().max(200),
|
|
11290
|
-
canonicalKey: z33.string().max(200).optional(),
|
|
11291
|
-
limit: z33.number().int().positive().max(200).optional(),
|
|
11292
|
-
cursor: z33.number().optional()
|
|
11293
|
-
});
|
|
11294
|
-
var seatVariant = z33.object({
|
|
11295
|
-
action: z33.literal("seat"),
|
|
11296
|
-
roleId: z33.string().max(200),
|
|
11297
|
-
person: z33.string().max(200).optional(),
|
|
11298
|
-
newPersonName: z33.string().max(120).optional(),
|
|
11299
|
-
teamId: z33.string().max(200).optional(),
|
|
11300
|
-
onMyAuthority: z33.boolean().optional()
|
|
11301
|
-
});
|
|
11302
|
-
var unseatVariant = z33.object({
|
|
11303
|
-
action: z33.literal("unseat"),
|
|
11304
|
-
roleId: z33.string().max(200),
|
|
11305
|
-
person: z33.string().max(200),
|
|
11306
|
-
teamId: z33.string().max(200).optional()
|
|
11307
|
-
});
|
|
11308
|
-
var releaseMoveVariant = z33.object({ action: z33.literal("release_move"), childId: z33.string().max(200), teamId: z33.string().max(200) });
|
|
11309
|
-
var acceptMoveVariant = z33.object({ action: z33.literal("accept_move"), childId: z33.string().max(200) });
|
|
11310
|
-
var refuseMoveVariant = z33.object({ action: z33.literal("refuse_move"), childId: z33.string().max(200), why: z33.string().max(1e3) });
|
|
11311
|
-
var roleActionUnion = z33.discriminatedUnion("action", [
|
|
11312
|
-
accountableVariant,
|
|
11313
|
-
seatVariant,
|
|
11314
|
-
unseatVariant,
|
|
11315
|
-
releaseMoveVariant,
|
|
11316
|
-
acceptMoveVariant,
|
|
11317
|
-
refuseMoveVariant
|
|
11318
|
-
]);
|
|
11319
|
-
var ROLE_ACTION_SPECS = {
|
|
11320
|
-
accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." },
|
|
11321
|
-
seat: {
|
|
11322
|
-
params: ["roleId", "person", "newPersonName", "teamId", "onMyAuthority"],
|
|
11323
|
-
description: "roleId is required, plus exactly one of person or newPersonName; teamId and onMyAuthority only for Team Lead."
|
|
11324
|
-
},
|
|
11325
|
-
unseat: { params: ["roleId", "person", "teamId"], description: "roleId and person are required; teamId only for Team Lead." },
|
|
11326
|
-
release_move: { params: ["childId", "teamId"], description: "childId and teamId (the team it moves to) are required." },
|
|
11327
|
-
accept_move: { params: ["childId"], description: "childId is required." },
|
|
11328
|
-
refuse_move: { params: ["childId", "why"], description: "childId and why are required." }
|
|
11329
|
-
};
|
|
11330
|
-
function formatHolders(result2) {
|
|
11331
|
-
if (result2.holders.length === 0) return [` holders: none${result2.holdersTruncated ? " found, but the membership scan is incomplete" : ""}`];
|
|
11332
|
-
return [
|
|
11333
|
-
" holders:",
|
|
11334
|
-
...result2.holders.map((h) => {
|
|
11335
|
-
const word = personStatusTag(h.status);
|
|
11336
|
-
const tag = word ? ` (${word})` : "";
|
|
11337
|
-
const team = h.teamName ? ` in ${sanitizeSingleLineField(h.teamName)}` : "";
|
|
11338
|
-
return ` ${sanitizeSingleLineField(h.displayName)}${tag}${team}`;
|
|
11339
|
-
}),
|
|
11340
|
-
...result2.holdersTruncated ? [" (membership scan cut at 500 rows, more holders may exist)"] : []
|
|
11341
|
-
];
|
|
11342
|
-
}
|
|
11343
|
-
function formatRow(row) {
|
|
11344
|
-
const id = row.entryId ?? row.id;
|
|
11345
|
-
const statusDisplay = row.workflowStatus ? `${row.status} / ${sanitizeSingleLineField(row.workflowStatus)}` : row.status;
|
|
11346
|
-
const collectionSlug = row.collectionSlug ? sanitizeSingleLineField(row.collectionSlug) : "?";
|
|
11347
|
-
return ` ${id} ${sanitizeSingleLineField(row.name)} [${collectionSlug}/${statusDisplay}]`;
|
|
11348
|
-
}
|
|
11349
|
-
function formatSection(label, rows, truncated, cursorHint) {
|
|
11350
|
-
if (rows.length === 0 && !truncated) return [` ${label}: not recorded yet`];
|
|
11351
|
-
const lines = rows.length === 0 ? [` ${label}: not recorded yet, but the scan is incomplete`] : [` ${label}:`, ...rows.map(formatRow)];
|
|
11352
|
-
if (truncated) lines.push(` (scan incomplete, more may exist \u2014 ${cursorHint ?? "raise limit (capped at 200, no cursor for this list)"})`);
|
|
11353
|
-
return lines;
|
|
11354
|
-
}
|
|
11355
|
-
function formatRoleAccountable(result2) {
|
|
11356
|
-
const roleLabel2 = `${sanitizeSingleLineField(result2.role.name)} (${result2.role.entryId ?? result2.role.id})`;
|
|
11357
|
-
const explicitCursorHint = result2.nextCursor !== null ? `raise limit or continue with cursor ${result2.nextCursor}` : "raise limit";
|
|
11358
|
-
return [
|
|
11359
|
-
`${roleLabel2} \u2014 accountability:`,
|
|
11360
|
-
...formatHolders(result2),
|
|
11361
|
-
...formatSection("explicit (owns)", result2.explicit, result2.explicitTruncated, explicitCursorHint),
|
|
11362
|
-
...formatSection("reporting (reports on)", result2.reporting, result2.reportingTruncated),
|
|
11363
|
-
` inherited: not-computed \u2014 ${result2.inheritedNotComputedReason}`
|
|
11364
|
-
].join("\n");
|
|
11365
|
-
}
|
|
11366
|
-
async function handleRoleAccountable(roleId, canonicalKey, limit, cursor) {
|
|
11367
|
-
try {
|
|
11368
|
-
const raw = await kernelQuery("chain.listByRole", { roleId, canonicalKey, limit, cursor });
|
|
11369
|
-
const result2 = raw;
|
|
11370
|
-
const message = formatRoleAccountable(result2);
|
|
11371
|
-
return successResult(message, message, result2);
|
|
11372
|
-
} catch (err) {
|
|
11373
|
-
return roleErrorResult(err, "accountable", { roleId, canonicalKey, limit, cursor });
|
|
11374
|
-
}
|
|
11375
|
-
}
|
|
11376
|
-
async function runSeatAction(action, fn, params) {
|
|
11377
|
-
try {
|
|
11378
|
-
requireWriteAccess();
|
|
11379
|
-
const sessionId = getAgentSessionId();
|
|
11380
|
-
const raw = await kernelMutation(fn, {
|
|
11381
|
-
roleRef: params.roleId,
|
|
11382
|
-
targetPersonRef: params.person,
|
|
11383
|
-
newPersonName: params.newPersonName,
|
|
11384
|
-
teamRef: params.teamId,
|
|
11385
|
-
sessionId,
|
|
11386
|
-
...params.onMyAuthority ? { onMyAuthority: true } : {}
|
|
11387
|
-
});
|
|
11388
|
-
const result2 = raw.refusal ? { ...raw, refusal: { ...raw.refusal, requiredAction: authorityRecovery(raw.refusal) } } : raw;
|
|
11389
|
-
const message = formatSeatSentence(action, result2, sanitizeSingleLineField);
|
|
11390
|
-
if (result2.outcome === "refused") {
|
|
11391
|
-
return failureResult(
|
|
11392
|
-
message,
|
|
11393
|
-
"PERMISSION_DENIED",
|
|
11394
|
-
message,
|
|
11395
|
-
result2.refusal?.requiredAction ?? "Ask the team's Team Lead to seat them.",
|
|
11396
|
-
void 0,
|
|
11397
|
-
result2
|
|
11398
|
-
);
|
|
11399
|
-
}
|
|
11400
|
-
return successResult(message, message, result2);
|
|
11401
|
-
} catch (err) {
|
|
11402
|
-
return roleErrorResult(err, action, params);
|
|
11403
|
-
}
|
|
11404
|
-
}
|
|
11405
|
-
function handleRoleSeat(roleId, person, newPersonName, teamId, onMyAuthority) {
|
|
11406
|
-
return runSeatAction("seat", "organisation.seatInRole", { roleId, person, newPersonName, teamId, onMyAuthority });
|
|
11407
|
-
}
|
|
11408
|
-
function handleRoleUnseat(roleId, person, teamId) {
|
|
11409
|
-
return runSeatAction("unseat", "organisation.unseatFromRole", { roleId, person, teamId });
|
|
11410
|
-
}
|
|
11411
|
-
function callMove(action, params, sessionId) {
|
|
11412
|
-
if (action === "release_move") {
|
|
11413
|
-
return kernelMutation("organisation.hierarchy.release", { childRef: params.childId, toParentRef: params.teamId, sessionId });
|
|
11414
|
-
}
|
|
11415
|
-
if (action === "accept_move") return kernelMutation("organisation.hierarchy.accept", { childRef: params.childId, sessionId });
|
|
11416
|
-
return kernelMutation("organisation.hierarchy.refuse", { childRef: params.childId, why: params.why, sessionId });
|
|
11417
|
-
}
|
|
11418
|
-
async function handleMove(action, params) {
|
|
11419
|
-
try {
|
|
11420
|
-
requireWriteAccess();
|
|
11421
|
-
const raw = await callMove(action, params, getAgentSessionId());
|
|
11422
|
-
if (raw.outcome === "refused") {
|
|
11423
|
-
const recovery = authorityRecovery(raw.refusal) ?? "Ask the Team Lead the refusal names.";
|
|
11424
|
-
const message2 = `Refused: ${sanitizeSingleLineField(raw.refusal.reason)} ${recovery}`;
|
|
11425
|
-
const code = ORGANISATION_VALIDATION_REFUSALS.has(raw.refusal.code) ? "VALIDATION_ERROR" : "PERMISSION_DENIED";
|
|
11426
|
-
return failureResult(message2, code, message2, recovery, void 0, raw);
|
|
11427
|
-
}
|
|
11428
|
-
const message = raw.replaced ? `${raw.line} It replaces the release toward ${sanitizeSingleLineField(raw.replaced)}.` : raw.line;
|
|
11429
|
-
return successResult(message, message, raw);
|
|
11430
|
-
} catch (err) {
|
|
11431
|
-
return roleErrorResult(err, action, params);
|
|
11432
|
-
}
|
|
11433
|
-
}
|
|
11434
|
-
function roleErrorResult(err, action, params = {}) {
|
|
11435
|
-
const classified = classifyError(err);
|
|
11436
|
-
const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
|
|
11437
|
-
const fallbackActions = retryIsFutile(classified.code) ? void 0 : [{ tool: "role", description: `Retry ${action}`, parameters: { action, ...definedParams } }];
|
|
11438
|
-
return failureResult(
|
|
11439
|
-
classified.message,
|
|
11440
|
-
classified.code,
|
|
11441
|
-
classified.message,
|
|
11442
|
-
classified.recovery ?? (action === "accountable" ? "Use action='accountable' with roleId set to a real role's chain id or entry id." : `Fix the input the message names and call action='${action}' again.`),
|
|
11443
|
-
classified.availableActions ?? fallbackActions,
|
|
11444
|
-
classified.diagnostics
|
|
11445
|
-
);
|
|
11446
|
-
}
|
|
11447
|
-
function registerRoleTools(server) {
|
|
11448
|
-
const roleHandlers = {
|
|
11449
|
-
accountable: (data) => handleRoleAccountable(data.roleId, data.canonicalKey, data.limit, data.cursor),
|
|
11450
|
-
seat: (data) => handleRoleSeat(data.roleId, data.person, data.newPersonName, data.teamId, data.onMyAuthority),
|
|
11451
|
-
unseat: (data) => handleRoleUnseat(data.roleId, data.person, data.teamId),
|
|
11452
|
-
release_move: (data) => handleMove("release_move", data),
|
|
11453
|
-
accept_move: (data) => handleMove("accept_move", data),
|
|
11454
|
-
refuse_move: (data) => handleMove("refuse_move", data)
|
|
11455
|
-
};
|
|
11456
|
-
server.registerTool(
|
|
11457
|
-
"role",
|
|
11458
|
-
{
|
|
11459
|
-
title: "Role",
|
|
11460
|
-
description: "Workspace roles \u2014 who is accountable for what, who holds it, and where it sits. Six actions:\n\n- **accountable**: what this role owns (`explicit` \u2014 the canonical ownership row for objective/key_result/tension, data.ownerRoleId for domain), reports on (`reporting`, data.reporterRoleId \u2014 key results only, a separate fact from ownership), and \u2014 always `not-computed` today, never faked as empty \u2014 inherits via Team-Lead vacancy coverage. Also lists `holders`.\n- **seat**: put a person in this role, by person id or email, or by `newPersonName` for someone with no login yet (a placeholder person, created once per exact name). The role's home team is used; name `teamId` only for Team Lead. A held role refuses a second holder and names the holder; the person keeps their other roles in the team. Needs the team's Team Lead. With `onMyAuthority`, the team's Team Lead seats a second Team Lead on their own authority; unseating them revokes it.\n- **unseat**: take this role from a person; their other roles in the team stay. The last active Team Lead of a team is refused. Invite a person, or take them out of a team, with the `people` tool.\n- **release_move** / **accept_move** / **refuse_move**: move a role or team (`childId`) to a team whose Team Lead is another seat. Acting as Team Lead of its current team, release it toward `teamId`; acting as Team Lead of that team, accept it, or refuse it with `why` (it stays, and a tension goes to its current team's Team Lead).",
|
|
11461
|
-
inputSchema: roleSchema,
|
|
11462
|
-
// The hints describe the whole tool, so they say the most it can do: unseat removes a role and can
|
|
11463
|
-
// delete a membership row (destructive), and a repeated seat still writes history and audit rows
|
|
11464
|
-
// (not idempotent), even though accountable is a pure read (PR #1508 review). Closed world: nothing here
|
|
11465
|
-
// reaches outside the workspace since invite moved to `people` (TASK-677, DEC-1981).
|
|
11466
|
-
annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: false }
|
|
11467
|
-
},
|
|
11468
|
-
thinWrapper(async (args) => {
|
|
11469
|
-
const parsed = parseOrFail(roleSchema, args);
|
|
11470
|
-
if (!parsed.ok) return parsed.result;
|
|
11471
|
-
const { action } = parsed.data;
|
|
11472
|
-
return runWithToolContext(
|
|
11473
|
-
{ tool: "role", action },
|
|
11474
|
-
() => dispatchDiscriminated("role", roleActionUnion, parsed.data, ROLE_ACTION_SPECS, roleHandlers)
|
|
11475
|
-
);
|
|
11476
|
-
})
|
|
11477
|
-
);
|
|
11478
|
-
}
|
|
11479
|
-
|
|
11480
11498
|
// src/resources/index.ts
|
|
11481
11499
|
import { existsSync as existsSync3 } from "fs";
|
|
11482
11500
|
import { dirname, join, resolve as resolve4 } from "path";
|
|
@@ -11805,7 +11823,7 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
11805
11823
|
}
|
|
11806
11824
|
|
|
11807
11825
|
// src/prompts/index.ts
|
|
11808
|
-
import { z as
|
|
11826
|
+
import { z as z35 } from "zod/v3";
|
|
11809
11827
|
async function buildReviewAgainstRulesPrompt(domain) {
|
|
11810
11828
|
const entries = await kernelQuery("chain.listEntries", { collectionSlug: "rules" });
|
|
11811
11829
|
const rules = entries.slice(0, 50);
|
|
@@ -11887,27 +11905,27 @@ function registerPrompts(server) {
|
|
|
11887
11905
|
server.prompt(
|
|
11888
11906
|
"review-against-rules",
|
|
11889
11907
|
"Review code or a design decision against the rules, focused on a given area. Fetches the rules and asks you to do a structured compliance review.",
|
|
11890
|
-
{ domain:
|
|
11908
|
+
{ domain: z35.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
|
|
11891
11909
|
async ({ domain }) => buildReviewAgainstRulesPrompt(domain)
|
|
11892
11910
|
);
|
|
11893
11911
|
server.prompt(
|
|
11894
11912
|
"name-check",
|
|
11895
11913
|
"Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
|
|
11896
|
-
{ names:
|
|
11914
|
+
{ names: z35.string().describe("Comma-separated list of names to check (e.g. 'user_id, workspace_id, entry_status')") },
|
|
11897
11915
|
async ({ names }) => buildNameCheckPrompt(names)
|
|
11898
11916
|
);
|
|
11899
11917
|
server.prompt(
|
|
11900
11918
|
"draft-decision-record",
|
|
11901
11919
|
"Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
|
|
11902
|
-
{ context:
|
|
11920
|
+
{ context: z35.string().describe("Description of the decision (e.g. 'We decided to keep one body field per entry because...')") },
|
|
11903
11921
|
async ({ context }) => buildDraftDecisionRecordPrompt(context)
|
|
11904
11922
|
);
|
|
11905
11923
|
server.prompt(
|
|
11906
11924
|
"draft-rule-from-context",
|
|
11907
11925
|
"Draft a new business rule from an observation or discovery made while coding. Fetches existing rules for the domain to ensure consistency.",
|
|
11908
11926
|
{
|
|
11909
|
-
observation:
|
|
11910
|
-
domain:
|
|
11927
|
+
observation: z35.string().describe("What you observed or discovered (e.g. 'A workspace can have more than one owner role')"),
|
|
11928
|
+
domain: z35.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
|
|
11911
11929
|
},
|
|
11912
11930
|
async ({ observation, domain }) => buildDraftRuleFromContextPrompt(observation, domain)
|
|
11913
11931
|
);
|
|
@@ -12003,7 +12021,7 @@ var INSTRUCTIONS = [
|
|
|
12003
12021
|
"Finish with `session action=wrapup-review`, then `session action=close`.",
|
|
12004
12022
|
"If the work falls outside the active work packages, name the gap and ask the user before designing it."
|
|
12005
12023
|
].join("\n");
|
|
12006
|
-
var sessionIdArg =
|
|
12024
|
+
var sessionIdArg = z36.string().max(200).optional().describe(
|
|
12007
12025
|
"The sessionId `session action=start` returned. Pass it on every write: the connection does not remember your session between calls."
|
|
12008
12026
|
);
|
|
12009
12027
|
function acceptSessionIdOnEveryTool(server) {
|
|
@@ -12072,4 +12090,4 @@ export {
|
|
|
12072
12090
|
SERVER_VERSION,
|
|
12073
12091
|
createProductBrainServer
|
|
12074
12092
|
};
|
|
12075
|
-
//# sourceMappingURL=chunk-
|
|
12093
|
+
//# sourceMappingURL=chunk-FYYPTIZM.js.map
|