halfcycle 0.7.0 → 0.7.1

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.7.0",
3
+ "version": "0.7.1",
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
  {
@@ -23048,6 +23048,19 @@ function accountKeysOf(path) {
23048
23048
  return typeof accounts === "object" && accounts !== null && !Array.isArray(accounts) ? Object.keys(accounts) : [];
23049
23049
  }
23050
23050
  var PACE_STATE_FILENAME = "state.json";
23051
+ function toldOf(v) {
23052
+ if (typeof v !== "object" || v === null || Array.isArray(v))
23053
+ return null;
23054
+ const o = v;
23055
+ const pace = paceStateSchema.safeParse(o["pace"]);
23056
+ const kind = o["windowKind"] === null ? null : paceWindowKindSchema.safeParse(o["windowKind"]);
23057
+ const allowance = o["allowance"];
23058
+ if (!pace.success || kind !== null && !kind.success)
23059
+ return null;
23060
+ if (typeof allowance !== "number" || !Number.isInteger(allowance) || allowance < 0)
23061
+ return null;
23062
+ return { pace: pace.data, allowance, windowKind: kind === null ? null : kind.data };
23063
+ }
23051
23064
  function paceStateEntryOf(v) {
23052
23065
  if (typeof v !== "object" || v === null || Array.isArray(v))
23053
23066
  return null;
@@ -23069,7 +23082,17 @@ function paceStateEntryOf(v) {
23069
23082
  if (typeof at !== "string" || Number.isNaN(Date.parse(at)))
23070
23083
  return null;
23071
23084
  const offered = Array.isArray(o["offeredFor"]) ? o["offeredFor"].filter((t) => typeof t === "string" && !Number.isNaN(Date.parse(t))) : [];
23072
- return { pace: pace.data, allowance, number: number4, windowKind: kind === null ? null : kind.data, until, at, ...offered.length > 0 ? { offeredFor: offered } : {} };
23085
+ const told = toldOf(o["told"]);
23086
+ return {
23087
+ pace: pace.data,
23088
+ allowance,
23089
+ number: number4,
23090
+ windowKind: kind === null ? null : kind.data,
23091
+ until,
23092
+ at,
23093
+ ...offered.length > 0 ? { offeredFor: offered } : {},
23094
+ ...told === null ? {} : { told }
23095
+ };
23073
23096
  }
23074
23097
  function rememberedBasisOf(v) {
23075
23098
  if (typeof v !== "object" || v === null || Array.isArray(v))
@@ -23100,8 +23123,14 @@ function writePaceState(dir, key, entry, basis) {
23100
23123
  if (entry === null)
23101
23124
  delete accounts[key];
23102
23125
  else {
23103
- const kept = entry.offeredFor ?? current.accounts[key]?.offeredFor;
23104
- accounts[key] = kept === void 0 ? entry : { ...entry, offeredFor: kept };
23126
+ const last = current.accounts[key];
23127
+ const kept = entry.offeredFor ?? last?.offeredFor;
23128
+ const told = entry.told ?? last?.told ?? (last === void 0 ? { pace: "full", allowance: entry.allowance, windowKind: null } : void 0);
23129
+ accounts[key] = {
23130
+ ...entry,
23131
+ ...kept === void 0 ? {} : { offeredFor: kept },
23132
+ ...told === void 0 ? {} : { told }
23133
+ };
23105
23134
  }
23106
23135
  writeJsonWhole(nodePath.join(dir, PACE_STATE_FILENAME), { accounts, basis: basis ?? current.basis });
23107
23136
  }
@@ -24275,6 +24304,22 @@ function tokensOf(usage) {
24275
24304
  }
24276
24305
  return out;
24277
24306
  }
24307
+ function builderTaskOf(own, t) {
24308
+ let next;
24309
+ let last;
24310
+ for (const lane of own) {
24311
+ if (lane.task === null)
24312
+ continue;
24313
+ const times = lane.events.map((e) => msOf(e.at));
24314
+ const after = times.find((at) => at > t);
24315
+ if (after !== void 0 && (next === void 0 || after < next.t))
24316
+ next = { task: lane.task, t: after };
24317
+ const before = lastAtOrBefore(times, t);
24318
+ if (before !== void 0 && (last === void 0 || before >= last.t))
24319
+ last = { task: lane.task, t: before };
24320
+ }
24321
+ return next?.task ?? last?.task ?? null;
24322
+ }
24278
24323
  function readUsage(lanes, window, deps = {}, models) {
24279
24324
  const from = Date.parse(window.from);
24280
24325
  const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
@@ -24291,7 +24336,7 @@ function readUsage(lanes, window, deps = {}, models) {
24291
24336
  return buckets.get(key) ?? buckets.set(key, { source, task, readable, messages: 0, inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 }).get(key);
24292
24337
  };
24293
24338
  const seen = /* @__PURE__ */ new Set();
24294
- const count = (path, view, taskAt) => {
24339
+ const count = (path, view, taskAt, builderTaskAt = () => null) => {
24295
24340
  const source = recordSourceOf(path);
24296
24341
  for (const line2 of view.lines) {
24297
24342
  const o = line2.value;
@@ -24311,8 +24356,9 @@ function readUsage(lanes, window, deps = {}, models) {
24311
24356
  const bucket = bucketFor(source, task, true);
24312
24357
  bucket.messages += 1;
24313
24358
  const model = message["model"];
24314
- if (models !== void 0 && task !== null && isTalliedModel(model)) {
24315
- const ofTask = models.get(task) ?? models.set(task, /* @__PURE__ */ new Map()).get(task);
24359
+ const modelTask = models === void 0 ? null : task ?? builderTaskAt(line2);
24360
+ if (models !== void 0 && modelTask !== null && isTalliedModel(model)) {
24361
+ const ofTask = models.get(modelTask) ?? models.set(modelTask, /* @__PURE__ */ new Map()).get(modelTask);
24316
24362
  ofTask.set(model, (ofTask.get(model) ?? 0) + 1);
24317
24363
  }
24318
24364
  bucket.inputTokens += tokens[0];
@@ -24358,7 +24404,7 @@ function readUsage(lanes, window, deps = {}, models) {
24358
24404
  return best.lane.task;
24359
24405
  const first = [...own].sort((a, b) => msOf(a.events[0].at) - msOf(b.events[0].at))[0];
24360
24406
  return first?.task ?? null;
24361
- });
24407
+ }, (line2) => builderTaskOf(own, line2.t));
24362
24408
  }
24363
24409
  }
24364
24410
  const codexLanes = active.filter((lane) => lane.rollout !== null && lane.transcript === null);
@@ -26438,9 +26484,11 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
26438
26484
  windowKind: decision.windowKind,
26439
26485
  until: decision.until === null ? null : decision.until.toISOString(),
26440
26486
  at: now.toISOString(),
26441
- offeredFor: offeredForNow(stored.accounts[key]?.offeredFor, null, now)
26487
+ offeredFor: offeredForNow(stored.accounts[key]?.offeredFor, null, now),
26488
+ told: { pace: decision.pace, allowance: decision.allowance, windowKind: decision.windowKind }
26442
26489
  };
26443
- const text = paceChangeText(before, settled2, working, now, basis.keepFreePercent);
26490
+ const told = before === null || before.told === void 0 ? before : { ...before, ...before.told };
26491
+ const text = paceChangeText(told, settled2, working, now, basis.keepFreePercent);
26444
26492
  const offer = text === null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
26445
26493
  const after = offer === null ? settled2 : { ...settled2, offeredFor: offeredForNow(settled2.offeredFor, offer.resetsAt, now) };
26446
26494
  write(dir, key, after, read !== null ? basis : null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "halfcycle",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Your coding agents are the engineers. Halfcycle is the rest of the team: it scopes, designs, plans and reviews production software, and runs the build for Claude Code and Codex.",
5
5
  "keywords": [
6
6
  "claude",