halfcycle 0.4.16 → 0.4.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "halfcycle",
3
- "version": "0.4.16",
3
+ "version": "0.4.17",
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
  {
@@ -15715,12 +15715,25 @@ var seatCoverageSchema = external_exports.object({
15715
15715
  message: "conformant cannot exceed enrolled",
15716
15716
  path: ["conformant"]
15717
15717
  });
15718
+ var LEFT_FOR_OWNER_TEXT_MAX = 300;
15719
+ var LEFT_FOR_OWNER_ENTRIES_MAX = 500;
15720
+ var leftForOwnerDecisionSchema = external_exports.object({
15721
+ item: plainText(LEFT_FOR_OWNER_TEXT_MAX),
15722
+ question: plainText(LEFT_FOR_OWNER_TEXT_MAX)
15723
+ }).strict();
15724
+ var leftForOwnerSchema = external_exports.object({
15725
+ tasks: external_exports.array(plainText(LEFT_FOR_OWNER_TEXT_MAX)).max(LEFT_FOR_OWNER_ENTRIES_MAX),
15726
+ waiting: external_exports.array(leftForOwnerDecisionSchema).max(LEFT_FOR_OWNER_ENTRIES_MAX)
15727
+ }).strict().refine((v) => v.tasks.length + v.waiting.length > 0, {
15728
+ message: "is sent only when some work was left for the owner"
15729
+ });
15718
15730
  var observedCloseSchema = external_exports.object({
15719
15731
  sequence: external_exports.number().int().min(1),
15720
15732
  closedAt: utcIso8601,
15721
15733
  closedBy: closedBySchema,
15722
15734
  crossed: crossedSchema,
15723
- seatCoverage: seatCoverageSchema.nullable()
15735
+ seatCoverage: seatCoverageSchema.nullable(),
15736
+ leftForOwner: leftForOwnerSchema.optional()
15724
15737
  }).strict();
15725
15738
  var couldNotRunCheckSchema = external_exports.object({
15726
15739
  check: plainText(),
@@ -18411,7 +18424,7 @@ var ownerWaitDeclarationSchema = external_exports.object({
18411
18424
  path: ["fixedItem"]
18412
18425
  });
18413
18426
  var ownerWaitDeclarationsSchema = external_exports.object({ declarations: external_exports.array(ownerWaitDeclarationSchema) }).strict();
18414
- var OWNER_WAIT_TOO_MANY = `This project already has ${String(OWNER_WAIT_ADDITIONS_MAX)} things added to what waits for the owner. Ask the owner to take one off in the console first.`;
18427
+ var OWNER_WAIT_TOO_MANY = `This project already has ${String(OWNER_WAIT_ADDITIONS_MAX)} things added to what waits for the owner. Ask the owner to take one off on their settings page in the console first; it cannot be done by typing in chat.`;
18415
18428
 
18416
18429
  // ../events/dist/pacing.js
18417
18430
  var CLAUDE_PLANS = Object.freeze([
@@ -23344,7 +23357,7 @@ function distinctBullets(explanations) {
23344
23357
  return bullets([...new Set(explanations)]);
23345
23358
  }
23346
23359
  function foundLine(count) {
23347
- return count === 1 ? "Halfcycle found 1 small thing to fix in this turn's work. The agent gets the details with your next message and will fix it; there is nothing for you to do." : `Halfcycle found ${count} small things to fix in this turn's work. The agent gets the details with your next message and will fix them; there is nothing for you to do.`;
23360
+ return count === 1 ? `Halfcycle found 1 small thing to fix in this turn's work. The agent gets the details with your next message and will fix it; there is nothing for you to do. Say "fix it" to have it fixed.` : `Halfcycle found ${count} small things to fix in this turn's work. The agent gets the details with your next message and will fix them; there is nothing for you to do. Say "fix them" to have them fixed.`;
23348
23361
  }
23349
23362
  function fixedLine(count, all) {
23350
23363
  if (all)
@@ -23354,7 +23367,7 @@ function fixedLine(count, all) {
23354
23367
  function stillOpenMessage(explanations) {
23355
23368
  const n = explanations.length;
23356
23369
  const head = n === 1 ? "Halfcycle: 1 thing it found is still not fixed after the agent's last turn." : `Halfcycle: ${n} things it found are still not fixed after the agent's last turn.`;
23357
- const tail = n === 1 ? "Ask the agent to fix it, or tell it to leave it as it is if that is what you want." : "Ask the agent to fix them, or tell it to leave them as they are if that is what you want.";
23370
+ const tail = n === 1 ? 'Ask the agent to fix it, or tell it to leave it as it is if that is what you want. Say "fix it" to have it fixed.' : 'Ask the agent to fix them, or tell it to leave them as they are if that is what you want. Say "fix them" to have them fixed.';
23358
23371
  return `${head}
23359
23372
  ${bullets(explanations)}
23360
23373
  ${tail}`;
@@ -1 +1 @@
1
- {"version":3,"file":"render-v2.d.ts","sourceRoot":"","sources":["../../src/build-record/render-v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAmBL,KAAK,WAAW,EAQjB,MAAM,mBAAmB,CAAC;AA8J3B;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAepD;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AA2MD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO/D;AAwVD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgFvE"}
1
+ {"version":3,"file":"render-v2.d.ts","sourceRoot":"","sources":["../../src/build-record/render-v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAmBL,KAAK,WAAW,EAQjB,MAAM,mBAAmB,CAAC;AA8J3B;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAepD;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AA2PD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO/D;AA2WD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgFvE"}
package/dist/cli.js CHANGED
@@ -1446,12 +1446,25 @@ var seatCoverageSchema = z6.object({
1446
1446
  message: "conformant cannot exceed enrolled",
1447
1447
  path: ["conformant"]
1448
1448
  });
1449
+ var LEFT_FOR_OWNER_TEXT_MAX = 300;
1450
+ var LEFT_FOR_OWNER_ENTRIES_MAX = 500;
1451
+ var leftForOwnerDecisionSchema = z6.object({
1452
+ item: plainText(LEFT_FOR_OWNER_TEXT_MAX),
1453
+ question: plainText(LEFT_FOR_OWNER_TEXT_MAX)
1454
+ }).strict();
1455
+ var leftForOwnerSchema = z6.object({
1456
+ tasks: z6.array(plainText(LEFT_FOR_OWNER_TEXT_MAX)).max(LEFT_FOR_OWNER_ENTRIES_MAX),
1457
+ waiting: z6.array(leftForOwnerDecisionSchema).max(LEFT_FOR_OWNER_ENTRIES_MAX)
1458
+ }).strict().refine((v) => v.tasks.length + v.waiting.length > 0, {
1459
+ message: "is sent only when some work was left for the owner"
1460
+ });
1449
1461
  var observedCloseSchema = z6.object({
1450
1462
  sequence: z6.number().int().min(1),
1451
1463
  closedAt: utcIso8601,
1452
1464
  closedBy: closedBySchema,
1453
1465
  crossed: crossedSchema,
1454
- seatCoverage: seatCoverageSchema.nullable()
1466
+ seatCoverage: seatCoverageSchema.nullable(),
1467
+ leftForOwner: leftForOwnerSchema.optional()
1455
1468
  }).strict();
1456
1469
  var couldNotRunCheckSchema = z6.object({
1457
1470
  check: plainText(),
@@ -4979,11 +4992,15 @@ function ownerWaitItemPhraseOf(item) {
4979
4992
  const bare = cut.endsWith(".") ? cut.slice(0, -1) : cut;
4980
4993
  return bare.charAt(0).toLowerCase() + bare.slice(1);
4981
4994
  }
4982
- var OWNER_WAIT_TOO_MANY = `This project already has ${String(OWNER_WAIT_ADDITIONS_MAX)} things added to what waits for the owner. Ask the owner to take one off in the console first.`;
4995
+ var OWNER_WAIT_TOO_MANY = `This project already has ${String(OWNER_WAIT_ADDITIONS_MAX)} things added to what waits for the owner. Ask the owner to take one off on their settings page in the console first; it cannot be done by typing in chat.`;
4996
+ function ownerWaitClosedItemOf(item) {
4997
+ if (!("fixed" in item))
4998
+ return `"${item.addedWords}" (added by an agent)`;
4999
+ const phrase = ownerWaitItemPhraseOf(item.fixed);
5000
+ return phrase.charAt(0).toUpperCase() + phrase.slice(1);
5001
+ }
4983
5002
  function ownerWaitClosedLineOf(item, question2) {
4984
- const phrase = "fixed" in item ? ownerWaitItemPhraseOf(item.fixed) : "";
4985
- const which = "fixed" in item ? phrase.charAt(0).toUpperCase() + phrase.slice(1) : `"${item.addedWords}" (added by an agent)`;
4986
- return `Waited for you: ${which} \u2014 the agent asked: "${question2}"`;
5003
+ return `Waited for you: ${ownerWaitClosedItemOf(item)} \u2014 the agent asked: "${question2}"`;
4987
5004
  }
4988
5005
  var OWNER_WAIT_DECLARATIONS_READ_FAILED = "Halfcycle could not read the decisions that waited for you.";
4989
5006
 
@@ -5092,7 +5109,7 @@ function claudePlanFromAnswer(answer) {
5092
5109
  return CLAUDE_PLANS[Number(trimmed) - 1]?.id ?? null;
5093
5110
  }
5094
5111
  function claudePlanRememberedText(plan, settingsUrl) {
5095
- return `Using the plan you gave before: ${claudePlanOf(plan).words}. You can change it at ${settingsUrl}.`;
5112
+ return `Using the plan you gave before: ${claudePlanOf(plan).words}. You can change it on your settings page, not by typing in chat: ${settingsUrl}`;
5096
5113
  }
5097
5114
  function paceP1Of(n, minutes) {
5098
5115
  const first = `Halfcycle suggests running ${paceAgentsOf(n)} at once.`;
@@ -5107,7 +5124,7 @@ function paceP3Of(window) {
5107
5124
  }
5108
5125
  function paceP4Of(n, settingsUrl) {
5109
5126
  const first = `Halfcycle does not know which Claude plan you use, so it starts with ${String(n)}.`;
5110
- return settingsUrl === null ? first : `${first} You can say which at ${settingsUrl}.`;
5127
+ return settingsUrl === null ? first : `${first} You can say which on your settings page, not by typing in chat: ${settingsUrl}`;
5111
5128
  }
5112
5129
  var PACE_P5 = "This build may use all of your allowance. It will not slow down to leave room for you.";
5113
5130
  function paceP6Of(k) {
@@ -5115,7 +5132,7 @@ function paceP6Of(k) {
5115
5132
  }
5116
5133
  function paceP7Of(settingsUrl) {
5117
5134
  const first = "Say a different number to change it.";
5118
- return settingsUrl === null ? first : `${first} To let builds use all of your allowance, change it at ${settingsUrl}.`;
5135
+ return settingsUrl === null ? first : `${first} To let builds use all of your allowance, change it on your settings page, not by typing in chat: ${settingsUrl}`;
5119
5136
  }
5120
5137
  function paceStartLinesOf(s) {
5121
5138
  const lines = [paceP1Of(s.number, s.minutes)];
@@ -5330,8 +5347,9 @@ var savedSchema = z33.object({
5330
5347
  function autonomyA13(accepted, carried) {
5331
5348
  return `Your autonomy setting accepted the ${String(accepted)} built parts and carried ${String(carried)} unbuilt parts forward. The phase is closed.`;
5332
5349
  }
5333
- function autonomyA14(count, parts) {
5334
- 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 and decide those parts. See the console's review.`;
5350
+ 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, in the console's review; that cannot be done by typing in chat. Then decide those parts there, or in your own Claude Code session: ` + typed;
5335
5353
  }
5336
5354
  function autonomyA15(count) {
5337
5355
  return `The phase waits for you: ${String(count)} parts were built without an approved scope, and only you can decide them.`;
@@ -10457,6 +10475,27 @@ function renderCouldNotRun(entries, p) {
10457
10475
  function headlineText(observed, attested, checks) {
10458
10476
  const met = attested.decision === "done-when-met";
10459
10477
  const problemsReported = attested.walk !== null && attested.walk.verdict === "defects";
10478
+ const left = observed.leftForOwner;
10479
+ if (left !== void 0 && observed.crossed.kind === "none") {
10480
+ const saw = `Halfcycle saw work that waits for you: ${leftForYouSummary(left)}, each listed in this record.`;
10481
+ if (!met) {
10482
+ return [LEFT_FOR_YOU_TITLE, `${saw} The person closing the phase chose to override rather than state its finish conditions were met.`];
10483
+ }
10484
+ return problemsReported ? [LEFT_FOR_YOU_TITLE, `${saw} The person closing the phase reported problems found in its acceptance walk.`] : [LEFT_FOR_YOU_TITLE, `${saw} The person closing the phase stated its finish conditions were met, but this work is still yours to do.`];
10485
+ }
10486
+ const [title, sentence] = headlineOverCrossed(observed, met, problemsReported, checks);
10487
+ return left === void 0 ? [title, sentence] : [title, `${sentence} Halfcycle also saw work that waits for you: ${leftForYouSummary(left)}, each listed in this record.`];
10488
+ }
10489
+ var LEFT_FOR_YOU_TITLE = "Closed with work left for you.";
10490
+ function leftForYouSummary(left) {
10491
+ const parts = [];
10492
+ if (left.tasks.length > 0)
10493
+ parts.push(`${counted(left.tasks.length, "task", "tasks")} held for you`);
10494
+ if (left.waiting.length > 0)
10495
+ parts.push(`${counted(left.waiting.length, "decision", "decisions")} waiting for your answer`);
10496
+ return parts.join(" and ");
10497
+ }
10498
+ function headlineOverCrossed(observed, met, problemsReported, checks) {
10460
10499
  switch (observed.crossed.kind) {
10461
10500
  case "none":
10462
10501
  if (!met) {
@@ -10524,6 +10563,18 @@ function outstanding(crossed, p) {
10524
10563
  ];
10525
10564
  }
10526
10565
  }
10566
+ function leftForYouLines(left, p) {
10567
+ if (left === void 0)
10568
+ return [];
10569
+ const lines = [`- Work left for you when the phase closed, which only you can do: ${leftForYouSummary(left)}.`];
10570
+ for (const title of left.tasks)
10571
+ lines.push(` - Task held for you: ${p.text(title)}`);
10572
+ for (const decision of left.waiting) {
10573
+ lines.push(` - Decision waiting for your answer, as the agent asked it: ${p.text(decision.question)}`);
10574
+ lines.push(` - On the list of what always waits for you as: ${p.text(decision.item)}`);
10575
+ }
10576
+ return lines;
10577
+ }
10527
10578
  function shownBy(steps) {
10528
10579
  const named = steps.filter((s) => s.name !== void 0).length;
10529
10580
  if (named === 0)
@@ -10596,6 +10647,7 @@ function renderClose(heading, observed, attested, checks, p, closingRound = fals
10596
10647
  `- Closed at: ${closedAtText(observed.closedAt, p)}`,
10597
10648
  `- Signed in as: ${signedInAs(observed.closedBy, p)}`,
10598
10649
  ...outstanding(observed.crossed, p),
10650
+ ...leftForYouLines(observed.leftForOwner, p),
10599
10651
  machines(observed.seatCoverage, checks)
10600
10652
  ].join("\n"),
10601
10653
  STATED_LABEL,
@@ -12926,7 +12978,8 @@ function uncheckedClaimLine(test) {
12926
12978
  }
12927
12979
  function answerClaimsInSystemViewLine(engagementId, phase) {
12928
12980
  const address = systemViewUrl(engagementId, phase);
12929
- return address === void 0 ? "Accept or reject each one in the System view." : `Accept or reject each one in the System view: ${address}`;
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}`;
12930
12983
  }
12931
12984
  function checksSectionLines(work, engagementId) {
12932
12985
  const unchecked = work.tasks.flatMap((task) => task.tests.filter((t) => t.state === "unchecked"));
@@ -13339,14 +13392,25 @@ function reviewOpenedLine(phase) {
13339
13392
  return `[halfcycle] The review of phase "${phase}" is open. The project's owner reviews each part: accept it, ask a question or send it back. Each part that was not built is carried to the next phase or dropped, with a reason. The phase closes when every part is decided.`;
13340
13393
  }
13341
13394
  var COULD_NOT_COUNT_LINE = "[halfcycle] Halfcycle could not count what this phase changed, so the owner judges each part on what the agents reported alone.";
13342
- function typedReviewHintLine(offered) {
13343
- return offered ? '[halfcycle] The owner reviews each part in their own Claude Code session: they say "review what was built" to see the list, then type one decision per line.' : `[halfcycle] ${TYPED_REVIEW_OFF_SENTENCE}`;
13395
+ function typedAcceptLine(phase) {
13396
+ return phase.includes(":") ? null : `accept ${phase}`;
13397
+ }
13398
+ function typedReviewHintLine(offered, phase) {
13399
+ if (!offered)
13400
+ return `[halfcycle] ${TYPED_REVIEW_OFF_SENTENCE}`;
13401
+ const accept = typedAcceptLine(phase);
13402
+ const lines = accept === null ? "then type one decision per line, as the whole message." : `then type ${accept} as the whole message to accept every built part, or one line per part, such as ${accept}/<part>; the list gives each part's lines.`;
13403
+ return `[halfcycle] The owner reviews each part in their own Claude Code session: they say "review what was built" to see the list, ${lines}`;
13344
13404
  }
13345
13405
  function systemViewReviewLine(offered, engagementId, phase) {
13346
13406
  const address = systemViewUrl(engagementId, phase);
13347
13407
  if (address === void 0)
13348
13408
  return void 0;
13349
- return offered ? `[halfcycle] Or the owner reviews it in the System view: ${address}` : `[halfcycle] The owner reviews it in the System view: ${address}`;
13409
+ if (!offered)
13410
+ return `[halfcycle] The owner reviews it in the System view: ${address}`;
13411
+ const accept = typedAcceptLine(phase);
13412
+ const instead = accept === null ? "typing in their own Claude Code session" : `typing ${accept} in their own Claude Code session`;
13413
+ return `[halfcycle] Or, instead of ${instead}, the owner reviews it in the System view: ${address}`;
13350
13414
  }
13351
13415
  function tasksOpenLine(phase, open, more) {
13352
13416
  const total = open.length + more;
@@ -13399,7 +13463,7 @@ function closeStepReport(phase, attempt, engagementId) {
13399
13463
  stdout.push(reviewOpenedLine(phase));
13400
13464
  if (!answer.counted)
13401
13465
  stdout.push(COULD_NOT_COUNT_LINE);
13402
- stdout.push(typedReviewHintLine(answer.typedReviewOffered));
13466
+ stdout.push(typedReviewHintLine(answer.typedReviewOffered, phase));
13403
13467
  {
13404
13468
  const viewLine = systemViewReviewLine(answer.typedReviewOffered, engagementId, phase);
13405
13469
  if (viewLine !== void 0)
@@ -13436,7 +13500,7 @@ function closeStepReport(phase, attempt, engagementId) {
13436
13500
  exitCode = 0;
13437
13501
  break;
13438
13502
  case "autonomy-waits":
13439
- stdout.push(answer.reason === "unchecked-claims" ? autonomyA14(answer.count, answer.parts.map((p) => p.name)) : autonomyA15(answer.count));
13503
+ stdout.push(answer.reason === "unchecked-claims" ? autonomyA14(answer.count, answer.parts.map((p) => p.name), typedAcceptLine(phase)) : autonomyA15(answer.count));
13440
13504
  exitCode = 0;
13441
13505
  break;
13442
13506
  default: