@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.
Files changed (104) hide show
  1. package/agentic/code/providers/model-capabilities.v1.json +197 -3
  2. package/bin/aiwg.mjs +8 -0
  3. package/dist/src/artifacts/cli.js +9 -5
  4. package/dist/src/auth/config.js +3 -8
  5. package/dist/src/auth/resource-credentials.js +35 -2
  6. package/dist/src/cli/handlers/diagnose.js +13 -0
  7. package/dist/src/cli/handlers/mc-admission.js +39 -0
  8. package/dist/src/cli/handlers/mc.js +2 -31
  9. package/dist/src/cli/handlers/models-help.js +52 -0
  10. package/dist/src/cli/handlers/models.js +11 -81
  11. package/dist/src/cli/handlers/resource-versions.js +8 -5
  12. package/dist/src/cli/handlers/script-runner.js +13 -1
  13. package/dist/src/cli/handlers/use-addon-profile.js +72 -0
  14. package/dist/src/cli/handlers/use.js +209 -233
  15. package/dist/src/cli/ui.js +1 -0
  16. package/dist/src/config/aiwg-config.js +38 -184
  17. package/dist/src/config/cli-help.js +54 -0
  18. package/dist/src/config/cli.js +5 -69
  19. package/dist/src/config/config-normalization.js +10 -0
  20. package/dist/src/config/worker-activation-gate.js +26 -0
  21. package/dist/src/config/worker-adoption-cli.js +102 -0
  22. package/dist/src/config/worker-adoption.js +368 -0
  23. package/dist/src/config/worker-config-digest.js +14 -0
  24. package/dist/src/config/worker-group-templates.js +150 -0
  25. package/dist/src/config/worker-guidance-warning.js +28 -0
  26. package/dist/src/config/worker-owner-lock.js +152 -0
  27. package/dist/src/config/worker-parallelism.js +154 -0
  28. package/dist/src/config/worker-write.js +75 -0
  29. package/dist/src/decision/telemetry/exporter.js +2 -1
  30. package/dist/src/decision/telemetry/index.js +1 -0
  31. package/dist/src/decision/telemetry/mapping.js +43 -0
  32. package/dist/src/decision/telemetry/otlp-http.js +5 -2
  33. package/dist/src/decision/telemetry/redaction.js +6 -1
  34. package/dist/src/decision/telemetry/types.js +3 -0
  35. package/dist/src/decision/telemetry/worker.js +69 -0
  36. package/dist/src/lint/rule-activation.js +15 -7
  37. package/dist/src/lint/runner.js +2 -2
  38. package/dist/src/mcp/server.mjs +2 -11
  39. package/dist/src/mcp/stdio-lifecycle.mjs +27 -0
  40. package/dist/src/mcp/tools/worker-failure-diagnostics.mjs +9 -0
  41. package/dist/src/mcp/tools/worker-invoke.mjs +6 -6
  42. package/dist/src/mission-protocol/codecs.js +8 -38
  43. package/dist/src/mission-protocol/worker-contract-diagnostics.js +62 -0
  44. package/dist/src/mission-protocol/worker-invocation-types.js +2 -0
  45. package/dist/src/models/conductor-data-policy.d.mts +8 -0
  46. package/dist/src/models/conductor-data-policy.mjs +190 -0
  47. package/dist/src/models/config-loader.js +19 -3
  48. package/dist/src/models/config-writer.js +27 -0
  49. package/dist/src/models/model-capabilities.v1.json +197 -3
  50. package/dist/src/models/provider-policy.js +7 -155
  51. package/dist/src/models/resolver.js +2 -293
  52. package/dist/src/models/worker-artifact-binding.mjs +12 -0
  53. package/dist/src/models/worker-direct-readiness-policy.js +155 -0
  54. package/dist/src/models/worker-direct-readiness.js +9 -218
  55. package/dist/src/models/worker-health-readiness.js +105 -26
  56. package/dist/src/models/worker-installation.mjs +12 -14
  57. package/dist/src/models/worker-member-references.js +64 -0
  58. package/dist/src/models/worker-plan.js +317 -0
  59. package/dist/src/models/worker-selection-policy.js +217 -0
  60. package/dist/src/models/wrapper-deployment.js +1 -1
  61. package/dist/src/resources/web-release.js +76 -65
  62. package/dist/src/serve/shared-host-admission-checks.js +116 -0
  63. package/dist/src/serve/shared-host-scheduler.js +25 -107
  64. package/dist/src/serve/shared-host-starvation.js +73 -0
  65. package/dist/src/serve/worker-artifacts.d.mts +4 -0
  66. package/dist/src/serve/worker-artifacts.mjs +56 -0
  67. package/dist/src/serve/worker-command-request.js +68 -0
  68. package/dist/src/serve/worker-invocation-paths.js +144 -0
  69. package/dist/src/serve/worker-invocation-preparation.js +169 -0
  70. package/dist/src/serve/worker-invocation.js +24 -291
  71. package/dist/src/serve/worker-stdin-frame.d.mts +2 -2
  72. package/dist/src/serve/worker-stdin-frame.mjs +6 -6
  73. package/dist/src/smiths/context-pipeline/parallelism-section.js +19 -7
  74. package/dist/src/storage/backends/fortemi.js +33 -29
  75. package/dist/src/storage/backends/logseq.js +16 -3
  76. package/dist/src/storage/backends/postgres.js +74 -33
  77. package/dist/src/storage/backends/postgrest.js +37 -13
  78. package/dist/src/storage/config.js +6 -1
  79. package/dist/src/uhp/config.js +4 -0
  80. package/package.json +9 -1
  81. package/schemas/mission-v1.schema.json +20 -19
  82. package/schemas/models/model-config-compatibility.v1.schema.json +16 -0
  83. package/tools/agents/providers/claude-post-deploy.mjs +35 -0
  84. package/tools/agents/providers/claude.mjs +3 -30
  85. package/tools/agents/providers/codex-post-deploy.mjs +13 -0
  86. package/tools/agents/providers/codex.mjs +2 -8
  87. package/tools/agents/providers/conductor-data-guard.mjs +61 -0
  88. package/tools/agents/providers/rule-delivery.mjs +3 -16
  89. package/tools/agents/providers/rule-presentation.mjs +38 -0
  90. package/tools/plugin/package-plugins.mjs +1 -1
  91. package/tools/ralph-external/lib/claude-adapter.mjs +2 -2
  92. package/tools/ralph-external/lib/codex-adapter.mjs +3 -3
  93. package/tools/ralph-external/lib/managed-worker-attempt.mjs +86 -0
  94. package/tools/ralph-external/lib/provider-adapter.mjs +11 -260
  95. package/tools/ralph-external/lib/session-attempt.mjs +85 -0
  96. package/tools/ralph-external/lib/strict-worker-json.mjs +190 -0
  97. package/tools/ralph-external/lib/worker-artifacts.mjs +209 -0
  98. package/tools/ralph-external/lib/worker-final.mjs +143 -0
  99. package/tools/ralph-external/lib/worker-inputs.mjs +55 -0
  100. package/tools/ralph-external/lib/worker-isolation.mjs +2 -44
  101. package/tools/ralph-external/lib/worker-launch-cli.mjs +47 -0
  102. package/tools/ralph-external/lib/worker-native-sandbox.mjs +83 -0
  103. package/tools/ralph-external/session-launcher.mjs +73 -217
  104. 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, validateUserProjectModelConfig, loadProviderModelCapabilities, WorkerPolicyError, assertWorkerRoleEffort, } from '../../models/provider-policy.js';
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: createResourceCredentialProvider(process.env),
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
- parsed = parseArgs(ctx.args);
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: { ...process.env, ...options.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