@gaia-ai/gaia 0.14.1 → 0.14.2
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/config.js +83 -16
- package/package.json +24 -24
package/dist/src/config.js
CHANGED
|
@@ -60,18 +60,25 @@ export function renderConfigReport(report, dryRun = false) {
|
|
|
60
60
|
lines.push('Connection readiness is unverified; successful migration does not verify server access.');
|
|
61
61
|
return `${lines.join('\n')}\n`;
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Attaches one `config <operation>` command to `parent` (either the `config`
|
|
65
|
+
* group or, for the `gaia init` shortcut, `program` itself). `hiddenScope`
|
|
66
|
+
* exists only for that shortcut: `gaia init` resolves to machine + connection
|
|
67
|
+
* without ever showing `--scope` or its value anywhere (not in `--help`, not
|
|
68
|
+
* in a default), since a human running `gaia init` never chooses or sees a
|
|
69
|
+
* scope at all — while `gaia config init` keeps asking for one (or requiring
|
|
70
|
+
* `--scope` explicitly) exactly as before.
|
|
71
|
+
*/
|
|
72
|
+
function buildConfigCommand(parent, operation, deps, hiddenScope, description) {
|
|
73
|
+
{
|
|
74
|
+
const command = parent
|
|
69
75
|
.command(operation)
|
|
70
|
-
.description(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
.description(description ??
|
|
77
|
+
(operation === 'init'
|
|
78
|
+
? 'initialize or repair selected configuration and verify readiness'
|
|
79
|
+
: operation === 'upgrade'
|
|
80
|
+
? 'migrate selected configuration without changing existing values'
|
|
81
|
+
: 'validate configuration offline; optionally verify online access'))
|
|
75
82
|
.option('--scope <scope>', 'machine | connection | project | all; init requires a scope')
|
|
76
83
|
.addOption(new Option('--format <format>', 'report format; JSON disables prompts')
|
|
77
84
|
.choices(['text', 'json'])
|
|
@@ -94,8 +101,11 @@ export function registerConfig(program, deps = {}) {
|
|
|
94
101
|
.option('--client-id <id>', 'OAuth client identifier')
|
|
95
102
|
.option('--workspace-id <uuid>', 'explicit workspace UUID')
|
|
96
103
|
.option('--workspace <name>', 'committed project workspace name')
|
|
97
|
-
.option('--secret-env <name>', 'environment variable containing the OAuth secret')
|
|
104
|
+
.option('--secret-env <name>', 'environment variable containing the OAuth secret')
|
|
105
|
+
.addOption(new Option('--auth-type <type>', 'sign in with device code (default, no secret) or a client secret (internal/CI)').choices(['client_credentials', 'device']));
|
|
98
106
|
command.action(async (options) => {
|
|
107
|
+
if (hiddenScope !== undefined && options.scope === undefined)
|
|
108
|
+
options.scope = hiddenScope;
|
|
99
109
|
const { applyConfigPlan, planConfig } = await import('@gaia-ai/conductor/config');
|
|
100
110
|
if (options.projectConnection !== undefined)
|
|
101
111
|
throw new Error('--project-connection is retired; use --connection <id> and .gaia/connection.config.local.js.');
|
|
@@ -134,11 +144,19 @@ export function registerConfig(program, deps = {}) {
|
|
|
134
144
|
const secret = options.secretEnv ? env[options.secretEnv] : undefined;
|
|
135
145
|
if (secret !== undefined)
|
|
136
146
|
inputs.secret = secret;
|
|
147
|
+
if (options.authType)
|
|
148
|
+
inputs.authType =
|
|
149
|
+
options.authType === 'client_credentials'
|
|
150
|
+
? 'oauth2_client_credentials'
|
|
151
|
+
: 'oauth2_device_code';
|
|
137
152
|
const planning = {
|
|
138
153
|
operation,
|
|
139
154
|
cwd,
|
|
140
155
|
home: deps.home ?? homedir(),
|
|
141
156
|
inputs,
|
|
157
|
+
// `gaia init` (hiddenScope !== undefined) never pulls the project
|
|
158
|
+
// layer in, even inside a project checkout (GAIA-496 finding 1).
|
|
159
|
+
...(hiddenScope !== undefined ? { excludeProjectLayer: true } : {}),
|
|
142
160
|
};
|
|
143
161
|
for (const key of ['scope', 'path', 'project', 'machinePath']) {
|
|
144
162
|
const value = options[key];
|
|
@@ -180,10 +198,25 @@ export function registerConfig(program, deps = {}) {
|
|
|
180
198
|
plan.report.files.some((file) => file.kind === 'connection' &&
|
|
181
199
|
file.selected &&
|
|
182
200
|
file.state === 'absent');
|
|
201
|
+
// No sign-in question: device code is the only way `gaia config init`
|
|
202
|
+
// offers (GAIA-496). `--auth-type client_credentials` remains for the
|
|
203
|
+
// internal/CI path but is never interviewed for or invented outside
|
|
204
|
+
// it — this default applies whether or not a terminal is attached, so
|
|
205
|
+
// a non-interactive `gaia init --yes` gets the same secret-free
|
|
206
|
+
// connection an interactive run does. A caller who already supplied a
|
|
207
|
+
// secret (`--secret-env`) evidently wants client_credentials and is
|
|
208
|
+
// left alone rather than silently switched to device code.
|
|
209
|
+
if (freshConnection &&
|
|
210
|
+
inputs.authType === undefined &&
|
|
211
|
+
inputs.secret === undefined) {
|
|
212
|
+
inputs.authType = 'oauth2_device_code';
|
|
213
|
+
plan = planConfig(planning);
|
|
214
|
+
}
|
|
183
215
|
if (interactive &&
|
|
184
216
|
operation !== 'check' &&
|
|
185
217
|
!cancelled &&
|
|
186
218
|
!plan.report.findings.some((f) => f.stage === 'scope')) {
|
|
219
|
+
const deviceCode = inputs.authType === 'oauth2_device_code';
|
|
187
220
|
const fields = [
|
|
188
221
|
['machineId', 'machine_id', 'Machine identity'],
|
|
189
222
|
['userId', 'user_id', 'Local operator identifier'],
|
|
@@ -192,10 +225,12 @@ export function registerConfig(program, deps = {}) {
|
|
|
192
225
|
['secret', 'client_secret', 'OAuth client secret'],
|
|
193
226
|
['workspaceId', 'workspace_id', 'Workspace UUID'],
|
|
194
227
|
['workspace', 'gaia.workspace', 'Workspace name'],
|
|
195
|
-
];
|
|
228
|
+
].filter(([input]) => !(deviceCode && input === 'secret'));
|
|
196
229
|
for (const [input, key, label] of fields) {
|
|
197
230
|
const requiredForFreshConnection = freshConnection &&
|
|
198
|
-
|
|
231
|
+
(deviceCode
|
|
232
|
+
? ['baseUrl', 'clientId']
|
|
233
|
+
: ['baseUrl', 'clientId', 'secret']).includes(input);
|
|
199
234
|
if (inputs[input] !== undefined ||
|
|
200
235
|
(!requiredForFreshConnection &&
|
|
201
236
|
!plan.report.findings.some((f) => plan.report.resolved_scopes.includes(f.owner) &&
|
|
@@ -203,7 +238,17 @@ export function registerConfig(program, deps = {}) {
|
|
|
203
238
|
(f.key === key || f.key?.endsWith(`.${key}`)))))
|
|
204
239
|
continue;
|
|
205
240
|
try {
|
|
206
|
-
const suggested = input === 'machineId'
|
|
241
|
+
const suggested = input === 'machineId'
|
|
242
|
+
? hostname().split('.')[0]
|
|
243
|
+
: input === 'baseUrl'
|
|
244
|
+
? // Suggests keytec's own fleet instance so pressing Enter
|
|
245
|
+
// reaches a working setup with no site to look up first;
|
|
246
|
+
// it is a default, not a requirement — any base URL
|
|
247
|
+
// typed over it is used verbatim (GAIA-496).
|
|
248
|
+
'https://gaia.keytec.de'
|
|
249
|
+
: deviceCode && input === 'clientId'
|
|
250
|
+
? 'gaia-cli'
|
|
251
|
+
: undefined;
|
|
207
252
|
const answer = (await prompt(`${label}${suggested ? ` [${suggested}]` : ''}`, input === 'secret')) || suggested;
|
|
208
253
|
if (answer !== undefined)
|
|
209
254
|
inputs[input] = answer;
|
|
@@ -257,7 +302,13 @@ export function registerConfig(program, deps = {}) {
|
|
|
257
302
|
resolveBases: [import.meta.url, pathToFileURL(`${cwd}/`).href],
|
|
258
303
|
},
|
|
259
304
|
...(deps.stateDir ? { stateDir: deps.stateDir } : {}),
|
|
260
|
-
|
|
305
|
+
// A fresh device-code connection cannot be verified without a
|
|
306
|
+
// human confirming the code, so it is left to the ordinary
|
|
307
|
+
// session-based check (which fails fast rather than polling
|
|
308
|
+
// forever for a confirmation that never arrives).
|
|
309
|
+
...(freshConnection && inputs.authType !== 'oauth2_device_code'
|
|
310
|
+
? { ephemeralClientCredentials: true }
|
|
311
|
+
: {}),
|
|
261
312
|
});
|
|
262
313
|
}
|
|
263
314
|
else if (!options.dryRun &&
|
|
@@ -304,3 +355,19 @@ export function registerConfig(program, deps = {}) {
|
|
|
304
355
|
});
|
|
305
356
|
}
|
|
306
357
|
}
|
|
358
|
+
export function registerConfig(program, deps = {}) {
|
|
359
|
+
const group = program
|
|
360
|
+
.command('config')
|
|
361
|
+
.description('initialize, migrate and validate scoped GAIA configuration');
|
|
362
|
+
for (const operation of ['init', 'upgrade', 'check'])
|
|
363
|
+
buildConfigCommand(group, operation, deps);
|
|
364
|
+
// `gaia init` is the user-facing shortcut that sets up machine identity AND
|
|
365
|
+
// the sign-in connection — the two things a human actually needs before
|
|
366
|
+
// running anything else. There is no `--scope` for it at all: it silently
|
|
367
|
+
// resolves both layers (via the same `all` inventory scope `gaia config
|
|
368
|
+
// init --scope all` uses outside a project — config-inventory.ts — but
|
|
369
|
+
// that value is never shown, defaulted, or documented here). The project
|
|
370
|
+
// scope stays reachable only through the full `gaia config init --scope
|
|
371
|
+
// project` command.
|
|
372
|
+
buildConfigCommand(program, 'init', deps, 'all', 'sign in: sets up machine identity and the connection (not project)');
|
|
373
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaia-ai/gaia",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "GAIA meta package: the `gaia` plugin-host CLI + all runtime plugins. Global install target.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,29 +38,29 @@
|
|
|
38
38
|
"jsonapi"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@gaia-ai/addon-agents": "^0.14.
|
|
42
|
-
"@gaia-ai/addon-auth-basic": "^0.14.
|
|
43
|
-
"@gaia-ai/addon-claude": "^0.14.
|
|
44
|
-
"@gaia-ai/addon-codex": "^0.14.
|
|
45
|
-
"@gaia-ai/addon-deployment": "^0.14.
|
|
46
|
-
"@gaia-ai/addon-dropsh": "^0.14.
|
|
47
|
-
"@gaia-ai/addon-essentials": "^0.14.
|
|
48
|
-
"@gaia-ai/addon-gaia-ui": "^0.14.
|
|
49
|
-
"@gaia-ai/addon-gaia-ui-artifacts": "^0.14.
|
|
50
|
-
"@gaia-ai/addon-grok": "^0.14.
|
|
51
|
-
"@gaia-ai/addon-herdr": "^0.14.
|
|
52
|
-
"@gaia-ai/addon-info": "^0.14.
|
|
53
|
-
"@gaia-ai/addon-kimi": "^0.14.
|
|
54
|
-
"@gaia-ai/addon-opencode": "^0.14.
|
|
55
|
-
"@gaia-ai/addon-pi": "^0.14.
|
|
56
|
-
"@gaia-ai/addon-ports": "^0.14.
|
|
57
|
-
"@gaia-ai/addon-ports-ui": "^0.14.
|
|
58
|
-
"@gaia-ai/addon-remote-drupal": "^0.14.
|
|
59
|
-
"@gaia-ai/addon-workspace": "^0.14.
|
|
60
|
-
"@gaia-ai/addon-workspace-git": "^0.14.
|
|
61
|
-
"@gaia-ai/conductor": "^0.14.
|
|
62
|
-
"@gaia-ai/core": "^0.14.
|
|
63
|
-
"@gaia-ai/ui": "^0.14.
|
|
41
|
+
"@gaia-ai/addon-agents": "^0.14.2",
|
|
42
|
+
"@gaia-ai/addon-auth-basic": "^0.14.2",
|
|
43
|
+
"@gaia-ai/addon-claude": "^0.14.2",
|
|
44
|
+
"@gaia-ai/addon-codex": "^0.14.2",
|
|
45
|
+
"@gaia-ai/addon-deployment": "^0.14.2",
|
|
46
|
+
"@gaia-ai/addon-dropsh": "^0.14.2",
|
|
47
|
+
"@gaia-ai/addon-essentials": "^0.14.2",
|
|
48
|
+
"@gaia-ai/addon-gaia-ui": "^0.14.2",
|
|
49
|
+
"@gaia-ai/addon-gaia-ui-artifacts": "^0.14.2",
|
|
50
|
+
"@gaia-ai/addon-grok": "^0.14.2",
|
|
51
|
+
"@gaia-ai/addon-herdr": "^0.14.2",
|
|
52
|
+
"@gaia-ai/addon-info": "^0.14.2",
|
|
53
|
+
"@gaia-ai/addon-kimi": "^0.14.2",
|
|
54
|
+
"@gaia-ai/addon-opencode": "^0.14.2",
|
|
55
|
+
"@gaia-ai/addon-pi": "^0.14.2",
|
|
56
|
+
"@gaia-ai/addon-ports": "^0.14.2",
|
|
57
|
+
"@gaia-ai/addon-ports-ui": "^0.14.2",
|
|
58
|
+
"@gaia-ai/addon-remote-drupal": "^0.14.2",
|
|
59
|
+
"@gaia-ai/addon-workspace": "^0.14.2",
|
|
60
|
+
"@gaia-ai/addon-workspace-git": "^0.14.2",
|
|
61
|
+
"@gaia-ai/conductor": "^0.14.2",
|
|
62
|
+
"@gaia-ai/core": "^0.14.2",
|
|
63
|
+
"@gaia-ai/ui": "^0.14.2",
|
|
64
64
|
"commander": "^12.1.0"
|
|
65
65
|
}
|
|
66
66
|
}
|