halfcycle 0.4.17 → 0.4.18
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 +71 -11
- package/dist/cli.js +47 -26
- package/dist/cli.js.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/review.d.ts +19 -4
- package/dist/review.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halfcycle",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.18",
|
|
4
4
|
"description": "Halfcycle Method bundle — resolution-stub slash commands, remote method-delivery registration, and governance-hook wiring for a Halfcycle engagement repo. It ships NO worker role files: a project's roles are authored from that project's own recorded decisions at orchestration kickoff (FX-2, W3-F-27).",
|
|
5
5
|
"commands": [
|
|
6
6
|
{
|
package/bin/bin.bundle.mjs
CHANGED
|
@@ -18295,7 +18295,8 @@ var chatReviewAcceptRequestSchema = external_exports.object({
|
|
|
18295
18295
|
act: external_exports.literal("accept"),
|
|
18296
18296
|
reference: phaseIdentitySchema,
|
|
18297
18297
|
reviewVersion: external_exports.number().int().min(0),
|
|
18298
|
-
parts: external_exports.array(systemPartIdSchema).max(REVIEW_PARTS_MAX)
|
|
18298
|
+
parts: external_exports.array(systemPartIdSchema).max(REVIEW_PARTS_MAX),
|
|
18299
|
+
waitingClaims: external_exports.literal(true).optional()
|
|
18299
18300
|
}).strict();
|
|
18300
18301
|
function notedRequest(act) {
|
|
18301
18302
|
return external_exports.object({
|
|
@@ -18310,12 +18311,20 @@ var chatReviewQuestionRequestSchema = notedRequest("question");
|
|
|
18310
18311
|
var chatReviewSendBackRequestSchema = notedRequest("send-back");
|
|
18311
18312
|
var chatReviewCarryRequestSchema = notedRequest("carry");
|
|
18312
18313
|
var chatReviewDropRequestSchema = notedRequest("drop");
|
|
18314
|
+
var chatReviewRejectRequestSchema = external_exports.object({
|
|
18315
|
+
act: external_exports.literal("reject"),
|
|
18316
|
+
reference: phaseIdentitySchema,
|
|
18317
|
+
reviewVersion: external_exports.number().int().min(0),
|
|
18318
|
+
task: buildTaskIdSchema,
|
|
18319
|
+
note: reviewNoteWireSchema
|
|
18320
|
+
}).strict();
|
|
18313
18321
|
var chatReviewRequestSchema = external_exports.discriminatedUnion("act", [
|
|
18314
18322
|
chatReviewAcceptRequestSchema,
|
|
18315
18323
|
chatReviewQuestionRequestSchema,
|
|
18316
18324
|
chatReviewSendBackRequestSchema,
|
|
18317
18325
|
chatReviewCarryRequestSchema,
|
|
18318
|
-
chatReviewDropRequestSchema
|
|
18326
|
+
chatReviewDropRequestSchema,
|
|
18327
|
+
chatReviewRejectRequestSchema
|
|
18319
18328
|
]);
|
|
18320
18329
|
function bareOutcome2(outcome) {
|
|
18321
18330
|
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
@@ -18328,7 +18337,8 @@ var chatReviewResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
|
18328
18337
|
...reviewDecisionResultSchema.options.filter(notTheConsoleNotDecidable),
|
|
18329
18338
|
bareOutcome2("show-first"),
|
|
18330
18339
|
bareOutcome2("not-offered"),
|
|
18331
|
-
chatAmbiguousSchema
|
|
18340
|
+
chatAmbiguousSchema,
|
|
18341
|
+
bareOutcome2("nothing-waiting")
|
|
18332
18342
|
]);
|
|
18333
18343
|
var reviewAnswerRequestSchema = external_exports.object({
|
|
18334
18344
|
part: systemPartIdSchema,
|
|
@@ -30429,6 +30439,9 @@ function reviewPhraseShape(prompt) {
|
|
|
30429
30439
|
const line2 = prompt.trim();
|
|
30430
30440
|
if (LINE_BREAK.test(line2))
|
|
30431
30441
|
return null;
|
|
30442
|
+
const reject = REJECT_VERB.exec(line2);
|
|
30443
|
+
if (reject !== null)
|
|
30444
|
+
return rejectShape(line2.slice(reject[0].length));
|
|
30432
30445
|
for (const [prefix, act] of VERBS) {
|
|
30433
30446
|
const verb = prefix.exec(line2);
|
|
30434
30447
|
if (verb === null)
|
|
@@ -30446,6 +30459,21 @@ function reviewPhraseShape(prompt) {
|
|
|
30446
30459
|
}
|
|
30447
30460
|
return null;
|
|
30448
30461
|
}
|
|
30462
|
+
var REJECT_VERB = /^reject /i;
|
|
30463
|
+
function rejectShape(rest) {
|
|
30464
|
+
const colon = rest.indexOf(":");
|
|
30465
|
+
if (colon === -1)
|
|
30466
|
+
return null;
|
|
30467
|
+
const head = rest.slice(0, colon);
|
|
30468
|
+
const slash = head.indexOf("/");
|
|
30469
|
+
if (slash === -1)
|
|
30470
|
+
return null;
|
|
30471
|
+
const reference = head.slice(0, slash);
|
|
30472
|
+
const task = head.slice(slash + 1);
|
|
30473
|
+
if (!isValidPhaseIdentity(reference) || /\s/.test(task) || !buildTaskIdSchema.safeParse(task).success)
|
|
30474
|
+
return null;
|
|
30475
|
+
return { kind: "reject", reference, task, words: rest.slice(colon + 1).trim() };
|
|
30476
|
+
}
|
|
30449
30477
|
function partShape(act, head, words) {
|
|
30450
30478
|
const slash = head.indexOf("/");
|
|
30451
30479
|
if (slash === -1)
|
|
@@ -30458,10 +30486,15 @@ function partShape(act, head, words) {
|
|
|
30458
30486
|
}
|
|
30459
30487
|
function matchReviewPhraseShape(shape, reviews) {
|
|
30460
30488
|
const resolved = resolvePhaseReference(shape.reference, reviews);
|
|
30461
|
-
const act = shape.kind === "phase" ? "accept" : shape.act;
|
|
30489
|
+
const act = shape.kind === "phase" ? "accept" : shape.kind === "reject" ? "reject" : shape.act;
|
|
30462
30490
|
if (resolved.kind === "ambiguous")
|
|
30463
30491
|
return { kind: "ambiguous", act, entries: resolved.entries };
|
|
30464
30492
|
const entry = resolved.kind === "found" ? resolved.entry : null;
|
|
30493
|
+
if (shape.kind === "reject") {
|
|
30494
|
+
if (entry === null)
|
|
30495
|
+
return { kind: "show-first", act: "reject" };
|
|
30496
|
+
return { kind: "reject", entry, reference: shape.reference, task: shape.task, words: shape.words };
|
|
30497
|
+
}
|
|
30465
30498
|
if (shape.kind === "phase") {
|
|
30466
30499
|
if (entry === null)
|
|
30467
30500
|
return { kind: "nothing" };
|
|
@@ -30650,6 +30683,8 @@ function reviewWrongActLine(name, built) {
|
|
|
30650
30683
|
}
|
|
30651
30684
|
function wordsActNoun(act) {
|
|
30652
30685
|
switch (act) {
|
|
30686
|
+
case "reject":
|
|
30687
|
+
return "a rejection";
|
|
30653
30688
|
case "question":
|
|
30654
30689
|
return "a question";
|
|
30655
30690
|
case "send-back":
|
|
@@ -30686,7 +30721,10 @@ function reviewPartNotListedLine(part, phase) {
|
|
|
30686
30721
|
return line(`${NOTHING_RECORDED}: "${part}" is not a part of the review of ${namedPhase(phase)} as it was listed here.`);
|
|
30687
30722
|
}
|
|
30688
30723
|
function reviewNothingToAcceptLine(phase) {
|
|
30689
|
-
return line(`${NOTHING_RECORDED}: no built part of ${namedPhase(phase)} waits for your decision.`);
|
|
30724
|
+
return line(`${NOTHING_RECORDED}: no built part and no check nobody ran of ${namedPhase(phase)} waits for your decision.`);
|
|
30725
|
+
}
|
|
30726
|
+
function reviewNoClaimWaitingLine(task, phase) {
|
|
30727
|
+
return line(`${NOTHING_RECORDED}: no check nobody ran on task "${task}" of ${namedPhase(phase)} waits for your answer. ${LIST_AGAIN} and copy the task from its reject line.`);
|
|
30690
30728
|
}
|
|
30691
30729
|
function reviewListedTooLongAgoLine(phase) {
|
|
30692
30730
|
return line(`${NOTHING_RECORDED}: ${namedPhase(phase)} was listed an hour or more ago. ${LIST_AGAIN}, then type the line again within the hour.`);
|
|
@@ -30762,9 +30800,12 @@ function reviewRecordedLine(decided, phase, waiting) {
|
|
|
30762
30800
|
}
|
|
30763
30801
|
function reviewBulkRecordedLine(accepted, phase, waiting) {
|
|
30764
30802
|
const named = namedPhase(phase);
|
|
30765
|
-
const first = accepted === 1 ? `Recorded in your session: 1 part of ${named} accepted.` : `Recorded in your session: ${accepted} parts of ${named} accepted.`;
|
|
30803
|
+
const first = accepted === 0 ? `Recorded in your session: any check nobody ran of ${named} that waited is accepted.` : accepted === 1 ? `Recorded in your session: 1 part of ${named} accepted, with any check nobody ran that waited.` : `Recorded in your session: ${accepted} parts of ${named} accepted, with any check nobody ran that waited.`;
|
|
30766
30804
|
return line(`${first} ${stillWaiting(waiting)}`);
|
|
30767
30805
|
}
|
|
30806
|
+
function reviewClaimsRejectedLine(task, phase, waiting) {
|
|
30807
|
+
return line(`Recorded in your session: the checks nobody ran on task "${task}" are rejected, with your words. ${stillWaitingOf(phase, waiting)}`);
|
|
30808
|
+
}
|
|
30768
30809
|
function reviewClosedLine(phase) {
|
|
30769
30810
|
return `Recorded in your session. That was the last decision: phase ${namedPhase(phase)} is closed. Run its close step now, then tell the person what it says.`;
|
|
30770
30811
|
}
|
|
@@ -30791,12 +30832,16 @@ function reviewLineForAnswer(context, answer) {
|
|
|
30791
30832
|
switch (answer.outcome) {
|
|
30792
30833
|
case "recorded": {
|
|
30793
30834
|
if (answer.closed) {
|
|
30794
|
-
return
|
|
30835
|
+
return context.listedParts === 0 ? reviewNoPartsClosedLine(phase) : reviewClosedLine(phase);
|
|
30795
30836
|
}
|
|
30837
|
+
if (context.task !== null)
|
|
30838
|
+
return reviewClaimsRejectedLine(context.task, phase, answer.waiting);
|
|
30796
30839
|
if (context.bulk)
|
|
30797
30840
|
return reviewBulkRecordedLine(answer.decided.length, phase, answer.waiting);
|
|
30798
30841
|
return reviewRecordedLine(answer.decided[0], phase, answer.waiting);
|
|
30799
30842
|
}
|
|
30843
|
+
case "nothing-waiting":
|
|
30844
|
+
return context.task !== null ? reviewNoClaimWaitingLine(context.task, phase) : reviewNothingToAcceptLine(phase);
|
|
30800
30845
|
case "review-changed":
|
|
30801
30846
|
return reviewChangedLine(phase);
|
|
30802
30847
|
case "no-review":
|
|
@@ -30977,14 +31022,22 @@ async function checkAndSendReview(match, engagementId, credential, env, opts) {
|
|
|
30977
31022
|
return reviewListedTooLongAgoLine(entry.phase);
|
|
30978
31023
|
let candidate;
|
|
30979
31024
|
if (match.kind === "accept") {
|
|
30980
|
-
if (entry.parts.length > 0 && match.parts.length === 0)
|
|
30981
|
-
return reviewNothingToAcceptLine(entry.phase);
|
|
30982
31025
|
candidate = {
|
|
30983
31026
|
act: "accept",
|
|
30984
31027
|
reference: match.reference,
|
|
30985
31028
|
reviewVersion: entry.reviewVersion,
|
|
30986
|
-
parts: match.parts.map((p) => p.part)
|
|
31029
|
+
parts: match.parts.map((p) => p.part),
|
|
31030
|
+
waitingClaims: true
|
|
30987
31031
|
};
|
|
31032
|
+
} else if (match.kind === "reject") {
|
|
31033
|
+
const words = match.words;
|
|
31034
|
+
if (words === "")
|
|
31035
|
+
return reviewNoWordsLine("reject");
|
|
31036
|
+
if (!reviewNoteWireSchema.safeParse(words).success)
|
|
31037
|
+
return reviewWordsTooLongLine();
|
|
31038
|
+
if (looksLikeSecret(words))
|
|
31039
|
+
return reviewWordsLookSecretLine();
|
|
31040
|
+
candidate = { act: "reject", reference: match.reference, reviewVersion: entry.reviewVersion, task: match.task, note: words };
|
|
30988
31041
|
} else {
|
|
30989
31042
|
const { act, part } = match;
|
|
30990
31043
|
if (!reviewActsFor(part.built).includes(act))
|
|
@@ -31037,7 +31090,14 @@ async function postReview(bulk, entry, request, engagementId, credential, env, o
|
|
|
31037
31090
|
return reviewCannotReachLine();
|
|
31038
31091
|
moveListedReviewForward(engagementId, opts.home, entry, answer.reviewVersion, answer.decided);
|
|
31039
31092
|
}
|
|
31040
|
-
return reviewLineForAnswer({
|
|
31093
|
+
return reviewLineForAnswer({
|
|
31094
|
+
act: request.act,
|
|
31095
|
+
bulk,
|
|
31096
|
+
phase: entry.phase,
|
|
31097
|
+
number: entry.number,
|
|
31098
|
+
listedParts: entry.parts.length,
|
|
31099
|
+
task: request.act === "reject" ? request.task : null
|
|
31100
|
+
}, answer);
|
|
31041
31101
|
} catch {
|
|
31042
31102
|
return reviewCannotReachLine();
|
|
31043
31103
|
} finally {
|
package/dist/cli.js
CHANGED
|
@@ -4851,7 +4851,8 @@ var chatReviewAcceptRequestSchema = z30.object({
|
|
|
4851
4851
|
act: z30.literal("accept"),
|
|
4852
4852
|
reference: phaseIdentitySchema,
|
|
4853
4853
|
reviewVersion: z30.number().int().min(0),
|
|
4854
|
-
parts: z30.array(systemPartIdSchema).max(REVIEW_PARTS_MAX)
|
|
4854
|
+
parts: z30.array(systemPartIdSchema).max(REVIEW_PARTS_MAX),
|
|
4855
|
+
waitingClaims: z30.literal(true).optional()
|
|
4855
4856
|
}).strict();
|
|
4856
4857
|
function notedRequest(act) {
|
|
4857
4858
|
return z30.object({
|
|
@@ -4866,12 +4867,20 @@ var chatReviewQuestionRequestSchema = notedRequest("question");
|
|
|
4866
4867
|
var chatReviewSendBackRequestSchema = notedRequest("send-back");
|
|
4867
4868
|
var chatReviewCarryRequestSchema = notedRequest("carry");
|
|
4868
4869
|
var chatReviewDropRequestSchema = notedRequest("drop");
|
|
4870
|
+
var chatReviewRejectRequestSchema = z30.object({
|
|
4871
|
+
act: z30.literal("reject"),
|
|
4872
|
+
reference: phaseIdentitySchema,
|
|
4873
|
+
reviewVersion: z30.number().int().min(0),
|
|
4874
|
+
task: buildTaskIdSchema,
|
|
4875
|
+
note: reviewNoteWireSchema
|
|
4876
|
+
}).strict();
|
|
4869
4877
|
var chatReviewRequestSchema = z30.discriminatedUnion("act", [
|
|
4870
4878
|
chatReviewAcceptRequestSchema,
|
|
4871
4879
|
chatReviewQuestionRequestSchema,
|
|
4872
4880
|
chatReviewSendBackRequestSchema,
|
|
4873
4881
|
chatReviewCarryRequestSchema,
|
|
4874
|
-
chatReviewDropRequestSchema
|
|
4882
|
+
chatReviewDropRequestSchema,
|
|
4883
|
+
chatReviewRejectRequestSchema
|
|
4875
4884
|
]);
|
|
4876
4885
|
function bareOutcome2(outcome) {
|
|
4877
4886
|
return z30.object({ outcome: z30.literal(outcome) }).strict();
|
|
@@ -4884,7 +4893,8 @@ var chatReviewResultSchema = z30.discriminatedUnion("outcome", [
|
|
|
4884
4893
|
...reviewDecisionResultSchema.options.filter(notTheConsoleNotDecidable),
|
|
4885
4894
|
bareOutcome2("show-first"),
|
|
4886
4895
|
bareOutcome2("not-offered"),
|
|
4887
|
-
chatAmbiguousSchema
|
|
4896
|
+
chatAmbiguousSchema,
|
|
4897
|
+
bareOutcome2("nothing-waiting")
|
|
4888
4898
|
]);
|
|
4889
4899
|
var reviewAnswerRequestSchema = z30.object({
|
|
4890
4900
|
part: systemPartIdSchema,
|
|
@@ -5348,8 +5358,8 @@ function autonomyA13(accepted, carried) {
|
|
|
5348
5358
|
return `Your autonomy setting accepted the ${String(accepted)} built parts and carried ${String(carried)} unbuilt parts forward. The phase is closed.`;
|
|
5349
5359
|
}
|
|
5350
5360
|
function autonomyA14(count, parts, acceptLine) {
|
|
5351
|
-
const typed = acceptLine === null ? 'say "review what was built" and type the lines it gives.' : `say "review what was built", then type ${acceptLine}.`;
|
|
5352
|
-
return `The phase waits for you: ${String(count)} tests the agents said pass were not run by Halfcycle, so ${namesOf(parts)} wait for you too. Only you can accept or reject those tests
|
|
5361
|
+
const typed = acceptLine === null ? 'say "review what was built" and type the lines it gives.' : `say "review what was built", then type ${acceptLine} to accept them with those parts, or type the reject line it gives for a task's tests.`;
|
|
5362
|
+
return `The phase waits for you: ${String(count)} tests the agents said pass were not run by Halfcycle, so ${namesOf(parts)} wait for you too. Only you can accept or reject those tests. In your own Claude Code session, ` + typed;
|
|
5353
5363
|
}
|
|
5354
5364
|
function autonomyA15(count) {
|
|
5355
5365
|
return `The phase waits for you: ${String(count)} parts were built without an approved scope, and only you can decide them.`;
|
|
@@ -7413,12 +7423,13 @@ ${GENERATED_USER_PROMPT_SCOPE_HEADER} the Halfcycle installer, now also for the
|
|
|
7413
7423
|
# own on or off, by typing one line as the whole prompt in their own Claude
|
|
7414
7424
|
# Code session: "approve <phase>", "send back <phase>: <note>", "accept
|
|
7415
7425
|
# <phase>/<part>", "question <phase>/<part>: <words>", "carry <phase>/<part>:
|
|
7416
|
-
# <words>", "drop <phase>/<part>: <words>", "
|
|
7426
|
+
# <words>", "drop <phase>/<part>: <words>", "reject <phase>/<task>: <words>",
|
|
7427
|
+
# "autonomy on" or "autonomy off".
|
|
7417
7428
|
#
|
|
7418
7429
|
# AN ORDINARY PROMPT STARTS NOTHING. This script reads the hook input once and
|
|
7419
7430
|
# looks only at the start of the prompt's value. Unless the prompt begins, after
|
|
7420
7431
|
# any whitespace (typed, or escaped in the input), with "approve ", "send back ",
|
|
7421
|
-
# "accept ", "question ", "carry ", "drop " or "autonomy ", in any case, it exits
|
|
7432
|
+
# "accept ", "question ", "carry ", "drop ", "reject " or "autonomy ", in any case, it exits
|
|
7422
7433
|
# 0 with no output, and Node never starts. A quote inside any other field arrives
|
|
7423
7434
|
# escaped, so no other field (the folder the session is in, for one) can read as
|
|
7424
7435
|
# the start of the prompt.
|
|
@@ -7442,7 +7453,7 @@ IFS= read -r -d '' HC_INPUT || true
|
|
|
7442
7453
|
# \\u escape, or as the UTF-8 bytes of a Unicode space. Compared byte for byte.
|
|
7443
7454
|
HC_LEAD='[[:space:]]|\\\\[nrtf]|\\\\u(000[9a-d]|0020|00a0|1680|200[0-9a]|202[89f]|205f|3000|feff)'
|
|
7444
7455
|
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'
|
|
7445
|
-
if ! printf '%s' "$HC_INPUT" | LC_ALL=C grep -Eiq "\\"prompt\\"[[:space:]]*:[[:space:]]*\\"($HC_LEAD)*(approve|send back|accept|question|carry|drop|autonomy) "; then
|
|
7456
|
+
if ! printf '%s' "$HC_INPUT" | LC_ALL=C grep -Eiq "\\"prompt\\"[[:space:]]*:[[:space:]]*\\"($HC_LEAD)*(approve|send back|accept|question|carry|drop|reject|autonomy) "; then
|
|
7446
7457
|
exit 0
|
|
7447
7458
|
fi
|
|
7448
7459
|
|
|
@@ -12927,23 +12938,36 @@ function typedLine(act, reference, part) {
|
|
|
12927
12938
|
return `drop ${reference}/${part}: <why>`;
|
|
12928
12939
|
}
|
|
12929
12940
|
}
|
|
12930
|
-
function
|
|
12941
|
+
function rv7aLine(reference) {
|
|
12942
|
+
return `The line accept ${reference} also accepts every check nobody ran that is listed below. Reject a task's checks first if you do not accept them.`;
|
|
12943
|
+
}
|
|
12944
|
+
function tasksWithWaitingClaims(claims) {
|
|
12945
|
+
return [...new Set(claims.filter((c) => c.answer === null).map((c) => c.task))];
|
|
12946
|
+
}
|
|
12947
|
+
function rv7Lines(view, claims) {
|
|
12931
12948
|
const reference = typedPhaseReference(view.phase, view.number);
|
|
12932
|
-
|
|
12933
|
-
return [`This phase has no parts to review. To close it, type: accept ${reference}`];
|
|
12949
|
+
const claimTasks = tasksWithWaitingClaims(claims);
|
|
12934
12950
|
const decidable = view.parts.filter((p) => p.decidable);
|
|
12935
|
-
if (
|
|
12936
|
-
|
|
12951
|
+
if (claimTasks.length === 0) {
|
|
12952
|
+
if (view.parts.length === 0)
|
|
12953
|
+
return [`This phase has no parts to review. To close it, type: accept ${reference}`];
|
|
12954
|
+
if (decidable.length === 0)
|
|
12955
|
+
return ["No part waits for your decision now."];
|
|
12956
|
+
}
|
|
12937
12957
|
const lines = ["To decide, type one of these lines in your own Claude Code session:"];
|
|
12938
12958
|
for (const part of decidable) {
|
|
12939
12959
|
for (const act of reviewActsFor(part.built))
|
|
12940
12960
|
lines.push(` ${typedLine(act, reference, part.part)}`);
|
|
12941
12961
|
}
|
|
12942
|
-
|
|
12962
|
+
for (const task of claimTasks)
|
|
12963
|
+
lines.push(` reject ${reference}/${task}: <why>`);
|
|
12964
|
+
if (decidable.some((p) => p.built) || claimTasks.length > 0)
|
|
12943
12965
|
lines.push(` accept ${reference}`);
|
|
12966
|
+
if (claimTasks.length > 0)
|
|
12967
|
+
lines.push(rv7aLine(reference));
|
|
12944
12968
|
return lines;
|
|
12945
12969
|
}
|
|
12946
|
-
function reviewListingLines(view) {
|
|
12970
|
+
function reviewListingLines(view, claims = []) {
|
|
12947
12971
|
const lines = [rv1Line(view)];
|
|
12948
12972
|
if (!view.counted)
|
|
12949
12973
|
lines.push(RV1A_LINE);
|
|
@@ -12951,7 +12975,7 @@ function reviewListingLines(view) {
|
|
|
12951
12975
|
lines.push(...observedPhaseLines(view.observed));
|
|
12952
12976
|
for (const part of view.parts)
|
|
12953
12977
|
lines.push(...partLines(part, view));
|
|
12954
|
-
lines.push(...rv7Lines(view));
|
|
12978
|
+
lines.push(...rv7Lines(view, claims));
|
|
12955
12979
|
return lines;
|
|
12956
12980
|
}
|
|
12957
12981
|
var CALLS_HEADING2 = "Calls made without asking you";
|
|
@@ -12976,21 +13000,17 @@ var CHECKS_SUBHEADING = "An agent says these pass and Halfcycle never ran them.
|
|
|
12976
13000
|
function uncheckedClaimLine(test) {
|
|
12977
13001
|
return `Unchecked: ${test.claimedBy} says "${test.label}" passes. Halfcycle never ran it.`;
|
|
12978
13002
|
}
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
const only = "Accept or reject each one in the System view; this cannot be done by typing in chat";
|
|
12982
|
-
return address === void 0 ? `${only}.` : `${only}: ${address}`;
|
|
12983
|
-
}
|
|
12984
|
-
function checksSectionLines(work, engagementId) {
|
|
13003
|
+
var ANSWER_CLAIMS_BY_TYPING_LINE = "To answer them, type the reject or accept line listed above in your own Claude Code session.";
|
|
13004
|
+
function checksSectionLines(work) {
|
|
12985
13005
|
const unchecked = work.tasks.flatMap((task) => task.tests.filter((t) => t.state === "unchecked"));
|
|
12986
13006
|
if (unchecked.length === 0)
|
|
12987
13007
|
return [];
|
|
12988
|
-
return [CHECKS_HEADING, CHECKS_SUBHEADING, ...unchecked.map(uncheckedClaimLine),
|
|
13008
|
+
return [CHECKS_HEADING, CHECKS_SUBHEADING, ...unchecked.map(uncheckedClaimLine), ANSWER_CLAIMS_BY_TYPING_LINE];
|
|
12989
13009
|
}
|
|
12990
|
-
function workSectionLines(work,
|
|
13010
|
+
function workSectionLines(work, _engagementId) {
|
|
12991
13011
|
if (work === null)
|
|
12992
13012
|
return [];
|
|
12993
|
-
return [...callsSectionLines(work.calls), ...checksSectionLines(work
|
|
13013
|
+
return [...callsSectionLines(work.calls), ...checksSectionLines(work)];
|
|
12994
13014
|
}
|
|
12995
13015
|
function rv8Line(view) {
|
|
12996
13016
|
if (view.state === "closed") {
|
|
@@ -13132,7 +13152,8 @@ async function runReviewShow(repoRoot, phase, deps) {
|
|
|
13132
13152
|
if (view.state !== "open")
|
|
13133
13153
|
return refused(rv8Line(view));
|
|
13134
13154
|
const work = await deps.readWork(credential, phase);
|
|
13135
|
-
const
|
|
13155
|
+
const phaseWork = work.kind === "work" ? work.work : null;
|
|
13156
|
+
const stdout = `${[...reviewListingLines(view, phaseWork?.uncheckedClaims ?? []), ...workSectionLines(phaseWork, credential.engagementId)].join("\n")}
|
|
13136
13157
|
`;
|
|
13137
13158
|
const written = deps.recordShown(credential.engagementId, shownReviewEntry(view, deps.now().toISOString()));
|
|
13138
13159
|
if (!written.ok)
|