@aiwg/cli 2026.10.1 → 2026.10.4
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/capability-matrix.yaml +270 -0
- package/agentic/code/providers/model-capabilities.v1.json +3183 -24
- package/bin/aiwg.mjs +135 -47
- package/dist/src/a2a/codecs.js +9 -0
- 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 +57 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
- 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 +285 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +65 -0
- package/dist/src/artifacts/index-refresh.js +576 -0
- package/dist/src/artifacts/index-worker.mjs +9 -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/repair.js +9 -4
- 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 +78 -12
- package/dist/src/cli/child-process-result.js +40 -0
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/env.js +38 -16
- package/dist/src/cli/flag-parsing.js +236 -0
- 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 +218 -5
- package/dist/src/cli/handlers/diagnose.js +13 -5
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/feedback.js +14 -5
- 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 +248 -30
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/mc.js +23 -0
- package/dist/src/cli/handlers/models.js +169 -10
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/ralph.js +3 -0
- package/dist/src/cli/handlers/refresh.js +28 -0
- package/dist/src/cli/handlers/regenerate.js +14 -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 +25 -11
- package/dist/src/cli/handlers/script-runner.js +19 -8
- package/dist/src/cli/handlers/session.js +406 -62
- package/dist/src/cli/handlers/sessions.js +243 -76
- package/dist/src/cli/handlers/setup-manifest.js +474 -79
- package/dist/src/cli/handlers/setup.js +180 -39
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +60 -3
- package/dist/src/cli/handlers/team.js +18 -8
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +307 -55
- package/dist/src/cli/handlers/utilities.js +125 -26
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/prompt-utils.js +72 -0
- package/dist/src/cli/provider-resolution.js +11 -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 +349 -35
- package/dist/src/config/cli.js +256 -23
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -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-health.mjs +14 -3
- 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 +38 -11
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/adapters/jev.js +75 -27
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +14 -7
- 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 +25 -6
- 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 +15 -14
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/index.js +1 -0
- package/dist/src/decision/interop.js +60 -8
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +942 -0
- 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/decision/validate.js +6 -3
- package/dist/src/effects/dispatch-verifier.js +252 -0
- package/dist/src/effects/index.js +1 -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/features/installer.js +2 -2
- package/dist/src/flow/graph-metadata.js +5 -0
- package/dist/src/gates/providers/loader.js +64 -18
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +15 -3
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +95 -5
- 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 +366 -56
- 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 +620 -85
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-file.mjs +279 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/config-layers.mjs +348 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/credentials.mjs +484 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +17 -27
- package/dist/src/mcp/helpers.mjs +109 -4
- 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/omp-config.mjs +50 -29
- package/dist/src/mcp/profiles.js +97 -23
- package/dist/src/mcp/profiles.mjs +99 -27
- package/dist/src/mcp/registry.js +248 -131
- package/dist/src/mcp/registry.mjs +169 -100
- 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 +127 -82
- 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-string.mjs +9 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tool-filters.mjs +357 -0
- package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
- package/dist/src/mcp/tools/decision.mjs +22 -3
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +50 -2
- package/dist/src/mcp/tools/subsystems.mjs +39 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
- package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
- package/dist/src/memory/project-registry.js +2 -2
- package/dist/src/mission-protocol/codecs.js +647 -1
- package/dist/src/mission-protocol/types.js +110 -0
- package/dist/src/mission-protocol/worker-status.js +2 -0
- package/dist/src/models/config-loader.js +76 -14
- package/dist/src/models/grok-build-models.js +93 -41
- package/dist/src/models/model-capabilities.v1.json +3183 -24
- package/dist/src/models/model-discovery.js +931 -67
- package/dist/src/models/provider-policy.js +719 -11
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/qualification-digest.mjs +17 -0
- package/dist/src/models/resolver.js +261 -0
- package/dist/src/models/worker-direct-readiness.js +550 -0
- package/dist/src/models/worker-dispatch-offer.js +169 -0
- package/dist/src/models/worker-health-readiness.js +144 -0
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +986 -0
- package/dist/src/models/wrapper-route.js +18 -0
- package/dist/src/ops/registry.js +9 -14
- package/dist/src/plugins/standalone-packager.js +4 -3
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +430 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/cli-command.mjs +75 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/capability-matrix.js +8 -0
- package/dist/src/providers/capability-matrix.yaml +270 -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 +53 -23
- 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/provider-definitions.js +9 -1
- package/dist/src/providers/provider-definitions.mjs +9 -2
- 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/executor-registry.js +16 -24
- package/dist/src/serve/fleet-mission-conductor.js +9 -0
- package/dist/src/serve/mission-conductor.js +47 -12
- package/dist/src/serve/shared-host-scheduler.js +2 -0
- package/dist/src/serve/worker-invocation.js +558 -0
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/serve/worker-stdin-frame.mjs +107 -0
- package/dist/src/sessions/adapter-registry.js +49 -0
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +82 -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 +43 -9
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
- package/dist/src/sessions/adapters/grokbot.js +434 -24
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
- package/dist/src/sessions/adapters/muse.js +200 -104
- 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 +30 -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 +25 -5
- package/dist/src/sessions/batch-import.js +72 -51
- package/dist/src/sessions/candidates.js +47 -11
- package/dist/src/sessions/contracts.js +75 -2
- package/dist/src/sessions/coverage-preflight.js +134 -0
- package/dist/src/sessions/discovery.js +3 -0
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/grok-build-cli.js +67 -5
- 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 +84 -46
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +133 -25
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +106 -0
- package/dist/src/sessions/repository.js +199 -63
- package/dist/src/sessions/workspace-discovery.js +315 -88
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/adapters/clawhub.js +10 -8
- package/dist/src/skills/adapters/openclaw.js +10 -7
- 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 +195 -14
- package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
- package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
- package/dist/src/smiths/mcpsmith/example.js +1 -1
- 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 +85 -31
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/logseq.js +68 -7
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
- package/dist/src/testing/generators/test-code-generator.js +57 -30
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/uhp/client.js +11 -1
- package/dist/src/uhp/mission.js +5 -0
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/checker.mjs +5 -5
- package/dist/src/update/notifier.mjs +54 -2
- 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/dist/src/writing/fidelity.js +18 -1
- package/package.json +32 -2
- package/schemas/mission-v1.schema.json +2429 -0
- package/schemas/models/model-catalog.v1.schema.json +301 -0
- package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
- package/schemas/models/model-policy.v1.schema.json +14 -0
- package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
- package/tools/_resolve-impl.mjs +39 -2
- package/tools/agents/deploy-agents.mjs +64 -23
- package/tools/agents/providers/base.mjs +153 -166
- 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/grokbot.mjs +11 -12
- package/tools/agents/providers/hermes.mjs +62 -49
- package/tools/agents/providers/omp.mjs +5 -2
- package/tools/agents/providers/openclaw-translator.mjs +19 -5
- 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 +360 -0
- package/tools/providers/omp-transport.mjs +194 -0
- package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
- package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
- package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
- package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
- package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
- package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
- 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 +439 -0
- 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 +2916 -0
|
@@ -4,9 +4,21 @@
|
|
|
4
4
|
* Implements `aiwg init` — the first-run wizard that creates
|
|
5
5
|
* `.aiwg/aiwg.config` for the current project.
|
|
6
6
|
*
|
|
7
|
-
* Prompts:
|
|
8
|
-
* 1. Which AI provider toolchains does this project target?
|
|
9
|
-
* 2. Would you like to add
|
|
7
|
+
* Prompts, and the argument that answers each one directly (#3062):
|
|
8
|
+
* 1. Which AI provider toolchains does this project target? → `--providers <list>`
|
|
9
|
+
* 2. Would you like to add default scripts (deploy/doctor/sync)? → `--default-scripts true|false`
|
|
10
|
+
* 3. Add a custom script (name + command)? → `--script <name>=<command>` (repeatable;
|
|
11
|
+
* implies yes) or `--custom-scripts true|false` (answers the question directly
|
|
12
|
+
* without supplying a script; `false` declines it outright)
|
|
13
|
+
* 4. Enable direct worker dispatch? → `--worker-dispatch enable|decline`
|
|
14
|
+
*
|
|
15
|
+
* With a terminal attached, any of these given directly skips that
|
|
16
|
+
* question — only genuinely missing values are still asked. Without one,
|
|
17
|
+
* omitted inputs fall back to their documented defaults (`claude`, default
|
|
18
|
+
* scripts on) rather than erroring, since those defaults are always safe to
|
|
19
|
+
* apply headless. `--non-interactive`/`--yes` force the non-interactive
|
|
20
|
+
* path even with a terminal attached. `--dry-run` never writes anything,
|
|
21
|
+
* including the baseline config itself.
|
|
10
22
|
*
|
|
11
23
|
* Runs automatically on first `aiwg use` when no config exists.
|
|
12
24
|
* Can also be run explicitly to reconfigure.
|
|
@@ -16,10 +28,14 @@
|
|
|
16
28
|
import readline from 'readline';
|
|
17
29
|
import { readAiwgConfig, writeAiwgConfig, emptyConfig, populateDeployedTo, VALID_PROVIDERS, getConfigPath, } from '../../config/aiwg-config.js';
|
|
18
30
|
import * as ui from '../ui.js';
|
|
19
|
-
import { askString as sharedAskString, askYesNo as sharedAskYesNo } from '../prompt-utils.js';
|
|
31
|
+
import { askString as sharedAskString, askYesNo as sharedAskYesNo, askConsent } from '../prompt-utils.js';
|
|
20
32
|
import { normalizeProviderDefinitionId } from '../../providers/provider-definitions.js';
|
|
21
33
|
import { writeNormalizedAiwgMd } from '../../smiths/context-pipeline/finalization.js';
|
|
22
34
|
import { ensureWorkspaceContext } from '../../smiths/context-pipeline/workspace-context.js';
|
|
35
|
+
import { detectInstalledWorkerClis, evaluateWorkerDispatchOffer, workerDispatchOfferQuestion, workerDispatchOfferHintWithArg, parseWorkerDispatchArg, } from '../../models/worker-dispatch-offer.js';
|
|
36
|
+
import { EXIT_CODES } from '../errors.js';
|
|
37
|
+
import { isInteractive } from '../env.js';
|
|
38
|
+
import { requireFlagValue, collectFlagValues, parseBooleanFlagValue, parseListFlagValue, parseKeyValueEntry, MissingFlagValueError, } from '../flag-parsing.js';
|
|
23
39
|
const PROVIDER_LABELS = {
|
|
24
40
|
antigravity: 'Google Antigravity .agents/',
|
|
25
41
|
claude: 'Claude Code .claude/',
|
|
@@ -76,6 +92,89 @@ async function askProviders(rl, signal) {
|
|
|
76
92
|
}
|
|
77
93
|
return selected.length > 0 ? selected : ['claude'];
|
|
78
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Non-interactive / --yes / no-TTY runs never prompt and never touch the
|
|
97
|
+
* config (#3050 item 2) — they only print one line naming the enable
|
|
98
|
+
* command, when two or more worker CLIs are detected and dispatch is not
|
|
99
|
+
* already on or declined. The hint also names `--worker-dispatch` (#3062):
|
|
100
|
+
* that argument answers the same question headlessly.
|
|
101
|
+
*/
|
|
102
|
+
function renderWorkerDispatchHintIfApplicable(parallelism, setup) {
|
|
103
|
+
const offer = evaluateWorkerDispatchOffer(parallelism, setup, detectInstalledWorkerClis());
|
|
104
|
+
if (offer.shouldOffer)
|
|
105
|
+
ui.dim(` ${workerDispatchOfferHintWithArg(offer.detected)}`);
|
|
106
|
+
}
|
|
107
|
+
function parseInitArgInputs(args) {
|
|
108
|
+
// #3062 second review, finding 4: `precedence: 'first'` matches this
|
|
109
|
+
// command's pre-existing (and, for `--providers`/`--default-scripts`/
|
|
110
|
+
// `--script`/`--custom-scripts`, only) convention — see
|
|
111
|
+
// `parseInitArgInputs`'s module-level callers for why `--worker-dispatch`
|
|
112
|
+
// specifically needs `rejectEmpty` (an explicit empty choice is never
|
|
113
|
+
// meaningful and must not silently fall through to "not given").
|
|
114
|
+
const workerDispatchArg = parseWorkerDispatchArg(requireFlagValue(args, { rejectEmpty: true }, '--worker-dispatch'));
|
|
115
|
+
const rawProviders = parseListFlagValue(requireFlagValue(args, {}, '--providers'));
|
|
116
|
+
const providersArg = rawProviders?.map((entry) => {
|
|
117
|
+
const canonical = normalizeProviderDefinitionId(entry);
|
|
118
|
+
if (!canonical || canonical === 'generic' || !VALID_PROVIDERS.includes(canonical)) {
|
|
119
|
+
throw new Error(`--providers: unknown provider '${entry}' (valid: ${VALID_PROVIDERS.join(', ')})`);
|
|
120
|
+
}
|
|
121
|
+
return canonical;
|
|
122
|
+
});
|
|
123
|
+
if (providersArg && providersArg.length === 0) {
|
|
124
|
+
throw new Error('--providers requires at least one provider name');
|
|
125
|
+
}
|
|
126
|
+
const defaultScriptsArg = parseBooleanFlagValue(requireFlagValue(args, {}, '--default-scripts'), '--default-scripts');
|
|
127
|
+
const customScriptsArg = parseBooleanFlagValue(requireFlagValue(args, {}, '--custom-scripts'), '--custom-scripts');
|
|
128
|
+
const scriptPairs = {};
|
|
129
|
+
for (const entry of collectFlagValues(args, {}, '--script')) {
|
|
130
|
+
const [name, command] = parseKeyValueEntry(entry, '--script');
|
|
131
|
+
scriptPairs[name] = command;
|
|
132
|
+
}
|
|
133
|
+
return { workerDispatchArg, providersArg, defaultScriptsArg, customScriptsArg, scriptPairs };
|
|
134
|
+
}
|
|
135
|
+
/** One-line description of what an explicit `--worker-dispatch` choice would write. */
|
|
136
|
+
function describeWorkerDispatchWrite(arg) {
|
|
137
|
+
return arg === 'enable'
|
|
138
|
+
? 'enable parallelism.worker_dispatch'
|
|
139
|
+
: 'record a worker-dispatch decline (setup.worker_dispatch_offer)';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Resolve an explicit `--worker-dispatch` choice into a decision to apply to
|
|
143
|
+
* a brand-new config (#3062). Under `--dry-run`, writes nothing — reports
|
|
144
|
+
* what would be written instead and returns `undefined` so the caller never
|
|
145
|
+
* applies it to the config it builds.
|
|
146
|
+
*/
|
|
147
|
+
function resolveWorkerDispatchDecisionForNewConfig(arg, dryRun) {
|
|
148
|
+
if (dryRun) {
|
|
149
|
+
ui.dim(` Would ${describeWorkerDispatchWrite(arg)} (--dry-run writes nothing).`);
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
return { kind: arg };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Interactive-only: asks the one consent question (default/unanswered is
|
|
156
|
+
* no, strict `y`/`yes` parsing only) when two or more worker CLIs are
|
|
157
|
+
* detected and dispatch is not already on or declined. Returns the
|
|
158
|
+
* decision to apply, or `undefined` when there is nothing to offer, or
|
|
159
|
+
* when the prompt timed out / stdin closed without an answer — only an
|
|
160
|
+
* actually-answered "no" is recorded as a persistent decline (#3050
|
|
161
|
+
* review item 4).
|
|
162
|
+
*/
|
|
163
|
+
async function askWorkerDispatchOffer(rl, parallelism, setup, signal) {
|
|
164
|
+
const offer = evaluateWorkerDispatchOffer(parallelism, setup, detectInstalledWorkerClis());
|
|
165
|
+
if (!offer.shouldOffer)
|
|
166
|
+
return undefined;
|
|
167
|
+
console.log('');
|
|
168
|
+
const outcome = await askConsent(rl, workerDispatchOfferQuestion(offer.detected), undefined, signal);
|
|
169
|
+
if (outcome.kind !== 'answered')
|
|
170
|
+
return undefined;
|
|
171
|
+
if (outcome.value) {
|
|
172
|
+
ui.success(' Will enable parallelism.worker_dispatch.');
|
|
173
|
+
return { kind: 'enable' };
|
|
174
|
+
}
|
|
175
|
+
ui.dim(' Noted — enable later with `aiwg config set --project parallelism.worker_dispatch true`.');
|
|
176
|
+
return { kind: 'decline' };
|
|
177
|
+
}
|
|
79
178
|
export const initHandler = {
|
|
80
179
|
id: 'init',
|
|
81
180
|
name: 'Init',
|
|
@@ -84,16 +183,34 @@ export const initHandler = {
|
|
|
84
183
|
aliases: [],
|
|
85
184
|
async execute(ctx) {
|
|
86
185
|
const force = ctx.args.includes('--force');
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
186
|
+
// `--non-interactive`/`--yes` are this command's own explicit flags for
|
|
187
|
+
// the one shared interactive decision (#3062 review item 12) — honored
|
|
188
|
+
// ahead of (and regardless of) the environment-only checks `isInteractive`
|
|
189
|
+
// otherwise applies (TTY, TERM, CI). Downstream code MUST NOT re-derive
|
|
90
190
|
// interactive-ness from process.stdin.isTTY again.
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
!process.stdin.isTTY ||
|
|
94
|
-
!process.stdout.isTTY ||
|
|
95
|
-
process.env['CI'] === 'true';
|
|
191
|
+
const explicitNonInteractive = ctx.args.includes('--non-interactive') || ctx.args.includes('--yes');
|
|
192
|
+
const nonInteractive = !isInteractive(explicitNonInteractive);
|
|
96
193
|
const projectDir = ctx.cwd;
|
|
194
|
+
// `--worker-dispatch enable|decline` answers the worker-dispatch offer
|
|
195
|
+
// directly (#3062), with or without a terminal, and is honored even when
|
|
196
|
+
// fewer than two worker CLIs are detected — an explicit choice overrides
|
|
197
|
+
// the presence-only detection gate. `--providers`/`--default-scripts`/
|
|
198
|
+
// `--script` answer the remaining wizard inputs the same way (review
|
|
199
|
+
// item 10). Every flag is parsed strictly (review item 11): present
|
|
200
|
+
// without a usable value is a usage error, raised here before any
|
|
201
|
+
// preflight check, read, or write.
|
|
202
|
+
let workerDispatchArg;
|
|
203
|
+
let providersArg;
|
|
204
|
+
let defaultScriptsArg;
|
|
205
|
+
let customScriptsArg;
|
|
206
|
+
let scriptPairs;
|
|
207
|
+
try {
|
|
208
|
+
({ workerDispatchArg, providersArg, defaultScriptsArg, customScriptsArg, scriptPairs } = parseInitArgInputs(ctx.args));
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
const message = err instanceof MissingFlagValueError ? `${err.message}.` : err instanceof Error ? err.message : String(err);
|
|
212
|
+
return { exitCode: EXIT_CODES.USAGE, message };
|
|
213
|
+
}
|
|
97
214
|
ui.blank();
|
|
98
215
|
console.log(` ${ui.brandMark()} ${ui.bold('AIWG Baseline Config')}`);
|
|
99
216
|
ui.rule();
|
|
@@ -101,7 +218,10 @@ export const initHandler = {
|
|
|
101
218
|
const existing = await readAiwgConfig(projectDir);
|
|
102
219
|
if (existing && !force) {
|
|
103
220
|
ui.info(`Config already exists: ${getConfigPath(projectDir)}`);
|
|
104
|
-
|
|
221
|
+
// #3062 review item 18: `--dry-run` must write nothing at all, not
|
|
222
|
+
// just skip the worker-dispatch increment below.
|
|
223
|
+
if (!ctx.dryRun)
|
|
224
|
+
await writeNormalizedAiwgMd(projectDir);
|
|
105
225
|
console.log(` Providers: ${existing.providers.join(', ')}`);
|
|
106
226
|
const scriptCount = Object.keys(existing.scripts).length;
|
|
107
227
|
if (scriptCount > 0) {
|
|
@@ -111,22 +231,72 @@ export const initHandler = {
|
|
|
111
231
|
ui.dim(' Ask your AIWG agent to review repo, tracker, delivery, signing, and provider policy.');
|
|
112
232
|
ui.dim(' Agents may use `aiwg setup project --dry-run` as the CLI helper for that review.');
|
|
113
233
|
ui.dim(' Run `aiwg init --force` only when you need to recreate the baseline config.');
|
|
234
|
+
// #3050: guide users to direct worker dispatch from the setup step they
|
|
235
|
+
// already run, instead of leaving it undiscoverable. `--dry-run` must
|
|
236
|
+
// never prompt and never write (review item 1) — it degrades to the
|
|
237
|
+
// same hint-only behavior as non-interactive runs.
|
|
238
|
+
// #3062: an explicit `--worker-dispatch` argument always answers the
|
|
239
|
+
// question directly (bypassing the ask/hint entirely) except under
|
|
240
|
+
// `--dry-run`, which still writes nothing — it reports what would be
|
|
241
|
+
// written instead.
|
|
242
|
+
if (workerDispatchArg) {
|
|
243
|
+
if (ctx.dryRun) {
|
|
244
|
+
ui.dim(` Would ${describeWorkerDispatchWrite(workerDispatchArg)} (--dry-run writes nothing).`);
|
|
245
|
+
}
|
|
246
|
+
else if (workerDispatchArg === 'enable') {
|
|
247
|
+
await writeAiwgConfig(projectDir, { ...existing, parallelism: { ...existing.parallelism, worker_dispatch: true } });
|
|
248
|
+
ui.success(' Enabled parallelism.worker_dispatch. Next: aiwg doctor --probe-workers --qualify.');
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
await writeAiwgConfig(projectDir, { ...existing, setup: { ...existing.setup, worker_dispatch_offer: 'declined' } });
|
|
252
|
+
ui.success(' Recorded worker-dispatch decline (setup.worker_dispatch_offer).');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else if (nonInteractive || ctx.dryRun) {
|
|
256
|
+
renderWorkerDispatchHintIfApplicable(existing.parallelism, existing.setup);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
260
|
+
try {
|
|
261
|
+
const decision = await askWorkerDispatchOffer(rl, existing.parallelism, existing.setup, ctx.signal);
|
|
262
|
+
if (decision?.kind === 'enable') {
|
|
263
|
+
await writeAiwgConfig(projectDir, { ...existing, parallelism: { ...existing.parallelism, worker_dispatch: true } });
|
|
264
|
+
ui.info('Next: aiwg doctor --probe-workers --qualify.');
|
|
265
|
+
}
|
|
266
|
+
else if (decision?.kind === 'decline') {
|
|
267
|
+
await writeAiwgConfig(projectDir, { ...existing, setup: { ...existing.setup, worker_dispatch_offer: 'declined' } });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
finally {
|
|
271
|
+
rl.close();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
114
274
|
ui.blank();
|
|
115
275
|
return { exitCode: 0 };
|
|
116
276
|
}
|
|
117
277
|
let providers;
|
|
118
278
|
let scripts = {};
|
|
279
|
+
let workerDispatchDecision;
|
|
280
|
+
const DEFAULT_SCRIPTS = { deploy: 'aiwg use all', doctor: 'aiwg doctor', sync: 'aiwg sync' };
|
|
119
281
|
if (nonInteractive) {
|
|
120
|
-
// Non-interactive:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
282
|
+
// Non-interactive: an explicit `--providers`/`--default-scripts`
|
|
283
|
+
// answers the corresponding wizard input directly (review item 10);
|
|
284
|
+
// anything not supplied keeps its prior default.
|
|
285
|
+
providers = providersArg ?? ['claude'];
|
|
286
|
+
const includeDefaultScripts = defaultScriptsArg ?? true;
|
|
287
|
+
scripts = { ...(includeDefaultScripts ? DEFAULT_SCRIPTS : {}), ...scriptPairs };
|
|
288
|
+
if (workerDispatchArg) {
|
|
289
|
+
workerDispatchDecision = resolveWorkerDispatchDecisionForNewConfig(workerDispatchArg, ctx.dryRun);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
renderWorkerDispatchHintIfApplicable(undefined, undefined);
|
|
293
|
+
}
|
|
127
294
|
}
|
|
128
295
|
else {
|
|
129
|
-
// Interactive wizard
|
|
296
|
+
// Interactive wizard — skip a prompt whenever its argument already
|
|
297
|
+
// answered it (review item 10/12: "with a terminal we can skip steps
|
|
298
|
+
// for any params provided and only provide interaction when we are
|
|
299
|
+
// missing a value").
|
|
130
300
|
const rl = readline.createInterface({
|
|
131
301
|
input: process.stdin,
|
|
132
302
|
output: process.stdout,
|
|
@@ -134,16 +304,29 @@ export const initHandler = {
|
|
|
134
304
|
try {
|
|
135
305
|
// Thread ctx.signal through every prompt so Ctrl-C during the wizard
|
|
136
306
|
// cancels cleanly instead of being absorbed by readline (POC #926).
|
|
137
|
-
providers = await askProviders(rl, ctx.signal);
|
|
307
|
+
providers = providersArg ?? await askProviders(rl, ctx.signal);
|
|
138
308
|
console.log('');
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
scripts
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
309
|
+
const includeDefaultScripts = defaultScriptsArg !== undefined
|
|
310
|
+
? defaultScriptsArg
|
|
311
|
+
: await askYesNo(rl, ' Add default scripts (deploy, doctor, sync)? [Y/n]: ', true, ctx.signal);
|
|
312
|
+
scripts = includeDefaultScripts ? { ...DEFAULT_SCRIPTS } : {};
|
|
313
|
+
if (Object.keys(scriptPairs).length > 0) {
|
|
314
|
+
// `--script` already answered "add a custom script?" (implicit
|
|
315
|
+
// yes) and its name/command sub-prompts — never ask any of the
|
|
316
|
+
// three (#3062 second review, finding 5a).
|
|
317
|
+
scripts = { ...scripts, ...scriptPairs };
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
// `--custom-scripts true|false` answers "add a custom script?"
|
|
321
|
+
// directly when `--script` itself was not given — an explicit
|
|
322
|
+
// decline (`false`) skips the question entirely, same as every
|
|
323
|
+
// other already-supplied input; `true` still asks for the
|
|
324
|
+
// name/command, since those were not supplied either.
|
|
325
|
+
const addCustom = customScriptsArg !== undefined
|
|
326
|
+
? customScriptsArg
|
|
327
|
+
: includeDefaultScripts
|
|
328
|
+
? await askYesNo(rl, ' Add a custom script? [y/N]: ', false, ctx.signal)
|
|
329
|
+
: false;
|
|
147
330
|
if (addCustom) {
|
|
148
331
|
const name = await askString(rl, ' Script name: ', '', ctx.signal);
|
|
149
332
|
const cmd = await askString(rl, ' Command: ', '', ctx.signal);
|
|
@@ -152,6 +335,21 @@ export const initHandler = {
|
|
|
152
335
|
}
|
|
153
336
|
}
|
|
154
337
|
}
|
|
338
|
+
// #3050: offer direct worker dispatch inside the same wizard — but
|
|
339
|
+
// `--dry-run` must never prompt or write anything from the offer
|
|
340
|
+
// (review item 1), so it degrades to the hint instead. An explicit
|
|
341
|
+
// `--worker-dispatch` argument (#3062) always answers the question
|
|
342
|
+
// directly instead of asking or hinting, still subject to `--dry-run`
|
|
343
|
+
// writing nothing.
|
|
344
|
+
if (workerDispatchArg) {
|
|
345
|
+
workerDispatchDecision = resolveWorkerDispatchDecisionForNewConfig(workerDispatchArg, ctx.dryRun);
|
|
346
|
+
}
|
|
347
|
+
else if (ctx.dryRun) {
|
|
348
|
+
renderWorkerDispatchHintIfApplicable(undefined, undefined);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
workerDispatchDecision = await askWorkerDispatchOffer(rl, undefined, undefined, ctx.signal);
|
|
352
|
+
}
|
|
155
353
|
}
|
|
156
354
|
finally {
|
|
157
355
|
rl.close();
|
|
@@ -160,10 +358,30 @@ export const initHandler = {
|
|
|
160
358
|
// Build config
|
|
161
359
|
let config = emptyConfig(providers);
|
|
162
360
|
config.scripts = scripts;
|
|
361
|
+
if (workerDispatchDecision?.kind === 'enable') {
|
|
362
|
+
config.parallelism = { ...config.parallelism, worker_dispatch: true };
|
|
363
|
+
}
|
|
364
|
+
else if (workerDispatchDecision?.kind === 'decline') {
|
|
365
|
+
config.setup = { ...config.setup, worker_dispatch_offer: 'declined' };
|
|
366
|
+
}
|
|
367
|
+
// #3062 review item 18: `--dry-run` writes nothing at all — not even
|
|
368
|
+
// the baseline config — rather than only skipping the worker-dispatch
|
|
369
|
+
// increment. Report what would be written instead.
|
|
370
|
+
if (ctx.dryRun) {
|
|
371
|
+
ui.blank();
|
|
372
|
+
ui.dim(` Would create ${getConfigPath(projectDir)} (--dry-run writes nothing).`);
|
|
373
|
+
ui.dim(` Providers: ${providers.join(', ')}`);
|
|
374
|
+
if (Object.keys(scripts).length > 0)
|
|
375
|
+
ui.dim(` Scripts: ${Object.keys(scripts).join(', ')}`);
|
|
376
|
+
ui.blank();
|
|
377
|
+
return { exitCode: 0 };
|
|
378
|
+
}
|
|
163
379
|
// Populate deployedTo from disk for entries with empty deployedTo (#721)
|
|
164
380
|
config = await populateDeployedTo(config, projectDir);
|
|
165
381
|
// Write
|
|
166
382
|
await writeAiwgConfig(projectDir, config);
|
|
383
|
+
if (workerDispatchDecision?.kind === 'enable')
|
|
384
|
+
ui.info('Next: aiwg doctor --probe-workers --qualify.');
|
|
167
385
|
const normalizedAiwgMdPath = await writeNormalizedAiwgMd(projectDir);
|
|
168
386
|
const workspace = await ensureWorkspaceContext(projectDir);
|
|
169
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');
|
|
@@ -15,6 +15,7 @@ import * as ui from '../ui.js';
|
|
|
15
15
|
import { promises as fs } from 'node:fs';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { createHash, randomBytes } from 'node:crypto';
|
|
18
|
+
import { assertMissionWorkerHandoff } from '../../mission-protocol/codecs.js';
|
|
18
19
|
// ── Constants ────────────────────────────────────────────────
|
|
19
20
|
const MC_ROOT = '.aiwg/ralph-external/mc';
|
|
20
21
|
const SESSIONS_DIR = join(MC_ROOT, 'sessions');
|
|
@@ -378,6 +379,18 @@ async function mcDispatch(ctx) {
|
|
|
378
379
|
ui.error(sessionId ? `Session not found: ${sessionId}` : 'No active session. Run `aiwg mc start` first.');
|
|
379
380
|
return { exitCode: 1 };
|
|
380
381
|
}
|
|
382
|
+
// mission-dispatch accepts only the frozen objective envelope. Worker
|
|
383
|
+
// bindings can arrive through its existing session, so inspect that payload.
|
|
384
|
+
try {
|
|
385
|
+
assertMissionWorkerHandoff(selected, 'mc-cli');
|
|
386
|
+
for (const mission of selected.missions)
|
|
387
|
+
assertMissionWorkerHandoff(mission, 'mc-cli');
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
391
|
+
ui.error(message);
|
|
392
|
+
return { exitCode: 1, message };
|
|
393
|
+
}
|
|
381
394
|
// #1361: Check project-level parallelism cap. Active missions = running or
|
|
382
395
|
// queued; if at cap, warn but still queue (FIFO behavior — the mission goes
|
|
383
396
|
// into the session as 'queued' and will run when a slot frees up).
|
|
@@ -560,6 +573,16 @@ async function mcRun(ctx) {
|
|
|
560
573
|
return { exitCode: 1 };
|
|
561
574
|
}
|
|
562
575
|
const queued = session.missions.filter((m) => m.status === 'queued');
|
|
576
|
+
try {
|
|
577
|
+
assertMissionWorkerHandoff(session, 'mc-cli');
|
|
578
|
+
for (const mission of queued)
|
|
579
|
+
assertMissionWorkerHandoff(mission, 'mc-cli');
|
|
580
|
+
}
|
|
581
|
+
catch (error) {
|
|
582
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
583
|
+
ui.error(message);
|
|
584
|
+
return { exitCode: 1, message };
|
|
585
|
+
}
|
|
563
586
|
if (queued.length === 0) {
|
|
564
587
|
ui.info(`No queued missions in session ${session.id}. Run \`aiwg mc dispatch ${session.id} "<objective>"\` to add one.`);
|
|
565
588
|
return { exitCode: 0 };
|
|
@@ -4,16 +4,114 @@
|
|
|
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';
|
|
10
|
-
import { compileModelPolicy, validateCanonicalModelPolicy, validateUserProjectModelConfig, } from '../../models/provider-policy.js';
|
|
11
|
+
import { compileModelPolicy, validateCanonicalModelPolicy, validateUserProjectModelConfig, loadProviderModelCapabilities, WorkerPolicyError, } from '../../models/provider-policy.js';
|
|
11
12
|
import { resolveGrokBuildRoleModel } from '../../models/grok-build-models.js';
|
|
13
|
+
import { readAiwgConfig, emptyConfig } from '../../config/aiwg-config.js';
|
|
14
|
+
import { ConfigLoader } from '../../models/config-loader.js';
|
|
15
|
+
import { loadRecordedWorkerInstallations, normalizeWorkerVersionBanner } from '../../models/worker-installation.mjs';
|
|
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
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* #2892: exported so the MCP worker-invoke bridge can resolve a direct worker
|
|
27
|
+
* plan in-process (same snapshot/driver construction as `aiwg models resolve`),
|
|
28
|
+
* without shelling out to the CLI. No new loader is introduced; this is the
|
|
29
|
+
* CLI's own existing default `ModelsWorkerServices.load`.
|
|
30
|
+
*/
|
|
31
|
+
export async function loadWorkerInputs(ctx) {
|
|
32
|
+
const config = await readAiwgConfig(ctx.cwd) ?? emptyConfig();
|
|
33
|
+
const loader = new ConfigLoader(ctx.cwd);
|
|
34
|
+
const models = await loader.load(config.parallelism);
|
|
35
|
+
const catalog = await effectiveCatalog(ctx, ctx.cwd, false, parseArgs(['resolve']));
|
|
36
|
+
const registry = loadProviderModelCapabilities();
|
|
37
|
+
// Let the resolver explain the dispatch gate before requiring host qualification (#3070).
|
|
38
|
+
if (!config.parallelism?.worker_dispatch) {
|
|
39
|
+
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
40
|
+
registry, installations: {} }, drivers: {} };
|
|
41
|
+
}
|
|
42
|
+
const { registry: qualifiedRegistry, installations, drivers, observations } = await loadRecordedWorkerInstallations({
|
|
43
|
+
registry, cwd: ctx.cwd, policy: models.defaults.workerSelection, parallelism: config.parallelism,
|
|
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
|
+
}
|
|
84
|
+
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
85
|
+
registry: qualifiedRegistry, installations }, drivers };
|
|
86
|
+
}
|
|
87
|
+
async function resolveDirect(ctx, services) {
|
|
88
|
+
let shell = false;
|
|
89
|
+
try {
|
|
90
|
+
const request = parseWorkerCommandArgs(ctx.args.slice(1));
|
|
91
|
+
shell = request.format === 'shell';
|
|
92
|
+
const { snapshot, drivers } = await services.load(ctx);
|
|
93
|
+
const plan = await resolveWorkerInvocation(snapshot, request, drivers, services.now?.());
|
|
94
|
+
const runnable = plan.invocation?.readiness === 'launchable';
|
|
95
|
+
if (shell && !runnable)
|
|
96
|
+
console.error(JSON.stringify({ status: 'blocked', diagnostics: plan.diagnostics }, null, 2));
|
|
97
|
+
else if (shell && plan.invocation?.transport === 'shell')
|
|
98
|
+
print(plan.invocation.shellCommand, false);
|
|
99
|
+
else
|
|
100
|
+
print(plan, true);
|
|
101
|
+
return { exitCode: runnable ? 0 : 2 };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const diagnostic = { status: 'blocked', diagnostics: [workerInvocationDiagnostic(error, error instanceof WorkerPolicyError
|
|
105
|
+
&& error.code === 'OG_ADAPTER_UNQUALIFIED' ? '/parallelism/clis' : '/request')] };
|
|
106
|
+
if (shell)
|
|
107
|
+
console.error(JSON.stringify(diagnostic, null, 2));
|
|
108
|
+
else
|
|
109
|
+
print(diagnostic, true);
|
|
110
|
+
return { exitCode: 2 };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
12
113
|
const TIERS = new Set(['economy', 'standard', 'premium', 'max-quality']);
|
|
13
|
-
const PROVIDERS = new Set(
|
|
14
|
-
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grok-build', 'grokbot', 'hermes',
|
|
15
|
-
'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
16
|
-
]);
|
|
114
|
+
const PROVIDERS = new Set(Object.keys(loadProviderModelCapabilities().providers));
|
|
17
115
|
function parseArgs(args) {
|
|
18
116
|
const [subcommand = 'help', ...rest] = args;
|
|
19
117
|
const flags = new Map();
|
|
@@ -222,18 +320,75 @@ function replaceFrontmatter(raw, item, tier) {
|
|
|
222
320
|
}
|
|
223
321
|
return `---\n${frontmatter}\n---\n${match[2]}`;
|
|
224
322
|
}
|
|
225
|
-
|
|
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.`;
|
|
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
|
+
}
|
|
375
|
+
// Preserve artifact/native resolve when direct-only flags are absent.
|
|
376
|
+
if (ctx.args[0] === 'resolve' && ctx.args.slice(1).some(arg => /^--(?:task|group|brief|workdir|final-output|transport|format|authorize-premium)(?:=|$)/.test(arg))) {
|
|
377
|
+
return resolveDirect(ctx, services);
|
|
378
|
+
}
|
|
226
379
|
const parsed = parseArgs(ctx.args);
|
|
380
|
+
if (parsed.subcommand === 'resolve') {
|
|
381
|
+
const supported = new Set(['agent', 'skill', 'glob', 'role', 'tier', 'framework', 'all', 'target', 'provider', 'model', 'json', 'help', 'dry-run']);
|
|
382
|
+
for (const key of parsed.flags.keys())
|
|
383
|
+
if (!supported.has(key))
|
|
384
|
+
return { exitCode: 2, message: `Unsupported models resolve flag: --${key}` };
|
|
385
|
+
}
|
|
227
386
|
const json = parsed.flags.has('json');
|
|
228
387
|
const dryRun = parsed.flags.has('dry-run') || ctx.dryRun === true;
|
|
229
388
|
const target = path.resolve(flagString(parsed, 'target') ?? ctx.cwd);
|
|
230
389
|
const provider = flagString(parsed, 'provider') ?? 'claude';
|
|
231
390
|
if (!PROVIDERS.has(provider))
|
|
232
391
|
return { exitCode: 2, message: `Unknown provider: ${provider}` };
|
|
233
|
-
if (parsed.subcommand === 'help' || parsed.flags.has('help')) {
|
|
234
|
-
print('Usage: aiwg models <audit|list|resolve|sources|refresh|set-default|set|validate|migrate> [selectors] [--provider P] [--dry-run] [--json]', json);
|
|
235
|
-
return { exitCode: 0 };
|
|
236
|
-
}
|
|
237
392
|
if (parsed.subcommand === 'sources' || parsed.subcommand === 'refresh') {
|
|
238
393
|
const { diffModelCatalog } = await import('../../models/model-discovery.js');
|
|
239
394
|
const catalog = await effectiveCatalog(ctx, target, parsed.subcommand === 'refresh', parsed, provider);
|
|
@@ -378,6 +533,10 @@ export const modelsHandler = {
|
|
|
378
533
|
description: 'Audit, resolve, validate, and safely update model policy',
|
|
379
534
|
category: 'catalog',
|
|
380
535
|
aliases: [],
|
|
536
|
+
help: async () => ({ exitCode: 0, message: MODELS_HELP, rawOutput: true }),
|
|
381
537
|
execute,
|
|
382
538
|
};
|
|
539
|
+
export function createModelsHandler(services) {
|
|
540
|
+
return { ...modelsHandler, execute: ctx => execute(ctx, services) };
|
|
541
|
+
}
|
|
383
542
|
//# sourceMappingURL=models.js.map
|
|
@@ -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;
|
|
@@ -336,6 +336,9 @@ export class RalphStatusHandler {
|
|
|
336
336
|
category = 'ralph';
|
|
337
337
|
aliases = ['agent-loop-status', 'ralph-status'];
|
|
338
338
|
async execute(ctx) {
|
|
339
|
+
if (ctx.args.includes('--workers')) {
|
|
340
|
+
return createScriptRunner(ctx.frameworkRoot).run('tools/ralph-external/index.mjs', ['--status', ...ctx.args]);
|
|
341
|
+
}
|
|
339
342
|
const showAll = ctx.args.includes('--all') || ctx.args.includes('-a');
|
|
340
343
|
const statuses = getLoopStatuses(process.cwd());
|
|
341
344
|
if (statuses.length === 0) {
|