halfcycle 0.4.10 → 0.4.11
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 +4 -1
- package/dist/build-record/render-v2.d.ts +5 -0
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +53 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.js +52 -10
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2082,11 +2082,16 @@ var phaseReviewViewSchema = z13.discriminatedUnion("state", [
|
|
|
2082
2082
|
|
|
2083
2083
|
// ../events/dist/build-record-v3.js
|
|
2084
2084
|
var BUILD_RECORD_V3_FORMAT = "halfcycle-build-record/v3";
|
|
2085
|
+
var recordRoundStatedSchema = z14.object({
|
|
2086
|
+
actor: attestedCloseSchema.shape.actor,
|
|
2087
|
+
statements: attestedStatementsSchema
|
|
2088
|
+
}).strict();
|
|
2085
2089
|
var recordReviewRoundSchema = z14.object({
|
|
2086
2090
|
round: z14.number().int().min(1),
|
|
2087
2091
|
openedAt: utcIso8601,
|
|
2088
2092
|
verdict: walkVerdictSchema,
|
|
2089
|
-
findings: z14.number().int().min(0)
|
|
2093
|
+
findings: z14.number().int().min(0),
|
|
2094
|
+
stated: recordRoundStatedSchema.optional()
|
|
2090
2095
|
}).strict();
|
|
2091
2096
|
var recordReviewApprovalSchema = z14.discriminatedUnion("kind", [
|
|
2092
2097
|
z14.object({
|
|
@@ -2148,6 +2153,9 @@ var recordReviewSchema = z14.object({
|
|
|
2148
2153
|
if (r.round !== i + 1) {
|
|
2149
2154
|
ctx.addIssue({ code: "custom", path: ["rounds", i, "round"], message: "rounds must be numbered 1, 2, 3 \u2026 in order with no gap" });
|
|
2150
2155
|
}
|
|
2156
|
+
if (i === v.rounds.length - 1 && r.stated !== void 0) {
|
|
2157
|
+
ctx.addIssue({ code: "custom", path: ["rounds", i, "stated"], message: "the last round's words are the close's own, so the round does not repeat them" });
|
|
2158
|
+
}
|
|
2151
2159
|
});
|
|
2152
2160
|
const seen = /* @__PURE__ */ new Set();
|
|
2153
2161
|
v.parts.forEach((p, i) => {
|
|
@@ -5226,12 +5234,13 @@ function machines(coverage, checks) {
|
|
|
5226
5234
|
const line = `${label}${String(coverage.enrolled)}. Of these, ${String(coverage.conformant)} had reported Halfcycle's checks as fully set up.`;
|
|
5227
5235
|
return checks === "not-observed" && coverage.conformant > 0 ? `${line} Set up is not the same as running: Halfcycle has no record of any check running during this phase.` : line;
|
|
5228
5236
|
}
|
|
5229
|
-
function walkLines(walk, p) {
|
|
5237
|
+
function walkLines(walk, p, closingRound = false) {
|
|
5230
5238
|
const label = "> - Acceptance walk (the finished work tried as a user would, by someone other than its builder): ";
|
|
5231
5239
|
if (walk === null)
|
|
5232
5240
|
return [`${label}the person closing the phase reported none.`];
|
|
5241
|
+
const it = closingRound ? "the round that closed the phase" : "it";
|
|
5233
5242
|
const lines = [
|
|
5234
|
-
`${label}${walk.verdict === "clean" ?
|
|
5243
|
+
`${label}${walk.verdict === "clean" ? `the person closing the phase said ${it} found no problems.` : `the person closing the phase said ${it} found problems.`}`
|
|
5235
5244
|
];
|
|
5236
5245
|
walk.findings.forEach((finding, i) => {
|
|
5237
5246
|
lines.push(`> - Finding ${String(i + 1)}: ${p.text(finding)}`);
|
|
@@ -5250,12 +5259,12 @@ function decisionLine(attested) {
|
|
|
5250
5259
|
}
|
|
5251
5260
|
return attested.walk !== null && attested.walk.verdict === "defects" ? "> - Decision: close the phase as it stood, with the problems its acceptance walk found." : "> - Decision: the phase's agreed finish conditions were met.";
|
|
5252
5261
|
}
|
|
5253
|
-
function renderStated(attested, p) {
|
|
5262
|
+
function renderStated(attested, p, closingRound = false) {
|
|
5254
5263
|
const lines = [
|
|
5255
5264
|
decisionLine(attested),
|
|
5256
5265
|
`> - Name given: ${attested.actor === null ? "removed with the account that made this close" : p.text(attested.actor)}`,
|
|
5257
5266
|
`> - Reason given: ${attested.reason === null ? "none." : p.text(attested.reason)}`,
|
|
5258
|
-
...walkLines(attested.walk, p),
|
|
5267
|
+
...walkLines(attested.walk, p, closingRound),
|
|
5259
5268
|
`> - Code closed at (commit): ${statedOrNot(attested.closeCommit, p)}`,
|
|
5260
5269
|
`> - What the phase set out to prove: ${statedOrNot(attested.statements.thesis, p)}`,
|
|
5261
5270
|
`> - What came out of it: ${statedOrNot(attested.statements.outcome, p)}`
|
|
@@ -5271,7 +5280,7 @@ function renderStated(attested, p) {
|
|
|
5271
5280
|
}
|
|
5272
5281
|
return lines.join("\n");
|
|
5273
5282
|
}
|
|
5274
|
-
function renderClose(heading, observed, attested, checks, p) {
|
|
5283
|
+
function renderClose(heading, observed, attested, checks, p, closingRound = false) {
|
|
5275
5284
|
return [
|
|
5276
5285
|
heading,
|
|
5277
5286
|
headline(observed, attested, checks),
|
|
@@ -5283,7 +5292,7 @@ function renderClose(heading, observed, attested, checks, p) {
|
|
|
5283
5292
|
machines(observed.seatCoverage, checks)
|
|
5284
5293
|
].join("\n"),
|
|
5285
5294
|
STATED_LABEL,
|
|
5286
|
-
renderStated(attested, p)
|
|
5295
|
+
renderStated(attested, p, closingRound)
|
|
5287
5296
|
];
|
|
5288
5297
|
}
|
|
5289
5298
|
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.";
|
|
@@ -5332,6 +5341,37 @@ function renderReview(record2, p) {
|
|
|
5332
5341
|
blocks.push(removals);
|
|
5333
5342
|
return blocks;
|
|
5334
5343
|
}
|
|
5344
|
+
var EARLIER_ROUNDS_LABEL = `${STATED_LABEL} What was said each time the owner's review was asked for, before the round that closed the phase. What was said for that last round is under the close above. If the account that asked for a round is later deleted, the name given for that round is removed.`;
|
|
5345
|
+
function renderRoundStated(round, stated, p) {
|
|
5346
|
+
const label = "> - Acceptance walk (the finished work tried as a user would, by someone other than its builder): ";
|
|
5347
|
+
const walk = round.verdict === "clean" ? "the person asking for this round said it found no problems." : round.findings === 0 ? "the person asking for this round said it found problems." : `the person asking for this round said it found ${counted(round.findings, "problem", "problems")}.`;
|
|
5348
|
+
const lines = [
|
|
5349
|
+
`> - Name given: ${stated.actor === null ? "removed with the account that asked for this round" : p.text(stated.actor)}`,
|
|
5350
|
+
`${label}${walk}`,
|
|
5351
|
+
`> - What the phase set out to prove: ${statedOrNot(stated.statements.thesis, p)}`,
|
|
5352
|
+
`> - What came out of it: ${statedOrNot(stated.statements.outcome, p)}`
|
|
5353
|
+
];
|
|
5354
|
+
const deviations = stated.statements.deviations;
|
|
5355
|
+
if (deviations.length === 0) {
|
|
5356
|
+
lines.push("> - Changes from the plan: None stated by the client.");
|
|
5357
|
+
} else {
|
|
5358
|
+
lines.push("> - Changes from the plan:");
|
|
5359
|
+
deviations.forEach((deviation, i) => {
|
|
5360
|
+
lines.push(`> - Change ${String(i + 1)}: ${p.text(deviation)}`);
|
|
5361
|
+
});
|
|
5362
|
+
}
|
|
5363
|
+
return lines.join("\n");
|
|
5364
|
+
}
|
|
5365
|
+
function renderEarlierRounds(record2, p) {
|
|
5366
|
+
const rounds = record2.review.rounds;
|
|
5367
|
+
const blocks = [];
|
|
5368
|
+
for (const round of rounds) {
|
|
5369
|
+
if (round.stated === void 0)
|
|
5370
|
+
continue;
|
|
5371
|
+
blocks.push(`### Round ${String(round.round)} of ${String(rounds.length)}`, renderRoundStated(round, round.stated, p));
|
|
5372
|
+
}
|
|
5373
|
+
return blocks.length === 0 ? [] : ["## Earlier rounds of the review", EARLIER_ROUNDS_LABEL, ...blocks];
|
|
5374
|
+
}
|
|
5335
5375
|
function renderBuildRecordV2Markdown(record2) {
|
|
5336
5376
|
const p = makePrinter();
|
|
5337
5377
|
const attestedBySequence = /* @__PURE__ */ new Map();
|
|
@@ -5345,6 +5385,8 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
5345
5385
|
const closes = [...record2.observed.closes].sort((a, b) => a.sequence - b.sequence);
|
|
5346
5386
|
const total = closes.length;
|
|
5347
5387
|
const latest = closes[total - 1];
|
|
5388
|
+
const rounds = record2.format === "halfcycle-build-record/v3" ? record2.review.rounds : [];
|
|
5389
|
+
const roundsAfter = rounds.length <= 1 ? null : `after ${String(rounds.length)} rounds of the owner's review.${rounds.some((r) => r.stated !== void 0) ? ' What was said for each earlier round is under "Earlier rounds of the review".' : ""}`;
|
|
5348
5390
|
const body = [
|
|
5349
5391
|
`Phase: ${phase} (the name the client gave it)`,
|
|
5350
5392
|
OBSERVED_LABEL,
|
|
@@ -5353,12 +5395,12 @@ function renderBuildRecordV2Markdown(record2) {
|
|
|
5353
5395
|
`- Project identifier: ${p.text(record2.observed.engagementId)}. Halfcycle keeps this project's records under this identifier.`,
|
|
5354
5396
|
`- Record format: ${p.text(record2.format)}. This names the layout this file and the .json file beside it follow, for software that reads them.`
|
|
5355
5397
|
].join("\n"),
|
|
5356
|
-
total === 1 ? "This phase was closed once." : `This phase was closed ${String(total)} times. The latest close is described first; each earlier close follows, as it was recorded when it was made
|
|
5398
|
+
total === 1 ? roundsAfter === null ? "This phase was closed once." : `This phase was closed once, ${roundsAfter}` : `This phase was closed ${String(total)} times. The latest close is described first; each earlier close follows, as it was recorded when it was made.${roundsAfter === null ? "" : ` The latest close came ${roundsAfter}`}`,
|
|
5357
5399
|
...renderChecks(record2.observed.checks, p),
|
|
5358
|
-
...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)
|
|
5400
|
+
...renderClose(total === 1 ? "## The close" : `## The latest close (close ${String(latest.sequence)} of ${String(total)})`, latest, attestedBySequence.get(latest.sequence), record2.observed.checks.state, p, rounds.length > 1)
|
|
5359
5401
|
];
|
|
5360
5402
|
if (record2.format === "halfcycle-build-record/v3")
|
|
5361
|
-
body.push(...renderReview(record2, p));
|
|
5403
|
+
body.push(...renderReview(record2, p), ...renderEarlierRounds(record2, p));
|
|
5362
5404
|
if (total > 1) {
|
|
5363
5405
|
body.push("## Earlier closes");
|
|
5364
5406
|
for (const close of closes.slice(0, -1)) {
|