@aiwg/cli 2026.10.3 → 2026.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/agentic/code/providers/model-capabilities.v1.json +96 -4
- package/bin/aiwg.mjs +50 -27
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +69 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +286 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +130 -0
- package/dist/src/artifacts/index-refresh.js +591 -0
- package/dist/src/artifacts/index-worker.mjs +11 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +19 -2
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +19 -12
- package/dist/src/cli/handlers/diagnose.js +4 -3
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +4 -1
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/models.js +104 -8
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/refresh.js +12 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +1 -2
- package/dist/src/cli/handlers/script-runner.js +3 -2
- package/dist/src/cli/handlers/session.js +19 -9
- package/dist/src/cli/handlers/sessions.js +137 -43
- package/dist/src/cli/handlers/setup-manifest.js +39 -44
- package/dist/src/cli/handlers/setup.js +41 -0
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +57 -2
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +294 -55
- package/dist/src/cli/handlers/utilities.js +26 -10
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +87 -37
- package/dist/src/config/cli.js +111 -5
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +2 -1
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +13 -8
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +2 -15
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +5 -13
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +131 -28
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/gates/providers/loader.js +61 -17
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +14 -2
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +78 -3
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +7 -1
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +36 -11
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +1 -1
- package/dist/src/mcp/helpers.mjs +3 -2
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/registry.js +3 -93
- package/dist/src/mcp/registry.mjs +3 -87
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +37 -375
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tools/decision.mjs +12 -11
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +12 -2
- package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
- package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
- package/dist/src/mission-protocol/codecs.js +8 -0
- package/dist/src/models/config-loader.js +7 -2
- package/dist/src/models/model-capabilities.v1.json +96 -4
- package/dist/src/models/model-discovery.js +76 -11
- package/dist/src/models/provider-policy.js +101 -7
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/resolver.js +12 -10
- package/dist/src/models/worker-direct-readiness.js +65 -44
- package/dist/src/models/worker-dispatch-offer.js +3 -3
- package/dist/src/models/worker-health-readiness.js +16 -3
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +135 -28
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +43 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +12 -4
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/mission-conductor.js +38 -12
- package/dist/src/serve/worker-invocation.js +30 -10
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/sessions/adapter-registry.js +23 -19
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +95 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +10 -10
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot.js +24 -13
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
- package/dist/src/sessions/adapters/muse.js +150 -93
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +29 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +16 -8
- package/dist/src/sessions/batch-import.js +252 -12
- package/dist/src/sessions/contracts.js +50 -3
- package/dist/src/sessions/coverage-preflight.js +27 -2
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +60 -38
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +145 -26
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +105 -0
- package/dist/src/sessions/repository.js +151 -54
- package/dist/src/sessions/workspace-discovery.js +292 -60
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/package.json +15 -2
- package/schemas/models/model-catalog.v1.schema.json +1 -1
- package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
- package/tools/_resolve-impl.mjs +13 -15
- package/tools/agents/deploy-agents.mjs +49 -21
- package/tools/agents/providers/base.mjs +104 -134
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/hermes.mjs +57 -47
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +6 -4
- package/tools/providers/omp-transport.mjs +4 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
- package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
- package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ATTRIBUTION_FIELD_PATTERN,
|
|
1
|
+
import { ATTRIBUTION_FIELD_PATTERN, DecisionAskUsageError, decisionCapabilities, DecisionLedgerSinceError, decisionLedgerHistory, decisionLedgerStats, evaluateRequestPath, listPatterns, livePlan, MAX_ATTRIBUTION_FIELD_LENGTH, materializeSyntheticClassificationSetup, parseDecisionLedgerSince, readDecisionContextFile, runDecisionOffloadCheckpoint, runOfflinePattern, setupJev, showPattern, syntheticClassificationSetup, validateDecisionInput, } from '../../decision/driver.js';
|
|
2
2
|
function jsonResult(value, exitCode = 0) {
|
|
3
3
|
return { exitCode, message: JSON.stringify(value, null, 2), rawOutput: true };
|
|
4
4
|
}
|
|
5
5
|
function usage() {
|
|
6
6
|
return [
|
|
7
7
|
'Usage: aiwg decision <capabilities|status|patterns|validate|evaluate|setup|history|stats> [options]',
|
|
8
|
-
' aiwg decision ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--context <text> | --context-file <path> | --context-stdin] [--threshold 0.8] [--timeout-ms 15000] [--provider <id>] [--session <id>] [--caller <tag>] [--record-text] [--json]',
|
|
8
|
+
' aiwg decision ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--context <text> | --context-file <path> | --context-stdin] [--threshold 0.8] [--timeout-ms 15000] [--passes N] [--escalation-passes N] [--provider <id>] [--session <id>] [--caller <tag>] [--record-text] [--json]',
|
|
9
9
|
'',
|
|
10
10
|
'Commands:',
|
|
11
11
|
' capabilities|status Show offline readiness, primitives, config and feature availability',
|
|
@@ -19,7 +19,7 @@ function usage() {
|
|
|
19
19
|
' setup jev [--token-stdin] [--region <r>] [--endpoint <url>] [--verify] [--remove]',
|
|
20
20
|
' ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--provider <id>] [--session <id>] [--caller <tag>] [--record-text]',
|
|
21
21
|
' history [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--json]',
|
|
22
|
-
' stats [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--group-by provider|session|kind|caller] [--json]',
|
|
22
|
+
' stats [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--group-by provider|session|kind|caller|passes|escalation] [--json]',
|
|
23
23
|
'',
|
|
24
24
|
'Notes:',
|
|
25
25
|
' Every COMPLETED `ask` call (CLI and MCP) appends one record to the decision',
|
|
@@ -139,22 +139,25 @@ async function decisionAsk(ctx) {
|
|
|
139
139
|
: choices !== undefined ? { kind: 'choices', choices: choices.split(',').map(value => value.trim()).filter(Boolean) }
|
|
140
140
|
: { kind: 'scale', ...scale },
|
|
141
141
|
...(context === undefined ? {} : { context }),
|
|
142
|
+
...(args.includes('--passes') ? { passes: parseNumber(takeRequiredOption(args, '--passes'), '--passes') } : {}),
|
|
143
|
+
...(args.includes('--escalation-passes') ? { escalationPasses: parseNumber(takeRequiredOption(args, '--escalation-passes'), '--escalation-passes') } : {}),
|
|
142
144
|
...(args.includes('--threshold') ? { threshold: parseNumber(takeOption(args, '--threshold'), '--threshold') } : {}),
|
|
143
145
|
...(args.includes('--timeout-ms') ? { timeoutMs: parseNumber(takeOption(args, '--timeout-ms'), '--timeout-ms') } : {}),
|
|
144
146
|
};
|
|
145
|
-
const
|
|
146
|
-
// Best-effort and bounded (recordDecisionAsk never throws and never hangs past its own
|
|
147
|
-
// deadline): a ledger failure, timeout, or attribution-detection error can never change
|
|
148
|
-
// `result` or the exit code decided below (review r1 findings 3 and 4).
|
|
149
|
-
await recordDecisionAsk(input, result, {
|
|
147
|
+
const invocation = await runDecisionOffloadCheckpoint(input, {
|
|
150
148
|
transport: 'cli',
|
|
151
149
|
projectRoot: ctx.cwd,
|
|
152
150
|
env: process.env,
|
|
153
151
|
explicitProvider: takeOption(args, '--provider'),
|
|
154
152
|
explicitSessionId,
|
|
155
|
-
caller: caller ??
|
|
153
|
+
caller: caller ?? 'decision-cli:ask',
|
|
154
|
+
ledgerCaller: caller ?? null,
|
|
155
|
+
category: caller ? undefined : 'unattributed',
|
|
156
156
|
recordText: args.includes('--record-text'),
|
|
157
157
|
});
|
|
158
|
+
if (!invocation.result)
|
|
159
|
+
throw invocation.outcome === 'unknown' ? invocation.error : new Error('Decision ask was skipped');
|
|
160
|
+
const result = invocation.result;
|
|
158
161
|
if (args.includes('--json'))
|
|
159
162
|
return jsonResult(result);
|
|
160
163
|
if (result.status === 'fallback')
|
|
@@ -175,7 +178,7 @@ function parseSince(value) {
|
|
|
175
178
|
}
|
|
176
179
|
const DECISION_LEDGER_KINDS = ['yes-no', 'choices', 'scale'];
|
|
177
180
|
const DECISION_LEDGER_STATUSES = ['answered', 'fallback'];
|
|
178
|
-
const DECISION_LEDGER_GROUP_BYS = ['provider', 'session', 'kind', 'caller'];
|
|
181
|
+
const DECISION_LEDGER_GROUP_BYS = ['provider', 'session', 'kind', 'caller', 'passes', 'escalation'];
|
|
179
182
|
function parseKindFilter(value) {
|
|
180
183
|
if (value === undefined)
|
|
181
184
|
return undefined;
|
|
@@ -305,10 +308,14 @@ async function decisionStats(ctx) {
|
|
|
305
308
|
if (result.groups.length === 0)
|
|
306
309
|
return { exitCode: 0, message: [...header, 'No decision ledger records match the filters.'].join('\n'), rawOutput: true };
|
|
307
310
|
const lines = result.groups.flatMap(group => [
|
|
308
|
-
`${result.groupBy ?? 'all'}=${group.key ?? 'null'}: ${group.totalCalls} calls (${group.answered} answered, ${group.fallback} fallback, rate=${group.fallbackRate.toFixed(2)})`,
|
|
311
|
+
`${result.groupBy ?? 'all'}=${group.key ?? 'null'}: ${group.totalCalls} calls (${group.answered} answered, ${group.fallback} fallback, hit rate=${group.hitRate.toFixed(2)}, fallback rate=${group.fallbackRate.toFixed(2)})`,
|
|
309
312
|
` confidence: mean=${group.confidence.mean?.toFixed(2) ?? '-'} min=${group.confidence.min?.toFixed(2) ?? '-'} max=${group.confidence.max?.toFixed(2) ?? '-'} (n=${group.confidence.count})`,
|
|
313
|
+
` agreement: mean=${group.agreement.mean?.toFixed(2) ?? '-'} escalated=${group.escalatedCalls} passes run=${group.passesRun}`,
|
|
310
314
|
` jev usage: input=${group.jevUsage.inputTokens} output=${group.jevUsage.outputTokens}`,
|
|
311
|
-
`
|
|
315
|
+
` tokens per answered decision=${group.tokensPerAnsweredDecision?.toFixed(2) ?? '-'}`,
|
|
316
|
+
` llm_tokens_avoided=${group.llm_tokens_avoided} jev_tokens=${group.jev_tokens} cost_weighted_net_usd=${group.cost_weighted_net_usd.toFixed(6)}`,
|
|
317
|
+
` v1 comparison only: estimated LLM tokens avoided=${group.estimatedLlmTokensAvoidedTotal} net savings=${group.netSavingsTokens}`,
|
|
318
|
+
...(group.legacyReestimatedCalls ? [` v1 records re-estimated=${group.legacyReestimatedCalls} weights=${JSON.stringify(result.legacyEstimationWeights)}`] : []),
|
|
312
319
|
]);
|
|
313
320
|
return { exitCode: 0, message: [...header, ...lines].join('\n'), rawOutput: true };
|
|
314
321
|
}
|
|
@@ -207,9 +207,9 @@ function redactSecretsInObject(obj) {
|
|
|
207
207
|
}
|
|
208
208
|
function collectGitInfo(cwd) {
|
|
209
209
|
try {
|
|
210
|
-
const branch = spawnSync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { stdio: 'pipe', timeout: 5000 });
|
|
211
|
-
const log = spawnSync('git', ['-C', cwd, 'log', '-10', '--oneline'], { stdio: 'pipe', timeout: 5000 });
|
|
212
|
-
const remote = spawnSync('git', ['-C', cwd, 'remote', '-v'], { stdio: 'pipe', timeout: 5000 });
|
|
210
|
+
const branch = spawnSync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { stdio: 'pipe', timeout: 5000, killSignal: 'SIGKILL' });
|
|
211
|
+
const log = spawnSync('git', ['-C', cwd, 'log', '-10', '--oneline'], { stdio: 'pipe', timeout: 5000, killSignal: 'SIGKILL' });
|
|
212
|
+
const remote = spawnSync('git', ['-C', cwd, 'remote', '-v'], { stdio: 'pipe', timeout: 5000, killSignal: 'SIGKILL' });
|
|
213
213
|
if (branch.status !== 0)
|
|
214
214
|
return null;
|
|
215
215
|
return [
|
|
@@ -232,6 +232,7 @@ function collectDoctorOutput() {
|
|
|
232
232
|
stdio: 'pipe',
|
|
233
233
|
timeout: 30_000,
|
|
234
234
|
env: { ...process.env, AIWG_LOG_DISABLE: '1', NO_COLOR: '1' },
|
|
235
|
+
killSignal: 'SIGKILL',
|
|
235
236
|
});
|
|
236
237
|
const out = r.stdout?.toString() ?? '';
|
|
237
238
|
const err = r.stderr?.toString() ?? '';
|
|
@@ -243,7 +243,7 @@ function openLedger(session, registry) {
|
|
|
243
243
|
* `kinds`, `record`, `reconcile` and `probe` all use it, so `kinds` lists
|
|
244
244
|
* exactly what the registry contains. Tracker authority is resolved lazily at
|
|
245
245
|
* verification time, so a project without tracker configuration still lists
|
|
246
|
-
* the tracker kinds and answers `unknown`
|
|
246
|
+
* the tracker kinds and answers `unknown` with a tracker precondition reason.
|
|
247
247
|
*/
|
|
248
248
|
export function buildCliVerifierRegistry(projectRoot, extensions = [], tracker = { config: null, remoteUrls: {} }) {
|
|
249
249
|
const injected = new Set(extensions.map(verifier => verifier.kind));
|
|
@@ -425,7 +425,9 @@ function expectationsFrom(parsed) {
|
|
|
425
425
|
return { expected, ...(timeoutMs !== undefined ? { timeoutMs } : {}), ...(verifierVersion ? { verifierVersion } : {}) };
|
|
426
426
|
}
|
|
427
427
|
function emit(rendered, format) {
|
|
428
|
-
const
|
|
428
|
+
const evidence = rendered.output.evidence;
|
|
429
|
+
const hint = typeof evidence?.hint === 'string' ? `\n${evidence.hint}` : '';
|
|
430
|
+
const message = format === 'text' ? rendered.text + hint : effectOutputJson(rendered.output);
|
|
429
431
|
return { exitCode: rendered.output.exitCode, message, rawOutput: true };
|
|
430
432
|
}
|
|
431
433
|
function errorOutput(error) {
|
|
@@ -28,6 +28,9 @@ function usage() {
|
|
|
28
28
|
}
|
|
29
29
|
export const evidenceHandler = {
|
|
30
30
|
id: 'evidence', name: 'Evidence', description: 'Export and verify portable evaluation evidence bundles', category: 'utility', aliases: [],
|
|
31
|
+
async help() {
|
|
32
|
+
return { exitCode: 0, message: usage(), rawOutput: true };
|
|
33
|
+
},
|
|
31
34
|
async execute(ctx) {
|
|
32
35
|
const [subcommand] = ctx.args;
|
|
33
36
|
if (!subcommand || subcommand === '--help' || subcommand === '-h')
|
|
@@ -92,6 +92,7 @@ function displayHelp() {
|
|
|
92
92
|
['show <type> <name>', 'Stream the body of an indexed artifact'],
|
|
93
93
|
['versions <list|resolve|show>', 'Browse and resolve signed AIWG web resource releases'],
|
|
94
94
|
['auth <login|status|logout>', 'Authenticate for paid AIWG web resources'],
|
|
95
|
+
['corpus <subcommand>', 'Research corpus tools (snapshot, radar, profiles, curator)'],
|
|
95
96
|
['index <subcommand>', 'Manage the artifact index (build/query/discover/deps/stats)'],
|
|
96
97
|
['artifacts move --to <path>', 'Move/rename the project AIWG artifact root and reindex'],
|
|
97
98
|
]);
|
|
@@ -73,6 +73,7 @@ import { installationHandler } from './installation.js';
|
|
|
73
73
|
import { uhpHandler } from './uhp.js';
|
|
74
74
|
import { schemaHandler } from './schema.js';
|
|
75
75
|
import { datasetHandler } from './dataset.js';
|
|
76
|
+
import { rulesHandler } from './rules.js';
|
|
76
77
|
import { decisionHandler } from './decision.js';
|
|
77
78
|
import { gatesHandler } from './gates.js';
|
|
78
79
|
// Re-export individual handlers
|
|
@@ -80,7 +81,7 @@ export {
|
|
|
80
81
|
// Maintenance
|
|
81
82
|
helpHandler, versionHandler, authHandler, doctorHandler, contextFirewallHandler, updateHandler, refreshHandler, regenerateHandler, workspaceContextHandler,
|
|
82
83
|
// Framework management
|
|
83
|
-
useHandler, listHandler, removeHandler, promoteHandler, installHandler, packagesHandler, marketplaceHandler, initHandler, setupHandler, setupGenerateHandler, setupRunHandler, setupValidateHandler, issueHandler, issueAuditHandler, runHandler, jobHandler, costReportHandler, evidenceHandler, artifactVerifyHandler, outputModeHandler, writerProfileHandler, botHandoffHandler, buildVerifyHandler, writingHandler, schemaHandler, datasetHandler, decisionHandler, gatesHandler, installationHandler,
|
|
84
|
+
useHandler, listHandler, removeHandler, promoteHandler, installHandler, packagesHandler, marketplaceHandler, initHandler, setupHandler, setupGenerateHandler, setupRunHandler, setupValidateHandler, issueHandler, issueAuditHandler, runHandler, jobHandler, costReportHandler, evidenceHandler, artifactVerifyHandler, outputModeHandler, writerProfileHandler, botHandoffHandler, buildVerifyHandler, writingHandler, schemaHandler, datasetHandler, decisionHandler, rulesHandler, gatesHandler, installationHandler,
|
|
84
85
|
// Project
|
|
85
86
|
newBundleHandler, quickrefHandler, newProjectHandler, sessionHandler, sessionsHandler,
|
|
86
87
|
// Workspace
|
|
@@ -172,6 +173,7 @@ export const allHandlers = [
|
|
|
172
173
|
schemaHandler,
|
|
173
174
|
datasetHandler,
|
|
174
175
|
decisionHandler,
|
|
176
|
+
rulesHandler,
|
|
175
177
|
gatesHandler,
|
|
176
178
|
// Workspace management
|
|
177
179
|
...workspaceHandlers,
|
|
@@ -245,7 +245,7 @@ export const initHandler = {
|
|
|
245
245
|
}
|
|
246
246
|
else if (workerDispatchArg === 'enable') {
|
|
247
247
|
await writeAiwgConfig(projectDir, { ...existing, parallelism: { ...existing.parallelism, worker_dispatch: true } });
|
|
248
|
-
ui.success(' Enabled parallelism.worker_dispatch.');
|
|
248
|
+
ui.success(' Enabled parallelism.worker_dispatch. Next: aiwg doctor --probe-workers --qualify.');
|
|
249
249
|
}
|
|
250
250
|
else {
|
|
251
251
|
await writeAiwgConfig(projectDir, { ...existing, setup: { ...existing.setup, worker_dispatch_offer: 'declined' } });
|
|
@@ -261,6 +261,7 @@ export const initHandler = {
|
|
|
261
261
|
const decision = await askWorkerDispatchOffer(rl, existing.parallelism, existing.setup, ctx.signal);
|
|
262
262
|
if (decision?.kind === 'enable') {
|
|
263
263
|
await writeAiwgConfig(projectDir, { ...existing, parallelism: { ...existing.parallelism, worker_dispatch: true } });
|
|
264
|
+
ui.info('Next: aiwg doctor --probe-workers --qualify.');
|
|
264
265
|
}
|
|
265
266
|
else if (decision?.kind === 'decline') {
|
|
266
267
|
await writeAiwgConfig(projectDir, { ...existing, setup: { ...existing.setup, worker_dispatch_offer: 'declined' } });
|
|
@@ -379,6 +380,8 @@ export const initHandler = {
|
|
|
379
380
|
config = await populateDeployedTo(config, projectDir);
|
|
380
381
|
// Write
|
|
381
382
|
await writeAiwgConfig(projectDir, config);
|
|
383
|
+
if (workerDispatchDecision?.kind === 'enable')
|
|
384
|
+
ui.info('Next: aiwg doctor --probe-workers --qualify.');
|
|
382
385
|
const normalizedAiwgMdPath = await writeNormalizedAiwgMd(projectDir);
|
|
383
386
|
const workspace = await ensureWorkspaceContext(projectDir);
|
|
384
387
|
ui.blank();
|
|
@@ -25,6 +25,11 @@ export const lintHandler = {
|
|
|
25
25
|
description: 'Lint AIWG artifacts against declarative rule sets',
|
|
26
26
|
category: 'utility',
|
|
27
27
|
aliases: ['-lint', '--lint'],
|
|
28
|
+
async help() {
|
|
29
|
+
const { main } = await import('../../lint/cli.js');
|
|
30
|
+
await main(['--help']);
|
|
31
|
+
return { exitCode: 0 };
|
|
32
|
+
},
|
|
28
33
|
async execute(ctx) {
|
|
29
34
|
try {
|
|
30
35
|
const { main } = await import('../../lint/cli.js');
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { promises as fs } from 'node:fs';
|
|
6
6
|
import os from 'node:os';
|
|
7
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
7
8
|
import path from 'node:path';
|
|
8
9
|
import { glob } from 'glob';
|
|
9
10
|
import { load as loadYaml } from 'js-yaml';
|
|
@@ -11,8 +12,16 @@ import { compileModelPolicy, validateCanonicalModelPolicy, validateUserProjectMo
|
|
|
11
12
|
import { resolveGrokBuildRoleModel } from '../../models/grok-build-models.js';
|
|
12
13
|
import { readAiwgConfig, emptyConfig } from '../../config/aiwg-config.js';
|
|
13
14
|
import { ConfigLoader } from '../../models/config-loader.js';
|
|
14
|
-
import { loadRecordedWorkerInstallations } from '../../models/worker-installation.mjs';
|
|
15
|
+
import { loadRecordedWorkerInstallations, normalizeWorkerVersionBanner } from '../../models/worker-installation.mjs';
|
|
15
16
|
import { parseWorkerCommandArgs, resolveWorkerInvocation, workerInvocationDiagnostic } from '../../serve/worker-invocation.js';
|
|
17
|
+
/** Compare selection facts without observation times or approval/provenance metadata. */
|
|
18
|
+
function approvalFacts(row) {
|
|
19
|
+
if (!row.worker)
|
|
20
|
+
return null;
|
|
21
|
+
const { observedAt, verifiedAt, firstObservedAt, fetchedAt, retiredAt, evidenceDigest, provenance, qualification, ...facts } = row.worker;
|
|
22
|
+
return { id: row.id, apiModelId: row.apiModelId, llmProvider: row.llmProvider,
|
|
23
|
+
hidden: row.hidden, reasoningEfforts: row.reasoningEfforts, facts };
|
|
24
|
+
}
|
|
16
25
|
/**
|
|
17
26
|
* #2892: exported so the MCP worker-invoke bridge can resolve a direct worker
|
|
18
27
|
* plan in-process (same snapshot/driver construction as `aiwg models resolve`),
|
|
@@ -30,9 +39,48 @@ export async function loadWorkerInputs(ctx) {
|
|
|
30
39
|
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
31
40
|
registry, installations: {} }, drivers: {} };
|
|
32
41
|
}
|
|
33
|
-
const { registry: qualifiedRegistry, installations, drivers } = await loadRecordedWorkerInstallations({
|
|
34
|
-
registry, cwd: ctx.cwd, policy: models.defaults.workerSelection,
|
|
42
|
+
const { registry: qualifiedRegistry, installations, drivers, observations } = await loadRecordedWorkerInstallations({
|
|
43
|
+
registry, cwd: ctx.cwd, policy: models.defaults.workerSelection, parallelism: config.parallelism,
|
|
35
44
|
});
|
|
45
|
+
catalog.discovery ??= { source: 'static', fetchedAt: new Date().toISOString(), providers: {} };
|
|
46
|
+
catalog.discovery.instances = { ...catalog.discovery.instances };
|
|
47
|
+
for (const [cli, approved] of Object.entries(observations)) {
|
|
48
|
+
const cached = catalog.discovery.instances[cli] ?? catalog.discovery.providers[approved.provider];
|
|
49
|
+
// Discovery stores the CLI banner; qualification stores its parsed version.
|
|
50
|
+
const invocation = drivers[cli]?.qualification.adapter.invocation;
|
|
51
|
+
const versionPattern = invocation?.kind === 'process' ? invocation.versionPattern : undefined;
|
|
52
|
+
const version = (value) => {
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
return value;
|
|
55
|
+
try {
|
|
56
|
+
return normalizeWorkerVersionBanner(value, versionPattern);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return value;
|
|
60
|
+
} // A changed or invalid banner must still fail closed.
|
|
61
|
+
};
|
|
62
|
+
const current = cached ? { ...cached, runtimeVersion: version(cached.runtimeVersion),
|
|
63
|
+
accountBinding: cached.accountBinding ?? cached.accountScope,
|
|
64
|
+
models: cached.models.map(row => row.worker ? { ...row,
|
|
65
|
+
worker: { ...row.worker, runtimeVersion: version(row.worker.runtimeVersion) } } : row) } : undefined;
|
|
66
|
+
// Stale discovery must not replace a newer approved observation.
|
|
67
|
+
if (!current || Date.parse(approved.observedAt) > Date.parse(current.observedAt)) {
|
|
68
|
+
catalog.discovery.instances[cli] = approved;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
catalog.discovery.instances[cli] = { ...current, models: current.models.map(row => {
|
|
72
|
+
const prior = approved.models.find(model => model.id === row.id);
|
|
73
|
+
if (!row.worker || !prior?.worker)
|
|
74
|
+
return row;
|
|
75
|
+
if (Date.parse(prior.worker.observedAt) > Date.parse(row.worker.observedAt))
|
|
76
|
+
return prior;
|
|
77
|
+
// New retirement/conflict/visibility evidence always requires requalification.
|
|
78
|
+
const safe = !row.hidden && row.worker.visibility !== 'hidden'
|
|
79
|
+
&& row.worker.lifecycle !== 'retired' && !row.worker.conflicts?.length;
|
|
80
|
+
return safe && isDeepStrictEqual(approvalFacts(row), approvalFacts(prior))
|
|
81
|
+
? { ...row, worker: { ...row.worker, qualification: prior.worker.qualification } } : row;
|
|
82
|
+
}) };
|
|
83
|
+
}
|
|
36
84
|
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
37
85
|
registry: qualifiedRegistry, installations }, drivers };
|
|
38
86
|
}
|
|
@@ -272,9 +320,60 @@ function replaceFrontmatter(raw, item, tier) {
|
|
|
272
320
|
}
|
|
273
321
|
return `---\n${frontmatter}\n---\n${match[2]}`;
|
|
274
322
|
}
|
|
323
|
+
const MODELS_HELP = `Usage: aiwg models <subcommand> [options]
|
|
324
|
+
|
|
325
|
+
Subcommands:
|
|
326
|
+
list List discovered agent and skill model policies
|
|
327
|
+
audit Compile selected policies and report diagnostics
|
|
328
|
+
resolve Resolve artifact policies, or a direct worker invocation
|
|
329
|
+
validate Validate selected artifact policies (not worker configuration)
|
|
330
|
+
sources Show the effective model catalog without network refresh
|
|
331
|
+
refresh Refresh model discovery (may access the network)
|
|
332
|
+
set-default <TIER> Write defaults.tier to models.json
|
|
333
|
+
set --tier <TIER> Update selected agent/skill frontmatter; requires a selector or --all
|
|
334
|
+
migrate Add canonical role/tier hints to legacy skills
|
|
335
|
+
|
|
336
|
+
Artifact selectors and options:
|
|
337
|
+
--agent <name> --skill <name> --glob <pattern> --role <role>
|
|
338
|
+
--tier <tier> --framework <name> --all
|
|
339
|
+
--provider <provider> Provider for artifact compilation (default: claude)
|
|
340
|
+
--model <id> Explicit Grok Build model for artifact resolve
|
|
341
|
+
--target <directory> Artifact/project root (default: current directory)
|
|
342
|
+
--scope project|user set-default destination (default: project)
|
|
343
|
+
--dry-run Preview mutations without writing
|
|
344
|
+
--json Emit JSON
|
|
345
|
+
--drift Include catalog drift for sources/refresh
|
|
346
|
+
--url <url> Remote catalog URL for refresh
|
|
347
|
+
--help, -h Show this reference
|
|
348
|
+
TIER: economy | standard | premium | max-quality
|
|
349
|
+
|
|
350
|
+
Direct worker resolution (plans an invocation; does not launch it):
|
|
351
|
+
aiwg models resolve --role <role> --task <class> --group <group>
|
|
352
|
+
--brief <file> --workdir <tree> --final-output <file>
|
|
353
|
+
[--transport shell|mcp] [--format json|shell] [--authorize-premium]
|
|
354
|
+
--role efficiency | coding | reasoning
|
|
355
|
+
--task Task class from defaults.workerSelection.taskClasses
|
|
356
|
+
Built-ins: inventory, implementation, architecture, review
|
|
357
|
+
--group Group from parallelism.groups and the role's guidance
|
|
358
|
+
--brief Absolute path to the task brief
|
|
359
|
+
--workdir Absolute path to the worker tree
|
|
360
|
+
--final-output Absolute path for the final result
|
|
361
|
+
--transport Must match group execution transport (default: shell)
|
|
362
|
+
--format JSON plan or POSIX shell command (default: json)
|
|
363
|
+
--json Alias for --format json
|
|
364
|
+
--authorize-premium Authorize premium for this resolution only
|
|
365
|
+
Agents require explicit human confirmation of escalation
|
|
366
|
+
|
|
367
|
+
Worker groups live in .aiwg/aiwg.config; role guidance lives in project-root models.json.
|
|
368
|
+
Configure both, then run aiwg doctor --probe-workers --qualify.
|
|
369
|
+
See docs/getting-started/worker-dispatch.md for a complete example.`;
|
|
275
370
|
async function execute(ctx, services = { load: loadWorkerInputs }) {
|
|
371
|
+
if (ctx.args.length === 0 || ctx.args[0] === 'help' || ctx.args.includes('--help') || ctx.args.includes('-h')) {
|
|
372
|
+
print(MODELS_HELP, false);
|
|
373
|
+
return { exitCode: 0 };
|
|
374
|
+
}
|
|
276
375
|
// Preserve artifact/native resolve when direct-only flags are absent.
|
|
277
|
-
if (ctx.args[0] === 'resolve' && ctx.args.slice(1).some(arg => /^--(?:task|group|brief|workdir|final-output|transport|format)(?:=|$)/.test(arg))) {
|
|
376
|
+
if (ctx.args[0] === 'resolve' && ctx.args.slice(1).some(arg => /^--(?:task|group|brief|workdir|final-output|transport|format|authorize-premium)(?:=|$)/.test(arg))) {
|
|
278
377
|
return resolveDirect(ctx, services);
|
|
279
378
|
}
|
|
280
379
|
const parsed = parseArgs(ctx.args);
|
|
@@ -290,10 +389,6 @@ async function execute(ctx, services = { load: loadWorkerInputs }) {
|
|
|
290
389
|
const provider = flagString(parsed, 'provider') ?? 'claude';
|
|
291
390
|
if (!PROVIDERS.has(provider))
|
|
292
391
|
return { exitCode: 2, message: `Unknown provider: ${provider}` };
|
|
293
|
-
if (parsed.subcommand === 'help' || parsed.flags.has('help')) {
|
|
294
|
-
print('Usage: aiwg models <audit|list|resolve|sources|refresh|set-default|set|validate|migrate> [selectors] [--provider P] [--dry-run] [--json]', json);
|
|
295
|
-
return { exitCode: 0 };
|
|
296
|
-
}
|
|
297
392
|
if (parsed.subcommand === 'sources' || parsed.subcommand === 'refresh') {
|
|
298
393
|
const { diffModelCatalog } = await import('../../models/model-discovery.js');
|
|
299
394
|
const catalog = await effectiveCatalog(ctx, target, parsed.subcommand === 'refresh', parsed, provider);
|
|
@@ -438,6 +533,7 @@ export const modelsHandler = {
|
|
|
438
533
|
description: 'Audit, resolve, validate, and safely update model policy',
|
|
439
534
|
category: 'catalog',
|
|
440
535
|
aliases: [],
|
|
536
|
+
help: async () => ({ exitCode: 0, message: MODELS_HELP, rawOutput: true }),
|
|
441
537
|
execute,
|
|
442
538
|
};
|
|
443
539
|
export function createModelsHandler(services) {
|
|
@@ -296,6 +296,8 @@ export function saveLauncherRegistry(projectRoot, registry) {
|
|
|
296
296
|
* Check if a process is still running
|
|
297
297
|
*/
|
|
298
298
|
export function isProcessAlive(pid) {
|
|
299
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
300
|
+
return false;
|
|
299
301
|
try {
|
|
300
302
|
process.kill(pid, 0);
|
|
301
303
|
return true;
|
|
@@ -572,6 +572,7 @@ export const refreshHandler = {
|
|
|
572
572
|
// #2507: give operators a reclaim path for artifacts an older
|
|
573
573
|
// AIWG left behind without a managed marker.
|
|
574
574
|
...(forceDeploy ? ['--force'] : []),
|
|
575
|
+
...(hasFlag(ctx.args, '--allow-over-budget') ? ['--allow-over-budget'] : []),
|
|
575
576
|
...modelDeployArgs,
|
|
576
577
|
],
|
|
577
578
|
rawArgs: ['use', fw],
|
|
@@ -596,6 +597,17 @@ export const refreshHandler = {
|
|
|
596
597
|
}
|
|
597
598
|
}
|
|
598
599
|
}
|
|
600
|
+
// Runtime updates can change the corpus even when there are no recorded
|
|
601
|
+
// deployments. Refresh both discovery representations, independently of use.
|
|
602
|
+
if (!dryRun) {
|
|
603
|
+
try {
|
|
604
|
+
const { refreshFrameworkCapabilities } = await import('../../artifacts/framework-capabilities.js');
|
|
605
|
+
await refreshFrameworkCapabilities(frameworkRoot, true, { force: true });
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
ui.warn(`Capability index refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
599
611
|
// Step 4.25: Report planned project-local deploys (#1035).
|
|
600
612
|
// The active use handler performs the actual project-local deploy during
|
|
601
613
|
// framework refresh; this block surfaces dry-run and completion details.
|
|
@@ -159,6 +159,9 @@ export const versionsHandler = {
|
|
|
159
159
|
description: "Browse and resolve signed AIWG web resource releases",
|
|
160
160
|
category: "index",
|
|
161
161
|
aliases: [],
|
|
162
|
+
async help() {
|
|
163
|
+
return { exitCode: 0, message: usage(), rawOutput: true };
|
|
164
|
+
},
|
|
162
165
|
async execute(ctx) {
|
|
163
166
|
if (ctx.args[0] === "help" || ctx.args[0] === "--help" || ctx.args[0] === "-h") {
|
|
164
167
|
console.log(usage());
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { loadRulePinConfigs, selectorKey, validateRulePinCapabilities } from '../../rules/pins.mjs';
|
|
4
|
+
const usage = `Usage: aiwg rules pin|unpin [rule...] [--tier critical,high] [--capability id,... | --group name] [--all-tiers] [--all]
|
|
5
|
+
aiwg rules pinned [--capability id] [--json]
|
|
6
|
+
aiwg rules inventory|list [--scope workspace|user|installation|catalog] [--capability id,...] [--activation mode,...] [--tier level,...] [--provider name] [--bodies] [--json]
|
|
7
|
+
aiwg rules group set <name> <capability>... | group list
|
|
8
|
+
Flags: --project (default), --user, --dry-run, --no-deploy, --json, --allow-over-budget
|
|
9
|
+
Pins and group changes validate every input without prompting. --dry-run prints effective rules and per-provider startup bytes.`;
|
|
10
|
+
const valueFlags = new Set(['--tier', '--capability', '--group', '--scope', '--activation', '--provider']);
|
|
11
|
+
const boolFlags = new Set(['--all-tiers', '--all', '--dry-run', '--no-deploy', '--json', '--allow-over-budget', '--user', '--project', '--help', '-h', '--bodies']);
|
|
12
|
+
function parse(args) {
|
|
13
|
+
const values = new Map();
|
|
14
|
+
const flags = new Set();
|
|
15
|
+
const positional = [];
|
|
16
|
+
for (let i = 0; i < args.length; i++) {
|
|
17
|
+
const arg = args[i];
|
|
18
|
+
if (valueFlags.has(arg)) {
|
|
19
|
+
if (!args[i + 1] || args[i + 1].startsWith('-') || values.has(arg))
|
|
20
|
+
throw new Error(`${arg} requires one value`);
|
|
21
|
+
values.set(arg, args[++i]);
|
|
22
|
+
}
|
|
23
|
+
else if (boolFlags.has(arg))
|
|
24
|
+
flags.add(arg);
|
|
25
|
+
else if (arg.startsWith('-'))
|
|
26
|
+
throw new Error(`Unknown flag: ${arg}`);
|
|
27
|
+
else
|
|
28
|
+
positional.push(arg);
|
|
29
|
+
}
|
|
30
|
+
if (flags.has('--user') && flags.has('--project'))
|
|
31
|
+
throw new Error('Choose --project or --user');
|
|
32
|
+
const list = (flag) => values.get(flag)?.split(',').map(id => id.trim());
|
|
33
|
+
return { values, flags, positional, list };
|
|
34
|
+
}
|
|
35
|
+
// Provider helpers log progress while assembling staged output. Keep the command's
|
|
36
|
+
// stdout a single JSON document (and keep temporary staging paths out of text output).
|
|
37
|
+
async function quietDeployment(deploy, options) {
|
|
38
|
+
const log = console.log;
|
|
39
|
+
const warn = console.warn;
|
|
40
|
+
try {
|
|
41
|
+
console.log = () => { };
|
|
42
|
+
console.warn = () => { };
|
|
43
|
+
return await deploy(options);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
console.log = log;
|
|
47
|
+
console.warn = warn;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export const rulesHandler = {
|
|
51
|
+
id: 'rules', name: 'Rule pins', category: 'config', aliases: [],
|
|
52
|
+
description: 'Pin rules to every request, inspect pins, and manage capability groups',
|
|
53
|
+
async help() { return { exitCode: 0, message: usage, rawOutput: true }; },
|
|
54
|
+
async execute(ctx) {
|
|
55
|
+
const json = ctx.args.includes('--json');
|
|
56
|
+
try {
|
|
57
|
+
const { values, flags, positional, list } = parse(ctx.args);
|
|
58
|
+
if (flags.has('--help') || flags.has('-h') || !positional.length)
|
|
59
|
+
return { exitCode: 0, message: usage, rawOutput: true };
|
|
60
|
+
const { rulePinState } = await import('../../rules/pin-state.js');
|
|
61
|
+
const { setRuleConfigKey } = await import('../../config/cli.js');
|
|
62
|
+
const [command, ...ids] = positional;
|
|
63
|
+
if (command === 'inventory' || command === 'list') {
|
|
64
|
+
if (ids.length || values.has('--group') || [...flags].some(flag => !['--json', '--bodies'].includes(flag)))
|
|
65
|
+
throw new Error('inventory accepts only inventory filters and output flags');
|
|
66
|
+
const scope = values.get('--scope') ?? 'workspace';
|
|
67
|
+
if (!['workspace', 'user', 'installation', 'catalog'].includes(scope))
|
|
68
|
+
throw new Error('Invalid inventory scope');
|
|
69
|
+
const activation = list('--activation');
|
|
70
|
+
const tier = list('--tier');
|
|
71
|
+
if (activation?.some(value => !['kernel', 'summary', 'bound', 'paths', 'on-demand'].includes(value)))
|
|
72
|
+
throw new Error('Invalid activation filter');
|
|
73
|
+
if (tier?.some(value => !['critical', 'high', 'medium', 'low'].includes(value)))
|
|
74
|
+
throw new Error('Invalid tier filter');
|
|
75
|
+
if (list('--capability')?.some(value => !value))
|
|
76
|
+
throw new Error('Invalid capability filter');
|
|
77
|
+
const { ruleInventory } = await import('../../rules/inventory.js');
|
|
78
|
+
const report = await ruleInventory(ctx.cwd, ctx.frameworkRoot, { scope: scope, capability: list('--capability'), activation, enforcement: tier, provider: values.get('--provider'), bodies: flags.has('--bodies') });
|
|
79
|
+
return { exitCode: 0, rawOutput: true, message: json ? JSON.stringify(report, null, 2) :
|
|
80
|
+
[`Scope: ${report.scope} (${report.scope_description})`, 'Per-rule delivery and session loading: unknown.', ...report.rules.map(rule => `${rule.capability}/${rule.name} [${rule.effective_activation ?? 'unconfigured'}, ${rule.enforcement ?? 'unknown'}]: ${rule.summary ?? '(no summary)'}; ${rule.fetch_command ?? 'fetch ID unknown'}${rule.content ? `\n${rule.content}` : ''}`), ...report.warnings, ...(!report.rules.length ? ['No matching rules.'] : [])].join('\n') };
|
|
81
|
+
}
|
|
82
|
+
if (values.has('--scope') || values.has('--activation') || values.has('--provider') || flags.has('--bodies'))
|
|
83
|
+
throw new Error('Inventory filters are only valid for rules inventory');
|
|
84
|
+
const source = flags.has('--user') ? 'user' : 'project';
|
|
85
|
+
const configs = loadRulePinConfigs(ctx.cwd);
|
|
86
|
+
const before = rulePinState(ctx.cwd, ctx.frameworkRoot, configs, true);
|
|
87
|
+
if (command === 'pinned') {
|
|
88
|
+
if (ids.length || [...values.keys()].some(key => key !== '--capability'))
|
|
89
|
+
throw new Error('pinned accepts only --capability and output/scope flags');
|
|
90
|
+
const filter = list('--capability');
|
|
91
|
+
if (filter?.some(id => !before.installed.includes(id)))
|
|
92
|
+
throw new Error(`Unknown capability. Installed ids: ${before.installed.join(', ')}`);
|
|
93
|
+
const rules = before.rules.filter(rule => !filter || filter.includes(rule.capability?.replace(/^(framework|addon|extension|plugin):/, '') || ''));
|
|
94
|
+
return { exitCode: 0, message: json ? JSON.stringify({ rules, warnings: before.warnings }, null, 2)
|
|
95
|
+
: [...rules.map(rule => `${rule.name}: pinned kernel (canonical ${rule.canonical_activation}) ${rule.matches.map(match => `${match.source}: ${JSON.stringify(match.selector)}`).join('; ')}`), ...before.warnings, ...(!rules.length ? ['No effective rule pins.'] : [])].join('\n'), rawOutput: true };
|
|
96
|
+
}
|
|
97
|
+
if (command === 'group' && ids[0] === 'list') {
|
|
98
|
+
if (ids.length !== 1 || values.size)
|
|
99
|
+
throw new Error('Usage: aiwg rules group list');
|
|
100
|
+
const groups = { user: configs.user.rules?.pin_groups || {}, project: configs.project.rules?.pin_groups || {} };
|
|
101
|
+
return { exitCode: 0, message: JSON.stringify(groups, null, 2), rawOutput: true };
|
|
102
|
+
}
|
|
103
|
+
const selected = configs[source];
|
|
104
|
+
selected.rules = { ...selected.rules };
|
|
105
|
+
if (command === 'group') {
|
|
106
|
+
const [action, name, ...capabilities] = ids;
|
|
107
|
+
if (action !== 'set' || !name || !capabilities.length || values.size)
|
|
108
|
+
throw new Error('Usage: aiwg rules group set <name> <capability>...');
|
|
109
|
+
selected.rules.pin_groups = { ...selected.rules.pin_groups, [name]: [...new Set(capabilities.flatMap(id => id.split(',')))].sort() };
|
|
110
|
+
}
|
|
111
|
+
else if (command === 'pin' || command === 'unpin') {
|
|
112
|
+
if (flags.has('--all-tiers') && values.has('--tier'))
|
|
113
|
+
throw new Error('--all-tiers and --tier are mutually exclusive');
|
|
114
|
+
const selector = {};
|
|
115
|
+
if (ids.length)
|
|
116
|
+
selector.rules = [...new Set(ids)].sort();
|
|
117
|
+
if (values.has('--tier'))
|
|
118
|
+
selector.enforcement = list('--tier');
|
|
119
|
+
if (values.has('--capability'))
|
|
120
|
+
selector.capabilities = list('--capability');
|
|
121
|
+
if (values.has('--group'))
|
|
122
|
+
selector.group = values.get('--group');
|
|
123
|
+
if (flags.has('--all'))
|
|
124
|
+
selector.all = true;
|
|
125
|
+
if (!Object.keys(selector).length)
|
|
126
|
+
throw new Error('Supply rule ids, --tier, --capability, --group, or --all');
|
|
127
|
+
if (flags.has('--all-tiers') && !selector.capabilities && !selector.group && !selector.all)
|
|
128
|
+
throw new Error('--all-tiers requires --capability, --group or --all');
|
|
129
|
+
const existing = selected.rules.always_load || [];
|
|
130
|
+
const key = selectorKey(selector);
|
|
131
|
+
if (command === 'pin') {
|
|
132
|
+
const unknown = ids.filter(id => !before.inventory.some(rule => [rule.name, rule.id, rule.path].includes(id)));
|
|
133
|
+
if (unknown.length)
|
|
134
|
+
throw new Error(`Unknown installed rule ids: ${unknown.join(', ')}`);
|
|
135
|
+
selected.rules.always_load = existing.some(item => selectorKey(item) === key) ? existing : [...existing, selector];
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
selected.rules.always_load = existing.filter(item => selectorKey(item) !== key);
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
throw new Error(usage);
|
|
142
|
+
// Only the edited scope is strict: stale pins in another scope remain visible warnings.
|
|
143
|
+
const errors = validateRulePinCapabilities(selected.rules, before.installed, { ...configs.user.rules?.pin_groups, ...configs.project.rules?.pin_groups });
|
|
144
|
+
if (errors.length)
|
|
145
|
+
throw new Error(errors.join('\n'));
|
|
146
|
+
const after = rulePinState(ctx.cwd, ctx.frameworkRoot, configs, true);
|
|
147
|
+
const providers = [...new Set([...(configs.project.providers || []), ...Object.values(configs.project.installed || {}).flatMap(entry => Object.keys(entry.deployedTo || {}))])];
|
|
148
|
+
const reports = [];
|
|
149
|
+
const failures = [];
|
|
150
|
+
const plans = [];
|
|
151
|
+
// Use precisely the installed rule inventory, including local bundles; do not select new capabilities.
|
|
152
|
+
for (const provider of providers) {
|
|
153
|
+
if (!['claude', 'codex', 'cursor', 'hermes', 'warp', 'openclaw'].includes(provider)) {
|
|
154
|
+
failures.push(`Rule pin projection is unavailable for provider '${provider}'`);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const module = await import(pathToFileURL(path.join(ctx.frameworkRoot, 'tools/agents/providers', `${provider}.mjs`)).href);
|
|
158
|
+
const options = { srcRoot: path.join(ctx.frameworkRoot, 'agentic/code'), target: ctx.cwd, mode: 'all',
|
|
159
|
+
ruleSources: after.inventory.map(rule => rule.path), config: configs.project, pinConfigs: configs,
|
|
160
|
+
rulesOnly: true, deployRules: true, deploySkills: false, deployCommands: false,
|
|
161
|
+
force: true, quiet: true, allowOverBudget: flags.has('--allow-over-budget') };
|
|
162
|
+
try {
|
|
163
|
+
const report = await quietDeployment(module.deploy, { ...options, dryRun: true, previewReport: true });
|
|
164
|
+
reports.push(report);
|
|
165
|
+
plans.push({ deploy: module.deploy, options });
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
failures.push(`${provider}: ${error instanceof Error ? error.message : String(error)}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (failures.length)
|
|
172
|
+
throw new Error(failures.join('\n'));
|
|
173
|
+
const dryRun = flags.has('--dry-run') || ctx.dryRun;
|
|
174
|
+
if (!dryRun) {
|
|
175
|
+
await setRuleConfigKey(ctx.cwd, source, 'rules', JSON.stringify(selected.rules));
|
|
176
|
+
if (!flags.has('--no-deploy'))
|
|
177
|
+
for (const plan of plans)
|
|
178
|
+
await quietDeployment(plan.deploy, plan.options);
|
|
179
|
+
}
|
|
180
|
+
const redeploy = 'aiwg refresh --skip-update --force' + (flags.has('--allow-over-budget') ? ' --allow-over-budget' : '');
|
|
181
|
+
const needsRedeploy = flags.has('--no-deploy') || plans.length === 0;
|
|
182
|
+
const output = { dry_run: !!dryRun, source, rules: after.rules, warnings: after.warnings, providers: reports,
|
|
183
|
+
deployed: !dryRun && !needsRedeploy, ...(needsRedeploy ? { redeploy } : {}) };
|
|
184
|
+
return { exitCode: 0, message: json ? JSON.stringify(output, null, 2)
|
|
185
|
+
: [dryRun ? 'Rule pin preview (config unchanged)' : 'Rule pins updated', ...after.rules.map(rule => `${rule.name}: kernel (canonical ${rule.canonical_activation})`),
|
|
186
|
+
...reports.map(report => { const r = report; return `${r.provider}: ${r.selected_bytes} startup bytes${report.exceeded ? ' (over budget; explicitly allowed)' : ''}`; }),
|
|
187
|
+
...after.warnings, ...(needsRedeploy ? [`Redeploy: ${redeploy}`] : [])].join('\n'), rawOutput: true };
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
191
|
+
return { exitCode: 1, message: json ? JSON.stringify({ error: message }) : message, rawOutput: json };
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=rules.js.map
|