omnius 1.0.728 → 1.0.730

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
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/dist/index.js
3
- size: 38123753 bytes
4
- sha256: e049258d999f7d4d056e6d5c2f2adade3356a8c217233909bd1b60ca6f35be27
3
+ size: 38141493 bytes
4
+ sha256: 129ae1a628f2ee04d633a2a2829eb8b968652fd68b8d93fadf28e3fc72eb1284
@@ -296100,21 +296100,32 @@ async function repairManagedDaemonUnit(port, preferredEntrypoint) {
296100
296100
  return false;
296101
296101
  }
296102
296102
  }
296103
- async function portHolderPids(port) {
296103
+ function daemonListenerLsofArgs(port) {
296104
+ return ["-nP", "-t", "-a", `-iTCP:${port}`, "-sTCP:LISTEN"];
296105
+ }
296106
+ function parsePidList(output) {
296107
+ return output.split(/[\s\n]+/).map((value) => parseInt(value, 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
296108
+ }
296109
+ function parseSsListenerPids(output) {
296110
+ return [...output.matchAll(/\bpid=(\d+)\b/g)].map((match2) => parseInt(match2[1], 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
296111
+ }
296112
+ async function daemonListenerPids(port, dependencies = { run: runUtilityCommand }) {
296104
296113
  try {
296105
- const lsof = await runUtilityCommand("lsof", ["-ti", `:${port}`], 3e3);
296106
- let output = lsof.stdout;
296107
- if (!output.trim()) {
296108
- const fuser = await runUtilityCommand("fuser", [`${port}/tcp`], 3e3);
296109
- output = `${fuser.stdout}
296110
- ${fuser.stderr}`;
296111
- if (!lsof.available && !fuser.available) return null;
296114
+ const lsof = await dependencies.run("lsof", daemonListenerLsofArgs(port), 3e3);
296115
+ if (lsof.available && (lsof.code === 0 || lsof.code === 1)) {
296116
+ return [...new Set(parsePidList(lsof.stdout))];
296112
296117
  }
296113
- return output.split(/[\s\n]+/).map((value) => parseInt(value, 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
296118
+ const ss = await dependencies.run("ss", ["-H", "-ltnp", `sport = :${port}`], 3e3);
296119
+ if (!ss.available || ss.code !== 0) return null;
296120
+ const pids = [...new Set(parseSsListenerPids(ss.stdout))];
296121
+ return ss.stdout.trim() && pids.length === 0 ? null : pids;
296114
296122
  } catch {
296115
296123
  return null;
296116
296124
  }
296117
296125
  }
296126
+ async function portHolderPids(port) {
296127
+ return daemonListenerPids(port);
296128
+ }
296118
296129
  async function daemonPortIsFree(port) {
296119
296130
  return new Promise((resolve10) => {
296120
296131
  const probe = createNetServer();
@@ -296135,8 +296146,7 @@ async function daemonPortIsFree(port) {
296135
296146
  async function waitForDaemonStopped(port, attempts = DAEMON_GRACEFUL_STOP_ATTEMPTS) {
296136
296147
  for (let attempt = 0; attempt < attempts; attempt++) {
296137
296148
  const healthy = await isDaemonRunning(port);
296138
- const holders = await portHolderPids(port);
296139
- const portFree = holders === null ? await daemonPortIsFree(port) : holders.length === 0;
296149
+ const portFree = await daemonPortIsFree(port);
296140
296150
  if (!healthy && portFree) return true;
296141
296151
  await delay(500);
296142
296152
  }
@@ -296152,42 +296162,44 @@ var DEFAULT_RECLAIM_DEPENDENCIES = {
296152
296162
  }),
296153
296163
  waitForFree: (port) => waitForDaemonStopped(port)
296154
296164
  };
296155
- async function reclaimStaleDaemonEndpointClaim(port) {
296165
+ function removeDaemonLockIfUnchanged(port, expected) {
296156
296166
  const lockFile = daemonLockFile(port);
296157
- const record = readDaemonLock(lockFile);
296158
- if (!record) return true;
296159
- if (!await daemonPortIsFree(port)) return true;
296160
- if (!processIsAlive(record.pid)) {
296161
- const current2 = readDaemonLock(lockFile);
296162
- if (current2?.pid === record.pid && current2.token === record.token) {
296163
- try {
296164
- unlinkSync2(lockFile);
296165
- } catch {
296166
- }
296167
- }
296167
+ const current = readDaemonLock(lockFile);
296168
+ if (!current) return true;
296169
+ if (current.pid !== expected.pid || current.token !== expected.token) return false;
296170
+ try {
296171
+ unlinkSync2(lockFile);
296168
296172
  return true;
296173
+ } catch (error) {
296174
+ return error.code === "ENOENT";
296169
296175
  }
296170
- const lease = listProcessLeases({ includeInactive: false }).find(
296176
+ }
296177
+ var DEFAULT_CLAIM_RECLAIM_DEPENDENCIES = {
296178
+ readLock: (port) => readDaemonLock(daemonLockFile(port)),
296179
+ portIsFree: (port) => daemonPortIsFree(port),
296180
+ processIsAlive: (pid) => processIsAlive(pid),
296181
+ leases: () => listProcessLeases({ includeInactive: false }),
296182
+ stopLease: (leaseId, port) => stopProcessLease(leaseId, {
296183
+ reason: `stale daemon endpoint claim on port ${port}`,
296184
+ termGraceMs: 1e3
296185
+ }),
296186
+ removeLockIfUnchanged: (port, expected) => removeDaemonLockIfUnchanged(port, expected)
296187
+ };
296188
+ async function reclaimStaleDaemonEndpointClaim(port, verifiedStoppedPids = /* @__PURE__ */ new Set(), dependencies = DEFAULT_CLAIM_RECLAIM_DEPENDENCIES) {
296189
+ const record = dependencies.readLock(port);
296190
+ if (!record) return dependencies.portIsFree(port);
296191
+ if (!await dependencies.portIsFree(port)) return false;
296192
+ const clearExactClaim = async () => dependencies.removeLockIfUnchanged(port, record) && dependencies.portIsFree(port);
296193
+ if (verifiedStoppedPids.has(record.pid) || !dependencies.processIsAlive(record.pid)) {
296194
+ return clearExactClaim();
296195
+ }
296196
+ const lease = dependencies.leases().find(
296171
296197
  (item) => item.status === "active" && item.pid === record.pid && item.ownerKind === "daemon" && item.ownerId === `daemon:${port}`
296172
296198
  );
296173
296199
  if (!lease) return false;
296174
- const stopped = await stopProcessLease(lease.leaseId, {
296175
- reason: `stale daemon endpoint claim on port ${port}`,
296176
- termGraceMs: 1e3
296177
- });
296200
+ const stopped = await dependencies.stopLease(lease.leaseId, port);
296178
296201
  if (stopped.action !== "killed" && stopped.action !== "dead") return false;
296179
- for (let attempt = 0; attempt < 20 && processIsAlive(record.pid); attempt++) {
296180
- await delay(100);
296181
- }
296182
- if (processIsAlive(record.pid)) return false;
296183
- const current = readDaemonLock(lockFile);
296184
- if (current?.pid === record.pid && current.token === record.token) {
296185
- try {
296186
- unlinkSync2(lockFile);
296187
- } catch {
296188
- }
296189
- }
296190
- return daemonPortIsFree(port);
296202
+ return clearExactClaim();
296191
296203
  }
296192
296204
  async function reclaimOwnedDaemonListener(port = getDaemonPort(), dependencies = DEFAULT_RECLAIM_DEPENDENCIES) {
296193
296205
  const holders = await dependencies.holderPids(port);
@@ -296269,9 +296281,9 @@ async function restartDaemon(port, expectedVersion, preferredEntrypoint) {
296269
296281
  const managed = await managedDaemonServiceMatchesPort(p);
296270
296282
  if (managed) {
296271
296283
  if (!await managedDaemonServiceOwnsPort(p)) {
296272
- const reclaimed = await reclaimOwnedDaemonListener(p);
296273
- if (!reclaimed.ok) return false;
296274
- await reclaimStaleDaemonEndpointClaim(p);
296284
+ const reclaimed2 = await reclaimOwnedDaemonListener(p);
296285
+ if (!reclaimed2.ok) return false;
296286
+ await reclaimStaleDaemonEndpointClaim(p, new Set(reclaimed2.clearedPids));
296275
296287
  }
296276
296288
  await runUserSystemctl(["reset-failed", "omnius-daemon.service"]);
296277
296289
  const restarted = await runUserSystemctl(["restart", "omnius-daemon.service"]);
@@ -296286,15 +296298,13 @@ async function restartDaemon(port, expectedVersion, preferredEntrypoint) {
296286
296298
  }
296287
296299
  await runUserSystemctl(["stop", "omnius-daemon.service"]);
296288
296300
  if (!await waitForDaemonStopped(p)) {
296289
- const reclaimed = await reclaimOwnedDaemonListener(p);
296290
- if (!reclaimed.ok) return false;
296301
+ const reclaimed2 = await reclaimOwnedDaemonListener(p);
296302
+ if (!reclaimed2.ok) return false;
296291
296303
  }
296292
296304
  }
296293
- if (await isDaemonRunning(p)) {
296294
- const reclaimed = await reclaimOwnedDaemonListener(p);
296295
- if (!reclaimed.ok) return false;
296296
- }
296297
- if (!await reclaimStaleDaemonEndpointClaim(p)) return false;
296305
+ const reclaimed = await reclaimOwnedDaemonListener(p);
296306
+ if (!reclaimed.ok) return false;
296307
+ if (!await reclaimStaleDaemonEndpointClaim(p, new Set(reclaimed.clearedPids))) return false;
296298
296308
  const pid = await startDaemon(p, preferredEntrypoint);
296299
296309
  if (!pid) return false;
296300
296310
  return (await waitForDaemonReady(p, expectedVersion)).ok;
@@ -296404,25 +296414,27 @@ async function startDaemon(port = getDaemonPort(), preferredEntrypoint) {
296404
296414
  }
296405
296415
  }
296406
296416
  }
296407
- async function stopDaemonAtPort(port = getDaemonPort()) {
296408
- if (await managedDaemonServiceMatchesPort(port)) {
296409
- const stopped = await runUserSystemctl(["stop", "omnius-daemon.service"]);
296410
- if (stopped.ok && await waitForDaemonStopped(port)) return true;
296417
+ var DEFAULT_DAEMON_STOP_DEPENDENCIES = {
296418
+ managedServiceMatchesPort: (port) => managedDaemonServiceMatchesPort(port),
296419
+ stopManagedService: async () => (await runUserSystemctl(["stop", "omnius-daemon.service"])).ok,
296420
+ waitForStopped: (port) => waitForDaemonStopped(port),
296421
+ reclaimListener: (port) => reclaimOwnedDaemonListener(port),
296422
+ reclaimClaim: (port, verifiedStoppedPids) => reclaimStaleDaemonEndpointClaim(port, verifiedStoppedPids)
296423
+ };
296424
+ async function stopDaemonAtPort(port = getDaemonPort(), dependencies = DEFAULT_DAEMON_STOP_DEPENDENCIES) {
296425
+ if (await dependencies.managedServiceMatchesPort(port)) {
296426
+ const stopped = await dependencies.stopManagedService();
296427
+ if (stopped && await dependencies.waitForStopped(port)) return true;
296411
296428
  }
296412
- const wasRunning = await isDaemonRunning(port);
296413
- const reclaimed = await reclaimOwnedDaemonListener(port);
296429
+ const reclaimed = await dependencies.reclaimListener(port);
296414
296430
  if (!reclaimed.ok) return false;
296415
- const claimCleared = await reclaimStaleDaemonEndpointClaim(port);
296416
- return claimCleared && (wasRunning || reclaimed.action === "cleared");
296431
+ const claimCleared = await dependencies.reclaimClaim(
296432
+ port,
296433
+ new Set(reclaimed.clearedPids)
296434
+ );
296435
+ return claimCleared && dependencies.waitForStopped(port);
296417
296436
  }
296418
296437
  async function quiesceDaemonForUpdate(port = getDaemonPort()) {
296419
- if (await managedDaemonServiceMatchesPort(port)) {
296420
- const stopped = await runUserSystemctl(["stop", "omnius-daemon.service"]);
296421
- if (stopped.ok && await waitForDaemonStopped(port)) return true;
296422
- }
296423
- if (!await isDaemonRunning(port)) {
296424
- return daemonPortIsFree(port);
296425
- }
296426
296438
  return stopDaemonAtPort(port);
296427
296439
  }
296428
296440
 
@@ -296662,6 +296674,19 @@ function transition(current, patch, paths) {
296662
296674
  function permissionRemediation(evidence) {
296663
296675
  return /EACCES|EPERM|permission denied/i.test(evidence) ? "The discovered npm global prefix is not writable. Configure a user-owned npm prefix or rerun the explicit update from a privileged terminal; Omnius never silently elevates." : void 0;
296664
296676
  }
296677
+ async function quiesceDaemonWithRetry(quiesce, attempts = 3, pauseMs = 250) {
296678
+ const boundedAttempts = Math.max(1, Math.min(5, Math.floor(attempts)));
296679
+ for (let attempt = 1; attempt <= boundedAttempts; attempt++) {
296680
+ try {
296681
+ if (await quiesce()) return true;
296682
+ } catch {
296683
+ }
296684
+ if (attempt < boundedAttempts && pauseMs > 0) {
296685
+ await new Promise((resolve10) => setTimeout(resolve10, pauseMs));
296686
+ }
296687
+ }
296688
+ return false;
296689
+ }
296665
296690
  function installGlobalPackageStreaming(input) {
296666
296691
  return new Promise((resolve10) => {
296667
296692
  const stderrTail = [];
@@ -296740,7 +296765,7 @@ async function runVerifiedUpdateTransaction(initial, dependencies, paths = resol
296740
296765
  try {
296741
296766
  if (dependencies.quiesceDaemon) {
296742
296767
  state = transition(state, { phase: "daemon_quiescing" }, paths);
296743
- if (!await dependencies.quiesceDaemon()) {
296768
+ if (!await quiesceDaemonWithRetry(dependencies.quiesceDaemon)) {
296744
296769
  throw new Error(
296745
296770
  `Could not safely stop the daemon at ${state.daemon_endpoint ?? "the configured endpoint"} before updating`
296746
296771
  );
@@ -5680,7 +5680,7 @@
5680
5680
  "id": "api.v1-chat",
5681
5681
  "kind": "api",
5682
5682
  "title": "/v1/chat",
5683
- "summary": "Stateful chat session with full agent tool access (OpenAI-compatible response shape)",
5683
+ "summary": "Stateful direct chat with explicit autonomous-agent opt-in",
5684
5684
  "aliases": [
5685
5685
  "/v1/chat"
5686
5686
  ],
@@ -5729,8 +5729,8 @@
5729
5729
  ],
5730
5730
  "operations": {
5731
5731
  "post": {
5732
- "summary": "Stateful chat session with full agent tool access (OpenAI-compatible response shape)",
5733
- "description": "Drop-in replacement for OpenAI /v1/chat/completions and Ollama /api/chat. By default the request runs the FULL Omnius agent stack (tools, multi-agent, memory, skills) under the hood and returns an OpenAI chat.completion shape on success. Set tools=false to bypass the agent and forward straight to the configured backend (fast path).",
5732
+ "summary": "Stateful direct chat with explicit autonomous-agent opt-in",
5733
+ "description": "Drop-in replacement for OpenAI /v1/chat/completions and Ollama /api/chat. Requests use direct backend inference by default. Set tools=true or use_tools=true to explicitly run the full Omnius autonomous-agent stack. Explicit agent runs have a daemon-enforced whole-run deadline and duplicate-work suppression.",
5734
5734
  "tags": [
5735
5735
  "Chat"
5736
5736
  ],
@@ -5781,8 +5781,27 @@
5781
5781
  },
5782
5782
  "tools": {
5783
5783
  "type": "boolean",
5784
- "default": true,
5785
- "description": "true (default) = full agent. false = direct backend chat. realtime=true also uses direct backend chat."
5784
+ "default": false,
5785
+ "description": "Set true to explicitly launch the full autonomous agent. Omitted or false uses direct backend chat."
5786
+ },
5787
+ "use_tools": {
5788
+ "type": "boolean",
5789
+ "default": false,
5790
+ "description": "Omnius-native alias for tools=true; the built-in web UI uses this explicit opt-in."
5791
+ },
5792
+ "timeout_s": {
5793
+ "type": "number",
5794
+ "minimum": 0,
5795
+ "maximum": 3600,
5796
+ "default": 180,
5797
+ "description": "Per-backend-request liveness timeout passed to the agent CLI."
5798
+ },
5799
+ "agent_timeout_s": {
5800
+ "type": "number",
5801
+ "minimum": 0.05,
5802
+ "maximum": 3600,
5803
+ "default": 180,
5804
+ "description": "Daemon-enforced whole-agent wall-clock deadline. Distinct from timeout_s."
5786
5805
  }
5787
5806
  }
5788
5807
  }
package/docs/DISCOVERY.md CHANGED
@@ -115,7 +115,7 @@ Daemon equivalents are `GET /v1/discovery/bootstrap`, `GET /v1/discovery?q=<inte
115
115
  | `api.v1-audio-speech` | /v1/audio/speech | OpenAI-compatible alias of /v1/voice/tts (input/voice/response_format names) |
116
116
  | `api.v1-audio-transcriptions` | /v1/audio/transcriptions | OpenAI-compatible alias of /v1/asr/transcriptions |
117
117
  | `api.v1-audit` | /v1/audit | Query audit log |
118
- | `api.v1-chat` | /v1/chat | Stateful chat session with full agent tool access (OpenAI-compatible response shape) |
118
+ | `api.v1-chat` | /v1/chat | Stateful direct chat with explicit autonomous-agent opt-in |
119
119
  | `api.v1-chat-attachments` | /v1/chat/attachments | Upload an attachment for a stateful chat |
120
120
  | `api.v1-chat-check-in` | /v1/chat/check-in | Send a steering check-in to the active chat session — returns model inference + queued steering_packet |
121
121
  | `api.v1-chat-completions` | /v1/chat/completions | OpenAI-compatible chat completion (with optional server-side agent loop) |
@@ -71,7 +71,7 @@ Realtime example:
71
71
 
72
72
  ## `/v1/chat`
73
73
 
74
- This is the Omnius stateful chat endpoint. By default it runs the full Omnius agent stack with tools, memory, skills, and multi-agent context. Set `tools: false` to use the fast direct backend path. `realtime: true` also uses the direct backend path.
74
+ This is the Omnius stateful chat endpoint. It uses direct backend inference by default. Set `tools: true` or `use_tools: true` to explicitly launch the full Omnius agent stack with tools, memory, skills, and multi-agent context. `realtime: true` always uses the direct backend path. Explicit agent runs default to a 180-second daemon-owned wall-clock deadline and reject equivalent concurrent work even when callers omit `session_id`.
75
75
 
76
76
  Body fields:
77
77
 
@@ -81,7 +81,10 @@ Body fields:
81
81
  | `model` | string | Optional model override |
82
82
  | `session_id` | string | Reuse or name a session |
83
83
  | `stream` | boolean | Stream when supported |
84
- | `tools` | boolean | Full agent stack by default |
84
+ | `tools` | boolean | Set true to explicitly launch the full agent stack |
85
+ | `use_tools` | boolean | Omnius-native alias for `tools: true` |
86
+ | `timeout_s` | number | Per-backend-request liveness timeout |
87
+ | `agent_timeout_s` | number | Whole-agent daemon deadline, default 180 seconds and maximum 3600 |
85
88
  | `realtime` | boolean | Short ASR/TTS conversation mode |
86
89
  | `realtime_options` | object | Realtime settings |
87
90
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.728",
3
+ "version": "1.0.730",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.728",
9
+ "version": "1.0.730",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.728",
3
+ "version": "1.0.730",
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",