@aiwg/cli 2026.10.11 → 2026.10.12

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 (132) hide show
  1. package/agentic/code/providers/model-catalog.v1.json +62 -12
  2. package/dist/src/artifacts/binding-target-identity.js +51 -0
  3. package/dist/src/artifacts/checksum-manifest.js +12 -0
  4. package/dist/src/artifacts/index-builder.js +11 -13
  5. package/dist/src/artifacts/query-engine.js +5 -11
  6. package/dist/src/cli/handlers/doctor-help.js +32 -0
  7. package/dist/src/cli/handlers/gates.js +19 -18
  8. package/dist/src/cli/handlers/models-help.js +7 -1
  9. package/dist/src/cli/handlers/models.js +3 -3
  10. package/dist/src/cli/handlers/script-runner.js +8 -5
  11. package/dist/src/cli/handlers/sessions-intake.js +104 -0
  12. package/dist/src/cli/handlers/sessions-tail.js +172 -0
  13. package/dist/src/cli/handlers/sessions.js +90 -17
  14. package/dist/src/cli/handlers/skill-lint.js +10 -3
  15. package/dist/src/cli/handlers/steward-format.js +100 -0
  16. package/dist/src/cli/handlers/steward-models.js +167 -0
  17. package/dist/src/cli/handlers/steward.js +14 -248
  18. package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
  19. package/dist/src/cli/handlers/use.js +6 -24
  20. package/dist/src/cli/handlers/utilities.js +1 -24
  21. package/dist/src/config/aiwg-config.js +7 -0
  22. package/dist/src/config/authorization-cli.js +89 -0
  23. package/dist/src/config/cli-help.js +1 -0
  24. package/dist/src/config/cli.js +10 -1
  25. package/dist/src/decision/context-pruning.js +3 -2
  26. package/dist/src/decision/ensemble/contract.js +15 -4
  27. package/dist/src/decision/ensemble-study/artifacts.js +5 -0
  28. package/dist/src/decision/ensemble-study/score.js +4 -3
  29. package/dist/src/decision/feature-export.js +3 -9
  30. package/dist/src/decision/heldout/collector.js +2 -2
  31. package/dist/src/decision/issue-triage/runtime.js +3 -9
  32. package/dist/src/decision/qualification/gates.js +2 -1
  33. package/dist/src/decision/qualification/release.js +2 -3
  34. package/dist/src/decision/routing/report.js +2 -0
  35. package/dist/src/decision/sdlc-screening.js +3 -5
  36. package/dist/src/decision/sensitivity/comparative.js +5 -3
  37. package/dist/src/gates/driver.js +6 -77
  38. package/dist/src/gates/evaluate.js +4 -11
  39. package/dist/src/gates/floors.js +4 -4
  40. package/dist/src/gates/index.js +3 -3
  41. package/dist/src/gates/lattice.js +26 -0
  42. package/dist/src/gates/registry.js +2 -1
  43. package/dist/src/gates/report.js +19 -7
  44. package/dist/src/issues/audit-cli.js +120 -0
  45. package/dist/src/issues/audit-contract.js +64 -0
  46. package/dist/src/issues/audit-local.js +82 -0
  47. package/dist/src/issues/audit.js +220 -0
  48. package/dist/src/lint/rule-activation.js +15 -1
  49. package/dist/src/mission-protocol/canonical-codecs.js +270 -0
  50. package/dist/src/mission-protocol/codecs.js +22 -550
  51. package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
  52. package/dist/src/mission-protocol/health-trace-types.js +43 -0
  53. package/dist/src/mission-protocol/types.js +2 -42
  54. package/dist/src/mission-protocol/worker-contract-json.js +10 -0
  55. package/dist/src/mission-protocol/worker-review-gate.js +100 -0
  56. package/dist/src/mission-protocol/worker-review-types.js +2 -0
  57. package/dist/src/models/catalog-policy.js +280 -0
  58. package/dist/src/models/index.js +1 -1
  59. package/dist/src/models/model-catalog.v1.json +62 -12
  60. package/dist/src/models/policy-resources.js +28 -0
  61. package/dist/src/models/provider-policy.js +10 -546
  62. package/dist/src/models/resolver.js +26 -8
  63. package/dist/src/models/router.js +15 -2
  64. package/dist/src/models/tiers.js +13 -0
  65. package/dist/src/models/types.js +0 -6
  66. package/dist/src/models/worker-ceilings.js +59 -0
  67. package/dist/src/models/worker-invocation-policy.js +243 -0
  68. package/dist/src/models/worker-plan.js +16 -20
  69. package/dist/src/models/worker-review-lineage.js +55 -0
  70. package/dist/src/models/worker-selection-policy.js +1 -1
  71. package/dist/src/models/wrapper-route.js +6 -3
  72. package/dist/src/policy/authorization.js +1 -0
  73. package/dist/src/policy/hitl-config.js +63 -0
  74. package/dist/src/policy/hitl-receipt.js +57 -0
  75. package/dist/src/policy/hitl-types.js +4 -0
  76. package/dist/src/policy/hitl-validation.js +39 -0
  77. package/dist/src/policy/hitl.js +117 -0
  78. package/dist/src/rules/activation.d.mts +1 -1
  79. package/dist/src/rules/activation.mjs +0 -2
  80. package/dist/src/rules/gate-coverage.js +51 -0
  81. package/dist/src/rules/gate-references.js +16 -0
  82. package/dist/src/rules/rule-frontmatter.schema.json +7 -1
  83. package/dist/src/serve/worker-command-request.js +21 -4
  84. package/dist/src/serve/worker-invocation-preparation.js +3 -1
  85. package/dist/src/serve/worker-invocation.js +21 -10
  86. package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
  87. package/dist/src/sessions/adapters/grok-build-native.js +269 -0
  88. package/dist/src/sessions/adapters/grok-build.js +57 -15
  89. package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
  90. package/dist/src/sessions/adapters/hermes.js +42 -3
  91. package/dist/src/sessions/adapters/warp.js +1 -1
  92. package/dist/src/sessions/batch-import.js +10 -0
  93. package/dist/src/sessions/contracts.js +1 -1
  94. package/dist/src/sessions/discovery-capability.js +38 -0
  95. package/dist/src/sessions/importer.js +8 -251
  96. package/dist/src/sessions/index.js +4 -0
  97. package/dist/src/sessions/intake-dir.js +71 -0
  98. package/dist/src/sessions/normalization.js +251 -0
  99. package/dist/src/sessions/tail.js +91 -0
  100. package/dist/src/sessions/workspace-discovery.js +83 -7
  101. package/dist/src/skills/agent-skill-sidecar.js +28 -0
  102. package/dist/src/skills/agent-skills.js +4 -23
  103. package/dist/src/skills/claude-surface-projection.js +25 -0
  104. package/dist/src/skills/deployer.js +8 -288
  105. package/dist/src/skills/deployment-policy.js +114 -0
  106. package/dist/src/skills/deployment-projection.js +152 -0
  107. package/dist/src/skills/deployment-types.js +20 -0
  108. package/dist/src/skills/exporter.js +8 -31
  109. package/dist/src/skills/provider-extensions.js +41 -0
  110. package/dist/src/skills/run.js +6 -0
  111. package/dist/src/skills/types.js +0 -8
  112. package/dist/src/skills/validator-resources.js +68 -0
  113. package/dist/src/skills/validator.js +6 -55
  114. package/dist/src/storage/cli-migrate-options.js +125 -0
  115. package/dist/src/storage/cli-migrate.js +111 -0
  116. package/dist/src/storage/cli.js +4 -279
  117. package/dist/src/storage/migration-adapter.js +79 -0
  118. package/dist/src/storage/migration-copy.js +108 -0
  119. package/dist/src/storage/migration-protocol.js +14 -197
  120. package/dist/src/storage/migration-records.js +186 -0
  121. package/dist/src/storage/migration-types.js +12 -0
  122. package/dist/src/tracker/forge-http.js +2 -1
  123. package/dist/src/tracker/issue-pages.js +110 -0
  124. package/package.json +1 -1
  125. package/schemas/mission-v1.schema.json +335 -0
  126. package/schemas/models/model-catalog.v1.schema.json +19 -1
  127. package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
  128. package/schemas/models/model-policy.v1.schema.json +1 -1
  129. package/tools/agents/providers/provider-paths-staging.mjs +35 -0
  130. package/tools/agents/providers/rule-binding-targets.mjs +146 -0
  131. package/tools/agents/providers/rule-delivery.mjs +7 -126
  132. package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
@@ -0,0 +1,167 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { AiwgError, EXIT_CODES } from '../errors.js';
4
+ import { getProjectDir } from '../../config/aiwg-config.js';
5
+ import { capabilityProviderId, normalizeProviderId, resolveActiveProvider } from '../provider-resolution.js';
6
+ import { routeModelTier } from '../../models/router.js';
7
+ import { buildWrapperRouteEnvelope } from '../../models/wrapper-route.js';
8
+ import { loadProviderModelCatalog } from '../../models/provider-policy.js';
9
+ import { CapabilityResolutionError, resolveRoutableCapability } from '../../artifacts/capability-resolver.js';
10
+ function isModelPolicyProvider(provider) {
11
+ return Object.hasOwn(loadProviderModelCatalog().providers, provider);
12
+ }
13
+ export async function handleStewardModels(args, matrix, ctx) {
14
+ const flagValue = (name) => {
15
+ const index = args.indexOf(name);
16
+ if (index < 0)
17
+ return undefined;
18
+ const value = args[index + 1];
19
+ if (!value || value.startsWith('--'))
20
+ throw new AiwgError({
21
+ code: 'ERR_USAGE_MISSING_VALUE',
22
+ message: `${name} requires a value.`,
23
+ exitCode: EXIT_CODES.USAGE,
24
+ });
25
+ return value;
26
+ };
27
+ if (args.includes('--route')) {
28
+ const rawProvider = flagValue('--provider') ?? await resolveActiveProvider({
29
+ cwd: ctx ? getProjectDir(ctx, ctx.args) : process.cwd(),
30
+ detectProcess: true,
31
+ }).then(result => result.provider ?? undefined);
32
+ const provider = normalizeProviderId(rawProvider);
33
+ if (!provider || provider === 'generic')
34
+ throw new AiwgError({
35
+ code: 'ERR_USAGE_UNKNOWN_PROVIDER',
36
+ message: `Cannot compile a wrapper route for provider: ${rawProvider ?? '(undetected)'}`,
37
+ hint: 'Pass --provider with a supported provider id.',
38
+ exitCode: EXIT_CODES.USAGE,
39
+ });
40
+ if (!isModelPolicyProvider(provider))
41
+ throw new AiwgError({
42
+ code: 'ERR_USAGE_UNSUPPORTED_PROVIDER',
43
+ message: `Model wrapper routing is not implemented for provider: ${provider}`,
44
+ hint: 'Use `aiwg steward capabilities --provider pi` for current Pi capability routing; model routing is tracked separately.',
45
+ exitCode: EXIT_CODES.USAGE,
46
+ });
47
+ const capabilityType = flagValue('--capability-type');
48
+ const capability = flagValue('--capability');
49
+ const assignment = flagValue('--assignment');
50
+ if (!capabilityType || !['agent', 'skill', 'rule', 'workflow'].includes(capabilityType))
51
+ throw new AiwgError({
52
+ code: 'ERR_USAGE_MISSING_VALUE',
53
+ message: '--capability-type requires agent, skill, rule, or workflow.',
54
+ exitCode: EXIT_CODES.USAGE,
55
+ });
56
+ if (!capability || !assignment)
57
+ throw new AiwgError({
58
+ code: 'ERR_USAGE_MISSING_VALUE',
59
+ message: '--route requires both --capability <id> and --assignment <bounded text>.',
60
+ exitCode: EXIT_CODES.USAGE,
61
+ });
62
+ const capabilityProvider = capabilityProviderId(provider);
63
+ const providerCapabilities = capabilityProvider ? matrix.providers[capabilityProvider] : undefined;
64
+ const launchMechanism = providerCapabilities?.native_features.tasks
65
+ ? 'native-subagent'
66
+ : providerCapabilities?.emulation.tasks === 'aiwg-mc' ? 'aiwg-mc' : 'manual';
67
+ const premiumAuthorized = args.includes('--allow-premium');
68
+ const { collectProviderInventory } = await import('../../providers/provider-inventory.js');
69
+ const { resolveDynamicModelCatalog } = await import('../../models/model-discovery.js');
70
+ const projectDir = ctx ? getProjectDir(ctx, ctx.args) : process.cwd();
71
+ const requestedAiwgRoot = ctx?.frameworkRoot ?? process.cwd();
72
+ const aiwgRoot = await access(join(requestedAiwgRoot, 'agentic/code/providers/model-catalog.v1.json')).then(() => requestedAiwgRoot).catch(() => process.cwd());
73
+ const resolvedCapability = await resolveRoutableCapability(aiwgRoot, capabilityType, capability).catch(error => {
74
+ if (!(error instanceof CapabilityResolutionError))
75
+ throw error;
76
+ throw new AiwgError({
77
+ code: error.kind === 'ambiguous'
78
+ ? 'ERR_USAGE_AMBIGUOUS_CAPABILITY'
79
+ : 'ERR_USAGE_UNKNOWN_CAPABILITY',
80
+ message: error.message,
81
+ hint: 'Run aiwg discover "<capability>" --json and pass an exact name or stable id.',
82
+ exitCode: EXIT_CODES.USAGE,
83
+ });
84
+ });
85
+ const catalog = await resolveDynamicModelCatalog({
86
+ aiwgRoot,
87
+ inventory: await collectProviderInventory(projectDir),
88
+ allowNetwork: false,
89
+ });
90
+ const baselineCatalog = loadProviderModelCatalog();
91
+ const effectiveCatalog = {
92
+ ...baselineCatalog,
93
+ ...catalog,
94
+ refreshedAt: catalog.refreshedAt ?? baselineCatalog.refreshedAt,
95
+ staleAfterDays: baselineCatalog.staleAfterDays,
96
+ providers: { ...baselineCatalog.providers, ...catalog.providers },
97
+ };
98
+ const envelope = buildWrapperRouteEnvelope({
99
+ provider,
100
+ capability: resolvedCapability,
101
+ assignment,
102
+ launchMechanism,
103
+ deterministic: args.includes('--deterministic'),
104
+ routine: args.includes('--routine'),
105
+ complex: args.includes('--complex'),
106
+ highImpact: args.includes('--high-impact'),
107
+ requestedPremium: args.includes('--premium'),
108
+ unattended: args.includes('--unattended'),
109
+ premiumAuthorized,
110
+ maxAutoTier: premiumAuthorized ? 3 : undefined,
111
+ catalog: effectiveCatalog,
112
+ });
113
+ if (args.includes('--json'))
114
+ console.log(JSON.stringify(envelope, null, 2));
115
+ else {
116
+ console.log('\n Model wrapper route');
117
+ console.log(` Provider: ${envelope.provider}`);
118
+ console.log(` Capability: ${envelope.capability.type} ${envelope.capability.name} (${envelope.capability.id})`);
119
+ console.log(` Tier/role: ${envelope.tier ?? 'deterministic'}/${envelope.role ?? 'none'}`);
120
+ console.log(` Wrapper: ${envelope.wrapper ?? 'none'}`);
121
+ console.log(` Model: ${envelope.model?.effectiveModel ?? 'inherited or no model call'} (${envelope.model?.outcome ?? 'deterministic'})`);
122
+ console.log(` Launch: ${envelope.launch.mechanism}`);
123
+ console.log(` Confirmation: ${envelope.decision.requiresConfirmation ? 'required' : 'not required'}`);
124
+ console.log('\n Wrapper prompt:\n');
125
+ console.log(envelope.launch.prompt);
126
+ }
127
+ return;
128
+ }
129
+ const tiers = Object.fromEntries(Object.entries(loadProviderModelCatalog().providers)
130
+ .filter(([, entry]) => entry.tiers)
131
+ .map(([provider, entry]) => [provider, Object.fromEntries(Object.entries(entry.tiers)
132
+ .map(([tier, model]) => [tier, { ...model, label: model.selection === 'user-elected' ? 'user-elected only' : tier }]))]));
133
+ const decision = routeModelTier({
134
+ deterministic: args.includes('--deterministic'),
135
+ routine: args.includes('--routine'),
136
+ complex: args.includes('--complex'),
137
+ highImpact: args.includes('--high-impact'),
138
+ requestedPremium: args.includes('--premium'),
139
+ unattended: args.includes('--unattended'),
140
+ premiumAuthorized: args.includes('--allow-premium'),
141
+ maxAutoTier: args.includes('--allow-premium') ? 3 : undefined,
142
+ });
143
+ if (args.includes('--json')) {
144
+ console.log(JSON.stringify({ decision, tiers }, null, 2));
145
+ return;
146
+ }
147
+ for (const [provider, ladder] of Object.entries(tiers)) {
148
+ for (const [tier, entry] of Object.entries(ladder))
149
+ console.log(` ${provider} ${tier}: ${entry.id} (${entry.label})`);
150
+ }
151
+ console.log('\n Model policy routing');
152
+ console.log(` Default stance: cheap-first role/tier intent, compiled per provider from the effective catalog.`);
153
+ console.log(` Suggested tier: ${decision.tier}${decision.modelTier ? ` (${decision.modelTier})` : ' (no model call)'}`);
154
+ console.log(` Confirmation: ${decision.requiresConfirmation ? 'required' : 'not required'}`);
155
+ console.log(` Summary before escalation: ${decision.summaryRequired ? 'required' : 'not required'}`);
156
+ console.log(` Rationale: ${decision.rationale.join('; ')}`);
157
+ console.log('\n Commands:');
158
+ console.log(' aiwg models sources --json # inspect effective cache/static/remote catalog provenance');
159
+ console.log(' aiwg models refresh --json # refresh dynamic provider catalog where supported');
160
+ console.log(' aiwg models audit --provider P # compile artifact policy and diagnostics');
161
+ console.log(' aiwg models resolve --provider P # show selected provider model for matching artifacts');
162
+ console.log('\n Authoring:');
163
+ console.log(' Agents: use model-role/model-tier; avoid exact provider IDs in source scaffolds.');
164
+ console.log(' Skills/commands: use commandHint.modelRole and commandHint.modelTier.');
165
+ return;
166
+ }
167
+ //# sourceMappingURL=steward-models.js.map
@@ -16,22 +16,15 @@
16
16
  * @source @src/cli/router.ts
17
17
  * @issue #599 #1261 #1262
18
18
  */
19
- import { access } from 'node:fs/promises';
20
- import { join } from 'node:path';
21
19
  import { AiwgError, EXIT_CODES, handlerResultFromError } from '../errors.js';
22
20
  import { loadCapabilityMatrix, isExternalStrategy, } from '../../providers/capability-matrix.js';
23
21
  import { getProjectDir, readAiwgConfig, writeAiwgConfig } from '../../config/aiwg-config.js';
24
22
  import { auditLegacyPermissions, archiveLegacyPermissionManifests, backupConfig, normalizeProjectPermissions, } from '../../policy/authorization.js';
25
23
  import { capabilityProviderId, normalizeProviderId, resolveActiveProvider } from '../provider-resolution.js';
26
24
  import { discoverProjectLocalBundles, } from '../../extensions/project-local-discovery.js';
27
- import { routeModelTier } from '../../models/router.js';
28
- import { buildWrapperRouteEnvelope } from '../../models/wrapper-route.js';
29
- import { loadProviderModelCatalog, } from '../../models/provider-policy.js';
30
- import { CapabilityResolutionError, resolveRoutableCapability, } from '../../artifacts/capability-resolver.js';
25
+ import { printFullMatrix, permissionsUsage, formatProvider, emulationLabel } from './steward-format.js';
26
+ import { handleStewardModels } from './steward-models.js';
31
27
  const BASELINE_PROVIDER = 'claude-code';
32
- function isModelPolicyProvider(provider) {
33
- return Object.hasOwn(loadProviderModelCatalog().providers, provider);
34
- }
35
28
  // ── Feature name normalization ────────────────────────────────────────────────
36
29
  /**
37
30
  * Accept both hyphenated (agent-teams) and underscored (agent_teams) feature
@@ -49,62 +42,6 @@ async function detectProvider(ctx) {
49
42
  return capabilityProviderId(resolution.provider);
50
43
  }
51
44
  // ── Formatters ────────────────────────────────────────────────────────────────
52
- const NATIVE_MARK = '✓ native';
53
- const EMULATED_MARK = '~ emulated';
54
- const EXTERNAL_MARK = '↗ external';
55
- const UNSUPPORTED_MARK = '- not supported';
56
- function emulationLabel(strategy) {
57
- if (!strategy)
58
- return 'none';
59
- if (strategy === 'native')
60
- return 'native (no fallback needed)';
61
- return strategy;
62
- }
63
- function formatProvider(id, provider, matrix, meta) {
64
- const lines = [];
65
- lines.push(`\n Provider: ${provider.display_name} (${id})`);
66
- if (meta) {
67
- lines.push(` Project-local: yes`);
68
- lines.push(` Base adapter: ${meta.baseAdapter}`);
69
- }
70
- lines.push(` Status: ${provider.status}`);
71
- lines.push(` Daemon: ${provider.daemon_tier}${provider.daemon_pty_adapter ? ' (+ pty-adapter)' : ''}`);
72
- lines.push(` ${'─'.repeat(60)}`);
73
- const featureKeys = Object.keys(matrix.features);
74
- for (const featureId of featureKeys) {
75
- const isNative = provider.native_features?.[featureId] === true;
76
- const emulation = provider.emulation?.[featureId] ?? null;
77
- const status = isNative
78
- ? NATIVE_MARK
79
- : isExternalStrategy(emulation) ? EXTERNAL_MARK : (emulation ? EMULATED_MARK : UNSUPPORTED_MARK);
80
- const feat = matrix.features[featureId];
81
- lines.push(`\n ${featureId} — ${status}`);
82
- if (feat?.description)
83
- lines.push(` ${feat.description}`);
84
- if (isNative) {
85
- if (id === 'omp' && featureId === 'mcp') {
86
- lines.push(' OMP supplies the native client. AIWG persistent injection/removal is available for project and profile scope; ephemeral injection is unsupported.');
87
- lines.push(' example: aiwg mcp inject --provider omp --servers local-tools');
88
- }
89
- else if (id === 'omp' && featureId === 'behaviors') {
90
- lines.push(' AIWG bridges selected handlers through an OMP extension; no default policy is installed. Permission-request and pre-compaction enforcement are unsupported.');
91
- }
92
- else if (id === 'omp' && (featureId === 'tasks' || featureId === 'agent_teams')) {
93
- lines.push(' OMP native leaf tasks use AIWG workspace admission limits and verified child results; nested requests share the same scheduler.');
94
- lines.push(' example: aiwg team run --provider omp --body-file tasks.json');
95
- }
96
- else if (feat?.native_example)
97
- lines.push(` example: ${feat.native_example}`);
98
- }
99
- else if (isExternalStrategy(emulation)) {
100
- lines.push(` trigger: system cron, systemd timer, or CI; AIWG does not own the clock`);
101
- }
102
- else if (emulation) {
103
- lines.push(` fallback: ${emulationLabel(emulation)}`);
104
- }
105
- }
106
- return lines.join('\n');
107
- }
108
45
  async function findProjectLocalProvider(projectDir, requestedProvider) {
109
46
  const discovery = await discoverProjectLocalBundles(projectDir);
110
47
  const requested = requestedProvider.trim().toLowerCase();
@@ -156,47 +93,6 @@ async function resolveStewardProvider(matrix, requestedProvider, ctx) {
156
93
  },
157
94
  };
158
95
  }
159
- function printFullMatrix(matrix) {
160
- const { providers, features } = matrix;
161
- const providerIds = Object.keys(providers);
162
- const featureIds = Object.keys(features);
163
- console.log(`\n Provider Capability Matrix (v${matrix.version})`);
164
- console.log(` ✓ = native ~ = AIWG emulation - = not supported\n`);
165
- const featureColW = 20;
166
- const provColW = 14;
167
- const header = ' ' + 'Feature'.padEnd(featureColW) + providerIds.map(p => p.padEnd(provColW)).join('');
168
- console.log(header);
169
- console.log(' ' + '─'.repeat(featureColW + providerIds.length * provColW));
170
- for (const featureId of featureIds) {
171
- const feat = features[featureId];
172
- let row = ' ' + featureId.padEnd(featureColW);
173
- for (const providerId of providerIds) {
174
- const provider = providers[providerId];
175
- const isNative = provider?.native_features?.[featureId] === true;
176
- const emulation = provider?.emulation?.[featureId] ?? null;
177
- const mark = isNative ? '✓' : (emulation ? '~' : '-');
178
- row += mark.padEnd(provColW);
179
- }
180
- console.log(row);
181
- if (feat?.description) {
182
- console.log(' ' + ' '.repeat(featureColW) + feat.description);
183
- }
184
- console.log('');
185
- }
186
- }
187
- // ── Main execution ─────────────────────────────────────────────────────────────
188
- function permissionsUsage() {
189
- return `
190
- aiwg steward permissions — authorization model audit and normalization
191
-
192
- Usage:
193
- aiwg steward permissions audit Find normalized-model errors and legacy grants
194
- aiwg steward permissions migrate --dry-run Preview legacy permission normalization
195
- aiwg steward permissions migrate --apply Back up and atomically normalize config
196
-
197
- Reads .aiwg/aiwg.config authorization block. Migration backs up before writing.
198
- `;
199
- }
200
96
  async function handleSteward(args, ctx) {
201
97
  const subcommand = args[0];
202
98
  if (!subcommand || subcommand === '--help' || subcommand === 'help') {
@@ -214,6 +110,7 @@ async function handleSteward(args, ctx) {
214
110
  aiwg steward models --route --capability-type <agent|skill|rule|workflow>
215
111
  --capability <id> --assignment <text> [--provider <name>] [--json]
216
112
  Emit a capability-bound wrapper launch envelope
113
+ aiwg steward authorization Bounded HITL policy: inspect/validate/preview/enable/revoke
217
114
  aiwg steward permissions audit Find normalized-model errors and legacy grants
218
115
  aiwg steward permissions migrate --dry-run Preview legacy permission normalization
219
116
  aiwg steward permissions migrate --apply Back up and atomically normalize config
@@ -242,6 +139,11 @@ async function handleSteward(args, ctx) {
242
139
  console.log(JSON.stringify(args.includes('--json') ? { decisionOffload } : decisionOffload, null, 2));
243
140
  return;
244
141
  }
142
+ if (subcommand === 'authorization') {
143
+ const { authorizationCli } = await import('../../config/authorization-cli.js');
144
+ await authorizationCli(args.slice(1), ctx?.cwd);
145
+ return;
146
+ }
245
147
  if (subcommand === 'permissions') {
246
148
  const operation = args[1];
247
149
  // `<namespace> --help` must reach the same usage block bare invocation prints (#2533).
@@ -478,148 +380,8 @@ async function handleSteward(args, ctx) {
478
380
  }
479
381
  return;
480
382
  }
481
- if (subcommand === 'models' || subcommand === 'model-routing') {
482
- const flagValue = (name) => {
483
- const index = args.indexOf(name);
484
- if (index < 0)
485
- return undefined;
486
- const value = args[index + 1];
487
- if (!value || value.startsWith('--'))
488
- throw new AiwgError({
489
- code: 'ERR_USAGE_MISSING_VALUE',
490
- message: `${name} requires a value.`,
491
- exitCode: EXIT_CODES.USAGE,
492
- });
493
- return value;
494
- };
495
- if (args.includes('--route')) {
496
- const rawProvider = flagValue('--provider') ?? await resolveActiveProvider({
497
- cwd: ctx ? getProjectDir(ctx, ctx.args) : process.cwd(),
498
- detectProcess: true,
499
- }).then(result => result.provider ?? undefined);
500
- const provider = normalizeProviderId(rawProvider);
501
- if (!provider || provider === 'generic')
502
- throw new AiwgError({
503
- code: 'ERR_USAGE_UNKNOWN_PROVIDER',
504
- message: `Cannot compile a wrapper route for provider: ${rawProvider ?? '(undetected)'}`,
505
- hint: 'Pass --provider with a supported provider id.',
506
- exitCode: EXIT_CODES.USAGE,
507
- });
508
- if (!isModelPolicyProvider(provider))
509
- throw new AiwgError({
510
- code: 'ERR_USAGE_UNSUPPORTED_PROVIDER',
511
- message: `Model wrapper routing is not implemented for provider: ${provider}`,
512
- hint: 'Use `aiwg steward capabilities --provider pi` for current Pi capability routing; model routing is tracked separately.',
513
- exitCode: EXIT_CODES.USAGE,
514
- });
515
- const capabilityType = flagValue('--capability-type');
516
- const capability = flagValue('--capability');
517
- const assignment = flagValue('--assignment');
518
- if (!capabilityType || !['agent', 'skill', 'rule', 'workflow'].includes(capabilityType))
519
- throw new AiwgError({
520
- code: 'ERR_USAGE_MISSING_VALUE',
521
- message: '--capability-type requires agent, skill, rule, or workflow.',
522
- exitCode: EXIT_CODES.USAGE,
523
- });
524
- if (!capability || !assignment)
525
- throw new AiwgError({
526
- code: 'ERR_USAGE_MISSING_VALUE',
527
- message: '--route requires both --capability <id> and --assignment <bounded text>.',
528
- exitCode: EXIT_CODES.USAGE,
529
- });
530
- const capabilityProvider = capabilityProviderId(provider);
531
- const providerCapabilities = capabilityProvider ? matrix.providers[capabilityProvider] : undefined;
532
- const launchMechanism = providerCapabilities?.native_features.tasks
533
- ? 'native-subagent'
534
- : providerCapabilities?.emulation.tasks === 'aiwg-mc' ? 'aiwg-mc' : 'manual';
535
- const premiumAuthorized = args.includes('--allow-premium');
536
- const { collectProviderInventory } = await import('../../providers/provider-inventory.js');
537
- const { resolveDynamicModelCatalog } = await import('../../models/model-discovery.js');
538
- const projectDir = ctx ? getProjectDir(ctx, ctx.args) : process.cwd();
539
- const requestedAiwgRoot = ctx?.frameworkRoot ?? process.cwd();
540
- const aiwgRoot = await access(join(requestedAiwgRoot, 'agentic/code/providers/model-catalog.v1.json')).then(() => requestedAiwgRoot).catch(() => process.cwd());
541
- const resolvedCapability = await resolveRoutableCapability(aiwgRoot, capabilityType, capability).catch(error => {
542
- if (!(error instanceof CapabilityResolutionError))
543
- throw error;
544
- throw new AiwgError({
545
- code: error.kind === 'ambiguous'
546
- ? 'ERR_USAGE_AMBIGUOUS_CAPABILITY'
547
- : 'ERR_USAGE_UNKNOWN_CAPABILITY',
548
- message: error.message,
549
- hint: 'Run aiwg discover "<capability>" --json and pass an exact name or stable id.',
550
- exitCode: EXIT_CODES.USAGE,
551
- });
552
- });
553
- const catalog = await resolveDynamicModelCatalog({
554
- aiwgRoot,
555
- inventory: await collectProviderInventory(projectDir),
556
- allowNetwork: false,
557
- });
558
- const baselineCatalog = loadProviderModelCatalog();
559
- const effectiveCatalog = {
560
- ...baselineCatalog,
561
- ...catalog,
562
- refreshedAt: catalog.refreshedAt ?? baselineCatalog.refreshedAt,
563
- staleAfterDays: baselineCatalog.staleAfterDays,
564
- providers: { ...baselineCatalog.providers, ...catalog.providers },
565
- };
566
- const envelope = buildWrapperRouteEnvelope({
567
- provider,
568
- capability: resolvedCapability,
569
- assignment,
570
- launchMechanism,
571
- deterministic: args.includes('--deterministic'),
572
- routine: args.includes('--routine'),
573
- complex: args.includes('--complex'),
574
- highImpact: args.includes('--high-impact'),
575
- requestedPremium: args.includes('--premium'),
576
- unattended: args.includes('--unattended'),
577
- premiumAuthorized,
578
- maxAutoTier: premiumAuthorized ? 3 : undefined,
579
- catalog: effectiveCatalog,
580
- });
581
- if (args.includes('--json'))
582
- console.log(JSON.stringify(envelope, null, 2));
583
- else {
584
- console.log('\n Model wrapper route');
585
- console.log(` Provider: ${envelope.provider}`);
586
- console.log(` Capability: ${envelope.capability.type} ${envelope.capability.name} (${envelope.capability.id})`);
587
- console.log(` Tier/role: ${envelope.tier ?? 'deterministic'}/${envelope.role ?? 'none'}`);
588
- console.log(` Wrapper: ${envelope.wrapper ?? 'none'}`);
589
- console.log(` Model: ${envelope.model?.effectiveModel ?? 'inherited or no model call'} (${envelope.model?.outcome ?? 'deterministic'})`);
590
- console.log(` Launch: ${envelope.launch.mechanism}`);
591
- console.log(` Confirmation: ${envelope.decision.requiresConfirmation ? 'required' : 'not required'}`);
592
- console.log('\n Wrapper prompt:\n');
593
- console.log(envelope.launch.prompt);
594
- }
595
- return;
596
- }
597
- const decision = routeModelTier({
598
- deterministic: args.includes('--deterministic'),
599
- routine: args.includes('--routine'),
600
- complex: args.includes('--complex'),
601
- highImpact: args.includes('--high-impact'),
602
- requestedPremium: args.includes('--premium'),
603
- unattended: args.includes('--unattended'),
604
- premiumAuthorized: args.includes('--allow-premium'),
605
- maxAutoTier: args.includes('--allow-premium') ? 3 : undefined,
606
- });
607
- console.log('\n Model policy routing');
608
- console.log(` Default stance: cheap-first role/tier intent, compiled per provider from the effective catalog.`);
609
- console.log(` Suggested tier: ${decision.tier}${decision.modelTier ? ` (${decision.modelTier})` : ' (no model call)'}`);
610
- console.log(` Confirmation: ${decision.requiresConfirmation ? 'required' : 'not required'}`);
611
- console.log(` Summary before escalation: ${decision.summaryRequired ? 'required' : 'not required'}`);
612
- console.log(` Rationale: ${decision.rationale.join('; ')}`);
613
- console.log('\n Commands:');
614
- console.log(' aiwg models sources --json # inspect effective cache/static/remote catalog provenance');
615
- console.log(' aiwg models refresh --json # refresh dynamic provider catalog where supported');
616
- console.log(' aiwg models audit --provider P # compile artifact policy and diagnostics');
617
- console.log(' aiwg models resolve --provider P # show selected provider model for matching artifacts');
618
- console.log('\n Authoring:');
619
- console.log(' Agents: use model-role/model-tier; avoid exact provider IDs in source scaffolds.');
620
- console.log(' Skills/commands: use commandHint.modelRole and commandHint.modelTier.');
621
- return;
622
- }
383
+ if (subcommand === 'models' || subcommand === 'model-routing')
384
+ return handleStewardModels(args, matrix, ctx);
623
385
  throw new AiwgError({
624
386
  code: 'ERR_USAGE_UNKNOWN_SUBCOMMAND',
625
387
  message: `Unknown steward subcommand: ${subcommand}`,
@@ -640,6 +402,10 @@ export const stewardHandler = {
640
402
  // sub-namespace help reachable, without executing anything (#2533).
641
403
  async help(ctx) {
642
404
  const positional = ctx.args.filter((arg) => !arg.startsWith('-'));
405
+ if (positional[0] === 'authorization') {
406
+ const { authorizationUsage } = await import('../../config/authorization-cli.js');
407
+ return { exitCode: 0, message: authorizationUsage, rawOutput: true };
408
+ }
643
409
  if (positional[0] === 'permissions') {
644
410
  return { exitCode: 0, message: permissionsUsage(), rawOutput: true };
645
411
  }
@@ -0,0 +1,61 @@
1
+ // Count bundle artifacts from native files and activation-selected rule receipts.
2
+ import { promises as fs } from 'node:fs';
3
+ import path from 'node:path';
4
+ export async function countDeployedBundleRules(bundlePath, target, deployPath) {
5
+ if (!deployPath)
6
+ return 0;
7
+ const destination = path.resolve(target, deployPath);
8
+ let selected = [];
9
+ try {
10
+ const receipt = JSON.parse(await fs.readFile(path.join(destination, '.aiwg-manifest.json'), 'utf8'));
11
+ selected = Array.isArray(receipt.ruleSources) ? receipt.ruleSources : [];
12
+ }
13
+ catch { /* Legacy deployments have only native files. */ }
14
+ let sources;
15
+ try {
16
+ sources = (await fs.readdir(path.join(bundlePath, 'rules'))).filter(name => name.endsWith('.md'));
17
+ }
18
+ catch {
19
+ return 0;
20
+ }
21
+ let count = 0;
22
+ for (const name of sources) {
23
+ if (selected.includes(path.resolve(bundlePath, 'rules', name))) {
24
+ count++;
25
+ continue;
26
+ }
27
+ for (const extension of ['.md', '.mdc']) {
28
+ try {
29
+ await fs.access(path.join(destination, path.basename(name, '.md') + extension));
30
+ count++;
31
+ break;
32
+ }
33
+ catch { /* A catalog-only, unselected rule is not deployed. */ }
34
+ }
35
+ }
36
+ return count;
37
+ }
38
+ export async function countDeployedBundleFiles(bundlePath, subdir, target, deployPath, extensions) {
39
+ if (!deployPath)
40
+ return 0;
41
+ let names;
42
+ try {
43
+ names = (await fs.readdir(path.join(bundlePath, subdir))).filter(name => name.endsWith('.md'));
44
+ }
45
+ catch {
46
+ return 0;
47
+ }
48
+ let count = 0;
49
+ for (const name of names) {
50
+ for (const extension of extensions) {
51
+ try {
52
+ await fs.access(path.join(path.resolve(target, deployPath), path.basename(name, '.md') + extension));
53
+ count++;
54
+ break;
55
+ }
56
+ catch { /* Only count artifacts actually written by this bundle. */ }
57
+ }
58
+ }
59
+ return count;
60
+ }
61
+ //# sourceMappingURL=use-bundle-counts.js.map
@@ -64,6 +64,7 @@ const PREPARABLE_BUILTIN_PROVIDERS = new Set(['claude', 'codex', 'cursor', 'herm
64
64
  // Distinct from agentsmith (which creates subagent personas).
65
65
  import { generate as generateContextFiles, discoverDeployedArtifacts, } from '../../smiths/context-pipeline/index.js';
66
66
  import { verifyModelWrapperDeployment } from '../../models/wrapper-deployment.js';
67
+ import { countDeployedBundleFiles, countDeployedBundleRules } from './use-bundle-counts.js';
67
68
  import { aggregateUseDeploymentResult, buildDryRunUseResult, renderUseDeploymentResult, verifyProviderDeployment, } from '../services/deployment-verification.js';
68
69
  import { finalizeProviderTransformationReceipt, providerReceiptHasLocalSources, sourceVerificationsFromSignedWebRelease, } from '../../providers/transformation-receipt-integration.js';
69
70
  import { loadResourceTrustRootFile, resolveWebRelease, } from '../../resources/web-release.js';
@@ -1028,24 +1029,6 @@ async function listBundleMdStems(bundlePath, subdir) {
1028
1029
  return [];
1029
1030
  }
1030
1031
  }
1031
- async function countDeployedBundleFiles(bundlePath, subdir, target, deployPath, extensions) {
1032
- if (!deployPath)
1033
- return 0;
1034
- const stems = await listBundleMdStems(bundlePath, subdir);
1035
- if (stems.length === 0)
1036
- return 0;
1037
- const destDir = resolveDeployPath(target, deployPath);
1038
- let count = 0;
1039
- for (const stem of stems) {
1040
- for (const ext of extensions) {
1041
- if (await fileExists(path.join(destDir, `${stem}${ext}`))) {
1042
- count++;
1043
- break;
1044
- }
1045
- }
1046
- }
1047
- return count;
1048
- }
1049
1032
  async function listBundleSkillNameCandidates(bundlePath) {
1050
1033
  const skillsRoot = path.join(bundlePath, 'skills');
1051
1034
  try {
@@ -1107,7 +1090,7 @@ async function countBundleDeployedArtifacts(bundlePath, target, provider) {
1107
1090
  agents: await countDeployedBundleFiles(bundlePath, 'agents', target, paths.agents, ['.md', '.toml']),
1108
1091
  commands: await countDeployedBundleFiles(bundlePath, 'commands', target, paths.commands, ['.md']),
1109
1092
  skills: await countDeployedBundleSkills(bundlePath, target, provider),
1110
- rules: await countDeployedBundleFiles(bundlePath, 'rules', target, paths.rules, ['.md', '.mdc']),
1093
+ rules: await countDeployedBundleRules(bundlePath, target, paths.rules),
1111
1094
  };
1112
1095
  }
1113
1096
  const SKILL_SUPPORT_REFERENCE = /(?:^|[\s`('"\[])((?:templates|references|scripts|assets)\/[A-Za-z0-9._@/+\-]+)(?=$|[\s`)'"\],:;])/gm;
@@ -3521,11 +3504,10 @@ export class UseHandler {
3521
3504
  try {
3522
3505
  const manifestPath = path.join(addonSource, 'manifest.json');
3523
3506
  const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
3524
- // Provider rule aggregation may rename many source rules into one
3525
- // managed index. Record this addon's contributed artifact counts,
3526
- // matching framework registry semantics, rather than trying to
3527
- // attribute shared aggregate filenames after deployment.
3528
- const counts = await countBundleSourceArtifacts(addonSource);
3507
+ // Record only artifacts actually written for this provider. Bridge-only
3508
+ // providers (e.g. project-scope grokbot) write zero native files,
3509
+ // so source-manifest counts would leave phantom registry entries.
3510
+ const counts = await countBundleDeployedArtifacts(addonSource, target, provider);
3529
3511
  const updated = updateInstalled(config, framework, provider, counts, {
3530
3512
  version: manifest.version ?? (await getVersionInfo()).version,
3531
3513
  source: 'bundled',
@@ -13,6 +13,7 @@ import fs from 'fs';
13
13
  import fsp from 'fs/promises';
14
14
  import path from 'path';
15
15
  import { createScriptRunner } from './script-runner.js';
16
+ import { DOCTOR_HELP } from './doctor-help.js';
16
17
  import { getFrameworkRoot } from '../../channel/manager.mjs';
17
18
  import { updateInstallation } from '../../update/service.mjs';
18
19
  import { useHandler as useFrameworkHandler } from './use.js';
@@ -494,30 +495,6 @@ async function runUserScopeDoctor(verbose) {
494
495
  message: lines.join('\n') + '\n',
495
496
  };
496
497
  }
497
- const DOCTOR_HELP = `aiwg doctor — check AIWG installation health
498
-
499
- Usage:
500
- aiwg doctor [options]
501
- aiwg -doctor [options]
502
- aiwg --doctor [options]
503
-
504
- Options:
505
- --deployment Verify configured provider deployments
506
- --provider <name> Limit deployment verification to one provider
507
- --bundle <name> Limit deployment verification to one bundle
508
- --scope <scope> Verification scope: project or user
509
- --user Alias for --scope user
510
- --qualify With --probe-workers, record installation and configured model/role approval
511
- --yes Confirm worker qualification without a terminal
512
- --dry-run With --probe-workers, preview qualification without writes
513
- --cli NAME Limit worker probes/qualification to one configured CLI
514
- --decision-offload Show offline advisory decision readiness and adoption report
515
- --probe-workers Run bounded worker CLI version probes (default: config-only, no subprocess)
516
- --project-local Include project-local artifact diagnostics
517
- --json Emit machine-readable output (with --probe-workers: one worker-probe record per CLI; with --deployment: deployment verification; with --decision-offload: offline snapshot)
518
- --verbose, -v Include verbose diagnostics
519
- --help, -h Show this help
520
- `;
521
498
  /**
522
499
  * Handler for doctor command
523
500
  *