@aiwg/cli 2026.10.8 → 2026.10.10
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/agentic/code/providers/model-capabilities.v1.json +197 -3
- package/bin/aiwg.mjs +8 -0
- package/dist/src/artifacts/cli.js +9 -5
- package/dist/src/auth/config.js +3 -8
- package/dist/src/auth/resource-credentials.js +35 -2
- package/dist/src/cli/handlers/diagnose.js +13 -0
- package/dist/src/cli/handlers/mc-admission.js +39 -0
- package/dist/src/cli/handlers/mc.js +2 -31
- package/dist/src/cli/handlers/models-help.js +52 -0
- package/dist/src/cli/handlers/models.js +11 -81
- package/dist/src/cli/handlers/resource-versions.js +8 -5
- package/dist/src/cli/handlers/script-runner.js +13 -1
- package/dist/src/cli/handlers/use-addon-profile.js +72 -0
- package/dist/src/cli/handlers/use.js +209 -233
- package/dist/src/cli/ui.js +1 -0
- package/dist/src/config/aiwg-config.js +38 -184
- package/dist/src/config/cli-help.js +54 -0
- package/dist/src/config/cli.js +5 -69
- package/dist/src/config/config-normalization.js +10 -0
- package/dist/src/config/worker-activation-gate.js +26 -0
- package/dist/src/config/worker-adoption-cli.js +102 -0
- package/dist/src/config/worker-adoption.js +368 -0
- package/dist/src/config/worker-config-digest.js +14 -0
- package/dist/src/config/worker-group-templates.js +150 -0
- package/dist/src/config/worker-guidance-warning.js +28 -0
- package/dist/src/config/worker-owner-lock.js +152 -0
- package/dist/src/config/worker-parallelism.js +154 -0
- package/dist/src/config/worker-write.js +75 -0
- package/dist/src/decision/telemetry/exporter.js +2 -1
- package/dist/src/decision/telemetry/index.js +1 -0
- package/dist/src/decision/telemetry/mapping.js +43 -0
- package/dist/src/decision/telemetry/otlp-http.js +5 -2
- package/dist/src/decision/telemetry/redaction.js +6 -1
- package/dist/src/decision/telemetry/types.js +3 -0
- package/dist/src/decision/telemetry/worker.js +69 -0
- package/dist/src/lint/rule-activation.js +15 -7
- package/dist/src/lint/runner.js +2 -2
- package/dist/src/mcp/server.mjs +2 -11
- package/dist/src/mcp/stdio-lifecycle.mjs +27 -0
- package/dist/src/mcp/tools/worker-failure-diagnostics.mjs +9 -0
- package/dist/src/mcp/tools/worker-invoke.mjs +6 -6
- package/dist/src/mission-protocol/codecs.js +8 -38
- package/dist/src/mission-protocol/worker-contract-diagnostics.js +62 -0
- package/dist/src/mission-protocol/worker-invocation-types.js +2 -0
- package/dist/src/models/conductor-data-policy.d.mts +8 -0
- package/dist/src/models/conductor-data-policy.mjs +190 -0
- package/dist/src/models/config-loader.js +19 -3
- package/dist/src/models/config-writer.js +27 -0
- package/dist/src/models/model-capabilities.v1.json +197 -3
- package/dist/src/models/provider-policy.js +7 -155
- package/dist/src/models/resolver.js +2 -293
- package/dist/src/models/worker-artifact-binding.mjs +12 -0
- package/dist/src/models/worker-direct-readiness-policy.js +155 -0
- package/dist/src/models/worker-direct-readiness.js +9 -218
- package/dist/src/models/worker-health-readiness.js +105 -26
- package/dist/src/models/worker-installation.mjs +12 -14
- package/dist/src/models/worker-member-references.js +64 -0
- package/dist/src/models/worker-plan.js +317 -0
- package/dist/src/models/worker-selection-policy.js +217 -0
- package/dist/src/models/wrapper-deployment.js +1 -1
- package/dist/src/resources/web-release.js +76 -65
- package/dist/src/serve/shared-host-admission-checks.js +116 -0
- package/dist/src/serve/shared-host-scheduler.js +25 -107
- package/dist/src/serve/shared-host-starvation.js +73 -0
- package/dist/src/serve/worker-artifacts.d.mts +4 -0
- package/dist/src/serve/worker-artifacts.mjs +56 -0
- package/dist/src/serve/worker-command-request.js +68 -0
- package/dist/src/serve/worker-invocation-paths.js +144 -0
- package/dist/src/serve/worker-invocation-preparation.js +169 -0
- package/dist/src/serve/worker-invocation.js +24 -291
- package/dist/src/serve/worker-stdin-frame.d.mts +2 -2
- package/dist/src/serve/worker-stdin-frame.mjs +6 -6
- package/dist/src/smiths/context-pipeline/parallelism-section.js +19 -7
- package/dist/src/storage/backends/fortemi.js +33 -29
- package/dist/src/storage/backends/logseq.js +16 -3
- package/dist/src/storage/backends/postgres.js +74 -33
- package/dist/src/storage/backends/postgrest.js +37 -13
- package/dist/src/storage/config.js +6 -1
- package/dist/src/uhp/config.js +4 -0
- package/package.json +9 -1
- package/schemas/mission-v1.schema.json +20 -19
- package/schemas/models/model-config-compatibility.v1.schema.json +16 -0
- package/tools/agents/providers/claude-post-deploy.mjs +35 -0
- package/tools/agents/providers/claude.mjs +3 -30
- package/tools/agents/providers/codex-post-deploy.mjs +13 -0
- package/tools/agents/providers/codex.mjs +2 -8
- package/tools/agents/providers/conductor-data-guard.mjs +61 -0
- package/tools/agents/providers/rule-delivery.mjs +3 -16
- package/tools/agents/providers/rule-presentation.mjs +38 -0
- package/tools/plugin/package-plugins.mjs +1 -1
- package/tools/ralph-external/lib/claude-adapter.mjs +2 -2
- package/tools/ralph-external/lib/codex-adapter.mjs +3 -3
- package/tools/ralph-external/lib/managed-worker-attempt.mjs +86 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +11 -260
- package/tools/ralph-external/lib/session-attempt.mjs +85 -0
- package/tools/ralph-external/lib/strict-worker-json.mjs +190 -0
- package/tools/ralph-external/lib/worker-artifacts.mjs +209 -0
- package/tools/ralph-external/lib/worker-final.mjs +143 -0
- package/tools/ralph-external/lib/worker-inputs.mjs +55 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +2 -44
- package/tools/ralph-external/lib/worker-launch-cli.mjs +47 -0
- package/tools/ralph-external/lib/worker-native-sandbox.mjs +83 -0
- package/tools/ralph-external/session-launcher.mjs +73 -217
- package/vscode-extension/schemas/aiwg.config.v1.json +161 -2
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { MODELS_HELP } from './models-help.js';
|
|
2
|
+
import { updateJson } from '../../models/config-writer.js';
|
|
3
|
+
import { atomicConfigWrite as atomicWrite } from '../../config/worker-write.js';
|
|
4
|
+
import { handleWorkerAdoptionArgs } from '../../config/worker-adoption-cli.js';
|
|
5
|
+
import { resolveParallelism } from '../../config/aiwg-config.js';
|
|
1
6
|
/**
|
|
2
7
|
* Safe model-policy audit, resolution, and mutation commands.
|
|
3
8
|
* @implements #1804
|
|
@@ -8,7 +13,7 @@ import { isDeepStrictEqual } from 'node:util';
|
|
|
8
13
|
import path from 'node:path';
|
|
9
14
|
import { glob } from 'glob';
|
|
10
15
|
import { load as loadYaml } from 'js-yaml';
|
|
11
|
-
import { compileModelPolicy, validateCanonicalModelPolicy,
|
|
16
|
+
import { compileModelPolicy, validateCanonicalModelPolicy, loadProviderModelCapabilities, WorkerPolicyError, assertWorkerRoleEffort, } from '../../models/provider-policy.js';
|
|
12
17
|
import { resolveGrokBuildRoleModel } from '../../models/grok-build-models.js';
|
|
13
18
|
import { readAiwgConfig, emptyConfig } from '../../config/aiwg-config.js';
|
|
14
19
|
import { ConfigLoader } from '../../models/config-loader.js';
|
|
@@ -34,22 +39,21 @@ export async function loadWorkerInputs(ctx) {
|
|
|
34
39
|
const models = await loader.load(config.parallelism);
|
|
35
40
|
const catalog = await effectiveCatalog(ctx, ctx.cwd, false, parseArgs(['resolve']));
|
|
36
41
|
const registry = loadProviderModelCapabilities();
|
|
37
|
-
// Let the resolver explain the dispatch gate before requiring host qualification (#3070).
|
|
38
42
|
if (!config.parallelism?.worker_dispatch) {
|
|
39
43
|
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
40
44
|
registry, installations: {} }, drivers: {} };
|
|
41
45
|
}
|
|
42
46
|
// Explain missing policy before a recorded approval's digest check can
|
|
43
47
|
// mask it. The host owner first preserves its missing-installation errors.
|
|
44
|
-
const parallelism = config.parallelism;
|
|
48
|
+
const parallelism = resolveParallelism(config.parallelism, config.providers[0]);
|
|
45
49
|
const precheckPolicy = () => {
|
|
46
50
|
if (!ctx.args.some(arg => arg === '--role' || arg.startsWith('--role=')))
|
|
47
51
|
return;
|
|
48
52
|
const request = parseWorkerCommandArgs(ctx.args.slice(1));
|
|
49
53
|
const members = Object.entries(parallelism.groups ?? {})
|
|
50
54
|
.filter(([id]) => !request.group || request.group === id)
|
|
51
|
-
.flatMap(([, group]) => group.members).filter(member => member.enabled !== false
|
|
52
|
-
&& parallelism.clis?.[member.cli]?.enabled !== false && member.roles.includes(request.role));
|
|
55
|
+
.flatMap(([, group]) => group.members ?? []).filter(member => member.enabled !== false
|
|
56
|
+
&& parallelism.clis?.[member.cli]?.enabled !== false && member.roles.includes((models.defaults.workerSelection?.roleGuidance?.[request.role]?.baseRole ?? request.role)));
|
|
53
57
|
const requiresExplicit = members.length > 0 && members.every(member => {
|
|
54
58
|
// Health metadata can identify the provider before an operator has
|
|
55
59
|
// qualified its dispatch adapter. It grants no dispatch authority.
|
|
@@ -269,35 +273,6 @@ function print(value, json) {
|
|
|
269
273
|
else
|
|
270
274
|
console.log(JSON.stringify(value, null, 2));
|
|
271
275
|
}
|
|
272
|
-
async function atomicWrite(file, content) {
|
|
273
|
-
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
274
|
-
const temporary = `${file}.tmp-${process.pid}`;
|
|
275
|
-
let mode = 0o600;
|
|
276
|
-
try {
|
|
277
|
-
mode = (await fs.stat(file)).mode;
|
|
278
|
-
}
|
|
279
|
-
catch { /* new file */ }
|
|
280
|
-
await fs.writeFile(temporary, content, { encoding: 'utf8', mode });
|
|
281
|
-
await fs.rename(temporary, file);
|
|
282
|
-
}
|
|
283
|
-
async function updateJson(file, mutate, dryRun) {
|
|
284
|
-
let value = {};
|
|
285
|
-
try {
|
|
286
|
-
value = JSON.parse(await fs.readFile(file, 'utf8'));
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
if (error?.code !== 'ENOENT')
|
|
290
|
-
throw error;
|
|
291
|
-
}
|
|
292
|
-
mutate(value);
|
|
293
|
-
const validation = validateUserProjectModelConfig(value);
|
|
294
|
-
if (!validation.valid)
|
|
295
|
-
throw new Error(validation.diagnostics.map(item => item.message).join('; '));
|
|
296
|
-
const content = `${JSON.stringify(value, null, 2)}\n`;
|
|
297
|
-
if (!dryRun)
|
|
298
|
-
await atomicWrite(file, content);
|
|
299
|
-
return { file, beforeWrite: value, dryRun };
|
|
300
|
-
}
|
|
301
276
|
async function effectiveCatalog(ctx, target, allowNetwork, parsed, provider) {
|
|
302
277
|
const { collectProviderInventory } = await import('../../providers/provider-inventory.js');
|
|
303
278
|
const { resolveDynamicModelCatalog } = await import('../../models/model-discovery.js');
|
|
@@ -350,53 +325,6 @@ function replaceFrontmatter(raw, item, tier) {
|
|
|
350
325
|
}
|
|
351
326
|
return `---\n${frontmatter}\n---\n${match[2]}`;
|
|
352
327
|
}
|
|
353
|
-
const MODELS_HELP = `Usage: aiwg models <subcommand> [options]
|
|
354
|
-
|
|
355
|
-
Subcommands:
|
|
356
|
-
list List discovered agent and skill model policies
|
|
357
|
-
audit Compile selected policies and report diagnostics
|
|
358
|
-
resolve Resolve artifact policies, or a direct worker invocation
|
|
359
|
-
validate Validate selected artifact policies (not worker configuration)
|
|
360
|
-
sources Show the effective model catalog without network refresh
|
|
361
|
-
refresh Refresh model discovery (may access the network)
|
|
362
|
-
set-default <TIER> Write defaults.tier to models.json
|
|
363
|
-
set --tier <TIER> Update selected agent/skill frontmatter; requires a selector or --all
|
|
364
|
-
migrate Add canonical role/tier hints to legacy skills
|
|
365
|
-
|
|
366
|
-
Artifact selectors and options:
|
|
367
|
-
--agent <name> --skill <name> --glob <pattern> --role <role>
|
|
368
|
-
--tier <tier> --framework <name> --all
|
|
369
|
-
--provider <provider> Provider for artifact compilation (default: claude)
|
|
370
|
-
--model <id> Explicit Grok Build model for artifact resolve
|
|
371
|
-
--target <directory> Artifact/project root (default: current directory)
|
|
372
|
-
--scope project|user set-default destination (default: project)
|
|
373
|
-
--dry-run Preview mutations without writing
|
|
374
|
-
--json Emit JSON
|
|
375
|
-
--drift Include catalog drift for sources/refresh
|
|
376
|
-
--url <url> Remote catalog URL for refresh
|
|
377
|
-
--help, -h Show this reference
|
|
378
|
-
TIER: economy | standard | premium | max-quality
|
|
379
|
-
|
|
380
|
-
Direct worker resolution (plans an invocation; does not launch it):
|
|
381
|
-
aiwg models resolve --role <role> --task <class> --group <group>
|
|
382
|
-
--brief <file> --workdir <tree> --final-output <file>
|
|
383
|
-
[--transport shell|mcp] [--format json|shell] [--authorize-premium]
|
|
384
|
-
--role efficiency | coding | reasoning
|
|
385
|
-
--task Task class from defaults.workerSelection.taskClasses
|
|
386
|
-
Built-ins: inventory, implementation, architecture, review
|
|
387
|
-
--group Group from parallelism.groups and the role's guidance
|
|
388
|
-
--brief Absolute path to the task brief
|
|
389
|
-
--workdir Absolute path to the worker tree
|
|
390
|
-
--final-output Absolute path for the final result
|
|
391
|
-
--transport Must match group execution transport (default: shell)
|
|
392
|
-
--format JSON plan or POSIX shell command (default: json)
|
|
393
|
-
--json Alias for --format json
|
|
394
|
-
--authorize-premium Authorize premium for this resolution only
|
|
395
|
-
Agents require explicit human confirmation of escalation
|
|
396
|
-
|
|
397
|
-
Worker groups live in .aiwg/aiwg.config; role guidance lives in project-root models.json.
|
|
398
|
-
Configure both, then run aiwg doctor --probe-workers --qualify.
|
|
399
|
-
See docs/getting-started/worker-dispatch.md for a complete example.`;
|
|
400
328
|
async function execute(ctx, services = { load: loadWorkerInputs }) {
|
|
401
329
|
if (ctx.args.length === 0 || ctx.args[0] === 'help' || ctx.args.includes('--help') || ctx.args.includes('-h')) {
|
|
402
330
|
print(MODELS_HELP, false);
|
|
@@ -406,6 +334,8 @@ async function execute(ctx, services = { load: loadWorkerInputs }) {
|
|
|
406
334
|
if (ctx.args[0] === 'resolve' && ctx.args.slice(1).some(arg => /^--(?:task|group|brief|workdir|final-output|transport|format|authorize-premium)(?:=|$)/.test(arg))) {
|
|
407
335
|
return resolveDirect(ctx, services);
|
|
408
336
|
}
|
|
337
|
+
if (await handleWorkerAdoptionArgs(ctx.args, ctx.cwd, 'models', ctx.signal, ctx.dryRun))
|
|
338
|
+
return { exitCode: 0 };
|
|
409
339
|
const parsed = parseArgs(ctx.args);
|
|
410
340
|
if (parsed.subcommand === 'resolve') {
|
|
411
341
|
const supported = new Set(['agent', 'skill', 'glob', 'role', 'tier', 'framework', 'all', 'target', 'provider', 'model', 'json', 'help', 'dry-run']);
|
|
@@ -3,13 +3,14 @@ import { loadResourceTrustRootFile, readVerifiedRegularFile, resolveWebRelease,
|
|
|
3
3
|
import { getProjectDir } from "../../config/aiwg-config.js";
|
|
4
4
|
import { cleanWebResourceCache } from "../../resources/cache-cleanup.js";
|
|
5
5
|
import { writeWebResourceLock } from "../../resources/lockfile.js";
|
|
6
|
-
import { createResourceCredentialProvider } from "../../auth/resource-credentials.js";
|
|
6
|
+
import { createResourceCredentialProvider, prepareResourceCredentials } from "../../auth/resource-credentials.js";
|
|
7
7
|
const MAX_RESOURCE_MANIFEST_BYTES = 4 * 1024 * 1024;
|
|
8
8
|
const DEFAULT_CHANNELS = ["stable", "latest", "canary", "main"];
|
|
9
9
|
function usage() {
|
|
10
10
|
return [
|
|
11
11
|
"Usage: aiwg versions <list|resolve|show|clean-cache> [selector] [--json] [--pretty] [--offline]",
|
|
12
12
|
"",
|
|
13
|
+
"Protected releases: --resource-token-stdin, --resource-token-file <path>, --resource-token-store <name>, --resource-token-env <NAME>, --resource-token-interactive",
|
|
13
14
|
"Examples:",
|
|
14
15
|
" aiwg versions list --json",
|
|
15
16
|
" aiwg versions resolve stable --json",
|
|
@@ -75,7 +76,7 @@ function parseArgs(args) {
|
|
|
75
76
|
channels,
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
|
-
function webReleaseOptionsFromEnvironment() {
|
|
79
|
+
function webReleaseOptionsFromEnvironment(credentialProvider = createResourceCredentialProvider(process.env)) {
|
|
79
80
|
const baseUrl = process.env.AIWG_RESOURCE_BASE_URL;
|
|
80
81
|
const cacheRoot = process.env.AIWG_RESOURCE_CACHE_ROOT;
|
|
81
82
|
const trustRootFile = process.env.AIWG_RESOURCE_TRUST_ROOT_FILE;
|
|
@@ -83,7 +84,7 @@ function webReleaseOptionsFromEnvironment() {
|
|
|
83
84
|
? undefined
|
|
84
85
|
: loadResourceTrustRootFile(path.resolve(trustRootFile));
|
|
85
86
|
return {
|
|
86
|
-
credentialProvider
|
|
87
|
+
credentialProvider,
|
|
87
88
|
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
88
89
|
...(cacheRoot === undefined ? {} : { cacheRoot }),
|
|
89
90
|
...(publicKeyPem === undefined ? {} : { publicKeyPem }),
|
|
@@ -168,14 +169,16 @@ export const versionsHandler = {
|
|
|
168
169
|
return { exitCode: 0 };
|
|
169
170
|
}
|
|
170
171
|
let parsed;
|
|
172
|
+
let credentials;
|
|
171
173
|
try {
|
|
172
|
-
|
|
174
|
+
credentials = await prepareResourceCredentials(ctx.args);
|
|
175
|
+
parsed = parseArgs(credentials.args);
|
|
173
176
|
}
|
|
174
177
|
catch (error) {
|
|
175
178
|
return { exitCode: 2, message: error instanceof Error ? error.message : String(error) };
|
|
176
179
|
}
|
|
177
180
|
try {
|
|
178
|
-
const baseOptions = webReleaseOptionsFromEnvironment();
|
|
181
|
+
const baseOptions = webReleaseOptionsFromEnvironment(credentials.credentialProvider);
|
|
179
182
|
if (parsed.subcommand === "clean-cache") {
|
|
180
183
|
const result = cleanWebResourceCache(getProjectDir(ctx, ctx.args), {
|
|
181
184
|
cacheRoot: process.env.AIWG_RESOURCE_CACHE_ROOT,
|
|
@@ -57,10 +57,13 @@ export class DefaultScriptRunner {
|
|
|
57
57
|
const stdio = options.capture
|
|
58
58
|
? ['pipe', options.stdoutFd ?? 'pipe', 'pipe']
|
|
59
59
|
: 'inherit';
|
|
60
|
+
const environment = { ...process.env, ...options.env };
|
|
61
|
+
for (const name of options.omitEnv ?? [])
|
|
62
|
+
delete environment[name];
|
|
60
63
|
const child = spawn('node', [fullPath, ...args], {
|
|
61
64
|
stdio,
|
|
62
65
|
cwd: options.cwd || process.cwd(),
|
|
63
|
-
env:
|
|
66
|
+
env: environment,
|
|
64
67
|
});
|
|
65
68
|
// Always drain captured pipes, even after the diagnostic cap is reached.
|
|
66
69
|
// stdout is not part of HandlerResult; discard it. Retain only the first
|
|
@@ -146,10 +149,13 @@ export class DefaultScriptRunner {
|
|
|
146
149
|
async runDeployment(fullPath, args, options) {
|
|
147
150
|
const previousConsole = globalThis.console;
|
|
148
151
|
const previousRoot = process.env.AIWG_ROOT;
|
|
152
|
+
const omitted = new Map((options.omitEnv ?? []).map(name => [name, process.env[name]]));
|
|
149
153
|
const stderrLimit = 1024 * 1024;
|
|
150
154
|
const diagnostics = [];
|
|
151
155
|
let diagnosticBytes = 0;
|
|
152
156
|
try {
|
|
157
|
+
for (const name of omitted.keys())
|
|
158
|
+
delete process.env[name];
|
|
153
159
|
if (options.env?.AIWG_ROOT !== undefined)
|
|
154
160
|
process.env.AIWG_ROOT = options.env.AIWG_ROOT;
|
|
155
161
|
if (options.capture) {
|
|
@@ -187,6 +193,12 @@ export class DefaultScriptRunner {
|
|
|
187
193
|
}
|
|
188
194
|
finally {
|
|
189
195
|
globalThis.console = previousConsole;
|
|
196
|
+
for (const [name, value] of omitted) {
|
|
197
|
+
if (value === undefined)
|
|
198
|
+
delete process.env[name];
|
|
199
|
+
else
|
|
200
|
+
process.env[name] = value;
|
|
201
|
+
}
|
|
190
202
|
if (previousRoot === undefined)
|
|
191
203
|
delete process.env.AIWG_ROOT;
|
|
192
204
|
else
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Select and persist an optional bundled addon memory profile.
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import * as ui from '../ui.js';
|
|
5
|
+
export async function selectAddonProfile(options) {
|
|
6
|
+
const { addonSource, framework, target, args, dryRunAddon, bulkIntent, signal } = options;
|
|
7
|
+
try {
|
|
8
|
+
const profileManifestPath = path.join(addonSource, 'manifest.json');
|
|
9
|
+
const profileManifestContent = await fs.readFile(profileManifestPath, 'utf-8');
|
|
10
|
+
const profileManifest = JSON.parse(profileManifestContent);
|
|
11
|
+
const topology = profileManifest.memory?.topology;
|
|
12
|
+
const templates = profileManifest.templates;
|
|
13
|
+
if (topology && templates && templates.length > 1) {
|
|
14
|
+
const profileIdx = args.findIndex(a => a === '--profile');
|
|
15
|
+
let selectedProfile;
|
|
16
|
+
if (profileIdx >= 0 && args[profileIdx + 1]) {
|
|
17
|
+
// Explicit --profile flag
|
|
18
|
+
selectedProfile = args[profileIdx + 1];
|
|
19
|
+
const templateFile = templates.find((t) => t.replace('.md', '') === selectedProfile || t === selectedProfile);
|
|
20
|
+
if (!templateFile) {
|
|
21
|
+
ui.warn(`Unknown profile "${selectedProfile}". Available: ${templates.map((t) => t.replace('.md', '')).join(', ')}`);
|
|
22
|
+
selectedProfile = undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (bulkIntent || !process.stdin.isTTY) {
|
|
26
|
+
// Bulk/automation or non-TTY: silently pick 'generic' default.
|
|
27
|
+
// The profile picker is annoying during `aiwg use all`.
|
|
28
|
+
selectedProfile = 'generic';
|
|
29
|
+
}
|
|
30
|
+
else if (process.stdin.isTTY) {
|
|
31
|
+
// Interactive profile selection via the shared `listSelect` helper
|
|
32
|
+
// (POC for spike #926). One call renders the option list, handles
|
|
33
|
+
// number-or-name matching, threads `signal` for Ctrl-C
|
|
34
|
+
// cancellation, and resolves to the fallback on timeout or empty
|
|
35
|
+
// input. The hand-rolled parse-and-branch that used to live here
|
|
36
|
+
// is now a one-liner.
|
|
37
|
+
const { createPromptInterface, listSelect } = await import('../prompt-utils.js');
|
|
38
|
+
ui.blank();
|
|
39
|
+
ui.header(' Select a topology profile:');
|
|
40
|
+
const templateNames = templates.map((t) => t.replace('.md', ''));
|
|
41
|
+
const options = templateNames.map((name) => ({
|
|
42
|
+
label: name === 'generic' ? `${name} (default)` : name,
|
|
43
|
+
value: name,
|
|
44
|
+
}));
|
|
45
|
+
const rl = createPromptInterface();
|
|
46
|
+
try {
|
|
47
|
+
selectedProfile = await listSelect(rl, ' Enter number or name [generic]: ', options, 'generic', signal);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
rl.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Write profile config to project namespace
|
|
54
|
+
if (selectedProfile && !dryRunAddon) {
|
|
55
|
+
const namespace = topology.namespace || `.aiwg/${framework}`;
|
|
56
|
+
const configDir = path.join(target, namespace);
|
|
57
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
58
|
+
const profileConfig = {
|
|
59
|
+
profile: selectedProfile,
|
|
60
|
+
pageTemplate: `templates/${selectedProfile}.md`,
|
|
61
|
+
selectedAt: new Date().toISOString(),
|
|
62
|
+
};
|
|
63
|
+
await fs.writeFile(path.join(configDir, 'config.json'), JSON.stringify(profileConfig, null, 2) + '\n');
|
|
64
|
+
ui.success(`Profile "${selectedProfile}" selected → ${namespace}/config.json`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Profile selection is optional — don't fail deployment
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=use-addon-profile.js.map
|