@gaia-ai/gaia 0.13.1 → 0.14.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.
@@ -1,7 +1,8 @@
1
1
  import { homedir, hostname } from 'node:os';
2
+ import { join } from 'node:path';
2
3
  import { createInterface } from 'node:readline';
3
4
  import { pathToFileURL } from 'node:url';
4
- import { applyConfigPlan, planConfig, } from '@gaia-ai/conductor/config';
5
+ import { reportLoadedGaiaConfigFields, resolveGaiaConnectionSelection, } from '@gaia-ai/core';
5
6
  import { Option } from 'commander';
6
7
  /** Terminal-only input. Secret characters are never echoed. */
7
8
  async function promptInput(label, secret = false) {
@@ -41,6 +42,12 @@ export function renderConfigReport(report, dryRun = false) {
41
42
  ];
42
43
  for (const file of report.files.filter((file) => file.selected))
43
44
  lines.push(`${file.layer}: ${file.path} (${file.state}; schema ${file.version.effective ?? 'unversioned'} → ${file.version.current ?? 'unversioned'}; ${file.fingerprint ?? 'absent'})`);
45
+ if (report.connection_resolution) {
46
+ const selected = report.connection_resolution;
47
+ lines.push(`Connection: ${selected.id} (${selected.selected_by}) — ${selected.path}`);
48
+ for (const field of selected.fields)
49
+ lines.push(` ${field.key}: ${String(field.value)} (from ${field.source})`);
50
+ }
44
51
  for (const change of report.changes)
45
52
  lines.push(`${change.path}: schema ${change.before_version ?? 'absent/unversioned'} → ${change.after_version ?? 'unversioned'}\n${change.diff}`);
46
53
  for (const finding of report.findings)
@@ -73,22 +80,25 @@ export function registerConfig(program, deps = {}) {
73
80
  .option('--project <name>', 'explicit project name for initialization')
74
81
  .option('--machine-path <file>', 'override machine configuration path')
75
82
  .option('--config <file>', 'override global connection configuration path')
83
+ .option('--connection <id>', 'named connection from ~/.gaia/connections')
76
84
  .option('--yes', 'disable prompts and automatic selections')
77
85
  .option('--online', 'authenticate and verify each selected workspace (not applicable for machine scope)');
78
86
  if (operation !== 'check')
79
87
  command
80
88
  .option('--dry-run', 'report planned changes without imports, network or writes')
81
- .addOption(new Option('--project-connection <choice>', 'retain inheritance/existing override, or explicitly create one')
82
- .choices(['keep', 'create'])
83
- .default('keep'))
89
+ .addOption(new Option('--project-connection <choice>', 'retired; use --connection'))
84
90
  .option('--machine-id <id>', 'explicit host identity')
85
91
  .option('--user-id <id>', 'local operator identifier')
86
92
  .option('--max-parallel <number>', 'positive integer host capacity')
87
93
  .option('--base-url <url>', 'connection server URL')
88
94
  .option('--client-id <id>', 'OAuth client identifier')
89
95
  .option('--workspace-id <uuid>', 'explicit workspace UUID')
96
+ .option('--workspace <name>', 'committed project workspace name')
90
97
  .option('--secret-env <name>', 'environment variable containing the OAuth secret');
91
98
  command.action(async (options) => {
99
+ const { applyConfigPlan, planConfig } = await import('@gaia-ai/conductor/config');
100
+ if (options.projectConnection !== undefined)
101
+ throw new Error('--project-connection is retired; use --connection <id> and .gaia/connection.config.local.js.');
92
102
  const cwd = deps.cwd ?? process.cwd();
93
103
  const env = deps.env ?? process.env;
94
104
  const interactive = (deps.isTTY ?? Boolean(process.stdin.isTTY && process.stdout.isTTY)) &&
@@ -113,6 +123,7 @@ export function registerConfig(program, deps = {}) {
113
123
  'baseUrl',
114
124
  'clientId',
115
125
  'workspaceId',
126
+ 'workspace',
116
127
  ]) {
117
128
  const value = options[key];
118
129
  if (value !== undefined)
@@ -127,7 +138,6 @@ export function registerConfig(program, deps = {}) {
127
138
  operation,
128
139
  cwd,
129
140
  home: deps.home ?? homedir(),
130
- projectConnection: options.projectConnection === 'create' ? 'create' : 'inherit',
131
141
  inputs,
132
142
  };
133
143
  for (const key of ['scope', 'path', 'project', 'machinePath']) {
@@ -137,6 +147,25 @@ export function registerConfig(program, deps = {}) {
137
147
  }
138
148
  if (options.config !== undefined)
139
149
  planning.connectionPath = options.config;
150
+ else if (options.connection !== undefined) {
151
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(options.connection))
152
+ throw new Error('--connection must be an identifier containing letters, numbers, dot, underscore or hyphen.');
153
+ planning.connectionPath = join(deps.home ?? homedir(), '.gaia', 'connections', `${options.connection}.js`);
154
+ }
155
+ let selectedConnection;
156
+ const initializesNamedConnection = operation === 'init' &&
157
+ options.connection !== undefined &&
158
+ ['connection', 'all'].includes(options.scope ?? '');
159
+ if (!initializesNamedConnection && options.scope !== 'machine') {
160
+ selectedConnection = await resolveGaiaConnectionSelection({
161
+ cwd,
162
+ home: deps.home ?? homedir(),
163
+ env,
164
+ ...(options.config ? { explicit: options.config } : {}),
165
+ ...(options.connection ? { connection: options.connection } : {}),
166
+ });
167
+ planning.connectionPath = selectedConnection.path;
168
+ }
140
169
  let plan = planConfig(planning);
141
170
  if (operation === 'init' &&
142
171
  options.project &&
@@ -162,10 +191,11 @@ export function registerConfig(program, deps = {}) {
162
191
  ['clientId', 'client_id', 'OAuth client identifier'],
163
192
  ['secret', 'client_secret', 'OAuth client secret'],
164
193
  ['workspaceId', 'workspace_id', 'Workspace UUID'],
194
+ ['workspace', 'gaia.workspace', 'Workspace name'],
165
195
  ];
166
196
  for (const [input, key, label] of fields) {
167
197
  const requiredForFreshConnection = freshConnection &&
168
- ['baseUrl', 'clientId', 'secret', 'workspaceId'].includes(input);
198
+ ['baseUrl', 'clientId', 'secret'].includes(input);
169
199
  if (inputs[input] !== undefined ||
170
200
  (!requiredForFreshConnection &&
171
201
  !plan.report.findings.some((f) => plan.report.resolved_scopes.includes(f.owner) &&
@@ -241,6 +271,31 @@ export function registerConfig(program, deps = {}) {
241
271
  reason,
242
272
  });
243
273
  }
274
+ const resolution = selectedConnection ??
275
+ (planning.connectionPath
276
+ ? {
277
+ path: planning.connectionPath,
278
+ connectionId: options.connection ?? 'default',
279
+ selectionSource: options.connection
280
+ ? 'flag-connection'
281
+ : 'flag-config',
282
+ }
283
+ : undefined);
284
+ if (resolution) {
285
+ let fields = [];
286
+ try {
287
+ fields = await reportLoadedGaiaConfigFields(resolution.path);
288
+ }
289
+ catch {
290
+ // Inventory findings already describe an unreadable or malformed file.
291
+ }
292
+ report.connection_resolution = {
293
+ id: resolution.connectionId ?? 'default',
294
+ selected_by: resolution.selectionSource,
295
+ path: resolution.path,
296
+ fields,
297
+ };
298
+ }
244
299
  (deps.stdout ?? ((text) => process.stdout.write(text)))(options.format === 'json'
245
300
  ? `${JSON.stringify(report)}\n`
246
301
  : renderConfigReport(report, options.dryRun));
package/dist/src/host.js CHANGED
@@ -5,7 +5,7 @@ import { commands as dropshCommands } from '@gaia-ai/addon-dropsh/preset';
5
5
  import { commands as infoCommands } from '@gaia-ai/addon-info/preset';
6
6
  import { commands as portsCommands } from '@gaia-ai/addon-ports/preset';
7
7
  import { commands as conductorCommands } from '@gaia-ai/conductor/preset';
8
- import { resolveCliVersion, resolveModuleEslintStyle, } from '@gaia-ai/core';
8
+ import { resolveCliVersion, resolveConfigPath, resolveModuleEslintStyle, } from '@gaia-ai/core';
9
9
  import { commands as uiCommands } from '@gaia-ai/ui/preset';
10
10
  import { Command } from 'commander';
11
11
  import { registerConfig } from './config.js';
@@ -140,9 +140,36 @@ function pluginDescribe(entry) {
140
140
  * are describe-only stubs). */
141
141
  export async function buildHostProgram(argv, opts = {}) {
142
142
  const bases = opts.bases ?? hostBases();
143
- const host = { resolveBases: bases };
144
143
  const commands = resolveCommands();
145
144
  const names = commands.map((c) => c.name);
145
+ const target = opts.forceTarget ?? scanTarget(argv, names);
146
+ const projectContext = target === 'ui'
147
+ ? await import('@gaia-ai/conductor/project-context')
148
+ : undefined;
149
+ const host = {
150
+ resolveBases: bases,
151
+ workspacePlugin: async (workspaceId) => {
152
+ const { workspacePlugin } = await import('@gaia-ai/addon-workspace');
153
+ return workspacePlugin({ workspace_id: workspaceId });
154
+ },
155
+ ...(projectContext
156
+ ? {
157
+ projectContext: {
158
+ resolveConfigPath: (cwd) => resolveConfigPath(undefined, cwd),
159
+ readWorkspace: (configPath) => projectContext.readGaiaProjectSelection(configPath).workspace,
160
+ resolveContext: async (configPath, connection) => {
161
+ const { createGaiaConnectionClient } = await import('@gaia-ai/core');
162
+ const { resolveGaiaProjectContext } = await import('@gaia-ai/conductor/contract');
163
+ const selection = projectContext.readGaiaProjectSelection(configPath);
164
+ return resolveGaiaProjectContext(await createGaiaConnectionClient(connection), selection);
165
+ },
166
+ writeWorkspace: async (configPath, name) => {
167
+ await projectContext.writeGaiaWorkspaceSelection(projectContext.gaiaProjectOwner(configPath), name, `Set gaia.workspace in ${configPath} to switch manually.`);
168
+ },
169
+ },
170
+ }
171
+ : {}),
172
+ };
146
173
  const program = new Command();
147
174
  // exitOverride so commander surfaces help/version/unknown-command as thrown
148
175
  // CommanderErrors (mapped in runHost) instead of calling process.exit —
@@ -171,7 +198,6 @@ export async function buildHostProgram(argv, opts = {}) {
171
198
  registerConfig(program, { host });
172
199
  registerUpdate(program);
173
200
  registerValidate(program);
174
- const target = opts.forceTarget ?? scanTarget(argv, names);
175
201
  for (const entry of commands) {
176
202
  if (entry.name === target) {
177
203
  const plugin = await loadCommandPlugin(entry, bases);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gaia-ai/gaia",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
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.13.1",
42
- "@gaia-ai/addon-auth-basic": "^0.13.1",
43
- "@gaia-ai/addon-claude": "^0.13.1",
44
- "@gaia-ai/addon-codex": "^0.13.1",
45
- "@gaia-ai/addon-deployment": "^0.13.1",
46
- "@gaia-ai/addon-dropsh": "^0.13.1",
47
- "@gaia-ai/addon-essentials": "^0.13.1",
48
- "@gaia-ai/addon-gaia-ui": "^0.13.1",
49
- "@gaia-ai/addon-gaia-ui-artifacts": "^0.13.1",
50
- "@gaia-ai/addon-grok": "^0.13.1",
51
- "@gaia-ai/addon-herdr": "^0.13.1",
52
- "@gaia-ai/addon-info": "^0.13.1",
53
- "@gaia-ai/addon-kimi": "^0.13.1",
54
- "@gaia-ai/addon-opencode": "^0.13.1",
55
- "@gaia-ai/addon-pi": "^0.13.1",
56
- "@gaia-ai/addon-ports": "^0.13.1",
57
- "@gaia-ai/addon-ports-ui": "^0.13.1",
58
- "@gaia-ai/addon-remote-drupal": "^0.13.1",
59
- "@gaia-ai/addon-workspace": "^0.13.1",
60
- "@gaia-ai/addon-workspace-git": "^0.13.1",
61
- "@gaia-ai/conductor": "^0.13.1",
62
- "@gaia-ai/core": "^0.13.1",
63
- "@gaia-ai/ui": "^0.13.1",
41
+ "@gaia-ai/addon-agents": "^0.14.0",
42
+ "@gaia-ai/addon-auth-basic": "^0.14.0",
43
+ "@gaia-ai/addon-claude": "^0.14.0",
44
+ "@gaia-ai/addon-codex": "^0.14.0",
45
+ "@gaia-ai/addon-deployment": "^0.14.0",
46
+ "@gaia-ai/addon-dropsh": "^0.14.0",
47
+ "@gaia-ai/addon-essentials": "^0.14.0",
48
+ "@gaia-ai/addon-gaia-ui": "^0.14.0",
49
+ "@gaia-ai/addon-gaia-ui-artifacts": "^0.14.0",
50
+ "@gaia-ai/addon-grok": "^0.14.0",
51
+ "@gaia-ai/addon-herdr": "^0.14.0",
52
+ "@gaia-ai/addon-info": "^0.14.0",
53
+ "@gaia-ai/addon-kimi": "^0.14.0",
54
+ "@gaia-ai/addon-opencode": "^0.14.0",
55
+ "@gaia-ai/addon-pi": "^0.14.0",
56
+ "@gaia-ai/addon-ports": "^0.14.0",
57
+ "@gaia-ai/addon-ports-ui": "^0.14.0",
58
+ "@gaia-ai/addon-remote-drupal": "^0.14.0",
59
+ "@gaia-ai/addon-workspace": "^0.14.0",
60
+ "@gaia-ai/addon-workspace-git": "^0.14.0",
61
+ "@gaia-ai/conductor": "^0.14.0",
62
+ "@gaia-ai/core": "^0.14.0",
63
+ "@gaia-ai/ui": "^0.14.0",
64
64
  "commander": "^12.1.0"
65
65
  }
66
66
  }