@bendyline/gezel 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/checks/index.js +10 -1
- package/dist/{index-CWMNVAhp.d.ts → index-4Q1N_3oe.d.ts} +1201 -10
- package/dist/index.d.ts +45 -7
- package/dist/index.js +801 -562
- package/dist/markdown/index.d.ts +1 -1
- package/dist/markdown/index.js +48 -3
- package/dist/{report-action-DIz_2QOu.d.ts → report-action-C0KuyeNw.d.ts} +38 -0
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.js +684 -559
- package/package.json +1 -1
package/dist/schemas/index.js
CHANGED
|
@@ -494,13 +494,14 @@ var GateCheckSchema = z3.discriminatedUnion("kind", [
|
|
|
494
494
|
label: z3.string().min(1).optional(),
|
|
495
495
|
artifact: z3.boolean().optional()
|
|
496
496
|
}),
|
|
497
|
-
/** `file` must NOT match `pattern` (regex)
|
|
497
|
+
/** `file` must NOT match `pattern` (regex), in the workspace or artifacts drawer. */
|
|
498
498
|
z3.object({
|
|
499
499
|
kind: z3.literal("notContains"),
|
|
500
500
|
file: z3.string().min(1),
|
|
501
501
|
pattern: z3.string().min(1),
|
|
502
502
|
flags: z3.string().optional(),
|
|
503
|
-
label: z3.string().min(1).optional()
|
|
503
|
+
label: z3.string().min(1).optional(),
|
|
504
|
+
artifact: z3.boolean().optional()
|
|
504
505
|
}),
|
|
505
506
|
/**
|
|
506
507
|
* `file` may use high-risk claim wording only when the exact matched
|
|
@@ -643,6 +644,20 @@ var GateCheckSchema = z3.discriminatedUnion("kind", [
|
|
|
643
644
|
tools: z3.array(z3.string().min(1)).min(1),
|
|
644
645
|
minSuccessful: z3.number().int().positive().optional()
|
|
645
646
|
}),
|
|
647
|
+
/**
|
|
648
|
+
* A PR-review coverage ledger must name every changed path materialized in
|
|
649
|
+
* a connector corpus. The ledger is workspace JSON (`reviewedFiles` by
|
|
650
|
+
* default); the source records live in the read-only artifacts drawer and
|
|
651
|
+
* carry their authoritative path in frontmatter. This prevents a polished
|
|
652
|
+
* report from passing after only the first context-sized prefix was read.
|
|
653
|
+
*/
|
|
654
|
+
z3.object({
|
|
655
|
+
kind: z3.literal("corpusCoverage"),
|
|
656
|
+
file: z3.string().min(1),
|
|
657
|
+
corpusDir: z3.string().min(1),
|
|
658
|
+
reviewedField: z3.string().min(1).optional(),
|
|
659
|
+
recordField: z3.string().min(1).optional()
|
|
660
|
+
}),
|
|
646
661
|
/**
|
|
647
662
|
* The H1 slide titles in `file` must match the numbered slide headings in
|
|
648
663
|
* `outlineFile`, one-for-one and in order. This makes a locked Markdown
|
|
@@ -915,6 +930,12 @@ var AdvanceWhenSchema = z5.object({
|
|
|
915
930
|
/** Step to activate on the signal. Defaults to `next`; must resolve like `next`. */
|
|
916
931
|
goto: z5.string().optional()
|
|
917
932
|
});
|
|
933
|
+
var CraftbookStepInputSchema = z5.object({
|
|
934
|
+
/** Path relative to the selected drawer's root. */
|
|
935
|
+
file: z5.string().min(1).describe("Path relative to the selected drawer root."),
|
|
936
|
+
/** Read from the artifacts drawer instead of the project workspace. */
|
|
937
|
+
artifact: z5.boolean().optional().describe("True for the artifacts drawer; false/omitted for the project workspace.")
|
|
938
|
+
});
|
|
918
939
|
var ModelTierSchema = z5.enum(MODEL_TIER_ORDER);
|
|
919
940
|
var CraftbookStepSchema = z5.object({
|
|
920
941
|
id: z5.string().min(1),
|
|
@@ -955,6 +976,10 @@ var CraftbookStepSchema = z5.object({
|
|
|
955
976
|
* read the LAST ref's output (legacy routing; prefer gate routing).
|
|
956
977
|
*/
|
|
957
978
|
onExit: ScriptRefListSchema.optional(),
|
|
979
|
+
/** Required file inputs for this step, in the order they should be opened. */
|
|
980
|
+
consumes: z5.array(CraftbookStepInputSchema).min(1).optional().describe(
|
|
981
|
+
"Files this step must open before working. Artifact inputs also require an explicit `read_artifact` call in the step prompt."
|
|
982
|
+
),
|
|
958
983
|
/** See {@link AdvanceWhenSchema}. */
|
|
959
984
|
advanceWhen: AdvanceWhenSchema.optional(),
|
|
960
985
|
/** The end-of-step decision. See {@link StepGateSchema} (current) / {@link GateSpecSchema} (legacy). */
|
|
@@ -1009,6 +1034,14 @@ function validateCraftbookGraph(cb) {
|
|
|
1009
1034
|
problems.push(`step "${s.id}" advanceWhen.goto "${s.advanceWhen.goto}" missing from steps`);
|
|
1010
1035
|
}
|
|
1011
1036
|
}
|
|
1037
|
+
for (const input of s.consumes ?? []) {
|
|
1038
|
+
if (!input.artifact) continue;
|
|
1039
|
+
if (!/`read_artifact(?:`|\()/.test(s.prompt ?? "")) {
|
|
1040
|
+
problems.push(
|
|
1041
|
+
`step "${s.id}" consumes artifact "${input.file}" but its prompt does not explicitly call \`read_artifact\``
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1012
1045
|
if (s.gate) {
|
|
1013
1046
|
const gate = normalizeStepGate(s.gate);
|
|
1014
1047
|
if (s.terminal && gate.at === "activation") {
|
|
@@ -1301,6 +1334,9 @@ var NewCraftbookStepSchema = z5.object({
|
|
|
1301
1334
|
assignee: TaskAssigneeSchema.optional(),
|
|
1302
1335
|
onEnter: ScriptRefListSchema.optional(),
|
|
1303
1336
|
onExit: ScriptRefListSchema.optional(),
|
|
1337
|
+
consumes: z5.array(CraftbookStepInputSchema).min(1).optional().describe(
|
|
1338
|
+
"Files this step must open before working. Artifact inputs also require an explicit `read_artifact` call in the step prompt."
|
|
1339
|
+
),
|
|
1304
1340
|
advanceWhen: AdvanceWhenSchema.optional(),
|
|
1305
1341
|
gate: StepGateUnionSchema.optional(),
|
|
1306
1342
|
/** See {@link StepDeliverableSchema} — one field attaches the enforced gate. */
|
|
@@ -1413,6 +1449,7 @@ function resolveSteps(blueprints) {
|
|
|
1413
1449
|
...s.assignee ? { assignee: s.assignee } : {},
|
|
1414
1450
|
...s.onEnter ? { onEnter: s.onEnter } : {},
|
|
1415
1451
|
...s.onExit ? { onExit: s.onExit } : {},
|
|
1452
|
+
...s.consumes && s.consumes.length > 0 ? { consumes: s.consumes } : {},
|
|
1416
1453
|
...s.advanceWhen ? { advanceWhen: s.advanceWhen } : {},
|
|
1417
1454
|
...s.gate ? { gate: s.gate } : {},
|
|
1418
1455
|
...s.next ? { next: s.next } : {},
|
|
@@ -1535,6 +1572,10 @@ function applyStepPatch(step, patch) {
|
|
|
1535
1572
|
delete updated.onExit;
|
|
1536
1573
|
} else updated.onExit = patch.onExit;
|
|
1537
1574
|
}
|
|
1575
|
+
if (patch.consumes !== void 0) {
|
|
1576
|
+
if (patch.consumes === null || patch.consumes.length === 0) delete updated.consumes;
|
|
1577
|
+
else updated.consumes = patch.consumes;
|
|
1578
|
+
}
|
|
1538
1579
|
if (patch.advanceWhen !== void 0) {
|
|
1539
1580
|
if (patch.advanceWhen === null) delete updated.advanceWhen;
|
|
1540
1581
|
else updated.advanceWhen = patch.advanceWhen;
|
|
@@ -1713,7 +1754,7 @@ function craftbookDocFormatFromEnv(value) {
|
|
|
1713
1754
|
}
|
|
1714
1755
|
|
|
1715
1756
|
// src/schemas/craftbook-test.ts
|
|
1716
|
-
import { z as
|
|
1757
|
+
import { z as z20 } from "zod";
|
|
1717
1758
|
|
|
1718
1759
|
// src/schemas/history.ts
|
|
1719
1760
|
import { z as z18 } from "zod";
|
|
@@ -3534,7 +3575,15 @@ var ChatEventSchema = z17.discriminatedUnion("type", [
|
|
|
3534
3575
|
kind: z17.string(),
|
|
3535
3576
|
summary: z17.string(),
|
|
3536
3577
|
at: z17.string(),
|
|
3537
|
-
taskRef: z17.string().optional()
|
|
3578
|
+
taskRef: z17.string().optional(),
|
|
3579
|
+
/**
|
|
3580
|
+
* Gezel responsible for the event, when History recorded one. Kept
|
|
3581
|
+
* separate from the human-readable summary so fixed-presentation
|
|
3582
|
+
* clients (notably the role-name-only CLI) can render the actor using
|
|
3583
|
+
* their own naming mode instead of leaking the friendly name embedded
|
|
3584
|
+
* in the audit prose.
|
|
3585
|
+
*/
|
|
3586
|
+
gezelId: z17.string().optional()
|
|
3538
3587
|
}),
|
|
3539
3588
|
/**
|
|
3540
3589
|
* Emitted when a gezel crosses a growth level threshold and a pending
|
|
@@ -4075,444 +4124,9 @@ var ListHistoryResponseSchema = z18.object({
|
|
|
4075
4124
|
entries: z18.array(HistoryEntrySchema)
|
|
4076
4125
|
});
|
|
4077
4126
|
|
|
4078
|
-
// src/schemas/craftbook-test.ts
|
|
4079
|
-
var CRAFTBOOK_TEST_SCHEMA_VERSION = 1;
|
|
4080
|
-
var CRAFTBOOK_TEST_FILENAME = "test.json";
|
|
4081
|
-
var PrometheusAlertsCheckSchema = z19.object({
|
|
4082
|
-
kind: z19.literal("prometheusAlerts"),
|
|
4083
|
-
file: z19.string().min(1),
|
|
4084
|
-
minRules: z19.number().int().positive().optional(),
|
|
4085
|
-
maxPageAlerts: z19.number().int().nonnegative().optional(),
|
|
4086
|
-
allowedSeverities: z19.array(z19.string().min(1)).optional(),
|
|
4087
|
-
requiredServices: z19.array(z19.string().min(1)).optional(),
|
|
4088
|
-
requiredRunbookUrls: z19.array(z19.string().min(1)).optional()
|
|
4089
|
-
}).strict();
|
|
4090
|
-
var NodeScriptPassesCheckSchema = z19.object({
|
|
4091
|
-
kind: z19.literal("nodeScriptPasses"),
|
|
4092
|
-
script: z19.string().min(1),
|
|
4093
|
-
timeoutMs: z19.number().int().positive().optional(),
|
|
4094
|
-
requiredOutput: z19.array(
|
|
4095
|
-
z19.object({
|
|
4096
|
-
pattern: z19.string().min(1),
|
|
4097
|
-
flags: z19.string().optional(),
|
|
4098
|
-
label: z19.string().optional()
|
|
4099
|
-
}).strict()
|
|
4100
|
-
).optional()
|
|
4101
|
-
}).strict();
|
|
4102
|
-
var BinaryDocumentCheckSchema = z19.object({
|
|
4103
|
-
kind: z19.literal("binaryDocument"),
|
|
4104
|
-
file: z19.string().min(1),
|
|
4105
|
-
/** Look in the artifacts drawer instead of the workspace. */
|
|
4106
|
-
artifact: z19.boolean().optional(),
|
|
4107
|
-
/** Floor on the container's byte length; defaults to 1000. */
|
|
4108
|
-
minBytes: z19.number().int().positive().optional()
|
|
4109
|
-
}).strict();
|
|
4110
|
-
var CraftbookTestCheckSchema = z19.union([
|
|
4111
|
-
GateCheckSchema,
|
|
4112
|
-
PrometheusAlertsCheckSchema,
|
|
4113
|
-
NodeScriptPassesCheckSchema,
|
|
4114
|
-
BinaryDocumentCheckSchema
|
|
4115
|
-
]);
|
|
4116
|
-
var MockServiceIdSchema = z19.string().min(1).regex(/^[a-z0-9][a-z0-9-]*$/, "mock service ids are lowercase kebab-case");
|
|
4117
|
-
var MockToolsetIdSchema = z19.string().min(1).regex(
|
|
4118
|
-
/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,
|
|
4119
|
-
"mock toolset ids are lowercase catalog ids or scoped npm-style ids"
|
|
4120
|
-
);
|
|
4121
|
-
var MockHttpRouteSchema = z19.object({
|
|
4122
|
-
method: z19.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).default("GET"),
|
|
4123
|
-
/** Exact path, `:param` segments, or a trailing `*` wildcard. */
|
|
4124
|
-
path: z19.string().min(1),
|
|
4125
|
-
status: z19.number().int().min(100).max(599).default(200),
|
|
4126
|
-
headers: z19.record(z19.string(), z19.string()).optional(),
|
|
4127
|
-
/** String bodies are served verbatim; anything else is JSON-encoded. */
|
|
4128
|
-
body: z19.unknown(),
|
|
4129
|
-
latencyMs: z19.number().int().nonnegative().optional()
|
|
4130
|
-
}).strict();
|
|
4131
|
-
var MockServiceSchema = z19.discriminatedUnion("kind", [
|
|
4132
|
-
z19.object({
|
|
4133
|
-
kind: z19.literal("http"),
|
|
4134
|
-
id: MockServiceIdSchema,
|
|
4135
|
-
description: z19.string().min(1),
|
|
4136
|
-
/**
|
|
4137
|
-
* v1 mock HTTP is reachable ONLY through the `http.authed`
|
|
4138
|
-
* credential rail (anonymous script/browser HTTP hard-rejects
|
|
4139
|
-
* loopback), so a credential is required. The harness seeds it and
|
|
4140
|
-
* grants the mock's exact origin on the trial project.
|
|
4141
|
-
*/
|
|
4142
|
-
credential: z19.object({
|
|
4143
|
-
name: z19.string().regex(/^mock\.[a-z0-9][a-z0-9.-]*$/, "mock credentials are named mock.<service-id>"),
|
|
4144
|
-
authScheme: z19.enum(["bearer", "basic"]).optional()
|
|
4145
|
-
}).strict(),
|
|
4146
|
-
routes: z19.array(MockHttpRouteSchema).min(1)
|
|
4147
|
-
}).strict(),
|
|
4148
|
-
z19.object({
|
|
4149
|
-
kind: z19.literal("webhook"),
|
|
4150
|
-
id: MockServiceIdSchema,
|
|
4151
|
-
description: z19.string().min(1),
|
|
4152
|
-
/** Receiver path; defaults to `/webhook` when omitted. */
|
|
4153
|
-
path: z19.string().min(1).optional()
|
|
4154
|
-
}).strict(),
|
|
4155
|
-
z19.object({
|
|
4156
|
-
kind: z19.literal("cli"),
|
|
4157
|
-
id: MockServiceIdSchema,
|
|
4158
|
-
description: z19.string().min(1),
|
|
4159
|
-
/** Fake-CLI shim seeded as a workspace file (today's dry-run pattern). */
|
|
4160
|
-
shim: z19.object({ path: z19.string().min(1), content: z19.string() }).strict()
|
|
4161
|
-
}).strict(),
|
|
4162
|
-
z19.object({
|
|
4163
|
-
kind: z19.literal("mcp"),
|
|
4164
|
-
id: MockServiceIdSchema,
|
|
4165
|
-
description: z19.string().min(1),
|
|
4166
|
-
/** Override the local-catalog id when the mock replaces a real dependency. */
|
|
4167
|
-
toolsetId: MockToolsetIdSchema.optional(),
|
|
4168
|
-
/**
|
|
4169
|
-
* Served live by the eval mock rail: each declared tool becomes a
|
|
4170
|
-
* real tool on a per-trial Streamable-HTTP MCP endpoint, installed
|
|
4171
|
-
* into the trial via a local-catalog `mock-mcp-<id>` toolset.
|
|
4172
|
-
* `resultTemplate` is JSON-encoded as the tool result text
|
|
4173
|
-
* (default `{"ok":true}` when absent).
|
|
4174
|
-
*/
|
|
4175
|
-
tools: z19.array(
|
|
4176
|
-
z19.object({
|
|
4177
|
-
name: z19.string().min(1),
|
|
4178
|
-
description: z19.string().min(1),
|
|
4179
|
-
resultTemplate: z19.unknown().optional(),
|
|
4180
|
-
/** Deterministic stateful responses, consumed in call order; the last repeats. */
|
|
4181
|
-
resultSequence: z19.array(z19.unknown()).min(1).optional(),
|
|
4182
|
-
/**
|
|
4183
|
-
* Deterministic eval-only file materialization after this
|
|
4184
|
-
* tool call. The fixture must match the container the
|
|
4185
|
-
* deliverable's extension claims — a `minimal-pptx` written
|
|
4186
|
-
* to a `.docx` path now fails the `binaryDocument` check on
|
|
4187
|
-
* content type rather than sliding through a byte floor.
|
|
4188
|
-
*/
|
|
4189
|
-
writeFixture: z19.object({
|
|
4190
|
-
surface: z19.enum(["workspace", "artifact"]),
|
|
4191
|
-
pathArgument: z19.string().min(1),
|
|
4192
|
-
fixture: z19.enum(["minimal-pptx", "minimal-docx", "minimal-pdf", "minimal-png"])
|
|
4193
|
-
}).strict().optional()
|
|
4194
|
-
}).strict()
|
|
4195
|
-
).min(1)
|
|
4196
|
-
}).strict()
|
|
4197
|
-
]);
|
|
4198
|
-
var CraftbookTestFixtureFileSchema = z19.object({
|
|
4199
|
-
path: z19.string().min(1),
|
|
4200
|
-
content: z19.string(),
|
|
4201
|
-
/** Defaults to `workspace`; `harness` never enters the model-visible project. */
|
|
4202
|
-
surface: z19.enum(["workspace", "artifact", "harness"]).optional(),
|
|
4203
|
-
/**
|
|
4204
|
-
* Whether the fixture is presented to the model as source material.
|
|
4205
|
-
* Defaults to true; false still seeds the file for browsers and graders.
|
|
4206
|
-
*/
|
|
4207
|
-
modelInput: z19.boolean().optional()
|
|
4208
|
-
}).strict();
|
|
4209
|
-
var CraftbookTestWorkerSchema = z19.object({
|
|
4210
|
-
name: z19.string().min(1),
|
|
4211
|
-
role: z19.string().min(1),
|
|
4212
|
-
description: z19.string().optional(),
|
|
4213
|
-
about: z19.string().optional()
|
|
4214
|
-
}).strict();
|
|
4215
|
-
var CraftbookTestSetupSchema = z19.object({
|
|
4216
|
-
projectName: z19.string().min(1),
|
|
4217
|
-
about: z19.string().optional(),
|
|
4218
|
-
missionObjectives: z19.string().optional(),
|
|
4219
|
-
files: z19.array(CraftbookTestFixtureFileSchema).default([]),
|
|
4220
|
-
/** Exact values supplied to the catalog craftbook's `paramSchema`. */
|
|
4221
|
-
craftbookParams: z19.record(z19.string(), z19.string()).optional(),
|
|
4222
|
-
/**
|
|
4223
|
-
* Direct execution target. When present the harness seeds this gezel
|
|
4224
|
-
* and sends the kickoff straight to it (measuring whether the book
|
|
4225
|
-
* guides the work); absent → the Meester routes.
|
|
4226
|
-
*/
|
|
4227
|
-
worker: CraftbookTestWorkerSchema.optional()
|
|
4228
|
-
}).strict();
|
|
4229
|
-
var CraftbookTestDeliverableSchema = z19.object({
|
|
4230
|
-
path: z19.string().min(1),
|
|
4231
|
-
kind: DeliverableKindSchema,
|
|
4232
|
-
minBytes: z19.number().int().positive().optional(),
|
|
4233
|
-
checks: z19.array(CraftbookTestCheckSchema).optional()
|
|
4234
|
-
}).strict();
|
|
4235
|
-
var CraftbookTestMockExpectationSchema = z19.object({
|
|
4236
|
-
/** Mock service id from `mocks[]`. */
|
|
4237
|
-
service: MockServiceIdSchema,
|
|
4238
|
-
minRequests: z19.number().int().positive().optional(),
|
|
4239
|
-
/** Regex sources matched against logged request paths. */
|
|
4240
|
-
requiredPaths: z19.array(z19.string().min(1)).optional(),
|
|
4241
|
-
forbiddenPaths: z19.array(z19.string().min(1)).optional(),
|
|
4242
|
-
/**
|
|
4243
|
-
* Exact MCP tool names that must each have been called at least once
|
|
4244
|
-
* on this service (`kind: 'mcp'` only). Exact names, not regexes —
|
|
4245
|
-
* the tool roster is fully declared in the same file, so a pattern
|
|
4246
|
-
* buys nothing and invites drift. Cross-checked against the mock's
|
|
4247
|
-
* declared `tools[]` at parse time.
|
|
4248
|
-
*/
|
|
4249
|
-
requiredTools: z19.array(z19.string().min(1)).optional(),
|
|
4250
|
-
/** Per-MCP-tool call budgets for repeated journeys or retries. */
|
|
4251
|
-
toolCalls: z19.record(
|
|
4252
|
-
z19.string().min(1),
|
|
4253
|
-
z19.object({
|
|
4254
|
-
minCalls: z19.number().int().nonnegative().default(1),
|
|
4255
|
-
maxCalls: z19.number().int().nonnegative().optional()
|
|
4256
|
-
}).strict().refine(
|
|
4257
|
-
(value) => value.maxCalls === void 0 || value.minCalls <= value.maxCalls,
|
|
4258
|
-
"minCalls must be less than or equal to maxCalls"
|
|
4259
|
-
)
|
|
4260
|
-
).optional()
|
|
4261
|
-
}).strict();
|
|
4262
|
-
var CraftbookTestHistoryExpectationSchema = z19.object({
|
|
4263
|
-
kind: HistoryEventKindSchema,
|
|
4264
|
-
minEntries: z19.number().int().nonnegative().default(1),
|
|
4265
|
-
maxEntries: z19.number().int().nonnegative().optional(),
|
|
4266
|
-
summaryPattern: z19.string().min(1).optional(),
|
|
4267
|
-
flags: z19.string().optional(),
|
|
4268
|
-
details: z19.record(z19.string(), z19.union([z19.string(), z19.number(), z19.boolean(), z19.null()])).optional()
|
|
4269
|
-
}).strict();
|
|
4270
|
-
var CraftbookTestSuccessSchema = z19.object({
|
|
4271
|
-
summary: z19.string().min(1),
|
|
4272
|
-
deliverables: z19.array(CraftbookTestDeliverableSchema).optional(),
|
|
4273
|
-
checks: z19.array(CraftbookTestCheckSchema).optional(),
|
|
4274
|
-
taskNotes: z19.object({
|
|
4275
|
-
minBytes: z19.number().int().positive().optional(),
|
|
4276
|
-
checks: z19.array(CraftbookTestCheckSchema).optional(),
|
|
4277
|
-
requireCraftbookTask: z19.boolean().optional()
|
|
4278
|
-
}).strict().optional(),
|
|
4279
|
-
taskGraph: z19.object({
|
|
4280
|
-
checks: z19.array(CraftbookTestCheckSchema).optional(),
|
|
4281
|
-
requireCraftbookTask: z19.boolean().optional(),
|
|
4282
|
-
/** Require the matching task to reach a terminal step (or complete). */
|
|
4283
|
-
requireTerminalStep: z19.boolean().optional(),
|
|
4284
|
-
requireDraftRef: z19.boolean().optional(),
|
|
4285
|
-
draft: z19.object({
|
|
4286
|
-
status: z19.enum(["draft", "paused", "active", "complete", "canceled"]).optional(),
|
|
4287
|
-
minDescriptionBytes: z19.number().int().positive().optional(),
|
|
4288
|
-
minOutcomes: z19.number().int().positive().optional(),
|
|
4289
|
-
minSteps: z19.number().int().positive().optional(),
|
|
4290
|
-
requireTerminalVerification: z19.boolean().optional(),
|
|
4291
|
-
requireGatedBuildSteps: z19.boolean().optional()
|
|
4292
|
-
}).strict().optional()
|
|
4293
|
-
}).strict().optional(),
|
|
4294
|
-
/** Assertions evaluated against the live mock server's request log. */
|
|
4295
|
-
mocks: z19.array(CraftbookTestMockExpectationSchema).optional(),
|
|
4296
|
-
/** Assertions evaluated against the project's append-only History log. */
|
|
4297
|
-
history: z19.array(CraftbookTestHistoryExpectationSchema).optional(),
|
|
4298
|
-
/** Workspace fixtures whose final content must equal the seeded bytes exactly. */
|
|
4299
|
-
unchangedFixtures: z19.array(z19.string().min(1)).optional()
|
|
4300
|
-
}).strict();
|
|
4301
|
-
var CraftbookTestRubricSchema = z19.object({
|
|
4302
|
-
artifact: z19.object({
|
|
4303
|
-
/** Workspace or artifact path the judge reads (adapter derives the basename). */
|
|
4304
|
-
path: z19.string().min(1),
|
|
4305
|
-
kind: z19.enum(["html", "markdown", "yaml", "typescript", "json", "text"])
|
|
4306
|
-
}).strict(),
|
|
4307
|
-
axes: z19.array(z19.object({ name: z19.string().min(1), description: z19.string().min(1) }).strict()).min(1),
|
|
4308
|
-
contextNote: z19.string().optional()
|
|
4309
|
-
}).strict();
|
|
4310
|
-
var CraftbookTestSpecSchema = z19.object({
|
|
4311
|
-
schemaVersion: z19.literal(CRAFTBOOK_TEST_SCHEMA_VERSION),
|
|
4312
|
-
title: z19.string().min(1),
|
|
4313
|
-
objective: z19.string().min(1),
|
|
4314
|
-
/**
|
|
4315
|
-
* Task-class taxonomy tags (e.g. `html-game`, `corpus`, `external`).
|
|
4316
|
-
* The single declared source for harness selection and batch
|
|
4317
|
-
* planning — replaces the old regex classifiers.
|
|
4318
|
-
*/
|
|
4319
|
-
tags: z19.array(z19.string().min(1)).default([]),
|
|
4320
|
-
/** Kickoff chat message the harness sends. Required — every book runs. */
|
|
4321
|
-
prompt: z19.string().min(1),
|
|
4322
|
-
setup: CraftbookTestSetupSchema,
|
|
4323
|
-
mocks: z19.array(MockServiceSchema).default([]),
|
|
4324
|
-
success: CraftbookTestSuccessSchema,
|
|
4325
|
-
rubric: CraftbookTestRubricSchema,
|
|
4326
|
-
qualityFocus: z19.array(z19.string().min(1)).default([]),
|
|
4327
|
-
/**
|
|
4328
|
-
* Sanctioned escape hatch for experiments — carried opaquely, never
|
|
4329
|
-
* interpreted by CI. Promote a field out of here before relying on it.
|
|
4330
|
-
*/
|
|
4331
|
-
extensions: z19.record(z19.string(), z19.unknown()).optional()
|
|
4332
|
-
}).strict().superRefine((spec, ctx) => {
|
|
4333
|
-
const mockIds = new Set(spec.mocks.map((m) => m.id));
|
|
4334
|
-
const mockById = new Map(spec.mocks.map((m) => [m.id, m]));
|
|
4335
|
-
for (const [i, expectation] of (spec.success.mocks ?? []).entries()) {
|
|
4336
|
-
if (!mockIds.has(expectation.service)) {
|
|
4337
|
-
ctx.addIssue({
|
|
4338
|
-
code: z19.ZodIssueCode.custom,
|
|
4339
|
-
path: ["success", "mocks", i, "service"],
|
|
4340
|
-
message: `success.mocks[${i}] references unknown mock service "${expectation.service}"`
|
|
4341
|
-
});
|
|
4342
|
-
}
|
|
4343
|
-
if (expectation.requiredTools && expectation.requiredTools.length > 0) {
|
|
4344
|
-
const target = mockById.get(expectation.service);
|
|
4345
|
-
if (target && target.kind !== "mcp") {
|
|
4346
|
-
ctx.addIssue({
|
|
4347
|
-
code: z19.ZodIssueCode.custom,
|
|
4348
|
-
path: ["success", "mocks", i, "requiredTools"],
|
|
4349
|
-
message: `success.mocks[${i}].requiredTools requires an mcp service; "${expectation.service}" is kind "${target.kind}"`
|
|
4350
|
-
});
|
|
4351
|
-
} else if (target?.kind === "mcp") {
|
|
4352
|
-
const declared = new Set(target.tools.map((tool) => tool.name));
|
|
4353
|
-
for (const name of expectation.requiredTools) {
|
|
4354
|
-
if (!declared.has(name)) {
|
|
4355
|
-
ctx.addIssue({
|
|
4356
|
-
code: z19.ZodIssueCode.custom,
|
|
4357
|
-
path: ["success", "mocks", i, "requiredTools"],
|
|
4358
|
-
message: `success.mocks[${i}].requiredTools names undeclared tool "${name}" on mcp service "${expectation.service}"`
|
|
4359
|
-
});
|
|
4360
|
-
}
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
}
|
|
4364
|
-
if (expectation.toolCalls && Object.keys(expectation.toolCalls).length > 0) {
|
|
4365
|
-
const target = mockById.get(expectation.service);
|
|
4366
|
-
if (target && target.kind !== "mcp") {
|
|
4367
|
-
ctx.addIssue({
|
|
4368
|
-
code: z19.ZodIssueCode.custom,
|
|
4369
|
-
path: ["success", "mocks", i, "toolCalls"],
|
|
4370
|
-
message: `success.mocks[${i}].toolCalls requires an mcp service; "${expectation.service}" is kind "${target.kind}"`
|
|
4371
|
-
});
|
|
4372
|
-
} else if (target?.kind === "mcp") {
|
|
4373
|
-
const declared = new Set(target.tools.map((tool) => tool.name));
|
|
4374
|
-
for (const name of Object.keys(expectation.toolCalls)) {
|
|
4375
|
-
if (!declared.has(name)) {
|
|
4376
|
-
ctx.addIssue({
|
|
4377
|
-
code: z19.ZodIssueCode.custom,
|
|
4378
|
-
path: ["success", "mocks", i, "toolCalls", name],
|
|
4379
|
-
message: `success.mocks[${i}].toolCalls names undeclared tool "${name}" on mcp service "${expectation.service}"`
|
|
4380
|
-
});
|
|
4381
|
-
}
|
|
4382
|
-
}
|
|
4383
|
-
}
|
|
4384
|
-
}
|
|
4385
|
-
}
|
|
4386
|
-
for (const [i, mock] of spec.mocks.entries()) {
|
|
4387
|
-
if (mock.kind === "http" && mock.credential.name !== `mock.${mock.id}`) {
|
|
4388
|
-
ctx.addIssue({
|
|
4389
|
-
code: z19.ZodIssueCode.custom,
|
|
4390
|
-
path: ["mocks", i, "credential", "name"],
|
|
4391
|
-
message: `http mock "${mock.id}" must use credential name "mock.${mock.id}"`
|
|
4392
|
-
});
|
|
4393
|
-
}
|
|
4394
|
-
}
|
|
4395
|
-
const workspaceFixtures = new Set(
|
|
4396
|
-
spec.setup.files.filter((file) => file.surface === void 0 || file.surface === "workspace").map((file) => file.path)
|
|
4397
|
-
);
|
|
4398
|
-
for (const [i, path] of (spec.success.unchangedFixtures ?? []).entries()) {
|
|
4399
|
-
if (!workspaceFixtures.has(path)) {
|
|
4400
|
-
ctx.addIssue({
|
|
4401
|
-
code: z19.ZodIssueCode.custom,
|
|
4402
|
-
path: ["success", "unchangedFixtures", i],
|
|
4403
|
-
message: `unchanged fixture "${path}" is not a seeded workspace file`
|
|
4404
|
-
});
|
|
4405
|
-
}
|
|
4406
|
-
}
|
|
4407
|
-
for (const [i, expectation] of (spec.success.history ?? []).entries()) {
|
|
4408
|
-
if (expectation.maxEntries !== void 0 && expectation.minEntries > expectation.maxEntries) {
|
|
4409
|
-
ctx.addIssue({
|
|
4410
|
-
code: z19.ZodIssueCode.custom,
|
|
4411
|
-
path: ["success", "history", i],
|
|
4412
|
-
message: "minEntries must be less than or equal to maxEntries"
|
|
4413
|
-
});
|
|
4414
|
-
}
|
|
4415
|
-
}
|
|
4416
|
-
});
|
|
4417
|
-
function parseCraftbookTestSpec(raw, opts) {
|
|
4418
|
-
const mode = opts?.mode ?? "strict";
|
|
4419
|
-
const candidate = mode === "tolerant" ? deepStripUnknown(raw) : raw;
|
|
4420
|
-
const parsed = CraftbookTestSpecSchema.safeParse(candidate);
|
|
4421
|
-
if (parsed.success) return { ok: true, spec: parsed.data };
|
|
4422
|
-
return {
|
|
4423
|
-
ok: false,
|
|
4424
|
-
errors: parsed.error.issues.map((issue) => {
|
|
4425
|
-
const path = issue.path.length > 0 ? issue.path.map(String).join(".") : "<root>";
|
|
4426
|
-
return `${path}: ${issue.message}`;
|
|
4427
|
-
})
|
|
4428
|
-
};
|
|
4429
|
-
}
|
|
4430
|
-
function deepStripUnknown(raw) {
|
|
4431
|
-
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
4432
|
-
const record = structuredClone(raw);
|
|
4433
|
-
const version = record.schemaVersion;
|
|
4434
|
-
if (typeof version === "number" && Number.isInteger(version) && version > CRAFTBOOK_TEST_SCHEMA_VERSION) {
|
|
4435
|
-
record.schemaVersion = CRAFTBOOK_TEST_SCHEMA_VERSION;
|
|
4436
|
-
}
|
|
4437
|
-
for (let pass = 0; pass < 16; pass++) {
|
|
4438
|
-
const attempt = CraftbookTestSpecSchema.safeParse(record);
|
|
4439
|
-
if (attempt.success) return record;
|
|
4440
|
-
const unknownKeyIssues = attempt.error.issues.filter(
|
|
4441
|
-
(issue) => issue.code === z19.ZodIssueCode.unrecognized_keys
|
|
4442
|
-
);
|
|
4443
|
-
if (unknownKeyIssues.length === 0) return record;
|
|
4444
|
-
for (const issue of unknownKeyIssues) {
|
|
4445
|
-
const target = resolvePath(record, issue.path);
|
|
4446
|
-
if (target && typeof target === "object" && !Array.isArray(target)) {
|
|
4447
|
-
for (const key of issue.keys) delete target[key];
|
|
4448
|
-
}
|
|
4449
|
-
}
|
|
4450
|
-
}
|
|
4451
|
-
return record;
|
|
4452
|
-
}
|
|
4453
|
-
function resolvePath(root, path) {
|
|
4454
|
-
let node = root;
|
|
4455
|
-
for (const segment of path) {
|
|
4456
|
-
if (node === null || typeof node !== "object") return void 0;
|
|
4457
|
-
node = node[segment];
|
|
4458
|
-
}
|
|
4459
|
-
return node;
|
|
4460
|
-
}
|
|
4461
|
-
|
|
4462
|
-
// src/schemas/codex-setup.ts
|
|
4463
|
-
import { z as z20 } from "zod";
|
|
4464
|
-
var CodexSetupModelOptionSchema = z20.object({
|
|
4465
|
-
id: z20.string().min(1),
|
|
4466
|
-
label: z20.string().min(1),
|
|
4467
|
-
description: z20.string().optional(),
|
|
4468
|
-
kind: z20.enum(["gezel", "model"]).default("model"),
|
|
4469
|
-
provider: z20.string().min(1),
|
|
4470
|
-
/** Stable gezel id for persona-backed entries. Absent on raw-model entries. */
|
|
4471
|
-
gezelId: z20.string().min(1).optional(),
|
|
4472
|
-
role: z20.string().min(1).optional(),
|
|
4473
|
-
/** Human-readable name of the effective inference model behind a gezel. */
|
|
4474
|
-
modelLabel: z20.string().min(1).optional(),
|
|
4475
|
-
contextWindow: z20.number().int().positive().optional(),
|
|
4476
|
-
supportsReasoning: z20.boolean().optional(),
|
|
4477
|
-
supportsTools: z20.boolean().optional()
|
|
4478
|
-
});
|
|
4479
|
-
var CodexSetupStateSchema = z20.enum([
|
|
4480
|
-
"not-configured",
|
|
4481
|
-
"configured",
|
|
4482
|
-
"update-needed",
|
|
4483
|
-
"conflict",
|
|
4484
|
-
"unavailable"
|
|
4485
|
-
]);
|
|
4486
|
-
var CodexSetupStatusResponseSchema = z20.object({
|
|
4487
|
-
state: CodexSetupStateSchema,
|
|
4488
|
-
models: z20.array(CodexSetupModelOptionSchema),
|
|
4489
|
-
configuredModel: z20.string().optional(),
|
|
4490
|
-
recommendedModel: z20.string().optional(),
|
|
4491
|
-
reasons: z20.array(z20.string()),
|
|
4492
|
-
message: z20.string().optional(),
|
|
4493
|
-
codexInstalled: z20.boolean(),
|
|
4494
|
-
codexVersion: z20.string().optional(),
|
|
4495
|
-
codexPath: z20.string().optional(),
|
|
4496
|
-
endpointsEnabled: z20.boolean(),
|
|
4497
|
-
profileName: z20.string().min(1),
|
|
4498
|
-
profilePath: z20.string().min(1),
|
|
4499
|
-
launchCommand: z20.string().min(1),
|
|
4500
|
-
bridge: z20.object({
|
|
4501
|
-
baseUrl: z20.string().url(),
|
|
4502
|
-
listening: z20.boolean(),
|
|
4503
|
-
port: z20.number().int().nonnegative()
|
|
4504
|
-
}),
|
|
4505
|
-
canConfigure: z20.boolean(),
|
|
4506
|
-
/** Whether Gezel-owned credential/state material exists and can be safely removed. */
|
|
4507
|
-
canRemove: z20.boolean()
|
|
4508
|
-
});
|
|
4509
|
-
var ConfigureCodexRequestSchema = z20.object({
|
|
4510
|
-
model: z20.string().min(1)
|
|
4511
|
-
});
|
|
4512
|
-
|
|
4513
4127
|
// src/schemas/project.ts
|
|
4514
|
-
import { z as
|
|
4515
|
-
var HttpsOriginSchema =
|
|
4128
|
+
import { z as z19 } from "zod";
|
|
4129
|
+
var HttpsOriginSchema = z19.string().url().refine(
|
|
4516
4130
|
(value) => {
|
|
4517
4131
|
try {
|
|
4518
4132
|
const url = new URL(value);
|
|
@@ -4523,7 +4137,7 @@ var HttpsOriginSchema = z21.string().url().refine(
|
|
|
4523
4137
|
},
|
|
4524
4138
|
{ message: "must be an exact HTTPS origin (for example https://api.example.com)" }
|
|
4525
4139
|
);
|
|
4526
|
-
var ProjectGitHubSchema =
|
|
4140
|
+
var ProjectGitHubSchema = z19.object({
|
|
4527
4141
|
// Accept any non-empty string. Git URLs come in many forms beyond
|
|
4528
4142
|
// `https://`: ssh shorthand (`git@github.com:owner/repo`), local
|
|
4529
4143
|
// filesystem paths (`/path/to/bare.git`), other-host references.
|
|
@@ -4531,89 +4145,89 @@ var ProjectGitHubSchema = z21.object({
|
|
|
4531
4145
|
// and broke Phase-3 worktree tests that use a local bare repo as
|
|
4532
4146
|
// the upstream. Higher layers (the github sync code) parse the URL
|
|
4533
4147
|
// and reject anything that doesn't shape up as a clonable ref.
|
|
4534
|
-
url:
|
|
4535
|
-
branch:
|
|
4148
|
+
url: z19.string().min(1),
|
|
4149
|
+
branch: z19.string().optional(),
|
|
4536
4150
|
/** Resolved absolute path to the working tree. Managed by the service. */
|
|
4537
|
-
checkoutDir:
|
|
4538
|
-
lastSyncedAt:
|
|
4151
|
+
checkoutDir: z19.string().optional(),
|
|
4152
|
+
lastSyncedAt: z19.string().optional(),
|
|
4539
4153
|
/** Repo default branch (e.g. "main"), detected lazily and cached. Managed by the service. */
|
|
4540
|
-
defaultBranch:
|
|
4154
|
+
defaultBranch: z19.string().optional()
|
|
4541
4155
|
});
|
|
4542
|
-
var ProjectConnectorBindingSchema =
|
|
4156
|
+
var ProjectConnectorBindingSchema = z19.object({
|
|
4543
4157
|
/** Stable binding id; also the SecretStore `fieldId` + corpus-slug seed. */
|
|
4544
|
-
id:
|
|
4158
|
+
id: z19.string().min(1),
|
|
4545
4159
|
/** The connector-type catalog id, e.g. `mail-gmail`, `linear-issues`. */
|
|
4546
|
-
type:
|
|
4160
|
+
type: z19.string().min(1),
|
|
4547
4161
|
/** Catalog source the type resolved from (provenance/pin). */
|
|
4548
|
-
sourceId:
|
|
4162
|
+
sourceId: z19.string().optional(),
|
|
4549
4163
|
/** Pinned connector-type version. */
|
|
4550
|
-
version:
|
|
4551
|
-
displayName:
|
|
4164
|
+
version: z19.string().optional(),
|
|
4165
|
+
displayName: z19.string().optional(),
|
|
4552
4166
|
/**
|
|
4553
4167
|
* Artifact-relative corpus root (`data/<corpusName>`), resolved once at bind
|
|
4554
4168
|
* time and never recomputed — renaming a binding must not strand its corpus.
|
|
4555
4169
|
*/
|
|
4556
|
-
corpusDir:
|
|
4170
|
+
corpusDir: z19.string().optional(),
|
|
4557
4171
|
/** Per-binding config, validated at bind time against the type's `configSchema`. */
|
|
4558
|
-
config:
|
|
4172
|
+
config: z19.record(z19.string(), z19.unknown()).default({}),
|
|
4559
4173
|
/** Opaque, adapter-shaped incremental-sync cursor. Persisted so resync resumes. */
|
|
4560
|
-
cursor:
|
|
4174
|
+
cursor: z19.unknown().optional(),
|
|
4561
4175
|
/** Pause syncing without unbinding. */
|
|
4562
|
-
disabled:
|
|
4563
|
-
lastSyncedAt:
|
|
4176
|
+
disabled: z19.boolean().optional(),
|
|
4177
|
+
lastSyncedAt: z19.string().optional(),
|
|
4564
4178
|
/** Last sync error, surfaced in the UI; cleared on the next success. */
|
|
4565
|
-
lastError:
|
|
4179
|
+
lastError: z19.string().optional()
|
|
4566
4180
|
});
|
|
4567
|
-
var ProjectNudgeConfigSchema =
|
|
4568
|
-
enabled:
|
|
4569
|
-
rapidIntervalMs:
|
|
4570
|
-
slowIntervalMs:
|
|
4571
|
-
recentActivityWindowMs:
|
|
4572
|
-
rapidAttemptsBeforeBackoff:
|
|
4181
|
+
var ProjectNudgeConfigSchema = z19.object({
|
|
4182
|
+
enabled: z19.boolean().optional(),
|
|
4183
|
+
rapidIntervalMs: z19.number().int().positive().optional(),
|
|
4184
|
+
slowIntervalMs: z19.number().int().positive().optional(),
|
|
4185
|
+
recentActivityWindowMs: z19.number().int().positive().optional(),
|
|
4186
|
+
rapidAttemptsBeforeBackoff: z19.number().int().positive().optional(),
|
|
4573
4187
|
/**
|
|
4574
4188
|
* Grace period applied to the very first nudge a project ever
|
|
4575
4189
|
* receives, measured from `project.createdAt`. Default per tempo;
|
|
4576
4190
|
* setting `0` opts out (legacy behavior — first nudge fires as
|
|
4577
4191
|
* soon as the rapid interval allows).
|
|
4578
4192
|
*/
|
|
4579
|
-
firstNudgeGraceMs:
|
|
4193
|
+
firstNudgeGraceMs: z19.number().int().nonnegative().optional()
|
|
4580
4194
|
});
|
|
4581
|
-
var ProjectNudgeStateSchema =
|
|
4582
|
-
lastNudgedAt:
|
|
4583
|
-
consecutiveRapidNudges:
|
|
4195
|
+
var ProjectNudgeStateSchema = z19.object({
|
|
4196
|
+
lastNudgedAt: z19.string().optional(),
|
|
4197
|
+
consecutiveRapidNudges: z19.number().int().nonnegative().optional()
|
|
4584
4198
|
});
|
|
4585
|
-
var ProjectTabVisibilitySchema =
|
|
4586
|
-
overview:
|
|
4587
|
-
tasks:
|
|
4588
|
-
approvals:
|
|
4589
|
-
workspace:
|
|
4590
|
-
artifacts:
|
|
4591
|
-
map:
|
|
4199
|
+
var ProjectTabVisibilitySchema = z19.object({
|
|
4200
|
+
overview: z19.boolean().optional(),
|
|
4201
|
+
tasks: z19.boolean().optional(),
|
|
4202
|
+
approvals: z19.boolean().optional(),
|
|
4203
|
+
workspace: z19.boolean().optional(),
|
|
4204
|
+
artifacts: z19.boolean().optional(),
|
|
4205
|
+
map: z19.boolean().optional()
|
|
4592
4206
|
}).strict();
|
|
4593
|
-
var ProjectManagedWorkspaceWritePolicySchema =
|
|
4594
|
-
var ProjectTypeProvenanceSchema =
|
|
4207
|
+
var ProjectManagedWorkspaceWritePolicySchema = z19.enum(["auto", "allow", "deny"]);
|
|
4208
|
+
var ProjectTypeProvenanceSchema = z19.object({
|
|
4595
4209
|
/** Catalog id of the applied project type. */
|
|
4596
|
-
id:
|
|
4210
|
+
id: z19.string(),
|
|
4597
4211
|
/** Type version installed at adoption. */
|
|
4598
|
-
version:
|
|
4212
|
+
version: z19.string(),
|
|
4599
4213
|
/** Catalog source the type resolved from (`bundled` | `local` | `community` | …). */
|
|
4600
|
-
source:
|
|
4214
|
+
source: z19.string(),
|
|
4601
4215
|
/** Param values collected at adoption, substituted into templates + seed files. */
|
|
4602
|
-
params:
|
|
4216
|
+
params: z19.record(z19.string(), z19.unknown()).optional(),
|
|
4603
4217
|
/** ISO timestamp of adoption. */
|
|
4604
|
-
appliedAt:
|
|
4218
|
+
appliedAt: z19.string()
|
|
4605
4219
|
});
|
|
4606
|
-
var ProjectSchema =
|
|
4220
|
+
var ProjectSchema = z19.object({
|
|
4607
4221
|
id: EntityIdSchema,
|
|
4608
|
-
name:
|
|
4609
|
-
description:
|
|
4610
|
-
workingDir:
|
|
4222
|
+
name: z19.string(),
|
|
4223
|
+
description: z19.string().optional(),
|
|
4224
|
+
workingDir: z19.string().optional(),
|
|
4611
4225
|
/** Optional gezel that acts as the project's voorman (foreman). Surfaces in
|
|
4612
4226
|
* the project detail pane, flows into the system prompt when a session is
|
|
4613
4227
|
* scoped here. For solo projects (`mode === 'solo'`) this same field
|
|
4614
4228
|
* holds the project's ambachtsman — the data is unchanged, only the
|
|
4615
4229
|
* label flips. */
|
|
4616
|
-
voormanGezelId:
|
|
4230
|
+
voormanGezelId: z19.string().optional(),
|
|
4617
4231
|
/**
|
|
4618
4232
|
* Internal marker: ISO timestamp of the one-time automatic voorman
|
|
4619
4233
|
* assignment. The indexer ensures every project ends up with a voorman
|
|
@@ -4623,7 +4237,7 @@ var ProjectSchema = z21.object({
|
|
|
4623
4237
|
* silently re-populated on the next scan. Not user-editable; absent on
|
|
4624
4238
|
* projects last written before this field existed.
|
|
4625
4239
|
*/
|
|
4626
|
-
voormanAutoAssignedAt:
|
|
4240
|
+
voormanAutoAssignedAt: z19.string().optional(),
|
|
4627
4241
|
/**
|
|
4628
4242
|
* Roster — gezels that have been pulled into this project. Populated
|
|
4629
4243
|
* automatically the first time a gezel is set as voorman, opens a
|
|
@@ -4638,7 +4252,7 @@ var ProjectSchema = z21.object({
|
|
|
4638
4252
|
* (back-compat with every project written before this field
|
|
4639
4253
|
* existed).
|
|
4640
4254
|
*/
|
|
4641
|
-
gezelIds:
|
|
4255
|
+
gezelIds: z19.array(z19.string()).optional(),
|
|
4642
4256
|
/**
|
|
4643
4257
|
* Suggested-work keys the user has dismissed ("don't offer this again
|
|
4644
4258
|
* here"). Advisory UI state, same spirit as `gezelIds`: enabling a
|
|
@@ -4648,7 +4262,7 @@ var ProjectSchema = z21.object({
|
|
|
4648
4262
|
* `project-type:<typeId>:<scheduleKey>`). Deliberately not exposed
|
|
4649
4263
|
* through the model-facing `update_project` MCP tool.
|
|
4650
4264
|
*/
|
|
4651
|
-
suggestedWorkDismissed:
|
|
4265
|
+
suggestedWorkDismissed: z19.array(z19.string()).optional(),
|
|
4652
4266
|
/**
|
|
4653
4267
|
* Shared per-project configuration values ("project properties") that
|
|
4654
4268
|
* craftbook params and features draw from — e.g. `content.language`,
|
|
@@ -4657,7 +4271,7 @@ var ProjectSchema = z21.object({
|
|
|
4657
4271
|
* ids are allowed (the registry improves display, it doesn't gate).
|
|
4658
4272
|
* Values are plain strings; empty string is treated as unset.
|
|
4659
4273
|
*/
|
|
4660
|
-
properties:
|
|
4274
|
+
properties: z19.record(z19.string(), z19.string()).optional(),
|
|
4661
4275
|
/**
|
|
4662
4276
|
* Project shape. `crew` (the default) is the original behavior — the
|
|
4663
4277
|
* voorman recruits and coordinates a team of specialists. `solo` is a
|
|
@@ -4668,7 +4282,7 @@ var ProjectSchema = z21.object({
|
|
|
4668
4282
|
* for back-compat with every project on disk before this field
|
|
4669
4283
|
* existed.
|
|
4670
4284
|
*/
|
|
4671
|
-
mode:
|
|
4285
|
+
mode: z19.enum(["crew", "solo"]).optional(),
|
|
4672
4286
|
/**
|
|
4673
4287
|
* Optional custom label for this project's lead gezel, overriding the
|
|
4674
4288
|
* mode-based default ("Voorman" / "Ambachtsman") everywhere the UI
|
|
@@ -4676,7 +4290,7 @@ var ProjectSchema = z21.object({
|
|
|
4676
4290
|
* "Opponent"); absent → the mode default. The data field stays
|
|
4677
4291
|
* `voormanGezelId` — only the label changes.
|
|
4678
4292
|
*/
|
|
4679
|
-
leadLabel:
|
|
4293
|
+
leadLabel: z19.string().optional(),
|
|
4680
4294
|
/**
|
|
4681
4295
|
* Lean-agent profile (set by a project type at adoption, e.g. checkers).
|
|
4682
4296
|
* When true, sessions here get a minimal tool surface (the type's script
|
|
@@ -4684,7 +4298,7 @@ var ProjectSchema = z21.object({
|
|
|
4684
4298
|
* scaffolding). Keeps small local models from being overwhelmed on a
|
|
4685
4299
|
* focused single-purpose task. Absent → the full agent profile.
|
|
4686
4300
|
*/
|
|
4687
|
-
leanProfile:
|
|
4301
|
+
leanProfile: z19.boolean().optional(),
|
|
4688
4302
|
/**
|
|
4689
4303
|
* Per-project workspace-indexing switch. Missing/true preserves the
|
|
4690
4304
|
* historical behavior: structural discovery plus the content-index refresh
|
|
@@ -4697,9 +4311,9 @@ var ProjectSchema = z21.object({
|
|
|
4697
4311
|
* document index. Project-type manifests may seed the value at adoption and
|
|
4698
4312
|
* the user can override it later in Project Settings.
|
|
4699
4313
|
*/
|
|
4700
|
-
indexingEnabled:
|
|
4314
|
+
indexingEnabled: z19.boolean().optional(),
|
|
4701
4315
|
github: ProjectGitHubSchema.optional(),
|
|
4702
|
-
connectors:
|
|
4316
|
+
connectors: z19.array(ProjectConnectorBindingSchema).optional(),
|
|
4703
4317
|
nudgeConfig: ProjectNudgeConfigSchema.optional(),
|
|
4704
4318
|
nudgeState: ProjectNudgeStateSchema.optional(),
|
|
4705
4319
|
/**
|
|
@@ -4722,7 +4336,7 @@ var ProjectSchema = z21.object({
|
|
|
4722
4336
|
* @deprecated Use `managedWorkspaceWritePolicy` and the centralized
|
|
4723
4337
|
* `projectManagedWorkspaceWritable` resolver.
|
|
4724
4338
|
*/
|
|
4725
|
-
allowGezelWrites:
|
|
4339
|
+
allowGezelWrites: z19.boolean().optional(),
|
|
4726
4340
|
/**
|
|
4727
4341
|
* Per-project Codex execution posture selected from the project status bar.
|
|
4728
4342
|
* It overrides per-gezel/install Codex defaults so the visible control is
|
|
@@ -4759,7 +4373,7 @@ var ProjectSchema = z21.object({
|
|
|
4759
4373
|
* weak local model having to take an explicit action. Reversible and
|
|
4760
4374
|
* non-destructive; chat and direct tool calls keep working.
|
|
4761
4375
|
*/
|
|
4762
|
-
status:
|
|
4376
|
+
status: z19.enum(["active", "readonly", "inactive", "stable"]).optional(),
|
|
4763
4377
|
/**
|
|
4764
4378
|
* Bury this project in the navigation without deleting it. Archived
|
|
4765
4379
|
* projects remain available from the dedicated section in the full
|
|
@@ -4769,13 +4383,13 @@ var ProjectSchema = z21.object({
|
|
|
4769
4383
|
* Missing/false means visible in the ordinary project UX, preserving
|
|
4770
4384
|
* compatibility with projects written before archiving existed.
|
|
4771
4385
|
*/
|
|
4772
|
-
archived:
|
|
4386
|
+
archived: z19.boolean().optional(),
|
|
4773
4387
|
/**
|
|
4774
4388
|
* Per-project override of the `run_nodejs_script` wall-clock
|
|
4775
4389
|
* timeout. Clamped between 30 seconds and 30 minutes. Missing →
|
|
4776
4390
|
* the service-side default (5 min) applies.
|
|
4777
4391
|
*/
|
|
4778
|
-
workspaceScriptTimeoutMs:
|
|
4392
|
+
workspaceScriptTimeoutMs: z19.number().int().min(3e4).max(30 * 6e4).optional(),
|
|
4779
4393
|
/**
|
|
4780
4394
|
* Named credentials this project is explicitly allowed to use.
|
|
4781
4395
|
* Credentials are stored once globally in `SecretStore`; a grant
|
|
@@ -4784,76 +4398,515 @@ var ProjectSchema = z21.object({
|
|
|
4784
4398
|
* Missing → no credentials granted. See `scripts/dispatcher.ts`
|
|
4785
4399
|
* and `secrets/registry.ts` for resolution.
|
|
4786
4400
|
*/
|
|
4787
|
-
grantedCredentials:
|
|
4401
|
+
grantedCredentials: z19.array(z19.string()).optional(),
|
|
4402
|
+
/**
|
|
4403
|
+
* Advanced exact-origin bindings for toolset credentials. Built-in provider
|
|
4404
|
+
* credentials are service-pinned and webhook credentials follow the
|
|
4405
|
+
* configured webhook URL, so entries for those names are ignored.
|
|
4406
|
+
*/
|
|
4407
|
+
credentialAllowedOrigins: z19.record(z19.string(), z19.array(HttpsOriginSchema)).optional(),
|
|
4408
|
+
/**
|
|
4409
|
+
* Explicit user override of the project's type (an id from the bundled
|
|
4410
|
+
* project-type taxonomy, see `project-types/taxonomy.ts`). When set, it
|
|
4411
|
+
* wins over `detectedProjectType` for craftbook suggestions. Cleared
|
|
4412
|
+
* (unset) → fall back to auto-detection. Missing on every project written
|
|
4413
|
+
* before this field existed.
|
|
4414
|
+
*/
|
|
4415
|
+
projectTypeId: z19.string().optional(),
|
|
4416
|
+
/**
|
|
4417
|
+
* Auto-detected project type, recomputed on each content-index scan from
|
|
4418
|
+
* the workspace file mix + about/mission text. Not user-editable — the
|
|
4419
|
+
* user expresses an override via `projectTypeId`. Absent until the first
|
|
4420
|
+
* scan classifies the project (or when nothing scores above the floor).
|
|
4421
|
+
*/
|
|
4422
|
+
detectedProjectType: z19.object({
|
|
4423
|
+
id: z19.string(),
|
|
4424
|
+
score: z19.number(),
|
|
4425
|
+
scannedAt: z19.string()
|
|
4426
|
+
}).optional(),
|
|
4427
|
+
/**
|
|
4428
|
+
* Provenance of an applied custom project type (see docs/project-types.md).
|
|
4429
|
+
* Distinct from `projectTypeId`, which is the taxonomy id used for craftbook
|
|
4430
|
+
* suggestion: a custom type stamps this on adoption and, when it `extends` a
|
|
4431
|
+
* taxonomy id, ALSO sets `projectTypeId` so detection-based suggestion
|
|
4432
|
+
* inherits. Absent on projects created without a custom type.
|
|
4433
|
+
*/
|
|
4434
|
+
projectType: ProjectTypeProvenanceSchema.optional(),
|
|
4435
|
+
/**
|
|
4436
|
+
* Filesystem ownership boundary. Missing/`user` is ordinary per-account
|
|
4437
|
+
* state. `machine-shared` is a grandfathered project mounted from the
|
|
4438
|
+
* installer-managed shared root and operated on by this user's daemon.
|
|
4439
|
+
* The engine broker never opens the project or receives its paths.
|
|
4440
|
+
*/
|
|
4441
|
+
storageScope: z19.enum(["user", "machine-shared"]).optional(),
|
|
4442
|
+
createdAt: z19.string(),
|
|
4443
|
+
updatedAt: z19.string()
|
|
4444
|
+
});
|
|
4445
|
+
function resolveProjectTypeId(project) {
|
|
4446
|
+
return project.projectTypeId ?? project.detectedProjectType?.id;
|
|
4447
|
+
}
|
|
4448
|
+
function projectAllowsAmbientWork(project) {
|
|
4449
|
+
const status = project.status ?? "active";
|
|
4450
|
+
return status === "active";
|
|
4451
|
+
}
|
|
4452
|
+
var InstalledPackageSchema = z19.object({
|
|
4453
|
+
name: z19.string(),
|
|
4454
|
+
version: z19.string()
|
|
4455
|
+
});
|
|
4456
|
+
var ProjectDetailSchema = ProjectSchema.extend({
|
|
4457
|
+
packages: z19.array(InstalledPackageSchema),
|
|
4458
|
+
/** Contents of `documents/about.md` inside the project, if present. */
|
|
4459
|
+
about: z19.string().optional(),
|
|
4460
|
+
/** Contents of `documents/missionObjectives.md`, if present. */
|
|
4461
|
+
missionObjectives: z19.string().optional()
|
|
4462
|
+
});
|
|
4463
|
+
var ProjectFileEntrySchema = z19.object({
|
|
4464
|
+
name: z19.string(),
|
|
4465
|
+
path: z19.string(),
|
|
4466
|
+
isDirectory: z19.boolean(),
|
|
4467
|
+
/** File mtime (ms epoch). Populated only when the caller opts into stats. */
|
|
4468
|
+
mtimeMs: z19.number().optional()
|
|
4469
|
+
});
|
|
4470
|
+
var ProjectGithubSchema = ProjectGitHubSchema;
|
|
4471
|
+
|
|
4472
|
+
// src/schemas/craftbook-test.ts
|
|
4473
|
+
var CRAFTBOOK_TEST_SCHEMA_VERSION = 1;
|
|
4474
|
+
var CRAFTBOOK_TEST_FILENAME = "test.json";
|
|
4475
|
+
var PrometheusAlertsCheckSchema = z20.object({
|
|
4476
|
+
kind: z20.literal("prometheusAlerts"),
|
|
4477
|
+
file: z20.string().min(1),
|
|
4478
|
+
minRules: z20.number().int().positive().optional(),
|
|
4479
|
+
maxPageAlerts: z20.number().int().nonnegative().optional(),
|
|
4480
|
+
allowedSeverities: z20.array(z20.string().min(1)).optional(),
|
|
4481
|
+
requiredServices: z20.array(z20.string().min(1)).optional(),
|
|
4482
|
+
requiredRunbookUrls: z20.array(z20.string().min(1)).optional()
|
|
4483
|
+
}).strict();
|
|
4484
|
+
var NodeScriptPassesCheckSchema = z20.object({
|
|
4485
|
+
kind: z20.literal("nodeScriptPasses"),
|
|
4486
|
+
script: z20.string().min(1),
|
|
4487
|
+
timeoutMs: z20.number().int().positive().optional(),
|
|
4488
|
+
requiredOutput: z20.array(
|
|
4489
|
+
z20.object({
|
|
4490
|
+
pattern: z20.string().min(1),
|
|
4491
|
+
flags: z20.string().optional(),
|
|
4492
|
+
label: z20.string().optional()
|
|
4493
|
+
}).strict()
|
|
4494
|
+
).optional()
|
|
4495
|
+
}).strict();
|
|
4496
|
+
var BinaryDocumentCheckSchema = z20.object({
|
|
4497
|
+
kind: z20.literal("binaryDocument"),
|
|
4498
|
+
file: z20.string().min(1),
|
|
4499
|
+
/** Look in the artifacts drawer instead of the workspace. */
|
|
4500
|
+
artifact: z20.boolean().optional(),
|
|
4501
|
+
/** Floor on the container's byte length; defaults to 1000. */
|
|
4502
|
+
minBytes: z20.number().int().positive().optional()
|
|
4503
|
+
}).strict();
|
|
4504
|
+
var CraftbookTestCheckSchema = z20.union([
|
|
4505
|
+
GateCheckSchema,
|
|
4506
|
+
PrometheusAlertsCheckSchema,
|
|
4507
|
+
NodeScriptPassesCheckSchema,
|
|
4508
|
+
BinaryDocumentCheckSchema
|
|
4509
|
+
]);
|
|
4510
|
+
var MockServiceIdSchema = z20.string().min(1).regex(/^[a-z0-9][a-z0-9-]*$/, "mock service ids are lowercase kebab-case");
|
|
4511
|
+
var MockToolsetIdSchema = z20.string().min(1).regex(
|
|
4512
|
+
/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,
|
|
4513
|
+
"mock toolset ids are lowercase catalog ids or scoped npm-style ids"
|
|
4514
|
+
);
|
|
4515
|
+
var MockHttpRouteSchema = z20.object({
|
|
4516
|
+
method: z20.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).default("GET"),
|
|
4517
|
+
/** Exact path, `:param` segments, or a trailing `*` wildcard. */
|
|
4518
|
+
path: z20.string().min(1),
|
|
4519
|
+
status: z20.number().int().min(100).max(599).default(200),
|
|
4520
|
+
headers: z20.record(z20.string(), z20.string()).optional(),
|
|
4521
|
+
/** String bodies are served verbatim; anything else is JSON-encoded. */
|
|
4522
|
+
body: z20.unknown(),
|
|
4523
|
+
latencyMs: z20.number().int().nonnegative().optional()
|
|
4524
|
+
}).strict();
|
|
4525
|
+
var MockServiceSchema = z20.discriminatedUnion("kind", [
|
|
4526
|
+
z20.object({
|
|
4527
|
+
kind: z20.literal("http"),
|
|
4528
|
+
id: MockServiceIdSchema,
|
|
4529
|
+
description: z20.string().min(1),
|
|
4530
|
+
/**
|
|
4531
|
+
* v1 mock HTTP is reachable ONLY through the `http.authed`
|
|
4532
|
+
* credential rail (anonymous script/browser HTTP hard-rejects
|
|
4533
|
+
* loopback), so a credential is required. The harness seeds it and
|
|
4534
|
+
* grants the mock's exact origin on the trial project.
|
|
4535
|
+
*/
|
|
4536
|
+
credential: z20.object({
|
|
4537
|
+
name: z20.string().regex(/^mock\.[a-z0-9][a-z0-9.-]*$/, "mock credentials are named mock.<service-id>"),
|
|
4538
|
+
authScheme: z20.enum(["bearer", "basic"]).optional()
|
|
4539
|
+
}).strict(),
|
|
4540
|
+
routes: z20.array(MockHttpRouteSchema).min(1)
|
|
4541
|
+
}).strict(),
|
|
4542
|
+
z20.object({
|
|
4543
|
+
kind: z20.literal("webhook"),
|
|
4544
|
+
id: MockServiceIdSchema,
|
|
4545
|
+
description: z20.string().min(1),
|
|
4546
|
+
/** Receiver path; defaults to `/webhook` when omitted. */
|
|
4547
|
+
path: z20.string().min(1).optional()
|
|
4548
|
+
}).strict(),
|
|
4549
|
+
z20.object({
|
|
4550
|
+
kind: z20.literal("cli"),
|
|
4551
|
+
id: MockServiceIdSchema,
|
|
4552
|
+
description: z20.string().min(1),
|
|
4553
|
+
/** Fake-CLI shim seeded as a workspace file (today's dry-run pattern). */
|
|
4554
|
+
shim: z20.object({ path: z20.string().min(1), content: z20.string() }).strict()
|
|
4555
|
+
}).strict(),
|
|
4556
|
+
z20.object({
|
|
4557
|
+
kind: z20.literal("mcp"),
|
|
4558
|
+
id: MockServiceIdSchema,
|
|
4559
|
+
description: z20.string().min(1),
|
|
4560
|
+
/** Override the local-catalog id when the mock replaces a real dependency. */
|
|
4561
|
+
toolsetId: MockToolsetIdSchema.optional(),
|
|
4562
|
+
/**
|
|
4563
|
+
* Served live by the eval mock rail: each declared tool becomes a
|
|
4564
|
+
* real tool on a per-trial Streamable-HTTP MCP endpoint, installed
|
|
4565
|
+
* into the trial via a local-catalog `mock-mcp-<id>` toolset.
|
|
4566
|
+
* `resultTemplate` is JSON-encoded as the tool result text
|
|
4567
|
+
* (default `{"ok":true}` when absent).
|
|
4568
|
+
*/
|
|
4569
|
+
tools: z20.array(
|
|
4570
|
+
z20.object({
|
|
4571
|
+
name: z20.string().min(1),
|
|
4572
|
+
description: z20.string().min(1),
|
|
4573
|
+
resultTemplate: z20.unknown().optional(),
|
|
4574
|
+
/** Deterministic stateful responses, consumed in call order; the last repeats. */
|
|
4575
|
+
resultSequence: z20.array(z20.unknown()).min(1).optional(),
|
|
4576
|
+
/**
|
|
4577
|
+
* Deterministic eval-only file materialization after this
|
|
4578
|
+
* tool call. The fixture must match the container the
|
|
4579
|
+
* deliverable's extension claims — a `minimal-pptx` written
|
|
4580
|
+
* to a `.docx` path now fails the `binaryDocument` check on
|
|
4581
|
+
* content type rather than sliding through a byte floor.
|
|
4582
|
+
*/
|
|
4583
|
+
writeFixture: z20.object({
|
|
4584
|
+
surface: z20.enum(["workspace", "artifact"]),
|
|
4585
|
+
pathArgument: z20.string().min(1),
|
|
4586
|
+
fixture: z20.enum(["minimal-pptx", "minimal-docx", "minimal-pdf", "minimal-png"])
|
|
4587
|
+
}).strict().optional()
|
|
4588
|
+
}).strict()
|
|
4589
|
+
).min(1)
|
|
4590
|
+
}).strict()
|
|
4591
|
+
]);
|
|
4592
|
+
var CraftbookTestFixtureFileSchema = z20.object({
|
|
4593
|
+
path: z20.string().min(1),
|
|
4594
|
+
content: z20.string(),
|
|
4595
|
+
/** Defaults to `workspace`; `harness` never enters the model-visible project. */
|
|
4596
|
+
surface: z20.enum(["workspace", "artifact", "harness"]).optional(),
|
|
4788
4597
|
/**
|
|
4789
|
-
*
|
|
4790
|
-
*
|
|
4791
|
-
* configured webhook URL, so entries for those names are ignored.
|
|
4598
|
+
* Whether the fixture is presented to the model as source material.
|
|
4599
|
+
* Defaults to true; false still seeds the file for browsers and graders.
|
|
4792
4600
|
*/
|
|
4793
|
-
|
|
4601
|
+
modelInput: z20.boolean().optional()
|
|
4602
|
+
}).strict();
|
|
4603
|
+
var CraftbookTestWorkerSchema = z20.object({
|
|
4604
|
+
name: z20.string().min(1),
|
|
4605
|
+
role: z20.string().min(1),
|
|
4606
|
+
description: z20.string().optional(),
|
|
4607
|
+
about: z20.string().optional()
|
|
4608
|
+
}).strict();
|
|
4609
|
+
var CraftbookTestSetupSchema = z20.object({
|
|
4610
|
+
projectName: z20.string().min(1),
|
|
4611
|
+
about: z20.string().optional(),
|
|
4612
|
+
missionObjectives: z20.string().optional(),
|
|
4613
|
+
/** Reproduce project write posture before the craftbook task starts. */
|
|
4614
|
+
managedWorkspaceWritePolicy: ProjectManagedWorkspaceWritePolicySchema.optional(),
|
|
4615
|
+
files: z20.array(CraftbookTestFixtureFileSchema).default([]),
|
|
4616
|
+
/** Exact values supplied to the catalog craftbook's `paramSchema`. */
|
|
4617
|
+
craftbookParams: z20.record(z20.string(), z20.string()).optional(),
|
|
4794
4618
|
/**
|
|
4795
|
-
*
|
|
4796
|
-
*
|
|
4797
|
-
*
|
|
4798
|
-
* (unset) → fall back to auto-detection. Missing on every project written
|
|
4799
|
-
* before this field existed.
|
|
4619
|
+
* Direct execution target. When present the harness seeds this gezel
|
|
4620
|
+
* and sends the kickoff straight to it (measuring whether the book
|
|
4621
|
+
* guides the work); absent → the Meester routes.
|
|
4800
4622
|
*/
|
|
4801
|
-
|
|
4623
|
+
worker: CraftbookTestWorkerSchema.optional()
|
|
4624
|
+
}).strict();
|
|
4625
|
+
var CraftbookTestDeliverableSchema = z20.object({
|
|
4626
|
+
path: z20.string().min(1),
|
|
4627
|
+
kind: DeliverableKindSchema,
|
|
4628
|
+
/** Grade the path in the project's artifacts drawer, not its workspace. */
|
|
4629
|
+
artifact: z20.boolean().optional(),
|
|
4630
|
+
minBytes: z20.number().int().positive().optional(),
|
|
4631
|
+
checks: z20.array(CraftbookTestCheckSchema).optional()
|
|
4632
|
+
}).strict();
|
|
4633
|
+
var CraftbookTestMockExpectationSchema = z20.object({
|
|
4634
|
+
/** Mock service id from `mocks[]`. */
|
|
4635
|
+
service: MockServiceIdSchema,
|
|
4636
|
+
minRequests: z20.number().int().positive().optional(),
|
|
4637
|
+
/** Regex sources matched against logged request paths. */
|
|
4638
|
+
requiredPaths: z20.array(z20.string().min(1)).optional(),
|
|
4639
|
+
forbiddenPaths: z20.array(z20.string().min(1)).optional(),
|
|
4802
4640
|
/**
|
|
4803
|
-
*
|
|
4804
|
-
*
|
|
4805
|
-
*
|
|
4806
|
-
*
|
|
4641
|
+
* Exact MCP tool names that must each have been called at least once
|
|
4642
|
+
* on this service (`kind: 'mcp'` only). Exact names, not regexes —
|
|
4643
|
+
* the tool roster is fully declared in the same file, so a pattern
|
|
4644
|
+
* buys nothing and invites drift. Cross-checked against the mock's
|
|
4645
|
+
* declared `tools[]` at parse time.
|
|
4807
4646
|
*/
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4647
|
+
requiredTools: z20.array(z20.string().min(1)).optional(),
|
|
4648
|
+
/** Per-MCP-tool call budgets for repeated journeys or retries. */
|
|
4649
|
+
toolCalls: z20.record(
|
|
4650
|
+
z20.string().min(1),
|
|
4651
|
+
z20.object({
|
|
4652
|
+
minCalls: z20.number().int().nonnegative().default(1),
|
|
4653
|
+
maxCalls: z20.number().int().nonnegative().optional()
|
|
4654
|
+
}).strict().refine(
|
|
4655
|
+
(value) => value.maxCalls === void 0 || value.minCalls <= value.maxCalls,
|
|
4656
|
+
"minCalls must be less than or equal to maxCalls"
|
|
4657
|
+
)
|
|
4658
|
+
).optional()
|
|
4659
|
+
}).strict();
|
|
4660
|
+
var CraftbookTestHistoryExpectationSchema = z20.object({
|
|
4661
|
+
kind: HistoryEventKindSchema,
|
|
4662
|
+
minEntries: z20.number().int().nonnegative().default(1),
|
|
4663
|
+
maxEntries: z20.number().int().nonnegative().optional(),
|
|
4664
|
+
summaryPattern: z20.string().min(1).optional(),
|
|
4665
|
+
flags: z20.string().optional(),
|
|
4666
|
+
details: z20.record(z20.string(), z20.union([z20.string(), z20.number(), z20.boolean(), z20.null()])).optional()
|
|
4667
|
+
}).strict();
|
|
4668
|
+
var CraftbookTestSuccessSchema = z20.object({
|
|
4669
|
+
summary: z20.string().min(1),
|
|
4670
|
+
deliverables: z20.array(CraftbookTestDeliverableSchema).optional(),
|
|
4671
|
+
checks: z20.array(CraftbookTestCheckSchema).optional(),
|
|
4672
|
+
taskNotes: z20.object({
|
|
4673
|
+
minBytes: z20.number().int().positive().optional(),
|
|
4674
|
+
checks: z20.array(CraftbookTestCheckSchema).optional(),
|
|
4675
|
+
requireCraftbookTask: z20.boolean().optional()
|
|
4676
|
+
}).strict().optional(),
|
|
4677
|
+
taskGraph: z20.object({
|
|
4678
|
+
checks: z20.array(CraftbookTestCheckSchema).optional(),
|
|
4679
|
+
requireCraftbookTask: z20.boolean().optional(),
|
|
4680
|
+
/** Require the matching task to reach a terminal step (or complete). */
|
|
4681
|
+
requireTerminalStep: z20.boolean().optional(),
|
|
4682
|
+
requireDraftRef: z20.boolean().optional(),
|
|
4683
|
+
draft: z20.object({
|
|
4684
|
+
status: z20.enum(["draft", "paused", "active", "complete", "canceled"]).optional(),
|
|
4685
|
+
minDescriptionBytes: z20.number().int().positive().optional(),
|
|
4686
|
+
minOutcomes: z20.number().int().positive().optional(),
|
|
4687
|
+
minSteps: z20.number().int().positive().optional(),
|
|
4688
|
+
requireTerminalVerification: z20.boolean().optional(),
|
|
4689
|
+
requireGatedBuildSteps: z20.boolean().optional()
|
|
4690
|
+
}).strict().optional()
|
|
4691
|
+
}).strict().optional(),
|
|
4692
|
+
/** Assertions evaluated against the live mock server's request log. */
|
|
4693
|
+
mocks: z20.array(CraftbookTestMockExpectationSchema).optional(),
|
|
4694
|
+
/** Assertions evaluated against the project's append-only History log. */
|
|
4695
|
+
history: z20.array(CraftbookTestHistoryExpectationSchema).optional(),
|
|
4696
|
+
/** Workspace fixtures whose final content must equal the seeded bytes exactly. */
|
|
4697
|
+
unchangedFixtures: z20.array(z20.string().min(1)).optional()
|
|
4698
|
+
}).strict();
|
|
4699
|
+
var CraftbookTestRubricSchema = z20.object({
|
|
4700
|
+
artifact: z20.object({
|
|
4701
|
+
/** Workspace or artifact path the judge reads (adapter derives the basename). */
|
|
4702
|
+
path: z20.string().min(1),
|
|
4703
|
+
kind: z20.enum(["html", "markdown", "yaml", "typescript", "json", "text"])
|
|
4704
|
+
}).strict(),
|
|
4705
|
+
axes: z20.array(z20.object({ name: z20.string().min(1), description: z20.string().min(1) }).strict()).min(1),
|
|
4706
|
+
contextNote: z20.string().optional()
|
|
4707
|
+
}).strict();
|
|
4708
|
+
var CraftbookTestSpecSchema = z20.object({
|
|
4709
|
+
schemaVersion: z20.literal(CRAFTBOOK_TEST_SCHEMA_VERSION),
|
|
4710
|
+
title: z20.string().min(1),
|
|
4711
|
+
objective: z20.string().min(1),
|
|
4813
4712
|
/**
|
|
4814
|
-
*
|
|
4815
|
-
*
|
|
4816
|
-
*
|
|
4817
|
-
* taxonomy id, ALSO sets `projectTypeId` so detection-based suggestion
|
|
4818
|
-
* inherits. Absent on projects created without a custom type.
|
|
4713
|
+
* Task-class taxonomy tags (e.g. `html-game`, `corpus`, `external`).
|
|
4714
|
+
* The single declared source for harness selection and batch
|
|
4715
|
+
* planning — replaces the old regex classifiers.
|
|
4819
4716
|
*/
|
|
4820
|
-
|
|
4717
|
+
tags: z20.array(z20.string().min(1)).default([]),
|
|
4718
|
+
/** Kickoff chat message the harness sends. Required — every book runs. */
|
|
4719
|
+
prompt: z20.string().min(1),
|
|
4720
|
+
setup: CraftbookTestSetupSchema,
|
|
4721
|
+
mocks: z20.array(MockServiceSchema).default([]),
|
|
4722
|
+
success: CraftbookTestSuccessSchema,
|
|
4723
|
+
rubric: CraftbookTestRubricSchema,
|
|
4724
|
+
qualityFocus: z20.array(z20.string().min(1)).default([]),
|
|
4821
4725
|
/**
|
|
4822
|
-
*
|
|
4823
|
-
*
|
|
4824
|
-
* installer-managed shared root and operated on by this user's daemon.
|
|
4825
|
-
* The engine broker never opens the project or receives its paths.
|
|
4726
|
+
* Sanctioned escape hatch for experiments — carried opaquely, never
|
|
4727
|
+
* interpreted by CI. Promote a field out of here before relying on it.
|
|
4826
4728
|
*/
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4729
|
+
extensions: z20.record(z20.string(), z20.unknown()).optional()
|
|
4730
|
+
}).strict().superRefine((spec, ctx) => {
|
|
4731
|
+
const mockIds = new Set(spec.mocks.map((m) => m.id));
|
|
4732
|
+
const mockById = new Map(spec.mocks.map((m) => [m.id, m]));
|
|
4733
|
+
for (const [i, expectation] of (spec.success.mocks ?? []).entries()) {
|
|
4734
|
+
if (!mockIds.has(expectation.service)) {
|
|
4735
|
+
ctx.addIssue({
|
|
4736
|
+
code: z20.ZodIssueCode.custom,
|
|
4737
|
+
path: ["success", "mocks", i, "service"],
|
|
4738
|
+
message: `success.mocks[${i}] references unknown mock service "${expectation.service}"`
|
|
4739
|
+
});
|
|
4740
|
+
}
|
|
4741
|
+
if (expectation.requiredTools && expectation.requiredTools.length > 0) {
|
|
4742
|
+
const target = mockById.get(expectation.service);
|
|
4743
|
+
if (target && target.kind !== "mcp") {
|
|
4744
|
+
ctx.addIssue({
|
|
4745
|
+
code: z20.ZodIssueCode.custom,
|
|
4746
|
+
path: ["success", "mocks", i, "requiredTools"],
|
|
4747
|
+
message: `success.mocks[${i}].requiredTools requires an mcp service; "${expectation.service}" is kind "${target.kind}"`
|
|
4748
|
+
});
|
|
4749
|
+
} else if (target?.kind === "mcp") {
|
|
4750
|
+
const declared = new Set(target.tools.map((tool) => tool.name));
|
|
4751
|
+
for (const name of expectation.requiredTools) {
|
|
4752
|
+
if (!declared.has(name)) {
|
|
4753
|
+
ctx.addIssue({
|
|
4754
|
+
code: z20.ZodIssueCode.custom,
|
|
4755
|
+
path: ["success", "mocks", i, "requiredTools"],
|
|
4756
|
+
message: `success.mocks[${i}].requiredTools names undeclared tool "${name}" on mcp service "${expectation.service}"`
|
|
4757
|
+
});
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
if (expectation.toolCalls && Object.keys(expectation.toolCalls).length > 0) {
|
|
4763
|
+
const target = mockById.get(expectation.service);
|
|
4764
|
+
if (target && target.kind !== "mcp") {
|
|
4765
|
+
ctx.addIssue({
|
|
4766
|
+
code: z20.ZodIssueCode.custom,
|
|
4767
|
+
path: ["success", "mocks", i, "toolCalls"],
|
|
4768
|
+
message: `success.mocks[${i}].toolCalls requires an mcp service; "${expectation.service}" is kind "${target.kind}"`
|
|
4769
|
+
});
|
|
4770
|
+
} else if (target?.kind === "mcp") {
|
|
4771
|
+
const declared = new Set(target.tools.map((tool) => tool.name));
|
|
4772
|
+
for (const name of Object.keys(expectation.toolCalls)) {
|
|
4773
|
+
if (!declared.has(name)) {
|
|
4774
|
+
ctx.addIssue({
|
|
4775
|
+
code: z20.ZodIssueCode.custom,
|
|
4776
|
+
path: ["success", "mocks", i, "toolCalls", name],
|
|
4777
|
+
message: `success.mocks[${i}].toolCalls names undeclared tool "${name}" on mcp service "${expectation.service}"`
|
|
4778
|
+
});
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
for (const [i, mock] of spec.mocks.entries()) {
|
|
4785
|
+
if (mock.kind === "http" && mock.credential.name !== `mock.${mock.id}`) {
|
|
4786
|
+
ctx.addIssue({
|
|
4787
|
+
code: z20.ZodIssueCode.custom,
|
|
4788
|
+
path: ["mocks", i, "credential", "name"],
|
|
4789
|
+
message: `http mock "${mock.id}" must use credential name "mock.${mock.id}"`
|
|
4790
|
+
});
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
const workspaceFixtures = new Set(
|
|
4794
|
+
spec.setup.files.filter((file) => file.surface === void 0 || file.surface === "workspace").map((file) => file.path)
|
|
4795
|
+
);
|
|
4796
|
+
for (const [i, path] of (spec.success.unchangedFixtures ?? []).entries()) {
|
|
4797
|
+
if (!workspaceFixtures.has(path)) {
|
|
4798
|
+
ctx.addIssue({
|
|
4799
|
+
code: z20.ZodIssueCode.custom,
|
|
4800
|
+
path: ["success", "unchangedFixtures", i],
|
|
4801
|
+
message: `unchanged fixture "${path}" is not a seeded workspace file`
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
for (const [i, expectation] of (spec.success.history ?? []).entries()) {
|
|
4806
|
+
if (expectation.maxEntries !== void 0 && expectation.minEntries > expectation.maxEntries) {
|
|
4807
|
+
ctx.addIssue({
|
|
4808
|
+
code: z20.ZodIssueCode.custom,
|
|
4809
|
+
path: ["success", "history", i],
|
|
4810
|
+
message: "minEntries must be less than or equal to maxEntries"
|
|
4811
|
+
});
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4830
4814
|
});
|
|
4831
|
-
function
|
|
4832
|
-
|
|
4815
|
+
function parseCraftbookTestSpec(raw, opts) {
|
|
4816
|
+
const mode = opts?.mode ?? "strict";
|
|
4817
|
+
const candidate = mode === "tolerant" ? deepStripUnknown(raw) : raw;
|
|
4818
|
+
const parsed = CraftbookTestSpecSchema.safeParse(candidate);
|
|
4819
|
+
if (parsed.success) return { ok: true, spec: parsed.data };
|
|
4820
|
+
return {
|
|
4821
|
+
ok: false,
|
|
4822
|
+
errors: parsed.error.issues.map((issue) => {
|
|
4823
|
+
const path = issue.path.length > 0 ? issue.path.map(String).join(".") : "<root>";
|
|
4824
|
+
return `${path}: ${issue.message}`;
|
|
4825
|
+
})
|
|
4826
|
+
};
|
|
4833
4827
|
}
|
|
4834
|
-
function
|
|
4835
|
-
|
|
4836
|
-
|
|
4828
|
+
function deepStripUnknown(raw) {
|
|
4829
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
4830
|
+
const record = structuredClone(raw);
|
|
4831
|
+
const version = record.schemaVersion;
|
|
4832
|
+
if (typeof version === "number" && Number.isInteger(version) && version > CRAFTBOOK_TEST_SCHEMA_VERSION) {
|
|
4833
|
+
record.schemaVersion = CRAFTBOOK_TEST_SCHEMA_VERSION;
|
|
4834
|
+
}
|
|
4835
|
+
for (let pass = 0; pass < 16; pass++) {
|
|
4836
|
+
const attempt = CraftbookTestSpecSchema.safeParse(record);
|
|
4837
|
+
if (attempt.success) return record;
|
|
4838
|
+
const unknownKeyIssues = attempt.error.issues.filter(
|
|
4839
|
+
(issue) => issue.code === z20.ZodIssueCode.unrecognized_keys
|
|
4840
|
+
);
|
|
4841
|
+
if (unknownKeyIssues.length === 0) return record;
|
|
4842
|
+
for (const issue of unknownKeyIssues) {
|
|
4843
|
+
const target = resolvePath(record, issue.path);
|
|
4844
|
+
if (target && typeof target === "object" && !Array.isArray(target)) {
|
|
4845
|
+
for (const key of issue.keys) delete target[key];
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
return record;
|
|
4850
|
+
}
|
|
4851
|
+
function resolvePath(root, path) {
|
|
4852
|
+
let node = root;
|
|
4853
|
+
for (const segment of path) {
|
|
4854
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
4855
|
+
node = node[segment];
|
|
4856
|
+
}
|
|
4857
|
+
return node;
|
|
4837
4858
|
}
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4859
|
+
|
|
4860
|
+
// src/schemas/codex-setup.ts
|
|
4861
|
+
import { z as z21 } from "zod";
|
|
4862
|
+
var CodexSetupModelOptionSchema = z21.object({
|
|
4863
|
+
id: z21.string().min(1),
|
|
4864
|
+
label: z21.string().min(1),
|
|
4865
|
+
description: z21.string().optional(),
|
|
4866
|
+
kind: z21.enum(["gezel", "model"]).default("model"),
|
|
4867
|
+
provider: z21.string().min(1),
|
|
4868
|
+
/** Stable gezel id for persona-backed entries. Absent on raw-model entries. */
|
|
4869
|
+
gezelId: z21.string().min(1).optional(),
|
|
4870
|
+
role: z21.string().min(1).optional(),
|
|
4871
|
+
/** Human-readable name of the effective inference model behind a gezel. */
|
|
4872
|
+
modelLabel: z21.string().min(1).optional(),
|
|
4873
|
+
contextWindow: z21.number().int().positive().optional(),
|
|
4874
|
+
supportsReasoning: z21.boolean().optional(),
|
|
4875
|
+
supportsTools: z21.boolean().optional()
|
|
4841
4876
|
});
|
|
4842
|
-
var
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4877
|
+
var CodexSetupStateSchema = z21.enum([
|
|
4878
|
+
"not-configured",
|
|
4879
|
+
"configured",
|
|
4880
|
+
"update-needed",
|
|
4881
|
+
"conflict",
|
|
4882
|
+
"unavailable"
|
|
4883
|
+
]);
|
|
4884
|
+
var CodexSetupStatusResponseSchema = z21.object({
|
|
4885
|
+
state: CodexSetupStateSchema,
|
|
4886
|
+
models: z21.array(CodexSetupModelOptionSchema),
|
|
4887
|
+
configuredModel: z21.string().optional(),
|
|
4888
|
+
recommendedModel: z21.string().optional(),
|
|
4889
|
+
reasons: z21.array(z21.string()),
|
|
4890
|
+
message: z21.string().optional(),
|
|
4891
|
+
codexInstalled: z21.boolean(),
|
|
4892
|
+
codexVersion: z21.string().optional(),
|
|
4893
|
+
codexPath: z21.string().optional(),
|
|
4894
|
+
endpointsEnabled: z21.boolean(),
|
|
4895
|
+
profileName: z21.string().min(1),
|
|
4896
|
+
profilePath: z21.string().min(1),
|
|
4897
|
+
launchCommand: z21.string().min(1),
|
|
4898
|
+
bridge: z21.object({
|
|
4899
|
+
baseUrl: z21.string().url(),
|
|
4900
|
+
listening: z21.boolean(),
|
|
4901
|
+
port: z21.number().int().nonnegative()
|
|
4902
|
+
}),
|
|
4903
|
+
canConfigure: z21.boolean(),
|
|
4904
|
+
/** Whether Gezel-owned credential/state material exists and can be safely removed. */
|
|
4905
|
+
canRemove: z21.boolean()
|
|
4848
4906
|
});
|
|
4849
|
-
var
|
|
4850
|
-
|
|
4851
|
-
path: z21.string(),
|
|
4852
|
-
isDirectory: z21.boolean(),
|
|
4853
|
-
/** File mtime (ms epoch). Populated only when the caller opts into stats. */
|
|
4854
|
-
mtimeMs: z21.number().optional()
|
|
4907
|
+
var ConfigureCodexRequestSchema = z21.object({
|
|
4908
|
+
model: z21.string().min(1)
|
|
4855
4909
|
});
|
|
4856
|
-
var ProjectGithubSchema = ProjectGitHubSchema;
|
|
4857
4910
|
|
|
4858
4911
|
// src/schemas/project-local.ts
|
|
4859
4912
|
import { z as z22 } from "zod";
|
|
@@ -5365,6 +5418,8 @@ var UpdateTaskStepRequestSchema = z23.object({
|
|
|
5365
5418
|
/** Step automation hooks (single ref or ordered list). `null` detaches. */
|
|
5366
5419
|
onEnter: ScriptRefListSchema.nullable().optional(),
|
|
5367
5420
|
onExit: ScriptRefListSchema.nullable().optional(),
|
|
5421
|
+
/** Required file inputs for the step. `null` clears the declaration. */
|
|
5422
|
+
consumes: z23.array(CraftbookStepInputSchema).min(1).nullable().optional(),
|
|
5368
5423
|
/** Auto-advance contract. `null` clears it. */
|
|
5369
5424
|
advanceWhen: AdvanceWhenSchema.nullable().optional(),
|
|
5370
5425
|
/** The end-of-step gate (current or legacy shape). `null` clears it. */
|
|
@@ -6294,6 +6349,13 @@ var ConnectorActionSchema = z26.object({
|
|
|
6294
6349
|
/** Consent gate this action clears at commit time (e.g. `recipient-allowlist`). */
|
|
6295
6350
|
consentScope: z26.string()
|
|
6296
6351
|
});
|
|
6352
|
+
var ConnectorSetupInstructionsSchema = z26.object({
|
|
6353
|
+
title: z26.string().min(1),
|
|
6354
|
+
description: z26.string().min(1).optional(),
|
|
6355
|
+
steps: z26.array(z26.string().min(1)).optional(),
|
|
6356
|
+
url: z26.string().url().optional(),
|
|
6357
|
+
urlLabel: z26.string().min(1).optional()
|
|
6358
|
+
});
|
|
6297
6359
|
var ConnectorTypeCompositionShape = {
|
|
6298
6360
|
/** Which driver executes the fetch. */
|
|
6299
6361
|
driver: ConnectorDriverSchema,
|
|
@@ -6301,6 +6363,8 @@ var ConnectorTypeCompositionShape = {
|
|
|
6301
6363
|
configSchema: z26.record(z26.string(), z26.unknown()).optional(),
|
|
6302
6364
|
/** Shape of the credential the binding stores in the SecretStore. */
|
|
6303
6365
|
secretShape: z26.record(z26.string(), z26.unknown()).optional(),
|
|
6366
|
+
/** Concise setup guidance rendered above the binding form. */
|
|
6367
|
+
setupInstructions: ConnectorSetupInstructionsSchema.optional(),
|
|
6304
6368
|
/**
|
|
6305
6369
|
* Driver-specific fetch config: `{adapterId}` (native) | `{server,list,fetch}`
|
|
6306
6370
|
* (mcp) | `{fetch|cli}` (script) | `{component,action,...}` (spectral).
|
|
@@ -6610,6 +6674,15 @@ var ChatModelMlxSourceSchema = z26.object({
|
|
|
6610
6674
|
});
|
|
6611
6675
|
var ChatModelIdentitySchema = IdentityCommonSchema.extend({
|
|
6612
6676
|
kind: z26.literal("chat-model"),
|
|
6677
|
+
/**
|
|
6678
|
+
* Organization that created the core model weights when it differs from
|
|
6679
|
+
* the catalog maintainer (for example, a quant maintained by its converter).
|
|
6680
|
+
* Omit when `maintainer` already names the maker.
|
|
6681
|
+
*/
|
|
6682
|
+
maker: z26.object({
|
|
6683
|
+
name: z26.string().min(1),
|
|
6684
|
+
url: z26.string().url().optional()
|
|
6685
|
+
}).optional(),
|
|
6613
6686
|
parameterSize: z26.string(),
|
|
6614
6687
|
supportsTools: z26.boolean(),
|
|
6615
6688
|
contextWindow: z26.number().int().positive().optional(),
|
|
@@ -6707,6 +6780,11 @@ var ChatModelManifestSchema = z26.object({
|
|
|
6707
6780
|
name: z26.string(),
|
|
6708
6781
|
url: z26.string().url().optional()
|
|
6709
6782
|
}),
|
|
6783
|
+
/** Core-model maker; present when it differs from `maintainer`. */
|
|
6784
|
+
maker: z26.object({
|
|
6785
|
+
name: z26.string().min(1),
|
|
6786
|
+
url: z26.string().url().optional()
|
|
6787
|
+
}).optional(),
|
|
6710
6788
|
logo: z26.string().optional(),
|
|
6711
6789
|
license: z26.string().optional(),
|
|
6712
6790
|
...LicenseMetaShape,
|
|
@@ -7518,6 +7596,18 @@ var ChatSessionSchema = z28.object({
|
|
|
7518
7596
|
}),
|
|
7519
7597
|
/** Snapshot of the gezel's about.md at session creation, for drift warnings. */
|
|
7520
7598
|
aboutSnapshot: z28.string().optional(),
|
|
7599
|
+
/**
|
|
7600
|
+
* Per-session override of `config.roleBasedNameOnlyMode` ("boring mode").
|
|
7601
|
+
* Stamped at creation when the creating client has a fixed presentation
|
|
7602
|
+
* mode — the TUI always renders role-based labels, so it pins the
|
|
7603
|
+
* sessions it creates to `true`. This keeps the prompt (what the model
|
|
7604
|
+
* is told about other gezels) consistent with what that client shows;
|
|
7605
|
+
* without it the TUI displayed `reviewer:` while the system prompt said
|
|
7606
|
+
* "the voorman is Tomas", and the model naturally leaked names into
|
|
7607
|
+
* prose. Unset = follow the live config flag, which is what desktop
|
|
7608
|
+
* sessions do.
|
|
7609
|
+
*/
|
|
7610
|
+
roleBasedNameOnlyMode: z28.boolean().optional(),
|
|
7521
7611
|
/** Set when the last attempted resume failed — UI surfaces a banner. */
|
|
7522
7612
|
resumeFailed: z28.boolean().optional(),
|
|
7523
7613
|
/**
|
|
@@ -7746,7 +7836,14 @@ var CreateChatSessionRequestSchema = z28.object({
|
|
|
7746
7836
|
projectId: z28.string().optional(),
|
|
7747
7837
|
taskRef: z28.string().optional(),
|
|
7748
7838
|
stepId: z28.string().optional(),
|
|
7749
|
-
craftbookRef: z28.string().optional()
|
|
7839
|
+
craftbookRef: z28.string().optional(),
|
|
7840
|
+
/**
|
|
7841
|
+
* Pin the session's name-rendering mode instead of following
|
|
7842
|
+
* `config.roleBasedNameOnlyMode`. Passed by clients whose presentation
|
|
7843
|
+
* mode is fixed (the TUI) so prompt-side name rendering matches their
|
|
7844
|
+
* labels. See `ChatSessionSchema.roleBasedNameOnlyMode`.
|
|
7845
|
+
*/
|
|
7846
|
+
roleBasedNameOnlyMode: z28.boolean().optional()
|
|
7750
7847
|
});
|
|
7751
7848
|
var ListChatSessionsResponseSchema = z28.object({
|
|
7752
7849
|
sessions: z28.array(ChatSessionSummarySchema)
|
|
@@ -8372,13 +8469,26 @@ var GitHubPullFileSchema = z33.object({
|
|
|
8372
8469
|
additions: z33.number().int(),
|
|
8373
8470
|
deletions: z33.number().int(),
|
|
8374
8471
|
changes: z33.number().int(),
|
|
8375
|
-
/**
|
|
8472
|
+
/** Unified diff hunk, if requested and returned by GitHub. */
|
|
8376
8473
|
patch: z33.string().optional(),
|
|
8474
|
+
/** Character count before Gezel's local patch budget was applied. */
|
|
8475
|
+
patchChars: z33.number().int().nonnegative().optional(),
|
|
8476
|
+
/** True when Gezel clipped `patch`; callers must request the file/diff directly. */
|
|
8477
|
+
patchTruncated: z33.boolean().optional(),
|
|
8377
8478
|
/** Prior path when `status === 'renamed'`. */
|
|
8378
8479
|
previousFilename: z33.string().optional()
|
|
8379
8480
|
});
|
|
8380
8481
|
var ListGitHubPullFilesResponseSchema = z33.object({
|
|
8381
|
-
files: z33.array(GitHubPullFileSchema)
|
|
8482
|
+
files: z33.array(GitHubPullFileSchema),
|
|
8483
|
+
/** Total files in the PR before an optional path filter. */
|
|
8484
|
+
allFiles: z33.number().int().nonnegative().optional(),
|
|
8485
|
+
/** Total files selected by the optional path filter. */
|
|
8486
|
+
totalFiles: z33.number().int().nonnegative().optional(),
|
|
8487
|
+
offset: z33.number().int().nonnegative().optional(),
|
|
8488
|
+
limit: z33.number().int().positive().optional(),
|
|
8489
|
+
hasMore: z33.boolean().optional(),
|
|
8490
|
+
nextOffset: z33.number().int().nonnegative().optional(),
|
|
8491
|
+
includesPatch: z33.boolean().optional()
|
|
8382
8492
|
});
|
|
8383
8493
|
var GitHubPullCommentSchema = z33.object({
|
|
8384
8494
|
id: z33.number(),
|
|
@@ -8395,7 +8505,14 @@ var ListGitHubPullCommentsResponseSchema = z33.object({
|
|
|
8395
8505
|
});
|
|
8396
8506
|
var GitHubPullDiffResponseSchema = z33.object({
|
|
8397
8507
|
number: z33.number().int(),
|
|
8398
|
-
diff: z33.string()
|
|
8508
|
+
diff: z33.string(),
|
|
8509
|
+
/** Exact changed path when this is a file-scoped diff. */
|
|
8510
|
+
path: z33.string().optional(),
|
|
8511
|
+
offset: z33.number().int().nonnegative().optional(),
|
|
8512
|
+
returnedChars: z33.number().int().nonnegative().optional(),
|
|
8513
|
+
totalChars: z33.number().int().nonnegative().optional(),
|
|
8514
|
+
truncated: z33.boolean().optional(),
|
|
8515
|
+
nextOffset: z33.number().int().nonnegative().optional()
|
|
8399
8516
|
});
|
|
8400
8517
|
var GitHubCreateCommentRequestSchema = z33.object({
|
|
8401
8518
|
body: z33.string().min(1)
|
|
@@ -10683,6 +10800,13 @@ var GezelConfigSchema = z37.object({
|
|
|
10683
10800
|
* Advanced.
|
|
10684
10801
|
*/
|
|
10685
10802
|
showAdvancedFeatures: z37.boolean().optional(),
|
|
10803
|
+
/**
|
|
10804
|
+
* When `true`, very early work-in-progress surfaces are revealed in the
|
|
10805
|
+
* UI and CLI. This is a discoverability preference, not a security or
|
|
10806
|
+
* service-layer capability boundary. Defaults on in development builds
|
|
10807
|
+
* and off in releases; an explicit user choice always wins.
|
|
10808
|
+
*/
|
|
10809
|
+
showWorkInProgressFeatures: z37.boolean().optional(),
|
|
10686
10810
|
/**
|
|
10687
10811
|
* Debug-only opt-in: when `true`, the service rewrites every
|
|
10688
10812
|
* template-derived gezel's `about.md` back to the prose its catalog
|
|
@@ -15039,6 +15163,7 @@ export {
|
|
|
15039
15163
|
CraftbookSchema,
|
|
15040
15164
|
CraftbookScriptsSchema,
|
|
15041
15165
|
CraftbookSpawnSchema,
|
|
15166
|
+
CraftbookStepInputSchema,
|
|
15042
15167
|
CraftbookStepSchema,
|
|
15043
15168
|
CraftbookSuggestionSchema,
|
|
15044
15169
|
CraftbookSummarySchema,
|