halfcycle 0.4.8 → 0.4.9
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 +2031 -216
- package/commands/agent-teams-orchestration.md +1 -1
- package/commands/consistency-check.md +1 -1
- package/commands/context-update.md +1 -1
- package/commands/halfcycle-design.md +1 -1
- package/commands/halfcycle-setup.md +1 -1
- package/commands/stack-assembly-worker.md +1 -1
- package/commands/task-execution.md +1 -1
- package/commands/task-graph.md +1 -1
- package/commands/write-spec.md +1 -1
- package/dist/bin.d.ts +2 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/build-record/obtain.d.ts +14 -7
- package/dist/build-record/obtain.d.ts.map +1 -1
- package/dist/build-record/render-v2.d.ts +32 -6
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/build-record/write.d.ts +2 -2
- package/dist/build-record/write.d.ts.map +1 -1
- package/dist/cli-contract.d.ts +2 -9
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +3189 -1401
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +215 -134
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/draw/index.d.ts +25 -5
- package/dist/draw/index.d.ts.map +1 -1
- package/dist/identity.d.ts +78 -9
- package/dist/identity.d.ts.map +1 -1
- package/dist/index.js +1624 -204
- package/dist/index.js.map +3 -3
- package/dist/install.d.ts +16 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/open-phase.d.ts +25 -1
- package/dist/open-phase.d.ts.map +1 -1
- package/dist/plan.d.ts +59 -18
- package/dist/plan.d.ts.map +1 -1
- package/dist/pre-create-checks.d.ts.map +1 -1
- package/dist/review.d.ts +228 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/shown-record.d.ts +46 -0
- package/dist/shown-record.d.ts.map +1 -0
- package/dist/system-report.d.ts +28 -4
- package/dist/system-report.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/project-page.d.ts +0 -24
- package/dist/project-page.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -238,6 +238,25 @@ var HALFCYCLE_COMMAND = "npx halfcycle@latest";
|
|
|
238
238
|
// ../core/dist/release-version.js
|
|
239
239
|
var RELEASE_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
240
240
|
|
|
241
|
+
// ../core/dist/github-address.js
|
|
242
|
+
var GITHUB_REPOSITORY_ADDRESS = /^https:\/\/github\.com\/[A-Za-z0-9][A-Za-z0-9-]{0,38}\/(?!\.{1,2}$)[A-Za-z0-9._-]{1,100}$/;
|
|
243
|
+
var HOST = "[Gg][Ii][Tt][Hh][Uu][Bb]\\.[Cc][Oo][Mm]";
|
|
244
|
+
var OWNER = "[A-Za-z0-9][A-Za-z0-9-]{0,38}";
|
|
245
|
+
var RAW_REPOSITORY = "[A-Za-z0-9._-]{1,104}";
|
|
246
|
+
var TAIL = `(${OWNER})/(${RAW_REPOSITORY})/?$`;
|
|
247
|
+
var URL_USERINFO = "(?:[^\\s/?#@]+@)?";
|
|
248
|
+
var SSH_USER = "(?:[^\\s/?#@:]+@)?";
|
|
249
|
+
var REMOTE_FORMS = [
|
|
250
|
+
new RegExp(`^https?://${URL_USERINFO}${HOST}/${TAIL}`),
|
|
251
|
+
new RegExp(`^ssh://${SSH_USER}${HOST}/${TAIL}`),
|
|
252
|
+
new RegExp(`^git://${HOST}/${TAIL}`),
|
|
253
|
+
new RegExp(`^${SSH_USER}${HOST}:${TAIL}`)
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
// ../core/dist/sign-in.js
|
|
257
|
+
var SIGN_IN_COMMAND = '"npx halfcycle"';
|
|
258
|
+
var HOOK_REMEDY = `Run ${SIGN_IN_COMMAND} in the project folder to sign in.`;
|
|
259
|
+
|
|
241
260
|
// ../events/dist/result.js
|
|
242
261
|
import { z as z2 } from "zod";
|
|
243
262
|
var firedGuardSchema = z2.object({
|
|
@@ -305,17 +324,29 @@ function hasLoneSurrogate(text) {
|
|
|
305
324
|
var LONE_SURROGATE_MESSAGE = "must be valid text: it holds half of a character pair with no other half";
|
|
306
325
|
|
|
307
326
|
// ../events/dist/state.js
|
|
327
|
+
import { z as z4 } from "zod";
|
|
328
|
+
|
|
329
|
+
// ../events/dist/human-agent.js
|
|
308
330
|
import { z as z3 } from "zod";
|
|
309
|
-
var
|
|
331
|
+
var HUMAN_AGENT = "Human";
|
|
332
|
+
var AGENT_NAME_MAX = 32;
|
|
333
|
+
var agentNameSchema = z3.string().min(1).max(AGENT_NAME_MAX);
|
|
334
|
+
|
|
335
|
+
// ../events/dist/state.js
|
|
336
|
+
var utcIso8601 = z4.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");
|
|
310
337
|
var STATE_RECORD_FORMAT = "halfcycle-state-record/v1";
|
|
311
|
-
var stepIdSchema =
|
|
312
|
-
var methodVersionSchema =
|
|
338
|
+
var stepIdSchema = z4.string().regex(/^(l[0-5](-l[0-5])?|xl)\.[a-z0-9-]+$/);
|
|
339
|
+
var methodVersionSchema = z4.string().regex(RELEASE_VERSION_PATTERN);
|
|
313
340
|
var anchorPathRegex = /^(?!\/)(?!.*#)(?!method\/)(?!(.*\/)?docs\/method\/).+$/;
|
|
314
|
-
var recordKindSchema =
|
|
315
|
-
var methodLayerSchema =
|
|
316
|
-
var
|
|
317
|
-
|
|
318
|
-
|
|
341
|
+
var recordKindSchema = z4.enum(["artefact", "step-run", "gate", "intervention"]);
|
|
342
|
+
var methodLayerSchema = z4.enum(["l0", "l1", "l2", "l3", "l3-l4", "l4", "l5", "xl"]);
|
|
343
|
+
var PHASE_SCOPED_LAYERS = ["l4", "l5"];
|
|
344
|
+
function isPhaseScopedLayer(layer) {
|
|
345
|
+
return PHASE_SCOPED_LAYERS.includes(layer);
|
|
346
|
+
}
|
|
347
|
+
var evidenceKindSchema = z4.enum(["anchor", "diff", "repro", "question-answer", "no-op"]);
|
|
348
|
+
var declarableEvidenceKindSchema = z4.enum(["anchor", "diff", "repro", "question-answer"]);
|
|
349
|
+
var dispositionSchema = z4.enum([
|
|
319
350
|
"prevented",
|
|
320
351
|
"corrected-in-spec",
|
|
321
352
|
"corrected-in-scope",
|
|
@@ -325,20 +356,20 @@ var dispositionSchema = z3.enum([
|
|
|
325
356
|
"surfaced",
|
|
326
357
|
"filed-forward"
|
|
327
358
|
]);
|
|
328
|
-
var mechanismSchema =
|
|
329
|
-
var artefactStateSchema =
|
|
359
|
+
var mechanismSchema = z4.enum(["guard", "verdict", "served-step", "method-step"]);
|
|
360
|
+
var artefactStateSchema = z4.enum(["created", "updated"]);
|
|
330
361
|
var QUALIFIED_OUTCOMES = ["declined", "parked"];
|
|
331
|
-
var qualifiedOutcomeSchema =
|
|
362
|
+
var qualifiedOutcomeSchema = z4.enum(QUALIFIED_OUTCOMES);
|
|
332
363
|
function isQualifiedOutcome(outcome) {
|
|
333
364
|
return QUALIFIED_OUTCOMES.includes(outcome);
|
|
334
365
|
}
|
|
335
|
-
var runOutcomeSchema =
|
|
366
|
+
var runOutcomeSchema = z4.enum([
|
|
336
367
|
"completed",
|
|
337
368
|
"attempted-failed",
|
|
338
369
|
...QUALIFIED_OUTCOMES
|
|
339
370
|
]);
|
|
340
|
-
var gateKindSchema =
|
|
341
|
-
var gateVerdictSchema =
|
|
371
|
+
var gateKindSchema = z4.enum(["approval", "mechanical"]);
|
|
372
|
+
var gateVerdictSchema = z4.enum(["pass", "fail", ...QUALIFIED_OUTCOMES]);
|
|
342
373
|
function outcomeReasonIssue(outcome, reason) {
|
|
343
374
|
if (isQualifiedOutcome(outcome) && reason === void 0) {
|
|
344
375
|
return { message: `outcomeReason is required when the outcome is '${outcome}'` };
|
|
@@ -350,47 +381,47 @@ function outcomeReasonIssue(outcome, reason) {
|
|
|
350
381
|
}
|
|
351
382
|
return null;
|
|
352
383
|
}
|
|
353
|
-
var anchorEvidenceSchema =
|
|
354
|
-
kind:
|
|
355
|
-
path:
|
|
384
|
+
var anchorEvidenceSchema = z4.object({
|
|
385
|
+
kind: z4.literal("anchor"),
|
|
386
|
+
path: z4.string().regex(anchorPathRegex),
|
|
356
387
|
// Optional 1-based line number within the file at `path`. Present when the
|
|
357
388
|
// writer knows the exact line; omitted — never `0`, never `null` — when it
|
|
358
389
|
// does not, because a line number is not always obtainable. Absence is a
|
|
359
390
|
// valid, permanent state here, not a gap meant to be filled in later.
|
|
360
|
-
line:
|
|
391
|
+
line: z4.number().optional()
|
|
361
392
|
}).strict();
|
|
362
|
-
var diffEvidenceSchema =
|
|
363
|
-
kind:
|
|
364
|
-
ref:
|
|
393
|
+
var diffEvidenceSchema = z4.object({
|
|
394
|
+
kind: z4.literal("diff"),
|
|
395
|
+
ref: z4.string()
|
|
365
396
|
}).strict();
|
|
366
|
-
var reproEvidenceSchema =
|
|
367
|
-
kind:
|
|
368
|
-
steps:
|
|
397
|
+
var reproEvidenceSchema = z4.object({
|
|
398
|
+
kind: z4.literal("repro"),
|
|
399
|
+
steps: z4.string().max(2e3)
|
|
369
400
|
}).strict();
|
|
370
|
-
var questionAnswerEvidenceSchema =
|
|
371
|
-
kind:
|
|
372
|
-
question:
|
|
373
|
-
before:
|
|
374
|
-
after:
|
|
401
|
+
var questionAnswerEvidenceSchema = z4.object({
|
|
402
|
+
kind: z4.literal("question-answer"),
|
|
403
|
+
question: z4.string().max(2e3),
|
|
404
|
+
before: z4.string().max(2e3),
|
|
405
|
+
after: z4.string().max(2e3)
|
|
375
406
|
}).strict();
|
|
376
|
-
var noOpEvidenceSchema =
|
|
377
|
-
kind:
|
|
378
|
-
inspected:
|
|
379
|
-
unchangedBecause:
|
|
407
|
+
var noOpEvidenceSchema = z4.object({
|
|
408
|
+
kind: z4.literal("no-op"),
|
|
409
|
+
inspected: z4.string().max(2e3),
|
|
410
|
+
unchangedBecause: z4.string().max(2e3)
|
|
380
411
|
}).strict();
|
|
381
|
-
var evidenceSchema =
|
|
412
|
+
var evidenceSchema = z4.discriminatedUnion("kind", [
|
|
382
413
|
anchorEvidenceSchema,
|
|
383
414
|
diffEvidenceSchema,
|
|
384
415
|
reproEvidenceSchema,
|
|
385
416
|
questionAnswerEvidenceSchema,
|
|
386
417
|
noOpEvidenceSchema
|
|
387
418
|
]);
|
|
388
|
-
var stateRecordEnvelopeSchema =
|
|
389
|
-
format:
|
|
419
|
+
var stateRecordEnvelopeSchema = z4.object({
|
|
420
|
+
format: z4.literal(STATE_RECORD_FORMAT),
|
|
390
421
|
recordKind: recordKindSchema,
|
|
391
|
-
recordId:
|
|
422
|
+
recordId: z4.string().uuid(),
|
|
392
423
|
methodVersion: methodVersionSchema,
|
|
393
|
-
engagementId:
|
|
424
|
+
engagementId: z4.string(),
|
|
394
425
|
stepId: stepIdSchema,
|
|
395
426
|
// Immutable: names when the thing happened, never when a later disposition
|
|
396
427
|
// moved.
|
|
@@ -406,80 +437,94 @@ var stateRecordEnvelopeSchema = z3.object({
|
|
|
406
437
|
// for the whole project rather than per phase. Absence is meaningful on its
|
|
407
438
|
// own — it is never replaced with a placeholder value, and it is read as
|
|
408
439
|
// "satisfies any phase", not as "unknown".
|
|
409
|
-
phase:
|
|
440
|
+
phase: z4.string().optional()
|
|
410
441
|
});
|
|
411
|
-
var artefactRefSchema =
|
|
412
|
-
name:
|
|
413
|
-
parent:
|
|
442
|
+
var artefactRefSchema = z4.object({
|
|
443
|
+
name: z4.string(),
|
|
444
|
+
parent: z4.string()
|
|
414
445
|
}).strict();
|
|
415
|
-
var coverageSchema =
|
|
416
|
-
asked:
|
|
417
|
-
answered:
|
|
446
|
+
var coverageSchema = z4.object({
|
|
447
|
+
asked: z4.number().int().nonnegative(),
|
|
448
|
+
answered: z4.number().int().nonnegative()
|
|
418
449
|
}).strict().superRefine((coverage, ctx) => {
|
|
419
450
|
if (coverage.answered > coverage.asked) {
|
|
420
451
|
ctx.addIssue({
|
|
421
|
-
code:
|
|
452
|
+
code: z4.ZodIssueCode.custom,
|
|
422
453
|
path: ["answered"],
|
|
423
454
|
message: "answered cannot be more than asked"
|
|
424
455
|
});
|
|
425
456
|
}
|
|
426
457
|
});
|
|
458
|
+
var projectTierSchema = z4.number().int().min(0).max(3);
|
|
427
459
|
var artefactRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
428
|
-
recordKind:
|
|
460
|
+
recordKind: z4.literal("artefact"),
|
|
429
461
|
artefactRef: artefactRefSchema,
|
|
430
462
|
// Some layer wrote it, by construction — an empty array is not a legitimate
|
|
431
463
|
// state, so the schema says so.
|
|
432
|
-
writtenByLayers:
|
|
464
|
+
writtenByLayers: z4.array(methodLayerSchema).min(1),
|
|
433
465
|
state: artefactStateSchema
|
|
434
466
|
}).strict();
|
|
435
467
|
var stepRunRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
436
|
-
recordKind:
|
|
468
|
+
recordKind: z4.literal("step-run"),
|
|
437
469
|
runOutcome: runOutcomeSchema,
|
|
438
|
-
failureReason:
|
|
439
|
-
outcomeReason:
|
|
470
|
+
failureReason: z4.string().optional(),
|
|
471
|
+
outcomeReason: z4.string().max(2e3).optional(),
|
|
472
|
+
// Who did this step, as the session reported it. Absent when not reported.
|
|
473
|
+
agent: agentNameSchema.optional(),
|
|
474
|
+
// When the session began this step. Absent when not reported.
|
|
475
|
+
startedAt: utcIso8601.optional(),
|
|
476
|
+
// The project's tier, when this step settled it. Absent on every other step.
|
|
477
|
+
projectTier: projectTierSchema.optional()
|
|
440
478
|
}).strict().superRefine((rec, ctx) => {
|
|
441
479
|
if (rec.runOutcome === "attempted-failed" && rec.failureReason === void 0) {
|
|
442
480
|
ctx.addIssue({
|
|
443
|
-
code:
|
|
481
|
+
code: z4.ZodIssueCode.custom,
|
|
444
482
|
path: ["failureReason"],
|
|
445
483
|
message: "failureReason is required when runOutcome is 'attempted-failed'"
|
|
446
484
|
});
|
|
447
485
|
}
|
|
448
486
|
if (rec.runOutcome !== "attempted-failed" && rec.failureReason !== void 0) {
|
|
449
487
|
ctx.addIssue({
|
|
450
|
-
code:
|
|
488
|
+
code: z4.ZodIssueCode.custom,
|
|
451
489
|
path: ["failureReason"],
|
|
452
490
|
message: "failureReason is only present when runOutcome is 'attempted-failed'"
|
|
453
491
|
});
|
|
454
492
|
}
|
|
455
493
|
const issue = outcomeReasonIssue(rec.runOutcome, rec.outcomeReason);
|
|
456
494
|
if (issue) {
|
|
457
|
-
ctx.addIssue({ code:
|
|
495
|
+
ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
|
|
458
496
|
}
|
|
459
497
|
});
|
|
460
498
|
var gateRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
461
|
-
recordKind:
|
|
499
|
+
recordKind: z4.literal("gate"),
|
|
462
500
|
gateKind: gateKindSchema,
|
|
463
501
|
verdict: gateVerdictSchema,
|
|
464
|
-
actor:
|
|
465
|
-
outcomeReason:
|
|
466
|
-
coverage: coverageSchema.optional()
|
|
502
|
+
actor: z4.string(),
|
|
503
|
+
outcomeReason: z4.string().max(2e3).optional(),
|
|
504
|
+
coverage: coverageSchema.optional(),
|
|
505
|
+
// Who did the step this checkpoint is on, as reported. Absent when not reported.
|
|
506
|
+
agent: agentNameSchema.optional(),
|
|
507
|
+
// When that step, or the review this checkpoint closes, began. Absent when not
|
|
508
|
+
// reported.
|
|
509
|
+
startedAt: utcIso8601.optional()
|
|
467
510
|
}).strict().superRefine((rec, ctx) => {
|
|
468
511
|
const issue = outcomeReasonIssue(rec.verdict, rec.outcomeReason);
|
|
469
512
|
if (issue) {
|
|
470
|
-
ctx.addIssue({ code:
|
|
513
|
+
ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
|
|
471
514
|
}
|
|
472
515
|
});
|
|
473
516
|
var interventionRecordSchema = stateRecordEnvelopeSchema.extend({
|
|
474
|
-
recordKind:
|
|
517
|
+
recordKind: z4.literal("intervention"),
|
|
475
518
|
layer: methodLayerSchema,
|
|
476
519
|
mechanism: mechanismSchema,
|
|
477
520
|
severity: severitySchema,
|
|
478
521
|
disposition: dispositionSchema,
|
|
479
|
-
summary:
|
|
480
|
-
coverage: coverageSchema.optional()
|
|
522
|
+
summary: z4.string().max(2e3),
|
|
523
|
+
coverage: coverageSchema.optional(),
|
|
524
|
+
// Who caught it, as the session reported. Absent when not reported.
|
|
525
|
+
agent: agentNameSchema.optional()
|
|
481
526
|
}).strict();
|
|
482
|
-
var stateRecordSchema =
|
|
527
|
+
var stateRecordSchema = z4.discriminatedUnion("recordKind", [
|
|
483
528
|
artefactRecordSchema,
|
|
484
529
|
stepRunRecordSchema,
|
|
485
530
|
gateRecordSchema,
|
|
@@ -487,7 +532,7 @@ var stateRecordSchema = z3.discriminatedUnion("recordKind", [
|
|
|
487
532
|
]);
|
|
488
533
|
|
|
489
534
|
// ../events/dist/build-record.js
|
|
490
|
-
import { z as
|
|
535
|
+
import { z as z5 } from "zod";
|
|
491
536
|
|
|
492
537
|
// ../events/dist/control-characters.js
|
|
493
538
|
var CONTROL_CHARACTER_CLASS = "\\p{Cc}";
|
|
@@ -577,11 +622,16 @@ var ACTOR_MAX = 200;
|
|
|
577
622
|
var FINDING_MAX = 500;
|
|
578
623
|
var FINDINGS_SHOWN_MAX = 50;
|
|
579
624
|
var PHASE_CLOSE_REASON_MAX = 1900;
|
|
580
|
-
var closeCommitSchema =
|
|
581
|
-
var walkVerdictSchema =
|
|
582
|
-
var
|
|
625
|
+
var closeCommitSchema = z5.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/, "must be a full commit hash: 40 or 64 lowercase hex characters");
|
|
626
|
+
var walkVerdictSchema = z5.enum(["clean", "defects"]);
|
|
627
|
+
var acceptanceOutcomeSchema = z5.object({
|
|
628
|
+
verdict: walkVerdictSchema,
|
|
629
|
+
findings: z5.number().int().nonnegative(),
|
|
630
|
+
findingsDetail: z5.array(z5.object({ summary: z5.string().refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE }) }).strict())
|
|
631
|
+
}).strict();
|
|
632
|
+
var closeDecisionSchema = z5.enum(["done-when-met", "override"]);
|
|
583
633
|
function plainText(max) {
|
|
584
|
-
const base = max === void 0 ?
|
|
634
|
+
const base = max === void 0 ? z5.string() : z5.string().max(max);
|
|
585
635
|
return base.refine((v) => !hasControlCharacter(v), {
|
|
586
636
|
message: "must be one line with no control characters (no line breaks, tabs or NUL)"
|
|
587
637
|
}).refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE });
|
|
@@ -593,81 +643,81 @@ function statementText(max) {
|
|
|
593
643
|
}
|
|
594
644
|
var closeActorSchema = plainText(ACTOR_MAX);
|
|
595
645
|
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`;
|
|
596
|
-
var phaseNameSchema =
|
|
646
|
+
var phaseNameSchema = z5.string().refine((v) => isValidPhaseIdentity(v), {
|
|
597
647
|
message: PHASE_NAME_RULE
|
|
598
648
|
});
|
|
599
|
-
var phaseIdentitySchema =
|
|
600
|
-
var closeStatementsSchema =
|
|
649
|
+
var phaseIdentitySchema = z5.union([z5.string(), z5.number()], { error: "must be a phase name or a whole number" }).refine((v) => isValidPhaseIdentity(v), { message: PHASE_NAME_RULE });
|
|
650
|
+
var closeStatementsSchema = z5.object({
|
|
601
651
|
thesis: statementText(STATEMENT_MAX).nullable(),
|
|
602
652
|
outcome: statementText(STATEMENT_MAX).nullable(),
|
|
603
|
-
deviations:
|
|
653
|
+
deviations: z5.array(statementText(DEVIATION_MAX)).max(DEVIATIONS_MAX),
|
|
604
654
|
closeCommit: closeCommitSchema.nullable()
|
|
605
655
|
}).strict();
|
|
606
|
-
var closedBySchema =
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
656
|
+
var closedBySchema = z5.discriminatedUnion("kind", [
|
|
657
|
+
z5.object({ kind: z5.literal("account"), email: plainText().nullable() }).strict(),
|
|
658
|
+
z5.object({ kind: z5.literal("no-account") }).strict(),
|
|
659
|
+
z5.object({ kind: z5.literal("account-removed") }).strict(),
|
|
660
|
+
z5.object({ kind: z5.literal("not-recorded") }).strict()
|
|
611
661
|
]);
|
|
612
662
|
var STEP_NAME_MAX = 200;
|
|
613
663
|
var stepNameSchema = plainText(STEP_NAME_MAX).refine((v) => v.trim().length > 0, {
|
|
614
664
|
message: "must not be blank"
|
|
615
665
|
});
|
|
616
|
-
var unfinishedStepSchema =
|
|
666
|
+
var unfinishedStepSchema = z5.object({
|
|
617
667
|
stepId: plainText(),
|
|
618
|
-
state:
|
|
668
|
+
state: z5.enum(["parked", "failed"]),
|
|
619
669
|
name: stepNameSchema.optional()
|
|
620
670
|
}).strict();
|
|
621
|
-
var crossedSchema =
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
671
|
+
var crossedSchema = z5.discriminatedUnion("kind", [
|
|
672
|
+
z5.object({ kind: z5.literal("none") }).strict(),
|
|
673
|
+
z5.object({ kind: z5.literal("unfinished-steps"), steps: z5.array(unfinishedStepSchema).min(1) }).strict(),
|
|
674
|
+
z5.object({ kind: z5.literal("clean-over-findings"), findings: z5.number().int().min(1) }).strict(),
|
|
675
|
+
z5.object({ kind: z5.literal("not-recorded") }).strict()
|
|
626
676
|
]);
|
|
627
|
-
var seatCoverageSchema =
|
|
628
|
-
enrolled:
|
|
629
|
-
conformant:
|
|
677
|
+
var seatCoverageSchema = z5.object({
|
|
678
|
+
enrolled: z5.number().int().nonnegative(),
|
|
679
|
+
conformant: z5.number().int().nonnegative()
|
|
630
680
|
}).strict().refine((c) => c.conformant <= c.enrolled, {
|
|
631
681
|
message: "conformant cannot exceed enrolled",
|
|
632
682
|
path: ["conformant"]
|
|
633
683
|
});
|
|
634
|
-
var observedCloseSchema =
|
|
635
|
-
sequence:
|
|
684
|
+
var observedCloseSchema = z5.object({
|
|
685
|
+
sequence: z5.number().int().min(1),
|
|
636
686
|
closedAt: utcIso8601,
|
|
637
687
|
closedBy: closedBySchema,
|
|
638
688
|
crossed: crossedSchema,
|
|
639
689
|
seatCoverage: seatCoverageSchema.nullable()
|
|
640
690
|
}).strict();
|
|
641
|
-
var couldNotRunCheckSchema =
|
|
691
|
+
var couldNotRunCheckSchema = z5.object({
|
|
642
692
|
check: plainText(),
|
|
643
693
|
description: plainText().nullable(),
|
|
644
694
|
reason: plainText()
|
|
645
695
|
}).strict();
|
|
646
|
-
var firedCheckSchema =
|
|
696
|
+
var firedCheckSchema = z5.object({
|
|
647
697
|
check: plainText(),
|
|
648
698
|
description: plainText().nullable(),
|
|
649
699
|
severity: severitySchema,
|
|
650
700
|
explanation: plainText().nullable(),
|
|
651
|
-
occurrences:
|
|
701
|
+
occurrences: z5.number().int().min(1)
|
|
652
702
|
}).strict();
|
|
653
|
-
var phaseChecksSchema =
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
state:
|
|
657
|
-
runs:
|
|
658
|
-
couldNotRun:
|
|
703
|
+
var phaseChecksSchema = z5.discriminatedUnion("state", [
|
|
704
|
+
z5.object({ state: z5.literal("not-observed") }).strict(),
|
|
705
|
+
z5.object({
|
|
706
|
+
state: z5.literal("nothing-fired"),
|
|
707
|
+
runs: z5.number().int().min(1),
|
|
708
|
+
couldNotRun: z5.array(couldNotRunCheckSchema)
|
|
659
709
|
}).strict(),
|
|
660
|
-
|
|
661
|
-
state:
|
|
662
|
-
runs:
|
|
663
|
-
couldNotRun:
|
|
664
|
-
fired:
|
|
710
|
+
z5.object({
|
|
711
|
+
state: z5.literal("fired"),
|
|
712
|
+
runs: z5.number().int().min(1),
|
|
713
|
+
couldNotRun: z5.array(couldNotRunCheckSchema),
|
|
714
|
+
fired: z5.array(firedCheckSchema).min(1)
|
|
665
715
|
}).strict()
|
|
666
716
|
]);
|
|
667
|
-
var observedSchema =
|
|
717
|
+
var observedSchema = z5.object({
|
|
668
718
|
engagementId: plainText(),
|
|
669
719
|
methodVersion: methodVersionSchema,
|
|
670
|
-
closes:
|
|
720
|
+
closes: z5.array(observedCloseSchema).min(1),
|
|
671
721
|
checks: phaseChecksSchema
|
|
672
722
|
}).strict().superRefine((o, ctx) => {
|
|
673
723
|
o.closes.forEach((close, i) => {
|
|
@@ -680,18 +730,18 @@ var observedSchema = z4.object({
|
|
|
680
730
|
}
|
|
681
731
|
});
|
|
682
732
|
});
|
|
683
|
-
var attestedWalkSchema =
|
|
733
|
+
var attestedWalkSchema = z5.object({
|
|
684
734
|
verdict: walkVerdictSchema,
|
|
685
|
-
findings:
|
|
686
|
-
findingsNotShown:
|
|
735
|
+
findings: z5.array(plainText(FINDING_MAX)).max(FINDINGS_SHOWN_MAX),
|
|
736
|
+
findingsNotShown: z5.number().int().nonnegative()
|
|
687
737
|
}).strict();
|
|
688
|
-
var attestedStatementsSchema =
|
|
738
|
+
var attestedStatementsSchema = z5.object({
|
|
689
739
|
thesis: plainText(STATEMENT_MAX).nullable(),
|
|
690
740
|
outcome: plainText(STATEMENT_MAX).nullable(),
|
|
691
|
-
deviations:
|
|
741
|
+
deviations: z5.array(plainText(DEVIATION_MAX)).max(DEVIATIONS_MAX)
|
|
692
742
|
}).strict();
|
|
693
|
-
var attestedCloseSchema =
|
|
694
|
-
sequence:
|
|
743
|
+
var attestedCloseSchema = z5.object({
|
|
744
|
+
sequence: z5.number().int().min(1),
|
|
695
745
|
decision: closeDecisionSchema,
|
|
696
746
|
actor: plainText(ACTOR_MAX).nullable(),
|
|
697
747
|
reason: plainText(PHASE_CLOSE_REASON_MAX).nullable(),
|
|
@@ -699,15 +749,10 @@ var attestedCloseSchema = z4.object({
|
|
|
699
749
|
closeCommit: closeCommitSchema.nullable(),
|
|
700
750
|
statements: attestedStatementsSchema
|
|
701
751
|
}).strict();
|
|
702
|
-
var attestedSchema =
|
|
703
|
-
closes:
|
|
752
|
+
var attestedSchema = z5.object({
|
|
753
|
+
closes: z5.array(attestedCloseSchema)
|
|
704
754
|
}).strict();
|
|
705
|
-
|
|
706
|
-
format: z4.literal(BUILD_RECORD_V2_FORMAT),
|
|
707
|
-
phase: phaseNameSchema,
|
|
708
|
-
observed: observedSchema,
|
|
709
|
-
attested: attestedSchema
|
|
710
|
-
}).strict().superRefine((record2, ctx) => {
|
|
755
|
+
function checkRecordHalves(record2, ctx) {
|
|
711
756
|
const observedBySequence = new Map(record2.observed.closes.map((c) => [c.sequence, c]));
|
|
712
757
|
const attestedSequences = record2.attested.closes.map((c) => c.sequence);
|
|
713
758
|
const sameSet = attestedSequences.length === observedBySequence.size && new Set(attestedSequences).size === attestedSequences.length && attestedSequences.every((s) => observedBySequence.has(s));
|
|
@@ -735,18 +780,24 @@ var buildRecordV2Schema = z4.object({
|
|
|
735
780
|
});
|
|
736
781
|
}
|
|
737
782
|
});
|
|
738
|
-
}
|
|
783
|
+
}
|
|
784
|
+
var buildRecordV2Schema = z5.object({
|
|
785
|
+
format: z5.literal(BUILD_RECORD_V2_FORMAT),
|
|
786
|
+
phase: phaseNameSchema,
|
|
787
|
+
observed: observedSchema,
|
|
788
|
+
attested: attestedSchema
|
|
789
|
+
}).strict().superRefine(checkRecordHalves);
|
|
739
790
|
|
|
740
791
|
// ../events/dist/crew.js
|
|
741
|
-
import { z as
|
|
742
|
-
var crewGroupSchema =
|
|
743
|
-
var crewTierSchema =
|
|
792
|
+
import { z as z6 } from "zod";
|
|
793
|
+
var crewGroupSchema = z6.enum(["builder", "reviewer", "always-on"]);
|
|
794
|
+
var crewTierSchema = z6.enum(["deep", "standard", "fast"]);
|
|
744
795
|
var CREW_DISCIPLINE_MAX = 64;
|
|
745
|
-
var crewFaceHeadSchema =
|
|
746
|
-
var crewFaceAntennaSchema =
|
|
747
|
-
var crewFaceEyesSchema =
|
|
748
|
-
var crewFaceMouthSchema =
|
|
749
|
-
var crewFaceSchema =
|
|
796
|
+
var crewFaceHeadSchema = z6.enum(["sq", "sqr", "rnd", "dome", "hex"]);
|
|
797
|
+
var crewFaceAntennaSchema = z6.enum(["none", "stalk", "twin", "dish"]);
|
|
798
|
+
var crewFaceEyesSchema = z6.enum(["dots", "bars", "visor", "cyclops"]);
|
|
799
|
+
var crewFaceMouthSchema = z6.enum(["line", "grid", "dots", "wave"]);
|
|
800
|
+
var crewFaceSchema = z6.object({
|
|
750
801
|
// The outline of the head. Members who do the same kind of work share one, so a
|
|
751
802
|
// team is recognisable before any name is read.
|
|
752
803
|
head: crewFaceHeadSchema,
|
|
@@ -757,17 +808,17 @@ var crewFaceSchema = z5.object({
|
|
|
757
808
|
// The mouth.
|
|
758
809
|
mouth: crewFaceMouthSchema,
|
|
759
810
|
// Whether this member is drawn with ears.
|
|
760
|
-
ears:
|
|
811
|
+
ears: z6.boolean()
|
|
761
812
|
}).strict();
|
|
762
|
-
var crewMemberSchema =
|
|
813
|
+
var crewMemberSchema = z6.object({
|
|
763
814
|
// The agent's name. The same twenty-one on every project, so a name is a
|
|
764
815
|
// vocabulary a returning client already knows.
|
|
765
|
-
callsign:
|
|
816
|
+
callsign: z6.string().min(1).max(32),
|
|
766
817
|
// Which of the three headings this member reads under.
|
|
767
818
|
group: crewGroupSchema,
|
|
768
819
|
// The kind of work this member takes. A task names a discipline, and only
|
|
769
820
|
// agents holding it can be dispatched to it.
|
|
770
|
-
discipline:
|
|
821
|
+
discipline: z6.string().min(1).max(CREW_DISCIPLINE_MAX),
|
|
771
822
|
// How much thinking this member brings. There is no field naming the supplier
|
|
772
823
|
// behind it, on this shape or on any other.
|
|
773
824
|
tier: crewTierSchema,
|
|
@@ -930,10 +981,1199 @@ var CREW_ROSTER = [
|
|
|
930
981
|
];
|
|
931
982
|
var CREW_ROSTER_SIZE = CREW_ROSTER.length;
|
|
932
983
|
var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
|
|
984
|
+
var crewRoleSchema = z6.enum([
|
|
985
|
+
"business-analyst",
|
|
986
|
+
"architect",
|
|
987
|
+
"spec-writer",
|
|
988
|
+
"builder",
|
|
989
|
+
"context-docs",
|
|
990
|
+
"spec-reviewer",
|
|
991
|
+
"code-test-reviewer",
|
|
992
|
+
"delivery-lead",
|
|
993
|
+
"quality-lead"
|
|
994
|
+
]);
|
|
995
|
+
var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
|
|
996
|
+
var crewRoleLayersSchema = z6.object({
|
|
997
|
+
leads: z6.array(crewLayerSchema),
|
|
998
|
+
helps: z6.array(crewLayerSchema)
|
|
999
|
+
}).strict();
|
|
1000
|
+
|
|
1001
|
+
// ../events/dist/build-snapshot.js
|
|
1002
|
+
import { z as z8 } from "zod";
|
|
1003
|
+
|
|
1004
|
+
// ../events/dist/system-description.js
|
|
1005
|
+
import { z as z7 } from "zod";
|
|
1006
|
+
var SYSTEM_DESCRIPTION_FORMAT = 1;
|
|
1007
|
+
var SYSTEM_PARTS_MAX = 60;
|
|
1008
|
+
var SYSTEM_CONNECTIONS_MAX = 400;
|
|
1009
|
+
var SYSTEM_SLOT_MAX = 11;
|
|
1010
|
+
var SYSTEM_OWNS_MAX = 20;
|
|
1011
|
+
var SYSTEM_OWNED_PATTERN_MAX = 200;
|
|
1012
|
+
var SYSTEM_PART_NAME_MAX = 60;
|
|
1013
|
+
var SYSTEM_PART_DESCRIPTION_MAX = 160;
|
|
1014
|
+
var SYSTEM_CONNECTION_LABEL_MAX = 60;
|
|
1015
|
+
var SYSTEM_PART_ID_PATTERN = /^[a-z][a-z0-9-]{0,39}$/;
|
|
1016
|
+
var SYSTEM_LANES = ["clients", "edge", "services", "data", "external"];
|
|
1017
|
+
var systemLaneSchema = z7.enum(SYSTEM_LANES, {
|
|
1018
|
+
error: `must be one of ${SYSTEM_LANES.join(", ")}`
|
|
1019
|
+
});
|
|
1020
|
+
var SYSTEM_CONNECTION_KINDS = ["call", "event", "write", "external"];
|
|
1021
|
+
var systemConnectionKindSchema = z7.enum(SYSTEM_CONNECTION_KINDS, {
|
|
1022
|
+
error: `must be one of ${SYSTEM_CONNECTION_KINDS.join(", ")}`
|
|
1023
|
+
});
|
|
1024
|
+
var LINE_SEPARATOR = /[\u2028\u2029]/;
|
|
1025
|
+
function descriptionText(max) {
|
|
1026
|
+
return statementText(max).refine((v) => v.trim().length > 0, { message: "must not be empty or only spaces" }).refine((v) => !LINE_SEPARATOR.test(v), {
|
|
1027
|
+
message: "must be one line: it holds a line or paragraph separator"
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
var systemPartIdSchema = z7.string().regex(SYSTEM_PART_ID_PATTERN, {
|
|
1031
|
+
message: "must be a short id: a lowercase letter, then lowercase letters, digits or hyphens, 40 characters at most"
|
|
1032
|
+
}).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key; choose another id" });
|
|
1033
|
+
function hasEmptySegment(pattern) {
|
|
1034
|
+
return pattern.split("/").some((segment) => segment.length === 0);
|
|
1035
|
+
}
|
|
1036
|
+
function hasDotSegment(pattern) {
|
|
1037
|
+
return pattern.split("/").some((segment) => segment === "." || segment === "..");
|
|
1038
|
+
}
|
|
1039
|
+
function hasPartialDoubleStar(pattern) {
|
|
1040
|
+
return pattern.split("/").some((segment) => segment.includes("**") && segment !== "**");
|
|
1041
|
+
}
|
|
1042
|
+
var SEGMENT_CHARACTERS = /^[A-Za-z0-9._\-*]*$/;
|
|
1043
|
+
function hasForeignCharacter(pattern) {
|
|
1044
|
+
return pattern.split("/").some((segment) => !SEGMENT_CHARACTERS.test(segment));
|
|
1045
|
+
}
|
|
1046
|
+
var systemOwnedPatternSchema = z7.string().max(SYSTEM_OWNED_PATTERN_MAX, { message: `must be at most ${SYSTEM_OWNED_PATTERN_MAX} characters` }).refine((v) => !hasEmptySegment(v), {
|
|
1047
|
+
message: "must not start or end with a slash, or have two slashes together"
|
|
1048
|
+
}).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), {
|
|
1049
|
+
message: 'may use only letters, digits, ".", "_", "-" and "*" between slashes'
|
|
1050
|
+
}).refine((v) => !looksLikeSecret(v), {
|
|
1051
|
+
message: "this path looks like a credential; list a shorter folder above it"
|
|
1052
|
+
});
|
|
1053
|
+
var systemPartSchema = z7.object({
|
|
1054
|
+
id: systemPartIdSchema,
|
|
1055
|
+
name: descriptionText(SYSTEM_PART_NAME_MAX),
|
|
1056
|
+
description: descriptionText(SYSTEM_PART_DESCRIPTION_MAX),
|
|
1057
|
+
lane: systemLaneSchema,
|
|
1058
|
+
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}` }),
|
|
1059
|
+
outside: z7.boolean(),
|
|
1060
|
+
owns: z7.array(systemOwnedPatternSchema).max(SYSTEM_OWNS_MAX, { message: `can list at most ${SYSTEM_OWNS_MAX} paths` })
|
|
1061
|
+
}).strict();
|
|
1062
|
+
var systemConnectionSchema = z7.object({
|
|
1063
|
+
from: systemPartIdSchema,
|
|
1064
|
+
to: systemPartIdSchema,
|
|
1065
|
+
kind: systemConnectionKindSchema,
|
|
1066
|
+
label: descriptionText(SYSTEM_CONNECTION_LABEL_MAX)
|
|
1067
|
+
}).strict();
|
|
1068
|
+
var systemDescriptionSchema = z7.object({
|
|
1069
|
+
format: z7.literal(SYSTEM_DESCRIPTION_FORMAT, { error: `must be ${SYSTEM_DESCRIPTION_FORMAT}` }),
|
|
1070
|
+
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)` }),
|
|
1071
|
+
connections: z7.array(systemConnectionSchema).max(SYSTEM_CONNECTIONS_MAX, { message: `can hold at most ${SYSTEM_CONNECTIONS_MAX} connections` })
|
|
1072
|
+
}).strict();
|
|
1073
|
+
var systemDescriptionProblemSchema = z7.object({
|
|
1074
|
+
path: z7.string(),
|
|
1075
|
+
message: z7.string()
|
|
1076
|
+
}).strict();
|
|
1077
|
+
var systemReportRecordedSchema = z7.object({
|
|
1078
|
+
outcome: z7.literal("recorded"),
|
|
1079
|
+
version: z7.number().int().min(1),
|
|
1080
|
+
reportedAt: utcIso8601
|
|
1081
|
+
}).strict();
|
|
1082
|
+
var systemReportRefusedSchema = z7.object({
|
|
1083
|
+
outcome: z7.literal("refused"),
|
|
1084
|
+
problems: z7.array(systemDescriptionProblemSchema).min(1)
|
|
1085
|
+
}).strict();
|
|
1086
|
+
var systemReportUnavailableSchema = z7.object({
|
|
1087
|
+
outcome: z7.literal("unavailable")
|
|
1088
|
+
}).strict();
|
|
1089
|
+
var systemReportResultSchema = z7.discriminatedUnion("outcome", [
|
|
1090
|
+
systemReportRecordedSchema,
|
|
1091
|
+
systemReportRefusedSchema,
|
|
1092
|
+
systemReportUnavailableSchema
|
|
1093
|
+
]);
|
|
1094
|
+
var SYSTEM_DRAW_SVG_MAX_BYTES = 2 * 1024 * 1024;
|
|
1095
|
+
var SYSTEM_DRAW_MERMAID_MAX_BYTES = 256 * 1024;
|
|
1096
|
+
var SYSTEM_DRAW_PNG_MAX_BYTES = 8 * 1024 * 1024;
|
|
1097
|
+
var systemDrawArchitectureRequestSchema = z7.object({
|
|
1098
|
+
picture: z7.literal("architecture"),
|
|
1099
|
+
version: z7.number().int().min(1)
|
|
1100
|
+
}).strict();
|
|
1101
|
+
var systemDrawPhaseRequestSchema = z7.object({
|
|
1102
|
+
picture: z7.literal("phase"),
|
|
1103
|
+
phase: phaseIdentitySchema,
|
|
1104
|
+
planVersion: z7.number().int().min(1)
|
|
1105
|
+
}).strict();
|
|
1106
|
+
var systemDrawClosedPhaseRequestSchema = z7.object({
|
|
1107
|
+
picture: z7.literal("closed-phase"),
|
|
1108
|
+
phase: phaseIdentitySchema
|
|
1109
|
+
}).strict();
|
|
1110
|
+
var systemDrawRequestSchema = z7.discriminatedUnion("picture", [
|
|
1111
|
+
systemDrawArchitectureRequestSchema,
|
|
1112
|
+
systemDrawPhaseRequestSchema,
|
|
1113
|
+
systemDrawClosedPhaseRequestSchema
|
|
1114
|
+
]);
|
|
1115
|
+
function utf8ByteLength2(text) {
|
|
1116
|
+
let bytes = 0;
|
|
1117
|
+
for (let i = 0; i < text.length; i++) {
|
|
1118
|
+
const unit = text.charCodeAt(i);
|
|
1119
|
+
if (unit < 128)
|
|
1120
|
+
bytes += 1;
|
|
1121
|
+
else if (unit < 2048)
|
|
1122
|
+
bytes += 2;
|
|
1123
|
+
else if (unit >= 55296 && unit <= 56319 && i + 1 < text.length) {
|
|
1124
|
+
const next = text.charCodeAt(i + 1);
|
|
1125
|
+
if (next >= 56320 && next <= 57343) {
|
|
1126
|
+
bytes += 4;
|
|
1127
|
+
i++;
|
|
1128
|
+
} else {
|
|
1129
|
+
bytes += 3;
|
|
1130
|
+
}
|
|
1131
|
+
} else
|
|
1132
|
+
bytes += 3;
|
|
1133
|
+
}
|
|
1134
|
+
return bytes;
|
|
1135
|
+
}
|
|
1136
|
+
var BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
1137
|
+
function base64DecodedLength(text) {
|
|
1138
|
+
const padding = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
|
|
1139
|
+
return text.length / 4 * 3 - padding;
|
|
1140
|
+
}
|
|
1141
|
+
var systemPictureSchema = z7.object({
|
|
1142
|
+
svg: z7.string().min(1).refine((v) => utf8ByteLength2(v) <= SYSTEM_DRAW_SVG_MAX_BYTES, { message: "the picture is larger than 2 MB" }),
|
|
1143
|
+
png: z7.string().min(1).refine((v) => v.length % 4 === 0 && BASE64.test(v), { message: "the image is not valid base64" }).refine((v) => base64DecodedLength(v) <= SYSTEM_DRAW_PNG_MAX_BYTES, { message: "the image is larger than 8 MB" })
|
|
1144
|
+
}).strict();
|
|
1145
|
+
var systemDrawRefusedSchema = z7.object({
|
|
1146
|
+
outcome: z7.literal("refused"),
|
|
1147
|
+
reason: z7.string().min(1)
|
|
1148
|
+
}).strict();
|
|
1149
|
+
var systemDrawUnavailableSchema = z7.object({
|
|
1150
|
+
outcome: z7.literal("unavailable")
|
|
1151
|
+
}).strict();
|
|
1152
|
+
var systemDrawNotClosedSchema = z7.object({
|
|
1153
|
+
outcome: z7.literal("not-closed")
|
|
1154
|
+
}).strict();
|
|
1155
|
+
|
|
1156
|
+
// ../events/dist/build-snapshot.js
|
|
1157
|
+
var buildTaskStateSchema = z8.enum([
|
|
1158
|
+
"pending",
|
|
1159
|
+
"in-flight",
|
|
1160
|
+
"completed",
|
|
1161
|
+
"failed",
|
|
1162
|
+
"blocked"
|
|
1163
|
+
]);
|
|
1164
|
+
var BUILD_TASK_TITLE_MAX = 240;
|
|
1165
|
+
var BUILD_SNAPSHOT_TASK_LIMIT = 500;
|
|
1166
|
+
var BUILD_TASK_WHY_OUTSIDE_PLAN_MAX = 160;
|
|
1167
|
+
var BUILD_TASK_BUDGET_MAX_MINUTES = 10080;
|
|
1168
|
+
var BUILD_TASK_NOTE_MAX = 240;
|
|
1169
|
+
var BUILD_TASK_CLEAR_COMMAND_MAX = 240;
|
|
1170
|
+
var buildTaskKindSchema = z8.enum(["build", "review", "spec", "walk"]);
|
|
1171
|
+
var buildTaskIdSchema = z8.string().min(1).max(64);
|
|
1172
|
+
var buildTaskSchema = z8.object({
|
|
1173
|
+
// The task's own id, as the coordinator's graph names it.
|
|
1174
|
+
id: buildTaskIdSchema,
|
|
1175
|
+
// What the task is, in the coordinator's words. A description of the work,
|
|
1176
|
+
// bounded and scanned — never an excerpt of anybody's code.
|
|
1177
|
+
title: z8.string().min(1).max(BUILD_TASK_TITLE_MAX),
|
|
1178
|
+
// What the task is doing right now.
|
|
1179
|
+
state: buildTaskStateSchema,
|
|
1180
|
+
// Who holds it — a bare callsign, or the value naming a person when the work is
|
|
1181
|
+
// a person's. Absent when nothing has been dispatched to it yet.
|
|
1182
|
+
agent: agentNameSchema.optional(),
|
|
1183
|
+
// The kind of work the holder does. Present exactly when an agent holds it.
|
|
1184
|
+
discipline: z8.string().min(1).max(64).optional(),
|
|
1185
|
+
// How much thinking the holder brings. Present exactly when an agent holds it,
|
|
1186
|
+
// and there is no field naming the supplier behind it.
|
|
1187
|
+
tier: z8.string().min(1).max(32).optional(),
|
|
1188
|
+
// The tasks this one cannot start before. Always present; empty means it waits
|
|
1189
|
+
// on nothing, which is different from not having been computed.
|
|
1190
|
+
dependsOn: z8.array(buildTaskIdSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
1191
|
+
// The one task this task checks, when it is a check on other work. Absent on a
|
|
1192
|
+
// task that is doing the work rather than checking it.
|
|
1193
|
+
reviews: buildTaskIdSchema.optional(),
|
|
1194
|
+
// Which wave of the phase this task belongs to — the wave that writes the
|
|
1195
|
+
// specifications, or the wave that builds them. Absent when the graph does not
|
|
1196
|
+
// record it, which is different from the task belonging to neither.
|
|
1197
|
+
layer: methodLayerSchema.optional(),
|
|
1198
|
+
// When it was picked up, and when it settled. A reader computes how long it
|
|
1199
|
+
// took; neither this row nor this payload carries a duration.
|
|
1200
|
+
startedAt: utcIso8601.optional(),
|
|
1201
|
+
settledAt: utcIso8601.optional(),
|
|
1202
|
+
// The parts of this project's system the task builds, by their ids. Absent when
|
|
1203
|
+
// it builds none; never an empty list.
|
|
1204
|
+
builds: z8.array(systemPartIdSchema).min(1).max(SYSTEM_PARTS_MAX).optional(),
|
|
1205
|
+
// In one line, why the task built a part the phase's plan does not include, in
|
|
1206
|
+
// the words of whoever holds it. Absent when it gave no reason.
|
|
1207
|
+
whyOutsidePlan: descriptionText(BUILD_TASK_WHY_OUTSIDE_PLAN_MAX).optional(),
|
|
1208
|
+
// How long the task is expected to take, in whole minutes, from one minute to one
|
|
1209
|
+
// week. A plan, not a measurement; absent when no budget was set.
|
|
1210
|
+
budgetMinutes: z8.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
|
|
1211
|
+
// What kind of work the task is: building, checking other work, writing what to
|
|
1212
|
+
// build, or a person trying the product. Absent when the graph does not say.
|
|
1213
|
+
kind: buildTaskKindSchema.optional(),
|
|
1214
|
+
// One line from whoever holds the task about where it stands. Absent when there
|
|
1215
|
+
// is nothing to say.
|
|
1216
|
+
note: descriptionText(BUILD_TASK_NOTE_MAX).optional(),
|
|
1217
|
+
// On a task held for a person, the one thing they do or run to clear it, in one
|
|
1218
|
+
// line. Absent when the task names none.
|
|
1219
|
+
clearCommand: descriptionText(BUILD_TASK_CLEAR_COMMAND_MAX).optional(),
|
|
1220
|
+
// On a task held for a person, the crew member ready to take it on once it is
|
|
1221
|
+
// cleared, by callsign. Absent when nobody is standing by.
|
|
1222
|
+
standingBy: agentNameSchema.optional()
|
|
1223
|
+
}).strict().superRefine((task, ctx) => {
|
|
1224
|
+
if (task.reviews !== void 0 && task.reviews === task.id) {
|
|
1225
|
+
ctx.addIssue({
|
|
1226
|
+
code: z8.ZodIssueCode.custom,
|
|
1227
|
+
path: ["reviews"],
|
|
1228
|
+
message: `'${task.id}' reviews itself \u2014 a review names the OTHER task it checks.`
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
if (task.layer !== void 0 && !isPhaseScopedLayer(task.layer)) {
|
|
1232
|
+
ctx.addIssue({
|
|
1233
|
+
code: z8.ZodIssueCode.custom,
|
|
1234
|
+
path: ["layer"],
|
|
1235
|
+
message: `'${task.layer}' is not a wave a phase runs \u2014 expected one of ${PHASE_SCOPED_LAYERS.join(", ")}.`
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
const profiled = task.agent !== void 0 && task.agent !== HUMAN_AGENT;
|
|
1239
|
+
for (const field of ["discipline", "tier"]) {
|
|
1240
|
+
if (profiled && task[field] === void 0) {
|
|
1241
|
+
ctx.addIssue({
|
|
1242
|
+
code: z8.ZodIssueCode.custom,
|
|
1243
|
+
path: [field],
|
|
1244
|
+
message: `'${field}' is required on a task an agent holds.`
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
if (!profiled && task[field] !== void 0) {
|
|
1248
|
+
ctx.addIssue({
|
|
1249
|
+
code: z8.ZodIssueCode.custom,
|
|
1250
|
+
path: [field],
|
|
1251
|
+
message: task.agent === void 0 ? `'${field}' must be absent on a task nobody holds.` : `'${field}' must be absent on work a person holds.`
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
var buildPhaseSchema = z8.string().min(1).max(128);
|
|
1257
|
+
var BUILD_PHASE_TITLE_MAX = 160;
|
|
1258
|
+
var buildPhaseTitleSchema = z8.string().min(1).max(BUILD_PHASE_TITLE_MAX);
|
|
1259
|
+
var buildTaskListSchema = z8.array(buildTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT).superRefine((tasks, ctx) => {
|
|
1260
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1261
|
+
for (const [index, task] of tasks.entries()) {
|
|
1262
|
+
if (seen.has(task.id)) {
|
|
1263
|
+
ctx.addIssue({
|
|
1264
|
+
code: z8.ZodIssueCode.custom,
|
|
1265
|
+
path: [index, "id"],
|
|
1266
|
+
message: `duplicate task id '${task.id}' \u2014 one graph names each task once.`
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
seen.add(task.id);
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
var buildTaskMarkSchema = z8.object({
|
|
1273
|
+
// The task that was marked.
|
|
1274
|
+
task: buildTaskIdSchema,
|
|
1275
|
+
// When it was first marked.
|
|
1276
|
+
at: utcIso8601
|
|
1277
|
+
}).strict();
|
|
1278
|
+
var buildSnapshotSchema = z8.object({
|
|
1279
|
+
// Which phase this graph belongs to.
|
|
1280
|
+
phase: buildPhaseSchema,
|
|
1281
|
+
// That phase's name in words, when the project gives it one.
|
|
1282
|
+
phaseTitle: buildPhaseTitleSchema.optional(),
|
|
1283
|
+
// Every task on it. Never a partial graph and never a change since last time.
|
|
1284
|
+
tasks: buildTaskListSchema,
|
|
1285
|
+
// When this graph was last reported.
|
|
1286
|
+
reportedAt: utcIso8601,
|
|
1287
|
+
// When work on this phase was first reported with no approval of its scope in force.
|
|
1288
|
+
builtWithoutApproval: utcIso8601.optional(),
|
|
1289
|
+
// Each task that started on a part still waiting for approval, and when it was
|
|
1290
|
+
// first seen doing so. Absent when there is none.
|
|
1291
|
+
tasksBuiltWithoutApproval: z8.array(buildTaskMarkSchema).min(1).max(BUILD_SNAPSHOT_TASK_LIMIT).optional()
|
|
1292
|
+
}).strict();
|
|
1293
|
+
var buildPhaseEntrySchema = z8.object({
|
|
1294
|
+
// Which phase has a stored graph.
|
|
1295
|
+
phase: buildPhaseSchema,
|
|
1296
|
+
// That phase's name in words, when the project gave it one.
|
|
1297
|
+
phaseTitle: buildPhaseTitleSchema.optional(),
|
|
1298
|
+
// When that phase's graph was last reported.
|
|
1299
|
+
reportedAt: utcIso8601,
|
|
1300
|
+
// Present when work on this phase was reported with no approval of its scope in force.
|
|
1301
|
+
builtWithoutApproval: z8.literal(true).optional()
|
|
1302
|
+
}).strict();
|
|
1303
|
+
var buildSnapshotReportSchema = z8.object({
|
|
1304
|
+
// Which phase this graph belongs to.
|
|
1305
|
+
phase: buildPhaseSchema,
|
|
1306
|
+
// That phase's name in words, when the project gives it one.
|
|
1307
|
+
phaseTitle: buildPhaseTitleSchema.optional(),
|
|
1308
|
+
// The whole graph, every time. Reporting a change instead of the graph is the
|
|
1309
|
+
// one thing this route does not accept.
|
|
1310
|
+
tasks: buildTaskListSchema
|
|
1311
|
+
}).strict();
|
|
1312
|
+
var buildSnapshotReportResultSchema = z8.object({
|
|
1313
|
+
// What happened. One outcome today; a refusal travels as the shared wire error.
|
|
1314
|
+
outcome: z8.literal("recorded"),
|
|
1315
|
+
// Which phase the graph was recorded against.
|
|
1316
|
+
phase: buildPhaseSchema,
|
|
1317
|
+
// When it was recorded.
|
|
1318
|
+
reportedAt: utcIso8601
|
|
1319
|
+
}).strict();
|
|
1320
|
+
|
|
1321
|
+
// ../events/dist/phase-plan.js
|
|
1322
|
+
import { z as z9 } from "zod";
|
|
1323
|
+
var PHASE_PLAN_FORMAT = 1;
|
|
1324
|
+
var PHASE_PLAN_CHANGES_MAX = 60;
|
|
1325
|
+
var PHASE_PLAN_SUMMARY_MAX = 160;
|
|
1326
|
+
var SCOPE_NOTE_MAX = 500;
|
|
1327
|
+
var PHASE_PLAN_PHASE_MAX = buildPhaseSchema.maxLength ?? 0;
|
|
1328
|
+
var PHASE_PLAN_CHANGE_KINDS = ["add", "change", "remove"];
|
|
1329
|
+
var phasePlanChangeSchema = z9.enum(PHASE_PLAN_CHANGE_KINDS, {
|
|
1330
|
+
error: `must be one of ${PHASE_PLAN_CHANGE_KINDS.join(", ")}`
|
|
1331
|
+
});
|
|
1332
|
+
var phasePlanPhaseSchema = phaseIdentitySchema.refine((v) => !isValidPhaseIdentity(v) || buildPhaseSchema.safeParse(String(v)).success, { message: `must be at most ${PHASE_PLAN_PHASE_MAX} characters` });
|
|
1333
|
+
var phasePlanSummarySchema = descriptionText(PHASE_PLAN_SUMMARY_MAX);
|
|
1334
|
+
var phasePlanEntrySchema = z9.object({
|
|
1335
|
+
part: systemPartIdSchema,
|
|
1336
|
+
change: phasePlanChangeSchema,
|
|
1337
|
+
summary: phasePlanSummarySchema
|
|
1338
|
+
}).strict();
|
|
1339
|
+
var phasePlanSchema = z9.object({
|
|
1340
|
+
format: z9.literal(PHASE_PLAN_FORMAT, { error: `must be ${PHASE_PLAN_FORMAT}` }),
|
|
1341
|
+
phase: phasePlanPhaseSchema,
|
|
1342
|
+
changes: z9.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` })
|
|
1343
|
+
}).strict();
|
|
1344
|
+
var scopePhaseSchema = buildPhaseSchema.refine((v) => isValidPhaseIdentity(v), {
|
|
1345
|
+
message: "must be a phase name"
|
|
1346
|
+
});
|
|
1347
|
+
var SCOPE_STATE_NAMES = [
|
|
1348
|
+
"not-planned",
|
|
1349
|
+
"waiting",
|
|
1350
|
+
"sent-back",
|
|
1351
|
+
"approved",
|
|
1352
|
+
"partly-stale",
|
|
1353
|
+
"withdrawn"
|
|
1354
|
+
];
|
|
1355
|
+
var scopeStateNameSchema = z9.enum(SCOPE_STATE_NAMES);
|
|
1356
|
+
var plannedScopeStateSchema = scopeStateNameSchema.exclude(["not-planned"]);
|
|
1357
|
+
var SCOPE_PART_STATUSES = ["approved", "waiting"];
|
|
1358
|
+
var scopePartStatusSchema = z9.enum(SCOPE_PART_STATUSES);
|
|
1359
|
+
var SCOPE_ACTS = ["approve", "send-back", "withdraw"];
|
|
1360
|
+
var scopeActSchema = z9.enum(SCOPE_ACTS);
|
|
1361
|
+
var SCOPE_GIVEN_IN = ["console", "chat"];
|
|
1362
|
+
var scopeGivenInSchema = z9.enum(SCOPE_GIVEN_IN);
|
|
1363
|
+
var scopeNoteSchema = descriptionText(SCOPE_NOTE_MAX);
|
|
1364
|
+
var scopeNoteWireSchema = z9.string().max(SCOPE_NOTE_MAX);
|
|
1365
|
+
var SCOPE_PART_VERDICTS = ["ok", "change"];
|
|
1366
|
+
var scopePartVerdictSchema = z9.enum(SCOPE_PART_VERDICTS);
|
|
1367
|
+
var scopeDecisionPartSchema = z9.object({
|
|
1368
|
+
part: systemPartIdSchema,
|
|
1369
|
+
verdict: scopePartVerdictSchema,
|
|
1370
|
+
note: scopeNoteWireSchema.optional()
|
|
1371
|
+
}).strict();
|
|
1372
|
+
var planVersionSchema = z9.number().int().min(1);
|
|
1373
|
+
var carriedPhaseSchema = z9.object({
|
|
1374
|
+
phase: scopePhaseSchema,
|
|
1375
|
+
number: z9.number().int().min(1)
|
|
1376
|
+
}).strict();
|
|
1377
|
+
var carriedFromEntrySchema = carriedPhaseSchema.extend({
|
|
1378
|
+
part: systemPartIdSchema
|
|
1379
|
+
}).strict();
|
|
1380
|
+
var phasePlanRequestSchema = z9.object({
|
|
1381
|
+
descriptionVersion: z9.number().int().min(1),
|
|
1382
|
+
plan: z9.unknown()
|
|
1383
|
+
}).strict();
|
|
1384
|
+
var phasePlanRecordedSchema = z9.object({
|
|
1385
|
+
outcome: z9.literal("recorded"),
|
|
1386
|
+
version: planVersionSchema,
|
|
1387
|
+
phaseNumber: z9.number().int().min(1),
|
|
1388
|
+
state: plannedScopeStateSchema,
|
|
1389
|
+
changedParts: z9.array(systemPartIdSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1390
|
+
typedApprovalOffered: z9.boolean(),
|
|
1391
|
+
reportedAt: utcIso8601,
|
|
1392
|
+
carriedFrom: z9.array(carriedFromEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX).optional()
|
|
1393
|
+
}).strict();
|
|
1394
|
+
var phasePlanRefusedSchema = z9.object({
|
|
1395
|
+
outcome: z9.literal("refused"),
|
|
1396
|
+
problems: z9.array(systemDescriptionProblemSchema).min(1)
|
|
1397
|
+
}).strict();
|
|
1398
|
+
var phasePlanUnavailableSchema = z9.object({
|
|
1399
|
+
outcome: z9.literal("unavailable")
|
|
1400
|
+
}).strict();
|
|
1401
|
+
var REMOVAL_OWED_ACTS = ["dropped", "removed"];
|
|
1402
|
+
var removalOwedPartSchema = z9.object({
|
|
1403
|
+
part: systemPartIdSchema,
|
|
1404
|
+
name: systemPartSchema.shape.name,
|
|
1405
|
+
phase: scopePhaseSchema,
|
|
1406
|
+
number: z9.number().int().min(1),
|
|
1407
|
+
act: z9.enum(REMOVAL_OWED_ACTS)
|
|
1408
|
+
}).strict();
|
|
1409
|
+
var phasePlanRemovalOwedSchema = z9.object({
|
|
1410
|
+
outcome: z9.literal("removal-owed"),
|
|
1411
|
+
parts: z9.array(removalOwedPartSchema).min(1).max(SYSTEM_PARTS_MAX)
|
|
1412
|
+
}).strict();
|
|
1413
|
+
var phasePlanResultSchema = z9.discriminatedUnion("outcome", [
|
|
1414
|
+
phasePlanRecordedSchema,
|
|
1415
|
+
phasePlanRefusedSchema,
|
|
1416
|
+
phasePlanUnavailableSchema,
|
|
1417
|
+
phasePlanRemovalOwedSchema
|
|
1418
|
+
]);
|
|
1419
|
+
var scopeApproveRequestSchema = z9.object({
|
|
1420
|
+
act: z9.literal("approve"),
|
|
1421
|
+
planVersion: planVersionSchema,
|
|
1422
|
+
parts: z9.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX)
|
|
1423
|
+
}).strict();
|
|
1424
|
+
var scopeSendBackRequestSchema = z9.object({
|
|
1425
|
+
act: z9.literal("send-back"),
|
|
1426
|
+
planVersion: planVersionSchema,
|
|
1427
|
+
parts: z9.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1428
|
+
note: scopeNoteWireSchema.optional()
|
|
1429
|
+
}).strict();
|
|
1430
|
+
var scopeWithdrawRequestSchema = z9.object({
|
|
1431
|
+
act: z9.literal("withdraw"),
|
|
1432
|
+
planVersion: planVersionSchema
|
|
1433
|
+
}).strict();
|
|
1434
|
+
var scopeDecisionRequestSchema = z9.discriminatedUnion("act", [
|
|
1435
|
+
scopeApproveRequestSchema,
|
|
1436
|
+
scopeSendBackRequestSchema,
|
|
1437
|
+
scopeWithdrawRequestSchema
|
|
1438
|
+
]);
|
|
1439
|
+
var scopeDecisionRecordedSchema = z9.object({
|
|
1440
|
+
outcome: z9.literal("recorded"),
|
|
1441
|
+
act: scopeActSchema,
|
|
1442
|
+
phase: scopePhaseSchema,
|
|
1443
|
+
planVersion: planVersionSchema,
|
|
1444
|
+
state: plannedScopeStateSchema,
|
|
1445
|
+
decidedAt: utcIso8601
|
|
1446
|
+
}).strict();
|
|
1447
|
+
var scopeDecisionAlreadyApprovedSchema = z9.object({
|
|
1448
|
+
outcome: z9.literal("already-approved"),
|
|
1449
|
+
replanNeeded: z9.boolean(),
|
|
1450
|
+
reason: z9.string().min(1)
|
|
1451
|
+
}).strict();
|
|
1452
|
+
var scopeDecisionRefusedSchema = z9.object({
|
|
1453
|
+
outcome: z9.literal("refused"),
|
|
1454
|
+
problems: z9.array(systemDescriptionProblemSchema).min(1)
|
|
1455
|
+
}).strict();
|
|
1456
|
+
var scopeDecisionUnavailableSchema = z9.object({
|
|
1457
|
+
outcome: z9.literal("unavailable")
|
|
1458
|
+
}).strict();
|
|
1459
|
+
function reasonOutcome(outcome) {
|
|
1460
|
+
return z9.object({ outcome: z9.literal(outcome), reason: z9.string().min(1) }).strict();
|
|
1461
|
+
}
|
|
1462
|
+
var scopeDecisionResultSchema = z9.discriminatedUnion("outcome", [
|
|
1463
|
+
scopeDecisionRecordedSchema,
|
|
1464
|
+
scopeDecisionAlreadyApprovedSchema,
|
|
1465
|
+
scopeDecisionRefusedSchema,
|
|
1466
|
+
scopeDecisionUnavailableSchema,
|
|
1467
|
+
reasonOutcome("not-owner"),
|
|
1468
|
+
reasonOutcome("no-owner"),
|
|
1469
|
+
reasonOutcome("plan-changed"),
|
|
1470
|
+
reasonOutcome("nothing-to-withdraw"),
|
|
1471
|
+
reasonOutcome("build-started")
|
|
1472
|
+
]);
|
|
1473
|
+
var scopeReadPartSchema = z9.object({
|
|
1474
|
+
part: systemPartIdSchema,
|
|
1475
|
+
name: systemPartSchema.shape.name,
|
|
1476
|
+
change: phasePlanChangeSchema,
|
|
1477
|
+
summary: phasePlanSummarySchema,
|
|
1478
|
+
status: scopePartStatusSchema,
|
|
1479
|
+
changed: z9.boolean(),
|
|
1480
|
+
carriedFrom: carriedPhaseSchema.optional()
|
|
1481
|
+
}).strict();
|
|
1482
|
+
var scopeReadDecisionSchema = z9.object({
|
|
1483
|
+
act: scopeActSchema,
|
|
1484
|
+
planVersion: planVersionSchema,
|
|
1485
|
+
givenIn: scopeGivenInSchema,
|
|
1486
|
+
at: utcIso8601,
|
|
1487
|
+
parts: z9.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
1488
|
+
note: scopeNoteWireSchema.optional()
|
|
1489
|
+
}).strict();
|
|
1490
|
+
var scopeReadNotPlannedSchema = z9.object({
|
|
1491
|
+
phase: scopePhaseSchema,
|
|
1492
|
+
state: z9.literal("not-planned"),
|
|
1493
|
+
canDecide: z9.boolean()
|
|
1494
|
+
}).strict();
|
|
1495
|
+
var scopeReadPlannedSchema = z9.object({
|
|
1496
|
+
phase: scopePhaseSchema,
|
|
1497
|
+
state: plannedScopeStateSchema,
|
|
1498
|
+
phaseNumber: z9.number().int().min(1),
|
|
1499
|
+
planVersion: planVersionSchema,
|
|
1500
|
+
parts: z9.array(scopeReadPartSchema).min(1).max(PHASE_PLAN_CHANGES_MAX),
|
|
1501
|
+
decisions: z9.array(scopeReadDecisionSchema),
|
|
1502
|
+
canDecide: z9.boolean(),
|
|
1503
|
+
replanLine: z9.string().min(1).optional()
|
|
1504
|
+
}).strict();
|
|
1505
|
+
var scopeReadSchema = z9.union([scopeReadNotPlannedSchema, scopeReadPlannedSchema]);
|
|
1506
|
+
|
|
1507
|
+
// ../events/dist/build-record-v3.js
|
|
1508
|
+
import { z as z14 } from "zod";
|
|
1509
|
+
|
|
1510
|
+
// ../events/dist/board-vocabulary.js
|
|
1511
|
+
import { z as z10 } from "zod";
|
|
1512
|
+
var boardStepStateSchema = z10.enum([
|
|
1513
|
+
"not-instrumented",
|
|
1514
|
+
"done",
|
|
1515
|
+
"did-not-pass",
|
|
1516
|
+
"could-not-complete",
|
|
1517
|
+
"not-yet-available",
|
|
1518
|
+
"qualified"
|
|
1519
|
+
]);
|
|
1520
|
+
var boardGateNameSchema = z10.enum([
|
|
1521
|
+
"scope",
|
|
1522
|
+
"architecture",
|
|
1523
|
+
"specs",
|
|
1524
|
+
"taskgraph",
|
|
1525
|
+
"phase-close"
|
|
1526
|
+
]);
|
|
1527
|
+
|
|
1528
|
+
// ../events/dist/code-link.js
|
|
1529
|
+
import { z as z11 } from "zod";
|
|
1530
|
+
var codeLinkAddressSchema = z11.string().regex(GITHUB_REPOSITORY_ADDRESS, { message: "must be a GitHub repository address: https://github.com/<owner>/<repo>" }).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key, so it is not sent" });
|
|
1531
|
+
var codeLinkFactsSchema = z11.object({
|
|
1532
|
+
repositoryAddress: codeLinkAddressSchema.nullable(),
|
|
1533
|
+
headOnGitHub: z11.boolean()
|
|
1534
|
+
}).strict().refine((v) => !(v.headOnGitHub && v.repositoryAddress === null), {
|
|
1535
|
+
message: "cannot be true when the code is not on GitHub",
|
|
1536
|
+
path: ["headOnGitHub"]
|
|
1537
|
+
});
|
|
1538
|
+
var PART_CODE_LINK_SCOPES = ["part", "phase"];
|
|
1539
|
+
var PART_CODE_LINK_RANGE_REASONS = ["not-github", "not-pushed"];
|
|
1540
|
+
var PART_CODE_LINK_URL_PREFIX = "https://github.com/";
|
|
1541
|
+
var partCodeLinkGithubSchema = z11.object({
|
|
1542
|
+
kind: z11.literal("github"),
|
|
1543
|
+
scope: z11.enum(PART_CODE_LINK_SCOPES),
|
|
1544
|
+
url: z11.string().startsWith(PART_CODE_LINK_URL_PREFIX, { message: "must start with https://github.com/" })
|
|
1545
|
+
}).strict();
|
|
1546
|
+
var partCodeLinkRangeSchema = z11.object({
|
|
1547
|
+
kind: z11.literal("range"),
|
|
1548
|
+
why: z11.enum(PART_CODE_LINK_RANGE_REASONS),
|
|
1549
|
+
from: closeCommitSchema,
|
|
1550
|
+
to: closeCommitSchema
|
|
1551
|
+
}).strict();
|
|
1552
|
+
var partCodeLinkNoneSchema = z11.object({
|
|
1553
|
+
kind: z11.literal("none")
|
|
1554
|
+
}).strict();
|
|
1555
|
+
var partCodeLinkSchema = z11.discriminatedUnion("kind", [
|
|
1556
|
+
partCodeLinkGithubSchema,
|
|
1557
|
+
partCodeLinkRangeSchema,
|
|
1558
|
+
partCodeLinkNoneSchema
|
|
1559
|
+
]);
|
|
1560
|
+
|
|
1561
|
+
// ../events/dist/observed-changes.js
|
|
1562
|
+
import { z as z12 } from "zod";
|
|
1563
|
+
var OBSERVED_PATHS_LISTED_MAX = 50;
|
|
1564
|
+
var OBSERVED_PATH_MAX = 300;
|
|
1565
|
+
var OBSERVED_COUNT_MAX = 1e6;
|
|
1566
|
+
var observedCountSchema = z12.number({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).int({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).max(OBSERVED_COUNT_MAX, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` });
|
|
1567
|
+
var observedDescriptionVersionSchema = z12.number().int().min(1);
|
|
1568
|
+
var observedPathSchema = z12.string().min(1, { message: "must not be empty" }).max(OBSERVED_PATH_MAX, { message: `must be at most ${OBSERVED_PATH_MAX} characters` });
|
|
1569
|
+
var observedPathListSchema = z12.array(observedPathSchema).max(OBSERVED_PATHS_LISTED_MAX, { message: `can list at most ${OBSERVED_PATHS_LISTED_MAX} paths` }).refine((paths) => new Set(paths).size === paths.length, { message: "must name each path once" });
|
|
1570
|
+
var observedMethodFilesSchema = z12.object({
|
|
1571
|
+
added: observedCountSchema,
|
|
1572
|
+
changed: observedCountSchema,
|
|
1573
|
+
removed: observedCountSchema
|
|
1574
|
+
}).strict();
|
|
1575
|
+
var observedFilesSchema = z12.object({
|
|
1576
|
+
added: observedCountSchema,
|
|
1577
|
+
changed: observedCountSchema,
|
|
1578
|
+
removed: observedCountSchema,
|
|
1579
|
+
testFilesAdded: observedCountSchema
|
|
1580
|
+
}).strict().refine((v) => v.testFilesAdded <= v.added, {
|
|
1581
|
+
message: "cannot be more than the files added",
|
|
1582
|
+
path: ["testFilesAdded"]
|
|
1583
|
+
});
|
|
1584
|
+
function filesChanged(files) {
|
|
1585
|
+
return files.added + files.changed + files.removed;
|
|
1586
|
+
}
|
|
1587
|
+
function pathsFitTheCount(files, paths) {
|
|
1588
|
+
return files === null ? paths.length === 0 : paths.length <= filesChanged(files);
|
|
1589
|
+
}
|
|
1590
|
+
function checkPartsUnique(parts, ctx, at) {
|
|
1591
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1592
|
+
parts.forEach((entry, i) => {
|
|
1593
|
+
if (seen.has(entry.part)) {
|
|
1594
|
+
ctx.addIssue({ code: "custom", path: [...at, i, "part"], message: `names the part "${entry.part}" twice` });
|
|
1595
|
+
}
|
|
1596
|
+
seen.add(entry.part);
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
var observedBasisCountSchema = z12.object({
|
|
1600
|
+
outcome: z12.literal("count"),
|
|
1601
|
+
phase: phaseNameSchema,
|
|
1602
|
+
startCommit: closeCommitSchema,
|
|
1603
|
+
descriptionVersion: observedDescriptionVersionSchema,
|
|
1604
|
+
description: systemDescriptionSchema
|
|
1605
|
+
}).strict();
|
|
1606
|
+
var observedBasisCannotCountSchema = z12.object({
|
|
1607
|
+
outcome: z12.literal("cannot-count"),
|
|
1608
|
+
phase: phaseNameSchema,
|
|
1609
|
+
reason: z12.literal("no-start-commit")
|
|
1610
|
+
}).strict();
|
|
1611
|
+
var observedBasisNothingToCountSchema = z12.object({
|
|
1612
|
+
outcome: z12.literal("nothing-to-count"),
|
|
1613
|
+
reason: z12.enum(["no-open-phase", "no-description"])
|
|
1614
|
+
}).strict();
|
|
1615
|
+
var observedBasisSchema = z12.discriminatedUnion("outcome", [
|
|
1616
|
+
observedBasisCountSchema,
|
|
1617
|
+
observedBasisCannotCountSchema,
|
|
1618
|
+
observedBasisNothingToCountSchema
|
|
1619
|
+
]);
|
|
1620
|
+
var observedReportPartSchema = z12.object({
|
|
1621
|
+
part: systemPartIdSchema,
|
|
1622
|
+
added: observedCountSchema,
|
|
1623
|
+
changed: observedCountSchema,
|
|
1624
|
+
removed: observedCountSchema,
|
|
1625
|
+
testFilesAdded: observedCountSchema
|
|
1626
|
+
}).strict().refine((v) => v.testFilesAdded <= v.added, {
|
|
1627
|
+
message: "cannot be more than the files added",
|
|
1628
|
+
path: ["testFilesAdded"]
|
|
1629
|
+
}).refine((v) => filesChanged(v) >= 1, {
|
|
1630
|
+
message: "a part is listed only when at least one file changed under it",
|
|
1631
|
+
path: ["added"]
|
|
1632
|
+
});
|
|
1633
|
+
var observedReportOutsideSchema = z12.object({
|
|
1634
|
+
added: observedCountSchema,
|
|
1635
|
+
changed: observedCountSchema,
|
|
1636
|
+
removed: observedCountSchema,
|
|
1637
|
+
testFilesAdded: observedCountSchema,
|
|
1638
|
+
paths: observedPathListSchema
|
|
1639
|
+
}).strict().refine((v) => v.testFilesAdded <= v.added, {
|
|
1640
|
+
message: "cannot be more than the files added",
|
|
1641
|
+
path: ["testFilesAdded"]
|
|
1642
|
+
}).refine((v) => pathsFitTheCount(v, v.paths), {
|
|
1643
|
+
message: "lists more paths than files changed",
|
|
1644
|
+
path: ["paths"]
|
|
1645
|
+
});
|
|
1646
|
+
var observedChangesReportSchema = z12.object({
|
|
1647
|
+
phase: phaseNameSchema,
|
|
1648
|
+
startCommit: closeCommitSchema,
|
|
1649
|
+
headCommit: closeCommitSchema,
|
|
1650
|
+
headCommittedAt: utcIso8601,
|
|
1651
|
+
commits: observedCountSchema,
|
|
1652
|
+
descriptionVersion: observedDescriptionVersionSchema,
|
|
1653
|
+
parts: z12.array(observedReportPartSchema).max(SYSTEM_PARTS_MAX, { message: `can list at most ${SYSTEM_PARTS_MAX} parts` }),
|
|
1654
|
+
methodFiles: observedMethodFilesSchema,
|
|
1655
|
+
outsideEveryPart: observedReportOutsideSchema,
|
|
1656
|
+
codeLink: codeLinkFactsSchema
|
|
1657
|
+
}).strict().superRefine((v, ctx) => checkPartsUnique(v.parts, ctx, ["parts"]));
|
|
1658
|
+
var observedSaidSchema = z12.object({
|
|
1659
|
+
title: buildTaskSchema.shape.title,
|
|
1660
|
+
agent: buildTaskSchema.shape.agent,
|
|
1661
|
+
whyOutsidePlan: buildTaskSchema.shape.whyOutsidePlan
|
|
1662
|
+
}).strict();
|
|
1663
|
+
var observedNotInPlanSchema = z12.object({
|
|
1664
|
+
part: systemPartIdSchema,
|
|
1665
|
+
name: systemPartSchema.shape.name,
|
|
1666
|
+
said: z12.array(observedSaidSchema).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1667
|
+
}).strict();
|
|
1668
|
+
var observedChangesRecordedSchema = z12.object({
|
|
1669
|
+
outcome: z12.literal("recorded"),
|
|
1670
|
+
notInPlan: z12.array(observedNotInPlanSchema).max(SYSTEM_PARTS_MAX).superRefine((parts, ctx) => checkPartsUnique(parts, ctx, [])),
|
|
1671
|
+
outside: z12.object({
|
|
1672
|
+
files: observedCountSchema,
|
|
1673
|
+
example: observedPathSchema.nullable()
|
|
1674
|
+
}).strict().refine((v) => v.example === null || v.files >= 1, {
|
|
1675
|
+
message: "names an example when no file changed",
|
|
1676
|
+
path: ["example"]
|
|
1677
|
+
})
|
|
1678
|
+
}).strict();
|
|
1679
|
+
var observedChangesKeptSchema = z12.object({
|
|
1680
|
+
outcome: z12.literal("kept")
|
|
1681
|
+
}).strict();
|
|
1682
|
+
var observedChangesReportResultSchema = z12.discriminatedUnion("outcome", [
|
|
1683
|
+
observedChangesRecordedSchema,
|
|
1684
|
+
observedChangesKeptSchema
|
|
1685
|
+
]);
|
|
1686
|
+
var OBSERVE_NOT_SENT_REASONS = [
|
|
1687
|
+
"not-configured",
|
|
1688
|
+
"nothing-to-count",
|
|
1689
|
+
"cannot-count",
|
|
1690
|
+
"start-not-here",
|
|
1691
|
+
"start-not-on-branch",
|
|
1692
|
+
"basis-moved",
|
|
1693
|
+
"refused",
|
|
1694
|
+
"unreachable"
|
|
1695
|
+
];
|
|
1696
|
+
var observeRunRecordedSchema = z12.object({ outcome: z12.literal("recorded") }).strict();
|
|
1697
|
+
var observeRunKeptSchema = z12.object({ outcome: z12.literal("kept") }).strict();
|
|
1698
|
+
var observeRunNotSentSchema = z12.object({
|
|
1699
|
+
outcome: z12.literal("not-sent"),
|
|
1700
|
+
reason: z12.enum(OBSERVE_NOT_SENT_REASONS)
|
|
1701
|
+
}).strict();
|
|
1702
|
+
var observeRunResultSchema = z12.discriminatedUnion("outcome", [
|
|
1703
|
+
observeRunRecordedSchema,
|
|
1704
|
+
observeRunKeptSchema,
|
|
1705
|
+
observeRunNotSentSchema
|
|
1706
|
+
]);
|
|
1707
|
+
var observedChecksFiredSchema = z12.array(z12.string().min(1)).refine((names) => names.every((name, i) => i === 0 || names[i - 1] < name), {
|
|
1708
|
+
message: "must be sorted, each name once"
|
|
1709
|
+
});
|
|
1710
|
+
var observedCountingSchema = z12.discriminatedUnion("state", [
|
|
1711
|
+
z12.object({
|
|
1712
|
+
state: z12.literal("counted"),
|
|
1713
|
+
startCommit: closeCommitSchema,
|
|
1714
|
+
startRecordedAt: utcIso8601,
|
|
1715
|
+
headCommit: closeCommitSchema,
|
|
1716
|
+
headCommittedAt: utcIso8601,
|
|
1717
|
+
commits: observedCountSchema,
|
|
1718
|
+
countedAt: utcIso8601
|
|
1719
|
+
}).strict(),
|
|
1720
|
+
z12.object({
|
|
1721
|
+
state: z12.literal("not-counted-yet"),
|
|
1722
|
+
startCommit: closeCommitSchema,
|
|
1723
|
+
startRecordedAt: utcIso8601
|
|
1724
|
+
}).strict(),
|
|
1725
|
+
z12.object({
|
|
1726
|
+
state: z12.literal("cannot-count")
|
|
1727
|
+
}).strict()
|
|
1728
|
+
]);
|
|
1729
|
+
var observedPartSchema = z12.object({
|
|
1730
|
+
part: systemPartIdSchema,
|
|
1731
|
+
files: observedFilesSchema.nullable(),
|
|
1732
|
+
checksFired: observedChecksFiredSchema
|
|
1733
|
+
}).strict().refine((v) => v.files !== null && filesChanged(v.files) >= 1 || v.checksFired.length >= 1, {
|
|
1734
|
+
message: "a part is listed only when files changed under it or a check fired on one",
|
|
1735
|
+
path: ["files"]
|
|
1736
|
+
});
|
|
1737
|
+
var observedOutsideSchema = z12.object({
|
|
1738
|
+
files: observedFilesSchema.nullable(),
|
|
1739
|
+
paths: observedPathListSchema,
|
|
1740
|
+
checksFired: observedChecksFiredSchema
|
|
1741
|
+
}).strict().refine((v) => pathsFitTheCount(v.files, v.paths), {
|
|
1742
|
+
message: "lists more paths than files changed",
|
|
1743
|
+
path: ["paths"]
|
|
1744
|
+
});
|
|
1745
|
+
var observedChangesSchema = z12.object({
|
|
1746
|
+
phase: phaseNameSchema,
|
|
1747
|
+
counting: observedCountingSchema,
|
|
1748
|
+
descriptionVersion: observedDescriptionVersionSchema.nullable(),
|
|
1749
|
+
parts: z12.array(observedPartSchema).max(SYSTEM_PARTS_MAX),
|
|
1750
|
+
methodFiles: observedMethodFilesSchema.nullable(),
|
|
1751
|
+
outsideEveryPart: observedOutsideSchema,
|
|
1752
|
+
codeLink: codeLinkFactsSchema.nullable()
|
|
1753
|
+
}).strict().superRefine((v, ctx) => {
|
|
1754
|
+
checkPartsUnique(v.parts, ctx, ["parts"]);
|
|
1755
|
+
const counted2 = v.counting.state === "counted";
|
|
1756
|
+
const rule = counted2 ? "must be present when the phase is counted" : "must be null until the phase is counted";
|
|
1757
|
+
if (v.methodFiles !== null !== counted2)
|
|
1758
|
+
ctx.addIssue({ code: "custom", path: ["methodFiles"], message: rule });
|
|
1759
|
+
if (v.outsideEveryPart.files !== null !== counted2) {
|
|
1760
|
+
ctx.addIssue({ code: "custom", path: ["outsideEveryPart", "files"], message: rule });
|
|
1761
|
+
}
|
|
1762
|
+
if (v.codeLink !== null !== counted2)
|
|
1763
|
+
ctx.addIssue({ code: "custom", path: ["codeLink"], message: rule });
|
|
1764
|
+
v.parts.forEach((entry, i) => {
|
|
1765
|
+
if (entry.files !== null !== counted2)
|
|
1766
|
+
ctx.addIssue({ code: "custom", path: ["parts", i, "files"], message: rule });
|
|
1767
|
+
});
|
|
1768
|
+
if (counted2 && v.descriptionVersion === null) {
|
|
1769
|
+
ctx.addIssue({ code: "custom", path: ["descriptionVersion"], message: "must name the version the counts used" });
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
var partOutsideThePlanSchema = z12.object({
|
|
1773
|
+
part: systemPartIdSchema,
|
|
1774
|
+
name: systemPartSchema.shape.name,
|
|
1775
|
+
seen: observedFilesSchema.nullable(),
|
|
1776
|
+
tasks: z12.array(observedSaidSchema.extend({ id: buildTaskSchema.shape.id }).strict()).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1777
|
+
}).strict();
|
|
1778
|
+
function shortCommit(commit) {
|
|
1779
|
+
return commit.slice(0, 7);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// ../events/dist/phase-review.js
|
|
1783
|
+
import { z as z13 } from "zod";
|
|
1784
|
+
var BUILT_PART_ACTS = Object.freeze(["accept", "question", "send-back"]);
|
|
1785
|
+
var NOT_BUILT_PART_ACTS = Object.freeze(["carry", "drop"]);
|
|
1786
|
+
var REVIEW_ACTS = Object.freeze([...BUILT_PART_ACTS, ...NOT_BUILT_PART_ACTS]);
|
|
1787
|
+
var reviewActSchema = z13.enum(REVIEW_ACTS);
|
|
1788
|
+
function reviewActsFor(built) {
|
|
1789
|
+
return built ? BUILT_PART_ACTS : NOT_BUILT_PART_ACTS;
|
|
1790
|
+
}
|
|
1791
|
+
var REVIEW_NOTE_MAX = SCOPE_NOTE_MAX;
|
|
1792
|
+
var reviewNoteWireSchema = z13.string().max(REVIEW_NOTE_MAX);
|
|
1793
|
+
var reviewNoteSchema = z13.string().min(1).max(REVIEW_NOTE_MAX);
|
|
1794
|
+
var REVIEW_ANSWER_MAX = 1e3;
|
|
1795
|
+
var reviewAgentAnswerSchema = z13.string().min(1).max(REVIEW_ANSWER_MAX);
|
|
1796
|
+
var REVIEW_PARTS_MAX = PHASE_PLAN_CHANGES_MAX * 2;
|
|
1797
|
+
var REVIEW_PART_CHANGES = Object.freeze([...PHASE_PLAN_CHANGE_KINDS, "not-in-plan"]);
|
|
1798
|
+
var reviewPartChangeSchema = z13.enum(REVIEW_PART_CHANGES);
|
|
1799
|
+
var REVIEW_DECISIONS = Object.freeze(["accepted", "carried", "dropped"]);
|
|
1800
|
+
var reviewDecisionSchema = z13.enum(REVIEW_DECISIONS);
|
|
1801
|
+
function actOf(decision) {
|
|
1802
|
+
if (decision === "accepted")
|
|
1803
|
+
return "accept";
|
|
1804
|
+
if (decision === "carried")
|
|
1805
|
+
return "carry";
|
|
1806
|
+
return "drop";
|
|
1807
|
+
}
|
|
1808
|
+
var reviewCarriedToSchema = carriedPhaseSchema.nullable();
|
|
1809
|
+
var reviewStepNameSchema = stepNameSchema.refine((v) => !stepIdSchema.safeParse(v.trim()).success, {
|
|
1810
|
+
message: "must be the step's plain name"
|
|
1811
|
+
});
|
|
1812
|
+
var reviewStepSchema = z13.object({
|
|
1813
|
+
name: reviewStepNameSchema.nullable(),
|
|
1814
|
+
state: unfinishedStepSchema.shape.state,
|
|
1815
|
+
judged: z13.boolean()
|
|
1816
|
+
}).strict();
|
|
1817
|
+
function codeLinkLine(link) {
|
|
1818
|
+
switch (link.kind) {
|
|
1819
|
+
case "github":
|
|
1820
|
+
return link.scope === "part" ? `The code: ${link.url}` : `The code: ${link.url} GitHub cannot show only this part's code, so this opens every change in this phase.`;
|
|
1821
|
+
case "range":
|
|
1822
|
+
return link.why === "not-github" ? `The code is on your machine, not on GitHub. This phase's changes are ${shortCommit(link.from)}..${shortCommit(link.to)}.` : `This phase's newest changes are not on GitHub yet. They are ${shortCommit(link.from)}..${shortCommit(link.to)} on your machine.`;
|
|
1823
|
+
case "none":
|
|
1824
|
+
return void 0;
|
|
1825
|
+
default:
|
|
1826
|
+
return assertNever(link);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
function assertNever(value) {
|
|
1830
|
+
throw new Error(`unexpected value: ${JSON.stringify(value)}`);
|
|
1831
|
+
}
|
|
1832
|
+
var openReviewRequestSchema = z13.object({
|
|
1833
|
+
actor: closeActorSchema,
|
|
1834
|
+
acceptanceOutcome: acceptanceOutcomeSchema,
|
|
1835
|
+
statements: closeStatementsSchema
|
|
1836
|
+
}).strict();
|
|
1837
|
+
var REVIEW_OPEN_TASKS_SHOWN_MAX = 10;
|
|
1838
|
+
var reviewOpenedSchema = z13.object({
|
|
1839
|
+
outcome: z13.literal("opened"),
|
|
1840
|
+
round: z13.number().int().min(1),
|
|
1841
|
+
parts: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
1842
|
+
notBuilt: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
1843
|
+
counted: z13.boolean(),
|
|
1844
|
+
typedReviewOffered: z13.boolean()
|
|
1845
|
+
}).strict().refine((v) => v.notBuilt <= v.parts, { message: "cannot exceed the parts in the round", path: ["notBuilt"] });
|
|
1846
|
+
var reviewTasksOpenSchema = z13.object({
|
|
1847
|
+
outcome: z13.literal("tasks-open"),
|
|
1848
|
+
open: z13.array(buildTaskSchema.shape.title).min(1).max(REVIEW_OPEN_TASKS_SHOWN_MAX),
|
|
1849
|
+
more: z13.number().int().min(0).max(BUILD_SNAPSHOT_TASK_LIMIT)
|
|
1850
|
+
}).strict();
|
|
1851
|
+
var reviewOutstandingSchema = z13.object({
|
|
1852
|
+
outcome: z13.literal("outstanding"),
|
|
1853
|
+
steps: z13.array(reviewStepSchema).min(1)
|
|
1854
|
+
}).strict();
|
|
1855
|
+
var reviewCleanOverFindingsSchema = z13.object({
|
|
1856
|
+
outcome: z13.literal("clean-over-findings"),
|
|
1857
|
+
findings: z13.number().int().min(1)
|
|
1858
|
+
}).strict();
|
|
1859
|
+
var reviewRefusedSchema = z13.object({
|
|
1860
|
+
outcome: z13.literal("refused"),
|
|
1861
|
+
problems: z13.array(systemDescriptionProblemSchema).min(1)
|
|
1862
|
+
}).strict();
|
|
1863
|
+
function bareReviewOutcome(outcome) {
|
|
1864
|
+
return z13.object({ outcome: z13.literal(outcome) }).strict();
|
|
1865
|
+
}
|
|
1866
|
+
var openReviewResultSchema = z13.discriminatedUnion("outcome", [
|
|
1867
|
+
reviewOpenedSchema,
|
|
1868
|
+
reviewTasksOpenSchema,
|
|
1869
|
+
bareReviewOutcome("no-build"),
|
|
1870
|
+
bareReviewOutcome("review-open"),
|
|
1871
|
+
reviewOutstandingSchema,
|
|
1872
|
+
reviewCleanOverFindingsSchema,
|
|
1873
|
+
reviewRefusedSchema,
|
|
1874
|
+
bareReviewOutcome("unavailable")
|
|
1875
|
+
]);
|
|
1876
|
+
var reviewPhaseNotOpenSchema = z13.object({
|
|
1877
|
+
statusCode: z13.literal(409),
|
|
1878
|
+
error: z13.literal("PhaseNotOpen"),
|
|
1879
|
+
message: z13.string().min(1),
|
|
1880
|
+
openPhase: z13.string().nullable()
|
|
1881
|
+
}).strict();
|
|
1882
|
+
var openReviewAnswerSchema = z13.union([openReviewResultSchema, reviewPhaseNotOpenSchema]);
|
|
1883
|
+
var reviewDecisionEntrySchema = z13.object({
|
|
1884
|
+
part: systemPartIdSchema,
|
|
1885
|
+
act: reviewActSchema,
|
|
1886
|
+
note: reviewNoteWireSchema.optional()
|
|
1887
|
+
}).strict();
|
|
1888
|
+
var reviewDecisionRequestSchema = z13.object({
|
|
1889
|
+
reviewVersion: z13.number().int().min(0),
|
|
1890
|
+
decisions: z13.array(reviewDecisionEntrySchema).max(REVIEW_PARTS_MAX)
|
|
1891
|
+
}).strict();
|
|
1892
|
+
var reviewDecidedSchema = z13.object({
|
|
1893
|
+
part: systemPartIdSchema,
|
|
1894
|
+
name: systemPartSchema.shape.name,
|
|
1895
|
+
act: reviewActSchema,
|
|
1896
|
+
carriedTo: reviewCarriedToSchema.optional()
|
|
1897
|
+
}).strict().refine((v) => v.carriedTo !== void 0 === (v.act === "carry"), {
|
|
1898
|
+
message: "is present exactly on a carry",
|
|
1899
|
+
path: ["carriedTo"]
|
|
1900
|
+
});
|
|
1901
|
+
var reviewRecordedSchema = z13.object({
|
|
1902
|
+
outcome: z13.literal("recorded"),
|
|
1903
|
+
decided: z13.array(reviewDecidedSchema).max(REVIEW_PARTS_MAX),
|
|
1904
|
+
waiting: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
|
|
1905
|
+
closed: z13.boolean(),
|
|
1906
|
+
reviewVersion: z13.number().int().min(1)
|
|
1907
|
+
}).strict().superRefine((v, ctx) => {
|
|
1908
|
+
if (v.closed && v.waiting !== 0) {
|
|
1909
|
+
ctx.addIssue({ code: "custom", path: ["waiting"], message: "must be 0 once the phase is closed" });
|
|
1910
|
+
}
|
|
1911
|
+
if (v.decided.length === 0 && !v.closed) {
|
|
1912
|
+
ctx.addIssue({ code: "custom", path: ["decided"], message: "may be empty only when the phase closed" });
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
var REVIEW_NOT_DECIDABLE_WHY = Object.freeze(["settled", "question-waiting", "sent-back"]);
|
|
1916
|
+
var reviewNotDecidablePartSchema = z13.object({
|
|
1917
|
+
part: systemPartIdSchema,
|
|
1918
|
+
name: systemPartSchema.shape.name,
|
|
1919
|
+
why: z13.enum(REVIEW_NOT_DECIDABLE_WHY)
|
|
1920
|
+
}).strict();
|
|
1921
|
+
var reviewNotDecidableSchema = z13.object({
|
|
1922
|
+
outcome: z13.literal("not-decidable"),
|
|
1923
|
+
parts: z13.array(reviewNotDecidablePartSchema).min(1).max(REVIEW_PARTS_MAX)
|
|
1924
|
+
}).strict();
|
|
1925
|
+
var reviewCloseRefusedSchema = z13.object({
|
|
1926
|
+
outcome: z13.literal("close-refused"),
|
|
1927
|
+
steps: z13.array(reviewStepSchema)
|
|
1928
|
+
}).strict();
|
|
1929
|
+
var reviewWalkChangedSchema = z13.object({
|
|
1930
|
+
outcome: z13.literal("walk-changed"),
|
|
1931
|
+
findings: z13.number().int().min(1)
|
|
1932
|
+
}).strict();
|
|
1933
|
+
var reviewDecisionResultSchema = z13.discriminatedUnion("outcome", [
|
|
1934
|
+
reviewRecordedSchema,
|
|
1935
|
+
bareReviewOutcome("review-changed"),
|
|
1936
|
+
bareReviewOutcome("no-review"),
|
|
1937
|
+
reviewNotDecidableSchema,
|
|
1938
|
+
reviewCloseRefusedSchema,
|
|
1939
|
+
reviewWalkChangedSchema,
|
|
1940
|
+
bareReviewOutcome("not-owner"),
|
|
1941
|
+
bareReviewOutcome("no-owner"),
|
|
1942
|
+
reviewRefusedSchema,
|
|
1943
|
+
bareReviewOutcome("unavailable")
|
|
1944
|
+
]);
|
|
1945
|
+
var reviewSentBackSchema = z13.object({
|
|
1946
|
+
round: z13.number().int().min(1),
|
|
1947
|
+
note: reviewNoteSchema
|
|
1948
|
+
}).strict();
|
|
1949
|
+
var reviewQuestionSchema = z13.object({
|
|
1950
|
+
question: reviewNoteSchema,
|
|
1951
|
+
agentAnswer: reviewAgentAnswerSchema.optional()
|
|
1952
|
+
}).strict();
|
|
1953
|
+
var reviewTaskSchema = z13.object({
|
|
1954
|
+
title: buildTaskSchema.shape.title,
|
|
1955
|
+
state: buildTaskStateSchema
|
|
1956
|
+
}).strict();
|
|
1957
|
+
var reviewViewPartSchema = z13.object({
|
|
1958
|
+
part: systemPartIdSchema,
|
|
1959
|
+
name: systemPartSchema.shape.name,
|
|
1960
|
+
change: reviewPartChangeSchema,
|
|
1961
|
+
built: z13.boolean(),
|
|
1962
|
+
builtWithoutApproval: z13.boolean(),
|
|
1963
|
+
decidable: z13.boolean(),
|
|
1964
|
+
waiting: z13.boolean(),
|
|
1965
|
+
decision: reviewDecisionSchema.optional(),
|
|
1966
|
+
reason: reviewNoteSchema.optional(),
|
|
1967
|
+
carriedTo: reviewCarriedToSchema.optional(),
|
|
1968
|
+
sentBack: z13.array(reviewSentBackSchema),
|
|
1969
|
+
questions: z13.array(reviewQuestionSchema),
|
|
1970
|
+
tasks: z13.array(reviewTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
1971
|
+
said: z13.array(observedSaidSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
1972
|
+
codeLink: partCodeLinkSchema
|
|
1973
|
+
}).strict().superRefine((v, ctx) => {
|
|
1974
|
+
if (v.waiting !== (v.decision === void 0)) {
|
|
1975
|
+
ctx.addIssue({ code: "custom", path: ["waiting"], message: "must be true exactly when the part has no decision" });
|
|
1976
|
+
}
|
|
1977
|
+
if (v.decidable && !v.waiting) {
|
|
1978
|
+
ctx.addIssue({ code: "custom", path: ["decidable"], message: "cannot be true for a settled part" });
|
|
1979
|
+
}
|
|
1980
|
+
if (v.decision !== void 0 && !reviewActsFor(v.built).includes(actOf(v.decision))) {
|
|
1981
|
+
ctx.addIssue({ code: "custom", path: ["decision"], message: "is not an act this part takes" });
|
|
1982
|
+
}
|
|
1983
|
+
const carriedOrDropped = v.decision === "carried" || v.decision === "dropped";
|
|
1984
|
+
if (v.reason !== void 0 !== carriedOrDropped) {
|
|
1985
|
+
ctx.addIssue({ code: "custom", path: ["reason"], message: "is present exactly on a carry or a drop" });
|
|
1986
|
+
}
|
|
1987
|
+
if (v.carriedTo !== void 0 !== (v.decision === "carried")) {
|
|
1988
|
+
ctx.addIssue({ code: "custom", path: ["carriedTo"], message: "is present exactly on a carry" });
|
|
1989
|
+
}
|
|
1990
|
+
if (v.change === "not-in-plan" && !v.built) {
|
|
1991
|
+
ctx.addIssue({ code: "custom", path: ["built"], message: "is always true for a part outside the plan" });
|
|
1992
|
+
}
|
|
1993
|
+
});
|
|
1994
|
+
var reviewPhaseNumberSchema = z13.number().int().min(1).nullable();
|
|
1995
|
+
var phaseReviewNoneSchema = z13.object({
|
|
1996
|
+
state: z13.literal("none"),
|
|
1997
|
+
phase: scopePhaseSchema,
|
|
1998
|
+
number: reviewPhaseNumberSchema,
|
|
1999
|
+
closedWithoutReview: z13.boolean()
|
|
2000
|
+
}).strict();
|
|
2001
|
+
var reviewWalkSchema = z13.object({
|
|
2002
|
+
verdict: walkVerdictSchema,
|
|
2003
|
+
findings: z13.number().int().min(0)
|
|
2004
|
+
}).strict();
|
|
2005
|
+
function reviewedViewSchema(state) {
|
|
2006
|
+
return z13.object({
|
|
2007
|
+
state: z13.literal(state),
|
|
2008
|
+
phase: scopePhaseSchema,
|
|
2009
|
+
number: reviewPhaseNumberSchema,
|
|
2010
|
+
cycle: z13.number().int().min(0),
|
|
2011
|
+
round: z13.number().int().min(1),
|
|
2012
|
+
reviewVersion: z13.number().int().min(1),
|
|
2013
|
+
typedReviewOffered: z13.boolean(),
|
|
2014
|
+
counted: z13.boolean(),
|
|
2015
|
+
walk: reviewWalkSchema,
|
|
2016
|
+
parts: z13.array(reviewViewPartSchema).max(REVIEW_PARTS_MAX),
|
|
2017
|
+
observed: observedChangesSchema.nullable(),
|
|
2018
|
+
description: systemDescriptionSchema
|
|
2019
|
+
}).strict().superRefine((v, ctx) => {
|
|
2020
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2021
|
+
v.parts.forEach((p, i) => {
|
|
2022
|
+
if (seen.has(p.part))
|
|
2023
|
+
ctx.addIssue({ code: "custom", path: ["parts", i, "part"], message: "is listed twice" });
|
|
2024
|
+
seen.add(p.part);
|
|
2025
|
+
});
|
|
2026
|
+
const counted2 = v.observed !== null && v.observed.counting.state === "counted";
|
|
2027
|
+
if (v.counted !== counted2) {
|
|
2028
|
+
ctx.addIssue({ code: "custom", path: ["counted"], message: "must be true exactly when the counts are counted" });
|
|
2029
|
+
}
|
|
2030
|
+
if (v.observed !== null && v.observed.phase !== v.phase) {
|
|
2031
|
+
ctx.addIssue({ code: "custom", path: ["observed", "phase"], message: "must be the phase under review" });
|
|
2032
|
+
}
|
|
2033
|
+
if (v.state === "closed") {
|
|
2034
|
+
v.parts.forEach((p, i) => {
|
|
2035
|
+
if (p.decision === void 0) {
|
|
2036
|
+
ctx.addIssue({ code: "custom", path: ["parts", i, "decision"], message: "every part of a closed review is decided" });
|
|
2037
|
+
}
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
var phaseReviewOpenSchema = reviewedViewSchema("open");
|
|
2043
|
+
var phaseReviewClosedSchema = reviewedViewSchema("closed");
|
|
2044
|
+
var phaseReviewViewSchema = z13.discriminatedUnion("state", [
|
|
2045
|
+
phaseReviewNoneSchema,
|
|
2046
|
+
phaseReviewOpenSchema,
|
|
2047
|
+
phaseReviewClosedSchema
|
|
2048
|
+
]);
|
|
2049
|
+
|
|
2050
|
+
// ../events/dist/build-record-v3.js
|
|
2051
|
+
var BUILD_RECORD_V3_FORMAT = "halfcycle-build-record/v3";
|
|
2052
|
+
var recordReviewRoundSchema = z14.object({
|
|
2053
|
+
round: z14.number().int().min(1),
|
|
2054
|
+
openedAt: utcIso8601,
|
|
2055
|
+
verdict: walkVerdictSchema,
|
|
2056
|
+
findings: z14.number().int().min(0)
|
|
2057
|
+
}).strict();
|
|
2058
|
+
var recordReviewApprovalSchema = z14.discriminatedUnion("kind", [
|
|
2059
|
+
z14.object({
|
|
2060
|
+
kind: z14.literal("approved"),
|
|
2061
|
+
planVersion: planVersionSchema,
|
|
2062
|
+
givenIn: scopeGivenInSchema,
|
|
2063
|
+
approvedAt: utcIso8601
|
|
2064
|
+
}).strict(),
|
|
2065
|
+
z14.object({ kind: z14.literal("none") }).strict()
|
|
2066
|
+
]);
|
|
2067
|
+
var recordReviewGateSchema = z14.object({
|
|
2068
|
+
gate: boardGateNameSchema,
|
|
2069
|
+
state: boardStepStateSchema
|
|
2070
|
+
}).strict();
|
|
2071
|
+
var recordReviewQuestionSchema = z14.object({
|
|
2072
|
+
question: reviewNoteSchema,
|
|
2073
|
+
agentAnswer: reviewAgentAnswerSchema
|
|
2074
|
+
}).strict();
|
|
2075
|
+
var recordReviewPartSchema = z14.object({
|
|
2076
|
+
part: systemPartIdSchema,
|
|
2077
|
+
name: systemPartSchema.shape.name,
|
|
2078
|
+
change: reviewPartChangeSchema,
|
|
2079
|
+
built: z14.boolean(),
|
|
2080
|
+
builtWithoutApproval: z14.boolean(),
|
|
2081
|
+
decision: reviewDecisionSchema,
|
|
2082
|
+
reason: reviewNoteSchema.optional(),
|
|
2083
|
+
carriedTo: reviewCarriedToSchema.optional(),
|
|
2084
|
+
sentBack: z14.array(reviewSentBackSchema),
|
|
2085
|
+
questions: z14.array(recordReviewQuestionSchema),
|
|
2086
|
+
codeLink: partCodeLinkSchema
|
|
2087
|
+
}).strict().superRefine((v, ctx) => {
|
|
2088
|
+
const carriedOrDropped = v.decision === "carried" || v.decision === "dropped";
|
|
2089
|
+
if (v.reason !== void 0 !== carriedOrDropped) {
|
|
2090
|
+
ctx.addIssue({ code: "custom", path: ["reason"], message: "is present exactly on a carry or a drop" });
|
|
2091
|
+
}
|
|
2092
|
+
if (v.carriedTo !== void 0 !== (v.decision === "carried")) {
|
|
2093
|
+
ctx.addIssue({ code: "custom", path: ["carriedTo"], message: "is present exactly on a carry" });
|
|
2094
|
+
}
|
|
2095
|
+
});
|
|
2096
|
+
var SPINE_ORDER = boardGateNameSchema.options;
|
|
2097
|
+
var recordReviewGatesSchema = z14.array(recordReviewGateSchema).superRefine((gates, ctx) => {
|
|
2098
|
+
const inOrder = gates.length === SPINE_ORDER.length && gates.every((g, i) => g.gate === SPINE_ORDER[i]);
|
|
2099
|
+
if (!inOrder) {
|
|
2100
|
+
ctx.addIssue({ code: "custom", message: `must be exactly the five checkpoints in order: ${SPINE_ORDER.join(", ")}` });
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
var recordReviewSchema = z14.object({
|
|
2104
|
+
sequence: z14.number().int().min(1),
|
|
2105
|
+
cycle: z14.number().int().min(0),
|
|
2106
|
+
rounds: z14.array(recordReviewRoundSchema).min(1),
|
|
2107
|
+
approval: recordReviewApprovalSchema,
|
|
2108
|
+
planVersion: planVersionSchema.nullable(),
|
|
2109
|
+
descriptionVersion: observedDescriptionVersionSchema,
|
|
2110
|
+
gates: recordReviewGatesSchema,
|
|
2111
|
+
observed: observedChangesSchema.nullable(),
|
|
2112
|
+
parts: z14.array(recordReviewPartSchema).max(REVIEW_PARTS_MAX)
|
|
2113
|
+
}).strict().superRefine((v, ctx) => {
|
|
2114
|
+
v.rounds.forEach((r, i) => {
|
|
2115
|
+
if (r.round !== i + 1) {
|
|
2116
|
+
ctx.addIssue({ code: "custom", path: ["rounds", i, "round"], message: "rounds must be numbered 1, 2, 3 \u2026 in order with no gap" });
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2120
|
+
v.parts.forEach((p, i) => {
|
|
2121
|
+
if (seen.has(p.part))
|
|
2122
|
+
ctx.addIssue({ code: "custom", path: ["parts", i, "part"], message: "is listed twice" });
|
|
2123
|
+
seen.add(p.part);
|
|
2124
|
+
if (v.observed === null && p.codeLink.kind !== "none") {
|
|
2125
|
+
ctx.addIssue({ code: "custom", path: ["parts", i, "codeLink"], message: "must be none when nothing was observed" });
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
2128
|
+
});
|
|
2129
|
+
var buildRecordV3Schema = z14.object({
|
|
2130
|
+
...buildRecordV2Schema.shape,
|
|
2131
|
+
format: z14.literal(BUILD_RECORD_V3_FORMAT),
|
|
2132
|
+
review: recordReviewSchema
|
|
2133
|
+
}).strict().superRefine((record2, ctx) => {
|
|
2134
|
+
checkRecordHalves(record2, ctx);
|
|
2135
|
+
const closes = record2.observed.closes;
|
|
2136
|
+
const newest = closes[closes.length - 1].sequence;
|
|
2137
|
+
if (record2.review.sequence !== newest) {
|
|
2138
|
+
ctx.addIssue({ code: "custom", path: ["review", "sequence"], message: "must be the newest close" });
|
|
2139
|
+
}
|
|
2140
|
+
const at = record2.attested.closes.findIndex((c) => c.sequence === record2.review.sequence);
|
|
2141
|
+
const close = at === -1 ? void 0 : record2.attested.closes[at];
|
|
2142
|
+
if (close !== void 0 && close.decision !== "done-when-met") {
|
|
2143
|
+
ctx.addIssue({ code: "custom", path: ["attested", "closes", at, "decision"], message: "a close made by a review is done-when-met" });
|
|
2144
|
+
}
|
|
2145
|
+
const last = record2.review.rounds[record2.review.rounds.length - 1];
|
|
2146
|
+
if (close !== void 0 && last !== void 0) {
|
|
2147
|
+
const attested = close.walk === null ? null : close.walk.findings.length + close.walk.findingsNotShown;
|
|
2148
|
+
if (attested !== last.findings) {
|
|
2149
|
+
ctx.addIssue({
|
|
2150
|
+
code: "custom",
|
|
2151
|
+
path: ["review", "rounds", record2.review.rounds.length - 1, "findings"],
|
|
2152
|
+
message: "must equal the findings of the closing walk"
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
if (record2.review.observed !== null && record2.review.observed.phase !== record2.phase) {
|
|
2157
|
+
ctx.addIssue({ code: "custom", path: ["review", "observed", "phase"], message: "must be this record's phase" });
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
var buildRecordSchema = z14.discriminatedUnion("format", [buildRecordV2Schema, buildRecordV3Schema]);
|
|
2161
|
+
function removalsOf(record2) {
|
|
2162
|
+
if (record2.format !== BUILD_RECORD_V3_FORMAT)
|
|
2163
|
+
return [];
|
|
2164
|
+
const out = [];
|
|
2165
|
+
for (const p of record2.review.parts) {
|
|
2166
|
+
if (p.change === "add" && p.decision === "dropped")
|
|
2167
|
+
out.push({ part: p.part, name: p.name, act: "dropped" });
|
|
2168
|
+
else if (p.change === "remove" && p.decision === "accepted")
|
|
2169
|
+
out.push({ part: p.part, name: p.name, act: "removed" });
|
|
2170
|
+
}
|
|
2171
|
+
return out;
|
|
2172
|
+
}
|
|
933
2173
|
|
|
934
2174
|
// ../events/dist/device-auth.js
|
|
935
|
-
import { z as
|
|
936
|
-
var utcIso86012 =
|
|
2175
|
+
import { z as z15 } from "zod";
|
|
2176
|
+
var utcIso86012 = z15.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");
|
|
937
2177
|
var DEVICE_AUTH_STATUS = {
|
|
938
2178
|
/** The poll: minted, nobody has acted yet. Keep polling. 200. */
|
|
939
2179
|
PENDING: "pending",
|
|
@@ -974,25 +2214,25 @@ var DEVICE_POLL_REFUSALS = [
|
|
|
974
2214
|
DEVICE_AUTH_STATUS.EXPIRED,
|
|
975
2215
|
DEVICE_AUTH_STATUS.UNKNOWN
|
|
976
2216
|
];
|
|
977
|
-
var deviceAuthStartResponseSchema =
|
|
978
|
-
deviceCode:
|
|
979
|
-
userCode:
|
|
980
|
-
verificationUrl:
|
|
2217
|
+
var deviceAuthStartResponseSchema = z15.object({
|
|
2218
|
+
deviceCode: z15.string().min(1),
|
|
2219
|
+
userCode: z15.string().min(1),
|
|
2220
|
+
verificationUrl: z15.string().min(1),
|
|
981
2221
|
expiresAt: utcIso86012,
|
|
982
|
-
pollIntervalMs:
|
|
2222
|
+
pollIntervalMs: z15.number().int().positive()
|
|
983
2223
|
}).strict();
|
|
984
|
-
var devicePollPendingSchema =
|
|
985
|
-
status:
|
|
986
|
-
pollIntervalMs:
|
|
2224
|
+
var devicePollPendingSchema = z15.object({
|
|
2225
|
+
status: z15.literal(DEVICE_AUTH_STATUS.PENDING),
|
|
2226
|
+
pollIntervalMs: z15.number().int().positive()
|
|
987
2227
|
}).strict();
|
|
988
|
-
var devicePollApprovedSchema =
|
|
989
|
-
status:
|
|
990
|
-
accountId:
|
|
991
|
-
credential:
|
|
2228
|
+
var devicePollApprovedSchema = z15.object({
|
|
2229
|
+
status: z15.literal(DEVICE_AUTH_STATUS.APPROVED),
|
|
2230
|
+
accountId: z15.string().min(1),
|
|
2231
|
+
credential: z15.string().min(1),
|
|
992
2232
|
expiresAt: utcIso86012
|
|
993
2233
|
}).strict();
|
|
994
|
-
var deviceAuthRefusalSchema =
|
|
995
|
-
status:
|
|
2234
|
+
var deviceAuthRefusalSchema = z15.object({
|
|
2235
|
+
status: z15.enum([
|
|
996
2236
|
DEVICE_AUTH_STATUS.DECLINED,
|
|
997
2237
|
DEVICE_AUTH_STATUS.EXPIRED,
|
|
998
2238
|
DEVICE_AUTH_STATUS.UNKNOWN,
|
|
@@ -1003,25 +2243,25 @@ var deviceAuthRefusalSchema = z6.object({
|
|
|
1003
2243
|
DEVICE_AUTH_STATUS.ALREADY_DECIDED,
|
|
1004
2244
|
DEVICE_AUTH_STATUS.TERMS_REQUIRED
|
|
1005
2245
|
]),
|
|
1006
|
-
message:
|
|
2246
|
+
message: z15.string().min(1)
|
|
1007
2247
|
}).strict();
|
|
1008
|
-
var devicePollResponseSchema =
|
|
2248
|
+
var devicePollResponseSchema = z15.union([
|
|
1009
2249
|
devicePollPendingSchema,
|
|
1010
2250
|
devicePollApprovedSchema,
|
|
1011
2251
|
deviceAuthRefusalSchema
|
|
1012
2252
|
]);
|
|
1013
|
-
var deviceConfirmRequestSchema =
|
|
1014
|
-
userCode:
|
|
1015
|
-
decision:
|
|
1016
|
-
externalAuthId:
|
|
1017
|
-
email:
|
|
1018
|
-
acceptTerms:
|
|
2253
|
+
var deviceConfirmRequestSchema = z15.object({
|
|
2254
|
+
userCode: z15.string().min(1),
|
|
2255
|
+
decision: z15.enum(["approve", "decline"]),
|
|
2256
|
+
externalAuthId: z15.string().min(1).optional(),
|
|
2257
|
+
email: z15.string().optional(),
|
|
2258
|
+
acceptTerms: z15.boolean().optional()
|
|
1019
2259
|
}).strict();
|
|
1020
|
-
var deviceConfirmRecordedSchema =
|
|
1021
|
-
status:
|
|
1022
|
-
accountId:
|
|
2260
|
+
var deviceConfirmRecordedSchema = z15.object({
|
|
2261
|
+
status: z15.literal(DEVICE_AUTH_STATUS.RECORDED),
|
|
2262
|
+
accountId: z15.string().min(1).optional()
|
|
1023
2263
|
}).strict();
|
|
1024
|
-
var deviceConfirmResponseSchema =
|
|
2264
|
+
var deviceConfirmResponseSchema = z15.union([
|
|
1025
2265
|
deviceConfirmRecordedSchema,
|
|
1026
2266
|
deviceAuthRefusalSchema
|
|
1027
2267
|
]);
|
|
@@ -1033,20 +2273,20 @@ function projectPageUrl(engagementId) {
|
|
|
1033
2273
|
}
|
|
1034
2274
|
|
|
1035
2275
|
// ../events/dist/credential-wire.js
|
|
1036
|
-
import { z as
|
|
1037
|
-
var engagementCredentialResponseSchema =
|
|
1038
|
-
engagementId:
|
|
1039
|
-
sessionToken:
|
|
1040
|
-
mcpUrl:
|
|
1041
|
-
guardUrl:
|
|
1042
|
-
controlTelemetryUrl:
|
|
1043
|
-
methodVersion:
|
|
1044
|
-
consoleUrl:
|
|
2276
|
+
import { z as z16 } from "zod";
|
|
2277
|
+
var engagementCredentialResponseSchema = z16.object({
|
|
2278
|
+
engagementId: z16.string(),
|
|
2279
|
+
sessionToken: z16.string(),
|
|
2280
|
+
mcpUrl: z16.string(),
|
|
2281
|
+
guardUrl: z16.string(),
|
|
2282
|
+
controlTelemetryUrl: z16.string(),
|
|
2283
|
+
methodVersion: z16.string().optional(),
|
|
2284
|
+
consoleUrl: z16.string().optional()
|
|
1045
2285
|
}).strict();
|
|
1046
|
-
var ciTokenExchangeResponseSchema =
|
|
1047
|
-
token:
|
|
2286
|
+
var ciTokenExchangeResponseSchema = z16.object({
|
|
2287
|
+
token: z16.string(),
|
|
1048
2288
|
expiresAt: utcIso8601,
|
|
1049
|
-
engagementId:
|
|
2289
|
+
engagementId: z16.string()
|
|
1050
2290
|
}).strict();
|
|
1051
2291
|
var NO_CREDENTIAL_PLACEHOLDER = "halfcycle:no-credential";
|
|
1052
2292
|
var NOT_THIS_ACCOUNT_PLACEHOLDER = "halfcycle:not-this-account";
|
|
@@ -1063,37 +2303,37 @@ var PLACEHOLDER_SENTENCES = Object.freeze({
|
|
|
1063
2303
|
});
|
|
1064
2304
|
|
|
1065
2305
|
// ../events/dist/phase-record.js
|
|
1066
|
-
import { z as
|
|
1067
|
-
var phaseRecordRefusalReasonSchema =
|
|
2306
|
+
import { z as z17 } from "zod";
|
|
2307
|
+
var phaseRecordRefusalReasonSchema = z17.enum([
|
|
1068
2308
|
"still-open",
|
|
1069
2309
|
"reopened",
|
|
1070
2310
|
"never-opened",
|
|
1071
2311
|
"never-closed",
|
|
1072
2312
|
"closed-before-records"
|
|
1073
2313
|
]);
|
|
1074
|
-
var phaseRecordRecordSchema =
|
|
1075
|
-
outcome:
|
|
2314
|
+
var phaseRecordRecordSchema = z17.object({
|
|
2315
|
+
outcome: z17.literal("record"),
|
|
1076
2316
|
phase: phaseNameSchema,
|
|
1077
|
-
record:
|
|
2317
|
+
record: buildRecordSchema
|
|
1078
2318
|
}).strict().refine((body) => body.record.phase === body.phase, {
|
|
1079
2319
|
message: "the record is for a different phase than the one asked for",
|
|
1080
2320
|
path: ["record", "phase"]
|
|
1081
2321
|
});
|
|
1082
|
-
var phaseRecordWithheldSchema =
|
|
1083
|
-
outcome:
|
|
2322
|
+
var phaseRecordWithheldSchema = z17.object({
|
|
2323
|
+
outcome: z17.literal("withheld"),
|
|
1084
2324
|
phase: phaseNameSchema,
|
|
1085
|
-
sequence:
|
|
2325
|
+
sequence: z17.number().int().min(1),
|
|
1086
2326
|
closedAt: utcIso8601,
|
|
1087
|
-
message:
|
|
2327
|
+
message: z17.string()
|
|
1088
2328
|
}).strict();
|
|
1089
2329
|
var phaseRecordRefusedSchema = wireErrorSchema.extend({
|
|
1090
|
-
outcome:
|
|
2330
|
+
outcome: z17.literal("refused"),
|
|
1091
2331
|
phase: phaseNameSchema,
|
|
1092
|
-
statusCode:
|
|
1093
|
-
error:
|
|
2332
|
+
statusCode: z17.literal(409),
|
|
2333
|
+
error: z17.literal("PhaseRecordRefused"),
|
|
1094
2334
|
reason: phaseRecordRefusalReasonSchema
|
|
1095
2335
|
}).strict();
|
|
1096
|
-
var phaseRecordResponseSchema =
|
|
2336
|
+
var phaseRecordResponseSchema = z17.discriminatedUnion("outcome", [
|
|
1097
2337
|
phaseRecordRecordSchema,
|
|
1098
2338
|
phaseRecordWithheldSchema,
|
|
1099
2339
|
phaseRecordRefusedSchema
|
|
@@ -1147,6 +2387,7 @@ var ENGAGEMENT_ENV_KEYS = [
|
|
|
1147
2387
|
...GUARD_ENV_KEYS,
|
|
1148
2388
|
"CONTROL_TELEMETRY_URL"
|
|
1149
2389
|
];
|
|
2390
|
+
var PHASE_STAMP_ENV_KEY = "HALFCYCLE_PHASE";
|
|
1150
2391
|
function reconcileEnvText2(existing, values, keys = ENGAGEMENT_ENV_KEYS) {
|
|
1151
2392
|
return reconcileEnvText(existing, values, keys);
|
|
1152
2393
|
}
|
|
@@ -1247,7 +2488,7 @@ halfcycle_env_file() {
|
|
|
1247
2488
|
|
|
1248
2489
|
// dist/identity.js
|
|
1249
2490
|
import { execFileSync } from "node:child_process";
|
|
1250
|
-
import { existsSync, linkSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2491
|
+
import { existsSync, linkSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1251
2492
|
import { dirname as dirname2, isAbsolute, join as join3 } from "node:path";
|
|
1252
2493
|
import { randomUUID } from "node:crypto";
|
|
1253
2494
|
var PROJECT_IDENTITY_NOTE = 'projectId is NOT the engagement id \u2014 it identifies this repository/worktree to Halfcycle, not an engagement. The engagement id lives in .halfcycle/bundle.json, in its "engagementId" field.';
|
|
@@ -1296,6 +2537,41 @@ function readRootCommit(targetRepoRoot) {
|
|
|
1296
2537
|
function readRemote(targetRepoRoot) {
|
|
1297
2538
|
return git(targetRepoRoot, ["remote", "get-url", "origin"]);
|
|
1298
2539
|
}
|
|
2540
|
+
function stripUrlUserinfoTextually(trimmed) {
|
|
2541
|
+
const schemeEnd = trimmed.indexOf("://") + 3;
|
|
2542
|
+
const pathStart = (() => {
|
|
2543
|
+
const match = /[/?#]/.exec(trimmed.slice(schemeEnd));
|
|
2544
|
+
return match ? schemeEnd + match.index : trimmed.length;
|
|
2545
|
+
})();
|
|
2546
|
+
const authority = trimmed.slice(schemeEnd, pathStart);
|
|
2547
|
+
const at = authority.lastIndexOf("@");
|
|
2548
|
+
if (at === -1)
|
|
2549
|
+
return trimmed;
|
|
2550
|
+
return trimmed.slice(0, schemeEnd) + authority.slice(at + 1) + trimmed.slice(pathStart);
|
|
2551
|
+
}
|
|
2552
|
+
function redactRemoteCredential(remote) {
|
|
2553
|
+
if (remote === null)
|
|
2554
|
+
return null;
|
|
2555
|
+
const trimmed = remote.trim();
|
|
2556
|
+
if (trimmed.includes("://")) {
|
|
2557
|
+
try {
|
|
2558
|
+
const url = new URL(trimmed);
|
|
2559
|
+
if (url.username === "" && url.password === "")
|
|
2560
|
+
return trimmed;
|
|
2561
|
+
url.username = "";
|
|
2562
|
+
url.password = "";
|
|
2563
|
+
return url.toString();
|
|
2564
|
+
} catch {
|
|
2565
|
+
return stripUrlUserinfoTextually(trimmed);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
const at = trimmed.lastIndexOf("@");
|
|
2569
|
+
if (at === -1)
|
|
2570
|
+
return trimmed;
|
|
2571
|
+
const userinfo = trimmed.slice(0, at);
|
|
2572
|
+
const rest = trimmed.slice(at + 1);
|
|
2573
|
+
return userinfo.includes(":") && rest.includes(":") ? rest : trimmed;
|
|
2574
|
+
}
|
|
1299
2575
|
function readIgnoredPaths(targetRepoRoot, paths) {
|
|
1300
2576
|
if (paths.length === 0)
|
|
1301
2577
|
return null;
|
|
@@ -1331,11 +2607,12 @@ function readIgnoredPaths(targetRepoRoot, paths) {
|
|
|
1331
2607
|
function mintOrReadIdentity(targetRepoRoot) {
|
|
1332
2608
|
const path = join3(targetRepoRoot, ".halfcycle", "project.json");
|
|
1333
2609
|
if (existsSync(path)) {
|
|
2610
|
+
repairRemoteCredential(targetRepoRoot);
|
|
1334
2611
|
const onDisk = JSON.parse(readFileSync2(path, "utf-8"));
|
|
1335
2612
|
const identity = {
|
|
1336
2613
|
projectId: onDisk.projectId ?? "",
|
|
1337
2614
|
rootCommit: onDisk.rootCommit ?? null,
|
|
1338
|
-
remote: onDisk.remote ?? null,
|
|
2615
|
+
remote: redactRemoteCredential(onDisk.remote ?? null),
|
|
1339
2616
|
note: PROJECT_IDENTITY_NOTE
|
|
1340
2617
|
};
|
|
1341
2618
|
return { identity, minted: false };
|
|
@@ -1346,10 +2623,40 @@ function mintIdentity(targetRepoRoot) {
|
|
|
1346
2623
|
return {
|
|
1347
2624
|
projectId: randomUUID(),
|
|
1348
2625
|
rootCommit: readRootCommit(targetRepoRoot),
|
|
1349
|
-
remote: readRemote(targetRepoRoot),
|
|
2626
|
+
remote: redactRemoteCredential(readRemote(targetRepoRoot)),
|
|
1350
2627
|
note: PROJECT_IDENTITY_NOTE
|
|
1351
2628
|
};
|
|
1352
2629
|
}
|
|
2630
|
+
function repairRemoteCredential(targetRepoRoot) {
|
|
2631
|
+
const path = join3(targetRepoRoot, ".halfcycle", "project.json");
|
|
2632
|
+
let onDisk;
|
|
2633
|
+
try {
|
|
2634
|
+
const parsed = JSON.parse(readFileSync2(path, "utf-8"));
|
|
2635
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
2636
|
+
return;
|
|
2637
|
+
onDisk = parsed;
|
|
2638
|
+
} catch {
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2641
|
+
const storedRemote = onDisk.remote ?? null;
|
|
2642
|
+
const remote = redactRemoteCredential(storedRemote);
|
|
2643
|
+
if (remote === storedRemote)
|
|
2644
|
+
return;
|
|
2645
|
+
const identity = {
|
|
2646
|
+
projectId: onDisk.projectId ?? "",
|
|
2647
|
+
rootCommit: onDisk.rootCommit ?? null,
|
|
2648
|
+
remote,
|
|
2649
|
+
note: PROJECT_IDENTITY_NOTE
|
|
2650
|
+
};
|
|
2651
|
+
const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
2652
|
+
try {
|
|
2653
|
+
writeFileSync2(temporary, serializeProjectIdentity(identity), { encoding: "utf-8", flag: "wx" });
|
|
2654
|
+
renameSync(temporary, path);
|
|
2655
|
+
} catch {
|
|
2656
|
+
} finally {
|
|
2657
|
+
rmSync(temporary, { force: true });
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
1353
2660
|
function serializeProjectIdentity(identity) {
|
|
1354
2661
|
return JSON.stringify(identity, null, 2) + "\n";
|
|
1355
2662
|
}
|
|
@@ -2399,18 +3706,21 @@ exit 0
|
|
|
2399
3706
|
var GENERATED_USER_PROMPT_SCOPE_HEADER = "# Typed scope approval \u2014 generated by";
|
|
2400
3707
|
function generateUserPromptScopeHook() {
|
|
2401
3708
|
return `#!/usr/bin/env bash
|
|
2402
|
-
${GENERATED_USER_PROMPT_SCOPE_HEADER} the Halfcycle installer.
|
|
3709
|
+
${GENERATED_USER_PROMPT_SCOPE_HEADER} the Halfcycle installer, now also for the close review.
|
|
2403
3710
|
#
|
|
2404
|
-
# Lets the owner of this project approve a phase's scope, or send it back,
|
|
2405
|
-
#
|
|
2406
|
-
# their own Claude Code session
|
|
3711
|
+
# Lets the owner of this project approve a phase's scope, or send it back, and
|
|
3712
|
+
# decide one part of a phase's close review, by typing one line as the whole
|
|
3713
|
+
# prompt in their own Claude Code session: "approve <phase>", "send back
|
|
3714
|
+
# <phase>: <note>", "accept <phase>/<part>", "question <phase>/<part>: <words>",
|
|
3715
|
+
# "carry <phase>/<part>: <words>" or "drop <phase>/<part>: <words>".
|
|
2407
3716
|
#
|
|
2408
3717
|
# AN ORDINARY PROMPT STARTS NOTHING. This script reads the hook input once and
|
|
2409
3718
|
# looks only at the start of the prompt's value. Unless the prompt begins, after
|
|
2410
|
-
# any whitespace (typed, or escaped in the input), with "approve "
|
|
2411
|
-
# "
|
|
2412
|
-
# A quote inside any other field arrives escaped,
|
|
2413
|
-
# the session is in, for one) can read as the
|
|
3719
|
+
# any whitespace (typed, or escaped in the input), with "approve ", "send back ",
|
|
3720
|
+
# "accept ", "question ", "carry " or "drop ", in any case, it exits 0 with no
|
|
3721
|
+
# output, and Node never starts. A quote inside any other field arrives escaped,
|
|
3722
|
+
# so no other field (the folder the session is in, for one) can read as the
|
|
3723
|
+
# start of the prompt.
|
|
2414
3724
|
#
|
|
2415
3725
|
# Otherwise it finds the project root from its own location, never from the
|
|
2416
3726
|
# folder the session has moved to, and hands the same input to the guard
|
|
@@ -2431,7 +3741,7 @@ IFS= read -r -d '' HC_INPUT || true
|
|
|
2431
3741
|
# \\u escape, or as the UTF-8 bytes of a Unicode space. Compared byte for byte.
|
|
2432
3742
|
HC_LEAD='[[:space:]]|\\\\[nrtf]|\\\\u(000[9a-d]|0020|00a0|1680|200[0-9a]|202[89f]|205f|3000|feff)'
|
|
2433
3743
|
HC_LEAD="$HC_LEAD|"$'\\xc2\\xa0|\\xe1\\x9a\\x80|\\xe2\\x80[\\x80-\\x8a\\xa8\\xa9\\xaf]|\\xe2\\x81\\x9f|\\xe3\\x80\\x80|\\xef\\xbb\\xbf'
|
|
2434
|
-
if ! printf '%s' "$HC_INPUT" | LC_ALL=C grep -Eiq "\\"prompt\\"[[:space:]]*:[[:space:]]*\\"($HC_LEAD)*(approve|send back) "; then
|
|
3744
|
+
if ! printf '%s' "$HC_INPUT" | LC_ALL=C grep -Eiq "\\"prompt\\"[[:space:]]*:[[:space:]]*\\"($HC_LEAD)*(approve|send back|accept|question|carry|drop) "; then
|
|
2435
3745
|
exit 0
|
|
2436
3746
|
fi
|
|
2437
3747
|
|
|
@@ -2711,8 +4021,10 @@ function checkDrift(targetRepoRoot) {
|
|
|
2711
4021
|
return { drifted: installed !== current, installed, current, methodVersion: pin?.methodVersion ?? null };
|
|
2712
4022
|
}
|
|
2713
4023
|
function writeProjectIdentity(targetRepo) {
|
|
2714
|
-
if (existsSync3(join5(targetRepo, PROJECT_IDENTITY_REL)))
|
|
4024
|
+
if (existsSync3(join5(targetRepo, PROJECT_IDENTITY_REL))) {
|
|
4025
|
+
repairRemoteCredential(targetRepo);
|
|
2715
4026
|
return "skipped";
|
|
4027
|
+
}
|
|
2716
4028
|
createProjectIdentityFile(targetRepo);
|
|
2717
4029
|
return "written";
|
|
2718
4030
|
}
|
|
@@ -3682,6 +4994,32 @@ function printRecordText(text) {
|
|
|
3682
4994
|
});
|
|
3683
4995
|
return out;
|
|
3684
4996
|
}
|
|
4997
|
+
var MARKUP = /[\\`*_~$<>&[\]{}#|]/;
|
|
4998
|
+
function printStrictText(text) {
|
|
4999
|
+
if (text === "")
|
|
5000
|
+
return "(blank)";
|
|
5001
|
+
let out = "";
|
|
5002
|
+
for (const ch of text) {
|
|
5003
|
+
if (HIDDEN.test(ch))
|
|
5004
|
+
out += `U+${ch.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")}`;
|
|
5005
|
+
else if (MARKUP.test(ch))
|
|
5006
|
+
out += `\\${ch}`;
|
|
5007
|
+
else
|
|
5008
|
+
out += ch;
|
|
5009
|
+
}
|
|
5010
|
+
return out;
|
|
5011
|
+
}
|
|
5012
|
+
function printItemStartText(text) {
|
|
5013
|
+
const out = printStrictText(text);
|
|
5014
|
+
if (out.startsWith(" "))
|
|
5015
|
+
return ` ${out.slice(1)}`;
|
|
5016
|
+
if (out.startsWith("-") || out.startsWith("+"))
|
|
5017
|
+
return `\\${out}`;
|
|
5018
|
+
const ordered = /^(\d{1,9})([.)])/.exec(out);
|
|
5019
|
+
if (ordered !== null)
|
|
5020
|
+
return `${ordered[1]}\\${out.slice(ordered[1].length)}`;
|
|
5021
|
+
return out;
|
|
5022
|
+
}
|
|
3685
5023
|
function makePrinter() {
|
|
3686
5024
|
let hidden = false;
|
|
3687
5025
|
return {
|
|
@@ -3690,6 +5028,16 @@ function makePrinter() {
|
|
|
3690
5028
|
hidden = true;
|
|
3691
5029
|
return printRecordText(value);
|
|
3692
5030
|
},
|
|
5031
|
+
strict(value) {
|
|
5032
|
+
if (!hidden && HIDDEN.test(value))
|
|
5033
|
+
hidden = true;
|
|
5034
|
+
return printStrictText(value);
|
|
5035
|
+
},
|
|
5036
|
+
itemStart(value) {
|
|
5037
|
+
if (!hidden && HIDDEN.test(value))
|
|
5038
|
+
hidden = true;
|
|
5039
|
+
return printItemStartText(value);
|
|
5040
|
+
},
|
|
3693
5041
|
sawHidden() {
|
|
3694
5042
|
return hidden;
|
|
3695
5043
|
}
|
|
@@ -3905,6 +5253,52 @@ function renderClose(heading, observed, attested, checks, p) {
|
|
|
3905
5253
|
renderStated(attested, p)
|
|
3906
5254
|
];
|
|
3907
5255
|
}
|
|
5256
|
+
var REVIEW_LABEL = "**Recorded by Halfcycle from the owner's review.** Each part the review held, and how the project's owner decided it. A line marked as the agent's is the agent's own answer, not Halfcycle's.";
|
|
5257
|
+
var REVIEW_NO_PARTS = "The review had no parts, so it closed on one accept that names no part.";
|
|
5258
|
+
function approvalLine(approval) {
|
|
5259
|
+
if (approval.kind === "none")
|
|
5260
|
+
return "Built without an approved scope.";
|
|
5261
|
+
const where = approval.givenIn === "console" ? "in the console" : "in their own session";
|
|
5262
|
+
return `Scope approved by the project's owner, plan version ${String(approval.planVersion)}, ${where}.`;
|
|
5263
|
+
}
|
|
5264
|
+
function decisionText(part, p) {
|
|
5265
|
+
switch (part.decision) {
|
|
5266
|
+
case "accepted":
|
|
5267
|
+
return "Accepted";
|
|
5268
|
+
case "carried":
|
|
5269
|
+
return part.carriedTo === null || part.carriedTo === void 0 ? `Carried to the next phase planned: ${p.text(part.reason ?? "")}` : `Carried to phase ${String(part.carriedTo.number)}: ${p.text(part.reason ?? "")}`;
|
|
5270
|
+
case "dropped":
|
|
5271
|
+
return `Dropped: ${p.text(part.reason ?? "")}`;
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
function reviewPartLines(part, p) {
|
|
5275
|
+
const lines = [`- ${p.itemStart(part.name)} \u2014 ${decisionText(part, p)}`];
|
|
5276
|
+
const code = codeLinkLine(part.codeLink);
|
|
5277
|
+
if (code !== void 0)
|
|
5278
|
+
lines.push(` - ${p.text(code)}`);
|
|
5279
|
+
for (const sent of part.sentBack)
|
|
5280
|
+
lines.push(` - Sent back in round ${String(sent.round)}: ${p.text(sent.note)}`);
|
|
5281
|
+
for (const q of part.questions) {
|
|
5282
|
+
lines.push(` - Question: ${p.text(q.question)}`);
|
|
5283
|
+
lines.push(` - The agent answered: ${p.text(q.agentAnswer)}`);
|
|
5284
|
+
}
|
|
5285
|
+
return lines;
|
|
5286
|
+
}
|
|
5287
|
+
function removalsLine(record2, p) {
|
|
5288
|
+
const removals = removalsOf(record2);
|
|
5289
|
+
if (removals.length === 0)
|
|
5290
|
+
return null;
|
|
5291
|
+
return `Take these parts out of docs/system.json: ${removals.map((r) => `"${p.strict(r.name)}" (${r.act})`).join(", ")}.`;
|
|
5292
|
+
}
|
|
5293
|
+
function renderReview(record2, p) {
|
|
5294
|
+
const review = record2.review;
|
|
5295
|
+
const blocks = ["## The owner's review", REVIEW_LABEL, approvalLine(review.approval)];
|
|
5296
|
+
blocks.push(review.parts.length === 0 ? REVIEW_NO_PARTS : review.parts.flatMap((part) => reviewPartLines(part, p)).join("\n"));
|
|
5297
|
+
const removals = removalsLine(record2, p);
|
|
5298
|
+
if (removals !== null)
|
|
5299
|
+
blocks.push(removals);
|
|
5300
|
+
return blocks;
|
|
5301
|
+
}
|
|
3908
5302
|
function renderBuildRecordV2Markdown(record2) {
|
|
3909
5303
|
const p = makePrinter();
|
|
3910
5304
|
const attestedBySequence = /* @__PURE__ */ new Map();
|
|
@@ -3930,6 +5324,8 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
3930
5324
|
...renderChecks(record2.observed.checks, p),
|
|
3931
5325
|
...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)
|
|
3932
5326
|
];
|
|
5327
|
+
if (record2.format === "halfcycle-build-record/v3")
|
|
5328
|
+
body.push(...renderReview(record2, p));
|
|
3933
5329
|
if (total > 1) {
|
|
3934
5330
|
body.push("## Earlier closes");
|
|
3935
5331
|
for (const close of closes.slice(0, -1)) {
|
|
@@ -3944,7 +5340,7 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
3944
5340
|
}
|
|
3945
5341
|
|
|
3946
5342
|
// dist/build-record/write.js
|
|
3947
|
-
import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync7, renameSync, rmSync as rmSync3, writeSync } from "node:fs";
|
|
5343
|
+
import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync7, renameSync as renameSync2, rmSync as rmSync3, writeSync } from "node:fs";
|
|
3948
5344
|
import { basename, join as join8, resolve, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
|
|
3949
5345
|
var BUILD_RECORD_DIR = join8("docs", "build-records");
|
|
3950
5346
|
function assertInsideOutDir(outDir, candidate, identity) {
|
|
@@ -3970,7 +5366,7 @@ function createExclusiveOnDisk(path, data) {
|
|
|
3970
5366
|
closeSync(fd);
|
|
3971
5367
|
}
|
|
3972
5368
|
function renameOnDisk(from, to) {
|
|
3973
|
-
|
|
5369
|
+
renameSync2(from, to);
|
|
3974
5370
|
}
|
|
3975
5371
|
var NODE_RECORD_PAIR_IO = {
|
|
3976
5372
|
createExclusive: createExclusiveOnDisk,
|
|
@@ -3996,7 +5392,7 @@ function isOwnEarlierRecord(existingText, served) {
|
|
|
3996
5392
|
} catch {
|
|
3997
5393
|
return false;
|
|
3998
5394
|
}
|
|
3999
|
-
const existing =
|
|
5395
|
+
const existing = buildRecordSchema.safeParse(parsedJson);
|
|
4000
5396
|
if (!existing.success)
|
|
4001
5397
|
return false;
|
|
4002
5398
|
const old = existing.data;
|
|
@@ -4079,6 +5475,23 @@ function replaceOne(io, tmp, finalPath, text) {
|
|
|
4079
5475
|
// dist/build-record/obtain.js
|
|
4080
5476
|
import { relative as relative3 } from "node:path";
|
|
4081
5477
|
|
|
5478
|
+
// dist/open-phase.js
|
|
5479
|
+
function writePhaseStamp(engagementId, phase, home) {
|
|
5480
|
+
if (!isEngagementId(engagementId)) {
|
|
5481
|
+
return { path: "(none \u2014 no valid project id)", reason: new InvalidEngagementIdError(engagementId).message };
|
|
5482
|
+
}
|
|
5483
|
+
const path = engagementEnvPath(engagementId, home);
|
|
5484
|
+
if (phase !== null && !isValidPhaseIdentity(phase)) {
|
|
5485
|
+
return { path, reason: new InvalidPhaseIdentityError(phase).message };
|
|
5486
|
+
}
|
|
5487
|
+
try {
|
|
5488
|
+
writeEngagementEnv(engagementId, { [PHASE_STAMP_ENV_KEY]: phase }, home, [PHASE_STAMP_ENV_KEY]);
|
|
5489
|
+
return null;
|
|
5490
|
+
} catch (err) {
|
|
5491
|
+
return { path, reason: err instanceof Error ? err.message : String(err) };
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
|
|
4082
5495
|
// dist/missing-route.js
|
|
4083
5496
|
var MESSAGE = {
|
|
4084
5497
|
GET: /^Route GET .* not found\.$/s,
|
|
@@ -4105,7 +5518,13 @@ var REFUSAL_REASONS = phaseRecordRefusalReasonSchema.options;
|
|
|
4105
5518
|
function buildRecordUrl(credential, phase) {
|
|
4106
5519
|
return `${credential.serviceUrl}/engagements/${encodeURIComponent(credential.engagementId)}/phases/${encodeURIComponent(phase)}/build-record`;
|
|
4107
5520
|
}
|
|
4108
|
-
|
|
5521
|
+
function clearStampFor(engagementId, phase, home) {
|
|
5522
|
+
const stamped = readEngagementEnv(engagementId, home)?.[PHASE_STAMP_ENV_KEY];
|
|
5523
|
+
if (stamped !== phase)
|
|
5524
|
+
return null;
|
|
5525
|
+
return writePhaseStamp(engagementId, null, home);
|
|
5526
|
+
}
|
|
5527
|
+
async function obtainBuildRecord(credential, repoRoot, phase, io = NODE_RECORD_PAIR_IO, home) {
|
|
4109
5528
|
const url = buildRecordUrl(credential, phase);
|
|
4110
5529
|
let res;
|
|
4111
5530
|
let text;
|
|
@@ -4158,7 +5577,8 @@ async function obtainBuildRecord(credential, repoRoot, phase, io = NODE_RECORD_P
|
|
|
4158
5577
|
kind: "written",
|
|
4159
5578
|
jsonPath: relative3(repoRoot, result.jsonPath),
|
|
4160
5579
|
mdPath: relative3(repoRoot, result.mdPath),
|
|
4161
|
-
headline: latestCloseHeadline(answer.record)
|
|
5580
|
+
headline: latestCloseHeadline(answer.record),
|
|
5581
|
+
stampFailure: clearStampFor(credential.engagementId, phase, home)
|
|
4162
5582
|
};
|
|
4163
5583
|
}
|
|
4164
5584
|
if (isMissingRoute("GET", res.status, raw)) {
|