@oxagen/cli 2.1.4-489 → 2.1.4-495

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 +304 -71
  2. package/package.json +1 -1
package/oxagen.mjs CHANGED
@@ -4839,6 +4839,16 @@ var init_envelope = __esm({
4839
4839
  ]).optional(),
4840
4840
  tool_denial_kind: short.optional(),
4841
4841
  tool_result_tokens: u32.optional(),
4842
+ /**
4843
+ * How `tool_result_tokens` is known (#5339). `reported` is Claude Code's own
4844
+ * count on its OTel tool span. `estimated` is the recorder's: the result's
4845
+ * UTF-8 bytes over four, from the hook that saw the result. A count with no
4846
+ * basis was written before the member existed, and only the OTel span wrote
4847
+ * a count then, so a reader takes it as `reported`. The recorder writes the
4848
+ * two together. The envelope does not require the pair, so a frame from a
4849
+ * host older than the member still parses.
4850
+ */
4851
+ tool_result_tokens_basis: external_exports.enum(TOKEN_SOURCE_BASES).optional(),
4842
4852
  batch_size: u8.optional(),
4843
4853
  batch_index: u8.optional(),
4844
4854
  attribution_skill: short.optional(),
@@ -5615,7 +5625,7 @@ function bundleSkillChars(skill) {
5615
5625
  for (const file of skill.files) chars += file.path.length + file.content.length;
5616
5626
  return chars;
5617
5627
  }
5618
- var TACHO_BATCH_SCHEMA, TACHO_BUNDLE_SCHEMA, TACHO_COMMANDS_SCHEMA, TACHO_ENROLLMENT_CLAIMS_SCHEMA, TACHO_ENFORCEMENT_TIER_ATTR, TACHO_GATEWAY_TIER, TACHO_GATEWAY_SESSION_HEADER, TACHO_GATEWAY_GENESIS_HEADER, TACHO_METERING_ATTR, TACHO_METERING_OBSERVED, TACHO_MODEL_SESSION_HEADER, TACHO_CREDENTIAL_BASIS_ATTR, TACHO_CREDENTIAL_GATEWAY_BROKERED, TACHO_CREDENTIAL_HARNESS_HELD, TACHO_CREDENTIAL_BASES, TACHO_RUN_TOKEN_ATTR, BUNDLE_FEATURE_GATEWAY_TOOLS, BUNDLE_FEATURE_MODEL_PRICES, BUNDLE_FEATURE_MODEL_ALLOWLIST, BUNDLE_FEATURE_INDEPENDENT_MODELS, BUNDLE_FEATURE_HOOK_FAIL_OPEN, BUNDLE_FEATURE_STEERING_MANIFEST, BUNDLE_FEATURE_CONTAINMENT, BUNDLE_FEATURE_DAILY_BUDGET, BUNDLE_FEATURE_STEER_NEXT_STEP, BUNDLE_FEATURE_UNBOUND_REPO, BUNDLE_FEATURE_CEDAR, BUNDLE_FEATURE_SKILLS, BUNDLE_FEATURE_CACHE_KEEP_ALIVE, BUNDLE_FEATURE_WORK_ORDERS, TACHO_BUNDLE_FEATURES, bundleFeaturesSchema, hostEnrollmentIdSchema, tachoPlatformSchema, tachoHarnessSchema, TACHO_HARNESS_LABELS, TACHO_HARNESS_TIERS, WRAPPED_HARNESSES, CONNECTED_HARNESSES, HARNESS_BINARY, MODEL_HARNESS_ROUTES, MODEL_ROUTED_HARNESSES, BROKERABLE_HARNESSES, BROKERABLE_HARNESS_PROVIDER, TACHO_TIER_SUMMARY, CUSTOM_AGENT_NAME_PATTERN, RESERVED_AGENT_NAMES, customAgentNameSchema, tachoHostStatusSchema, tachoBundleModeSchema, tachoCommandSchema, tachoCommandStatusSchema, tachoCommandAckStatusSchema, tachoDeliveryModeSchema, denyGenerationSchema, deliveredCommandSchema, deliveredCommandResponseSchema, WORK_ORDER_ID_PATTERN, WORK_ITEM_ID_PATTERN, workOrderCommandPayloadSchema, WORK_ORDER_CLAIM_PATH, WORK_ORDER_REJECT_PATH, workOrderClaimResponseSchema, workOrderRejectResponseSchema, WORK_ORDER_ENV, WORK_ORDER_ATTR, steeringForceSchema, steeringItemKindSchema, steeringCutReasonSchema, steeringManifestItemSchema, STEERING_MANIFEST_SCHEMA, steeringManifestSchema, steeringManifestFrameSchema, cedarIdSchema, cedarPrincipalSchema, cedarToolSchema, cedarBundleSchema, BUNDLE_SKILLS_MAX, BUNDLE_SKILL_FILES_MAX, BUNDLE_SKILLS_CHARS_MAX, BASE64_PATTERN, bundleSkillFileSchema, bundleSkillSchema, policyBundleSchema, enrollmentClaimsSchema, tachoEventWireSchema, daemonHealthSchema, TACHO_MAX_BATCH, TACHO_MAX_BODY_BYTES, TACHO_MAX_REQUEST_BYTES, TACHO_REQUEST_ENVELOPE_BYTES, tachoBodySchema, tachoBatchSchema, agentDaySpendSchema, controlEnvelopeSchema, ingestResponseSchema, bundleResponseSchema, commandAcknowledgementSchema, commandsResponseSchema, enrollmentResponseSchema, tokenEnrollmentResponseSchema;
5628
+ var TACHO_BATCH_SCHEMA, TACHO_BUNDLE_SCHEMA, TACHO_COMMANDS_SCHEMA, TACHO_ENROLLMENT_CLAIMS_SCHEMA, TACHO_ENFORCEMENT_TIER_ATTR, TACHO_GATEWAY_TIER, TACHO_GATEWAY_SESSION_HEADER, TACHO_GATEWAY_GENESIS_HEADER, MCP_STREAMABLE_HTTP_ACCEPT, TACHO_METERING_ATTR, TACHO_METERING_OBSERVED, TACHO_MODEL_SESSION_HEADER, TACHO_CREDENTIAL_BASIS_ATTR, TACHO_CREDENTIAL_GATEWAY_BROKERED, TACHO_CREDENTIAL_HARNESS_HELD, TACHO_CREDENTIAL_BASES, TACHO_RUN_TOKEN_ATTR, BUNDLE_FEATURE_GATEWAY_TOOLS, BUNDLE_FEATURE_MODEL_PRICES, BUNDLE_FEATURE_MODEL_ALLOWLIST, BUNDLE_FEATURE_INDEPENDENT_MODELS, BUNDLE_FEATURE_HOOK_FAIL_OPEN, BUNDLE_FEATURE_STEERING_MANIFEST, BUNDLE_FEATURE_CONTAINMENT, BUNDLE_FEATURE_DAILY_BUDGET, BUNDLE_FEATURE_STEER_NEXT_STEP, BUNDLE_FEATURE_UNBOUND_REPO, BUNDLE_FEATURE_CEDAR, BUNDLE_FEATURE_SKILLS, BUNDLE_FEATURE_CACHE_KEEP_ALIVE, BUNDLE_FEATURE_WORK_ORDERS, TACHO_BUNDLE_FEATURES, bundleFeaturesSchema, hostEnrollmentIdSchema, tachoPlatformSchema, tachoHarnessSchema, TACHO_HARNESS_LABELS, TACHO_HARNESS_TIERS, WRAPPED_HARNESSES, CONNECTED_HARNESSES, HARNESS_BINARY, MODEL_HARNESS_ROUTES, MODEL_ROUTED_HARNESSES, BROKERABLE_HARNESSES, BROKERABLE_HARNESS_PROVIDER, TACHO_TIER_SUMMARY, CUSTOM_AGENT_NAME_PATTERN, RESERVED_AGENT_NAMES, customAgentNameSchema, tachoHostStatusSchema, tachoBundleModeSchema, tachoCommandSchema, tachoCommandStatusSchema, tachoCommandAckStatusSchema, tachoDeliveryModeSchema, denyGenerationSchema, deliveredCommandSchema, deliveredCommandResponseSchema, WORK_ORDER_ID_PATTERN, WORK_ITEM_ID_PATTERN, workOrderCommandPayloadSchema, WORK_ORDER_CLAIM_PATH, WORK_ORDER_REJECT_PATH, workOrderClaimResponseSchema, workOrderRejectResponseSchema, WORK_ORDER_ENV, WORK_ORDER_ATTR, steeringForceSchema, steeringItemKindSchema, steeringCutReasonSchema, steeringManifestItemSchema, STEERING_MANIFEST_SCHEMA, steeringManifestSchema, steeringManifestFrameSchema, cedarIdSchema, cedarPrincipalSchema, cedarToolSchema, cedarBundleSchema, BUNDLE_SKILLS_MAX, BUNDLE_SKILL_FILES_MAX, BUNDLE_SKILLS_CHARS_MAX, BASE64_PATTERN, bundleSkillFileSchema, bundleSkillSchema, policyBundleSchema, enrollmentClaimsSchema, tachoEventWireSchema, daemonHealthSchema, TACHO_MAX_BATCH, TACHO_MAX_BODY_BYTES, TACHO_MAX_REQUEST_BYTES, TACHO_REQUEST_ENVELOPE_BYTES, tachoBodySchema, tachoBatchSchema, agentDaySpendSchema, controlEnvelopeSchema, ingestResponseSchema, bundleResponseSchema, commandAcknowledgementSchema, commandsResponseSchema, enrollmentResponseSchema, tokenEnrollmentResponseSchema;
5619
5629
  var init_wire = __esm({
5620
5630
  "../../packages/tacho/src/wire.ts"() {
5621
5631
  "use strict";
@@ -5631,6 +5641,7 @@ var init_wire = __esm({
5631
5641
  TACHO_GATEWAY_TIER = "gateway";
5632
5642
  TACHO_GATEWAY_SESSION_HEADER = "x-tacho-gateway-session";
5633
5643
  TACHO_GATEWAY_GENESIS_HEADER = "x-tacho-gateway-genesis";
5644
+ MCP_STREAMABLE_HTTP_ACCEPT = "application/json, text/event-stream";
5634
5645
  TACHO_METERING_ATTR = "oxagen.metering";
5635
5646
  TACHO_METERING_OBSERVED = "observed";
5636
5647
  TACHO_MODEL_SESSION_HEADER = "x-oxagen-session";
@@ -11528,7 +11539,10 @@ function normalizeHook(raw, env, options) {
11528
11539
  body2["tool_output_digest"] = digestJcs(
11529
11540
  input.tool_response
11530
11541
  );
11531
- body2["tool_output_bytes"] = jsonByteLength(input.tool_response);
11542
+ const bytes = jsonByteLength(input.tool_response);
11543
+ body2["tool_output_bytes"] = bytes;
11544
+ body2["tool_result_tokens"] = Math.ceil(bytes / 4);
11545
+ body2["tool_result_tokens_basis"] = "estimated";
11532
11546
  }
11533
11547
  if (failed3) {
11534
11548
  const error = input.error ?? input["error_type"];
@@ -14512,7 +14526,24 @@ function steeringFactsOf(steering) {
14512
14526
  steering_tokens_basis: "estimated"
14513
14527
  };
14514
14528
  }
14515
- var REQUEST_FULL_DIGEST_ATTR, SYSTEM_CONTEXT_PARTS_OMITTED_ATTR, MEMORY_REQUESTS, LISTED_PER_TURN, U32_MAX, NAME_MAX, tokenSourceFacts, SystemContextMemory, SHARED_SYSTEM_CONTEXT_MEMORY, CONVERSATION_FIELDS2, STEERING_ASSEMBLY_PART, SystemContextTracker;
14529
+ function contextFactsOf(tokens) {
14530
+ if (tokens <= 0) return {};
14531
+ return {
14532
+ context_frame_tokens: tokens,
14533
+ context_frame_tokens_basis: "estimated"
14534
+ };
14535
+ }
14536
+ function injectedMarksOf(value) {
14537
+ if (!Array.isArray(value)) return [];
14538
+ return value.flatMap((mark) => {
14539
+ if (typeof mark !== "object" || mark === null) return [];
14540
+ const { at, tokens } = mark;
14541
+ if (typeof at !== "string" || typeof tokens !== "number") return [];
14542
+ if (!Number.isFinite(tokens)) return [];
14543
+ return [{ at, tokens: clampU32(tokens) }];
14544
+ });
14545
+ }
14546
+ var REQUEST_FULL_DIGEST_ATTR, SYSTEM_CONTEXT_PARTS_OMITTED_ATTR, MEMORY_REQUESTS, LISTED_PER_TURN, INJECTED_MARKS_MAX, U32_MAX, NAME_MAX, tokenSourceFacts, SystemContextMemory, SHARED_SYSTEM_CONTEXT_MEMORY, CONVERSATION_FIELDS2, STEERING_ASSEMBLY_PART, SystemContextTracker;
14516
14547
  var init_system_context = __esm({
14517
14548
  "../../packages/tacho/src/claude-code/system-context.ts"() {
14518
14549
  "use strict";
@@ -14524,6 +14555,7 @@ var init_system_context = __esm({
14524
14555
  SYSTEM_CONTEXT_PARTS_OMITTED_ATTR = "oxagen.system_context_parts_omitted";
14525
14556
  MEMORY_REQUESTS = 512;
14526
14557
  LISTED_PER_TURN = 16;
14558
+ INJECTED_MARKS_MAX = 32;
14527
14559
  U32_MAX = 4294967295;
14528
14560
  NAME_MAX = 512;
14529
14561
  tokenSourceFacts = modelFacts.pick({
@@ -14580,11 +14612,16 @@ var init_system_context = __esm({
14580
14612
  this.steering = parts === void 0 ? void 0 : { parts, tokens: state?.steeringTokens ?? sum(parts) };
14581
14613
  this.listedTurn = state?.listedTurn;
14582
14614
  this.listed = [...state?.listed ?? []];
14615
+ this.injected = injectedMarksOf(state?.injected);
14616
+ const floor = state?.injectedFloor;
14617
+ this.injectedFloor = typeof floor === "number" && Number.isFinite(floor) ? clampU32(floor) : 0;
14583
14618
  }
14584
14619
  memory;
14585
14620
  steering;
14586
14621
  listedTurn;
14587
14622
  listed;
14623
+ injected;
14624
+ injectedFloor;
14588
14625
  state() {
14589
14626
  const state = {};
14590
14627
  if (this.steering !== void 0) {
@@ -14593,6 +14630,9 @@ var init_system_context = __esm({
14593
14630
  }
14594
14631
  if (this.listedTurn !== void 0) state.listedTurn = this.listedTurn;
14595
14632
  if (this.listed.length > 0) state.listed = [...this.listed];
14633
+ if (this.injected.length > 0)
14634
+ state.injected = this.injected.map((mark) => ({ ...mark }));
14635
+ if (this.injectedFloor > 0) state.injectedFloor = this.injectedFloor;
14596
14636
  return state;
14597
14637
  }
14598
14638
  /** Take the steering a sealed `steering.manifest` frame names. */
@@ -14600,21 +14640,84 @@ var init_system_context = __esm({
14600
14640
  const steering = steeringContext(body2);
14601
14641
  if (steering !== void 0) this.steering = steering;
14602
14642
  }
14643
+ /**
14644
+ * Note text an Oxagen hook answer handed the agent after its start, at
14645
+ * `at`, when the answer left (#5339). The text joins the conversation, so
14646
+ * every call made from `at` on carries it. Empty text notes nothing.
14647
+ *
14648
+ * The caller passes only text the session's own conversation reads. The
14649
+ * start's text is the steering manifest's to count, and a subagent's text
14650
+ * stays in the subagent's conversation.
14651
+ */
14652
+ noteInjectedContext(text4, at) {
14653
+ const tokens = clampU32(budgetTokens(text4));
14654
+ if (tokens === 0) return;
14655
+ this.markInjected(at, this.injectedTotal() + tokens);
14656
+ }
14657
+ /**
14658
+ * Empty the running total at `at`: a compaction or a `/clear` took the
14659
+ * text out of the conversation. A call made before `at` still reads the
14660
+ * total it was made with.
14661
+ */
14662
+ clearInjectedContext(at) {
14663
+ if (this.injected.length === 0 && this.injectedFloor === 0) return;
14664
+ this.markInjected(at, 0);
14665
+ }
14666
+ injectedTotal() {
14667
+ return this.injected.at(-1)?.tokens ?? this.injectedFloor;
14668
+ }
14669
+ markInjected(at, tokens) {
14670
+ this.injected.push({ at, tokens: clampU32(tokens) });
14671
+ while (this.injected.length > INJECTED_MARKS_MAX) {
14672
+ const oldest = this.injected.shift();
14673
+ if (oldest !== void 0) this.injectedFloor = oldest.tokens;
14674
+ }
14675
+ }
14676
+ /**
14677
+ * The context Oxagen's hooks had handed the session when a call was made
14678
+ * at `at`: the latest mark at or before it. A record can arrive after
14679
+ * later answers left, since OTel exports in batches and the transcript is
14680
+ * read behind the session. A call with no readable time reads the latest
14681
+ * total. A call older than every mark kept reads the total before them.
14682
+ */
14683
+ injectedAt(at) {
14684
+ const when = at === void 0 ? Number.NaN : Date.parse(at);
14685
+ if (Number.isNaN(when)) return this.injectedTotal();
14686
+ for (let index = this.injected.length - 1; index >= 0; index -= 1) {
14687
+ const mark = this.injected[index];
14688
+ if (mark === void 0) continue;
14689
+ const markAt = Date.parse(mark.at);
14690
+ if (Number.isNaN(markAt) || markAt <= when) return mark.tokens;
14691
+ }
14692
+ return this.injectedFloor;
14693
+ }
14603
14694
  /**
14604
14695
  * Measure one model call. `content` is the proxy's exchange body, `attrs`
14605
- * the frame's attrs, and `turn` a key that changes when the turn does.
14696
+ * the frame's attrs, `turn` a key that changes when the turn does, and
14697
+ * `at` when the call was made.
14606
14698
  */
14607
- measure(content, attrs2, turn) {
14699
+ measure(content, attrs2, turn, at) {
14608
14700
  const recorded = requestOf(content);
14609
14701
  const resolved = recorded === void 0 ? void 0 : resolveRequest(recorded.request, this.memory);
14610
14702
  if (recorded === void 0 || resolved === void 0)
14611
- return this.checked(steeringFactsOf(this.steering), {}, () => {
14612
- });
14703
+ return this.checked(
14704
+ {
14705
+ ...steeringFactsOf(this.steering),
14706
+ ...contextFactsOf(this.injectedAt(at))
14707
+ },
14708
+ {},
14709
+ () => {
14710
+ }
14711
+ );
14613
14712
  const fullDigest = attrs2?.[REQUEST_FULL_DIGEST_ATTR];
14614
14713
  const key = isSha256Digest(fullDigest) ? fullDigest : recorded.request[PRIOR_MEMBER] === void 0 ? digestBytes(recorded.text) : void 0;
14615
14714
  if (key !== void 0) this.memory.set(key, resolved);
14616
- const steering = resolved.tools.length > 0 ? this.steering : void 0;
14617
- const facts = steeringFactsOf(steering);
14715
+ const main3 = resolved.tools.length > 0;
14716
+ const steering = main3 ? this.steering : void 0;
14717
+ const facts = {
14718
+ ...steeringFactsOf(steering),
14719
+ ...main3 ? contextFactsOf(this.injectedAt(at)) : {}
14720
+ };
14618
14721
  const parts = [
14619
14722
  ...resolved.system,
14620
14723
  ...resolved.instructions,
@@ -14647,15 +14750,23 @@ var init_system_context = __esm({
14647
14750
  /**
14648
14751
  * The token sources of a model call whose request the recorder never saw:
14649
14752
  * the counted OTel or transcript row of a call the proxy did not carry
14650
- * (#4493). Only the steering count is known without the request. The tool
14651
- * definition count, the context frame count, and the system context stay
14652
- * absent, never zero. Nothing changes on the tracker, so there is nothing
14653
- * to commit. The caller asks only for a call that carries the session's
14654
- * conversation, since a side call carries no steering.
14655
- */
14656
- measureUnseen() {
14657
- return this.checked(steeringFactsOf(this.steering), {}, () => {
14658
- }).facts;
14753
+ * (#4493). Two counts are known without the request: the steering, from
14754
+ * the manifest, and the context frames, from the hook answers noted before
14755
+ * `at`, when the call was made (#5339). The tool definition count and the
14756
+ * system context stay absent, never zero. Nothing changes on the tracker,
14757
+ * so there is nothing to commit. The caller asks only for a call that
14758
+ * carries the session's conversation, since a side call carries neither.
14759
+ */
14760
+ measureUnseen(at) {
14761
+ return this.checked(
14762
+ {
14763
+ ...steeringFactsOf(this.steering),
14764
+ ...contextFactsOf(this.injectedAt(at))
14765
+ },
14766
+ {},
14767
+ () => {
14768
+ }
14769
+ ).facts;
14659
14770
  }
14660
14771
  /**
14661
14772
  * Hand back facts the envelope accepts, or none. A body the envelope
@@ -15295,7 +15406,12 @@ function spanDraft(span, resource) {
15295
15406
  ...s(attrs2, "tool_name") !== void 0 ? { tool_name: s(attrs2, "tool_name") } : {},
15296
15407
  ...s(attrs2, "tool_use_id") !== void 0 ? { tool_use_id: s(attrs2, "tool_use_id") } : {},
15297
15408
  ...n(attrs2, "duration_ms") !== void 0 ? { tool_duration_ms: n(attrs2, "duration_ms") } : {},
15298
- ...n(attrs2, "result_tokens") !== void 0 ? { tool_result_tokens: n(attrs2, "result_tokens") } : {},
15409
+ // Claude Code's own count, so it is `reported`. A reader prefers it
15410
+ // to the hook's estimate of the same call (#5339).
15411
+ ...n(attrs2, "result_tokens") !== void 0 ? {
15412
+ tool_result_tokens: n(attrs2, "result_tokens"),
15413
+ tool_result_tokens_basis: "reported"
15414
+ } : {},
15299
15415
  ...s(attrs2, "file_path") !== void 0 ? { tool_target: s(attrs2, "file_path") } : {},
15300
15416
  ...s(attrs2, "full_command") !== void 0 ? { tool_target: (s(attrs2, "full_command") ?? "").slice(0, 512) } : {},
15301
15417
  ...s(attrs2, "skill_name") !== void 0 ? { attribution_skill: s(attrs2, "skill_name") } : {},
@@ -16543,16 +16659,18 @@ var init_recorder = __esm({
16543
16659
  if (kind === "agent_stop") this.turnOpen = false;
16544
16660
  const sighting = kind === "llm_call" ? this.llmCallSighting(body2, fields.source ?? "collector") : NO_SIGHTING;
16545
16661
  const duplicate = sighting.attrs ?? {};
16662
+ const ts2 = fields.ts ?? this.now();
16546
16663
  const measured = kind === "llm_call" ? this.systemContext.measure(
16547
16664
  fields.content,
16548
16665
  fields.attrs,
16549
- this.turnOpen ? `turn:${this.turnSeq}` : `idle:${this.turnSeq}`
16666
+ this.turnOpen ? `turn:${this.turnSeq}` : `idle:${this.turnSeq}`,
16667
+ ts2
16550
16668
  ) : void 0;
16551
16669
  const event = this.seal(
16552
16670
  kind,
16553
16671
  measured !== void 0 ? { ...measured.facts, ...body2 } : body2,
16554
16672
  {
16555
- ts: fields.ts ?? this.now(),
16673
+ ts: ts2,
16556
16674
  source: fields.source ?? "collector",
16557
16675
  ...fields.hook_event_name !== void 0 ? { hook_event_name: fields.hook_event_name } : {},
16558
16676
  attrs: { ...fields.attrs, ...measured?.attrs, ...duplicate },
@@ -16966,19 +17084,32 @@ var init_recorder = __esm({
16966
17084
  * recorder knows without the call's request (#4493). Only the counted row,
16967
17085
  * the first sighting of its call, takes them. A stamped duplicate is never
16968
17086
  * summed, and the rollup joins a stamped proxy row back for the members the
16969
- * counted row lacks. The steering count is the one source known without
16970
- * the request, so the tool definitions and the system context stay absent
16971
- * (ADR-062, amendment of 2026-10-02). A member the producer set itself
16972
- * wins, as on a proxied call. Only a call on the session's own
16973
- * conversation comes here: an OTel record whose `query_source` says so
16974
- * ({@link onSessionConversation}), or a transcript `assistant` record,
16975
- * since Claude Code writes no side call to the transcript.
16976
- */
16977
- withUnseenRequestSources(body2, attrs2) {
17087
+ * counted row lacks. Two sources are known without the request: the
17088
+ * steering count, and the context frames Oxagen's hooks handed the session
17089
+ * before `ts`, when the call was made (#5339). The tool definitions and the
17090
+ * system context stay absent (ADR-062, amendments of 2026-10-02 and
17091
+ * 2026-10-03). A member the producer set itself wins, as on a proxied call.
17092
+ * Only a call on the session's own conversation comes here: an OTel record
17093
+ * whose `query_source` says so ({@link onSessionConversation}), or a
17094
+ * transcript `assistant` record, since Claude Code writes no side call to
17095
+ * the transcript.
17096
+ */
17097
+ withUnseenRequestSources(body2, attrs2, ts2) {
16978
17098
  if (attrs2[LLM_CALL_DUPLICATE_OF_ATTR] !== void 0) return body2;
16979
- const facts = this.systemContext.measureUnseen();
17099
+ const facts = this.systemContext.measureUnseen(ts2);
16980
17100
  return Object.keys(facts).length === 0 ? body2 : { ...facts, ...body2 };
16981
17101
  }
17102
+ /**
17103
+ * Note text an Oxagen hook answer handed this session's agent after its
17104
+ * start, at `at`, when the answer left (#5339). Every model call on the
17105
+ * session's own conversation from then on carries the running total as
17106
+ * `context_frame_tokens`. The hook handler calls this only for a live
17107
+ * answer, since a replay's answer reaches no harness. A rollback of the
17108
+ * chain takes the note back with everything else the hook changed.
17109
+ */
17110
+ noteInjectedContext(text4, at) {
17111
+ this.systemContext.noteInjectedContext(text4, at);
17112
+ }
16982
17113
  /**
16983
17114
  * The attrs a `tool_call` carries, or undefined when the chain already
16984
17115
  * holds this call and the row must not be sealed at all.
@@ -17112,6 +17243,9 @@ var init_recorder = __esm({
17112
17243
  this.started = true;
17113
17244
  this.stopped = false;
17114
17245
  body2 = { ...body2, env_snapshot: this.envSnapshot };
17246
+ const source = body2["session_start_source"];
17247
+ if (source === "compact" || source === "clear")
17248
+ this.systemContext.clearInjectedContext(ts2);
17115
17249
  }
17116
17250
  if (draft.kind === "turn_start") {
17117
17251
  if (this.turnOpen) {
@@ -17388,7 +17522,7 @@ var init_recorder = __esm({
17388
17522
  }
17389
17523
  const event = this.seal(
17390
17524
  draft.kind,
17391
- draft.kind === "llm_call" && draft.source === "otel_log" && onSessionConversation(draft.standard.context.query_source) ? this.withUnseenRequestSources(draft.body, duplicate) : draft.body,
17525
+ draft.kind === "llm_call" && draft.source === "otel_log" && onSessionConversation(draft.standard.context.query_source) ? this.withUnseenRequestSources(draft.body, duplicate, draft.ts) : draft.body,
17392
17526
  {
17393
17527
  ts: draft.ts,
17394
17528
  source: draft.source,
@@ -17471,7 +17605,7 @@ var init_recorder = __esm({
17471
17605
  duplicate = { [LLM_CALL_DUPLICATE_OF_ATTR]: "transcript" };
17472
17606
  }
17473
17607
  if (draft.kind === "llm_call")
17474
- body2 = this.withUnseenRequestSources(body2, duplicate);
17608
+ body2 = this.withUnseenRequestSources(body2, duplicate, draft.ts);
17475
17609
  let content = draft.content;
17476
17610
  if (this.isSealedPrompt(draft.kind, body2)) {
17477
17611
  content = void 0;
@@ -23363,7 +23497,7 @@ import { readFileSync as readFileSync11 } from "node:fs";
23363
23497
  import { dirname as dirname8, resolve as resolve2 } from "node:path";
23364
23498
  import { fileURLToPath } from "node:url";
23365
23499
  function readVersion() {
23366
- if (true) return "2.1.4-489";
23500
+ if (true) return "2.1.4-495";
23367
23501
  try {
23368
23502
  const here = dirname8(fileURLToPath(import.meta.url));
23369
23503
  const pkg = JSON.parse(
@@ -28339,16 +28473,20 @@ function requestedMcpEndpoint(deps, warnings) {
28339
28473
  }
28340
28474
  return request3.pinned;
28341
28475
  }
28342
- function repointCommands(host, runtime) {
28343
- const same = host.hook_command === runtime.hookCommand && sameArgv(host.daemon_command, runtime.daemonCommand) && sameArgv(host.mcp_stdio_command ?? [], runtime.mcpStdioCommand);
28344
- if (same) return void 0;
28476
+ function repointCommands(host, runtime, wrapperVersion) {
28477
+ if (sameCommands(host, runtime) && host.wrapper_version === wrapperVersion)
28478
+ return void 0;
28345
28479
  return {
28346
28480
  ...host,
28347
28481
  hook_command: runtime.hookCommand,
28348
28482
  daemon_command: runtime.daemonCommand,
28349
- mcp_stdio_command: runtime.mcpStdioCommand
28483
+ mcp_stdio_command: runtime.mcpStdioCommand,
28484
+ wrapper_version: wrapperVersion
28350
28485
  };
28351
28486
  }
28487
+ function sameCommands(host, runtime) {
28488
+ return host.hook_command === runtime.hookCommand && sameArgv(host.daemon_command, runtime.daemonCommand) && sameArgv(host.mcp_stdio_command ?? [], runtime.mcpStdioCommand);
28489
+ }
28352
28490
  function sameArgv(a, b5) {
28353
28491
  return a.length === b5.length && a.every((part2, i2) => part2 === b5[i2]);
28354
28492
  }
@@ -28557,7 +28695,7 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
28557
28695
  writeHostFile(deps.paths.hostFile, host);
28558
28696
  deps.out(` MCP endpoint pinned to ${pinned} (TACHO_MCP_ENDPOINT)`);
28559
28697
  }
28560
- const repointed = repointCommands(host, deps.runtime);
28698
+ const repointed = repointCommands(host, deps.runtime, deps.wrapperVersion);
28561
28699
  if (repointed !== void 0) {
28562
28700
  if (deps.runtime.transient !== void 0) {
28563
28701
  warnings.push(
@@ -28570,9 +28708,14 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
28570
28708
  } else {
28571
28709
  host = { ...repointed, harness_files: harnessFilesRecord(deps.paths) };
28572
28710
  writeHostFile(deps.paths.hostFile, host);
28573
- deps.out(
28574
- ` service and hooks now run from ${deps.runtime.binDir} (was ${existing.hook_command})`
28575
- );
28711
+ if (!sameCommands(existing, deps.runtime))
28712
+ deps.out(
28713
+ ` service and hooks now run from ${deps.runtime.binDir} (was ${existing.hook_command})`
28714
+ );
28715
+ if (existing.wrapper_version !== deps.wrapperVersion)
28716
+ deps.out(
28717
+ ` host.json now records version ${deps.wrapperVersion} (was ${existing.wrapper_version})`
28718
+ );
28576
28719
  }
28577
28720
  }
28578
28721
  } else {
@@ -29906,6 +30049,11 @@ function shimError(id, message) {
29906
30049
  error: { code: -32002, message }
29907
30050
  };
29908
30051
  }
30052
+ function answersNoRequest(message) {
30053
+ if (Array.isArray(message) || !("error" in message)) return false;
30054
+ const id = message.id;
30055
+ return id === null || id === void 0;
30056
+ }
29909
30057
  function resolveTarget(options, deps) {
29910
30058
  const paths = agentPathsForEnrollment(
29911
30059
  tachoHome(deps.env, deps.home),
@@ -29937,8 +30085,9 @@ async function runMcpStdio(options, deps) {
29937
30085
  const text4 = line.trim();
29938
30086
  if (text4.length === 0) continue;
29939
30087
  let id;
30088
+ let method;
29940
30089
  try {
29941
- id = JSON.parse(text4).id;
30090
+ ({ id, method } = JSON.parse(text4));
29942
30091
  } catch {
29943
30092
  deps.stdout.write(
29944
30093
  `${JSON.stringify(shimError(null, "the shim received a line that is not JSON"))}
@@ -29946,7 +30095,7 @@ async function runMcpStdio(options, deps) {
29946
30095
  );
29947
30096
  continue;
29948
30097
  }
29949
- const expectsReply = id !== void 0;
30098
+ const expectsReply = id !== void 0 && typeof method === "string";
29950
30099
  const reply2 = (document) => {
29951
30100
  if (expectsReply) deps.stdout.write(`${JSON.stringify(document)}
29952
30101
  `);
@@ -29961,7 +30110,9 @@ async function runMcpStdio(options, deps) {
29961
30110
  headers: {
29962
30111
  Authorization: `Bearer ${target2.token}`,
29963
30112
  "Content-Type": "application/json",
29964
- Accept: "application/json",
30113
+ // The two media types the MCP transport requires of a client. The
30114
+ // local gateway always answers with JSON, which this accepts.
30115
+ Accept: MCP_STREAMABLE_HTTP_ACCEPT,
29965
30116
  // Loopback, so this is not a real origin check — it is here so the
29966
30117
  // gateway's guard sees a Host it recognises even behind a proxy
29967
30118
  // that rewrites one.
@@ -29983,8 +30134,12 @@ async function runMcpStdio(options, deps) {
29983
30134
  parsed = void 0;
29984
30135
  }
29985
30136
  if (typeof parsed === "object" && parsed !== null) {
29986
- if (expectsReply || response.ok) deps.stdout.write(`${body2}
30137
+ if (expectsReply && answersNoRequest(parsed)) {
30138
+ reply2({ ...parsed, id });
30139
+ } else if (expectsReply) {
30140
+ deps.stdout.write(`${body2}
29987
30141
  `);
30142
+ }
29988
30143
  } else if (!response.ok || expectsReply && body2.length > 0) {
29989
30144
  deps.stderr.write(
29990
30145
  `oxagen mcp-stdio: the gateway answered ${response.status}: ${body2.slice(0, 200)}
@@ -30018,6 +30173,7 @@ var init_mcp_stdio = __esm({
30018
30173
  init_agents();
30019
30174
  init_host_file();
30020
30175
  init_paths();
30176
+ init_wire();
30021
30177
  GATEWAY_TIMEOUT_MS = 5 * 6e4;
30022
30178
  }
30023
30179
  });
@@ -34674,12 +34830,45 @@ function readRpcBody(text4) {
34674
34830
  return JSON.parse(trimmed);
34675
34831
  }
34676
34832
  let last;
34677
- for (const line of trimmed.split(/\r?\n/)) {
34678
- if (line.startsWith("data:")) last = line.slice(5).trim();
34833
+ for (const event of trimmed.split(/\r?\n\r?\n/)) {
34834
+ const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(line.startsWith("data: ") ? 6 : 5));
34835
+ const payload = data.join("\n");
34836
+ if (payload.trim().length > 0) last = payload;
34679
34837
  }
34680
34838
  if (last === void 0) return void 0;
34681
34839
  return JSON.parse(last);
34682
34840
  }
34841
+ function isRpcErrorObject(value) {
34842
+ if (value === null || typeof value !== "object") return false;
34843
+ const error = value;
34844
+ return typeof error["code"] === "number" && typeof error["message"] === "string";
34845
+ }
34846
+ function answerFor(id, upstream) {
34847
+ const { status: status2, body: body2 } = upstream;
34848
+ const ok = status2 >= 200 && status2 < 300;
34849
+ const message = body2 !== null && typeof body2 === "object" && !Array.isArray(body2) ? body2 : void 0;
34850
+ const error = message?.["error"];
34851
+ if (isRpcErrorObject(error)) {
34852
+ if (message?.["id"] === id) return { status: status2, body: body2 };
34853
+ return {
34854
+ status: status2,
34855
+ body: { jsonrpc: "2.0", id, error }
34856
+ };
34857
+ }
34858
+ if (ok && message !== void 0 && "result" in message) {
34859
+ if (message["id"] === id) return { status: status2, body: body2 };
34860
+ }
34861
+ const flat = upstream.text.replace(/\s+/g, " ").trim();
34862
+ const what = flat.length === 0 ? "with no body" : `with a body that is not a JSON-RPC answer to this request: ${flat.slice(0, UPSTREAM_EXCERPT_MAX)}`;
34863
+ return {
34864
+ status: ok ? 502 : status2,
34865
+ body: rpcError(
34866
+ id,
34867
+ RPC_INTERNAL_ERROR,
34868
+ `the Oxagen control plane answered HTTP ${status2} ${what}`
34869
+ )
34870
+ };
34871
+ }
34683
34872
  function outcomeOf(status2, rpc) {
34684
34873
  if (rpc?.error !== void 0)
34685
34874
  return rpc.error.code === RPC_REFUSED ? "rejected" : "error";
@@ -34733,10 +34922,11 @@ function createMcpGateway(deps) {
34733
34922
  headers: {
34734
34923
  Authorization: `Bearer ${attribution2.apiKey}`,
34735
34924
  "Content-Type": "application/json",
34736
- // JSON only: the gateway answers one request at a time and has no
34737
- // stream to hand a client. A server that streams anyway is handled
34738
- // by `readRpcBody`.
34739
- Accept: "application/json",
34925
+ // Both media types, as the MCP transport requires. The hosted
34926
+ // server refuses any other Accept with a 406 (#5356). It answers
34927
+ // with an event stream, and `readRpcBody` reads the response out of
34928
+ // it, so the client still gets one JSON answer.
34929
+ Accept: MCP_STREAMABLE_HTTP_ACCEPT,
34740
34930
  "User-Agent": "oxagen-local-gateway",
34741
34931
  "X-Tacho-Host": attribution2.hostEnrollmentId,
34742
34932
  // Which chain this call belongs to. The control plane takes the
@@ -34756,7 +34946,13 @@ function createMcpGateway(deps) {
34756
34946
  signal: controller.signal
34757
34947
  });
34758
34948
  const text4 = await response.text();
34759
- return { status: response.status, body: readRpcBody(text4) };
34949
+ let body2;
34950
+ try {
34951
+ body2 = readRpcBody(text4);
34952
+ } catch {
34953
+ body2 = void 0;
34954
+ }
34955
+ return { status: response.status, body: body2, text: text4 };
34760
34956
  } finally {
34761
34957
  clearTimeout(timer);
34762
34958
  }
@@ -34809,9 +35005,9 @@ function createMcpGateway(deps) {
34809
35005
  if (name !== void 0) clients.set(context.sessionId, name);
34810
35006
  }
34811
35007
  const startedAt = now();
34812
- let response;
35008
+ let upstream;
34813
35009
  try {
34814
- response = await forward(request3, attribution2);
35010
+ upstream = await forward(request3, attribution2);
34815
35011
  } catch (error) {
34816
35012
  const message = error instanceof Error ? error.message : String(error);
34817
35013
  log(`mcp gateway forward failed: ${message}`);
@@ -34825,6 +35021,17 @@ function createMcpGateway(deps) {
34825
35021
  )
34826
35022
  };
34827
35023
  }
35024
+ let response = typeof request3.id === "string" || typeof request3.id === "number" ? answerFor(request3.id, upstream) : { status: upstream.status, body: upstream.body };
35025
+ if (response.body !== upstream.body) {
35026
+ const said = response.body.error?.message;
35027
+ log(
35028
+ `mcp gateway gave ${request3.method} an error with the request's id after HTTP ${upstream.status}: ${said ?? "no message"}`
35029
+ );
35030
+ } else if (upstream.status < 200 || upstream.status >= 300) {
35031
+ log(
35032
+ `mcp gateway: the control plane answered ${request3.method} with HTTP ${upstream.status}`
35033
+ );
35034
+ }
34828
35035
  const rpc = response.body;
34829
35036
  if (request3.method === "tools/list" && rpc?.result !== void 0) {
34830
35037
  const bundle2 = deps.bundle?.();
@@ -34944,7 +35151,7 @@ function toolNameOf(params) {
34944
35151
  const name = params?.["name"];
34945
35152
  return typeof name === "string" && name.length > 0 ? name : "unknown";
34946
35153
  }
34947
- var RPC_INVALID_REQUEST, RPC_INTERNAL_ERROR, RPC_REFUSED, CLAUDE_CODE_TOOL_USE_ID_META, MAX_TOOL_USE_ID_LENGTH, DEFAULT_TIMEOUT_MS3, REFUSAL_RULES_MAX, REFUSAL_RULE_MAX;
35154
+ var RPC_INVALID_REQUEST, RPC_INTERNAL_ERROR, RPC_REFUSED, CLAUDE_CODE_TOOL_USE_ID_META, MAX_TOOL_USE_ID_LENGTH, DEFAULT_TIMEOUT_MS3, UPSTREAM_EXCERPT_MAX, REFUSAL_RULES_MAX, REFUSAL_RULE_MAX;
34948
35155
  var init_mcp_gateway = __esm({
34949
35156
  "../../packages/tacho/src/collector/mcp-gateway.ts"() {
34950
35157
  "use strict";
@@ -34958,6 +35165,7 @@ var init_mcp_gateway = __esm({
34958
35165
  CLAUDE_CODE_TOOL_USE_ID_META = "claudecode/toolUseId";
34959
35166
  MAX_TOOL_USE_ID_LENGTH = 512;
34960
35167
  DEFAULT_TIMEOUT_MS3 = 3e4;
35168
+ UPSTREAM_EXCERPT_MAX = 200;
34961
35169
  REFUSAL_RULES_MAX = 64;
34962
35170
  REFUSAL_RULE_MAX = 512;
34963
35171
  }
@@ -38383,6 +38591,11 @@ function drainMidTurn(input, record, deps, events, replay, used = 0) {
38383
38591
  if (continuation !== void 0) texts.push(continuation);
38384
38592
  return texts;
38385
38593
  }
38594
+ function noteHandedContext(record, input, replay, text4, at) {
38595
+ if (replay !== void 0 || input.agent_id !== void 0) return;
38596
+ if (text4.length === 0) return;
38597
+ record.recorder.noteInjectedContext(text4, at);
38598
+ }
38386
38599
  function hookLedgerKey(raw, harness, hookId) {
38387
38600
  if (hookId !== void 0) return hookId;
38388
38601
  if (harness === "stella" || typeof raw !== "object" || raw === null)
@@ -38685,6 +38898,11 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
38685
38898
  ) : void 0;
38686
38899
  if (block === void 0) record.control.resumeOwed = void 0;
38687
38900
  if (block === void 0) notePrompt(record, promptText(input));
38901
+ const handed = [
38902
+ ...delivered,
38903
+ ...recalled !== void 0 ? [recalled.text] : []
38904
+ ];
38905
+ const context = handed.join(CONTEXT_JOINER);
38688
38906
  events.push(
38689
38907
  ...record.recorder.ingestHook(
38690
38908
  payload,
@@ -38692,11 +38910,16 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
38692
38910
  at,
38693
38911
  (draft) => withReplay({
38694
38912
  ...draft,
38695
- ...recalled !== void 0 ? {
38913
+ ...recalled !== void 0 || handed.length > 0 ? {
38696
38914
  attrs: {
38697
38915
  ...draft.attrs,
38698
- "oxagen.recall_digest": digestText(recalled.text),
38699
- "oxagen.recalled_memories": String(recalled.count)
38916
+ ...recalled !== void 0 ? {
38917
+ "oxagen.recall_digest": digestText(recalled.text),
38918
+ "oxagen.recalled_memories": String(recalled.count)
38919
+ } : {},
38920
+ // How much text the answer hands the agent, as the start
38921
+ // records it (#5339).
38922
+ ...handed.length > 0 ? { "oxagen.delivered_chars": String(context.length) } : {}
38700
38923
  }
38701
38924
  } : {},
38702
38925
  body: {
@@ -38717,16 +38940,13 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
38717
38940
  record
38718
38941
  };
38719
38942
  }
38720
- const context = [
38721
- ...delivered,
38722
- ...recalled !== void 0 ? [recalled.text] : []
38723
- ];
38943
+ noteHandedContext(record, input, replay, context, at);
38724
38944
  return {
38725
38945
  events,
38726
- response: context.length > 0 ? {
38946
+ response: handed.length > 0 ? {
38727
38947
  hookSpecificOutput: {
38728
38948
  hookEventName: "UserPromptSubmit",
38729
- additionalContext: context.join(CONTEXT_JOINER)
38949
+ additionalContext: context
38730
38950
  }
38731
38951
  } : {},
38732
38952
  record
@@ -38995,6 +39215,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
38995
39215
  if (operatorBlock(view, record) !== void 0)
38996
39216
  return { events, response: {}, record };
38997
39217
  const texts = drainMidTurn(input, record, deps, events, replay);
39218
+ noteHandedContext(record, input, replay, texts.join(CONTEXT_JOINER), at);
38998
39219
  return {
38999
39220
  events,
39000
39221
  response: texts.length > 0 ? {
@@ -39029,6 +39250,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
39029
39250
  ...drainMidTurn(input, record, deps, events, replay, ask?.length ?? 0),
39030
39251
  ...ask !== void 0 ? [ask] : []
39031
39252
  ];
39253
+ noteHandedContext(record, input, replay, texts.join(CONTEXT_JOINER), at);
39032
39254
  return {
39033
39255
  events,
39034
39256
  response: texts.length > 0 ? { decision: "block", reason: texts.join(CONTEXT_JOINER) } : {},
@@ -47228,7 +47450,17 @@ async function initializeDaemon(options, server, port, ready) {
47228
47450
  `no enrollment at ${paths.hostFile}; run \`oxagen agent enroll\` first`
47229
47451
  );
47230
47452
  }
47231
- let host = loaded;
47453
+ let host = loaded.wrapper_version === TACHO_VERSION ? loaded : { ...loaded, wrapper_version: TACHO_VERSION };
47454
+ const onDisk = readHostFileLenient(paths.hostFile).host;
47455
+ if (onDisk !== void 0 && onDisk.host_enrollment_id === host.host_enrollment_id && onDisk.wrapper_version !== TACHO_VERSION) {
47456
+ log(
47457
+ `host.json now records version ${TACHO_VERSION} (was ${onDisk.wrapper_version})`
47458
+ );
47459
+ writeHostFile(paths.hostFile, {
47460
+ ...onDisk,
47461
+ wrapper_version: TACHO_VERSION
47462
+ });
47463
+ }
47232
47464
  for (const dir of [paths.dir, paths.wal, paths.spool, paths.quarantine])
47233
47465
  ensureDir(dir);
47234
47466
  const recallMemories = options.memoryRecall ?? options.listen ?? true ? createMemoryRecall({
@@ -47517,10 +47749,10 @@ async function initializeDaemon(options, server, port, ready) {
47517
47749
  const marked = new Set(marks.map(({ session }) => session));
47518
47750
  const unmarked = registry2.list().filter((session) => within4(session) && !marked.has(session));
47519
47751
  if (unmarked.length > 0) {
47520
- const onDisk = new Set(wal.sessions());
47752
+ const onDisk2 = new Set(wal.sessions());
47521
47753
  for (const session of unmarked) {
47522
47754
  const recorder = session.recorder;
47523
- if (!onDisk.has(recorder.sessionUuid)) {
47755
+ if (!onDisk2.has(recorder.sessionUuid)) {
47524
47756
  recorder.rollbackToBirth();
47525
47757
  continue;
47526
47758
  }
@@ -47612,8 +47844,8 @@ async function initializeDaemon(options, server, port, ready) {
47612
47844
  bundle_etag: host.bundle.etag,
47613
47845
  // What this daemon's `policyBundleSchema` names, so the control plane
47614
47846
  // can send a gated bundle field without breaking hosts that predate it.
47615
- // Reported from the running code rather than from `host.json`, which
47616
- // `enroll` writes once and no upgrade rewrites.
47847
+ // Reported from the running code rather than read off `version`, which
47848
+ // a daemon older than #5365 took from the enrollment, not the upgrade.
47617
47849
  bundle_features: [...TACHO_BUNDLE_FEATURES],
47618
47850
  // Omitted until a read succeeds: absent means nothing was said, and a
47619
47851
  // daemon that could not read the files has nothing to say.
@@ -49811,6 +50043,7 @@ var init_daemon = __esm({
49811
50043
  init_work_orders();
49812
50044
  init_ids();
49813
50045
  init_timestamp();
50046
+ init_version();
49814
50047
  init_wire();
49815
50048
  init_backfill2();
49816
50049
  init_detector();
@@ -52035,7 +52268,7 @@ var init_package = __esm({
52035
52268
  "package.json"() {
52036
52269
  package_default = {
52037
52270
  name: "@oxagen/cli",
52038
- version: "2.1.4-489",
52271
+ version: "2.1.4-495",
52039
52272
  description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
52040
52273
  type: "module",
52041
52274
  main: "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxagen/cli",
3
- "version": "2.1.4-489",
3
+ "version": "2.1.4-495",
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": {