@automagik/omni 2.260430.3 → 2.260430.5
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/commands/trust.d.ts +19 -0
- package/dist/commands/trust.d.ts.map +1 -0
- package/dist/index.js +98 -1
- package/dist/server/index.js +68 -3
- package/package.json +10 -10
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust Commands — manage genie host fingerprint registrations.
|
|
3
|
+
*
|
|
4
|
+
* omni trust list List active genie hosts
|
|
5
|
+
* omni trust get <id> Show one host (active or revoked)
|
|
6
|
+
* omni trust update <id> --scope <a,b,c> Replace host scopes wholesale
|
|
7
|
+
* omni trust revoke <id> Soft-delete (stamps revoked_at)
|
|
8
|
+
*
|
|
9
|
+
* Wish: omni-host-fingerprint-trust, Group 1.2. Talks to the
|
|
10
|
+
* `/api/v2/trust/hosts` endpoints landed in Group 1.1 (#556).
|
|
11
|
+
*
|
|
12
|
+
* Why raw fetch instead of the OmniClient SDK: trust types aren't in the
|
|
13
|
+
* OpenAPI spec yet (the SDK is generated from there). Adding them requires
|
|
14
|
+
* a regen + version bump; out of scope for this PR. We use the same
|
|
15
|
+
* baseUrl / apiKey the SDK uses, so behavior is identical.
|
|
16
|
+
*/
|
|
17
|
+
import { Command } from 'commander';
|
|
18
|
+
export declare function createTrustCommand(): Command;
|
|
19
|
+
//# sourceMappingURL=trust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../src/commands/trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwHpC,wBAAgB,kBAAkB,IAAI,OAAO,CAmB5C"}
|
package/dist/index.js
CHANGED
|
@@ -113981,7 +113981,7 @@ import { fileURLToPath } from "url";
|
|
|
113981
113981
|
// package.json
|
|
113982
113982
|
var package_default = {
|
|
113983
113983
|
name: "@automagik/omni",
|
|
113984
|
-
version: "2.260430.
|
|
113984
|
+
version: "2.260430.5",
|
|
113985
113985
|
description: "LLM-optimized CLI for Omni",
|
|
113986
113986
|
type: "module",
|
|
113987
113987
|
bin: {
|
|
@@ -124980,6 +124980,97 @@ function createStopCommand() {
|
|
|
124980
124980
|
return new Command("stop").description("Stop all omni PM2 processes").action(runStop);
|
|
124981
124981
|
}
|
|
124982
124982
|
|
|
124983
|
+
// src/commands/trust.ts
|
|
124984
|
+
init_config();
|
|
124985
|
+
init_output();
|
|
124986
|
+
function trustEndpoint(path) {
|
|
124987
|
+
if (!hasAuth()) {
|
|
124988
|
+
error("Not authenticated. Run: omni auth login --api-key <key>", undefined, 2);
|
|
124989
|
+
}
|
|
124990
|
+
const config2 = loadConfig();
|
|
124991
|
+
const baseUrl = (config2.apiUrl ?? "http://localhost:8882").replace(/\/+$/, "");
|
|
124992
|
+
return `${baseUrl}/api/v2/trust${path}`;
|
|
124993
|
+
}
|
|
124994
|
+
function authHeaders() {
|
|
124995
|
+
const config2 = loadConfig();
|
|
124996
|
+
const headers = { "Content-Type": "application/json" };
|
|
124997
|
+
if (config2.apiKey) {
|
|
124998
|
+
headers.Authorization = `Bearer ${config2.apiKey}`;
|
|
124999
|
+
}
|
|
125000
|
+
return headers;
|
|
125001
|
+
}
|
|
125002
|
+
async function callApi(method, path, body) {
|
|
125003
|
+
const res = await fetch(trustEndpoint(path), {
|
|
125004
|
+
method,
|
|
125005
|
+
headers: authHeaders(),
|
|
125006
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
125007
|
+
});
|
|
125008
|
+
if (!res.ok) {
|
|
125009
|
+
const text3 = await res.text().catch(() => "");
|
|
125010
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}${text3 ? `: ${text3}` : ""}`);
|
|
125011
|
+
}
|
|
125012
|
+
return await res.json();
|
|
125013
|
+
}
|
|
125014
|
+
function formatHostRow(host) {
|
|
125015
|
+
return {
|
|
125016
|
+
id: host.id.slice(0, 8),
|
|
125017
|
+
hostname: host.hostname,
|
|
125018
|
+
scopes: host.scopes.join(", ") || "(none)",
|
|
125019
|
+
pubkeyPrefix: `${host.pubkey.slice(0, 12)}\u2026`,
|
|
125020
|
+
lastSeen: host.lastSeenAt ? new Date(host.lastSeenAt).toISOString().replace("T", " ").slice(0, 16) : "never",
|
|
125021
|
+
status: host.revokedAt ? "revoked" : "active"
|
|
125022
|
+
};
|
|
125023
|
+
}
|
|
125024
|
+
async function handleList4() {
|
|
125025
|
+
try {
|
|
125026
|
+
const { items } = await callApi("GET", "/hosts");
|
|
125027
|
+
list(items.map(formatHostRow), {
|
|
125028
|
+
emptyMessage: "No genie hosts registered. Run `genie omni handshake` from a genie installation to register one.",
|
|
125029
|
+
rawData: items
|
|
125030
|
+
});
|
|
125031
|
+
} catch (err2) {
|
|
125032
|
+
error(`Failed to list genie hosts: ${err2 instanceof Error ? err2.message : "Unknown error"}`);
|
|
125033
|
+
}
|
|
125034
|
+
}
|
|
125035
|
+
async function handleGet3(id) {
|
|
125036
|
+
try {
|
|
125037
|
+
const { data: data2 } = await callApi("GET", `/hosts/${encodeURIComponent(id)}`);
|
|
125038
|
+
data(data2);
|
|
125039
|
+
} catch (err2) {
|
|
125040
|
+
error(`Failed to get genie host: ${err2 instanceof Error ? err2.message : "Unknown error"}`);
|
|
125041
|
+
}
|
|
125042
|
+
}
|
|
125043
|
+
async function handleUpdate3(id, options3) {
|
|
125044
|
+
const scopes = options3.scope.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
125045
|
+
if (scopes.length === 0) {
|
|
125046
|
+
error("--scope must contain at least one scope (use `omni trust revoke <id>` to deny everything).");
|
|
125047
|
+
}
|
|
125048
|
+
try {
|
|
125049
|
+
const { data: data2 } = await callApi("PATCH", `/hosts/${encodeURIComponent(id)}`, { scopes });
|
|
125050
|
+
success(`Updated genie host ${data2.id} scopes: ${data2.scopes.join(", ")}`);
|
|
125051
|
+
data(data2);
|
|
125052
|
+
} catch (err2) {
|
|
125053
|
+
error(`Failed to update genie host: ${err2 instanceof Error ? err2.message : "Unknown error"}`);
|
|
125054
|
+
}
|
|
125055
|
+
}
|
|
125056
|
+
async function handleRevoke2(id) {
|
|
125057
|
+
try {
|
|
125058
|
+
const { data: data2 } = await callApi("DELETE", `/hosts/${encodeURIComponent(id)}`);
|
|
125059
|
+
success(`Revoked genie host ${data2.id} (${data2.hostname}). Tombstone kept for audit.`);
|
|
125060
|
+
data(data2);
|
|
125061
|
+
} catch (err2) {
|
|
125062
|
+
error(`Failed to revoke genie host: ${err2 instanceof Error ? err2.message : "Unknown error"}`);
|
|
125063
|
+
}
|
|
125064
|
+
}
|
|
125065
|
+
function createTrustCommand() {
|
|
125066
|
+
const trust = new Command("trust").description("Manage genie host fingerprint registrations");
|
|
125067
|
+
trust.command("list").description("List active (non-revoked) genie hosts").action(handleList4);
|
|
125068
|
+
trust.command("get <id>").description("Show details for one genie host (active or revoked)").action(handleGet3);
|
|
125069
|
+
trust.command("update <id>").description("Replace a genie host scopes (comma-separated)").requiredOption("--scope <list>", 'Comma-separated scope list, e.g. "agents:write,providers:write"').action(handleUpdate3);
|
|
125070
|
+
trust.command("revoke <id>").description("Revoke a genie host (irreversible \u2014 re-register with a fresh keypair to restore trust)").action(handleRevoke2);
|
|
125071
|
+
return trust;
|
|
125072
|
+
}
|
|
125073
|
+
|
|
124983
125074
|
// src/commands/tts.ts
|
|
124984
125075
|
init_output();
|
|
124985
125076
|
function createTtsCommand() {
|
|
@@ -126213,6 +126304,12 @@ var COMMANDS = [
|
|
|
126213
126304
|
helpGroup: "Management",
|
|
126214
126305
|
helpDescription: "API key management"
|
|
126215
126306
|
},
|
|
126307
|
+
{
|
|
126308
|
+
create: createTrustCommand,
|
|
126309
|
+
category: "advanced",
|
|
126310
|
+
helpGroup: "Management",
|
|
126311
|
+
helpDescription: "Genie host fingerprint trust (omni-host-fingerprint-trust wish)"
|
|
126312
|
+
},
|
|
126216
126313
|
{
|
|
126217
126314
|
create: createAccessCommand,
|
|
126218
126315
|
category: "advanced",
|
package/dist/server/index.js
CHANGED
|
@@ -224556,7 +224556,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
224556
224556
|
var require_package8 = __commonJS((exports, module) => {
|
|
224557
224557
|
module.exports = {
|
|
224558
224558
|
name: "@omni/api",
|
|
224559
|
-
version: "2.260430.
|
|
224559
|
+
version: "2.260430.5",
|
|
224560
224560
|
type: "module",
|
|
224561
224561
|
exports: {
|
|
224562
224562
|
".": {
|
|
@@ -241417,6 +241417,17 @@ var init_scope_enforcer = __esm(() => {
|
|
|
241417
241417
|
});
|
|
241418
241418
|
|
|
241419
241419
|
// ../api/src/middleware/require-signed-instance.ts
|
|
241420
|
+
function isUnlockOnlyBody(body) {
|
|
241421
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
241422
|
+
return false;
|
|
241423
|
+
const obj = body;
|
|
241424
|
+
const keys = Object.keys(obj);
|
|
241425
|
+
if (keys.length !== 1)
|
|
241426
|
+
return false;
|
|
241427
|
+
if (keys[0] !== "requireGenieSignature")
|
|
241428
|
+
return false;
|
|
241429
|
+
return obj.requireGenieSignature === false;
|
|
241430
|
+
}
|
|
241420
241431
|
async function safeReadJsonBody2(c) {
|
|
241421
241432
|
const method = c.req.method.toUpperCase();
|
|
241422
241433
|
if (method === "GET" || method === "DELETE" || method === "HEAD" || method === "OPTIONS")
|
|
@@ -241462,6 +241473,13 @@ var init_require_signed_instance = __esm(() => {
|
|
|
241462
241473
|
if (signedBy) {
|
|
241463
241474
|
return next();
|
|
241464
241475
|
}
|
|
241476
|
+
if (method === "PATCH" && isUnlockOnlyBody(body)) {
|
|
241477
|
+
log61.info("allowing unlock-only PATCH on require_genie_signature instance", {
|
|
241478
|
+
instanceId: instance4.id,
|
|
241479
|
+
apiKeyId: c.get("apiKey")?.id
|
|
241480
|
+
});
|
|
241481
|
+
return next();
|
|
241482
|
+
}
|
|
241465
241483
|
const apiKey = c.get("apiKey");
|
|
241466
241484
|
log61.warn("rejecting unsigned request to require_genie_signature instance", {
|
|
241467
241485
|
instanceId: instance4.id,
|
|
@@ -241472,7 +241490,7 @@ var init_require_signed_instance = __esm(() => {
|
|
|
241472
241490
|
return c.json({
|
|
241473
241491
|
error: {
|
|
241474
241492
|
code: "GENIE_SIGNATURE_REQUIRED",
|
|
241475
|
-
message: `Instance ${instance4.id} requires a verified X-Genie-Signature; bearer-only requests are rejected. Sign with \`genie omni handshake\` + per-request signing, or
|
|
241493
|
+
message: `Instance ${instance4.id} requires a verified X-Genie-Signature; bearer-only requests are rejected. Sign with \`genie omni handshake\` + per-request signing, or unlock with PATCH /api/v2/instances/${instance4.id} body {"requireGenieSignature": false} (always allowed via bearer to prevent operator lockout).`,
|
|
241476
241494
|
instance: instance4.id
|
|
241477
241495
|
}
|
|
241478
241496
|
}, 401);
|
|
@@ -281176,6 +281194,21 @@ class GenieHostsService {
|
|
|
281176
281194
|
async touchLastSeen(id) {
|
|
281177
281195
|
await this.db.update(genieHosts).set({ lastSeenAt: new Date, updatedAt: new Date }).where(and2(eq(genieHosts.id, id), isNull2(genieHosts.revokedAt)));
|
|
281178
281196
|
}
|
|
281197
|
+
async updateScopes(id, scopes) {
|
|
281198
|
+
const [updated] = await this.db.update(genieHosts).set({ scopes, updatedAt: new Date }).where(and2(eq(genieHosts.id, id), isNull2(genieHosts.revokedAt))).returning();
|
|
281199
|
+
if (updated) {
|
|
281200
|
+
log87.info("genie host scopes updated", { hostId: updated.id, scopes });
|
|
281201
|
+
}
|
|
281202
|
+
return updated ?? null;
|
|
281203
|
+
}
|
|
281204
|
+
async revoke(id) {
|
|
281205
|
+
const now = new Date;
|
|
281206
|
+
const [revoked] = await this.db.update(genieHosts).set({ revokedAt: now, updatedAt: now }).where(and2(eq(genieHosts.id, id), isNull2(genieHosts.revokedAt))).returning();
|
|
281207
|
+
if (revoked) {
|
|
281208
|
+
log87.info("genie host revoked", { hostId: revoked.id, hostname: revoked.hostname });
|
|
281209
|
+
}
|
|
281210
|
+
return revoked ?? null;
|
|
281211
|
+
}
|
|
281179
281212
|
}
|
|
281180
281213
|
var log87;
|
|
281181
281214
|
var init_genie_hosts = __esm(() => {
|
|
@@ -302631,7 +302664,7 @@ var init_settings3 = __esm(() => {
|
|
|
302631
302664
|
});
|
|
302632
302665
|
|
|
302633
302666
|
// ../api/src/routes/v2/trust.ts
|
|
302634
|
-
var trustRoutes, PUBKEY_PATTERN, handshakeSchema;
|
|
302667
|
+
var trustRoutes, PUBKEY_PATTERN, handshakeSchema, idParamSchema6, updateScopesSchema;
|
|
302635
302668
|
var init_trust = __esm(() => {
|
|
302636
302669
|
init_dist6();
|
|
302637
302670
|
init_dist2();
|
|
@@ -302658,6 +302691,38 @@ var init_trust = __esm(() => {
|
|
|
302658
302691
|
const items = await services.genieHosts.listActive();
|
|
302659
302692
|
return c.json({ items });
|
|
302660
302693
|
});
|
|
302694
|
+
idParamSchema6 = exports_external.object({ id: exports_external.string().uuid() });
|
|
302695
|
+
trustRoutes.get("/hosts/:id", zValidator("param", idParamSchema6), async (c) => {
|
|
302696
|
+
const { id } = c.req.valid("param");
|
|
302697
|
+
const services = c.get("services");
|
|
302698
|
+
const host = await services.genieHosts.findById(id);
|
|
302699
|
+
if (!host) {
|
|
302700
|
+
return c.json({ error: { code: "NOT_FOUND", message: `genie host ${id} not found` } }, 404);
|
|
302701
|
+
}
|
|
302702
|
+
return c.json({ data: host });
|
|
302703
|
+
});
|
|
302704
|
+
updateScopesSchema = exports_external.object({
|
|
302705
|
+
scopes: exports_external.array(exports_external.string().min(1)).max(64)
|
|
302706
|
+
});
|
|
302707
|
+
trustRoutes.patch("/hosts/:id", zValidator("param", idParamSchema6), zValidator("json", updateScopesSchema), async (c) => {
|
|
302708
|
+
const { id } = c.req.valid("param");
|
|
302709
|
+
const { scopes } = c.req.valid("json");
|
|
302710
|
+
const services = c.get("services");
|
|
302711
|
+
const host = await services.genieHosts.updateScopes(id, scopes);
|
|
302712
|
+
if (!host) {
|
|
302713
|
+
return c.json({ error: { code: "NOT_FOUND", message: `genie host ${id} not found or revoked` } }, 404);
|
|
302714
|
+
}
|
|
302715
|
+
return c.json({ data: host });
|
|
302716
|
+
});
|
|
302717
|
+
trustRoutes.delete("/hosts/:id", zValidator("param", idParamSchema6), async (c) => {
|
|
302718
|
+
const { id } = c.req.valid("param");
|
|
302719
|
+
const services = c.get("services");
|
|
302720
|
+
const host = await services.genieHosts.revoke(id);
|
|
302721
|
+
if (!host) {
|
|
302722
|
+
return c.json({ error: { code: "NOT_FOUND", message: `genie host ${id} not found or already revoked` } }, 404);
|
|
302723
|
+
}
|
|
302724
|
+
return c.json({ data: host });
|
|
302725
|
+
});
|
|
302661
302726
|
});
|
|
302662
302727
|
|
|
302663
302728
|
// ../api/src/routes/v2/turns.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automagik/omni",
|
|
3
|
-
"version": "2.260430.
|
|
3
|
+
"version": "2.260430.5",
|
|
4
4
|
"description": "LLM-optimized CLI for Omni",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,15 +50,15 @@
|
|
|
50
50
|
"qrcode-terminal": "^0.12.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@omni/api": "2.260430.
|
|
54
|
-
"@omni/channel-discord": "2.260430.
|
|
55
|
-
"@omni/channel-gupshup": "2.260430.
|
|
56
|
-
"@omni/channel-sdk": "2.260430.
|
|
57
|
-
"@omni/channel-slack": "2.260430.
|
|
58
|
-
"@omni/channel-telegram": "2.260430.
|
|
59
|
-
"@omni/channel-whatsapp": "2.260430.
|
|
60
|
-
"@omni/core": "2.260430.
|
|
61
|
-
"@omni/sdk": "2.260430.
|
|
53
|
+
"@omni/api": "2.260430.4",
|
|
54
|
+
"@omni/channel-discord": "2.260430.4",
|
|
55
|
+
"@omni/channel-gupshup": "2.260430.4",
|
|
56
|
+
"@omni/channel-sdk": "2.260430.4",
|
|
57
|
+
"@omni/channel-slack": "2.260430.4",
|
|
58
|
+
"@omni/channel-telegram": "2.260430.4",
|
|
59
|
+
"@omni/channel-whatsapp": "2.260430.4",
|
|
60
|
+
"@omni/core": "2.260430.4",
|
|
61
|
+
"@omni/sdk": "2.260430.4",
|
|
62
62
|
"@types/node": "^22.10.3",
|
|
63
63
|
"@types/qrcode-terminal": "^0.12.2",
|
|
64
64
|
"typescript": "^5.7.3"
|