@oxagen/cli 2.1.5-76 → 2.1.5-88

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.
Files changed (2) hide show
  1. package/oxagen.mjs +207 -42
  2. package/package.json +1 -1
package/oxagen.mjs CHANGED
@@ -6276,7 +6276,11 @@ var init_wire = __esm({
6276
6276
  * first model call, by digesting its remote and looking for the digest
6277
6277
  * in `bound_remote_digests`: every repository the organization bound,
6278
6278
  * in any workspace, each as its canonical digest and its folded digest
6279
- * (`canonicalRemote` and `foldedRemote` in `remote.ts`).
6279
+ * (`canonicalRemote` and `foldedRemote` in `remote.ts`). An organisation
6280
+ * with more than fit under the cap gets a list cut to it, the host
6281
+ * workspace's repositories first, and a repository the cut left out is
6282
+ * asked about like an unbound one (#4439). The list is never dropped,
6283
+ * because an absent clause asks nothing.
6280
6284
  *
6281
6285
  * `link` carries what the link path would apply, for the question the
6282
6286
  * host shows. `timeout_ms` is how long the host waits before it answers
@@ -12118,6 +12122,48 @@ var init_frame_body = __esm({
12118
12122
  }
12119
12123
  });
12120
12124
 
12125
+ // ../../packages/tacho/src/claude-code/prompt-issue-refs.ts
12126
+ function issueNumber(text5) {
12127
+ const n2 = Number(text5);
12128
+ return Number.isSafeInteger(n2) && n2 > 0 ? n2 : void 0;
12129
+ }
12130
+ function promptIssueRefs(prompt) {
12131
+ const found = [];
12132
+ const rest = prompt.replace(ISSUE_URL2, (whole, owner, repo, num, at2) => {
12133
+ const n2 = issueNumber(num);
12134
+ if (n2 !== void 0) found.push({ at: at2, ref: `${owner}/${repo}#${n2}` });
12135
+ return " ".repeat(whole.length);
12136
+ });
12137
+ for (const match of rest.matchAll(REPO_REF)) {
12138
+ const n2 = issueNumber(match[3]);
12139
+ if (n2 !== void 0)
12140
+ found.push({ at: match.index, ref: `${match[1]}/${match[2]}#${n2}` });
12141
+ }
12142
+ for (const match of rest.matchAll(BARE_REF)) {
12143
+ const n2 = issueNumber(match[1]);
12144
+ if (n2 !== void 0) found.push({ at: match.index, ref: `#${n2}` });
12145
+ }
12146
+ found.sort((a, b3) => a.at - b3.at);
12147
+ const refs = [];
12148
+ for (const { ref: ref2 } of found) {
12149
+ if (refs.length === PROMPT_ISSUE_REFS_MAX) break;
12150
+ if (!refs.some((seen) => seen.toLowerCase() === ref2.toLowerCase()))
12151
+ refs.push(ref2);
12152
+ }
12153
+ return refs;
12154
+ }
12155
+ var PROMPT_ISSUE_REFS_ATTR, PROMPT_ISSUE_REFS_MAX, ISSUE_URL2, REPO_REF, BARE_REF;
12156
+ var init_prompt_issue_refs = __esm({
12157
+ "../../packages/tacho/src/claude-code/prompt-issue-refs.ts"() {
12158
+ "use strict";
12159
+ PROMPT_ISSUE_REFS_ATTR = "prompt.issue_refs";
12160
+ PROMPT_ISSUE_REFS_MAX = 10;
12161
+ ISSUE_URL2 = /https?:\/\/(?:www\.)?github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/issues\/(\d+)(?![\w-])/gi;
12162
+ REPO_REF = /(?<![\w./-])([A-Za-z0-9][A-Za-z0-9-]*)\/([A-Za-z0-9_.-]+)#(\d+)(?![\w-])/g;
12163
+ BARE_REF = /(?<![\w/&#-])#(\d+)(?![\w-])/g;
12164
+ }
12165
+ });
12166
+
12121
12167
  // ../../packages/tacho/src/claude-code/hooks.ts
12122
12168
  function kindOf(value) {
12123
12169
  if (value === null) return "null";
@@ -12320,14 +12366,17 @@ function normalizeHook(raw, env, options) {
12320
12366
  } : {}
12321
12367
  };
12322
12368
  const kind = input.hook_event_name === "UserPromptSubmit" ? "turn_start" : "oxagen:message";
12369
+ const issueRefs = kind === "turn_start" && prompt !== void 0 && workOrderIdOf(env[WORK_ORDER_ENV]) === void 0 ? promptIssueRefs(prompt) : [];
12323
12370
  return [
12324
- draft(
12325
- kind,
12326
- body2,
12327
- prompt !== void 0 ? {
12328
- content: textContent(prompt)
12371
+ draft(kind, body2, {
12372
+ ...prompt !== void 0 ? { content: textContent(prompt) } : {},
12373
+ ...issueRefs.length > 0 ? {
12374
+ attrs: {
12375
+ ...base2.attrs,
12376
+ [PROMPT_ISSUE_REFS_ATTR]: issueRefs.join(" ")
12377
+ }
12329
12378
  } : {}
12330
- )
12379
+ })
12331
12380
  ];
12332
12381
  }
12333
12382
  case "PreToolUse": {
@@ -12711,6 +12760,7 @@ var init_hooks = __esm({
12711
12760
  init_ids();
12712
12761
  init_frame_body();
12713
12762
  init_wire();
12763
+ init_prompt_issue_refs();
12714
12764
  init_context();
12715
12765
  init_payload_members();
12716
12766
  init_github_text();
@@ -26672,7 +26722,7 @@ import { readFileSync as readFileSync10 } from "node:fs";
26672
26722
  import { dirname as dirname9, resolve as resolve3 } from "node:path";
26673
26723
  import { fileURLToPath } from "node:url";
26674
26724
  function readVersion() {
26675
- if (true) return "2.1.5-76";
26725
+ if (true) return "2.1.5-88";
26676
26726
  try {
26677
26727
  const here = dirname9(fileURLToPath(import.meta.url));
26678
26728
  const pkg = JSON.parse(
@@ -46233,7 +46283,7 @@ function createGitLane(deps) {
46233
46283
  reconciledHeads.delete(sessionUuid2);
46234
46284
  }
46235
46285
  }
46236
- function putBack(read2) {
46286
+ function putBack2(read2) {
46237
46287
  const sessionUuid2 = read2.session.recorder.sessionUuid;
46238
46288
  if (read2.priorReconcileAt === void 0)
46239
46289
  lastReconcileAt.delete(sessionUuid2);
@@ -46269,7 +46319,7 @@ function createGitLane(deps) {
46269
46319
  force: true,
46270
46320
  reconcile: item.due
46271
46321
  });
46272
- for (const rest of found.slice(index + 1)) putBack(rest);
46322
+ for (const rest of found.slice(index + 1)) putBack2(rest);
46273
46323
  throw error;
46274
46324
  }
46275
46325
  }
@@ -46310,7 +46360,7 @@ function createGitLane(deps) {
46310
46360
  priorReconcileAt: last
46311
46361
  });
46312
46362
  } catch (error) {
46313
- putBack({ session, due, priorReconcileAt: last });
46363
+ putBack2({ session, due, priorReconcileAt: last });
46314
46364
  throw error;
46315
46365
  }
46316
46366
  }
@@ -46745,7 +46795,7 @@ var init_reflection_ask = __esm({
46745
46795
  });
46746
46796
 
46747
46797
  // ../../packages/tacho/src/interjection.ts
46748
- var digest3, timestamp, count5, configVersion, workspaceSlug, interjectionKeySchema, INTERJECTION_RECEIPT_ID_PATTERN, INTERJECTION_QUESTION_MAX, INTERJECTION_PATHS, INTERJECTION_ANSWER_SOURCES, SKILLS_RESOLVED_REASONS, repoUnknownBodySchema, interjectLinkPathSchema, interjectCreatePathSchema, interjectBodySchema, answerBodySchema, repoBoundBodySchema, workspaceCreatedBodySchema, skillsResolvedBodySchema, interjectionAnswerPayloadSchema;
46798
+ var digest3, timestamp, count5, configVersion, workspaceSlug, interjectionKeySchema, INTERJECTION_RECEIPT_ID_PATTERN, INTERJECTION_QUESTION_MAX, INTERJECTION_PATHS, INTERJECTION_ANSWER_SOURCES, SKILLS_RESOLVED_REASONS, repoUnknownBodySchema, interjectLinkPathSchema, interjectCreatePathSchema, INTERJECT_PROVIDERS, interjectBodySchema, answerBodySchema, repoBoundBodySchema, workspaceCreatedBodySchema, skillsResolvedBodySchema, interjectionAnswerPayloadSchema;
46749
46799
  var init_interjection = __esm({
46750
46800
  "../../packages/tacho/src/interjection.ts"() {
46751
46801
  "use strict";
@@ -46796,6 +46846,7 @@ var init_interjection = __esm({
46796
46846
  proposed_slug: workspaceSlug.nullable(),
46797
46847
  skills_enabled: external_exports.literal(false)
46798
46848
  }).strict();
46849
+ INTERJECT_PROVIDERS = ["github", "gitlab"];
46799
46850
  interjectBodySchema = external_exports.object({
46800
46851
  interjection_key: interjectionKeySchema,
46801
46852
  reason: external_exports.literal("repo_unknown"),
@@ -46809,7 +46860,16 @@ var init_interjection = __esm({
46809
46860
  /** What the timeout answers. */
46810
46861
  on_timeout: external_exports.literal("deny"),
46811
46862
  /** The two paths a person can take, link first. Deny needs no path. */
46812
- paths: external_exports.tuple([interjectLinkPathSchema, interjectCreatePathSchema])
46863
+ paths: external_exports.tuple([interjectLinkPathSchema, interjectCreatePathSchema]),
46864
+ /**
46865
+ * The forge the remote's host names (#4439): `github` for github.com and
46866
+ * `gitlab` for gitlab.com. Absent for any other host, and from a host
46867
+ * built before the field, which the control plane reads as GitHub. The
46868
+ * host string itself stays on the machine. A GitLab project binds through
46869
+ * its own project access token, so the control plane offers no link for
46870
+ * a `gitlab` question.
46871
+ */
46872
+ provider: external_exports.enum(INTERJECT_PROVIDERS).optional()
46813
46873
  }).strict();
46814
46874
  answerBodySchema = external_exports.object({
46815
46875
  interjection_key: interjectionKeySchema,
@@ -46898,6 +46958,12 @@ function proposedSlug(name) {
46898
46958
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+/, "").slice(0, SLUG_MAX).replace(/-+$/, "");
46899
46959
  return slug.length >= SLUG_MIN && SLUG_PATTERN.test(slug) ? slug : null;
46900
46960
  }
46961
+ function providerOf(canonical3) {
46962
+ const host = canonical3.slice(0, canonical3.indexOf("/")).toLowerCase();
46963
+ if (host === "github.com") return "github";
46964
+ if (host === "gitlab.com") return "gitlab";
46965
+ return void 0;
46966
+ }
46901
46967
  function prepareInterjection(record, clause, remote, now) {
46902
46968
  const key = ulid(now);
46903
46969
  const question = interjectionQuestion(clause, record.harness);
@@ -46934,7 +47000,8 @@ function prepareInterjection(record, clause, remote, now) {
46934
47000
  proposed_slug: name === null ? null : proposedSlug(name),
46935
47001
  skills_enabled: false
46936
47002
  }
46937
- ]
47003
+ ],
47004
+ ...providerOf(remote.canonical) === void 0 ? {} : { provider: providerOf(remote.canonical) }
46938
47005
  });
46939
47006
  if (!unknown2.success || !interject.success) return void 0;
46940
47007
  return {
@@ -46964,6 +47031,8 @@ function sealInterjection(record, pending, fields) {
46964
47031
  function expireInterjection(record, now, fields) {
46965
47032
  const held = record.control.interjection;
46966
47033
  if (held === void 0 || Date.parse(held.expiresAt) > now) return void 0;
47034
+ expiredByHook.set(record, held);
47035
+ putBack.delete(held);
46967
47036
  return settle(
46968
47037
  record,
46969
47038
  held,
@@ -46972,6 +47041,18 @@ function expireInterjection(record, now, fields) {
46972
47041
  fields
46973
47042
  );
46974
47043
  }
47044
+ function restoreExpiredInterjection(record, held) {
47045
+ if (held === void 0 || record.control.interjection !== void 0 || expiredByHook.get(record) !== held)
47046
+ return false;
47047
+ record.control.interjection = held;
47048
+ expiredByHook.delete(record);
47049
+ putBack.add(held);
47050
+ return true;
47051
+ }
47052
+ function heldQuestionWasPutBack(record) {
47053
+ const held = record.control.interjection;
47054
+ return held !== void 0 && putBack.has(held);
47055
+ }
46975
47056
  function interjectionAnswerOf(payload) {
46976
47057
  const parsed2 = interjectionAnswerPayloadSchema.safeParse(
46977
47058
  payload["interjection"]
@@ -47045,7 +47126,7 @@ function settle(record, held, answer, payload, fields) {
47045
47126
  record.control.interjection = void 0;
47046
47127
  return events;
47047
47128
  }
47048
- var SLUG_PATTERN, SLUG_MIN, SLUG_MAX, NAME_MAX2, INTERJECTION_OPEN, INTERJECTION_TIMED_OUT_TEXT;
47129
+ var SLUG_PATTERN, SLUG_MIN, SLUG_MAX, NAME_MAX2, INTERJECTION_OPEN, INTERJECTION_TIMED_OUT_TEXT, expiredByHook, putBack;
47049
47130
  var init_interjection2 = __esm({
47050
47131
  "../../packages/tacho/src/collector/interjection.ts"() {
47051
47132
  "use strict";
@@ -47058,6 +47139,8 @@ var init_interjection2 = __esm({
47058
47139
  NAME_MAX2 = 120;
47059
47140
  INTERJECTION_OPEN = "interjection_open";
47060
47141
  INTERJECTION_TIMED_OUT_TEXT = "Oxagen asked a person whether to bind this repository to a workspace, and nobody answered in time. This session goes on without skills.";
47142
+ expiredByHook = /* @__PURE__ */ new WeakMap();
47143
+ putBack = /* @__PURE__ */ new WeakSet();
47061
47144
  }
47062
47145
  });
47063
47146
 
@@ -47882,7 +47965,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
47882
47965
  hook_event_name: "UserPromptSubmit",
47883
47966
  attrs: replayed
47884
47967
  };
47885
- const timedOut = replay === void 0 ? expireInterjection(record, deps.now(), questionFields) : void 0;
47968
+ const timedOut = replay === void 0 || heldQuestionWasPutBack(record) ? expireInterjection(record, deps.now(), questionFields) : void 0;
47886
47969
  if (timedOut !== void 0) events.push(...timedOut);
47887
47970
  const asked = await repositoryQuestion(
47888
47971
  record,
@@ -47970,7 +48053,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
47970
48053
  const toolInput = input.tool_input;
47971
48054
  noteToolCall(record, toolName3, toolInput);
47972
48055
  noteRecallHints(record, input.tool_name, toolInput);
47973
- const timedOut = replay === void 0 ? expireInterjection(record, deps.now(), {
48056
+ const timedOut = replay === void 0 || heldQuestionWasPutBack(record) ? expireInterjection(record, deps.now(), {
47974
48057
  hook_event_name: "PreToolUse",
47975
48058
  attrs: replayed
47976
48059
  }) : void 0;
@@ -52513,21 +52596,26 @@ ${tools}---
52513
52596
 
52514
52597
  ${skill.body.replace(/^\n+/, "")}`;
52515
52598
  }
52599
+ function updateFramed(hash3, part2) {
52600
+ const bytes = typeof part2 === "string" ? Buffer.from(part2, "utf8") : part2;
52601
+ const length = Buffer.alloc(8);
52602
+ length.writeBigUInt64BE(BigInt(bytes.byteLength));
52603
+ hash3.update(length);
52604
+ hash3.update(bytes);
52605
+ }
52516
52606
  function skillDigest(skill) {
52517
52607
  const hash3 = createHash11("sha256");
52518
- hash3.update(skillMarkdown(skill));
52608
+ updateFramed(hash3, skillMarkdown(skill));
52519
52609
  for (const file of skill.files) {
52520
- hash3.update("\0");
52521
- hash3.update(file.path);
52522
- hash3.update("\0");
52523
- hash3.update(file.content);
52610
+ updateFramed(hash3, file.path);
52611
+ updateFramed(hash3, file.content);
52524
52612
  }
52525
52613
  return `sha256:${hash3.digest("hex")}`;
52526
52614
  }
52527
52615
  function isMarker(value) {
52528
52616
  if (typeof value !== "object" || value === null) return false;
52529
- const { digest: digest6, sessions } = value;
52530
- return typeof digest6 === "string" && typeof sessions === "object" && sessions !== null && Object.values(sessions).every((at2) => typeof at2 === "string");
52617
+ const { digest: digest6, lineage, sessions } = value;
52618
+ return typeof digest6 === "string" && (lineage === void 0 || typeof lineage === "string") && typeof sessions === "object" && sessions !== null && Object.values(sessions).every((at2) => typeof at2 === "string");
52531
52619
  }
52532
52620
  async function readMarker(folder) {
52533
52621
  let entries2;
@@ -52624,21 +52712,38 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
52624
52712
  if (found.state === "absent") {
52625
52713
  await writeSkill(root, skill, {
52626
52714
  digest: digest6,
52715
+ lineage: skill.lineage,
52627
52716
  sessions: { [sessionId]: now.toISOString() }
52628
52717
  });
52629
52718
  result2.placed.push(skill.name);
52630
52719
  continue;
52631
52720
  }
52632
52721
  const live = liveSessions(found.marker, now);
52722
+ const othersLive = Object.keys(live).some(
52723
+ (session) => session !== sessionId
52724
+ );
52725
+ const held = found.marker.lineage;
52726
+ if (held !== void 0 && held !== skill.lineage && othersLive) {
52727
+ result2.skipped.push(skill.name);
52728
+ result2.warnings.push(
52729
+ `${folder} holds ${held} for another running session, so ${skill.lineage} was not placed.`
52730
+ );
52731
+ continue;
52732
+ }
52633
52733
  const joined = { ...live, [sessionId]: now.toISOString() };
52634
- if (found.marker.digest === digest6) {
52635
- await writeMarker(folder, { digest: digest6, sessions: joined });
52734
+ if (found.marker.digest === digest6 && (held === void 0 || held === skill.lineage)) {
52735
+ await writeMarker(folder, {
52736
+ digest: digest6,
52737
+ lineage: skill.lineage,
52738
+ sessions: joined
52739
+ });
52636
52740
  result2.placed.push(skill.name);
52637
52741
  continue;
52638
52742
  }
52639
- if (Object.keys(live).some((session) => session !== sessionId)) {
52743
+ if (othersLive) {
52640
52744
  await writeMarker(folder, {
52641
52745
  digest: found.marker.digest,
52746
+ ...held === void 0 ? {} : { lineage: held },
52642
52747
  sessions: joined
52643
52748
  });
52644
52749
  result2.skipped.push(skill.name);
@@ -52649,6 +52754,7 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
52649
52754
  }
52650
52755
  await writeSkill(root, skill, {
52651
52756
  digest: digest6,
52757
+ lineage: skill.lineage,
52652
52758
  sessions: { [sessionId]: now.toISOString() }
52653
52759
  });
52654
52760
  result2.placed.push(skill.name);
@@ -52682,7 +52788,7 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
52682
52788
  await rm2(folder, { recursive: true, force: true });
52683
52789
  result2.removed.push(name);
52684
52790
  } else if (held) {
52685
- await writeMarker(folder, { digest: found.marker.digest, sessions });
52791
+ await writeMarker(folder, { ...found.marker, sessions });
52686
52792
  result2.kept.push(name);
52687
52793
  }
52688
52794
  }
@@ -55068,6 +55174,7 @@ function createModelProxy(deps) {
55068
55174
  attrs: attrs2
55069
55175
  };
55070
55176
  const metered = route.api !== "other";
55177
+ await deps.daySpendSeeded?.();
55071
55178
  const { model: askedModel, ambiguous: modelAmbiguous } = modelOf(
55072
55179
  readable,
55073
55180
  json2
@@ -58292,6 +58399,7 @@ async function initializeDaemon(options, server, port, ready, clock2) {
58292
58399
  if (session.sealed && !sealed) session.sealed = false;
58293
58400
  session.control.repoChecked = repoChecked;
58294
58401
  if (interjection === void 0) session.control.interjection = void 0;
58402
+ else restoreExpiredInterjection(session, interjection);
58295
58403
  const held = new Set(messages.map((message) => message.id));
58296
58404
  const arrived = session.control.messages.filter(
58297
58405
  (message) => !held.has(message.id)
@@ -59957,16 +60065,29 @@ async function initializeDaemon(options, server, port, ready, clock2) {
59957
60065
  }
59958
60066
  await refreshUpstreams();
59959
60067
  function walDaySpendMicros(day) {
60068
+ let total2 = 0;
60069
+ for (const session of wal.sessions())
60070
+ total2 += sessionDaySpendMicros(session, day);
60071
+ return total2;
60072
+ }
60073
+ function sessionDaySpendMicros(session, day) {
59960
60074
  const start = Date.parse(`${day}T00:00:00.000Z`);
59961
60075
  const end = Date.parse(nextUtcDayStart(day));
60076
+ return observedSpendMicros(wal.eventsSince(session, start), (event) => {
60077
+ const at2 = Date.parse(event.ts);
60078
+ return at2 >= start && at2 < end;
60079
+ });
60080
+ }
60081
+ async function walDaySpendMicrosYielding(day) {
60082
+ const yieldToLoop = () => new Promise((resolve26) => setImmediate(resolve26));
60083
+ await yieldToLoop();
59962
60084
  let total2 = 0;
59963
60085
  for (const session of wal.sessions()) {
59964
- total2 += observedSpendMicros(wal.eventsSince(session, start), (event) => {
59965
- const at2 = Date.parse(event.ts);
59966
- return at2 >= start && at2 < end;
59967
- });
60086
+ if (stopped2) return void 0;
60087
+ total2 += sessionDaySpendMicros(session, day);
60088
+ await yieldToLoop();
59968
60089
  }
59969
- return total2;
60090
+ return stopped2 ? void 0 : total2;
59970
60091
  }
59971
60092
  function observedSpendMicros(events, within4 = () => true) {
59972
60093
  let total2 = 0;
@@ -59993,6 +60114,7 @@ async function initializeDaemon(options, server, port, ready, clock2) {
59993
60114
  };
59994
60115
  }
59995
60116
  let startupDaySpend;
60117
+ let daySpendSeed = Promise.resolve();
59996
60118
  const modelProxy = createModelProxy({
59997
60119
  registry: registry2,
59998
60120
  hostRecorder: () => hostRecorder,
@@ -60011,6 +60133,7 @@ async function initializeDaemon(options, server, port, ready, clock2) {
60011
60133
  // counter asks this once per process (`createDaySpend`), so the figure
60012
60134
  // read at startup is used once. A first call on a later day than
60013
60135
  // startup's reads the WAL for that day.
60136
+ daySpendSeeded: () => daySpendSeed,
60014
60137
  priorDaySpendMicros: spendRead("the day's spend", (day) => {
60015
60138
  const seeded = startupDaySpend;
60016
60139
  startupDaySpend = void 0;
@@ -60463,17 +60586,26 @@ async function initializeDaemon(options, server, port, ready, clock2) {
60463
60586
  }
60464
60587
  }
60465
60588
  clock2.phase("restart gaps");
60466
- try {
60589
+ ready(api);
60590
+ clock2.ready();
60591
+ {
60467
60592
  const day = utcDay(now());
60468
- startupDaySpend = { day, micros: walDaySpendMicros(day) };
60469
- } catch (error) {
60470
- log(
60471
- `day spend not read from the WAL at startup: ${error instanceof Error ? error.message : String(error)}`
60593
+ const began = performance.now();
60594
+ daySpendSeed = walDaySpendMicrosYielding(day).then(
60595
+ (micros) => {
60596
+ if (micros === void 0) return;
60597
+ startupDaySpend = { day, micros };
60598
+ log(
60599
+ `day spend read took ${Math.round(performance.now() - began)}ms after ready`
60600
+ );
60601
+ },
60602
+ (error) => {
60603
+ log(
60604
+ `day spend not read from the WAL at startup: ${error instanceof Error ? error.message : String(error)}`
60605
+ );
60606
+ }
60472
60607
  );
60473
60608
  }
60474
- clock2.phase("day spend");
60475
- ready(api);
60476
- clock2.ready();
60477
60609
  servingSince = now();
60478
60610
  if (options.listen ?? true) {
60479
60611
  const unixSocket = (options.platform ?? process.platform) !== "win32";
@@ -60924,6 +61056,7 @@ async function initializeDaemon(options, server, port, ready, clock2) {
60924
61056
  bodyPurgeIdle: async () => {
60925
61057
  while (bodyPurge !== void 0) await bodyPurge;
60926
61058
  },
61059
+ daySpendSeeded: () => daySpendSeed,
60927
61060
  workOrdersIdle: () => workOrderAutostart.idle(),
60928
61061
  stop: async () => {
60929
61062
  if (stopped2) return;
@@ -61057,6 +61190,7 @@ var init_daemon = __esm({
61057
61190
  init_registry();
61058
61191
  init_server();
61059
61192
  init_spool();
61193
+ init_interjection2();
61060
61194
  init_refused();
61061
61195
  init_session_heads();
61062
61196
  init_transcript_tailer();
@@ -63376,7 +63510,7 @@ var init_package = __esm({
63376
63510
  "package.json"() {
63377
63511
  package_default = {
63378
63512
  name: "@oxagen/cli",
63379
- version: "2.1.5-76",
63513
+ version: "2.1.5-88",
63380
63514
  description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
63381
63515
  type: "module",
63382
63516
  main: "./dist/index.js",
@@ -79174,9 +79308,40 @@ var init_digest3 = __esm({
79174
79308
  });
79175
79309
 
79176
79310
  // ../../packages/run-evidence/src/limits.ts
79311
+ function countCapFor(collection) {
79312
+ const shareBytes = Math.floor(
79313
+ ENVELOPE_ITEM_BUDGET_JCS_BYTES * ENVELOPE_COLLECTION_SHARES[collection] / 100
79314
+ );
79315
+ return Math.floor(shareBytes / MAX_ENVELOPE_ITEM_JCS_BYTES);
79316
+ }
79317
+ var MAX_ENVELOPE_JCS_BYTES, ENVELOPE_RESERVED_JCS_BYTES, MAX_ENVELOPE_ITEM_JCS_BYTES, ENVELOPE_COLLECTION_SHARES, ENVELOPE_ITEM_BUDGET_JCS_BYTES, MAX_CONTEXT_FRAMES, MAX_MODEL_CALLS, MAX_CHANGES, MAX_TOOL_CALLS, MAX_APPROVALS, MAX_VERIFICATIONS, MAX_COMMITS, MAX_PULL_REQUESTS, MAX_ARTIFACTS;
79177
79318
  var init_limits = __esm({
79178
79319
  "../../packages/run-evidence/src/limits.ts"() {
79179
79320
  "use strict";
79321
+ MAX_ENVELOPE_JCS_BYTES = 1048576;
79322
+ ENVELOPE_RESERVED_JCS_BYTES = 65536;
79323
+ MAX_ENVELOPE_ITEM_JCS_BYTES = 512;
79324
+ ENVELOPE_COLLECTION_SHARES = {
79325
+ contextFrames: 10,
79326
+ modelCalls: 15,
79327
+ changes: 20,
79328
+ toolCalls: 30,
79329
+ approvals: 3,
79330
+ verifications: 5,
79331
+ commits: 7,
79332
+ pullRequests: 2,
79333
+ artifacts: 8
79334
+ };
79335
+ ENVELOPE_ITEM_BUDGET_JCS_BYTES = MAX_ENVELOPE_JCS_BYTES - ENVELOPE_RESERVED_JCS_BYTES;
79336
+ MAX_CONTEXT_FRAMES = countCapFor("contextFrames");
79337
+ MAX_MODEL_CALLS = countCapFor("modelCalls");
79338
+ MAX_CHANGES = countCapFor("changes");
79339
+ MAX_TOOL_CALLS = countCapFor("toolCalls");
79340
+ MAX_APPROVALS = countCapFor("approvals");
79341
+ MAX_VERIFICATIONS = countCapFor("verifications");
79342
+ MAX_COMMITS = countCapFor("commits");
79343
+ MAX_PULL_REQUESTS = countCapFor("pullRequests");
79344
+ MAX_ARTIFACTS = countCapFor("artifacts");
79180
79345
  }
79181
79346
  });
79182
79347
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxagen/cli",
3
- "version": "2.1.5-76",
3
+ "version": "2.1.5-88",
4
4
  "description": "Oxagen governance CLI — spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
5
5
  "type": "module",
6
6
  "bin": {