@onesi/genesis-cli 0.1.13 → 0.2.0
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/README.md +29 -2
- package/dist/beacons.js +68 -0
- package/dist/dials.js +7 -4
- package/dist/fleets.js +30 -0
- package/dist/flocks.d.ts +7 -1
- package/dist/flocks.js +257 -3
- package/dist/henry.d.ts +5 -1
- package/dist/henry.js +60 -1
- package/dist/hives-coverage.d.ts +12 -0
- package/dist/hives-coverage.js +116 -0
- package/dist/hives-node-transport.js +3 -0
- package/dist/hives-operations.d.ts +1 -0
- package/dist/hives-operations.js +2 -0
- package/dist/hives-platform.d.ts +13 -0
- package/dist/hives-platform.js +133 -0
- package/dist/iam-directory.d.ts +15 -0
- package/dist/iam-directory.js +71 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +255 -23
- package/dist/minds.d.ts +1 -1
- package/dist/minds.js +37 -2
- package/dist/onboard/art.d.ts +50 -0
- package/dist/onboard/art.js +139 -0
- package/dist/onboard/brand.d.ts +56 -0
- package/dist/onboard/brand.js +134 -0
- package/dist/onboard/caps.d.ts +90 -0
- package/dist/onboard/caps.js +232 -0
- package/dist/onboard/encode.d.ts +23 -0
- package/dist/onboard/encode.js +235 -0
- package/dist/onboard/eye.d.ts +103 -0
- package/dist/onboard/eye.js +147 -0
- package/dist/onboard/index.d.ts +61 -0
- package/dist/onboard/index.js +562 -0
- package/dist/onboard/mcp.d.ts +35 -0
- package/dist/onboard/mcp.js +118 -0
- package/dist/onboard/raster.d.ts +43 -0
- package/dist/onboard/raster.js +253 -0
- package/dist/onboard/sound.d.ts +2 -0
- package/dist/onboard/sound.js +54 -0
- package/dist/onboard/state.d.ts +24 -0
- package/dist/onboard/state.js +48 -0
- package/dist/onboard/term.d.ts +69 -0
- package/dist/onboard/term.js +292 -0
- package/dist/onboard/ui.d.ts +97 -0
- package/dist/onboard/ui.js +615 -0
- package/dist/orgs.d.ts +16 -0
- package/dist/orgs.js +89 -0
- package/dist/products.d.ts +6 -2
- package/dist/products.js +238 -12
- package/dist/relays-commands/certificates.d.ts +3 -0
- package/dist/relays-commands/certificates.js +20 -0
- package/dist/relays-commands/domains.d.ts +3 -0
- package/dist/relays-commands/domains.js +23 -0
- package/dist/relays-commands/index.d.ts +4 -0
- package/dist/relays-commands/index.js +10 -0
- package/dist/relays-commands/monitoring.d.ts +3 -0
- package/dist/relays-commands/monitoring.js +41 -0
- package/dist/relays-commands/telemetry.d.ts +3 -0
- package/dist/relays-commands/telemetry.js +28 -0
- package/dist/relays-commands/zones.d.ts +5 -0
- package/dist/relays-commands/zones.js +9 -0
- package/dist/runner.js +2 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { registerMinds } from './minds.js';
|
|
2
2
|
import { registerRelaysEnrollment } from './relays-enrollment.js';
|
|
3
|
+
import { RELAYS_COMMANDS } from './relays-commands/index.js';
|
|
3
4
|
import { registerBeacons } from './beacons.js';
|
|
4
5
|
import { registerDials } from './dials.js';
|
|
5
|
-
import {
|
|
6
|
+
import { registerIamDirectory } from './iam-directory.js';
|
|
7
|
+
import { registerOperationCommands, registerProducts } from './products.js';
|
|
8
|
+
import { registerOrgs } from './orgs.js';
|
|
6
9
|
import { Command, CommanderError } from 'commander';
|
|
7
10
|
import { Genesis, GenesisError, errorCatalog, errorOutcome, isMindsOperation, HivesOperationError, HivesQueueOperationError, MindsAgentError, MindsOwnerError, hivesResponseBytes, MAX_FUNCTION_BODY_BYTES, MAX_FUNCTION_JSON_BYTES, DEFAULT_BASE_URL, requireSecureUrl } from '@onesi/genesis';
|
|
8
11
|
import { authConfig, completeLogin, selectSavedContext, savedLoginProvider, startLogin } from './auth.js';
|
|
@@ -16,6 +19,7 @@ import { registerFlocks } from './flocks.js';
|
|
|
16
19
|
import { registerRunner } from './runner.js';
|
|
17
20
|
import { createHivesNodeTransport } from './hives-node-transport.js';
|
|
18
21
|
import { registerHivesOperations } from './hives-operations.js';
|
|
22
|
+
import { registerHivesCoverage } from './hives-coverage.js';
|
|
19
23
|
import { readFunctionFile, readFunctionJson, writeFunctionOutput } from './function-input.js';
|
|
20
24
|
import { basename } from 'node:path';
|
|
21
25
|
import { readWasmFile } from './wasm-input.js';
|
|
@@ -36,7 +40,7 @@ export function buildProgram(deps = {}) {
|
|
|
36
40
|
const auth = { ...authConfig(env, f), sleep: deps.sleep };
|
|
37
41
|
const program = new Command('genesis')
|
|
38
42
|
.description('One CLI for every Genesis service.')
|
|
39
|
-
.version('0.
|
|
43
|
+
.version('0.2.0')
|
|
40
44
|
.option('--json', 'machine-readable JSON output')
|
|
41
45
|
.option('--api-key <key>', 'use this API key (default: GENESIS_API_KEY, then your `genesis login`)')
|
|
42
46
|
.option('--base-url <url>', 'gateway URL (default: GENESIS_BASE_URL or https://os.one.ml/api)')
|
|
@@ -52,7 +56,7 @@ export function buildProgram(deps = {}) {
|
|
|
52
56
|
const opts = {
|
|
53
57
|
apiKey: o.apiKey ?? env.GENESIS_API_KEY, token: env.GENESIS_TOKEN,
|
|
54
58
|
baseUrl: o.baseUrl ?? env.GENESIS_BASE_URL, routing: o.direct || env.GENESIS_ROUTING === 'direct' ? 'direct' : 'gateway',
|
|
55
|
-
fetch: f, userAgent: 'genesis-cli/0.
|
|
59
|
+
fetch: f, userAgent: 'genesis-cli/0.2.0',
|
|
56
60
|
credentials: store ? savedLoginProvider(auth, store) : undefined,
|
|
57
61
|
};
|
|
58
62
|
return new Genesis(hivesTransport ? { ...opts, fetch: createHivesNodeTransport(opts, deps.signal) } : opts);
|
|
@@ -82,23 +86,102 @@ export function buildProgram(deps = {}) {
|
|
|
82
86
|
return (await gen.whoami()).org;
|
|
83
87
|
};
|
|
84
88
|
const silos = program.command('silos').description('Serverless PostgreSQL');
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.action(async (options) =>
|
|
89
|
+
const silosInstances = silos.command('instances').description('Database instances in the selected Genesis project (genesis select)');
|
|
90
|
+
silosInstances.command('list').action(async () => out.log(JSON.stringify(await (await client()).silos.instances.list(), null, 2)));
|
|
91
|
+
silosInstances.command('get <instance_id>').action(async (id) => out.log(JSON.stringify(await (await client()).silos.instances.get(id), null, 2)));
|
|
92
|
+
silosInstances.command('create').requiredOption('--name <name>', 'Instance name (lowercase, 1-63 characters)')
|
|
93
|
+
.action(async (options) => out.log(JSON.stringify(await (await client()).silos.instances.create({ name: options.name }), null, 2)));
|
|
94
|
+
const silosJson = (value) => out.log(JSON.stringify(value, null, 2));
|
|
95
|
+
silosInstances.command('rename <instance_id>').requiredOption('--name <name>', 'New instance name (lowercase, 1-63 characters)')
|
|
96
|
+
.action(async (id, options) => silosJson(await (await client()).silos.instances.update(id, { name: options.name })));
|
|
97
|
+
silosInstances.command('delete <instance_id>').description('Delete an instance and stop it; its name is free again at once')
|
|
98
|
+
.action(async (id) => silosJson((await (await client()).silos.instances.delete(id)) ?? { deleted: id }));
|
|
99
|
+
silosInstances.command('suspend <instance_id>').description('Checkpoint, then stop the instance')
|
|
100
|
+
.action(async (id) => silosJson(await (await client()).silos.instances.suspend(id)));
|
|
101
|
+
silosInstances.command('resume <instance_id>').description('Start the instance now')
|
|
102
|
+
.action(async (id) => silosJson(await (await client()).silos.instances.resume(id)));
|
|
103
|
+
silosInstances.command('query <instance_id>').description('Run one SQL statement (never replayed)')
|
|
104
|
+
.requiredOption('--sql <sql>', 'SQL statement').option('--params <json>', 'JSON array of positional parameters for $1, $2, …')
|
|
105
|
+
.option('--branch <branch_id>', 'run on this branch instead of the default branch')
|
|
106
|
+
.action(async (id, options) => {
|
|
107
|
+
let params;
|
|
108
|
+
if (options.params !== undefined) {
|
|
109
|
+
try {
|
|
110
|
+
params = JSON.parse(options.params);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
params = undefined;
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(params))
|
|
116
|
+
throw new Error('--params must be a JSON array, for example \'[1,"a"]\'.');
|
|
117
|
+
}
|
|
118
|
+
silosJson(await (await client()).silos.instances.query(id, { sql: options.sql, ...(params ? { params } : {}), ...(options.branch ? { branchId: options.branch } : {}) }));
|
|
119
|
+
});
|
|
120
|
+
silosInstances.command('batch <instance_id>').description('Run up to 50 statements in one transaction (never replayed)')
|
|
121
|
+
.option('--file <path>', 'UTF-8 JSON file: {"statements":[{"sql":"…","params":[…]}]}').option('--stdin', 'read that JSON from stdin')
|
|
122
|
+
.action(async (id, o) => {
|
|
123
|
+
let body;
|
|
124
|
+
if (Boolean(o.file) === Boolean(o.stdin))
|
|
125
|
+
throw new Error('Choose exactly one input source: --file or --stdin.');
|
|
126
|
+
const text = await (deps.readSecretInput ?? readSecretInput)(o, 64 * 1024);
|
|
127
|
+
try {
|
|
128
|
+
body = JSON.parse(text);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new Error('Batch input must be JSON: {"statements":[{"sql":"…"}]}.');
|
|
132
|
+
}
|
|
133
|
+
silosJson(await (await client()).silos.instances.batch(id, body));
|
|
134
|
+
});
|
|
135
|
+
silosInstances.command('metrics <instance_id>').description('Live counters, storage and activity times')
|
|
136
|
+
.action(async (id) => silosJson(await (await client()).silos.instances.metrics(id)));
|
|
137
|
+
silosInstances.command('listen <instance_id>').description('Wait for NOTIFY on channels (up to --wait ms, at most 15000)')
|
|
138
|
+
.requiredOption('--channel <name...>', 'channel to listen on (repeatable, up to 10)').option('--wait <ms>', 'how long to wait (default 10000)')
|
|
139
|
+
.option('--branch <branch_id>', 'listen on this branch instead of the default branch')
|
|
140
|
+
.action(async (id, o) => {
|
|
141
|
+
const waitMs = o.wait === undefined ? undefined : Number(o.wait);
|
|
142
|
+
if (waitMs !== undefined && !(Number.isInteger(waitMs) && waitMs >= 0 && waitMs <= 15000))
|
|
143
|
+
throw new Error('--wait must be an integer from 0 to 15000.');
|
|
144
|
+
silosJson(await (await client()).silos.instances.listen(id, { channels: o.channel, ...(waitMs !== undefined ? { waitMs } : {}), ...(o.branch ? { branchId: o.branch } : {}) }));
|
|
145
|
+
});
|
|
146
|
+
silos.command('usage').description('Silos usage of the selected Genesis project, last 30 days')
|
|
147
|
+
.action(async () => silosJson(await (await client()).silos.usage()));
|
|
148
|
+
silos.command('regions').description('Regions Silos instances are created in')
|
|
149
|
+
.action(async () => silosJson(await (await client()).silos.regions.list()));
|
|
150
|
+
const silosBranches = silos.command('branches').description('Branches of a database instance');
|
|
151
|
+
silosBranches.command('list <instance_id>').action(async (id) => silosJson(await (await client()).silos.instances.branches.list(id)));
|
|
152
|
+
silosBranches.command('get <instance_id> <branch_id>').action(async (id, branch) => silosJson(await (await client()).silos.instances.branches.get(id, branch)));
|
|
153
|
+
silosBranches.command('create <instance_id>').description('Copy the latest checkpoint of the parent (default: the default branch)')
|
|
154
|
+
.requiredOption('--name <name>', 'Branch name (lowercase, 1-63 characters)').option('--parent <branch_id>', 'parent branch')
|
|
155
|
+
.action(async (id, o) => silosJson(await (await client()).silos.instances.branches.create(id, o.parent ? { name: o.name, parentBranchId: o.parent } : { name: o.name })));
|
|
156
|
+
silosBranches.command('rename <instance_id> <branch_id>').requiredOption('--name <name>', 'New branch name')
|
|
157
|
+
.action(async (id, branch, o) => silosJson(await (await client()).silos.instances.branches.update(id, branch, { name: o.name })));
|
|
158
|
+
silosBranches.command('delete <instance_id> <branch_id>').description('Delete a branch other than the default branch')
|
|
159
|
+
.action(async (id, branch) => silosJson((await (await client()).silos.instances.branches.delete(id, branch)) ?? { deleted: branch }));
|
|
160
|
+
silosBranches.command('restore <instance_id> <branch_id>').description('Replace the branch data with a stored snapshot')
|
|
161
|
+
.requiredOption('--snapshot <snapshot_id>', 'snapshot id from `genesis silos snapshots list`').option('--from <branch_id>', 'branch the snapshot was taken on (default: this branch)')
|
|
162
|
+
.action(async (id, branch, o) => silosJson(await (await client()).silos.instances.branches.restore(id, branch, o.from ? { snapshotId: o.snapshot, sourceBranchId: o.from } : { snapshotId: o.snapshot })));
|
|
163
|
+
const silosSnapshots = silos.command('snapshots').description('Stored snapshots of a database instance');
|
|
164
|
+
silosSnapshots.command('list <instance_id>').action(async (id) => silosJson(await (await client()).silos.instances.snapshots.list(id)));
|
|
165
|
+
silosSnapshots.command('create <instance_id>').description('Checkpoint a branch and store the snapshot').option('--branch <branch_id>', 'branch (default: the default branch)')
|
|
166
|
+
.action(async (id, o) => silosJson(await (await client()).silos.instances.snapshots.create(id, o.branch ? { branchId: o.branch } : {})));
|
|
93
167
|
const traces = program.command('traces').description('Research and evidence');
|
|
94
168
|
const tracesRuns = traces.command('runs').description('Research runs in your verified organization');
|
|
95
169
|
tracesRuns.command('create').requiredOption('--type <type>', 'Run type, e.g. deep_research').requiredOption('--query <query>', 'Research question')
|
|
96
170
|
.requiredOption('--idempotency-key <key>', 'Stable key; reuse it to replay instead of creating a second run')
|
|
97
|
-
.
|
|
171
|
+
.option('--max-sources <n>', 'Most sources the run may collect (1-100)')
|
|
172
|
+
.option('--include-domain <domain...>', 'Search only these domains, e.g. wikipedia.org')
|
|
173
|
+
.action(async (o) => {
|
|
174
|
+
const config = { ...(o.maxSources !== undefined ? { max_sources: positiveInteger(o.maxSources, '--max-sources', 100) } : {}), ...(o.includeDomain?.length ? { include_domains: o.includeDomain } : {}) };
|
|
175
|
+
out.log(JSON.stringify(await (await client()).traces.runs.create({ type: o.type, query: o.query, ...(Object.keys(config).length ? { config } : {}) }, o.idempotencyKey), null, 2));
|
|
176
|
+
});
|
|
98
177
|
tracesRuns.command('list').action(async () => out.log(JSON.stringify(await (await client()).traces.runs.list(), null, 2)));
|
|
99
178
|
tracesRuns.command('get <run_id>').action(async (id) => out.log(JSON.stringify(await (await client()).traces.runs.get(id), null, 2)));
|
|
100
179
|
traces.command('search <query>').requiredOption('--idempotency-key <key>', 'Stable key; metered once')
|
|
101
|
-
.
|
|
180
|
+
.option('--max-results <n>', 'Results to return (1-20, default 3)')
|
|
181
|
+
.option('--include-domain <domain...>', 'Search only these domains, e.g. wikipedia.org')
|
|
182
|
+
.action(async (query, o) => out.log(JSON.stringify(await (await client()).traces.search({
|
|
183
|
+
query, max_results: positiveInteger(o.maxResults, '--max-results', 20) ?? 3, ...(o.includeDomain?.length ? { include_domains: o.includeDomain } : {})
|
|
184
|
+
}, o.idempotencyKey), null, 2)));
|
|
102
185
|
traces.command('usage').action(async () => out.log(JSON.stringify(await (await client()).traces.usage.events(), null, 2)));
|
|
103
186
|
const blinds = program.command('blinds').description('Blinds credential custody');
|
|
104
187
|
const show = async (call) => out.log(JSON.stringify(await call((await client()).blinds), null, 2));
|
|
@@ -115,7 +198,41 @@ export function buildProgram(deps = {}) {
|
|
|
115
198
|
...(o.domain ? { destination_domains: o.domain } : {}), ...(o.provider ? { provider: o.provider } : {}) }, key(o)));
|
|
116
199
|
});
|
|
117
200
|
credentials.command('revoke <variable>').option(...keyOption).action((variable, o) => show(b => b.credentials.revoke(variable, key(o))));
|
|
201
|
+
credentials.command('revoke-all').description('Revoke every credential in the selected organization (irreversible)')
|
|
202
|
+
.requiredOption('--yes', 'Confirm the bulk revoke').option(...keyOption).action((o) => show(b => b.credentials.revokeAll(key(o))));
|
|
118
203
|
blinds.command('connections').description('Active OAuth connections (metadata only)').action(() => show(b => b.oauth.connections({ signal: deps.signal })));
|
|
204
|
+
const offsetInteger = (value) => {
|
|
205
|
+
if (value === undefined)
|
|
206
|
+
return undefined;
|
|
207
|
+
if (!/^\d+$/.test(value) || !Number.isSafeInteger(Number(value)))
|
|
208
|
+
throw new Error('--offset must be a non-negative integer.');
|
|
209
|
+
return Number(value);
|
|
210
|
+
};
|
|
211
|
+
const catalog = (o) => {
|
|
212
|
+
const limit = positiveInteger(o.limit, '--limit', 1000), offset = offsetInteger(o.offset);
|
|
213
|
+
return { ...(o.q ? { q: o.q } : {}), ...(o.category ? { category: o.category } : {}),
|
|
214
|
+
...(limit !== undefined ? { limit } : {}), ...(offset !== undefined ? { offset } : {}) };
|
|
215
|
+
};
|
|
216
|
+
const providers = blinds.command('providers').description('Provider catalog: what a credential can be bound to');
|
|
217
|
+
providers.command('list').option('--q <text>', 'Match slug, name or description').option('--category <name>').option('--auth-mode <mode>', 'oauth2, api_key, ...')
|
|
218
|
+
.option('--oauth', 'Only providers that use OAuth 2.0 (cannot be combined with --auth-mode)').option('--limit <n>', 'Page size, 1 to 1000').option('--offset <n>')
|
|
219
|
+
.action((o) => {
|
|
220
|
+
if (o.oauth && o.authMode)
|
|
221
|
+
throw new Error('--oauth already selects auth mode oauth2; drop --auth-mode.');
|
|
222
|
+
const query = catalog(o);
|
|
223
|
+
return show(b => o.oauth ? b.oauth.providers(query, { signal: deps.signal })
|
|
224
|
+
: b.providers.list({ ...query, ...(o.authMode ? { auth_mode: o.authMode } : {}) }, { signal: deps.signal }));
|
|
225
|
+
});
|
|
226
|
+
providers.command('get <slug>').action((slug) => show(b => b.providers.get(slug, { signal: deps.signal })));
|
|
227
|
+
const settings = blinds.command('settings').description('Consent policy and notifications');
|
|
228
|
+
settings.command('get').action(() => show(b => b.settings.get({ signal: deps.signal })));
|
|
229
|
+
settings.command('set').description('Replace the settings: an omitted --email or --slack turns that notification off').requiredOption('--consent-policy <policy>', 'never, per_variable or per_delegate')
|
|
230
|
+
.option('--email', 'Email notifications on').option('--slack', 'Slack notifications on').option(...keyOption)
|
|
231
|
+
.action((o) => show(b => b.settings.update({ consent_policy: o.consentPolicy, email_notifications: !!o.email, slack_notifications: !!o.slack }, key(o))));
|
|
232
|
+
blinds.command('agents').description('Agents seen using Blinds, with request counts').action(() => show(b => b.agents({ signal: deps.signal })));
|
|
233
|
+
blinds.command('alerts').description('Failed or denied Blinds events').action(() => show(b => b.alerts({ signal: deps.signal })));
|
|
234
|
+
blinds.command('operation <operation_id>').description('Receipt for a mutation, by its Idempotency-Key')
|
|
235
|
+
.action((id) => show(b => b.operations.get(id, { signal: deps.signal })));
|
|
119
236
|
const consent = blinds.command('consent').description('Agent consent requests and decisions');
|
|
120
237
|
consent.command('pending').action(() => show(b => b.consent.pending({ signal: deps.signal })));
|
|
121
238
|
consent.command('list').action(() => show(b => b.consent.records({ signal: deps.signal })));
|
|
@@ -141,7 +258,22 @@ export function buildProgram(deps = {}) {
|
|
|
141
258
|
});
|
|
142
259
|
}
|
|
143
260
|
registerDials(program, { client, orgId, emit });
|
|
261
|
+
registerIamDirectory(program, { client, orgId, emit });
|
|
144
262
|
registerProducts(program, { client, emit, signal: deps.signal });
|
|
263
|
+
registerOrgs(program, { client, emit, signal: deps.signal });
|
|
264
|
+
// Agent enrollment sends only the grant's enrollment key (mek_...), never this CLI's login or API key.
|
|
265
|
+
(program.commands.find(c => c.name() === 'iam').commands.find(c => c.name() === 'agents')).command('enroll')
|
|
266
|
+
.description('Enroll an agent under an agent enrollment grant (POST /v1/iam/agents/enroll); the credential secret is shown once')
|
|
267
|
+
.requiredOption('--body-file <path>', 'JSON request body (externalKey, displayName, mindId, permissions, ...)')
|
|
268
|
+
.option('--key-file <path>', 'file holding the enrollment key (mek_...)').option('--key-stdin', 'read the enrollment key from stdin')
|
|
269
|
+
.action(async (o) => {
|
|
270
|
+
const key = o.keyFile || o.keyStdin ? (await (deps.readSecretInput ?? readSecretInput)({ file: o.keyFile, stdin: o.keyStdin }, 1024)).trim() : env.GENESIS_ENROLLMENT_KEY;
|
|
271
|
+
if (!key)
|
|
272
|
+
throw new Error('Give the enrollment key with --key-file, --key-stdin or GENESIS_ENROLLMENT_KEY; it is never accepted as an argument.');
|
|
273
|
+
const body = await readFunctionJson(o.bodyFile, 16 * 1024);
|
|
274
|
+
const result = await new Genesis({ baseUrl: g().baseUrl ?? env.GENESIS_BASE_URL, fetch: f, userAgent: 'genesis-cli/0.1.13' }).iam.agents.enroll(key, body);
|
|
275
|
+
emit(result, () => JSON.stringify(result, null, 2));
|
|
276
|
+
});
|
|
145
277
|
// ---- auth ------------------------------------------------------------
|
|
146
278
|
program.command('login').description('Sign in with One in your browser').option('--no-browser', 'just print the link')
|
|
147
279
|
.option('--device', 'sign in from a machine without a local browser: approve a code from any signed-in browser')
|
|
@@ -196,7 +328,8 @@ export function buildProgram(deps = {}) {
|
|
|
196
328
|
emit({ user: saved.user, organization_id: saved.organization_id, verified: false, reason: e.message }, () => `${c.bold('User')} ${saved.user?.email ?? saved.user?.id}\n${c.bold('Org')} ${saved.organization_id ?? '-'}\n${c.yellow('!')} ${c.dim('From your saved login; One account verify unavailable: ' + e.message)}`);
|
|
197
329
|
}
|
|
198
330
|
});
|
|
199
|
-
|
|
331
|
+
// `orgs usage|observations|billing|payment-methods|service` and the Orgs (legal entity) commands are registered by registerProducts and registerOrgs.
|
|
332
|
+
const orgs = (program.commands.find(command => command.name() === 'orgs') ?? program.command('orgs')).description('Your organizations, their usage and billing reads, and Orgs: legal entities, seats, resolutions, documents, filings, formation and the record');
|
|
200
333
|
orgs.command('list', { isDefault: true }).description('Show your current organization').action(async () => {
|
|
201
334
|
const s = await (await getStore()).get();
|
|
202
335
|
if (!s)
|
|
@@ -247,7 +380,8 @@ export function buildProgram(deps = {}) {
|
|
|
247
380
|
emit({ revoked: id }, () => `${c.green('✓')} Revoked ${id} ${c.dim('(takes effect within 60s)')}`);
|
|
248
381
|
});
|
|
249
382
|
// ---- foundry ---------------------------------------------------------
|
|
250
|
-
|
|
383
|
+
// registerProducts (above) already added the generated `foundry` commands; the hand-written ones join them.
|
|
384
|
+
const foundry = program.commands.find(c => c.name() === 'foundry') ?? program.command('foundry').description('Foundry: models and inference');
|
|
251
385
|
const foundryBilling = foundry.command('billing').description('Current organization’s native TEST billing; original One account human login required');
|
|
252
386
|
foundryBilling.command('profile').action(async () => out.log(JSON.stringify(await (await client()).foundry.billing.profile({ signal: deps.signal }), null, 2)));
|
|
253
387
|
foundryBilling.command('ensure').requiredOption('--operation-key <key>', 'Persisted operation key; reconcile unknown outcomes before retrying').action(async (o) => out.log(JSON.stringify(await (await client()).foundry.billing.ensureProfile(o.operationKey, { signal: deps.signal }), null, 2)));
|
|
@@ -285,7 +419,7 @@ export function buildProgram(deps = {}) {
|
|
|
285
419
|
const hivesClient = () => client(true);
|
|
286
420
|
// ---- hives -----------------------------------------------------------
|
|
287
421
|
const hives = program.command('hives').description('Hives: projects, secrets, deployments, functions, schedules and activity');
|
|
288
|
-
registerHivesOperations(hives, { client: hivesClient, emit, readRequest: deps.readHivesRequest });
|
|
422
|
+
registerHivesOperations(hives, { client: hivesClient, emit, readRequest: deps.readHivesRequest, line: (text) => out.log(text) });
|
|
289
423
|
const deployments = hives.command('deployments').description('Real WASM artifacts and deployment lifecycle');
|
|
290
424
|
const emitDeployment = (data) => emit(data, () => table(data && typeof data === 'object' && !Array.isArray(data) && !('data' in data) ? [data] : listOf(data), ['id', 'version', 'status', 'module_hash', 'created_at']));
|
|
291
425
|
deployments.command('list <project_id>')
|
|
@@ -358,10 +492,10 @@ export function buildProgram(deps = {}) {
|
|
|
358
492
|
const result = await (await hivesClient()).hives.functions.delete(project, id);
|
|
359
493
|
emit(result, () => `Deleted function ${id}.`);
|
|
360
494
|
});
|
|
361
|
-
function invocationCommand(command, kind) {
|
|
495
|
+
function invocationCommand(command, kind, alias = false) {
|
|
362
496
|
if (kind === 'functions')
|
|
363
497
|
command.option('--idempotency-key <key>', 'Persisted original invocation key; required by Genesis funding. Reuse it after uncertainty.');
|
|
364
|
-
command.description('Complete real guest execution; write exact bytes, including executed HTTP error bodies')
|
|
498
|
+
command.description(alias ? 'Compatibility alias of invoke (/invoke/async): the same completed guest response, no durable queue' : 'Complete real guest execution; write exact bytes, including executed HTTP error bodies')
|
|
365
499
|
.option('--request-file <file>', 'JSON method/path/headers/body or body_base64')
|
|
366
500
|
.option('--body-file <file>', 'Exact binary body (up to 10 MiB; serialized guest envelope may reach its cap earlier)')
|
|
367
501
|
.option('--method <method>', 'guest HTTP method', 'POST').option('--path <path>', 'guest path including query', '/')
|
|
@@ -374,7 +508,8 @@ export function buildProgram(deps = {}) {
|
|
|
374
508
|
let request = o.requestFile ? await readFunctionJson(o.requestFile, MAX_FUNCTION_JSON_BYTES) : { method: o.method, path: o.path };
|
|
375
509
|
if (o.bodyFile)
|
|
376
510
|
request.body_base64 = Buffer.from(await readFunctionFile(o.bodyFile, MAX_FUNCTION_BODY_BYTES)).toString('base64');
|
|
377
|
-
const
|
|
511
|
+
const hivesApi = (await hivesClient()).hives;
|
|
512
|
+
const response = alias ? await hivesApi.functions.invokeAsync(project, id, request, { idempotencyKey: o.idempotencyKey }) : await hivesApi[kind].invoke(project, id, request, { idempotencyKey: o.idempotencyKey });
|
|
378
513
|
const bytes = await hivesResponseBytes(response);
|
|
379
514
|
if (g().json)
|
|
380
515
|
out.log(JSON.stringify({ status: response.status, headers: Object.fromEntries(response.headers), body_base64: Buffer.from(bytes).toString('base64') }));
|
|
@@ -389,6 +524,8 @@ export function buildProgram(deps = {}) {
|
|
|
389
524
|
}
|
|
390
525
|
invocationCommand(functions.command('invoke <project_id> <function_id>'), 'functions');
|
|
391
526
|
invocationCommand(deployments.command('invoke <project_id> <deployment_id>'), 'deployments');
|
|
527
|
+
// The service's /invoke/async compatibility alias: the same completed guest response, no durable queue.
|
|
528
|
+
invocationCommand(functions.command('invoke-async <project_id> <function_id>'), 'functions', true);
|
|
392
529
|
const operations = functions.command('operations').description('Read or release the original funding operation without replaying the guest');
|
|
393
530
|
operations.command('get <project_id> <function_id> <operation_id>').action(async (project, fn, operation) => {
|
|
394
531
|
const result = await (await hivesClient()).hives.functions.operations.get(project, fn, operation);
|
|
@@ -545,9 +682,12 @@ export function buildProgram(deps = {}) {
|
|
|
545
682
|
page: positiveInteger(o.page, '--page', 10000), per_page: positiveInteger(o.perPage, '--per-page', 100) });
|
|
546
683
|
emit(r, () => table(listOf(r), ['created_at', 'action', 'actor_id', 'resource_type', 'resource_name']));
|
|
547
684
|
});
|
|
685
|
+
// Last: extends the hives groups defined above (flights, logs, env values, domain reads).
|
|
686
|
+
registerHivesCoverage(hives, { client: hivesClient, emit, readRequest: deps.readHivesRequest });
|
|
548
687
|
// ---- relays ----------------------------------------------------------
|
|
549
688
|
const relays = program.command('relays').description('Relays: DNS zones and records');
|
|
550
689
|
registerRelaysEnrollment(relays, client, emit);
|
|
690
|
+
registerOperationCommands(relays, RELAYS_COMMANDS, { client, emit, signal: deps.signal });
|
|
551
691
|
relays.command('zones').description('List DNS zones').option('--search <q>').action(async (o) => {
|
|
552
692
|
const r = await (await client()).relays.zones.list(o.search ? { search: o.search } : {});
|
|
553
693
|
emit(r, () => table((r.zones ?? []), ['name', 'type', 'record_count', 'dnssec_enabled', 'status']));
|
|
@@ -560,7 +700,58 @@ export function buildProgram(deps = {}) {
|
|
|
560
700
|
const result = await (await client()).relays.zones.dnssec(zone);
|
|
561
701
|
emit(result, () => JSON.stringify(result, null, 2));
|
|
562
702
|
});
|
|
703
|
+
// Writes need relays:write and act on the selected project's existing Relays account.
|
|
704
|
+
const dnsInt = (value, option, minimum, maximum) => {
|
|
705
|
+
if (value === undefined)
|
|
706
|
+
return undefined;
|
|
707
|
+
if (!/^\d+$/.test(value) || Number(value) < minimum || Number(value) > maximum)
|
|
708
|
+
throw new Error(`${option} must be an integer from ${minimum} to ${maximum}.`);
|
|
709
|
+
return Number(value);
|
|
710
|
+
};
|
|
711
|
+
const recordId = (value) => dnsInt(value, '<record_id>', 1, Number.MAX_SAFE_INTEGER);
|
|
712
|
+
relays.command('create-zone <name>').description('Create a DNS zone')
|
|
713
|
+
.option('--type <type>', 'NATIVE, MASTER or SLAVE (default NATIVE)').option('--no-default-records', 'skip the default records')
|
|
714
|
+
.action(async (name, o) => {
|
|
715
|
+
const result = await (await client()).relays.zones.create({ name, ...(o.type ? { type: o.type.toUpperCase() } : {}),
|
|
716
|
+
create_default_records: o.defaultRecords });
|
|
717
|
+
emit(result, () => `${c.green('✓')} Created zone ${name}`);
|
|
718
|
+
});
|
|
719
|
+
relays.command('update-zone <zone>').description('Update a zone\'s type or SOA settings')
|
|
720
|
+
.option('--type <type>', 'NATIVE, MASTER or SLAVE').option('--primary-ns <host>').option('--hostmaster <email>')
|
|
721
|
+
.option('--refresh <seconds>').option('--retry <seconds>').option('--expire <seconds>').option('--soa-ttl <seconds>')
|
|
722
|
+
.action(async (zone, o) => {
|
|
723
|
+
const soa = Object.fromEntries(Object.entries({ primary_ns: o.primaryNs, hostmaster: o.hostmaster,
|
|
724
|
+
refresh: dnsInt(o.refresh, '--refresh', 60, 2 ** 31), retry: dnsInt(o.retry, '--retry', 60, 2 ** 31),
|
|
725
|
+
expire: dnsInt(o.expire, '--expire', 3600, 2 ** 31), ttl: dnsInt(o.soaTtl, '--soa-ttl', 60, 2 ** 31) }).filter(([, v]) => v !== undefined));
|
|
726
|
+
const body = { ...(o.type ? { type: o.type.toUpperCase() } : {}), ...(Object.keys(soa).length ? { soa } : {}) };
|
|
727
|
+
if (!Object.keys(body).length)
|
|
728
|
+
throw new Error('Nothing to update: pass --type or an SOA option.');
|
|
729
|
+
const result = await (await client()).relays.zones.update(zone, body);
|
|
730
|
+
emit(result, () => `${c.green('✓')} Updated zone ${zone}`);
|
|
731
|
+
});
|
|
732
|
+
relays.command('delete-zone <zone>').description('Delete a zone and all its records').action(async (zone) => {
|
|
733
|
+
const result = await (await client()).relays.zones.delete(zone);
|
|
734
|
+
emit(result, () => `${c.green('✓')} Deleted zone ${zone}`);
|
|
735
|
+
});
|
|
563
736
|
const records = relays.command('records').description('DNS records in a zone');
|
|
737
|
+
records.command('get <zone> <record_id>').description('Read one record').action(async (zone, id) => {
|
|
738
|
+
const result = await (await client()).relays.records.get(zone, recordId(id));
|
|
739
|
+
emit(result, () => JSON.stringify(result, null, 2));
|
|
740
|
+
});
|
|
741
|
+
records.command('update <zone> <record_id>').description('Update a record')
|
|
742
|
+
.option('--name <name>').option('--type <type>').option('--content <content>').option('--ttl <seconds>', 'TTL, 60 to 86400')
|
|
743
|
+
.option('--priority <n>', '0 to 65535').option('--comment <text>').option('--disable', 'disable the record').option('--enable', 'enable the record')
|
|
744
|
+
.action(async (zone, id, o) => {
|
|
745
|
+
if (o.disable && o.enable)
|
|
746
|
+
throw new Error('Pass --disable or --enable, not both.');
|
|
747
|
+
const body = Object.fromEntries(Object.entries({ name: o.name, type: o.type?.toUpperCase(), content: o.content,
|
|
748
|
+
ttl: dnsInt(o.ttl, '--ttl', 60, 86400), priority: dnsInt(o.priority, '--priority', 0, 65535), comment: o.comment,
|
|
749
|
+
disabled: o.disable ? true : o.enable ? false : undefined }).filter(([, v]) => v !== undefined));
|
|
750
|
+
if (!Object.keys(body).length)
|
|
751
|
+
throw new Error('Nothing to update: pass at least one field option.');
|
|
752
|
+
const result = await (await client()).relays.records.update(zone, recordId(id), body);
|
|
753
|
+
emit(result, () => `${c.green('✓')} Updated record ${id} in ${zone}`);
|
|
754
|
+
});
|
|
564
755
|
records.command('list <zone>', { isDefault: true }).option('--type <type>').action(async (zone, o) => {
|
|
565
756
|
const r = await (await client()).relays.records.list(zone, o.type ? { type: o.type } : {});
|
|
566
757
|
emit(r, () => table((r.records ?? []), ['id', 'name', 'type', 'content', 'ttl']));
|
|
@@ -573,10 +764,31 @@ export function buildProgram(deps = {}) {
|
|
|
573
764
|
await (await client()).relays.records.delete(zone, Number(id));
|
|
574
765
|
emit({ deleted: Number(id) }, () => `${c.green('✓')} Deleted record ${id} from ${zone}`);
|
|
575
766
|
});
|
|
576
|
-
addHenryCommands(program, client, value => out.log(JSON.stringify(value, null, 2)));
|
|
767
|
+
addHenryCommands(program, client, value => out.log(JSON.stringify(value, null, 2)), { line: text => out.log(text), ...(deps.signal ? { signal: deps.signal } : {}) });
|
|
577
768
|
registerFleets(program, client, (data) => emit(data, () => JSON.stringify(data, null, 2)));
|
|
578
|
-
registerFlocks(program, client,
|
|
769
|
+
registerFlocks(program, client, emit, env, deps.readFlocksCode, () => !!g().json);
|
|
579
770
|
registerBeacons(program, client, emit);
|
|
771
|
+
// ---- setup -----------------------------------------------------------
|
|
772
|
+
// The first-run experience lives in ./onboard and is imported only here, so no other command loads it.
|
|
773
|
+
program.command('setup [step]').description('Set up Genesis: sign in, pick a project, add the MCP server to your agents (resumable)')
|
|
774
|
+
.option('--restart', 'start again from the first step')
|
|
775
|
+
.option('--no-animation', 'draw every step still (also GENESIS_REDUCED_MOTION=1)')
|
|
776
|
+
.option('--screen-reader', 'linear output for screen readers (also GENESIS_SCREEN_READER=1)')
|
|
777
|
+
.option('--screencast', 'mask account names, emails and IDs, for recording demos (also GENESIS_SCREENCAST=1)')
|
|
778
|
+
.option('--sound', 'a soft chime when you are signed in and when setup finishes (also GENESIS_SOUND=1)')
|
|
779
|
+
.action(async (step, o) => {
|
|
780
|
+
const code = await runSetupLazily(o, step);
|
|
781
|
+
if (code)
|
|
782
|
+
throw new CommanderError(code, 'genesis.setup', '');
|
|
783
|
+
});
|
|
784
|
+
const runSetupLazily = async (o, step) => {
|
|
785
|
+
const [{ runSetup }, authModule, deviceModule] = await Promise.all([import('./onboard/index.js'), import('./auth.js'), import('./device-login.js')]);
|
|
786
|
+
return runSetup({ version: program.version() ?? '', env, fetch: f, auth, getStore, client: () => client(), openBrowser: deps.openBrowser ?? defaultOpen,
|
|
787
|
+
baseUrl: g().baseUrl ?? env.GENESIS_BASE_URL ?? DEFAULT_BASE_URL, log: (s) => out.log(s),
|
|
788
|
+
flags: { json: g().json, animation: o.animation, screenReader: o.screenReader, sound: o.sound, screencast: o.screencast, restart: o.restart, step },
|
|
789
|
+
login: { startLogin: authModule.startLogin, completeLogin: authModule.completeLogin, selectSavedContext: authModule.selectSavedContext,
|
|
790
|
+
savedLoginProvider: authModule.savedLoginProvider, startDeviceLogin: deviceModule.startDeviceLogin, completeDeviceLogin: deviceModule.completeDeviceLogin } });
|
|
791
|
+
};
|
|
580
792
|
// ---- status ----------------------------------------------------------
|
|
581
793
|
program.command('status').description('Live state of each Genesis service, from the gateway (GET /v1/status)').action(async () => {
|
|
582
794
|
const configured = g().baseUrl ?? env.GENESIS_BASE_URL ?? DEFAULT_BASE_URL;
|
|
@@ -591,7 +803,7 @@ export function buildProgram(deps = {}) {
|
|
|
591
803
|
const url = `${base.href.replace(/\/+$/, '')}/v1/status`;
|
|
592
804
|
let response;
|
|
593
805
|
try {
|
|
594
|
-
response = await f(url, { method: 'GET', headers: { accept: 'application/json', 'user-agent': 'genesis-cli/0.
|
|
806
|
+
response = await f(url, { method: 'GET', headers: { accept: 'application/json', 'user-agent': 'genesis-cli/0.2.0' }, signal: AbortSignal.timeout(15_000) });
|
|
595
807
|
}
|
|
596
808
|
catch (e) {
|
|
597
809
|
throw new Error(`Gateway unreachable at ${safe(url)}: ${safe(e.message)}`);
|
|
@@ -609,9 +821,26 @@ export function buildProgram(deps = {}) {
|
|
|
609
821
|
});
|
|
610
822
|
return program;
|
|
611
823
|
}
|
|
824
|
+
/**
|
|
825
|
+
* A bare `genesis` on a terminal, before setup is finished, is the first run: it opens `genesis setup`. Everywhere
|
|
826
|
+
* else (a pipe, CI, TERM=dumb, setup complete) it prints the help as before. Only the setup state file is read here.
|
|
827
|
+
*/
|
|
828
|
+
async function firstRun(argv, deps) {
|
|
829
|
+
if (argv.length > 2 || deps.out)
|
|
830
|
+
return false;
|
|
831
|
+
const env = deps.env ?? process.env;
|
|
832
|
+
const set = (v) => !!v && v !== '0' && v !== 'false';
|
|
833
|
+
if (!process.stdout.isTTY || !process.stdin.isTTY || env.TERM === 'dumb'
|
|
834
|
+
|| set(env.CI) || env.GITHUB_ACTIONS || env.BUILDKITE || env.GITLAB_CI || env.TF_BUILD)
|
|
835
|
+
return false;
|
|
836
|
+
const { SetupStore, complete } = await import('./onboard/state.js');
|
|
837
|
+
return !complete(await SetupStore.for(env).read());
|
|
838
|
+
}
|
|
612
839
|
export async function main(argv, deps = {}) {
|
|
613
840
|
const out = deps.out ?? stdio;
|
|
614
841
|
const program = buildProgram(deps);
|
|
842
|
+
if (await firstRun(argv, deps).catch(() => false))
|
|
843
|
+
argv = [...argv, 'setup'];
|
|
615
844
|
try {
|
|
616
845
|
await program.parseAsync(argv);
|
|
617
846
|
return 0;
|
|
@@ -621,6 +850,9 @@ export async function main(argv, deps = {}) {
|
|
|
621
850
|
return e.exitCode;
|
|
622
851
|
const json = program.opts().json;
|
|
623
852
|
if (e instanceof GenesisError) {
|
|
853
|
+
// Dials needs a project, workspace and environment: from flags, a selected context or an org key's binding.
|
|
854
|
+
const dialsScopeHint = e.operationId?.startsWith('dials_') && /invalid_scope/i.test(`${e.code ?? ''} ${e.message} ${e.type}`)
|
|
855
|
+
? ' Pass --workspace, --project and --environment, select a context (genesis context select), or use an org API key bound to a project.' : '';
|
|
624
856
|
if (json)
|
|
625
857
|
out.err(JSON.stringify({ error: { type: e.type, status: e.status, message: e.message, request_id: e.requestId, ...errorCatalog(e),
|
|
626
858
|
...((e instanceof HivesOperationError || e instanceof HivesQueueOperationError) ? { operation: e.operation } : {}),
|
|
@@ -628,7 +860,7 @@ export async function main(argv, deps = {}) {
|
|
|
628
860
|
...(e instanceof MindsAgentError || e instanceof MindsOwnerError ? { code: e.code, ...(e instanceof MindsAgentError ? { dpop_nonce: e.dpopNonce } : {}),
|
|
629
861
|
...(errorOutcome(e.body) !== undefined ? { outcome: errorOutcome(e.body) } : {}) } : {}) } }));
|
|
630
862
|
else
|
|
631
|
-
out.err(`${c.red('✗')} ${safe(e.message)}${(e instanceof HivesOperationError || e instanceof HivesQueueOperationError) ? ` Operation: ${safe(e.operation.operation_id)} (${safe(e.operation.state)}).` : ''}${e.status ? c.dim(` (${e.status} ${safe(e.type)}${e.requestId ?
|
|
863
|
+
out.err(`${c.red('✗')} ${safe(e.message)}${dialsScopeHint}${(e instanceof HivesOperationError || e instanceof HivesQueueOperationError) ? ` Operation: ${safe(e.operation.operation_id)} (${safe(e.operation.state)}).` : ''}${e.status ? c.dim(` (${e.status} ${safe(e.type)})`) : ''}${e.requestId ? `\n${c.dim(`request_id: ${safe(e.requestId)}`)}` : ''}`);
|
|
632
864
|
return 1;
|
|
633
865
|
}
|
|
634
866
|
const msg = e.message ?? String(e);
|
package/dist/minds.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
|
-
import type
|
|
2
|
+
import { type Genesis } from '@onesi/genesis';
|
|
3
3
|
export declare function registerMinds(program: Command, client: () => Promise<Genesis>, emit: (data: unknown) => void, agentClient?: () => Promise<Genesis>, signal?: AbortSignal, ownerClient?: () => Promise<Genesis>): void;
|
package/dist/minds.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFile, stat } from 'node:fs/promises';
|
|
2
2
|
import { registerMindsOwner } from './minds-owner.js';
|
|
3
3
|
import { Option } from 'commander';
|
|
4
|
+
import { mindsServices } from '@onesi/genesis';
|
|
4
5
|
export function registerMinds(program, client, emit, agentClient = client, signal, ownerClient = client) {
|
|
5
|
-
|
|
6
|
+
// `minds engine ...` (generated, products.ts) may already have created the root.
|
|
7
|
+
const minds = (program.commands.find(c => c.name() === 'minds') ?? program.command('minds')).description('Owned Minds and persisted memory; a human Console Sandbox session, or an org API key with minds:read/minds:write/minds:manage');
|
|
6
8
|
registerMindsOwner(minds, ownerClient, emit, signal);
|
|
7
9
|
minds.command('list').option('--after <uuid>').option('--limit <number>').description('List real Minds and the current creation context fingerprint').action(async (options) => {
|
|
8
10
|
emit(await (await client()).minds.list({ ...(options.after ? { after: options.after } : {}), ...(options.limit ? { limit: Number(options.limit) } : {}) }));
|
|
@@ -17,7 +19,13 @@ export function registerMinds(program, client, emit, agentClient = client, signa
|
|
|
17
19
|
.requiredOption('--context-sha256 <hash>', 'context_sha256 from the current minds list response')
|
|
18
20
|
.addOption(new Option('--plan <plan>', 'explicit plan; entitlement remains server-authorized').choices(['free', 'pro']))
|
|
19
21
|
.addOption(new Option('--profile-id <profile>', 'fixed native profile; Pro defaults to D1, Free accepts only F1').choices(['F1', 'D1', 'D2']))
|
|
20
|
-
.
|
|
22
|
+
.option('--services <list>', `comma-separated engine service groups (${mindsServices.join(', ')}); kv and memory always run`)
|
|
23
|
+
.action(async (name, options) => {
|
|
24
|
+
const services = options.services === undefined ? undefined : String(options.services).split(',').map((item) => item.trim()).filter(Boolean);
|
|
25
|
+
if (services && services.some(item => !mindsServices.includes(item)))
|
|
26
|
+
throw new Error(`Unknown Minds service; choose from ${mindsServices.join(', ')}.`);
|
|
27
|
+
emit(await (await client()).minds.create(name, { idempotencyKey: options.idempotencyKey, contextSha256: options.contextSha256, ...(options.plan === undefined ? {} : { plan: options.plan }), ...(options.profileId === undefined ? {} : { profileId: options.profileId }), ...(services === undefined ? {} : { services }) }));
|
|
28
|
+
});
|
|
21
29
|
minds.command('resume <mind_id>').description('Resume the same Mind and retained volume; 202 means the operation is accepted')
|
|
22
30
|
.requiredOption('--expected-generation <number>', 'desired_generation from a fresh owned Mind read')
|
|
23
31
|
.requiredOption('--idempotency-key <uuid>', 'persist this UUID4 with the original generation after an uncertain response')
|
|
@@ -27,6 +35,23 @@ export function registerMinds(program, client, emit, agentClient = client, signa
|
|
|
27
35
|
.requiredOption('--expected-generation <number>', 'desired_generation from a fresh owned Mind read')
|
|
28
36
|
.requiredOption('--idempotency-key <uuid>', 'persist this UUID4 and original generation; no automatic retry')
|
|
29
37
|
.action(async (id, options) => emit(await (await client()).minds.stop(id, Number(options.expectedGeneration), { idempotencyKey: options.idempotencyKey })));
|
|
38
|
+
minds.command('delete <mind_id>').description('Delete the Mind (lifecycle delete; org API keys need minds:write); 202 means accepted')
|
|
39
|
+
.requiredOption('--expected-generation <number>', 'desired_generation from a fresh owned Mind read')
|
|
40
|
+
.requiredOption('--idempotency-key <uuid>', 'persist this UUID4 and original generation; no automatic retry')
|
|
41
|
+
.action(async (id, options) => emit(await (await client()).minds.delete(id, Number(options.expectedGeneration), { idempotencyKey: options.idempotencyKey })));
|
|
42
|
+
minds.command('resize <mind_id>').description('Resize to an existing Pro profile (org API keys need minds:manage); 202 means accepted')
|
|
43
|
+
.requiredOption('--expected-generation <number>', 'desired_generation from a fresh owned Mind read')
|
|
44
|
+
.addOption(new Option('--profile-id <profile>', 'existing Pro profile').choices(['F1', 'D1', 'D2']).makeOptionMandatory())
|
|
45
|
+
.requiredOption('--idempotency-key <uuid>', 'persist this UUID4 and original generation; no automatic retry')
|
|
46
|
+
.action(async (id, options) => emit(await (await client()).minds.resize(id, Number(options.expectedGeneration), options.profileId, { idempotencyKey: options.idempotencyKey })));
|
|
47
|
+
const deliveries = minds.command('webhook-deliveries').description('Durable webhook receipts for an owned Mind; a stopped-idle Mind is woken');
|
|
48
|
+
deliveries.command('create <mind_id>').description('Record one delivery; replay the same delivery_id and body to read the original receipt')
|
|
49
|
+
.requiredOption('--delivery-id <uuid>', 'caller-chosen non-nil UUID; retain it after an uncertain response')
|
|
50
|
+
.requiredOption('--event-reference <reference>', 'opaque upstream event reference ([A-Za-z0-9_.:/-], at most 200)')
|
|
51
|
+
.requiredOption('--event-sha256 <hash>', 'lowercase hex SHA-256 of the upstream event')
|
|
52
|
+
.action(async (id, options) => emit(await (await client()).minds.webhookDeliveries.create(id, { delivery_id: options.deliveryId, event_reference: options.eventReference, event_sha256: options.eventSha256 })));
|
|
53
|
+
deliveries.command('get <mind_id> <delivery_id>').description('Read a receipt this principal issued')
|
|
54
|
+
.action(async (id, delivery) => emit(await (await client()).minds.webhookDeliveries.get(id, delivery)));
|
|
30
55
|
const memory = minds.command('memory').description('Every operation selects one owned, ready Mind');
|
|
31
56
|
memory.command('insert <mind_id>').requiredOption('--event-file <path>', 'JSON event with id, content and timestamp; returned id is its storage UUID')
|
|
32
57
|
.action(async (id, options) => {
|
|
@@ -55,6 +80,16 @@ export function registerMinds(program, client, emit, agentClient = client, signa
|
|
|
55
80
|
emit(await (await client()).minds.memory.search(mind, text, Number(options.limit)));
|
|
56
81
|
});
|
|
57
82
|
const agent = minds.command('agent').description('Use an existing agent credential; does not create an attachment or exchange a human session');
|
|
83
|
+
const createProof = async (path) => ({ signal, dpopProof: await readBounded(path, 4_096) });
|
|
84
|
+
agent.command('create <name>').description('Create a Free/F1 Sandbox Mind with an approved agent-create token; 202 means provisioning')
|
|
85
|
+
.requiredOption('--approval-id <uuid>', 'owner approval admitting this creation')
|
|
86
|
+
.requiredOption('--approval-version <number>', 'approval version')
|
|
87
|
+
.requiredOption('--operation-id <uuid>', 'persisted UUID4; also the idempotency key and the status lookup id')
|
|
88
|
+
.requiredOption('--dpop-proof-file <path>', 'fresh DPoP proof for the controller create method and URL')
|
|
89
|
+
.action(async (name, options) => emit(await (await agentClient()).minds.agent.create({ name, approvalId: options.approvalId, approvalVersion: Number(options.approvalVersion), operationId: options.operationId }, await createProof(options.dpopProofFile))));
|
|
90
|
+
agent.command('create-status <operation_id>').description('Read an agent Mind creation operation')
|
|
91
|
+
.requiredOption('--dpop-proof-file <path>', 'fresh DPoP proof for the controller status method and URL')
|
|
92
|
+
.action(async (operation, options) => emit(await (await agentClient()).minds.agent.createStatus(operation, await createProof(options.dpopProofFile))));
|
|
58
93
|
const agentMemory = agent.command('memory').description('Private or explicitly authorized group memory; requests are never automatically retried');
|
|
59
94
|
const scoped = (command) => command.option('--group <agp_id>', 'explicit canonical group; omit for private memory')
|
|
60
95
|
.option('--dpop-proof-file <path>', 'fresh DPoP proof for the controller capability method and URL');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One's marks as drawings: the emblem (Digital One, the disc with the eye knocked out), the Ones, and the hybrid ONE
|
|
3
|
+
* logotype whose O can close to the disc, wake as the eye, hop through the Ones and open back to the ring (JR-B103's
|
|
4
|
+
* cycle, the One site's components/ui/nav-logotype.tsx). Everything is drawn into a raster.Canvas from brand.ts.
|
|
5
|
+
*
|
|
6
|
+
* Paint rules (one-system.css): the disc is One's black on light and chalk on dark, never outlined or glowing; amber
|
|
7
|
+
* is only ever light inside the eye; the Ones wear their own colours, and those colours mean nothing else.
|
|
8
|
+
*/
|
|
9
|
+
import { ONES, type OneShape } from './brand.js';
|
|
10
|
+
import { Canvas, type Color, type Mat } from './raster.js';
|
|
11
|
+
import { sample, LIGHT, type Pose } from './eye.js';
|
|
12
|
+
/**
|
|
13
|
+
* The terminal's own foreground. When the probe could not learn the background we draw ink and Digital One in this
|
|
14
|
+
* colour and the encoder emits SGR 39, so the mark is always the user's own ink: black on light, chalk on dark.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_INK: Color;
|
|
17
|
+
export declare const isDefaultInk: (c: Color) => boolean;
|
|
18
|
+
export type Tone = 'light' | 'dark' | 'unknown';
|
|
19
|
+
export declare const inkFor: (tone: Tone) => Color;
|
|
20
|
+
export interface Head {
|
|
21
|
+
/** null: Digital One. Otherwise one of the Ones. */
|
|
22
|
+
one: OneShape | null;
|
|
23
|
+
pose: Pose;
|
|
24
|
+
/** agent-eye's light moment, -1 (waiting below) … 0 (full) … 1 (gone above); amber, inside the eye only. */
|
|
25
|
+
light?: number;
|
|
26
|
+
/** Squash for a hop: 1 is at rest; below 1 squats onto the pivot, above stretches. */
|
|
27
|
+
squash?: number;
|
|
28
|
+
/** Vertical offset in head units (a hop's lift). */
|
|
29
|
+
hop?: number;
|
|
30
|
+
}
|
|
31
|
+
/** Draw a head into the -100…100 box mapped by `m`. */
|
|
32
|
+
export declare function drawHead(cv: Canvas, m: Mat, head: Head, tone: Tone): void;
|
|
33
|
+
export declare const LOGO_ASPECT: number;
|
|
34
|
+
export interface LogoState {
|
|
35
|
+
/** 0…1: the ring draws on clockwise from twelve o'clock. */
|
|
36
|
+
ring: number;
|
|
37
|
+
/** 0 the ring … 1 the disc (its hole closes on the enter curve). */
|
|
38
|
+
fill: number;
|
|
39
|
+
/** When set, the O is a head (One's eye awake, or one of the Ones) in the O's circle. */
|
|
40
|
+
head?: Head | null;
|
|
41
|
+
/** 0…1 each: the N and the E arrive, rising into place. */
|
|
42
|
+
n: number;
|
|
43
|
+
e: number;
|
|
44
|
+
}
|
|
45
|
+
export declare const LOGO_REST: LogoState;
|
|
46
|
+
/** The hybrid ONE, `px` tall (cap height plus the O's overshoot), its top-left at (x, y) in canvas pixels. */
|
|
47
|
+
export declare function drawLogotype(cv: Canvas, x: number, y: number, px: number, s: LogoState, tone: Tone, hint?: boolean): void;
|
|
48
|
+
/** Digital One, `px` across, centred at (cx, cy). */
|
|
49
|
+
export declare function drawEmblem(cv: Canvas, cx: number, cy: number, px: number, head: Partial<Head>, tone: Tone): void;
|
|
50
|
+
export { ONES, LIGHT, sample };
|