halfcycle 0.4.12 → 0.4.14
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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +9366 -567
- package/bin/pre-tool-use-filter.sh +470 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/build-record/pair-io.d.ts +49 -0
- package/dist/build-record/pair-io.d.ts.map +1 -0
- package/dist/build-record/render-change.d.ts +25 -0
- package/dist/build-record/render-change.d.ts.map +1 -0
- package/dist/build-record/render-v2.d.ts +10 -5
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/build-record/write-change.d.ts +63 -0
- package/dist/build-record/write-change.d.ts.map +1 -0
- package/dist/build-record/write.d.ts +5 -15
- package/dist/build-record/write.d.ts.map +1 -1
- package/dist/change.d.ts +136 -0
- package/dist/change.d.ts.map +1 -0
- package/dist/check-tasks.d.ts +71 -0
- package/dist/check-tasks.d.ts.map +1 -0
- package/dist/claude-plan.d.ts +114 -0
- package/dist/claude-plan.d.ts.map +1 -0
- package/dist/cli-contract.d.ts +12 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +9017 -5228
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +113 -10
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/halfcycle-monorepo.d.ts +26 -0
- package/dist/halfcycle-monorepo.d.ts.map +1 -0
- package/dist/index.js +1617 -845
- package/dist/index.js.map +3 -3
- package/dist/install-manifest.d.ts +18 -1
- package/dist/install-manifest.d.ts.map +1 -1
- package/dist/install.d.ts +225 -3
- package/dist/install.d.ts.map +1 -1
- package/dist/merge-settings.d.ts +25 -2
- package/dist/merge-settings.d.ts.map +1 -1
- package/dist/open-phase.d.ts +1 -1
- package/dist/open-phase.d.ts.map +1 -1
- package/dist/pace.d.ts +138 -0
- package/dist/pace.d.ts.map +1 -0
- package/dist/phase-work.d.ts +37 -0
- package/dist/phase-work.d.ts.map +1 -0
- package/dist/plan.d.ts +5 -2
- package/dist/plan.d.ts.map +1 -1
- package/dist/prove.d.ts +77 -0
- package/dist/prove.d.ts.map +1 -0
- package/dist/review.d.ts +19 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/system-report.d.ts +4 -4
- package/dist/system-report.d.ts.map +1 -1
- package/dist/uninstall.d.ts +4 -1
- package/dist/uninstall.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
3
3
|
import { createHash as createHash2 } from "node:crypto";
|
|
4
4
|
import { existsSync as existsSync3, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5
|
-
import {
|
|
5
|
+
import { homedir as homedir2 } from "node:os";
|
|
6
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join5, posix, relative, resolve } from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
7
8
|
|
|
8
9
|
// ../core/dist/guard-record.js
|
|
@@ -115,12 +116,15 @@ ${block}`);
|
|
|
115
116
|
// ../core/dist/hook-wiring.js
|
|
116
117
|
var SETTINGS_REL = ".claude/settings.json";
|
|
117
118
|
var VENDORED_BIN_REL = ".halfcycle/bin/bin.bundle.mjs";
|
|
119
|
+
var PRE_FILTER_SHELL_FILENAME = "pre-tool-use-filter.sh";
|
|
120
|
+
var PRE_FILTER_FUNCTION = "halfcycle_pt_skip";
|
|
118
121
|
var SESSION_START_MARKER_REL = ".claude/hooks/session-start-marker.sh";
|
|
119
122
|
var GUARD_RUNNER_REL = ".claude/hooks/guard-runner.sh";
|
|
120
123
|
var USER_PROMPT_REMINDER_REL = ".claude/hooks/user-prompt-reminder.sh";
|
|
121
124
|
var USER_PROMPT_SCOPE_REL = ".claude/hooks/user-prompt-scope.sh";
|
|
122
125
|
var SESSION_END_MARKER_REL = ".claude/hooks/session-end-marker.sh";
|
|
123
126
|
var WRITE_CAPABLE_TOOLS = ["Edit", "MultiEdit", "NotebookEdit", "Write"];
|
|
127
|
+
var PRE_TOOL_USE_MATCHER = "^(Bash|Read|Grep|Write|Edit|MultiEdit|NotebookEdit|Agent)$";
|
|
124
128
|
function hookCommand(script, verb) {
|
|
125
129
|
const invocation = `bash "$CLAUDE_PROJECT_DIR"/${script}`;
|
|
126
130
|
return verb === void 0 ? invocation : `${invocation} ${verb}`;
|
|
@@ -154,6 +158,13 @@ var HALFCYCLE_HOOK_WIRING = [
|
|
|
154
158
|
command: hookCommand(USER_PROMPT_SCOPE_REL),
|
|
155
159
|
script: USER_PROMPT_SCOPE_REL
|
|
156
160
|
},
|
|
161
|
+
{
|
|
162
|
+
event: "PreToolUse",
|
|
163
|
+
matcher: PRE_TOOL_USE_MATCHER,
|
|
164
|
+
timeout: 10,
|
|
165
|
+
command: hookCommand(GUARD_RUNNER_REL, "hook pre-tool-use"),
|
|
166
|
+
script: GUARD_RUNNER_REL
|
|
167
|
+
},
|
|
157
168
|
{
|
|
158
169
|
event: "PostToolUse",
|
|
159
170
|
matcher: WRITE_CAPABLE_TOOLS.join("|"),
|
|
@@ -257,13 +268,69 @@ var REMOTE_FORMS = [
|
|
|
257
268
|
var SIGN_IN_COMMAND = '"npx halfcycle"';
|
|
258
269
|
var HOOK_REMEDY = `Run ${SIGN_IN_COMMAND} in the project folder to sign in.`;
|
|
259
270
|
|
|
260
|
-
// ../
|
|
271
|
+
// ../core/dist/task-plan.js
|
|
261
272
|
import { z as z2 } from "zod";
|
|
262
|
-
var
|
|
263
|
-
|
|
264
|
-
|
|
273
|
+
var TASK_PLAN_TASKS_MAX = 500;
|
|
274
|
+
var TASK_PLAN_ID_MAX = 64;
|
|
275
|
+
var TASK_PLAN_KINDS = ["build", "review", "spec", "walk", "check"];
|
|
276
|
+
var CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f]/;
|
|
277
|
+
var planText = z2.string().refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" });
|
|
278
|
+
var taskIdSchema = z2.string().min(1).max(TASK_PLAN_ID_MAX).refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" });
|
|
279
|
+
var taskPlanTaskSchema = z2.object({
|
|
280
|
+
id: taskIdSchema,
|
|
281
|
+
kind: z2.enum(TASK_PLAN_KINDS),
|
|
282
|
+
dependsOn: z2.array(taskIdSchema).max(TASK_PLAN_TASKS_MAX),
|
|
283
|
+
reviews: taskIdSchema.optional(),
|
|
284
|
+
heldBy: z2.literal("person").optional(),
|
|
285
|
+
touches: z2.object({
|
|
286
|
+
files: z2.array(planText).optional(),
|
|
287
|
+
interfaces: z2.array(planText).optional()
|
|
288
|
+
}).strict().optional(),
|
|
289
|
+
wholeProject: z2.literal(true).optional(),
|
|
290
|
+
ships: z2.enum(["deploy", "release"]).optional()
|
|
291
|
+
}).strict().superRefine((task, ctx) => {
|
|
292
|
+
if (task.reviews !== void 0 && task.kind !== "review") {
|
|
293
|
+
ctx.addIssue({
|
|
294
|
+
code: "custom",
|
|
295
|
+
path: ["reviews"],
|
|
296
|
+
message: "only a review task names the task it reviews"
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (task.wholeProject !== void 0 && task.kind !== "check") {
|
|
300
|
+
ctx.addIssue({
|
|
301
|
+
code: "custom",
|
|
302
|
+
path: ["wholeProject"],
|
|
303
|
+
message: "only a check task is a whole-project check"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if ((task.kind === "review" || task.kind === "check" || task.kind === "walk") && ((task.touches?.files?.length ?? 0) > 0 || (task.touches?.interfaces?.length ?? 0) > 0)) {
|
|
307
|
+
ctx.addIssue({
|
|
308
|
+
code: "custom",
|
|
309
|
+
path: ["touches"],
|
|
310
|
+
message: "a review, check or walk task touches nothing"
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
var taskPlanSchema = z2.object({
|
|
315
|
+
phase: z2.string().min(1).refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" }),
|
|
316
|
+
tasks: z2.array(taskPlanTaskSchema).max(TASK_PLAN_TASKS_MAX)
|
|
317
|
+
}).strict();
|
|
318
|
+
var taskListRowSchema = z2.object({
|
|
319
|
+
id: planText,
|
|
320
|
+
dependsOn: z2.array(planText)
|
|
321
|
+
}).loose();
|
|
322
|
+
var taskListFileSchema = z2.union([
|
|
323
|
+
z2.object({ phase: planText, tasks: z2.array(taskListRowSchema) }).loose(),
|
|
324
|
+
z2.array(z2.unknown())
|
|
325
|
+
]);
|
|
326
|
+
|
|
327
|
+
// ../events/dist/result.js
|
|
328
|
+
import { z as z3 } from "zod";
|
|
329
|
+
var firedGuardSchema = z3.object({
|
|
330
|
+
guardId: z3.string(),
|
|
331
|
+
patternRef: z3.string(),
|
|
265
332
|
severity: severitySchema,
|
|
266
|
-
explanation:
|
|
333
|
+
explanation: z3.string(),
|
|
267
334
|
/**
|
|
268
335
|
* The repo-relative path of the file this firing was decided on. The matcher
|
|
269
336
|
* has the file live at the moment it decides to fire; this is the field that
|
|
@@ -287,66 +354,62 @@ var firedGuardSchema = z2.object({
|
|
|
287
354
|
* safe-parse it and decide what to do with a refusal, rather than assume the
|
|
288
355
|
* two shapes agree.
|
|
289
356
|
*/
|
|
290
|
-
path:
|
|
357
|
+
path: z3.string().optional()
|
|
291
358
|
}).strict();
|
|
292
|
-
var notRunCheckSchema =
|
|
359
|
+
var notRunCheckSchema = z3.object({
|
|
293
360
|
/** Which check did not run, by the same reference a fired check carries. */
|
|
294
|
-
patternRef:
|
|
361
|
+
patternRef: z3.string(),
|
|
295
362
|
/**
|
|
296
363
|
* Why it could not run, in plain words — what this client did not send, or
|
|
297
364
|
* that the check's kind is not implemented yet. Never the check's own rule.
|
|
298
365
|
*/
|
|
299
|
-
reason:
|
|
366
|
+
reason: z3.string()
|
|
300
367
|
}).strict();
|
|
301
|
-
var resultEnvelopeSchema =
|
|
302
|
-
guardsFired:
|
|
368
|
+
var resultEnvelopeSchema = z3.object({
|
|
369
|
+
guardsFired: z3.array(firedGuardSchema),
|
|
303
370
|
severity: severitySchema.nullable(),
|
|
304
|
-
blocking:
|
|
305
|
-
explanation:
|
|
371
|
+
blocking: z3.boolean(),
|
|
372
|
+
explanation: z3.string(),
|
|
306
373
|
/**
|
|
307
374
|
* The checks that could not run on this edit, each named with the reason.
|
|
308
375
|
* Absent when every check ran — so an evaluation where nothing was skipped
|
|
309
376
|
* looks exactly as it always has, and an absent list is never an empty one.
|
|
310
377
|
*/
|
|
311
|
-
notRun:
|
|
378
|
+
notRun: z3.array(notRunCheckSchema).optional()
|
|
312
379
|
}).strict();
|
|
313
|
-
var wireErrorSchema =
|
|
314
|
-
statusCode:
|
|
315
|
-
error:
|
|
316
|
-
message:
|
|
380
|
+
var wireErrorSchema = z3.object({
|
|
381
|
+
statusCode: z3.number(),
|
|
382
|
+
error: z3.string(),
|
|
383
|
+
message: z3.string()
|
|
317
384
|
}).strict();
|
|
318
385
|
|
|
319
|
-
// ../events/dist/
|
|
320
|
-
|
|
321
|
-
function hasLoneSurrogate(text) {
|
|
322
|
-
return LONE_SURROGATE.test(text);
|
|
323
|
-
}
|
|
324
|
-
var LONE_SURROGATE_MESSAGE = "must be valid text: it holds half of a character pair with no other half";
|
|
386
|
+
// ../events/dist/build-record.js
|
|
387
|
+
import { z as z6 } from "zod";
|
|
325
388
|
|
|
326
389
|
// ../events/dist/state.js
|
|
327
|
-
import { z as
|
|
390
|
+
import { z as z5 } from "zod";
|
|
328
391
|
|
|
329
392
|
// ../events/dist/human-agent.js
|
|
330
|
-
import { z as
|
|
393
|
+
import { z as z4 } from "zod";
|
|
331
394
|
var HUMAN_AGENT = "Human";
|
|
332
395
|
var AGENT_NAME_MAX = 32;
|
|
333
|
-
var agentNameSchema =
|
|
396
|
+
var agentNameSchema = z4.string().min(1).max(AGENT_NAME_MAX);
|
|
334
397
|
|
|
335
398
|
// ../events/dist/state.js
|
|
336
|
-
var utcIso8601 =
|
|
399
|
+
var utcIso8601 = z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
|
|
337
400
|
var STATE_RECORD_FORMAT = "halfcycle-state-record/v1";
|
|
338
|
-
var stepIdSchema =
|
|
339
|
-
var methodVersionSchema =
|
|
401
|
+
var stepIdSchema = z5.string().regex(/^(l[0-5](-l[0-5])?|xl)\.[a-z0-9-]+$/);
|
|
402
|
+
var methodVersionSchema = z5.string().regex(RELEASE_VERSION_PATTERN);
|
|
340
403
|
var anchorPathRegex = /^(?!\/)(?!.*#)(?!method\/)(?!(.*\/)?docs\/method\/).+$/;
|
|
341
|
-
var recordKindSchema =
|
|
342
|
-
var methodLayerSchema =
|
|
404
|
+
var recordKindSchema = z5.enum(["artefact", "step-run", "gate", "intervention"]);
|
|
405
|
+
var methodLayerSchema = z5.enum(["l0", "l1", "l2", "l3", "l3-l4", "l4", "l5", "xl"]);
|
|
343
406
|
var PHASE_SCOPED_LAYERS = ["l4", "l5"];
|
|
344
407
|
function isPhaseScopedLayer(layer) {
|
|
345
408
|
return PHASE_SCOPED_LAYERS.includes(layer);
|
|
346
409
|
}
|
|
347
|
-
var evidenceKindSchema =
|
|
348
|
-
var declarableEvidenceKindSchema =
|
|
349
|
-
var dispositionSchema =
|
|
410
|
+
var evidenceKindSchema = z5.enum(["anchor", "diff", "repro", "question-answer", "no-op"]);
|
|
411
|
+
var declarableEvidenceKindSchema = z5.enum(["anchor", "diff", "repro", "question-answer"]);
|
|
412
|
+
var dispositionSchema = z5.enum([
|
|
350
413
|
"prevented",
|
|
351
414
|
"corrected-in-spec",
|
|
352
415
|
"corrected-in-scope",
|
|
@@ -356,20 +419,20 @@ var dispositionSchema = z4.enum([
|
|
|
356
419
|
"surfaced",
|
|
357
420
|
"filed-forward"
|
|
358
421
|
]);
|
|
359
|
-
var mechanismSchema =
|
|
360
|
-
var artefactStateSchema =
|
|
422
|
+
var mechanismSchema = z5.enum(["guard", "verdict", "served-step", "method-step"]);
|
|
423
|
+
var artefactStateSchema = z5.enum(["created", "updated"]);
|
|
361
424
|
var QUALIFIED_OUTCOMES = ["declined", "parked"];
|
|
362
|
-
var qualifiedOutcomeSchema =
|
|
425
|
+
var qualifiedOutcomeSchema = z5.enum(QUALIFIED_OUTCOMES);
|
|
363
426
|
function isQualifiedOutcome(outcome) {
|
|
364
427
|
return QUALIFIED_OUTCOMES.includes(outcome);
|
|
365
428
|
}
|
|
366
|
-
var runOutcomeSchema =
|
|
429
|
+
var runOutcomeSchema = z5.enum([
|
|
367
430
|
"completed",
|
|
368
431
|
"attempted-failed",
|
|
369
432
|
...QUALIFIED_OUTCOMES
|
|
370
433
|
]);
|
|
371
|
-
var gateKindSchema =
|
|
372
|
-
var gateVerdictSchema =
|
|
434
|
+
var gateKindSchema = z5.enum(["approval", "mechanical"]);
|
|
435
|
+
var gateVerdictSchema = z5.enum(["pass", "fail", ...QUALIFIED_OUTCOMES]);
|
|
373
436
|
function outcomeReasonIssue(outcome, reason) {
|
|
374
437
|
if (isQualifiedOutcome(outcome) && reason === void 0) {
|
|
375
438
|
return { message: `outcomeReason is required when the outcome is '${outcome}'` };
|
|
@@ -381,47 +444,47 @@ function outcomeReasonIssue(outcome, reason) {
|
|
|
381
444
|
}
|
|
382
445
|
return null;
|
|
383
446
|
}
|
|
384
|
-
var anchorEvidenceSchema =
|
|
385
|
-
kind:
|
|
386
|
-
path:
|
|
447
|
+
var anchorEvidenceSchema = z5.object({
|
|
448
|
+
kind: z5.literal("anchor"),
|
|
449
|
+
path: z5.string().regex(anchorPathRegex),
|
|
387
450
|
// Optional 1-based line number within the file at `path`. Present when the
|
|
388
451
|
// writer knows the exact line; omitted — never `0`, never `null` — when it
|
|
389
452
|
// does not, because a line number is not always obtainable. Absence is a
|
|
390
453
|
// valid, permanent state here, not a gap meant to be filled in later.
|
|
391
|
-
line:
|
|
454
|
+
line: z5.number().optional()
|
|
392
455
|
}).strict();
|
|
393
|
-
var diffEvidenceSchema =
|
|
394
|
-
kind:
|
|
395
|
-
ref:
|
|
456
|
+
var diffEvidenceSchema = z5.object({
|
|
457
|
+
kind: z5.literal("diff"),
|
|
458
|
+
ref: z5.string()
|
|
396
459
|
}).strict();
|
|
397
|
-
var reproEvidenceSchema =
|
|
398
|
-
kind:
|
|
399
|
-
steps:
|
|
460
|
+
var reproEvidenceSchema = z5.object({
|
|
461
|
+
kind: z5.literal("repro"),
|
|
462
|
+
steps: z5.string().max(2e3)
|
|
400
463
|
}).strict();
|
|
401
|
-
var questionAnswerEvidenceSchema =
|
|
402
|
-
kind:
|
|
403
|
-
question:
|
|
404
|
-
before:
|
|
405
|
-
after:
|
|
464
|
+
var questionAnswerEvidenceSchema = z5.object({
|
|
465
|
+
kind: z5.literal("question-answer"),
|
|
466
|
+
question: z5.string().max(2e3),
|
|
467
|
+
before: z5.string().max(2e3),
|
|
468
|
+
after: z5.string().max(2e3)
|
|
406
469
|
}).strict();
|
|
407
|
-
var noOpEvidenceSchema =
|
|
408
|
-
kind:
|
|
409
|
-
inspected:
|
|
410
|
-
unchangedBecause:
|
|
470
|
+
var noOpEvidenceSchema = z5.object({
|
|
471
|
+
kind: z5.literal("no-op"),
|
|
472
|
+
inspected: z5.string().max(2e3),
|
|
473
|
+
unchangedBecause: z5.string().max(2e3)
|
|
411
474
|
}).strict();
|
|
412
|
-
var evidenceSchema =
|
|
475
|
+
var evidenceSchema = z5.discriminatedUnion("kind", [
|
|
413
476
|
anchorEvidenceSchema,
|
|
414
477
|
diffEvidenceSchema,
|
|
415
478
|
reproEvidenceSchema,
|
|
416
479
|
questionAnswerEvidenceSchema,
|
|
417
480
|
noOpEvidenceSchema
|
|
418
481
|
]);
|
|
419
|
-
var stateRecordEnvelopeSchema =
|
|
420
|
-
format:
|
|
482
|
+
var stateRecordEnvelopeSchema = z5.object({
|
|
483
|
+
format: z5.literal(STATE_RECORD_FORMAT),
|
|
421
484
|
recordKind: recordKindSchema,
|
|
422
|
-
recordId:
|
|
485
|
+
recordId: z5.string().uuid(),
|
|
423
486
|
methodVersion: methodVersionSchema,
|
|
424
|
-
engagementId:
|
|
487
|
+
engagementId: z5.string(),
|
|
425
488
|
stepId: stepIdSchema,
|
|
426
489
|
// Immutable: names when the thing happened, never when a later disposition
|
|
427
490
|
// moved.
|
|
@@ -437,38 +500,38 @@ var stateRecordEnvelopeSchema = z4.object({
|
|
|
437
500
|
// for the whole project rather than per phase. Absence is meaningful on its
|
|
438
501
|
// own — it is never replaced with a placeholder value, and it is read as
|
|
439
502
|
// "satisfies any phase", not as "unknown".
|
|
440
|
-
phase:
|
|
503
|
+
phase: z5.string().optional()
|
|
441
504
|
});
|
|
442
|
-
var artefactRefSchema =
|
|
443
|
-
name:
|
|
444
|
-
parent:
|
|
505
|
+
var artefactRefSchema = z5.object({
|
|
506
|
+
name: z5.string(),
|
|
507
|
+
parent: z5.string()
|
|
445
508
|
}).strict();
|
|
446
|
-
var coverageSchema =
|
|
447
|
-
asked:
|
|
448
|
-
answered:
|
|
509
|
+
var coverageSchema = z5.object({
|
|
510
|
+
asked: z5.number().int().nonnegative(),
|
|
511
|
+
answered: z5.number().int().nonnegative()
|
|
449
512
|
}).strict().superRefine((coverage, ctx) => {
|
|
450
513
|
if (coverage.answered > coverage.asked) {
|
|
451
514
|
ctx.addIssue({
|
|
452
|
-
code:
|
|
515
|
+
code: z5.ZodIssueCode.custom,
|
|
453
516
|
path: ["answered"],
|
|
454
517
|
message: "answered cannot be more than asked"
|
|
455
518
|
});
|
|
456
519
|
}
|
|
457
520
|
});
|
|
458
|
-
var projectTierSchema =
|
|
521
|
+
var projectTierSchema = z5.number().int().min(0).max(3);
|
|
459
522
|
var artefactRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
460
|
-
recordKind:
|
|
523
|
+
recordKind: z5.literal("artefact"),
|
|
461
524
|
artefactRef: artefactRefSchema,
|
|
462
525
|
// Some layer wrote it, by construction — an empty array is not a legitimate
|
|
463
526
|
// state, so the schema says so.
|
|
464
|
-
writtenByLayers:
|
|
527
|
+
writtenByLayers: z5.array(methodLayerSchema).min(1),
|
|
465
528
|
state: artefactStateSchema
|
|
466
529
|
}).strict();
|
|
467
530
|
var stepRunRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
468
|
-
recordKind:
|
|
531
|
+
recordKind: z5.literal("step-run"),
|
|
469
532
|
runOutcome: runOutcomeSchema,
|
|
470
|
-
failureReason:
|
|
471
|
-
outcomeReason:
|
|
533
|
+
failureReason: z5.string().optional(),
|
|
534
|
+
outcomeReason: z5.string().max(2e3).optional(),
|
|
472
535
|
// Who did this step, as the session reported it. Absent when not reported.
|
|
473
536
|
agent: agentNameSchema.optional(),
|
|
474
537
|
// When the session began this step. Absent when not reported.
|
|
@@ -478,29 +541,29 @@ var stepRunRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
|
478
541
|
}).strict().superRefine((rec, ctx) => {
|
|
479
542
|
if (rec.runOutcome === "attempted-failed" && rec.failureReason === void 0) {
|
|
480
543
|
ctx.addIssue({
|
|
481
|
-
code:
|
|
544
|
+
code: z5.ZodIssueCode.custom,
|
|
482
545
|
path: ["failureReason"],
|
|
483
546
|
message: "failureReason is required when runOutcome is 'attempted-failed'"
|
|
484
547
|
});
|
|
485
548
|
}
|
|
486
549
|
if (rec.runOutcome !== "attempted-failed" && rec.failureReason !== void 0) {
|
|
487
550
|
ctx.addIssue({
|
|
488
|
-
code:
|
|
551
|
+
code: z5.ZodIssueCode.custom,
|
|
489
552
|
path: ["failureReason"],
|
|
490
553
|
message: "failureReason is only present when runOutcome is 'attempted-failed'"
|
|
491
554
|
});
|
|
492
555
|
}
|
|
493
556
|
const issue = outcomeReasonIssue(rec.runOutcome, rec.outcomeReason);
|
|
494
557
|
if (issue) {
|
|
495
|
-
ctx.addIssue({ code:
|
|
558
|
+
ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
|
|
496
559
|
}
|
|
497
560
|
});
|
|
498
561
|
var gateRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
499
|
-
recordKind:
|
|
562
|
+
recordKind: z5.literal("gate"),
|
|
500
563
|
gateKind: gateKindSchema,
|
|
501
564
|
verdict: gateVerdictSchema,
|
|
502
|
-
actor:
|
|
503
|
-
outcomeReason:
|
|
565
|
+
actor: z5.string(),
|
|
566
|
+
outcomeReason: z5.string().max(2e3).optional(),
|
|
504
567
|
coverage: coverageSchema.optional(),
|
|
505
568
|
// Who did the step this checkpoint is on, as reported. Absent when not reported.
|
|
506
569
|
agent: agentNameSchema.optional(),
|
|
@@ -510,35 +573,32 @@ var gateRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
|
510
573
|
}).strict().superRefine((rec, ctx) => {
|
|
511
574
|
const issue = outcomeReasonIssue(rec.verdict, rec.outcomeReason);
|
|
512
575
|
if (issue) {
|
|
513
|
-
ctx.addIssue({ code:
|
|
576
|
+
ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
|
|
514
577
|
}
|
|
515
578
|
});
|
|
516
579
|
var interventionRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
517
|
-
recordKind:
|
|
580
|
+
recordKind: z5.literal("intervention"),
|
|
518
581
|
layer: methodLayerSchema,
|
|
519
582
|
mechanism: mechanismSchema,
|
|
520
583
|
severity: severitySchema,
|
|
521
584
|
disposition: dispositionSchema,
|
|
522
|
-
summary:
|
|
585
|
+
summary: z5.string().max(2e3),
|
|
523
586
|
coverage: coverageSchema.optional(),
|
|
524
587
|
// Who caught it, as the session reported. Absent when not reported.
|
|
525
588
|
agent: agentNameSchema.optional()
|
|
526
589
|
}).strict();
|
|
527
|
-
var stateRecordSchema =
|
|
590
|
+
var stateRecordSchema = z5.discriminatedUnion("recordKind", [
|
|
528
591
|
artefactRecordSchema,
|
|
529
592
|
stepRunRecordSchema,
|
|
530
593
|
gateRecordSchema,
|
|
531
594
|
interventionRecordSchema
|
|
532
595
|
]);
|
|
533
596
|
|
|
534
|
-
// ../events/dist/build-record.js
|
|
535
|
-
import { z as z5 } from "zod";
|
|
536
|
-
|
|
537
597
|
// ../events/dist/control-characters.js
|
|
538
598
|
var CONTROL_CHARACTER_CLASS = "\\p{Cc}";
|
|
539
|
-
var
|
|
599
|
+
var CONTROL_CHARACTER2 = new RegExp(CONTROL_CHARACTER_CLASS, "u");
|
|
540
600
|
function hasControlCharacter(text) {
|
|
541
|
-
return
|
|
601
|
+
return CONTROL_CHARACTER2.test(text);
|
|
542
602
|
}
|
|
543
603
|
|
|
544
604
|
// ../events/dist/phase-identity.js
|
|
@@ -613,6 +673,13 @@ function describeIdentity(identity) {
|
|
|
613
673
|
return `(a ${typeof identity})`;
|
|
614
674
|
}
|
|
615
675
|
|
|
676
|
+
// ../events/dist/lone-surrogates.js
|
|
677
|
+
var LONE_SURROGATE = new RegExp("\\p{Cs}", "u");
|
|
678
|
+
function hasLoneSurrogate(text) {
|
|
679
|
+
return LONE_SURROGATE.test(text);
|
|
680
|
+
}
|
|
681
|
+
var LONE_SURROGATE_MESSAGE = "must be valid text: it holds half of a character pair with no other half";
|
|
682
|
+
|
|
616
683
|
// ../events/dist/build-record.js
|
|
617
684
|
var BUILD_RECORD_V2_FORMAT = "halfcycle-build-record/v2";
|
|
618
685
|
var STATEMENT_MAX = 2e3;
|
|
@@ -622,16 +689,16 @@ var ACTOR_MAX = 200;
|
|
|
622
689
|
var FINDING_MAX = 500;
|
|
623
690
|
var FINDINGS_SHOWN_MAX = 50;
|
|
624
691
|
var PHASE_CLOSE_REASON_MAX = 1900;
|
|
625
|
-
var closeCommitSchema =
|
|
626
|
-
var walkVerdictSchema =
|
|
627
|
-
var acceptanceOutcomeSchema =
|
|
692
|
+
var closeCommitSchema = z6.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/, "must be a full commit hash: 40 or 64 lowercase hex characters");
|
|
693
|
+
var walkVerdictSchema = z6.enum(["clean", "defects"]);
|
|
694
|
+
var acceptanceOutcomeSchema = z6.object({
|
|
628
695
|
verdict: walkVerdictSchema,
|
|
629
|
-
findings:
|
|
630
|
-
findingsDetail:
|
|
696
|
+
findings: z6.number().int().nonnegative(),
|
|
697
|
+
findingsDetail: z6.array(z6.object({ summary: z6.string().refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE }) }).strict())
|
|
631
698
|
}).strict();
|
|
632
|
-
var closeDecisionSchema =
|
|
699
|
+
var closeDecisionSchema = z6.enum(["done-when-met", "override"]);
|
|
633
700
|
function plainText(max) {
|
|
634
|
-
const base = max === void 0 ?
|
|
701
|
+
const base = max === void 0 ? z6.string() : z6.string().max(max);
|
|
635
702
|
return base.refine((v) => !hasControlCharacter(v), {
|
|
636
703
|
message: "must be one line with no control characters (no line breaks, tabs or NUL)"
|
|
637
704
|
}).refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE });
|
|
@@ -643,81 +710,81 @@ function statementText(max) {
|
|
|
643
710
|
}
|
|
644
711
|
var closeActorSchema = plainText(ACTOR_MAX);
|
|
645
712
|
var PHASE_NAME_RULE = `must be a phase name: not empty, no slash or backslash, not starting with a dot, no control characters, at most ${PHASE_NAME_MAX_BYTES} bytes`;
|
|
646
|
-
var phaseNameSchema =
|
|
713
|
+
var phaseNameSchema = z6.string().refine((v) => isValidPhaseIdentity(v), {
|
|
647
714
|
message: PHASE_NAME_RULE
|
|
648
715
|
});
|
|
649
|
-
var phaseIdentitySchema =
|
|
650
|
-
var closeStatementsSchema =
|
|
716
|
+
var phaseIdentitySchema = z6.union([z6.string(), z6.number()], { error: "must be a phase name or a whole number" }).refine((v) => isValidPhaseIdentity(v), { message: PHASE_NAME_RULE });
|
|
717
|
+
var closeStatementsSchema = z6.object({
|
|
651
718
|
thesis: statementText(STATEMENT_MAX).nullable(),
|
|
652
719
|
outcome: statementText(STATEMENT_MAX).nullable(),
|
|
653
|
-
deviations:
|
|
720
|
+
deviations: z6.array(statementText(DEVIATION_MAX)).max(DEVIATIONS_MAX),
|
|
654
721
|
closeCommit: closeCommitSchema.nullable()
|
|
655
722
|
}).strict();
|
|
656
|
-
var closedBySchema =
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
723
|
+
var closedBySchema = z6.discriminatedUnion("kind", [
|
|
724
|
+
z6.object({ kind: z6.literal("account"), email: plainText().nullable() }).strict(),
|
|
725
|
+
z6.object({ kind: z6.literal("no-account") }).strict(),
|
|
726
|
+
z6.object({ kind: z6.literal("account-removed") }).strict(),
|
|
727
|
+
z6.object({ kind: z6.literal("not-recorded") }).strict()
|
|
661
728
|
]);
|
|
662
729
|
var STEP_NAME_MAX = 200;
|
|
663
730
|
var stepNameSchema = plainText(STEP_NAME_MAX).refine((v) => v.trim().length > 0, {
|
|
664
731
|
message: "must not be blank"
|
|
665
732
|
});
|
|
666
|
-
var unfinishedStepSchema =
|
|
733
|
+
var unfinishedStepSchema = z6.object({
|
|
667
734
|
stepId: plainText(),
|
|
668
|
-
state:
|
|
735
|
+
state: z6.enum(["parked", "failed"]),
|
|
669
736
|
name: stepNameSchema.optional()
|
|
670
737
|
}).strict();
|
|
671
|
-
var crossedSchema =
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
738
|
+
var crossedSchema = z6.discriminatedUnion("kind", [
|
|
739
|
+
z6.object({ kind: z6.literal("none") }).strict(),
|
|
740
|
+
z6.object({ kind: z6.literal("unfinished-steps"), steps: z6.array(unfinishedStepSchema).min(1) }).strict(),
|
|
741
|
+
z6.object({ kind: z6.literal("clean-over-findings"), findings: z6.number().int().min(1) }).strict(),
|
|
742
|
+
z6.object({ kind: z6.literal("not-recorded") }).strict()
|
|
676
743
|
]);
|
|
677
|
-
var seatCoverageSchema =
|
|
678
|
-
enrolled:
|
|
679
|
-
conformant:
|
|
744
|
+
var seatCoverageSchema = z6.object({
|
|
745
|
+
enrolled: z6.number().int().nonnegative(),
|
|
746
|
+
conformant: z6.number().int().nonnegative()
|
|
680
747
|
}).strict().refine((c) => c.conformant <= c.enrolled, {
|
|
681
748
|
message: "conformant cannot exceed enrolled",
|
|
682
749
|
path: ["conformant"]
|
|
683
750
|
});
|
|
684
|
-
var observedCloseSchema =
|
|
685
|
-
sequence:
|
|
751
|
+
var observedCloseSchema = z6.object({
|
|
752
|
+
sequence: z6.number().int().min(1),
|
|
686
753
|
closedAt: utcIso8601,
|
|
687
754
|
closedBy: closedBySchema,
|
|
688
755
|
crossed: crossedSchema,
|
|
689
756
|
seatCoverage: seatCoverageSchema.nullable()
|
|
690
757
|
}).strict();
|
|
691
|
-
var couldNotRunCheckSchema =
|
|
758
|
+
var couldNotRunCheckSchema = z6.object({
|
|
692
759
|
check: plainText(),
|
|
693
760
|
description: plainText().nullable(),
|
|
694
761
|
reason: plainText()
|
|
695
762
|
}).strict();
|
|
696
|
-
var firedCheckSchema =
|
|
763
|
+
var firedCheckSchema = z6.object({
|
|
697
764
|
check: plainText(),
|
|
698
765
|
description: plainText().nullable(),
|
|
699
766
|
severity: severitySchema,
|
|
700
767
|
explanation: plainText().nullable(),
|
|
701
|
-
occurrences:
|
|
768
|
+
occurrences: z6.number().int().min(1)
|
|
702
769
|
}).strict();
|
|
703
|
-
var phaseChecksSchema =
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
state:
|
|
707
|
-
runs:
|
|
708
|
-
couldNotRun:
|
|
770
|
+
var phaseChecksSchema = z6.discriminatedUnion("state", [
|
|
771
|
+
z6.object({ state: z6.literal("not-observed") }).strict(),
|
|
772
|
+
z6.object({
|
|
773
|
+
state: z6.literal("nothing-fired"),
|
|
774
|
+
runs: z6.number().int().min(1),
|
|
775
|
+
couldNotRun: z6.array(couldNotRunCheckSchema)
|
|
709
776
|
}).strict(),
|
|
710
|
-
|
|
711
|
-
state:
|
|
712
|
-
runs:
|
|
713
|
-
couldNotRun:
|
|
714
|
-
fired:
|
|
777
|
+
z6.object({
|
|
778
|
+
state: z6.literal("fired"),
|
|
779
|
+
runs: z6.number().int().min(1),
|
|
780
|
+
couldNotRun: z6.array(couldNotRunCheckSchema),
|
|
781
|
+
fired: z6.array(firedCheckSchema).min(1)
|
|
715
782
|
}).strict()
|
|
716
783
|
]);
|
|
717
|
-
var observedSchema =
|
|
784
|
+
var observedSchema = z6.object({
|
|
718
785
|
engagementId: plainText(),
|
|
719
786
|
methodVersion: methodVersionSchema,
|
|
720
|
-
closes:
|
|
787
|
+
closes: z6.array(observedCloseSchema).min(1),
|
|
721
788
|
checks: phaseChecksSchema
|
|
722
789
|
}).strict().superRefine((o, ctx) => {
|
|
723
790
|
o.closes.forEach((close, i) => {
|
|
@@ -730,18 +797,18 @@ var observedSchema = z5.object({
|
|
|
730
797
|
}
|
|
731
798
|
});
|
|
732
799
|
});
|
|
733
|
-
var attestedWalkSchema =
|
|
800
|
+
var attestedWalkSchema = z6.object({
|
|
734
801
|
verdict: walkVerdictSchema,
|
|
735
|
-
findings:
|
|
736
|
-
findingsNotShown:
|
|
802
|
+
findings: z6.array(plainText(FINDING_MAX)).max(FINDINGS_SHOWN_MAX),
|
|
803
|
+
findingsNotShown: z6.number().int().nonnegative()
|
|
737
804
|
}).strict();
|
|
738
|
-
var attestedStatementsSchema =
|
|
805
|
+
var attestedStatementsSchema = z6.object({
|
|
739
806
|
thesis: plainText(STATEMENT_MAX).nullable(),
|
|
740
807
|
outcome: plainText(STATEMENT_MAX).nullable(),
|
|
741
|
-
deviations:
|
|
808
|
+
deviations: z6.array(plainText(DEVIATION_MAX)).max(DEVIATIONS_MAX)
|
|
742
809
|
}).strict();
|
|
743
|
-
var attestedCloseSchema =
|
|
744
|
-
sequence:
|
|
810
|
+
var attestedCloseSchema = z6.object({
|
|
811
|
+
sequence: z6.number().int().min(1),
|
|
745
812
|
decision: closeDecisionSchema,
|
|
746
813
|
actor: plainText(ACTOR_MAX).nullable(),
|
|
747
814
|
reason: plainText(PHASE_CLOSE_REASON_MAX).nullable(),
|
|
@@ -749,8 +816,8 @@ var attestedCloseSchema = z5.object({
|
|
|
749
816
|
closeCommit: closeCommitSchema.nullable(),
|
|
750
817
|
statements: attestedStatementsSchema
|
|
751
818
|
}).strict();
|
|
752
|
-
var attestedSchema =
|
|
753
|
-
closes:
|
|
819
|
+
var attestedSchema = z6.object({
|
|
820
|
+
closes: z6.array(attestedCloseSchema)
|
|
754
821
|
}).strict();
|
|
755
822
|
function checkRecordHalves(record2, ctx) {
|
|
756
823
|
const observedBySequence = new Map(record2.observed.closes.map((c) => [c.sequence, c]));
|
|
@@ -781,362 +848,112 @@ function checkRecordHalves(record2, ctx) {
|
|
|
781
848
|
}
|
|
782
849
|
});
|
|
783
850
|
}
|
|
784
|
-
var buildRecordV2Schema =
|
|
785
|
-
format:
|
|
851
|
+
var buildRecordV2Schema = z6.object({
|
|
852
|
+
format: z6.literal(BUILD_RECORD_V2_FORMAT),
|
|
786
853
|
phase: phaseNameSchema,
|
|
787
854
|
observed: observedSchema,
|
|
788
855
|
attested: attestedSchema
|
|
789
856
|
}).strict().superRefine(checkRecordHalves);
|
|
790
857
|
|
|
791
|
-
// ../events/dist/
|
|
792
|
-
import { z as
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
var
|
|
797
|
-
var
|
|
798
|
-
var
|
|
799
|
-
var
|
|
800
|
-
var
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
858
|
+
// ../events/dist/build-snapshot.js
|
|
859
|
+
import { z as z8 } from "zod";
|
|
860
|
+
|
|
861
|
+
// ../events/dist/system-description.js
|
|
862
|
+
import { z as z7 } from "zod";
|
|
863
|
+
var SYSTEM_DESCRIPTION_FORMAT = 1;
|
|
864
|
+
var SYSTEM_PARTS_MAX = 60;
|
|
865
|
+
var SYSTEM_CONNECTIONS_MAX = 400;
|
|
866
|
+
var SYSTEM_SLOT_MAX = 11;
|
|
867
|
+
var SYSTEM_OWNS_MAX = 20;
|
|
868
|
+
var SYSTEM_OWNED_PATTERN_MAX = 200;
|
|
869
|
+
var SYSTEM_PART_NAME_MAX = 60;
|
|
870
|
+
var SYSTEM_PART_DESCRIPTION_MAX = 160;
|
|
871
|
+
var SYSTEM_CONNECTION_LABEL_MAX = 60;
|
|
872
|
+
var SYSTEM_PART_ID_PATTERN = /^[a-z][a-z0-9-]{0,39}$/;
|
|
873
|
+
var SYSTEM_LANES = ["clients", "edge", "services", "data", "external"];
|
|
874
|
+
var systemLaneSchema = z7.enum(SYSTEM_LANES, {
|
|
875
|
+
error: `must be one of ${SYSTEM_LANES.join(", ")}`
|
|
876
|
+
});
|
|
877
|
+
var SYSTEM_CONNECTION_KINDS = ["call", "event", "write", "external"];
|
|
878
|
+
var systemConnectionKindSchema = z7.enum(SYSTEM_CONNECTION_KINDS, {
|
|
879
|
+
error: `must be one of ${SYSTEM_CONNECTION_KINDS.join(", ")}`
|
|
880
|
+
});
|
|
881
|
+
var LINE_SEPARATOR = /[\u2028\u2029]/;
|
|
882
|
+
function descriptionText(max) {
|
|
883
|
+
return statementText(max).refine((v) => v.trim().length > 0, { message: "must not be empty or only spaces" }).refine((v) => !LINE_SEPARATOR.test(v), {
|
|
884
|
+
message: "must be one line: it holds a line or paragraph separator"
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
var systemPartIdSchema = z7.string().regex(SYSTEM_PART_ID_PATTERN, {
|
|
888
|
+
message: "must be a short id: a lowercase letter, then lowercase letters, digits or hyphens, 40 characters at most"
|
|
889
|
+
}).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key; choose another id" });
|
|
890
|
+
function hasEmptySegment(pattern) {
|
|
891
|
+
return pattern.split("/").some((segment) => segment.length === 0);
|
|
892
|
+
}
|
|
893
|
+
function hasDotSegment(pattern) {
|
|
894
|
+
return pattern.split("/").some((segment) => segment === "." || segment === "..");
|
|
895
|
+
}
|
|
896
|
+
function hasPartialDoubleStar(pattern) {
|
|
897
|
+
return pattern.split("/").some((segment) => segment.includes("**") && segment !== "**");
|
|
898
|
+
}
|
|
899
|
+
var SEGMENT_CHARACTERS = /^[A-Za-z0-9._\-*]*$/;
|
|
900
|
+
function hasForeignCharacter(pattern) {
|
|
901
|
+
return pattern.split("/").some((segment) => !SEGMENT_CHARACTERS.test(segment));
|
|
902
|
+
}
|
|
903
|
+
var systemOwnedPatternSchema = z7.string().max(SYSTEM_OWNED_PATTERN_MAX, { message: `must be at most ${SYSTEM_OWNED_PATTERN_MAX} characters` }).refine((v) => !hasEmptySegment(v), {
|
|
904
|
+
message: "must not start or end with a slash, or have two slashes together"
|
|
905
|
+
}).refine((v) => !hasDotSegment(v), { message: 'must not have a "." or ".." folder in it' }).refine((v) => !hasPartialDoubleStar(v), { message: '"**" must stand alone between slashes' }).refine((v) => !hasForeignCharacter(v), {
|
|
906
|
+
message: 'may use only letters, digits, ".", "_", "-" and "*" between slashes'
|
|
907
|
+
}).refine((v) => !looksLikeSecret(v), {
|
|
908
|
+
message: "this path looks like a credential; list a shorter folder above it"
|
|
909
|
+
});
|
|
910
|
+
var systemPartSchema = z7.object({
|
|
911
|
+
id: systemPartIdSchema,
|
|
912
|
+
name: descriptionText(SYSTEM_PART_NAME_MAX),
|
|
913
|
+
description: descriptionText(SYSTEM_PART_DESCRIPTION_MAX),
|
|
914
|
+
lane: systemLaneSchema,
|
|
915
|
+
slot: z7.number({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).int({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).max(SYSTEM_SLOT_MAX, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }),
|
|
916
|
+
outside: z7.boolean(),
|
|
917
|
+
owns: z7.array(systemOwnedPatternSchema).max(SYSTEM_OWNS_MAX, { message: `can list at most ${SYSTEM_OWNS_MAX} paths` })
|
|
812
918
|
}).strict();
|
|
813
|
-
var
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
"
|
|
822
|
-
|
|
919
|
+
var systemConnectionSchema = z7.object({
|
|
920
|
+
from: systemPartIdSchema,
|
|
921
|
+
to: systemPartIdSchema,
|
|
922
|
+
kind: systemConnectionKindSchema,
|
|
923
|
+
label: descriptionText(SYSTEM_CONNECTION_LABEL_MAX)
|
|
924
|
+
}).strict();
|
|
925
|
+
var systemDescriptionSchema = z7.object({
|
|
926
|
+
format: z7.literal(SYSTEM_DESCRIPTION_FORMAT, { error: `must be ${SYSTEM_DESCRIPTION_FORMAT}` }),
|
|
927
|
+
parts: z7.array(systemPartSchema).min(1, { message: "must list at least one part" }).max(SYSTEM_PARTS_MAX, { message: `can hold at most ${SYSTEM_PARTS_MAX} parts (five lanes of twelve slots)` }),
|
|
928
|
+
connections: z7.array(systemConnectionSchema).max(SYSTEM_CONNECTIONS_MAX, { message: `can hold at most ${SYSTEM_CONNECTIONS_MAX} connections` })
|
|
929
|
+
}).strict();
|
|
930
|
+
var systemDescriptionProblemSchema = z7.object({
|
|
931
|
+
path: z7.string(),
|
|
932
|
+
message: z7.string()
|
|
933
|
+
}).strict();
|
|
934
|
+
var systemReportRecordedSchema = z7.object({
|
|
935
|
+
outcome: z7.literal("recorded"),
|
|
936
|
+
version: z7.number().int().min(1),
|
|
937
|
+
reportedAt: utcIso8601
|
|
938
|
+
}).strict();
|
|
939
|
+
var systemReportRefusedSchema = z7.object({
|
|
940
|
+
outcome: z7.literal("refused"),
|
|
941
|
+
problems: z7.array(systemDescriptionProblemSchema).min(1)
|
|
942
|
+
}).strict();
|
|
943
|
+
var systemReportUnavailableSchema = z7.object({
|
|
944
|
+
outcome: z7.literal("unavailable")
|
|
945
|
+
}).strict();
|
|
946
|
+
var systemReportResultSchema = z7.discriminatedUnion("outcome", [
|
|
947
|
+
systemReportRecordedSchema,
|
|
948
|
+
systemReportRefusedSchema,
|
|
949
|
+
systemReportUnavailableSchema
|
|
823
950
|
]);
|
|
824
|
-
var
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
// The part this member plays, which decides the stages it leads and helps with.
|
|
831
|
-
role: crewRoleSchema,
|
|
832
|
-
// The kind of work this member takes. A task names a discipline, and only
|
|
833
|
-
// agents holding it can be dispatched to it.
|
|
834
|
-
discipline: z6.string().min(1).max(CREW_DISCIPLINE_MAX),
|
|
835
|
-
// How much thinking this member brings. There is no field naming the supplier
|
|
836
|
-
// behind it, on this shape or on any other.
|
|
837
|
-
tier: crewTierSchema,
|
|
838
|
-
// How this member's face is drawn. The same face on every project, so a
|
|
839
|
-
// returning client recognises a member before reading the name.
|
|
840
|
-
face: crewFaceSchema
|
|
841
|
-
}).strict();
|
|
842
|
-
var CREW_ROSTER = [
|
|
843
|
-
// ── analysts and architects ─────────────────────────────────────────────────
|
|
844
|
-
{
|
|
845
|
-
callsign: "SOFIA",
|
|
846
|
-
group: "analyst-architect",
|
|
847
|
-
role: "business-analyst",
|
|
848
|
-
discipline: "business analyst",
|
|
849
|
-
tier: "deep",
|
|
850
|
-
face: { head: "gable", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
851
|
-
},
|
|
852
|
-
{
|
|
853
|
-
callsign: "BEA",
|
|
854
|
-
group: "analyst-architect",
|
|
855
|
-
role: "business-analyst",
|
|
856
|
-
discipline: "business analyst",
|
|
857
|
-
tier: "standard",
|
|
858
|
-
face: { head: "gable", antenna: "none", eyes: "visor", mouth: "line", ears: false }
|
|
859
|
-
},
|
|
860
|
-
{
|
|
861
|
-
callsign: "WREN",
|
|
862
|
-
group: "analyst-architect",
|
|
863
|
-
role: "architect",
|
|
864
|
-
discipline: "solution architect",
|
|
865
|
-
tier: "deep",
|
|
866
|
-
face: { head: "gable", antenna: "dish", eyes: "bars", mouth: "line", ears: true }
|
|
867
|
-
},
|
|
868
|
-
{
|
|
869
|
-
callsign: "PEI",
|
|
870
|
-
group: "analyst-architect",
|
|
871
|
-
role: "architect",
|
|
872
|
-
discipline: "technical architect",
|
|
873
|
-
tier: "standard",
|
|
874
|
-
face: { head: "gable", antenna: "twin", eyes: "cyclops", mouth: "dots", ears: false }
|
|
875
|
-
},
|
|
876
|
-
// ── builders: code ──────────────────────────────────────────────────────────
|
|
877
|
-
{
|
|
878
|
-
callsign: "ADA",
|
|
879
|
-
group: "builder",
|
|
880
|
-
role: "builder",
|
|
881
|
-
discipline: "implementation",
|
|
882
|
-
tier: "deep",
|
|
883
|
-
face: { head: "sq", antenna: "stalk", eyes: "dots", mouth: "line", ears: false }
|
|
884
|
-
},
|
|
885
|
-
{
|
|
886
|
-
callsign: "OTTO",
|
|
887
|
-
group: "builder",
|
|
888
|
-
role: "builder",
|
|
889
|
-
discipline: "implementation",
|
|
890
|
-
tier: "deep",
|
|
891
|
-
face: { head: "sq", antenna: "twin", eyes: "bars", mouth: "grid", ears: true }
|
|
892
|
-
},
|
|
893
|
-
{
|
|
894
|
-
callsign: "MILO",
|
|
895
|
-
group: "builder",
|
|
896
|
-
role: "builder",
|
|
897
|
-
discipline: "implementation",
|
|
898
|
-
tier: "standard",
|
|
899
|
-
face: { head: "sqr", antenna: "stalk", eyes: "dots", mouth: "dots", ears: false }
|
|
900
|
-
},
|
|
901
|
-
{
|
|
902
|
-
callsign: "NOVA",
|
|
903
|
-
group: "builder",
|
|
904
|
-
role: "builder",
|
|
905
|
-
discipline: "implementation",
|
|
906
|
-
tier: "standard",
|
|
907
|
-
face: { head: "sq", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
908
|
-
},
|
|
909
|
-
{
|
|
910
|
-
callsign: "HUGO",
|
|
911
|
-
group: "builder",
|
|
912
|
-
role: "builder",
|
|
913
|
-
discipline: "infrastructure",
|
|
914
|
-
tier: "standard",
|
|
915
|
-
face: { head: "sq", antenna: "twin", eyes: "dots", mouth: "grid", ears: true }
|
|
916
|
-
},
|
|
917
|
-
// ── builders: specs and docs ────────────────────────────────────────────────
|
|
918
|
-
{
|
|
919
|
-
callsign: "IRIS",
|
|
920
|
-
group: "builder",
|
|
921
|
-
role: "spec-writer",
|
|
922
|
-
discipline: "feature spec",
|
|
923
|
-
tier: "deep",
|
|
924
|
-
face: { head: "dome", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
925
|
-
},
|
|
926
|
-
{
|
|
927
|
-
callsign: "JUNO",
|
|
928
|
-
group: "builder",
|
|
929
|
-
role: "spec-writer",
|
|
930
|
-
discipline: "feature spec",
|
|
931
|
-
tier: "standard",
|
|
932
|
-
face: { head: "dome", antenna: "none", eyes: "dots", mouth: "wave", ears: false }
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
callsign: "LEX",
|
|
936
|
-
group: "builder",
|
|
937
|
-
role: "context-docs",
|
|
938
|
-
discipline: "context & docs",
|
|
939
|
-
tier: "fast",
|
|
940
|
-
face: { head: "dome", antenna: "twin", eyes: "bars", mouth: "dots", ears: false }
|
|
941
|
-
},
|
|
942
|
-
// ── reviewers ───────────────────────────────────────────────────────────────
|
|
943
|
-
{
|
|
944
|
-
callsign: "VERA",
|
|
945
|
-
group: "reviewer",
|
|
946
|
-
role: "spec-reviewer",
|
|
947
|
-
discipline: "spec consistency",
|
|
948
|
-
tier: "deep",
|
|
949
|
-
face: { head: "rnd", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
950
|
-
},
|
|
951
|
-
{
|
|
952
|
-
callsign: "ODIN",
|
|
953
|
-
group: "reviewer",
|
|
954
|
-
role: "spec-reviewer",
|
|
955
|
-
discipline: "cross-spec audit",
|
|
956
|
-
tier: "deep",
|
|
957
|
-
face: { head: "rnd", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
958
|
-
},
|
|
959
|
-
{
|
|
960
|
-
callsign: "CASS",
|
|
961
|
-
group: "reviewer",
|
|
962
|
-
role: "code-test-reviewer",
|
|
963
|
-
discipline: "code review",
|
|
964
|
-
tier: "deep",
|
|
965
|
-
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "grid", ears: true }
|
|
966
|
-
},
|
|
967
|
-
{
|
|
968
|
-
callsign: "THEO",
|
|
969
|
-
group: "reviewer",
|
|
970
|
-
role: "code-test-reviewer",
|
|
971
|
-
discipline: "code review",
|
|
972
|
-
tier: "standard",
|
|
973
|
-
face: { head: "rnd", antenna: "twin", eyes: "bars", mouth: "line", ears: false }
|
|
974
|
-
},
|
|
975
|
-
{
|
|
976
|
-
callsign: "KAI",
|
|
977
|
-
group: "reviewer",
|
|
978
|
-
role: "code-test-reviewer",
|
|
979
|
-
discipline: "code review",
|
|
980
|
-
tier: "standard",
|
|
981
|
-
face: { head: "rnd", antenna: "none", eyes: "bars", mouth: "line", ears: true }
|
|
982
|
-
},
|
|
983
|
-
{
|
|
984
|
-
callsign: "ECHO",
|
|
985
|
-
group: "reviewer",
|
|
986
|
-
role: "code-test-reviewer",
|
|
987
|
-
discipline: "test quality",
|
|
988
|
-
tier: "standard",
|
|
989
|
-
face: { head: "rnd", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
callsign: "MAVIS",
|
|
993
|
-
group: "reviewer",
|
|
994
|
-
role: "code-test-reviewer",
|
|
995
|
-
discipline: "suites & coverage",
|
|
996
|
-
tier: "standard",
|
|
997
|
-
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "dots", ears: false }
|
|
998
|
-
},
|
|
999
|
-
{
|
|
1000
|
-
callsign: "ZARA",
|
|
1001
|
-
group: "reviewer",
|
|
1002
|
-
role: "code-test-reviewer",
|
|
1003
|
-
discipline: "smoke & walk aid",
|
|
1004
|
-
tier: "standard",
|
|
1005
|
-
face: { head: "rnd", antenna: "dish", eyes: "bars", mouth: "wave", ears: false }
|
|
1006
|
-
},
|
|
1007
|
-
{
|
|
1008
|
-
callsign: "NORA",
|
|
1009
|
-
group: "reviewer",
|
|
1010
|
-
role: "code-test-reviewer",
|
|
1011
|
-
discipline: "evidence & provenance",
|
|
1012
|
-
tier: "fast",
|
|
1013
|
-
face: { head: "rnd", antenna: "twin", eyes: "dots", mouth: "line", ears: false }
|
|
1014
|
-
},
|
|
1015
|
-
// ── leads ───────────────────────────────────────────────────────────────────
|
|
1016
|
-
{
|
|
1017
|
-
callsign: "ARGUS",
|
|
1018
|
-
group: "lead",
|
|
1019
|
-
role: "quality-lead",
|
|
1020
|
-
discipline: "quality lead \xB7 every diff",
|
|
1021
|
-
tier: "standard",
|
|
1022
|
-
face: { head: "hex", antenna: "dish", eyes: "visor", mouth: "grid", ears: true }
|
|
1023
|
-
},
|
|
1024
|
-
{
|
|
1025
|
-
callsign: "ATLAS",
|
|
1026
|
-
group: "lead",
|
|
1027
|
-
role: "delivery-lead",
|
|
1028
|
-
discipline: "delivery lead",
|
|
1029
|
-
tier: "deep",
|
|
1030
|
-
face: { head: "hex", antenna: "twin", eyes: "cyclops", mouth: "line", ears: true }
|
|
1031
|
-
}
|
|
1032
|
-
];
|
|
1033
|
-
var CREW_ROSTER_SIZE = CREW_ROSTER.length;
|
|
1034
|
-
var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
|
|
1035
|
-
var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
|
|
1036
|
-
var crewRoleLayersSchema = z6.object({
|
|
1037
|
-
leads: z6.array(crewLayerSchema),
|
|
1038
|
-
helps: z6.array(crewLayerSchema)
|
|
1039
|
-
}).strict();
|
|
1040
|
-
|
|
1041
|
-
// ../events/dist/build-snapshot.js
|
|
1042
|
-
import { z as z8 } from "zod";
|
|
1043
|
-
|
|
1044
|
-
// ../events/dist/system-description.js
|
|
1045
|
-
import { z as z7 } from "zod";
|
|
1046
|
-
var SYSTEM_DESCRIPTION_FORMAT = 1;
|
|
1047
|
-
var SYSTEM_PARTS_MAX = 60;
|
|
1048
|
-
var SYSTEM_CONNECTIONS_MAX = 400;
|
|
1049
|
-
var SYSTEM_SLOT_MAX = 11;
|
|
1050
|
-
var SYSTEM_OWNS_MAX = 20;
|
|
1051
|
-
var SYSTEM_OWNED_PATTERN_MAX = 200;
|
|
1052
|
-
var SYSTEM_PART_NAME_MAX = 60;
|
|
1053
|
-
var SYSTEM_PART_DESCRIPTION_MAX = 160;
|
|
1054
|
-
var SYSTEM_CONNECTION_LABEL_MAX = 60;
|
|
1055
|
-
var SYSTEM_PART_ID_PATTERN = /^[a-z][a-z0-9-]{0,39}$/;
|
|
1056
|
-
var SYSTEM_LANES = ["clients", "edge", "services", "data", "external"];
|
|
1057
|
-
var systemLaneSchema = z7.enum(SYSTEM_LANES, {
|
|
1058
|
-
error: `must be one of ${SYSTEM_LANES.join(", ")}`
|
|
1059
|
-
});
|
|
1060
|
-
var SYSTEM_CONNECTION_KINDS = ["call", "event", "write", "external"];
|
|
1061
|
-
var systemConnectionKindSchema = z7.enum(SYSTEM_CONNECTION_KINDS, {
|
|
1062
|
-
error: `must be one of ${SYSTEM_CONNECTION_KINDS.join(", ")}`
|
|
1063
|
-
});
|
|
1064
|
-
var LINE_SEPARATOR = /[\u2028\u2029]/;
|
|
1065
|
-
function descriptionText(max) {
|
|
1066
|
-
return statementText(max).refine((v) => v.trim().length > 0, { message: "must not be empty or only spaces" }).refine((v) => !LINE_SEPARATOR.test(v), {
|
|
1067
|
-
message: "must be one line: it holds a line or paragraph separator"
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
var systemPartIdSchema = z7.string().regex(SYSTEM_PART_ID_PATTERN, {
|
|
1071
|
-
message: "must be a short id: a lowercase letter, then lowercase letters, digits or hyphens, 40 characters at most"
|
|
1072
|
-
}).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key; choose another id" });
|
|
1073
|
-
function hasEmptySegment(pattern) {
|
|
1074
|
-
return pattern.split("/").some((segment) => segment.length === 0);
|
|
1075
|
-
}
|
|
1076
|
-
function hasDotSegment(pattern) {
|
|
1077
|
-
return pattern.split("/").some((segment) => segment === "." || segment === "..");
|
|
1078
|
-
}
|
|
1079
|
-
function hasPartialDoubleStar(pattern) {
|
|
1080
|
-
return pattern.split("/").some((segment) => segment.includes("**") && segment !== "**");
|
|
1081
|
-
}
|
|
1082
|
-
var SEGMENT_CHARACTERS = /^[A-Za-z0-9._\-*]*$/;
|
|
1083
|
-
function hasForeignCharacter(pattern) {
|
|
1084
|
-
return pattern.split("/").some((segment) => !SEGMENT_CHARACTERS.test(segment));
|
|
1085
|
-
}
|
|
1086
|
-
var systemOwnedPatternSchema = z7.string().max(SYSTEM_OWNED_PATTERN_MAX, { message: `must be at most ${SYSTEM_OWNED_PATTERN_MAX} characters` }).refine((v) => !hasEmptySegment(v), {
|
|
1087
|
-
message: "must not start or end with a slash, or have two slashes together"
|
|
1088
|
-
}).refine((v) => !hasDotSegment(v), { message: 'must not have a "." or ".." folder in it' }).refine((v) => !hasPartialDoubleStar(v), { message: '"**" must stand alone between slashes' }).refine((v) => !hasForeignCharacter(v), {
|
|
1089
|
-
message: 'may use only letters, digits, ".", "_", "-" and "*" between slashes'
|
|
1090
|
-
}).refine((v) => !looksLikeSecret(v), {
|
|
1091
|
-
message: "this path looks like a credential; list a shorter folder above it"
|
|
1092
|
-
});
|
|
1093
|
-
var systemPartSchema = z7.object({
|
|
1094
|
-
id: systemPartIdSchema,
|
|
1095
|
-
name: descriptionText(SYSTEM_PART_NAME_MAX),
|
|
1096
|
-
description: descriptionText(SYSTEM_PART_DESCRIPTION_MAX),
|
|
1097
|
-
lane: systemLaneSchema,
|
|
1098
|
-
slot: z7.number({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).int({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).max(SYSTEM_SLOT_MAX, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }),
|
|
1099
|
-
outside: z7.boolean(),
|
|
1100
|
-
owns: z7.array(systemOwnedPatternSchema).max(SYSTEM_OWNS_MAX, { message: `can list at most ${SYSTEM_OWNS_MAX} paths` })
|
|
1101
|
-
}).strict();
|
|
1102
|
-
var systemConnectionSchema = z7.object({
|
|
1103
|
-
from: systemPartIdSchema,
|
|
1104
|
-
to: systemPartIdSchema,
|
|
1105
|
-
kind: systemConnectionKindSchema,
|
|
1106
|
-
label: descriptionText(SYSTEM_CONNECTION_LABEL_MAX)
|
|
1107
|
-
}).strict();
|
|
1108
|
-
var systemDescriptionSchema = z7.object({
|
|
1109
|
-
format: z7.literal(SYSTEM_DESCRIPTION_FORMAT, { error: `must be ${SYSTEM_DESCRIPTION_FORMAT}` }),
|
|
1110
|
-
parts: z7.array(systemPartSchema).min(1, { message: "must list at least one part" }).max(SYSTEM_PARTS_MAX, { message: `can hold at most ${SYSTEM_PARTS_MAX} parts (five lanes of twelve slots)` }),
|
|
1111
|
-
connections: z7.array(systemConnectionSchema).max(SYSTEM_CONNECTIONS_MAX, { message: `can hold at most ${SYSTEM_CONNECTIONS_MAX} connections` })
|
|
1112
|
-
}).strict();
|
|
1113
|
-
var systemDescriptionProblemSchema = z7.object({
|
|
1114
|
-
path: z7.string(),
|
|
1115
|
-
message: z7.string()
|
|
1116
|
-
}).strict();
|
|
1117
|
-
var systemReportRecordedSchema = z7.object({
|
|
1118
|
-
outcome: z7.literal("recorded"),
|
|
1119
|
-
version: z7.number().int().min(1),
|
|
1120
|
-
reportedAt: utcIso8601
|
|
1121
|
-
}).strict();
|
|
1122
|
-
var systemReportRefusedSchema = z7.object({
|
|
1123
|
-
outcome: z7.literal("refused"),
|
|
1124
|
-
problems: z7.array(systemDescriptionProblemSchema).min(1)
|
|
1125
|
-
}).strict();
|
|
1126
|
-
var systemReportUnavailableSchema = z7.object({
|
|
1127
|
-
outcome: z7.literal("unavailable")
|
|
1128
|
-
}).strict();
|
|
1129
|
-
var systemReportResultSchema = z7.discriminatedUnion("outcome", [
|
|
1130
|
-
systemReportRecordedSchema,
|
|
1131
|
-
systemReportRefusedSchema,
|
|
1132
|
-
systemReportUnavailableSchema
|
|
1133
|
-
]);
|
|
1134
|
-
var SYSTEM_DRAW_SVG_MAX_BYTES = 2 * 1024 * 1024;
|
|
1135
|
-
var SYSTEM_DRAW_MERMAID_MAX_BYTES = 256 * 1024;
|
|
1136
|
-
var SYSTEM_DRAW_PNG_MAX_BYTES = 8 * 1024 * 1024;
|
|
1137
|
-
var systemDrawArchitectureRequestSchema = z7.object({
|
|
1138
|
-
picture: z7.literal("architecture"),
|
|
1139
|
-
version: z7.number().int().min(1)
|
|
951
|
+
var SYSTEM_DRAW_SVG_MAX_BYTES = 2 * 1024 * 1024;
|
|
952
|
+
var SYSTEM_DRAW_MERMAID_MAX_BYTES = 256 * 1024;
|
|
953
|
+
var SYSTEM_DRAW_PNG_MAX_BYTES = 8 * 1024 * 1024;
|
|
954
|
+
var systemDrawArchitectureRequestSchema = z7.object({
|
|
955
|
+
picture: z7.literal("architecture"),
|
|
956
|
+
version: z7.number().int().min(1)
|
|
1140
957
|
}).strict();
|
|
1141
958
|
var systemDrawPhaseRequestSchema = z7.object({
|
|
1142
959
|
picture: z7.literal("phase"),
|
|
@@ -1207,7 +1024,7 @@ var BUILD_TASK_WHY_OUTSIDE_PLAN_MAX = 160;
|
|
|
1207
1024
|
var BUILD_TASK_BUDGET_MAX_MINUTES = 10080;
|
|
1208
1025
|
var BUILD_TASK_NOTE_MAX = 240;
|
|
1209
1026
|
var BUILD_TASK_CLEAR_COMMAND_MAX = 240;
|
|
1210
|
-
var buildTaskKindSchema = z8.enum(["build", "review", "spec", "walk"]);
|
|
1027
|
+
var buildTaskKindSchema = z8.enum(["build", "review", "spec", "walk", "check"]);
|
|
1211
1028
|
var buildTaskIdSchema = z8.string().min(1).max(64);
|
|
1212
1029
|
var buildTaskSchema = z8.object({
|
|
1213
1030
|
// The task's own id, as the coordinator's graph names it.
|
|
@@ -1249,7 +1066,8 @@ var buildTaskSchema = z8.object({
|
|
|
1249
1066
|
// week. A plan, not a measurement; absent when no budget was set.
|
|
1250
1067
|
budgetMinutes: z8.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
|
|
1251
1068
|
// What kind of work the task is: building, checking other work, writing what to
|
|
1252
|
-
// build,
|
|
1069
|
+
// build, a person trying the product, or a run of the project's own checks.
|
|
1070
|
+
// Absent when the graph does not say.
|
|
1253
1071
|
kind: buildTaskKindSchema.optional(),
|
|
1254
1072
|
// One line from whoever holds the task about where it stands. Absent when there
|
|
1255
1073
|
// is nothing to say.
|
|
@@ -1359,27 +1177,55 @@ var buildSnapshotReportResultSchema = z8.object({
|
|
|
1359
1177
|
}).strict();
|
|
1360
1178
|
|
|
1361
1179
|
// ../events/dist/phase-plan.js
|
|
1180
|
+
import { z as z10 } from "zod";
|
|
1181
|
+
|
|
1182
|
+
// ../events/dist/change-path-order.js
|
|
1362
1183
|
import { z as z9 } from "zod";
|
|
1184
|
+
var PATH_ORDER = Object.freeze(["small", "mini", "full"]);
|
|
1185
|
+
var changePathSchema = z9.enum(PATH_ORDER);
|
|
1186
|
+
var PHASE_PATHS = Object.freeze(["mini", "full"]);
|
|
1187
|
+
var phasePathSchema = z9.enum(PHASE_PATHS);
|
|
1188
|
+
var changeUpPathSchema = z9.enum(["mini", "full"]);
|
|
1189
|
+
var CHANGE_PATH_NEXT = Object.freeze({
|
|
1190
|
+
small: Object.freeze({ say: "make the small change", section: "small" }),
|
|
1191
|
+
mini: Object.freeze({ say: "scope the mini phase", section: "mini" }),
|
|
1192
|
+
full: Object.freeze({ say: "plan the next phase", section: "full" })
|
|
1193
|
+
});
|
|
1194
|
+
var changePathNextSchema = z9.object({
|
|
1195
|
+
say: z9.enum([CHANGE_PATH_NEXT.small.say, CHANGE_PATH_NEXT.mini.say, CHANGE_PATH_NEXT.full.say]),
|
|
1196
|
+
section: changePathSchema
|
|
1197
|
+
}).strict();
|
|
1198
|
+
var CHANGE_SENTENCE_MAX = 4e3;
|
|
1199
|
+
var planMovedUpSchema = z9.object({
|
|
1200
|
+
to: z9.literal("full"),
|
|
1201
|
+
sentence: z9.string().min(1).max(CHANGE_SENTENCE_MAX),
|
|
1202
|
+
next: changePathNextSchema
|
|
1203
|
+
}).strict().refine((m) => m.next.say === CHANGE_PATH_NEXT.full.say && m.next.section === CHANGE_PATH_NEXT.full.section, {
|
|
1204
|
+
message: "names the full path's next phrase and section",
|
|
1205
|
+
path: ["next"]
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
// ../events/dist/phase-plan.js
|
|
1363
1209
|
var PHASE_PLAN_FORMAT = 1;
|
|
1364
1210
|
var PHASE_PLAN_CHANGES_MAX = 60;
|
|
1365
1211
|
var PHASE_PLAN_SUMMARY_MAX = 160;
|
|
1366
1212
|
var SCOPE_NOTE_MAX = 500;
|
|
1367
1213
|
var PHASE_PLAN_PHASE_MAX = buildPhaseSchema.maxLength ?? 0;
|
|
1368
1214
|
var PHASE_PLAN_CHANGE_KINDS = ["add", "change", "remove"];
|
|
1369
|
-
var phasePlanChangeSchema =
|
|
1215
|
+
var phasePlanChangeSchema = z10.enum(PHASE_PLAN_CHANGE_KINDS, {
|
|
1370
1216
|
error: `must be one of ${PHASE_PLAN_CHANGE_KINDS.join(", ")}`
|
|
1371
1217
|
});
|
|
1372
1218
|
var phasePlanPhaseSchema = phaseIdentitySchema.refine((v) => !isValidPhaseIdentity(v) || buildPhaseSchema.safeParse(String(v)).success, { message: `must be at most ${PHASE_PLAN_PHASE_MAX} characters` });
|
|
1373
1219
|
var phasePlanSummarySchema = descriptionText(PHASE_PLAN_SUMMARY_MAX);
|
|
1374
|
-
var phasePlanEntrySchema =
|
|
1220
|
+
var phasePlanEntrySchema = z10.object({
|
|
1375
1221
|
part: systemPartIdSchema,
|
|
1376
1222
|
change: phasePlanChangeSchema,
|
|
1377
1223
|
summary: phasePlanSummarySchema
|
|
1378
1224
|
}).strict();
|
|
1379
|
-
var phasePlanSchema =
|
|
1380
|
-
format:
|
|
1225
|
+
var phasePlanSchema = z10.object({
|
|
1226
|
+
format: z10.literal(PHASE_PLAN_FORMAT, { error: `must be ${PHASE_PLAN_FORMAT}` }),
|
|
1381
1227
|
phase: phasePlanPhaseSchema,
|
|
1382
|
-
changes:
|
|
1228
|
+
changes: z10.array(phasePlanEntrySchema).min(1, { message: "must list at least one part" }).max(PHASE_PLAN_CHANGES_MAX, { message: `can list at most ${PHASE_PLAN_CHANGES_MAX} parts` })
|
|
1383
1229
|
}).strict();
|
|
1384
1230
|
var scopePhaseSchema = buildPhaseSchema.refine((v) => isValidPhaseIdentity(v), {
|
|
1385
1231
|
message: "must be a phase name"
|
|
@@ -1391,109 +1237,110 @@ var SCOPE_STATE_NAMES = [
|
|
|
1391
1237
|
"approved",
|
|
1392
1238
|
"partly-stale"
|
|
1393
1239
|
];
|
|
1394
|
-
var scopeStateNameSchema =
|
|
1240
|
+
var scopeStateNameSchema = z10.enum(SCOPE_STATE_NAMES);
|
|
1395
1241
|
var plannedScopeStateSchema = scopeStateNameSchema.exclude(["not-planned"]);
|
|
1396
1242
|
var SCOPE_PART_STATUSES = ["approved", "waiting"];
|
|
1397
|
-
var scopePartStatusSchema =
|
|
1243
|
+
var scopePartStatusSchema = z10.enum(SCOPE_PART_STATUSES);
|
|
1398
1244
|
var SCOPE_ACTS = ["approve", "send-back"];
|
|
1399
|
-
var scopeActSchema =
|
|
1245
|
+
var scopeActSchema = z10.enum(SCOPE_ACTS);
|
|
1400
1246
|
var SCOPE_GIVEN_IN = ["console", "chat"];
|
|
1401
|
-
var scopeGivenInSchema =
|
|
1247
|
+
var scopeGivenInSchema = z10.enum(SCOPE_GIVEN_IN);
|
|
1402
1248
|
var scopeNoteSchema = descriptionText(SCOPE_NOTE_MAX);
|
|
1403
|
-
var scopeNoteWireSchema =
|
|
1249
|
+
var scopeNoteWireSchema = z10.string().max(SCOPE_NOTE_MAX);
|
|
1404
1250
|
var SCOPE_PART_VERDICTS = ["ok", "change"];
|
|
1405
|
-
var scopePartVerdictSchema =
|
|
1406
|
-
var scopeDecisionPartSchema =
|
|
1251
|
+
var scopePartVerdictSchema = z10.enum(SCOPE_PART_VERDICTS);
|
|
1252
|
+
var scopeDecisionPartSchema = z10.object({
|
|
1407
1253
|
part: systemPartIdSchema,
|
|
1408
1254
|
verdict: scopePartVerdictSchema,
|
|
1409
1255
|
note: scopeNoteWireSchema.optional()
|
|
1410
1256
|
}).strict();
|
|
1411
|
-
var planVersionSchema =
|
|
1412
|
-
var carriedPhaseSchema =
|
|
1257
|
+
var planVersionSchema = z10.number().int().min(1);
|
|
1258
|
+
var carriedPhaseSchema = z10.object({
|
|
1413
1259
|
phase: scopePhaseSchema,
|
|
1414
|
-
number:
|
|
1260
|
+
number: z10.number().int().min(1)
|
|
1415
1261
|
}).strict();
|
|
1416
1262
|
var carriedFromEntrySchema = carriedPhaseSchema.extend({
|
|
1417
1263
|
part: systemPartIdSchema
|
|
1418
1264
|
}).strict();
|
|
1419
|
-
var phasePlanRequestSchema =
|
|
1420
|
-
descriptionVersion:
|
|
1421
|
-
plan:
|
|
1265
|
+
var phasePlanRequestSchema = z10.object({
|
|
1266
|
+
descriptionVersion: z10.number().int().min(1),
|
|
1267
|
+
plan: z10.unknown()
|
|
1422
1268
|
}).strict();
|
|
1423
|
-
var phasePlanRecordedSchema =
|
|
1424
|
-
outcome:
|
|
1269
|
+
var phasePlanRecordedSchema = z10.object({
|
|
1270
|
+
outcome: z10.literal("recorded"),
|
|
1425
1271
|
version: planVersionSchema,
|
|
1426
|
-
phaseNumber:
|
|
1272
|
+
phaseNumber: z10.number().int().min(1),
|
|
1427
1273
|
state: plannedScopeStateSchema,
|
|
1428
|
-
changedParts:
|
|
1429
|
-
typedApprovalOffered:
|
|
1274
|
+
changedParts: z10.array(systemPartIdSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1275
|
+
typedApprovalOffered: z10.boolean(),
|
|
1430
1276
|
reportedAt: utcIso8601,
|
|
1431
|
-
carriedFrom:
|
|
1277
|
+
carriedFrom: z10.array(carriedFromEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX).optional(),
|
|
1278
|
+
movedUp: planMovedUpSchema.optional()
|
|
1432
1279
|
}).strict();
|
|
1433
|
-
var phasePlanRefusedSchema =
|
|
1434
|
-
outcome:
|
|
1435
|
-
problems:
|
|
1280
|
+
var phasePlanRefusedSchema = z10.object({
|
|
1281
|
+
outcome: z10.literal("refused"),
|
|
1282
|
+
problems: z10.array(systemDescriptionProblemSchema).min(1)
|
|
1436
1283
|
}).strict();
|
|
1437
|
-
var phasePlanUnavailableSchema =
|
|
1438
|
-
outcome:
|
|
1284
|
+
var phasePlanUnavailableSchema = z10.object({
|
|
1285
|
+
outcome: z10.literal("unavailable")
|
|
1439
1286
|
}).strict();
|
|
1440
1287
|
var REMOVAL_OWED_ACTS = ["dropped", "removed"];
|
|
1441
|
-
var removalOwedPartSchema =
|
|
1288
|
+
var removalOwedPartSchema = z10.object({
|
|
1442
1289
|
part: systemPartIdSchema,
|
|
1443
1290
|
name: systemPartSchema.shape.name,
|
|
1444
1291
|
phase: scopePhaseSchema,
|
|
1445
|
-
number:
|
|
1446
|
-
act:
|
|
1292
|
+
number: z10.number().int().min(1),
|
|
1293
|
+
act: z10.enum(REMOVAL_OWED_ACTS)
|
|
1447
1294
|
}).strict();
|
|
1448
|
-
var phasePlanRemovalOwedSchema =
|
|
1449
|
-
outcome:
|
|
1450
|
-
parts:
|
|
1295
|
+
var phasePlanRemovalOwedSchema = z10.object({
|
|
1296
|
+
outcome: z10.literal("removal-owed"),
|
|
1297
|
+
parts: z10.array(removalOwedPartSchema).min(1).max(SYSTEM_PARTS_MAX)
|
|
1451
1298
|
}).strict();
|
|
1452
|
-
var phasePlanResultSchema =
|
|
1299
|
+
var phasePlanResultSchema = z10.discriminatedUnion("outcome", [
|
|
1453
1300
|
phasePlanRecordedSchema,
|
|
1454
1301
|
phasePlanRefusedSchema,
|
|
1455
1302
|
phasePlanUnavailableSchema,
|
|
1456
1303
|
phasePlanRemovalOwedSchema
|
|
1457
1304
|
]);
|
|
1458
|
-
var scopeApproveRequestSchema =
|
|
1459
|
-
act:
|
|
1305
|
+
var scopeApproveRequestSchema = z10.object({
|
|
1306
|
+
act: z10.literal("approve"),
|
|
1460
1307
|
planVersion: planVersionSchema,
|
|
1461
|
-
parts:
|
|
1308
|
+
parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX)
|
|
1462
1309
|
}).strict();
|
|
1463
|
-
var scopeSendBackRequestSchema =
|
|
1464
|
-
act:
|
|
1310
|
+
var scopeSendBackRequestSchema = z10.object({
|
|
1311
|
+
act: z10.literal("send-back"),
|
|
1465
1312
|
planVersion: planVersionSchema,
|
|
1466
|
-
parts:
|
|
1313
|
+
parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1467
1314
|
note: scopeNoteWireSchema.optional()
|
|
1468
1315
|
}).strict();
|
|
1469
|
-
var scopeDecisionRequestSchema =
|
|
1316
|
+
var scopeDecisionRequestSchema = z10.discriminatedUnion("act", [
|
|
1470
1317
|
scopeApproveRequestSchema,
|
|
1471
1318
|
scopeSendBackRequestSchema
|
|
1472
1319
|
]);
|
|
1473
|
-
var scopeDecisionRecordedSchema =
|
|
1474
|
-
outcome:
|
|
1320
|
+
var scopeDecisionRecordedSchema = z10.object({
|
|
1321
|
+
outcome: z10.literal("recorded"),
|
|
1475
1322
|
act: scopeActSchema,
|
|
1476
1323
|
phase: scopePhaseSchema,
|
|
1477
1324
|
planVersion: planVersionSchema,
|
|
1478
1325
|
state: plannedScopeStateSchema,
|
|
1479
1326
|
decidedAt: utcIso8601
|
|
1480
1327
|
}).strict();
|
|
1481
|
-
var scopeDecisionAlreadyApprovedSchema =
|
|
1482
|
-
outcome:
|
|
1483
|
-
replanNeeded:
|
|
1484
|
-
reason:
|
|
1328
|
+
var scopeDecisionAlreadyApprovedSchema = z10.object({
|
|
1329
|
+
outcome: z10.literal("already-approved"),
|
|
1330
|
+
replanNeeded: z10.boolean(),
|
|
1331
|
+
reason: z10.string().min(1)
|
|
1485
1332
|
}).strict();
|
|
1486
|
-
var scopeDecisionRefusedSchema =
|
|
1487
|
-
outcome:
|
|
1488
|
-
problems:
|
|
1333
|
+
var scopeDecisionRefusedSchema = z10.object({
|
|
1334
|
+
outcome: z10.literal("refused"),
|
|
1335
|
+
problems: z10.array(systemDescriptionProblemSchema).min(1)
|
|
1489
1336
|
}).strict();
|
|
1490
|
-
var scopeDecisionUnavailableSchema =
|
|
1491
|
-
outcome:
|
|
1337
|
+
var scopeDecisionUnavailableSchema = z10.object({
|
|
1338
|
+
outcome: z10.literal("unavailable")
|
|
1492
1339
|
}).strict();
|
|
1493
1340
|
function reasonOutcome(outcome) {
|
|
1494
|
-
return
|
|
1341
|
+
return z10.object({ outcome: z10.literal(outcome), reason: z10.string().min(1) }).strict();
|
|
1495
1342
|
}
|
|
1496
|
-
var scopeDecisionResultSchema =
|
|
1343
|
+
var scopeDecisionResultSchema = z10.discriminatedUnion("outcome", [
|
|
1497
1344
|
scopeDecisionRecordedSchema,
|
|
1498
1345
|
scopeDecisionAlreadyApprovedSchema,
|
|
1499
1346
|
scopeDecisionRefusedSchema,
|
|
@@ -1503,60 +1350,42 @@ var scopeDecisionResultSchema = z9.discriminatedUnion("outcome", [
|
|
|
1503
1350
|
reasonOutcome("plan-changed"),
|
|
1504
1351
|
reasonOutcome("build-started")
|
|
1505
1352
|
]);
|
|
1506
|
-
var scopeReadPartSchema =
|
|
1353
|
+
var scopeReadPartSchema = z10.object({
|
|
1507
1354
|
part: systemPartIdSchema,
|
|
1508
1355
|
name: systemPartSchema.shape.name,
|
|
1509
1356
|
change: phasePlanChangeSchema,
|
|
1510
1357
|
summary: phasePlanSummarySchema,
|
|
1511
1358
|
status: scopePartStatusSchema,
|
|
1512
|
-
changed:
|
|
1359
|
+
changed: z10.boolean(),
|
|
1513
1360
|
carriedFrom: carriedPhaseSchema.optional()
|
|
1514
1361
|
}).strict();
|
|
1515
|
-
var scopeReadDecisionSchema =
|
|
1362
|
+
var scopeReadDecisionSchema = z10.object({
|
|
1516
1363
|
act: scopeActSchema,
|
|
1517
1364
|
planVersion: planVersionSchema,
|
|
1518
1365
|
givenIn: scopeGivenInSchema,
|
|
1519
1366
|
at: utcIso8601,
|
|
1520
|
-
parts:
|
|
1367
|
+
parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1521
1368
|
note: scopeNoteWireSchema.optional()
|
|
1522
1369
|
}).strict();
|
|
1523
|
-
var scopeReadNotPlannedSchema =
|
|
1370
|
+
var scopeReadNotPlannedSchema = z10.object({
|
|
1524
1371
|
phase: scopePhaseSchema,
|
|
1525
|
-
state:
|
|
1526
|
-
canDecide:
|
|
1372
|
+
state: z10.literal("not-planned"),
|
|
1373
|
+
canDecide: z10.boolean()
|
|
1527
1374
|
}).strict();
|
|
1528
|
-
var scopeReadPlannedSchema =
|
|
1375
|
+
var scopeReadPlannedSchema = z10.object({
|
|
1529
1376
|
phase: scopePhaseSchema,
|
|
1530
1377
|
state: plannedScopeStateSchema,
|
|
1531
|
-
phaseNumber:
|
|
1378
|
+
phaseNumber: z10.number().int().min(1),
|
|
1532
1379
|
planVersion: planVersionSchema,
|
|
1533
|
-
parts:
|
|
1534
|
-
decisions:
|
|
1535
|
-
canDecide:
|
|
1536
|
-
replanLine:
|
|
1380
|
+
parts: z10.array(scopeReadPartSchema).min(1).max(PHASE_PLAN_CHANGES_MAX),
|
|
1381
|
+
decisions: z10.array(scopeReadDecisionSchema),
|
|
1382
|
+
canDecide: z10.boolean(),
|
|
1383
|
+
replanLine: z10.string().min(1).optional()
|
|
1537
1384
|
}).strict();
|
|
1538
|
-
var scopeReadSchema =
|
|
1539
|
-
|
|
1540
|
-
// ../events/dist/build-record-v3.js
|
|
1541
|
-
import { z as z14 } from "zod";
|
|
1385
|
+
var scopeReadSchema = z10.union([scopeReadNotPlannedSchema, scopeReadPlannedSchema]);
|
|
1542
1386
|
|
|
1543
|
-
// ../events/dist/
|
|
1544
|
-
import { z as
|
|
1545
|
-
var boardStepStateSchema = z10.enum([
|
|
1546
|
-
"not-instrumented",
|
|
1547
|
-
"done",
|
|
1548
|
-
"did-not-pass",
|
|
1549
|
-
"could-not-complete",
|
|
1550
|
-
"not-yet-available",
|
|
1551
|
-
"qualified"
|
|
1552
|
-
]);
|
|
1553
|
-
var boardGateNameSchema = z10.enum([
|
|
1554
|
-
"scope",
|
|
1555
|
-
"architecture",
|
|
1556
|
-
"specs",
|
|
1557
|
-
"taskgraph",
|
|
1558
|
-
"phase-close"
|
|
1559
|
-
]);
|
|
1387
|
+
// ../events/dist/observed-changes.js
|
|
1388
|
+
import { z as z12 } from "zod";
|
|
1560
1389
|
|
|
1561
1390
|
// ../events/dist/code-link.js
|
|
1562
1391
|
import { z as z11 } from "zod";
|
|
@@ -1592,7 +1421,6 @@ var partCodeLinkSchema = z11.discriminatedUnion("kind", [
|
|
|
1592
1421
|
]);
|
|
1593
1422
|
|
|
1594
1423
|
// ../events/dist/observed-changes.js
|
|
1595
|
-
import { z as z12 } from "zod";
|
|
1596
1424
|
var OBSERVED_PATHS_LISTED_MAX = 50;
|
|
1597
1425
|
var OBSERVED_PATH_MAX = 300;
|
|
1598
1426
|
var OBSERVED_COUNT_MAX = 1e6;
|
|
@@ -1801,36 +1629,659 @@ var observedChangesSchema = z12.object({
|
|
|
1801
1629
|
if (counted2 && v.descriptionVersion === null) {
|
|
1802
1630
|
ctx.addIssue({ code: "custom", path: ["descriptionVersion"], message: "must name the version the counts used" });
|
|
1803
1631
|
}
|
|
1804
|
-
});
|
|
1805
|
-
var partOutsideThePlanSchema = z12.object({
|
|
1806
|
-
part: systemPartIdSchema,
|
|
1807
|
-
name: systemPartSchema.shape.name,
|
|
1808
|
-
seen: observedFilesSchema.nullable(),
|
|
1809
|
-
tasks: z12.array(observedSaidSchema.extend({ id: buildTaskSchema.shape.id }).strict()).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1632
|
+
});
|
|
1633
|
+
var partOutsideThePlanSchema = z12.object({
|
|
1634
|
+
part: systemPartIdSchema,
|
|
1635
|
+
name: systemPartSchema.shape.name,
|
|
1636
|
+
seen: observedFilesSchema.nullable(),
|
|
1637
|
+
tasks: z12.array(observedSaidSchema.extend({ id: buildTaskSchema.shape.id }).strict()).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1638
|
+
}).strict();
|
|
1639
|
+
function shortCommit(commit) {
|
|
1640
|
+
return commit.slice(0, 7);
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// ../events/dist/work-record.js
|
|
1644
|
+
import { z as z14 } from "zod";
|
|
1645
|
+
|
|
1646
|
+
// ../events/dist/crew-tier.js
|
|
1647
|
+
import { z as z13 } from "zod";
|
|
1648
|
+
var crewTierSchema = z13.enum(["deep", "standard", "fast"]);
|
|
1649
|
+
|
|
1650
|
+
// ../events/dist/work-record.js
|
|
1651
|
+
var agentWorkText = statementText(STATEMENT_MAX);
|
|
1652
|
+
var WORK_FINDINGS_MAX = 100;
|
|
1653
|
+
var WORK_ANSWERS_MAX = 100;
|
|
1654
|
+
var WORK_ATTEMPT_LIMIT = 4;
|
|
1655
|
+
var WORK_CLAIM_CHECKS_MAX = 20;
|
|
1656
|
+
var findingIdSchema = z14.string().regex(/^F[1-9][0-9]?\.[AQ][1-9][0-9]{0,2}$/, { message: "must be a finding id such as F1.A1" });
|
|
1657
|
+
var WORK_STAGES = Object.freeze(["asked", "quality"]);
|
|
1658
|
+
var workStageSchema = z14.enum(WORK_STAGES);
|
|
1659
|
+
var workVerdictSchema = z14.enum(["pass", "fail"]);
|
|
1660
|
+
var WORK_FINDING_KINDS = Object.freeze([
|
|
1661
|
+
"asked",
|
|
1662
|
+
"quality",
|
|
1663
|
+
"unrecorded-call",
|
|
1664
|
+
"undeclared-listed-decision"
|
|
1665
|
+
]);
|
|
1666
|
+
var workFindingKindSchema = z14.enum(WORK_FINDING_KINDS);
|
|
1667
|
+
var WORK_ASKED_ONLY_FINDING_KINDS = Object.freeze([
|
|
1668
|
+
"unrecorded-call",
|
|
1669
|
+
"undeclared-listed-decision"
|
|
1670
|
+
]);
|
|
1671
|
+
var workOutcomeSchema = z14.enum(["fixed", "declined", "deferred"]);
|
|
1672
|
+
var DIAGNOSIS_CAUSES = Object.freeze([
|
|
1673
|
+
"spec",
|
|
1674
|
+
"ordering",
|
|
1675
|
+
"approach",
|
|
1676
|
+
"capability",
|
|
1677
|
+
"environment",
|
|
1678
|
+
"review"
|
|
1679
|
+
]);
|
|
1680
|
+
var diagnosisCauseSchema = z14.enum(DIAGNOSIS_CAUSES);
|
|
1681
|
+
var diagnosisNextSchema = z14.enum(["different-way", "stop", "ask-person"]);
|
|
1682
|
+
var callUndoableSchema = z14.enum(["yes", "no"]);
|
|
1683
|
+
var callKindSchema = z14.enum(["default", "listed"]);
|
|
1684
|
+
var commitShaSchema = closeCommitSchema;
|
|
1685
|
+
var workChangeIdSchema = z14.string().uuid({ message: "must be the change id Halfcycle gave" });
|
|
1686
|
+
var workTaskSubjectSchema = z14.object({
|
|
1687
|
+
kind: z14.literal("task"),
|
|
1688
|
+
phase: buildPhaseSchema,
|
|
1689
|
+
task: buildTaskIdSchema
|
|
1690
|
+
}).strict();
|
|
1691
|
+
var workChangeSubjectSchema = z14.object({
|
|
1692
|
+
kind: z14.literal("change"),
|
|
1693
|
+
change: workChangeIdSchema
|
|
1694
|
+
}).strict();
|
|
1695
|
+
var workPhaseSubjectSchema = z14.object({
|
|
1696
|
+
kind: z14.literal("phase"),
|
|
1697
|
+
phase: buildPhaseSchema
|
|
1698
|
+
}).strict();
|
|
1699
|
+
var workSubjectSchema = z14.discriminatedUnion("kind", [
|
|
1700
|
+
workTaskSubjectSchema,
|
|
1701
|
+
workChangeSubjectSchema,
|
|
1702
|
+
workPhaseSubjectSchema
|
|
1703
|
+
]);
|
|
1704
|
+
var workItemSubjectSchema = z14.discriminatedUnion("kind", [workTaskSubjectSchema, workChangeSubjectSchema]);
|
|
1705
|
+
var workFindingInputSchema = z14.object({
|
|
1706
|
+
kind: workFindingKindSchema,
|
|
1707
|
+
says: agentWorkText
|
|
1708
|
+
}).strict();
|
|
1709
|
+
var workReviewRecordSchema = z14.object({
|
|
1710
|
+
record: z14.literal("review"),
|
|
1711
|
+
subject: workItemSubjectSchema,
|
|
1712
|
+
stage: workStageSchema,
|
|
1713
|
+
verdict: workVerdictSchema,
|
|
1714
|
+
reviewer: agentNameSchema,
|
|
1715
|
+
builder: agentNameSchema,
|
|
1716
|
+
builderTier: crewTierSchema,
|
|
1717
|
+
head: commitShaSchema,
|
|
1718
|
+
findings: z14.array(workFindingInputSchema).max(WORK_FINDINGS_MAX, { message: `can carry at most ${WORK_FINDINGS_MAX} findings` }),
|
|
1719
|
+
retryReason: agentWorkText.optional(),
|
|
1720
|
+
diagnosis: z14.string().uuid({ message: "must be the diagnosis id Halfcycle gave" }).optional(),
|
|
1721
|
+
followsDiagnosis: z14.boolean().optional()
|
|
1722
|
+
}).strict().refine((r) => r.stage === "asked" || r.findings.every((f) => !WORK_ASKED_ONLY_FINDING_KINDS.includes(f.kind)), {
|
|
1723
|
+
message: "a review for quality cannot raise an unrecorded call or an undeclared listed decision",
|
|
1724
|
+
path: ["findings"]
|
|
1725
|
+
});
|
|
1726
|
+
var workAnswerSchema = z14.object({
|
|
1727
|
+
finding: findingIdSchema,
|
|
1728
|
+
outcome: workOutcomeSchema,
|
|
1729
|
+
reason: agentWorkText.optional()
|
|
1730
|
+
}).strict().refine((a) => a.outcome === "fixed" === (a.reason === void 0), {
|
|
1731
|
+
message: "a reason is given exactly when a finding is declined or deferred",
|
|
1732
|
+
path: ["reason"]
|
|
1733
|
+
});
|
|
1734
|
+
var workOutcomesRecordSchema = z14.object({
|
|
1735
|
+
record: z14.literal("outcomes"),
|
|
1736
|
+
subject: workItemSubjectSchema,
|
|
1737
|
+
by: agentNameSchema,
|
|
1738
|
+
answers: z14.array(workAnswerSchema).min(1, { message: "must answer at least one finding" }).max(WORK_ANSWERS_MAX, { message: `can carry at most ${WORK_ANSWERS_MAX} answers` })
|
|
1739
|
+
}).strict().refine((r) => new Set(r.answers.map((a) => a.finding)).size === r.answers.length, {
|
|
1740
|
+
message: "answers each finding once",
|
|
1741
|
+
path: ["answers"]
|
|
1742
|
+
});
|
|
1743
|
+
var workClaimsRecordSchema = z14.object({
|
|
1744
|
+
record: z14.literal("claims"),
|
|
1745
|
+
subject: workItemSubjectSchema,
|
|
1746
|
+
head: commitShaSchema,
|
|
1747
|
+
by: agentNameSchema,
|
|
1748
|
+
checks: z14.array(z14.object({ label: agentWorkText }).strict()).min(1, { message: "must name at least one check" }).max(WORK_CLAIM_CHECKS_MAX, { message: `can name at most ${WORK_CLAIM_CHECKS_MAX} checks` })
|
|
1749
|
+
}).strict().refine((r) => new Set(r.checks.map((c) => c.label)).size === r.checks.length, {
|
|
1750
|
+
message: "names each check once",
|
|
1751
|
+
path: ["checks"]
|
|
1752
|
+
});
|
|
1753
|
+
var workDiagnosisRecordSchema = z14.object({
|
|
1754
|
+
record: z14.literal("diagnosis"),
|
|
1755
|
+
subject: workItemSubjectSchema,
|
|
1756
|
+
afterAttempt: z14.number().int().min(2, { message: "must be attempt 2 or later" }).max(WORK_ATTEMPT_LIMIT - 1, { message: `must be attempt ${WORK_ATTEMPT_LIMIT - 1} or earlier` }),
|
|
1757
|
+
by: agentNameSchema,
|
|
1758
|
+
cause: diagnosisCauseSchema,
|
|
1759
|
+
says: agentWorkText,
|
|
1760
|
+
next: diagnosisNextSchema,
|
|
1761
|
+
change: agentWorkText.optional(),
|
|
1762
|
+
question: agentWorkText.optional(),
|
|
1763
|
+
answer: agentWorkText.optional()
|
|
1764
|
+
}).strict().refine((r) => r.next === "different-way" === (r.change !== void 0), {
|
|
1765
|
+
message: "says what will change exactly when the next step is to try a different way",
|
|
1766
|
+
path: ["change"]
|
|
1767
|
+
}).refine((r) => r.next === "ask-person" === (r.question !== void 0), {
|
|
1768
|
+
message: "carries a question exactly when the next step is to ask the person",
|
|
1769
|
+
path: ["question"]
|
|
1770
|
+
});
|
|
1771
|
+
var workCallRecordSchema = z14.object({
|
|
1772
|
+
record: z14.literal("call"),
|
|
1773
|
+
subject: workSubjectSchema,
|
|
1774
|
+
by: agentNameSchema,
|
|
1775
|
+
question: agentWorkText,
|
|
1776
|
+
chose: agentWorkText,
|
|
1777
|
+
statedDefault: agentWorkText,
|
|
1778
|
+
undoable: callUndoableSchema,
|
|
1779
|
+
how: agentWorkText.optional()
|
|
1780
|
+
}).strict().refine((r) => r.undoable === "yes" === (r.how !== void 0), {
|
|
1781
|
+
message: "says how to undo it exactly when it can be undone",
|
|
1782
|
+
path: ["how"]
|
|
1783
|
+
});
|
|
1784
|
+
var workRecordSchema = z14.discriminatedUnion("record", [
|
|
1785
|
+
workReviewRecordSchema,
|
|
1786
|
+
workOutcomesRecordSchema,
|
|
1787
|
+
workClaimsRecordSchema,
|
|
1788
|
+
workDiagnosisRecordSchema,
|
|
1789
|
+
workCallRecordSchema
|
|
1790
|
+
]);
|
|
1791
|
+
var WORK_STANDINGS = Object.freeze([
|
|
1792
|
+
"not-reviewed",
|
|
1793
|
+
"stopped",
|
|
1794
|
+
"held",
|
|
1795
|
+
"needs-diagnosis",
|
|
1796
|
+
"failed",
|
|
1797
|
+
"in-review",
|
|
1798
|
+
"findings-open",
|
|
1799
|
+
"passed"
|
|
1800
|
+
]);
|
|
1801
|
+
var workStandingSchema = z14.enum(WORK_STANDINGS);
|
|
1802
|
+
var workRecordResultSchema = z14.object({
|
|
1803
|
+
outcome: z14.enum(["recorded", "kept"]),
|
|
1804
|
+
attempt: z14.number().int().min(1).optional(),
|
|
1805
|
+
findings: z14.array(findingIdSchema).max(WORK_FINDINGS_MAX).optional(),
|
|
1806
|
+
diagnosis: z14.string().uuid().optional(),
|
|
1807
|
+
standing: workStandingSchema,
|
|
1808
|
+
says: z14.string().min(1)
|
|
1809
|
+
}).strict();
|
|
1810
|
+
var WORK_REFUSAL_STATUS = Object.freeze({
|
|
1811
|
+
"phase-not-open": 409,
|
|
1812
|
+
"unknown-task": 400,
|
|
1813
|
+
"unknown-change": 404,
|
|
1814
|
+
"change-finished": 409,
|
|
1815
|
+
"out-of-order": 409,
|
|
1816
|
+
"same-agent": 409,
|
|
1817
|
+
"already-recorded": 409,
|
|
1818
|
+
"already-answered": 409,
|
|
1819
|
+
"unknown-finding": 400,
|
|
1820
|
+
"findings-unanswered": 409,
|
|
1821
|
+
"listed-decision-passed": 400,
|
|
1822
|
+
"needs-diagnosis": 409,
|
|
1823
|
+
"no-diagnosis-due": 409,
|
|
1824
|
+
"not-fresh": 409,
|
|
1825
|
+
"graph-unchanged": 409,
|
|
1826
|
+
"no-graph": 400,
|
|
1827
|
+
"wrong-diagnosis": 409,
|
|
1828
|
+
"diagnosis-not-followed": 400,
|
|
1829
|
+
stopped: 409,
|
|
1830
|
+
held: 409,
|
|
1831
|
+
"attempt-limit": 409,
|
|
1832
|
+
"same-attempt": 409,
|
|
1833
|
+
"call-not-recorded": 409
|
|
1834
|
+
});
|
|
1835
|
+
var WORK_REFUSALS = Object.freeze(Object.keys(WORK_REFUSAL_STATUS));
|
|
1836
|
+
var workRefusalSchema = z14.enum(WORK_REFUSALS);
|
|
1837
|
+
var workRefusalErrorSchema = wireErrorSchema.extend({ error: workRefusalSchema }).strict().refine((e) => e.statusCode === WORK_REFUSAL_STATUS[e.error], {
|
|
1838
|
+
message: "carries the status its refusal is answered with",
|
|
1839
|
+
path: ["statusCode"]
|
|
1840
|
+
});
|
|
1841
|
+
var testCommandIdSchema = z14.string().regex(/^[0-9a-f]{16}$/, { message: "must be 16 lower-case hex characters" });
|
|
1842
|
+
var workCountSchema = z14.number().int().min(0);
|
|
1843
|
+
var testRunReportSchema = z14.object({
|
|
1844
|
+
runId: z14.string().uuid(),
|
|
1845
|
+
subject: workItemSubjectSchema,
|
|
1846
|
+
label: agentWorkText,
|
|
1847
|
+
when: z14.enum(["before", "after"]),
|
|
1848
|
+
commandId: testCommandIdSchema,
|
|
1849
|
+
head: commitShaSchema,
|
|
1850
|
+
changedOutsideTests: workCountSchema,
|
|
1851
|
+
uncommitted: workCountSchema,
|
|
1852
|
+
beforeRunId: z14.string().uuid().nullable(),
|
|
1853
|
+
changedSinceBefore: workCountSchema.nullable(),
|
|
1854
|
+
exitCode: z14.number().int().nullable(),
|
|
1855
|
+
timedOut: z14.boolean(),
|
|
1856
|
+
passed: workCountSchema.nullable(),
|
|
1857
|
+
failed: workCountSchema.nullable(),
|
|
1858
|
+
durationMs: workCountSchema,
|
|
1859
|
+
startedAt: utcIso8601,
|
|
1860
|
+
reason: agentWorkText.optional()
|
|
1861
|
+
}).strict().refine((r) => r.passed === null === (r.failed === null), {
|
|
1862
|
+
message: "counts both passed and failed, or neither",
|
|
1863
|
+
path: ["failed"]
|
|
1864
|
+
}).refine((r) => r.when === "after" || r.beforeRunId === null && r.changedSinceBefore === null, {
|
|
1865
|
+
message: "a run before the change is measured against no earlier run",
|
|
1866
|
+
path: ["beforeRunId"]
|
|
1867
|
+
}).refine((r) => !r.timedOut || r.exitCode === null, {
|
|
1868
|
+
message: "a run that timed out has no exit code",
|
|
1869
|
+
path: ["exitCode"]
|
|
1870
|
+
});
|
|
1871
|
+
var testRunResultSchema = z14.object({ outcome: z14.literal("recorded") }).strict();
|
|
1872
|
+
var TEST_PROOF_REASONS = Object.freeze([
|
|
1873
|
+
"no-run-before",
|
|
1874
|
+
"before-after-change",
|
|
1875
|
+
"not-counted",
|
|
1876
|
+
"passed-before",
|
|
1877
|
+
"no-run-after",
|
|
1878
|
+
"command-changed",
|
|
1879
|
+
"not-after-before",
|
|
1880
|
+
"nothing-changed",
|
|
1881
|
+
"failed-after",
|
|
1882
|
+
"after-not-at-claimed-head"
|
|
1883
|
+
]);
|
|
1884
|
+
var testProofReasonSchema = z14.enum(TEST_PROOF_REASONS);
|
|
1885
|
+
var testProofStateSchema = z14.enum(["proven", "not-proven", "unchecked"]);
|
|
1886
|
+
var testRunCountsSchema = z14.object({
|
|
1887
|
+
passed: workCountSchema.nullable(),
|
|
1888
|
+
failed: workCountSchema.nullable(),
|
|
1889
|
+
durationMs: workCountSchema,
|
|
1890
|
+
timedOut: z14.boolean()
|
|
1891
|
+
}).strict();
|
|
1892
|
+
var workTestSchema = z14.object({
|
|
1893
|
+
label: agentWorkText,
|
|
1894
|
+
state: testProofStateSchema,
|
|
1895
|
+
why: testProofReasonSchema.optional(),
|
|
1896
|
+
claimedBy: agentNameSchema,
|
|
1897
|
+
before: testRunCountsSchema.optional(),
|
|
1898
|
+
after: testRunCountsSchema.optional()
|
|
1899
|
+
}).strict().refine((t) => t.state === "not-proven" === (t.why !== void 0), {
|
|
1900
|
+
message: "gives a reason exactly when a check is not proven",
|
|
1901
|
+
path: ["why"]
|
|
1902
|
+
});
|
|
1903
|
+
var workFindingOutcomeSchema = z14.object({
|
|
1904
|
+
outcome: workOutcomeSchema,
|
|
1905
|
+
reason: agentWorkText.optional(),
|
|
1906
|
+
by: agentNameSchema
|
|
1907
|
+
}).strict().refine((o) => o.outcome === "fixed" === (o.reason === void 0), {
|
|
1908
|
+
message: "a reason is given exactly when a finding is declined or deferred",
|
|
1909
|
+
path: ["reason"]
|
|
1910
|
+
});
|
|
1911
|
+
var workFindingSchema = z14.object({
|
|
1912
|
+
id: findingIdSchema,
|
|
1913
|
+
kind: workFindingKindSchema,
|
|
1914
|
+
says: agentWorkText,
|
|
1915
|
+
outcome: workFindingOutcomeSchema.optional()
|
|
1916
|
+
}).strict();
|
|
1917
|
+
var workStageViewSchema = z14.object({
|
|
1918
|
+
reviewer: agentNameSchema,
|
|
1919
|
+
verdict: workVerdictSchema,
|
|
1920
|
+
findings: z14.array(workFindingSchema).max(WORK_FINDINGS_MAX)
|
|
1921
|
+
}).strict();
|
|
1922
|
+
var workAttemptSchema = z14.object({
|
|
1923
|
+
attempt: z14.number().int().min(1),
|
|
1924
|
+
builder: agentNameSchema,
|
|
1925
|
+
builderTier: crewTierSchema,
|
|
1926
|
+
head: commitShaSchema,
|
|
1927
|
+
retryReason: agentWorkText.optional(),
|
|
1928
|
+
diagnosis: z14.string().uuid().optional(),
|
|
1929
|
+
followsDiagnosis: z14.boolean().optional(),
|
|
1930
|
+
asked: workStageViewSchema.optional(),
|
|
1931
|
+
quality: workStageViewSchema.optional()
|
|
1932
|
+
}).strict();
|
|
1933
|
+
var workDiagnosisSchema = z14.object({
|
|
1934
|
+
id: z14.string().uuid(),
|
|
1935
|
+
afterAttempt: z14.number().int().min(2).max(WORK_ATTEMPT_LIMIT - 1),
|
|
1936
|
+
by: agentNameSchema,
|
|
1937
|
+
cause: diagnosisCauseSchema,
|
|
1938
|
+
says: agentWorkText,
|
|
1939
|
+
next: diagnosisNextSchema,
|
|
1940
|
+
change: agentWorkText.optional(),
|
|
1941
|
+
question: agentWorkText.optional(),
|
|
1942
|
+
answer: agentWorkText.optional()
|
|
1943
|
+
}).strict().refine((d) => d.next === "different-way" === (d.change !== void 0), {
|
|
1944
|
+
message: "says what will change exactly when the next step is to try a different way",
|
|
1945
|
+
path: ["change"]
|
|
1946
|
+
}).refine((d) => d.next === "ask-person" === (d.question !== void 0), {
|
|
1947
|
+
message: "carries a question exactly when the next step is to ask the person",
|
|
1948
|
+
path: ["question"]
|
|
1949
|
+
});
|
|
1950
|
+
var workCallSchema = z14.object({
|
|
1951
|
+
subject: workSubjectSchema,
|
|
1952
|
+
by: agentNameSchema,
|
|
1953
|
+
kind: callKindSchema,
|
|
1954
|
+
question: agentWorkText,
|
|
1955
|
+
chose: agentWorkText,
|
|
1956
|
+
statedDefault: agentWorkText,
|
|
1957
|
+
undoable: callUndoableSchema,
|
|
1958
|
+
how: agentWorkText.nullable(),
|
|
1959
|
+
at: utcIso8601
|
|
1960
|
+
}).strict().superRefine((c, ctx) => checkReadCallHow(c, ctx));
|
|
1961
|
+
function checkReadCallHow(c, ctx) {
|
|
1962
|
+
if (c.undoable === "yes" !== (c.how !== null)) {
|
|
1963
|
+
ctx.addIssue({ code: "custom", path: ["how"], message: "says how to undo it exactly when it can be undone" });
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
var workTaskViewSchema = z14.object({
|
|
1967
|
+
task: buildTaskIdSchema,
|
|
1968
|
+
standing: workStandingSchema,
|
|
1969
|
+
attempts: z14.array(workAttemptSchema),
|
|
1970
|
+
diagnoses: z14.array(workDiagnosisSchema),
|
|
1971
|
+
tests: z14.array(workTestSchema)
|
|
1972
|
+
}).strict();
|
|
1973
|
+
var WORK_CLAIM_ACTS = Object.freeze(["accept", "reject"]);
|
|
1974
|
+
var workClaimActSchema = z14.enum(WORK_CLAIM_ACTS);
|
|
1975
|
+
var workClaimAnswerSchema = z14.object({
|
|
1976
|
+
act: workClaimActSchema,
|
|
1977
|
+
note: z14.string().min(1).max(SCOPE_NOTE_MAX).nullable()
|
|
1978
|
+
}).strict().refine((a) => a.act === "reject" === (a.note !== null), {
|
|
1979
|
+
message: "carries the owner's note exactly on a reject",
|
|
1980
|
+
path: ["note"]
|
|
1981
|
+
});
|
|
1982
|
+
var workUncheckedClaimSchema = z14.object({
|
|
1983
|
+
task: buildTaskIdSchema,
|
|
1984
|
+
label: agentWorkText,
|
|
1985
|
+
head: commitShaSchema,
|
|
1986
|
+
claimedBy: agentNameSchema,
|
|
1987
|
+
answer: workClaimAnswerSchema.nullable()
|
|
1988
|
+
}).strict();
|
|
1989
|
+
var phaseWorkSchema = z14.object({
|
|
1990
|
+
phase: buildPhaseSchema,
|
|
1991
|
+
tasks: z14.array(workTaskViewSchema),
|
|
1992
|
+
calls: z14.array(workCallSchema),
|
|
1993
|
+
uncheckedClaims: z14.array(workUncheckedClaimSchema)
|
|
1994
|
+
}).strict();
|
|
1995
|
+
|
|
1996
|
+
// ../events/dist/crew.js
|
|
1997
|
+
import { z as z15 } from "zod";
|
|
1998
|
+
var crewGroupSchema = z15.enum(["analyst-architect", "builder", "reviewer", "lead"]);
|
|
1999
|
+
var CREW_DISCIPLINE_MAX = 64;
|
|
2000
|
+
var crewFaceHeadSchema = z15.enum(["sq", "sqr", "rnd", "dome", "hex", "gable"]);
|
|
2001
|
+
var crewFaceAntennaSchema = z15.enum(["none", "stalk", "twin", "dish"]);
|
|
2002
|
+
var crewFaceEyesSchema = z15.enum(["dots", "bars", "visor", "cyclops"]);
|
|
2003
|
+
var crewFaceMouthSchema = z15.enum(["line", "grid", "dots", "wave"]);
|
|
2004
|
+
var crewFaceSchema = z15.object({
|
|
2005
|
+
// The outline of the head. Members who do the same kind of work share one, so a
|
|
2006
|
+
// team is recognisable before any name is read.
|
|
2007
|
+
head: crewFaceHeadSchema,
|
|
2008
|
+
// What sits on top of the head, if anything.
|
|
2009
|
+
antenna: crewFaceAntennaSchema,
|
|
2010
|
+
// The eyes.
|
|
2011
|
+
eyes: crewFaceEyesSchema,
|
|
2012
|
+
// The mouth.
|
|
2013
|
+
mouth: crewFaceMouthSchema,
|
|
2014
|
+
// Whether this member is drawn with ears.
|
|
2015
|
+
ears: z15.boolean()
|
|
2016
|
+
}).strict();
|
|
2017
|
+
var crewRoleSchema = z15.enum([
|
|
2018
|
+
"business-analyst",
|
|
2019
|
+
"architect",
|
|
2020
|
+
"spec-writer",
|
|
2021
|
+
"builder",
|
|
2022
|
+
"context-docs",
|
|
2023
|
+
"spec-reviewer",
|
|
2024
|
+
"code-test-reviewer",
|
|
2025
|
+
"delivery-lead",
|
|
2026
|
+
"quality-lead"
|
|
2027
|
+
]);
|
|
2028
|
+
var crewMemberSchema = z15.object({
|
|
2029
|
+
// The agent's name. The same names on every project, so a name is a
|
|
2030
|
+
// vocabulary a returning client already knows.
|
|
2031
|
+
callsign: z15.string().min(1).max(32),
|
|
2032
|
+
// Which of the four teams this member belongs to.
|
|
2033
|
+
group: crewGroupSchema,
|
|
2034
|
+
// The part this member plays, which decides the stages it leads and helps with.
|
|
2035
|
+
role: crewRoleSchema,
|
|
2036
|
+
// The kind of work this member takes. A task names a discipline, and only
|
|
2037
|
+
// agents holding it can be dispatched to it.
|
|
2038
|
+
discipline: z15.string().min(1).max(CREW_DISCIPLINE_MAX),
|
|
2039
|
+
// How much thinking this member brings. There is no field naming the supplier
|
|
2040
|
+
// behind it, on this shape or on any other.
|
|
2041
|
+
tier: crewTierSchema,
|
|
2042
|
+
// How this member's face is drawn. The same face on every project, so a
|
|
2043
|
+
// returning client recognises a member before reading the name.
|
|
2044
|
+
face: crewFaceSchema
|
|
2045
|
+
}).strict();
|
|
2046
|
+
var CREW_ROSTER = [
|
|
2047
|
+
// ── analysts and architects ─────────────────────────────────────────────────
|
|
2048
|
+
{
|
|
2049
|
+
callsign: "SOFIA",
|
|
2050
|
+
group: "analyst-architect",
|
|
2051
|
+
role: "business-analyst",
|
|
2052
|
+
discipline: "business analyst",
|
|
2053
|
+
tier: "deep",
|
|
2054
|
+
face: { head: "gable", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
2055
|
+
},
|
|
2056
|
+
{
|
|
2057
|
+
callsign: "BEA",
|
|
2058
|
+
group: "analyst-architect",
|
|
2059
|
+
role: "business-analyst",
|
|
2060
|
+
discipline: "business analyst",
|
|
2061
|
+
tier: "standard",
|
|
2062
|
+
face: { head: "gable", antenna: "none", eyes: "visor", mouth: "line", ears: false }
|
|
2063
|
+
},
|
|
2064
|
+
{
|
|
2065
|
+
callsign: "WREN",
|
|
2066
|
+
group: "analyst-architect",
|
|
2067
|
+
role: "architect",
|
|
2068
|
+
discipline: "solution architect",
|
|
2069
|
+
tier: "deep",
|
|
2070
|
+
face: { head: "gable", antenna: "dish", eyes: "bars", mouth: "line", ears: true }
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
callsign: "PEI",
|
|
2074
|
+
group: "analyst-architect",
|
|
2075
|
+
role: "architect",
|
|
2076
|
+
discipline: "technical architect",
|
|
2077
|
+
tier: "standard",
|
|
2078
|
+
face: { head: "gable", antenna: "twin", eyes: "cyclops", mouth: "dots", ears: false }
|
|
2079
|
+
},
|
|
2080
|
+
// ── builders: code ──────────────────────────────────────────────────────────
|
|
2081
|
+
{
|
|
2082
|
+
callsign: "ADA",
|
|
2083
|
+
group: "builder",
|
|
2084
|
+
role: "builder",
|
|
2085
|
+
discipline: "implementation",
|
|
2086
|
+
tier: "deep",
|
|
2087
|
+
face: { head: "sq", antenna: "stalk", eyes: "dots", mouth: "line", ears: false }
|
|
2088
|
+
},
|
|
2089
|
+
{
|
|
2090
|
+
callsign: "OTTO",
|
|
2091
|
+
group: "builder",
|
|
2092
|
+
role: "builder",
|
|
2093
|
+
discipline: "implementation",
|
|
2094
|
+
tier: "deep",
|
|
2095
|
+
face: { head: "sq", antenna: "twin", eyes: "bars", mouth: "grid", ears: true }
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
callsign: "MILO",
|
|
2099
|
+
group: "builder",
|
|
2100
|
+
role: "builder",
|
|
2101
|
+
discipline: "implementation",
|
|
2102
|
+
tier: "standard",
|
|
2103
|
+
face: { head: "sqr", antenna: "stalk", eyes: "dots", mouth: "dots", ears: false }
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
callsign: "NOVA",
|
|
2107
|
+
group: "builder",
|
|
2108
|
+
role: "builder",
|
|
2109
|
+
discipline: "implementation",
|
|
2110
|
+
tier: "standard",
|
|
2111
|
+
face: { head: "sq", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
callsign: "HUGO",
|
|
2115
|
+
group: "builder",
|
|
2116
|
+
role: "builder",
|
|
2117
|
+
discipline: "infrastructure",
|
|
2118
|
+
tier: "standard",
|
|
2119
|
+
face: { head: "sq", antenna: "twin", eyes: "dots", mouth: "grid", ears: true }
|
|
2120
|
+
},
|
|
2121
|
+
// ── builders: specs and docs ────────────────────────────────────────────────
|
|
2122
|
+
{
|
|
2123
|
+
callsign: "IRIS",
|
|
2124
|
+
group: "builder",
|
|
2125
|
+
role: "spec-writer",
|
|
2126
|
+
discipline: "feature spec",
|
|
2127
|
+
tier: "deep",
|
|
2128
|
+
face: { head: "dome", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
callsign: "JUNO",
|
|
2132
|
+
group: "builder",
|
|
2133
|
+
role: "spec-writer",
|
|
2134
|
+
discipline: "feature spec",
|
|
2135
|
+
tier: "standard",
|
|
2136
|
+
face: { head: "dome", antenna: "none", eyes: "dots", mouth: "wave", ears: false }
|
|
2137
|
+
},
|
|
2138
|
+
{
|
|
2139
|
+
callsign: "LEX",
|
|
2140
|
+
group: "builder",
|
|
2141
|
+
role: "context-docs",
|
|
2142
|
+
discipline: "context & docs",
|
|
2143
|
+
tier: "fast",
|
|
2144
|
+
face: { head: "dome", antenna: "twin", eyes: "bars", mouth: "dots", ears: false }
|
|
2145
|
+
},
|
|
2146
|
+
// ── reviewers ───────────────────────────────────────────────────────────────
|
|
2147
|
+
{
|
|
2148
|
+
callsign: "VERA",
|
|
2149
|
+
group: "reviewer",
|
|
2150
|
+
role: "spec-reviewer",
|
|
2151
|
+
discipline: "spec consistency",
|
|
2152
|
+
tier: "deep",
|
|
2153
|
+
face: { head: "rnd", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
2154
|
+
},
|
|
2155
|
+
{
|
|
2156
|
+
callsign: "ODIN",
|
|
2157
|
+
group: "reviewer",
|
|
2158
|
+
role: "spec-reviewer",
|
|
2159
|
+
discipline: "cross-spec audit",
|
|
2160
|
+
tier: "deep",
|
|
2161
|
+
face: { head: "rnd", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
callsign: "CASS",
|
|
2165
|
+
group: "reviewer",
|
|
2166
|
+
role: "code-test-reviewer",
|
|
2167
|
+
discipline: "code review",
|
|
2168
|
+
tier: "deep",
|
|
2169
|
+
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "grid", ears: true }
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
callsign: "THEO",
|
|
2173
|
+
group: "reviewer",
|
|
2174
|
+
role: "code-test-reviewer",
|
|
2175
|
+
discipline: "code review",
|
|
2176
|
+
tier: "standard",
|
|
2177
|
+
face: { head: "rnd", antenna: "twin", eyes: "bars", mouth: "line", ears: false }
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
callsign: "KAI",
|
|
2181
|
+
group: "reviewer",
|
|
2182
|
+
role: "code-test-reviewer",
|
|
2183
|
+
discipline: "code review",
|
|
2184
|
+
tier: "standard",
|
|
2185
|
+
face: { head: "rnd", antenna: "none", eyes: "bars", mouth: "line", ears: true }
|
|
2186
|
+
},
|
|
2187
|
+
{
|
|
2188
|
+
callsign: "ECHO",
|
|
2189
|
+
group: "reviewer",
|
|
2190
|
+
role: "code-test-reviewer",
|
|
2191
|
+
discipline: "test quality",
|
|
2192
|
+
tier: "standard",
|
|
2193
|
+
face: { head: "rnd", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
2194
|
+
},
|
|
2195
|
+
{
|
|
2196
|
+
callsign: "MAVIS",
|
|
2197
|
+
group: "reviewer",
|
|
2198
|
+
role: "code-test-reviewer",
|
|
2199
|
+
discipline: "suites & coverage",
|
|
2200
|
+
tier: "standard",
|
|
2201
|
+
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "dots", ears: false }
|
|
2202
|
+
},
|
|
2203
|
+
{
|
|
2204
|
+
callsign: "ZARA",
|
|
2205
|
+
group: "reviewer",
|
|
2206
|
+
role: "code-test-reviewer",
|
|
2207
|
+
discipline: "smoke & walk aid",
|
|
2208
|
+
tier: "standard",
|
|
2209
|
+
face: { head: "rnd", antenna: "dish", eyes: "bars", mouth: "wave", ears: false }
|
|
2210
|
+
},
|
|
2211
|
+
{
|
|
2212
|
+
callsign: "NORA",
|
|
2213
|
+
group: "reviewer",
|
|
2214
|
+
role: "code-test-reviewer",
|
|
2215
|
+
discipline: "evidence & provenance",
|
|
2216
|
+
tier: "fast",
|
|
2217
|
+
face: { head: "rnd", antenna: "twin", eyes: "dots", mouth: "line", ears: false }
|
|
2218
|
+
},
|
|
2219
|
+
// ── leads ───────────────────────────────────────────────────────────────────
|
|
2220
|
+
{
|
|
2221
|
+
callsign: "ARGUS",
|
|
2222
|
+
group: "lead",
|
|
2223
|
+
role: "quality-lead",
|
|
2224
|
+
discipline: "quality lead \xB7 every diff",
|
|
2225
|
+
tier: "standard",
|
|
2226
|
+
face: { head: "hex", antenna: "dish", eyes: "visor", mouth: "grid", ears: true }
|
|
2227
|
+
},
|
|
2228
|
+
{
|
|
2229
|
+
callsign: "ATLAS",
|
|
2230
|
+
group: "lead",
|
|
2231
|
+
role: "delivery-lead",
|
|
2232
|
+
discipline: "delivery lead",
|
|
2233
|
+
tier: "deep",
|
|
2234
|
+
face: { head: "hex", antenna: "twin", eyes: "cyclops", mouth: "line", ears: true }
|
|
2235
|
+
}
|
|
2236
|
+
];
|
|
2237
|
+
var CREW_ROSTER_SIZE = CREW_ROSTER.length;
|
|
2238
|
+
var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
|
|
2239
|
+
var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
|
|
2240
|
+
var crewRoleLayersSchema = z15.object({
|
|
2241
|
+
leads: z15.array(crewLayerSchema),
|
|
2242
|
+
helps: z15.array(crewLayerSchema)
|
|
1810
2243
|
}).strict();
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
}
|
|
2244
|
+
|
|
2245
|
+
// ../events/dist/build-record-v3.js
|
|
2246
|
+
import { z as z18 } from "zod";
|
|
2247
|
+
|
|
2248
|
+
// ../events/dist/board-vocabulary.js
|
|
2249
|
+
import { z as z16 } from "zod";
|
|
2250
|
+
var boardStepStateSchema = z16.enum([
|
|
2251
|
+
"not-instrumented",
|
|
2252
|
+
"done",
|
|
2253
|
+
"did-not-pass",
|
|
2254
|
+
"could-not-complete",
|
|
2255
|
+
"not-yet-available",
|
|
2256
|
+
"qualified"
|
|
2257
|
+
]);
|
|
2258
|
+
var boardGateNameSchema = z16.enum([
|
|
2259
|
+
"scope",
|
|
2260
|
+
"architecture",
|
|
2261
|
+
"specs",
|
|
2262
|
+
"taskgraph",
|
|
2263
|
+
"phase-close"
|
|
2264
|
+
]);
|
|
1814
2265
|
|
|
1815
2266
|
// ../events/dist/phase-review.js
|
|
1816
|
-
import { z as
|
|
2267
|
+
import { z as z17 } from "zod";
|
|
1817
2268
|
var BUILT_PART_ACTS = Object.freeze(["accept", "question", "send-back"]);
|
|
1818
2269
|
var NOT_BUILT_PART_ACTS = Object.freeze(["carry", "drop"]);
|
|
1819
2270
|
var REVIEW_ACTS = Object.freeze([...BUILT_PART_ACTS, ...NOT_BUILT_PART_ACTS]);
|
|
1820
|
-
var reviewActSchema =
|
|
2271
|
+
var reviewActSchema = z17.enum(REVIEW_ACTS);
|
|
1821
2272
|
function reviewActsFor(built) {
|
|
1822
2273
|
return built ? BUILT_PART_ACTS : NOT_BUILT_PART_ACTS;
|
|
1823
2274
|
}
|
|
1824
2275
|
var REVIEW_NOTE_MAX = SCOPE_NOTE_MAX;
|
|
1825
|
-
var reviewNoteWireSchema =
|
|
1826
|
-
var reviewNoteSchema =
|
|
2276
|
+
var reviewNoteWireSchema = z17.string().max(REVIEW_NOTE_MAX);
|
|
2277
|
+
var reviewNoteSchema = z17.string().min(1).max(REVIEW_NOTE_MAX);
|
|
1827
2278
|
var REVIEW_ANSWER_MAX = 1e3;
|
|
1828
|
-
var reviewAgentAnswerSchema =
|
|
2279
|
+
var reviewAgentAnswerSchema = z17.string().min(1).max(REVIEW_ANSWER_MAX);
|
|
1829
2280
|
var REVIEW_PARTS_MAX = PHASE_PLAN_CHANGES_MAX * 2;
|
|
1830
2281
|
var REVIEW_PART_CHANGES = Object.freeze([...PHASE_PLAN_CHANGE_KINDS, "not-in-plan"]);
|
|
1831
|
-
var reviewPartChangeSchema =
|
|
2282
|
+
var reviewPartChangeSchema = z17.enum(REVIEW_PART_CHANGES);
|
|
1832
2283
|
var REVIEW_DECISIONS = Object.freeze(["accepted", "carried", "dropped"]);
|
|
1833
|
-
var reviewDecisionSchema =
|
|
2284
|
+
var reviewDecisionSchema = z17.enum(REVIEW_DECISIONS);
|
|
1834
2285
|
function actOf(decision) {
|
|
1835
2286
|
if (decision === "accepted")
|
|
1836
2287
|
return "accept";
|
|
@@ -1842,10 +2293,10 @@ var reviewCarriedToSchema = carriedPhaseSchema.nullable();
|
|
|
1842
2293
|
var reviewStepNameSchema = stepNameSchema.refine((v) => !stepIdSchema.safeParse(v.trim()).success, {
|
|
1843
2294
|
message: "must be the step's plain name"
|
|
1844
2295
|
});
|
|
1845
|
-
var reviewStepSchema =
|
|
2296
|
+
var reviewStepSchema = z17.object({
|
|
1846
2297
|
name: reviewStepNameSchema.nullable(),
|
|
1847
2298
|
state: unfinishedStepSchema.shape.state,
|
|
1848
|
-
judged:
|
|
2299
|
+
judged: z17.boolean()
|
|
1849
2300
|
}).strict();
|
|
1850
2301
|
function codeLinkLine(link) {
|
|
1851
2302
|
switch (link.kind) {
|
|
@@ -1862,41 +2313,41 @@ function codeLinkLine(link) {
|
|
|
1862
2313
|
function assertNever(value) {
|
|
1863
2314
|
throw new Error(`unexpected value: ${JSON.stringify(value)}`);
|
|
1864
2315
|
}
|
|
1865
|
-
var openReviewRequestSchema =
|
|
2316
|
+
var openReviewRequestSchema = z17.object({
|
|
1866
2317
|
actor: closeActorSchema,
|
|
1867
2318
|
acceptanceOutcome: acceptanceOutcomeSchema,
|
|
1868
2319
|
statements: closeStatementsSchema
|
|
1869
2320
|
}).strict();
|
|
1870
2321
|
var REVIEW_OPEN_TASKS_SHOWN_MAX = 10;
|
|
1871
|
-
var reviewOpenedSchema =
|
|
1872
|
-
outcome:
|
|
1873
|
-
round:
|
|
1874
|
-
parts:
|
|
1875
|
-
notBuilt:
|
|
1876
|
-
counted:
|
|
1877
|
-
typedReviewOffered:
|
|
2322
|
+
var reviewOpenedSchema = z17.object({
|
|
2323
|
+
outcome: z17.literal("opened"),
|
|
2324
|
+
round: z17.number().int().min(1),
|
|
2325
|
+
parts: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
2326
|
+
notBuilt: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
2327
|
+
counted: z17.boolean(),
|
|
2328
|
+
typedReviewOffered: z17.boolean()
|
|
1878
2329
|
}).strict().refine((v) => v.notBuilt <= v.parts, { message: "cannot exceed the parts in the round", path: ["notBuilt"] });
|
|
1879
|
-
var reviewTasksOpenSchema =
|
|
1880
|
-
outcome:
|
|
1881
|
-
open:
|
|
1882
|
-
more:
|
|
2330
|
+
var reviewTasksOpenSchema = z17.object({
|
|
2331
|
+
outcome: z17.literal("tasks-open"),
|
|
2332
|
+
open: z17.array(buildTaskSchema.shape.title).min(1).max(REVIEW_OPEN_TASKS_SHOWN_MAX),
|
|
2333
|
+
more: z17.number().int().min(0).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1883
2334
|
}).strict();
|
|
1884
|
-
var reviewOutstandingSchema =
|
|
1885
|
-
outcome:
|
|
1886
|
-
steps:
|
|
2335
|
+
var reviewOutstandingSchema = z17.object({
|
|
2336
|
+
outcome: z17.literal("outstanding"),
|
|
2337
|
+
steps: z17.array(reviewStepSchema).min(1)
|
|
1887
2338
|
}).strict();
|
|
1888
|
-
var reviewCleanOverFindingsSchema =
|
|
1889
|
-
outcome:
|
|
1890
|
-
findings:
|
|
2339
|
+
var reviewCleanOverFindingsSchema = z17.object({
|
|
2340
|
+
outcome: z17.literal("clean-over-findings"),
|
|
2341
|
+
findings: z17.number().int().min(1)
|
|
1891
2342
|
}).strict();
|
|
1892
|
-
var reviewRefusedSchema =
|
|
1893
|
-
outcome:
|
|
1894
|
-
problems:
|
|
2343
|
+
var reviewRefusedSchema = z17.object({
|
|
2344
|
+
outcome: z17.literal("refused"),
|
|
2345
|
+
problems: z17.array(systemDescriptionProblemSchema).min(1)
|
|
1895
2346
|
}).strict();
|
|
1896
2347
|
function bareReviewOutcome(outcome) {
|
|
1897
|
-
return
|
|
2348
|
+
return z17.object({ outcome: z17.literal(outcome) }).strict();
|
|
1898
2349
|
}
|
|
1899
|
-
var openReviewResultSchema =
|
|
2350
|
+
var openReviewResultSchema = z17.discriminatedUnion("outcome", [
|
|
1900
2351
|
reviewOpenedSchema,
|
|
1901
2352
|
reviewTasksOpenSchema,
|
|
1902
2353
|
bareReviewOutcome("no-build"),
|
|
@@ -1906,23 +2357,33 @@ var openReviewResultSchema = z13.discriminatedUnion("outcome", [
|
|
|
1906
2357
|
reviewRefusedSchema,
|
|
1907
2358
|
bareReviewOutcome("unavailable")
|
|
1908
2359
|
]);
|
|
1909
|
-
var reviewPhaseNotOpenSchema =
|
|
1910
|
-
statusCode:
|
|
1911
|
-
error:
|
|
1912
|
-
message:
|
|
1913
|
-
openPhase:
|
|
2360
|
+
var reviewPhaseNotOpenSchema = z17.object({
|
|
2361
|
+
statusCode: z17.literal(409),
|
|
2362
|
+
error: z17.literal("PhaseNotOpen"),
|
|
2363
|
+
message: z17.string().min(1),
|
|
2364
|
+
openPhase: z17.string().nullable()
|
|
1914
2365
|
}).strict();
|
|
1915
|
-
var openReviewAnswerSchema =
|
|
1916
|
-
var reviewDecisionEntrySchema =
|
|
2366
|
+
var openReviewAnswerSchema = z17.union([openReviewResultSchema, reviewPhaseNotOpenSchema]);
|
|
2367
|
+
var reviewDecisionEntrySchema = z17.object({
|
|
1917
2368
|
part: systemPartIdSchema,
|
|
1918
2369
|
act: reviewActSchema,
|
|
1919
2370
|
note: reviewNoteWireSchema.optional()
|
|
1920
2371
|
}).strict();
|
|
1921
|
-
var
|
|
1922
|
-
|
|
1923
|
-
|
|
2372
|
+
var reviewClaimActSchema = workClaimActSchema;
|
|
2373
|
+
var REVIEW_CLAIMS_MAX = BUILD_SNAPSHOT_TASK_LIMIT * WORK_CLAIM_CHECKS_MAX;
|
|
2374
|
+
var reviewClaimAnswerSchema = z17.object({
|
|
2375
|
+
task: buildTaskIdSchema,
|
|
2376
|
+
label: agentWorkText,
|
|
2377
|
+
head: commitShaSchema,
|
|
2378
|
+
act: reviewClaimActSchema,
|
|
2379
|
+
note: reviewNoteWireSchema.optional()
|
|
2380
|
+
}).strict();
|
|
2381
|
+
var reviewDecisionRequestSchema = z17.object({
|
|
2382
|
+
reviewVersion: z17.number().int().min(0),
|
|
2383
|
+
decisions: z17.array(reviewDecisionEntrySchema).max(REVIEW_PARTS_MAX),
|
|
2384
|
+
claims: z17.array(reviewClaimAnswerSchema).max(REVIEW_CLAIMS_MAX)
|
|
1924
2385
|
}).strict();
|
|
1925
|
-
var reviewDecidedSchema =
|
|
2386
|
+
var reviewDecidedSchema = z17.object({
|
|
1926
2387
|
part: systemPartIdSchema,
|
|
1927
2388
|
name: systemPartSchema.shape.name,
|
|
1928
2389
|
act: reviewActSchema,
|
|
@@ -1931,39 +2392,51 @@ var reviewDecidedSchema = z13.object({
|
|
|
1931
2392
|
message: "is present exactly on a carry",
|
|
1932
2393
|
path: ["carriedTo"]
|
|
1933
2394
|
});
|
|
1934
|
-
var reviewRecordedSchema =
|
|
1935
|
-
outcome:
|
|
1936
|
-
decided:
|
|
1937
|
-
waiting:
|
|
1938
|
-
closed:
|
|
1939
|
-
reviewVersion:
|
|
2395
|
+
var reviewRecordedSchema = z17.object({
|
|
2396
|
+
outcome: z17.literal("recorded"),
|
|
2397
|
+
decided: z17.array(reviewDecidedSchema).max(REVIEW_PARTS_MAX),
|
|
2398
|
+
waiting: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
2399
|
+
closed: z17.boolean(),
|
|
2400
|
+
reviewVersion: z17.number().int().min(1)
|
|
1940
2401
|
}).strict().superRefine((v, ctx) => {
|
|
1941
2402
|
if (v.closed && v.waiting !== 0) {
|
|
1942
2403
|
ctx.addIssue({ code: "custom", path: ["waiting"], message: "must be 0 once the phase is closed" });
|
|
1943
2404
|
}
|
|
1944
|
-
if (v.decided.length === 0 && !v.closed) {
|
|
1945
|
-
ctx.addIssue({ code: "custom", path: ["decided"], message: "may be empty only when the phase closed" });
|
|
1946
|
-
}
|
|
1947
2405
|
});
|
|
1948
2406
|
var REVIEW_NOT_DECIDABLE_WHY = Object.freeze(["settled", "question-waiting", "sent-back"]);
|
|
1949
|
-
var reviewNotDecidablePartSchema =
|
|
2407
|
+
var reviewNotDecidablePartSchema = z17.object({
|
|
1950
2408
|
part: systemPartIdSchema,
|
|
1951
2409
|
name: systemPartSchema.shape.name,
|
|
1952
|
-
why:
|
|
2410
|
+
why: z17.enum(REVIEW_NOT_DECIDABLE_WHY)
|
|
2411
|
+
}).strict();
|
|
2412
|
+
var REVIEW_CLAIM_NOT_DECIDABLE_WHY = Object.freeze(["not-unchecked", "answered", "claim-changed"]);
|
|
2413
|
+
var reviewClaimNotDecidableWhySchema = z17.enum(REVIEW_CLAIM_NOT_DECIDABLE_WHY);
|
|
2414
|
+
var reviewNotDecidableClaimSchema = z17.object({
|
|
2415
|
+
task: buildTaskIdSchema,
|
|
2416
|
+
label: agentWorkText,
|
|
2417
|
+
why: reviewClaimNotDecidableWhySchema
|
|
1953
2418
|
}).strict();
|
|
1954
|
-
var reviewNotDecidableSchema =
|
|
1955
|
-
outcome:
|
|
1956
|
-
parts:
|
|
2419
|
+
var reviewNotDecidableSchema = z17.object({
|
|
2420
|
+
outcome: z17.literal("not-decidable"),
|
|
2421
|
+
parts: z17.array(reviewNotDecidablePartSchema).max(REVIEW_PARTS_MAX),
|
|
2422
|
+
claims: z17.array(reviewNotDecidableClaimSchema).max(REVIEW_CLAIMS_MAX)
|
|
2423
|
+
}).strict().refine((v) => v.parts.length + v.claims.length > 0, {
|
|
2424
|
+
message: "names at least one part or claim",
|
|
2425
|
+
path: ["parts"]
|
|
2426
|
+
});
|
|
2427
|
+
var reviewPartsNotDecidableSchema = z17.object({
|
|
2428
|
+
outcome: z17.literal("not-decidable"),
|
|
2429
|
+
parts: z17.array(reviewNotDecidablePartSchema).min(1).max(REVIEW_PARTS_MAX)
|
|
1957
2430
|
}).strict();
|
|
1958
|
-
var reviewCloseRefusedSchema =
|
|
1959
|
-
outcome:
|
|
1960
|
-
steps:
|
|
2431
|
+
var reviewCloseRefusedSchema = z17.object({
|
|
2432
|
+
outcome: z17.literal("close-refused"),
|
|
2433
|
+
steps: z17.array(reviewStepSchema)
|
|
1961
2434
|
}).strict();
|
|
1962
|
-
var reviewWalkChangedSchema =
|
|
1963
|
-
outcome:
|
|
1964
|
-
findings:
|
|
2435
|
+
var reviewWalkChangedSchema = z17.object({
|
|
2436
|
+
outcome: z17.literal("walk-changed"),
|
|
2437
|
+
findings: z17.number().int().min(1)
|
|
1965
2438
|
}).strict();
|
|
1966
|
-
var reviewDecisionResultSchema =
|
|
2439
|
+
var reviewDecisionResultSchema = z17.discriminatedUnion("outcome", [
|
|
1967
2440
|
reviewRecordedSchema,
|
|
1968
2441
|
bareReviewOutcome("review-changed"),
|
|
1969
2442
|
bareReviewOutcome("no-review"),
|
|
@@ -1975,33 +2448,33 @@ var reviewDecisionResultSchema = z13.discriminatedUnion("outcome", [
|
|
|
1975
2448
|
reviewRefusedSchema,
|
|
1976
2449
|
bareReviewOutcome("unavailable")
|
|
1977
2450
|
]);
|
|
1978
|
-
var reviewSentBackSchema =
|
|
1979
|
-
round:
|
|
2451
|
+
var reviewSentBackSchema = z17.object({
|
|
2452
|
+
round: z17.number().int().min(1),
|
|
1980
2453
|
note: reviewNoteSchema
|
|
1981
2454
|
}).strict();
|
|
1982
|
-
var reviewQuestionSchema =
|
|
2455
|
+
var reviewQuestionSchema = z17.object({
|
|
1983
2456
|
question: reviewNoteSchema,
|
|
1984
2457
|
agentAnswer: reviewAgentAnswerSchema.optional()
|
|
1985
2458
|
}).strict();
|
|
1986
|
-
var reviewTaskSchema =
|
|
2459
|
+
var reviewTaskSchema = z17.object({
|
|
1987
2460
|
title: buildTaskSchema.shape.title,
|
|
1988
2461
|
state: buildTaskStateSchema
|
|
1989
2462
|
}).strict();
|
|
1990
|
-
var reviewViewPartSchema =
|
|
2463
|
+
var reviewViewPartSchema = z17.object({
|
|
1991
2464
|
part: systemPartIdSchema,
|
|
1992
2465
|
name: systemPartSchema.shape.name,
|
|
1993
2466
|
change: reviewPartChangeSchema,
|
|
1994
|
-
built:
|
|
1995
|
-
builtWithoutApproval:
|
|
1996
|
-
decidable:
|
|
1997
|
-
waiting:
|
|
2467
|
+
built: z17.boolean(),
|
|
2468
|
+
builtWithoutApproval: z17.boolean(),
|
|
2469
|
+
decidable: z17.boolean(),
|
|
2470
|
+
waiting: z17.boolean(),
|
|
1998
2471
|
decision: reviewDecisionSchema.optional(),
|
|
1999
2472
|
reason: reviewNoteSchema.optional(),
|
|
2000
2473
|
carriedTo: reviewCarriedToSchema.optional(),
|
|
2001
|
-
sentBack:
|
|
2002
|
-
questions:
|
|
2003
|
-
tasks:
|
|
2004
|
-
said:
|
|
2474
|
+
sentBack: z17.array(reviewSentBackSchema),
|
|
2475
|
+
questions: z17.array(reviewQuestionSchema),
|
|
2476
|
+
tasks: z17.array(reviewTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
2477
|
+
said: z17.array(observedSaidSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
2005
2478
|
codeLink: partCodeLinkSchema
|
|
2006
2479
|
}).strict().superRefine((v, ctx) => {
|
|
2007
2480
|
if (v.waiting !== (v.decision === void 0)) {
|
|
@@ -2024,29 +2497,29 @@ var reviewViewPartSchema = z13.object({
|
|
|
2024
2497
|
ctx.addIssue({ code: "custom", path: ["built"], message: "is always true for a part outside the plan" });
|
|
2025
2498
|
}
|
|
2026
2499
|
});
|
|
2027
|
-
var reviewPhaseNumberSchema =
|
|
2028
|
-
var phaseReviewNoneSchema =
|
|
2029
|
-
state:
|
|
2500
|
+
var reviewPhaseNumberSchema = z17.number().int().min(1).nullable();
|
|
2501
|
+
var phaseReviewNoneSchema = z17.object({
|
|
2502
|
+
state: z17.literal("none"),
|
|
2030
2503
|
phase: scopePhaseSchema,
|
|
2031
2504
|
number: reviewPhaseNumberSchema,
|
|
2032
|
-
closedWithoutReview:
|
|
2505
|
+
closedWithoutReview: z17.boolean()
|
|
2033
2506
|
}).strict();
|
|
2034
|
-
var reviewWalkSchema =
|
|
2507
|
+
var reviewWalkSchema = z17.object({
|
|
2035
2508
|
verdict: walkVerdictSchema,
|
|
2036
|
-
findings:
|
|
2509
|
+
findings: z17.number().int().min(0)
|
|
2037
2510
|
}).strict();
|
|
2038
2511
|
function reviewedViewSchema(state) {
|
|
2039
|
-
return
|
|
2040
|
-
state:
|
|
2512
|
+
return z17.object({
|
|
2513
|
+
state: z17.literal(state),
|
|
2041
2514
|
phase: scopePhaseSchema,
|
|
2042
2515
|
number: reviewPhaseNumberSchema,
|
|
2043
|
-
cycle:
|
|
2044
|
-
round:
|
|
2045
|
-
reviewVersion:
|
|
2046
|
-
typedReviewOffered:
|
|
2047
|
-
counted:
|
|
2516
|
+
cycle: z17.number().int().min(0),
|
|
2517
|
+
round: z17.number().int().min(1),
|
|
2518
|
+
reviewVersion: z17.number().int().min(1),
|
|
2519
|
+
typedReviewOffered: z17.boolean(),
|
|
2520
|
+
counted: z17.boolean(),
|
|
2048
2521
|
walk: reviewWalkSchema,
|
|
2049
|
-
parts:
|
|
2522
|
+
parts: z17.array(reviewViewPartSchema).max(REVIEW_PARTS_MAX),
|
|
2050
2523
|
observed: observedChangesSchema.nullable(),
|
|
2051
2524
|
description: systemDescriptionSchema
|
|
2052
2525
|
}).strict().superRefine((v, ctx) => {
|
|
@@ -2074,7 +2547,7 @@ function reviewedViewSchema(state) {
|
|
|
2074
2547
|
}
|
|
2075
2548
|
var phaseReviewOpenSchema = reviewedViewSchema("open");
|
|
2076
2549
|
var phaseReviewClosedSchema = reviewedViewSchema("closed");
|
|
2077
|
-
var phaseReviewViewSchema =
|
|
2550
|
+
var phaseReviewViewSchema = z17.discriminatedUnion("state", [
|
|
2078
2551
|
phaseReviewNoneSchema,
|
|
2079
2552
|
phaseReviewOpenSchema,
|
|
2080
2553
|
phaseReviewClosedSchema
|
|
@@ -2082,45 +2555,45 @@ var phaseReviewViewSchema = z13.discriminatedUnion("state", [
|
|
|
2082
2555
|
|
|
2083
2556
|
// ../events/dist/build-record-v3.js
|
|
2084
2557
|
var BUILD_RECORD_V3_FORMAT = "halfcycle-build-record/v3";
|
|
2085
|
-
var recordRoundStatedSchema =
|
|
2558
|
+
var recordRoundStatedSchema = z18.object({
|
|
2086
2559
|
actor: attestedCloseSchema.shape.actor,
|
|
2087
2560
|
statements: attestedStatementsSchema
|
|
2088
2561
|
}).strict();
|
|
2089
|
-
var recordReviewRoundSchema =
|
|
2090
|
-
round:
|
|
2562
|
+
var recordReviewRoundSchema = z18.object({
|
|
2563
|
+
round: z18.number().int().min(1),
|
|
2091
2564
|
openedAt: utcIso8601,
|
|
2092
2565
|
verdict: walkVerdictSchema,
|
|
2093
|
-
findings:
|
|
2566
|
+
findings: z18.number().int().min(0),
|
|
2094
2567
|
stated: recordRoundStatedSchema.optional()
|
|
2095
2568
|
}).strict();
|
|
2096
|
-
var recordReviewApprovalSchema =
|
|
2097
|
-
|
|
2098
|
-
kind:
|
|
2569
|
+
var recordReviewApprovalSchema = z18.discriminatedUnion("kind", [
|
|
2570
|
+
z18.object({
|
|
2571
|
+
kind: z18.literal("approved"),
|
|
2099
2572
|
planVersion: planVersionSchema,
|
|
2100
2573
|
givenIn: scopeGivenInSchema,
|
|
2101
2574
|
approvedAt: utcIso8601
|
|
2102
2575
|
}).strict(),
|
|
2103
|
-
|
|
2576
|
+
z18.object({ kind: z18.literal("none") }).strict()
|
|
2104
2577
|
]);
|
|
2105
|
-
var recordReviewGateSchema =
|
|
2578
|
+
var recordReviewGateSchema = z18.object({
|
|
2106
2579
|
gate: boardGateNameSchema,
|
|
2107
2580
|
state: boardStepStateSchema
|
|
2108
2581
|
}).strict();
|
|
2109
|
-
var recordReviewQuestionSchema =
|
|
2582
|
+
var recordReviewQuestionSchema = z18.object({
|
|
2110
2583
|
question: reviewNoteSchema,
|
|
2111
2584
|
agentAnswer: reviewAgentAnswerSchema
|
|
2112
2585
|
}).strict();
|
|
2113
|
-
var recordReviewPartSchema =
|
|
2586
|
+
var recordReviewPartSchema = z18.object({
|
|
2114
2587
|
part: systemPartIdSchema,
|
|
2115
2588
|
name: systemPartSchema.shape.name,
|
|
2116
2589
|
change: reviewPartChangeSchema,
|
|
2117
|
-
built:
|
|
2118
|
-
builtWithoutApproval:
|
|
2590
|
+
built: z18.boolean(),
|
|
2591
|
+
builtWithoutApproval: z18.boolean(),
|
|
2119
2592
|
decision: reviewDecisionSchema,
|
|
2120
2593
|
reason: reviewNoteSchema.optional(),
|
|
2121
2594
|
carriedTo: reviewCarriedToSchema.optional(),
|
|
2122
|
-
sentBack:
|
|
2123
|
-
questions:
|
|
2595
|
+
sentBack: z18.array(reviewSentBackSchema),
|
|
2596
|
+
questions: z18.array(recordReviewQuestionSchema),
|
|
2124
2597
|
codeLink: partCodeLinkSchema
|
|
2125
2598
|
}).strict().superRefine((v, ctx) => {
|
|
2126
2599
|
const carriedOrDropped = v.decision === "carried" || v.decision === "dropped";
|
|
@@ -2132,23 +2605,24 @@ var recordReviewPartSchema = z14.object({
|
|
|
2132
2605
|
}
|
|
2133
2606
|
});
|
|
2134
2607
|
var SPINE_ORDER = boardGateNameSchema.options;
|
|
2135
|
-
var recordReviewGatesSchema =
|
|
2608
|
+
var recordReviewGatesSchema = z18.array(recordReviewGateSchema).superRefine((gates, ctx) => {
|
|
2136
2609
|
const inOrder = gates.length === SPINE_ORDER.length && gates.every((g, i) => g.gate === SPINE_ORDER[i]);
|
|
2137
2610
|
if (!inOrder) {
|
|
2138
2611
|
ctx.addIssue({ code: "custom", message: `must be exactly the five checkpoints in order: ${SPINE_ORDER.join(", ")}` });
|
|
2139
2612
|
}
|
|
2140
2613
|
});
|
|
2141
|
-
var recordReviewSchema =
|
|
2142
|
-
sequence:
|
|
2143
|
-
cycle:
|
|
2144
|
-
rounds:
|
|
2614
|
+
var recordReviewSchema = z18.object({
|
|
2615
|
+
sequence: z18.number().int().min(1),
|
|
2616
|
+
cycle: z18.number().int().min(0),
|
|
2617
|
+
rounds: z18.array(recordReviewRoundSchema).min(1),
|
|
2145
2618
|
approval: recordReviewApprovalSchema,
|
|
2146
2619
|
planVersion: planVersionSchema.nullable(),
|
|
2147
2620
|
descriptionVersion: observedDescriptionVersionSchema,
|
|
2148
2621
|
gates: recordReviewGatesSchema,
|
|
2149
2622
|
observed: observedChangesSchema.nullable(),
|
|
2150
|
-
parts:
|
|
2151
|
-
}).strict().superRefine((v, ctx) =>
|
|
2623
|
+
parts: z18.array(recordReviewPartSchema).max(REVIEW_PARTS_MAX)
|
|
2624
|
+
}).strict().superRefine((v, ctx) => checkRecordReview(v, ctx));
|
|
2625
|
+
function checkRecordReview(v, ctx) {
|
|
2152
2626
|
v.rounds.forEach((r, i) => {
|
|
2153
2627
|
if (r.round !== i + 1) {
|
|
2154
2628
|
ctx.addIssue({ code: "custom", path: ["rounds", i, "round"], message: "rounds must be numbered 1, 2, 3 \u2026 in order with no gap" });
|
|
@@ -2166,12 +2640,13 @@ var recordReviewSchema = z14.object({
|
|
|
2166
2640
|
ctx.addIssue({ code: "custom", path: ["parts", i, "codeLink"], message: "must be none when nothing was observed" });
|
|
2167
2641
|
}
|
|
2168
2642
|
});
|
|
2169
|
-
}
|
|
2170
|
-
var buildRecordV3Schema =
|
|
2643
|
+
}
|
|
2644
|
+
var buildRecordV3Schema = z18.object({
|
|
2171
2645
|
...buildRecordV2Schema.shape,
|
|
2172
|
-
format:
|
|
2646
|
+
format: z18.literal(BUILD_RECORD_V3_FORMAT),
|
|
2173
2647
|
review: recordReviewSchema
|
|
2174
|
-
}).strict().superRefine((record2, ctx) =>
|
|
2648
|
+
}).strict().superRefine((record2, ctx) => checkReviewedRecord(record2, ctx));
|
|
2649
|
+
function checkReviewedRecord(record2, ctx) {
|
|
2175
2650
|
checkRecordHalves(record2, ctx);
|
|
2176
2651
|
const closes = record2.observed.closes;
|
|
2177
2652
|
const newest = closes[closes.length - 1].sequence;
|
|
@@ -2197,24 +2672,11 @@ var buildRecordV3Schema = z14.object({
|
|
|
2197
2672
|
if (record2.review.observed !== null && record2.review.observed.phase !== record2.phase) {
|
|
2198
2673
|
ctx.addIssue({ code: "custom", path: ["review", "observed", "phase"], message: "must be this record's phase" });
|
|
2199
2674
|
}
|
|
2200
|
-
});
|
|
2201
|
-
var buildRecordSchema = z14.discriminatedUnion("format", [buildRecordV2Schema, buildRecordV3Schema]);
|
|
2202
|
-
function removalsOf(record2) {
|
|
2203
|
-
if (record2.format !== BUILD_RECORD_V3_FORMAT)
|
|
2204
|
-
return [];
|
|
2205
|
-
const out = [];
|
|
2206
|
-
for (const p of record2.review.parts) {
|
|
2207
|
-
if (p.change === "add" && p.decision === "dropped")
|
|
2208
|
-
out.push({ part: p.part, name: p.name, act: "dropped" });
|
|
2209
|
-
else if (p.change === "remove" && p.decision === "accepted")
|
|
2210
|
-
out.push({ part: p.part, name: p.name, act: "removed" });
|
|
2211
|
-
}
|
|
2212
|
-
return out;
|
|
2213
2675
|
}
|
|
2214
2676
|
|
|
2215
2677
|
// ../events/dist/device-auth.js
|
|
2216
|
-
import { z as
|
|
2217
|
-
var utcIso86012 =
|
|
2678
|
+
import { z as z19 } from "zod";
|
|
2679
|
+
var utcIso86012 = z19.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
|
|
2218
2680
|
var DEVICE_AUTH_STATUS = {
|
|
2219
2681
|
/** The poll: minted, nobody has acted yet. Keep polling. 200. */
|
|
2220
2682
|
PENDING: "pending",
|
|
@@ -2255,25 +2717,25 @@ var DEVICE_POLL_REFUSALS = [
|
|
|
2255
2717
|
DEVICE_AUTH_STATUS.EXPIRED,
|
|
2256
2718
|
DEVICE_AUTH_STATUS.UNKNOWN
|
|
2257
2719
|
];
|
|
2258
|
-
var deviceAuthStartResponseSchema =
|
|
2259
|
-
deviceCode:
|
|
2260
|
-
userCode:
|
|
2261
|
-
verificationUrl:
|
|
2720
|
+
var deviceAuthStartResponseSchema = z19.object({
|
|
2721
|
+
deviceCode: z19.string().min(1),
|
|
2722
|
+
userCode: z19.string().min(1),
|
|
2723
|
+
verificationUrl: z19.string().min(1),
|
|
2262
2724
|
expiresAt: utcIso86012,
|
|
2263
|
-
pollIntervalMs:
|
|
2725
|
+
pollIntervalMs: z19.number().int().positive()
|
|
2264
2726
|
}).strict();
|
|
2265
|
-
var devicePollPendingSchema =
|
|
2266
|
-
status:
|
|
2267
|
-
pollIntervalMs:
|
|
2727
|
+
var devicePollPendingSchema = z19.object({
|
|
2728
|
+
status: z19.literal(DEVICE_AUTH_STATUS.PENDING),
|
|
2729
|
+
pollIntervalMs: z19.number().int().positive()
|
|
2268
2730
|
}).strict();
|
|
2269
|
-
var devicePollApprovedSchema =
|
|
2270
|
-
status:
|
|
2271
|
-
accountId:
|
|
2272
|
-
credential:
|
|
2731
|
+
var devicePollApprovedSchema = z19.object({
|
|
2732
|
+
status: z19.literal(DEVICE_AUTH_STATUS.APPROVED),
|
|
2733
|
+
accountId: z19.string().min(1),
|
|
2734
|
+
credential: z19.string().min(1),
|
|
2273
2735
|
expiresAt: utcIso86012
|
|
2274
2736
|
}).strict();
|
|
2275
|
-
var deviceAuthRefusalSchema =
|
|
2276
|
-
status:
|
|
2737
|
+
var deviceAuthRefusalSchema = z19.object({
|
|
2738
|
+
status: z19.enum([
|
|
2277
2739
|
DEVICE_AUTH_STATUS.DECLINED,
|
|
2278
2740
|
DEVICE_AUTH_STATUS.EXPIRED,
|
|
2279
2741
|
DEVICE_AUTH_STATUS.UNKNOWN,
|
|
@@ -2284,25 +2746,25 @@ var deviceAuthRefusalSchema = z15.object({
|
|
|
2284
2746
|
DEVICE_AUTH_STATUS.ALREADY_DECIDED,
|
|
2285
2747
|
DEVICE_AUTH_STATUS.TERMS_REQUIRED
|
|
2286
2748
|
]),
|
|
2287
|
-
message:
|
|
2749
|
+
message: z19.string().min(1)
|
|
2288
2750
|
}).strict();
|
|
2289
|
-
var devicePollResponseSchema =
|
|
2751
|
+
var devicePollResponseSchema = z19.union([
|
|
2290
2752
|
devicePollPendingSchema,
|
|
2291
2753
|
devicePollApprovedSchema,
|
|
2292
2754
|
deviceAuthRefusalSchema
|
|
2293
2755
|
]);
|
|
2294
|
-
var deviceConfirmRequestSchema =
|
|
2295
|
-
userCode:
|
|
2296
|
-
decision:
|
|
2297
|
-
externalAuthId:
|
|
2298
|
-
email:
|
|
2299
|
-
acceptTerms:
|
|
2756
|
+
var deviceConfirmRequestSchema = z19.object({
|
|
2757
|
+
userCode: z19.string().min(1),
|
|
2758
|
+
decision: z19.enum(["approve", "decline"]),
|
|
2759
|
+
externalAuthId: z19.string().min(1).optional(),
|
|
2760
|
+
email: z19.string().optional(),
|
|
2761
|
+
acceptTerms: z19.boolean().optional()
|
|
2300
2762
|
}).strict();
|
|
2301
|
-
var deviceConfirmRecordedSchema =
|
|
2302
|
-
status:
|
|
2303
|
-
accountId:
|
|
2763
|
+
var deviceConfirmRecordedSchema = z19.object({
|
|
2764
|
+
status: z19.literal(DEVICE_AUTH_STATUS.RECORDED),
|
|
2765
|
+
accountId: z19.string().min(1).optional()
|
|
2304
2766
|
}).strict();
|
|
2305
|
-
var deviceConfirmResponseSchema =
|
|
2767
|
+
var deviceConfirmResponseSchema = z19.union([
|
|
2306
2768
|
deviceConfirmRecordedSchema,
|
|
2307
2769
|
deviceAuthRefusalSchema
|
|
2308
2770
|
]);
|
|
@@ -2314,20 +2776,20 @@ function projectPageUrl(engagementId) {
|
|
|
2314
2776
|
}
|
|
2315
2777
|
|
|
2316
2778
|
// ../events/dist/credential-wire.js
|
|
2317
|
-
import { z as
|
|
2318
|
-
var engagementCredentialResponseSchema =
|
|
2319
|
-
engagementId:
|
|
2320
|
-
sessionToken:
|
|
2321
|
-
mcpUrl:
|
|
2322
|
-
guardUrl:
|
|
2323
|
-
controlTelemetryUrl:
|
|
2324
|
-
methodVersion:
|
|
2325
|
-
consoleUrl:
|
|
2779
|
+
import { z as z20 } from "zod";
|
|
2780
|
+
var engagementCredentialResponseSchema = z20.object({
|
|
2781
|
+
engagementId: z20.string(),
|
|
2782
|
+
sessionToken: z20.string(),
|
|
2783
|
+
mcpUrl: z20.string(),
|
|
2784
|
+
guardUrl: z20.string(),
|
|
2785
|
+
controlTelemetryUrl: z20.string(),
|
|
2786
|
+
methodVersion: z20.string().optional(),
|
|
2787
|
+
consoleUrl: z20.string().optional()
|
|
2326
2788
|
}).strict();
|
|
2327
|
-
var ciTokenExchangeResponseSchema =
|
|
2328
|
-
token:
|
|
2789
|
+
var ciTokenExchangeResponseSchema = z20.object({
|
|
2790
|
+
token: z20.string(),
|
|
2329
2791
|
expiresAt: utcIso8601,
|
|
2330
|
-
engagementId:
|
|
2792
|
+
engagementId: z20.string()
|
|
2331
2793
|
}).strict();
|
|
2332
2794
|
var NO_CREDENTIAL_PLACEHOLDER = "halfcycle:no-credential";
|
|
2333
2795
|
var NOT_THIS_ACCOUNT_PLACEHOLDER = "halfcycle:not-this-account";
|
|
@@ -2344,42 +2806,118 @@ var PLACEHOLDER_SENTENCES = Object.freeze({
|
|
|
2344
2806
|
});
|
|
2345
2807
|
|
|
2346
2808
|
// ../events/dist/phase-record.js
|
|
2347
|
-
import { z as
|
|
2348
|
-
|
|
2809
|
+
import { z as z22 } from "zod";
|
|
2810
|
+
|
|
2811
|
+
// ../events/dist/build-record-v4.js
|
|
2812
|
+
import { z as z21 } from "zod";
|
|
2813
|
+
var BUILD_RECORD_V4_FORMAT = "halfcycle-build-record/v4";
|
|
2814
|
+
var recordReviewClaimSchema = z21.object({
|
|
2815
|
+
...reviewClaimAnswerSchema.shape,
|
|
2816
|
+
note: reviewNoteSchema.nullable()
|
|
2817
|
+
}).strict().superRefine((c, ctx) => {
|
|
2818
|
+
if (c.act === "accept" !== (c.note === null)) {
|
|
2819
|
+
ctx.addIssue({ code: "custom", path: ["note"], message: "carries the owner's note exactly on a reject" });
|
|
2820
|
+
}
|
|
2821
|
+
});
|
|
2822
|
+
var recordCallSchema = z21.object(workCallSchema.shape).omit({ at: true }).strict().superRefine((c, ctx) => checkReadCallHow(c, ctx));
|
|
2823
|
+
var recordReviewV4Schema = z21.object({
|
|
2824
|
+
...recordReviewSchema.shape,
|
|
2825
|
+
claims: z21.array(recordReviewClaimSchema).max(REVIEW_CLAIMS_MAX),
|
|
2826
|
+
calls: z21.array(recordCallSchema)
|
|
2827
|
+
}).strict().superRefine((v, ctx) => checkRecordReview(v, ctx));
|
|
2828
|
+
var buildRecordV4Schema = z21.object({
|
|
2829
|
+
...buildRecordV3Schema.shape,
|
|
2830
|
+
format: z21.literal(BUILD_RECORD_V4_FORMAT),
|
|
2831
|
+
path: phasePathSchema,
|
|
2832
|
+
review: recordReviewV4Schema
|
|
2833
|
+
}).strict().superRefine((record2, ctx) => checkReviewedRecord(record2, ctx));
|
|
2834
|
+
var buildRecordSchema = z21.discriminatedUnion("format", [
|
|
2835
|
+
buildRecordV2Schema,
|
|
2836
|
+
buildRecordV3Schema,
|
|
2837
|
+
buildRecordV4Schema
|
|
2838
|
+
]);
|
|
2839
|
+
var OWNER_REVIEW_FORMATS = Object.freeze([BUILD_RECORD_V3_FORMAT, BUILD_RECORD_V4_FORMAT]);
|
|
2840
|
+
function hasOwnerReview(record2) {
|
|
2841
|
+
return OWNER_REVIEW_FORMATS.includes(record2.format);
|
|
2842
|
+
}
|
|
2843
|
+
function keptClaimsOf(record2) {
|
|
2844
|
+
return record2.format === BUILD_RECORD_V4_FORMAT ? record2.review.claims : null;
|
|
2845
|
+
}
|
|
2846
|
+
function keptCallsOf(record2) {
|
|
2847
|
+
return record2.format === BUILD_RECORD_V4_FORMAT ? record2.review.calls : null;
|
|
2848
|
+
}
|
|
2849
|
+
function keptPathOf(record2) {
|
|
2850
|
+
return record2.format === BUILD_RECORD_V4_FORMAT ? record2.path : null;
|
|
2851
|
+
}
|
|
2852
|
+
function removalsOf(record2) {
|
|
2853
|
+
if (!hasOwnerReview(record2))
|
|
2854
|
+
return [];
|
|
2855
|
+
const out = [];
|
|
2856
|
+
for (const p of record2.review.parts) {
|
|
2857
|
+
if (p.change === "add" && p.decision === "dropped")
|
|
2858
|
+
out.push({ part: p.part, name: p.name, act: "dropped" });
|
|
2859
|
+
else if (p.change === "remove" && p.decision === "accepted")
|
|
2860
|
+
out.push({ part: p.part, name: p.name, act: "removed" });
|
|
2861
|
+
}
|
|
2862
|
+
return out;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
// ../events/dist/phase-record.js
|
|
2866
|
+
var phaseRecordRefusalReasonSchema = z22.enum([
|
|
2349
2867
|
"still-open",
|
|
2350
2868
|
"reopened",
|
|
2351
2869
|
"never-opened",
|
|
2352
2870
|
"never-closed",
|
|
2353
2871
|
"closed-before-records"
|
|
2354
2872
|
]);
|
|
2355
|
-
var phaseRecordRecordSchema =
|
|
2356
|
-
outcome:
|
|
2873
|
+
var phaseRecordRecordSchema = z22.object({
|
|
2874
|
+
outcome: z22.literal("record"),
|
|
2357
2875
|
phase: phaseNameSchema,
|
|
2358
2876
|
record: buildRecordSchema
|
|
2359
2877
|
}).strict().refine((body) => body.record.phase === body.phase, {
|
|
2360
2878
|
message: "the record is for a different phase than the one asked for",
|
|
2361
2879
|
path: ["record", "phase"]
|
|
2362
2880
|
});
|
|
2363
|
-
var phaseRecordWithheldSchema =
|
|
2364
|
-
outcome:
|
|
2881
|
+
var phaseRecordWithheldSchema = z22.object({
|
|
2882
|
+
outcome: z22.literal("withheld"),
|
|
2365
2883
|
phase: phaseNameSchema,
|
|
2366
|
-
sequence:
|
|
2884
|
+
sequence: z22.number().int().min(1),
|
|
2367
2885
|
closedAt: utcIso8601,
|
|
2368
|
-
message:
|
|
2886
|
+
message: z22.string()
|
|
2369
2887
|
}).strict();
|
|
2370
2888
|
var phaseRecordRefusedSchema = wireErrorSchema.extend({
|
|
2371
|
-
outcome:
|
|
2889
|
+
outcome: z22.literal("refused"),
|
|
2372
2890
|
phase: phaseNameSchema,
|
|
2373
|
-
statusCode:
|
|
2374
|
-
error:
|
|
2891
|
+
statusCode: z22.literal(409),
|
|
2892
|
+
error: z22.literal("PhaseRecordRefused"),
|
|
2375
2893
|
reason: phaseRecordRefusalReasonSchema
|
|
2376
2894
|
}).strict();
|
|
2377
|
-
var phaseRecordResponseSchema =
|
|
2895
|
+
var phaseRecordResponseSchema = z22.discriminatedUnion("outcome", [
|
|
2378
2896
|
phaseRecordRecordSchema,
|
|
2379
2897
|
phaseRecordWithheldSchema,
|
|
2380
2898
|
phaseRecordRefusedSchema
|
|
2381
2899
|
]);
|
|
2382
2900
|
|
|
2901
|
+
// ../events/dist/work-words.js
|
|
2902
|
+
var CALLS_HEADING = "Calls made without asking you";
|
|
2903
|
+
var CALLS_EXPLAINED = "These are the decisions the agents recorded taking on their own, each against a stated default. Halfcycle lists what they recorded; it cannot see a call an agent did not record.";
|
|
2904
|
+
function callMadeLine(call) {
|
|
2905
|
+
return `${call.by} decided "${call.question}": chose "${call.chose}". The stated default was "${call.statedDefault}".`;
|
|
2906
|
+
}
|
|
2907
|
+
function callUndoLine(call) {
|
|
2908
|
+
return call.undoable === "yes" ? `${call.by} says this can be undone: "${call.how ?? ""}"` : `${call.by} says this cannot be undone.`;
|
|
2909
|
+
}
|
|
2910
|
+
var NO_CALLS_LINE = "No agent recorded a call made without asking in this phase.";
|
|
2911
|
+
var UNCHECKED_CLAIMS_HEADING = "Checks nobody ran";
|
|
2912
|
+
function claimSaidLine(claim) {
|
|
2913
|
+
return `Task ${claim.task}: an agent said "${claim.label}" passes at commit ${claim.head}, and Halfcycle never ran it.`;
|
|
2914
|
+
}
|
|
2915
|
+
function recordedClaimLine(claim) {
|
|
2916
|
+
const said = claimSaidLine(claim);
|
|
2917
|
+
return claim.act === "accept" ? `${said} Accepted by the project's owner.` : `${said} Rejected by the project's owner: "${claim.note ?? ""}"`;
|
|
2918
|
+
}
|
|
2919
|
+
var NO_UNCHECKED_CLAIMS_LINE = "No agent said a check passes that Halfcycle never ran.";
|
|
2920
|
+
|
|
2383
2921
|
// dist/engagement-credential.js
|
|
2384
2922
|
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2385
2923
|
import { platform as platform2 } from "node:os";
|
|
@@ -2849,8 +3387,12 @@ function parseManifest(text) {
|
|
|
2849
3387
|
"eventsCreated",
|
|
2850
3388
|
"hooksCreated",
|
|
2851
3389
|
"permissionsCreated",
|
|
2852
|
-
"denyCreated"
|
|
3390
|
+
"denyCreated",
|
|
3391
|
+
"statusLineSha256"
|
|
2853
3392
|
], '"settings"');
|
|
3393
|
+
if (s["statusLineSha256"] !== void 0 && (typeof s["statusLineSha256"] !== "string" || !HEX64.test(s["statusLineSha256"]))) {
|
|
3394
|
+
throw new UnreadableManifestError('"settings.statusLineSha256" is not a hash');
|
|
3395
|
+
}
|
|
2854
3396
|
const settings = {
|
|
2855
3397
|
created: bool(s["created"], "settings.created"),
|
|
2856
3398
|
adopted: bool(s["adopted"], "settings.adopted"),
|
|
@@ -2860,7 +3402,8 @@ function parseManifest(text) {
|
|
|
2860
3402
|
eventsCreated: stringArray(s["eventsCreated"], "settings.eventsCreated"),
|
|
2861
3403
|
hooksCreated: bool(s["hooksCreated"], "settings.hooksCreated"),
|
|
2862
3404
|
permissionsCreated: bool(s["permissionsCreated"], "settings.permissionsCreated"),
|
|
2863
|
-
denyCreated: bool(s["denyCreated"], "settings.denyCreated")
|
|
3405
|
+
denyCreated: bool(s["denyCreated"], "settings.denyCreated"),
|
|
3406
|
+
...typeof s["statusLineSha256"] === "string" ? { statusLineSha256: s["statusLineSha256"] } : {}
|
|
2864
3407
|
};
|
|
2865
3408
|
let mcp;
|
|
2866
3409
|
if (raw["mcp"] !== void 0) {
|
|
@@ -2938,6 +3481,7 @@ function recordSettings(draft, observed) {
|
|
|
2938
3481
|
draft.settings = observed;
|
|
2939
3482
|
return;
|
|
2940
3483
|
}
|
|
3484
|
+
const statusLineSha256 = observed.statusLineSha256 ?? prev.statusLineSha256;
|
|
2941
3485
|
draft.settings = {
|
|
2942
3486
|
created: prev.created,
|
|
2943
3487
|
adopted: prev.adopted,
|
|
@@ -2947,9 +3491,17 @@ function recordSettings(draft, observed) {
|
|
|
2947
3491
|
eventsCreated: union(prev.eventsCreated, observed.eventsCreated),
|
|
2948
3492
|
hooksCreated: prev.hooksCreated,
|
|
2949
3493
|
permissionsCreated: prev.permissionsCreated,
|
|
2950
|
-
denyCreated: prev.denyCreated
|
|
3494
|
+
denyCreated: prev.denyCreated,
|
|
3495
|
+
...statusLineSha256 !== void 0 ? { statusLineSha256 } : {}
|
|
2951
3496
|
};
|
|
2952
3497
|
}
|
|
3498
|
+
function recordDenyRetired(draft, hashes) {
|
|
3499
|
+
const settings = draft.settings;
|
|
3500
|
+
if (settings === void 0 || hashes.length === 0)
|
|
3501
|
+
return;
|
|
3502
|
+
const gone = new Set(hashes);
|
|
3503
|
+
draft.settings = { ...settings, denyAddedSha256: settings.denyAddedSha256.filter((h) => !gone.has(h)) };
|
|
3504
|
+
}
|
|
2953
3505
|
function recordMcp(draft, observed) {
|
|
2954
3506
|
const prev = draft.mcp;
|
|
2955
3507
|
if (prev === void 0) {
|
|
@@ -3034,7 +3586,7 @@ function withoutHalfcycleCommands(entry, halfcycleCommands) {
|
|
|
3034
3586
|
const remaining = entry.hooks.filter((h) => !isHalfcycleCommand(h, halfcycleCommands));
|
|
3035
3587
|
return remaining.length > 0 ? { ...entry, hooks: remaining } : null;
|
|
3036
3588
|
}
|
|
3037
|
-
function mergeSettings(existing, generated) {
|
|
3589
|
+
function mergeSettings(existing, generated, retiredOurs, statusLine) {
|
|
3038
3590
|
const merged = { ...existing };
|
|
3039
3591
|
if (generated.$schema !== void 0) {
|
|
3040
3592
|
merged.$schema = generated.$schema;
|
|
@@ -3056,18 +3608,30 @@ function mergeSettings(existing, generated) {
|
|
|
3056
3608
|
mergedHooks[event] = [...developerEntries, ...halfcycleEntries];
|
|
3057
3609
|
}
|
|
3058
3610
|
merged.hooks = mergedHooks;
|
|
3059
|
-
merged.permissions = mergePermissions(existing.permissions, generated.permissions);
|
|
3611
|
+
merged.permissions = mergePermissions(existing.permissions, generated.permissions, retiredOurs);
|
|
3612
|
+
if (statusLine !== void 0 && !("statusLine" in existing)) {
|
|
3613
|
+
merged.statusLine = { ...statusLine };
|
|
3614
|
+
}
|
|
3060
3615
|
return merged;
|
|
3061
3616
|
}
|
|
3062
|
-
function mergePermissions(existing, generated) {
|
|
3617
|
+
function mergePermissions(existing, generated, retiredOurs) {
|
|
3063
3618
|
if (existing === void 0 && generated === void 0)
|
|
3064
3619
|
return void 0;
|
|
3065
3620
|
const result = { ...existing ?? {} };
|
|
3621
|
+
const theirs = Array.isArray(existing?.deny) ? [...existing.deny] : void 0;
|
|
3622
|
+
if (theirs !== void 0) {
|
|
3623
|
+
for (const rule of retiredOurs) {
|
|
3624
|
+
const at = theirs.lastIndexOf(rule);
|
|
3625
|
+
if (at >= 0)
|
|
3626
|
+
theirs.splice(at, 1);
|
|
3627
|
+
}
|
|
3628
|
+
result.deny = theirs;
|
|
3629
|
+
}
|
|
3066
3630
|
const generatedDeny = generated?.deny ?? [];
|
|
3067
3631
|
if (generatedDeny.length > 0) {
|
|
3068
|
-
const
|
|
3069
|
-
const seen = new Set(
|
|
3070
|
-
result.deny = [...
|
|
3632
|
+
const kept = theirs ?? [];
|
|
3633
|
+
const seen = new Set(kept);
|
|
3634
|
+
result.deny = [...kept, ...generatedDeny.filter((p) => !seen.has(p))];
|
|
3071
3635
|
}
|
|
3072
3636
|
return result;
|
|
3073
3637
|
}
|
|
@@ -3166,6 +3730,17 @@ function resolveVendoredBinary() {
|
|
|
3166
3730
|
}
|
|
3167
3731
|
throw new Error(`[halfcycle] Cannot find the self-contained guard binary bin.bundle.mjs. This copy of the halfcycle package is incomplete \u2014 reinstall it, or rebuild it if you are working on it. Looked in: ${candidates.join(", ")}.`);
|
|
3168
3732
|
}
|
|
3733
|
+
function resolvePreFilterShell() {
|
|
3734
|
+
const candidates = [
|
|
3735
|
+
join5(BUNDLE_ROOT, "bin", PRE_FILTER_SHELL_FILENAME),
|
|
3736
|
+
join5(BUNDLE_ROOT, "..", "runner", "dist", PRE_FILTER_SHELL_FILENAME)
|
|
3737
|
+
];
|
|
3738
|
+
for (const candidate of candidates) {
|
|
3739
|
+
if (existsSync3(candidate))
|
|
3740
|
+
return readFileSync4(candidate, "utf-8");
|
|
3741
|
+
}
|
|
3742
|
+
throw new Error(`[halfcycle] Cannot find ${PRE_FILTER_SHELL_FILENAME}. This copy of the halfcycle package is incomplete \u2014 reinstall it, or rebuild it if you are working on it. Looked in: ${candidates.join(", ")}.`);
|
|
3743
|
+
}
|
|
3169
3744
|
var WRITE_ALLOWLIST = [
|
|
3170
3745
|
".claude/commands",
|
|
3171
3746
|
".claude/hooks",
|
|
@@ -3200,7 +3775,18 @@ function commandStubRel(name) {
|
|
|
3200
3775
|
}
|
|
3201
3776
|
var RETIRED_MCP_HEADERS_HELPER_REL = ".halfcycle/mcp-headers.sh";
|
|
3202
3777
|
var RETIRED_WRITE_SET_FILES = [RETIRED_MCP_HEADERS_HELPER_REL];
|
|
3203
|
-
var RETIRED_DENY_PATTERNS = [
|
|
3778
|
+
var RETIRED_DENY_PATTERNS = [
|
|
3779
|
+
"Bash(rm -rf:*)",
|
|
3780
|
+
"Bash(git push --force:*)",
|
|
3781
|
+
"Bash(git push -f:*)",
|
|
3782
|
+
"Bash(git reset --hard:*)",
|
|
3783
|
+
"Bash(pnpm publish:*)",
|
|
3784
|
+
"Bash(npm publish:*)"
|
|
3785
|
+
];
|
|
3786
|
+
function retiredRulesThisInstallAdded(previous) {
|
|
3787
|
+
const added = new Set(previous?.settings.denyAddedSha256 ?? []);
|
|
3788
|
+
return RETIRED_DENY_PATTERNS.filter((rule) => added.has(sha256Hex(rule)));
|
|
3789
|
+
}
|
|
3204
3790
|
function closedWriteSet() {
|
|
3205
3791
|
const commands = readPluginManifest().commands ?? [];
|
|
3206
3792
|
const files = /* @__PURE__ */ new Set([
|
|
@@ -3235,7 +3821,8 @@ function closedWriteSet() {
|
|
|
3235
3821
|
GITATTRIBUTES_HEADER,
|
|
3236
3822
|
...lfRules([...Object.keys(OWNED_GENERATED_HEADERS), ...RETIRED_WRITE_SET_FILES])
|
|
3237
3823
|
]),
|
|
3238
|
-
generatedSha256: sha256OfWhatThisVersionWrites(commands)
|
|
3824
|
+
generatedSha256: sha256OfWhatThisVersionWrites(commands),
|
|
3825
|
+
statusLineSha256: /* @__PURE__ */ new Set([canonicalSha256(HALFCYCLE_STATUS_LINE)])
|
|
3239
3826
|
};
|
|
3240
3827
|
}
|
|
3241
3828
|
function sha256OfWhatThisVersionWrites(commands) {
|
|
@@ -3270,7 +3857,7 @@ function noteFile(draft, targetRepo, rel, outcome) {
|
|
|
3270
3857
|
}
|
|
3271
3858
|
recordInstalledFile(draft, rel, readFileSync4(join5(targetRepo, rel)));
|
|
3272
3859
|
}
|
|
3273
|
-
function recordSettingsMerge(draft, existing, generated, preexisted) {
|
|
3860
|
+
function recordSettingsMerge(draft, existing, generated, preexisted, merged) {
|
|
3274
3861
|
const generatedHooks = generated.hooks ?? {};
|
|
3275
3862
|
const hookCommands = Object.values(generatedHooks).flatMap((entries) => entries.flatMap((entry) => entry.hooks.map((h) => h.command)));
|
|
3276
3863
|
const ours = /* @__PURE__ */ new Set([...hookCommands, ...HALFCYCLE_HOOK_COMMANDS]);
|
|
@@ -3287,9 +3874,16 @@ function recordSettingsMerge(draft, existing, generated, preexisted) {
|
|
|
3287
3874
|
eventsCreated: Object.keys(generatedHooks).filter((event) => !(existingHooks && event in existingHooks)),
|
|
3288
3875
|
hooksCreated: existing.hooks === void 0,
|
|
3289
3876
|
permissionsCreated: existing.permissions === void 0,
|
|
3290
|
-
denyCreated: existing.permissions?.deny === void 0
|
|
3877
|
+
denyCreated: existing.permissions?.deny === void 0,
|
|
3878
|
+
...ourStatusLineSha256(merged) !== void 0 ? { statusLineSha256: ourStatusLineSha256(merged) } : {}
|
|
3291
3879
|
});
|
|
3292
3880
|
}
|
|
3881
|
+
function ourStatusLineSha256(settings) {
|
|
3882
|
+
if (!("statusLine" in settings))
|
|
3883
|
+
return void 0;
|
|
3884
|
+
const hash = canonicalSha256(settings["statusLine"]);
|
|
3885
|
+
return hash === canonicalSha256(HALFCYCLE_STATUS_LINE) ? hash : void 0;
|
|
3886
|
+
}
|
|
3293
3887
|
function recordMcpMerge(draft, existingText, writtenText) {
|
|
3294
3888
|
const before = existingText === null ? void 0 : JSON.parse(existingText);
|
|
3295
3889
|
const servers = isPlainObject(before) ? before["mcpServers"] : void 0;
|
|
@@ -3514,12 +4108,6 @@ function record(report, outcome, rel) {
|
|
|
3514
4108
|
bucket[outcome].push(rel);
|
|
3515
4109
|
}
|
|
3516
4110
|
var DENY_PATTERNS = [
|
|
3517
|
-
"Bash(rm -rf:*)",
|
|
3518
|
-
"Bash(git push --force:*)",
|
|
3519
|
-
"Bash(git push -f:*)",
|
|
3520
|
-
"Bash(git reset --hard:*)",
|
|
3521
|
-
"Bash(pnpm publish:*)",
|
|
3522
|
-
"Bash(npm publish:*)",
|
|
3523
4111
|
"Bash(gh repo delete:*)",
|
|
3524
4112
|
"Bash(git push --no-verify:*)",
|
|
3525
4113
|
"Bash(git commit --no-verify:*)"
|
|
@@ -3546,6 +4134,29 @@ function settingsParseRefusal(targetRepo, err) {
|
|
|
3546
4134
|
return `${file} could not be read as JSON${where} \u2014 fix it and run "npx halfcycle" again.`;
|
|
3547
4135
|
}
|
|
3548
4136
|
var SETTINGS_SCHEMA = "https://json.schemastore.org/claude-code-settings.json";
|
|
4137
|
+
var HALFCYCLE_STATUS_LINE = Object.freeze({
|
|
4138
|
+
type: "command",
|
|
4139
|
+
command: 'bash "$CLAUDE_PROJECT_DIR"/.claude/hooks/guard-runner.sh statusline'
|
|
4140
|
+
});
|
|
4141
|
+
function statusLineSetElsewhere(targetRepo, home = homedir2(), env = process.env) {
|
|
4142
|
+
const places = [join5(targetRepo, ".claude", "settings.local.json"), join5(home, ".claude", "settings.json")];
|
|
4143
|
+
const configDir = env["CLAUDE_CONFIG_DIR"];
|
|
4144
|
+
if (configDir !== void 0 && configDir !== "") {
|
|
4145
|
+
const expanded = configDir === "~" ? home : configDir.startsWith("~/") ? join5(home, configDir.slice(2)) : configDir;
|
|
4146
|
+
places.push(join5(isAbsolute2(expanded) ? expanded : resolve(expanded), "settings.json"));
|
|
4147
|
+
}
|
|
4148
|
+
return places.some((path) => {
|
|
4149
|
+
if (!existsSync3(path))
|
|
4150
|
+
return false;
|
|
4151
|
+
let value;
|
|
4152
|
+
try {
|
|
4153
|
+
value = JSON.parse(readFileSync4(path, "utf-8"));
|
|
4154
|
+
} catch {
|
|
4155
|
+
return true;
|
|
4156
|
+
}
|
|
4157
|
+
return !isPlainObject(value) || "statusLine" in value;
|
|
4158
|
+
});
|
|
4159
|
+
}
|
|
3549
4160
|
function generateSettingsJson() {
|
|
3550
4161
|
const hooks = {};
|
|
3551
4162
|
for (const { event, matcher, timeout, command } of HALFCYCLE_HOOK_WIRING) {
|
|
@@ -3566,7 +4177,7 @@ function generateSettingsJson() {
|
|
|
3566
4177
|
return JSON.stringify(settings, null, 2) + "\n";
|
|
3567
4178
|
}
|
|
3568
4179
|
var GENERATED_GUARD_RUNNER_HEADER = "# Governance hook wrapper \u2014 generated by";
|
|
3569
|
-
function generateGuardRunnerWrapper() {
|
|
4180
|
+
function generateGuardRunnerWrapper(preFilter = resolvePreFilterShell()) {
|
|
3570
4181
|
return `#!/usr/bin/env bash
|
|
3571
4182
|
${GENERATED_GUARD_RUNNER_HEADER} the Halfcycle installer.
|
|
3572
4183
|
#
|
|
@@ -3610,13 +4221,119 @@ if [ "$HALFCYCLE_ENV_NOT_THIS_ACCOUNT" = "1" ]; then
|
|
|
3610
4221
|
export HALFCYCLE_NOT_THIS_ACCOUNT=1
|
|
3611
4222
|
fi
|
|
3612
4223
|
|
|
4224
|
+
${preToolUseFallbackShell()}
|
|
4225
|
+
|
|
4226
|
+
${preFilter.trimEnd()}
|
|
4227
|
+
|
|
4228
|
+
# Before a tool runs, on a bash new enough for the cheap pass: read the call
|
|
4229
|
+
# once; when no risky action can be in it, answer here (the pass writes the
|
|
4230
|
+
# time line) and do not start Node. Otherwise hand the same input on below.
|
|
4231
|
+
if [ "$1" = hook ] && [ "$2" = pre-tool-use ] && [ "\${BASH_VERSINFO[0]:-0}" -ge 5 ]; then
|
|
4232
|
+
hc_input=$(cat 2>/dev/null) || IFS= read -r -d '' hc_input
|
|
4233
|
+
${PRE_FILTER_FUNCTION} && exit 0
|
|
4234
|
+
node -e "${nodeFloorProgram("")}" || {
|
|
4235
|
+
printf '%s' "$hc_input" | halfcycle_pre_tool_use_fallback
|
|
4236
|
+
exit 0
|
|
4237
|
+
}
|
|
4238
|
+
exec node "$PROJECT_DIR/${VENDORED_BIN_REL}" "$@" <<< "$hc_input"
|
|
4239
|
+
fi
|
|
4240
|
+
|
|
3613
4241
|
# On a Node older than Halfcycle supports, the runner cannot even be read, so
|
|
3614
|
-
# say that in one line instead of handing it a stack trace.
|
|
3615
|
-
|
|
4242
|
+
# say that in one line instead of handing it a stack trace. Before a tool runs,
|
|
4243
|
+
# the check itself is what cannot start, so the commands it would have stopped
|
|
4244
|
+
# are stopped here instead and everything else goes ahead.
|
|
4245
|
+
node -e "${nodeFloorProgram("")}" || {
|
|
4246
|
+
hc_node_status=$?
|
|
4247
|
+
if [ "$1" = hook ] && [ "$2" = pre-tool-use ]; then
|
|
4248
|
+
halfcycle_pre_tool_use_fallback
|
|
4249
|
+
exit 0
|
|
4250
|
+
fi
|
|
4251
|
+
exit "$hc_node_status"
|
|
4252
|
+
}
|
|
3616
4253
|
|
|
3617
4254
|
exec node "$PROJECT_DIR/${VENDORED_BIN_REL}" "$@"
|
|
3618
4255
|
`;
|
|
3619
4256
|
}
|
|
4257
|
+
var PRE_TOOL_USE_FALLBACK_SENTENCE = `Halfcycle: This command was stopped. Halfcycle's check is not running, because Node is not installed or is older than version ${NODE_FLOOR_MAJOR}, so Halfcycle cannot tell what the command would delete, overwrite or publish. To fix it, install Node ${NODE_FLOOR_MAJOR} or newer and open a new session. Nothing was changed.`;
|
|
4258
|
+
function retiredDenyPrefixes() {
|
|
4259
|
+
return RETIRED_DENY_PATTERNS.map((rule) => {
|
|
4260
|
+
const m = /^Bash\((.+):\*\)$/.exec(rule);
|
|
4261
|
+
if (m === null || m[1].includes("'")) {
|
|
4262
|
+
throw new Error(`[halfcycle] retired deny rule ${rule} is not a plain Bash(<prefix>:*) rule`);
|
|
4263
|
+
}
|
|
4264
|
+
return m[1];
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
4267
|
+
function preToolUseFallbackShell() {
|
|
4268
|
+
const reply = JSON.stringify({
|
|
4269
|
+
systemMessage: PRE_TOOL_USE_FALLBACK_SENTENCE,
|
|
4270
|
+
hookSpecificOutput: {
|
|
4271
|
+
hookEventName: "PreToolUse",
|
|
4272
|
+
permissionDecision: "deny",
|
|
4273
|
+
permissionDecisionReason: PRE_TOOL_USE_FALLBACK_SENTENCE
|
|
4274
|
+
}
|
|
4275
|
+
});
|
|
4276
|
+
const arms = retiredDenyPrefixes().map((prefix) => ` ${quoteForShell(prefix)}*) ;;`).join("\n");
|
|
4277
|
+
return `# --- Halfcycle fallback when the check cannot start (generated; do not edit) ---
|
|
4278
|
+
# Runs only before a tool runs, and only when Node is missing or too old. It
|
|
4279
|
+
# reads the shell command the agent is about to run and stops the few commands
|
|
4280
|
+
# that can lose work for good; everything else goes ahead.
|
|
4281
|
+
halfcycle_pre_tool_use_fallback() {
|
|
4282
|
+
local LC_ALL=C hc_in= hc_rest
|
|
4283
|
+
IFS= read -r -d '' hc_in
|
|
4284
|
+
case $hc_in in *'"tool_name":'*) ;; *) return 0 ;; esac
|
|
4285
|
+
hc_rest=\${hc_in#*'"tool_name":'}
|
|
4286
|
+
hc_rest=\${hc_rest#"\${hc_rest%%[! ]*}"}
|
|
4287
|
+
case $hc_rest in '"Bash"'*) ;; *) return 0 ;; esac
|
|
4288
|
+
case $hc_in in *'"tool_input"'*) ;; *) return 0 ;; esac
|
|
4289
|
+
hc_rest=\${hc_in#*'"tool_input"'}
|
|
4290
|
+
case $hc_rest in *'"command":'*) ;; *) return 0 ;; esac
|
|
4291
|
+
hc_rest=\${hc_rest#*'"command":'}
|
|
4292
|
+
hc_rest=\${hc_rest#"\${hc_rest%%[! ]*}"}
|
|
4293
|
+
case $hc_rest in '"'*) hc_rest=\${hc_rest#'"'} ;; *) return 0 ;; esac
|
|
4294
|
+
printf '%s' "$hc_rest" 2>/dev/null | {
|
|
4295
|
+
hc_piece= hc_esc= hc_prev= hc_end=
|
|
4296
|
+
while IFS= read -r -n 1 hc_c; do
|
|
4297
|
+
if [ -n "$hc_esc" ]; then
|
|
4298
|
+
hc_esc=
|
|
4299
|
+
case $hc_c in
|
|
4300
|
+
n) hc_c=';' ;;
|
|
4301
|
+
'\\'|'"') ;;
|
|
4302
|
+
*) hc_c="\\\\$hc_c" ;;
|
|
4303
|
+
esac
|
|
4304
|
+
else
|
|
4305
|
+
case $hc_c in
|
|
4306
|
+
'\\') hc_esc=1; continue ;;
|
|
4307
|
+
'"') hc_end=1; break ;;
|
|
4308
|
+
esac
|
|
4309
|
+
fi
|
|
4310
|
+
case $hc_prev$hc_c in
|
|
4311
|
+
'&&'|*';'|*'|')
|
|
4312
|
+
halfcycle_retired_spelling "$hc_piece" && return 0
|
|
4313
|
+
hc_piece= hc_prev=
|
|
4314
|
+
continue
|
|
4315
|
+
;;
|
|
4316
|
+
esac
|
|
4317
|
+
if [ -z "$hc_piece" ]; then
|
|
4318
|
+
case $hc_c in ' '|' ') continue ;; esac
|
|
4319
|
+
fi
|
|
4320
|
+
[ \${#hc_piece} -lt 64 ] && hc_piece=$hc_piece$hc_c
|
|
4321
|
+
hc_prev=$hc_c
|
|
4322
|
+
done
|
|
4323
|
+
[ -n "$hc_end" ] && halfcycle_retired_spelling "$hc_piece"
|
|
4324
|
+
return 0
|
|
4325
|
+
}
|
|
4326
|
+
return 0
|
|
4327
|
+
}
|
|
4328
|
+
halfcycle_retired_spelling() {
|
|
4329
|
+
case $1 in
|
|
4330
|
+
${arms}
|
|
4331
|
+
*) return 1 ;;
|
|
4332
|
+
esac
|
|
4333
|
+
printf '%s\\n' ${quoteForShell(reply)}
|
|
4334
|
+
}
|
|
4335
|
+
# --- end Halfcycle fallback ---------------------------------------------------`;
|
|
4336
|
+
}
|
|
3620
4337
|
var GENERATED_SESSION_START_HEADER = "# Session-start marker \u2014 generated by";
|
|
3621
4338
|
var SESSION_ID_FROM_HOOK_INPUT_SH = `SESSION_ID="$(printf '%s' "$INPUT" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const j=JSON.parse(s);process.stdout.write(typeof j.session_id==="string"?j.session_id:"")}catch{process.stdout.write("")}})' 2>/dev/null || true)"`;
|
|
3622
4339
|
var REPO_HASH_FROM_ROOT_SH = `HASH="$(printf '%s' "$REPO_ROOT" | node -e 'const c=[];process.stdin.on("data",d=>c.push(d)).on("end",()=>{process.stdout.write(require("node:crypto").createHash("sha256").update(Buffer.concat(c)).digest("hex").slice(0,12))})' 2>/dev/null || true)"`;
|
|
@@ -3901,7 +4618,7 @@ function generateMcpRegistration(existing, mcpOrigin) {
|
|
|
3901
4618
|
};
|
|
3902
4619
|
return JSON.stringify(base, null, 2) + "\n";
|
|
3903
4620
|
}
|
|
3904
|
-
var REQUIRED_GITIGNORE_ENTRIES = [".halfcycle/state.json", `${ZONE_B_DIR}
|
|
4621
|
+
var REQUIRED_GITIGNORE_ENTRIES = [".halfcycle/state.json", `${ZONE_B_DIR}/`, ".claude/worktrees/"];
|
|
3905
4622
|
var GITIGNORE_HEADER = "# Halfcycle \u2014 machine-local secrets/state and Zone-B (never push to client remote)";
|
|
3906
4623
|
function adoptBlockUnderHeader(before, header, claimable) {
|
|
3907
4624
|
const claimed = [];
|
|
@@ -4024,13 +4741,16 @@ function writeBundlePin(targetRepoRoot, version, engagementId, engagementType, c
|
|
|
4024
4741
|
const pinText = inLineEndingOf(readFileOrNull(pinPath), JSON.stringify(pin, null, 2) + "\n");
|
|
4025
4742
|
writeAllowlisted(pinPath, targetRepoRoot, pinText, writtenPaths);
|
|
4026
4743
|
}
|
|
4027
|
-
function
|
|
4744
|
+
function renderCrewRoster() {
|
|
4028
4745
|
const doc = {
|
|
4029
4746
|
$comment: "GENERATED by the Halfcycle installer \u2014 do not edit by hand. Re-run the installer to pick up a roster change.",
|
|
4030
4747
|
crew: CREW_ROSTER
|
|
4031
4748
|
};
|
|
4032
|
-
|
|
4749
|
+
return `${JSON.stringify(doc, null, 2)}
|
|
4033
4750
|
`;
|
|
4751
|
+
}
|
|
4752
|
+
function writeCrewRoster(targetRepoRoot, report) {
|
|
4753
|
+
const rendered = renderCrewRoster();
|
|
4034
4754
|
const crewPath = join5(targetRepoRoot, CREW_ROSTER_REL);
|
|
4035
4755
|
return recordOwned(report, crewPath, targetRepoRoot, rendered, CREW_ROSTER_REL);
|
|
4036
4756
|
}
|
|
@@ -4170,8 +4890,11 @@ async function install(options) {
|
|
|
4170
4890
|
} catch (err) {
|
|
4171
4891
|
throw new SettingsParseRefused(settingsParseRefusal(targetRepo, err));
|
|
4172
4892
|
}
|
|
4173
|
-
|
|
4174
|
-
const
|
|
4893
|
+
const retiredOurs = retiredRulesThisInstallAdded(draft.previous);
|
|
4894
|
+
const statusLine = statusLineSetElsewhere(targetRepo, home, options.env) ? void 0 : HALFCYCLE_STATUS_LINE;
|
|
4895
|
+
const mergedSettings = mergeSettings(existingSettings, generatedSettings, retiredOurs, statusLine);
|
|
4896
|
+
recordSettingsMerge(draft, existingSettings, generatedSettings, settingsPreexisted, mergedSettings);
|
|
4897
|
+
recordDenyRetired(draft, retiredOurs.map((rule) => sha256Hex(rule)));
|
|
4175
4898
|
const mergedSettingsText = inLineEndingOf(readFileOrNull(settingsPath), JSON.stringify(mergedSettings, null, 2) + "\n");
|
|
4176
4899
|
mkdirSync4(dirname3(settingsPath), { recursive: true });
|
|
4177
4900
|
writeFileSync4(settingsPath, mergedSettingsText, "utf-8");
|
|
@@ -5094,6 +5817,10 @@ var HEADER_CHECKS = "Halfcycle's checks are automatic rules drawn from the ways
|
|
|
5094
5817
|
var HEADER_KEPT = "Halfcycle derived this record and kept a copy of it when the phase closed. It changes that copy afterwards in one way only. If an account that closed this phase is later deleted, its email is removed, and so is the name given at any close Halfcycle recorded as made by that account. The client's Halfcycle command-line tool wrote this file from the kept copy, when the phase closed or when the record was fetched again. So a later deletion reaches this file the next time the record is fetched. The same record, as data, is in the .json file of the same name beside this one. If the phase is closed again, this file is replaced by a new record that describes every close, this one included.";
|
|
5095
5818
|
var HEADER_HIDDEN = "Some text in this record contains characters that do not print. Each is shown as U+ and its code of four or more hex digits; the .json file holds the text exactly.";
|
|
5096
5819
|
var OBSERVED_LABEL = "**Observed by Halfcycle**";
|
|
5820
|
+
var PATH_LINE = Object.freeze({
|
|
5821
|
+
mini: "Path: mini phase",
|
|
5822
|
+
full: "Path: full phase"
|
|
5823
|
+
});
|
|
5097
5824
|
var STATED_LABEL = "**Stated by the client** \u2014 Halfcycle did not check these.";
|
|
5098
5825
|
var MISMATCHED_HALVES = "This Build Record could not be written: its two parts describe different closes.";
|
|
5099
5826
|
function renderChecks(checks, p) {
|
|
@@ -5341,6 +6068,30 @@ function renderReview(record2, p) {
|
|
|
5341
6068
|
blocks.push(removals);
|
|
5342
6069
|
return blocks;
|
|
5343
6070
|
}
|
|
6071
|
+
function renderCalls(calls, p) {
|
|
6072
|
+
if (calls.length === 0)
|
|
6073
|
+
return [`## ${CALLS_HEADING}`, NO_CALLS_LINE];
|
|
6074
|
+
const lines = calls.flatMap((c) => {
|
|
6075
|
+
const by = p.itemStart(c.by);
|
|
6076
|
+
return [
|
|
6077
|
+
`- ${callMadeLine({ by, question: p.text(c.question), chose: p.text(c.chose), statedDefault: p.text(c.statedDefault) })}`,
|
|
6078
|
+
` - ${callUndoLine({ by: p.text(c.by), undoable: c.undoable, how: c.how === null ? null : p.text(c.how) })}`
|
|
6079
|
+
];
|
|
6080
|
+
});
|
|
6081
|
+
return [`## ${CALLS_HEADING}`, CALLS_EXPLAINED, lines.join("\n")];
|
|
6082
|
+
}
|
|
6083
|
+
function renderClaims(claims, p) {
|
|
6084
|
+
if (claims.length === 0)
|
|
6085
|
+
return [`## ${UNCHECKED_CLAIMS_HEADING}`, NO_UNCHECKED_CLAIMS_LINE];
|
|
6086
|
+
const lines = claims.map((c) => `- ${recordedClaimLine({
|
|
6087
|
+
task: p.text(c.task),
|
|
6088
|
+
label: p.text(c.label),
|
|
6089
|
+
head: shortCommit(c.head),
|
|
6090
|
+
act: c.act,
|
|
6091
|
+
note: c.note === null ? null : p.text(c.note)
|
|
6092
|
+
})}`);
|
|
6093
|
+
return [`## ${UNCHECKED_CLAIMS_HEADING}`, lines.join("\n")];
|
|
6094
|
+
}
|
|
5344
6095
|
var EARLIER_ROUNDS_LABEL = `${STATED_LABEL} What was said each time the owner's review was asked for, before the round that closed the phase. What was said for that last round is under the close above. If the account that asked for a round is later deleted, the name given for that round is removed.`;
|
|
5345
6096
|
function renderRoundStated(round, stated, p) {
|
|
5346
6097
|
const label = "> - Acceptance walk (the finished work tried as a user would, by someone other than its builder): ";
|
|
@@ -5385,7 +6136,8 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
5385
6136
|
const closes = [...record2.observed.closes].sort((a, b) => a.sequence - b.sequence);
|
|
5386
6137
|
const total = closes.length;
|
|
5387
6138
|
const latest = closes[total - 1];
|
|
5388
|
-
const rounds = record2
|
|
6139
|
+
const rounds = hasOwnerReview(record2) ? record2.review.rounds : [];
|
|
6140
|
+
const path = keptPathOf(record2);
|
|
5389
6141
|
const roundsAfter = rounds.length <= 1 ? null : `after ${String(rounds.length)} rounds of the owner's review.${rounds.some((r) => r.stated !== void 0) ? ' What was said for each earlier round is under "Earlier rounds of the review".' : ""}`;
|
|
5390
6142
|
const body = [
|
|
5391
6143
|
`Phase: ${phase} (the name the client gave it)`,
|
|
@@ -5393,14 +6145,23 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
5393
6145
|
[
|
|
5394
6146
|
`- Method version: ${p.text(record2.observed.methodVersion)}. The Halfcycle method is updated from time to time, and each update has its own version number. This is the one the phase was run under. A project moves to a newer version only between phases.`,
|
|
5395
6147
|
`- Project identifier: ${p.text(record2.observed.engagementId)}. Halfcycle keeps this project's records under this identifier.`,
|
|
5396
|
-
`- Record format: ${p.text(record2.format)}. This names the layout this file and the .json file beside it follow, for software that reads them
|
|
6148
|
+
`- Record format: ${p.text(record2.format)}. This names the layout this file and the .json file beside it follow, for software that reads them.`,
|
|
6149
|
+
...path === null ? [] : [`- ${PATH_LINE[path]}`]
|
|
5397
6150
|
].join("\n"),
|
|
5398
6151
|
total === 1 ? roundsAfter === null ? "This phase was closed once." : `This phase was closed once, ${roundsAfter}` : `This phase was closed ${String(total)} times. The latest close is described first; each earlier close follows, as it was recorded when it was made.${roundsAfter === null ? "" : ` The latest close came ${roundsAfter}`}`,
|
|
5399
6152
|
...renderChecks(record2.observed.checks, p),
|
|
5400
6153
|
...renderClose(total === 1 ? "## The close" : `## The latest close (close ${String(latest.sequence)} of ${String(total)})`, latest, attestedBySequence.get(latest.sequence), record2.observed.checks.state, p, rounds.length > 1)
|
|
5401
6154
|
];
|
|
5402
|
-
if (record2
|
|
5403
|
-
body.push(...renderReview(record2, p)
|
|
6155
|
+
if (hasOwnerReview(record2))
|
|
6156
|
+
body.push(...renderReview(record2, p));
|
|
6157
|
+
const calls = keptCallsOf(record2);
|
|
6158
|
+
if (calls !== null)
|
|
6159
|
+
body.push(...renderCalls(calls, p));
|
|
6160
|
+
const claims = keptClaimsOf(record2);
|
|
6161
|
+
if (claims !== null)
|
|
6162
|
+
body.push(...renderClaims(claims, p));
|
|
6163
|
+
if (hasOwnerReview(record2))
|
|
6164
|
+
body.push(...renderEarlierRounds(record2, p));
|
|
5404
6165
|
if (total > 1) {
|
|
5405
6166
|
body.push("## Earlier closes");
|
|
5406
6167
|
for (const close of closes.slice(0, -1)) {
|
|
@@ -5415,16 +6176,11 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
5415
6176
|
}
|
|
5416
6177
|
|
|
5417
6178
|
// dist/build-record/write.js
|
|
5418
|
-
import {
|
|
5419
|
-
import { basename, join as join8, resolve, relative as relative2, isAbsolute as
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
const isPlainFilename = rel !== "" && rel !== ".." && !isAbsolute2(rel) && rel === basename(rel);
|
|
5424
|
-
if (!isPlainFilename) {
|
|
5425
|
-
throw new InvalidPhaseIdentityError(identity, BUILD_RECORD_DIR);
|
|
5426
|
-
}
|
|
5427
|
-
}
|
|
6179
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, rmSync as rmSync4 } from "node:fs";
|
|
6180
|
+
import { basename, join as join8, resolve as resolve2, relative as relative2, isAbsolute as isAbsolute3 } from "node:path";
|
|
6181
|
+
|
|
6182
|
+
// dist/build-record/pair-io.js
|
|
6183
|
+
import { closeSync, openSync, readFileSync as readFileSync7, renameSync as renameSync2, rmSync as rmSync3, writeSync } from "node:fs";
|
|
5428
6184
|
function createExclusiveOnDisk(path, data) {
|
|
5429
6185
|
const bytes = typeof data === "string" ? Buffer.from(data, "utf-8") : data;
|
|
5430
6186
|
const fd = openSync(path, "wx");
|
|
@@ -5460,6 +6216,41 @@ function readIfPresent(path) {
|
|
|
5460
6216
|
return null;
|
|
5461
6217
|
}
|
|
5462
6218
|
}
|
|
6219
|
+
function createPairExclusive(io, jsonPath, jsonText, mdPath, mdText) {
|
|
6220
|
+
let createdJson = false;
|
|
6221
|
+
try {
|
|
6222
|
+
io.createExclusive(jsonPath, jsonText);
|
|
6223
|
+
createdJson = true;
|
|
6224
|
+
io.createExclusive(mdPath, mdText);
|
|
6225
|
+
return "created";
|
|
6226
|
+
} catch (err) {
|
|
6227
|
+
if (createdJson)
|
|
6228
|
+
rmSync3(jsonPath, { force: true });
|
|
6229
|
+
if (!isEexist(err))
|
|
6230
|
+
throw err;
|
|
6231
|
+
return "exists";
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
function replaceOne(io, tmp, finalPath, text) {
|
|
6235
|
+
rmSync3(tmp, { force: true });
|
|
6236
|
+
try {
|
|
6237
|
+
io.createExclusive(tmp, text);
|
|
6238
|
+
io.rename(tmp, finalPath);
|
|
6239
|
+
} catch (err) {
|
|
6240
|
+
rmSync3(tmp, { force: true });
|
|
6241
|
+
throw err;
|
|
6242
|
+
}
|
|
6243
|
+
}
|
|
6244
|
+
|
|
6245
|
+
// dist/build-record/write.js
|
|
6246
|
+
var BUILD_RECORD_DIR = join8("docs", "build-records");
|
|
6247
|
+
function assertInsideOutDir(outDir, candidate, identity) {
|
|
6248
|
+
const rel = relative2(outDir, resolve2(candidate));
|
|
6249
|
+
const isPlainFilename = rel !== "" && rel !== ".." && !isAbsolute3(rel) && rel === basename(rel);
|
|
6250
|
+
if (!isPlainFilename) {
|
|
6251
|
+
throw new InvalidPhaseIdentityError(identity, BUILD_RECORD_DIR);
|
|
6252
|
+
}
|
|
6253
|
+
}
|
|
5463
6254
|
function isOwnEarlierRecord(existingText, served) {
|
|
5464
6255
|
let parsedJson;
|
|
5465
6256
|
try {
|
|
@@ -5488,7 +6279,7 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
|
|
|
5488
6279
|
if (!isValidPhaseIdentity(phase)) {
|
|
5489
6280
|
throw new InvalidPhaseIdentityError(phase, BUILD_RECORD_DIR);
|
|
5490
6281
|
}
|
|
5491
|
-
const outDir =
|
|
6282
|
+
const outDir = resolve2(repoRoot, BUILD_RECORD_DIR);
|
|
5492
6283
|
const segment = renderPhaseSegment(phase);
|
|
5493
6284
|
const jsonPath = join8(outDir, `${segment}.json`);
|
|
5494
6285
|
const mdPath = join8(outDir, `${segment}.md`);
|
|
@@ -5500,17 +6291,8 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
|
|
|
5500
6291
|
const jsonText = serialiseServedRecord(rawRecord);
|
|
5501
6292
|
const mdText = renderBuildRecordV2Markdown(record2);
|
|
5502
6293
|
mkdirSync6(outDir, { recursive: true });
|
|
5503
|
-
|
|
5504
|
-
try {
|
|
5505
|
-
io.createExclusive(jsonPath, jsonText);
|
|
5506
|
-
createdJson = true;
|
|
5507
|
-
io.createExclusive(mdPath, mdText);
|
|
6294
|
+
if (createPairExclusive(io, jsonPath, jsonText, mdPath, mdText) === "created") {
|
|
5508
6295
|
return { kind: "created", jsonPath, mdPath };
|
|
5509
|
-
} catch (err) {
|
|
5510
|
-
if (createdJson)
|
|
5511
|
-
rmSync3(jsonPath, { force: true });
|
|
5512
|
-
if (!isEexist(err))
|
|
5513
|
-
throw err;
|
|
5514
6296
|
}
|
|
5515
6297
|
const existingJson = readIfPresent(jsonPath);
|
|
5516
6298
|
if (existingJson === null) {
|
|
@@ -5530,22 +6312,12 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
|
|
|
5530
6312
|
try {
|
|
5531
6313
|
replaceOne(io, jsonTmp, jsonPath, existingJson);
|
|
5532
6314
|
} catch {
|
|
5533
|
-
|
|
6315
|
+
rmSync4(jsonPath, { force: true });
|
|
5534
6316
|
}
|
|
5535
6317
|
throw err;
|
|
5536
6318
|
}
|
|
5537
6319
|
return { kind: "replaced", jsonPath, mdPath };
|
|
5538
6320
|
}
|
|
5539
|
-
function replaceOne(io, tmp, finalPath, text) {
|
|
5540
|
-
rmSync3(tmp, { force: true });
|
|
5541
|
-
try {
|
|
5542
|
-
io.createExclusive(tmp, text);
|
|
5543
|
-
io.rename(tmp, finalPath);
|
|
5544
|
-
} catch (err) {
|
|
5545
|
-
rmSync3(tmp, { force: true });
|
|
5546
|
-
throw err;
|
|
5547
|
-
}
|
|
5548
|
-
}
|
|
5549
6321
|
|
|
5550
6322
|
// dist/build-record/obtain.js
|
|
5551
6323
|
import { relative as relative3 } from "node:path";
|