omnius 1.0.599 → 1.0.601

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/dist/index.js CHANGED
@@ -630870,6 +630870,23 @@ function mergeRanges(ranges) {
630870
630870
  function rangeLabel(ranges) {
630871
630871
  return ranges.map((r2) => r2.end === Infinity || r2.start === 0 ? "whole file" : `lines ${r2.start}-${r2.end}`).join(", ");
630872
630872
  }
630873
+ function sameRange(a2, b) {
630874
+ return a2.start === b.start && a2.end === b.end;
630875
+ }
630876
+ function rangeCovers(observed, requested) {
630877
+ const requestedWhole = requested.start === 0 || requested.end === Infinity;
630878
+ const observedWhole = observed.start === 0 || observed.end === Infinity;
630879
+ if (requestedWhole)
630880
+ return observedWhole;
630881
+ if (observedWhole)
630882
+ return true;
630883
+ return observed.start <= requested.start && requested.end <= observed.end;
630884
+ }
630885
+ function rangeWidth(range) {
630886
+ if (range.start === 0 || range.end === Infinity)
630887
+ return Infinity;
630888
+ return Math.max(0, range.end - range.start + 1);
630889
+ }
630873
630890
  function looksLikePartialCapture(content) {
630874
630891
  return /\[(?:oversize\s+(?:output|llmContent)|Tool output truncated|GREP_PARTIAL)\b/i.test(content);
630875
630892
  }
@@ -630895,16 +630912,36 @@ var init_evidenceLedger = __esm({
630895
630912
  "use strict";
630896
630913
  EvidenceLedger = class {
630897
630914
  entries = /* @__PURE__ */ new Map();
630915
+ /** Exact replay bodies, independently range-bound from aggregate receipts. */
630916
+ readBodies = /* @__PURE__ */ new Map();
630917
+ recordBody(path16, body, reset) {
630918
+ const prior = reset ? [] : this.readBodies.get(path16) ?? [];
630919
+ const retained = prior.filter((candidate) => !sameRange(candidate.range, body.range));
630920
+ retained.push(body);
630921
+ retained.sort((a2, b) => b.lastReadTurn - a2.lastReadTurn);
630922
+ this.readBodies.set(path16, retained.slice(0, 16));
630923
+ }
630898
630924
  /** Record a successful read. `fileVersion` is the file's current writeCount. */
630899
630925
  recordRead(input) {
630900
- const { path: path16, content, range, fileVersion, turn } = input;
630926
+ const { path: path16, content, fileVersion, turn } = input;
630901
630927
  if (!path16 || !content)
630902
630928
  return;
630929
+ const reportedRange = input.artifactMaterialization?.sourceRange;
630930
+ const materializedRange = reportedRange && typeof reportedRange.endLine === "number" ? {
630931
+ startLine: reportedRange.startLine,
630932
+ endLine: reportedRange.endLine
630933
+ } : void 0;
630934
+ const requestedWhole = input.range.start === 0 || input.range.end === Infinity;
630935
+ const range = !requestedWhole && materializedRange ? {
630936
+ start: materializedRange.startLine,
630937
+ end: materializedRange.endLine
630938
+ } : { ...input.range };
630903
630939
  const inferredPartial = input.artifactMaterialization?.status === "partial" || input.fidelity === "partial" || looksLikePartialCapture(content);
630904
630940
  const built = input.fidelity === "extract" ? { text: content, fidelity: "extract" } : inferredPartial ? { text: content, fidelity: "partial" } : { text: content, fidelity: "full" };
630905
630941
  const materialization = input.artifactMaterialization ?? (inferredPartial ? inferredPartialMaterialization(content) : void 0);
630906
630942
  const existing = this.entries.get(path16);
630907
- if (existing && existing.readVersion === fileVersion && !existing.stale) {
630943
+ const sameRevision = existing && existing.readVersion === fileVersion && !existing.stale && (!existing.contentHash || !input.contentHash || existing.contentHash === input.contentHash);
630944
+ if (existing && sameRevision) {
630908
630945
  if (built.fidelity === "extract" && existing.fidelity === "full") {
630909
630946
  const keepExistingCompleteExtract = existing.derivedExtract?.complete === true && input.extractComplete !== true;
630910
630947
  this.entries.set(path16, {
@@ -630926,6 +630963,14 @@ var init_evidenceLedger = __esm({
630926
630963
  return;
630927
630964
  }
630928
630965
  if (built.fidelity === "partial" && existing.fidelity === "full") {
630966
+ this.recordBody(path16, {
630967
+ range,
630968
+ content: built.text,
630969
+ ...input.contentHash ? { contentHash: input.contentHash } : {},
630970
+ fidelity: "partial",
630971
+ lastReadTurn: turn,
630972
+ ...materialization ? { artifactMaterialization: materialization } : {}
630973
+ }, false);
630929
630974
  this.entries.set(path16, {
630930
630975
  ...existing,
630931
630976
  lastReadTurn: turn,
@@ -630934,9 +630979,20 @@ var init_evidenceLedger = __esm({
630934
630979
  return;
630935
630980
  }
630936
630981
  const keepNew = existing.fidelity === "partial" && built.fidelity !== "partial" || built.text.length >= existing.content.length;
630982
+ if (built.fidelity !== "extract") {
630983
+ this.recordBody(path16, {
630984
+ range,
630985
+ content: built.text,
630986
+ ...input.contentHash ? { contentHash: input.contentHash } : {},
630987
+ fidelity: built.fidelity,
630988
+ lastReadTurn: turn,
630989
+ ...materialization ? { artifactMaterialization: materialization } : {}
630990
+ }, false);
630991
+ }
630937
630992
  this.entries.set(path16, {
630938
630993
  ...existing,
630939
630994
  content: keepNew ? built.text : existing.content,
630995
+ contentRange: keepNew ? range : existing.contentRange,
630940
630996
  contentHash: input.contentHash ?? existing.contentHash,
630941
630997
  fidelity: keepNew ? built.fidelity : existing.fidelity,
630942
630998
  ...keepNew && materialization ? { artifactMaterialization: materialization } : existing.artifactMaterialization ? { artifactMaterialization: existing.artifactMaterialization } : {},
@@ -630948,12 +631004,25 @@ var init_evidenceLedger = __esm({
630948
631004
  });
630949
631005
  return;
630950
631006
  }
631007
+ if (built.fidelity !== "extract") {
631008
+ this.recordBody(path16, {
631009
+ range,
631010
+ content: built.text,
631011
+ ...input.contentHash ? { contentHash: input.contentHash } : {},
631012
+ fidelity: built.fidelity,
631013
+ lastReadTurn: turn,
631014
+ ...materialization ? { artifactMaterialization: materialization } : {}
631015
+ }, true);
631016
+ } else {
631017
+ this.readBodies.delete(path16);
631018
+ }
630951
631019
  this.entries.set(path16, {
630952
631020
  path: path16,
630953
631021
  contentHash: input.contentHash,
630954
631022
  readVersion: fileVersion,
630955
631023
  mtimeMs: input.mtimeMs ?? 0,
630956
631024
  lastReadTurn: turn,
631025
+ contentRange: range,
630957
631026
  ranges: [range],
630958
631027
  content: built.text,
630959
631028
  fidelity: built.fidelity,
@@ -630974,6 +631043,19 @@ var init_evidenceLedger = __esm({
630974
631043
  const e2 = this.entries.get(path16);
630975
631044
  return !!e2 && !e2.stale && e2.fidelity !== "partial";
630976
631045
  }
631046
+ /**
631047
+ * Resolve a replay body only when that body's own provenance fully covers
631048
+ * the requested range. Aggregate `EvidenceEntry.ranges` are receipts only.
631049
+ */
631050
+ resolveFreshRead(input) {
631051
+ const entry = this.entries.get(input.path);
631052
+ if (!entry || entry.stale)
631053
+ return void 0;
631054
+ if (input.contentHash && input.contentHash !== entry.contentHash) {
631055
+ return void 0;
631056
+ }
631057
+ return (this.readBodies.get(input.path) ?? []).filter((body) => body.fidelity === "full" && (!input.contentHash || body.contentHash === input.contentHash) && rangeCovers(body.range, input.requestedRange)).sort((a2, b) => rangeWidth(a2.range) - rangeWidth(b.range) || b.lastReadTurn - a2.lastReadTurn)[0];
631058
+ }
630977
631059
  /**
630978
631060
  * Validate evidence freshness against the real filesystem via stat().
630979
631061
  * If the file's mtime has changed since we last read it (external mutation
@@ -631022,6 +631104,7 @@ var init_evidenceLedger = __esm({
631022
631104
  const cap = Math.max(1, Math.min(200, Math.floor(maxEntries)));
631023
631105
  return [...this.entries.values()].sort((a2, b) => b.lastReadTurn - a2.lastReadTurn).slice(0, cap).map((entry) => ({
631024
631106
  ...entry,
631107
+ contentRange: { ...entry.contentRange },
631025
631108
  ranges: entry.ranges.map((range) => ({ ...range })),
631026
631109
  ...entry.derivedExtract ? {
631027
631110
  derivedExtract: {
@@ -631053,6 +631136,7 @@ var init_evidenceLedger = __esm({
631053
631136
  }
631054
631137
  clear() {
631055
631138
  this.entries.clear();
631139
+ this.readBodies.clear();
631056
631140
  }
631057
631141
  /**
631058
631142
  * Render the evidence block for the ACTIVE CONTEXT FRAME. Freshest reads
@@ -631077,8 +631161,10 @@ var init_evidenceLedger = __esm({
631077
631161
  let used = lines.join("\n").length;
631078
631162
  for (const e2 of sorted) {
631079
631163
  const selectedExtract = !e2.stale && e2.derivedExtract?.complete === true ? e2.derivedExtract : void 0;
631080
- const renderedRanges = selectedExtract?.ranges ?? e2.ranges;
631081
- const header = e2.stale ? `▸ ${e2.path} @v${e2.readVersion} [STALE — changed since read; re-read needed] (${rangeLabel(e2.ranges)})` : selectedExtract ? `▸ ${e2.path} @v${e2.readVersion} [DERIVED EXTRACT — contract complete; canonical full source retained] (${rangeLabel(renderedRanges)}):` : e2.fidelity === "partial" ? `▸ ${e2.path} @v${e2.readVersion} [PARTIAL — successful output was capped; do not infer omitted text is absent] (${rangeLabel(e2.ranges)})` : `▸ ${e2.path} @v${e2.readVersion} [FRESH${e2.contentHash ? ` sha256=${e2.contentHash}` : ""}] (${rangeLabel(e2.ranges)}):`;
631164
+ const renderedRanges = selectedExtract?.ranges ?? [e2.contentRange];
631165
+ const coverage = rangeLabel(e2.ranges);
631166
+ const bodyRange = rangeLabel(renderedRanges);
631167
+ const header = e2.stale ? `▸ ${e2.path} @v${e2.readVersion} [STALE — changed since read; re-read needed] (${rangeLabel(e2.ranges)})` : selectedExtract ? `▸ ${e2.path} @v${e2.readVersion} [DERIVED EXTRACT — contract complete; canonical full source retained] (${rangeLabel(renderedRanges)}):` : e2.fidelity === "partial" ? `▸ ${e2.path} @v${e2.readVersion} [PARTIAL — successful output was capped; do not infer omitted text is absent] (body ${bodyRange}; coverage ${coverage})` : `▸ ${e2.path} @v${e2.readVersion} [FRESH${e2.contentHash ? ` sha256=${e2.contentHash}` : ""}] (body ${bodyRange}; coverage ${coverage}):`;
631082
631168
  if (compact6) {
631083
631169
  const receipt2 = `- evidence_id=file:${e2.path}@v${e2.readVersion} outcome=${e2.stale ? "stale" : "fresh"} fidelity=${e2.fidelity} sha256=${e2.contentHash ?? "unknown"} ranges=${rangeLabel(renderedRanges)}`;
631084
631170
  if (used + receipt2.length + 1 <= maxChars) {
@@ -651412,20 +651498,6 @@ ${blob}
651412
651498
  const p2 = pathForResult(idx);
651413
651499
  if (p2 && latestIdxForPath.get(p2) === idx)
651414
651500
  continue;
651415
- if (p2 && content.length >= 100) {
651416
- try {
651417
- this._evidenceLedger.recordRead({
651418
- path: this._normalizeEvidencePath(p2),
651419
- content,
651420
- contentHash: this._extractFileReadSha256(content) ?? void 0,
651421
- range: { start: 0, end: Number.POSITIVE_INFINITY },
651422
- fileVersion: this._worldFacts.files.get(p2)?.writeCount ?? 0,
651423
- mtimeMs: this._statMtimeMsForToolPath(p2),
651424
- turn: this._taskState?.toolCallCount ?? 0
651425
- });
651426
- } catch {
651427
- }
651428
- }
651429
651501
  const meta = metaForResult(idx);
651430
651502
  let stub;
651431
651503
  if (p2) {
@@ -651585,20 +651657,6 @@ ${blob}
651585
651657
  if (covered)
651586
651658
  return cov.fingerprint;
651587
651659
  }
651588
- if (!iv.whole && Number.isFinite(iv.end)) {
651589
- let best = null;
651590
- const requestedLength = Math.max(1, iv.end - iv.start + 1);
651591
- for (const cov of intervals) {
651592
- if (cov.whole || !Number.isFinite(cov.end))
651593
- continue;
651594
- const overlap = Math.max(0, Math.min(iv.end, cov.end) - Math.max(iv.start, cov.start) + 1);
651595
- if (overlap / requestedLength >= 0.8 && (!best || overlap > best.overlap)) {
651596
- best = { fingerprint: cov.fingerprint, overlap };
651597
- }
651598
- }
651599
- if (best)
651600
- return best.fingerprint;
651601
- }
651602
651660
  return exactFingerprint;
651603
651661
  }
651604
651662
  /** Register a read's region under the fingerprint that cached its result. */
@@ -652779,16 +652837,12 @@ ${notice}`;
652779
652837
  this._emitSteeringLifecycle(record, gatesOldPlan ? `admitted at turn ${turn}; old-plan actions are gated pending structured reconciliation` : `admitted at turn ${turn}; awaiting structured reconciliation`);
652780
652838
  }
652781
652839
  }
652782
- _canonicalReadEvidencePayload(canonicalPath2, contentHash2) {
652783
- const evidence = this._evidenceLedger.get(canonicalPath2);
652784
- if (evidence && !evidence.stale && evidence.contentHash === contentHash2 && evidence.fidelity === "full" && this._mustHonorExplicitFullFileRead(Buffer.byteLength(evidence.content, "utf8"), evidence.content.split("\n").length, this._branchRoutingContextWindow())) {
652785
- return evidence.content;
652786
- }
652787
- const branch = this._branchEvidenceByPath.get(canonicalPath2);
652788
- if (branch && branch.contentHash === contentHash2 && branch.taskEpoch === this._taskEpoch && branch.contractComplete) {
652789
- return branch.output;
652790
- }
652791
- return null;
652840
+ _canonicalReadEvidencePayload(canonicalPath2, contentHash2, requestedRange) {
652841
+ return this._evidenceLedger.resolveFreshRead({
652842
+ path: canonicalPath2,
652843
+ requestedRange,
652844
+ contentHash: contentHash2
652845
+ })?.content ?? null;
652792
652846
  }
652793
652847
  _rehydrateResolvedReadEvidence(input) {
652794
652848
  return [
@@ -658897,27 +658951,26 @@ ${cachedResult}`,
658897
658951
  let branchEvidenceResult = null;
658898
658952
  if (normalizedDispatchName === "file_read" && this._fileReadMode(tc.arguments) !== "extract") {
658899
658953
  const exactReadFingerprint = this._buildToolFingerprint("file_read", tc.arguments);
658954
+ const exactReadInterval = this._readIntervalFromArgs("file_read", tc.arguments);
658955
+ const requestedReadRange = exactReadInterval && !exactReadInterval.whole ? {
658956
+ start: exactReadInterval.start,
658957
+ end: exactReadInterval.end
658958
+ } : {
658959
+ start: 0,
658960
+ end: Number.POSITIVE_INFINITY
658961
+ };
658900
658962
  const exactReadKey = this._resolveReadCoverageFingerprint("file_read", tc.arguments, exactReadFingerprint);
658901
658963
  const priorRead = exactFileReadObservations.get(exactReadKey);
658902
658964
  if (priorRead) {
658903
658965
  const currentRead = this._fileReadDiskIdentity(tc.arguments);
658904
658966
  if (currentRead && currentRead.contentHash === priorRead.contentHash) {
658905
658967
  exactFileReadObservations.set(exactReadKey, currentRead);
658906
- const canonicalPayload = this._canonicalReadEvidencePayload(currentRead.canonicalPath, currentRead.contentHash);
658968
+ const canonicalPayload = this._canonicalReadEvidencePayload(currentRead.canonicalPath, currentRead.contentHash, requestedReadRange);
658907
658969
  if (canonicalPayload) {
658908
- const evidence = this._evidenceLedger.get(currentRead.canonicalPath);
658909
- const fullSource = evidence?.fidelity === "full" && evidence.content === canonicalPayload;
658910
- const delivered = fullSource ? canonicalPayload : this._rehydrateResolvedReadEvidence({
658911
- fingerprint: exactReadKey,
658912
- canonicalPath: currentRead.canonicalPath,
658913
- contentHash: currentRead.contentHash,
658914
- payload: canonicalPayload,
658915
- turn
658916
- });
658917
658970
  branchEvidenceResult = {
658918
658971
  success: true,
658919
- output: delivered,
658920
- llmContent: delivered,
658972
+ output: canonicalPayload,
658973
+ llmContent: canonicalPayload,
658921
658974
  beforeHash: currentRead.contentHash,
658922
658975
  runtimeAuthored: true,
658923
658976
  noop: true,
@@ -658930,16 +658983,15 @@ ${cachedResult}`,
658930
658983
  this.emit({
658931
658984
  type: "status",
658932
658985
  toolName: normalizedDispatchName,
658933
- content: fullSource ? `Exact unchanged file_read served as canonical full source: ${currentRead.path} sha256=${currentRead.contentHash.slice(0, 12)}` : `Exact unchanged file_read reused complete branch evidence: ${currentRead.path} sha256=${currentRead.contentHash.slice(0, 12)}`,
658986
+ content: `Unchanged file_read served from range-safe canonical source: ${currentRead.path} sha256=${currentRead.contentHash.slice(0, 12)}`,
658934
658987
  turn,
658935
658988
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
658936
658989
  });
658937
658990
  } else {
658938
- exactFileReadObservations.delete(exactReadKey);
658939
658991
  this.emit({
658940
658992
  type: "status",
658941
658993
  toolName: normalizedDispatchName,
658942
- content: `Exact read cache lacks model-visible source; executing requested read: ${currentRead.path}`,
658994
+ content: `Read cache has no body covering the requested range; executing requested read: ${currentRead.path}`,
658943
658995
  turn,
658944
658996
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
658945
658997
  });
@@ -659265,6 +659317,14 @@ ${diagnostic}`;
659265
659317
  const rLimit = typeof tc.arguments?.["limit"] === "number" ? tc.arguments["limit"] : void 0;
659266
659318
  const start3 = rOffset === void 0 && rLimit === void 0 ? 0 : Math.max(1, rOffset ?? 1);
659267
659319
  const end = rOffset === void 0 && rLimit === void 0 ? Number.POSITIVE_INFINITY : rLimit !== void 0 ? Math.max(1, rOffset ?? 1) + Math.max(0, rLimit) - 1 : Number.POSITIVE_INFINITY;
659320
+ const requestedWhole = start3 === 0;
659321
+ const reportedRange = result.artifactMaterialization?.sourceRange;
659322
+ const materializedRange = reportedRange && typeof reportedRange.endLine === "number" ? {
659323
+ startLine: reportedRange.startLine,
659324
+ endLine: reportedRange.endLine
659325
+ } : void 0;
659326
+ const effectiveStart = !requestedWhole && materializedRange ? materializedRange.startLine : start3;
659327
+ const effectiveEnd = !requestedWhole && materializedRange ? materializedRange.endLine : end;
659268
659328
  this._evidenceLedger.recordRead({
659269
659329
  path: this._normalizeEvidencePath(p2),
659270
659330
  content: result.output,
@@ -659283,8 +659343,8 @@ ${diagnostic}`;
659283
659343
  path: this._normalizeEvidencePath(p2),
659284
659344
  contentHash: result.beforeHash,
659285
659345
  sourceRange: {
659286
- startLine: start3 || 1,
659287
- endLine: end === Number.POSITIVE_INFINITY ? Number.MAX_SAFE_INTEGER : end
659346
+ startLine: effectiveStart || 1,
659347
+ endLine: effectiveEnd === Number.POSITIVE_INFINITY ? Number.MAX_SAFE_INTEGER : effectiveEnd
659288
659348
  },
659289
659349
  turn
659290
659350
  });
@@ -659295,8 +659355,14 @@ ${diagnostic}`;
659295
659355
  this._inlineReadArtifacts.delete(oldest);
659296
659356
  }
659297
659357
  }
659298
- if (result.partial !== true && result.artifactMaterialization?.status !== "partial") {
659299
- this._registerReadCoverage("file_read", tc.arguments, toolFingerprint);
659358
+ if (result.runtimeAuthored !== true && result.partial !== true && result.artifactMaterialization?.status !== "partial" && this._fileReadMode(tc.arguments) !== "extract") {
659359
+ const coverageArgs = !requestedWhole && materializedRange ? {
659360
+ ...tc.arguments,
659361
+ offset: effectiveStart,
659362
+ limit: Math.max(0, effectiveEnd - effectiveStart + 1)
659363
+ } : tc.arguments;
659364
+ const exactCoverageFingerprint = this._buildToolFingerprint("file_read", coverageArgs);
659365
+ this._registerReadCoverage("file_read", coverageArgs, this._resolveReadCoverageFingerprint("file_read", coverageArgs, exactCoverageFingerprint));
659300
659366
  }
659301
659367
  }
659302
659368
  if (this._fileSummaryStore && result.success && result.output && result.output.length > 100) {
@@ -678074,6 +678140,8 @@ ${AGENTS_END}`;
678074
678140
  var daemon_exports = {};
678075
678141
  __export(daemon_exports, {
678076
678142
  claimDaemonEndpoint: () => claimDaemonEndpoint,
678143
+ daemonPortFromServiceEnvironment: () => daemonPortFromServiceEnvironment,
678144
+ daemonServiceMatchesPort: () => daemonServiceMatchesPort,
678077
678145
  ensureDaemon: () => ensureDaemon,
678078
678146
  ensureDaemonVersion: () => ensureDaemonVersion,
678079
678147
  forceKillDaemon: () => forceKillDaemon,
@@ -678089,7 +678157,8 @@ __export(daemon_exports, {
678089
678157
  releaseDaemonEndpointForCurrentProcess: () => releaseDaemonEndpointForCurrentProcess,
678090
678158
  restartDaemon: () => restartDaemon,
678091
678159
  startDaemon: () => startDaemon,
678092
- stopDaemon: () => stopDaemon
678160
+ stopDaemon: () => stopDaemon,
678161
+ stopDaemonAtPort: () => stopDaemonAtPort
678093
678162
  });
678094
678163
  import { spawn as spawn28 } from "node:child_process";
678095
678164
  import { existsSync as existsSync116, readFileSync as readFileSync94, writeFileSync as writeFileSync60, mkdirSync as mkdirSync69, unlinkSync as unlinkSync22, openSync as openSync4, closeSync as closeSync4, writeSync as writeSync3, statSync as statSync46, renameSync as renameSync17 } from "node:fs";
@@ -678213,7 +678282,9 @@ async function isDaemonRunning(port) {
678213
678282
  const resp = await fetch(`http://127.0.0.1:${p2}/health`, {
678214
678283
  signal: AbortSignal.timeout(2e3)
678215
678284
  });
678216
- return resp.ok;
678285
+ if (!resp.ok) return false;
678286
+ const health = await resp.json();
678287
+ return health.status === "ok" && (typeof health.boot_version === "string" || typeof health.version === "string");
678217
678288
  } catch {
678218
678289
  return false;
678219
678290
  }
@@ -678279,12 +678350,49 @@ async function runUserSystemctl(args, timeout2 = 2e4) {
678279
678350
  return { available: false, ok: false };
678280
678351
  }
678281
678352
  }
678353
+ async function readUserSystemctl(args, timeout2 = 5e3) {
678354
+ try {
678355
+ const { spawnSync: spawnSync11 } = await import("node:child_process");
678356
+ const result = spawnSync11("systemctl", ["--user", ...args], {
678357
+ encoding: "utf8",
678358
+ stdio: ["ignore", "pipe", "ignore"],
678359
+ timeout: timeout2
678360
+ });
678361
+ return result.status === 0 ? result.stdout.trim() : null;
678362
+ } catch {
678363
+ return null;
678364
+ }
678365
+ }
678282
678366
  async function hasManagedDaemonService() {
678283
678367
  const enabled2 = await runUserSystemctl(["is-enabled", "omnius-daemon.service"], 5e3);
678284
678368
  if (enabled2.ok) return true;
678285
678369
  const active = await runUserSystemctl(["is-active", "omnius-daemon.service"], 5e3);
678286
678370
  return active.ok;
678287
678371
  }
678372
+ function daemonPortFromServiceEnvironment(value2) {
678373
+ const host = value2.match(/(?:^|\s)OMNIUS_HOST=(?:"([^"]+)"|'([^']+)'|([^\s]+))/)?.slice(1).find(Boolean);
678374
+ const direct = value2.match(/(?:^|\s)OMNIUS_PORT=(?:"(\d+)"|'(\d+)'|(\d+))/)?.slice(1).find(Boolean);
678375
+ const candidate = host?.match(/:(\d+)$/)?.[1] ?? direct;
678376
+ if (!candidate) return null;
678377
+ const port = Number(candidate);
678378
+ return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : null;
678379
+ }
678380
+ function daemonServiceMatchesPort(requestedPort, effectiveEnvironment) {
678381
+ const effectivePort2 = daemonPortFromServiceEnvironment(effectiveEnvironment);
678382
+ return effectivePort2 === null ? requestedPort === DEFAULT_PORT2 : effectivePort2 === requestedPort;
678383
+ }
678384
+ async function managedDaemonServiceMatchesPort(port) {
678385
+ if (!await hasManagedDaemonService()) return false;
678386
+ const environment = await readUserSystemctl([
678387
+ "show",
678388
+ "omnius-daemon.service",
678389
+ "--property",
678390
+ "Environment",
678391
+ "--value"
678392
+ ]);
678393
+ if (environment === null) return false;
678394
+ return daemonServiceMatchesPort(port, environment);
678395
+ }
678288
678396
  function systemdQuote(value2) {
678289
678397
  return /[\s"\\]/.test(value2) ? `"${value2.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : value2;
678290
678398
  }
@@ -678382,6 +678490,43 @@ async function waitForDaemonStopped(port, attempts = DAEMON_GRACEFUL_STOP_ATTEMP
678382
678490
  }
678383
678491
  return false;
678384
678492
  }
678493
+ async function reclaimStaleDaemonEndpointClaim(port) {
678494
+ const lockFile = daemonLockFile(port);
678495
+ const record = readDaemonLock(lockFile);
678496
+ if (!record) return true;
678497
+ if (!await daemonPortIsFree(port)) return true;
678498
+ if (!processIsAlive(record.pid)) {
678499
+ const current2 = readDaemonLock(lockFile);
678500
+ if (current2?.pid === record.pid && current2.token === record.token) {
678501
+ try {
678502
+ unlinkSync22(lockFile);
678503
+ } catch {
678504
+ }
678505
+ }
678506
+ return true;
678507
+ }
678508
+ const lease = listProcessLeases({ includeInactive: false }).find(
678509
+ (item) => item.status === "active" && item.pid === record.pid && item.ownerKind === "daemon" && item.ownerId === `daemon:${port}`
678510
+ );
678511
+ if (!lease) return false;
678512
+ const stopped = await stopProcessLease(lease.leaseId, {
678513
+ reason: `stale daemon endpoint claim on port ${port}`,
678514
+ termGraceMs: 1e3
678515
+ });
678516
+ if (stopped.action !== "killed" && stopped.action !== "dead") return false;
678517
+ for (let attempt = 0; attempt < 20 && processIsAlive(record.pid); attempt++) {
678518
+ await delay3(100);
678519
+ }
678520
+ if (processIsAlive(record.pid)) return false;
678521
+ const current = readDaemonLock(lockFile);
678522
+ if (current?.pid === record.pid && current.token === record.token) {
678523
+ try {
678524
+ unlinkSync22(lockFile);
678525
+ } catch {
678526
+ }
678527
+ }
678528
+ return daemonPortIsFree(port);
678529
+ }
678385
678530
  async function reclaimOwnedDaemonListener(port = getDaemonPort(), dependencies = DEFAULT_RECLAIM_DEPENDENCIES) {
678386
678531
  const holders = await dependencies.holderPids(port);
678387
678532
  if (holders === null) {
@@ -678457,7 +678602,7 @@ async function reclaimOwnedDaemonListener(port = getDaemonPort(), dependencies =
678457
678602
  }
678458
678603
  async function restartDaemon(port, expectedVersion) {
678459
678604
  const p2 = port ?? getDaemonPort();
678460
- const managed = await hasManagedDaemonService();
678605
+ const managed = await managedDaemonServiceMatchesPort(p2);
678461
678606
  if (managed) {
678462
678607
  const restarted = await runUserSystemctl(["restart", "omnius-daemon.service"]);
678463
678608
  if (restarted.ok && (await waitForDaemonReady(p2, expectedVersion)).ok) return true;
@@ -678478,6 +678623,7 @@ async function restartDaemon(port, expectedVersion) {
678478
678623
  const reclaimed = await reclaimOwnedDaemonListener(p2);
678479
678624
  if (!reclaimed.ok) return false;
678480
678625
  }
678626
+ if (!await reclaimStaleDaemonEndpointClaim(p2)) return false;
678481
678627
  const pid = await startDaemon(p2);
678482
678628
  if (!pid) return false;
678483
678629
  return (await waitForDaemonReady(p2, expectedVersion)).ok;
@@ -678584,7 +678730,7 @@ async function startDaemon(port = getDaemonPort()) {
678584
678730
  projectRoot: process.cwd(),
678585
678731
  lifecycle: "daemon",
678586
678732
  persistent: true,
678587
- reason: `shared API daemon on port ${getDaemonPort()}`,
678733
+ reason: `shared API daemon on port ${daemonPort}`,
678588
678734
  command: [daemonCommand.command, ...daemonCommand.args].join(" "),
678589
678735
  cwd: process.cwd()
678590
678736
  });
@@ -678629,6 +678775,17 @@ function stopDaemon() {
678629
678775
  return false;
678630
678776
  }
678631
678777
  }
678778
+ async function stopDaemonAtPort(port = getDaemonPort()) {
678779
+ if (await managedDaemonServiceMatchesPort(port)) {
678780
+ const stopped = await runUserSystemctl(["stop", "omnius-daemon.service"]);
678781
+ if (stopped.ok && await waitForDaemonStopped(port)) return true;
678782
+ }
678783
+ const wasRunning = await isDaemonRunning(port);
678784
+ const reclaimed = await reclaimOwnedDaemonListener(port);
678785
+ if (!reclaimed.ok) return false;
678786
+ const claimCleared = await reclaimStaleDaemonEndpointClaim(port);
678787
+ return claimCleared && (wasRunning || reclaimed.action === "cleared");
678788
+ }
678632
678789
  async function forceKillDaemon(port) {
678633
678790
  const p2 = port ?? getDaemonPort();
678634
678791
  let killed = 0;
@@ -678738,6 +678895,9 @@ async function ensureDaemonVersion(expectedVersion = getLocalCliVersion(), port
678738
678895
  process.platform === "linux" && reclaimed.action === "blocked"
678739
678896
  );
678740
678897
  }
678898
+ if (!await reclaimStaleDaemonEndpointClaim(port)) {
678899
+ return finish(false, "failed", null, 0, process.platform === "linux");
678900
+ }
678741
678901
  getDaemonPid();
678742
678902
  const pid = await startDaemon(port);
678743
678903
  if (!pid) {
@@ -678822,9 +678982,11 @@ __export(tray_exports, {
678822
678982
  resolveTrayEndpoint: () => resolveTrayEndpoint,
678823
678983
  resolveTrayLaunchCommand: () => resolveTrayLaunchCommand,
678824
678984
  resolveTrayPaths: () => resolveTrayPaths,
678985
+ resolveTrayRegistrationCommand: () => resolveTrayRegistrationCommand,
678825
678986
  runTrayForeground: () => runTrayForeground,
678826
678987
  startTray: () => startTray,
678827
678988
  stopTray: () => stopTray,
678989
+ trayProcessCommandLooksOwned: () => trayProcessCommandLooksOwned,
678828
678990
  trayRequiresRestart: () => trayRequiresRestart,
678829
678991
  traySupport: () => traySupport,
678830
678992
  trayUpdatePresentation: () => trayUpdatePresentation,
@@ -678840,6 +679002,7 @@ import {
678840
679002
  mkdirSync as mkdirSync70,
678841
679003
  openSync as openSync5,
678842
679004
  readFileSync as readFileSync95,
679005
+ realpathSync,
678843
679006
  renameSync as renameSync18,
678844
679007
  unlinkSync as unlinkSync23,
678845
679008
  writeFileSync as writeFileSync61,
@@ -678855,7 +679018,8 @@ function trayUpdatePresentation(currentVersion, latestVersion, state = null) {
678855
679018
  title: `Updating to v${state.target_version} — ${state.phase.replaceAll("_", " ")}`,
678856
679019
  tooltip: `Operation ${state.operation_id}; progress is shared with the dashboard and CLI`,
678857
679020
  enabled: false,
678858
- targetVersion: state.target_version
679021
+ targetVersion: state.target_version,
679022
+ action: "update-omnius"
678859
679023
  };
678860
679024
  }
678861
679025
  if (state?.status === "failed" && state.target_version === latestVersion) {
@@ -678863,7 +679027,8 @@ function trayUpdatePresentation(currentVersion, latestVersion, state = null) {
678863
679027
  title: `Update to v${state.target_version} failed — retry`,
678864
679028
  tooltip: state.remediation || state.error || "Open the tray logs for update diagnostics",
678865
679029
  enabled: true,
678866
- targetVersion: state.target_version
679030
+ targetVersion: state.target_version,
679031
+ action: "update-omnius"
678867
679032
  };
678868
679033
  }
678869
679034
  if (currentVersion && latestVersion) {
@@ -678871,13 +679036,15 @@ function trayUpdatePresentation(currentVersion, latestVersion, state = null) {
678871
679036
  title: `Update Omnius to v${latestVersion}`,
678872
679037
  tooltip: `Install and verify the global package, executable, daemon, and tray (current v${currentVersion})`,
678873
679038
  enabled: true,
678874
- targetVersion: latestVersion
679039
+ targetVersion: latestVersion,
679040
+ action: "update-omnius"
678875
679041
  };
678876
679042
  }
678877
679043
  return {
678878
- title: currentVersion ? `Omnius v${currentVersion} is up to date` : "Check for Omnius updates",
678879
- tooltip: "Automatic update checks use the same cached registry result as the CLI and dashboard",
678880
- enabled: false
679044
+ title: currentVersion ? `Check for Omnius updates (v${currentVersion})` : "Check for Omnius updates",
679045
+ tooltip: "Check npm now; automatic checks continue in the background",
679046
+ enabled: Boolean(currentVersion),
679047
+ action: "check-update"
678881
679048
  };
678882
679049
  }
678883
679050
  function uidSuffix() {
@@ -678928,19 +679095,6 @@ function normalizeTrayEndpoint(value2) {
678928
679095
  return null;
678929
679096
  }
678930
679097
  }
678931
- function systemdDaemonEnvironment() {
678932
- if (process.platform !== "linux") return "";
678933
- try {
678934
- const result = spawnSync9(
678935
- "systemctl",
678936
- ["--user", "show", SERVICE_LABEL, "--property", "Environment", "--value"],
678937
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }
678938
- );
678939
- return result.status === 0 ? result.stdout.trim() : "";
678940
- } catch {
678941
- return "";
678942
- }
678943
- }
678944
679098
  function endpointFromServiceEnvironment(value2) {
678945
679099
  const host = value2.match(/(?:^|\s)OMNIUS_HOST=(?:"([^"]+)"|'([^']+)'|([^\s]+))/)?.slice(1).find(Boolean);
678946
679100
  const port = value2.match(/(?:^|\s)OMNIUS_PORT=(?:"(\d+)"|'(\d+)'|(\d+))/)?.slice(1).find(Boolean);
@@ -678952,7 +679106,6 @@ function resolveTrayEndpoint(explicit) {
678952
679106
  process.env["OMNIUS_TRAY_ENDPOINT"],
678953
679107
  process.env["OMNIUS_HOST"],
678954
679108
  process.env["OMNIUS_PORT"],
678955
- endpointFromServiceEnvironment(systemdDaemonEnvironment()),
678956
679109
  DEFAULT_ENDPOINT
678957
679110
  ];
678958
679111
  for (const candidate of candidates) {
@@ -679092,6 +679245,30 @@ function readProcessState(path16) {
679092
679245
  return null;
679093
679246
  }
679094
679247
  }
679248
+ function processCommandLine(pid) {
679249
+ try {
679250
+ if (process.platform === "linux") {
679251
+ return readFileSync95(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
679252
+ }
679253
+ if (process.platform !== "win32") {
679254
+ return spawnSync9("ps", ["-p", String(pid), "-o", "command="], {
679255
+ encoding: "utf8",
679256
+ stdio: ["ignore", "pipe", "ignore"],
679257
+ timeout: 2e3
679258
+ }).stdout.trim();
679259
+ }
679260
+ return spawnSync9("wmic", ["process", "where", `ProcessId=${pid}`, "get", "CommandLine", "/value"], {
679261
+ encoding: "utf8",
679262
+ stdio: ["ignore", "pipe", "ignore"],
679263
+ timeout: 2e3
679264
+ }).stdout;
679265
+ } catch {
679266
+ return "";
679267
+ }
679268
+ }
679269
+ function trayProcessCommandLooksOwned(command) {
679270
+ return /(?:^|\s)tray\s+run(?:\s|$)/i.test(command) && (/(?:^|[\\/\s])omnius(?:[\\/\s]|$)/i.test(command) || /[\\/]dist[\\/]index\.js\b|launcher\.cjs\b/i.test(command));
679271
+ }
679095
679272
  function writeProcessState(paths, state) {
679096
679273
  mkdirSync70(paths.runtimeDir, { recursive: true, mode: 448 });
679097
679274
  const temporary = `${paths.stateFile}.${process.pid}.tmp`;
@@ -679166,6 +679343,34 @@ function resolveTrayLaunchCommand() {
679166
679343
  }
679167
679344
  return null;
679168
679345
  }
679346
+ function installedOmniusLaunchCommand() {
679347
+ try {
679348
+ const result = spawnSync9(process.platform === "win32" ? "where" : "which", ["omnius"], {
679349
+ encoding: "utf8",
679350
+ stdio: ["ignore", "pipe", "ignore"],
679351
+ timeout: 2e3
679352
+ });
679353
+ const first2 = result.stdout?.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
679354
+ return first2 && existsSync117(first2) ? commandForEntrypoint2(realpathSync(first2)) : null;
679355
+ } catch {
679356
+ return null;
679357
+ }
679358
+ }
679359
+ function resolveTrayRegistrationCommand() {
679360
+ return installedOmniusLaunchCommand() ?? resolveTrayLaunchCommand();
679361
+ }
679362
+ function registrationIconPath(launch) {
679363
+ const extension3 = process.platform === "win32" ? "ico" : "png";
679364
+ const entrypoints = [...launch.args, launch.command].filter((candidate) => existsSync117(candidate));
679365
+ for (const entrypoint of entrypoints) {
679366
+ const real = realpathSync(entrypoint);
679367
+ for (const packageRoot of [dirname43(real), join129(dirname43(real), "..")]) {
679368
+ const candidate = join129(packageRoot, "assets", "tray", `omnius-online.${extension3}`);
679369
+ if (existsSync117(candidate)) return candidate;
679370
+ }
679371
+ }
679372
+ return assetPath("online");
679373
+ }
679169
679374
  function desktopExecQuote(value2) {
679170
679375
  return `"${value2.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("$", "\\$").replaceAll("`", "\\`")}"`;
679171
679376
  }
@@ -679219,13 +679424,13 @@ start "" /b ${argv.map(windowsCmdQuote).join(" ")}\r
679219
679424
  throw new Error(`Autostart is not supported on ${platform8}`);
679220
679425
  }
679221
679426
  function writeTrayAutostart(endpoint) {
679222
- const launch = resolveTrayLaunchCommand();
679427
+ const launch = resolveTrayRegistrationCommand();
679223
679428
  if (!launch) throw new Error("Could not resolve the installed Omnius CLI entrypoint");
679224
679429
  const paths = resolveTrayPaths();
679225
679430
  mkdirSync70(dirname43(paths.autostartFile), { recursive: true });
679226
679431
  writeFileSync61(
679227
679432
  paths.autostartFile,
679228
- buildAutostartContent(process.platform, launch, endpoint, assetPath("online")),
679433
+ buildAutostartContent(process.platform, launch, endpoint, registrationIconPath(launch)),
679229
679434
  { encoding: "utf8", mode: process.platform === "win32" ? 448 : 384 }
679230
679435
  );
679231
679436
  return paths.autostartFile;
@@ -679247,44 +679452,12 @@ function uninstallTrayAutostart() {
679247
679452
  unlinkSync23(paths.autostartFile);
679248
679453
  return true;
679249
679454
  }
679250
- function runServiceControl(action) {
679251
- try {
679252
- if (process.platform === "linux") {
679253
- const result = spawnSync9("systemctl", ["--user", action, SERVICE_LABEL], {
679254
- stdio: "ignore",
679255
- timeout: 1e4
679256
- });
679257
- return result.status === 0;
679258
- }
679259
- if (process.platform === "darwin" && typeof process.getuid === "function") {
679260
- const domain = `gui/${process.getuid()}`;
679261
- const plist = join129(homedir40(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
679262
- if (action === "stop") {
679263
- return spawnSync9("launchctl", ["bootout", `${domain}/${LAUNCHD_LABEL}`], { stdio: "ignore", timeout: 1e4 }).status === 0;
679264
- }
679265
- if (action === "restart") {
679266
- return spawnSync9("launchctl", ["kickstart", "-k", `${domain}/${LAUNCHD_LABEL}`], { stdio: "ignore", timeout: 1e4 }).status === 0;
679267
- }
679268
- spawnSync9("launchctl", ["bootstrap", domain, plist], { stdio: "ignore", timeout: 1e4 });
679269
- return spawnSync9("launchctl", ["kickstart", `${domain}/${LAUNCHD_LABEL}`], { stdio: "ignore", timeout: 1e4 }).status === 0;
679270
- }
679271
- if (process.platform === "win32") {
679272
- const args = action === "stop" ? ["/End", "/TN", WINDOWS_TASK_NAME] : ["/Run", "/TN", WINDOWS_TASK_NAME];
679273
- return spawnSync9("schtasks", args, { stdio: "ignore", timeout: 1e4 }).status === 0;
679274
- }
679275
- } catch {
679276
- }
679277
- return false;
679278
- }
679279
679455
  async function controlDaemon(action, endpoint) {
679280
- if (runServiceControl(action)) return true;
679281
- if (action === "stop") return stopDaemon();
679282
- if (action === "restart") {
679283
- stopDaemon();
679284
- await new Promise((resolve87) => setTimeout(resolve87, 500));
679285
- }
679286
679456
  const port = Number(new URL(endpoint).port);
679287
- return await startDaemon(Number.isInteger(port) && port > 0 ? port : void 0) !== null;
679457
+ if (!Number.isInteger(port) || port <= 0) return false;
679458
+ if (action === "stop") return stopDaemonAtPort(port);
679459
+ if (action === "restart") return restartDaemon(port, getLocalCliVersion());
679460
+ return (await ensureDaemonVersion(getLocalCliVersion(), port)).ok;
679288
679461
  }
679289
679462
  function openExternal(target) {
679290
679463
  try {
@@ -679328,7 +679501,7 @@ function menuForHealth(health, endpoint, registered, update2) {
679328
679501
  title: update2.title,
679329
679502
  tooltip: update2.tooltip,
679330
679503
  enabled: update2.enabled,
679331
- action: "update-omnius"
679504
+ action: update2.action
679332
679505
  };
679333
679506
  return {
679334
679507
  healthItem,
@@ -679396,7 +679569,9 @@ async function startTray(explicitEndpoint) {
679396
679569
  if (!trayRequiresRestart(existing, endpoint, liveHealth)) {
679397
679570
  return { ...existing, health: liveHealth };
679398
679571
  }
679399
- await stopTray();
679572
+ if (!await stopTray()) {
679573
+ throw new Error(`Could not stop the existing Omnius indicator on ${existing.endpoint}`);
679574
+ }
679400
679575
  }
679401
679576
  const support = traySupport();
679402
679577
  if (!support.supported) throw new Error(support.reason || "Tray is not supported on this host");
@@ -679447,16 +679622,49 @@ async function stopTray() {
679447
679622
  }
679448
679623
  return false;
679449
679624
  }
679625
+ const state = readProcessState(paths.stateFile);
679626
+ if (state?.pid !== pid || !trayProcessCommandLooksOwned(processCommandLine(pid))) {
679627
+ return false;
679628
+ }
679450
679629
  try {
679451
679630
  process.kill(pid, "SIGTERM");
679452
679631
  } catch {
679453
679632
  return false;
679454
679633
  }
679455
679634
  for (let i2 = 0; i2 < 30; i2++) {
679456
- if (!isProcessAlive2(pid)) return true;
679635
+ if (!isProcessAlive2(pid)) {
679636
+ try {
679637
+ unlinkSync23(paths.pidFile);
679638
+ } catch {
679639
+ }
679640
+ try {
679641
+ unlinkSync23(paths.stateFile);
679642
+ } catch {
679643
+ }
679644
+ return true;
679645
+ }
679457
679646
  await new Promise((resolve87) => setTimeout(resolve87, 100));
679458
679647
  }
679459
- return !isProcessAlive2(pid);
679648
+ if (!trayProcessCommandLooksOwned(processCommandLine(pid))) return false;
679649
+ try {
679650
+ process.kill(pid, "SIGKILL");
679651
+ } catch {
679652
+ }
679653
+ for (let i2 = 0; i2 < 20; i2++) {
679654
+ if (!isProcessAlive2(pid)) {
679655
+ try {
679656
+ unlinkSync23(paths.pidFile);
679657
+ } catch {
679658
+ }
679659
+ try {
679660
+ unlinkSync23(paths.stateFile);
679661
+ } catch {
679662
+ }
679663
+ return true;
679664
+ }
679665
+ await new Promise((resolve87) => setTimeout(resolve87, 100));
679666
+ }
679667
+ return false;
679460
679668
  }
679461
679669
  async function runTrayForeground(explicitEndpoint) {
679462
679670
  const support = traySupport();
@@ -679553,6 +679761,7 @@ async function runTrayForeground(explicitEndpoint) {
679553
679761
  menuState.updateItem.title = updateView.title;
679554
679762
  menuState.updateItem.tooltip = updateView.tooltip;
679555
679763
  menuState.updateItem.enabled = updateView.enabled;
679764
+ menuState.updateItem.action = updateView.action;
679556
679765
  const autostartRegistered = existsSync117(paths.autostartFile);
679557
679766
  const autostartChanged = menuState.autostartItem.checked !== autostartRegistered;
679558
679767
  if (autostartChanged) menuState.autostartItem.checked = autostartRegistered;
@@ -679621,6 +679830,22 @@ async function runTrayForeground(explicitEndpoint) {
679621
679830
  await tray?.sendAction({ type: "update-item", item: menuState.updateItem });
679622
679831
  break;
679623
679832
  }
679833
+ case "check-update": {
679834
+ const currentVersion = health.version;
679835
+ if (!currentVersion) break;
679836
+ availableUpdate = await checkForUpdate(currentVersion, true);
679837
+ updateView = trayUpdatePresentation(
679838
+ currentVersion,
679839
+ availableUpdate?.latestVersion,
679840
+ readUpdateState()
679841
+ );
679842
+ menuState.updateItem.title = updateView.title;
679843
+ menuState.updateItem.tooltip = updateView.tooltip;
679844
+ menuState.updateItem.enabled = updateView.enabled;
679845
+ menuState.updateItem.action = updateView.action;
679846
+ await tray?.sendAction({ type: "update-item", item: menuState.updateItem });
679847
+ break;
679848
+ }
679624
679849
  case "quit":
679625
679850
  await shutdown();
679626
679851
  break;
@@ -679642,7 +679867,7 @@ async function runTrayForeground(explicitEndpoint) {
679642
679867
  releaseTrayPid(paths);
679643
679868
  }
679644
679869
  }
679645
- var DEFAULT_ENDPOINT, TRAY_HELPER_VERSION, POLL_INTERVAL_MS, START_WAIT_MS, SERVICE_LABEL, LAUNCHD_LABEL, WINDOWS_TASK_NAME, EXPECTED_HELPER_SHA256;
679870
+ var DEFAULT_ENDPOINT, TRAY_HELPER_VERSION, POLL_INTERVAL_MS, START_WAIT_MS, EXPECTED_HELPER_SHA256;
679646
679871
  var init_tray = __esm({
679647
679872
  "packages/cli/src/tray.ts"() {
679648
679873
  init_daemon();
@@ -679652,9 +679877,6 @@ var init_tray = __esm({
679652
679877
  TRAY_HELPER_VERSION = "2.1.4";
679653
679878
  POLL_INTERVAL_MS = 1e4;
679654
679879
  START_WAIT_MS = 5e3;
679655
- SERVICE_LABEL = "omnius-daemon.service";
679656
- LAUNCHD_LABEL = "ai.omnius.daemon";
679657
- WINDOWS_TASK_NAME = "OmniusDaemon";
679658
679880
  EXPECTED_HELPER_SHA256 = {
679659
679881
  aix: void 0,
679660
679882
  android: void 0,
@@ -679693,6 +679915,26 @@ function output(status, json = false) {
679693
679915
  `);
679694
679916
  else printStatus(status);
679695
679917
  }
679918
+ function endpointPort(endpoint) {
679919
+ const port = Number(new URL(endpoint).port);
679920
+ if (!Number.isInteger(port) || port <= 0) {
679921
+ throw new Error(`Invalid tray daemon endpoint: ${endpoint}`);
679922
+ }
679923
+ return port;
679924
+ }
679925
+ async function ensureTrayDaemonOnline(endpoint) {
679926
+ const port = endpointPort(endpoint);
679927
+ const daemon = await ensureDaemonVersion(getLocalCliVersion(), port);
679928
+ if (!daemon.ok) {
679929
+ throw new Error(`Could not reconcile the Omnius daemon on port ${port}`);
679930
+ }
679931
+ for (let attempt = 0; attempt < 10; attempt++) {
679932
+ const health = await pollTrayHealth(endpoint);
679933
+ if (health.kind === "online") return;
679934
+ await new Promise((resolve87) => setTimeout(resolve87, 200));
679935
+ }
679936
+ throw new Error(`Omnius daemon did not become online at ${endpoint}`);
679937
+ }
679696
679938
  async function trayCommand(options2) {
679697
679939
  const raw = options2.subCommand || "status";
679698
679940
  if (!SUBCOMMANDS.has(raw)) {
@@ -679701,10 +679943,12 @@ async function trayCommand(options2) {
679701
679943
  const subCommand = raw;
679702
679944
  const endpoint = resolveTrayEndpoint(options2.endpoint);
679703
679945
  if (subCommand === "run") {
679946
+ await ensureTrayDaemonOnline(endpoint);
679704
679947
  await runTrayForeground(endpoint);
679705
679948
  return;
679706
679949
  }
679707
679950
  if (subCommand === "install") {
679951
+ await ensureTrayDaemonOnline(endpoint);
679708
679952
  const registrationFile = installTrayAutostart(endpoint);
679709
679953
  const status = await startTray(endpoint);
679710
679954
  if (!options2.json) process.stdout.write(`Registered tray autostart: ${registrationFile}
@@ -679721,6 +679965,7 @@ async function trayCommand(options2) {
679721
679965
  return;
679722
679966
  }
679723
679967
  if (subCommand === "start") {
679968
+ await ensureTrayDaemonOnline(endpoint);
679724
679969
  output(await startTray(endpoint), options2.json);
679725
679970
  return;
679726
679971
  }
@@ -679732,7 +679977,11 @@ async function trayCommand(options2) {
679732
679977
  return;
679733
679978
  }
679734
679979
  if (subCommand === "restart") {
679735
- await stopTray();
679980
+ await ensureTrayDaemonOnline(endpoint);
679981
+ const status = await getTrayStatus(endpoint);
679982
+ if (status.running && !await stopTray()) {
679983
+ throw new Error(`Could not stop the existing Omnius indicator on ${status.endpoint}`);
679984
+ }
679736
679985
  output(await startTray(endpoint), options2.json);
679737
679986
  return;
679738
679987
  }
@@ -679742,6 +679991,7 @@ var SUBCOMMANDS;
679742
679991
  var init_tray2 = __esm({
679743
679992
  "packages/cli/src/commands/tray.ts"() {
679744
679993
  init_tray();
679994
+ init_daemon();
679745
679995
  SUBCOMMANDS = /* @__PURE__ */ new Set([
679746
679996
  "install",
679747
679997
  "uninstall",
@@ -724558,9 +724808,18 @@ async function runIndicatorCommand(rawAction, operations = DEFAULT_OPERATIONS) {
724558
724808
  daemon
724559
724809
  };
724560
724810
  }
724811
+ operations.register?.(endpoint);
724561
724812
  const started = await operations.start(endpoint);
724813
+ if (!started.running || !started.ready || started.endpoint !== endpoint || started.error) {
724814
+ return {
724815
+ level: "error",
724816
+ message: `Indicator did not bind to ${endpoint}. ` + formatIndicatorStatus(started, daemon),
724817
+ status: started,
724818
+ daemon
724819
+ };
724820
+ }
724562
724821
  const health = await waitForOnlineHealth(endpoint, operations);
724563
- const status = { ...started, endpoint, health };
724822
+ const status = { ...started, health };
724564
724823
  const level = status.error ? "error" : status.running && status.ready && health.kind === "online" ? "info" : "error";
724565
724824
  return {
724566
724825
  level,
@@ -724582,6 +724841,7 @@ var init_indicator_command = __esm({
724582
724841
  init_daemon();
724583
724842
  DEFAULT_OPERATIONS = {
724584
724843
  ensureDaemon: () => ensureDaemonVersion(),
724844
+ register: (endpoint) => installTrayAutostart(endpoint),
724585
724845
  start: (endpoint) => startTray(endpoint),
724586
724846
  status: () => getTrayStatus(),
724587
724847
  health: (endpoint) => pollTrayHealth(endpoint),
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.599",
3
+ "version": "1.0.601",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.599",
9
+ "version": "1.0.601",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -4084,9 +4084,9 @@
4084
4084
  }
4085
4085
  },
4086
4086
  "node_modules/hono": {
4087
- "version": "4.12.34",
4088
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.34.tgz",
4089
- "integrity": "sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==",
4087
+ "version": "4.13.0",
4088
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.0.tgz",
4089
+ "integrity": "sha512-jhunvfHWxd7J5EFfSgH4xsYJzSe/lfqbUCxiyyeaQasUsXeEHXtzVid+7EOGByc5JnFa23SSFL3Y2RV/z1T+eQ==",
4090
4090
  "license": "MIT",
4091
4091
  "engines": {
4092
4092
  "node": ">=16.9.0"
@@ -7675,9 +7675,9 @@
7675
7675
  "license": "ISC"
7676
7676
  },
7677
7677
  "node_modules/ws": {
7678
- "version": "8.21.1",
7679
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
7680
- "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
7678
+ "version": "8.21.2",
7679
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz",
7680
+ "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
7681
7681
  "license": "MIT",
7682
7682
  "engines": {
7683
7683
  "node": ">=10.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.599",
3
+ "version": "1.0.601",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/library.js",