@aiwg/cli 2026.8.8 → 2026.8.11

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 (70) hide show
  1. package/README.md +23 -8
  2. package/THIRD_PARTY_NOTICES.md +35 -0
  3. package/agentic/code/providers/capability-matrix.yaml +3 -3
  4. package/bin/aiwg.mjs +125 -0
  5. package/dist/src/agents/packaged-agent-inventory.js +37 -1
  6. package/dist/src/artifacts/backends/graphology-backend.js +4 -3
  7. package/dist/src/artifacts/backends/sqlite-backend.js +4 -5
  8. package/dist/src/artifacts/cli.js +2 -2
  9. package/dist/src/artifacts/corpus-tools/cli.js +27 -0
  10. package/dist/src/artifacts/corpus-tools/profile-embed.js +3 -2
  11. package/dist/src/artifacts/corpus-tools/retrieval-lab.js +356 -0
  12. package/dist/src/artifacts/discover-facets.js +2 -2
  13. package/dist/src/artifacts/embedding-index.js +9 -8
  14. package/dist/src/artifacts/fortemi-core-sync.js +23 -8
  15. package/dist/src/artifacts/graph-backend.js +2 -2
  16. package/dist/src/artifacts/query-engine.js +21 -7
  17. package/dist/src/artifacts/repair.js +47 -0
  18. package/dist/src/artifacts/types.js +3 -3
  19. package/dist/src/cli/command-log.js +2 -2
  20. package/dist/src/cli/handlers/artifacts.js +50 -1
  21. package/dist/src/cli/handlers/cost-report.js +71 -0
  22. package/dist/src/cli/handlers/evidence.js +78 -0
  23. package/dist/src/cli/handlers/help.js +9 -0
  24. package/dist/src/cli/handlers/index.js +8 -3
  25. package/dist/src/cli/handlers/local-executor.js +4 -3
  26. package/dist/src/cli/handlers/refresh.js +63 -17
  27. package/dist/src/cli/handlers/regenerate.js +3 -3
  28. package/dist/src/cli/handlers/serve.js +15 -36
  29. package/dist/src/cli/handlers/setup-manifest.js +8 -1
  30. package/dist/src/cli/handlers/use.js +272 -70
  31. package/dist/src/cli/handlers/utilities.js +149 -0
  32. package/dist/src/cli/handlers/workspace.js +10 -0
  33. package/dist/src/cli/help-generator.js +2 -1
  34. package/dist/src/cli/router.js +4 -1
  35. package/dist/src/cli/services/deployment-verification.js +596 -0
  36. package/dist/src/cli/skill-usage.js +2 -2
  37. package/dist/src/cli/workflow-orchestrator.js +1 -1
  38. package/dist/src/cli/workspace-signals.js +2 -2
  39. package/dist/src/config/aiwg-config.js +54 -27
  40. package/dist/src/config/cli.js +3 -3
  41. package/dist/src/config/project-artifacts-health.js +2 -0
  42. package/dist/src/config/project-artifacts-health.mjs +123 -0
  43. package/dist/src/config/project-artifacts-runtime.mjs +16 -0
  44. package/dist/src/config/project-artifacts.js +2 -1
  45. package/dist/src/cost/fleet-report.js +329 -0
  46. package/dist/src/evidence/bundle.js +256 -0
  47. package/dist/src/extensions/commands/definitions.js +77 -25
  48. package/dist/src/extensions/deployment-registration.js +6 -4
  49. package/dist/src/features/catalog.js +26 -0
  50. package/dist/src/features/cli.js +1 -3
  51. package/dist/src/features/runtime.js +17 -1
  52. package/dist/src/issues/cli.js +91 -7
  53. package/dist/src/mcp/server.mjs +1 -1
  54. package/dist/src/ops/registry.js +2 -2
  55. package/dist/src/policy/authorization.js +2 -2
  56. package/dist/src/providers/capability-matrix.yaml +3 -3
  57. package/dist/src/providers/provider-definitions.js +7 -5
  58. package/dist/src/providers/provider-definitions.mjs +1 -1
  59. package/dist/src/serve/pty-bridge.js +2 -8
  60. package/dist/src/serve/screen-reader.js +3 -6
  61. package/dist/src/smiths/context-pipeline/aiwg-md.js +2 -2
  62. package/dist/src/smiths/context-pipeline/finalization.js +18 -5
  63. package/dist/src/smiths/context-pipeline/generator.js +2 -2
  64. package/dist/src/smiths/context-pipeline/workspace-context.js +16 -17
  65. package/package.json +2 -1
  66. package/tools/agents/deploy-agents.mjs +10 -11
  67. package/tools/agents/providers/base.mjs +61 -7
  68. package/tools/agents/providers/openclaw.mjs +5 -2
  69. package/tools/agents/providers/windsurf.mjs +13 -24
  70. package/tools/skills/deploy-skills-codex.mjs +21 -5
@@ -232,6 +232,7 @@ function installerConsistencyChecks(manifest, manifestDir) {
232
232
  const recoveryIds = new Set((manifest.spec.recovery ?? []).map((recovery) => recovery.id));
233
233
  const osConfigIds = new Set((manifest.spec.os_config ?? []).map((entry) => entry.id));
234
234
  const installType = manifest.metadata.install_type ?? 'user';
235
+ const executionMode = manifest.metadata.execution_mode ?? 'deterministic';
235
236
  for (const [index, step] of manifest.spec.steps.entries()) {
236
237
  if (allStepIds.has(step.id)) {
237
238
  findings.push({ severity: 'error', path: `/spec/steps/${index}/id`, rule: 'uniqueStepId', message: `duplicate step id '${step.id}'` });
@@ -260,7 +261,7 @@ function installerConsistencyChecks(manifest, manifestDir) {
260
261
  if (!step.instruction) {
261
262
  findings.push({ severity: 'error', path: `${pointer}/instruction`, rule: 'agenticInstruction', message: 'agentic step requires instruction' });
262
263
  }
263
- else {
264
+ else if (executionMode !== 'provider-orchestrated') {
264
265
  findings.push({ severity: 'warning', path: pointer, rule: 'agenticStep', message: 'agentic steps are exception handling only and require manual intervention during setup-run' });
265
266
  }
266
267
  }
@@ -687,6 +688,12 @@ export function runSetupManifest(options) {
687
688
  return { exitCode: 1, message: 'setup-run: manifest validation failed before execution' };
688
689
  }
689
690
  const manifest = validation.manifest;
691
+ if (manifest.metadata.execution_mode === 'provider-orchestrated') {
692
+ return {
693
+ exitCode: 2,
694
+ message: 'setup-run: this manifest is provider-orchestrated; give its URL or contents to a supported AI provider instead of executing it as a deterministic CLI manifest',
695
+ };
696
+ }
690
697
  const target = detectPlatform(options);
691
698
  if (!manifest.spec.platforms.some((candidate) => platformMatches(target, candidate))) {
692
699
  return { exitCode: 1, message: `setup-run: platform ${target.os}${target.distro ? `/${target.distro}` : ''}/${target.arch}/${target.shell} is not declared in the manifest` };
@@ -36,16 +36,22 @@ import { installAiwgHooks } from '../../extensions/claude-hooks-installer.js';
36
36
  import { detectScope, mirrorToUserScope, rejectOpenClawProjectScope, USER_SCOPE_PATHS, } from '../scope-resolver.js';
37
37
  import { maybeWarnProjectIsolation } from '../project-isolation/index.js';
38
38
  import { formatWorkspaceSignalPlan, includedBundleIds, resolveWorkspaceSignalPlan, writeWorkspaceSignalPlan, } from '../workspace-signals.js';
39
- import { getProviderArtifactPathStrings, getProviderKernelSkillPath, normalizeProviderDefinitionId, } from '../../providers/provider-definitions.js';
39
+ import { getProviderArtifactPathStrings, getProviderDefinition, getProviderKernelSkillPath, normalizeProviderDefinitionId, } from '../../providers/provider-definitions.js';
40
40
  // Module-level guard so the iteration loops further down (which re-enter
41
41
  // execute() per framework/provider) don't re-emit the warning each pass.
42
42
  // Reset is not needed: a single CLI process is one user invocation.
43
43
  let projectIsolationChecked = false;
44
+ // Non-zero only while the outer `aiwg use --json` orchestration wrapper is
45
+ // collecting child-process output. The CLI is single-command-per-process;
46
+ // recursive provider expansion shares this guard intentionally.
47
+ let machineReadableUseDepth = 0;
44
48
  // Context-pipeline: emits WORKSPACE.md + AIWG.md + provider adapters last.
45
49
  // for non-Claude providers per ADR-1 (.aiwg/architecture/adr-agents-md-aggregation.md).
46
50
  // Distinct from agentsmith (which creates subagent personas).
47
51
  import { generate as generateContextFiles, discoverDeployedArtifacts, } from '../../smiths/context-pipeline/index.js';
48
52
  import { verifyModelWrapperDeployment } from '../../models/wrapper-deployment.js';
53
+ import { loadGraphIndexFile } from '../../artifacts/index-reader.js';
54
+ import { aggregateUseDeploymentResult, buildDryRunUseResult, renderUseDeploymentResult, verifyProviderDeployment, } from '../services/deployment-verification.js';
49
55
  /**
50
56
  * Valid framework identifiers
51
57
  */
@@ -517,11 +523,13 @@ async function runPreDeployCollisionCheck(opts) {
517
523
  sourceSkillsDir,
518
524
  });
519
525
  const report = formatCollisionReport(results, { verbose });
520
- if (report) {
526
+ if (report && machineReadableUseDepth === 0) {
521
527
  process.stderr.write(report + '\n');
522
528
  }
523
529
  if (hasBlockingCollisions(results) && !force) {
524
- process.stderr.write('\nDeployment blocked. Use --force to override.\n');
530
+ if (machineReadableUseDepth === 0) {
531
+ process.stderr.write('\nDeployment blocked. Use --force to override.\n');
532
+ }
525
533
  return false;
526
534
  }
527
535
  return true;
@@ -559,7 +567,7 @@ const NEXT_STEPS = {
559
567
  'warp/sdlc': agenticNextSteps('Open Warp: Start a Warp session in this project root.'),
560
568
  'copilot/sdlc': agenticNextSteps('Open VS Code: Open this workspace and use Copilot Chat.'),
561
569
  'codex/sdlc': agenticNextSteps('Open Codex: Restart Codex in this project root.'),
562
- 'windsurf/sdlc': agenticNextSteps('Open Windsurf: Open this project in Windsurf and ask Cascade for AIWG status.'),
570
+ 'windsurf/sdlc': agenticNextSteps('Open Devin Desktop: Open this project in Devin Desktop and ask Devin for AIWG status.'),
563
571
  'openclaw/sdlc': agenticNextSteps('Start OpenClaw: Open OpenClaw with this project workspace.'),
564
572
  'openclaw/marketing': agenticNextSteps('Start OpenClaw: Open OpenClaw with this project workspace.'),
565
573
  'openclaw/all': agenticNextSteps('Start OpenClaw: Open OpenClaw with this project workspace.'),
@@ -575,9 +583,6 @@ export function nextStepsFor(framework, provider = 'claude') {
575
583
  const steps = NEXT_STEPS[providerKey] ?? NEXT_STEPS[framework] ?? NEXT_STEPS.sdlc;
576
584
  return steps.map((step) => step.replace('{{aiwg-regenerate}}', regenerateInvocation));
577
585
  }
578
- function printNextSteps(framework, provider = 'claude') {
579
- ui.section('Next steps:', nextStepsFor(framework, provider));
580
- }
581
586
  /**
582
587
  * Per-provider session-reload requirement after `aiwg use`.
583
588
  *
@@ -613,8 +618,8 @@ const SESSION_RELOAD_NOTICE = {
613
618
  rationale: 'Warp aggregates context from WARP.md when a new tab spawns; existing tabs keep the prior version.',
614
619
  },
615
620
  windsurf: {
616
- action: 'Restart Windsurf or reload the workspace so the aggregated AGENTS.md is re-parsed.',
617
- rationale: 'Windsurf reads AGENTS.md once per workspace session.',
621
+ action: 'Restart Devin Desktop or reload the workspace so the aggregated AGENTS.md is re-parsed.',
622
+ rationale: 'Devin Desktop reads the Windsurf-compatible AGENTS.md once per workspace session.',
618
623
  },
619
624
  factory: {
620
625
  action: 'Restart your Factory droid runtime to pick up new entries in .factory/droids/.',
@@ -723,18 +728,6 @@ async function countDeployedArtifacts(target, paths, provider) {
723
728
  behaviors: await countDirs(paths.behaviors),
724
729
  };
725
730
  }
726
- async function countDiscoverableSkills(aiwgRoot) {
727
- try {
728
- const { loadGraphIndexFile } = await import('../../artifacts/index-reader.js');
729
- const index = loadGraphIndexFile(aiwgRoot, 'metadata.json', 'framework');
730
- if (!index?.entries)
731
- return null;
732
- return Object.values(index.entries).filter(entry => entry.type === 'skill').length;
733
- }
734
- catch {
735
- return null;
736
- }
737
- }
738
731
  /**
739
732
  * Detect forge targets from .git/config remote URLs.
740
733
  * Returns a list of forge types found: 'github' | 'gitea'
@@ -1106,7 +1099,7 @@ async function deployProjectLocalBundles(opts) {
1106
1099
  const upstream = await buildUpstreamRegistry({ frameworkRoot });
1107
1100
  const shadowResult = await resolveShadows(targetBundles, upstream);
1108
1101
  const report = formatShadowReport(shadowResult);
1109
- if (report) {
1102
+ if (report && machineReadableUseDepth === 0) {
1110
1103
  process.stderr.write(report + '\n');
1111
1104
  }
1112
1105
  // #1037/#1049 — Activity log per shadow resolution
@@ -1237,15 +1230,12 @@ function resolveBuiltInProviderForUse(provider) {
1237
1230
  }
1238
1231
  function unsupportedProviderMessage(provider) {
1239
1232
  const normalized = provider.trim().toLowerCase();
1240
- if (normalized === 'devin' || normalized === 'devin-cli') {
1233
+ if (normalized === 'devin-cli') {
1241
1234
  return [
1242
1235
  `Unsupported provider: ${provider}`,
1243
1236
  '',
1244
- 'Devin Desktop is supported through the Windsurf compatibility adapter:',
1245
- ' aiwg use sdlc --provider windsurf',
1246
- ' aiwg use sdlc --provider devin-desktop',
1247
- '',
1248
- 'Devin CLI has distinct rules/skills surfaces and is recorded as future-provider metadata; AIWG does not emit .devin/ provider output yet.',
1237
+ 'Devin CLI has distinct rules/skills surfaces and is not a deployable AIWG provider yet.',
1238
+ 'Use --provider devin for Devin Desktop deployments.',
1249
1239
  ].join('\n');
1250
1240
  }
1251
1241
  return null;
@@ -1670,6 +1660,60 @@ async function generateGlobalProjectContext(opts) {
1670
1660
  },
1671
1661
  });
1672
1662
  }
1663
+ async function ensurePostDeployPhases(opts) {
1664
+ const currentIndex = loadGraphIndexFile(opts.frameworkRoot, 'metadata.json', 'framework');
1665
+ const builtAt = currentIndex ? Date.parse(currentIndex.builtAt) : Number.NaN;
1666
+ const startedAt = Date.parse(opts.invocationStartedAt);
1667
+ if (!Number.isFinite(builtAt) || builtAt + 2_000 < startedAt) {
1668
+ try {
1669
+ const { buildIndex } = await import('../../artifacts/index-builder.js');
1670
+ await buildIndex(opts.frameworkRoot, { graph: 'framework', explicit: false });
1671
+ }
1672
+ catch {
1673
+ // The shared verifier reports the index failure with stable remediation.
1674
+ }
1675
+ }
1676
+ // The Fortemi export is the default discovery backend. Rebuilding only the
1677
+ // source graph makes any existing export stale, so every successful use
1678
+ // must leave the shared cache synchronized (#142/#2103). This also
1679
+ // materializes a fresh-install cache without requiring a manual index sync.
1680
+ try {
1681
+ const { getFortemiCoreSyncStatus, syncFortemiCoreIndex, } = await import('../../artifacts/fortemi-core-sync.js');
1682
+ const status = getFortemiCoreSyncStatus(opts.frameworkRoot, 'framework');
1683
+ if (!status.built || status.stale) {
1684
+ syncFortemiCoreIndex(opts.frameworkRoot, { graph: 'framework' });
1685
+ }
1686
+ }
1687
+ catch {
1688
+ // The shared verifier reports discovery failures with stable remediation.
1689
+ }
1690
+ if (opts.args.includes('--no-context-files'))
1691
+ return;
1692
+ const paths = getProviderPaths(opts.provider);
1693
+ const sections = await discoverDeployedArtifacts(opts.projectPath, {
1694
+ agents: paths.agents,
1695
+ rules: paths.rules,
1696
+ skills: paths.skills,
1697
+ behaviors: paths.behaviors,
1698
+ });
1699
+ try {
1700
+ await generateContextFiles({
1701
+ provider: opts.provider,
1702
+ projectPath: opts.projectPath,
1703
+ sections,
1704
+ detectExistingFiles: true,
1705
+ force: opts.args.includes('--force-context-files'),
1706
+ skip: {
1707
+ workspaceMd: opts.args.includes('--no-workspace-md'),
1708
+ aiwgMd: opts.args.includes('--no-aiwg-md'),
1709
+ agentsMd: opts.args.includes('--no-agents-md'),
1710
+ },
1711
+ });
1712
+ }
1713
+ catch {
1714
+ // The shared verifier reports context or provider-wiring failures.
1715
+ }
1716
+ }
1673
1717
  async function deploySourceDirectory(opts) {
1674
1718
  const args = [
1675
1719
  '--source', opts.source,
@@ -1820,7 +1864,158 @@ export class UseHandler {
1820
1864
  description = 'Deploy AIWG framework to project or user scope';
1821
1865
  category = 'framework';
1822
1866
  aliases = [];
1867
+ orchestrationDepth = 0;
1823
1868
  async execute(ctx) {
1869
+ const requestedBundle = firstUsePositional(ctx.args)
1870
+ ?? (ctx.args[0] === '--profile' ? 'all' : undefined);
1871
+ const bypassOrchestration = this.orchestrationDepth > 0
1872
+ || !requestedBundle
1873
+ || requestedBundle === 'cockpit'
1874
+ || ctx.args.includes('--workspace-signals');
1875
+ if (bypassOrchestration)
1876
+ return this.executeCore(ctx);
1877
+ this.orchestrationDepth += 1;
1878
+ try {
1879
+ return await this.executeOrchestrated(ctx, requestedBundle);
1880
+ }
1881
+ finally {
1882
+ this.orchestrationDepth -= 1;
1883
+ }
1884
+ }
1885
+ async executeOrchestrated(ctx, requestedBundle) {
1886
+ const startedAt = new Date().toISOString();
1887
+ const json = ctx.args.includes('--json');
1888
+ const coreArgs = ctx.args.filter((arg) => arg !== '--json');
1889
+ const remainingArgs = removeFirstPositional(coreArgs);
1890
+ const projectDir = getProjectDir(ctx, remainingArgs);
1891
+ const frameworkRoot = ctx.frameworkRoot || await getFrameworkRoot();
1892
+ const config = await readAiwgConfig(projectDir);
1893
+ const requestedProviders = configuredGlobalProviders(remainingArgs, config);
1894
+ const providers = [];
1895
+ for (const requestedProvider of requestedProviders) {
1896
+ const local = await resolveProjectLocalProviderAdapter(projectDir, requestedProvider);
1897
+ const builtIn = local.requestedProvider
1898
+ ? local.provider
1899
+ : resolveBuiltInProviderForUse(local.provider).provider;
1900
+ if (!providers.includes(builtIn))
1901
+ providers.push(builtIn);
1902
+ }
1903
+ const dryRun = remainingArgs.includes('--dry-run');
1904
+ const requestedScope = remainingArgs.includes('--global')
1905
+ ? 'user'
1906
+ : detectScope(remainingArgs);
1907
+ const contextOptOut = [
1908
+ '--no-context-files',
1909
+ '--no-workspace-md',
1910
+ '--no-aiwg-md',
1911
+ '--no-agents-md',
1912
+ ].some((flag) => remainingArgs.includes(flag));
1913
+ const originalConsole = {
1914
+ log: console.log,
1915
+ info: console.info,
1916
+ warn: console.warn,
1917
+ error: console.error,
1918
+ };
1919
+ if (json) {
1920
+ machineReadableUseDepth += 1;
1921
+ console.log = () => { };
1922
+ console.info = () => { };
1923
+ console.warn = () => { };
1924
+ console.error = () => { };
1925
+ }
1926
+ let coreResult;
1927
+ try {
1928
+ coreResult = await this.executeCore({ ...ctx, args: coreArgs });
1929
+ }
1930
+ finally {
1931
+ if (json) {
1932
+ machineReadableUseDepth -= 1;
1933
+ console.log = originalConsole.log;
1934
+ console.info = originalConsole.info;
1935
+ console.warn = originalConsole.warn;
1936
+ console.error = originalConsole.error;
1937
+ }
1938
+ }
1939
+ let result;
1940
+ if (dryRun && coreResult.exitCode === 0) {
1941
+ result = buildDryRunUseResult({
1942
+ projectRoot: projectDir,
1943
+ frameworkRoot,
1944
+ providers,
1945
+ scope: requestedScope,
1946
+ requestedBundles: [requestedBundle],
1947
+ contextOptOut,
1948
+ });
1949
+ }
1950
+ else {
1951
+ if (coreResult.exitCode === 0 && !dryRun && !VALID_FRAMEWORKS.includes(requestedBundle)) {
1952
+ for (const provider of providers) {
1953
+ await ensurePostDeployPhases({
1954
+ frameworkRoot,
1955
+ projectPath: projectDir,
1956
+ provider,
1957
+ args: remainingArgs,
1958
+ invocationStartedAt: startedAt,
1959
+ });
1960
+ }
1961
+ }
1962
+ const providerResults = [];
1963
+ for (const provider of providers) {
1964
+ const effectiveScope = provider === 'openclaw' || provider === 'openhuman'
1965
+ ? 'user'
1966
+ : requestedScope;
1967
+ providerResults.push(await verifyProviderDeployment({
1968
+ projectRoot: projectDir,
1969
+ frameworkRoot,
1970
+ provider,
1971
+ scope: effectiveScope,
1972
+ requestedBundles: [requestedBundle],
1973
+ contextOptOut,
1974
+ invocationStartedAt: dryRun ? undefined : startedAt,
1975
+ deploymentExitCode: coreResult.exitCode,
1976
+ deploymentMessage: coreResult.message,
1977
+ }));
1978
+ }
1979
+ result = aggregateUseDeploymentResult({
1980
+ projectRoot: projectDir,
1981
+ frameworkRoot,
1982
+ scope: requestedScope,
1983
+ requestedBundles: [requestedBundle],
1984
+ providers: providerResults,
1985
+ });
1986
+ if (dryRun) {
1987
+ result.dryRun = true;
1988
+ result.exitClassification = 'failure';
1989
+ }
1990
+ }
1991
+ if (json) {
1992
+ return { exitCode: result.exitCode, message: JSON.stringify(result, null, 2), rawOutput: true };
1993
+ }
1994
+ const verbose = coreArgs.includes('--verbose') || coreArgs.includes('-v');
1995
+ const versionInfo = await getVersionInfo().catch(() => null);
1996
+ const widthFromEnvironment = Number(process.env.COLUMNS);
1997
+ const width = Number.isFinite(process.stdout.columns) && process.stdout.columns > 0
1998
+ ? process.stdout.columns
1999
+ : Number.isFinite(widthFromEnvironment) && widthFromEnvironment > 0
2000
+ ? widthFromEnvironment
2001
+ : 100;
2002
+ const canonicalProvider = result.providers[0]?.provider ?? 'claude';
2003
+ const rendered = renderUseDeploymentResult(result, {
2004
+ verbose,
2005
+ width,
2006
+ version: versionInfo
2007
+ ? { version: versionInfo.version, repository: versionInfo.repoUrl || 'aiwg.io' }
2008
+ : undefined,
2009
+ nextSteps: verbose && result.outcome !== 'failed' && VALID_FRAMEWORKS.includes(requestedBundle)
2010
+ ? nextStepsFor(requestedBundle, canonicalProvider)
2011
+ : undefined,
2012
+ });
2013
+ return {
2014
+ exitCode: result.exitCode,
2015
+ message: [coreResult.message, rendered].filter(Boolean).join('\n'),
2016
+ };
2017
+ }
2018
+ async executeCore(ctx) {
1824
2019
  const explicitTarget = firstUsePositional(ctx.args);
1825
2020
  if (ctx.args.includes('--workspace-signals')) {
1826
2021
  const signalArgs = ctx.args.filter((a) => a !== '--workspace-signals');
@@ -2062,7 +2257,7 @@ export class UseHandler {
2062
2257
  const verbose = remainingArgs.includes('--verbose') || remainingArgs.includes('-v');
2063
2258
  const force = remainingArgs.includes('--force');
2064
2259
  const copyAll = remainingArgs.includes('--copy-all') || remainingArgs.includes('--copy-standard-skills');
2065
- const quiet = !verbose && !dryRun;
2260
+ const quiet = machineReadableUseDepth > 0 || (!verbose && !dryRun);
2066
2261
  ui.blank();
2067
2262
  ui.header(` Workspace-aware deployment (${plan.profile})`);
2068
2263
  ui.dim(` Included frameworks: ${selectedFrameworks.join(', ') || '(none)'}`);
@@ -2135,7 +2330,7 @@ export class UseHandler {
2135
2330
  target,
2136
2331
  dryRun,
2137
2332
  verbose,
2138
- quiet: !verbose && !dryRun,
2333
+ quiet: machineReadableUseDepth > 0 || (!verbose && !dryRun),
2139
2334
  modelArgs: modelDeployArgs,
2140
2335
  });
2141
2336
  if (plResult.failed > 0) {
@@ -2326,13 +2521,19 @@ export class UseHandler {
2326
2521
  const dryRunAddon = remainingArgs.includes('--dry-run');
2327
2522
  const runner = createScriptRunner(frameworkRoot);
2328
2523
  const addonBaseArgs = ['--deploy-commands', '--deploy-skills', '--deploy-rules'];
2524
+ // An explicitly selected upstream addon must be self-contained in the
2525
+ // project. Unlike a full framework deploy, its standard skills cannot be
2526
+ // left index-only: the user asked to install this specific bundle and
2527
+ // its supporting scripts must travel with the skill directory.
2528
+ addonBaseArgs.push('--copy-all');
2329
2529
  addonBaseArgs.push(...modelDeployArgs);
2330
2530
  if (provider)
2331
2531
  addonBaseArgs.push('--provider', provider);
2332
2532
  if (target)
2333
2533
  addonBaseArgs.push('--target', target);
2334
2534
  // Forward --copy-all (#1219) so addon-only deploys also honor it.
2335
- if (remainingArgs.includes('--copy-all') || remainingArgs.includes('--copy-standard-skills')) {
2535
+ if ((remainingArgs.includes('--copy-all') || remainingArgs.includes('--copy-standard-skills'))
2536
+ && !addonBaseArgs.includes('--copy-all')) {
2336
2537
  addonBaseArgs.push('--copy-all');
2337
2538
  }
2338
2539
  if (dryRunAddon)
@@ -2424,6 +2625,30 @@ export class UseHandler {
2424
2625
  message: `Failed to register CLI commands: ${error instanceof Error ? error.message : String(error)}`,
2425
2626
  };
2426
2627
  }
2628
+ // Persist the same lifecycle record frameworks and project-local bundles
2629
+ // receive so status, refresh, doctor, and remove can account for this
2630
+ // upstream addon and every provider artifact it actually deployed.
2631
+ if (!dryRunAddon && config) {
2632
+ try {
2633
+ const manifestPath = path.join(addonSource, 'manifest.json');
2634
+ const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
2635
+ // Provider rule aggregation may rename many source rules into one
2636
+ // managed index. Record this addon's contributed artifact counts,
2637
+ // matching framework registry semantics, rather than trying to
2638
+ // attribute shared aggregate filenames after deployment.
2639
+ const counts = await countBundleSourceArtifacts(addonSource);
2640
+ const updated = updateInstalled(config, framework, provider, counts, {
2641
+ version: manifest.version ?? (await getVersionInfo()).version,
2642
+ source: 'bundled',
2643
+ manifestHash: await hashManifest(manifestPath),
2644
+ });
2645
+ await writeAiwgConfig(projectDir, updated);
2646
+ config = updated;
2647
+ }
2648
+ catch (error) {
2649
+ ui.warn(`Addon registry update failed for '${framework}': ${error instanceof Error ? error.message : String(error)}`);
2650
+ }
2651
+ }
2427
2652
  // Profile picker for addons with memory topology and multiple templates
2428
2653
  try {
2429
2654
  const profileManifestPath = path.join(addonSource, 'manifest.json');
@@ -2542,8 +2767,9 @@ export class UseHandler {
2542
2767
  const filteredArgs = deployArgs.filter(a => a !== '--no-utils' && a !== '--no-project-local' && a !== '--ci-hooks-enabled' && a !== '--force' && a !== '--skip-conflicts' && a !== '--no-harness-agents');
2543
2768
  const deployFilteredArgs = removeFlagWithOptionalValue(filteredArgs, '--harness-agents');
2544
2769
  // Pass --quiet to suppress deploy-agents.mjs header/footer in default mode (#460)
2545
- // Dry-run must not capture output its purpose is to show what would happen
2546
- if (!verbose && !dryRun)
2770
+ // Human dry-run remains verbose; machine-readable dry-run captures the
2771
+ // preview so stdout stays a single JSON document.
2772
+ if (machineReadableUseDepth > 0 || (!verbose && !dryRun))
2547
2773
  deployFilteredArgs.push('--quiet');
2548
2774
  // Extract provider and target from remainingArgs to pass to addon deployments
2549
2775
  // Config-first resolution (#621): explicit --provider overrides config, config overrides default 'claude'
@@ -2583,6 +2809,9 @@ export class UseHandler {
2583
2809
  if (unsupportedMessage) {
2584
2810
  return { exitCode: 1, message: unsupportedMessage };
2585
2811
  }
2812
+ if (requestedProvider.trim().toLowerCase() === 'windsurf') {
2813
+ ui.warn("Provider id 'windsurf' is deprecated; use '--provider devin' for Devin Desktop. Existing .windsurf/ output paths remain supported.");
2814
+ }
2586
2815
  const provider = builtInProviderResolution.provider;
2587
2816
  const providerDeployArgs = builtInProviderResolution.requestedProvider
2588
2817
  ? withProviderOverride(deployFilteredArgs, provider)
@@ -2645,14 +2874,15 @@ export class UseHandler {
2645
2874
  }
2646
2875
  }
2647
2876
  // Deploy main framework
2648
- const quiet = !verbose && !dryRun;
2877
+ const quiet = machineReadableUseDepth > 0 || (!verbose && !dryRun);
2649
2878
  const captureOpts = quiet ? { capture: true } : {};
2650
2879
  if (quiet) {
2651
2880
  const installLabel = framework === 'all'
2652
2881
  ? 'Installing complete AIWG surface'
2653
2882
  : `Installing ${framework} framework`;
2883
+ const providerLabel = getProviderDefinition(provider)?.displayName ?? provider;
2654
2884
  ui.blank();
2655
- console.log(` ${ui.brandMark()} ${ui.bold(installLabel)} ${ui.dimText(`for ${provider === 'claude' ? 'Claude Code' : provider}`)}`);
2885
+ console.log(` ${ui.brandMark()} ${ui.bold(installLabel)} ${ui.dimText(`for ${providerLabel}`)}`);
2656
2886
  ui.blank();
2657
2887
  }
2658
2888
  const runner = createScriptRunner(ctx.frameworkRoot);
@@ -2886,6 +3116,7 @@ export class UseHandler {
2886
3116
  behaviorsPath: paths.behaviors,
2887
3117
  provider,
2888
3118
  cwd: target,
3119
+ quiet: !verbose,
2889
3120
  });
2890
3121
  if (verbose)
2891
3122
  console.log('Extension registration complete');
@@ -2905,7 +3136,6 @@ export class UseHandler {
2905
3136
  // (e.g., test fixtures, deploy from npm install rather than the
2906
3137
  // source repo). buildIndex() calls `process.exit(1)` on missing
2907
3138
  // scan dirs which would short-circuit our catch.
2908
- let discoverableSkillCount = null;
2909
3139
  if (!dryRun) {
2910
3140
  // Build the framework graph against $AIWG_ROOT, not the project's
2911
3141
  // target dir (#1217). The framework source is user-global at
@@ -2936,10 +3166,11 @@ export class UseHandler {
2936
3166
  // project (#1217). The output index location is XDG-shared
2937
3167
  // regardless of build cwd.
2938
3168
  await buildIndex(aiwgRootForIndex, { graph: 'framework', explicit: false });
3169
+ const { syncFortemiCoreIndex } = await import('../../artifacts/fortemi-core-sync.js');
3170
+ syncFortemiCoreIndex(aiwgRootForIndex, { graph: 'framework' });
2939
3171
  console.log = origLog;
2940
- discoverableSkillCount = await countDiscoverableSkills(aiwgRootForIndex);
2941
3172
  const indexElapsedSec = ((Date.now() - indexStart) / 1000).toFixed(1);
2942
- ui.success(`Capability index ready (${indexElapsedSec}s) — agents can search the installed capability set.`);
3173
+ ui.success(`Capability index ready (${indexElapsedSec}s).`);
2943
3174
  }
2944
3175
  catch (error) {
2945
3176
  console.log = origLog;
@@ -2951,42 +3182,13 @@ export class UseHandler {
2951
3182
  console.log('Framework source not found; skipping capability index rebuild');
2952
3183
  }
2953
3184
  }
2954
- // Show completion summary and next steps (default mode only)
3185
+ // Collect deployment counts for registry persistence and the final
3186
+ // orchestrated report. Presentation happens once, after verification, so
3187
+ // users do not see a second competing summary.
2955
3188
  let counts = { agents: 0, commands: 0, skills: 0, rules: 0, behaviors: 0 };
2956
3189
  if (quiet) {
2957
- // Count deployed artifacts
2958
3190
  const paths = getProviderPaths(provider);
2959
3191
  counts = await countDeployedArtifacts(target, paths, provider);
2960
- if (counts.agents > 0)
2961
- ui.deployCount('Agents', counts.agents);
2962
- if (counts.commands > 0)
2963
- ui.deployCount('Commands', counts.commands);
2964
- if (counts.skills > 0)
2965
- ui.deployCount('Skills', counts.skills);
2966
- if (discoverableSkillCount !== null)
2967
- ui.deployCount('Discoverable skills', discoverableSkillCount);
2968
- if (counts.rules > 0)
2969
- ui.deployCount('Rules', counts.rules);
2970
- if (counts.behaviors > 0)
2971
- ui.deployCount('Behaviors', counts.behaviors);
2972
- ui.blank();
2973
- printNextSteps(framework, provider);
2974
- // #1240: warn the operator that the running session can't see the newly
2975
- // deployed agents until reloaded. Skipping this notice is what produced
2976
- // the "Agent type 'software-implementer' not found" symptom on a stale
2977
- // Claude Code session.
2978
- ui.blank();
2979
- printSessionReloadNotice(provider);
2980
- // Append version confirmation line (#719)
2981
- try {
2982
- const versionInfo = await getVersionInfo();
2983
- ui.blank();
2984
- const repoStamp = versionInfo.repoUrl || 'aiwg.io';
2985
- ui.dim(` AIWG v${versionInfo.version} — ${repoStamp}`);
2986
- }
2987
- catch {
2988
- // Graceful fallback: omit version line if versionInfo unavailable
2989
- }
2990
3192
  }
2991
3193
  // Deploy CI workflow files when --ci-hooks-enabled is set (#661)
2992
3194
  if (ciHooksEnabled) {