@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
|
@@ -13,9 +13,135 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @implements #1362
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { dirname } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { findPackageRoot } from '../../cli/find-package-root.js';
|
|
19
|
+
import { readAiwgConfigCandidate, validateWorkerConfigCandidate, resolveParallelism, PROVIDER_PARALLELISM_DEFAULTS } from '../../config/aiwg-config.js';
|
|
17
20
|
export const PARALLELISM_BLOCK_START = '<!-- AIWG-PARALLELISM-CAP:START -->';
|
|
18
21
|
export const PARALLELISM_BLOCK_END = '<!-- AIWG-PARALLELISM-CAP:END -->';
|
|
22
|
+
/**
|
|
23
|
+
* One-line note rendered when the bundled model defaults cannot be loaded.
|
|
24
|
+
* The orchestration health block is omitted; the rest of the section renders
|
|
25
|
+
* unchanged so context regeneration never throws for a missing home install.
|
|
26
|
+
*/
|
|
27
|
+
export const PARALLELISM_HEALTH_UNRESOLVED_NOTE = 'Health values could not be resolved from the bundled defaults, so the orchestration health block is omitted.';
|
|
28
|
+
/**
|
|
29
|
+
* Locate this package's bundled AIWG defaults (`models-v2.json` under
|
|
30
|
+
* `agentic/...`) from the running code, whether it runs from a source
|
|
31
|
+
* checkout or an installed package. Uses the canonical package-root walk
|
|
32
|
+
* shared with the rest of src/ (`findPackageRoot`), never a hand-rolled
|
|
33
|
+
* relative path and never the user's home install.
|
|
34
|
+
*/
|
|
35
|
+
function resolveBundledAiwgHome() {
|
|
36
|
+
try {
|
|
37
|
+
return findPackageRoot(dirname(fileURLToPath(import.meta.url))) ?? undefined;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the AIWG home to pass to `ConfigLoader` for this generator's own
|
|
45
|
+
* read: an explicit, non-empty `AIWG_HOME` always wins; otherwise fall back
|
|
46
|
+
* to this package's own bundled defaults so regeneration does not depend on
|
|
47
|
+
* what (if anything) is installed at the user's home. This function only
|
|
48
|
+
* ever READS `process.env.AIWG_HOME` — it never sets or deletes it, so
|
|
49
|
+
* concurrent callers and any spawned children never observe a value this
|
|
50
|
+
* generator did not itself receive from the real environment.
|
|
51
|
+
*/
|
|
52
|
+
function resolveAiwgHome() {
|
|
53
|
+
return process.env.AIWG_HOME || resolveBundledAiwgHome();
|
|
54
|
+
}
|
|
55
|
+
function isBundledDefaultsFailure(error) {
|
|
56
|
+
return error instanceof Error && error.message.includes('Failed to load AIWG default config');
|
|
57
|
+
}
|
|
58
|
+
function oneLine(value, maxLen) {
|
|
59
|
+
return value.replace(/[\r\n|]+/g, ' ').trim().slice(0, maxLen);
|
|
60
|
+
}
|
|
61
|
+
/** At most this many group summaries render; the rest collapse to "+N more". */
|
|
62
|
+
export const MAX_SHOWN_GROUPS = 8;
|
|
63
|
+
/**
|
|
64
|
+
* Config-level member exclusions for one group, mirroring the static gates
|
|
65
|
+
* in `resolveWorkerPlan()` (`src/models/resolver.ts`): a member or its CLI
|
|
66
|
+
* installation flagged `enabled: false` is statically excluded. This is
|
|
67
|
+
* NOT the live eligibility verdict — `resolveWorkerPlan()` resolves
|
|
68
|
+
* eligibility per (group, member, effort) tuple against the current
|
|
69
|
+
* catalog and request, so a member excluded nowhere here can still be
|
|
70
|
+
* excluded for a specific role/task/effort, and vice versa is never true
|
|
71
|
+
* (a statically excluded member is always excluded live too). Only the
|
|
72
|
+
* per-member reasons render; the group itself is never labeled
|
|
73
|
+
* "eligible"/"not eligible" — see the request-scoped resolve guidance
|
|
74
|
+
* below the group list.
|
|
75
|
+
*
|
|
76
|
+
* A `requiredRoles` entry with no enabled covering member is a config
|
|
77
|
+
* error `validateParallelismConfig()` (and `resolveParallelism()` /
|
|
78
|
+
* `ConfigLoader.load()`, both called earlier in `buildParallelismSection()`)
|
|
79
|
+
* already rejects outright — a config reaching this function can never
|
|
80
|
+
* have one, so that case is not re-rendered here.
|
|
81
|
+
*/
|
|
82
|
+
function excludedMembers(parallelism, group) {
|
|
83
|
+
const excluded = [];
|
|
84
|
+
for (const member of group.members) {
|
|
85
|
+
if (member.enabled === false)
|
|
86
|
+
excluded.push(`${member.id} (member disabled)`);
|
|
87
|
+
else if (parallelism?.clis?.[member.cli]?.enabled === false)
|
|
88
|
+
excluded.push(`${member.id} (installation ${member.cli} disabled)`);
|
|
89
|
+
}
|
|
90
|
+
return excluded;
|
|
91
|
+
}
|
|
92
|
+
function groupSummaries(entries, parallelism) {
|
|
93
|
+
return entries.map(([id, group]) => {
|
|
94
|
+
const roles = [...new Set(group.members.flatMap(m => m.roles ?? []))].join('/');
|
|
95
|
+
const clis = [...new Set(group.members.map(m => m.cli))].join('/');
|
|
96
|
+
const parts = [`${oneLine(id, 64)} (members: ${group.members.length}`];
|
|
97
|
+
if (clis)
|
|
98
|
+
parts.push(`clis: ${oneLine(clis, 96)}`);
|
|
99
|
+
if (roles)
|
|
100
|
+
parts.push(`roles: ${oneLine(roles, 96)}`);
|
|
101
|
+
if (group.maxParallel !== undefined)
|
|
102
|
+
parts.push(`maxParallel: ${group.maxParallel}`);
|
|
103
|
+
if (group.requiredRoles?.length)
|
|
104
|
+
parts.push(`requiredRoles: ${group.requiredRoles.join('/')}`);
|
|
105
|
+
parts.push('configured');
|
|
106
|
+
const excluded = excludedMembers(parallelism, group);
|
|
107
|
+
if (excluded.length)
|
|
108
|
+
parts.push(`excluded members: ${oneLine(excluded.join(', '), 160)}`);
|
|
109
|
+
return parts.join('; ') + ')';
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* One configured health window with its origin. The origin mirrors
|
|
114
|
+
* `resolveWorkerEffectiveHealth()` (`src/serve/worker-invocation.ts`): a
|
|
115
|
+
* field the project config leaves unset resolves from the built-in defaults.
|
|
116
|
+
*/
|
|
117
|
+
function healthValue(health, field, fallback) {
|
|
118
|
+
const value = health?.[field] ?? fallback;
|
|
119
|
+
return { value, origin: health?.[field] === undefined ? 'default' : 'project config' };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Plain-language dispatch state line (#3050 item 5). Agents must not assume
|
|
123
|
+
* other worker CLIs are unavailable just because dispatch is off — they
|
|
124
|
+
* should detect them and offer the opt-in, not silently work around it.
|
|
125
|
+
*/
|
|
126
|
+
function workerDispatchStateLine(parallelism, setup) {
|
|
127
|
+
if (parallelism?.worker_dispatch === true) {
|
|
128
|
+
return '**Direct worker dispatch**: on (`parallelism.worker_dispatch`).';
|
|
129
|
+
}
|
|
130
|
+
// A recorded decline (#3050 review item 3) means a person already said no
|
|
131
|
+
// to this offer — render the plain off state without repeating the
|
|
132
|
+
// detect-and-offer instruction, so agents stop re-litigating a settled
|
|
133
|
+
// decision every session. The decline is a setup/onboarding preference,
|
|
134
|
+
// not worker policy, so it lives in `setup`, not in the frozen
|
|
135
|
+
// `parallelism` contract fragment (B-OG-29).
|
|
136
|
+
if (setup?.worker_dispatch_offer === 'declined') {
|
|
137
|
+
return '**Direct worker dispatch**: off (`parallelism.worker_dispatch`); a prior offer was declined '
|
|
138
|
+
+ '(`setup.worker_dispatch_offer`). Do not re-offer it. It can still be turned on with '
|
|
139
|
+
+ '`aiwg config set --project parallelism.worker_dispatch true` if the user asks for it directly.';
|
|
140
|
+
}
|
|
141
|
+
return '**Direct worker dispatch**: off (`parallelism.worker_dispatch`). Do not assume other worker CLIs '
|
|
142
|
+
+ 'are unavailable — detect them yourself and offer `aiwg config set --project parallelism.worker_dispatch true` '
|
|
143
|
+
+ 'to the user if it would help.';
|
|
144
|
+
}
|
|
19
145
|
function delegationSupport(provider) {
|
|
20
146
|
switch (provider) {
|
|
21
147
|
case 'antigravity':
|
|
@@ -45,12 +171,34 @@ function delegationSupport(provider) {
|
|
|
45
171
|
* - `AIWG_HIDE_PARALLELISM_IN_CONTEXT=1` is set
|
|
46
172
|
* - No `.aiwg/aiwg.config` exists at the project path
|
|
47
173
|
*/
|
|
48
|
-
export async function buildParallelismSection(projectPath) {
|
|
174
|
+
export async function buildParallelismSection(projectPath, deps = {}) {
|
|
49
175
|
if (process.env.AIWG_HIDE_PARALLELISM_IN_CONTEXT === '1')
|
|
50
176
|
return '';
|
|
51
|
-
|
|
177
|
+
// Step 1: the project config, independently validated except for the
|
|
178
|
+
// worker-model defaults (never throws solely because bundled defaults are
|
|
179
|
+
// unreachable — any error here is a genuine config problem and stays fatal).
|
|
180
|
+
const cfg = deps.readConfig
|
|
181
|
+
? await deps.readConfig(projectPath)
|
|
182
|
+
: await readAiwgConfigCandidate(projectPath);
|
|
52
183
|
if (!cfg)
|
|
53
184
|
return '';
|
|
185
|
+
// Step 2: worker-model defaults validation, attempted only when dispatch
|
|
186
|
+
// is enabled. A bundled-defaults failure degrades (health/group details
|
|
187
|
+
// are omitted below with a one-line note); every other error stays fatal.
|
|
188
|
+
let healthUnresolved = false;
|
|
189
|
+
if (cfg.parallelism?.worker_dispatch === true) {
|
|
190
|
+
try {
|
|
191
|
+
if (deps.validateWorkerConfig)
|
|
192
|
+
await deps.validateWorkerConfig(projectPath, cfg);
|
|
193
|
+
else
|
|
194
|
+
await validateWorkerConfigCandidate(projectPath, cfg, { aiwgHome: resolveAiwgHome() });
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (!isBundledDefaultsFailure(error))
|
|
198
|
+
throw error;
|
|
199
|
+
healthUnresolved = true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
54
202
|
const primary = cfg.providers[0];
|
|
55
203
|
const resolved = resolveParallelism(cfg.parallelism, primary);
|
|
56
204
|
const providerDefaults = primary && PROVIDER_PARALLELISM_DEFAULTS[primary];
|
|
@@ -84,20 +232,53 @@ export async function buildParallelismSection(projectPath) {
|
|
|
84
232
|
lines.push(`*Rationale*: ${resolved.rationale}`);
|
|
85
233
|
}
|
|
86
234
|
lines.push('');
|
|
87
|
-
lines.push('
|
|
88
|
-
lines.push('');
|
|
89
|
-
lines.push('For each non-trivial task, assess whether it contains independent, bounded subtasks that can run concurrently. When delegation is supported, prefer the deployed model-pinned wrappers by task characteristics and consequence:');
|
|
90
|
-
lines.push('');
|
|
91
|
-
lines.push('- `aiwg-model-efficiency-worker`: discovery, inventory, focused edits, and other bounded low-cost work.');
|
|
92
|
-
lines.push('- `aiwg-model-coding-worker`: implementation, tests, debugging, and routine technical delivery.');
|
|
93
|
-
lines.push('- `aiwg-model-reasoning-worker`: architecture, synthesis, difficult analysis, and high-consequence review.');
|
|
94
|
-
lines.push('');
|
|
95
|
-
lines.push('Do not delegate trivial work, tightly coupled changes, serial dependencies, or tasks likely to collide in shared state; also keep work local when coordination costs exceed the expected benefit. Parallelize only independent work, and take the MIN of provider limits, `max_parallel_subagents`, `AIWG_CONTEXT_WINDOW` budget, framework-specific caps (including the RLM 7-agent hard cap for RLM dispatches), and natural task decomposition. Bump the project cap via `aiwg config set --project parallelism.max_parallel_subagents N`.');
|
|
96
|
-
lines.push('');
|
|
97
|
-
lines.push('The primary agent retains orchestration, final integration, conflict resolution, validation, and user-facing accountability.');
|
|
235
|
+
lines.push('Delegation policy and model-worker selection: `aiwg show rule subagent-scoping`.');
|
|
236
|
+
lines.push('After changing project parallelism with `aiwg config set/reset --project`, follow the emitted provider-specific regeneration commands and run `aiwg workspace-context doctor`.');
|
|
98
237
|
lines.push('');
|
|
99
238
|
lines.push(delegationSupport(primary));
|
|
100
239
|
lines.push('');
|
|
240
|
+
lines.push(workerDispatchStateLine(cfg.parallelism, cfg.setup));
|
|
241
|
+
lines.push('');
|
|
242
|
+
// Group dispatch disabled (worker_dispatch unset/false): the resolver reports
|
|
243
|
+
// `disabled`, so no group block renders — the subagent-scoping pointer above
|
|
244
|
+
// remains available.
|
|
245
|
+
if (cfg.parallelism?.worker_dispatch === true && healthUnresolved) {
|
|
246
|
+
lines.push(PARALLELISM_HEALTH_UNRESOLVED_NOTE);
|
|
247
|
+
lines.push('');
|
|
248
|
+
}
|
|
249
|
+
else if (cfg.parallelism?.worker_dispatch === true) {
|
|
250
|
+
const health = cfg.parallelism?.health;
|
|
251
|
+
const check = healthValue(health, 'checkSeconds', 15);
|
|
252
|
+
const startup = healthValue(health, 'startupSeconds', 60);
|
|
253
|
+
const quiet = healthValue(health, 'quietSeconds', 90);
|
|
254
|
+
const stall = healthValue(health, 'stallSeconds', 300);
|
|
255
|
+
const hard = healthValue(health, 'hardTimeoutSeconds', 1800);
|
|
256
|
+
lines.push('### Orchestration groups (group dispatch enabled)');
|
|
257
|
+
lines.push('');
|
|
258
|
+
const entries = Object.entries(cfg.parallelism?.groups ?? {});
|
|
259
|
+
if (entries.length > 0) {
|
|
260
|
+
// Slice before summarizing so at most MAX_SHOWN_GROUPS summaries are built.
|
|
261
|
+
const shown = groupSummaries(entries.slice(0, MAX_SHOWN_GROUPS), cfg.parallelism).join(' | ');
|
|
262
|
+
const hidden = entries.length - MAX_SHOWN_GROUPS;
|
|
263
|
+
lines.push(`Configured groups: ${shown}${hidden > 0 ? ` (+${hidden} more)` : ''}`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
lines.push('Configured groups: none — group dispatch is enabled but no groups are configured; the subagent-scoping rule applies.');
|
|
267
|
+
}
|
|
268
|
+
lines.push('');
|
|
269
|
+
lines.push('A group above shown as configured, with excluded members or an uncovered required role listed, is a static config read — not a live eligibility verdict. Eligibility is resolved per (group, member, effort) tuple against the current catalog and request; see `aiwg models resolve` below to check a specific role/task/group.');
|
|
270
|
+
lines.push('');
|
|
271
|
+
lines.push('Tier 0 direct handoff is the default: use your own shell or a qualified MCP worker tool. No Mission/MC session, scheduler, daemon, or activation marker is needed. Self-count active native + CLI + MCP workers, take the minimum of the project, group, CLI, model, and context caps, and launch each writing task once.');
|
|
272
|
+
lines.push('');
|
|
273
|
+
lines.push('Before resolving, qualify the installed CLIs and configured model roles with `aiwg doctor --probe-workers --qualify` (`--yes` for headless confirmation).');
|
|
274
|
+
lines.push('Agents pass `--authorize-premium` to `aiwg models resolve` only after the human explicitly confirmed the premium escalation (escalation-discipline rule); authorization applies to that resolution only.');
|
|
275
|
+
lines.push('Resolve each bounded brief with `aiwg models resolve --role <role> --task <class> --group <group> --brief <file> --workdir <tree> --final-output <file> --transport shell --format shell`. Copy the exact rendered command or the MCP server/tool/arguments byte-for-byte; never assemble vendor flags from memory. Re-resolve after any brief, profile, model, or workspace change. `--format shell` prints only the launch command: to see the resolved health windows for an attempt, use `--format json` (the default) and read `invocation.health` with its per-field `origins`.');
|
|
276
|
+
lines.push('');
|
|
277
|
+
lines.push(`Configured health windows (each followed by its origin — \`default\` or \`project config\`): check every ${check.value}s (${check.origin}); confirm startup within ${startup.value}s (${startup.origin}); quiet limit ${quiet.value}s (${quiet.origin}); stall limit ${stall.value}s (${stall.origin}); hard stop ${hard.value}s (${hard.origin}). Per-attempt windows scale quiet and stall by the single largest applicable role/effort/model factor, never their product (for example, reasoning at \`xhigh\` effort resolves 180s/600s from the 90s/300s defaults; an effective 1.25 scale gives 112.5s/375s). Only the hard deadline and its diagnostic/termination grace periods are capped by the remaining wall-clock and transport ceilings; startup, quiet, and stall keep their configured or scaled values, and \`truncatedWindows\` instead records when one of them would exceed that capped deadline (\`resolveWorkerEffectiveHealth()\` in \`src/serve/worker-invocation.ts\`). Resolved values win over these configured values.`);
|
|
278
|
+
lines.push('');
|
|
279
|
+
lines.push('Supervise by observer state, never by suspicion. `quiet` (no observed activity for the quiet window, reported with confidence `suspected`) is not a stop: read the status (`aiwg ralph-external --status --workers --runs-root <dir> --json` is read-only and never kills or retries), check owned-worktree progress, and keep waiting — the observer’s `shouldStop()` stays false. `stalled` (no progress for the stall window) opens diagnosis through the diagnostic grace period; only `hung` (still no progress after grace, with the process live and connected) authorizes a no-progress stop — and only a worker this conductor owns. The launcher also stops independently of progress state on `failed-to-start`, the hard wall-clock deadline (`HARD_DEADLINE`), the step-count limit (`STEP_LIMIT`), and a fatal observer-record failure (`tools/ralph-external/session-launcher.mjs`). Confirm the stop (a sent signal, lease expiry, or final-file presence is not proof — only a confirmed exit is), preserve partial work for independent verification, then re-resolve within remaining attempts and budgets. Observer loss (`OBSERVER_GAP`, `DISCONNECTED`, degraded or unobserved coverage, opaque MCP output) is unknown, never worker failure: keep polling owned run files and processes from the shell at the same cadence. Heartbeats and log bytes are not progress. On correlated failure across workers sharing one account, quota, or host, pause further launches there and report cause and scope.');
|
|
280
|
+
lines.push('');
|
|
281
|
+
}
|
|
101
282
|
lines.push(PARALLELISM_BLOCK_END);
|
|
102
283
|
lines.push('');
|
|
103
284
|
return lines.join('\n');
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* an operator runs the explicit migration workflow.
|
|
8
8
|
*/
|
|
9
9
|
import { createHash } from 'node:crypto';
|
|
10
|
-
import { promises as fs } from 'node:fs';
|
|
10
|
+
import { promises as fs, existsSync } from 'node:fs';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
11
12
|
import * as path from 'node:path';
|
|
12
13
|
import { buildAiwgMdContent } from './aiwg-md.js';
|
|
13
14
|
import { buildNormalizedAiwgMd } from './finalization.js';
|
|
@@ -592,11 +593,106 @@ function sensitiveEvidence(content) {
|
|
|
592
593
|
}
|
|
593
594
|
return findings;
|
|
594
595
|
}
|
|
596
|
+
// Directory names the context-graph walk always skips, regardless of where
|
|
597
|
+
// the walk root is: VCS/build output that is never hand-authored project
|
|
598
|
+
// content (#277, pre-existing) plus two reserved, self-identifying names
|
|
599
|
+
// that are never legitimately a real project directory.
|
|
600
|
+
const CONTEXT_WALK_ALWAYS_IGNORED_DIR_NAMES = new Set([
|
|
601
|
+
'.git', 'node_modules', 'dist', 'build', 'coverage', '.aiwg',
|
|
602
|
+
]);
|
|
603
|
+
// Cache/registry directory names that are only skipped when the walk root
|
|
604
|
+
// is the home directory itself (#277 fix-round). A project subtree that
|
|
605
|
+
// happens to be named `.cache`, `target`, `.gradle`, etc. is NOT generated
|
|
606
|
+
// data and must still be scanned — these names are only reliably "cache,
|
|
607
|
+
// not project" when they sit directly under $HOME. `Library/Caches` and
|
|
608
|
+
// `.local/share` are two-segment (parent + name) patterns, handled
|
|
609
|
+
// separately below.
|
|
610
|
+
const HOME_LEVEL_CACHE_DIR_NAMES = new Set([
|
|
611
|
+
'.cache', '.cargo', '.rustup', '.npm', '.nvm', '.pnpm-store',
|
|
612
|
+
'.gradle', '.m2', 'Trash',
|
|
613
|
+
]);
|
|
614
|
+
/** True when `dirPath` contains `markerFile` — a cheap, synchronous, read-only check. */
|
|
615
|
+
function hasMarkerFile(dirPath, markerFile) {
|
|
616
|
+
return existsSync(path.join(dirPath, markerFile));
|
|
617
|
+
}
|
|
618
|
+
/** A `target` directory is Cargo/build output only when it carries the
|
|
619
|
+
* standard `CACHEDIR.TAG` marker, or sits next to a `Cargo.toml` — not
|
|
620
|
+
* merely because it is named `target` (#277 fix-round). */
|
|
621
|
+
function isGeneratedTargetDir(dirPath) {
|
|
622
|
+
if (hasMarkerFile(dirPath, 'CACHEDIR.TAG'))
|
|
623
|
+
return true;
|
|
624
|
+
return existsSync(path.join(path.dirname(dirPath), 'Cargo.toml'));
|
|
625
|
+
}
|
|
626
|
+
/** A `venv`/`.venv` directory is a Python virtualenv only when it carries
|
|
627
|
+
* `pyvenv.cfg` — not merely because of its name (#277 fix-round). */
|
|
628
|
+
function isPythonVenvDir(dirPath) {
|
|
629
|
+
return hasMarkerFile(dirPath, 'pyvenv.cfg');
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Whether the context-graph walk should skip `entryName` (a directory
|
|
633
|
+
* directly under `directory`) without descending into it.
|
|
634
|
+
*
|
|
635
|
+
* `isHomeRoot` gates the home-level cache list and the `Library/Caches` /
|
|
636
|
+
* `.local/share` two-segment patterns — they apply only when the overall
|
|
637
|
+
* walk root is $HOME, never for an arbitrary project subtree that happens
|
|
638
|
+
* to share one of those names (#277 fix-round).
|
|
639
|
+
*/
|
|
640
|
+
export function shouldSkipContextWalkDir(directory, entryName, isHomeRoot) {
|
|
641
|
+
if (CONTEXT_WALK_ALWAYS_IGNORED_DIR_NAMES.has(entryName))
|
|
642
|
+
return true;
|
|
643
|
+
if (entryName.startsWith('.context-migration-'))
|
|
644
|
+
return true;
|
|
645
|
+
const childPath = path.join(directory, entryName);
|
|
646
|
+
if (entryName === 'target' && isGeneratedTargetDir(childPath))
|
|
647
|
+
return true;
|
|
648
|
+
if ((entryName === 'venv' || entryName === '.venv') && isPythonVenvDir(childPath))
|
|
649
|
+
return true;
|
|
650
|
+
// Codex's own plugin/temp scratch — a known, specific noise source named
|
|
651
|
+
// in the original report, not a broad `.tmp` exclusion (#277 fix-round).
|
|
652
|
+
if (entryName === '.tmp' && path.basename(directory) === '.codex')
|
|
653
|
+
return true;
|
|
654
|
+
if (isHomeRoot) {
|
|
655
|
+
if (HOME_LEVEL_CACHE_DIR_NAMES.has(entryName))
|
|
656
|
+
return true;
|
|
657
|
+
if (entryName === 'Caches' && path.basename(directory) === 'Library')
|
|
658
|
+
return true;
|
|
659
|
+
if (entryName === 'share' && path.basename(directory) === '.local')
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
/** Walk depth/entry bounds for the context-graph walk (#277). A hit sets
|
|
665
|
+
* `truncated: true` on the result instead of silently stopping. Overridable
|
|
666
|
+
* via environment for tests that need to exercise the bound without
|
|
667
|
+
* building a correspondingly large fixture tree. */
|
|
668
|
+
function readPositiveIntEnv(name, fallback) {
|
|
669
|
+
const raw = process.env[name];
|
|
670
|
+
if (!raw)
|
|
671
|
+
return fallback;
|
|
672
|
+
const parsed = Number.parseInt(raw, 10);
|
|
673
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
674
|
+
}
|
|
675
|
+
const CONTEXT_WALK_MAX_DEPTH = readPositiveIntEnv('AIWG_CONTEXT_WALK_MAX_DEPTH', 10);
|
|
676
|
+
const CONTEXT_WALK_MAX_DIRECTORIES = readPositiveIntEnv('AIWG_CONTEXT_WALK_MAX_DIRECTORIES', 20_000);
|
|
595
677
|
async function nestedInstructionFiles(projectPath) {
|
|
596
678
|
const found = [];
|
|
597
|
-
const ignored = new Set(['.git', 'node_modules', 'dist', 'build', 'coverage', '.aiwg']);
|
|
598
679
|
const artifactRoot = path.resolve(resolveProjectAiwgDir(projectPath));
|
|
599
|
-
|
|
680
|
+
// Running from $HOME is the exact shape of #277: bound the walk to the
|
|
681
|
+
// top level and apply the home-level cache exclusions instead of
|
|
682
|
+
// recursing into every cache/registry/venv underneath it. A markerless
|
|
683
|
+
// but otherwise ordinary (non-home) project root keeps the full bounded
|
|
684
|
+
// walk — "no project marker" is not evidence the directory is generated
|
|
685
|
+
// data (#277 fix-round).
|
|
686
|
+
const isHomeDirectory = path.resolve(projectPath) === path.resolve(homedir());
|
|
687
|
+
const maxDepth = isHomeDirectory ? 1 : CONTEXT_WALK_MAX_DEPTH;
|
|
688
|
+
let visitedDirectories = 0;
|
|
689
|
+
let truncated = false;
|
|
690
|
+
async function walk(directory, depth) {
|
|
691
|
+
if (depth > maxDepth || visitedDirectories >= CONTEXT_WALK_MAX_DIRECTORIES) {
|
|
692
|
+
truncated = true;
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
visitedDirectories += 1;
|
|
600
696
|
let entries;
|
|
601
697
|
try {
|
|
602
698
|
entries = await fs.readdir(directory, { withFileTypes: true });
|
|
@@ -605,12 +701,14 @@ async function nestedInstructionFiles(projectPath) {
|
|
|
605
701
|
return;
|
|
606
702
|
}
|
|
607
703
|
for (const entry of entries) {
|
|
704
|
+
// Dirent.isDirectory() is false for symlinks (it reflects the entry
|
|
705
|
+
// itself, not its target), so symlinked directories are never
|
|
706
|
+
// followed out of the root by this walk.
|
|
608
707
|
if (entry.isDirectory()) {
|
|
609
708
|
const child = path.join(directory, entry.name);
|
|
610
|
-
if (!
|
|
611
|
-
&& !entry.name.startsWith('.context-migration-')
|
|
709
|
+
if (!shouldSkipContextWalkDir(directory, entry.name, isHomeDirectory)
|
|
612
710
|
&& path.resolve(child) !== artifactRoot)
|
|
613
|
-
await walk(child);
|
|
711
|
+
await walk(child, depth + 1);
|
|
614
712
|
}
|
|
615
713
|
else if (['AGENTS.md', 'CLAUDE.md', 'WARP.md'].includes(entry.name)) {
|
|
616
714
|
const relative = path.relative(projectPath, path.join(directory, entry.name)).replace(/\\/g, '/');
|
|
@@ -621,8 +719,8 @@ async function nestedInstructionFiles(projectPath) {
|
|
|
621
719
|
}
|
|
622
720
|
}
|
|
623
721
|
}
|
|
624
|
-
await walk(projectPath);
|
|
625
|
-
return found.sort((a, b) => a.localeCompare(b));
|
|
722
|
+
await walk(projectPath, 1);
|
|
723
|
+
return { files: found.sort((a, b) => a.localeCompare(b)), truncated };
|
|
626
724
|
}
|
|
627
725
|
async function migratedProviderFiles(projectPath) {
|
|
628
726
|
const directory = projectAiwgPath(projectPath, 'context', 'providers');
|
|
@@ -638,10 +736,11 @@ async function migratedProviderFiles(projectPath) {
|
|
|
638
736
|
}
|
|
639
737
|
export async function auditWorkspaceContext(projectPath) {
|
|
640
738
|
const extractedProject = await extractExistingProjectContext(projectPath);
|
|
739
|
+
const nested = await nestedInstructionFiles(projectPath);
|
|
641
740
|
const candidates = new Set([
|
|
642
741
|
'WORKSPACE.md',
|
|
643
742
|
...LEGACY_ROOT_FILES,
|
|
644
|
-
...
|
|
743
|
+
...nested.files,
|
|
645
744
|
...await migratedProviderFiles(projectPath),
|
|
646
745
|
]);
|
|
647
746
|
const sources = [];
|
|
@@ -740,6 +839,7 @@ export async function auditWorkspaceContext(projectPath) {
|
|
|
740
839
|
overlaps,
|
|
741
840
|
conflicts,
|
|
742
841
|
sensitiveFindings,
|
|
842
|
+
contextWalkTruncated: nested.truncated,
|
|
743
843
|
plan: {
|
|
744
844
|
routing,
|
|
745
845
|
scopeReview,
|
|
@@ -1039,6 +1139,13 @@ export async function workspaceLinkedFiles(projectPath) {
|
|
|
1039
1139
|
export async function diagnoseWorkspaceContext(projectPath) {
|
|
1040
1140
|
const diagnostics = [];
|
|
1041
1141
|
const audit = await auditWorkspaceContext(projectPath);
|
|
1142
|
+
if (audit.contextWalkTruncated) {
|
|
1143
|
+
diagnostics.push({
|
|
1144
|
+
severity: 'info',
|
|
1145
|
+
code: 'context-walk-truncated',
|
|
1146
|
+
message: 'Nested-instruction-file walk stopped early (depth/entry bound reached, or the root looks like $HOME or has no project markers); the context graph may be incomplete.',
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1042
1149
|
const workspacePath = path.join(projectPath, 'WORKSPACE.md');
|
|
1043
1150
|
const workspace = await readOptional(workspacePath);
|
|
1044
1151
|
if (!workspace) {
|
|
@@ -13,6 +13,7 @@ import { promises as fs } from 'node:fs';
|
|
|
13
13
|
import * as path from 'node:path';
|
|
14
14
|
import { homedir } from 'node:os';
|
|
15
15
|
import { substituteEnvVars } from './shim.js';
|
|
16
|
+
import { tomlString } from '../../mcp/toml-string.mjs';
|
|
16
17
|
/** Codex-native event names (subset; extend when verified against codex-rs). */
|
|
17
18
|
const CODEX_EVENT_MAP = {
|
|
18
19
|
PreToolUse: 'before_tool',
|
|
@@ -44,16 +45,16 @@ export function renderCodexHookToml(source) {
|
|
|
44
45
|
const subCommand = substituteEnvVars(source.command, 'codex');
|
|
45
46
|
const subArgs = (source.args || []).map((a) => substituteEnvVars(a, 'codex'));
|
|
46
47
|
lines.push(`[[hooks.${codexEvent}]]`);
|
|
47
|
-
lines.push(`# AIWG-managed hook: ${source.id} — ${source.description}`);
|
|
48
|
-
lines.push(`command =
|
|
48
|
+
lines.push(`# AIWG-managed hook: ${`${source.id} — ${source.description}`.replace(/[\x00-\x1f\x7f]/g, ' ')}`);
|
|
49
|
+
lines.push(`command = ${tomlString(subCommand)}`);
|
|
49
50
|
if (subArgs.length > 0) {
|
|
50
|
-
lines.push(`args = [${subArgs.map(
|
|
51
|
+
lines.push(`args = [${subArgs.map(tomlString).join(', ')}]`);
|
|
51
52
|
}
|
|
52
53
|
if (source.safetyCritical) {
|
|
53
54
|
lines.push(`# safety-critical: cannot be auto-removed without --allow-unsafe-shadow`);
|
|
54
55
|
}
|
|
55
56
|
lines.push(`_aiwg_managed = true`);
|
|
56
|
-
lines.push(`_aiwg_id =
|
|
57
|
+
lines.push(`_aiwg_id = ${tomlString(source.id)}`);
|
|
57
58
|
lines.push('');
|
|
58
59
|
}
|
|
59
60
|
return lines.join('\n');
|
|
@@ -95,7 +96,7 @@ export async function translateForCodex(source, options) {
|
|
|
95
96
|
result.skipReason = 'degrade-on declared codex';
|
|
96
97
|
return result;
|
|
97
98
|
}
|
|
98
|
-
const configPath = path.join(homedir(), '.codex', 'config.toml');
|
|
99
|
+
const configPath = path.join(process.env.CODEX_HOME || path.join(homedir(), '.codex'), 'config.toml');
|
|
99
100
|
const block = renderCodexHookToml(source);
|
|
100
101
|
if (block.trim().length === 0) {
|
|
101
102
|
result.skipped = true;
|
|
@@ -99,7 +99,7 @@ async function main() {
|
|
|
99
99
|
console.log(` node ${generatedServer.files.server}`);
|
|
100
100
|
console.log();
|
|
101
101
|
console.log(' To register with Claude Code:');
|
|
102
|
-
console.log(' Add to .
|
|
102
|
+
console.log(' Add to .mcp.json:');
|
|
103
103
|
console.log(' {');
|
|
104
104
|
console.log(' "mcpServers": {');
|
|
105
105
|
console.log(' "git": {');
|
|
@@ -161,7 +161,7 @@ function createManifest(serverId, serverName, analyzerResult, config) {
|
|
|
161
161
|
resources: [],
|
|
162
162
|
prompts: [],
|
|
163
163
|
dependencies: {
|
|
164
|
-
runtime: ['node >=
|
|
164
|
+
runtime: ['node >= 24'],
|
|
165
165
|
external: [
|
|
166
166
|
`${analyzerResult.metadata.sourceName}${analyzerResult.metadata.sourceVersion ? ' >= ' + analyzerResult.metadata.sourceVersion : ''}`
|
|
167
167
|
]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export class RuntimeDiscovery {
|
|
2
|
+
basePath: string;
|
|
3
|
+
constructor(basePath?: string | null, options?: { cwd?: string; quiet?: boolean });
|
|
4
|
+
discover(options?: { force?: boolean }): Promise<any>;
|
|
5
|
+
verify(): Promise<any>;
|
|
6
|
+
getCatalog(): Promise<any>;
|
|
7
|
+
generateDefinition(): Promise<any>;
|
|
8
|
+
checkTool(toolName: string): Promise<any>;
|
|
9
|
+
getSummary(): Promise<any>;
|
|
10
|
+
}
|