omnius 1.0.530 → 1.0.532
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 +2832 -2316
- package/dist/postinstall-daemon.cjs +112 -6
- package/docs/rest/QUICKREF.md +6 -1
- package/docs/rest/auth-and-scopes.md +15 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -38,6 +38,7 @@ var SERVICE_LABEL = "omnius-daemon";
|
|
|
38
38
|
var LAUNCHD_LABEL = "ai.omnius.daemon";
|
|
39
39
|
var WIN_TASK_NAME = "OmniusDaemon";
|
|
40
40
|
var REQUIRED_AIWG_VERSION = "2026.5.11";
|
|
41
|
+
var INSTALL_STEPS = 7;
|
|
41
42
|
|
|
42
43
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
43
44
|
|
|
@@ -86,6 +87,108 @@ function shellQuote(value) {
|
|
|
86
87
|
return "'" + String(value).replace(/'/g, "'\\''") + "'";
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
function userHomeFor(user) {
|
|
91
|
+
if (!user) return HOME;
|
|
92
|
+
try {
|
|
93
|
+
var current = os.userInfo().username;
|
|
94
|
+
if (user === current || user === process.env.USER || user === process.env.LOGNAME) return HOME;
|
|
95
|
+
} catch (e) {}
|
|
96
|
+
if (IS_WIN) return HOME;
|
|
97
|
+
if (IS_MAC) {
|
|
98
|
+
try {
|
|
99
|
+
var macHome = runCapture("dscl . -read /Users/" + shellQuote(user) + " NFSHomeDirectory").split(/\s+/).pop();
|
|
100
|
+
if (macHome) return macHome;
|
|
101
|
+
} catch (e) {}
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
var pwdEntry = runCapture("getent passwd " + shellQuote(user));
|
|
105
|
+
if (pwdEntry) {
|
|
106
|
+
var parts = pwdEntry.split(":");
|
|
107
|
+
if (parts[5]) return parts[5];
|
|
108
|
+
}
|
|
109
|
+
} catch (e) {}
|
|
110
|
+
return path.join("/home", user);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function chownToUser(file, user) {
|
|
114
|
+
if (IS_WIN || !user || !process.getuid || process.getuid() !== 0) return;
|
|
115
|
+
try {
|
|
116
|
+
var uid = parseInt(runCapture("id -u " + shellQuote(user)), 10);
|
|
117
|
+
var gid = parseInt(runCapture("id -g " + shellQuote(user)), 10);
|
|
118
|
+
if (Number.isFinite(uid) && Number.isFinite(gid)) fs.chownSync(file, uid, gid);
|
|
119
|
+
} catch (e) {}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function envAuthConfigured() {
|
|
123
|
+
var names = [
|
|
124
|
+
"OMNIUS_REST_API_KEYS",
|
|
125
|
+
"OMNIUS_API_KEYS",
|
|
126
|
+
"OMNIUS_REST_API_KEY",
|
|
127
|
+
"OMNIUS_API_KEY",
|
|
128
|
+
"OMNIUS_REST_READ_API_KEY",
|
|
129
|
+
"OMNIUS_READ_API_KEY",
|
|
130
|
+
"OMNIUS_REST_RUN_API_KEY",
|
|
131
|
+
"OMNIUS_RUN_API_KEY",
|
|
132
|
+
"OMNIUS_REST_ADMIN_API_KEY",
|
|
133
|
+
"OMNIUS_ADMIN_API_KEY",
|
|
134
|
+
];
|
|
135
|
+
for (var i = 0; i < names.length; i++) {
|
|
136
|
+
if (process.env[names[i]] && String(process.env[names[i]]).trim()) return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function runtimeKeysExistForUser(user) {
|
|
142
|
+
try {
|
|
143
|
+
var file = process.env.OMNIUS_RUNTIME_KEYS_FILE || path.join(userHomeFor(user), ".omnius", "keys.json");
|
|
144
|
+
if (!fs.existsSync(file)) return false;
|
|
145
|
+
var parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
146
|
+
return Array.isArray(parsed) && parsed.some(function (rec) { return rec && rec.key && !rec.revoked; });
|
|
147
|
+
} catch (e) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function ensureBootstrapApiKeyForUser(user) {
|
|
153
|
+
if (process.env.OMNIUS_SKIP_BOOTSTRAP_KEY === "1") {
|
|
154
|
+
log("OMNIUS_SKIP_BOOTSTRAP_KEY=1 - skipping local REST bootstrap key.");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
var home = userHomeFor(user);
|
|
159
|
+
var dir = path.join(home, ".omnius");
|
|
160
|
+
var file = path.join(dir, "api.key");
|
|
161
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
162
|
+
chownToUser(dir, user);
|
|
163
|
+
if (fs.existsSync(file) && String(fs.readFileSync(file, "utf8")).trim()) {
|
|
164
|
+
try { fs.chmodSync(file, 0o600); } catch (e) {}
|
|
165
|
+
chownToUser(file, user);
|
|
166
|
+
log("Local REST bootstrap key already exists: " + file);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (envAuthConfigured()) {
|
|
170
|
+
log("REST auth env key detected - local bootstrap key not created.");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (runtimeKeysExistForUser(user)) {
|
|
174
|
+
log("Runtime REST keys already exist - local bootstrap key not created.");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
var key = "omnius_bootstrap_" + require("crypto").randomBytes(32).toString("hex");
|
|
178
|
+
var tmp = file + ".tmp." + process.pid + "." + Date.now();
|
|
179
|
+
fs.writeFileSync(tmp, key + "\n", "utf8");
|
|
180
|
+
try { fs.chmodSync(tmp, 0o600); } catch (e) {}
|
|
181
|
+
chownToUser(tmp, user);
|
|
182
|
+
fs.renameSync(tmp, file);
|
|
183
|
+
try { fs.chmodSync(file, 0o600); } catch (e) {}
|
|
184
|
+
chownToUser(file, user);
|
|
185
|
+
log("Created local REST bootstrap key: " + file);
|
|
186
|
+
log("Use /apikey show inside Omnius, then send REST calls with Authorization: Bearer <key>.");
|
|
187
|
+
} catch (e) {
|
|
188
|
+
warn("Could not create local REST bootstrap key (non-fatal): " + (e && e.message ? e.message : String(e)));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
89
192
|
function installedGlobalAiwgVersion() {
|
|
90
193
|
try {
|
|
91
194
|
var globalRoot = runCapture("npm root -g");
|
|
@@ -732,19 +835,22 @@ function repairBrokenWrappers() {
|
|
|
732
835
|
|
|
733
836
|
function main() {
|
|
734
837
|
// Always do the nexus cleanup first, regardless of opt-out.
|
|
735
|
-
progress(1,
|
|
838
|
+
progress(1, INSTALL_STEPS, "Cleaning stale Nexus runtime state");
|
|
736
839
|
cleanNexus();
|
|
737
840
|
|
|
738
841
|
// Auto-repair stale Omnius model wrappers BEFORE restarting the daemon, so the
|
|
739
842
|
// freshly-restarted daemon picks up the rebuilt models on first inference.
|
|
740
|
-
progress(2,
|
|
843
|
+
progress(2, INSTALL_STEPS, "Checking local model wrappers");
|
|
741
844
|
try { repairBrokenWrappers(); } catch (e) {
|
|
742
845
|
warn("wrapper auto-repair crashed (non-fatal): " + (e && e.message));
|
|
743
846
|
}
|
|
744
847
|
|
|
745
|
-
progress(3,
|
|
848
|
+
progress(3, INSTALL_STEPS, "Ensuring AIWG CLI");
|
|
746
849
|
ensureGlobalAiwgInstall();
|
|
747
850
|
|
|
851
|
+
progress(4, INSTALL_STEPS, "Ensuring local REST key");
|
|
852
|
+
ensureBootstrapApiKeyForUser(effectiveUser());
|
|
853
|
+
|
|
748
854
|
if (process.env.OMNIUS_SKIP_DAEMON_INSTALL === "1") {
|
|
749
855
|
log("OMNIUS_SKIP_DAEMON_INSTALL=1 — skipping daemon service install.");
|
|
750
856
|
return safeExit(0);
|
|
@@ -756,7 +862,7 @@ function main() {
|
|
|
756
862
|
// restart can't reach it, so we have to clean up explicitly. Without this,
|
|
757
863
|
// the new service-managed daemon fails to bind port 11435 and the user
|
|
758
864
|
// ends up running stale in-memory code from the previous version.
|
|
759
|
-
progress(
|
|
865
|
+
progress(5, INSTALL_STEPS, "Clearing daemon port");
|
|
760
866
|
forceKillPortHolder(PORT, function (killedCount) {
|
|
761
867
|
if (killedCount > 0) {
|
|
762
868
|
log("Killed " + killedCount + " stale daemon process(es) holding port " + PORT + ".");
|
|
@@ -787,7 +893,7 @@ function runMainAfterKill() {
|
|
|
787
893
|
// idempotent and ensures the unit file matches the current bundle.
|
|
788
894
|
}
|
|
789
895
|
|
|
790
|
-
progress(
|
|
896
|
+
progress(6, INSTALL_STEPS, "Installing daemon service");
|
|
791
897
|
log("Installing Omnius API daemon service for port " + PORT + " ...");
|
|
792
898
|
log(" node: " + nodeBin);
|
|
793
899
|
log(" omnius script: " + omniusScript);
|
|
@@ -818,7 +924,7 @@ function runMainAfterKill() {
|
|
|
818
924
|
}
|
|
819
925
|
|
|
820
926
|
// Wait up to 15s for /health to come up, but don't fail npm install.
|
|
821
|
-
progress(
|
|
927
|
+
progress(7, INSTALL_STEPS, "Verifying daemon health");
|
|
822
928
|
waitForHealth(15000, function (healthy) {
|
|
823
929
|
if (healthy) {
|
|
824
930
|
log("Omnius API daemon is live: http://127.0.0.1:" + PORT + "/health");
|
package/docs/rest/QUICKREF.md
CHANGED
|
@@ -28,6 +28,11 @@ Auth header:
|
|
|
28
28
|
Authorization: Bearer <key>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
Local global installs create a daemon bootstrap key at `~/.omnius/api.key`.
|
|
32
|
+
Inside Omnius, run `/apikey show` to display it, `/apikey copy` to copy it, and
|
|
33
|
+
`/apikey mint run` to create a project runtime key for agents or MCP-style
|
|
34
|
+
REST clients.
|
|
35
|
+
|
|
31
36
|
## Health
|
|
32
37
|
|
|
33
38
|
```bash
|
|
@@ -131,5 +136,5 @@ Requires admin scope:
|
|
|
131
136
|
curl -s -X POST http://127.0.0.1:11435/v1/keys \
|
|
132
137
|
-H 'authorization: Bearer admin-secret' \
|
|
133
138
|
-H 'content-type: application/json' \
|
|
134
|
-
-d '{"scope":"run","
|
|
139
|
+
-d '{"scope":"run","project":"myactuator","rpm":60,"tpd":100000,"max_jobs":3}'
|
|
135
140
|
```
|
|
@@ -37,7 +37,9 @@ Fields:
|
|
|
37
37
|
|
|
38
38
|
## Runtime Keys
|
|
39
39
|
|
|
40
|
-
Runtime keys are stored under `~/.omnius/keys.json` and are checked after environment keys.
|
|
40
|
+
Runtime keys are stored under `~/.omnius/keys.json` by default and are checked after environment keys and the local bootstrap key. Override the store with `OMNIUS_RUNTIME_KEYS_FILE` or put all Omnius state under another directory with `OMNIUS_CONFIG_HOME`.
|
|
41
|
+
|
|
42
|
+
Global installs create a local daemon bootstrap key at `~/.omnius/api.key` if one does not exist. The daemon accepts it as an admin token, so a local operator can start Omnius and run `/apikey show` to reveal it, or `/apikey mint run` to create a project runtime key.
|
|
41
43
|
|
|
42
44
|
| Method | Path | Scope | Purpose |
|
|
43
45
|
| --- | --- | --- | --- |
|
|
@@ -50,7 +52,8 @@ Mint body:
|
|
|
50
52
|
```json
|
|
51
53
|
{
|
|
52
54
|
"scope": "run",
|
|
53
|
-
"
|
|
55
|
+
"project": "myactuator",
|
|
56
|
+
"owner": "project:myactuator",
|
|
54
57
|
"profile": "readonly",
|
|
55
58
|
"rpm": 60,
|
|
56
59
|
"tpd": 100000,
|
|
@@ -58,6 +61,16 @@ Mint body:
|
|
|
58
61
|
}
|
|
59
62
|
```
|
|
60
63
|
|
|
64
|
+
If `owner` is omitted and `project` is provided, Omnius uses `project:<project>` as the audit owner.
|
|
65
|
+
|
|
66
|
+
Agent and MCP-style clients should persist the returned secret in their own secret store and send it as:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Authorization: Bearer <key>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Do not put API keys in query strings. Omnius rejects query-string keys to keep them out of logs and browser history.
|
|
73
|
+
|
|
61
74
|
## Scope Semantics
|
|
62
75
|
|
|
63
76
|
`read` is for inspection:
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.532",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.532",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED