@legioncodeinc/honeycomb 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/daemon/index.js CHANGED
@@ -7369,7 +7369,7 @@ var require_dist = __commonJS({
7369
7369
  // dist/src/shared/constants.js
7370
7370
  var DAEMON_PORT = 3850;
7371
7371
  var DAEMON_HOST = "127.0.0.1";
7372
- var HONEYCOMB_VERSION = true ? "0.1.7" : "0.0.0-dev";
7372
+ var HONEYCOMB_VERSION = true ? "0.1.9" : "0.0.0-dev";
7373
7373
 
7374
7374
  // node_modules/zod/v4/classic/external.js
7375
7375
  var external_exports = {};
@@ -22440,7 +22440,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
22440
22440
  });
22441
22441
  if (!chunk) {
22442
22442
  if (i === 1) {
22443
- await new Promise((resolve6) => setTimeout(resolve6));
22443
+ await new Promise((resolve7) => setTimeout(resolve7));
22444
22444
  maxReadCount = 3;
22445
22445
  continue;
22446
22446
  }
@@ -22593,7 +22593,7 @@ async function startDaemon(daemon) {
22593
22593
  let server;
22594
22594
  let boundPort = daemon.config.port;
22595
22595
  try {
22596
- server = await new Promise((resolve6, reject) => {
22596
+ server = await new Promise((resolve7, reject) => {
22597
22597
  let handle;
22598
22598
  try {
22599
22599
  handle = serve({
@@ -22602,7 +22602,7 @@ async function startDaemon(daemon) {
22602
22602
  port: daemon.config.port
22603
22603
  }, (info) => {
22604
22604
  boundPort = info.port;
22605
- resolve6(handle);
22605
+ resolve7(handle);
22606
22606
  });
22607
22607
  handle.on?.("error", (err) => reject(err));
22608
22608
  } catch (err) {
@@ -22617,13 +22617,13 @@ async function startDaemon(daemon) {
22617
22617
  return {
22618
22618
  address: { host: daemon.config.host, port: boundPort },
22619
22619
  async close() {
22620
- await new Promise((resolve6, reject) => {
22620
+ await new Promise((resolve7, reject) => {
22621
22621
  server.close((err) => {
22622
22622
  if (err) {
22623
22623
  reject(err instanceof Error ? err : new Error(String(err)));
22624
22624
  return;
22625
22625
  }
22626
- resolve6();
22626
+ resolve7();
22627
22627
  });
22628
22628
  });
22629
22629
  await daemon.stopServices();
@@ -25673,6 +25673,28 @@ var SESSIONS_COLUMNS = Object.freeze([
25673
25673
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
25674
25674
  { name: "agent_id", sql: "TEXT NOT NULL DEFAULT 'default'" },
25675
25675
  { name: "visibility", sql: "TEXT NOT NULL DEFAULT 'global'" },
25676
+ // ── PRD-060a (a-AC-3 / a-AC-6): per-turn token + cache usage ──────────────────
25677
+ // Additive columns, healed in via the SAME `ALTER TABLE ADD COLUMN` path the rest
25678
+ // of the catalog uses (the heal engine iterates THIS array; nothing else to wire).
25679
+ //
25680
+ // ZERO vs NULL (a-AC-1 / a-AC-6, the open-question ruling): these four counts are
25681
+ // NULLABLE BIGINT with NO `DEFAULT 0`. The distinction is load-bearing — a genuine
25682
+ // `cache_read_input_tokens = 0` (a real measurement: nothing read from cache) must
25683
+ // stay DISTINCT from "no usage data" (the count was never produced). A `DEFAULT 0`
25684
+ // would collapse "absent" into "measured zero", which a-AC-6 forbids, so absent is
25685
+ // encoded as SQL NULL and a measured zero as the integer 0. Nullable columns are
25686
+ // exempt from the NOT-NULL-needs-a-DEFAULT load guard (NULL is their implicit
25687
+ // default), so `ALTER TABLE ADD COLUMN … BIGINT` heals cleanly onto a populated
25688
+ // legacy table: existing rows read back NULL = "token data absent" (a-AC-4).
25689
+ { name: "input_tokens", sql: "BIGINT" },
25690
+ { name: "output_tokens", sql: "BIGINT" },
25691
+ { name: "cache_read_input_tokens", sql: "BIGINT" },
25692
+ { name: "cache_creation_input_tokens", sql: "BIGINT" },
25693
+ // The capture-source discriminant (a-AC-7): every Claude-Code row carries
25694
+ // `source_tool = 'claude-code'`, so 060b/060e can render a "Claude Code only"
25695
+ // partial state. NOT NULL DEFAULT '' (a discriminant always present; '' = unknown
25696
+ // source) — heal-safe on a populated table because the empty string backfills.
25697
+ { name: "source_tool", sql: "TEXT NOT NULL DEFAULT ''" },
25676
25698
  { name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
25677
25699
  { name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
25678
25700
  ]);
@@ -25939,6 +25961,52 @@ var ROUTER_HISTORY_COLUMNS = Object.freeze([
25939
25961
  { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
25940
25962
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" }
25941
25963
  ]);
25964
+ var ROI_METRICS_COLUMNS = Object.freeze([
25965
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
25966
+ { name: "session_id", sql: "TEXT NOT NULL DEFAULT ''" },
25967
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
25968
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
25969
+ { name: "agent_id", sql: "TEXT NOT NULL DEFAULT 'default'" },
25970
+ { name: "project_id", sql: "TEXT NOT NULL DEFAULT ''" },
25971
+ { name: "team_id", sql: "TEXT NOT NULL DEFAULT ''" },
25972
+ // GATED: '' until a verified backend-token claim populates it (f-AC-6/f-AC-7).
25973
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
25974
+ { name: "input_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
25975
+ { name: "output_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
25976
+ { name: "cache_read_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
25977
+ { name: "cache_creation_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
25978
+ // MEASURED / MODELED / GROSS / INFRA money — BIGINT integer cents, never FLOAT (f-AC-4).
25979
+ { name: "measured_cache_savings_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
25980
+ { name: "modeled_savings_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
25981
+ { name: "modeled_assumption_ref", sql: "TEXT NOT NULL DEFAULT ''" },
25982
+ { name: "gross_cost_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
25983
+ { name: "infra_cost_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
25984
+ // cost_basis ∈ {measured, allocated, none}; allocation_method '' unless allocated (f-AC-5).
25985
+ { name: "cost_basis", sql: "TEXT NOT NULL DEFAULT 'none'" },
25986
+ { name: "allocation_method", sql: "TEXT NOT NULL DEFAULT ''" },
25987
+ { name: "price_ref", sql: "TEXT NOT NULL DEFAULT ''" },
25988
+ { name: "period_start", sql: "TEXT NOT NULL DEFAULT ''" },
25989
+ { name: "period_end", sql: "TEXT NOT NULL DEFAULT ''" },
25990
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" }
25991
+ ]);
25992
+ var ROI_COST_BASES = Object.freeze(["measured", "allocated", "none"]);
25993
+ var TEAMS_COLUMNS = Object.freeze([
25994
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
25995
+ { name: "team_id", sql: "TEXT NOT NULL DEFAULT ''" },
25996
+ { name: "team_name", sql: "TEXT NOT NULL DEFAULT ''" },
25997
+ // 'agent' rows work today; 'user' rows inert until user_id verified.
25998
+ { name: "member_type", sql: "TEXT NOT NULL DEFAULT 'agent'" },
25999
+ { name: "member_id", sql: "TEXT NOT NULL DEFAULT ''" },
26000
+ { name: "role", sql: "TEXT NOT NULL DEFAULT 'member'" },
26001
+ { name: "active", sql: "BIGINT NOT NULL DEFAULT 1" },
26002
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
26003
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
26004
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 0" },
26005
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
26006
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
26007
+ ]);
26008
+ var TEAM_MEMBER_TYPES = Object.freeze(["agent", "user"]);
26009
+ var TEAM_ACTIVE = 1;
25942
26010
  var TENANCY_TABLES = defineGroup([
25943
26011
  {
25944
26012
  name: "agents",
@@ -25977,6 +26045,25 @@ var TENANCY_TABLES = defineGroup([
25977
26045
  pattern: "append-only",
25978
26046
  embeddingColumns: [],
25979
26047
  scope: "tenant"
26048
+ },
26049
+ {
26050
+ // PRD-060f (f-AC-1/f-AC-2): the shared spend ledger. APPEND-ONLY — one
26051
+ // immutable row per session, a re-price APPENDs a new row (new price_ref),
26052
+ // NEVER an in-place UPDATE; the canonical row is MAX(created_at) per session.
26053
+ name: "roi_metrics",
26054
+ columns: ROI_METRICS_COLUMNS,
26055
+ pattern: "append-only",
26056
+ embeddingColumns: [],
26057
+ scope: "tenant"
26058
+ },
26059
+ {
26060
+ // PRD-060f (f-AC-8): the roster. VERSION-BUMPED — one row per (team, member),
26061
+ // an edit APPENDs version N+1, read ORDER BY version DESC (same as api_keys).
26062
+ name: "teams",
26063
+ columns: TEAMS_COLUMNS,
26064
+ pattern: "version-bumped",
26065
+ embeddingColumns: [],
26066
+ scope: "tenant"
25980
26067
  }
25981
26068
  ]);
25982
26069
  function buildApiKeyLookupByIdSql(id) {
@@ -27740,8 +27827,9 @@ function createEmbedSupervisor(deps = {}) {
27740
27827
  const cfg = resolveConfig2(deps.config);
27741
27828
  const spawnChild = deps.spawnChild ?? defaultSpawnChild(env);
27742
27829
  const probeHealth = deps.probeHealth ?? defaultProbeHealth(env);
27743
- const disabled = !resolveEmbedClientOptions(env).enabled;
27830
+ let enabled = deps.enabled ?? resolveEmbedClientOptions(env).enabled;
27744
27831
  let started = false;
27832
+ let lifecycleStarted = false;
27745
27833
  let stopping = false;
27746
27834
  let child = null;
27747
27835
  let live = false;
@@ -27812,7 +27900,7 @@ function createEmbedSupervisor(deps = {}) {
27812
27900
  return;
27813
27901
  await spawnAndWatch();
27814
27902
  }
27815
- return {
27903
+ const api = {
27816
27904
  get live() {
27817
27905
  return live;
27818
27906
  },
@@ -27820,16 +27908,17 @@ function createEmbedSupervisor(deps = {}) {
27820
27908
  return warm;
27821
27909
  },
27822
27910
  get disabled() {
27823
- return disabled;
27911
+ return !enabled;
27824
27912
  },
27825
27913
  get restarts() {
27826
27914
  return restarts;
27827
27915
  },
27828
27916
  async start() {
27917
+ lifecycleStarted = true;
27829
27918
  if (started)
27830
27919
  return;
27831
27920
  started = true;
27832
- if (disabled) {
27921
+ if (!enabled) {
27833
27922
  logger.event("embed.disabled");
27834
27923
  return;
27835
27924
  }
@@ -27871,12 +27960,29 @@ function createEmbedSupervisor(deps = {}) {
27871
27960
  live = false;
27872
27961
  warm = false;
27873
27962
  restarts = 0;
27874
- if (disabled || stopping)
27963
+ if (!enabled || stopping)
27875
27964
  return;
27876
27965
  logger.event("embed.manual_restart");
27877
27966
  await spawnAndWatch();
27967
+ },
27968
+ async setEnabled(want) {
27969
+ enabled = want;
27970
+ if (want) {
27971
+ logger.event("embed.enabled");
27972
+ if (!lifecycleStarted)
27973
+ return;
27974
+ if (child === null) {
27975
+ started = false;
27976
+ await api.start();
27977
+ }
27978
+ } else {
27979
+ logger.event("embed.disabled_live");
27980
+ if (child !== null)
27981
+ await api.stop();
27982
+ }
27878
27983
  }
27879
27984
  };
27985
+ return api;
27880
27986
  }
27881
27987
  var noopEmbedSupervisor = {
27882
27988
  live: false,
@@ -27888,6 +27994,8 @@ var noopEmbedSupervisor = {
27888
27994
  stop() {
27889
27995
  },
27890
27996
  async restart() {
27997
+ },
27998
+ async setEnabled() {
27891
27999
  }
27892
28000
  };
27893
28001
 
@@ -27896,7 +28004,9 @@ function buildHealthDetail(inputs) {
27896
28004
  const reasons = {
27897
28005
  storage: inputs.status === "ok" ? "reachable" : "unreachable",
27898
28006
  embeddings: inputs.embeddingsEnabled ? "on" : "off",
27899
- schema: inputs.schemaMissingTable === true ? "missing_table" : "ok"
28007
+ schema: inputs.schemaMissingTable === true ? "missing_table" : "ok",
28008
+ // PRD-063b / b-AC-7: read the supplied Portkey state verbatim (no probe). Omitted → `off`.
28009
+ portkey: inputs.portkey ?? "off"
27900
28010
  };
27901
28011
  return { status: inputs.status, reasons };
27902
28012
  }
@@ -27931,6 +28041,10 @@ var ROUTE_GROUPS = Object.freeze([
27931
28041
  { path: "/api/org", protect: true, session: false },
27932
28042
  { path: "/api/workspace", protect: true, session: false },
27933
28043
  { path: "/api/diagnostics", protect: true, session: false },
28044
+ // The dashboard imperative-actions surface (logout / embeddings / restart / uninstall). Protected
28045
+ // (inherits auth/RBAC) AND additionally local-mode + origin/CSRF gated inside the handlers
28046
+ // (`dashboard/actions-api.ts`), since these are credential/process/lifecycle actions.
28047
+ { path: "/api/actions", protect: true, session: false },
27934
28048
  { path: "/api/pipeline", protect: true, session: false },
27935
28049
  { path: "/api/repair", protect: true, session: false },
27936
28050
  { path: "/api/inference", protect: true, session: false },
@@ -28068,7 +28182,7 @@ function coarsePipelineStatus(storage) {
28068
28182
  }
28069
28183
 
28070
28184
  // dist/src/daemon/runtime/assemble.js
28071
- import { mkdirSync as mkdirSync20, readFileSync as readFileSync22, rmSync as rmSync9, writeFileSync as writeFileSync17 } from "node:fs";
28185
+ import { mkdirSync as mkdirSync20, mkdtempSync, readFileSync as readFileSync22, rmSync as rmSync10, writeFileSync as writeFileSync17 } from "node:fs";
28072
28186
  import { homedir as homedir25 } from "node:os";
28073
28187
  import { join as join32 } from "node:path";
28074
28188
 
@@ -28496,7 +28610,7 @@ function buildAllowedProperties(input) {
28496
28610
  }
28497
28611
  var systemTelemetryClock = () => (/* @__PURE__ */ new Date()).toISOString();
28498
28612
  var DEFAULT_EMIT_TIMEOUT_MS = 2e3;
28499
- var HONEYCOMB_VERSION2 = true ? "0.1.7" : "0.0.0-dev";
28613
+ var HONEYCOMB_VERSION2 = true ? "0.1.9" : "0.0.0-dev";
28500
28614
  async function emitTelemetry(event, opts, deps = {}) {
28501
28615
  const env = deps.env ?? process.env;
28502
28616
  const key = deps.posthogKey ?? POSTHOG_KEY;
@@ -28566,7 +28680,7 @@ async function postCapture(event, properties, distinctId, key, deps) {
28566
28680
  }
28567
28681
 
28568
28682
  // dist/src/daemon/runtime/auth/deeplake-issuer.js
28569
- var realSleeper = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
28683
+ var realSleeper = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
28570
28684
  var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
28571
28685
  var DEEPLAKE_ORG_HEADER = "X-Activeloop-Org-Id";
28572
28686
  var DEEPLAKE_CLIENT_VALUE = "honeycomb";
@@ -29094,7 +29208,7 @@ function resolveRequestScope(input) {
29094
29208
 
29095
29209
  // dist/src/daemon/runtime/auth/device-flow.js
29096
29210
  import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
29097
- var realSleeper2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
29211
+ var realSleeper2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
29098
29212
  var DEFAULT_MAX_POLLS2 = 900;
29099
29213
  function reporterOf(deps) {
29100
29214
  return deps.reporter ?? { prompt: (line) => console.log(line) };
@@ -29876,7 +29990,7 @@ function recursEnough(pairs) {
29876
29990
  }
29877
29991
  var systemGateSpawner = {
29878
29992
  run(spec, prompt, timeoutMs) {
29879
- return new Promise((resolve6, reject) => {
29993
+ return new Promise((resolve7, reject) => {
29880
29994
  const child = spawn2(spec.command, [...spec.args], { shell: false, windowsHide: true });
29881
29995
  let stdout = "";
29882
29996
  let settled = false;
@@ -29900,7 +30014,7 @@ var systemGateSpawner = {
29900
30014
  child.on("error", (err) => finish(() => reject(err)));
29901
30015
  child.on("close", (code) => {
29902
30016
  if (code === 0)
29903
- finish(() => resolve6(stdout));
30017
+ finish(() => resolve7(stdout));
29904
30018
  else
29905
30019
  finish(() => reject(new Error(`skillify gate CLI exited with code ${code ?? "null"}`)));
29906
30020
  });
@@ -30004,7 +30118,7 @@ function uniqueSessionIds(pairs) {
30004
30118
  return out;
30005
30119
  }
30006
30120
  function withTimeout(promise2, timeoutMs, message) {
30007
- return new Promise((resolve6, reject) => {
30121
+ return new Promise((resolve7, reject) => {
30008
30122
  let settled = false;
30009
30123
  const timer = setTimeout(() => {
30010
30124
  if (settled)
@@ -30017,7 +30131,7 @@ function withTimeout(promise2, timeoutMs, message) {
30017
30131
  return;
30018
30132
  settled = true;
30019
30133
  clearTimeout(timer);
30020
- resolve6(v);
30134
+ resolve7(v);
30021
30135
  }, (e) => {
30022
30136
  if (settled)
30023
30137
  return;
@@ -30392,7 +30506,7 @@ function buildSummaryPrompt(session, events) {
30392
30506
  }
30393
30507
  var systemSummarySpawner = {
30394
30508
  run(spec, prompt, timeoutMs) {
30395
- return new Promise((resolve6, reject) => {
30509
+ return new Promise((resolve7, reject) => {
30396
30510
  const child = spawn3(spec.command, [...spec.args], {
30397
30511
  shell: false,
30398
30512
  windowsHide: true,
@@ -30428,7 +30542,7 @@ var systemSummarySpawner = {
30428
30542
  child.on("error", (err) => finish(() => reject(err)));
30429
30543
  child.on("close", (code) => {
30430
30544
  if (code === 0)
30431
- finish(() => resolve6(stdout));
30545
+ finish(() => resolve7(stdout));
30432
30546
  else
30433
30547
  finish(() => reject(new Error(`summary gate CLI exited with code ${code ?? "null"}`)));
30434
30548
  });
@@ -30449,7 +30563,7 @@ function createHostSummaryGenCli(spec, spawner = systemSummarySpawner, timeoutMs
30449
30563
  }
30450
30564
  var systemSleeper = {
30451
30565
  sleep(ms) {
30452
- return new Promise((resolve6) => setTimeout(resolve6, ms));
30566
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
30453
30567
  }
30454
30568
  };
30455
30569
  async function runSummaryWorker(trigger, session, deps) {
@@ -31071,6 +31185,17 @@ function createSummaryJobWorker(deps) {
31071
31185
 
31072
31186
  // dist/src/daemon/runtime/capture/event-contract.js
31073
31187
  var nonEmpty = external_exports.string().trim().min(1);
31188
+ var tokenCount = external_exports.number().int().nonnegative();
31189
+ var TurnUsageSchema = external_exports.object({
31190
+ /** `input_tokens` — prompt tokens billed for this turn. */
31191
+ input: tokenCount.optional(),
31192
+ /** `output_tokens` — completion tokens billed for this turn. */
31193
+ output: tokenCount.optional(),
31194
+ /** `cache_read_input_tokens` — tokens served from the prompt cache (a real 0 ≠ absent). */
31195
+ cacheRead: tokenCount.optional(),
31196
+ /** `cache_creation_input_tokens` — tokens written into the prompt cache. */
31197
+ cacheCreation: tokenCount.optional()
31198
+ }).optional().transform((u) => u !== void 0 && (u.input !== void 0 || u.output !== void 0 || u.cacheRead !== void 0 || u.cacheCreation !== void 0) ? u : void 0);
31074
31199
  var UserMessageEventSchema = external_exports.object({
31075
31200
  kind: external_exports.literal("user_message"),
31076
31201
  text: external_exports.string()
@@ -31083,7 +31208,9 @@ var ToolCallEventSchema = external_exports.object({
31083
31208
  });
31084
31209
  var AssistantMessageEventSchema = external_exports.object({
31085
31210
  kind: external_exports.literal("assistant_message"),
31086
- text: external_exports.string()
31211
+ text: external_exports.string(),
31212
+ /** PRD-060a: optional per-turn token + cache counts; absent when unavailable. */
31213
+ usage: TurnUsageSchema
31087
31214
  });
31088
31215
  var CaptureEventSchema = external_exports.discriminatedUnion("kind", [
31089
31216
  UserMessageEventSchema,
@@ -31503,7 +31630,7 @@ var CaptureRouteHandler = class {
31503
31630
  */
31504
31631
  buildRow(id, event, meta3, nowIso10, projectId) {
31505
31632
  const message = this.config.envelopeBudgetBytes > 0 ? budgetedStringify(event, meta3, this.config.envelopeBudgetBytes) : JSON.stringify({ event, metadata: meta3 });
31506
- return [
31633
+ const row = [
31507
31634
  ["id", val.str(id)],
31508
31635
  ["path", val.str(meta3.path)],
31509
31636
  ["filename", val.str(meta3.hookEventName)],
@@ -31517,9 +31644,17 @@ var CaptureRouteHandler = class {
31517
31644
  ["project_id", val.str(projectId)],
31518
31645
  ["plugin_version", val.str(meta3.pluginVersion)],
31519
31646
  ["agent_id", val.str(meta3.agentId)],
31647
+ // PRD-060a (a-AC-7): the capture-source discriminant. `metadata.agent` is the
31648
+ // canonical harness token the shim stamps (`claude-code` for the reference
31649
+ // shim), so every Claude-Code-captured row carries `source_tool='claude-code'`.
31650
+ ["source_tool", val.str(meta3.agent)],
31520
31651
  ["creation_date", val.str(nowIso10)],
31521
31652
  ["last_update_date", val.str(nowIso10)]
31522
31653
  ];
31654
+ for (const [col, value] of usageColumns(event)) {
31655
+ row.push([col, val.num(value)]);
31656
+ }
31657
+ return row;
31523
31658
  }
31524
31659
  /**
31525
31660
  * Resolve the capture row's `project_id` from the session cwd (PRD-049b 49b-AC-1 / 49b-AC-3).
@@ -31662,6 +31797,21 @@ function embedTextFor(event) {
31662
31797
  return [event.tool, serialize(event.input), serialize(event.response)].filter((s) => s.length > 0).join("\n");
31663
31798
  }
31664
31799
  }
31800
+ function usageColumns(event) {
31801
+ if (event.kind !== "assistant_message" || event.usage === void 0)
31802
+ return [];
31803
+ const u = event.usage;
31804
+ const cols = [];
31805
+ if (u.input !== void 0)
31806
+ cols.push(["input_tokens", u.input]);
31807
+ if (u.output !== void 0)
31808
+ cols.push(["output_tokens", u.output]);
31809
+ if (u.cacheRead !== void 0)
31810
+ cols.push(["cache_read_input_tokens", u.cacheRead]);
31811
+ if (u.cacheCreation !== void 0)
31812
+ cols.push(["cache_creation_input_tokens", u.cacheCreation]);
31813
+ return cols;
31814
+ }
31665
31815
  function groupRowsByScope(batch) {
31666
31816
  const byKey = /* @__PURE__ */ new Map();
31667
31817
  for (const item of batch) {
@@ -33656,6 +33806,11 @@ async function runGraphBuild(identity, scope, options) {
33656
33806
  push: push.kind
33657
33807
  };
33658
33808
  }
33809
+ async function buildCodebaseGraphSnapshot(scope, options) {
33810
+ const workspaceDir = options.workspaceDir ?? process.cwd();
33811
+ const identity = options.identity ?? resolveSnapshotIdentity(workspaceDir, scope);
33812
+ return runGraphBuild(identity, scope, options);
33813
+ }
33659
33814
  function mountGraphApi(daemon, options) {
33660
33815
  const group = daemon.group(GRAPH_GROUP);
33661
33816
  if (group === void 0)
@@ -35259,6 +35414,37 @@ function mountSkillPropagationApi(daemon, options) {
35259
35414
  }
35260
35415
  }
35261
35416
 
35417
+ // dist/src/dashboard/contracts.js
35418
+ var EMPTY_DASHBOARD_DATA = Object.freeze({
35419
+ kpis: { memoryCount: 0, sessionCount: 0, turnCount: 0, estimatedSavings: 0, teamSkillCount: 0 },
35420
+ sessions: { sessions: [] },
35421
+ settings: { orgId: "", orgName: "", workspace: "", settings: {} },
35422
+ graph: { built: false, nodes: [], edges: [] },
35423
+ rules: { rules: [] },
35424
+ skillSync: { skills: [] }
35425
+ });
35426
+ var EMPTY_ROI_VIEW = Object.freeze({
35427
+ savings: {
35428
+ status: "absent",
35429
+ measuredCents: 0,
35430
+ modeledCents: 0,
35431
+ assumption: { kind: "", assumptionText: "", signedOff: false },
35432
+ blendedCentsPerMtok: null
35433
+ },
35434
+ infra: { status: "absent", cents: 0, costBasis: "none" },
35435
+ pollination: { status: "absent", cents: 0, lines: [] },
35436
+ net: { status: "absent", computed: false, netCents: 0, modeled: true, costBasis: "none" },
35437
+ rollups: [],
35438
+ perUserAvailable: false,
35439
+ scopedAcrossDevices: false,
35440
+ ratesAsOf: ""
35441
+ });
35442
+ var EMPTY_ROI_TREND = Object.freeze({
35443
+ status: "absent",
35444
+ series: [],
35445
+ startedAt: ""
35446
+ });
35447
+
35262
35448
  // dist/src/daemon/runtime/dashboard/installed-assets.js
35263
35449
  import { homedir as homedir11 } from "node:os";
35264
35450
  import { join as join16 } from "node:path";
@@ -35417,6 +35603,548 @@ function sanitizeName(name) {
35417
35603
  return name.replace(/[^A-Za-z0-9._-]/g, "_");
35418
35604
  }
35419
35605
 
35606
+ // dist/src/daemon/runtime/dashboard/roi-rates.js
35607
+ var ANTHROPIC_CACHE_READ_MULTIPLIER = 0.1;
35608
+ var ANTHROPIC_CACHE_WRITE_MULTIPLIER = 1.25;
35609
+ function anthropicCacheRate(inputCentsPerMtok, multiplier) {
35610
+ return Math.round(inputCentsPerMtok * multiplier);
35611
+ }
35612
+ var RATES_AS_OF = "2026-06-26";
35613
+ var RATE_TABLE = Object.freeze([
35614
+ Object.freeze({
35615
+ provider: "anthropic",
35616
+ model: "claude-sonnet-4-6",
35617
+ input_cents_per_mtok: 300,
35618
+ output_cents_per_mtok: 1500,
35619
+ cache_read_cents_per_mtok: anthropicCacheRate(300, ANTHROPIC_CACHE_READ_MULTIPLIER),
35620
+ cache_write_cents_per_mtok: anthropicCacheRate(300, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
35621
+ }),
35622
+ Object.freeze({
35623
+ provider: "anthropic",
35624
+ model: "claude-opus-4-8",
35625
+ input_cents_per_mtok: 1500,
35626
+ output_cents_per_mtok: 7500,
35627
+ cache_read_cents_per_mtok: anthropicCacheRate(1500, ANTHROPIC_CACHE_READ_MULTIPLIER),
35628
+ cache_write_cents_per_mtok: anthropicCacheRate(1500, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
35629
+ }),
35630
+ // Finding (haiku-rate): the skillify gate runs `claude-haiku-4-5` (roi-pollination.ts
35631
+ // SKILLIFY_HAIKU_MODEL). Without its own row, `priceHaikuTokens` fell back to the Sonnet default and
35632
+ // MIS-priced Honeycomb's own-inference cost. Anthropic Haiku per-Mtok: $1 in / $5 out; the cache
35633
+ // columns are derived from input via the SAME 0.1x / 1.25x multipliers (the invariant a test asserts).
35634
+ Object.freeze({
35635
+ provider: "anthropic",
35636
+ model: "claude-haiku-4-5",
35637
+ input_cents_per_mtok: 100,
35638
+ output_cents_per_mtok: 500,
35639
+ cache_read_cents_per_mtok: anthropicCacheRate(100, ANTHROPIC_CACHE_READ_MULTIPLIER),
35640
+ cache_write_cents_per_mtok: anthropicCacheRate(100, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
35641
+ })
35642
+ ]);
35643
+ var DEFAULT_RATE_PROVIDER = "anthropic";
35644
+ var DEFAULT_RATE_MODEL = "claude-sonnet-4-6";
35645
+ function rateRowFor(provider, model) {
35646
+ return RATE_TABLE.find((r) => r.provider === provider && r.model === model);
35647
+ }
35648
+ function defaultRateRow() {
35649
+ const row = rateRowFor(DEFAULT_RATE_PROVIDER, DEFAULT_RATE_MODEL);
35650
+ if (row === void 0) {
35651
+ throw new Error("roi-rates: the default rate row must exist in RATE_TABLE");
35652
+ }
35653
+ return row;
35654
+ }
35655
+ function resolveRate(provider, model) {
35656
+ if (provider === void 0 || model === void 0 || provider.length === 0 || model.length === 0) {
35657
+ return defaultRateRow();
35658
+ }
35659
+ return rateRowFor(provider, model) ?? defaultRateRow();
35660
+ }
35661
+
35662
+ // dist/src/daemon/runtime/dashboard/roi-savings.js
35663
+ function measured(value) {
35664
+ return { tag: "measured", value };
35665
+ }
35666
+ function modeled(value, assumption) {
35667
+ return { tag: "modeled", value, assumption };
35668
+ }
35669
+ function tokensAtRate(tokens, centsPerMtok) {
35670
+ return Math.round(tokens * centsPerMtok / 1e6);
35671
+ }
35672
+ function measuredCacheSavings(turns) {
35673
+ let savingsCents = 0;
35674
+ let measuredTurns = 0;
35675
+ for (const turn of turns) {
35676
+ if (turn.cache_read_input_tokens === null)
35677
+ continue;
35678
+ measuredTurns += 1;
35679
+ const rate = resolveRate(turn.provider, turn.model);
35680
+ const deltaCentsPerMtok = rate.input_cents_per_mtok - rate.cache_read_cents_per_mtok;
35681
+ savingsCents += tokensAtRate(turn.cache_read_input_tokens, deltaCentsPerMtok);
35682
+ }
35683
+ const totalTurns = turns.length;
35684
+ const status = totalTurns === 0 || measuredTurns === 0 ? "absent" : measuredTurns < totalTurns ? "partial" : "measured";
35685
+ return measured({ savingsCents, measuredTurns, totalTurns, status });
35686
+ }
35687
+ function blendedCentsPerMtok(turns) {
35688
+ let totalCents = 0;
35689
+ let totalTokens = 0;
35690
+ for (const turn of turns) {
35691
+ const rate = resolveRate(turn.provider, turn.model);
35692
+ if (turn.input_tokens !== null) {
35693
+ totalCents += tokensAtRate(turn.input_tokens, rate.input_cents_per_mtok);
35694
+ totalTokens += turn.input_tokens;
35695
+ }
35696
+ if (turn.output_tokens !== null) {
35697
+ totalCents += tokensAtRate(turn.output_tokens, rate.output_cents_per_mtok);
35698
+ totalTokens += turn.output_tokens;
35699
+ }
35700
+ if (turn.cache_read_input_tokens !== null) {
35701
+ totalCents += tokensAtRate(turn.cache_read_input_tokens, rate.cache_read_cents_per_mtok);
35702
+ totalTokens += turn.cache_read_input_tokens;
35703
+ }
35704
+ if (turn.cache_creation_input_tokens !== null) {
35705
+ totalCents += tokensAtRate(turn.cache_creation_input_tokens, rate.cache_write_cents_per_mtok);
35706
+ totalTokens += turn.cache_creation_input_tokens;
35707
+ }
35708
+ }
35709
+ if (totalTokens === 0)
35710
+ return null;
35711
+ return Math.round(totalCents / totalTokens * 1e6);
35712
+ }
35713
+ var MEMORY_INJECTION_ASSUMPTION = Object.freeze({
35714
+ kind: "turns-saved-per-session",
35715
+ turnsSavedPerSession: 2,
35716
+ avgTokensPerSavedTurn: 4e3,
35717
+ includesOutputTokens: false,
35718
+ signedOff: false,
35719
+ assumptionText: "PLACEHOLDER (pending operator sign-off): estimates that injecting memory saves ~2 turns of re-explaining per session, at ~4,000 input tokens per saved turn, priced at the session's input rate. Output-token savings are NOT yet claimed. This is a model, not a billed figure."
35720
+ });
35721
+ function modeledMemoryInjectionSavings(sessions, rate = resolveRate(void 0, void 0), assumption = MEMORY_INJECTION_ASSUMPTION) {
35722
+ const savedTokens = Math.max(0, sessions) * assumption.turnsSavedPerSession * assumption.avgTokensPerSavedTurn;
35723
+ let estimatedCents = tokensAtRate(savedTokens, rate.input_cents_per_mtok);
35724
+ if (assumption.includesOutputTokens) {
35725
+ estimatedCents += tokensAtRate(savedTokens, rate.output_cents_per_mtok);
35726
+ }
35727
+ return modeled({ estimatedCents, sessions: Math.max(0, sessions) }, assumption);
35728
+ }
35729
+
35730
+ // dist/src/daemon/runtime/dashboard/roi-billing.js
35731
+ var realSleeper3 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
35732
+ var systemBillingClock = {
35733
+ now() {
35734
+ return Date.now();
35735
+ }
35736
+ };
35737
+ var DEFAULT_MAX_RETRIES2 = 3;
35738
+ var DEFAULT_TIMEOUT_MS = 1e4;
35739
+ var DEFAULT_TTL_MS2 = 5 * 6e4;
35740
+ var DEEPLAKE_CLIENT_HEADER2 = "X-Deeplake-Client";
35741
+ var DEEPLAKE_ORG_HEADER2 = "X-Activeloop-Org-Id";
35742
+ var DEEPLAKE_CLIENT_VALUE2 = "honeycomb";
35743
+ var centsField = external_exports.number().int().catch(0);
35744
+ var numberField = external_exports.number().catch(0);
35745
+ var ComputeTierSchema = external_exports.object({
35746
+ tier: external_exports.string().catch(""),
35747
+ hours: numberField,
35748
+ cost_cents: centsField,
35749
+ unit_price_cents: centsField
35750
+ });
35751
+ var BillingComparisonSchema = external_exports.object({
35752
+ compute_cost_previous: centsField,
35753
+ total_cost_previous: centsField,
35754
+ delta_pct: numberField
35755
+ });
35756
+ var BillingComputeSchema = external_exports.object({
35757
+ total_cost_cents: centsField,
35758
+ total_pod_hours: numberField,
35759
+ by_tier: external_exports.array(ComputeTierSchema).catch([])
35760
+ });
35761
+ var BillingSummarySchema = external_exports.object({
35762
+ balance_cents: centsField,
35763
+ period_start: external_exports.string().catch(""),
35764
+ period_end: external_exports.string().catch(""),
35765
+ total_cost_cents: centsField,
35766
+ storage_cost_cents: centsField,
35767
+ transfer_cost_cents: centsField,
35768
+ projected_end_of_period_cents: centsField,
35769
+ compute: BillingComputeSchema,
35770
+ comparison: BillingComparisonSchema
35771
+ });
35772
+ var SESSION_TYPES = ["query", "embedding", "ingestion"];
35773
+ var SessionTypeSchema = external_exports.enum(SESSION_TYPES);
35774
+ var ComputeSessionSchema = external_exports.object({
35775
+ session_type: SessionTypeSchema,
35776
+ gpu_hours: numberField,
35777
+ gpu_units: numberField,
35778
+ price_cents_per_gpu_hour: centsField,
35779
+ // Finding (billing-zero): keep `total_cost_cents` OPTIONAL/nullish so a MISSING field (absent on the
35780
+ // wire) stays `undefined` and is distinguishable from a legitimate explicit `0` (a free session). The
35781
+ // `.catch(undefined)` keeps a present-but-malformed value from throwing while NOT collapsing it to 0
35782
+ // -- `buildSessionTypeBreakdown` derives a cost ONLY when the field is truly absent, never over an
35783
+ // explicit 0 (which would overwrite a legitimately-free session with gpu_hours x price).
35784
+ total_cost_cents: centsField.optional().nullable().catch(void 0)
35785
+ });
35786
+ var ComputeUsageSchema = external_exports.object({
35787
+ total_cost_cents: centsField,
35788
+ total_gpu_hours: numberField,
35789
+ sessions: external_exports.array(ComputeSessionSchema).catch([])
35790
+ });
35791
+ function sessionTypeTotalCents(lines) {
35792
+ return lines.reduce((sum, line) => sum + line.cost_cents, 0);
35793
+ }
35794
+ function isRetryable2(status) {
35795
+ return status === 429 || status >= 500 && status <= 599;
35796
+ }
35797
+ function billingHeaders(creds) {
35798
+ const headers = {
35799
+ Authorization: `Bearer ${creds.token}`,
35800
+ "Content-Type": "application/json",
35801
+ [DEEPLAKE_CLIENT_HEADER2]: DEEPLAKE_CLIENT_VALUE2
35802
+ };
35803
+ if (creds.orgId.length > 0)
35804
+ headers[DEEPLAKE_ORG_HEADER2] = creds.orgId;
35805
+ return headers;
35806
+ }
35807
+ function resolveBillingApiUrl(creds) {
35808
+ const base = creds.apiUrl !== void 0 && creds.apiUrl.length > 0 ? creds.apiUrl : DEFAULT_DEEPLAKE_API_URL;
35809
+ return base.replace(/\/+$/, "");
35810
+ }
35811
+ function buildSessionTypeBreakdown(usage) {
35812
+ return usage.sessions.map((s) => {
35813
+ const derived = Math.round(s.gpu_hours * s.price_cents_per_gpu_hour);
35814
+ const cost_cents = s.total_cost_cents !== void 0 && s.total_cost_cents !== null ? s.total_cost_cents : derived;
35815
+ return {
35816
+ session_type: s.session_type,
35817
+ gpu_hours: s.gpu_hours,
35818
+ price_cents_per_gpu_hour: s.price_cents_per_gpu_hour,
35819
+ cost_cents
35820
+ };
35821
+ });
35822
+ }
35823
+ function createInfraCostReadModel(options = {}) {
35824
+ const doFetch = options.fetch ?? globalThis.fetch;
35825
+ const sleep2 = options.sleep ?? realSleeper3;
35826
+ const clock = options.clock ?? systemBillingClock;
35827
+ const dir = options.dir;
35828
+ const loadCreds = options.creds ?? (() => loadDiskCredentials(dir));
35829
+ const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES2;
35830
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
35831
+ const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS2;
35832
+ let cached3;
35833
+ async function getJson(apiUrl, path4, headers) {
35834
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
35835
+ const controller = new AbortController();
35836
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
35837
+ try {
35838
+ const resp = await doFetch(`${apiUrl}${path4}`, { method: "GET", headers, signal: controller.signal });
35839
+ if (resp.ok) {
35840
+ return await resp.json().catch(() => null);
35841
+ }
35842
+ if (isRetryable2(resp.status) && attempt < maxRetries) {
35843
+ clearTimeout(timer);
35844
+ await sleep2(250 * 2 ** attempt);
35845
+ continue;
35846
+ }
35847
+ return null;
35848
+ } catch {
35849
+ if (attempt < maxRetries) {
35850
+ clearTimeout(timer);
35851
+ await sleep2(250 * 2 ** attempt);
35852
+ continue;
35853
+ }
35854
+ return null;
35855
+ } finally {
35856
+ clearTimeout(timer);
35857
+ }
35858
+ }
35859
+ return null;
35860
+ }
35861
+ function parseOrMissing(raw2, schema) {
35862
+ if (raw2 === null || raw2 === void 0)
35863
+ return void 0;
35864
+ const result = schema.safeParse(raw2);
35865
+ return result.success ? result.data : void 0;
35866
+ }
35867
+ async function fetchSnapshot() {
35868
+ const creds = loadCreds();
35869
+ if (creds === null || creds.token.length === 0) {
35870
+ return { status: "unauthenticated", missing: [], sessionTypes: [], fetchedAt: clock.now() };
35871
+ }
35872
+ const apiUrl = resolveBillingApiUrl(creds);
35873
+ const headers = billingHeaders(creds);
35874
+ const [summaryRaw, computeRaw] = await Promise.all([
35875
+ getJson(apiUrl, "/billing/summary", headers),
35876
+ getJson(apiUrl, "/billing/usage/compute", headers)
35877
+ ]);
35878
+ const summary = parseOrMissing(summaryRaw, BillingSummarySchema);
35879
+ const compute = parseOrMissing(computeRaw, ComputeUsageSchema);
35880
+ const missing = [];
35881
+ if (summary === void 0)
35882
+ missing.push("/billing/summary");
35883
+ if (compute === void 0)
35884
+ missing.push("/billing/usage/compute");
35885
+ const okCount = (summary !== void 0 ? 1 : 0) + (compute !== void 0 ? 1 : 0);
35886
+ const status = okCount === 0 ? "unreachable" : okCount === 2 ? "ok" : "partial";
35887
+ const sessionTypes = compute !== void 0 ? buildSessionTypeBreakdown(compute) : [];
35888
+ return {
35889
+ status,
35890
+ missing,
35891
+ ...summary !== void 0 ? { summary } : {},
35892
+ ...compute !== void 0 ? { compute } : {},
35893
+ sessionTypes,
35894
+ fetchedAt: clock.now()
35895
+ };
35896
+ }
35897
+ return {
35898
+ async read() {
35899
+ const now = clock.now();
35900
+ if (cached3 !== void 0 && now - cached3.fetchedAt < ttlMs) {
35901
+ return cached3;
35902
+ }
35903
+ const snapshot = await fetchSnapshot();
35904
+ cached3 = snapshot;
35905
+ return snapshot;
35906
+ },
35907
+ invalidate() {
35908
+ cached3 = void 0;
35909
+ }
35910
+ };
35911
+ }
35912
+
35913
+ // dist/src/daemon/runtime/dashboard/roi-pollination.js
35914
+ var SKILLIFY_PROVIDER = "anthropic";
35915
+ var SKILLIFY_HAIKU_MODEL = "claude-haiku-4-5";
35916
+ function tokensAtRate2(tokens, centsPerMtok) {
35917
+ return Math.round(tokens * centsPerMtok / 1e6);
35918
+ }
35919
+ function priceHaikuTokens(snapshot) {
35920
+ if (snapshot.perModel !== void 0 && snapshot.perModel.length > 0) {
35921
+ return snapshot.perModel.reduce((sum, b) => sum + priceBucket(b), 0);
35922
+ }
35923
+ const rate = resolveRate(SKILLIFY_PROVIDER, snapshot.model ?? SKILLIFY_HAIKU_MODEL);
35924
+ return tokensAtRate2(snapshot.inputTokens, rate.input_cents_per_mtok) + tokensAtRate2(snapshot.outputTokens, rate.output_cents_per_mtok) + tokensAtRate2(snapshot.cacheReadInputTokens, rate.cache_read_cents_per_mtok) + tokensAtRate2(snapshot.cacheCreationInputTokens, rate.cache_write_cents_per_mtok);
35925
+ }
35926
+ function priceBucket(b) {
35927
+ const rate = resolveRate(SKILLIFY_PROVIDER, b.model.length > 0 ? b.model : SKILLIFY_HAIKU_MODEL);
35928
+ return tokensAtRate2(b.inputTokens, rate.input_cents_per_mtok) + tokensAtRate2(b.outputTokens, rate.output_cents_per_mtok) + tokensAtRate2(b.cacheReadInputTokens, rate.cache_read_cents_per_mtok) + tokensAtRate2(b.cacheCreationInputTokens, rate.cache_write_cents_per_mtok);
35929
+ }
35930
+ function composeHaikuContribution(snapshot) {
35931
+ const buckets = snapshot.perModel;
35932
+ const model = buckets !== void 0 && buckets.length > 1 ? "mixed" : buckets !== void 0 && buckets.length === 1 ? buckets[0].model : snapshot.model ?? SKILLIFY_HAIKU_MODEL;
35933
+ if (snapshot.recorded === 0) {
35934
+ return {
35935
+ status: "absent",
35936
+ cents: 0,
35937
+ recorded: 0,
35938
+ inputTokens: 0,
35939
+ outputTokens: 0,
35940
+ cacheReadInputTokens: 0,
35941
+ cacheCreationInputTokens: 0,
35942
+ model
35943
+ };
35944
+ }
35945
+ return {
35946
+ status: "measured",
35947
+ cents: priceHaikuTokens(snapshot),
35948
+ recorded: snapshot.recorded,
35949
+ inputTokens: snapshot.inputTokens,
35950
+ outputTokens: snapshot.outputTokens,
35951
+ cacheReadInputTokens: snapshot.cacheReadInputTokens,
35952
+ cacheCreationInputTokens: snapshot.cacheCreationInputTokens,
35953
+ model
35954
+ };
35955
+ }
35956
+ function emptyPerType() {
35957
+ return { query: 0, embedding: 0, ingestion: 0 };
35958
+ }
35959
+ function composeDeeplakeContribution(infra) {
35960
+ const perTypeCents = emptyPerType();
35961
+ for (const line of infra.sessionTypes) {
35962
+ perTypeCents[line.session_type] += line.cost_cents;
35963
+ }
35964
+ return {
35965
+ status: infra.status,
35966
+ cents: sessionTypeTotalCents(infra.sessionTypes),
35967
+ bySessionType: infra.sessionTypes,
35968
+ perTypeCents
35969
+ };
35970
+ }
35971
+ var STATUS_SEVERITY = Object.freeze({
35972
+ unauthenticated: 0,
35973
+ // worst — no credentials, no figure.
35974
+ unreachable: 1,
35975
+ // billing could not be read.
35976
+ absent: 2,
35977
+ // Haiku has no data yet.
35978
+ partial: 3,
35979
+ // billing partially read.
35980
+ measured: 4,
35981
+ // Haiku ok (a real token figure).
35982
+ ok: 5
35983
+ // best — billing fully read.
35984
+ });
35985
+ function worstPollinationStatus(haiku, deeplake) {
35986
+ if (haiku === "measured" && deeplake === "ok")
35987
+ return "ok";
35988
+ const haikuStatus = haiku;
35989
+ const deeplakeStatus = deeplake;
35990
+ return STATUS_SEVERITY[haikuStatus] <= STATUS_SEVERITY[deeplakeStatus] ? haikuStatus : deeplakeStatus;
35991
+ }
35992
+ function composePollinationCost(usage, infra) {
35993
+ const haiku = composeHaikuContribution(usage.snapshot());
35994
+ const deeplake = composeDeeplakeContribution(infra);
35995
+ return {
35996
+ pollinationCents: haiku.cents + deeplake.cents,
35997
+ status: worstPollinationStatus(haiku.status, deeplake.status),
35998
+ haiku,
35999
+ deeplake
36000
+ };
36001
+ }
36002
+
36003
+ // dist/src/daemon/runtime/dashboard/roi-skillify-meter.js
36004
+ function emptySnapshot() {
36005
+ return {
36006
+ recorded: 0,
36007
+ inputTokens: 0,
36008
+ outputTokens: 0,
36009
+ cacheReadInputTokens: 0,
36010
+ cacheCreationInputTokens: 0
36011
+ };
36012
+ }
36013
+ function snapshotSource(snapshot) {
36014
+ return { snapshot: () => snapshot };
36015
+ }
36016
+ var emptyUsageSource = snapshotSource(emptySnapshot());
36017
+
36018
+ // dist/src/daemon/runtime/recall/scope-clause.js
36019
+ var PROJECT_ID_COLUMN = "project_id";
36020
+ var PROJECT_ID_UNSET = "";
36021
+ var CROSS_PROJECT_ADMITTED = Object.freeze(["user", "workspace"]);
36022
+ var SCOPE_READ_POLICIES = Object.freeze(["isolated", "shared", "group"]);
36023
+ function asReadPolicy(raw2) {
36024
+ return SCOPE_READ_POLICIES.includes(raw2) ? raw2 : null;
36025
+ }
36026
+ function buildProjectScopeClause(input) {
36027
+ const projectColumn = input.projectColumn ?? PROJECT_ID_COLUMN;
36028
+ const rawId = input.projectId ?? "";
36029
+ const isInbox = rawId.trim() === "" || rawId === UNSORTED_PROJECT_ID;
36030
+ const bound = input.bound ?? !isInbox;
36031
+ const col = sqlIdent(projectColumn);
36032
+ const primaryId = bound ? rawId : UNSORTED_PROJECT_ID;
36033
+ const admitted = primaryId === PROJECT_ID_UNSET ? [PROJECT_ID_UNSET] : [primaryId, PROJECT_ID_UNSET];
36034
+ const disjuncts = admitted.map((id) => `${col} = ${sLiteral(id)}`);
36035
+ const values = [...admitted];
36036
+ if (input.promotionColumn !== void 0 && input.promotionColumn !== "") {
36037
+ const promoCol = sqlIdent(input.promotionColumn);
36038
+ for (const reach of CROSS_PROJECT_ADMITTED) {
36039
+ disjuncts.push(`${promoCol} = ${sLiteral(reach)}`);
36040
+ values.push(reach);
36041
+ }
36042
+ }
36043
+ const sql = `(${disjuncts.join(" OR ")})`;
36044
+ return { sql, values, bound };
36045
+ }
36046
+ function buildProjectScopeConjunct(input) {
36047
+ return ` AND ${buildProjectScopeClause(input).sql}`;
36048
+ }
36049
+
36050
+ // dist/src/daemon/runtime/dashboard/roi-ledger.js
36051
+ var BACKEND_TOKEN_SOURCE = "backend-token";
36052
+ function resolveGatedUserId(verifiedClaim) {
36053
+ if (verifiedClaim !== void 0 && verifiedClaim.source === BACKEND_TOKEN_SOURCE) {
36054
+ return verifiedClaim.userId;
36055
+ }
36056
+ return "";
36057
+ }
36058
+ async function resolveTeamId(client, scope, agentId) {
36059
+ const tbl = sqlIdent("teams");
36060
+ const memberType = sqlIdent("member_type");
36061
+ const memberId = sqlIdent("member_id");
36062
+ const activeCol = sqlIdent("active");
36063
+ const versionCol = sqlIdent("version");
36064
+ const sql = `SELECT team_id FROM "${tbl}" AS t WHERE ${memberType} = ${sLiteral("agent")} AND ${memberId} = ${sLiteral(agentId)} AND ${activeCol} = ${TEAM_ACTIVE} AND ${versionCol} = (SELECT MAX(${versionCol}) FROM "${tbl}" AS u WHERE u.${memberType} = ${sLiteral("agent")} AND u.${memberId} = ${sLiteral(agentId)}) LIMIT 1`;
36065
+ let res;
36066
+ try {
36067
+ res = await client.query(sql, scope);
36068
+ } catch {
36069
+ return "";
36070
+ }
36071
+ if (!isOk(res) || res.rows.length === 0)
36072
+ return "";
36073
+ const raw2 = res.rows[0].team_id;
36074
+ return typeof raw2 === "string" ? raw2 : "";
36075
+ }
36076
+ function toInt(n) {
36077
+ if (n === void 0 || !Number.isFinite(n))
36078
+ return 0;
36079
+ return Math.trunc(n);
36080
+ }
36081
+ function asCostBasis(raw2) {
36082
+ return raw2 !== void 0 && ROI_COST_BASES.includes(raw2) ? raw2 : "none";
36083
+ }
36084
+ async function appendRoiMetric(client, scope, input) {
36085
+ const agentId = input.agentId.trim() === "" ? "default" : input.agentId;
36086
+ const teamId = await resolveTeamId(client, scope, agentId);
36087
+ const userId = resolveGatedUserId(input.verifiedClaim);
36088
+ const costBasis = asCostBasis(input.costBasis);
36089
+ const row = [
36090
+ ["id", val.str(input.id)],
36091
+ ["session_id", val.str(input.sessionId)],
36092
+ ["org_id", val.str(scope.org)],
36093
+ ["workspace_id", val.str(scope.workspace ?? "")],
36094
+ ["agent_id", val.str(agentId)],
36095
+ ["project_id", val.str(input.projectId ?? "")],
36096
+ ["team_id", val.str(teamId)],
36097
+ ["user_id", val.str(userId)],
36098
+ ["input_tokens", val.num(toInt(input.inputTokens))],
36099
+ ["output_tokens", val.num(toInt(input.outputTokens))],
36100
+ ["cache_read_tokens", val.num(toInt(input.cacheReadTokens))],
36101
+ ["cache_creation_tokens", val.num(toInt(input.cacheCreationTokens))],
36102
+ ["measured_cache_savings_cents", val.num(toInt(input.measuredCacheSavingsCents))],
36103
+ ["modeled_savings_cents", val.num(toInt(input.modeledSavingsCents))],
36104
+ ["modeled_assumption_ref", val.str(input.modeledAssumptionRef ?? "")],
36105
+ ["gross_cost_cents", val.num(toInt(input.grossCostCents))],
36106
+ ["infra_cost_cents", val.num(toInt(input.infraCostCents))],
36107
+ ["cost_basis", val.str(costBasis)],
36108
+ ["allocation_method", val.str(input.allocationMethod ?? "")],
36109
+ ["price_ref", val.str(input.priceRef ?? "")],
36110
+ ["period_start", val.str(input.periodStart ?? "")],
36111
+ ["period_end", val.str(input.periodEnd ?? "")],
36112
+ ["created_at", val.str(input.createdAt)]
36113
+ ];
36114
+ const result = await appendOnlyInsert(client, healTargetFor("roi_metrics"), scope, row);
36115
+ return { result, teamId, userId };
36116
+ }
36117
+ function buildRoiReadScopeSql(input, tableAlias) {
36118
+ const agentCol = tableAlias !== void 0 ? `${sqlIdent(tableAlias)}.${sqlIdent("agent_id")}` : sqlIdent("agent_id");
36119
+ const ownSql = `${agentCol} = ${sLiteral(input.agentId)}`;
36120
+ const noRows = `(${sLiteral("1")} = ${sLiteral("0")})`;
36121
+ const policy = asReadPolicy(input.readPolicy);
36122
+ if (input.agentId.trim() === "" || policy === null || policy === "isolated") {
36123
+ const ownClause = input.agentId.trim() === "" ? noRows : ownSql;
36124
+ return { sql: `(${ownClause})`, policyApplied: "isolated" };
36125
+ }
36126
+ if (policy === "shared") {
36127
+ return { sql: `(${sLiteral("1")} = ${sLiteral("1")})`, policyApplied: "shared" };
36128
+ }
36129
+ return { sql: `(${ownSql})`, policyApplied: "group" };
36130
+ }
36131
+ async function readRoiMetrics(client, scope, input) {
36132
+ const tbl = sqlIdent("roi_metrics");
36133
+ const { sql: scopeSql } = buildRoiReadScopeSql(input, "m");
36134
+ const projectClause = input.projectId !== void 0 && input.projectId.trim() !== "" ? ` AND ${sqlIdent("m")}.${sqlIdent("project_id")} = ${sLiteral(input.projectId.trim())}` : "";
36135
+ const sql = `SELECT m.* FROM "${tbl}" AS m WHERE ${scopeSql}${projectClause} AND NOT EXISTS (SELECT 1 FROM "${tbl}" AS n WHERE n.session_id = m.session_id AND (n.created_at > m.created_at OR (n.created_at = m.created_at AND n.id > m.id)))`;
36136
+ let res;
36137
+ try {
36138
+ res = await client.query(sql, scope);
36139
+ } catch (err) {
36140
+ return { status: "shared-ledger-absent", reason: err instanceof Error ? err.message : "query threw" };
36141
+ }
36142
+ if (!isOk(res)) {
36143
+ return { status: "shared-ledger-absent", reason: res.kind === "query_error" ? res.message : res.kind };
36144
+ }
36145
+ return { status: "ok", rows: res.rows };
36146
+ }
36147
+
35420
36148
  // dist/src/daemon/runtime/dashboard/api.js
35421
36149
  var DASHBOARD_GROUPS = Object.freeze({
35422
36150
  /**
@@ -35461,7 +36189,14 @@ var DASHBOARD_GROUPS = Object.freeze({
35461
36189
  * READ-ONLY filesystem walk; tenancy-independent (no org header required). PRD-036b calls
35462
36190
  * the underlying `scanInstalledAssets` IN-PROCESS, not over this HTTP surface.
35463
36191
  */
35464
- installedAssets: "/api/diagnostics"
36192
+ installedAssets: "/api/diagnostics",
36193
+ /**
36194
+ * ROI composite read-model (PRD-060e) — served off the diagnostics group at `/roi` + `/roi/trend`
36195
+ * (full paths `/api/diagnostics/roi` + `/api/diagnostics/roi/trend`). Local-mode-only loopback like
36196
+ * every other dashboard view-model; attached under the already-mounted, protected diagnostics group
36197
+ * (no new group, no `server.ts` edit). The page is a PURE function of the `RoiView` this returns.
36198
+ */
36199
+ roi: "/api/diagnostics"
35465
36200
  });
35466
36201
  function toNum2(value) {
35467
36202
  const n = typeof value === "number" ? value : Number(value ?? 0);
@@ -35475,30 +36210,35 @@ async function selectRows2(storage, sql, scope) {
35475
36210
  return isOk(result) ? result.rows : [];
35476
36211
  }
35477
36212
  var CHARS_PER_TOKEN2 = 4;
35478
- async function fetchKpisView(storage, scope) {
36213
+ async function fetchKpiCounts(storage, scope, projectId) {
35479
36214
  const memTbl = sqlIdent("memories");
35480
36215
  const sessTbl = sqlIdent("sessions");
35481
- const [memRows, sessRows, savingsRows, teamSkillRows] = await Promise.all([
35482
- selectRows2(storage, `SELECT COUNT(*) AS n FROM "${memTbl}"`, scope),
35483
- selectRows2(storage, `SELECT COUNT(*) AS n FROM "${sessTbl}"`, scope),
35484
- selectRows2(storage, buildEstimatedSavingsSql(), scope),
36216
+ const projClause = projectWhereClause(projectId);
36217
+ const [memRows, sessRows, teamSkillRows] = await Promise.all([
36218
+ selectRows2(storage, `SELECT COUNT(*) AS n FROM "${memTbl}"${projClause}`, scope),
36219
+ selectRows2(storage, `SELECT COUNT(*) AS n FROM "${sessTbl}"${projClause}`, scope),
35485
36220
  selectRows2(storage, buildTeamSkillCountSql(), scope)
35486
36221
  ]);
35487
36222
  const sessionCount = toNum2(sessRows[0]?.n);
35488
- const estimatedSavings = Math.floor(toNum2(savingsRows[0]?.chars) / CHARS_PER_TOKEN2);
35489
36223
  return {
35490
36224
  memoryCount: toNum2(memRows[0]?.n),
35491
36225
  // 035a: same value, two names — `sessionCount` kept (additive), `turnCount` is what the UI reads.
35492
36226
  sessionCount,
35493
36227
  turnCount: sessionCount,
35494
- estimatedSavings,
35495
36228
  teamSkillCount: toNum2(teamSkillRows[0]?.n)
35496
36229
  };
35497
36230
  }
35498
- function buildEstimatedSavingsSql() {
36231
+ async function fetchEstimatedSavings(storage, scope, projectId) {
36232
+ const savingsRows = await selectRows2(storage, buildEstimatedSavingsSql(projectId), scope);
36233
+ return Math.floor(toNum2(savingsRows[0]?.chars) / CHARS_PER_TOKEN2);
36234
+ }
36235
+ function buildEstimatedSavingsSql(projectId) {
35499
36236
  const tbl = sqlIdent("memories");
35500
36237
  const col = sqlIdent("content");
35501
- return `SELECT SUM(LENGTH(${col})) AS chars FROM "${tbl}"`;
36238
+ return `SELECT SUM(LENGTH(${col})) AS chars FROM "${tbl}"${projectWhereClause(projectId)}`;
36239
+ }
36240
+ function projectWhereClause(projectId) {
36241
+ return projectId !== void 0 && projectId !== "" ? ` WHERE ${sqlIdent("project_id")} = ${sLiteral(projectId)}` : "";
35502
36242
  }
35503
36243
  function buildTeamSkillCountSql() {
35504
36244
  const tbl = sqlIdent(SYNCED_ASSETS_TABLE);
@@ -35645,28 +36385,210 @@ async function fetchSkillSyncView(storage, scope, scan = scanInstalledAssets) {
35645
36385
  }
35646
36386
  return { skills: [...merged.values()] };
35647
36387
  }
36388
+ var DEFAULT_ROI_READ_POLICY = "shared";
36389
+ function roiSectionStatusFor(status) {
36390
+ if (status === "measured")
36391
+ return "ok";
36392
+ return status;
36393
+ }
36394
+ function tokenCountOrNull(value) {
36395
+ if (value === null || value === void 0)
36396
+ return null;
36397
+ const n = typeof value === "number" ? value : Number(value);
36398
+ return Number.isFinite(n) ? Math.trunc(n) : null;
36399
+ }
36400
+ function rowToCapturedTurn(r) {
36401
+ const sourceTool = toStr2(r.source_tool);
36402
+ return {
36403
+ input_tokens: tokenCountOrNull(r.input_tokens),
36404
+ output_tokens: tokenCountOrNull(r.output_tokens),
36405
+ cache_read_input_tokens: tokenCountOrNull(r.cache_read_input_tokens),
36406
+ cache_creation_input_tokens: tokenCountOrNull(r.cache_creation_input_tokens),
36407
+ ...sourceTool !== "" ? { sourceTool } : {}
36408
+ };
36409
+ }
36410
+ var ROI_SESSIONS_LIMIT = 5e3;
36411
+ async function readCapturedTurns(storage, scope, projectId) {
36412
+ const tbl = sqlIdent("sessions");
36413
+ const dateCol = sqlIdent("creation_date");
36414
+ const idCol = sqlIdent("id");
36415
+ const projClause = projectWhereClause(projectId);
36416
+ const sql = `SELECT ${sqlIdent("input_tokens")}, ${sqlIdent("output_tokens")}, ${sqlIdent("cache_read_input_tokens")}, ${sqlIdent("cache_creation_input_tokens")}, ${sqlIdent("source_tool")} FROM "${tbl}"${projClause} ORDER BY ${dateCol} DESC, ${idCol} DESC LIMIT ${ROI_SESSIONS_LIMIT}`;
36417
+ const rows = await selectRows2(storage, sql, scope);
36418
+ return rows.map(rowToCapturedTurn);
36419
+ }
36420
+ var ROLLUP_DIMENSIONS = Object.freeze([
36421
+ { dimension: "org", column: "org_id" },
36422
+ { dimension: "team", column: "team_id" },
36423
+ { dimension: "agent", column: "agent_id" },
36424
+ { dimension: "project", column: "project_id" }
36425
+ ]);
36426
+ function asCostBasisTag(raw2) {
36427
+ const s = toStr2(raw2);
36428
+ return s === "measured" || s === "allocated" || s === "none" ? s : "none";
36429
+ }
36430
+ function computeRollups(rows) {
36431
+ return ROLLUP_DIMENSIONS.map(({ dimension, column }) => {
36432
+ const groups = /* @__PURE__ */ new Map();
36433
+ const allBases = /* @__PURE__ */ new Set();
36434
+ for (const r of rows) {
36435
+ const key = toStr2(r[column]);
36436
+ const measured2 = toNum2(r.measured_cache_savings_cents);
36437
+ const modeled2 = toNum2(r.modeled_savings_cents);
36438
+ const infra = toNum2(r.infra_cost_cents);
36439
+ const gross = toNum2(r.gross_cost_cents);
36440
+ const basis = asCostBasisTag(r.cost_basis);
36441
+ allBases.add(basis);
36442
+ const g = groups.get(key) ?? { measured: 0, net: 0, infra: 0, sessions: 0, bases: /* @__PURE__ */ new Set() };
36443
+ g.measured += measured2;
36444
+ g.net += measured2 + modeled2 - (infra + gross);
36445
+ g.infra += infra;
36446
+ g.sessions += 1;
36447
+ g.bases.add(basis);
36448
+ groups.set(key, g);
36449
+ }
36450
+ const rollupRows = [...groups.entries()].map(([key, g]) => ({
36451
+ key,
36452
+ label: key,
36453
+ measuredSavingsCents: g.measured,
36454
+ netCents: g.net,
36455
+ infraCostCents: g.infra,
36456
+ // A row whose own group mixes bases is flagged `allocated` (the more-cautious tag); a single
36457
+ // basis carries through verbatim, so a measured-only row stays `measured`.
36458
+ costBasis: g.bases.size > 1 ? "allocated" : [...g.bases][0] ?? "none",
36459
+ sessions: g.sessions
36460
+ }));
36461
+ return { dimension, rows: rollupRows, mixedBasis: allBases.size > 1 };
36462
+ });
36463
+ }
36464
+ async function fetchRoiView(storage, scope, options = {}) {
36465
+ const agentId = options.agentId !== void 0 && options.agentId.trim() !== "" ? options.agentId.trim() : "";
36466
+ const readPolicy = options.readPolicy ?? DEFAULT_ROI_READ_POLICY;
36467
+ const infraModel = options.infra ?? createInfraCostReadModel();
36468
+ const usage = options.usage ?? emptyUsageSource;
36469
+ const projectId = options.projectId !== void 0 && options.projectId.trim() !== "" ? options.projectId.trim() : void 0;
36470
+ try {
36471
+ const [turns, infra, ledger] = await Promise.all([
36472
+ readCapturedTurns(storage, scope, projectId),
36473
+ infraModel.read(),
36474
+ readRoiMetrics(storage, scope, { agentId, readPolicy, ...projectId !== void 0 ? { projectId } : {} })
36475
+ ]);
36476
+ return assembleRoiView({ turns, infra, usage, ledger, readPolicy });
36477
+ } catch {
36478
+ return EMPTY_ROI_VIEW;
36479
+ }
36480
+ }
36481
+ function assembleRoiView(input) {
36482
+ const { turns, infra, usage, ledger, readPolicy } = input;
36483
+ const measured2 = measuredCacheSavings(turns);
36484
+ const modeled2 = modeledMemoryInjectionSavings(turns.length);
36485
+ const blended = blendedCentsPerMtok(turns);
36486
+ const captureStatus = measured2.value.status;
36487
+ const savingsStatus = captureStatus === "measured" ? "ok" : captureStatus;
36488
+ const savings = {
36489
+ status: savingsStatus,
36490
+ measuredCents: measured2.value.savingsCents,
36491
+ modeledCents: modeled2.value.estimatedCents,
36492
+ assumption: {
36493
+ kind: modeled2.assumption.kind,
36494
+ assumptionText: modeled2.assumption.assumptionText,
36495
+ signedOff: modeled2.assumption.signedOff
36496
+ },
36497
+ blendedCentsPerMtok: blended
36498
+ };
36499
+ const infraStatus = roiSectionStatusFor(infra.status);
36500
+ const infraCents = infra.summary !== void 0 ? infra.summary.total_cost_cents : 0;
36501
+ const infraSection = {
36502
+ status: infraStatus,
36503
+ cents: infraCents,
36504
+ // Org/workspace infra read from billing is a MEASURED fact when present; otherwise no line.
36505
+ costBasis: infra.status === "ok" || infra.status === "partial" ? "measured" : "none"
36506
+ };
36507
+ const pollination = composePollinationCost(usage, infra);
36508
+ const pollinationLines = [
36509
+ { label: "haiku-skillify", cents: pollination.haiku.cents },
36510
+ ...pollination.deeplake.bySessionType.map((s) => ({ label: `deeplake-${s.session_type}`, cents: s.cost_cents }))
36511
+ ];
36512
+ const pollinationSection = {
36513
+ status: roiSectionStatusFor(pollination.status),
36514
+ cents: pollination.pollinationCents,
36515
+ lines: pollinationLines
36516
+ };
36517
+ const savingsPresent = savingsStatus === "ok";
36518
+ const infraConfident = infraStatus === "ok";
36519
+ const pollinationConfident = pollinationSection.status === "ok";
36520
+ const netComputable = savingsPresent && infraConfident && pollinationConfident;
36521
+ let netSection;
36522
+ if (netComputable) {
36523
+ const netCents = measured2.value.savingsCents + modeled2.value.estimatedCents - (infraCents + pollination.pollinationCents);
36524
+ netSection = {
36525
+ status: "ok",
36526
+ computed: true,
36527
+ netCents,
36528
+ modeled: true,
36529
+ // the net folds a modeled term → ALWAYS `est.` (e-AC-3 net-hero inheritance).
36530
+ costBasis: infraSection.costBasis
36531
+ };
36532
+ } else {
36533
+ const reason = !savingsPresent ? savingsStatus : !infraConfident ? infraStatus : pollinationSection.status;
36534
+ netSection = { status: reason, computed: false, netCents: 0, modeled: true, costBasis: "none" };
36535
+ }
36536
+ const ledgerRows = ledger.status === "ok" ? ledger.rows : [];
36537
+ const rollups = computeRollups(ledgerRows);
36538
+ return {
36539
+ savings,
36540
+ infra: infraSection,
36541
+ pollination: pollinationSection,
36542
+ net: netSection,
36543
+ rollups,
36544
+ // PER-USER GATE (e-AC-14): there is no verified backend user-claim today, so per-user is NEVER
36545
+ // available — the page shows the "per-user requires verified login" empty state, never a $0/name.
36546
+ perUserAvailable: false,
36547
+ // ACROSS-DEVICE (e-AC-12): a `shared` read returned workspace-wide rows (across devices); an
36548
+ // `isolated` read returned only this machine's. The page captions the scope from this.
36549
+ scopedAcrossDevices: readPolicy === "shared",
36550
+ ratesAsOf: RATES_AS_OF
36551
+ };
36552
+ }
36553
+ async function fetchRoiTrendView(storage, scope, _range, _options = {}) {
36554
+ void storage;
36555
+ void scope;
36556
+ return EMPTY_ROI_TREND;
36557
+ }
35648
36558
  var NO_ORG_BODY4 = { error: "bad_request", reason: "x-honeycomb-org header is required" };
35649
36559
  function mountDashboardApi(daemon, options) {
35650
36560
  const storage = options.storage;
35651
36561
  const resolveScope5 = (c) => resolveScopeOrLocalDefault(c, daemon.config.mode, options.defaultScope);
35652
36562
  const kpis = daemon.group(DASHBOARD_GROUPS.kpis);
35653
36563
  if (kpis !== void 0) {
36564
+ const countsCache = createTtlViewCache(DIAG_TTL_MS);
36565
+ const savingsCache = createTtlViewCache(SAVINGS_TTL_MS);
35654
36566
  kpis.get("/kpis", async (c) => {
35655
36567
  const scope = resolveScope5(c);
35656
36568
  if (scope === null)
35657
36569
  return c.json(NO_ORG_BODY4, 400);
35658
- return c.json(await fetchKpisView(storage, scope));
36570
+ const project = resolveRequestProject(c, scope);
36571
+ const projectId = project.degraded ? void 0 : project.projectId;
36572
+ const key = scopeCacheKey(scope, projectId);
36573
+ const [counts, estimatedSavings] = await Promise.all([
36574
+ countsCache(key, () => fetchKpiCounts(storage, scope, projectId)),
36575
+ savingsCache(key, () => fetchEstimatedSavings(storage, scope, projectId))
36576
+ ]);
36577
+ return c.json({ ...counts, estimatedSavings });
35659
36578
  });
35660
36579
  }
35661
36580
  const sessions = daemon.group(DASHBOARD_GROUPS.sessions);
35662
36581
  if (sessions !== void 0) {
36582
+ const sessionsCache = createTtlViewCache(DIAG_TTL_MS);
35663
36583
  sessions.get("/sessions", async (c) => {
35664
36584
  const scope = resolveScope5(c);
35665
36585
  if (scope === null)
35666
36586
  return c.json(NO_ORG_BODY4, 400);
36587
+ const cursorRaw = c.req.query("cursor");
35667
36588
  const limit = resolveSessionsLimit(c.req.query("limit"));
35668
- const before = decodeSessionsCursor(c.req.query("cursor"));
35669
- return c.json(await fetchSessionsView(storage, scope, before !== void 0 ? { limit, before } : { limit }));
36589
+ const before = decodeSessionsCursor(cursorRaw);
36590
+ const key = scopeCacheKey(scope, String(limit), cursorRaw);
36591
+ return c.json(await sessionsCache(key, () => fetchSessionsView(storage, scope, before !== void 0 ? { limit, before } : { limit })));
35670
36592
  });
35671
36593
  }
35672
36594
  const settings = daemon.group(DASHBOARD_GROUPS.settings);
@@ -35689,20 +36611,22 @@ function mountDashboardApi(daemon, options) {
35689
36611
  }
35690
36612
  const rules = daemon.group(DASHBOARD_GROUPS.rules);
35691
36613
  if (rules !== void 0) {
36614
+ const rulesCache = createTtlViewCache(DIAG_TTL_MS);
35692
36615
  rules.get("/rules", async (c) => {
35693
36616
  const scope = resolveScope5(c);
35694
36617
  if (scope === null)
35695
36618
  return c.json(NO_ORG_BODY4, 400);
35696
- return c.json(await fetchRulesView(storage, scope));
36619
+ return c.json(await rulesCache(scopeCacheKey(scope), () => fetchRulesView(storage, scope)));
35697
36620
  });
35698
36621
  }
35699
36622
  const skills = daemon.group(DASHBOARD_GROUPS.skills);
35700
36623
  if (skills !== void 0) {
36624
+ const skillsCache = createTtlViewCache(DIAG_TTL_MS);
35701
36625
  skills.get("/skills", async (c) => {
35702
36626
  const scope = resolveScope5(c);
35703
36627
  if (scope === null)
35704
36628
  return c.json(NO_ORG_BODY4, 400);
35705
- return c.json(await fetchSkillSyncView(storage, scope));
36629
+ return c.json(await skillsCache(scopeCacheKey(scope), () => fetchSkillSyncView(storage, scope)));
35706
36630
  });
35707
36631
  }
35708
36632
  const installedAssets = daemon.group(DASHBOARD_GROUPS.installedAssets);
@@ -35712,6 +36636,34 @@ function mountDashboardApi(daemon, options) {
35712
36636
  return c.json(await inventoryCache());
35713
36637
  });
35714
36638
  }
36639
+ const roi = daemon.group(DASHBOARD_GROUPS.roi);
36640
+ if (roi !== void 0) {
36641
+ const roiOptions = (c, scope) => {
36642
+ const project = resolveRequestProject(c, scope);
36643
+ return {
36644
+ ...options.roiInfra !== void 0 ? { infra: options.roiInfra } : {},
36645
+ ...options.roiUsage !== void 0 ? { usage: options.roiUsage } : {},
36646
+ readPolicy: resolveRoiReadPolicy(c.req.query("policy")),
36647
+ ...!project.degraded ? { projectId: project.projectId } : {}
36648
+ };
36649
+ };
36650
+ roi.get("/roi", async (c) => {
36651
+ const scope = resolveScope5(c);
36652
+ if (scope === null)
36653
+ return c.json(NO_ORG_BODY4, 400);
36654
+ return c.json(await fetchRoiView(storage, scope, roiOptions(c, scope)));
36655
+ });
36656
+ roi.get("/roi/trend", async (c) => {
36657
+ const scope = resolveScope5(c);
36658
+ if (scope === null)
36659
+ return c.json(NO_ORG_BODY4, 400);
36660
+ const range = c.req.query("range") ?? "";
36661
+ return c.json(await fetchRoiTrendView(storage, scope, range, roiOptions(c, scope)));
36662
+ });
36663
+ }
36664
+ }
36665
+ function resolveRoiReadPolicy(raw2) {
36666
+ return raw2 === "isolated" || raw2 === "shared" || raw2 === "group" ? raw2 : DEFAULT_ROI_READ_POLICY;
35715
36667
  }
35716
36668
  var INSTALLED_ASSETS_TTL_MS = 5e3;
35717
36669
  function createInventoryCache() {
@@ -35725,72 +36677,601 @@ function createInventoryCache() {
35725
36677
  return value;
35726
36678
  };
35727
36679
  }
36680
+ var DIAG_TTL_MS = 1e4;
36681
+ var SAVINGS_TTL_MS = 6e4;
36682
+ var CACHE_MAX_KEYS = 64;
36683
+ function scopeCacheKey(scope, ...extra) {
36684
+ return [scope.org, scope.workspace ?? "", ...extra.map((e) => e ?? "")].join("\0");
36685
+ }
36686
+ function createTtlViewCache(ttlMs) {
36687
+ const cache = /* @__PURE__ */ new Map();
36688
+ return async (key, compute) => {
36689
+ const now = Date.now();
36690
+ const hit = cache.get(key);
36691
+ if (hit !== void 0 && now - hit.at < ttlMs)
36692
+ return hit.value;
36693
+ const value = await compute();
36694
+ if (cache.size >= CACHE_MAX_KEYS && !cache.has(key))
36695
+ cache.clear();
36696
+ cache.set(key, { value, at: now });
36697
+ return value;
36698
+ };
36699
+ }
35728
36700
 
35729
- // dist/src/hooks/shared/contracts.js
35730
- var LOGICAL_EVENTS = [
35731
- "session-start",
35732
- "user_message",
35733
- "pre-tool-use",
35734
- "tool_call",
35735
- "assistant_message",
35736
- "session-end"
35737
- ];
35738
- var HookSessionMetaSchema = external_exports.object({
35739
- sessionId: external_exports.string().trim().min(1),
35740
- path: external_exports.string().optional(),
35741
- cwd: external_exports.string().optional(),
35742
- permissionMode: external_exports.string().optional(),
35743
- hookEventName: external_exports.string().optional(),
35744
- agentId: external_exports.string().optional(),
35745
- agent: external_exports.string().optional()
35746
- });
35747
- var HookInputSchema = external_exports.object({
35748
- event: external_exports.enum(LOGICAL_EVENTS),
35749
- meta: HookSessionMetaSchema,
35750
- data: external_exports.unknown().optional(),
35751
- messageEmbedding: external_exports.array(external_exports.number()).optional(),
35752
- runtimePath: external_exports.enum(["plugin", "legacy"])
35753
- });
36701
+ // dist/src/daemon/runtime/dashboard/actions-api.js
36702
+ import { spawn as spawn4 } from "node:child_process";
36703
+ import { rmSync as rmSync5 } from "node:fs";
36704
+ import { dirname as dirname12, resolve as resolve5 } from "node:path";
35754
36705
 
35755
- // dist/src/daemon-client/vfs/classify.js
35756
- var GOAL_STATUS_TOKENS = ["opened", "in_progress", "closed"];
35757
- var GOAL_STATUS_SET = new Set(GOAL_STATUS_TOKENS);
35758
- function toMountRelative(path4) {
35759
- const trimmed = path4.replace(/^\/+/, "");
35760
- const marker = "/memory/";
35761
- const last = trimmed.lastIndexOf(marker);
35762
- if (last >= 0)
35763
- return trimmed.slice(last + marker.length);
35764
- if (trimmed.startsWith("memory/"))
35765
- return trimmed.slice("memory/".length);
35766
- return trimmed;
36706
+ // dist/src/daemon/runtime/secrets/api.js
36707
+ function localDefaultScopeResolver(mode, defaultScope) {
36708
+ return {
36709
+ resolve(c) {
36710
+ const fromHeader = headerScopeResolver.resolve(c);
36711
+ if (fromHeader !== null)
36712
+ return fromHeader;
36713
+ if (mode === "local" && defaultScope !== void 0) {
36714
+ return { org: defaultScope.org, workspace: defaultScope.workspace ?? "default" };
36715
+ }
36716
+ return null;
36717
+ }
36718
+ };
35767
36719
  }
35768
- function segmentsOf(rel) {
35769
- return rel.split("/").filter((s) => s !== "");
36720
+ var headerScopeResolver = {
36721
+ resolve(c) {
36722
+ const org = c.req.header("x-honeycomb-org");
36723
+ if (org === void 0 || org.length === 0)
36724
+ return null;
36725
+ const workspace = c.req.header("x-honeycomb-workspace");
36726
+ const agentId = c.req.header("x-honeycomb-agent");
36727
+ const ws = workspace !== void 0 && workspace.length > 0 ? workspace : "default";
36728
+ return agentId !== void 0 && agentId.length > 0 ? { org, workspace: ws, agentId } : { org, workspace: ws };
36729
+ }
36730
+ };
36731
+ function mountSecretsApi(group, deps) {
36732
+ const scope = deps.scope ?? headerScopeResolver;
36733
+ const store = deps.store;
36734
+ const runner = deps.execRunner;
36735
+ if (runner !== void 0) {
36736
+ group.post("/exec", async (c) => {
36737
+ const sc = scope.resolve(c);
36738
+ if (sc === null)
36739
+ return badTenancy(c);
36740
+ const request = await readExecRequest(c, sc);
36741
+ if (request === null) {
36742
+ return c.json({ error: "bad_request", reason: "exec body must carry a command" }, 400);
36743
+ }
36744
+ const res = runner.submit(request);
36745
+ if (!res.ok) {
36746
+ if (res.reason === "queue_full") {
36747
+ return c.json({ error: "queue_full", reason: "exec pool and queue are at capacity" }, 429);
36748
+ }
36749
+ return c.json({ error: "bad_request", reason: "invalid exec request" }, 400);
36750
+ }
36751
+ return c.json({ ok: true, jobId: res.jobId, status: "queued" }, 202);
36752
+ });
36753
+ group.get("/exec/:jobId", (c) => {
36754
+ const sc = scope.resolve(c);
36755
+ if (sc === null)
36756
+ return badTenancy(c);
36757
+ const jobId = c.req.param("jobId");
36758
+ const view = runner.getStatus(jobId, sc);
36759
+ if (view === null) {
36760
+ return c.json({ error: "not_found", reason: "no such exec job" }, 404);
36761
+ }
36762
+ return c.json(view);
36763
+ });
36764
+ group.all("/bitwarden/*", (c) => c.json({ error: "use_exec", reason: "reference a Bitwarden item via exec vaultRefs; values are never returned" }, 400));
36765
+ group.all("/1password/*", (c) => c.json({ error: "use_exec", reason: "reference a 1Password item via exec vaultRefs; values are never returned" }, 400));
36766
+ } else {
36767
+ group.post("/exec", (c) => notImplementedRoute(c, "POST /api/secrets/exec (secret_exec)"));
36768
+ group.get("/exec/:jobId", (c) => notImplementedRoute(c, "GET /api/secrets/exec/:jobId (exec status)"));
36769
+ group.all("/bitwarden/*", (c) => notImplementedRoute(c, "Bitwarden vault provider"));
36770
+ group.all("/1password/*", (c) => notImplementedRoute(c, "1Password vault provider"));
36771
+ }
36772
+ group.get("/", (c) => {
36773
+ const sc = scope.resolve(c);
36774
+ if (sc === null)
36775
+ return badTenancy(c);
36776
+ const names = store.listSecretNames(sc);
36777
+ return c.json({ names });
36778
+ });
36779
+ group.post("/:name", async (c) => {
36780
+ const sc = scope.resolve(c);
36781
+ if (sc === null)
36782
+ return badTenancy(c);
36783
+ const name = c.req.param("name");
36784
+ const value = await readValue(c);
36785
+ if (value === null) {
36786
+ return c.json({ error: "bad_request", reason: "request body must carry a string value" }, 400);
36787
+ }
36788
+ const res = await store.setSecret(name, value, sc);
36789
+ if (!res.ok) {
36790
+ if (res.reason === "invalid_name") {
36791
+ return c.json({ error: "bad_request", reason: "invalid secret name" }, 400);
36792
+ }
36793
+ return c.json({ error: "store_failed", reason: "could not store the secret" }, 502);
36794
+ }
36795
+ return c.json({ ok: true, name }, 201);
36796
+ });
36797
+ group.delete("/:name", (c) => {
36798
+ const sc = scope.resolve(c);
36799
+ if (sc === null)
36800
+ return badTenancy(c);
36801
+ const name = c.req.param("name");
36802
+ const res = store.deleteSecret(name, sc);
36803
+ if (!res.ok) {
36804
+ if (res.reason === "invalid_name") {
36805
+ return c.json({ error: "bad_request", reason: "invalid secret name" }, 400);
36806
+ }
36807
+ if (res.reason === "not_found") {
36808
+ return c.json({ error: "not_found", reason: "no such secret" }, 404);
36809
+ }
36810
+ return c.json({ error: "delete_failed", reason: "could not delete the secret" }, 502);
36811
+ }
36812
+ return c.json({ ok: true, name });
36813
+ });
35770
36814
  }
35771
- function isGoalShape(segs) {
35772
- if (segs.length !== 4)
36815
+ function badTenancy(c) {
36816
+ return c.json({ error: "bad_request", reason: "x-honeycomb-org header is required" }, 400);
36817
+ }
36818
+ async function readValue(c) {
36819
+ const contentType = c.req.header("content-type") ?? "";
36820
+ if (contentType.includes("application/json")) {
36821
+ try {
36822
+ const body = await c.req.json();
36823
+ if (typeof body === "object" && body !== null) {
36824
+ const v = body.value;
36825
+ if (typeof v === "string" && v.length > 0)
36826
+ return v;
36827
+ }
36828
+ return null;
36829
+ } catch {
36830
+ return null;
36831
+ }
36832
+ }
36833
+ const text = await c.req.text();
36834
+ return text.length > 0 ? text : null;
36835
+ }
36836
+ function notImplementedRoute(c, what) {
36837
+ return c.json({ error: "not_implemented", reason: `${what} is implemented in PRD-012b` }, 501);
36838
+ }
36839
+ async function readExecRequest(c, scope) {
36840
+ let body;
36841
+ try {
36842
+ body = await c.req.json();
36843
+ } catch {
36844
+ return null;
36845
+ }
36846
+ if (typeof body !== "object" || body === null)
36847
+ return null;
36848
+ const b = body;
36849
+ const command = b.command;
36850
+ if (typeof command !== "string" || command.length === 0)
36851
+ return null;
36852
+ const args = Array.isArray(b.args) ? b.args.filter((a) => typeof a === "string") : [];
36853
+ const secretNames = Array.isArray(b.secretNames) ? b.secretNames.filter((n) => typeof n === "string") : [];
36854
+ const vaultRefs = {};
36855
+ if (typeof b.vaultRefs === "object" && b.vaultRefs !== null) {
36856
+ for (const [k, v] of Object.entries(b.vaultRefs)) {
36857
+ if (typeof v === "string")
36858
+ vaultRefs[k] = v;
36859
+ }
36860
+ }
36861
+ const timeoutMs = typeof b.timeoutMs === "number" ? b.timeoutMs : void 0;
36862
+ return { command, args, secretNames, vaultRefs, scope, timeoutMs };
36863
+ }
36864
+
36865
+ // dist/src/daemon/runtime/vault/catalog.js
36866
+ var PROVIDER_CATALOG = Object.freeze([
36867
+ Object.freeze({
36868
+ id: "anthropic",
36869
+ label: "Anthropic",
36870
+ models: Object.freeze(["claude-sonnet-4-6", "claude-opus-4-8"]),
36871
+ openEnded: false
36872
+ }),
36873
+ Object.freeze({
36874
+ id: "openai",
36875
+ label: "OpenAI",
36876
+ models: Object.freeze(["gpt-4o", "gpt-4o-mini", "gpt-4.1"]),
36877
+ openEnded: false
36878
+ }),
36879
+ Object.freeze({
36880
+ id: "openrouter",
36881
+ label: "OpenRouter",
36882
+ // Suggestions only — OpenRouter accepts a free-form `vendor/model` id (passthrough).
36883
+ models: Object.freeze(["anthropic/claude-sonnet-4.6", "openai/gpt-4o"]),
36884
+ openEnded: true
36885
+ }),
36886
+ Object.freeze({
36887
+ // PRD-063a: Portkey is a GATEWAY, not a model vendor — its `portkey.config` id is
36888
+ // free-form (a config or virtual-key id copied from the Portkey dashboard), so it is
36889
+ // `openEnded: true` like OpenRouter and carries NO curated model list of its own.
36890
+ id: "portkey",
36891
+ label: "Portkey",
36892
+ models: Object.freeze([]),
36893
+ openEnded: true
36894
+ })
36895
+ ]);
36896
+ function providerEntry(provider) {
36897
+ return PROVIDER_CATALOG.find((p) => p.id === provider);
36898
+ }
36899
+ function isValidProviderModel(provider, model) {
36900
+ const entry = providerEntry(provider);
36901
+ if (entry === void 0)
35773
36902
  return false;
35774
- const [head, owner, status, file2] = segs;
35775
- if (head !== "goal")
36903
+ if (typeof model !== "string" || model.length === 0)
35776
36904
  return false;
35777
- if (owner === "")
36905
+ if (entry.openEnded)
36906
+ return true;
36907
+ return entry.models.includes(model);
36908
+ }
36909
+ function catalogView() {
36910
+ return PROVIDER_CATALOG;
36911
+ }
36912
+
36913
+ // dist/src/daemon/runtime/secrets/contracts.js
36914
+ import { homedir as homedir12, hostname as hostname3, userInfo } from "node:os";
36915
+ var SECRET_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
36916
+ var MAX_SECRET_NAME_LENGTH = 128;
36917
+ function isValidSecretName(value) {
36918
+ if (typeof value !== "string")
35778
36919
  return false;
35779
- if (!GOAL_STATUS_SET.has(status))
36920
+ if (value.length === 0 || value.length > MAX_SECRET_NAME_LENGTH)
35780
36921
  return false;
35781
- return isMdFileWithStem(file2);
36922
+ if (value === "." || value === "..")
36923
+ return false;
36924
+ if (value.includes("/") || value.includes("\\") || value.includes("\0"))
36925
+ return false;
36926
+ return SECRET_NAME_PATTERN.test(value);
35782
36927
  }
35783
- function isKpiShape(segs) {
35784
- if (segs.length !== 3)
36928
+ function asSecretName(value) {
36929
+ return isValidSecretName(value) ? value : null;
36930
+ }
36931
+ function isSecretRecord(value) {
36932
+ if (typeof value !== "object" || value === null)
35785
36933
  return false;
35786
- const [head, goalId, file2] = segs;
35787
- if (head !== "kpi")
36934
+ const r = value;
36935
+ if (typeof r.nonce !== "string" || typeof r.ciphertext !== "string" || typeof r.createdAt !== "string") {
35788
36936
  return false;
35789
- if (goalId === "")
36937
+ }
36938
+ const scope = r.scope;
36939
+ if (typeof scope !== "object" || scope === null)
35790
36940
  return false;
35791
- return isMdFileWithStem(file2);
36941
+ const s = scope;
36942
+ if (typeof s.org !== "string" || typeof s.workspace !== "string")
36943
+ return false;
36944
+ if (s.agentId !== void 0 && typeof s.agentId !== "string")
36945
+ return false;
36946
+ return true;
35792
36947
  }
35793
- function isMdFileWithStem(file2) {
36948
+ var MACHINE_KEY_DIR_NAME = ".honeycomb";
36949
+ var MACHINE_KEY_FILE_NAME = ".machine-key";
36950
+ function hostnameUserFallbackId() {
36951
+ let user = "";
36952
+ try {
36953
+ user = userInfo().username;
36954
+ } catch {
36955
+ user = "";
36956
+ }
36957
+ return `host:${hostname3()}|user:${user}|home:${homedir12()}`;
36958
+ }
36959
+
36960
+ // dist/src/daemon/runtime/vault/contracts.js
36961
+ function asRecordClass(value) {
36962
+ return isValidSecretName(value) ? value : null;
36963
+ }
36964
+
36965
+ // dist/src/daemon/runtime/vault/registry.js
36966
+ var SECRET_CLASS = "secret";
36967
+ var SETTING_CLASS = "setting";
36968
+ var SecretValueSchema = external_exports.string().min(1);
36969
+ var SettingValueSchema = external_exports.union([external_exports.string(), external_exports.number().finite(), external_exports.boolean()]);
36970
+ var SECRET_DESCRIPTOR = Object.freeze({
36971
+ id: SECRET_CLASS,
36972
+ posture: "internal-only",
36973
+ schema: SecretValueSchema
36974
+ });
36975
+ var SETTING_DESCRIPTOR = Object.freeze({
36976
+ id: SETTING_CLASS,
36977
+ posture: "daemon-readable",
36978
+ schema: SettingValueSchema
36979
+ });
36980
+ var VaultRegistry = class {
36981
+ table;
36982
+ constructor(descriptors) {
36983
+ this.table = /* @__PURE__ */ new Map();
36984
+ for (const d of descriptors)
36985
+ this.table.set(d.id, d);
36986
+ }
36987
+ /**
36988
+ * Register a new record class (D-7). Validates the id is traversal-proof (a class is an
36989
+ * on-disk segment) and that the posture is one the store understands, then adds the
36990
+ * descriptor. Re-registering an existing id REPLACES it (so a test can swap a throwaway
36991
+ * class); registering the built-in `secret`/`setting` ids is allowed but discouraged —
36992
+ * their posture must not be loosened. Returns the registry for chaining.
36993
+ *
36994
+ * Throws on an invalid (traversal-unsafe) class id — that is a programming error, not a
36995
+ * runtime input, so it fails loud rather than silently dropping the class.
36996
+ */
36997
+ registerClass(descriptor) {
36998
+ const safe = asRecordClass(descriptor.id);
36999
+ if (safe === null) {
37000
+ throw new Error(`vault.registerClass: invalid (traversal-unsafe) class id`);
37001
+ }
37002
+ this.table.set(descriptor.id, descriptor);
37003
+ return this;
37004
+ }
37005
+ /** Whether a class id is registered. */
37006
+ has(klass) {
37007
+ return this.table.has(klass);
37008
+ }
37009
+ /** The registered class ids (sorted), for diagnostics — never values. */
37010
+ classIds() {
37011
+ return [...this.table.keys()].sort();
37012
+ }
37013
+ /**
37014
+ * Resolve a class's descriptor for a WRITE, validating the value against the class
37015
+ * schema (zod-at-boundary). Returns `unknown_class` for an unregistered class or
37016
+ * `invalid_value` when the value fails the schema — both fail-closed (nothing is
37017
+ * written). On success the descriptor (with the validated value available via the
37018
+ * caller's re-parse) is returned.
37019
+ */
37020
+ resolveForWrite(klass, value) {
37021
+ const descriptor = this.table.get(klass);
37022
+ if (descriptor === void 0)
37023
+ return { ok: false, reason: "unknown_class" };
37024
+ const parsed = descriptor.schema.safeParse(value);
37025
+ if (!parsed.success)
37026
+ return { ok: false, reason: "invalid_value" };
37027
+ return { ok: true, descriptor };
37028
+ }
37029
+ /**
37030
+ * The POSTURE GATE (a-AC-2). Resolve a class's descriptor for a READ that intends to
37031
+ * RETURN the value to a surface (the `getSetting` path). REJECTS a class whose posture
37032
+ * is `internal-only` with `not_readable` — so a `secret` can NEVER be read back through
37033
+ * the daemon-readable accessor. An unknown class is `unknown_class`. This is the single
37034
+ * point where the secret-vs-setting security boundary is enforced, as data.
37035
+ */
37036
+ assertReadable(klass) {
37037
+ const descriptor = this.table.get(klass);
37038
+ if (descriptor === void 0)
37039
+ return { ok: false, reason: "unknown_class" };
37040
+ if (descriptor.posture !== "daemon-readable")
37041
+ return { ok: false, reason: "not_readable" };
37042
+ return { ok: true, descriptor };
37043
+ }
37044
+ /** Resolve a descriptor with no value/posture check (internal callers that already gate). */
37045
+ descriptorOf(klass) {
37046
+ return this.table.get(klass);
37047
+ }
37048
+ };
37049
+ function createVaultRegistry(extra = []) {
37050
+ return new VaultRegistry([SECRET_DESCRIPTOR, SETTING_DESCRIPTOR, ...extra]);
37051
+ }
37052
+
37053
+ // dist/src/daemon/runtime/vault/api.js
37054
+ var SETTINGS_GROUP = "/api/settings";
37055
+ var EMBEDDINGS_ENABLED_KEY = "embeddings.enabled";
37056
+ var KNOWN_SETTING_KEYS = [
37057
+ "activeProvider",
37058
+ "activeModel",
37059
+ "pollinating.enabled",
37060
+ EMBEDDINGS_ENABLED_KEY,
37061
+ "recallMode",
37062
+ "portkey.enabled",
37063
+ "portkey.config",
37064
+ "portkey.fallbackToProvider"
37065
+ ];
37066
+ var RECALL_MODES = ["keyword", "semantic", "hybrid"];
37067
+ function isValidRecallMode(value) {
37068
+ return RECALL_MODES.includes(value);
37069
+ }
37070
+ var DASHBOARD_PREF_PREFIX = "dashboard.";
37071
+ function isKnownSettingKey(key) {
37072
+ if (KNOWN_SETTING_KEYS.includes(key))
37073
+ return true;
37074
+ return key.startsWith(DASHBOARD_PREF_PREFIX) && key.length > DASHBOARD_PREF_PREFIX.length;
37075
+ }
37076
+ function mountSettingsGroup(group, deps) {
37077
+ const scope = deps.scope ?? headerScopeResolver;
37078
+ const store = deps.store;
37079
+ group.get("/", async (c) => {
37080
+ const sc = scope.resolve(c);
37081
+ if (sc === null)
37082
+ return badTenancy2(c);
37083
+ const keys = store.listSettingKeys(sc);
37084
+ const settings = {};
37085
+ for (const key of keys) {
37086
+ const res = await store.getSetting(key, sc);
37087
+ if (res.ok)
37088
+ settings[key] = res.value;
37089
+ }
37090
+ return c.json({ settings, catalog: catalogView() });
37091
+ });
37092
+ group.get("/:key", async (c) => {
37093
+ const sc = scope.resolve(c);
37094
+ if (sc === null)
37095
+ return badTenancy2(c);
37096
+ const key = c.req.param("key");
37097
+ if (!isKnownSettingKey(key)) {
37098
+ return c.json({ error: "not_found", reason: "no such setting" }, 404);
37099
+ }
37100
+ const res = await store.getSetting(key, sc);
37101
+ if (!res.ok) {
37102
+ if (res.reason === "not_found")
37103
+ return c.json({ error: "not_found", reason: "no such setting" }, 404);
37104
+ if (res.reason === "not_readable")
37105
+ return c.json({ error: "not_found", reason: "no such setting" }, 404);
37106
+ return c.json({ error: "read_failed", reason: "could not read the setting" }, 502);
37107
+ }
37108
+ return c.json({ key, value: res.value });
37109
+ });
37110
+ group.post("/:key", async (c) => {
37111
+ const sc = scope.resolve(c);
37112
+ if (sc === null)
37113
+ return badTenancy2(c);
37114
+ const key = c.req.param("key");
37115
+ if (!isKnownSettingKey(key)) {
37116
+ return c.json({ error: "bad_request", reason: "unknown setting key" }, 400);
37117
+ }
37118
+ const value = await readSettingValue(c);
37119
+ if (value === null) {
37120
+ return c.json({ error: "bad_request", reason: "request body must carry a scalar value" }, 400);
37121
+ }
37122
+ const semanticError = await validateSettingSemantics(store, sc, key, value);
37123
+ if (semanticError !== null) {
37124
+ return c.json({ error: "bad_request", reason: semanticError }, 400);
37125
+ }
37126
+ const res = await store.setSetting(key, value, sc);
37127
+ if (!res.ok) {
37128
+ if (res.reason === "invalid_value") {
37129
+ return c.json({ error: "bad_request", reason: "invalid setting value" }, 400);
37130
+ }
37131
+ if (res.reason === "not_readable" || res.reason === "unknown_class") {
37132
+ return c.json({ error: "bad_request", reason: "setting class is not writable" }, 400);
37133
+ }
37134
+ return c.json({ error: "store_failed", reason: "could not store the setting" }, 502);
37135
+ }
37136
+ return c.json({ ok: true, key, value }, 201);
37137
+ });
37138
+ }
37139
+ function mountSettingsApi(daemon, deps) {
37140
+ const group = daemon.group(SETTINGS_GROUP);
37141
+ if (group === void 0)
37142
+ return;
37143
+ mountSettingsGroup(group, deps);
37144
+ }
37145
+ function badTenancy2(c) {
37146
+ return c.json({ error: "bad_request", reason: "x-honeycomb-org header is required" }, 400);
37147
+ }
37148
+ async function readSettingValue(c) {
37149
+ const contentType = c.req.header("content-type") ?? "";
37150
+ if (contentType.includes("application/json")) {
37151
+ try {
37152
+ const body = await c.req.json();
37153
+ if (typeof body === "object" && body !== null) {
37154
+ const v = body.value;
37155
+ const parsed = SettingValueSchema.safeParse(v);
37156
+ return parsed.success ? parsed.data : null;
37157
+ }
37158
+ return null;
37159
+ } catch {
37160
+ return null;
37161
+ }
37162
+ }
37163
+ const text = await c.req.text();
37164
+ return text.length > 0 ? text : null;
37165
+ }
37166
+ async function validateSettingSemantics(store, scope, key, value) {
37167
+ if (key === "activeProvider") {
37168
+ if (providerEntry(String(value)) === void 0)
37169
+ return "unknown provider";
37170
+ return null;
37171
+ }
37172
+ if (key === "activeModel") {
37173
+ const provRes = await store.getSetting("activeProvider", scope);
37174
+ const provider = provRes.ok ? String(provRes.value) : "";
37175
+ if (provider.length === 0)
37176
+ return "set activeProvider before activeModel";
37177
+ if (!isValidProviderModel(provider, String(value)))
37178
+ return "model not in provider catalog";
37179
+ return null;
37180
+ }
37181
+ if (key === "recallMode") {
37182
+ if (!isValidRecallMode(String(value)))
37183
+ return "recallMode must be keyword, semantic, or hybrid";
37184
+ return null;
37185
+ }
37186
+ if (key === "portkey.enabled" || key === "portkey.fallbackToProvider") {
37187
+ if (typeof value !== "boolean")
37188
+ return `${key} must be a boolean`;
37189
+ return null;
37190
+ }
37191
+ if (key === "portkey.config") {
37192
+ if (typeof value !== "string")
37193
+ return "portkey.config must be a string";
37194
+ if (/[\u0000-\u001F\u007F]/.test(value))
37195
+ return "portkey.config must not contain control characters";
37196
+ const enabledRes = await store.getSetting("portkey.enabled", scope);
37197
+ const enabled = enabledRes.ok && enabledRes.value === true;
37198
+ if (enabled && value.length === 0)
37199
+ return "portkey.config must be non-empty when portkey.enabled is true";
37200
+ return null;
37201
+ }
37202
+ return null;
37203
+ }
37204
+
37205
+ // dist/src/daemon/runtime/dashboard/harness-detect.js
37206
+ import { existsSync as existsSync12 } from "node:fs";
37207
+ import { homedir as homedir16 } from "node:os";
37208
+ import { join as join20 } from "node:path";
37209
+
37210
+ // dist/src/hooks/shared/contracts.js
37211
+ var LOGICAL_EVENTS = [
37212
+ "session-start",
37213
+ "user_message",
37214
+ "pre-tool-use",
37215
+ "tool_call",
37216
+ "assistant_message",
37217
+ "session-end"
37218
+ ];
37219
+ var HookSessionMetaSchema = external_exports.object({
37220
+ sessionId: external_exports.string().trim().min(1),
37221
+ path: external_exports.string().optional(),
37222
+ cwd: external_exports.string().optional(),
37223
+ permissionMode: external_exports.string().optional(),
37224
+ hookEventName: external_exports.string().optional(),
37225
+ agentId: external_exports.string().optional(),
37226
+ agent: external_exports.string().optional()
37227
+ });
37228
+ var HookInputSchema = external_exports.object({
37229
+ event: external_exports.enum(LOGICAL_EVENTS),
37230
+ meta: HookSessionMetaSchema,
37231
+ data: external_exports.unknown().optional(),
37232
+ messageEmbedding: external_exports.array(external_exports.number()).optional(),
37233
+ runtimePath: external_exports.enum(["plugin", "legacy"])
37234
+ });
37235
+
37236
+ // dist/src/daemon-client/vfs/classify.js
37237
+ var GOAL_STATUS_TOKENS = ["opened", "in_progress", "closed"];
37238
+ var GOAL_STATUS_SET = new Set(GOAL_STATUS_TOKENS);
37239
+ function toMountRelative(path4) {
37240
+ const trimmed = path4.replace(/^\/+/, "");
37241
+ const marker = "/memory/";
37242
+ const last = trimmed.lastIndexOf(marker);
37243
+ if (last >= 0)
37244
+ return trimmed.slice(last + marker.length);
37245
+ if (trimmed.startsWith("memory/"))
37246
+ return trimmed.slice("memory/".length);
37247
+ return trimmed;
37248
+ }
37249
+ function segmentsOf(rel) {
37250
+ return rel.split("/").filter((s) => s !== "");
37251
+ }
37252
+ function isGoalShape(segs) {
37253
+ if (segs.length !== 4)
37254
+ return false;
37255
+ const [head, owner, status, file2] = segs;
37256
+ if (head !== "goal")
37257
+ return false;
37258
+ if (owner === "")
37259
+ return false;
37260
+ if (!GOAL_STATUS_SET.has(status))
37261
+ return false;
37262
+ return isMdFileWithStem(file2);
37263
+ }
37264
+ function isKpiShape(segs) {
37265
+ if (segs.length !== 3)
37266
+ return false;
37267
+ const [head, goalId, file2] = segs;
37268
+ if (head !== "kpi")
37269
+ return false;
37270
+ if (goalId === "")
37271
+ return false;
37272
+ return isMdFileWithStem(file2);
37273
+ }
37274
+ function isMdFileWithStem(file2) {
35794
37275
  return file2.endsWith(".md") && file2.length > ".md".length;
35795
37276
  }
35796
37277
  function classifyPath(path4) {
@@ -35829,7 +37310,7 @@ var HEALTH_DIMENSION_WIRABLE = Object.freeze({
35829
37310
 
35830
37311
  // dist/src/notifications/state.js
35831
37312
  import { closeSync as closeSync3, existsSync as existsSync10, mkdirSync as mkdirSync11, openSync as openSync3, readFileSync as readFileSync13, renameSync as renameSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
35832
- import { homedir as homedir12 } from "node:os";
37313
+ import { homedir as homedir13 } from "node:os";
35833
37314
  import { join as join17 } from "node:path";
35834
37315
 
35835
37316
  // dist/src/daemon/runtime/assets/contracts.js
@@ -35853,7 +37334,7 @@ var audienceMatches = (asset, ctx) => {
35853
37334
 
35854
37335
  // dist/src/daemon-client/assets/install.js
35855
37336
  import { existsSync as existsSync11, mkdirSync as mkdirSync12, readFileSync as readFileSync14, renameSync as renameSync7, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
35856
- import { homedir as homedir13 } from "node:os";
37337
+ import { homedir as homedir14 } from "node:os";
35857
37338
  import { dirname as dirname10, join as join18, resolve as resolve4 } from "node:path";
35858
37339
  var HARNESS_SKILL_DIRS = Object.freeze({
35859
37340
  claude_code: join18(".claude", "skills"),
@@ -35873,38 +37354,52 @@ var HARNESS_AGENT_DIRS = Object.freeze({
35873
37354
  });
35874
37355
 
35875
37356
  // dist/src/commands/contracts.js
37357
+ var VERB_GROUPS = Object.freeze([
37358
+ { key: "memory", label: "Memory & recall" },
37359
+ { key: "knowledge", label: "Knowledge & skills" },
37360
+ { key: "agents", label: "Agents, routing & config" },
37361
+ { key: "account", label: "Account & workspaces" },
37362
+ { key: "system", label: "Setup & system" }
37363
+ ]);
35876
37364
  var VERB_TABLE = Object.freeze([
35877
- { verb: "setup", cls: "local", summary: "detect assistants, wire hooks, bring up the daemon" },
35878
- { verb: "install", cls: "local", summary: "bring up the daemon (health-gated) + open the dashboard (PRD-050a)" },
35879
- { verb: "status", cls: "local", summary: "daemon connectivity + login + D1\u2013D5 environment health" },
35880
- { verb: "daemon", cls: "local", summary: "start | stop | status the loopback daemon (3850)" },
35881
- { verb: "dashboard", cls: "local", summary: "launch the daemon-served dashboard (020b)" },
35882
- { verb: "telemetry", cls: "local", summary: "show exactly what adoption telemetry has been / would be sent (--show, PRD-050e)" },
35883
- { verb: "pollinate", cls: "storage", summary: "trigger a pollinating consolidation pass on the daemon (009/026)" },
35884
- { verb: "maintenance", cls: "storage", summary: "run version-history compaction over version-bumped tables (030)" },
35885
- { verb: "remember", cls: "storage", summary: "write a memory through the daemon (--type fact|convention|preference|decision|gotcha|reference)" },
35886
- { verb: "recall", cls: "storage", summary: "recall memories through the daemon" },
35887
- { verb: "memory", cls: "storage", summary: "lifecycle: conflicts (list/resolve), stale-refs (list), inspect <id> --lifecycle (058d)" },
35888
- { verb: "agent", cls: "storage", summary: "run an agent turn through the daemon" },
35889
- { verb: "ontology", cls: "storage", summary: "inspect/propose ontology changes through the daemon" },
35890
- { verb: "secret", cls: "storage", summary: "manage named secrets through the daemon" },
35891
- { verb: "settings", cls: "storage", summary: "get/set/list vault settings + provider\u2192model selector through the daemon" },
35892
- { verb: "asset", cls: "storage", summary: "register/promote/demote/style skills+agents through the tier\xD7style lattice (033)" },
35893
- { verb: "skill", cls: "storage", summary: "skillify scope/pull/unpull/force/promote through the daemon (promote = cross-project, 049c)" },
35894
- { verb: "skillify", cls: "storage", summary: "pull team skills from the daemon (016c)" },
35895
- { verb: "hook", cls: "local", summary: "inspect/wire harness hooks" },
35896
- { verb: "route", cls: "storage", summary: "manage inference routes through the daemon" },
35897
- { verb: "sources", cls: "storage", summary: "connect/index/purge sources through the daemon" },
35898
- { verb: "graph", cls: "storage", summary: "build/query the codebase graph through the daemon" },
35899
- { verb: "goal", cls: "storage", summary: "manage goals/KPIs through the daemon" },
35900
- { verb: "whoami", cls: "auth", summary: "show the authenticated user, org, and workspace (GET /me)" },
35901
- { verb: "org", cls: "auth", summary: "list/switch org (passthrough to the auth dispatcher)" },
35902
- { verb: "workspace", cls: "auth", summary: "list/switch/use workspace (passthrough to the auth dispatcher)" },
35903
- { verb: "workspaces", cls: "auth", summary: "list workspaces in the active org (alias of `workspace list`)" },
35904
- { verb: "project", cls: "auth", summary: "list/bind/use projects + show the resolved per-folder scope (049d)" },
35905
- { verb: "sessions", cls: "storage", summary: "list/prune captured sessions through the daemon" },
35906
- { verb: "uninstall", cls: "local", summary: "reverse only Honeycomb's changes" },
35907
- { verb: "update", cls: "local", summary: "self-update the CLI, daemon, and bundles" }
37365
+ // Memory & recall the product's core write/read/lifecycle surface.
37366
+ { verb: "remember", cls: "storage", group: "memory", summary: "write a memory through the daemon (--type fact|convention|preference|decision|gotcha|reference)" },
37367
+ { verb: "recall", cls: "storage", group: "memory", summary: "recall memories through the daemon" },
37368
+ { verb: "memory", cls: "storage", group: "memory", summary: "lifecycle: conflicts (list/resolve), stale-refs (list), inspect <id> --lifecycle (058d)" },
37369
+ { verb: "sessions", cls: "storage", group: "memory", summary: "list/prune captured sessions through the daemon" },
37370
+ { verb: "pollinate", cls: "storage", group: "memory", summary: "trigger a pollinating consolidation pass on the daemon (009/026)" },
37371
+ { verb: "maintenance", cls: "storage", group: "memory", summary: "run version-history compaction over version-bumped tables (030)" },
37372
+ // Knowledge & skills — skills, assets, ontology, the codebase graph, and goals.
37373
+ { verb: "skill", cls: "storage", group: "knowledge", summary: "skillify scope/pull/unpull/force/promote through the daemon (promote = cross-project, 049c)" },
37374
+ { verb: "skillify", cls: "storage", group: "knowledge", summary: "pull team skills from the daemon (016c)" },
37375
+ { verb: "asset", cls: "storage", group: "knowledge", summary: "register/promote/demote/style skills+agents through the tier\xD7style lattice (033)" },
37376
+ { verb: "ontology", cls: "storage", group: "knowledge", summary: "inspect/propose ontology changes through the daemon" },
37377
+ { verb: "graph", cls: "storage", group: "knowledge", summary: "build/query the codebase graph through the daemon" },
37378
+ { verb: "sources", cls: "storage", group: "knowledge", summary: "connect/index/purge sources through the daemon" },
37379
+ { verb: "goal", cls: "storage", group: "knowledge", summary: "manage goals/KPIs through the daemon" },
37380
+ // Agents, routing & config agent turns, inference routes, secrets, and vault settings.
37381
+ { verb: "agent", cls: "storage", group: "agents", summary: "run an agent turn through the daemon" },
37382
+ { verb: "route", cls: "storage", group: "agents", summary: "manage inference routes through the daemon" },
37383
+ { verb: "secret", cls: "storage", group: "agents", summary: "manage named secrets through the daemon" },
37384
+ { verb: "settings", cls: "storage", group: "agents", summary: "get/set/list vault settings + provider\u2192model selector through the daemon" },
37385
+ // Account & workspaces — auth, identity, and the org/workspace/project scope surface.
37386
+ { verb: "login", cls: "auth", group: "account", summary: "authenticate via device flow, or --token <key> for headless (023)" },
37387
+ { verb: "logout", cls: "auth", group: "account", summary: "remove the shared credentials and sign out (023)" },
37388
+ { verb: "whoami", cls: "auth", group: "account", summary: "show the authenticated user, org, and workspace (GET /me)" },
37389
+ { verb: "org", cls: "auth", group: "account", summary: "list/switch org (passthrough to the auth dispatcher)" },
37390
+ { verb: "workspace", cls: "auth", group: "account", summary: "list/switch/use workspace (passthrough to the auth dispatcher)" },
37391
+ { verb: "workspaces", cls: "auth", group: "account", summary: "list workspaces in the active org (alias of `workspace list`)" },
37392
+ { verb: "project", cls: "auth", group: "account", summary: "list/bind/use projects + show the resolved per-folder scope (049d)" },
37393
+ // Setup & system install/onboard, daemon lifecycle, dashboard, hooks, telemetry, update.
37394
+ { verb: "setup", cls: "local", group: "system", summary: "detect assistants, wire hooks, bring up the daemon" },
37395
+ { verb: "install", cls: "local", group: "system", summary: "bring up the daemon (health-gated) + open the dashboard (PRD-050a)" },
37396
+ { verb: "status", cls: "local", group: "system", summary: "daemon connectivity + login + D1\u2013D5 environment health" },
37397
+ { verb: "daemon", cls: "local", group: "system", summary: "start | stop | status the loopback daemon (3850)" },
37398
+ { verb: "dashboard", cls: "local", group: "system", summary: "launch the daemon-served dashboard (020b)" },
37399
+ { verb: "hook", cls: "local", group: "system", summary: "inspect/wire harness hooks" },
37400
+ { verb: "telemetry", cls: "local", group: "system", summary: "show exactly what adoption telemetry has been / would be sent (--show, PRD-050e)" },
37401
+ { verb: "update", cls: "local", group: "system", summary: "self-update the CLI, daemon, and bundles" },
37402
+ { verb: "uninstall", cls: "local", group: "system", summary: "reverse only Honeycomb's changes" }
35908
37403
  ]);
35909
37404
  var DEFAULT_GLOBAL_FLAGS = Object.freeze({
35910
37405
  help: false,
@@ -35916,7 +37411,7 @@ var DEFAULT_GLOBAL_FLAGS = Object.freeze({
35916
37411
  // dist/src/daemon/runtime/assets/device.js
35917
37412
  import { randomUUID as randomUUID2 } from "node:crypto";
35918
37413
  import { mkdirSync as mkdirSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
35919
- import { homedir as homedir14, hostname as hostname3 } from "node:os";
37414
+ import { homedir as homedir15, hostname as hostname4 } from "node:os";
35920
37415
  import { dirname as dirname11, join as join19 } from "node:path";
35921
37416
 
35922
37417
  // dist/src/hooks/normalize.js
@@ -36007,8 +37502,61 @@ function nestedString(raw2, a, b) {
36007
37502
  function userMessageData(text) {
36008
37503
  return { kind: "user_message", text };
36009
37504
  }
36010
- function assistantMessageData(text) {
36011
- return { kind: "assistant_message", text };
37505
+ function assistantMessageData(text, usage) {
37506
+ const normalized = usage !== void 0 ? compactUsage(usage) : void 0;
37507
+ return {
37508
+ kind: "assistant_message",
37509
+ text,
37510
+ ...normalized !== void 0 ? { usage: normalized } : {}
37511
+ };
37512
+ }
37513
+ function compactUsage(usage) {
37514
+ const out = {};
37515
+ if (isCount(usage.input))
37516
+ out.input = usage.input;
37517
+ if (isCount(usage.output))
37518
+ out.output = usage.output;
37519
+ if (isCount(usage.cacheRead))
37520
+ out.cacheRead = usage.cacheRead;
37521
+ if (isCount(usage.cacheCreation))
37522
+ out.cacheCreation = usage.cacheCreation;
37523
+ return Object.keys(out).length > 0 ? out : void 0;
37524
+ }
37525
+ function isCount(n) {
37526
+ return typeof n === "number" && Number.isInteger(n) && n >= 0;
37527
+ }
37528
+ function extractTurnUsage(raw2) {
37529
+ const block = usageBlock(raw2);
37530
+ if (block === void 0)
37531
+ return void 0;
37532
+ const usage = {
37533
+ ...readCount(block, "input_tokens") !== void 0 ? { input: readCount(block, "input_tokens") } : {},
37534
+ ...readCount(block, "output_tokens") !== void 0 ? { output: readCount(block, "output_tokens") } : {},
37535
+ ...readCount(block, "cache_read_input_tokens") !== void 0 ? { cacheRead: readCount(block, "cache_read_input_tokens") } : {},
37536
+ ...readCount(block, "cache_creation_input_tokens") !== void 0 ? { cacheCreation: readCount(block, "cache_creation_input_tokens") } : {}
37537
+ };
37538
+ return compactUsage(usage);
37539
+ }
37540
+ function usageBlock(raw2) {
37541
+ const top = nested(raw2, "usage");
37542
+ if (top !== null && typeof top === "object")
37543
+ return top;
37544
+ const inner = nestedRecord(nested(raw2, "message"), "usage");
37545
+ return inner;
37546
+ }
37547
+ function nestedRecord(obj, key) {
37548
+ if (obj !== null && typeof obj === "object") {
37549
+ const value = obj[key];
37550
+ if (value !== null && typeof value === "object")
37551
+ return value;
37552
+ }
37553
+ return void 0;
37554
+ }
37555
+ function readCount(block, key) {
37556
+ const value = block[key];
37557
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
37558
+ return void 0;
37559
+ return value;
36012
37560
  }
36013
37561
  function toolCallData(tool, input, response) {
36014
37562
  return { kind: "tool_call", tool, input, response };
@@ -36058,7 +37606,7 @@ function claudeCodeExtractData(raw2, logical) {
36058
37606
  case "tool_call":
36059
37607
  return toolCallData(pickString(raw2, "tool_name", "tool"), nested(raw2, "tool_input"), nested(raw2, "tool_response"));
36060
37608
  case "assistant_message":
36061
- return assistantMessageData(pickString(raw2, "text", "message"));
37609
+ return assistantMessageData(pickString(raw2, "text", "message"), extractTurnUsage(raw2));
36062
37610
  case "session-end":
36063
37611
  return sessionEndData(pickString(raw2, "reason") || "Stop");
36064
37612
  default:
@@ -36388,6 +37936,200 @@ function capabilitiesFor(name) {
36388
37936
  return HARNESS_CAPABILITIES[name];
36389
37937
  }
36390
37938
 
37939
+ // dist/src/daemon/runtime/dashboard/harness-detect.js
37940
+ var HARNESS_MARKERS = [
37941
+ {
37942
+ name: "claude-code",
37943
+ // src/connectors/claude-code.ts: configPath() = ~/.claude/settings.json; pluginRoot = ~/.claude/plugins/honeycomb.
37944
+ paths: (h) => [join20(h, ".claude", "settings.json"), join20(h, ".claude", "plugins", "honeycomb")]
37945
+ },
37946
+ {
37947
+ name: "cursor",
37948
+ // src/connectors/cursor.ts: configPath() = ~/.cursor/hooks.json; pluginRoot = ~/.cursor/honeycomb.
37949
+ paths: (h) => [join20(h, ".cursor", "hooks.json"), join20(h, ".cursor", "honeycomb")]
37950
+ },
37951
+ {
37952
+ name: "codex",
37953
+ // hivemind-v1/src/cli/install-codex.ts: HOOKS_PATH = ~/.codex/hooks.json; PLUGIN_DIR = ~/.codex/hivemind.
37954
+ paths: (h) => [join20(h, ".codex", "hooks.json"), join20(h, ".codex", "hivemind")]
37955
+ },
37956
+ {
37957
+ name: "hermes",
37958
+ // hivemind-v1/src/cli/install-hermes.ts: CONFIG_PATH = ~/.hermes/config.yaml; HIVEMIND_DIR = ~/.hermes/hivemind.
37959
+ paths: (h) => [join20(h, ".hermes", "config.yaml"), join20(h, ".hermes", "hivemind")]
37960
+ },
37961
+ {
37962
+ name: "pi",
37963
+ // hivemind-v1/src/cli/install-pi.ts: AGENTS_MD = ~/.pi/agent/AGENTS.md; EXTENSION_PATH = ~/.pi/agent/extensions/hivemind.ts.
37964
+ paths: (h) => [
37965
+ join20(h, ".pi", "agent", "extensions", "hivemind.ts"),
37966
+ join20(h, ".pi", "agent", "AGENTS.md")
37967
+ ]
37968
+ },
37969
+ {
37970
+ name: "openclaw",
37971
+ // hivemind-v1/src/cli/install-openclaw.ts: PLUGIN_DIR = ~/.openclaw/extensions/hivemind.
37972
+ paths: (h) => [join20(h, ".openclaw", "extensions", "hivemind")]
37973
+ }
37974
+ ];
37975
+ function markerExists(path4) {
37976
+ try {
37977
+ return existsSync12(path4);
37978
+ } catch {
37979
+ return false;
37980
+ }
37981
+ }
37982
+ function detectInstalledHarnesses(homeDir = homedir16(), _cwd = process.cwd()) {
37983
+ const canonical = new Set(CANONICAL_HARNESS_IDS);
37984
+ const installed = /* @__PURE__ */ new Set();
37985
+ for (const marker of HARNESS_MARKERS) {
37986
+ if (!canonical.has(marker.name))
37987
+ continue;
37988
+ if (marker.paths(homeDir).some(markerExists))
37989
+ installed.add(marker.name);
37990
+ }
37991
+ return installed;
37992
+ }
37993
+
37994
+ // dist/src/daemon/runtime/dashboard/actions-api.js
37995
+ var ACTIONS_GROUP = "/api/actions";
37996
+ var RESTART_SHUTDOWN_DELAY_MS = 100;
37997
+ function isLoopbackOrigin(origin) {
37998
+ try {
37999
+ const host = new URL(origin).hostname;
38000
+ return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]";
38001
+ } catch {
38002
+ return false;
38003
+ }
38004
+ }
38005
+ function actionGuard(c, mode) {
38006
+ if (mode !== "local") {
38007
+ return c.json({ error: "forbidden", reason: "actions are available in local mode only" }, 403);
38008
+ }
38009
+ const site = c.req.header("sec-fetch-site");
38010
+ if (site === "cross-site" || site === "same-site") {
38011
+ return c.json({ error: "forbidden", reason: "cross-origin request rejected" }, 403);
38012
+ }
38013
+ const origin = c.req.header("origin");
38014
+ if (origin !== void 0 && origin !== "" && !isLoopbackOrigin(origin)) {
38015
+ return c.json({ error: "forbidden", reason: "untrusted origin" }, 403);
38016
+ }
38017
+ const session = c.req.header("x-honeycomb-session");
38018
+ if (session === void 0 || session.trim() === "") {
38019
+ return c.json({ error: "forbidden", reason: "missing dashboard session header" }, 403);
38020
+ }
38021
+ return null;
38022
+ }
38023
+ async function readEnabled(c) {
38024
+ try {
38025
+ const body = await c.req.json();
38026
+ if (typeof body === "object" && body !== null) {
38027
+ const v = body.enabled;
38028
+ if (typeof v === "boolean")
38029
+ return v;
38030
+ if (v === "true" || v === 1)
38031
+ return true;
38032
+ if (v === "false" || v === 0)
38033
+ return false;
38034
+ }
38035
+ return null;
38036
+ } catch {
38037
+ return null;
38038
+ }
38039
+ }
38040
+ function defaultRemoveCredentials() {
38041
+ for (const path4 of [credentialsPath(), legacyCredentialsPath()]) {
38042
+ try {
38043
+ rmSync5(path4, { force: true });
38044
+ } catch {
38045
+ }
38046
+ }
38047
+ }
38048
+ function defaultShutdown() {
38049
+ try {
38050
+ process.kill(process.pid, "SIGTERM");
38051
+ } catch {
38052
+ }
38053
+ }
38054
+ function defaultSpawnRestart() {
38055
+ const entry = process.argv[1];
38056
+ if (entry === void 0 || entry === "")
38057
+ return;
38058
+ const helper = resolve5(dirname12(entry), "restart-helper.js");
38059
+ const child = spawn4(process.execPath, [helper], {
38060
+ detached: true,
38061
+ stdio: "ignore",
38062
+ env: { ...process.env, HONEYCOMB_RESTART_ENTRY: entry, HONEYCOMB_RESTART_PORT: String(DAEMON_PORT) }
38063
+ });
38064
+ child.unref();
38065
+ }
38066
+ function defaultUninstall() {
38067
+ const harnesses = [...detectInstalledHarnesses()];
38068
+ return {
38069
+ ok: true,
38070
+ harnesses,
38071
+ removed: false,
38072
+ command: "honeycomb uninstall",
38073
+ note: "Run `honeycomb uninstall` in your terminal to remove Honeycomb's hooks from your coding assistants. It reverses only Honeycomb's changes; your DeepLake login is left intact (use Log out for that)."
38074
+ };
38075
+ }
38076
+ function mountActionsGroup(group, mode, options) {
38077
+ const embed = options.embed;
38078
+ const store = options.store;
38079
+ const removeCredentials = options.removeCredentials ?? defaultRemoveCredentials;
38080
+ const shutdown = options.shutdown ?? defaultShutdown;
38081
+ const spawnRestart = options.spawnRestart ?? defaultSpawnRestart;
38082
+ const uninstall = options.uninstall ?? defaultUninstall;
38083
+ const settingsScope = localDefaultScopeResolver(mode, options.defaultScope);
38084
+ group.post("/logout", (c) => {
38085
+ const denied = actionGuard(c, mode);
38086
+ if (denied)
38087
+ return denied;
38088
+ removeCredentials();
38089
+ return c.json({ ok: true });
38090
+ });
38091
+ group.post("/embeddings", async (c) => {
38092
+ const denied = actionGuard(c, mode);
38093
+ if (denied)
38094
+ return denied;
38095
+ const enabled = await readEnabled(c);
38096
+ if (enabled === null) {
38097
+ return c.json({ error: "bad_request", reason: "body must carry { enabled: boolean }" }, 400);
38098
+ }
38099
+ if (store !== void 0) {
38100
+ const sc = settingsScope.resolve(c);
38101
+ if (sc !== null) {
38102
+ try {
38103
+ await store.setSetting(EMBEDDINGS_ENABLED_KEY, enabled, sc);
38104
+ } catch {
38105
+ }
38106
+ }
38107
+ }
38108
+ await embed.setEnabled(enabled);
38109
+ return c.json({ ok: true, enabled });
38110
+ });
38111
+ group.post("/restart", (c) => {
38112
+ const denied = actionGuard(c, mode);
38113
+ if (denied)
38114
+ return denied;
38115
+ spawnRestart();
38116
+ setTimeout(() => shutdown(), RESTART_SHUTDOWN_DELAY_MS);
38117
+ return c.json({ ok: true, restarting: true });
38118
+ });
38119
+ group.post("/uninstall", (c) => {
38120
+ const denied = actionGuard(c, mode);
38121
+ if (denied)
38122
+ return denied;
38123
+ return c.json(uninstall());
38124
+ });
38125
+ }
38126
+ function mountActionsApi(daemon, options) {
38127
+ const group = daemon.group(ACTIONS_GROUP);
38128
+ if (group === void 0)
38129
+ return;
38130
+ mountActionsGroup(group, daemon.config.mode, options);
38131
+ }
38132
+
36391
38133
  // dist/src/daemon/runtime/dashboard/harness-api.js
36392
38134
  var HARNESS_GROUP = "/api/diagnostics";
36393
38135
  var HARNESS_PATH = "/harnesses";
@@ -36917,25 +38659,25 @@ async function tableAbsent(probe, table) {
36917
38659
  }
36918
38660
 
36919
38661
  // dist/src/daemon/runtime/dashboard/asset-install-target.js
36920
- import { existsSync as existsSync12, mkdirSync as mkdirSync14, readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "node:fs";
36921
- import { homedir as homedir15 } from "node:os";
36922
- import { join as join20 } from "node:path";
36923
- var SKILLS_SUBDIR = join20(".claude", "skills");
36924
- var AGENTS_SUBDIR = join20(".claude", "agents");
38662
+ import { existsSync as existsSync13, mkdirSync as mkdirSync14, readFileSync as readFileSync16, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
38663
+ import { homedir as homedir17 } from "node:os";
38664
+ import { join as join21 } from "node:path";
38665
+ var SKILLS_SUBDIR = join21(".claude", "skills");
38666
+ var AGENTS_SUBDIR = join21(".claude", "agents");
36925
38667
  var SKILL_FILE3 = "SKILL.md";
36926
38668
  function createFsAssetInstallTarget(dirs = {}) {
36927
38669
  const projectDir = dirs.projectDir ?? process.cwd();
36928
- const globalDir = dirs.globalDir ?? homedir15();
38670
+ const globalDir = dirs.globalDir ?? homedir17();
36929
38671
  const rootFor = (install) => install === "global" ? globalDir : projectDir;
36930
38672
  const pathFor = (assetType, install, name) => {
36931
38673
  const root = rootFor(install);
36932
38674
  const segment = sanitizeSegment3(name);
36933
38675
  if (assetType === "agent") {
36934
- const dir2 = join20(root, AGENTS_SUBDIR);
36935
- return { dir: dir2, file: join20(dir2, `${segment}.md`) };
38676
+ const dir2 = join21(root, AGENTS_SUBDIR);
38677
+ return { dir: dir2, file: join21(dir2, `${segment}.md`) };
36936
38678
  }
36937
- const dir = join20(root, SKILLS_SUBDIR, segment);
36938
- return { dir, file: join20(dir, SKILL_FILE3) };
38679
+ const dir = join21(root, SKILLS_SUBDIR, segment);
38680
+ return { dir, file: join21(dir, SKILL_FILE3) };
36939
38681
  };
36940
38682
  return {
36941
38683
  async write(assetType, install, name, body) {
@@ -36951,7 +38693,7 @@ function createFsAssetInstallTarget(dirs = {}) {
36951
38693
  async read(assetType, install, name) {
36952
38694
  try {
36953
38695
  const { file: file2 } = pathFor(assetType, install, name);
36954
- if (!existsSync12(file2))
38696
+ if (!existsSync13(file2))
36955
38697
  return null;
36956
38698
  return readFileSync16(file2, "utf-8");
36957
38699
  } catch {
@@ -36962,14 +38704,14 @@ function createFsAssetInstallTarget(dirs = {}) {
36962
38704
  try {
36963
38705
  const { dir, file: file2 } = pathFor(assetType, install, name);
36964
38706
  if (assetType === "agent") {
36965
- if (!existsSync12(file2))
38707
+ if (!existsSync13(file2))
36966
38708
  return false;
36967
- rmSync5(file2, { force: true });
38709
+ rmSync6(file2, { force: true });
36968
38710
  return true;
36969
38711
  }
36970
- if (!existsSync12(dir))
38712
+ if (!existsSync13(dir))
36971
38713
  return false;
36972
- rmSync5(dir, { recursive: true, force: true });
38714
+ rmSync6(dir, { recursive: true, force: true });
36973
38715
  return true;
36974
38716
  } catch {
36975
38717
  return false;
@@ -36977,7 +38719,7 @@ function createFsAssetInstallTarget(dirs = {}) {
36977
38719
  },
36978
38720
  exists(assetType, install, name) {
36979
38721
  try {
36980
- return existsSync12(pathFor(assetType, install, name).file);
38722
+ return existsSync13(pathFor(assetType, install, name).file);
36981
38723
  } catch {
36982
38724
  return false;
36983
38725
  }
@@ -37355,67 +39097,9 @@ function pickAssetType(value) {
37355
39097
  return typeof value === "string" && SYNCED_ASSET_TYPES.includes(value) ? value : null;
37356
39098
  }
37357
39099
 
37358
- // dist/src/daemon/runtime/dashboard/harness-detect.js
37359
- import { existsSync as existsSync13 } from "node:fs";
37360
- import { homedir as homedir16 } from "node:os";
37361
- import { join as join21 } from "node:path";
37362
- var HARNESS_MARKERS = [
37363
- {
37364
- name: "claude-code",
37365
- // src/connectors/claude-code.ts: configPath() = ~/.claude/settings.json; pluginRoot = ~/.claude/plugins/honeycomb.
37366
- paths: (h) => [join21(h, ".claude", "settings.json"), join21(h, ".claude", "plugins", "honeycomb")]
37367
- },
37368
- {
37369
- name: "cursor",
37370
- // src/connectors/cursor.ts: configPath() = ~/.cursor/hooks.json; pluginRoot = ~/.cursor/honeycomb.
37371
- paths: (h) => [join21(h, ".cursor", "hooks.json"), join21(h, ".cursor", "honeycomb")]
37372
- },
37373
- {
37374
- name: "codex",
37375
- // hivemind-v1/src/cli/install-codex.ts: HOOKS_PATH = ~/.codex/hooks.json; PLUGIN_DIR = ~/.codex/hivemind.
37376
- paths: (h) => [join21(h, ".codex", "hooks.json"), join21(h, ".codex", "hivemind")]
37377
- },
37378
- {
37379
- name: "hermes",
37380
- // hivemind-v1/src/cli/install-hermes.ts: CONFIG_PATH = ~/.hermes/config.yaml; HIVEMIND_DIR = ~/.hermes/hivemind.
37381
- paths: (h) => [join21(h, ".hermes", "config.yaml"), join21(h, ".hermes", "hivemind")]
37382
- },
37383
- {
37384
- name: "pi",
37385
- // hivemind-v1/src/cli/install-pi.ts: AGENTS_MD = ~/.pi/agent/AGENTS.md; EXTENSION_PATH = ~/.pi/agent/extensions/hivemind.ts.
37386
- paths: (h) => [
37387
- join21(h, ".pi", "agent", "extensions", "hivemind.ts"),
37388
- join21(h, ".pi", "agent", "AGENTS.md")
37389
- ]
37390
- },
37391
- {
37392
- name: "openclaw",
37393
- // hivemind-v1/src/cli/install-openclaw.ts: PLUGIN_DIR = ~/.openclaw/extensions/hivemind.
37394
- paths: (h) => [join21(h, ".openclaw", "extensions", "hivemind")]
37395
- }
37396
- ];
37397
- function markerExists(path4) {
37398
- try {
37399
- return existsSync13(path4);
37400
- } catch {
37401
- return false;
37402
- }
37403
- }
37404
- function detectInstalledHarnesses(homeDir = homedir16(), _cwd = process.cwd()) {
37405
- const canonical = new Set(CANONICAL_HARNESS_IDS);
37406
- const installed = /* @__PURE__ */ new Set();
37407
- for (const marker of HARNESS_MARKERS) {
37408
- if (!canonical.has(marker.name))
37409
- continue;
37410
- if (marker.paths(homeDir).some(markerExists))
37411
- installed.add(marker.name);
37412
- }
37413
- return installed;
37414
- }
37415
-
37416
39100
  // dist/src/daemon/runtime/dashboard/web-assets.js
37417
39101
  import { existsSync as existsSync14, readFileSync as readFileSync17 } from "node:fs";
37418
- import { dirname as dirname12, join as join22 } from "node:path";
39102
+ import { dirname as dirname13, join as join22 } from "node:path";
37419
39103
  import { fileURLToPath as fileURLToPath2 } from "node:url";
37420
39104
  var CSS_FILES = ["tokens/fonts.css", "tokens/colors.css", "tokens/typography.css", "tokens/spacing.css", "tokens/base.css"];
37421
39105
  var LOGO_FILE = "logos/honeycomb-memory-cluster.svg";
@@ -37440,7 +39124,7 @@ var DASHBOARD_APP_BUNDLE = "dashboard-app.js";
37440
39124
  function resolveAssetsDir(startUrl = import.meta.url) {
37441
39125
  let dir;
37442
39126
  try {
37443
- dir = dirname12(fileURLToPath2(startUrl));
39127
+ dir = dirname13(fileURLToPath2(startUrl));
37444
39128
  } catch {
37445
39129
  return null;
37446
39130
  }
@@ -37448,7 +39132,7 @@ function resolveAssetsDir(startUrl = import.meta.url) {
37448
39132
  const candidate = join22(dir, "assets");
37449
39133
  if (existsSync14(join22(candidate, "styles.css")))
37450
39134
  return candidate;
37451
- const parent = dirname12(dir);
39135
+ const parent = dirname13(dir);
37452
39136
  if (parent === dir)
37453
39137
  break;
37454
39138
  dir = parent;
@@ -37457,7 +39141,7 @@ function resolveAssetsDir(startUrl = import.meta.url) {
37457
39141
  }
37458
39142
  function resolveBundleDir(startUrl = import.meta.url) {
37459
39143
  try {
37460
- return dirname12(fileURLToPath2(startUrl));
39144
+ return dirname13(fileURLToPath2(startUrl));
37461
39145
  } catch {
37462
39146
  return null;
37463
39147
  }
@@ -37569,24 +39253,27 @@ function mountDashboardHost(daemon, options = {}) {
37569
39253
  if (root === void 0)
37570
39254
  return;
37571
39255
  const assets = options.assets ?? createWebAssets();
37572
- root.get(DASHBOARD_HOST_PATH, (c) => c.html(renderShell()));
39256
+ root.get(DASHBOARD_HOST_PATH, (c) => {
39257
+ c.header("cache-control", "no-cache");
39258
+ return c.html(renderShell());
39259
+ });
37573
39260
  root.get(DASHBOARD_APP_PATH, (c) => {
37574
39261
  const asset = assets.appJs();
37575
39262
  if (asset === null)
37576
39263
  return c.text("dashboard bundle not built", 404);
37577
- return c.body(asset.body, 200, { "content-type": asset.contentType });
39264
+ return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
37578
39265
  });
37579
39266
  root.get(DASHBOARD_CSS_PATH, (c) => {
37580
39267
  const asset = assets.css();
37581
39268
  if (asset === null)
37582
39269
  return c.text("dashboard styles unavailable", 404);
37583
- return c.body(asset.body, 200, { "content-type": asset.contentType });
39270
+ return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
37584
39271
  });
37585
39272
  root.get(DASHBOARD_LOGO_PATH, (c) => {
37586
39273
  const asset = assets.logo();
37587
39274
  if (asset === null)
37588
39275
  return c.text("dashboard logo unavailable", 404);
37589
- return c.body(asset.body, 200, { "content-type": asset.contentType });
39276
+ return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
37590
39277
  });
37591
39278
  root.get(DASHBOARD_FONT_PATH, (c) => {
37592
39279
  const asset = assets.font(c.req.param("name"));
@@ -37635,8 +39322,8 @@ function mountSetupLogin(daemon, options = {}) {
37635
39322
  };
37636
39323
  let rejectGrant = () => {
37637
39324
  };
37638
- const grantReady = new Promise((resolve6, reject) => {
37639
- resolveGrant = resolve6;
39325
+ const grantReady = new Promise((resolve7, reject) => {
39326
+ resolveGrant = resolve7;
37640
39327
  rejectGrant = reject;
37641
39328
  });
37642
39329
  const deps = {
@@ -37667,7 +39354,7 @@ function mountSetupLogin(daemon, options = {}) {
37667
39354
 
37668
39355
  // dist/src/daemon/runtime/dashboard/setup-state.js
37669
39356
  import { existsSync as existsSync15 } from "node:fs";
37670
- import { homedir as homedir17 } from "node:os";
39357
+ import { homedir as homedir18 } from "node:os";
37671
39358
  import { join as join23 } from "node:path";
37672
39359
  var SETUP_STATE_PATH = "/setup/state";
37673
39360
  var SETUP_STATE_GROUP = "/";
@@ -37690,7 +39377,7 @@ function derivePriorTool(recorded, hivemindDirPresent) {
37690
39377
  return hivemindDirPresent ? { hivemind: "present" } : recorded;
37691
39378
  }
37692
39379
  function resolveSetupState(deps = {}) {
37693
- const home = deps.homeDir ?? homedir17();
39380
+ const home = deps.homeDir ?? homedir18();
37694
39381
  const env = deps.env ?? process.env;
37695
39382
  const onboarding = loadOnboarding(deps.onboardingDir);
37696
39383
  const legacyCredentialsDir = deps.legacyCredentialsDir ?? join23(home, LEGACY_CREDENTIALS_DIR_NAME);
@@ -37725,8 +39412,8 @@ function mountSetupStateApi(daemon, deps = {}) {
37725
39412
 
37726
39413
  // dist/src/daemon/runtime/onboarding/hivemind-uninstall.js
37727
39414
  import { execFileSync as execFileSync5 } from "node:child_process";
37728
- import { cpSync, existsSync as existsSync16, rmSync as rmSync6 } from "node:fs";
37729
- import { homedir as homedir18 } from "node:os";
39415
+ import { cpSync, existsSync as existsSync16, rmSync as rmSync7 } from "node:fs";
39416
+ import { homedir as homedir19 } from "node:os";
37730
39417
  import { join as join24 } from "node:path";
37731
39418
  var HIVEMIND_DIR_NAME2 = ".hivemind";
37732
39419
  var HIVEMIND_NPM_PACKAGE = "@deeplake/hivemind";
@@ -37748,7 +39435,7 @@ function hivemindBackupPath(home, iso) {
37748
39435
  return join24(home, `${HIVEMIND_BACKUP_PREFIX}${safe}`);
37749
39436
  }
37750
39437
  function backupAndUninstallHivemind(deps = {}) {
37751
- const home = deps.homeDir ?? homedir18();
39438
+ const home = deps.homeDir ?? homedir19();
37752
39439
  const npmRemove = deps.npmRemove ?? defaultNpmGlobalRemover;
37753
39440
  const dir = hivemindDirPath(home);
37754
39441
  let npmRemoved = false;
@@ -37764,7 +39451,7 @@ function backupAndUninstallHivemind(deps = {}) {
37764
39451
  const backupPath = hivemindBackupPath(home, iso);
37765
39452
  cpSync(dir, backupPath, { recursive: true });
37766
39453
  try {
37767
- rmSync6(dir, { recursive: true, force: true });
39454
+ rmSync7(dir, { recursive: true, force: true });
37768
39455
  return { removed: true, backupPath, npmRemoved };
37769
39456
  } catch {
37770
39457
  return { removed: false, backupPath, npmRemoved };
@@ -37773,9 +39460,9 @@ function backupAndUninstallHivemind(deps = {}) {
37773
39460
  function restoreHivemindBackup(backupPath, deps = {}) {
37774
39461
  if (backupPath.length === 0 || !existsSync16(backupPath))
37775
39462
  return false;
37776
- const home = deps.homeDir ?? homedir18();
39463
+ const home = deps.homeDir ?? homedir19();
37777
39464
  const dir = hivemindDirPath(home);
37778
- rmSync6(dir, { recursive: true, force: true });
39465
+ rmSync7(dir, { recursive: true, force: true });
37779
39466
  cpSync(backupPath, dir, { recursive: true });
37780
39467
  return true;
37781
39468
  }
@@ -38595,8 +40282,8 @@ function resolveProjectsScope(c, defaultScope) {
38595
40282
 
38596
40283
  // dist/src/daemon/runtime/projects/onboarding-api.js
38597
40284
  import { existsSync as existsSync17, readdirSync as readdirSync3, realpathSync, statSync as statSync2 } from "node:fs";
38598
- import { homedir as homedir19 } from "node:os";
38599
- import { isAbsolute as isAbsolute2, join as join25, resolve as resolve5, sep as sep3 } from "node:path";
40285
+ import { homedir as homedir20 } from "node:os";
40286
+ import { isAbsolute as isAbsolute2, join as join25, resolve as resolve6, sep as sep3 } from "node:path";
38600
40287
  var ONBOARDING_GROUP = "/api/diagnostics";
38601
40288
  var FS_BROWSE_PATH = "/fs/browse";
38602
40289
  var PROJECTS_BIND_PATH = "/projects/bind";
@@ -38624,19 +40311,19 @@ function suggestProjectId(absPath, readRemote) {
38624
40311
  return repo;
38625
40312
  }
38626
40313
  }
38627
- const segs = resolve5(absPath).split(sep3).filter((s) => s.length > 0);
40314
+ const segs = resolve6(absPath).split(sep3).filter((s) => s.length > 0);
38628
40315
  const base = segs[segs.length - 1];
38629
40316
  return base ?? "";
38630
40317
  }
38631
40318
  function canonicalize(absPath) {
38632
- let head = resolve5(absPath);
40319
+ let head = resolve6(absPath);
38633
40320
  const tail = [];
38634
40321
  for (; ; ) {
38635
40322
  try {
38636
40323
  const real = realpathSync(head);
38637
40324
  return stripTrailingSep(tail.length > 0 ? join25(real, ...tail.reverse()) : real);
38638
40325
  } catch {
38639
- const parent = resolve5(head, "..");
40326
+ const parent = resolve6(head, "..");
38640
40327
  if (parent === head)
38641
40328
  return stripTrailingSep(head);
38642
40329
  const segmentStart = parent.endsWith(sep3) ? parent.length : parent.length + sep3.length;
@@ -38663,7 +40350,7 @@ function parentWithinRoot(dir, root) {
38663
40350
  const normalizedRoot = root;
38664
40351
  if (dir === normalizedRoot)
38665
40352
  return null;
38666
- const parent = canonicalize(resolve5(dir, ".."));
40353
+ const parent = canonicalize(resolve6(dir, ".."));
38667
40354
  return parent === normalizedRoot || parent.startsWith(normalizedRoot + sep3) ? parent : normalizedRoot;
38668
40355
  }
38669
40356
  function listChildDirs(dir) {
@@ -38701,7 +40388,7 @@ function mountOnboardingApi(daemon, options) {
38701
40388
  if (group === void 0)
38702
40389
  return;
38703
40390
  const mode = daemon.config.mode;
38704
- const root = canonicalize(options.browseRoot ?? homedir19());
40391
+ const root = canonicalize(options.browseRoot ?? homedir20());
38705
40392
  const readRemote = options.readRemote ?? defaultGitRemoteReader;
38706
40393
  const notLocal = () => mode !== "local";
38707
40394
  group.get(FS_BROWSE_PATH, (c) => {
@@ -38793,7 +40480,7 @@ function resolveBindPath(path4) {
38793
40480
  const trimmed = path4.trim();
38794
40481
  if (trimmed.length === 0 || !isAbsolute2(trimmed))
38795
40482
  return null;
38796
- return resolve5(trimmed);
40483
+ return resolve6(trimmed);
38797
40484
  }
38798
40485
  function rejectBind(path4, reason) {
38799
40486
  return { bound: false, path: path4, projectId: "", error: reason };
@@ -38822,9 +40509,9 @@ function remoteFor(absPath, readRemote) {
38822
40509
  return raw2 !== null ? canonicalizeRemote(raw2) : "";
38823
40510
  }
38824
40511
  function removeBinding(absPath, options) {
38825
- const normalized = stripTrailingSep(resolve5(absPath));
40512
+ const normalized = stripTrailingSep(resolve6(absPath));
38826
40513
  const loaded = loadProjectsCache(options.projectsDir);
38827
- const kept = loaded.bindings.filter((b) => stripTrailingSep(resolve5(b.path)) !== normalized);
40514
+ const kept = loaded.bindings.filter((b) => stripTrailingSep(resolve6(b.path)) !== normalized);
38828
40515
  if (kept.length === loaded.bindings.length) {
38829
40516
  return { unbound: false, path: normalized };
38830
40517
  }
@@ -39381,35 +41068,6 @@ async function readBody4(c) {
39381
41068
  }
39382
41069
  }
39383
41070
 
39384
- // dist/src/daemon/runtime/recall/scope-clause.js
39385
- var PROJECT_ID_COLUMN = "project_id";
39386
- var PROJECT_ID_UNSET = "";
39387
- var CROSS_PROJECT_ADMITTED = Object.freeze(["user", "workspace"]);
39388
- var SCOPE_READ_POLICIES = Object.freeze(["isolated", "shared", "group"]);
39389
- function buildProjectScopeClause(input) {
39390
- const projectColumn = input.projectColumn ?? PROJECT_ID_COLUMN;
39391
- const rawId = input.projectId ?? "";
39392
- const isInbox = rawId.trim() === "" || rawId === UNSORTED_PROJECT_ID;
39393
- const bound = input.bound ?? !isInbox;
39394
- const col = sqlIdent(projectColumn);
39395
- const primaryId = bound ? rawId : UNSORTED_PROJECT_ID;
39396
- const admitted = primaryId === PROJECT_ID_UNSET ? [PROJECT_ID_UNSET] : [primaryId, PROJECT_ID_UNSET];
39397
- const disjuncts = admitted.map((id) => `${col} = ${sLiteral(id)}`);
39398
- const values = [...admitted];
39399
- if (input.promotionColumn !== void 0 && input.promotionColumn !== "") {
39400
- const promoCol = sqlIdent(input.promotionColumn);
39401
- for (const reach of CROSS_PROJECT_ADMITTED) {
39402
- disjuncts.push(`${promoCol} = ${sLiteral(reach)}`);
39403
- values.push(reach);
39404
- }
39405
- }
39406
- const sql = `(${disjuncts.join(" OR ")})`;
39407
- return { sql, values, bound };
39408
- }
39409
- function buildProjectScopeConjunct(input) {
39410
- return ` AND ${buildProjectScopeClause(input).sql}`;
39411
- }
39412
-
39413
41071
  // dist/src/daemon/runtime/memories/reads.js
39414
41072
  var DEFAULT_LIST_LIMIT = 50;
39415
41073
  var MAX_LIST_LIMIT = 500;
@@ -40459,7 +42117,7 @@ function recordKey(record2) {
40459
42117
  // dist/src/daemon/runtime/notifications/api.js
40460
42118
  var NOTIFICATIONS_GROUP = "/api/diagnostics";
40461
42119
  var NOTIFICATIONS_PATH = "/notifications";
40462
- var headerScopeResolver = {
42120
+ var headerScopeResolver2 = {
40463
42121
  resolve(c) {
40464
42122
  const org = c.req.header("x-honeycomb-org");
40465
42123
  if (org === void 0 || org.length === 0)
@@ -40503,7 +42161,7 @@ function mountNotificationsApi(daemon, options) {
40503
42161
  if (group === void 0)
40504
42162
  return;
40505
42163
  const table = options.table ?? "notifications";
40506
- const scopeResolver = options.scope ?? headerScopeResolver;
42164
+ const scopeResolver = options.scope ?? headerScopeResolver2;
40507
42165
  group.get(NOTIFICATIONS_PATH, async (c) => {
40508
42166
  const scope = scopeResolver.resolve(c);
40509
42167
  if (scope === null) {
@@ -40689,6 +42347,8 @@ var DEFAULT_TRAVERSAL_MIN_EDGE_WEIGHT = 0.3;
40689
42347
  var DEFAULT_TRAVERSAL_TIMEOUT_MS = 500;
40690
42348
  var DEFAULT_RERANKER = "none";
40691
42349
  var DEFAULT_RERANKER_TIMEOUT_MS = 300;
42350
+ var DEFAULT_RERANKER_PROVIDER_TIMEOUT_MS = 1e3;
42351
+ var DEFAULT_RERANKER_COHERE_MODEL = "rerank-v3.5";
40692
42352
  var DEFAULT_RERANKER_WINDOW = 50;
40693
42353
  var DEFAULT_DEDUP_ENABLED = true;
40694
42354
  var DEFAULT_DEDUP_SIMILARITY_THRESHOLD = 0.9;
@@ -40707,7 +42367,7 @@ var DEFAULT_RESOLUTION_BOOST = 1.25;
40707
42367
  var DEFAULT_REHEARSAL_BOOST = 1.1;
40708
42368
  var DEFAULT_REHEARSAL_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
40709
42369
  var DEFAULT_MIN_INJECTION_SCORE = 0.6;
40710
- var RERANKER_STRATEGIES = Object.freeze(["embedding-cosine", "llm", "none"]);
42370
+ var RERANKER_STRATEGIES = Object.freeze(["embedding-cosine", "llm", "cohere", "none"]);
40711
42371
  var BoolFlag3 = external_exports.preprocess((raw2) => {
40712
42372
  if (typeof raw2 === "boolean")
40713
42373
  return raw2;
@@ -40762,12 +42422,26 @@ var TraversalConfigSchema = external_exports.object({
40762
42422
  timeoutMs: ClampedInt4(DEFAULT_TRAVERSAL_TIMEOUT_MS, 1).default(DEFAULT_TRAVERSAL_TIMEOUT_MS)
40763
42423
  });
40764
42424
  var RerankerConfigSchema = external_exports.object({
40765
- /** The reranker strategy (D-4). */
42425
+ /** The reranker strategy (D-4 + PRD-063c). */
40766
42426
  strategy: external_exports.enum(RERANKER_STRATEGIES).default(DEFAULT_RERANKER),
40767
- /** Reranker timeout in ms; on timeout keep the original order (d-AC-2 / b-AC-2). */
42427
+ /** Reranker timeout in ms; on timeout keep the original order (d-AC-2 / b-AC-2). LOCAL-cosine budget. */
40768
42428
  timeoutMs: ClampedInt4(DEFAULT_RERANKER_TIMEOUT_MS, 1).default(DEFAULT_RERANKER_TIMEOUT_MS),
42429
+ /**
42430
+ * The PROVIDER-rerank timeout in ms (PRD-063c / c-AC-3): the budget for the `cohere` outbound
42431
+ * Portkey round-trip, larger than the local-cosine {@link timeoutMs} because it crosses the
42432
+ * network. A `cohere` call that exceeds it FAILS SOFT to the RRF order. Defaults to
42433
+ * {@link DEFAULT_RERANKER_PROVIDER_TIMEOUT_MS} (1000ms); the local-cosine path never reads it.
42434
+ */
42435
+ providerTimeoutMs: ClampedInt4(DEFAULT_RERANKER_PROVIDER_TIMEOUT_MS, 1).default(DEFAULT_RERANKER_PROVIDER_TIMEOUT_MS),
40769
42436
  /** Rerank window N: how many fused top-N candidates to re-score (PRD-047b). */
40770
- window: ClampedInt4(DEFAULT_RERANKER_WINDOW, 1).default(DEFAULT_RERANKER_WINDOW)
42437
+ window: ClampedInt4(DEFAULT_RERANKER_WINDOW, 1).default(DEFAULT_RERANKER_WINDOW),
42438
+ /**
42439
+ * The Cohere rerank `model` id sent to Portkey when the strategy is `cohere` (PRD-063c / c-D-1).
42440
+ * Defaults to {@link DEFAULT_RERANKER_COHERE_MODEL}; the operator may override it (or configure
42441
+ * the model inside Portkey). A non-string env value falls back to the default. Only the `cohere`
42442
+ * strategy reads it.
42443
+ */
42444
+ cohereModel: external_exports.string().min(1).catch(DEFAULT_RERANKER_COHERE_MODEL).default(DEFAULT_RERANKER_COHERE_MODEL)
40771
42445
  });
40772
42446
  var DedupConfigSchema = external_exports.object({
40773
42447
  /** Whether semantic near-duplicate dedup runs; ON by default (PRD-047c / c-AC-3). */
@@ -40867,7 +42541,9 @@ function envRecallConfigProvider(env = process.env) {
40867
42541
  reranker: {
40868
42542
  strategy: env.HONEYCOMB_RECALL_RERANKER,
40869
42543
  timeoutMs: env.HONEYCOMB_RECALL_RERANKER_TIMEOUT_MS,
40870
- window: env.HONEYCOMB_RECALL_RERANKER_WINDOW
42544
+ providerTimeoutMs: env.HONEYCOMB_RECALL_RERANKER_PROVIDER_TIMEOUT_MS,
42545
+ window: env.HONEYCOMB_RECALL_RERANKER_WINDOW,
42546
+ cohereModel: env.HONEYCOMB_RECALL_RERANKER_COHERE_MODEL
40871
42547
  },
40872
42548
  dampening: {
40873
42549
  gravity: env.HONEYCOMB_RECALL_DAMPENING_GRAVITY,
@@ -40936,10 +42612,10 @@ var Semaphore = class {
40936
42612
  this.held += 1;
40937
42613
  return Promise.resolve();
40938
42614
  }
40939
- return new Promise((resolve6) => {
42615
+ return new Promise((resolve7) => {
40940
42616
  this.waiters.push(() => {
40941
42617
  this.held += 1;
40942
- resolve6();
42618
+ resolve7();
40943
42619
  });
40944
42620
  });
40945
42621
  }
@@ -41442,9 +43118,16 @@ async function fetchCandidateEmbeddings(candidates, request, deps) {
41442
43118
  }
41443
43119
  async function rerankHits(hits, queryVector, config2, request, deps) {
41444
43120
  const rrfOrder = [...hits];
43121
+ if (hits.length === 0)
43122
+ return rrfOrder;
43123
+ if (config2.strategy === "cohere") {
43124
+ if (deps.cohereRerank === void 0)
43125
+ return rrfOrder;
43126
+ return rerankWithCohere(rrfOrder, config2, request, deps, deps.cohereRerank);
43127
+ }
41445
43128
  if (config2.strategy !== "embedding-cosine")
41446
43129
  return rrfOrder;
41447
- if (hits.length === 0)
43130
+ if (queryVector === null)
41448
43131
  return rrfOrder;
41449
43132
  const now = deps.now ?? Date.now;
41450
43133
  const start = now();
@@ -41475,6 +43158,56 @@ async function rerankHits(hits, queryVector, config2, request, deps) {
41475
43158
  return rrfOrder;
41476
43159
  }
41477
43160
  }
43161
+ async function rerankWithCohere(rrfOrder, config2, request, deps, seam) {
43162
+ const baseOrder = [...rrfOrder];
43163
+ const now = deps.now ?? Date.now;
43164
+ const start = now();
43165
+ const window = Math.max(1, Math.trunc(config2.window));
43166
+ const head = baseOrder.slice(0, window);
43167
+ const tail = baseOrder.slice(window);
43168
+ const documents = head.map((h) => h.text);
43169
+ try {
43170
+ const timeoutMs = Math.max(1, Math.trunc(config2.providerTimeoutMs));
43171
+ const TIMED_OUT = /* @__PURE__ */ Symbol("rerank-timeout");
43172
+ let timer;
43173
+ const timeout = new Promise((resolve7) => {
43174
+ timer = setTimeout(() => resolve7(TIMED_OUT), timeoutMs);
43175
+ });
43176
+ let outcome;
43177
+ try {
43178
+ outcome = await Promise.race([seam.rerank(request.query, documents, head.length), timeout]);
43179
+ } finally {
43180
+ if (timer !== void 0)
43181
+ clearTimeout(timer);
43182
+ }
43183
+ if (outcome === TIMED_OUT || outcome.ok === false)
43184
+ return baseOrder;
43185
+ const scoreByIndex = /* @__PURE__ */ new Map();
43186
+ for (const r of outcome.results) {
43187
+ if (r.index >= 0 && r.index < head.length && !scoreByIndex.has(r.index)) {
43188
+ scoreByIndex.set(r.index, r.relevanceScore);
43189
+ }
43190
+ }
43191
+ const scoredSlots = [];
43192
+ for (let i = 0; i < head.length; i++) {
43193
+ if (scoreByIndex.has(i))
43194
+ scoredSlots.push(i);
43195
+ }
43196
+ const orderedByScore = scoredSlots.map((index) => ({ index, score: scoreByIndex.get(index) })).sort((a, b) => {
43197
+ if (b.score !== a.score)
43198
+ return b.score - a.score;
43199
+ return a.index - b.index;
43200
+ });
43201
+ const reorderedHead = head.slice();
43202
+ scoredSlots.forEach((slot, i) => {
43203
+ reorderedHead[slot] = head[orderedByScore[i].index];
43204
+ });
43205
+ void start;
43206
+ return [...reorderedHead, ...tail];
43207
+ } catch {
43208
+ return baseOrder;
43209
+ }
43210
+ }
41478
43211
  function provenanceRank(source) {
41479
43212
  if (source === "memories")
41480
43213
  return 0;
@@ -41641,661 +43374,214 @@ function applyRecencyActivation(hits, byClass, activationExponent, nowMs, stalen
41641
43374
  return activated.map(({ hit, activation, staleFields }) => ({ ...hit, ...staleFields, freshnessScore: activation }));
41642
43375
  }
41643
43376
  activated.sort((a, b) => {
41644
- if (b.score !== a.score)
41645
- return b.score - a.score;
41646
- return a.index - b.index;
41647
- });
41648
- return activated.map(({ hit, activation, score, staleFields }) => ({ ...hit, ...staleFields, score, freshnessScore: activation }));
41649
- }
41650
- async function applyActrActivation(hits, source, byClass, activationExponent, nowMs, scope, staleness) {
41651
- const exponent = Math.max(0, Number.isFinite(activationExponent) ? activationExponent : DEFAULT_RECENCY_ACTIVATION_EXPONENT);
41652
- const params = source.params ?? DEFAULT_ACTR_PARAMS;
41653
- let inputs;
41654
- try {
41655
- inputs = await source.load(hits, scope);
41656
- } catch {
41657
- return applyRecencyActivation(hits, byClass, activationExponent, nowMs, staleness);
41658
- }
41659
- const computed = hits.map((hit, index) => {
41660
- const key = fusionKey(hit.source, hit.id);
41661
- const input = inputs.get(key);
41662
- if (input === void 0) {
41663
- const halfLife = halfLifeForSource(hit.source, byClass);
41664
- const lastReinforcedAt = hit.lastReinforcedAt;
41665
- const a2 = recencyActivation(refTimestampMs(hit.createdAt, lastReinforcedAt), nowMs, halfLife);
41666
- return { hit, index, activation: a2, accessCount: void 0 };
41667
- }
41668
- const a = actrActivation(input.history, nowMs, params);
41669
- return { hit, index, activation: a, accessCount: input.accessCount };
41670
- });
41671
- const adjusted = computed.map((c) => {
41672
- const stale = stalenessContribution(c.hit, staleness);
41673
- const orderingWeight = (exponent === 1 ? c.activation : Math.pow(c.activation, exponent)) * stale.factor;
41674
- return { ...c, staleFields: stale.fields, orderingWeight, score: c.hit.score * orderingWeight };
41675
- });
41676
- const stamp = (c) => ({
41677
- ...c.hit,
41678
- ...c.staleFields,
41679
- score: c.score,
41680
- freshnessScore: c.activation,
41681
- // the swap: A_actr behind the SAME field 058a used (PRD-058e).
41682
- activation: c.activation,
41683
- ...c.accessCount !== void 0 ? { accessCount: c.accessCount } : {}
41684
- });
41685
- const anyPenalty = adjusted.some((c) => c.orderingWeight < 1);
41686
- if (!anyPenalty) {
41687
- return adjusted.map(stamp);
41688
- }
41689
- const ordered = [...adjusted].sort((a, b) => {
41690
- if (b.score !== a.score)
41691
- return b.score - a.score;
41692
- return a.index - b.index;
41693
- });
41694
- return ordered.map(stamp);
41695
- }
41696
- function buildConfidenceFetchSql(ids) {
41697
- const tbl = sqlIdent("memories");
41698
- const idCol = sqlIdent("id");
41699
- const confCol = sqlIdent("confidence");
41700
- const inList = ids.map((id) => sLiteral(id)).join(", ");
41701
- return `SELECT ${idCol} AS id, ${confCol} AS confidence FROM "${tbl}" WHERE ${idCol} IN (${inList})`;
41702
- }
41703
- async function applyCalibrationStage(hits, model, request, deps) {
41704
- const memoryIds = hits.filter((h) => h.source === "memories" && h.id !== "").map((h) => h.id);
41705
- if (memoryIds.length === 0)
41706
- return [...hits];
41707
- let confById = /* @__PURE__ */ new Map();
41708
- try {
41709
- const rows = await runArm(buildConfidenceFetchSql(memoryIds), request, deps);
41710
- for (const row of rows) {
41711
- const id = cell(row.id);
41712
- if (id === "")
41713
- continue;
41714
- const f = typeof row.confidence === "number" ? row.confidence : Number(row.confidence);
41715
- if (Number.isFinite(f))
41716
- confById.set(id, f);
41717
- }
41718
- } catch {
41719
- return [...hits];
41720
- }
41721
- return hits.map((hit) => {
41722
- if (hit.source !== "memories")
41723
- return hit;
41724
- const f = confById.get(hit.id);
41725
- if (f === void 0)
41726
- return hit;
41727
- const c = applyCalibration(model, f);
41728
- return { ...hit, rawConfidence: f, calibratedConfidence: c };
41729
- });
41730
- }
41731
- async function recordRecallAccessEvents(hits, deps) {
41732
- const record2 = deps.recordRecallAccess;
41733
- if (record2 === void 0)
41734
- return;
41735
- const ids = hits.filter((h) => h.source === "memories" && h.id !== "").map((h) => h.id);
41736
- await Promise.all(ids.map(async (id) => {
41737
- try {
41738
- await record2(id);
41739
- } catch {
41740
- }
41741
- }));
41742
- }
41743
- var CHARS_PER_TOKEN3 = 4;
41744
- function estimateTokenCount(text) {
41745
- const trimmedLen = text.trim().length;
41746
- if (trimmedLen === 0)
41747
- return 1;
41748
- return Math.max(1, Math.ceil(trimmedLen / CHARS_PER_TOKEN3));
41749
- }
41750
- function selectWithinTokenBudget(hits, tokenBudget, lambda, embByKey) {
41751
- if (hits.length === 0)
41752
- return [];
41753
- const budget = Math.max(1, Math.trunc(tokenBudget));
41754
- const lam = Math.min(1, Math.max(0, lambda));
41755
- const pool = hits.map((hit) => ({
41756
- hit,
41757
- rel: hit.score,
41758
- cost: estimateTokenCount(hit.text),
41759
- vec: embByKey.get(fusionKey(hit.source, hit.id))
41760
- }));
41761
- const selected = [];
41762
- const remaining = new Set(pool);
41763
- const seed = pool[0];
41764
- selected.push(seed);
41765
- remaining.delete(seed);
41766
- let used = seed.cost;
41767
- while (remaining.size > 0) {
41768
- let best = null;
41769
- let bestMmr = -Infinity;
41770
- for (const cand of remaining) {
41771
- if (used + cand.cost > budget)
41772
- continue;
41773
- let maxSim = 0;
41774
- for (const s of selected) {
41775
- if (cand.vec === void 0 || s.vec === void 0)
41776
- continue;
41777
- const cos = cosineSimilarity(cand.vec, s.vec);
41778
- if (cos !== null && cos > maxSim)
41779
- maxSim = cos;
41780
- }
41781
- const mmr = lam * cand.rel - (1 - lam) * maxSim;
41782
- if (mmr > bestMmr) {
41783
- bestMmr = mmr;
41784
- best = cand;
41785
- }
41786
- }
41787
- if (best === null)
41788
- break;
41789
- selected.push(best);
41790
- remaining.delete(best);
41791
- used += best.cost;
41792
- }
41793
- return selected.map((s) => s.hit);
41794
- }
41795
- async function recallMemories(request, deps) {
41796
- const term = request.query.trim();
41797
- const limit = resolveRecallLimit(request.limit);
41798
- if (term === "") {
41799
- return { hits: [], sources: [], degraded: true };
41800
- }
41801
- const keywordOnly = deps.recallMode === "keyword";
41802
- const projectClause = projectConjunctFor(request);
41803
- const [semanticRun, memoriesRows, memoryRows, sessionsRows] = await Promise.all([
41804
- keywordOnly ? Promise.resolve(null) : runSemanticArms(request, deps, limit),
41805
- runArm(buildMemoriesArmSql(term, limit, projectClause), request, deps),
41806
- runArm(buildMemoryArmSql(term, limit, projectClause), request, deps),
41807
- runArm(buildSessionsArmSql(term, limit, projectClause), request, deps)
41808
- ]);
41809
- const degraded = keywordOnly ? false : semanticRun === null;
41810
- const arms = [
41811
- ...semanticRun?.arms ?? [],
41812
- rowsToRankedArm(memoriesRows),
41813
- rowsToRankedArm(memoryRows),
41814
- rowsToRankedArm(sessionsRows)
41815
- ];
41816
- const { hits, sources } = fuseHits(arms, limit);
41817
- const rerankerConfig = deps.reranker ?? { strategy: DEFAULT_RERANKER, timeoutMs: DEFAULT_RERANKER_TIMEOUT_MS, window: DEFAULT_RERANKER_WINDOW };
41818
- const ranked = semanticRun === null || rerankerConfig.strategy === "none" ? (
41819
- // No query vector to rerank against, or RRF-only requested → keep the fused order.
41820
- hits
41821
- ) : await rerankHits(hits, semanticRun.queryVector, rerankerConfig, request, deps);
41822
- const dedupConfig = deps.dedup ?? { enabled: DEFAULT_DEDUP_ENABLED, similarityThreshold: DEFAULT_DEDUP_SIMILARITY_THRESHOLD };
41823
- const deduped = await dedupHits(ranked, dedupConfig, request, deps);
41824
- const dedupedSources = deduped.length === ranked.length ? sources : [...new Set(deduped.map((h) => h.source))];
41825
- const byClass = deps.recency?.halfLifeDaysByClass;
41826
- const activationExponent = deps.recency?.activationExponent ?? DEFAULT_RECENCY_ACTIVATION_EXPONENT;
41827
- const nowMs = (deps.now ?? Date.now)();
41828
- const staleness = await resolveStaleness(deduped, deps, request.scope);
41829
- const activated = deps.activationSource !== void 0 ? await applyActrActivation(deduped, deps.activationSource, byClass, activationExponent, nowMs, request.scope, staleness) : applyRecencyActivation(deduped, byClass, activationExponent, nowMs, staleness);
41830
- const calibrated = deps.calibration !== void 0 ? await applyCalibrationStage(activated, deps.calibration, request, deps) : activated;
41831
- const dampened = await applyConflictGate(calibrated, deps, request.scope);
41832
- const budget = request.tokenBudget;
41833
- if (typeof budget !== "number" || !Number.isFinite(budget) || budget <= 0) {
41834
- await recordRecallAccessEvents(dampened, deps);
41835
- return { hits: dampened, sources: dedupedSources, degraded };
41836
- }
41837
- try {
41838
- const lambda = deps.contextAssembly?.mmrLambda ?? DEFAULT_MMR_LAMBDA;
41839
- const embByKey = await fetchCandidateEmbeddings(dampened, request, deps);
41840
- const assembled = selectWithinTokenBudget(dampened, budget, lambda, embByKey);
41841
- const assembledSources = assembled.length === dampened.length ? dedupedSources : [...new Set(assembled.map((h) => h.source))];
41842
- await recordRecallAccessEvents(assembled, deps);
41843
- return { hits: assembled, sources: assembledSources, degraded };
41844
- } catch {
41845
- await recordRecallAccessEvents(dampened, deps);
41846
- return { hits: dampened, sources: dedupedSources, degraded };
41847
- }
41848
- }
41849
-
41850
- // dist/src/daemon/runtime/secrets/api.js
41851
- var headerScopeResolver2 = {
41852
- resolve(c) {
41853
- const org = c.req.header("x-honeycomb-org");
41854
- if (org === void 0 || org.length === 0)
41855
- return null;
41856
- const workspace = c.req.header("x-honeycomb-workspace");
41857
- const agentId = c.req.header("x-honeycomb-agent");
41858
- const ws = workspace !== void 0 && workspace.length > 0 ? workspace : "default";
41859
- return agentId !== void 0 && agentId.length > 0 ? { org, workspace: ws, agentId } : { org, workspace: ws };
41860
- }
41861
- };
41862
- function mountSecretsApi(group, deps) {
41863
- const scope = deps.scope ?? headerScopeResolver2;
41864
- const store = deps.store;
41865
- const runner = deps.execRunner;
41866
- if (runner !== void 0) {
41867
- group.post("/exec", async (c) => {
41868
- const sc = scope.resolve(c);
41869
- if (sc === null)
41870
- return badTenancy(c);
41871
- const request = await readExecRequest(c, sc);
41872
- if (request === null) {
41873
- return c.json({ error: "bad_request", reason: "exec body must carry a command" }, 400);
41874
- }
41875
- const res = runner.submit(request);
41876
- if (!res.ok) {
41877
- if (res.reason === "queue_full") {
41878
- return c.json({ error: "queue_full", reason: "exec pool and queue are at capacity" }, 429);
41879
- }
41880
- return c.json({ error: "bad_request", reason: "invalid exec request" }, 400);
41881
- }
41882
- return c.json({ ok: true, jobId: res.jobId, status: "queued" }, 202);
41883
- });
41884
- group.get("/exec/:jobId", (c) => {
41885
- const sc = scope.resolve(c);
41886
- if (sc === null)
41887
- return badTenancy(c);
41888
- const jobId = c.req.param("jobId");
41889
- const view = runner.getStatus(jobId, sc);
41890
- if (view === null) {
41891
- return c.json({ error: "not_found", reason: "no such exec job" }, 404);
41892
- }
41893
- return c.json(view);
41894
- });
41895
- group.all("/bitwarden/*", (c) => c.json({ error: "use_exec", reason: "reference a Bitwarden item via exec vaultRefs; values are never returned" }, 400));
41896
- group.all("/1password/*", (c) => c.json({ error: "use_exec", reason: "reference a 1Password item via exec vaultRefs; values are never returned" }, 400));
41897
- } else {
41898
- group.post("/exec", (c) => notImplementedRoute(c, "POST /api/secrets/exec (secret_exec)"));
41899
- group.get("/exec/:jobId", (c) => notImplementedRoute(c, "GET /api/secrets/exec/:jobId (exec status)"));
41900
- group.all("/bitwarden/*", (c) => notImplementedRoute(c, "Bitwarden vault provider"));
41901
- group.all("/1password/*", (c) => notImplementedRoute(c, "1Password vault provider"));
41902
- }
41903
- group.get("/", (c) => {
41904
- const sc = scope.resolve(c);
41905
- if (sc === null)
41906
- return badTenancy(c);
41907
- const names = store.listSecretNames(sc);
41908
- return c.json({ names });
41909
- });
41910
- group.post("/:name", async (c) => {
41911
- const sc = scope.resolve(c);
41912
- if (sc === null)
41913
- return badTenancy(c);
41914
- const name = c.req.param("name");
41915
- const value = await readValue(c);
41916
- if (value === null) {
41917
- return c.json({ error: "bad_request", reason: "request body must carry a string value" }, 400);
41918
- }
41919
- const res = await store.setSecret(name, value, sc);
41920
- if (!res.ok) {
41921
- if (res.reason === "invalid_name") {
41922
- return c.json({ error: "bad_request", reason: "invalid secret name" }, 400);
41923
- }
41924
- return c.json({ error: "store_failed", reason: "could not store the secret" }, 502);
41925
- }
41926
- return c.json({ ok: true, name }, 201);
41927
- });
41928
- group.delete("/:name", (c) => {
41929
- const sc = scope.resolve(c);
41930
- if (sc === null)
41931
- return badTenancy(c);
41932
- const name = c.req.param("name");
41933
- const res = store.deleteSecret(name, sc);
41934
- if (!res.ok) {
41935
- if (res.reason === "invalid_name") {
41936
- return c.json({ error: "bad_request", reason: "invalid secret name" }, 400);
41937
- }
41938
- if (res.reason === "not_found") {
41939
- return c.json({ error: "not_found", reason: "no such secret" }, 404);
41940
- }
41941
- return c.json({ error: "delete_failed", reason: "could not delete the secret" }, 502);
41942
- }
41943
- return c.json({ ok: true, name });
41944
- });
41945
- }
41946
- function badTenancy(c) {
41947
- return c.json({ error: "bad_request", reason: "x-honeycomb-org header is required" }, 400);
41948
- }
41949
- async function readValue(c) {
41950
- const contentType = c.req.header("content-type") ?? "";
41951
- if (contentType.includes("application/json")) {
41952
- try {
41953
- const body = await c.req.json();
41954
- if (typeof body === "object" && body !== null) {
41955
- const v = body.value;
41956
- if (typeof v === "string" && v.length > 0)
41957
- return v;
41958
- }
41959
- return null;
41960
- } catch {
41961
- return null;
41962
- }
41963
- }
41964
- const text = await c.req.text();
41965
- return text.length > 0 ? text : null;
41966
- }
41967
- function notImplementedRoute(c, what) {
41968
- return c.json({ error: "not_implemented", reason: `${what} is implemented in PRD-012b` }, 501);
41969
- }
41970
- async function readExecRequest(c, scope) {
41971
- let body;
41972
- try {
41973
- body = await c.req.json();
41974
- } catch {
41975
- return null;
41976
- }
41977
- if (typeof body !== "object" || body === null)
41978
- return null;
41979
- const b = body;
41980
- const command = b.command;
41981
- if (typeof command !== "string" || command.length === 0)
41982
- return null;
41983
- const args = Array.isArray(b.args) ? b.args.filter((a) => typeof a === "string") : [];
41984
- const secretNames = Array.isArray(b.secretNames) ? b.secretNames.filter((n) => typeof n === "string") : [];
41985
- const vaultRefs = {};
41986
- if (typeof b.vaultRefs === "object" && b.vaultRefs !== null) {
41987
- for (const [k, v] of Object.entries(b.vaultRefs)) {
41988
- if (typeof v === "string")
41989
- vaultRefs[k] = v;
41990
- }
41991
- }
41992
- const timeoutMs = typeof b.timeoutMs === "number" ? b.timeoutMs : void 0;
41993
- return { command, args, secretNames, vaultRefs, scope, timeoutMs };
41994
- }
41995
-
41996
- // dist/src/daemon/runtime/vault/catalog.js
41997
- var PROVIDER_CATALOG = Object.freeze([
41998
- Object.freeze({
41999
- id: "anthropic",
42000
- label: "Anthropic",
42001
- models: Object.freeze(["claude-sonnet-4-6", "claude-opus-4-8"]),
42002
- openEnded: false
42003
- }),
42004
- Object.freeze({
42005
- id: "openai",
42006
- label: "OpenAI",
42007
- models: Object.freeze(["gpt-4o", "gpt-4o-mini", "gpt-4.1"]),
42008
- openEnded: false
42009
- }),
42010
- Object.freeze({
42011
- id: "openrouter",
42012
- label: "OpenRouter",
42013
- // Suggestions only — OpenRouter accepts a free-form `vendor/model` id (passthrough).
42014
- models: Object.freeze(["anthropic/claude-sonnet-4.6", "openai/gpt-4o"]),
42015
- openEnded: true
42016
- })
42017
- ]);
42018
- function providerEntry(provider) {
42019
- return PROVIDER_CATALOG.find((p) => p.id === provider);
42020
- }
42021
- function isValidProviderModel(provider, model) {
42022
- const entry = providerEntry(provider);
42023
- if (entry === void 0)
42024
- return false;
42025
- if (typeof model !== "string" || model.length === 0)
42026
- return false;
42027
- if (entry.openEnded)
42028
- return true;
42029
- return entry.models.includes(model);
42030
- }
42031
- function catalogView() {
42032
- return PROVIDER_CATALOG;
42033
- }
42034
-
42035
- // dist/src/daemon/runtime/secrets/contracts.js
42036
- import { homedir as homedir20, hostname as hostname4, userInfo } from "node:os";
42037
- var SECRET_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
42038
- var MAX_SECRET_NAME_LENGTH = 128;
42039
- function isValidSecretName(value) {
42040
- if (typeof value !== "string")
42041
- return false;
42042
- if (value.length === 0 || value.length > MAX_SECRET_NAME_LENGTH)
42043
- return false;
42044
- if (value === "." || value === "..")
42045
- return false;
42046
- if (value.includes("/") || value.includes("\\") || value.includes("\0"))
42047
- return false;
42048
- return SECRET_NAME_PATTERN.test(value);
42049
- }
42050
- function asSecretName(value) {
42051
- return isValidSecretName(value) ? value : null;
42052
- }
42053
- function isSecretRecord(value) {
42054
- if (typeof value !== "object" || value === null)
42055
- return false;
42056
- const r = value;
42057
- if (typeof r.nonce !== "string" || typeof r.ciphertext !== "string" || typeof r.createdAt !== "string") {
42058
- return false;
42059
- }
42060
- const scope = r.scope;
42061
- if (typeof scope !== "object" || scope === null)
42062
- return false;
42063
- const s = scope;
42064
- if (typeof s.org !== "string" || typeof s.workspace !== "string")
42065
- return false;
42066
- if (s.agentId !== void 0 && typeof s.agentId !== "string")
42067
- return false;
42068
- return true;
42069
- }
42070
- var MACHINE_KEY_DIR_NAME = ".honeycomb";
42071
- var MACHINE_KEY_FILE_NAME = ".machine-key";
42072
- function hostnameUserFallbackId() {
42073
- let user = "";
42074
- try {
42075
- user = userInfo().username;
42076
- } catch {
42077
- user = "";
42078
- }
42079
- return `host:${hostname4()}|user:${user}|home:${homedir20()}`;
42080
- }
42081
-
42082
- // dist/src/daemon/runtime/vault/contracts.js
42083
- function asRecordClass(value) {
42084
- return isValidSecretName(value) ? value : null;
42085
- }
42086
-
42087
- // dist/src/daemon/runtime/vault/registry.js
42088
- var SECRET_CLASS = "secret";
42089
- var SETTING_CLASS = "setting";
42090
- var SecretValueSchema = external_exports.string().min(1);
42091
- var SettingValueSchema = external_exports.union([external_exports.string(), external_exports.number().finite(), external_exports.boolean()]);
42092
- var SECRET_DESCRIPTOR = Object.freeze({
42093
- id: SECRET_CLASS,
42094
- posture: "internal-only",
42095
- schema: SecretValueSchema
42096
- });
42097
- var SETTING_DESCRIPTOR = Object.freeze({
42098
- id: SETTING_CLASS,
42099
- posture: "daemon-readable",
42100
- schema: SettingValueSchema
42101
- });
42102
- var VaultRegistry = class {
42103
- table;
42104
- constructor(descriptors) {
42105
- this.table = /* @__PURE__ */ new Map();
42106
- for (const d of descriptors)
42107
- this.table.set(d.id, d);
42108
- }
42109
- /**
42110
- * Register a new record class (D-7). Validates the id is traversal-proof (a class is an
42111
- * on-disk segment) and that the posture is one the store understands, then adds the
42112
- * descriptor. Re-registering an existing id REPLACES it (so a test can swap a throwaway
42113
- * class); registering the built-in `secret`/`setting` ids is allowed but discouraged —
42114
- * their posture must not be loosened. Returns the registry for chaining.
42115
- *
42116
- * Throws on an invalid (traversal-unsafe) class id — that is a programming error, not a
42117
- * runtime input, so it fails loud rather than silently dropping the class.
42118
- */
42119
- registerClass(descriptor) {
42120
- const safe = asRecordClass(descriptor.id);
42121
- if (safe === null) {
42122
- throw new Error(`vault.registerClass: invalid (traversal-unsafe) class id`);
42123
- }
42124
- this.table.set(descriptor.id, descriptor);
42125
- return this;
42126
- }
42127
- /** Whether a class id is registered. */
42128
- has(klass) {
42129
- return this.table.has(klass);
42130
- }
42131
- /** The registered class ids (sorted), for diagnostics — never values. */
42132
- classIds() {
42133
- return [...this.table.keys()].sort();
42134
- }
42135
- /**
42136
- * Resolve a class's descriptor for a WRITE, validating the value against the class
42137
- * schema (zod-at-boundary). Returns `unknown_class` for an unregistered class or
42138
- * `invalid_value` when the value fails the schema — both fail-closed (nothing is
42139
- * written). On success the descriptor (with the validated value available via the
42140
- * caller's re-parse) is returned.
42141
- */
42142
- resolveForWrite(klass, value) {
42143
- const descriptor = this.table.get(klass);
42144
- if (descriptor === void 0)
42145
- return { ok: false, reason: "unknown_class" };
42146
- const parsed = descriptor.schema.safeParse(value);
42147
- if (!parsed.success)
42148
- return { ok: false, reason: "invalid_value" };
42149
- return { ok: true, descriptor };
42150
- }
42151
- /**
42152
- * The POSTURE GATE (a-AC-2). Resolve a class's descriptor for a READ that intends to
42153
- * RETURN the value to a surface (the `getSetting` path). REJECTS a class whose posture
42154
- * is `internal-only` with `not_readable` — so a `secret` can NEVER be read back through
42155
- * the daemon-readable accessor. An unknown class is `unknown_class`. This is the single
42156
- * point where the secret-vs-setting security boundary is enforced, as data.
42157
- */
42158
- assertReadable(klass) {
42159
- const descriptor = this.table.get(klass);
42160
- if (descriptor === void 0)
42161
- return { ok: false, reason: "unknown_class" };
42162
- if (descriptor.posture !== "daemon-readable")
42163
- return { ok: false, reason: "not_readable" };
42164
- return { ok: true, descriptor };
42165
- }
42166
- /** Resolve a descriptor with no value/posture check (internal callers that already gate). */
42167
- descriptorOf(klass) {
42168
- return this.table.get(klass);
42169
- }
42170
- };
42171
- function createVaultRegistry(extra = []) {
42172
- return new VaultRegistry([SECRET_DESCRIPTOR, SETTING_DESCRIPTOR, ...extra]);
42173
- }
42174
-
42175
- // dist/src/daemon/runtime/vault/api.js
42176
- var SETTINGS_GROUP = "/api/settings";
42177
- var KNOWN_SETTING_KEYS = ["activeProvider", "activeModel", "pollinating.enabled", "recallMode"];
42178
- var RECALL_MODES = ["keyword", "semantic", "hybrid"];
42179
- function isValidRecallMode(value) {
42180
- return RECALL_MODES.includes(value);
42181
- }
42182
- var DASHBOARD_PREF_PREFIX = "dashboard.";
42183
- function isKnownSettingKey(key) {
42184
- if (KNOWN_SETTING_KEYS.includes(key))
42185
- return true;
42186
- return key.startsWith(DASHBOARD_PREF_PREFIX) && key.length > DASHBOARD_PREF_PREFIX.length;
42187
- }
42188
- function mountSettingsGroup(group, deps) {
42189
- const scope = deps.scope ?? headerScopeResolver2;
42190
- const store = deps.store;
42191
- group.get("/", async (c) => {
42192
- const sc = scope.resolve(c);
42193
- if (sc === null)
42194
- return badTenancy2(c);
42195
- const keys = store.listSettingKeys(sc);
42196
- const settings = {};
42197
- for (const key of keys) {
42198
- const res = await store.getSetting(key, sc);
42199
- if (res.ok)
42200
- settings[key] = res.value;
42201
- }
42202
- return c.json({ settings, catalog: catalogView() });
43377
+ if (b.score !== a.score)
43378
+ return b.score - a.score;
43379
+ return a.index - b.index;
42203
43380
  });
42204
- group.get("/:key", async (c) => {
42205
- const sc = scope.resolve(c);
42206
- if (sc === null)
42207
- return badTenancy2(c);
42208
- const key = c.req.param("key");
42209
- if (!isKnownSettingKey(key)) {
42210
- return c.json({ error: "not_found", reason: "no such setting" }, 404);
42211
- }
42212
- const res = await store.getSetting(key, sc);
42213
- if (!res.ok) {
42214
- if (res.reason === "not_found")
42215
- return c.json({ error: "not_found", reason: "no such setting" }, 404);
42216
- if (res.reason === "not_readable")
42217
- return c.json({ error: "not_found", reason: "no such setting" }, 404);
42218
- return c.json({ error: "read_failed", reason: "could not read the setting" }, 502);
43381
+ return activated.map(({ hit, activation, score, staleFields }) => ({ ...hit, ...staleFields, score, freshnessScore: activation }));
43382
+ }
43383
+ async function applyActrActivation(hits, source, byClass, activationExponent, nowMs, scope, staleness) {
43384
+ const exponent = Math.max(0, Number.isFinite(activationExponent) ? activationExponent : DEFAULT_RECENCY_ACTIVATION_EXPONENT);
43385
+ const params = source.params ?? DEFAULT_ACTR_PARAMS;
43386
+ let inputs;
43387
+ try {
43388
+ inputs = await source.load(hits, scope);
43389
+ } catch {
43390
+ return applyRecencyActivation(hits, byClass, activationExponent, nowMs, staleness);
43391
+ }
43392
+ const computed = hits.map((hit, index) => {
43393
+ const key = fusionKey(hit.source, hit.id);
43394
+ const input = inputs.get(key);
43395
+ if (input === void 0) {
43396
+ const halfLife = halfLifeForSource(hit.source, byClass);
43397
+ const lastReinforcedAt = hit.lastReinforcedAt;
43398
+ const a2 = recencyActivation(refTimestampMs(hit.createdAt, lastReinforcedAt), nowMs, halfLife);
43399
+ return { hit, index, activation: a2, accessCount: void 0 };
42219
43400
  }
42220
- return c.json({ key, value: res.value });
43401
+ const a = actrActivation(input.history, nowMs, params);
43402
+ return { hit, index, activation: a, accessCount: input.accessCount };
42221
43403
  });
42222
- group.post("/:key", async (c) => {
42223
- const sc = scope.resolve(c);
42224
- if (sc === null)
42225
- return badTenancy2(c);
42226
- const key = c.req.param("key");
42227
- if (!isKnownSettingKey(key)) {
42228
- return c.json({ error: "bad_request", reason: "unknown setting key" }, 400);
42229
- }
42230
- const value = await readSettingValue(c);
42231
- if (value === null) {
42232
- return c.json({ error: "bad_request", reason: "request body must carry a scalar value" }, 400);
42233
- }
42234
- const semanticError = await validateSettingSemantics(store, sc, key, value);
42235
- if (semanticError !== null) {
42236
- return c.json({ error: "bad_request", reason: semanticError }, 400);
42237
- }
42238
- const res = await store.setSetting(key, value, sc);
42239
- if (!res.ok) {
42240
- if (res.reason === "invalid_value") {
42241
- return c.json({ error: "bad_request", reason: "invalid setting value" }, 400);
42242
- }
42243
- if (res.reason === "not_readable" || res.reason === "unknown_class") {
42244
- return c.json({ error: "bad_request", reason: "setting class is not writable" }, 400);
42245
- }
42246
- return c.json({ error: "store_failed", reason: "could not store the setting" }, 502);
43404
+ const adjusted = computed.map((c) => {
43405
+ const stale = stalenessContribution(c.hit, staleness);
43406
+ const orderingWeight = (exponent === 1 ? c.activation : Math.pow(c.activation, exponent)) * stale.factor;
43407
+ return { ...c, staleFields: stale.fields, orderingWeight, score: c.hit.score * orderingWeight };
43408
+ });
43409
+ const stamp = (c) => ({
43410
+ ...c.hit,
43411
+ ...c.staleFields,
43412
+ score: c.score,
43413
+ freshnessScore: c.activation,
43414
+ // the swap: A_actr behind the SAME field 058a used (PRD-058e).
43415
+ activation: c.activation,
43416
+ ...c.accessCount !== void 0 ? { accessCount: c.accessCount } : {}
43417
+ });
43418
+ const anyPenalty = adjusted.some((c) => c.orderingWeight < 1);
43419
+ if (!anyPenalty) {
43420
+ return adjusted.map(stamp);
43421
+ }
43422
+ const ordered = [...adjusted].sort((a, b) => {
43423
+ if (b.score !== a.score)
43424
+ return b.score - a.score;
43425
+ return a.index - b.index;
43426
+ });
43427
+ return ordered.map(stamp);
43428
+ }
43429
+ function buildConfidenceFetchSql(ids) {
43430
+ const tbl = sqlIdent("memories");
43431
+ const idCol = sqlIdent("id");
43432
+ const confCol = sqlIdent("confidence");
43433
+ const inList = ids.map((id) => sLiteral(id)).join(", ");
43434
+ return `SELECT ${idCol} AS id, ${confCol} AS confidence FROM "${tbl}" WHERE ${idCol} IN (${inList})`;
43435
+ }
43436
+ async function applyCalibrationStage(hits, model, request, deps) {
43437
+ const memoryIds = hits.filter((h) => h.source === "memories" && h.id !== "").map((h) => h.id);
43438
+ if (memoryIds.length === 0)
43439
+ return [...hits];
43440
+ let confById = /* @__PURE__ */ new Map();
43441
+ try {
43442
+ const rows = await runArm(buildConfidenceFetchSql(memoryIds), request, deps);
43443
+ for (const row of rows) {
43444
+ const id = cell(row.id);
43445
+ if (id === "")
43446
+ continue;
43447
+ const f = typeof row.confidence === "number" ? row.confidence : Number(row.confidence);
43448
+ if (Number.isFinite(f))
43449
+ confById.set(id, f);
42247
43450
  }
42248
- return c.json({ ok: true, key, value }, 201);
43451
+ } catch {
43452
+ return [...hits];
43453
+ }
43454
+ return hits.map((hit) => {
43455
+ if (hit.source !== "memories")
43456
+ return hit;
43457
+ const f = confById.get(hit.id);
43458
+ if (f === void 0)
43459
+ return hit;
43460
+ const c = applyCalibration(model, f);
43461
+ return { ...hit, rawConfidence: f, calibratedConfidence: c };
42249
43462
  });
42250
43463
  }
42251
- function mountSettingsApi(daemon, deps) {
42252
- const group = daemon.group(SETTINGS_GROUP);
42253
- if (group === void 0)
43464
+ async function recordRecallAccessEvents(hits, deps) {
43465
+ const record2 = deps.recordRecallAccess;
43466
+ if (record2 === void 0)
42254
43467
  return;
42255
- mountSettingsGroup(group, deps);
43468
+ const ids = hits.filter((h) => h.source === "memories" && h.id !== "").map((h) => h.id);
43469
+ await Promise.all(ids.map(async (id) => {
43470
+ try {
43471
+ await record2(id);
43472
+ } catch {
43473
+ }
43474
+ }));
42256
43475
  }
42257
- function badTenancy2(c) {
42258
- return c.json({ error: "bad_request", reason: "x-honeycomb-org header is required" }, 400);
43476
+ var CHARS_PER_TOKEN3 = 4;
43477
+ function estimateTokenCount(text) {
43478
+ const trimmedLen = text.trim().length;
43479
+ if (trimmedLen === 0)
43480
+ return 1;
43481
+ return Math.max(1, Math.ceil(trimmedLen / CHARS_PER_TOKEN3));
42259
43482
  }
42260
- async function readSettingValue(c) {
42261
- const contentType = c.req.header("content-type") ?? "";
42262
- if (contentType.includes("application/json")) {
42263
- try {
42264
- const body = await c.req.json();
42265
- if (typeof body === "object" && body !== null) {
42266
- const v = body.value;
42267
- const parsed = SettingValueSchema.safeParse(v);
42268
- return parsed.success ? parsed.data : null;
43483
+ function selectWithinTokenBudget(hits, tokenBudget, lambda, embByKey) {
43484
+ if (hits.length === 0)
43485
+ return [];
43486
+ const budget = Math.max(1, Math.trunc(tokenBudget));
43487
+ const lam = Math.min(1, Math.max(0, lambda));
43488
+ const pool = hits.map((hit) => ({
43489
+ hit,
43490
+ rel: hit.score,
43491
+ cost: estimateTokenCount(hit.text),
43492
+ vec: embByKey.get(fusionKey(hit.source, hit.id))
43493
+ }));
43494
+ const selected = [];
43495
+ const remaining = new Set(pool);
43496
+ const seed = pool[0];
43497
+ selected.push(seed);
43498
+ remaining.delete(seed);
43499
+ let used = seed.cost;
43500
+ while (remaining.size > 0) {
43501
+ let best = null;
43502
+ let bestMmr = -Infinity;
43503
+ for (const cand of remaining) {
43504
+ if (used + cand.cost > budget)
43505
+ continue;
43506
+ let maxSim = 0;
43507
+ for (const s of selected) {
43508
+ if (cand.vec === void 0 || s.vec === void 0)
43509
+ continue;
43510
+ const cos = cosineSimilarity(cand.vec, s.vec);
43511
+ if (cos !== null && cos > maxSim)
43512
+ maxSim = cos;
43513
+ }
43514
+ const mmr = lam * cand.rel - (1 - lam) * maxSim;
43515
+ if (mmr > bestMmr) {
43516
+ bestMmr = mmr;
43517
+ best = cand;
42269
43518
  }
42270
- return null;
42271
- } catch {
42272
- return null;
42273
43519
  }
43520
+ if (best === null)
43521
+ break;
43522
+ selected.push(best);
43523
+ remaining.delete(best);
43524
+ used += best.cost;
42274
43525
  }
42275
- const text = await c.req.text();
42276
- return text.length > 0 ? text : null;
43526
+ return selected.map((s) => s.hit);
42277
43527
  }
42278
- async function validateSettingSemantics(store, scope, key, value) {
42279
- if (key === "activeProvider") {
42280
- if (providerEntry(String(value)) === void 0)
42281
- return "unknown provider";
42282
- return null;
43528
+ async function recallMemories(request, deps) {
43529
+ const term = request.query.trim();
43530
+ const limit = resolveRecallLimit(request.limit);
43531
+ if (term === "") {
43532
+ return { hits: [], sources: [], degraded: true };
42283
43533
  }
42284
- if (key === "activeModel") {
42285
- const provRes = await store.getSetting("activeProvider", scope);
42286
- const provider = provRes.ok ? String(provRes.value) : "";
42287
- if (provider.length === 0)
42288
- return "set activeProvider before activeModel";
42289
- if (!isValidProviderModel(provider, String(value)))
42290
- return "model not in provider catalog";
42291
- return null;
43534
+ const keywordOnly = deps.recallMode === "keyword";
43535
+ const projectClause = projectConjunctFor(request);
43536
+ const [semanticRun, memoriesRows, memoryRows, sessionsRows] = await Promise.all([
43537
+ keywordOnly ? Promise.resolve(null) : runSemanticArms(request, deps, limit),
43538
+ runArm(buildMemoriesArmSql(term, limit, projectClause), request, deps),
43539
+ runArm(buildMemoryArmSql(term, limit, projectClause), request, deps),
43540
+ runArm(buildSessionsArmSql(term, limit, projectClause), request, deps)
43541
+ ]);
43542
+ const degraded = keywordOnly ? false : semanticRun === null;
43543
+ const arms = [
43544
+ ...semanticRun?.arms ?? [],
43545
+ rowsToRankedArm(memoriesRows),
43546
+ rowsToRankedArm(memoryRows),
43547
+ rowsToRankedArm(sessionsRows)
43548
+ ];
43549
+ const { hits, sources } = fuseHits(arms, limit);
43550
+ const rerankerConfig = deps.reranker ?? {
43551
+ strategy: DEFAULT_RERANKER,
43552
+ timeoutMs: DEFAULT_RERANKER_TIMEOUT_MS,
43553
+ providerTimeoutMs: DEFAULT_RERANKER_PROVIDER_TIMEOUT_MS,
43554
+ window: DEFAULT_RERANKER_WINDOW,
43555
+ cohereModel: DEFAULT_RERANKER_COHERE_MODEL
43556
+ };
43557
+ const skipRerank = rerankerConfig.strategy === "none" || rerankerConfig.strategy !== "cohere" && semanticRun === null;
43558
+ const ranked = skipRerank ? hits : await rerankHits(hits, semanticRun?.queryVector ?? null, rerankerConfig, request, deps);
43559
+ const dedupConfig = deps.dedup ?? { enabled: DEFAULT_DEDUP_ENABLED, similarityThreshold: DEFAULT_DEDUP_SIMILARITY_THRESHOLD };
43560
+ const deduped = await dedupHits(ranked, dedupConfig, request, deps);
43561
+ const dedupedSources = deduped.length === ranked.length ? sources : [...new Set(deduped.map((h) => h.source))];
43562
+ const byClass = deps.recency?.halfLifeDaysByClass;
43563
+ const activationExponent = deps.recency?.activationExponent ?? DEFAULT_RECENCY_ACTIVATION_EXPONENT;
43564
+ const nowMs = (deps.now ?? Date.now)();
43565
+ const staleness = await resolveStaleness(deduped, deps, request.scope);
43566
+ const activated = deps.activationSource !== void 0 ? await applyActrActivation(deduped, deps.activationSource, byClass, activationExponent, nowMs, request.scope, staleness) : applyRecencyActivation(deduped, byClass, activationExponent, nowMs, staleness);
43567
+ const calibrated = deps.calibration !== void 0 ? await applyCalibrationStage(activated, deps.calibration, request, deps) : activated;
43568
+ const dampened = await applyConflictGate(calibrated, deps, request.scope);
43569
+ const budget = request.tokenBudget;
43570
+ if (typeof budget !== "number" || !Number.isFinite(budget) || budget <= 0) {
43571
+ await recordRecallAccessEvents(dampened, deps);
43572
+ return { hits: dampened, sources: dedupedSources, degraded };
42292
43573
  }
42293
- if (key === "recallMode") {
42294
- if (!isValidRecallMode(String(value)))
42295
- return "recallMode must be keyword, semantic, or hybrid";
42296
- return null;
43574
+ try {
43575
+ const lambda = deps.contextAssembly?.mmrLambda ?? DEFAULT_MMR_LAMBDA;
43576
+ const embByKey = await fetchCandidateEmbeddings(dampened, request, deps);
43577
+ const assembled = selectWithinTokenBudget(dampened, budget, lambda, embByKey);
43578
+ const assembledSources = assembled.length === dampened.length ? dedupedSources : [...new Set(assembled.map((h) => h.source))];
43579
+ await recordRecallAccessEvents(assembled, deps);
43580
+ return { hits: assembled, sources: assembledSources, degraded };
43581
+ } catch {
43582
+ await recordRecallAccessEvents(dampened, deps);
43583
+ return { hits: dampened, sources: dedupedSources, degraded };
42297
43584
  }
42298
- return null;
42299
43585
  }
42300
43586
 
42301
43587
  // dist/src/daemon/runtime/memories/calibration-store.js
@@ -43335,7 +44621,13 @@ function mountMemoriesApi(daemon, options) {
43335
44621
  // PRD-058a: the per-request recency override (per-class half-lives + activation exponent).
43336
44622
  ...recency !== void 0 ? { recency } : {},
43337
44623
  // PRD-058b: the κ gate's conflict-suppression seam (drops the κ = ρ open-conflict loser).
43338
- ...options.conflictSuppression !== void 0 ? { conflictSuppression: options.conflictSuppression } : {}
44624
+ ...options.conflictSuppression !== void 0 ? { conflictSuppression: options.conflictSuppression } : {},
44625
+ // PRD-063c: the operator-selected reranker config + the Cohere-via-Portkey seam. The
44626
+ // `cohere` strategy activates ONLY when BOTH are present (the strategy is `cohere` AND the
44627
+ // gateway-on seam is wired); otherwise the engine keeps the RRF order / runs the local
44628
+ // cosine path — byte-identical to today (c-AC-4).
44629
+ ...options.reranker !== void 0 ? { reranker: options.reranker } : {},
44630
+ ...options.cohereRerank !== void 0 ? { cohereRerank: options.cohereRerank } : {}
43339
44631
  });
43340
44632
  logDegradedRecall(options.logger, result);
43341
44633
  logProjectScopeDegraded(options.logger, project);
@@ -44803,7 +46095,7 @@ var DISCOVERY_POLLS = 20;
44803
46095
  var DISCOVERY_POLL_DELAY_MS = 400;
44804
46096
  var DISCOVERY_STABLE_BREAK = 4;
44805
46097
  function sleep(ms) {
44806
- return new Promise((resolve6) => setTimeout(resolve6, ms));
46098
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
44807
46099
  }
44808
46100
  function nowIso7() {
44809
46101
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -46041,7 +47333,7 @@ function guardedLookup(allowLoopback) {
46041
47333
  }
46042
47334
  function requestOnce(url2, timeoutMs, maxBytes, allowLoopback) {
46043
47335
  const requestFn = url2.protocol === "https:" ? httpsRequest : httpRequest;
46044
- return new Promise((resolve6, reject) => {
47336
+ return new Promise((resolve7, reject) => {
46045
47337
  const req = requestFn(url2, {
46046
47338
  method: "GET",
46047
47339
  headers: { "user-agent": USER_AGENT, accept: "*/*" },
@@ -46068,7 +47360,7 @@ function requestOnce(url2, timeoutMs, maxBytes, allowLoopback) {
46068
47360
  if (aborted2)
46069
47361
  return;
46070
47362
  const location = res.headers.location;
46071
- resolve6({
47363
+ resolve7({
46072
47364
  status: res.statusCode ?? 0,
46073
47365
  location: typeof location === "string" ? location : void 0,
46074
47366
  contentType: typeof res.headers["content-type"] === "string" ? res.headers["content-type"] : "",
@@ -47242,7 +48534,7 @@ function buildSourcesApiDeps(options) {
47242
48534
  // dist/src/daemon/runtime/secrets/store.js
47243
48535
  import { execFileSync as execFileSync6 } from "node:child_process";
47244
48536
  import { randomBytes as randomBytes5 } from "node:crypto";
47245
- import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync16, readdirSync as readdirSync4, readFileSync as readFileSync18, rmSync as rmSync7, statSync as statSync3, writeFileSync as writeFileSync13 } from "node:fs";
48537
+ import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync16, readdirSync as readdirSync4, readFileSync as readFileSync18, rmSync as rmSync8, statSync as statSync3, writeFileSync as writeFileSync13 } from "node:fs";
47246
48538
  import { homedir as homedir21 } from "node:os";
47247
48539
  import { join as join27 } from "node:path";
47248
48540
 
@@ -48114,7 +49406,7 @@ var SecretsStore = class {
48114
49406
  return { ok: false, reason: "not_found" };
48115
49407
  }
48116
49408
  try {
48117
- rmSync7(file2);
49409
+ rmSync8(file2);
48118
49410
  this.audit("deleted", scope, "ok", safe);
48119
49411
  return { ok: true };
48120
49412
  } catch {
@@ -48235,7 +49527,7 @@ function stripRefWrapper(ref) {
48235
49527
  }
48236
49528
 
48237
49529
  // dist/src/daemon/runtime/vault/store.js
48238
- import { appendFileSync as appendFileSync2, existsSync as existsSync19, mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as readFileSync19, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "node:fs";
49530
+ import { appendFileSync as appendFileSync2, existsSync as existsSync19, mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as readFileSync19, rmSync as rmSync9, writeFileSync as writeFileSync14 } from "node:fs";
48239
49531
  import { join as join28 } from "node:path";
48240
49532
  var VAULT_DIR_NAME = ".vault";
48241
49533
  var VAULT_AUDIT_FILE_NAME = "vault-audit.ndjson";
@@ -48409,7 +49701,7 @@ var VaultStore = class {
48409
49701
  return { ok: false, reason: "not_found" };
48410
49702
  }
48411
49703
  try {
48412
- rmSync8(file2);
49704
+ rmSync9(file2);
48413
49705
  this.audit(safeClass, "deleted", scope, "ok", safe);
48414
49706
  return { ok: true };
48415
49707
  } catch {
@@ -49344,12 +50636,64 @@ var RouterModelClient = class {
49344
50636
  var ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
49345
50637
  var ANTHROPIC_VERSION = "2023-06-01";
49346
50638
  var DEFAULT_MAX_TOKENS = 4096;
50639
+ var noopUsageSink = {
50640
+ record() {
50641
+ }
50642
+ };
50643
+ function usageReportingTransport(post, usageSink) {
50644
+ function reportUsage(usage) {
50645
+ try {
50646
+ usageSink.record(usage);
50647
+ } catch {
50648
+ }
50649
+ }
50650
+ return {
50651
+ async execute(call) {
50652
+ const { output, usage } = await post(call);
50653
+ reportUsage(usage);
50654
+ return { output };
50655
+ },
50656
+ stream(call) {
50657
+ async function* gen() {
50658
+ const { output, usage } = await post(call);
50659
+ reportUsage(usage);
50660
+ yield { delta: output };
50661
+ }
50662
+ return gen();
50663
+ }
50664
+ };
50665
+ }
50666
+ function safeJsonParse(text) {
50667
+ try {
50668
+ return JSON.parse(text);
50669
+ } catch {
50670
+ return void 0;
50671
+ }
50672
+ }
49347
50673
  var AnthropicContentBlockSchema = external_exports.object({
49348
50674
  type: external_exports.string(),
49349
50675
  text: external_exports.string().optional()
49350
50676
  });
50677
+ var AnthropicUsageSchema = external_exports.object({
50678
+ input_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
50679
+ output_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
50680
+ cache_read_input_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
50681
+ cache_creation_input_tokens: external_exports.number().int().nonnegative().catch(0).default(0)
50682
+ });
50683
+ var ZERO_USAGE = {
50684
+ input_tokens: 0,
50685
+ output_tokens: 0,
50686
+ cache_read_input_tokens: 0,
50687
+ cache_creation_input_tokens: 0
50688
+ };
49351
50689
  var AnthropicMessagesResponseSchema = external_exports.object({
49352
- content: external_exports.array(AnthropicContentBlockSchema).default([])
50690
+ content: external_exports.array(AnthropicContentBlockSchema).default([]),
50691
+ // Finding (usage-failsoft): `.default(ZERO_USAGE)` only covers `usage === undefined`. A response with
50692
+ // `usage: null` or a malformed `usage` object would FAIL the object parse and -- because this field is
50693
+ // part of the whole-response schema -- bubble up to a 502 that DROPS an otherwise-valid completion.
50694
+ // `.catch(ZERO_USAGE)` makes ANY invalid value (null, a string, a malformed object) fall back to
50695
+ // zero-usage so a valid completion is NEVER dropped over its (side-channel) usage block.
50696
+ usage: AnthropicUsageSchema.default(ZERO_USAGE).catch(ZERO_USAGE)
49353
50697
  });
49354
50698
  function toAnthropicBody(call, defaultMaxTokens) {
49355
50699
  const systemParts = [];
@@ -49377,6 +50721,7 @@ function createAnthropicTransport(deps = {}) {
49377
50721
  const doFetch = deps.fetch ?? globalThis.fetch;
49378
50722
  const url2 = deps.baseUrl ?? ANTHROPIC_MESSAGES_URL;
49379
50723
  const defaultMaxTokens = deps.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
50724
+ const usageSink = deps.usageSink ?? noopUsageSink;
49380
50725
  async function post(call) {
49381
50726
  const body = toAnthropicBody(call, defaultMaxTokens);
49382
50727
  let res;
@@ -49397,36 +50742,130 @@ function createAnthropicTransport(deps = {}) {
49397
50742
  if (!res.ok) {
49398
50743
  throw new ProviderError(res.status, `anthropic transport: provider returned status ${res.status}`);
49399
50744
  }
49400
- const raw2 = await res.text().then((t) => safeJson2(t));
50745
+ const raw2 = await res.text().then((t) => safeJsonParse(t));
49401
50746
  const parsed = AnthropicMessagesResponseSchema.safeParse(raw2);
49402
50747
  if (!parsed.success) {
49403
50748
  throw new ProviderError(502, "anthropic transport: malformed provider response");
49404
50749
  }
49405
- return joinContentText(parsed.data.content);
50750
+ const u = parsed.data.usage;
50751
+ const usage = {
50752
+ model: call.target.model,
50753
+ workload: call.request.workload,
50754
+ inputTokens: u.input_tokens,
50755
+ outputTokens: u.output_tokens,
50756
+ cacheReadInputTokens: u.cache_read_input_tokens,
50757
+ cacheCreationInputTokens: u.cache_creation_input_tokens
50758
+ };
50759
+ return { output: joinContentText(parsed.data.content), usage };
49406
50760
  }
50761
+ return usageReportingTransport(post, usageSink);
50762
+ }
50763
+
50764
+ // dist/src/daemon/runtime/inference/transport-portkey.js
50765
+ var PORTKEY_BASE_URL = "https://api.portkey.ai/v1";
50766
+ var PORTKEY_CHAT_COMPLETIONS_URL = `${PORTKEY_BASE_URL}/chat/completions`;
50767
+ var PORTKEY_RERANK_URL = `${PORTKEY_BASE_URL}/rerank`;
50768
+ var PORTKEY_API_KEY_HEADER = "x-portkey-api-key";
50769
+ var PORTKEY_CONFIG_HEADER = "x-portkey-config";
50770
+ function buildPortkeyHeaders(apiKey, configId) {
49407
50771
  return {
49408
- async execute(call) {
49409
- const output = await post(call);
49410
- return { output };
49411
- },
49412
- stream(call) {
49413
- async function* gen() {
49414
- const output = await post(call);
49415
- yield { delta: output };
49416
- }
49417
- return gen();
49418
- }
50772
+ [PORTKEY_API_KEY_HEADER]: apiKey,
50773
+ [PORTKEY_CONFIG_HEADER]: configId,
50774
+ "content-type": "application/json"
49419
50775
  };
49420
50776
  }
49421
- function safeJson2(text) {
49422
- try {
49423
- return JSON.parse(text);
49424
- } catch {
49425
- return void 0;
50777
+ var PORTKEY_DEFAULT_MAX_TOKENS = 4096;
50778
+ var PortkeyChoiceSchema = external_exports.object({
50779
+ message: external_exports.object({ content: external_exports.string().nullable().optional() }).optional()
50780
+ });
50781
+ var PortkeyUsageSchema = external_exports.object({
50782
+ prompt_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
50783
+ completion_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
50784
+ prompt_tokens_details: external_exports.object({ cached_tokens: external_exports.number().int().nonnegative().catch(0).default(0) }).partial().optional()
50785
+ });
50786
+ var ZERO_PORTKEY_USAGE = { prompt_tokens: 0, completion_tokens: 0 };
50787
+ var PortkeyChatResponseSchema = external_exports.object({
50788
+ choices: external_exports.array(PortkeyChoiceSchema).default([]),
50789
+ // As with the Anthropic transport's usage block: `.catch()` so ANY invalid `usage` value
50790
+ // (null, a string, a malformed object) falls back to zero-usage and a VALID completion is
50791
+ // never dropped over its (side-channel) usage block.
50792
+ usage: PortkeyUsageSchema.default(ZERO_PORTKEY_USAGE).catch(ZERO_PORTKEY_USAGE)
50793
+ });
50794
+ function toPortkeyBody(call, defaultMaxTokens) {
50795
+ return {
50796
+ model: call.target.model,
50797
+ max_tokens: call.request.maxTokens ?? defaultMaxTokens,
50798
+ messages: call.request.messages.map((m) => ({ role: m.role, content: m.content }))
50799
+ };
50800
+ }
50801
+ function joinChoiceText(choices) {
50802
+ return choices.map((c) => c.message?.content).filter((t) => typeof t === "string").join("");
50803
+ }
50804
+ function createPortkeyTransport(deps) {
50805
+ const doFetch = deps.fetch ?? globalThis.fetch;
50806
+ const url2 = deps.baseUrl ?? PORTKEY_CHAT_COMPLETIONS_URL;
50807
+ const defaultMaxTokens = deps.defaultMaxTokens ?? PORTKEY_DEFAULT_MAX_TOKENS;
50808
+ const usageSink = deps.usageSink ?? noopUsageSink;
50809
+ const configId = deps.config;
50810
+ const onTransportError = deps.onTransportError;
50811
+ function reportTransportError(statusCode) {
50812
+ if (onTransportError === void 0)
50813
+ return;
50814
+ try {
50815
+ onTransportError(statusCode);
50816
+ } catch {
50817
+ }
50818
+ }
50819
+ async function post(call) {
50820
+ const body = toPortkeyBody(call, defaultMaxTokens);
50821
+ let res;
50822
+ try {
50823
+ res = await doFetch(url2, {
50824
+ method: "POST",
50825
+ headers: buildPortkeyHeaders(call.apiKey, configId),
50826
+ body: JSON.stringify(body)
50827
+ });
50828
+ } catch (err) {
50829
+ reportTransportError(503);
50830
+ const detail = err instanceof Error ? err.name : "network error";
50831
+ throw new ProviderError(503, `portkey transport: request failed (${detail})`);
50832
+ }
50833
+ if (!res.ok) {
50834
+ reportTransportError(res.status);
50835
+ throw new ProviderError(res.status, `portkey transport: gateway returned status ${res.status}`);
50836
+ }
50837
+ const raw2 = await res.text().then((t) => safeJsonParse(t));
50838
+ const parsed = PortkeyChatResponseSchema.safeParse(raw2);
50839
+ if (!parsed.success) {
50840
+ throw new ProviderError(502, "portkey transport: malformed gateway response");
50841
+ }
50842
+ const u = parsed.data.usage;
50843
+ const usage = {
50844
+ model: call.target.model,
50845
+ workload: call.request.workload,
50846
+ inputTokens: u.prompt_tokens,
50847
+ outputTokens: u.completion_tokens,
50848
+ cacheReadInputTokens: u.prompt_tokens_details?.cached_tokens ?? 0,
50849
+ // Portkey's OpenAI-shaped usage has no cache-WRITE field; surface 0 (never fabricate).
50850
+ cacheCreationInputTokens: 0
50851
+ };
50852
+ return { output: joinChoiceText(parsed.data.choices), usage };
49426
50853
  }
50854
+ return usageReportingTransport(post, usageSink);
49427
50855
  }
49428
50856
 
49429
50857
  // dist/src/daemon/runtime/inference/model-client-factory.js
50858
+ var PORTKEY_API_KEY_REF = "${PORTKEY_API_KEY}";
50859
+ var PORTKEY_API_KEY_NAME = "PORTKEY_API_KEY";
50860
+ var PORTKEY_ACCOUNT_ID = "portkey-gateway";
50861
+ var PORTKEY_TARGET_ID = "portkey-target";
50862
+ var PORTKEY_POLICY_ID = "portkey-default";
50863
+ var PortkeyUnconfiguredError = class extends Error {
50864
+ constructor() {
50865
+ super("portkey: enabled but PORTKEY_API_KEY is not set (fail-closed; set the key or disable portkey.enabled)");
50866
+ this.name = "PortkeyUnconfiguredError";
50867
+ }
50868
+ };
49430
50869
  async function resolveConfig3(source) {
49431
50870
  if (typeof source === "string") {
49432
50871
  return loadInferenceConfigFromYaml(source);
@@ -49444,7 +50883,7 @@ function applyProviderModelOverride(config2, override) {
49444
50883
  workloads: config2.workloads
49445
50884
  };
49446
50885
  }
49447
- async function buildInferenceModelClient(deps) {
50886
+ async function buildProviderPathClient(deps) {
49448
50887
  let config2;
49449
50888
  try {
49450
50889
  config2 = await resolveConfig3(deps.config);
@@ -49456,7 +50895,7 @@ async function buildInferenceModelClient(deps) {
49456
50895
  }
49457
50896
  const effectiveConfig = deps.providerModelOverride !== void 0 ? applyProviderModelOverride(config2, deps.providerModelOverride) : config2;
49458
50897
  const secrets = createSecretResolver(deps.secretsStore, deps.scope);
49459
- const transport = createAnthropicTransport();
50898
+ const transport = createAnthropicTransport(deps.usageSink !== void 0 ? { usageSink: deps.usageSink } : {});
49460
50899
  const router = createInferenceRouter({
49461
50900
  config: effectiveConfig,
49462
50901
  transport,
@@ -49465,6 +50904,161 @@ async function buildInferenceModelClient(deps) {
49465
50904
  });
49466
50905
  return new RouterModelClient(router);
49467
50906
  }
50907
+ async function buildInferenceModelClient(deps) {
50908
+ const { client } = await buildInferenceModelClientWithStatus(deps);
50909
+ return client;
50910
+ }
50911
+ async function buildInferenceModelClientWithStatus(deps) {
50912
+ const portkey = deps.portkey;
50913
+ if (portkey === void 0 || !portkey.enabled) {
50914
+ return { client: await buildProviderPathClient(deps), portkeyStatus: "off" };
50915
+ }
50916
+ try {
50917
+ const client = await resolvePortkeyClient(deps, portkey);
50918
+ return { client, portkeyStatus: "ok" };
50919
+ } catch (err) {
50920
+ if (err instanceof PortkeyUnconfiguredError) {
50921
+ return { client: noopModelClient, portkeyStatus: "unconfigured" };
50922
+ }
50923
+ return { client: noopModelClient, portkeyStatus: "unconfigured" };
50924
+ }
50925
+ }
50926
+ async function resolvePortkeyClient(deps, portkey) {
50927
+ const names = deps.secretsStore.listSecretNames(deps.scope);
50928
+ if (!names.includes(PORTKEY_API_KEY_NAME)) {
50929
+ throw new PortkeyUnconfiguredError();
50930
+ }
50931
+ const secrets = createSecretResolver(deps.secretsStore, deps.scope);
50932
+ const transport = createPortkeyTransport({
50933
+ config: portkey.config,
50934
+ ...deps.usageSink !== void 0 ? { usageSink: deps.usageSink } : {},
50935
+ ...deps.onPortkeyUnreachable !== void 0 ? { onTransportError: deps.onPortkeyUnreachable } : {}
50936
+ });
50937
+ const router = createInferenceRouter({
50938
+ config: buildPortkeyConfig(portkey.model),
50939
+ transport,
50940
+ secrets,
50941
+ history: deps.history ?? noopRoutingHistoryStore
50942
+ });
50943
+ const portkeyClient = new RouterModelClient(router);
50944
+ if (!portkey.fallbackToProvider) {
50945
+ return portkeyClient;
50946
+ }
50947
+ const providerClient = await buildProviderPathClient(deps);
50948
+ return new PortkeyFallbackModelClient(portkeyClient, providerClient);
50949
+ }
50950
+ function buildPortkeyConfig(model) {
50951
+ return {
50952
+ accounts: [{ id: PORTKEY_ACCOUNT_ID, provider: "portkey", apiKeyRef: PORTKEY_API_KEY_REF }],
50953
+ targets: [
50954
+ {
50955
+ id: PORTKEY_TARGET_ID,
50956
+ accountRef: PORTKEY_ACCOUNT_ID,
50957
+ model,
50958
+ privacyTier: "public",
50959
+ capabilities: ["chat"],
50960
+ contextWindow: 1e6
50961
+ }
50962
+ ],
50963
+ policies: [{ id: PORTKEY_POLICY_ID, mode: "strict", chain: [PORTKEY_TARGET_ID] }],
50964
+ workloads: [
50965
+ { name: "memory_extraction", policyRef: PORTKEY_POLICY_ID, requiredCapabilities: ["chat"], minPrivacyTier: "public" },
50966
+ { name: "memory_decision", policyRef: PORTKEY_POLICY_ID, requiredCapabilities: ["chat"], minPrivacyTier: "public" },
50967
+ { name: "memory_pollinating", policyRef: PORTKEY_POLICY_ID, requiredCapabilities: ["chat"], minPrivacyTier: "public" }
50968
+ ]
50969
+ };
50970
+ }
50971
+ var PortkeyFallbackModelClient = class {
50972
+ portkey;
50973
+ provider;
50974
+ constructor(portkey, provider) {
50975
+ this.portkey = portkey;
50976
+ this.provider = provider;
50977
+ }
50978
+ async complete(a, b) {
50979
+ try {
50980
+ return typeof a === "string" ? await this.portkey.complete(a, b) : await this.portkey.complete(a);
50981
+ } catch (err) {
50982
+ void err;
50983
+ return typeof a === "string" ? this.provider.complete(a, b) : this.provider.complete(a);
50984
+ }
50985
+ }
50986
+ };
50987
+
50988
+ // dist/src/daemon/runtime/recall/rerank-portkey.js
50989
+ var RERANK_FAILED = Object.freeze({ ok: false });
50990
+ var RerankResultSchema = external_exports.object({
50991
+ index: external_exports.number().int().nonnegative(),
50992
+ relevance_score: external_exports.number()
50993
+ });
50994
+ var RerankResponseSchema = external_exports.object({
50995
+ results: external_exports.array(RerankResultSchema)
50996
+ });
50997
+ function createPortkeyRerankClient(deps) {
50998
+ const doFetch = deps.fetch ?? globalThis.fetch;
50999
+ const url2 = deps.baseUrl ?? PORTKEY_RERANK_URL;
51000
+ const configId = deps.config;
51001
+ const onTransportError = deps.onTransportError;
51002
+ function reportTransportError(statusCode) {
51003
+ if (onTransportError === void 0)
51004
+ return;
51005
+ try {
51006
+ onTransportError(statusCode);
51007
+ } catch {
51008
+ }
51009
+ }
51010
+ return {
51011
+ async rerank(apiKey, request) {
51012
+ const body = {
51013
+ model: request.model,
51014
+ query: request.query,
51015
+ documents: request.documents,
51016
+ top_n: request.topN
51017
+ };
51018
+ let res;
51019
+ try {
51020
+ res = await doFetch(url2, {
51021
+ method: "POST",
51022
+ // SAME auth pair as the chat transport (c-D-2); the key lives only in the header (c-AC-2).
51023
+ headers: buildPortkeyHeaders(apiKey, configId),
51024
+ body: JSON.stringify(body)
51025
+ });
51026
+ } catch {
51027
+ reportTransportError(503);
51028
+ return RERANK_FAILED;
51029
+ }
51030
+ if (!res.ok) {
51031
+ reportTransportError(res.status);
51032
+ return RERANK_FAILED;
51033
+ }
51034
+ const text = await res.text().catch(() => "");
51035
+ const parsed = RerankResponseSchema.safeParse(safeJsonParse(text));
51036
+ if (!parsed.success) {
51037
+ process.stderr.write("honeycomb: portkey rerank returned an unusable 2xx body; failing soft to RRF order\n");
51038
+ return RERANK_FAILED;
51039
+ }
51040
+ const results = parsed.data.results.filter((r) => r.index < request.documents.length).map((r) => ({ index: r.index, relevanceScore: r.relevance_score }));
51041
+ return { ok: true, results };
51042
+ }
51043
+ };
51044
+ }
51045
+ function buildCohereRerankSeam(deps) {
51046
+ return {
51047
+ async rerank(query, documents, topN) {
51048
+ let apiKey;
51049
+ try {
51050
+ apiKey = await deps.secrets.resolve(deps.apiKeyRef);
51051
+ } catch {
51052
+ return { ok: false };
51053
+ }
51054
+ try {
51055
+ return await deps.client.rerank(apiKey, { model: deps.model, query, documents, topN });
51056
+ } catch {
51057
+ return RERANK_FAILED;
51058
+ }
51059
+ }
51060
+ };
51061
+ }
49468
51062
 
49469
51063
  // dist/src/daemon/runtime/services/poll-backoff.js
49470
51064
  var DEFAULT_POLL_BACKOFF_FLOOR_MS = 1e3;
@@ -51416,7 +53010,7 @@ function sanitizeSegment4(name) {
51416
53010
  // dist/src/daemon/runtime/skillify/watermark.js
51417
53011
  import { mkdirSync as mkdirSync19, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
51418
53012
  import { homedir as homedir23 } from "node:os";
51419
- import { dirname as dirname13, join as join30 } from "node:path";
53013
+ import { dirname as dirname14, join as join30 } from "node:path";
51420
53014
  function defaultWatermarkBaseDir() {
51421
53015
  return join30(homedir23(), ".honeycomb", "state", "skillify");
51422
53016
  }
@@ -51442,7 +53036,7 @@ function createWatermarkStore(baseDir = defaultWatermarkBaseDir()) {
51442
53036
  const next = current === null ? oldest : earlier(current, oldest);
51443
53037
  const file2 = { watermark: next, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
51444
53038
  const path4 = fileFor(projectKey);
51445
- mkdirSync19(dirname13(path4), { recursive: true });
53039
+ mkdirSync19(dirname14(path4), { recursive: true });
51446
53040
  writeFileSync16(path4, JSON.stringify(file2, null, 2), "utf-8");
51447
53041
  return next;
51448
53042
  }
@@ -51470,6 +53064,95 @@ function sanitizeSegment5(projectKey) {
51470
53064
  return cleaned === "" ? "default" : cleaned;
51471
53065
  }
51472
53066
 
53067
+ // dist/src/daemon/runtime/dashboard/roi-session-writer.js
53068
+ import { randomUUID as randomUUID7 } from "node:crypto";
53069
+ var SESSION_TURNS_LIMIT = 2e3;
53070
+ function tokenCountOrNull2(value) {
53071
+ if (value === null || value === void 0)
53072
+ return null;
53073
+ const n = typeof value === "number" ? value : Number(value);
53074
+ return Number.isFinite(n) ? Math.trunc(n) : null;
53075
+ }
53076
+ function rowToCapturedTurn2(r) {
53077
+ const sourceTool = typeof r.source_tool === "string" ? r.source_tool : "";
53078
+ return {
53079
+ input_tokens: tokenCountOrNull2(r.input_tokens),
53080
+ output_tokens: tokenCountOrNull2(r.output_tokens),
53081
+ cache_read_input_tokens: tokenCountOrNull2(r.cache_read_input_tokens),
53082
+ cache_creation_input_tokens: tokenCountOrNull2(r.cache_creation_input_tokens),
53083
+ ...sourceTool !== "" ? { sourceTool } : {}
53084
+ };
53085
+ }
53086
+ async function readSessionTurns(storage, scope, path4) {
53087
+ const tbl = sqlIdent("sessions");
53088
+ const pathCol = sqlIdent("path");
53089
+ const sql = `SELECT ${sqlIdent("input_tokens")}, ${sqlIdent("output_tokens")}, ${sqlIdent("cache_read_input_tokens")}, ${sqlIdent("cache_creation_input_tokens")}, ${sqlIdent("source_tool")} FROM "${tbl}" WHERE ${pathCol} = ${sLiteral(path4)} LIMIT ${SESSION_TURNS_LIMIT}`;
53090
+ let result;
53091
+ try {
53092
+ result = await storage.query(sql, scope);
53093
+ } catch {
53094
+ return [];
53095
+ }
53096
+ return isOk(result) ? result.rows.map(rowToCapturedTurn2) : [];
53097
+ }
53098
+ function createRoiSessionWriter(deps) {
53099
+ const clock = deps.clock ?? { now: () => Date.now() };
53100
+ return {
53101
+ async writeForSession(input) {
53102
+ try {
53103
+ if (input.path.trim() === "") {
53104
+ deps.logger?.event("roi.write.skipped", { reason: "blank path", sessionId: input.sessionId });
53105
+ return;
53106
+ }
53107
+ const turns = await readSessionTurns(deps.storage, deps.scope, input.path);
53108
+ const measured2 = measuredCacheSavings(turns);
53109
+ const modeled2 = modeledMemoryInjectionSavings(1);
53110
+ let inputTokens = 0;
53111
+ let outputTokens = 0;
53112
+ let cacheReadTokens = 0;
53113
+ let cacheCreationTokens = 0;
53114
+ for (const t of turns) {
53115
+ inputTokens += t.input_tokens ?? 0;
53116
+ outputTokens += t.output_tokens ?? 0;
53117
+ cacheReadTokens += t.cache_read_input_tokens ?? 0;
53118
+ cacheCreationTokens += t.cache_creation_input_tokens ?? 0;
53119
+ }
53120
+ const createdAt = new Date(clock.now()).toISOString();
53121
+ const { teamId, userId } = await appendRoiMetric(deps.storage, deps.scope, {
53122
+ id: randomUUID7(),
53123
+ sessionId: input.sessionId,
53124
+ agentId: input.agentId,
53125
+ ...input.projectId !== void 0 ? { projectId: input.projectId } : {},
53126
+ inputTokens,
53127
+ outputTokens,
53128
+ cacheReadTokens,
53129
+ cacheCreationTokens,
53130
+ measuredCacheSavingsCents: measured2.value.savingsCents,
53131
+ modeledSavingsCents: modeled2.value.estimatedCents,
53132
+ modeledAssumptionRef: modeled2.assumption.kind,
53133
+ grossCostCents: 0,
53134
+ infraCostCents: 0,
53135
+ costBasis: "none",
53136
+ allocationMethod: "",
53137
+ createdAt
53138
+ });
53139
+ deps.logger?.event("roi.write.appended", {
53140
+ sessionId: input.sessionId,
53141
+ measuredCents: measured2.value.savingsCents,
53142
+ teamId,
53143
+ // user_id is gated to '' today — surface that it stayed gated (never a leaked identity).
53144
+ userGated: userId === ""
53145
+ });
53146
+ } catch (err) {
53147
+ deps.logger?.event("roi.write.failed", {
53148
+ sessionId: input.sessionId,
53149
+ reason: err instanceof Error ? err.message : String(err)
53150
+ });
53151
+ }
53152
+ }
53153
+ };
53154
+ }
53155
+
51473
53156
  // dist/src/daemon/runtime/skillify/worker.js
51474
53157
  var SKILLIFY_JOB_KIND = "skillify";
51475
53158
  var DEFAULT_POLL_INTERVAL_MS4 = 1e3;
@@ -51512,6 +53195,8 @@ var SkillifyJobWorkerImpl = class {
51512
53195
  gateOverride;
51513
53196
  fetcherOverride;
51514
53197
  storeOverride;
53198
+ /** PRD-060e/060f — the per-session ROI writer fired once at completion (fail-soft). */
53199
+ roiWriter;
51515
53200
  handle;
51516
53201
  /** Guards against overlapping `runOnce` invocations on the poll loop. */
51517
53202
  running = false;
@@ -51537,6 +53222,7 @@ var SkillifyJobWorkerImpl = class {
51537
53222
  this.gateOverride = deps.gateOverride;
51538
53223
  this.fetcherOverride = deps.fetcherOverride;
51539
53224
  this.storeOverride = deps.storeOverride;
53225
+ this.roiWriter = deps.roiWriter ?? createRoiSessionWriter({ storage: this.storage, scope: this.scope });
51540
53226
  }
51541
53227
  async runOnce() {
51542
53228
  let leased;
@@ -51577,6 +53263,19 @@ var SkillifyJobWorkerImpl = class {
51577
53263
  const outcome = await writeSkill(result.outcome.verdict, { store, install, author: this.author, projectId }, result.outcome.minedSessionIds, "global");
51578
53264
  const sessionDates = result.outcome.pairs.map((p) => p.sessionDate);
51579
53265
  this.watermarkStore.advance(projectKey, sessionDates);
53266
+ try {
53267
+ await this.roiWriter.writeForSession({
53268
+ sessionId: payload.sessionId,
53269
+ path: payload.path,
53270
+ agentId: this.author,
53271
+ projectId
53272
+ });
53273
+ } catch (roiErr) {
53274
+ this.logger?.event("skillify.worker.roi_write_failed", {
53275
+ id: job.id,
53276
+ reason: roiErr instanceof Error ? roiErr.message : String(roiErr)
53277
+ });
53278
+ }
51580
53279
  await this.queue.complete(job.id);
51581
53280
  this.logger?.event("skillify.worker.completed", {
51582
53281
  id: job.id,
@@ -51735,8 +53434,8 @@ var TransportError = class extends Error {
51735
53434
  this.status = status;
51736
53435
  }
51737
53436
  };
51738
- var DEEPLAKE_CLIENT_HEADER2 = "X-Deeplake-Client";
51739
- var DEEPLAKE_ORG_HEADER2 = "X-Activeloop-Org-Id";
53437
+ var DEEPLAKE_CLIENT_HEADER3 = "X-Deeplake-Client";
53438
+ var DEEPLAKE_ORG_HEADER3 = "X-Activeloop-Org-Id";
51740
53439
  var HttpDeepLakeTransport = class {
51741
53440
  endpoint;
51742
53441
  token;
@@ -51752,8 +53451,8 @@ var HttpDeepLakeTransport = class {
51752
53451
  headers: {
51753
53452
  Authorization: `Bearer ${this.token}`,
51754
53453
  "Content-Type": "application/json",
51755
- [DEEPLAKE_ORG_HEADER2]: req.org,
51756
- [DEEPLAKE_CLIENT_HEADER2]: "honeycomb"
53454
+ [DEEPLAKE_ORG_HEADER3]: req.org,
53455
+ [DEEPLAKE_CLIENT_HEADER3]: "honeycomb"
51757
53456
  },
51758
53457
  signal: req.signal,
51759
53458
  body: JSON.stringify({ query: req.sql })
@@ -52098,6 +53797,7 @@ var AGENT_CONFIG_FILE_NAME = "agent.yaml";
52098
53797
  var LOCK_FILE_NAME = "daemon.lock";
52099
53798
  var PID_FILE_NAME = "daemon.pid";
52100
53799
  var DEFAULT_HEALTH_PROBE_INTERVAL_MS = 15e3;
53800
+ var DEFAULT_GRAPH_BUILD_INTERVAL_MS = 60 * 60 * 1e3;
52101
53801
  var defaultSeamFns = {
52102
53802
  attachHooks: attachHooksHandlers,
52103
53803
  mountDashboard: mountDashboardApi,
@@ -52175,7 +53875,7 @@ function readPidFile(path4) {
52175
53875
  function releaseSingleInstanceLock(runtimeDir) {
52176
53876
  for (const name of [LOCK_FILE_NAME, PID_FILE_NAME]) {
52177
53877
  try {
52178
- rmSync9(join32(runtimeDir, name), { force: true });
53878
+ rmSync10(join32(runtimeDir, name), { force: true });
52179
53879
  } catch {
52180
53880
  }
52181
53881
  }
@@ -52198,7 +53898,7 @@ function authForMode(mode, storage, scope) {
52198
53898
  }
52199
53899
  return { authenticator: composeAuthenticator(storage, scope), policy: defaultDenyPolicy };
52200
53900
  }
52201
- function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDetail, workspaceDir, installedHarnesses, logStore, seams = defaultSeamFns, vault) {
53901
+ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDetail, workspaceDir, installedHarnesses, logStore, seams = defaultSeamFns, vault, rerankerDeps) {
52202
53902
  const captureHandler = seams.attachHooks(daemon, {
52203
53903
  storage,
52204
53904
  queue: daemon.services.queue,
@@ -52243,7 +53943,12 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
52243
53943
  embed: embed.client,
52244
53944
  logger: daemon.logger,
52245
53945
  conflictSuppression,
52246
- ...vault !== void 0 ? { vault } : {}
53946
+ ...vault !== void 0 ? { vault } : {},
53947
+ // PRD-063c: the operator-selected reranker config + the late-bound Cohere-via-Portkey seam.
53948
+ // The `cohere` strategy only does anything when BOTH the strategy is `cohere` (env) AND the
53949
+ // gateway is ON (the seam's inner transport is wired in `start()`); otherwise RRF / local
53950
+ // cosine, byte-identical to today (c-AC-4). Absent rerankerDeps (a unit mount) → engine default.
53951
+ ...rerankerDeps !== void 0 ? { reranker: rerankerDeps.reranker, cohereRerank: rerankerDeps.cohereRerank } : {}
52247
53952
  });
52248
53953
  if (seams.mountConflicts !== void 0) {
52249
53954
  seams.mountConflicts(daemon, { storage, defaultScope });
@@ -52255,7 +53960,7 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
52255
53960
  seams.mountMemoriesPrime(daemon, { storage, defaultScope });
52256
53961
  }
52257
53962
  seams.mountVfs(daemon, { storage, defaultScope });
52258
- seams.mountProductData(daemon, resolveProductDataDeps(storage, defaultScope, daemon.services.queue, embed.client));
53963
+ seams.mountProductData(daemon, resolveProductDataDeps(storage, defaultScope, daemon.services.queue, embed.client, daemon.config.mode));
52259
53964
  seams.mountPollinate(daemon, { storage, defaultScope, enqueuer: daemon.services.queue });
52260
53965
  try {
52261
53966
  seams.mountProjectsSync(daemon, { storage, defaultScope });
@@ -52326,10 +54031,14 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
52326
54031
  }
52327
54032
  return captureHandler;
52328
54033
  }
52329
- function resolveProductDataDeps(storage, defaultScope, queue, embed) {
52330
- const baseDir = process.env.HONEYCOMB_WORKSPACE ?? process.cwd();
54034
+ function resolveProductDataDeps(storage, defaultScope, queue, embed, mode) {
54035
+ const baseDir = resolveWorkspaceBaseDir();
52331
54036
  const secrets = {
52332
- store: new SecretsStore({ baseDir, machineKey: createMachineKeyProvider() })
54037
+ store: new SecretsStore({ baseDir, machineKey: createMachineKeyProvider() }),
54038
+ // PRD-022 local-mode default: the dashboard's `GET /api/secrets` (names-only) carries no
54039
+ // `x-honeycomb-org` header, so resolve the daemon's single local tenant instead of 400ing.
54040
+ // Team/hybrid stay fail-closed (a missing org still 400s) — cross-tenant access is rejected.
54041
+ scope: localDefaultScopeResolver(mode, defaultScope)
52333
54042
  };
52334
54043
  let sources;
52335
54044
  try {
@@ -52347,8 +54056,35 @@ function resolveProductDataDeps(storage, defaultScope, queue, embed) {
52347
54056
  defaultScope
52348
54057
  };
52349
54058
  }
54059
+ var workspaceBaseDirMemo;
52350
54060
  function resolveWorkspaceBaseDir() {
52351
- return process.env.HONEYCOMB_WORKSPACE ?? process.cwd();
54061
+ if (workspaceBaseDirMemo !== void 0)
54062
+ return workspaceBaseDirMemo;
54063
+ const fromEnv = process.env.HONEYCOMB_WORKSPACE;
54064
+ const candidate = fromEnv !== void 0 && fromEnv.length > 0 ? fromEnv : process.cwd();
54065
+ if (isWritableDir(candidate)) {
54066
+ workspaceBaseDirMemo = candidate;
54067
+ return candidate;
54068
+ }
54069
+ const fallback = join32(homedir25(), ".honeycomb");
54070
+ process.stderr.write(`honeycomb: workspace "${candidate}" is not writable; using "${fallback}" for filesystem state (secrets, logs, agent.yaml)
54071
+ `);
54072
+ try {
54073
+ mkdirSync20(fallback, { recursive: true, mode: DIR_MODE });
54074
+ } catch {
54075
+ }
54076
+ workspaceBaseDirMemo = fallback;
54077
+ return fallback;
54078
+ }
54079
+ function isWritableDir(dir) {
54080
+ try {
54081
+ mkdirSync20(dir, { recursive: true });
54082
+ const probe = mkdtempSync(join32(dir, ".honeycomb-write-test-"));
54083
+ rmSync10(probe, { recursive: true, force: true });
54084
+ return true;
54085
+ } catch {
54086
+ return false;
54087
+ }
52352
54088
  }
52353
54089
  function resolveAgentConfigPath(options) {
52354
54090
  return options.agentConfigPath ?? join32(resolveWorkspaceBaseDir(), AGENT_CONFIG_FILE_NAME);
@@ -52359,6 +54095,9 @@ function secretScopeFromQueryScope(scope) {
52359
54095
  var VAULT_PROVIDER_KEY = "activeProvider";
52360
54096
  var VAULT_MODEL_KEY = "activeModel";
52361
54097
  var VAULT_POLLINATING_ENABLED_KEY = "pollinating.enabled";
54098
+ var VAULT_PORTKEY_ENABLED_KEY = "portkey.enabled";
54099
+ var VAULT_PORTKEY_CONFIG_KEY = "portkey.config";
54100
+ var VAULT_PORTKEY_FALLBACK_KEY = "portkey.fallbackToProvider";
52362
54101
  function catalogTrustedTableProbe() {
52363
54102
  const names = CATALOG.map((t) => t.name);
52364
54103
  return { tables: () => Promise.resolve(names) };
@@ -52389,6 +54128,41 @@ async function readProviderModelOverride(vault, scope) {
52389
54128
  return void 0;
52390
54129
  }
52391
54130
  }
54131
+ async function readPortkeySelection(vault, scope) {
54132
+ if (vault === void 0)
54133
+ return void 0;
54134
+ try {
54135
+ const enabledRes = await vault.getSetting(VAULT_PORTKEY_ENABLED_KEY, scope);
54136
+ const enabled = enabledRes.ok && coerceSettingBool(enabledRes.value);
54137
+ if (!enabled)
54138
+ return void 0;
54139
+ const configRes = await vault.getSetting(VAULT_PORTKEY_CONFIG_KEY, scope);
54140
+ const config2 = configRes.ok ? String(configRes.value) : "";
54141
+ if (config2.length === 0)
54142
+ return void 0;
54143
+ const modelRes = await vault.getSetting(VAULT_MODEL_KEY, scope);
54144
+ const model = modelRes.ok ? String(modelRes.value) : "";
54145
+ const fallbackRes = await vault.getSetting(VAULT_PORTKEY_FALLBACK_KEY, scope);
54146
+ const fallbackToProvider = fallbackRes.ok && coerceSettingBool(fallbackRes.value);
54147
+ return { enabled: true, config: config2, model, fallbackToProvider };
54148
+ } catch {
54149
+ return void 0;
54150
+ }
54151
+ }
54152
+ async function resolvePortkeyAssemblyStatus(selection, scope) {
54153
+ if (selection === void 0 || !selection.enabled)
54154
+ return "off";
54155
+ try {
54156
+ const secretsStore = new SecretsStore({
54157
+ baseDir: resolveWorkspaceBaseDir(),
54158
+ machineKey: createMachineKeyProvider()
54159
+ });
54160
+ const names = secretsStore.listSecretNames(secretScopeFromQueryScope(scope));
54161
+ return names.includes(PORTKEY_API_KEY_NAME) ? "ok" : "unconfigured";
54162
+ } catch {
54163
+ return "unconfigured";
54164
+ }
54165
+ }
52392
54166
  async function readVaultPollinatingEnabled(vault, scope) {
52393
54167
  if (vault === void 0)
52394
54168
  return { decidedByVault: false, enabled: false };
@@ -52402,6 +54176,17 @@ async function readVaultPollinatingEnabled(vault, scope) {
52402
54176
  return { decidedByVault: false, enabled: false };
52403
54177
  }
52404
54178
  }
54179
+ async function readBootEmbeddingsEnabled(vault, scope) {
54180
+ if (vault !== void 0) {
54181
+ try {
54182
+ const res = await vault.getSetting(EMBEDDINGS_ENABLED_KEY, scope);
54183
+ if (res.ok)
54184
+ return coerceSettingBool(res.value);
54185
+ } catch {
54186
+ }
54187
+ }
54188
+ return resolveEmbedClientOptions().enabled;
54189
+ }
52405
54190
  function coerceSettingBool(value) {
52406
54191
  if (typeof value === "boolean")
52407
54192
  return value;
@@ -52411,7 +54196,7 @@ function coerceSettingBool(value) {
52411
54196
  return value === "true" || value === "1";
52412
54197
  return false;
52413
54198
  }
52414
- async function buildGatedPollinatingWorker(options, storage, scope, queue, vault, backoff) {
54199
+ async function buildGatedPollinatingWorker(options, storage, scope, queue, vault, backoff, portkeyDeps) {
52415
54200
  let config2;
52416
54201
  try {
52417
54202
  config2 = resolvePollinatingConfig(options.pollinatingConfigProvider);
@@ -52435,7 +54220,9 @@ async function buildGatedPollinatingWorker(options, storage, scope, queue, vault
52435
54220
  scope: secretScopeFromQueryScope(scope),
52436
54221
  secretsStore,
52437
54222
  config: resolveAgentConfigPath(options),
52438
- ...providerModelOverride !== void 0 ? { providerModelOverride } : {}
54223
+ ...providerModelOverride !== void 0 ? { providerModelOverride } : {},
54224
+ ...portkeyDeps?.selection !== void 0 ? { portkey: portkeyDeps.selection } : {},
54225
+ ...portkeyDeps !== void 0 ? { onPortkeyUnreachable: portkeyDeps.onUnreachable } : {}
52439
54226
  });
52440
54227
  const trigger = createPollinatingTrigger({ storage, scope, config: config2, enqueuer: queue });
52441
54228
  return createPollinatingWorker({ queue, storage, scope, config: config2, model, trigger, backoff });
@@ -52459,7 +54246,7 @@ function makePipelineEntryEnqueuer(queue) {
52459
54246
  });
52460
54247
  };
52461
54248
  }
52462
- async function buildPipelineWorker(options, storage, scope, queue, embed, backoff) {
54249
+ async function buildPipelineWorker(options, storage, scope, queue, embed, backoff, portkeyDeps) {
52463
54250
  let config2;
52464
54251
  try {
52465
54252
  config2 = resolvePipelineConfig();
@@ -52475,7 +54262,9 @@ async function buildPipelineWorker(options, storage, scope, queue, embed, backof
52475
54262
  model = await buildInferenceModelClient({
52476
54263
  scope: secretScopeFromQueryScope(scope),
52477
54264
  secretsStore,
52478
- config: resolveAgentConfigPath(options)
54265
+ config: resolveAgentConfigPath(options),
54266
+ ...portkeyDeps?.selection !== void 0 ? { portkey: portkeyDeps.selection } : {},
54267
+ ...portkeyDeps !== void 0 ? { onPortkeyUnreachable: portkeyDeps.onUnreachable } : {}
52479
54268
  });
52480
54269
  } catch {
52481
54270
  model = noopModelClient;
@@ -52510,6 +54299,7 @@ function assembleDaemon(options = {}) {
52510
54299
  const tenancy = resolveDaemonTenancy(provider);
52511
54300
  const scope = tenancy.scope;
52512
54301
  const daemonOrgName = tenancy.orgName;
54302
+ const vault = options.vault ?? (options.storage === void 0 ? buildVaultStore() : void 0);
52513
54303
  const services = {
52514
54304
  queue: createJobQueueService({ storage, scope }),
52515
54305
  watcher: createFileWatcherService({
@@ -52525,10 +54315,34 @@ function assembleDaemon(options = {}) {
52525
54315
  // fake supervisor so the hermetic assembly never spawns a real process.
52526
54316
  embed: options.embedSupervisor ?? createEmbedSupervisor()
52527
54317
  };
54318
+ const embedSupervisor = services.embed;
54319
+ if (embedSupervisor !== void 0 && vault !== void 0) {
54320
+ void readBootEmbeddingsEnabled(vault, secretScopeFromQueryScope(scope)).then(async (enabled) => {
54321
+ if (enabled !== !embedSupervisor.disabled)
54322
+ await embedSupervisor.setEnabled(enabled);
54323
+ }).catch((err) => {
54324
+ const reason = err instanceof Error ? err.message : String(err);
54325
+ process.stderr.write(`honeycomb: embeddings boot reconciliation failed (non-fatal): ${reason}
54326
+ `);
54327
+ });
54328
+ }
52528
54329
  let healthBit = "ok";
52529
54330
  const pipelineProbe = () => healthBit;
52530
- const embeddingsEnabled = options.embeddingsEnabled ?? (options.embed !== void 0 ? false : resolveEmbedClientOptions().enabled);
52531
- const healthDetail = () => buildHealthDetail({ status: healthBit, embeddingsEnabled });
54331
+ const embeddingsReason = () => options.embeddingsEnabled ?? (options.embed !== void 0 ? false : embedSupervisor !== void 0 ? !embedSupervisor.disabled : resolveEmbedClientOptions().enabled);
54332
+ let portkeyHealth = "off";
54333
+ const recordPortkeyUnreachable = (_statusCode) => {
54334
+ portkeyHealth = "unreachable";
54335
+ };
54336
+ const healthDetail = () => buildHealthDetail({ status: healthBit, embeddingsEnabled: embeddingsReason(), portkey: portkeyHealth });
54337
+ let cohereRerankInner;
54338
+ const cohereRerankSeam = {
54339
+ rerank(query, documents, topN) {
54340
+ const inner = cohereRerankInner;
54341
+ if (inner === void 0)
54342
+ return Promise.resolve({ ok: false });
54343
+ return inner.rerank(query, documents, topN);
54344
+ }
54345
+ };
52532
54346
  const { authenticator, policy } = authForMode(config2.mode, storage, scope);
52533
54347
  const createOptions = {
52534
54348
  config: config2,
@@ -52543,11 +54357,19 @@ function assembleDaemon(options = {}) {
52543
54357
  const daemon = createDaemon(createOptions);
52544
54358
  const embed = options.embed ?? createEmbedAttachment({ storage });
52545
54359
  const installedHarnesses = options.installedHarnesses ?? (options.harnessTargets !== void 0 && options.harnessTargets.length > 0 ? new Set(options.harnessTargets.map((t) => t.name)) : options.storage === void 0 ? detectInstalledHarnesses() : /* @__PURE__ */ new Set());
52546
- const vault = options.vault ?? (options.storage === void 0 ? buildVaultStore() : void 0);
52547
- const captureHandler = assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
54360
+ let rerankerMountDeps;
54361
+ try {
54362
+ rerankerMountDeps = { reranker: resolveRecallConfig().reranker, cohereRerank: cohereRerankSeam };
54363
+ } catch {
54364
+ rerankerMountDeps = {
54365
+ reranker: RecallConfigSchema.parse({}).reranker,
54366
+ cohereRerank: cohereRerankSeam
54367
+ };
54368
+ }
54369
+ const captureHandler = assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault, rerankerMountDeps);
52548
54370
  if (vault !== void 0 && vault instanceof VaultStore) {
52549
54371
  try {
52550
- mountSettingsApi(daemon, { store: vault });
54372
+ mountSettingsApi(daemon, { store: vault, scope: localDefaultScopeResolver(daemon.config.mode, scope) });
52551
54373
  } catch (err) {
52552
54374
  const reason = err instanceof Error ? err.message : String(err);
52553
54375
  process.stderr.write(`honeycomb: settings API mount failed (non-fatal): ${reason}
@@ -52559,6 +54381,17 @@ function assembleDaemon(options = {}) {
52559
54381
  } catch (err) {
52560
54382
  const reason = err instanceof Error ? err.message : String(err);
52561
54383
  process.stderr.write(`honeycomb: auth status API mount failed (non-fatal): ${reason}
54384
+ `);
54385
+ }
54386
+ try {
54387
+ mountActionsApi(daemon, {
54388
+ embed: daemon.services.embed,
54389
+ defaultScope: scope,
54390
+ ...vault instanceof VaultStore ? { store: vault } : {}
54391
+ });
54392
+ } catch (err) {
54393
+ const reason = err instanceof Error ? err.message : String(err);
54394
+ process.stderr.write(`honeycomb: actions API mount failed (non-fatal): ${reason}
52562
54395
  `);
52563
54396
  }
52564
54397
  try {
@@ -52609,6 +54442,27 @@ function assembleDaemon(options = {}) {
52609
54442
  healthBit = "degraded";
52610
54443
  }
52611
54444
  }
54445
+ const autoBuildGraph = options.storage === void 0 && config2.mode === "local";
54446
+ let graphBuildTimer = null;
54447
+ let graphBuildInFlight = false;
54448
+ async function rebuildCodebaseGraph() {
54449
+ if (graphBuildInFlight)
54450
+ return;
54451
+ graphBuildInFlight = true;
54452
+ try {
54453
+ await buildCodebaseGraphSnapshot(scope, {
54454
+ storage,
54455
+ defaultScope: scope,
54456
+ workspaceDir: options.workspaceDir ?? process.cwd()
54457
+ });
54458
+ } catch (err) {
54459
+ const reason = err instanceof Error ? err.message : String(err);
54460
+ process.stderr.write(`honeycomb: codebase graph auto-build failed (non-fatal): ${reason}
54461
+ `);
54462
+ } finally {
54463
+ graphBuildInFlight = false;
54464
+ }
54465
+ }
52612
54466
  let started = false;
52613
54467
  let locked = false;
52614
54468
  let pollinatingWorker = null;
@@ -52633,6 +54487,15 @@ function assembleDaemon(options = {}) {
52633
54487
  if (typeof probeTimer.unref === "function") {
52634
54488
  probeTimer.unref();
52635
54489
  }
54490
+ if (autoBuildGraph) {
54491
+ void rebuildCodebaseGraph();
54492
+ graphBuildTimer = setInterval(() => {
54493
+ void rebuildCodebaseGraph();
54494
+ }, DEFAULT_GRAPH_BUILD_INTERVAL_MS);
54495
+ if (typeof graphBuildTimer.unref === "function") {
54496
+ graphBuildTimer.unref();
54497
+ }
54498
+ }
52636
54499
  await daemon.startServices();
52637
54500
  let pollBackoff;
52638
54501
  try {
@@ -52646,6 +54509,33 @@ function assembleDaemon(options = {}) {
52646
54509
  } catch {
52647
54510
  consolidatePoll = false;
52648
54511
  }
54512
+ let portkeyWorkerDeps = { onUnreachable: recordPortkeyUnreachable };
54513
+ try {
54514
+ const portkeySelection = await readPortkeySelection(vault, secretScopeFromQueryScope(scope));
54515
+ portkeyHealth = await resolvePortkeyAssemblyStatus(portkeySelection, scope);
54516
+ portkeyWorkerDeps = {
54517
+ ...portkeySelection !== void 0 ? { selection: portkeySelection } : {},
54518
+ onUnreachable: recordPortkeyUnreachable
54519
+ };
54520
+ if (portkeySelection !== void 0) {
54521
+ const rerankSecrets = createSecretResolver(new SecretsStore({ baseDir: resolveWorkspaceBaseDir(), machineKey: createMachineKeyProvider() }), secretScopeFromQueryScope(scope));
54522
+ const rerankClient = createPortkeyRerankClient({
54523
+ config: portkeySelection.config,
54524
+ onTransportError: recordPortkeyUnreachable
54525
+ });
54526
+ cohereRerankInner = buildCohereRerankSeam({
54527
+ client: rerankClient,
54528
+ secrets: rerankSecrets,
54529
+ apiKeyRef: PORTKEY_API_KEY_REF,
54530
+ model: rerankerMountDeps.reranker.cohereModel
54531
+ });
54532
+ } else {
54533
+ cohereRerankInner = void 0;
54534
+ }
54535
+ } catch {
54536
+ portkeyHealth = "off";
54537
+ cohereRerankInner = void 0;
54538
+ }
52649
54539
  try {
52650
54540
  summaryWorker = buildSummaryWorker(storage, scope, daemon.services.queue, embed);
52651
54541
  summaryWorker.start();
@@ -52656,7 +54546,7 @@ function assembleDaemon(options = {}) {
52656
54546
  summaryWorker = null;
52657
54547
  }
52658
54548
  try {
52659
- pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed, pollBackoff);
54549
+ pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed, pollBackoff, portkeyWorkerDeps);
52660
54550
  if (!consolidatePoll)
52661
54551
  pipelineWorker.start();
52662
54552
  } catch (err) {
@@ -52688,7 +54578,7 @@ function assembleDaemon(options = {}) {
52688
54578
  }
52689
54579
  }
52690
54580
  try {
52691
- pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault, pollBackoff);
54581
+ pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault, pollBackoff, portkeyWorkerDeps);
52692
54582
  const pollinatingInjected = options.pollinatingWorker !== void 0;
52693
54583
  if (consolidatePoll && !pollinatingInjected) {
52694
54584
  const participants = [pipelineWorker, pollinatingWorker].filter((p) => p !== null);
@@ -52743,6 +54633,10 @@ function assembleDaemon(options = {}) {
52743
54633
  clearInterval(probeTimer);
52744
54634
  probeTimer = null;
52745
54635
  }
54636
+ if (graphBuildTimer !== null) {
54637
+ clearInterval(graphBuildTimer);
54638
+ graphBuildTimer = null;
54639
+ }
52746
54640
  if (started) {
52747
54641
  await daemon.stopServices();
52748
54642
  started = false;
@@ -52845,9 +54739,9 @@ export {
52845
54739
  CompactionConfigError,
52846
54740
  CompactionRefusedError,
52847
54741
  CompactionRetentionSchema,
52848
- DEEPLAKE_CLIENT_HEADER2 as DEEPLAKE_CLIENT_HEADER,
54742
+ DEEPLAKE_CLIENT_HEADER3 as DEEPLAKE_CLIENT_HEADER,
52849
54743
  DEFAULT_MAX_POLLS as DEEPLAKE_DEFAULT_MAX_POLLS,
52850
- DEEPLAKE_ORG_HEADER2 as DEEPLAKE_ORG_HEADER,
54744
+ DEEPLAKE_ORG_HEADER3 as DEEPLAKE_ORG_HEADER,
52851
54745
  DEFAULT_CONVERGE_BACKOFF_BASE_MS,
52852
54746
  DEFAULT_CONVERGE_BACKOFF_CAP_MS,
52853
54747
  DEFAULT_CONVERGE_BUDGET,