@gaia-ai/gaia 0.2.0 → 0.3.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/dist/src/cli/gaia.js +82 -34
- package/dist/src/cli/init.d.ts +8 -0
- package/dist/src/cli/init.js +23 -12
- package/package.json +5 -5
package/dist/src/cli/gaia.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import { dirname } from 'node:path';
|
|
2
3
|
import { createInterface } from 'node:readline';
|
|
3
4
|
import { Command } from 'commander';
|
|
@@ -416,8 +417,8 @@ Examples:
|
|
|
416
417
|
conductor
|
|
417
418
|
.command('init')
|
|
418
419
|
.description('scaffold the committed .gaia/conductor.config.js for this repo plus the user-global conductor.config.machine.js context (identity + connection incl. secret)')
|
|
419
|
-
.
|
|
420
|
-
.
|
|
420
|
+
.option('--base-url <url>', 'control-plane base URL (site.base_url) — required only when onboarding this machine')
|
|
421
|
+
.option('--project <name>', 'GAIA project name — required only to scaffold the committed repo config; omit for machine-only onboarding')
|
|
421
422
|
.option('--secret-env <VAR>', 'env var name to read the oauth client secret from (else TTY prompt)')
|
|
422
423
|
.option('--client-id <id>', 'oauth consumer id', 'gaia-agent')
|
|
423
424
|
.option('--machine-id <id>', 'machine host token for the context (defaults to hostname())')
|
|
@@ -425,40 +426,64 @@ Examples:
|
|
|
425
426
|
.option('--machine-path <path>', 'user-global machine context path (defaults to ~/.config/conductor/conductor.config.machine.js)')
|
|
426
427
|
.option('--config <path>', 'target committed config path', './.gaia/conductor.config.js')
|
|
427
428
|
.option('--force', 'overwrite an existing committed config', false)
|
|
429
|
+
.option('--reonboard', 'force machine-context onboarding even if a context file exists', false)
|
|
428
430
|
.action(async (opts) => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
// The secret lives in the machine context; resolve it only when that
|
|
439
|
-
// context does not already carry one (existing values are never
|
|
440
|
-
// overwritten). Source: --secret-env value, else a TTY prompt.
|
|
431
|
+
// Two independent axes decide what init writes:
|
|
432
|
+
// - machine axis: an existing context means project-only; --reonboard
|
|
433
|
+
// (or an absent context) forces machine-context (re)scaffolding.
|
|
434
|
+
// - repo axis: --project scaffolds the committed repo config; omitting
|
|
435
|
+
// it means machine-only (no repo). The 4 quadrants:
|
|
436
|
+
// context absent + project → both files
|
|
437
|
+
// context absent + no proj → machine-only onboarding
|
|
438
|
+
// context present + project → project-only
|
|
439
|
+
// context present + no proj → no-op (machine already onboarded)
|
|
441
440
|
const machinePath = opts.machinePath ?? machineContextPath();
|
|
442
441
|
const existing = await readMachineContext(machinePath);
|
|
442
|
+
const contextPresent = existsSync(machinePath);
|
|
443
|
+
const onboarding = !contextPresent || opts.reonboard;
|
|
444
|
+
const project = opts.project ?? '';
|
|
445
|
+
const hasProject = project.trim() !== '';
|
|
446
|
+
// Context present and nothing repo-scoped to do → no-op with guidance.
|
|
447
|
+
if (!onboarding && !hasProject) {
|
|
448
|
+
console.log(`machine already onboarded (${machinePath}) — pass --project to set up a repo`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
let userId = opts.userId ?? '';
|
|
443
452
|
let secret = '';
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
secret
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (
|
|
451
|
-
if (process.stdin.isTTY)
|
|
452
|
-
|
|
453
|
+
const baseUrl = opts.baseUrl ?? '';
|
|
454
|
+
if (onboarding) {
|
|
455
|
+
// Full onboarding: base-url + user-id + secret are required here.
|
|
456
|
+
if (baseUrl.trim() === '') {
|
|
457
|
+
throw new Error('--base-url is required when onboarding this machine (no machine context yet, or --reonboard)');
|
|
458
|
+
}
|
|
459
|
+
if (userId.trim() === '') {
|
|
460
|
+
if (process.stdin.isTTY)
|
|
461
|
+
userId = await promptUserId();
|
|
462
|
+
if (userId.trim() === '') {
|
|
463
|
+
throw new Error('--user-id is required (or run in a TTY to be prompted)');
|
|
453
464
|
}
|
|
465
|
+
}
|
|
466
|
+
// The secret lives in the machine context; resolve it only when that
|
|
467
|
+
// context does not already carry one (existing values are never
|
|
468
|
+
// overwritten). Source: --secret-env value, else a TTY prompt.
|
|
469
|
+
if (typeof existing.client_secret !== 'string' ||
|
|
470
|
+
existing.client_secret.trim() === '') {
|
|
471
|
+
secret =
|
|
472
|
+
opts.secretEnv !== undefined
|
|
473
|
+
? (process.env[opts.secretEnv] ?? '')
|
|
474
|
+
: '';
|
|
454
475
|
if (secret.trim() === '') {
|
|
455
|
-
|
|
476
|
+
if (process.stdin.isTTY)
|
|
477
|
+
secret = await promptSecret();
|
|
478
|
+
if (secret.trim() === '') {
|
|
479
|
+
throw new Error('OAuth client secret required: pass --secret-env <VAR> (exported) or run in a TTY to be prompted');
|
|
480
|
+
}
|
|
456
481
|
}
|
|
457
482
|
}
|
|
458
483
|
}
|
|
459
484
|
const inputs = {
|
|
460
|
-
baseUrl
|
|
461
|
-
project
|
|
485
|
+
baseUrl,
|
|
486
|
+
project,
|
|
462
487
|
clientId: opts.clientId,
|
|
463
488
|
secret,
|
|
464
489
|
userId,
|
|
@@ -470,16 +495,39 @@ Examples:
|
|
|
470
495
|
configPath: opts.config,
|
|
471
496
|
force: opts.force,
|
|
472
497
|
machinePath,
|
|
498
|
+
skipMachine: !onboarding,
|
|
499
|
+
skipCommitted: !hasProject,
|
|
473
500
|
});
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
501
|
+
// Mode banner.
|
|
502
|
+
if (!onboarding) {
|
|
503
|
+
console.log(`machine context found (${machinePath}) → setting up project only`);
|
|
504
|
+
if (typeof existing.base_url !== 'string' ||
|
|
505
|
+
existing.base_url.trim() === '') {
|
|
506
|
+
console.log(`warning: ${machinePath} exists but looks incomplete (no base_url) — ` +
|
|
507
|
+
`run with --reonboard to fill the machine context`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
else if (!hasProject) {
|
|
511
|
+
console.log(`onboarding this machine (no project) → run again with --project inside a repo to set it up`);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
console.log(opts.reonboard
|
|
515
|
+
? `re-onboarding this machine (--reonboard)`
|
|
516
|
+
: `no machine context → onboarding this machine`);
|
|
517
|
+
}
|
|
518
|
+
if (hasProject) {
|
|
519
|
+
console.log(res.wroteCommitted
|
|
520
|
+
? `wrote ${res.committedPath}`
|
|
521
|
+
: `kept ${res.committedPath} (exists — pass --force to replace)`);
|
|
522
|
+
}
|
|
477
523
|
const m = res.machine;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
524
|
+
if (onboarding) {
|
|
525
|
+
console.log(m.created
|
|
526
|
+
? `wrote ${m.path} (user-global machine context)`
|
|
527
|
+
: m.filledKeys.length > 0
|
|
528
|
+
? `updated ${m.path} (filled: ${m.filledKeys.join(', ')})`
|
|
529
|
+
: `kept ${m.path} (already complete)`);
|
|
530
|
+
}
|
|
483
531
|
console.log(`\nNext steps:\n` +
|
|
484
532
|
` gaia dropsh auth login --provider session\n` +
|
|
485
533
|
` gaia dropsh auth login --provider pm\n` +
|
package/dist/src/cli/init.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export interface ScaffoldOptions {
|
|
|
11
11
|
configPath: string;
|
|
12
12
|
force: boolean;
|
|
13
13
|
machinePath?: string;
|
|
14
|
+
/** When true, scaffold the committed config only — never read/write the machine context. */
|
|
15
|
+
skipMachine?: boolean;
|
|
16
|
+
/** When true, scaffold the machine context only — never write the committed config. */
|
|
17
|
+
skipCommitted?: boolean;
|
|
14
18
|
}
|
|
15
19
|
export interface ScaffoldResult {
|
|
16
20
|
committedPath: string;
|
|
@@ -70,5 +74,9 @@ export declare function scaffoldMachineContext(opts: MachineContextOptions): Pro
|
|
|
70
74
|
* (created only if missing — never overwritten unless `force`) and the
|
|
71
75
|
* user-global machine context (create-if-missing / fill-only-missing). The
|
|
72
76
|
* optional per-project conductor.config.local.js is NOT generated.
|
|
77
|
+
*
|
|
78
|
+
* `skipMachine` writes the committed config only (project-only setup); its
|
|
79
|
+
* mirror `skipCommitted` writes the machine context only (machine-only
|
|
80
|
+
* onboarding, no repo). Setting both is a no-op.
|
|
73
81
|
*/
|
|
74
82
|
export declare function scaffold(inputs: InitInputs, opts: ScaffoldOptions): Promise<ScaffoldResult>;
|
package/dist/src/cli/init.js
CHANGED
|
@@ -199,22 +199,33 @@ export async function scaffoldMachineContext(opts) {
|
|
|
199
199
|
* (created only if missing — never overwritten unless `force`) and the
|
|
200
200
|
* user-global machine context (create-if-missing / fill-only-missing). The
|
|
201
201
|
* optional per-project conductor.config.local.js is NOT generated.
|
|
202
|
+
*
|
|
203
|
+
* `skipMachine` writes the committed config only (project-only setup); its
|
|
204
|
+
* mirror `skipCommitted` writes the machine context only (machine-only
|
|
205
|
+
* onboarding, no repo). Setting both is a no-op.
|
|
202
206
|
*/
|
|
203
207
|
export async function scaffold(inputs, opts) {
|
|
204
208
|
const committedPath = opts.configPath;
|
|
205
|
-
mkdirSync(dirname(committedPath), { recursive: true });
|
|
206
209
|
let wroteCommitted = false;
|
|
207
|
-
if (!
|
|
208
|
-
|
|
209
|
-
|
|
210
|
+
if (!opts.skipCommitted) {
|
|
211
|
+
mkdirSync(dirname(committedPath), { recursive: true });
|
|
212
|
+
if (!existsSync(committedPath) || opts.force) {
|
|
213
|
+
writeFileSync(committedPath, renderCommittedConfig(inputs), 'utf8');
|
|
214
|
+
wroteCommitted = true;
|
|
215
|
+
}
|
|
210
216
|
}
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
const machinePath = opts.machinePath ?? machineContextPath();
|
|
218
|
+
const machine = opts.skipMachine
|
|
219
|
+
? { path: machinePath, created: false, filledKeys: [] }
|
|
220
|
+
: await scaffoldMachineContext({
|
|
221
|
+
path: machinePath,
|
|
222
|
+
userId: inputs.userId ?? '',
|
|
223
|
+
baseUrl: inputs.baseUrl,
|
|
224
|
+
clientId: inputs.clientId,
|
|
225
|
+
secret: inputs.secret,
|
|
226
|
+
...(inputs.machineId !== undefined
|
|
227
|
+
? { machineId: inputs.machineId }
|
|
228
|
+
: {}),
|
|
229
|
+
});
|
|
219
230
|
return { committedPath, wroteCommitted, machine };
|
|
220
231
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaia-ai/gaia",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "GAIA Network conductor node: registers, claims tickets via JSON:API, runs agents through spawn plugins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@dropsh/plugin-oauth2": "^0.4.1",
|
|
43
43
|
"@dropsh/plugin-schemata": "^0.4.1",
|
|
44
|
-
"@gaia-ai/plugin-claude": "^0.
|
|
45
|
-
"@gaia-ai/plugin-codex": "^0.
|
|
46
|
-
"@gaia-ai/plugin-herdr": "^0.
|
|
47
|
-
"@gaia-ai/plugin-herdr-workspace": "^0.
|
|
44
|
+
"@gaia-ai/plugin-claude": "^0.3.0",
|
|
45
|
+
"@gaia-ai/plugin-codex": "^0.3.0",
|
|
46
|
+
"@gaia-ai/plugin-herdr": "^0.3.0",
|
|
47
|
+
"@gaia-ai/plugin-herdr-workspace": "^0.3.0",
|
|
48
48
|
"commander": "^12.1.0",
|
|
49
49
|
"dropsh": "^0.4.1",
|
|
50
50
|
"pino": "^9.6.0",
|