@bendyline/gezel 1.0.6 → 1.1.0

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.
@@ -1,5 +1,5 @@
1
1
  // src/schemas/craftbook.ts
2
- import { z as z5 } from "zod";
2
+ import { z as z6 } from "zod";
3
3
 
4
4
  // src/roles/tier.ts
5
5
  var MODEL_TIER_ORDER = [
@@ -34,7 +34,9 @@ var NamedScriptCapabilitySchema = z2.enum([
34
34
  "tasks.read",
35
35
  "tasks.write",
36
36
  "memory.read",
37
- "memory.write"
37
+ "memory.write",
38
+ "index.read",
39
+ "index.refresh"
38
40
  ]);
39
41
  var CredentialCapabilitySchema = z2.string().regex(
40
42
  /^credential:[a-zA-Z][\w.:-]*$/,
@@ -601,6 +603,18 @@ var GateCheckSchema = z3.discriminatedUnion("kind", [
601
603
  minRows: z3.number().int().nonnegative().optional(),
602
604
  uniqueBy: z3.string().optional(),
603
605
  format: z3.enum(["json", "csv", "auto"]).optional(),
606
+ /**
607
+ * Accept fields beyond `fields` (default false — an exact field set).
608
+ *
609
+ * Strict is right for a locked-schema data deliverable, where an
610
+ * unexpected key means the writer misunderstood the contract. It is
611
+ * wrong for a REGISTER — a findings list, a drift list — where extra
612
+ * context (a cwe, a title, an id) is a better deliverable, not a
613
+ * broken one, and rejecting it grades schema-guessing instead of the
614
+ * work. The underlying `recordSchema` check has always supported this;
615
+ * only the declarative gate could not say it.
616
+ */
617
+ allowExtraFields: z3.boolean().optional(),
604
618
  artifact: z3.boolean().optional()
605
619
  }),
606
620
  /**
@@ -646,12 +660,43 @@ var GateCheckSchema = z3.discriminatedUnion("kind", [
646
660
  * `sourcePath` is non-empty, an exact successful `read_file` of that path
647
661
  * qualifies; otherwise one of `tools` must have completed against an
648
662
  * external source. The runtime supplies the live tool-call evidence.
663
+ * `externalOptional` softens only the no-sourcePath branch: authored local
664
+ * sources remain mandatory, while a topic-only workflow may recommend web
665
+ * research without becoming impossible under an offline security policy.
649
666
  */
650
667
  z3.object({
651
668
  kind: z3.literal("researchEvidence"),
652
669
  sourcePath: z3.string().optional(),
653
670
  tools: z3.array(z3.string().min(1)).min(1),
654
- minSuccessful: z3.number().int().positive().optional()
671
+ minSuccessful: z3.number().int().positive().optional(),
672
+ externalOptional: z3.boolean().optional()
673
+ }),
674
+ /**
675
+ * Require a real command run during this activation, verified against the
676
+ * service-written run receipts (`workspace.script.run` / `workspace.npx.run`
677
+ * history events — the model cannot forge them, and the gate never
678
+ * executes anything itself). Exactly one of `script` (a package.json
679
+ * script name) or `bin` (an npx binary) names the command; `args` must
680
+ * match the receipt's extra args exactly (default: argless). `expect`
681
+ * judges the LATEST matching run's exit code — `'fail'` is the
682
+ * red-before-green half of a repro-first fix (the failing test must
683
+ * actually fail), `'pass'` is the suite-green proof after it. A timed-out
684
+ * run satisfies neither. On a drafting task the project's commands run
685
+ * against the unmodified tree, so `onDraft: 'defer'` (the default)
686
+ * approves with an explicit "execution deferred until Apply" note instead
687
+ * of demanding a receipt that would be a lie; `'require'` hard-blocks
688
+ * instead. Books standardize on the argless canonical invocation because
689
+ * command approvals pin one invocation hash per script name.
690
+ */
691
+ z3.object({
692
+ kind: z3.literal("commandEvidence"),
693
+ script: z3.string().min(1).optional(),
694
+ bin: z3.string().min(1).optional(),
695
+ args: z3.array(z3.string()).optional(),
696
+ expect: z3.enum(["pass", "fail"]),
697
+ minRuns: z3.number().int().positive().optional(),
698
+ onDraft: z3.enum(["defer", "require"]).optional(),
699
+ label: z3.string().min(1).optional()
655
700
  }),
656
701
  /**
657
702
  * A PR-review coverage ledger must name every changed path materialized in
@@ -943,16 +988,39 @@ var HookResultSchema = z4.object({
943
988
  message: z4.string().optional()
944
989
  });
945
990
 
991
+ // src/schemas/retrieval.ts
992
+ import { z as z5 } from "zod";
993
+ var RETRIEVAL_MODES = ["off", "lean", "balanced", "deep"];
994
+ var RetrievalModeSchema = z5.enum(RETRIEVAL_MODES);
995
+ var RETRIEVAL_SOURCES = [
996
+ "workspace",
997
+ "artifacts",
998
+ "project-memory",
999
+ "gezel-memory",
1000
+ "shared",
1001
+ // Installed knowledge catalogs (read-only reference corpora — .gezk).
1002
+ // Scoped by the user's registry + the project's knowledgeCatalogs policy.
1003
+ "knowledge"
1004
+ ];
1005
+ var RetrievalSourceSchema = z5.enum(RETRIEVAL_SOURCES);
1006
+ var RetrievalPolicySchema = z5.object({
1007
+ mode: RetrievalModeSchema,
1008
+ /** Hard prompt budget after the mode preset and context-window clamp. */
1009
+ maxTokens: z5.number().int().min(0).max(16e3).optional(),
1010
+ /** Absent means every corpus appropriate to the current session. */
1011
+ sources: z5.array(RetrievalSourceSchema).min(1).optional()
1012
+ });
1013
+
946
1014
  // src/schemas/craftbook.ts
947
- var CraftbookBranchSchema = z5.object({
1015
+ var CraftbookBranchSchema = z6.object({
948
1016
  when: ScriptOutputPredicateSchema,
949
- goto: z5.string()
1017
+ goto: z6.string()
950
1018
  });
951
- var AdvanceWhenSchema = z5.object({
1019
+ var AdvanceWhenSchema = z6.object({
952
1020
  /** Workspace-relative deliverable whose presence signals "this step is done". */
953
- file: z5.string().min(1),
1021
+ file: z6.string().min(1),
954
1022
  /** Liveness floor in bytes (guards against an empty/stub file). Default 1. */
955
- minBytes: z5.number().int().positive().optional(),
1023
+ minBytes: z6.number().int().positive().optional(),
956
1024
  /**
957
1025
  * Named content check the runtime runs before advancing. `html-complete`
958
1026
  * = a non-truncated HTML doc (balanced `<script>` tags + a closing
@@ -973,7 +1041,7 @@ var AdvanceWhenSchema = z5.object({
973
1041
  * `insert_at_marker` targeting `file` this turn). The `sniff`/`minBytes`
974
1042
  * floor still applies on top. Absent → legacy "exists is enough".
975
1043
  */
976
- requireChange: z5.boolean().optional(),
1044
+ requireChange: z6.boolean().optional(),
977
1045
  /**
978
1046
  * Resolve `file` against the project's ARTIFACTS drawer
979
1047
  * (`read_artifact` / `write_artifact`) instead of the shipped workspace.
@@ -983,28 +1051,87 @@ var AdvanceWhenSchema = z5.object({
983
1051
  * deliverable is gated for size/shape exactly like a workspace one.
984
1052
  * Absent → workspace (the default).
985
1053
  */
986
- artifact: z5.boolean().optional(),
1054
+ artifact: z6.boolean().optional(),
987
1055
  /** Step to activate on the signal. Defaults to `next`; must resolve like `next`. */
988
- goto: z5.string().optional()
1056
+ goto: z6.string().optional()
989
1057
  });
990
- var CraftbookStepInputSchema = z5.object({
1058
+ var CraftbookStepInputSchema = z6.object({
991
1059
  /** Path relative to the selected drawer's root. */
992
- file: z5.string().min(1).describe("Path relative to the selected drawer root."),
1060
+ file: z6.string().min(1).describe("Path relative to the selected drawer root."),
993
1061
  /** Read from the artifacts drawer instead of the project workspace. */
994
- artifact: z5.boolean().optional().describe("True for the artifacts drawer; false/omitted for the project workspace.")
1062
+ artifact: z6.boolean().optional().describe("True for the artifacts drawer; false/omitted for the project workspace.")
995
1063
  });
996
- var ModelTierSchema = z5.enum(MODEL_TIER_ORDER);
997
- var CraftbookStepSchema = z5.object({
998
- id: z5.string().min(1),
999
- name: z5.string().min(1),
1000
- description: z5.string().optional(),
1064
+ var CraftbookStepWritableOutputMediumSchema = z6.enum([
1065
+ "workspace",
1066
+ "artifact",
1067
+ "task-note"
1068
+ ]);
1069
+ var CraftbookStepOutputMediumSchema = z6.enum([
1070
+ ...CraftbookStepWritableOutputMediumSchema.options,
1071
+ "none"
1072
+ ]);
1073
+ var CraftbookStepToolPolicySchema = z6.object({
1074
+ disallowToolsets: z6.array(z6.string().trim().min(1)).min(1).optional(),
1075
+ disallowBuiltinToolsets: z6.array(z6.string().trim().min(1)).min(1).optional(),
1076
+ outputMedium: CraftbookStepOutputMediumSchema.optional(),
1077
+ /**
1078
+ * Other intentional write surfaces used while producing the primary
1079
+ * result (for example edit workspace source + emit an artifact report).
1080
+ * `none` is never a secondary medium.
1081
+ */
1082
+ additionalOutputMedia: z6.array(CraftbookStepWritableOutputMediumSchema).min(1).optional()
1083
+ }).strict().superRefine((policy, ctx) => {
1084
+ const additional = new Set(policy.additionalOutputMedia ?? []);
1085
+ if (policy.outputMedium === "none" && additional.size > 0) {
1086
+ ctx.addIssue({
1087
+ code: z6.ZodIssueCode.custom,
1088
+ path: ["additionalOutputMedia"],
1089
+ message: "`none` cannot have secondary output media"
1090
+ });
1091
+ }
1092
+ if (policy.outputMedium && policy.outputMedium !== "none" && additional.has(policy.outputMedium)) {
1093
+ ctx.addIssue({
1094
+ code: z6.ZodIssueCode.custom,
1095
+ path: ["additionalOutputMedia"],
1096
+ message: "the primary output medium must not be repeated as a secondary medium"
1097
+ });
1098
+ }
1099
+ const media = /* @__PURE__ */ new Set([policy.outputMedium, ...additional]);
1100
+ const denied = new Set(policy.disallowBuiltinToolsets ?? []);
1101
+ if (media.has("workspace") && denied.has("workspace-fs-write")) {
1102
+ ctx.addIssue({
1103
+ code: z6.ZodIssueCode.custom,
1104
+ path: ["disallowBuiltinToolsets"],
1105
+ message: "workspace output conflicts with disallowing `workspace-fs-write`"
1106
+ });
1107
+ }
1108
+ if (media.has("artifact") && denied.has("artifacts")) {
1109
+ ctx.addIssue({
1110
+ code: z6.ZodIssueCode.custom,
1111
+ path: ["disallowBuiltinToolsets"],
1112
+ message: "artifact output conflicts with disallowing `artifacts`"
1113
+ });
1114
+ }
1115
+ if (media.has("task-note") && denied.has("tasks")) {
1116
+ ctx.addIssue({
1117
+ code: z6.ZodIssueCode.custom,
1118
+ path: ["disallowBuiltinToolsets"],
1119
+ message: "task-note output conflicts with disallowing `tasks`"
1120
+ });
1121
+ }
1122
+ });
1123
+ var ModelTierSchema = z6.enum(MODEL_TIER_ORDER);
1124
+ var CraftbookStepSchema = z6.object({
1125
+ id: z6.string().min(1),
1126
+ name: z6.string().min(1),
1127
+ description: z6.string().optional(),
1001
1128
  /**
1002
1129
  * Per-step prompt body. In bundled/local catalog form, this is loaded
1003
1130
  * from the per-step `prompt.md` file (when the version manifest carries
1004
1131
  * a separate file) and inlined at resolution time.
1005
1132
  */
1006
- prompt: z5.string().optional(),
1007
- suggestedGezelId: z5.string().optional(),
1133
+ prompt: z6.string().optional(),
1134
+ suggestedGezelId: z6.string().optional(),
1008
1135
  /**
1009
1136
  * Free-form role hint ("reviewer", "developer", "designer"). When set
1010
1137
  * and `suggestedGezelId` / `assignee` are both absent at step
@@ -1015,7 +1142,7 @@ var CraftbookStepSchema = z5.object({
1015
1142
  * specific gezel id. Override by setting `assignee` or
1016
1143
  * `suggestedGezelId` at task create time.
1017
1144
  */
1018
- suggestedRole: z5.string().optional(),
1145
+ suggestedRole: z6.string().optional(),
1019
1146
  /**
1020
1147
  * Minimum model tier to run this step unsupervised. Overrides the
1021
1148
  * `suggestedRole`'s registry floor (roles/registry.ts) when set;
@@ -1024,26 +1151,32 @@ var CraftbookStepSchema = z5.object({
1024
1151
  * that clears the floor runs the step.
1025
1152
  */
1026
1153
  capabilityFloor: ModelTierSchema.optional(),
1154
+ /** Per-phase indexed-context policy; overrides gezel and install defaults. */
1155
+ retrieval: RetrievalPolicySchema.optional(),
1156
+ /** Per-step subtractive tool and output-surface policy. */
1157
+ toolPolicy: CraftbookStepToolPolicySchema.optional(),
1027
1158
  assignee: TaskAssigneeSchema.optional(),
1028
1159
  /** Setup scripts, run in order when the step activates. Single ref = legacy shape. */
1029
1160
  onEnter: ScriptRefListSchema.optional(),
1030
1161
  /**
1031
1162
  * Cleanup scripts — the `finally` of the step. Run in order AFTER the
1032
- * gate (if any) approves; never on a gate reject. Branch predicates
1033
- * read the LAST ref's output (legacy routing; prefer gate routing).
1163
+ * gate (if any) approves; never on a gate reject. Every script must
1164
+ * succeed or the step remains incomplete and the task pauses. Branch
1165
+ * predicates read the LAST ref's output (legacy routing; prefer gate
1166
+ * routing).
1034
1167
  */
1035
1168
  onExit: ScriptRefListSchema.optional(),
1036
1169
  /** Required file inputs for this step, in the order they should be opened. */
1037
- consumes: z5.array(CraftbookStepInputSchema).min(1).optional().describe(
1170
+ consumes: z6.array(CraftbookStepInputSchema).min(1).optional().describe(
1038
1171
  "Files this step must open before working. Artifact inputs also require an explicit `read_artifact` call in the step prompt."
1039
1172
  ),
1040
1173
  /** See {@link AdvanceWhenSchema}. */
1041
1174
  advanceWhen: AdvanceWhenSchema.optional(),
1042
1175
  /** The end-of-step decision. See {@link StepGateSchema} (current) / {@link GateSpecSchema} (legacy). */
1043
1176
  gate: StepGateUnionSchema.optional(),
1044
- next: z5.string().optional(),
1045
- branches: z5.array(CraftbookBranchSchema).optional(),
1046
- terminal: z5.boolean().optional(),
1177
+ next: z6.string().optional(),
1178
+ branches: z6.array(CraftbookBranchSchema).optional(),
1179
+ terminal: z6.boolean().optional(),
1047
1180
  /**
1048
1181
  * Marks the parent step that triggers a declarative per-item fanout
1049
1182
  * (see {@link CraftbookSpawnSchema}). When this step activates on a
@@ -1051,19 +1184,19 @@ var CraftbookStepSchema = z5.object({
1051
1184
  * JSON array on its declared surface and spawns one child task per item — no model
1052
1185
  * tool call. Inert unless the craftbook also declares `spawn`.
1053
1186
  */
1054
- spawnFanout: z5.boolean().optional()
1187
+ spawnFanout: z6.boolean().optional()
1055
1188
  });
1056
- var CraftbookSpawnSchema = z5.object({
1189
+ var CraftbookSpawnSchema = z6.object({
1057
1190
  /** Surface-relative JSON file the parent produces; its array drives the fanout. */
1058
- overFile: z5.string().min(1),
1191
+ overFile: z6.string().min(1),
1059
1192
  /** Read overFile from the artifacts drawer instead of the project workspace. */
1060
- overArtifact: z5.boolean().optional(),
1193
+ overArtifact: z6.boolean().optional(),
1061
1194
  /** Dotted path to the array inside `overFile`. Absent → the file itself is the array. */
1062
- itemsPath: z5.string().optional(),
1195
+ itemsPath: z6.string().optional(),
1063
1196
  /** Entry step id of the child template. Defaults to the first `steps` entry. */
1064
- entryStepId: z5.string().optional(),
1197
+ entryStepId: z6.string().optional(),
1065
1198
  /** The per-child step template — same shape as a craftbook's own steps. */
1066
- steps: z5.array(CraftbookStepSchema).min(1)
1199
+ steps: z6.array(CraftbookStepSchema).min(1)
1067
1200
  });
1068
1201
  function validateCraftbookGraph(cb) {
1069
1202
  const problems = [];
@@ -1118,70 +1251,88 @@ function validateCraftbookGraph(cb) {
1118
1251
  function refineCraftbook(cb, ctx) {
1119
1252
  for (const message of validateCraftbookGraph(cb)) {
1120
1253
  ctx.addIssue({
1121
- code: z5.ZodIssueCode.custom,
1254
+ code: z6.ZodIssueCode.custom,
1122
1255
  message,
1123
1256
  path: message.startsWith("entryStepId") ? ["entryStepId"] : ["steps"]
1124
1257
  });
1125
1258
  }
1126
1259
  for (const message of validateCraftbookScriptRefs(cb)) {
1127
- ctx.addIssue({ code: z5.ZodIssueCode.custom, message, path: ["steps"] });
1260
+ ctx.addIssue({ code: z6.ZodIssueCode.custom, message, path: ["steps"] });
1128
1261
  }
1129
1262
  }
1130
- var CraftbookRequirementSchema = z5.discriminatedUnion("kind", [
1263
+ var CraftbookRequirementSchema = z6.discriminatedUnion("kind", [
1131
1264
  /** The project is connected to a GitHub repository. */
1132
- z5.object({ kind: z5.literal("github") }),
1265
+ z6.object({ kind: z6.literal("github") }),
1133
1266
  /** The project's current git branch is not the main line (main/master). */
1134
- z5.object({ kind: z5.literal("non-main-branch") })
1267
+ z6.object({ kind: z6.literal("non-main-branch") })
1135
1268
  ]);
1136
- var CraftbookRunModesSchema = z5.object({
1137
- scheduled: z5.enum(["supported", "recommended"]).optional(),
1138
- nightShift: z5.enum(["supported", "recommended"]).optional()
1269
+ var CraftbookRecommendationSchema = z6.discriminatedUnion("kind", [
1270
+ /**
1271
+ * Works better with the install-wide External services capability
1272
+ * (`securityPolicy.allowExternalServices`) — web search, URL fetch.
1273
+ */
1274
+ z6.object({
1275
+ kind: z6.literal("external-services"),
1276
+ /** Human-readable rationale shown in the nudge ("verifies sources with live web search"). */
1277
+ reason: z6.string().optional()
1278
+ })
1279
+ ]);
1280
+ var CraftbookRunModesSchema = z6.object({
1281
+ scheduled: z6.enum(["supported", "recommended"]).optional(),
1282
+ nightShift: z6.enum(["supported", "recommended"]).optional()
1139
1283
  });
1140
- var CraftbookToolsetNeedSchema = z5.object({
1284
+ var CraftbookToolsetNeedSchema = z6.object({
1141
1285
  /** Catalog toolset id, e.g. `github`, `usb-camera`. */
1142
- toolsetId: z5.string().min(1),
1286
+ toolsetId: z6.string().min(1),
1143
1287
  /** Catalog source provenance (bundled/community), when pinned. */
1144
- sourceId: z5.string().optional(),
1288
+ sourceId: z6.string().optional(),
1145
1289
  /** Optional semver floor; presence is recorded but not yet enforced. */
1146
- minVersion: z5.string().optional(),
1290
+ minVersion: z6.string().optional(),
1147
1291
  /**
1148
1292
  * When true, the need is a suggestion only — surfaced as a hint, never
1149
1293
  * blocks invocation. Default (absent/false) = required: the launcher
1150
1294
  * offers install before the craftbook can run.
1151
1295
  */
1152
- optional: z5.boolean().optional(),
1296
+ optional: z6.boolean().optional(),
1153
1297
  /**
1154
1298
  * When true, pre-authorize every tool this toolset exposes for the
1155
1299
  * duration the craftbook is active — both via a synthesized PreToolUse
1156
1300
  * allow-hook (in-process providers) and the Claude-CLI permission
1157
1301
  * broker. Off by default; opt in for unattended/scheduled craftbooks.
1158
1302
  */
1159
- autoAllow: z5.boolean().optional(),
1303
+ autoAllow: z6.boolean().optional(),
1160
1304
  /** Human-readable rationale shown in the launcher ("pull camera frames"). */
1161
- reason: z5.string().optional()
1305
+ reason: z6.string().optional()
1306
+ });
1307
+ var CraftbookCommandNeedSchema = z6.object({
1308
+ scope: z6.enum(["script", "npx"]),
1309
+ name: z6.string().min(1),
1310
+ args: z6.array(z6.string()).optional(),
1311
+ reason: z6.string().optional(),
1312
+ optional: z6.boolean().optional()
1162
1313
  });
1163
- var CraftbookConnectorNeedSchema = z5.object({
1314
+ var CraftbookConnectorNeedSchema = z6.object({
1164
1315
  /** Catalog connector-type id, e.g. `github-pulls`, `mail-gmail`. */
1165
- typeId: z5.string().min(1),
1316
+ typeId: z6.string().min(1),
1166
1317
  /** Catalog source provenance (bundled/community), when pinned. */
1167
- sourceId: z5.string().optional(),
1318
+ sourceId: z6.string().optional(),
1168
1319
  /**
1169
1320
  * When true, the craftbook still runs without the connector bound —
1170
1321
  * the corpus is a bonus, not the substrate. Default (absent/false) =
1171
1322
  * required: the launcher offers to bind it before the craftbook runs.
1172
1323
  */
1173
- optional: z5.boolean().optional(),
1324
+ optional: z6.boolean().optional(),
1174
1325
  /** Human-readable rationale shown in the launcher ("pull the PR diff"). */
1175
- reason: z5.string().optional()
1326
+ reason: z6.string().optional()
1176
1327
  });
1177
1328
  var CRAFTBOOK_SCRIPT_MAX_BYTES = 64 * 1024;
1178
1329
  var CRAFTBOOK_SCRIPTS_TOTAL_MAX_BYTES = 256 * 1024;
1179
1330
  var CRAFTBOOK_SCRIPTS_MAX_COUNT = 24;
1180
- var CraftbookScriptsSchema = z5.record(ScriptNameSchema, z5.string().min(1).max(CRAFTBOOK_SCRIPT_MAX_BYTES)).superRefine((scripts, ctx) => {
1331
+ var CraftbookScriptsSchema = z6.record(ScriptNameSchema, z6.string().min(1).max(CRAFTBOOK_SCRIPT_MAX_BYTES)).superRefine((scripts, ctx) => {
1181
1332
  const names = Object.keys(scripts);
1182
1333
  if (names.length > CRAFTBOOK_SCRIPTS_MAX_COUNT) {
1183
1334
  ctx.addIssue({
1184
- code: z5.ZodIssueCode.custom,
1335
+ code: z6.ZodIssueCode.custom,
1185
1336
  message: `a craftbook carries at most ${CRAFTBOOK_SCRIPTS_MAX_COUNT} scripts (got ${names.length})`
1186
1337
  });
1187
1338
  }
@@ -1189,14 +1340,14 @@ var CraftbookScriptsSchema = z5.record(ScriptNameSchema, z5.string().min(1).max(
1189
1340
  for (const name of names) total += scripts[name].length;
1190
1341
  if (total > CRAFTBOOK_SCRIPTS_TOTAL_MAX_BYTES) {
1191
1342
  ctx.addIssue({
1192
- code: z5.ZodIssueCode.custom,
1343
+ code: z6.ZodIssueCode.custom,
1193
1344
  message: `craftbook scripts total ${total} bytes \u2014 the ceiling is ${CRAFTBOOK_SCRIPTS_TOTAL_MAX_BYTES}`
1194
1345
  });
1195
1346
  }
1196
1347
  });
1197
- var CraftbookBasedOnSchema = z5.object({
1198
- name: z5.string().min(1),
1199
- url: z5.string().url().regex(/^https?:\/\//i, "basedOn.url must use http or https")
1348
+ var CraftbookBasedOnSchema = z6.object({
1349
+ name: z6.string().min(1),
1350
+ url: z6.string().url().regex(/^https?:\/\//i, "basedOn.url must use http or https")
1200
1351
  });
1201
1352
  function validateCraftbookScriptRefs(cb) {
1202
1353
  if (!cb.scripts) return [];
@@ -1218,32 +1369,32 @@ function validateCraftbookScriptRefs(cb) {
1218
1369
  }
1219
1370
  return problems;
1220
1371
  }
1221
- var CraftbookSchema = z5.object({
1372
+ var CraftbookSchema = z6.object({
1222
1373
  /** Matches catalog folder name. For ad-hoc embedded craftbooks (inline-steps tasks), a generated id. */
1223
- id: z5.string().min(1),
1224
- name: z5.string().min(1),
1225
- description: z5.string().optional(),
1374
+ id: z6.string().min(1),
1375
+ name: z6.string().min(1),
1376
+ description: z6.string().optional(),
1226
1377
  /** Semver from the catalog version this craftbook was resolved from. Unset for ad-hoc embedded books. */
1227
- version: z5.string().optional(),
1378
+ version: z6.string().optional(),
1228
1379
  /** Optional credit + link to the upstream work this craftbook adapts. */
1229
1380
  basedOn: CraftbookBasedOnSchema.optional(),
1230
- plan: z5.string().optional(),
1381
+ plan: z6.string().optional(),
1231
1382
  defaultAssignee: TaskAssigneeSchema.optional(),
1232
- steps: z5.array(CraftbookStepSchema).min(1),
1233
- entryStepId: z5.string().min(1),
1383
+ steps: z6.array(CraftbookStepSchema).min(1),
1384
+ entryStepId: z6.string().min(1),
1234
1385
  /**
1235
1386
  * User-speech phrases that route to this craftbook. Matched
1236
1387
  * case-insensitively as substrings against the user's chat input
1237
1388
  * (or against a slash-command argument). Optional; absent =
1238
1389
  * invocable only via explicit `invoke_craftbook` / Commands panel.
1239
1390
  */
1240
- triggers: z5.array(z5.string()).optional(),
1391
+ triggers: z6.array(z6.string()).optional(),
1241
1392
  /**
1242
1393
  * Pre/PostToolUse hooks installed for the duration the craftbook
1243
1394
  * is active. The MCP bridge consults this list before forwarding
1244
1395
  * a `tools/call`. See `hook.ts` for the decision contract.
1245
1396
  */
1246
- hooks: z5.array(HookSpecSchema).optional(),
1397
+ hooks: z6.array(HookSpecSchema).optional(),
1247
1398
  /**
1248
1399
  * Optional squisq/JSON-Schema object describing the parameters this
1249
1400
  * craftbook collects before it runs. Its top-level `properties` are
@@ -1254,19 +1405,26 @@ var CraftbookSchema = z5.object({
1254
1405
  * structurally; typed as squisq's `SquisqAnnotatedSchema` at the UI
1255
1406
  * boundary. Absent = parameterless (the command is injected directly).
1256
1407
  */
1257
- paramSchema: z5.record(z5.string(), z5.unknown()).optional(),
1408
+ paramSchema: z6.record(z6.string(), z6.unknown()).optional(),
1258
1409
  /**
1259
1410
  * CLI token the launcher stages into the terminal and that the
1260
1411
  * terminal recognizes. Defaults to `id` when absent — e.g. the
1261
1412
  * "Code Review" craftbook (id `review`) sets `command: "code-review"`.
1262
1413
  */
1263
- command: z5.string().regex(/^[a-z][a-z0-9-]*$/).optional(),
1414
+ command: z6.string().regex(/^[a-z][a-z0-9-]*$/).optional(),
1264
1415
  /**
1265
1416
  * Prerequisites a project must satisfy for this craftbook to be
1266
1417
  * applicable. When unmet, the craftbook is hidden from the launcher
1267
1418
  * and not recognized as a terminal command. Absent = always offered.
1268
1419
  */
1269
- requirements: z5.array(CraftbookRequirementSchema).optional(),
1420
+ requirements: z6.array(CraftbookRequirementSchema).optional(),
1421
+ /**
1422
+ * Soft "works better with" hints — never gate, only inform UI copy
1423
+ * (the craftbook start card's permission nudge). See
1424
+ * {@link CraftbookRecommendationSchema}. Carried into the runtime
1425
+ * craftbook and the task snapshot, unlike `requirements`.
1426
+ */
1427
+ recommends: z6.array(CraftbookRecommendationSchema).optional(),
1270
1428
  /** Unattended launch modes this recipe is suitable for. */
1271
1429
  runModes: CraftbookRunModesSchema.optional(),
1272
1430
  /**
@@ -1277,7 +1435,14 @@ var CraftbookSchema = z5.object({
1277
1435
  * `requirements`, this is carried into the runtime craftbook and the task
1278
1436
  * snapshot. Absent = no declared toolset dependencies.
1279
1437
  */
1280
- toolsets: z5.array(CraftbookToolsetNeedSchema).optional(),
1438
+ toolsets: z6.array(CraftbookToolsetNeedSchema).optional(),
1439
+ /**
1440
+ * Project commands this craftbook's `commandEvidence` gates verify runs
1441
+ * of. See {@link CraftbookCommandNeedSchema}. Carried into the runtime
1442
+ * craftbook and the task snapshot so the kickoff path can raise the
1443
+ * first-use approval questions up front.
1444
+ */
1445
+ commands: z6.array(CraftbookCommandNeedSchema).optional(),
1281
1446
  /**
1282
1447
  * Connectors whose mirrored `artifacts/data/` corpus this craftbook reads. The
1283
1448
  * launcher binds and syncs them before the first step runs. See
@@ -1285,7 +1450,7 @@ var CraftbookSchema = z5.object({
1285
1450
  * craftbook and the task snapshot so a running task records what it
1286
1451
  * was launched against. Absent = no connector dependencies.
1287
1452
  */
1288
- connectors: z5.array(CraftbookConnectorNeedSchema).optional(),
1453
+ connectors: z6.array(CraftbookConnectorNeedSchema).optional(),
1289
1454
  /**
1290
1455
  * Embedded script sources (name → TypeScript). See
1291
1456
  * {@link CraftbookScriptsSchema}. Hydrated at resolution time for
@@ -1301,10 +1466,30 @@ var CraftbookSchema = z5.object({
1301
1466
  * task snapshot so the runtime reads it at fanout time.
1302
1467
  */
1303
1468
  spawn: CraftbookSpawnSchema.optional(),
1304
- createdAt: z5.string(),
1305
- updatedAt: z5.string()
1469
+ /**
1470
+ * This craftbook is authored mode-agnostic: it works identically whether
1471
+ * a run edits the workspace in place or drafts a diffpack change
1472
+ * proposal. Concretely, its workspace deliverables and gates evaluate
1473
+ * through the draft overlay, and it carries no mode-specific prose and
1474
+ * no `{{diffpack.*}}` tokens — the runtime injects drafting framing and
1475
+ * re-roots the write tools. Declaring it lets an invocation opt the run
1476
+ * into proposing (`deliveryMode: 'propose'`, or automatically for
1477
+ * unattended runs); the mode is a property of the RUN, never of the
1478
+ * book. Resolution rule in `TaskManager.create`.
1479
+ */
1480
+ diffpackCapable: z6.boolean().optional(),
1481
+ /**
1482
+ * Minimum model tier for the WHOLE book: every step floors at least
1483
+ * here (per-step `capabilityFloor` still overrides absolutely, and a
1484
+ * stricter role floor still wins — see `effectiveCapabilityFloor` in
1485
+ * roles/registry.ts). The honest "this recipe needs a medium model"
1486
+ * declaration, consumed by per-step routing at dispatch.
1487
+ */
1488
+ capabilityFloor: ModelTierSchema.optional(),
1489
+ createdAt: z6.string(),
1490
+ updatedAt: z6.string()
1306
1491
  }).superRefine(refineCraftbook);
1307
- var DeliverableKindSchema = z5.enum([
1492
+ var DeliverableKindSchema = z6.enum([
1308
1493
  "html-game",
1309
1494
  "html-multiscreen-game",
1310
1495
  "html-page",
@@ -1323,97 +1508,103 @@ var DeliverableKindSchema = z5.enum([
1323
1508
  "data-file",
1324
1509
  "generic-file"
1325
1510
  ]);
1326
- var StepDeliverableSchema = z5.object({
1511
+ var StepDeliverableSchema = z6.object({
1327
1512
  /** Workspace-relative file the step must produce. The only required field. */
1328
- path: z5.string().min(1),
1513
+ path: z6.string().min(1),
1329
1514
  /** Artifact class; inferred from the file extension when absent. */
1330
1515
  kind: DeliverableKindSchema.optional(),
1331
1516
  /** Override the class-default byte floor. */
1332
- minBytes: z5.number().int().positive().optional(),
1517
+ minBytes: z6.number().int().positive().optional(),
1333
1518
  /** Gate rejections before the task pauses for help. */
1334
- maxAttempts: z5.number().int().positive().optional(),
1519
+ maxAttempts: z6.number().int().positive().optional(),
1335
1520
  /** Gate the artifacts drawer instead of the workspace. */
1336
- artifact: z5.boolean().optional(),
1521
+ artifact: z6.boolean().optional(),
1337
1522
  /**
1338
1523
  * The deliverable is an EDIT to a pre-existing file (fix/refactor):
1339
1524
  * presence alone never advances the step — the assignee must have
1340
1525
  * written to the file this turn. See {@link AdvanceWhenSchema}.
1341
1526
  */
1342
- requireChange: z5.boolean().optional(),
1527
+ requireChange: z6.boolean().optional(),
1343
1528
  /**
1344
1529
  * For code deliverables: additionally execute the file in the sandbox
1345
1530
  * and require exit 0 (a `node:test`/`assert` file exits nonzero on
1346
1531
  * failure — exactly the contract). Opt-in.
1347
1532
  */
1348
- execute: z5.boolean().optional(),
1533
+ execute: z6.boolean().optional(),
1349
1534
  /** For data deliverables: required column names (adds a tableShape check). */
1350
- columns: z5.array(z5.string().min(1)).min(1).optional(),
1535
+ columns: z6.array(z6.string().min(1)).min(1).optional(),
1351
1536
  /** For data deliverables: minimum row count (adds a tableShape check). */
1352
- minRows: z5.number().int().positive().optional()
1353
- });
1354
- var NewCraftbookStepSchema = z5.object({
1355
- id: z5.string().optional(),
1356
- name: z5.string().min(1),
1357
- description: z5.string().optional(),
1358
- prompt: z5.string().optional(),
1359
- suggestedGezelId: z5.string().optional(),
1537
+ minRows: z6.number().int().positive().optional()
1538
+ });
1539
+ var NewCraftbookStepSchema = z6.object({
1540
+ id: z6.string().optional(),
1541
+ name: z6.string().min(1),
1542
+ description: z6.string().optional(),
1543
+ prompt: z6.string().optional(),
1544
+ suggestedGezelId: z6.string().optional(),
1360
1545
  /** See {@link CraftbookStepSchema.shape.suggestedRole}. */
1361
- suggestedRole: z5.string().optional(),
1546
+ suggestedRole: z6.string().optional(),
1362
1547
  /** See {@link CraftbookStepSchema.shape.capabilityFloor}. */
1363
1548
  capabilityFloor: ModelTierSchema.optional(),
1549
+ /** See {@link CraftbookStepSchema.shape.retrieval}. */
1550
+ retrieval: RetrievalPolicySchema.optional(),
1551
+ /** See {@link CraftbookStepSchema.shape.toolPolicy}. */
1552
+ toolPolicy: CraftbookStepToolPolicySchema.optional(),
1364
1553
  assignee: TaskAssigneeSchema.optional(),
1365
1554
  onEnter: ScriptRefListSchema.optional(),
1366
1555
  onExit: ScriptRefListSchema.optional(),
1367
- consumes: z5.array(CraftbookStepInputSchema).min(1).optional().describe(
1556
+ consumes: z6.array(CraftbookStepInputSchema).min(1).optional().describe(
1368
1557
  "Files this step must open before working. Artifact inputs also require an explicit `read_artifact` call in the step prompt."
1369
1558
  ),
1370
1559
  advanceWhen: AdvanceWhenSchema.optional(),
1371
1560
  gate: StepGateUnionSchema.optional(),
1372
1561
  /** See {@link StepDeliverableSchema} — one field attaches the enforced gate. */
1373
1562
  deliverable: StepDeliverableSchema.optional(),
1374
- next: z5.string().optional(),
1375
- branches: z5.array(CraftbookBranchSchema).optional(),
1376
- terminal: z5.boolean().optional(),
1563
+ next: z6.string().optional(),
1564
+ branches: z6.array(CraftbookBranchSchema).optional(),
1565
+ terminal: z6.boolean().optional(),
1377
1566
  /** See {@link CraftbookStepSchema.shape.spawnFanout}. */
1378
- spawnFanout: z5.boolean().optional()
1567
+ spawnFanout: z6.boolean().optional()
1379
1568
  });
1380
- var CreateCraftbookRequestSchema = z5.object({
1381
- id: z5.string().optional(),
1382
- name: z5.string().min(1),
1383
- description: z5.string().optional(),
1569
+ var CreateCraftbookRequestSchema = z6.object({
1570
+ id: z6.string().optional(),
1571
+ name: z6.string().min(1),
1572
+ description: z6.string().optional(),
1384
1573
  basedOn: CraftbookBasedOnSchema.optional(),
1385
- plan: z5.string().optional(),
1574
+ plan: z6.string().optional(),
1386
1575
  defaultAssignee: TaskAssigneeSchema.optional(),
1387
- steps: z5.array(NewCraftbookStepSchema).min(1),
1388
- entryStepId: z5.string().optional(),
1389
- paramSchema: z5.record(z5.string(), z5.unknown()).optional(),
1390
- command: z5.string().regex(/^[a-z][a-z0-9-]*$/).optional(),
1391
- requirements: z5.array(CraftbookRequirementSchema).optional(),
1576
+ steps: z6.array(NewCraftbookStepSchema).min(1),
1577
+ entryStepId: z6.string().optional(),
1578
+ paramSchema: z6.record(z6.string(), z6.unknown()).optional(),
1579
+ command: z6.string().regex(/^[a-z][a-z0-9-]*$/).optional(),
1580
+ requirements: z6.array(CraftbookRequirementSchema).optional(),
1581
+ recommends: z6.array(CraftbookRecommendationSchema).optional(),
1392
1582
  runModes: CraftbookRunModesSchema.optional(),
1393
- toolsets: z5.array(CraftbookToolsetNeedSchema).optional(),
1583
+ toolsets: z6.array(CraftbookToolsetNeedSchema).optional(),
1394
1584
  scripts: CraftbookScriptsSchema.optional()
1395
1585
  });
1396
- var UpdateCraftbookRequestSchema = z5.object({
1397
- name: z5.string().min(1).optional(),
1398
- description: z5.string().nullable().optional(),
1586
+ var UpdateCraftbookRequestSchema = z6.object({
1587
+ name: z6.string().min(1).optional(),
1588
+ description: z6.string().nullable().optional(),
1399
1589
  basedOn: CraftbookBasedOnSchema.nullable().optional(),
1400
- plan: z5.string().nullable().optional(),
1590
+ plan: z6.string().nullable().optional(),
1401
1591
  defaultAssignee: TaskAssigneeSchema.nullable().optional(),
1402
- steps: z5.array(NewCraftbookStepSchema).min(1).optional(),
1403
- entryStepId: z5.string().optional(),
1404
- paramSchema: z5.record(z5.string(), z5.unknown()).nullable().optional(),
1405
- command: z5.string().regex(/^[a-z][a-z0-9-]*$/).nullable().optional(),
1406
- requirements: z5.array(CraftbookRequirementSchema).nullable().optional(),
1592
+ steps: z6.array(NewCraftbookStepSchema).min(1).optional(),
1593
+ entryStepId: z6.string().optional(),
1594
+ paramSchema: z6.record(z6.string(), z6.unknown()).nullable().optional(),
1595
+ command: z6.string().regex(/^[a-z][a-z0-9-]*$/).nullable().optional(),
1596
+ requirements: z6.array(CraftbookRequirementSchema).nullable().optional(),
1597
+ recommends: z6.array(CraftbookRecommendationSchema).nullable().optional(),
1407
1598
  runModes: CraftbookRunModesSchema.nullable().optional(),
1408
- toolsets: z5.array(CraftbookToolsetNeedSchema).nullable().optional(),
1599
+ toolsets: z6.array(CraftbookToolsetNeedSchema).nullable().optional(),
1409
1600
  /** Full-replace semantics: the map is the truth. `null` clears all scripts. */
1410
1601
  scripts: CraftbookScriptsSchema.nullable().optional()
1411
1602
  });
1412
- var CraftbookSummarySchema = z5.object({
1413
- id: z5.string(),
1414
- name: z5.string(),
1415
- description: z5.string().optional(),
1416
- version: z5.string().optional(),
1603
+ var CraftbookSummarySchema = z6.object({
1604
+ id: z6.string(),
1605
+ name: z6.string(),
1606
+ description: z6.string().optional(),
1607
+ version: z6.string().optional(),
1417
1608
  basedOn: CraftbookBasedOnSchema.optional(),
1418
1609
  /**
1419
1610
  * Where the craftbook came from. `bundled` — shipped catalog;
@@ -1422,51 +1613,51 @@ var CraftbookSummarySchema = z5.object({
1422
1613
  * folder (often auto-imported from a `.claude/skills` / `agents/skills`
1423
1614
  * SKILL.md). Project craftbooks only surface inside their own project.
1424
1615
  */
1425
- source: z5.enum(["bundled", "local", "project"]),
1426
- stepCount: z5.number().int().nonnegative()
1616
+ source: z6.enum(["bundled", "local", "project"]),
1617
+ stepCount: z6.number().int().nonnegative()
1427
1618
  });
1428
- var ListCraftbooksResponseSchema = z5.object({
1429
- craftbooks: z5.array(CraftbookSummarySchema)
1619
+ var ListCraftbooksResponseSchema = z6.object({
1620
+ craftbooks: z6.array(CraftbookSummarySchema)
1430
1621
  });
1431
- var ProjectCraftbookProvenanceSchema = z5.object({
1432
- installedBy: z5.literal("project-type"),
1433
- typeId: z5.string(),
1434
- typeVersion: z5.string(),
1435
- bookVersion: z5.string(),
1622
+ var ProjectCraftbookProvenanceSchema = z6.object({
1623
+ installedBy: z6.literal("project-type"),
1624
+ typeId: z6.string(),
1625
+ typeVersion: z6.string(),
1626
+ bookVersion: z6.string(),
1436
1627
  /** sha256 over the installed book's canonical recipe JSON. */
1437
- contentHash: z5.string(),
1438
- installedAt: z5.string()
1439
- });
1440
- var CraftbookSuggestionSchema = z5.object({
1441
- id: z5.string(),
1442
- name: z5.string(),
1443
- description: z5.string().optional(),
1444
- source: z5.enum(["bundled", "local", "project"]),
1445
- version: z5.string().optional(),
1628
+ contentHash: z6.string(),
1629
+ installedAt: z6.string()
1630
+ });
1631
+ var CraftbookSuggestionSchema = z6.object({
1632
+ id: z6.string(),
1633
+ name: z6.string(),
1634
+ description: z6.string().optional(),
1635
+ source: z6.enum(["bundled", "local", "project"]),
1636
+ version: z6.string().optional(),
1446
1637
  basedOn: CraftbookBasedOnSchema.optional(),
1447
- stepCount: z5.number().int().nonnegative(),
1448
- tags: z5.array(z5.string()).optional(),
1449
- triggers: z5.array(z5.string()).optional(),
1450
- score: z5.number(),
1451
- semantic: z5.number().optional(),
1452
- lexical: z5.number()
1638
+ stepCount: z6.number().int().nonnegative(),
1639
+ tags: z6.array(z6.string()).optional(),
1640
+ triggers: z6.array(z6.string()).optional(),
1641
+ score: z6.number(),
1642
+ semantic: z6.number().optional(),
1643
+ lexical: z6.number()
1453
1644
  });
1454
- var SuggestCraftbooksResponseSchema = z5.object({
1455
- suggestions: z5.array(CraftbookSuggestionSchema)
1645
+ var SuggestCraftbooksResponseSchema = z6.object({
1646
+ suggestions: z6.array(CraftbookSuggestionSchema)
1456
1647
  });
1457
- var CraftbookResponseSchema = z5.object({
1648
+ var CraftbookResponseSchema = z6.object({
1458
1649
  craftbook: CraftbookSchema
1459
1650
  });
1460
1651
  function slugifyStepId(input) {
1461
1652
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "step";
1462
1653
  }
1463
- var StepPositionSchema = z5.object({
1654
+ var StepPositionSchema = z6.object({
1464
1655
  /** Insert immediately after the step with this id. */
1465
- after: z5.string().optional(),
1656
+ after: z6.string().optional(),
1466
1657
  /** Insert immediately before the step with this id. */
1467
- before: z5.string().optional(),
1658
+ before: z6.string().optional(),
1468
1659
  /** Absolute insertion index (clamped to [0, length]). */
1469
- index: z5.number().int().nonnegative().optional()
1660
+ index: z6.number().int().nonnegative().optional()
1470
1661
  });
1471
1662
 
1472
1663
  // src/markdown/frontmatter.ts
@@ -1642,11 +1833,21 @@ var FRONTMATTER_KEYS = [
1642
1833
  "plan",
1643
1834
  "defaultAssignee",
1644
1835
  "requirements",
1836
+ "recommends",
1645
1837
  "runModes",
1646
1838
  "toolsets",
1647
1839
  "connectors",
1648
1840
  "paramSchema",
1649
1841
  "hooks",
1842
+ // Whole-book declarations that are NOT step fields. Omitting one here is
1843
+ // worse than dropping it: the parser reports `unknown key "spawn"` and
1844
+ // refuses the save, so a model that correctly authored a fanout book in
1845
+ // the markdown arm is told its document is malformed.
1846
+ "spawn",
1847
+ "commands",
1848
+ "diffpackCapable",
1849
+ "capabilityFloor",
1850
+ "minGezelVersion",
1650
1851
  "version",
1651
1852
  "releasedAt"
1652
1853
  ];
@@ -1656,6 +1857,8 @@ var STEP_FENCE_KEYS = [
1656
1857
  "suggestedGezelId",
1657
1858
  "suggestedRole",
1658
1859
  "capabilityFloor",
1860
+ "retrieval",
1861
+ "toolPolicy",
1659
1862
  "assignee",
1660
1863
  "deliverable",
1661
1864
  "onEnter",
@@ -1665,7 +1868,10 @@ var STEP_FENCE_KEYS = [
1665
1868
  "gate",
1666
1869
  "next",
1667
1870
  "branches",
1668
- "terminal"
1871
+ "terminal",
1872
+ // Marks the step the spawn block fans out from. Without it a book can
1873
+ // declare `spawn` and have no step that triggers it.
1874
+ "spawnFanout"
1669
1875
  ];
1670
1876
  function parseCraftbookMarkdown(text) {
1671
1877
  const errors = [];
@@ -1853,10 +2059,10 @@ function defaultStepIdForName(name) {
1853
2059
  }
1854
2060
 
1855
2061
  // src/schemas/gezel.ts
1856
- import { z as z17 } from "zod";
2062
+ import { z as z19 } from "zod";
1857
2063
 
1858
2064
  // src/poppetje/schema.ts
1859
- import { z as z6 } from "zod";
2065
+ import { z as z7 } from "zod";
1860
2066
 
1861
2067
  // src/poppetje/catalogs.ts
1862
2068
  var BODY_ARCHETYPES = {
@@ -2002,45 +2208,45 @@ function migrateLegacyAccessory(raw) {
2002
2208
  }
2003
2209
  return r;
2004
2210
  }
2005
- var PoppetjeSchema = z6.preprocess(
2211
+ var PoppetjeSchema = z7.preprocess(
2006
2212
  migrateLegacyAccessory,
2007
- z6.object({
2213
+ z7.object({
2008
2214
  /** Stable id; locks the wood-grain noise seed. Pin to the gezel id at creation. */
2009
- key: z6.string().min(1),
2010
- name: z6.string(),
2011
- bodyShape: z6.enum(BODY_SHAPE_KEYS),
2012
- figureScale: z6.enum(FIGURE_SCALE_KEYS),
2215
+ key: z7.string().min(1),
2216
+ name: z7.string(),
2217
+ bodyShape: z7.enum(BODY_SHAPE_KEYS),
2218
+ figureScale: z7.enum(FIGURE_SCALE_KEYS),
2013
2219
  /** Mid-tone of the head. Paired with skin2 for the lateral gradient. */
2014
- skin: z6.string(),
2220
+ skin: z7.string(),
2015
2221
  /** Darker edge tone. */
2016
- skin2: z6.string(),
2017
- hair: z6.string(),
2018
- hairShape: z6.enum(HAIR_SHAPES),
2222
+ skin2: z7.string(),
2223
+ hair: z7.string(),
2224
+ hairShape: z7.enum(HAIR_SHAPES),
2019
2225
  /** Replaces hair when set; 'hood' renders at body level. */
2020
- hat: z6.enum(HAT_OPTIONS).nullable().optional().default(null),
2226
+ hat: z7.enum(HAT_OPTIONS).nullable().optional().default(null),
2021
2227
  /** Body overlay; null for an unadorned shirt. */
2022
- dress: z6.enum(DRESS_OPTIONS).nullable().optional().default(null),
2228
+ dress: z7.enum(DRESS_OPTIONS).nullable().optional().default(null),
2023
2229
  /** Wearable face accessory (glasses, earring, monocle). User-toggleable. */
2024
- accessory: z6.enum(ACCESSORY_OPTIONS).nullable().optional().default(null),
2230
+ accessory: z7.enum(ACCESSORY_OPTIONS).nullable().optional().default(null),
2025
2231
  /** Facial hair (beard, mustache). Physical — reroll-only. */
2026
- facialHair: z6.enum(FACIAL_HAIR_OPTIONS).nullable().optional().default(null),
2232
+ facialHair: z7.enum(FACIAL_HAIR_OPTIONS).nullable().optional().default(null),
2027
2233
  /** Small facial detail (freckles, mole). Physical — reroll-only. */
2028
- mark: z6.enum(MARK_OPTIONS).nullable().optional().default(null),
2029
- expression: z6.enum(EXPRESSION_OPTIONS).optional().default("smile"),
2030
- shirt: z6.string(),
2031
- shirtAccent: z6.string(),
2234
+ mark: z7.enum(MARK_OPTIONS).nullable().optional().default(null),
2235
+ expression: z7.enum(EXPRESSION_OPTIONS).optional().default("smile"),
2236
+ shirt: z7.string(),
2237
+ shirtAccent: z7.string(),
2032
2238
  /**
2033
2239
  * Painted garment pattern over the shirt (buttons, stripes, sash, …).
2034
2240
  * Files written before patterns existed parse as `plain` — the bare
2035
2241
  * shirt those characters always had.
2036
2242
  */
2037
- shirtPattern: z6.enum(SHIRT_PATTERN_OPTIONS).optional().default("plain")
2243
+ shirtPattern: z7.enum(SHIRT_PATTERN_OPTIONS).optional().default("plain")
2038
2244
  })
2039
2245
  );
2040
2246
 
2041
2247
  // src/schemas/claude.ts
2042
- import { z as z7 } from "zod";
2043
- var ClaudePermissionModeSchema = z7.enum([
2248
+ import { z as z8 } from "zod";
2249
+ var ClaudePermissionModeSchema = z8.enum([
2044
2250
  "default",
2045
2251
  "acceptEdits",
2046
2252
  "plan",
@@ -2048,20 +2254,20 @@ var ClaudePermissionModeSchema = z7.enum([
2048
2254
  ]);
2049
2255
 
2050
2256
  // src/schemas/codex.ts
2051
- import { z as z8 } from "zod";
2052
- var CodexPermissionModeSchema = z8.enum(["plan", "edit", "reviewed", "full"]);
2053
- var LegacyCodexPermissionModeSchema = z8.enum([
2257
+ import { z as z9 } from "zod";
2258
+ var CodexPermissionModeSchema = z9.enum(["plan", "edit", "reviewed", "full"]);
2259
+ var LegacyCodexPermissionModeSchema = z9.enum([
2054
2260
  "default",
2055
2261
  "acceptEdits",
2056
2262
  "bypassPermissions"
2057
2263
  ]);
2058
- var CodexPermissionModeCompatSchema = z8.union([
2264
+ var CodexPermissionModeCompatSchema = z9.union([
2059
2265
  CodexPermissionModeSchema,
2060
2266
  LegacyCodexPermissionModeSchema
2061
2267
  ]);
2062
2268
 
2063
2269
  // src/schemas/entity-id.ts
2064
- import { z as z9 } from "zod";
2270
+ import { z as z10 } from "zod";
2065
2271
 
2066
2272
  // src/entity-id.ts
2067
2273
  var SAFE_ENTITY_ID = /^[A-Za-z0-9@][A-Za-z0-9@._-]{0,199}$/;
@@ -2096,169 +2302,169 @@ function isSafeEntityId(value) {
2096
2302
  }
2097
2303
 
2098
2304
  // src/schemas/entity-id.ts
2099
- var EntityIdSchema = z9.string().refine(isSafeEntityId, {
2305
+ var EntityIdSchema = z10.string().refine(isSafeEntityId, {
2100
2306
  message: "must be a portable single-segment entity id"
2101
2307
  });
2102
2308
 
2103
2309
  // src/schemas/growth.ts
2104
- import { z as z11 } from "zod";
2310
+ import { z as z12 } from "zod";
2105
2311
 
2106
2312
  // src/schemas/tuning-profile-registry.ts
2107
- import { z as z10 } from "zod";
2108
- var TuningProfileIdSchema = z10.string().min(1).describe("Canonical tuning profile id.");
2313
+ import { z as z11 } from "zod";
2314
+ var TuningProfileIdSchema = z11.string().min(1).describe("Canonical tuning profile id.");
2109
2315
 
2110
2316
  // src/schemas/growth.ts
2111
- var GrowthEvidenceSchema = z11.object({
2317
+ var GrowthEvidenceSchema = z12.object({
2112
2318
  /** Memory-file day (YYYY-MM-DD) — rewritten server-side from the matched entry. */
2113
- day: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/),
2114
- kind: z11.enum(["fact", "decision", "pref", "status"]),
2115
- excerpt: z11.string().min(1).max(400)
2116
- });
2117
- var TraitProposalSchema = z11.object({
2118
- id: z11.string(),
2119
- kind: z11.literal("trait"),
2120
- title: z11.string().min(1).max(80),
2319
+ day: z12.string().regex(/^\d{4}-\d{2}-\d{2}$/),
2320
+ kind: z12.enum(["fact", "decision", "pref", "status"]),
2321
+ excerpt: z12.string().min(1).max(400)
2322
+ });
2323
+ var TraitProposalSchema = z12.object({
2324
+ id: z12.string(),
2325
+ kind: z12.literal("trait"),
2326
+ title: z12.string().min(1).max(80),
2121
2327
  /** One imperative second-person sentence destined for the prompt. */
2122
- traitText: z11.string().min(1).max(200),
2123
- evidence: z11.array(GrowthEvidenceSchema).min(1).max(3)
2328
+ traitText: z12.string().min(1).max(200),
2329
+ evidence: z12.array(GrowthEvidenceSchema).min(1).max(3)
2124
2330
  });
2125
- var TuningActionSchema = z11.discriminatedUnion("type", [
2126
- z11.object({ type: z11.literal("profile"), profile: TuningProfileIdSchema }),
2331
+ var TuningActionSchema = z12.discriminatedUnion("type", [
2332
+ z12.object({ type: z12.literal("profile"), profile: TuningProfileIdSchema }),
2127
2333
  /** Resolved + clamped at accept time against the then-current frontmatter. */
2128
- z11.object({ type: z11.literal("temperature"), delta: z11.union([z11.literal(0.1), z11.literal(-0.1)]) })
2334
+ z12.object({ type: z12.literal("temperature"), delta: z12.union([z12.literal(0.1), z12.literal(-0.1)]) })
2129
2335
  ]);
2130
- var TuningProposalSchema = z11.object({
2131
- id: z11.string(),
2132
- kind: z11.literal("tuning"),
2133
- title: z11.string().max(80),
2134
- description: z11.string().max(300),
2336
+ var TuningProposalSchema = z12.object({
2337
+ id: z12.string(),
2338
+ kind: z12.literal("tuning"),
2339
+ title: z12.string().max(80),
2340
+ description: z12.string().max(300),
2135
2341
  action: TuningActionSchema
2136
2342
  });
2137
- var CosmeticProposalSchema = z11.object({
2138
- id: z11.string(),
2139
- kind: z11.literal("cosmetic"),
2140
- title: z11.string().max(80),
2343
+ var CosmeticProposalSchema = z12.object({
2344
+ id: z12.string(),
2345
+ kind: z12.literal("cosmetic"),
2346
+ title: z12.string().max(80),
2141
2347
  /** Key into GROWTH_COSMETICS, or a generic `level-N` milestone marker. */
2142
- cosmeticId: z11.string()
2348
+ cosmeticId: z12.string()
2143
2349
  });
2144
- var GrowthProposalSchema = z11.discriminatedUnion("kind", [
2350
+ var GrowthProposalSchema = z12.discriminatedUnion("kind", [
2145
2351
  TraitProposalSchema,
2146
2352
  TuningProposalSchema,
2147
2353
  CosmeticProposalSchema
2148
2354
  ]);
2149
- var PendingLevelUpSchema = z11.object({
2150
- toLevel: z11.number().int().min(2),
2151
- proposals: z11.array(GrowthProposalSchema).min(1).max(5),
2152
- createdAt: z11.string()
2153
- });
2154
- var GrowthSignalsSchema = z11.object({
2155
- memoryXp: z11.number().int().nonnegative().default(0),
2156
- lessonsXp: z11.number().int().nonnegative().default(0),
2157
- taskXp: z11.number().int().nonnegative().default(0),
2158
- consultXp: z11.number().int().nonnegative().default(0)
2159
- });
2160
- var AdoptedTraitRecordSchema = z11.object({
2161
- traitId: z11.string(),
2162
- text: z11.string(),
2163
- level: z11.number().int(),
2164
- adoptedAt: z11.string(),
2165
- evidence: z11.array(GrowthEvidenceSchema),
2355
+ var PendingLevelUpSchema = z12.object({
2356
+ toLevel: z12.number().int().min(2),
2357
+ proposals: z12.array(GrowthProposalSchema).min(1).max(5),
2358
+ createdAt: z12.string()
2359
+ });
2360
+ var GrowthSignalsSchema = z12.object({
2361
+ memoryXp: z12.number().int().nonnegative().default(0),
2362
+ lessonsXp: z12.number().int().nonnegative().default(0),
2363
+ taskXp: z12.number().int().nonnegative().default(0),
2364
+ consultXp: z12.number().int().nonnegative().default(0)
2365
+ });
2366
+ var AdoptedTraitRecordSchema = z12.object({
2367
+ traitId: z12.string(),
2368
+ text: z12.string(),
2369
+ level: z12.number().int(),
2370
+ adoptedAt: z12.string(),
2371
+ evidence: z12.array(GrowthEvidenceSchema),
2166
2372
  /** Set when the user later retires the trait — kept for the character sheet. */
2167
- removedAt: z11.string().optional()
2373
+ removedAt: z12.string().optional()
2168
2374
  });
2169
- var DeclinedProposalRecordSchema = z11.object({
2170
- kind: z11.enum(["trait", "tuning", "cosmetic"]),
2171
- title: z11.string(),
2375
+ var DeclinedProposalRecordSchema = z12.object({
2376
+ kind: z12.enum(["trait", "tuning", "cosmetic"]),
2377
+ title: z12.string(),
2172
2378
  /** Used for never-re-offer matching on trait proposals. */
2173
- traitText: z11.string().optional(),
2174
- level: z11.number().int(),
2175
- declinedAt: z11.string()
2176
- });
2177
- var GezelGrowthStateSchema = z11.object({
2178
- version: z11.literal(1).default(1),
2179
- level: z11.number().int().min(1).default(1),
2180
- xp: z11.number().int().nonnegative().default(0),
2379
+ traitText: z12.string().optional(),
2380
+ level: z12.number().int(),
2381
+ declinedAt: z12.string()
2382
+ });
2383
+ var GezelGrowthStateSchema = z12.object({
2384
+ version: z12.literal(1).default(1),
2385
+ level: z12.number().int().min(1).default(1),
2386
+ xp: z12.number().int().nonnegative().default(0),
2181
2387
  signals: GrowthSignalsSchema.prefault({}),
2182
- lastComputedAt: z11.string().optional(),
2388
+ lastComputedAt: z12.string().optional(),
2183
2389
  pendingLevelUp: PendingLevelUpSchema.optional(),
2184
- adoptedTraits: z11.array(AdoptedTraitRecordSchema).default([]),
2185
- declinedProposals: z11.array(DeclinedProposalRecordSchema).default([]),
2186
- unlockedCosmetics: z11.array(z11.object({ id: z11.string(), at: z11.string() })).default([])
2390
+ adoptedTraits: z12.array(AdoptedTraitRecordSchema).default([]),
2391
+ declinedProposals: z12.array(DeclinedProposalRecordSchema).default([]),
2392
+ unlockedCosmetics: z12.array(z12.object({ id: z12.string(), at: z12.string() })).default([])
2187
2393
  });
2188
- var GezelGrowthSummarySchema = z11.object({
2189
- level: z11.number().int().min(1),
2394
+ var GezelGrowthSummarySchema = z12.object({
2395
+ level: z12.number().int().min(1),
2190
2396
  /** True when a level-up is waiting for the user's choice. */
2191
- pending: z11.boolean().optional()
2397
+ pending: z12.boolean().optional()
2192
2398
  });
2193
2399
 
2194
2400
  // src/schemas/model-tuning.ts
2195
- import { z as z12 } from "zod";
2196
- var DrySamplerSchema = z12.object({
2197
- multiplier: z12.number().min(0).max(5).describe("DRY penalty strength. 0 disables. 0.8 is a reasonable default."),
2198
- base: z12.number().min(0).max(5).optional().describe("Base of the exponential penalty for repeated tokens. Default 1.75."),
2199
- allowedLength: z12.number().int().min(0).max(64).optional().describe("Minimum n-gram length before DRY kicks in. Default 2.")
2401
+ import { z as z13 } from "zod";
2402
+ var DrySamplerSchema = z13.object({
2403
+ multiplier: z13.number().min(0).max(5).describe("DRY penalty strength. 0 disables. 0.8 is a reasonable default."),
2404
+ base: z13.number().min(0).max(5).optional().describe("Base of the exponential penalty for repeated tokens. Default 1.75."),
2405
+ allowedLength: z13.number().int().min(0).max(64).optional().describe("Minimum n-gram length before DRY kicks in. Default 2.")
2200
2406
  }).describe("DRY anti-repetition sampler (llama.cpp only).");
2201
- var XtcSamplerSchema = z12.object({
2202
- probability: z12.number().min(0).max(1).describe("Probability of triggering XTC on any given step."),
2203
- threshold: z12.number().min(0).max(1).describe("Minimum top-token probability for XTC to fire.")
2407
+ var XtcSamplerSchema = z13.object({
2408
+ probability: z13.number().min(0).max(1).describe("Probability of triggering XTC on any given step."),
2409
+ threshold: z13.number().min(0).max(1).describe("Minimum top-token probability for XTC to fire.")
2204
2410
  }).describe("XTC sampler (llama.cpp only).");
2205
- var SamplingBlockSchema = z12.object({
2206
- temperature: z12.number().min(0).max(2).optional().describe("Sampling temperature. 0 = greedy. Most reasoning models want 0.6\u20131.0."),
2207
- topP: z12.number().min(0).max(1).optional().describe("Nucleus sampling. 0.95 is the common default for Qwen, Gemma, Nemotron."),
2208
- topK: z12.number().int().min(0).max(1e3).optional().describe("Top-k cutoff. 20 for Qwen think, 64 for Gemma, 1 for greedy-on-instruct."),
2209
- minP: z12.number().min(0).max(1).optional().describe("Min-p cutoff (llama.cpp / MLX / Ollama). Qwen recommends 0."),
2210
- maxTokens: z12.number().int().positive().optional().describe("Per-turn output token cap. Maps to num_predict / max_tokens / n_predict."),
2211
- seed: z12.number().int().optional().describe("RNG seed. Unset / negative = random. Best-effort determinism on cloud."),
2212
- repetitionPenalty: z12.number().min(0).max(3).optional().describe("Local engines (Ollama / llama.cpp / MLX): repeat_penalty. 1.0 = off, 1.1 = mild."),
2213
- repetitionContext: z12.number().int().positive().optional().describe("Local engines: window size for repetition penalty (`repeat_last_n`)."),
2214
- frequencyPenalty: z12.number().min(-2).max(2).optional().describe("Cloud (OpenAI) and Ollama / llama.cpp: penalize repeated tokens by frequency."),
2215
- presencePenalty: z12.number().min(-2).max(2).optional().describe("Cloud (OpenAI) and Ollama / llama.cpp: penalize any reused token."),
2411
+ var SamplingBlockSchema = z13.object({
2412
+ temperature: z13.number().min(0).max(2).optional().describe("Sampling temperature. 0 = greedy. Most reasoning models want 0.6\u20131.0."),
2413
+ topP: z13.number().min(0).max(1).optional().describe("Nucleus sampling. 0.95 is the common default for Qwen, Gemma, Nemotron."),
2414
+ topK: z13.number().int().min(0).max(1e3).optional().describe("Top-k cutoff. 20 for Qwen think, 64 for Gemma, 1 for greedy-on-instruct."),
2415
+ minP: z13.number().min(0).max(1).optional().describe("Min-p cutoff (llama.cpp / MLX / Ollama). Qwen recommends 0."),
2416
+ maxTokens: z13.number().int().positive().optional().describe("Per-turn output token cap. Maps to num_predict / max_tokens / n_predict."),
2417
+ seed: z13.number().int().optional().describe("RNG seed. Unset / negative = random. Best-effort determinism on cloud."),
2418
+ repetitionPenalty: z13.number().min(0).max(3).optional().describe("Local engines (Ollama / llama.cpp / MLX): repeat_penalty. 1.0 = off, 1.1 = mild."),
2419
+ repetitionContext: z13.number().int().positive().optional().describe("Local engines: window size for repetition penalty (`repeat_last_n`)."),
2420
+ frequencyPenalty: z13.number().min(-2).max(2).optional().describe("Cloud (OpenAI) and Ollama / llama.cpp: penalize repeated tokens by frequency."),
2421
+ presencePenalty: z13.number().min(-2).max(2).optional().describe("Cloud (OpenAI) and Ollama / llama.cpp: penalize any reused token."),
2216
2422
  dry: DrySamplerSchema.optional(),
2217
2423
  xtc: XtcSamplerSchema.optional()
2218
2424
  }).describe("Sampling parameters applied per-request.");
2219
- var ReasoningBlockSchema = z12.object({
2220
- effort: z12.enum(["low", "medium", "high"]).optional().describe(
2425
+ var ReasoningBlockSchema = z13.object({
2426
+ effort: z13.enum(["low", "medium", "high"]).optional().describe(
2221
2427
  "Cloud reasoning effort. Maps to OpenAI `reasoning.effort` and Anthropic `thinking.budget_tokens` tiers."
2222
2428
  ),
2223
- thinkingBudget: z12.number().int().positive().optional().describe(
2429
+ thinkingBudget: z13.number().int().positive().optional().describe(
2224
2430
  "Explicit thinking-token budget (Anthropic `thinking.budget_tokens`, Nemotron `reasoning_budget`). Wins over `effort` when both set."
2225
2431
  ),
2226
- enableThinking: z12.boolean().optional().describe(
2432
+ enableThinking: z13.boolean().optional().describe(
2227
2433
  "Chat-template toggle for dual-mode models (Qwen3+, Nemotron Nano/Super). Implicit on cloud thinking models."
2228
2434
  ),
2229
- templateKwargs: z12.record(z12.string(), z12.union([z12.string(), z12.number(), z12.boolean()])).optional().describe(
2435
+ templateKwargs: z13.record(z13.string(), z13.union([z13.string(), z13.number(), z13.boolean()])).optional().describe(
2230
2436
  "Chat-template variables that drive this model's reasoning depth, forwarded verbatim as `chat_template_kwargs` on local engines. The names are the model's own \u2014 GPT-OSS reads `reasoning_effort`, Muse Glimmer reads `reasoning_strength` (low|medium|high|xhigh) \u2014 so the manifest declares them rather than the runtime guessing. Lives under `reasoning` (not `engine`) because depth is a per-request choice a tuning profile overrides: `thinking-coding` can ask for xhigh while `instruct` asks for low. Cloud providers ignore it; use `reasoning.effort` there."
2231
2437
  )
2232
2438
  }).describe("Reasoning controls.");
2233
- var StructuredOutputSchema = z12.object({
2234
- responseFormat: z12.enum(["text", "json_object"]).optional().describe("Output mode. `text` = freeform (default). `json_object` = enforce JSON."),
2235
- jsonSchema: z12.unknown().optional().describe("Pin output to a JSON Schema (OpenAI strict mode, llama.cpp --json-schema)."),
2236
- grammar: z12.string().optional().describe("llama.cpp GBNF grammar. Last-resort structured-output knob.")
2439
+ var StructuredOutputSchema = z13.object({
2440
+ responseFormat: z13.enum(["text", "json_object"]).optional().describe("Output mode. `text` = freeform (default). `json_object` = enforce JSON."),
2441
+ jsonSchema: z13.unknown().optional().describe("Pin output to a JSON Schema (OpenAI strict mode, llama.cpp --json-schema)."),
2442
+ grammar: z13.string().optional().describe("llama.cpp GBNF grammar. Last-resort structured-output knob.")
2237
2443
  }).describe("Structured-output controls.");
2238
- var PromptTagsSchema = z12.object({
2239
- enableThinkingTag: z12.string().optional().describe("User-prompt tag that enables thinking for this turn (e.g. `/think`)."),
2240
- disableThinkingTag: z12.string().optional().describe("User-prompt tag that disables thinking for this turn (e.g. `/no_think`).")
2444
+ var PromptTagsSchema = z13.object({
2445
+ enableThinkingTag: z13.string().optional().describe("User-prompt tag that enables thinking for this turn (e.g. `/think`)."),
2446
+ disableThinkingTag: z13.string().optional().describe("User-prompt tag that disables thinking for this turn (e.g. `/no_think`).")
2241
2447
  }).describe("Per-turn reasoning toggle tags.");
2242
- var LlamaCppEngineConfigSchema = z12.object({
2243
- nGpuLayers: z12.number().int().min(-1).optional().describe("`--n-gpu-layers` override. -1 = all. Unset = b9843 `auto`/`--fit`."),
2244
- cpuMoe: z12.boolean().optional().describe("`--cpu-moe`: keep ALL MoE experts in system RAM (attention/dense on GPU)."),
2245
- nCpuMoe: z12.number().int().min(0).optional().describe("`--n-cpu-moe N`: keep the first N layers\u2019 MoE experts in RAM. Partial split."),
2246
- cacheReuse: z12.number().int().min(0).optional().describe(
2448
+ var LlamaCppEngineConfigSchema = z13.object({
2449
+ nGpuLayers: z13.number().int().min(-1).optional().describe("`--n-gpu-layers` override. -1 = all. Unset = b9843 `auto`/`--fit`."),
2450
+ cpuMoe: z13.boolean().optional().describe("`--cpu-moe`: keep ALL MoE experts in system RAM (attention/dense on GPU)."),
2451
+ nCpuMoe: z13.number().int().min(0).optional().describe("`--n-cpu-moe N`: keep the first N layers\u2019 MoE experts in RAM. Partial split."),
2452
+ cacheReuse: z13.number().int().min(0).optional().describe(
2247
2453
  "`--cache-reuse N` prefix-KV reuse chunk. 0 = disable. Unset inherits the global default."
2248
2454
  ),
2249
- swaFull: z12.boolean().optional().describe("`--swa-full`: full-size SWA cache (Gemma family)."),
2250
- flashAttn: z12.enum(["on", "off", "auto"]).optional().describe("`--flash-attn` mode override for this model."),
2251
- ubatchSize: z12.number().int().positive().optional().describe("`--ubatch-size` (inner microbatch) override for this model."),
2252
- contextSize: z12.number().int().positive().optional().describe(
2455
+ swaFull: z13.boolean().optional().describe("`--swa-full`: full-size SWA cache (Gemma family)."),
2456
+ flashAttn: z13.enum(["on", "off", "auto"]).optional().describe("`--flash-attn` mode override for this model."),
2457
+ ubatchSize: z13.number().int().positive().optional().describe("`--ubatch-size` (inner microbatch) override for this model."),
2458
+ contextSize: z13.number().int().positive().optional().describe(
2253
2459
  "Per-turn context ceiling (tokens) this model launches with. Capped by GGUF train ctx."
2254
2460
  ),
2255
- chatTemplate: z12.string().min(1).optional().describe(
2461
+ chatTemplate: z13.string().min(1).optional().describe(
2256
2462
  "`--chat-template` override for GGUFs whose embedded Jinja template is incompatible with llama.cpp tool parsing."
2257
2463
  ),
2258
- threads: z12.number().int().positive().optional().describe("`--threads` override."),
2259
- batchSize: z12.number().int().positive().optional().describe("`--batch-size` override."),
2260
- spec: z12.object({
2261
- type: z12.enum([
2464
+ threads: z13.number().int().positive().optional().describe("`--threads` override."),
2465
+ batchSize: z13.number().int().positive().optional().describe("`--batch-size` override."),
2466
+ spec: z13.object({
2467
+ type: z13.enum([
2262
2468
  "none",
2263
2469
  "draft-mtp",
2264
2470
  "draft-eagle3",
@@ -2270,24 +2476,24 @@ var LlamaCppEngineConfigSchema = z12.object({
2270
2476
  "ngram-map-k4v",
2271
2477
  "ngram-cache"
2272
2478
  ]).optional().describe("`--spec-type` speculative-decoding mode for this model."),
2273
- mtp: z12.boolean().optional().describe(
2479
+ mtp: z13.boolean().optional().describe(
2274
2480
  "VERIFIED capability metadata: this model\u2019s target or companion GGUF carries MTP tensors. Does not enable `draft-mtp` by itself."
2275
2481
  ),
2276
- draftModelId: z12.string().optional().describe("Catalog id / path of the draft model for `draft-simple`."),
2277
- nMax: z12.number().int().positive().optional().describe("`--spec-draft-n-max`: tokens drafted per step.")
2482
+ draftModelId: z13.string().optional().describe("Catalog id / path of the draft model for `draft-simple`."),
2483
+ nMax: z13.number().int().positive().optional().describe("`--spec-draft-n-max`: tokens drafted per step.")
2278
2484
  }).optional().describe("Speculative-decoding config for this model.")
2279
2485
  }).describe("Per-model llama.cpp launch-flag defaults (engine-level, applied at model load).");
2280
- var EngineConfigSchema = z12.object({
2486
+ var EngineConfigSchema = z13.object({
2281
2487
  llamaCpp: LlamaCppEngineConfigSchema.optional()
2282
2488
  }).describe("Per-model engine launch-flag defaults, keyed by engine.");
2283
- var ChatModelTuningBaseSchema = z12.object({
2489
+ var ChatModelTuningBaseSchema = z13.object({
2284
2490
  sampling: SamplingBlockSchema.optional(),
2285
2491
  samplingWhenThinking: SamplingBlockSchema.optional().describe(
2286
2492
  "Sparse override of `sampling` applied when the runtime determines reasoning is engaged. Used by Qwen3+ (different sampling for /think mode) and Nemotron Nano (different sampling for thinking vs instruct)."
2287
2493
  ),
2288
2494
  reasoning: ReasoningBlockSchema.optional(),
2289
2495
  output: StructuredOutputSchema.optional(),
2290
- toolChoice: z12.enum(["auto", "required", "none"]).optional().describe(
2496
+ toolChoice: z13.enum(["auto", "required", "none"]).optional().describe(
2291
2497
  "Tool selection mode (cloud + llama.cpp + MLX). `auto` lets the model decide; `required` forces a tool call this turn; `none` disables tools."
2292
2498
  ),
2293
2499
  promptTags: PromptTagsSchema.optional()
@@ -2296,16 +2502,16 @@ var ChatModelTuningSchema = ChatModelTuningBaseSchema.extend({
2296
2502
  engine: EngineConfigSchema.optional().describe(
2297
2503
  "Per-model ENGINE launch-flag defaults (llama.cpp `--n-gpu-layers`, `--cpu-moe`, `--spec-type`, \u2026). Applied once at model load, not per request \u2014 so it lives on the top-level tuning object, not inside per-request `profiles`."
2298
2504
  ),
2299
- profiles: z12.record(TuningProfileIdSchema, ChatModelTuningBaseSchema.partial()).optional().describe(
2505
+ profiles: z13.record(TuningProfileIdSchema, ChatModelTuningBaseSchema.partial()).optional().describe(
2300
2506
  "Named tuning presets this model implements. Gezel frontmatter `tuningProfile` selects one; the resolver applies the profile as a layer between installDefault and catalog base. Missing requested profiles walk the canonical fallback chain."
2301
2507
  )
2302
2508
  }).describe("Per-model sampling, reasoning, and output defaults.");
2303
2509
 
2304
2510
  // src/schemas/question.ts
2305
- import { z as z14 } from "zod";
2511
+ import { z as z15 } from "zod";
2306
2512
 
2307
2513
  // src/schemas/npm-package.ts
2308
- import { z as z13 } from "zod";
2514
+ import { z as z14 } from "zod";
2309
2515
  var NPM_NAME_SEGMENT = /^[a-z0-9](?:[a-z0-9._~-]*[a-z0-9])?$/;
2310
2516
  var SEMVER_NUMBER = String.raw`(?:0|[1-9]\d*)`;
2311
2517
  var SEMVER_PART = String.raw`(?:${SEMVER_NUMBER}|[xX*])`;
@@ -2337,36 +2543,41 @@ function isValidNpmRegistryVersion(value) {
2337
2543
  return atoms.length > 0 && atoms.every((atom) => SEMVER_ATOM.test(atom));
2338
2544
  });
2339
2545
  }
2340
- var NpmPackageNameSchema = z13.string().refine(isValidNpmPackageName, {
2546
+ var NpmPackageNameSchema = z14.string().refine(isValidNpmPackageName, {
2341
2547
  message: "must be a lowercase npm registry package name (for example zod or @types/node)"
2342
2548
  });
2343
- var NpmRegistryVersionSchema = z13.string().refine(isValidNpmRegistryVersion, {
2549
+ var NpmRegistryVersionSchema = z14.string().refine(isValidNpmRegistryVersion, {
2344
2550
  message: "must be a registry dist-tag or semver range"
2345
2551
  });
2346
- var NpmRegistryPackageRequestSchema = z13.object({
2552
+ var NpmRegistryPackageRequestSchema = z14.object({
2347
2553
  package: NpmPackageNameSchema,
2348
2554
  version: NpmRegistryVersionSchema.optional()
2349
2555
  }).strict();
2350
2556
 
2351
2557
  // src/schemas/question.ts
2352
- var NpmInstallApprovalDecisionSchema = z14.object({
2558
+ var NpmInstallApprovalDecisionSchema = z15.object({
2353
2559
  package: NpmPackageNameSchema,
2354
2560
  version: NpmRegistryVersionSchema,
2355
- decision: z14.enum(["install", "always", "decline"])
2561
+ decision: z15.enum(["install", "always", "decline"])
2356
2562
  });
2357
- var QuestionAnswerSchema = z14.object({
2563
+ var QuestionAnswerSchema = z15.object({
2358
2564
  /** Indices into `choices` the user picked. Empty when only write-in. */
2359
- selectedChoices: z14.array(z14.number().int().min(0)).optional(),
2565
+ selectedChoices: z15.array(z15.number().int().min(0)).optional(),
2360
2566
  /** Free-text the user typed. Empty when they only clicked choices. */
2361
- writeIn: z14.string().optional(),
2567
+ writeIn: z15.string().optional(),
2362
2568
  /**
2363
2569
  * Set when the user explicitly dismissed BUT wants the gezel to
2364
2570
  * proceed anyway with sensible defaults. Triggers a synthetic
2365
2571
  * follow-up turn with a `[The user wants you to proceed…]` seed
2366
2572
  * so the gezel knows to make decisions on the user's behalf.
2367
- * UI label: "Just do whatever".
2573
+ *
2574
+ * The plain question card no longer offers this — a "decide for me"
2575
+ * button next to a question the gezel is blocked on invited the one
2576
+ * answer that teaches it nothing. It stays on the approval cards that
2577
+ * mean it literally (declining an image generation, an npm install,
2578
+ * a schedule) and on the permission broker's dismissal path.
2368
2579
  */
2369
- declined: z14.boolean().optional(),
2580
+ declined: z15.boolean().optional(),
2370
2581
  /**
2371
2582
  * Set when the user just wants the question to go away — no
2372
2583
  * follow-up turn, no work done, nothing for the gezel to act on.
@@ -2375,123 +2586,140 @@ var QuestionAnswerSchema = z14.object({
2375
2586
  * from `declined` so the model never sees a "user wants defaults"
2376
2587
  * signal that the user didn't intend. UI label: "Skip".
2377
2588
  */
2378
- silentSkip: z14.boolean().optional(),
2589
+ silentSkip: z15.boolean().optional(),
2379
2590
  /**
2380
2591
  * Per-package decisions for `npm-install-approval` questions. When
2381
2592
  * set, the answer handler installs / always-allows / declines each
2382
2593
  * package and emits a single follow-up summary into the session.
2383
2594
  */
2384
- npmInstallDecisions: z14.array(NpmInstallApprovalDecisionSchema).optional(),
2385
- at: z14.string()
2595
+ npmInstallDecisions: z15.array(NpmInstallApprovalDecisionSchema).optional(),
2596
+ at: z15.string()
2386
2597
  });
2387
- var NpmInstallApprovalPackageSchema = z14.object({
2598
+ var NpmInstallApprovalPackageSchema = z15.object({
2388
2599
  package: NpmPackageNameSchema,
2389
2600
  version: NpmRegistryVersionSchema
2390
2601
  });
2391
- var CommandApprovalScopeSchema = z14.enum(["script", "npx"]);
2392
- var CommandApprovalInputFileSchema = z14.object({
2602
+ var CommandApprovalScopeSchema = z15.enum(["script", "npx"]);
2603
+ var CommandApprovalInputFileSchema = z15.object({
2393
2604
  /** Workspace-relative, slash-normalized path shown in the approval prompt. */
2394
- path: z14.string().min(1),
2395
- sha256: z14.string().regex(/^[a-f0-9]{64}$/)
2605
+ path: z15.string().min(1),
2606
+ sha256: z15.string().regex(/^[a-f0-9]{64}$/)
2396
2607
  });
2397
- var CommandApprovalIntentSchema = z14.object({
2398
- kind: z14.literal("command-approval"),
2608
+ var CommandApprovalIntentSchema = z15.object({
2609
+ kind: z15.literal("command-approval"),
2399
2610
  scope: CommandApprovalScopeSchema,
2400
- name: z14.string().min(1),
2401
- body: z14.string().optional(),
2402
- args: z14.array(z14.string()).optional(),
2403
- inputFiles: z14.array(CommandApprovalInputFileSchema).max(128).optional()
2404
- });
2405
- var ToolPermissionIntentSchema = z14.object({
2406
- kind: z14.literal("tool-permission"),
2407
- toolName: z14.string(),
2408
- toolInput: z14.record(z14.string(), z14.unknown())
2409
- });
2410
- var ToolsetInstallApprovalIntentSchema = z14.object({
2411
- kind: z14.literal("toolset-install-approval"),
2412
- toolsetId: z14.string(),
2413
- sourceId: z14.string(),
2414
- version: z14.string(),
2415
- targetProjectId: z14.string(),
2416
- craftbookId: z14.string()
2417
- });
2418
- var ImageGenerationApprovalIntentSchema = z14.object({
2419
- kind: z14.literal("image-generation-approval"),
2420
- provider: z14.string(),
2421
- model: z14.string(),
2611
+ name: z15.string().min(1),
2612
+ body: z15.string().optional(),
2613
+ args: z15.array(z15.string()).optional(),
2614
+ inputFiles: z15.array(CommandApprovalInputFileSchema).max(128).optional()
2615
+ });
2616
+ var ToolPermissionIntentSchema = z15.object({
2617
+ kind: z15.literal("tool-permission"),
2618
+ toolName: z15.string(),
2619
+ toolInput: z15.record(z15.string(), z15.unknown())
2620
+ });
2621
+ var ClaudeUserQuestionOptionSchema = z15.object({
2622
+ label: z15.string().min(1),
2623
+ description: z15.string().optional()
2624
+ });
2625
+ var ClaudeUserQuestionIntentSchema = z15.object({
2626
+ kind: z15.literal("claude-user-question"),
2627
+ /** The CLI's short topic chip for the question (e.g. "Gate block"). */
2628
+ header: z15.string().optional(),
2629
+ /** Options with descriptions; labels mirror the Question's `choices`. */
2630
+ options: z15.array(ClaudeUserQuestionOptionSchema),
2631
+ /** 0-based position within the originating multi-question call. */
2632
+ questionIndex: z15.number().int().min(0),
2633
+ /** Total questions in the originating call (cards appear sequentially). */
2634
+ questionCount: z15.number().int().min(1)
2635
+ });
2636
+ var ToolsetInstallApprovalIntentSchema = z15.object({
2637
+ kind: z15.literal("toolset-install-approval"),
2638
+ toolsetId: z15.string(),
2639
+ sourceId: z15.string(),
2640
+ version: z15.string(),
2641
+ targetProjectId: z15.string(),
2642
+ craftbookId: z15.string()
2643
+ });
2644
+ var ImageGenerationApprovalIntentSchema = z15.object({
2645
+ kind: z15.literal("image-generation-approval"),
2646
+ provider: z15.string(),
2647
+ model: z15.string(),
2422
2648
  /** Truncated prompt the model is about to send. Surfaced verbatim. */
2423
- promptPreview: z14.string(),
2649
+ promptPreview: z15.string(),
2424
2650
  /** Resolved generation size, e.g. '2K 16:9' or '1024x1024'. Optional. */
2425
- estimatedSize: z14.string().optional()
2651
+ estimatedSize: z15.string().optional()
2426
2652
  });
2427
- var VideoGenerationApprovalIntentSchema = z14.object({
2428
- kind: z14.literal("video-generation-approval"),
2429
- provider: z14.string(),
2430
- model: z14.string(),
2431
- promptPreview: z14.string(),
2653
+ var VideoGenerationApprovalIntentSchema = z15.object({
2654
+ kind: z15.literal("video-generation-approval"),
2655
+ provider: z15.string(),
2656
+ model: z15.string(),
2657
+ promptPreview: z15.string(),
2432
2658
  /** Resolved clip shape, e.g. '704×480 · 97f · 24fps'. Optional. */
2433
- estimatedSize: z14.string().optional()
2659
+ estimatedSize: z15.string().optional()
2434
2660
  });
2435
- var ScheduleApprovalIntentSchema = z14.object({
2436
- kind: z14.literal("schedule-approval"),
2437
- typeId: z14.string(),
2438
- craftbookId: z14.string(),
2661
+ var ScheduleApprovalIntentSchema = z15.object({
2662
+ kind: z15.literal("schedule-approval"),
2663
+ typeId: z15.string(),
2664
+ craftbookId: z15.string(),
2439
2665
  /**
2440
2666
  * Recurrence flavor. Absent → 'scheduled' (every question written
2441
2667
  * before this field existed is a cron schedule). 'night-shift' hosts
2442
2668
  * run inside the Night Shift window instead of on a user-visible cron;
2443
2669
  * the card copy switches accordingly.
2444
2670
  */
2445
- runMode: z14.enum(["scheduled", "night-shift"]).optional(),
2671
+ runMode: z15.enum(["scheduled", "night-shift"]).optional(),
2446
2672
  /**
2447
2673
  * 5-field cron expression (UTC). Surfaced verbatim on the card for
2448
2674
  * 'scheduled' hosts; for 'night-shift' hosts it is the internal
2449
2675
  * heartbeat and the card shows the window instead.
2450
2676
  */
2451
- cron: z14.string(),
2452
- overlap: z14.enum(["skip", "queue", "concurrent"]).optional()
2677
+ cron: z15.string(),
2678
+ overlap: z15.enum(["skip", "queue", "concurrent"]).optional()
2453
2679
  });
2454
- var NightShiftReviewIntentSchema = z14.object({
2455
- kind: z14.literal("night-shift-review"),
2680
+ var NightShiftReviewIntentSchema = z15.object({
2681
+ kind: z15.literal("night-shift-review"),
2456
2682
  /** The window's day key (see `nightShiftWindowKey`). */
2457
- windowKey: z14.string(),
2458
- tasksCompleted: z14.number(),
2459
- reports: z14.array(
2460
- z14.object({
2461
- projectId: z14.string(),
2462
- path: z14.string(),
2463
- title: z14.string().optional(),
2464
- actionCount: z14.number()
2683
+ windowKey: z15.string(),
2684
+ tasksCompleted: z15.number(),
2685
+ reports: z15.array(
2686
+ z15.object({
2687
+ projectId: z15.string(),
2688
+ path: z15.string(),
2689
+ title: z15.string().optional(),
2690
+ actionCount: z15.number()
2465
2691
  })
2466
2692
  )
2467
2693
  });
2468
- var TaskPausedReasonSchema = z14.enum([
2694
+ var TaskPausedReasonSchema = z15.enum([
2469
2695
  "gate_exhausted",
2470
2696
  "gate_plateau",
2471
2697
  "gate_unsatisfiable",
2472
2698
  "gate_infrastructure",
2699
+ "step_exit_infrastructure",
2473
2700
  "step_stalled",
2474
2701
  "budget_exhausted"
2475
2702
  ]);
2476
- var TaskPausedIntentSchema = z14.object({
2477
- kind: z14.literal("task-paused"),
2703
+ var TaskPausedIntentSchema = z15.object({
2704
+ kind: z15.literal("task-paused"),
2478
2705
  /** `projectId/num` of the paused task — the dedup key. */
2479
- taskRef: z14.string(),
2480
- stepId: z14.string().optional(),
2706
+ taskRef: z15.string(),
2707
+ stepId: z15.string().optional(),
2481
2708
  reason: TaskPausedReasonSchema
2482
2709
  });
2483
- var QuestionIntentSchema = z14.discriminatedUnion("kind", [
2484
- z14.object({
2485
- kind: z14.literal("npm-install-approval"),
2710
+ var QuestionIntentSchema = z15.discriminatedUnion("kind", [
2711
+ z15.object({
2712
+ kind: z15.literal("npm-install-approval"),
2486
2713
  /**
2487
2714
  * Packages that need approval. Always at least one; multiple when
2488
2715
  * the gezel batched an install call (encouraged) or when we merged
2489
2716
  * a later request into the same pending question for dedup.
2490
2717
  */
2491
- packages: z14.array(NpmInstallApprovalPackageSchema).min(1)
2718
+ packages: z15.array(NpmInstallApprovalPackageSchema).min(1)
2492
2719
  }),
2493
2720
  CommandApprovalIntentSchema,
2494
2721
  ToolPermissionIntentSchema,
2722
+ ClaudeUserQuestionIntentSchema,
2495
2723
  ToolsetInstallApprovalIntentSchema,
2496
2724
  ImageGenerationApprovalIntentSchema,
2497
2725
  VideoGenerationApprovalIntentSchema,
@@ -2499,61 +2727,61 @@ var QuestionIntentSchema = z14.discriminatedUnion("kind", [
2499
2727
  NightShiftReviewIntentSchema,
2500
2728
  TaskPausedIntentSchema
2501
2729
  ]);
2502
- var QuestionSchema = z14.object({
2503
- id: z14.string(),
2504
- projectId: z14.string(),
2505
- gezelId: z14.string(),
2506
- sessionId: z14.string(),
2730
+ var QuestionSchema = z15.object({
2731
+ id: z15.string(),
2732
+ projectId: z15.string(),
2733
+ gezelId: z15.string(),
2734
+ sessionId: z15.string(),
2507
2735
  /** Body of the question — supports markdown. */
2508
- prompt: z14.string().min(1),
2736
+ prompt: z15.string().min(1),
2509
2737
  /** Optional preset choices. Empty / omitted => write-in only. */
2510
- choices: z14.array(z14.string()).max(20).optional(),
2738
+ choices: z15.array(z15.string()).max(20).optional(),
2511
2739
  /** Whether the user can also type a write-in alongside choices. Default true. */
2512
- allowWriteIn: z14.boolean().optional(),
2740
+ allowWriteIn: z15.boolean().optional(),
2513
2741
  /** Whether multiple choices may be selected. Default false. */
2514
- multiSelect: z14.boolean().optional(),
2742
+ multiSelect: z15.boolean().optional(),
2515
2743
  /**
2516
2744
  * Approval-flow attachment: a task this question is *about*. Stored in
2517
2745
  * `projectId/num` form so existing parsing helpers work. The UI shows
2518
2746
  * the task title + status above the prompt and offers an "Open task"
2519
2747
  * link.
2520
2748
  */
2521
- taskRef: z14.string().optional(),
2749
+ taskRef: z15.string().optional(),
2522
2750
  /**
2523
2751
  * Approval-flow attachment: a document this question is *about*.
2524
2752
  * Project-relative path when `projectId` is set, otherwise into the
2525
2753
  * global `~/.gezel/documents/` library. The UI renders a collapsed
2526
2754
  * preview + "Open document" link.
2527
2755
  */
2528
- documentPath: z14.string().optional(),
2756
+ documentPath: z15.string().optional(),
2529
2757
  /**
2530
2758
  * Service-created specialized-question marker (see `QuestionIntent`
2531
2759
  * for context). Absent for plain user-facing questions asked via
2532
2760
  * the `ask_user_question` MCP tool.
2533
2761
  */
2534
2762
  intent: QuestionIntentSchema.optional(),
2535
- createdAt: z14.string(),
2763
+ createdAt: z15.string(),
2536
2764
  /** Set once the user has answered (or declined). */
2537
2765
  answer: QuestionAnswerSchema.optional()
2538
2766
  });
2539
2767
 
2540
2768
  // src/schemas/recognition.ts
2541
- import { z as z15 } from "zod";
2542
- var ImageExifSchema = z15.object({
2543
- make: z15.string().optional(),
2544
- model: z15.string().optional(),
2545
- lensModel: z15.string().optional(),
2546
- dateTimeOriginal: z15.string().optional(),
2547
- orientation: z15.number().int().min(1).max(8).optional(),
2548
- software: z15.string().optional(),
2549
- imageDescription: z15.string().optional()
2550
- });
2551
- var ImageStaticMetaSchema = z15.object({
2552
- format: z15.enum(["png", "jpeg", "gif", "webp", "svg", "unknown"]),
2553
- width: z15.number().int().positive().optional(),
2554
- height: z15.number().int().positive().optional(),
2555
- byteLength: z15.number().int().nonnegative(),
2556
- sha256: z15.string().regex(/^[a-f0-9]{64}$/),
2769
+ import { z as z16 } from "zod";
2770
+ var ImageExifSchema = z16.object({
2771
+ make: z16.string().optional(),
2772
+ model: z16.string().optional(),
2773
+ lensModel: z16.string().optional(),
2774
+ dateTimeOriginal: z16.string().optional(),
2775
+ orientation: z16.number().int().min(1).max(8).optional(),
2776
+ software: z16.string().optional(),
2777
+ imageDescription: z16.string().optional()
2778
+ });
2779
+ var ImageStaticMetaSchema = z16.object({
2780
+ format: z16.enum(["png", "jpeg", "gif", "webp", "svg", "unknown"]),
2781
+ width: z16.number().int().positive().optional(),
2782
+ height: z16.number().int().positive().optional(),
2783
+ byteLength: z16.number().int().nonnegative(),
2784
+ sha256: z16.string().regex(/^[a-f0-9]{64}$/),
2557
2785
  /**
2558
2786
  * PNG `tEXt`/`iTXt`/`zTXt` keyword→value pairs. Generation provenance lives
2559
2787
  * here (A1111 writes `parameters`, ComfyUI writes `prompt`/`workflow`) and
@@ -2562,153 +2790,171 @@ var ImageStaticMetaSchema = z15.object({
2562
2790
  * Attacker-controlled: anyone can author a PNG whose `Description` chunk
2563
2791
  * reads "Ignore previous instructions". Renderers MUST fence and cap this.
2564
2792
  */
2565
- pngText: z15.record(z15.string(), z15.string()).optional(),
2793
+ pngText: z16.record(z16.string(), z16.string()).optional(),
2566
2794
  exif: ImageExifSchema.optional(),
2567
2795
  /** Withheld from every prompt. See the schema doc above. */
2568
- gps: z15.object({ lat: z15.number(), lon: z15.number() }).optional(),
2796
+ gps: z16.object({ lat: z16.number(), lon: z16.number() }).optional(),
2569
2797
  /** True when the file carried location data we deliberately dropped. */
2570
- gpsRedacted: z15.boolean().optional(),
2798
+ gpsRedacted: z16.boolean().optional(),
2571
2799
  /**
2572
2800
  * Heuristic from dimensions, format, and metadata — drives `auto` mode
2573
2801
  * selection without paying a classifier call.
2574
2802
  */
2575
- likelyScreenshot: z15.boolean().optional()
2803
+ likelyScreenshot: z16.boolean().optional()
2576
2804
  });
2577
- var RecognitionModeSchema = z15.enum(["describe", "ocr", "ui", "extract"]);
2578
- var RecognitionModeRequestSchema = z15.enum(["auto", "describe", "ocr", "ui", "extract"]);
2579
- var ImageRecognitionSchema = z15.object({
2580
- schemaVersion: z15.literal(1),
2581
- sha256: z15.string().regex(/^[a-f0-9]{64}$/),
2805
+ var RecognitionModeSchema = z16.enum(["describe", "ocr", "ui", "extract"]);
2806
+ var RecognitionModeRequestSchema = z16.enum(["auto", "describe", "ocr", "ui", "extract"]);
2807
+ var ImageRecognitionSchema = z16.object({
2808
+ schemaVersion: z16.literal(1),
2809
+ sha256: z16.string().regex(/^[a-f0-9]{64}$/),
2582
2810
  meta: ImageStaticMetaSchema,
2583
- modes: z15.array(RecognitionModeSchema).min(1),
2584
- description: z15.string().optional(),
2585
- ocrText: z15.string().optional(),
2586
- structured: z15.object({
2587
- templateId: z15.string().optional(),
2588
- data: z15.unknown()
2811
+ modes: z16.array(RecognitionModeSchema).min(1),
2812
+ description: z16.string().optional(),
2813
+ ocrText: z16.string().optional(),
2814
+ structured: z16.object({
2815
+ templateId: z16.string().optional(),
2816
+ data: z16.unknown()
2589
2817
  }).optional(),
2590
- engine: z15.enum(["llama-cpp", "mlx", "mock", "none"]),
2591
- modelId: z15.string(),
2592
- status: z15.enum(["ok", "partial", "failed", "static-only"]),
2593
- failureReason: z15.string().optional(),
2594
- durationMs: z15.number().int().nonnegative(),
2595
- at: z15.string()
2818
+ engine: z16.enum(["llama-cpp", "mlx", "mock", "none"]),
2819
+ modelId: z16.string(),
2820
+ status: z16.enum(["ok", "partial", "failed", "static-only"]),
2821
+ failureReason: z16.string().optional(),
2822
+ durationMs: z16.number().int().nonnegative(),
2823
+ at: z16.string()
2596
2824
  });
2597
- var MessageImageDigestSchema = z15.object({
2825
+ var MessageImageDigestSchema = z16.object({
2598
2826
  /** The markdown ref exactly as it appears in the message body. */
2599
- ref: z15.string(),
2600
- sha256: z15.string().regex(/^[a-f0-9]{64}$/),
2827
+ ref: z16.string(),
2828
+ sha256: z16.string().regex(/^[a-f0-9]{64}$/),
2601
2829
  /** Pre-rendered, already capped and fenced-safe. */
2602
- digest: z15.string(),
2603
- modelId: z15.string(),
2604
- modes: z15.array(RecognitionModeSchema),
2605
- status: z15.enum(["ok", "partial", "failed", "static-only"]),
2606
- at: z15.string()
2830
+ digest: z16.string(),
2831
+ modelId: z16.string(),
2832
+ modes: z16.array(RecognitionModeSchema),
2833
+ status: z16.enum(["ok", "partial", "failed", "static-only"]),
2834
+ at: z16.string()
2607
2835
  });
2608
- var RecognitionRequestSchema = z15.object({
2836
+ var RecognitionRequestSchema = z16.object({
2609
2837
  /** Project-relative artifact path, e.g. `attachments/<uuid>.png`. */
2610
- artifactPath: z15.string().min(1).optional(),
2611
- data: z15.string().min(1).optional(),
2612
- mimeType: z15.string().optional(),
2838
+ artifactPath: z16.string().min(1).optional(),
2839
+ data: z16.string().min(1).optional(),
2840
+ mimeType: z16.string().optional(),
2613
2841
  mode: RecognitionModeRequestSchema.default("auto"),
2614
2842
  /** JSON Schema for `extract` mode — fed to llama-server `response_format`. */
2615
- schema: z15.unknown().optional(),
2843
+ schema: z16.unknown().optional(),
2616
2844
  /** Overrides the configured recognition model for this call. */
2617
- model: z15.string().optional()
2845
+ model: z16.string().optional()
2618
2846
  });
2619
- var RecognitionHealthSchema = z15.object({
2620
- state: z15.enum(["ok", "no-model", "not-configured", "error"]),
2621
- modelId: z15.string().optional(),
2622
- detail: z15.string().optional()
2847
+ var RecognitionHealthSchema = z16.object({
2848
+ state: z16.enum(["ok", "no-model", "not-configured", "error"]),
2849
+ modelId: z16.string().optional(),
2850
+ detail: z16.string().optional()
2623
2851
  });
2624
- var RecognitionPullEventSchema = z15.union([
2625
- z15.object({
2626
- type: z15.literal("progress"),
2627
- bytesWritten: z15.number().int().nonnegative(),
2628
- totalBytes: z15.number().int().nonnegative().optional()
2852
+ var RecognitionPullEventSchema = z16.union([
2853
+ z16.object({
2854
+ type: z16.literal("progress"),
2855
+ bytesWritten: z16.number().int().nonnegative(),
2856
+ totalBytes: z16.number().int().nonnegative().optional()
2629
2857
  }),
2630
- z15.object({ type: z15.literal("error"), error: z15.string() }),
2631
- z15.object({ type: z15.literal("done"), id: z15.string() })
2858
+ z16.object({ type: z16.literal("error"), error: z16.string() }),
2859
+ z16.object({ type: z16.literal("done"), id: z16.string() })
2632
2860
  ]);
2633
- var RecognitionCatalogEntrySchema = z15.object({
2634
- id: z15.string(),
2635
- name: z15.string(),
2636
- description: z15.string(),
2637
- license: z15.string(),
2638
- approxSizeBytes: z15.number().int().nonnegative(),
2639
- recoScore: z15.number()
2861
+ var RecognitionCatalogEntrySchema = z16.object({
2862
+ id: z16.string(),
2863
+ name: z16.string(),
2864
+ description: z16.string(),
2865
+ license: z16.string(),
2866
+ approxSizeBytes: z16.number().int().nonnegative(),
2867
+ recoScore: z16.number()
2640
2868
  });
2641
- var ListRecognitionCatalogResponseSchema = z15.object({
2642
- models: z15.array(RecognitionCatalogEntrySchema)
2869
+ var ListRecognitionCatalogResponseSchema = z16.object({
2870
+ models: z16.array(RecognitionCatalogEntrySchema)
2643
2871
  });
2644
- var InstalledRecognitionModelSchema = z15.object({
2645
- id: z15.string(),
2646
- name: z15.string(),
2647
- approxSizeBytes: z15.number().int().nonnegative(),
2648
- installedAt: z15.string(),
2649
- weightsPath: z15.string().optional(),
2650
- mmprojPath: z15.string().optional()
2872
+ var InstalledRecognitionModelSchema = z16.object({
2873
+ id: z16.string(),
2874
+ name: z16.string(),
2875
+ approxSizeBytes: z16.number().int().nonnegative(),
2876
+ installedAt: z16.string(),
2877
+ weightsPath: z16.string().optional(),
2878
+ mmprojPath: z16.string().optional()
2879
+ });
2880
+ var ListInstalledRecognitionModelsResponseSchema = z16.object({
2881
+ models: z16.array(InstalledRecognitionModelSchema)
2882
+ });
2883
+
2884
+ // src/schemas/session-lineage.ts
2885
+ import { z as z17 } from "zod";
2886
+ var SessionLinkSchema = z17.object({
2887
+ sessionId: z17.string(),
2888
+ gezelId: z17.string()
2651
2889
  });
2652
- var ListInstalledRecognitionModelsResponseSchema = z15.object({
2653
- models: z15.array(InstalledRecognitionModelSchema)
2890
+ var SessionParentSchema = SessionLinkSchema.extend({
2891
+ kind: z17.enum(["delegation", "consultation", "task-entry", "task-handoff"])
2654
2892
  });
2655
2893
 
2656
2894
  // src/schemas/session-telemetry.ts
2657
- import { z as z16 } from "zod";
2658
- var SessionGpuTaskSchema = z16.enum([
2895
+ import { z as z18 } from "zod";
2896
+ var SessionGpuTaskSchema = z18.enum([
2659
2897
  "image_generation",
2660
2898
  "video_generation",
2661
2899
  "image_recognition"
2662
2900
  ]);
2663
- var SessionTurnTelemetrySchema = z16.object({
2901
+ var SessionTurnPhaseSchema = z18.enum(["preparing", "recall", "provider"]);
2902
+ var SessionTurnTelemetrySchema = z18.object({
2664
2903
  /** Epoch ms when the in-flight turn started. */
2665
- startedAt: z16.number(),
2666
- streamedContentChars: z16.number().int().nonnegative(),
2667
- toolCalls: z16.number().int().nonnegative(),
2668
- fileMutations: z16.number().int().nonnegative()
2669
- });
2670
- var SessionTelemetrySchema = z16.object({
2671
- sessionId: z16.string(),
2672
- gezelId: z16.string(),
2673
- projectId: z16.string(),
2904
+ startedAt: z18.number(),
2905
+ phase: SessionTurnPhaseSchema,
2906
+ /** Epoch ms when `phase` last changed. */
2907
+ phaseStartedAt: z18.number(),
2908
+ /** Provider requests issued by this user-visible turn, including retries. */
2909
+ providerRequestsStarted: z18.number().int().nonnegative(),
2910
+ streamedContentChars: z18.number().int().nonnegative(),
2911
+ toolCalls: z18.number().int().nonnegative(),
2912
+ fileMutations: z18.number().int().nonnegative()
2913
+ });
2914
+ var SessionTelemetrySchema = z18.object({
2915
+ sessionId: z18.string(),
2916
+ gezelId: z18.string(),
2917
+ projectId: z18.string(),
2674
2918
  /** True while a send is currently running for this session. */
2675
- inflight: z16.boolean(),
2676
- turnsStarted: z16.number().int().nonnegative(),
2677
- deltaChunks: z16.number().int().nonnegative(),
2678
- streamedContentChars: z16.number().int().nonnegative(),
2679
- wirePulses: z16.number().int().nonnegative(),
2680
- heartbeats: z16.number().int().nonnegative(),
2681
- enginePhaseEvents: z16.number().int().nonnegative(),
2919
+ inflight: z18.boolean(),
2920
+ turnsStarted: z18.number().int().nonnegative(),
2921
+ /** Provider requests issued across all turns in this daemon process. */
2922
+ providerRequestsStarted: z18.number().int().nonnegative(),
2923
+ deltaChunks: z18.number().int().nonnegative(),
2924
+ streamedContentChars: z18.number().int().nonnegative(),
2925
+ wirePulses: z18.number().int().nonnegative(),
2926
+ heartbeats: z18.number().int().nonnegative(),
2927
+ enginePhaseEvents: z18.number().int().nonnegative(),
2682
2928
  /**
2683
2929
  * `engine_phase === 'generating'` transitions — roughly one per completion
2684
2930
  * request the engine served (the slot-launch granularity stall logic and
2685
2931
  * the eval chatter threshold were calibrated against).
2686
2932
  */
2687
- generationSpurts: z16.number().int().nonnegative(),
2688
- toolCalls: z16.number().int().nonnegative(),
2689
- toolArgChars: z16.number().int().nonnegative(),
2690
- fileMutations: z16.number().int().nonnegative(),
2691
- gpuEvents: z16.number().int().nonnegative(),
2933
+ generationSpurts: z18.number().int().nonnegative(),
2934
+ toolCalls: z18.number().int().nonnegative(),
2935
+ toolArgChars: z18.number().int().nonnegative(),
2936
+ fileMutations: z18.number().int().nonnegative(),
2937
+ gpuEvents: z18.number().int().nonnegative(),
2692
2938
  gpuTaskActive: SessionGpuTaskSchema.nullable(),
2693
2939
  /** Epoch ms of the last streamed signal (delta / pulse / heartbeat / phase). */
2694
- lastStreamActivityAt: z16.number().nullable(),
2695
- lastToolActivityAt: z16.number().nullable(),
2696
- lastMutationAt: z16.number().nullable(),
2697
- lastGpuActivityAt: z16.number().nullable(),
2940
+ lastStreamActivityAt: z18.number().nullable(),
2941
+ lastToolActivityAt: z18.number().nullable(),
2942
+ lastMutationAt: z18.number().nullable(),
2943
+ lastGpuActivityAt: z18.number().nullable(),
2698
2944
  /** Max of all activity timestamps — "when did ANY progress signal last fire". */
2699
- lastProgressAt: z16.number().nullable(),
2945
+ lastProgressAt: z18.number().nullable(),
2700
2946
  /** Counters scoped to the currently-running turn; null between turns. */
2701
2947
  currentTurn: SessionTurnTelemetrySchema.nullable()
2702
2948
  });
2703
- var SessionTelemetryListResponseSchema = z16.object({
2949
+ var SessionTelemetryListResponseSchema = z18.object({
2704
2950
  /** Bumped when counter semantics change; consumers gate on it. */
2705
- version: z16.literal(1),
2706
- capturedAt: z16.number(),
2707
- sessions: z16.array(SessionTelemetrySchema)
2951
+ version: z18.literal(1),
2952
+ capturedAt: z18.number(),
2953
+ sessions: z18.array(SessionTelemetrySchema)
2708
2954
  });
2709
2955
 
2710
2956
  // src/schemas/gezel.ts
2711
- var ProviderNameSchema = z17.enum([
2957
+ var ProviderNameSchema = z19.enum([
2712
2958
  "copilot",
2713
2959
  "openai",
2714
2960
  "anthropic",
@@ -2730,27 +2976,27 @@ var ProviderNameSchema = z17.enum([
2730
2976
  // forward-pass is remoted — so `remote` is NOT a local provider.
2731
2977
  "remote"
2732
2978
  ]);
2733
- var GezelGenderSchema = z17.enum(["male", "female", "non-binary"]);
2734
- var FixedFunctionConfigSchema = z17.object({
2979
+ var GezelGenderSchema = z19.enum(["male", "female", "non-binary"]);
2980
+ var FixedFunctionConfigSchema = z19.object({
2735
2981
  /** MCP tool name to forward to (e.g. `'generate_image'`). */
2736
- tool: z17.string().min(1),
2982
+ tool: z19.string().min(1),
2737
2983
  /** Argument key on the tool that receives the user's message text. */
2738
- promptKey: z17.string().min(1).default("prompt"),
2984
+ promptKey: z19.string().min(1).default("prompt"),
2739
2985
  /** Defaults merged into every call; user text on `promptKey` always wins. */
2740
- defaults: z17.record(z17.string(), z17.unknown()).optional()
2986
+ defaults: z19.record(z19.string(), z19.unknown()).optional()
2741
2987
  });
2742
- var GezelTraitSchema = z17.object({
2743
- id: z17.string(),
2988
+ var GezelTraitSchema = z19.object({
2989
+ id: z19.string(),
2744
2990
  /** One imperative second-person sentence, rendered as a prompt bullet. */
2745
- text: z17.string().min(1).max(200),
2746
- adoptedAt: z17.string(),
2747
- source: z17.enum(["levelup", "manual"]).optional()
2991
+ text: z19.string().min(1).max(200),
2992
+ adoptedAt: z19.string(),
2993
+ source: z19.enum(["levelup", "manual"]).optional()
2748
2994
  });
2749
- var GezelFrontmatterSchema = z17.object({
2995
+ var GezelFrontmatterSchema = z19.object({
2750
2996
  id: EntityIdSchema.optional(),
2751
- name: z17.string(),
2752
- description: z17.string().optional(),
2753
- role: z17.string().optional(),
2997
+ name: z19.string(),
2998
+ description: z19.string().optional(),
2999
+ role: z19.string().optional(),
2754
3000
  /**
2755
3001
  * Kebab-case slug derived from `role` (or `gezel-N` when role is absent),
2756
3002
  * globally unique across the install. Collisions get `-2`, `-3`, …
@@ -2758,7 +3004,7 @@ var GezelFrontmatterSchema = z17.object({
2758
3004
  * identifier for @-mentions and as the sole rendered identifier when
2759
3005
  * `config.roleBasedNameOnlyMode` is enabled.
2760
3006
  */
2761
- roleBasedName: z17.string().optional(),
3007
+ roleBasedName: z19.string().optional(),
2762
3008
  /**
2763
3009
  * One of `male` / `female` / `non-binary`. Assigned at creation time
2764
3010
  * from the matching gendered first-name pool (with a small chance of
@@ -2767,9 +3013,9 @@ var GezelFrontmatterSchema = z17.object({
2767
3013
  * own prompt. Absent on legacy gezels, where references omit pronouns.
2768
3014
  */
2769
3015
  gender: GezelGenderSchema.optional(),
2770
- model: z17.string().optional(),
3016
+ model: z19.string().optional(),
2771
3017
  provider: ProviderNameSchema.optional(),
2772
- reasoningEffort: z17.string().optional(),
3018
+ reasoningEffort: z19.string().optional(),
2773
3019
  /**
2774
3020
  * Per-gezel sampling / reasoning / structured-output / tool-call overrides.
2775
3021
  * Sparse — only set fields override the catalog's recommended defaults.
@@ -2802,8 +3048,8 @@ var GezelFrontmatterSchema = z17.object({
2802
3048
  * low-temperature `thinking-precise` without locking the user out.
2803
3049
  */
2804
3050
  suggestedTuningProfile: TuningProfileIdSchema.optional(),
2805
- tools: z17.array(z17.string()).optional(),
2806
- tags: z17.array(z17.string()).optional(),
3051
+ tools: z19.array(z19.string()).optional(),
3052
+ tags: z19.array(z19.string()).optional(),
2807
3053
  /**
2808
3054
  * When set, switches this gezel into "fixed-function" mode: chat
2809
3055
  * messages bypass the LLM and forward to the named MCP tool. See
@@ -2813,14 +3059,20 @@ var GezelFrontmatterSchema = z17.object({
2813
3059
  */
2814
3060
  fixedFunction: FixedFunctionConfigSchema.optional(),
2815
3061
  /** Ollama-only: override the context window (tokens) for this gezel. */
2816
- numCtx: z17.number().int().positive().optional(),
3062
+ numCtx: z19.number().int().positive().optional(),
2817
3063
  /** When false, suppresses auto-recall on session start for this gezel. */
2818
- autoRecall: z17.boolean().optional(),
3064
+ autoRecall: z19.boolean().optional(),
3065
+ /**
3066
+ * Per-gezel proactive indexed-context policy. Supersedes `autoRecall` when
3067
+ * present; absent inherits the install default. The generic `search` tool is
3068
+ * still available in `off` mode.
3069
+ */
3070
+ retrieval: RetrievalPolicySchema.optional(),
2819
3071
  /**
2820
3072
  * Chat bubble font id (one of `GEZEL_CHAT_FONTS[*].id`). When unset or
2821
3073
  * unrecognized, chat bubbles inherit the app default (Hanken Grotesk).
2822
3074
  */
2823
- font: z17.string().optional(),
3075
+ font: z19.string().optional(),
2824
3076
  /**
2825
3077
  * Kokoro TTS voice id (one of `KOKORO_VOICES[*].id`, e.g. `af_heart`,
2826
3078
  * `bm_george`). Drives spoken audio rendering — `synthesize_speech`
@@ -2829,7 +3081,7 @@ var GezelFrontmatterSchema = z17.object({
2829
3081
  * dialog. Absent on legacy gezels — synthesize falls back to the
2830
3082
  * default voice (`af_heart`) when missing.
2831
3083
  */
2832
- voice: z17.string().optional(),
3084
+ voice: z19.string().optional(),
2833
3085
  /**
2834
3086
  * Provenance: the id of the gilde catalog template this gezel was
2835
3087
  * created from, if any. Written by exact-template or about-omitted
@@ -2837,7 +3089,7 @@ var GezelFrontmatterSchema = z17.object({
2837
3089
  * Absent on bespoke-generated or hand-authored gezels. The UI uses
2838
3090
  * this to offer "reset to original template" on the about editor.
2839
3091
  */
2840
- templateId: z17.string().optional(),
3092
+ templateId: z19.string().optional(),
2841
3093
  /**
2842
3094
  * Provenance: the semver of the template version installed at create
2843
3095
  * time. Paired with `templateId`. Absent on gezels created before this
@@ -2845,7 +3097,7 @@ var GezelFrontmatterSchema = z17.object({
2845
3097
  * source version" and offers a refresh to current latest without
2846
3098
  * comparing.
2847
3099
  */
2848
- templateVersion: z17.string().optional(),
3100
+ templateVersion: z19.string().optional(),
2849
3101
  /**
2850
3102
  * Copilot-only: when true, deny the Copilot CLI's built-in tools
2851
3103
  * (bash, web_fetch, view, str_replace_editor, read_file, write_file,
@@ -2854,7 +3106,7 @@ var GezelFrontmatterSchema = z17.object({
2854
3106
  * itself defaults to the sandboxed MCP surface.
2855
3107
  * Provider other than copilot: ignored.
2856
3108
  */
2857
- sandboxCopilot: z17.boolean().optional(),
3109
+ sandboxCopilot: z19.boolean().optional(),
2858
3110
  /**
2859
3111
  * `anthropic-cli`-only: per-gezel override for the Claude CLI permission
2860
3112
  * mode. Forwarded as `--permission-mode <value>` to each `claude` invocation.
@@ -2880,7 +3132,7 @@ var GezelFrontmatterSchema = z17.object({
2880
3132
  * abstract sigil instead of the parametric poppetje. Default (absent /
2881
3133
  * false) renders the poppetje everywhere. Toggled from Gezel Detail.
2882
3134
  */
2883
- iconOverride: z17.boolean().optional(),
3135
+ iconOverride: z19.boolean().optional(),
2884
3136
  /**
2885
3137
  * Standing behavior traits, adopted through the growth system (or
2886
3138
  * hand-authored). Rendered as their own `### Traits` block in the
@@ -2889,7 +3141,7 @@ var GezelFrontmatterSchema = z17.object({
2889
3141
  * The frontmatter list is AUTHORITATIVE for what's active — growth.json
2890
3142
  * keeps the evidence-bearing adoption log.
2891
3143
  */
2892
- traits: z17.array(GezelTraitSchema).max(8).optional(),
3144
+ traits: z19.array(GezelTraitSchema).max(8).optional(),
2893
3145
  /**
2894
3146
  * Overrides `config.recognition.mode` for this gezel. A gezel whose job is
2895
3147
  * reading screenshots sets `always`; everyone else inherits.
@@ -2899,46 +3151,48 @@ var GezelFrontmatterSchema = z17.object({
2899
3151
  * support burden. Native vision is a property of the model *install*, not of
2900
3152
  * the gezel, so it has no frontmatter counterpart.
2901
3153
  */
2902
- recognition: z17.enum(["auto", "always", "off"]).optional()
3154
+ recognition: z19.enum(["auto", "always", "off"]).optional()
2903
3155
  });
2904
- var GezelSectionSchema = z17.object({
2905
- heading: z17.string(),
2906
- template: z17.string().optional(),
2907
- params: z17.record(z17.string(), z17.string()).optional(),
2908
- body: z17.string()
3156
+ var GezelSectionSchema = z19.object({
3157
+ heading: z19.string(),
3158
+ template: z19.string().optional(),
3159
+ params: z19.record(z19.string(), z19.string()).optional(),
3160
+ body: z19.string()
2909
3161
  });
2910
- var ParsedGezelSchema = z17.object({
3162
+ var ParsedGezelSchema = z19.object({
2911
3163
  frontmatter: GezelFrontmatterSchema,
2912
- sections: z17.array(GezelSectionSchema),
2913
- source: z17.string()
3164
+ sections: z19.array(GezelSectionSchema),
3165
+ source: z19.string()
2914
3166
  });
2915
- var GezelSummarySchema = z17.object({
3167
+ var GezelSummarySchema = z19.object({
2916
3168
  id: EntityIdSchema,
2917
- name: z17.string(),
2918
- description: z17.string().optional(),
2919
- role: z17.string().optional(),
3169
+ name: z19.string(),
3170
+ description: z19.string().optional(),
3171
+ role: z19.string().optional(),
2920
3172
  /** Mirrors `GezelFrontmatter.roleBasedName`. */
2921
- roleBasedName: z17.string().optional(),
3173
+ roleBasedName: z19.string().optional(),
2922
3174
  /** Mirrors `GezelFrontmatter.gender`. */
2923
3175
  gender: GezelGenderSchema.optional(),
2924
- model: z17.string().optional(),
3176
+ model: z19.string().optional(),
2925
3177
  provider: ProviderNameSchema.optional(),
2926
- reasoningEffort: z17.string().optional(),
3178
+ reasoningEffort: z19.string().optional(),
2927
3179
  /** Mirrors `GezelFrontmatter.tuningProfile`. */
2928
3180
  tuningProfile: TuningProfileIdSchema.optional(),
2929
3181
  /** Mirrors `GezelFrontmatter.suggestedTuningProfile`. */
2930
3182
  suggestedTuningProfile: TuningProfileIdSchema.optional(),
2931
- numCtx: z17.number().int().positive().optional(),
2932
- autoRecall: z17.boolean().optional(),
2933
- font: z17.string().optional(),
3183
+ numCtx: z19.number().int().positive().optional(),
3184
+ autoRecall: z19.boolean().optional(),
3185
+ /** Mirrors `GezelFrontmatter.retrieval`. */
3186
+ retrieval: RetrievalPolicySchema.optional(),
3187
+ font: z19.string().optional(),
2934
3188
  /** Mirrors `GezelFrontmatter.voice` — Kokoro TTS voice id. */
2935
- voice: z17.string().optional(),
3189
+ voice: z19.string().optional(),
2936
3190
  /** Mirrors `GezelFrontmatter.templateId` when the gezel came from a gilde template. */
2937
- templateId: z17.string().optional(),
3191
+ templateId: z19.string().optional(),
2938
3192
  /** Mirrors `GezelFrontmatter.templateVersion`. */
2939
- templateVersion: z17.string().optional(),
3193
+ templateVersion: z19.string().optional(),
2940
3194
  /** Mirrors `GezelFrontmatter.sandboxCopilot`. */
2941
- sandboxCopilot: z17.boolean().optional(),
3195
+ sandboxCopilot: z19.boolean().optional(),
2942
3196
  /** Mirrors `GezelFrontmatter.claudePermissionMode`. */
2943
3197
  claudePermissionMode: ClaudePermissionModeSchema.optional(),
2944
3198
  /** Mirrors `GezelFrontmatter.codexPermissionMode`. */
@@ -2951,7 +3205,7 @@ var GezelSummarySchema = z17.object({
2951
3205
  * affordance.
2952
3206
  */
2953
3207
  fixedFunction: FixedFunctionConfigSchema.optional(),
2954
- icon: z17.string().optional(),
3208
+ icon: z19.string().optional(),
2955
3209
  /**
2956
3210
  * The resolved poppetje character data for this gezel. Inlined on
2957
3211
  * every list/detail response so the UI can render the parametric SVG
@@ -2961,9 +3215,9 @@ var GezelSummarySchema = z17.object({
2961
3215
  */
2962
3216
  poppetje: PoppetjeSchema.optional(),
2963
3217
  /** Mirrors `GezelFrontmatter.iconOverride`. */
2964
- iconOverride: z17.boolean().optional(),
3218
+ iconOverride: z19.boolean().optional(),
2965
3219
  /** Mirrors `GezelFrontmatter.recognition`. */
2966
- recognition: z17.enum(["auto", "always", "off"]).optional(),
3220
+ recognition: z19.enum(["auto", "always", "off"]).optional(),
2967
3221
  /**
2968
3222
  * Where this gezel lives. `global` (the default when absent — back-compat
2969
3223
  * with every gezel on disk before this field existed) is the install-wide
@@ -2973,15 +3227,15 @@ var GezelSummarySchema = z17.object({
2973
3227
  * badges project-scoped gezels and the roster only surfaces them inside
2974
3228
  * their own project.
2975
3229
  */
2976
- scope: z17.enum(["global", "project"]).optional(),
3230
+ scope: z19.enum(["global", "project"]).optional(),
2977
3231
  /**
2978
3232
  * Filesystem ownership boundary, distinct from `scope` above. Shared gezel
2979
3233
  * identity lives in the installer-managed machine root; chats, memories,
2980
3234
  * growth, credentials, and installed toolsets remain in the user home.
2981
3235
  */
2982
- storageScope: z17.enum(["user", "machine-shared"]).optional(),
3236
+ storageScope: z19.enum(["user", "machine-shared"]).optional(),
2983
3237
  /** Mirrors `GezelFrontmatter.traits`. */
2984
- traits: z17.array(GezelTraitSchema).optional(),
3238
+ traits: z19.array(GezelTraitSchema).optional(),
2985
3239
  /**
2986
3240
  * Lightweight growth summary (level + pending level-up flag),
2987
3241
  * hydrated from growth.json and inlined on list/detail responses —
@@ -2989,11 +3243,11 @@ var GezelSummarySchema = z17.object({
2989
3243
  * without N+1 follow-up requests.
2990
3244
  */
2991
3245
  growth: GezelGrowthSummarySchema.optional(),
2992
- updatedAt: z17.string()
3246
+ updatedAt: z19.string()
2993
3247
  });
2994
3248
  var GezelDetailSchema = GezelSummarySchema.extend({
2995
3249
  parsed: ParsedGezelSchema,
2996
- about: z17.string(),
3250
+ about: z19.string(),
2997
3251
  /**
2998
3252
  * Optional contents of the per-gezel `tools.md` file. When present
2999
3253
  * (non-null), fully replaces the auto-injected `## Tools available
@@ -3003,43 +3257,95 @@ var GezelDetailSchema = GezelSummarySchema.extend({
3003
3257
  * default) means no override file exists and the runtime renders
3004
3258
  * the auto-block from the live MCP bridge.
3005
3259
  */
3006
- toolsMd: z17.string().nullable().default(null)
3260
+ toolsMd: z19.string().nullable().default(null)
3007
3261
  });
3008
- var ToolCallImageSchema = z17.object({
3262
+ var ToolCallImageSchema = z19.object({
3009
3263
  /** Path relative to the project's artifacts/ root (e.g. `sessions/2026-04-19_143015_snake-test/tool-3-img-0.png`). */
3010
- path: z17.string(),
3264
+ path: z19.string(),
3011
3265
  /** MIME type of the image, used by the UI to set the right `<img>` src URL. */
3012
- mimeType: z17.string()
3266
+ mimeType: z19.string()
3013
3267
  });
3014
- var ToolCallAudioSchema = z17.object({
3268
+ var ToolCallAudioSchema = z19.object({
3015
3269
  /** Path relative to the project's artifacts/ root. */
3016
- path: z17.string(),
3270
+ path: z19.string(),
3017
3271
  /** MIME type, e.g. `audio/wav`. */
3018
- mimeType: z17.string(),
3272
+ mimeType: z19.string(),
3019
3273
  /** Duration in seconds when known — used by the UI to show length without preloading the blob. */
3020
- durationSeconds: z17.number().optional(),
3274
+ durationSeconds: z19.number().optional(),
3021
3275
  /** Voice id used to produce this audio (TTS only). */
3022
- voice: z17.string().optional()
3276
+ voice: z19.string().optional()
3023
3277
  });
3024
- var ToolCallVideoSchema = z17.object({
3278
+ var ToolCallVideoSchema = z19.object({
3025
3279
  /** Path relative to the project's artifacts/ root (e.g. `generated/video-123.mp4`). */
3026
- path: z17.string(),
3280
+ path: z19.string(),
3027
3281
  /** MIME type, e.g. `video/mp4`. */
3028
- mimeType: z17.string(),
3282
+ mimeType: z19.string(),
3029
3283
  /** Optional poster-frame artifact path for the `<video poster>` attribute. */
3030
- posterPath: z17.string().optional()
3284
+ posterPath: z19.string().optional()
3285
+ });
3286
+ var ToolCardStepSchema = z19.object({
3287
+ id: z19.string(),
3288
+ name: z19.string(),
3289
+ status: z19.enum(["done", "active", "pending"])
3031
3290
  });
3032
- var ChatMessageToolCallSchema = z17.object({
3033
- name: z17.string(),
3034
- durationMs: z17.number(),
3035
- success: z17.boolean(),
3036
- errorMessage: z17.string().optional(),
3291
+ var CraftbookStartCardSchema = z19.object({
3292
+ kind: z19.literal("craftbook-start"),
3293
+ craftbookId: z19.string(),
3294
+ craftbookName: z19.string(),
3295
+ /** Task ref `projectId/num`. */
3296
+ taskRef: z19.string(),
3297
+ /** The TASK's project — may differ from the session's when invoked cross-project. */
3298
+ projectId: z19.string(),
3299
+ /** Task status at event time. */
3300
+ status: z19.string(),
3301
+ activeStepId: z19.string().optional(),
3302
+ steps: z19.array(ToolCardStepSchema),
3303
+ /** True when the call idempotently returned an already-running task. */
3304
+ reused: z19.boolean().optional(),
3305
+ /**
3306
+ * The craftbook declares it works better with the External services
3307
+ * capability. The UI nudges (with the optional author rationale) only
3308
+ * while the resolved security policy has it disabled.
3309
+ */
3310
+ recommendsExternalServices: z19.object({ reason: z19.string().optional() }).optional()
3311
+ });
3312
+ var TaskStepAdvanceCardSchema = z19.object({
3313
+ kind: z19.literal("task-step-advance"),
3314
+ craftbookId: z19.string(),
3315
+ craftbookName: z19.string(),
3316
+ taskRef: z19.string(),
3317
+ projectId: z19.string(),
3318
+ status: z19.string(),
3319
+ completedStepId: z19.string(),
3320
+ completedStepName: z19.string().optional(),
3321
+ /** Absent when the advance took the task terminal (complete/canceled). */
3322
+ activeStepId: z19.string().optional(),
3323
+ activeStepName: z19.string().optional(),
3324
+ steps: z19.array(ToolCardStepSchema)
3325
+ });
3326
+ var ToolCallCardSchema = z19.discriminatedUnion("kind", [
3327
+ CraftbookStartCardSchema,
3328
+ TaskStepAdvanceCardSchema
3329
+ ]);
3330
+ var ChatMessageToolCallSchema = z19.object({
3331
+ name: z19.string(),
3332
+ /**
3333
+ * ISO timestamp of the call's START. Optional: absent on every message
3334
+ * persisted before this field existed, so readers must not assume it.
3335
+ * End time derives as `at + durationMs`. This is what gives replay
3336
+ * (run recordings, the eval movie pipeline) intra-turn ordering with
3337
+ * absolute time — array order alone cannot place calls on a timeline.
3338
+ */
3339
+ at: z19.string().optional(),
3340
+ durationMs: z19.number(),
3341
+ success: z19.boolean(),
3342
+ errorMessage: z19.string().optional(),
3037
3343
  /** File path the tool touched, for the References pane. */
3038
- path: z17.string().optional(),
3344
+ path: z19.string().optional(),
3039
3345
  /** Ordered file paths touched by a batched filesystem tool. */
3040
- paths: z17.array(z17.string()).optional(),
3346
+ paths: z19.array(z19.string()).optional(),
3041
3347
  /** Compact, human-readable one-liner ("→ Freja: update the game loop · file: workspace/index.html"). */
3042
- argsSummary: z17.string().optional(),
3348
+ argsSummary: z19.string().optional(),
3043
3349
  /**
3044
3350
  * The tool call's FULL arguments, rendered as readable text (field by
3045
3351
  * field, bulky values shown in full — not truncated like
@@ -3050,54 +3356,95 @@ var ChatMessageToolCallSchema = z17.object({
3050
3356
  * arguments are not a secret vector in this codebase (secrets live in
3051
3357
  * the toolset-config path), so this is not separately redacted.
3052
3358
  */
3053
- argsFull: z17.string().optional(),
3359
+ argsFull: z19.string().optional(),
3054
3360
  /** Short full response, or a bounded beginning/end summary for a long response. */
3055
- resultText: z17.string().optional(),
3361
+ resultText: z19.string().optional(),
3056
3362
  /** True when `resultText` is a bounded summary rather than the complete response. */
3057
- resultTruncated: z17.boolean().optional(),
3363
+ resultTruncated: z19.boolean().optional(),
3058
3364
  /** Image artifacts the tool returned (e.g. browser_snapshot screenshots). */
3059
- images: z17.array(ToolCallImageSchema).optional(),
3365
+ images: z19.array(ToolCallImageSchema).optional(),
3060
3366
  /** Audio artifacts the tool returned (e.g. synthesize_speech WAV). */
3061
- audios: z17.array(ToolCallAudioSchema).optional(),
3367
+ audios: z19.array(ToolCallAudioSchema).optional(),
3062
3368
  /** Video artifacts the tool returned (e.g. generate_video mp4). */
3063
- videos: z17.array(ToolCallVideoSchema).optional(),
3369
+ videos: z19.array(ToolCallVideoSchema).optional(),
3064
3370
  /**
3065
3371
  * Unified diff describing the change a surgical-edit tool made
3066
3372
  * (`replace_in_file`, `apply_patch`, `insert_at_marker`). Used by the UI
3067
3373
  * to render an inline diff under the tool-call row. Capped at ~100KB
3068
3374
  * server-side; larger diffs are truncated with a marker line.
3069
3375
  */
3070
- diff: z17.string().optional(),
3071
- addedLines: z17.number().int().nonnegative().optional(),
3072
- removedLines: z17.number().int().nonnegative().optional()
3376
+ diff: z19.string().optional(),
3377
+ addedLines: z19.number().int().nonnegative().optional(),
3378
+ removedLines: z19.number().int().nonnegative().optional(),
3379
+ /** Rich inline card payload for tools with special renderings — see ToolCallCardSchema. */
3380
+ card: ToolCallCardSchema.optional(),
3381
+ /**
3382
+ * Offset into the turn's `ChatMessage.reasoning` string marking where
3383
+ * this call fired — the same trick `intents[].afterChars` plays on
3384
+ * `content`. Lets the collapsed Thinking expander splice a small
3385
+ * marker into the trace at the spot the model stopped deliberating
3386
+ * and acted, so an expanded trace reads in causal order instead of as
3387
+ * one undifferentiated block above an unrelated tool list.
3388
+ *
3389
+ * Sourced from the PROVIDER's running reasoning length
3390
+ * (`LLMSession.getCurrentTurnReasoningLength`), never from a
3391
+ * manager-side count of `reasoning_delta` events: the persisted trace
3392
+ * is whatever `getLastTurnReasoning()` returns, which several local
3393
+ * providers build by extracting `<think>` blocks per tool-loop
3394
+ * iteration rather than from the delta stream. An offset into a
3395
+ * different string would drift silently.
3396
+ *
3397
+ * Absent for providers that don't implement the getter, and on every
3398
+ * message written before this field existed — the expander then
3399
+ * renders the plain trace it always did.
3400
+ */
3401
+ afterReasoningChars: z19.number().int().min(0).optional()
3073
3402
  });
3074
- var ChatSessionSourceSchema = z17.object({
3075
- kind: z17.literal("external"),
3403
+ var ChatSessionSourceSchema = z19.object({
3404
+ kind: z19.literal("external"),
3076
3405
  /** Stable integration id, e.g. `pi`. */
3077
- appId: z17.string().min(1),
3406
+ appId: z19.string().min(1),
3078
3407
  /** Human-facing application name, e.g. `Pi`. */
3079
- appName: z17.string().min(1),
3408
+ appName: z19.string().min(1),
3080
3409
  /** The external application's stable conversation/session identifier. */
3081
- externalConversationId: z17.string().min(1),
3410
+ externalConversationId: z19.string().min(1),
3082
3411
  /** External threads are ledger views; the owning app controls replies. */
3083
- readOnly: z17.literal(true),
3412
+ readOnly: z19.literal(true),
3084
3413
  /** Working-directory hint supplied by the external app, when available. */
3085
- workingDirectory: z17.string().optional(),
3414
+ workingDirectory: z19.string().optional(),
3086
3415
  /** Project id/name hint supplied by the external app, when available. */
3087
- projectHint: z17.string().optional()
3416
+ projectHint: z19.string().optional()
3088
3417
  });
3089
- var ReferencedFileKindSchema = z17.enum(["artifact", "workspace"]);
3090
- var ReferencedFileSchema = z17.object({
3418
+ var ReferencedFileKindSchema = z19.enum(["artifact", "workspace"]);
3419
+ var ReferencedFileSchema = z19.object({
3091
3420
  kind: ReferencedFileKindSchema,
3092
- path: z17.string()
3093
- });
3094
- var ChatMessageSchema = z17.object({
3095
- role: z17.enum(["user", "assistant"]),
3096
- content: z17.string(),
3097
- at: z17.string(),
3098
- from: z17.object({
3099
- gezelId: z17.string(),
3100
- gezelName: z17.string()
3421
+ path: z19.string()
3422
+ });
3423
+ var ContextCompactionSchema = z19.object({
3424
+ removedCount: z19.number().int().nonnegative(),
3425
+ contextWindow: z19.number().int().positive(),
3426
+ estimatedTokensBefore: z19.number().int().nonnegative(),
3427
+ compactionCount: z19.number().int().positive(),
3428
+ autoCompactRatio: z19.number().positive().max(1)
3429
+ });
3430
+ var ChatMessageSchema = z19.object({
3431
+ role: z19.enum(["user", "assistant"]),
3432
+ content: z19.string(),
3433
+ at: z19.string(),
3434
+ from: z19.object({
3435
+ gezelId: z19.string(),
3436
+ gezelName: z19.string(),
3437
+ /**
3438
+ * The SENDER's session id — the durable per-edge record of which
3439
+ * thread this message came from. `session.parentSession` only says
3440
+ * which session first opened the thread (stable containment);
3441
+ * this field is the ground truth for every individual delegation
3442
+ * edge, including later senders into an existing session. Optional:
3443
+ * absent on messages persisted before the field existed.
3444
+ */
3445
+ sessionId: z19.string().optional(),
3446
+ /** How the sender reached this session; mirrors SessionParent.kind. */
3447
+ kind: z19.enum(["delegation", "consultation", "task-entry", "task-handoff"]).optional()
3101
3448
  }).optional(),
3102
3449
  /**
3103
3450
  * Real files the assistant reply named in its body text — artifacts
@@ -3107,7 +3454,7 @@ var ChatMessageSchema = z17.object({
3107
3454
  * match a real file. Back-stops Copilot's tool-call blindspot and any
3108
3455
  * "AI wrote a file outside the MCP tools" path.
3109
3456
  */
3110
- referencedFiles: z17.array(ReferencedFileSchema).optional(),
3457
+ referencedFiles: z19.array(ReferencedFileSchema).optional(),
3111
3458
  /**
3112
3459
  * The artifact-only projection of {@link referencedFiles}, still
3113
3460
  * written so an older `@bendyline/gezel-cli` (or any out-of-tree
@@ -3117,7 +3464,7 @@ var ChatMessageSchema = z17.object({
3117
3464
  *
3118
3465
  * @deprecated superseded by `referencedFiles`
3119
3466
  */
3120
- referencedArtifacts: z17.array(z17.string()).optional(),
3467
+ referencedArtifacts: z19.array(z19.string()).optional(),
3121
3468
  /**
3122
3469
  * Task refs (`<projectId>/<num>`) the assistant reply mentioned. Same
3123
3470
  * shape as `referencedFiles` — populated on save, gated on the
@@ -3126,14 +3473,33 @@ var ChatMessageSchema = z17.object({
3126
3473
  * gezel-ux-roadmap/2" mention so the user can jump to it without
3127
3474
  * scrolling the body for the ref.
3128
3475
  */
3129
- referencedTasks: z17.array(z17.string()).optional(),
3476
+ referencedTasks: z19.array(z19.string()).optional(),
3477
+ /**
3478
+ * Indexed-context sources consulted for THIS user turn (proactive
3479
+ * retrieval). Citations only — source/path/line/score, never the retrieved
3480
+ * text (which lives solely in the provider prompt). Lets the UI render a
3481
+ * "consulted N sources" row so proactive RAG is visible diligence instead
3482
+ * of invisible machinery.
3483
+ */
3484
+ retrieval: z19.object({
3485
+ hits: z19.array(
3486
+ z19.object({
3487
+ source: RetrievalSourceSchema,
3488
+ projectId: z19.string().optional(),
3489
+ path: z19.string().optional(),
3490
+ line: z19.number().int().positive().optional(),
3491
+ lineEnd: z19.number().int().positive().optional(),
3492
+ score: z19.number()
3493
+ })
3494
+ )
3495
+ }).optional(),
3130
3496
  /**
3131
3497
  * Tool calls the assistant fired during this turn. Populated on the
3132
3498
  * final assistant message; the UI renders them as a collapsible
3133
3499
  * "thinking" expando above the reply body so the user can still see
3134
3500
  * what ran even after the live stream has closed.
3135
3501
  */
3136
- toolCalls: z17.array(ChatMessageToolCallSchema).optional(),
3502
+ toolCalls: z19.array(ChatMessageToolCallSchema).optional(),
3137
3503
  /**
3138
3504
  * Phase announcements the model emitted via Copilot's `report_intent`
3139
3505
  * tool during this turn. Each entry carries the intent label and an
@@ -3144,10 +3510,10 @@ var ChatMessageSchema = z17.object({
3144
3510
  * replay and history export are unaffected. Copilot-only; other
3145
3511
  * providers don't emit these.
3146
3512
  */
3147
- intents: z17.array(
3148
- z17.object({
3149
- label: z17.string(),
3150
- afterChars: z17.number().int().min(0)
3513
+ intents: z19.array(
3514
+ z19.object({
3515
+ label: z19.string(),
3516
+ afterChars: z19.number().int().min(0)
3151
3517
  })
3152
3518
  ).optional(),
3153
3519
  /**
@@ -3157,7 +3523,7 @@ var ChatMessageSchema = z17.object({
3157
3523
  * itself lives in the per-project questions file; this id is just
3158
3524
  * the foreign key.
3159
3525
  */
3160
- pendingQuestionId: z17.string().optional(),
3526
+ pendingQuestionId: z19.string().optional(),
3161
3527
  /**
3162
3528
  * Marks the message as a system-generated synthesis rather than a real
3163
3529
  * model turn.
@@ -3186,13 +3552,20 @@ var ChatMessageSchema = z17.object({
3186
3552
  * UI renders these as muted bubbles; the model sees them as normal
3187
3553
  * assistant turns (the role label is what matters to the API).
3188
3554
  */
3189
- synthetic: z17.enum([
3555
+ synthetic: z19.enum([
3190
3556
  "compaction-summary",
3191
3557
  "context-loop-halt",
3192
3558
  "turn-aborted",
3193
3559
  "growth-announcement",
3194
3560
  "keurmeester-notice"
3195
3561
  ]).optional(),
3562
+ /**
3563
+ * Present on a synthetic `compaction-summary` message. The UI renders this
3564
+ * as an explicit context-maintenance marker (including the effective token
3565
+ * window and number of messages summarized) rather than pretending it was
3566
+ * an ordinary assistant reply.
3567
+ */
3568
+ contextCompaction: ContextCompactionSchema.optional(),
3196
3569
  /**
3197
3570
  * Display flag: the model sees this message as normal history, but the
3198
3571
  * chat transcript UI never renders a bubble for it. Set on
@@ -3204,7 +3577,7 @@ var ChatMessageSchema = z17.object({
3204
3577
  * from loaded transcripts and the live-timeline handler skips its bubble
3205
3578
  * while still opening the assistant's streaming slot.
3206
3579
  */
3207
- hidden: z17.boolean().optional(),
3580
+ hidden: z19.boolean().optional(),
3208
3581
  /**
3209
3582
  * This user message was delivered from the session's mid-turn queue
3210
3583
  * as a nudge — typed while the previous turn was still streaming and
@@ -3212,7 +3585,14 @@ var ChatMessageSchema = z17.object({
3212
3585
  * Display-only marker: the model sees a normal user turn; the UI
3213
3586
  * renders a small "nudged" chip on the bubble.
3214
3587
  */
3215
- nudge: z17.boolean().optional(),
3588
+ nudge: z19.boolean().optional(),
3589
+ /**
3590
+ * The prompt draft (`artifacts/prompts/<draftId>/`) this user message was
3591
+ * sent from. Display-only: the model never sees it, and the draft may since
3592
+ * have been swept, so the UI must treat a dangling id as "no prompt to
3593
+ * open" rather than an error.
3594
+ */
3595
+ draftId: z19.string().optional(),
3216
3596
  /**
3217
3597
  * The machinery — not the human — authored this `role: 'user'` message.
3218
3598
  * Task dispatch seeds, step handoffs, and project-page reaction seeds
@@ -3231,7 +3611,7 @@ var ChatMessageSchema = z17.object({
3231
3611
  * widen it without a second field. Messages written before this field
3232
3612
  * existed are inferred at read time — see `Store.listTimeline`.
3233
3613
  */
3234
- origin: z17.enum(["system"]).optional(),
3614
+ origin: z19.enum(["system"]).optional(),
3235
3615
  /**
3236
3616
  * Persistent warnings attached to this assistant turn — fabricated
3237
3617
  * tool-use detection, degraded provider state, etc. The streaming
@@ -3241,7 +3621,7 @@ var ChatMessageSchema = z17.object({
3241
3621
  * reload. Populated by the chat manager just before `events.publish`
3242
3622
  * fires the `complete` event.
3243
3623
  */
3244
- warnings: z17.array(z17.string()).optional(),
3624
+ warnings: z19.array(z19.string()).optional(),
3245
3625
  /**
3246
3626
  * Chain-of-thought captured during this turn. Local providers
3247
3627
  * (ollama, llama-cpp, mlx, ds4) extract `<think>…</think>` /
@@ -3254,14 +3634,14 @@ var ChatMessageSchema = z17.object({
3254
3634
  * Responses hides reasoning server-side and leaves this unset.
3255
3635
  * Empty / whitespace-only captures are dropped.
3256
3636
  */
3257
- reasoning: z17.string().optional(),
3637
+ reasoning: z19.string().optional(),
3258
3638
  /**
3259
3639
  * Observed wall-clock span of the streamed private-reasoning trace,
3260
3640
  * measured from the first `reasoning_delta` to the last. Optional
3261
3641
  * because older messages and providers that only expose reasoning at
3262
3642
  * commit time have no trustworthy phase timing.
3263
3643
  */
3264
- reasoningDurationMs: z17.number().int().nonnegative().optional(),
3644
+ reasoningDurationMs: z19.number().int().nonnegative().optional(),
3265
3645
  /**
3266
3646
  * Tool-call bodies the model emitted that the salvage layer
3267
3647
  * couldn't parse — the literal text from `<|tool_call|>` markers
@@ -3276,10 +3656,10 @@ var ChatMessageSchema = z17.object({
3276
3656
  * hundred chars per body in the populator so a long fabricated body
3277
3657
  * doesn't blow up the session file.
3278
3658
  */
3279
- attemptedToolCalls: z17.array(
3280
- z17.object({
3281
- body: z17.string(),
3282
- reason: z17.string().optional()
3659
+ attemptedToolCalls: z19.array(
3660
+ z19.object({
3661
+ body: z19.string(),
3662
+ reason: z19.string().optional()
3283
3663
  })
3284
3664
  ).optional(),
3285
3665
  /**
@@ -3295,28 +3675,28 @@ var ChatMessageSchema = z17.object({
3295
3675
  * daemon restart, a provider reset, or a context-pressure rebuild — leaving
3296
3676
  * the model replaying a bare `![](attachments/9f3.png)`.
3297
3677
  */
3298
- recognizedImages: z17.array(MessageImageDigestSchema).optional()
3678
+ recognizedImages: z19.array(MessageImageDigestSchema).optional()
3299
3679
  });
3300
- var ChatTurnErrorDetailSchema = z17.object({
3301
- code: z17.string().max(64).optional(),
3680
+ var ChatTurnErrorDetailSchema = z19.object({
3681
+ code: z19.string().max(64).optional(),
3302
3682
  /** Component that failed — a provider name (`llama-cpp`) or a subsystem. */
3303
- engine: z17.string().max(64).optional(),
3683
+ engine: z19.string().max(64).optional(),
3304
3684
  /** Correlation key, also written into the engine's own incident log. */
3305
- incidentId: z17.string().max(64).optional(),
3685
+ incidentId: z19.string().max(64).optional(),
3306
3686
  /** Native crash class from the exit snapshot, e.g. `cuda-out-of-memory`. */
3307
- panicKind: z17.string().max(64).optional(),
3308
- exitCode: z17.number().int().nullable().optional(),
3309
- signal: z17.string().max(32).nullable().optional(),
3687
+ panicKind: z19.string().max(64).optional(),
3688
+ exitCode: z19.number().int().nullable().optional(),
3689
+ signal: z19.string().max(32).nullable().optional(),
3310
3690
  /**
3311
3691
  * Request-independent launch facts copied from the crash snapshot, which
3312
3692
  * is contractually free of prompts, tool arguments, and secrets. Bounded
3313
3693
  * by the extractor. A machine profile cannot reconstruct which model at
3314
3694
  * which context size with which KV type crashed; this can.
3315
3695
  */
3316
- diagnostics: z17.record(z17.string(), z17.union([z17.string(), z17.number(), z17.boolean()])).optional()
3696
+ diagnostics: z19.record(z19.string(), z19.union([z19.string(), z19.number(), z19.boolean()])).optional()
3317
3697
  });
3318
- var ChatEventSchema = z17.discriminatedUnion("type", [
3319
- z17.object({ type: z17.literal("delta"), content: z17.string() }),
3698
+ var ChatEventSchema = z19.discriminatedUnion("type", [
3699
+ z19.object({ type: z19.literal("delta"), content: z19.string() }),
3320
3700
  /**
3321
3701
  * Live private-reasoning tokens (ds4's think phase), streamed on their
3322
3702
  * own channel so they never mix into the visible `delta` stream, the
@@ -3324,14 +3704,14 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3324
3704
  * renders them as a distinct "thinking" block that collapses into the
3325
3705
  * committed message's reasoning expander once `complete` lands.
3326
3706
  */
3327
- z17.object({ type: z17.literal("reasoning_delta"), content: z17.string() }),
3328
- z17.object({ type: z17.literal("complete"), message: ChatMessageSchema }),
3707
+ z19.object({ type: z19.literal("reasoning_delta"), content: z19.string() }),
3708
+ z19.object({ type: z19.literal("complete"), message: ChatMessageSchema }),
3329
3709
  /**
3330
3710
  * The user submitted a message, but a cold provider session is still being
3331
3711
  * created. Project timelines render this as a temporary pending row until
3332
3712
  * the durable `user_message` or a terminal `error` arrives.
3333
3713
  */
3334
- z17.object({ type: z17.literal("user_message_pending"), preview: z17.string() }),
3714
+ z19.object({ type: z19.literal("user_message_pending"), preview: z19.string() }),
3335
3715
  /**
3336
3716
  * Emitted right after the user's message is appended to the session
3337
3717
  * record. The legacy session-scoped UI inserted user messages locally
@@ -3339,27 +3719,29 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3339
3719
  * envelope streams need it so the interleaved timeline can render the
3340
3720
  * user's bubble immediately, before any assistant deltas.
3341
3721
  */
3342
- z17.object({ type: z17.literal("user_message"), message: ChatMessageSchema }),
3722
+ z19.object({ type: z19.literal("user_message"), message: ChatMessageSchema }),
3343
3723
  /**
3344
3724
  * Emitted when the assistant invokes an MCP tool (OpenAI + Mock paths
3345
3725
  * only — Copilot runs tools inside its subprocess, invisible to us).
3346
3726
  * The UI surfaces these as "thinking" breadcrumbs.
3347
3727
  */
3348
- z17.object({
3349
- type: z17.literal("tool"),
3350
- name: z17.string(),
3351
- durationMs: z17.number(),
3352
- success: z17.boolean(),
3353
- errorMessage: z17.string().optional(),
3728
+ z19.object({
3729
+ type: z19.literal("tool"),
3730
+ name: z19.string(),
3731
+ /** ISO start-of-call timestamp; see ChatMessageToolCallSchema.at. */
3732
+ at: z19.string().optional(),
3733
+ durationMs: z19.number(),
3734
+ success: z19.boolean(),
3735
+ errorMessage: z19.string().optional(),
3354
3736
  /**
3355
3737
  * File path the tool touched (if any). Set for tools that take a `path`
3356
3738
  * argument: readFile, writeFile, read_artifact, write_artifact,
3357
3739
  * read_document, write_document. Lets the UI build a References panel
3358
3740
  * without guessing.
3359
3741
  */
3360
- path: z17.string().optional(),
3742
+ path: z19.string().optional(),
3361
3743
  /** Ordered file paths touched by a batched filesystem tool. */
3362
- paths: z17.array(z17.string()).optional(),
3744
+ paths: z19.array(z19.string()).optional(),
3363
3745
  /**
3364
3746
  * Compact human-readable preview of the non-bulky arguments. Example:
3365
3747
  * `gezel: "Maya", message: "what's the status of..."`. Values are
@@ -3367,44 +3749,46 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3367
3749
  * UI to render a useful in-progress tool line instead of just the
3368
3750
  * tool name.
3369
3751
  */
3370
- argsSummary: z17.string().optional(),
3752
+ argsSummary: z19.string().optional(),
3371
3753
  /** Full, readable args for the expand + copy affordance. See the persisted `ChatMessageToolCall.argsFull`. */
3372
- argsFull: z17.string().optional(),
3754
+ argsFull: z19.string().optional(),
3373
3755
  /** Short full response, or a bounded beginning/end summary. */
3374
- resultText: z17.string().optional(),
3756
+ resultText: z19.string().optional(),
3375
3757
  /** True when `resultText` is a bounded summary rather than the complete response. */
3376
- resultTruncated: z17.boolean().optional(),
3758
+ resultTruncated: z19.boolean().optional(),
3377
3759
  /**
3378
3760
  * Image artifacts the tool returned (most commonly browser screenshots).
3379
3761
  * Paths are relative to the project's artifacts/ root and resolved
3380
3762
  * to URLs by the UI via the artifact-read endpoint.
3381
3763
  */
3382
- images: z17.array(ToolCallImageSchema).optional(),
3764
+ images: z19.array(ToolCallImageSchema).optional(),
3383
3765
  /**
3384
3766
  * Audio artifacts the tool returned (synthesize_speech narrations,
3385
3767
  * voice memos transcribed via transcribe_audio). Same artifact-path
3386
3768
  * resolution as `images`.
3387
3769
  */
3388
- audios: z17.array(ToolCallAudioSchema).optional(),
3770
+ audios: z19.array(ToolCallAudioSchema).optional(),
3389
3771
  /**
3390
3772
  * Video artifacts the tool returned (`generate_video`). Same
3391
3773
  * artifact-path resolution as `images`; rendered as a `<video>`
3392
3774
  * player in the chat row.
3393
3775
  */
3394
- videos: z17.array(ToolCallVideoSchema).optional(),
3776
+ videos: z19.array(ToolCallVideoSchema).optional(),
3395
3777
  /**
3396
3778
  * Unified diff describing the change a surgical-edit tool made
3397
3779
  * (`replace_in_file`, `apply_patch`, `insert_at_marker`). Streams to the
3398
3780
  * UI mid-turn so the chat bubble can render an inline diff under
3399
3781
  * the tool-call row even before the assistant message is finalized.
3400
3782
  */
3401
- diff: z17.string().optional(),
3402
- addedLines: z17.number().int().nonnegative().optional(),
3403
- removedLines: z17.number().int().nonnegative().optional()
3783
+ diff: z19.string().optional(),
3784
+ addedLines: z19.number().int().nonnegative().optional(),
3785
+ removedLines: z19.number().int().nonnegative().optional(),
3786
+ /** Rich inline card payload for tools with special renderings — see ToolCallCardSchema. */
3787
+ card: ToolCallCardSchema.optional()
3404
3788
  }),
3405
- z17.object({
3406
- type: z17.literal("error"),
3407
- error: z17.string(),
3789
+ z19.object({
3790
+ type: z19.literal("error"),
3791
+ error: z19.string(),
3408
3792
  // Not `detail` — three sibling variants in this union already use that
3409
3793
  // name for free-form progress prose, and one union with two meanings for
3410
3794
  // one key is a trap.
@@ -3415,8 +3799,8 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3415
3799
  * surface. This is terminal for the live UI, but is deliberately not an
3416
3800
  * error: it must not poison the session or render failure recovery UI.
3417
3801
  */
3418
- z17.object({ type: z17.literal("cancelled") }),
3419
- z17.object({ type: z17.literal("done") }),
3802
+ z19.object({ type: z19.literal("cancelled") }),
3803
+ z19.object({ type: z19.literal("done") }),
3420
3804
  /**
3421
3805
  * Emitted when a turn ends up waiting in the provider queue for more
3422
3806
  * than a brief grace period (~200ms). `aheadOf` is an approximate
@@ -3426,7 +3810,7 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3426
3810
  * emit this event — avoids flashing the indicator on the happy path
3427
3811
  * where the queue is empty.
3428
3812
  */
3429
- z17.object({ type: z17.literal("queued"), aheadOf: z17.number().int().min(0) }),
3813
+ z19.object({ type: z19.literal("queued"), aheadOf: z19.number().int().min(0) }),
3430
3814
  /**
3431
3815
  * Ollama-only: emitted for each bare framing chunk that arrives
3432
3816
  * on the wire without visible content / tool_calls — the
@@ -3436,7 +3820,7 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3436
3820
  * when the model isn't producing visible output. Reset on the
3437
3821
  * next real `delta`, `tool`, or `complete`.
3438
3822
  */
3439
- z17.object({ type: z17.literal("wire_pulse") }),
3823
+ z19.object({ type: z19.literal("wire_pulse") }),
3440
3824
  /**
3441
3825
  * Live tool-argument stream. Fired while the model is generating a
3442
3826
  * structured tool call — most visibly a multi-minute `write_file`
@@ -3448,7 +3832,7 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3448
3832
  * "working" block (same pattern as `reasoning_delta`) and drops the
3449
3833
  * block when the corresponding `tool` event lands.
3450
3834
  */
3451
- z17.object({ type: z17.literal("tool_args_delta"), name: z17.string(), content: z17.string() }),
3835
+ z19.object({ type: z19.literal("tool_args_delta"), name: z19.string(), content: z19.string() }),
3452
3836
  /**
3453
3837
  * Emitted when a provider tells us it's still doing work — even though
3454
3838
  * no visible text/tool event has arrived. Today this is wired from
@@ -3459,24 +3843,24 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3459
3843
  * Optional `label` carries a short phase hint ('thinking', 'tool',
3460
3844
  * etc.) that the streaming bubble can surface as a status line.
3461
3845
  */
3462
- z17.object({ type: z17.literal("heartbeat"), label: z17.string().optional() }),
3846
+ z19.object({ type: z19.literal("heartbeat"), label: z19.string().optional() }),
3463
3847
  /**
3464
3848
  * Provider-side warning surfaced mid-turn (e.g. Copilot rate-limit,
3465
3849
  * context pressure, degraded mode). The UI renders these inline on
3466
3850
  * the streaming bubble so the user sees them immediately instead of
3467
3851
  * only finding out when the turn completes or times out.
3468
3852
  */
3469
- z17.object({
3470
- type: z17.literal("warning"),
3471
- message: z17.string(),
3853
+ z19.object({
3854
+ type: z19.literal("warning"),
3855
+ message: z19.string(),
3472
3856
  /**
3473
3857
  * Optional in-app destination for a warning's inline action. Kept
3474
3858
  * deliberately narrow: warnings are still readable prose when an older
3475
3859
  * client ignores this additive field.
3476
3860
  */
3477
- action: z17.object({
3478
- kind: z17.literal("settings"),
3479
- section: z17.enum(["llamaCpp", "mlx", "ds4"])
3861
+ action: z19.object({
3862
+ kind: z19.literal("settings"),
3863
+ section: z19.enum(["llamaCpp", "mlx", "ds4"])
3480
3864
  }).optional()
3481
3865
  }),
3482
3866
  /**
@@ -3487,18 +3871,18 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3487
3871
  * offset on the final assistant message so completed bubbles render
3488
3872
  * the same segmentation on reload.
3489
3873
  */
3490
- z17.object({ type: z17.literal("intent"), label: z17.string() }),
3874
+ z19.object({ type: z19.literal("intent"), label: z19.string() }),
3491
3875
  /**
3492
3876
  * Emitted when a new message is enqueued on the per-session queue
3493
3877
  * because the session already has a turn in flight. The timeline
3494
3878
  * renders a "ghost bubble" under the session's streaming bubble
3495
3879
  * showing the queued text preview. Cleared via `queue_removed`.
3496
3880
  */
3497
- z17.object({
3498
- type: z17.literal("queue_enqueued"),
3499
- queueId: z17.string(),
3500
- preview: z17.string(),
3501
- enqueuedAt: z17.string(),
3881
+ z19.object({
3882
+ type: z19.literal("queue_enqueued"),
3883
+ queueId: z19.string(),
3884
+ preview: z19.string(),
3885
+ enqueuedAt: z19.string(),
3502
3886
  /**
3503
3887
  * The entry was queued as a mid-turn nudge — the ghost bubble labels
3504
3888
  * it "nudge" and contiguous nudges merge into one turn on drain.
@@ -3506,7 +3890,7 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3506
3890
  * every coalesce/edit); the edit affordance fetches it lazily via
3507
3891
  * `GET /api/sessions/:id/queue`.
3508
3892
  */
3509
- nudge: z17.boolean().optional()
3893
+ nudge: z19.boolean().optional()
3510
3894
  }),
3511
3895
  /**
3512
3896
  * Emitted when a queued entry leaves the queue — either because
@@ -3515,22 +3899,39 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3515
3899
  * dropped without running (`reason: 'canceled'` via user action,
3516
3900
  * `reason: 'rejected'` via session archive / delete / shutdown).
3517
3901
  */
3518
- z17.object({
3519
- type: z17.literal("queue_removed"),
3520
- queueId: z17.string(),
3521
- reason: z17.enum(["started", "canceled", "rejected"])
3902
+ z19.object({
3903
+ type: z19.literal("queue_removed"),
3904
+ queueId: z19.string(),
3905
+ reason: z19.enum(["started", "canceled", "rejected"])
3906
+ }),
3907
+ /**
3908
+ * Effective context policy for a local or remote-local session. Emitted on
3909
+ * each turn so the live UI can show the model's token window immediately;
3910
+ * the same values are persisted on the session for reloads.
3911
+ */
3912
+ z19.object({
3913
+ type: z19.literal("context_window"),
3914
+ numCtx: z19.number().int().positive(),
3915
+ model: z19.string(),
3916
+ autoCompactRatio: z19.number().positive().max(1),
3917
+ /**
3918
+ * Estimated prompt size for the turn about to run, in the same
3919
+ * chars/4 units the compaction check itself uses. Absent on older
3920
+ * daemons, which published the window without the fill.
3921
+ */
3922
+ estimatedTokens: z19.number().int().nonnegative().optional()
3522
3923
  }),
3523
3924
  /**
3524
- * Local-provider context policy: emitted when accumulated conversation
3525
- * exceeds a safety fraction of the session's effective model context.
3526
- * The UI may suggest starting fresh because this event is never emitted
3527
- * for a first-turn standing system/tool prefix.
3925
+ * Local-provider context policy: emitted only when accumulated conversation
3926
+ * could not be compacted automatically. Normal pressure is handled without
3927
+ * a warning; this is the exceptional maintenance-failure path.
3528
3928
  */
3529
- z17.object({
3530
- type: z17.literal("context_warning"),
3531
- estimatedTokens: z17.number(),
3532
- numCtx: z17.number(),
3533
- model: z17.string()
3929
+ z19.object({
3930
+ type: z19.literal("context_warning"),
3931
+ estimatedTokens: z19.number(),
3932
+ numCtx: z19.number(),
3933
+ model: z19.string(),
3934
+ reason: z19.literal("compaction_failed").optional()
3534
3935
  }),
3535
3936
  /**
3536
3937
  * Local-provider context policy: emitted right after in-flight compaction collapses
@@ -3539,10 +3940,16 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3539
3940
  * for a "compacted" variant and refreshes the visible timeline (older
3540
3941
  * bubbles are now gone from disk).
3541
3942
  */
3542
- z17.object({
3543
- type: z17.literal("context_compacted"),
3544
- removedCount: z17.number().int().nonnegative(),
3545
- model: z17.string()
3943
+ z19.object({
3944
+ type: z19.literal("context_compacted"),
3945
+ removedCount: z19.number().int().nonnegative(),
3946
+ model: z19.string(),
3947
+ /** Optional for wire compatibility with pre-context-visibility daemons. */
3948
+ numCtx: z19.number().int().positive().optional(),
3949
+ estimatedTokensBefore: z19.number().int().nonnegative().optional(),
3950
+ autoCompactRatio: z19.number().positive().max(1).optional(),
3951
+ compactionCount: z19.number().int().positive().optional(),
3952
+ mode: z19.enum(["between-turn", "mid-turn"]).optional()
3546
3953
  }),
3547
3954
  /**
3548
3955
  * Emitted when the chat manager detects a self-chat / compaction loop —
@@ -3551,10 +3958,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3551
3958
  * compaction cycle without making progress. The pipeline halts the turn
3552
3959
  * so the user can intervene; the UI surfaces a "looks stuck" banner.
3553
3960
  */
3554
- z17.object({
3555
- type: z17.literal("context_loop"),
3556
- compactionsThisSend: z17.number().int().positive(),
3557
- reason: z17.string()
3961
+ z19.object({
3962
+ type: z19.literal("context_loop"),
3963
+ compactionsThisSend: z19.number().int().positive(),
3964
+ reason: z19.string()
3558
3965
  }),
3559
3966
  /**
3560
3967
  * Emitted when the Keurmeester (frontier quality inspector) steps in
@@ -3562,23 +3969,23 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3562
3969
  * UI renders a "stepped in" notice on the thread; the full case
3563
3970
  * record lives under `~/.gezel/keurmeester/cases/` keyed by caseId.
3564
3971
  */
3565
- z17.object({
3566
- type: z17.literal("keurmeester_intervention"),
3567
- caseId: z17.string(),
3568
- gezelId: z17.string(),
3569
- gezelName: z17.string(),
3570
- action: z17.string(),
3571
- summary: z17.string()
3972
+ z19.object({
3973
+ type: z19.literal("keurmeester_intervention"),
3974
+ caseId: z19.string(),
3975
+ gezelId: z19.string(),
3976
+ gezelName: z19.string(),
3977
+ action: z19.string(),
3978
+ summary: z19.string()
3572
3979
  }),
3573
3980
  /**
3574
3981
  * Emitted once per session the first time auto-recall runs, so the UI
3575
3982
  * can render a "pulled N memories from prior work" chip above the first
3576
3983
  * assistant reply.
3577
3984
  */
3578
- z17.object({
3579
- type: z17.literal("recall_applied"),
3580
- hitCount: z17.number(),
3581
- query: z17.string()
3985
+ z19.object({
3986
+ type: z19.literal("recall_applied"),
3987
+ hitCount: z19.number(),
3988
+ query: z19.string()
3582
3989
  }),
3583
3990
  /**
3584
3991
  * Emitted when a gezel posts a structured question via the
@@ -3586,14 +3993,14 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3586
3993
  * questions on this event so the in-chat card, Home pane, and Home
3587
3994
  * tab badge all light up together.
3588
3995
  */
3589
- z17.object({ type: z17.literal("question_asked"), question: QuestionSchema }),
3996
+ z19.object({ type: z19.literal("question_asked"), question: QuestionSchema }),
3590
3997
  /**
3591
3998
  * Emitted when the user submits (or declines) an answer. The UI
3592
3999
  * uses the same fan-out as `question_asked` to refresh every
3593
4000
  * surface; the chat bubble's pending card collapses to its
3594
4001
  * answered state.
3595
4002
  */
3596
- z17.object({ type: z17.literal("question_answered"), question: QuestionSchema }),
4003
+ z19.object({ type: z19.literal("question_answered"), question: QuestionSchema }),
3597
4004
  /**
3598
4005
  * A durable task audit event, fanned onto the project's live stream after
3599
4006
  * it has been appended to History. This keeps lightweight clients (most
@@ -3601,13 +4008,13 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3601
4008
  * second task lifecycle bus. `task.tick` heartbeats are intentionally not
3602
4009
  * published; this channel is for user-meaningful changes.
3603
4010
  */
3604
- z17.object({
3605
- type: z17.literal("task_event"),
3606
- eventId: z17.string(),
3607
- kind: z17.string(),
3608
- summary: z17.string(),
3609
- at: z17.string(),
3610
- taskRef: z17.string().optional(),
4011
+ z19.object({
4012
+ type: z19.literal("task_event"),
4013
+ eventId: z19.string(),
4014
+ kind: z19.string(),
4015
+ summary: z19.string(),
4016
+ at: z19.string(),
4017
+ taskRef: z19.string().optional(),
3611
4018
  /**
3612
4019
  * Gezel responsible for the event, when History recorded one. Kept
3613
4020
  * separate from the human-readable summary so fixed-presentation
@@ -3615,18 +4022,18 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3615
4022
  * their own naming mode instead of leaking the friendly name embedded
3616
4023
  * in the audit prose.
3617
4024
  */
3618
- gezelId: z17.string().optional()
4025
+ gezelId: z19.string().optional()
3619
4026
  }),
3620
4027
  /**
3621
4028
  * Emitted when a gezel crosses a growth level threshold and a pending
3622
4029
  * level-up is created. The UI refreshes growth badges/dots and raises
3623
4030
  * a single calm OS notification when the window is hidden.
3624
4031
  */
3625
- z17.object({
3626
- type: z17.literal("growth_level_up"),
3627
- gezelId: z17.string(),
3628
- gezelName: z17.string(),
3629
- toLevel: z17.number().int()
4032
+ z19.object({
4033
+ type: z19.literal("growth_level_up"),
4034
+ gezelId: z19.string(),
4035
+ gezelName: z19.string(),
4036
+ toLevel: z19.number().int()
3630
4037
  }),
3631
4038
  /**
3632
4039
  * llama-cpp-only: lifecycle phase of the supervised on-device engine
@@ -3649,13 +4056,19 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3649
4056
  * the phase label so users who want to know what's happening can
3650
4057
  * see, without cluttering the happy-path status line.
3651
4058
  */
3652
- z17.object({
3653
- type: z17.literal("engine_phase"),
3654
- provider: z17.enum(["llama-cpp", "mlx", "ds4"]),
3655
- phase: z17.enum(["starting", "loading_model", "prefill", "generating", "ready"]),
3656
- detail: z17.string().optional(),
3657
- progress: z17.number().min(0).max(1).optional(),
3658
- ttftMs: z17.number().int().nonnegative().optional(),
4059
+ z19.object({
4060
+ type: z19.literal("engine_phase"),
4061
+ provider: z19.enum(["llama-cpp", "mlx", "ds4"]),
4062
+ phase: z19.enum(["starting", "loading_model", "prefill", "generating", "ready"]),
4063
+ /**
4064
+ * Human-readable subject for an ephemeral background completion. Unlike
4065
+ * `detail` (engine diagnostics), this names the user's work — for example
4066
+ * "Indexing src/app.ts". Ordinary chat turns leave it absent.
4067
+ */
4068
+ activity: z19.string().optional(),
4069
+ detail: z19.string().optional(),
4070
+ progress: z19.number().min(0).max(1).optional(),
4071
+ ttftMs: z19.number().int().nonnegative().optional(),
3659
4072
  /**
3660
4073
  * Exact cumulative completion tokens decoded so far this turn, as the
3661
4074
  * engine counts them (llama-server `timings.predicted_n`, MLX's
@@ -3664,14 +4077,14 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3664
4077
  * to an explicitly-approximate character estimate when it is absent,
3665
4078
  * so this field is what lets a readout drop its "≈".
3666
4079
  */
3667
- outputTokens: z17.number().int().nonnegative().optional(),
4080
+ outputTokens: z19.number().int().nonnegative().optional(),
3668
4081
  /**
3669
4082
  * Exact decode rate right now, engine-measured over the generation
3670
4083
  * phase alone (llama-server `timings.predicted_per_second`, MLX's
3671
4084
  * `generation_tps`). Same contract as `outputTokens`: absent means the
3672
4085
  * UI must derive and mark its own estimate.
3673
4086
  */
3674
- tokensPerSec: z17.number().nonnegative().optional()
4087
+ tokensPerSec: z19.number().nonnegative().optional()
3675
4088
  }),
3676
4089
  /**
3677
4090
  * Per-turn telemetry for locally-hosted providers (llama-cpp, Ollama,
@@ -3686,21 +4099,21 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3686
4099
  * local speed metric isn't meaningful when the latency is
3687
4100
  * dominated by network round-trips.
3688
4101
  */
3689
- z17.object({
3690
- type: z17.literal("turn_stats"),
3691
- provider: z17.enum(["llama-cpp", "ollama", "mlx", "ds4"]),
4102
+ z19.object({
4103
+ type: z19.literal("turn_stats"),
4104
+ provider: z19.enum(["llama-cpp", "ollama", "mlx", "ds4"]),
3692
4105
  /**
3693
4106
  * Model that generated the turn, as the session recorded it. Lets the
3694
4107
  * UI bucket speed by model instead of averaging a 27B and a 4B into
3695
4108
  * one meaningless number. Optional because older daemons (and remote
3696
4109
  * peers on an older wire) don't send it.
3697
4110
  */
3698
- model: z17.string().optional(),
3699
- promptTokens: z17.number().int().nonnegative(),
3700
- completionTokens: z17.number().int().nonnegative(),
3701
- durationMs: z17.number().int().nonnegative(),
4111
+ model: z19.string().optional(),
4112
+ promptTokens: z19.number().int().nonnegative(),
4113
+ completionTokens: z19.number().int().nonnegative(),
4114
+ durationMs: z19.number().int().nonnegative(),
3702
4115
  /** Generation speed in tokens/sec — completionTokens / generationSeconds. */
3703
- tokensPerSec: z17.number().nonnegative().optional()
4116
+ tokensPerSec: z19.number().nonnegative().optional()
3704
4117
  }),
3705
4118
  /**
3706
4119
  * Static engine-level metrics that don't change during a session —
@@ -3712,11 +4125,11 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3712
4125
  * `engine_phase` (every session waiting on the same supervisor
3713
4126
  * startup gets a copy).
3714
4127
  */
3715
- z17.object({
3716
- type: z17.literal("engine_stats"),
3717
- provider: z17.enum(["llama-cpp", "mlx", "ds4"]),
4128
+ z19.object({
4129
+ type: z19.literal("engine_stats"),
4130
+ provider: z19.enum(["llama-cpp", "mlx", "ds4"]),
3718
4131
  /** Total bytes allocated across all GGUF buffers + KV cache. */
3719
- ramAllocBytes: z17.number().nonnegative()
4132
+ ramAllocBytes: z19.number().nonnegative()
3720
4133
  }),
3721
4134
  /**
3722
4135
  * VRAM tenancy change — a non-LLM workload has taken (or released)
@@ -3746,9 +4159,9 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3746
4159
  * `step`/`totalSteps` drive a real progress bar; `secondsPerStep`
3747
4160
  * lets the UI show an ETA.
3748
4161
  */
3749
- z17.object({
3750
- type: z17.literal("gpu_swap"),
3751
- state: z17.enum(["started", "progress", "ended"]),
4162
+ z19.object({
4163
+ type: z19.literal("gpu_swap"),
4164
+ state: z19.enum(["started", "progress", "ended"]),
3752
4165
  /**
3753
4166
  * Shared with session telemetry so a new workload can't light up the
3754
4167
  * bubble while staying invisible to stall detection.
@@ -3761,12 +4174,12 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3761
4174
  * seconds", which reads as a bug.
3762
4175
  */
3763
4176
  task: SessionGpuTaskSchema,
3764
- detail: z17.string().optional(),
3765
- prompt: z17.string().optional(),
3766
- progress: z17.number().min(0).max(1).optional(),
3767
- step: z17.number().int().nonnegative().optional(),
3768
- totalSteps: z17.number().int().positive().optional(),
3769
- secondsPerStep: z17.number().nonnegative().optional()
4177
+ detail: z19.string().optional(),
4178
+ prompt: z19.string().optional(),
4179
+ progress: z19.number().min(0).max(1).optional(),
4180
+ step: z19.number().int().nonnegative().optional(),
4181
+ totalSteps: z19.number().int().positive().optional(),
4182
+ secondsPerStep: z19.number().nonnegative().optional()
3770
4183
  }),
3771
4184
  /**
3772
4185
  * The turn is parked inside a synchronous `ask_gezel` /
@@ -3789,10 +4202,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3789
4202
  * side, same as the `ask_gezel` tool result), so the UI can render
3790
4203
  * it verbatim.
3791
4204
  */
3792
- z17.object({
3793
- type: z17.literal("awaiting_gezel"),
3794
- state: z17.enum(["started", "ended"]),
3795
- targetGezelName: z17.string()
4205
+ z19.object({
4206
+ type: z19.literal("awaiting_gezel"),
4207
+ state: z19.enum(["started", "ended"]),
4208
+ targetGezelName: z19.string()
3796
4209
  }),
3797
4210
  /**
3798
4211
  * A new project was created (via the New Project dialog, the
@@ -3803,10 +4216,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3803
4216
  * for the next manual refresh / tab-focus poll. Not a renderable
3804
4217
  * timeline event (like `growth_level_up`); the chat surfaces ignore it.
3805
4218
  */
3806
- z17.object({
3807
- type: z17.literal("project_created"),
3808
- projectId: z17.string(),
3809
- name: z17.string()
4219
+ z19.object({
4220
+ type: z19.literal("project_created"),
4221
+ projectId: z19.string(),
4222
+ name: z19.string()
3810
4223
  }),
3811
4224
  /**
3812
4225
  * A project was deleted (via the Project Actions menu, or an equivalent
@@ -3816,10 +4229,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3816
4229
  * waiting for the next manual refresh / tab-focus poll. Not a renderable
3817
4230
  * timeline event; the chat surfaces ignore it.
3818
4231
  */
3819
- z17.object({
3820
- type: z17.literal("project_deleted"),
3821
- projectId: z17.string(),
3822
- name: z17.string()
4232
+ z19.object({
4233
+ type: z19.literal("project_deleted"),
4234
+ projectId: z19.string(),
4235
+ name: z19.string()
3823
4236
  }),
3824
4237
  /**
3825
4238
  * A new shared gezel joined the global roster. Emitted on the global
@@ -3828,10 +4241,30 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3828
4241
  * gezels deliberately do not emit this event because they do not belong in
3829
4242
  * the global Gezellen list.
3830
4243
  */
3831
- z17.object({
3832
- type: z17.literal("gezel_created"),
3833
- gezelId: z17.string(),
3834
- name: z17.string()
4244
+ z19.object({
4245
+ type: z19.literal("gezel_created"),
4246
+ gezelId: z19.string(),
4247
+ name: z19.string()
4248
+ }),
4249
+ /**
4250
+ * A prompt draft was created, edited, re-filed, sent, or removed. Emitted
4251
+ * on the project stream so a thread picker open in another window folds the
4252
+ * change in. Content-only churn rides this event too (autosave fires it
4253
+ * about once a second per typing user), so consumers must debounce and
4254
+ * should ignore an event for the draft they are themselves editing.
4255
+ *
4256
+ * `gezelId` is the draft's, not the envelope's: a draft that will start a
4257
+ * new thread has no session for the envelope to be scoped by.
4258
+ */
4259
+ z19.object({
4260
+ type: z19.literal("prompt_draft_changed"),
4261
+ projectId: z19.string(),
4262
+ gezelId: z19.string(),
4263
+ draftId: z19.string(),
4264
+ sessionId: z19.string().nullable(),
4265
+ status: z19.enum(["draft", "sent"]),
4266
+ deleted: z19.boolean().optional(),
4267
+ updatedAt: z19.string()
3835
4268
  }),
3836
4269
  /**
3837
4270
  * Global (project-less) signal that Night Shift mode flipped ON/OFF.
@@ -3839,10 +4272,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3839
4272
  * menu pill reflects the live state. `source` is the active driver
3840
4273
  * (scheduled window vs. a manual shift), null when inactive.
3841
4274
  */
3842
- z17.object({
3843
- type: z17.literal("night_shift"),
3844
- active: z17.boolean(),
3845
- source: z17.enum(["scheduled", "manual"]).nullable()
4275
+ z19.object({
4276
+ type: z19.literal("night_shift"),
4277
+ active: z19.boolean(),
4278
+ source: z19.enum(["scheduled", "manual"]).nullable()
3846
4279
  }),
3847
4280
  /**
3848
4281
  * Global signal from the meester status generator. `started` fires
@@ -3851,10 +4284,10 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3851
4284
  * produced nothing usable — the Home greeting refetches on the
3852
4285
  * terminal states instead of polling.
3853
4286
  */
3854
- z17.object({
3855
- type: z17.literal("meester_status"),
3856
- state: z17.enum(["started", "ended", "failed"]),
3857
- generatedAt: z17.string().optional()
4287
+ z19.object({
4288
+ type: z19.literal("meester_status"),
4289
+ state: z19.enum(["started", "ended", "failed"]),
4290
+ generatedAt: z19.string().optional()
3858
4291
  }),
3859
4292
  /**
3860
4293
  * Global signal from the ambient dashboard generator. `ended` means a
@@ -3863,11 +4296,11 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3863
4296
  * the wallpaper when the user opted in, and the Settings card
3864
4297
  * refreshes its preview.
3865
4298
  */
3866
- z17.object({
3867
- type: z17.literal("ambient_dashboard"),
3868
- state: z17.enum(["started", "ended", "failed"]),
3869
- generatedAt: z17.string().optional(),
3870
- filename: z17.string().optional()
4299
+ z19.object({
4300
+ type: z19.literal("ambient_dashboard"),
4301
+ state: z19.enum(["started", "ended", "failed"]),
4302
+ generatedAt: z19.string().optional(),
4303
+ filename: z19.string().optional()
3871
4304
  }),
3872
4305
  /**
3873
4306
  * Global (history-free) heartbeat from the boekwachter indexing loops —
@@ -3875,23 +4308,27 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
3875
4308
  * indicator pill; complements (doesn't replace) the polled per-project
3876
4309
  * index status. `pending` = files still awaiting AI enrichment when known.
3877
4310
  */
3878
- z17.object({
3879
- type: z17.literal("index_progress"),
3880
- phase: z17.enum(["scan", "shadow", "enrich", "review", "digest"]),
3881
- state: z17.enum(["started", "progress", "ended"]),
3882
- projectId: z17.string().optional(),
3883
- detail: z17.string().optional(),
3884
- pending: z17.number().int().nonnegative().optional(),
4311
+ z19.object({
4312
+ type: z19.literal("index_progress"),
4313
+ phase: z19.enum(["scan", "shadow", "enrich", "review", "digest"]),
4314
+ state: z19.enum(["started", "progress", "ended"]),
4315
+ projectId: z19.string().optional(),
4316
+ detail: z19.string().optional(),
4317
+ pending: z19.number().int().nonnegative().optional(),
3885
4318
  /** The concrete autonomous gezel doing this work, when the project has one. */
3886
- gezelId: z17.string().optional(),
4319
+ gezelId: z19.string().optional(),
3887
4320
  /** Snapshot of their display name so transient progress remains human-readable. */
3888
- gezelName: z17.string().optional()
4321
+ gezelName: z19.string().optional()
3889
4322
  })
3890
4323
  ]);
3891
- var ChatEventEnvelopeSchema = z17.object({
3892
- sessionId: z17.string(),
3893
- gezelId: z17.string(),
3894
- projectId: z17.string(),
4324
+ var ChatEventEnvelopeSchema = z19.object({
4325
+ sessionId: z19.string(),
4326
+ gezelId: z19.string(),
4327
+ projectId: z19.string(),
4328
+ /** Present when this live session was opened by another session. */
4329
+ parentSession: SessionParentSchema.optional(),
4330
+ /** Immediate task-step session that handed work to this live session. */
4331
+ handoffFrom: SessionLinkSchema.optional(),
3895
4332
  /** Present for externally-owned read-only threads, including live turns. */
3896
4333
  sessionSource: ChatSessionSourceSchema.optional(),
3897
4334
  event: ChatEventSchema
@@ -4024,8 +4461,8 @@ function promoteBareChannelNames(text) {
4024
4461
  }
4025
4462
 
4026
4463
  // src/schemas/report-action.ts
4027
- import { z as z18 } from "zod";
4028
- var ReportActionKindSchema = z18.enum(["fire-craftbook", "create-task", "apply-edits"]);
4464
+ import { z as z20 } from "zod";
4465
+ var ReportActionKindSchema = z20.enum(["fire-craftbook", "create-task", "apply-edits"]);
4029
4466
  var commonFields = {
4030
4467
  /**
4031
4468
  * Author-supplied stable slug — keeps lifecycle state attached across
@@ -4033,121 +4470,121 @@ var commonFields = {
4033
4470
  * content hash (`a-<hash>`), which is stable only while the block's
4034
4471
  * body is byte-identical.
4035
4472
  */
4036
- id: z18.string().regex(/^[a-z0-9][a-z0-9_-]*$/i).optional(),
4473
+ id: z20.string().regex(/^[a-z0-9][a-z0-9_-]*$/i).optional(),
4037
4474
  /** Short human label for the card ("Fix the unchecked null in parser.ts"). */
4038
- title: z18.string().min(1),
4475
+ title: z20.string().min(1),
4039
4476
  /** One-or-two-sentence rationale shown under the title. */
4040
- reason: z18.string().optional(),
4477
+ reason: z20.string().optional(),
4041
4478
  /**
4042
4479
  * Target project. Defaults to the report's own project. Cross-project
4043
4480
  * targets are a primary case — the bundled oversight report lives in
4044
4481
  * `default` but recommends work in specific projects.
4045
4482
  */
4046
- projectId: z18.string().optional()
4483
+ projectId: z20.string().optional()
4047
4484
  };
4048
- var FireCraftbookActionSchema = z18.object({
4049
- kind: z18.literal("fire-craftbook"),
4485
+ var FireCraftbookActionSchema = z20.object({
4486
+ kind: z20.literal("fire-craftbook"),
4050
4487
  ...commonFields,
4051
- craftbookId: z18.string().min(1),
4488
+ craftbookId: z20.string().min(1),
4052
4489
  /** Invocation params for the craftbook's paramSchema (stringified values). */
4053
- params: z18.record(z18.string(), z18.string()).optional()
4490
+ params: z20.record(z20.string(), z20.string()).optional()
4054
4491
  });
4055
- var CreateTaskActionSchema = z18.object({
4056
- kind: z18.literal("create-task"),
4492
+ var CreateTaskActionSchema = z20.object({
4493
+ kind: z20.literal("create-task"),
4057
4494
  ...commonFields,
4058
4495
  /** Full work instruction for the bespoke task's single step. */
4059
- prompt: z18.string().min(1),
4496
+ prompt: z20.string().min(1),
4060
4497
  /** Role to recruit for the work (ensure_gezel jobTitle). Default: software developer. */
4061
- role: z18.string().optional()
4498
+ role: z20.string().optional()
4062
4499
  });
4063
- var ApplyEditsActionSchema = z18.object({
4064
- kind: z18.literal("apply-edits"),
4500
+ var ApplyEditsActionSchema = z20.object({
4501
+ kind: z20.literal("apply-edits"),
4065
4502
  ...commonFields,
4066
- edits: z18.array(
4067
- z18.object({
4503
+ edits: z20.array(
4504
+ z20.object({
4068
4505
  /** Workspace-relative target file in the TARGET project. */
4069
- path: z18.string().min(1),
4506
+ path: z20.string().min(1),
4070
4507
  /** Artifacts-relative sidecar `.diff` path in the REPORT's project. */
4071
- diffArtifact: z18.string().min(1)
4508
+ diffArtifact: z20.string().min(1)
4072
4509
  })
4073
4510
  ).min(1)
4074
4511
  });
4075
- var ReportActionSchema = z18.discriminatedUnion("kind", [
4512
+ var ReportActionSchema = z20.discriminatedUnion("kind", [
4076
4513
  FireCraftbookActionSchema,
4077
4514
  CreateTaskActionSchema,
4078
4515
  ApplyEditsActionSchema
4079
4516
  ]);
4080
- var ReportActionStateSchema = z18.enum([
4517
+ var ReportActionStateSchema = z20.enum([
4081
4518
  "suggested",
4082
4519
  "fired",
4083
4520
  "applied",
4084
4521
  "failed",
4085
4522
  "dismissed"
4086
4523
  ]);
4087
- var ReportActionRecordSchema = z18.object({
4088
- actionId: z18.string(),
4524
+ var ReportActionRecordSchema = z20.object({
4525
+ actionId: z20.string(),
4089
4526
  /** Artifacts-relative path of the report the action came from. */
4090
- reportPath: z18.string(),
4527
+ reportPath: z20.string(),
4091
4528
  kind: ReportActionKindSchema,
4092
- contentHash: z18.string(),
4093
- firstSeenAt: z18.string(),
4529
+ contentHash: z20.string(),
4530
+ firstSeenAt: z20.string(),
4094
4531
  state: ReportActionStateSchema,
4095
4532
  /** Task materialized by fire-craftbook / create-task. */
4096
- taskRef: z18.string().optional(),
4097
- firedAt: z18.string().optional(),
4533
+ taskRef: z20.string().optional(),
4534
+ firedAt: z20.string().optional(),
4098
4535
  /** Stamped when the fired task settles. */
4099
- settledAt: z18.string().optional(),
4100
- outcome: z18.enum(["complete", "canceled"]).optional(),
4536
+ settledAt: z20.string().optional(),
4537
+ outcome: z20.enum(["complete", "canceled"]).optional(),
4101
4538
  /** apply-edits per-file results. */
4102
- results: z18.array(
4103
- z18.object({
4104
- path: z18.string(),
4105
- ok: z18.boolean(),
4106
- error: z18.string().optional()
4539
+ results: z20.array(
4540
+ z20.object({
4541
+ path: z20.string(),
4542
+ ok: z20.boolean(),
4543
+ error: z20.string().optional()
4107
4544
  })
4108
4545
  ).optional()
4109
4546
  });
4110
- var ReportActionParseIssueSchema = z18.object({
4547
+ var ReportActionParseIssueSchema = z20.object({
4111
4548
  /** Zero-based index among the report's gezel-action fences. */
4112
- index: z18.number().int(),
4113
- message: z18.string(),
4549
+ index: z20.number().int(),
4550
+ message: z20.string(),
4114
4551
  /** Raw fence body, for the "unreadable action block" card. */
4115
- raw: z18.string()
4552
+ raw: z20.string()
4116
4553
  });
4117
- var ReportActionViewSchema = z18.object({
4554
+ var ReportActionViewSchema = z20.object({
4118
4555
  action: ReportActionSchema,
4119
- id: z18.string(),
4120
- contentHash: z18.string(),
4556
+ id: z20.string(),
4557
+ contentHash: z20.string(),
4121
4558
  state: ReportActionStateSchema,
4122
- taskRef: z18.string().optional(),
4123
- firedAt: z18.string().optional(),
4124
- settledAt: z18.string().optional(),
4125
- outcome: z18.enum(["complete", "canceled"]).optional(),
4126
- results: z18.array(z18.object({ path: z18.string(), ok: z18.boolean(), error: z18.string().optional() })).optional(),
4559
+ taskRef: z20.string().optional(),
4560
+ firedAt: z20.string().optional(),
4561
+ settledAt: z20.string().optional(),
4562
+ outcome: z20.enum(["complete", "canceled"]).optional(),
4563
+ results: z20.array(z20.object({ path: z20.string(), ok: z20.boolean(), error: z20.string().optional() })).optional(),
4127
4564
  /** The stored record predates a changed block body (report regenerated). */
4128
- contentChanged: z18.boolean().optional()
4565
+ contentChanged: z20.boolean().optional()
4129
4566
  });
4130
- var ReportActionsResponseSchema = z18.object({
4131
- actions: z18.array(ReportActionViewSchema),
4132
- issues: z18.array(ReportActionParseIssueSchema),
4567
+ var ReportActionsResponseSchema = z20.object({
4568
+ actions: z20.array(ReportActionViewSchema),
4569
+ issues: z20.array(ReportActionParseIssueSchema),
4133
4570
  /** Records whose action vanished from the regenerated report. */
4134
- stale: z18.array(ReportActionRecordSchema)
4571
+ stale: z20.array(ReportActionRecordSchema)
4135
4572
  });
4136
- var FireReportActionRequestSchema = z18.object({
4573
+ var FireReportActionRequestSchema = z20.object({
4137
4574
  /** Artifacts-relative report path. */
4138
- path: z18.string().min(1),
4139
- actionId: z18.string().min(1),
4575
+ path: z20.string().min(1),
4576
+ actionId: z20.string().min(1),
4140
4577
  /** apply-edits: none. fire-craftbook: overrides the block's params. */
4141
- params: z18.record(z18.string(), z18.string()).optional()
4578
+ params: z20.record(z20.string(), z20.string()).optional()
4142
4579
  });
4143
- var FireReportActionResponseSchema = z18.object({
4580
+ var FireReportActionResponseSchema = z20.object({
4144
4581
  record: ReportActionRecordSchema,
4145
4582
  /** Set for fire-craftbook / create-task. */
4146
- taskRef: z18.string().optional()
4583
+ taskRef: z20.string().optional()
4147
4584
  });
4148
- var DismissReportActionRequestSchema = z18.object({
4149
- path: z18.string().min(1),
4150
- actionId: z18.string().min(1)
4585
+ var DismissReportActionRequestSchema = z20.object({
4586
+ path: z20.string().min(1),
4587
+ actionId: z20.string().min(1)
4151
4588
  });
4152
4589
 
4153
4590
  // src/markdown/report-actions.ts