@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
|
@@ -11,10 +11,19 @@
|
|
|
11
11
|
import realFs from 'fs';
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import os from 'os';
|
|
14
|
+
import yaml from 'yaml';
|
|
14
15
|
import { classifyModelRole } from './model-role.mjs';
|
|
15
16
|
import { createHash } from 'crypto';
|
|
16
17
|
import { createRequire } from 'module';
|
|
17
|
-
import {
|
|
18
|
+
import { importImpl } from '../../_resolve-impl.mjs';
|
|
19
|
+
|
|
20
|
+
const { parseRuleFrontmatter, inferRuleActivation } = await importImpl(import.meta.url, 'rules/activation.mjs');
|
|
21
|
+
const { resolveRulesInlineBudget, DEFAULT_RULES_INLINE_BUDGET_TOKENS } = await importImpl(import.meta.url, 'rules/inline-budget.mjs');
|
|
22
|
+
export { DEFAULT_RULES_INLINE_BUDGET_TOKENS, parseRuleFrontmatter as parseRuleActivation };
|
|
23
|
+
const { boundedExecFileSync } = await importImpl(import.meta.url, 'process/bounded-child-process.mjs');
|
|
24
|
+
const { extractFrameworkSlug, sameSkillOwner, canDeploySkill, pruneRecordedSkillFiles, releaseSkillOwnership } =
|
|
25
|
+
await importImpl(import.meta.url, 'providers/skill-ownership.mjs');
|
|
26
|
+
export { extractFrameworkSlug, sameSkillOwner, pruneRecordedSkillFiles, releaseSkillOwnership };
|
|
18
27
|
|
|
19
28
|
// Use graceful-fs to prevent EMFILE crashes on systems with low ulimit.
|
|
20
29
|
// graceful-fs queues open() calls when FD pressure is detected and retries
|
|
@@ -240,8 +249,9 @@ export function updateSidecarManifest(dir, deployedEntries, opts) {
|
|
|
240
249
|
const existing = readSidecarManifest(dir) || { managed: {} };
|
|
241
250
|
|
|
242
251
|
for (const entry of deployedEntries) {
|
|
243
|
-
const { filename, hash, frameworkSlug, kind } = entry;
|
|
252
|
+
const { filename, hash, frameworkSlug, kind, sourcePath } = entry;
|
|
244
253
|
const sidecarEntry = { hash: `sha256:${hash}`, source, version };
|
|
254
|
+
if (sourcePath) sidecarEntry.sourcePath = sourcePath;
|
|
245
255
|
if (frameworkSlug) sidecarEntry.frameworkSlug = frameworkSlug;
|
|
246
256
|
// `kind` marks artifacts whose lifecycle is governed elsewhere — currently
|
|
247
257
|
// only `skill-command` wrappers, which follow their source skill (#2507).
|
|
@@ -252,26 +262,6 @@ export function updateSidecarManifest(dir, deployedEntries, opts) {
|
|
|
252
262
|
writeSidecarManifest(dir, existing, dryRun);
|
|
253
263
|
}
|
|
254
264
|
|
|
255
|
-
// ============================================================================
|
|
256
|
-
// Cross-Framework Collision Detection (#1169)
|
|
257
|
-
// ============================================================================
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Extract the framework slug from a source file path.
|
|
261
|
-
*
|
|
262
|
-
* Recognizes paths under `agentic/code/frameworks/<slug>/...` and
|
|
263
|
-
* `agentic/code/addons/<slug>/...`. Returns null for paths outside
|
|
264
|
-
* those namespaces (operator-authored bundles, addons under
|
|
265
|
-
* `.aiwg/addons/`, etc.) — those don't get collision-tracked.
|
|
266
|
-
*/
|
|
267
|
-
export function extractFrameworkSlug(srcPath) {
|
|
268
|
-
if (typeof srcPath !== 'string') return null;
|
|
269
|
-
// Normalize separators for cross-platform matching
|
|
270
|
-
const normalized = srcPath.replace(/\\/g, '/');
|
|
271
|
-
const m = normalized.match(/agentic\/code\/(?:frameworks|addons)\/([^/]+)\//);
|
|
272
|
-
return m ? m[1] : null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
265
|
// ============================================================================
|
|
276
266
|
// Model Configuration
|
|
277
267
|
// ============================================================================
|
|
@@ -376,41 +366,38 @@ const PROVIDER_TO_PLATFORM = {
|
|
|
376
366
|
|
|
377
367
|
/**
|
|
378
368
|
* Parse the platforms: field from a SKILL.md frontmatter block.
|
|
379
|
-
*
|
|
380
|
-
* Returns null if
|
|
381
|
-
* Returns an empty array
|
|
369
|
+
* Accepts a string or a list of strings; all alone means unrestricted.
|
|
370
|
+
* Returns null if platforms is missing, or no frontmatter is present.
|
|
371
|
+
* Returns an empty array for malformed frontmatter or invalid platforms.
|
|
382
372
|
*/
|
|
383
373
|
export function parseSkillPlatforms(content) {
|
|
384
|
-
|
|
385
|
-
if (
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
// Inline array: platforms: [claude-code, codex] or platforms: [all]
|
|
390
|
-
const inlineMatch = fm.match(/^platforms:\s*\[([^\]]*)\]/m);
|
|
391
|
-
if (inlineMatch) {
|
|
392
|
-
const items = inlineMatch[1].split(',').map(s => s.trim()).filter(Boolean);
|
|
393
|
-
if (items.length === 0 || (items.length === 1 && items[0] === 'all')) return null;
|
|
394
|
-
return items;
|
|
374
|
+
// A leading UTF-8 BOM must not hide the frontmatter (and its restrictions).
|
|
375
|
+
if (content.charCodeAt(0) === 0xfeff) content = content.slice(1);
|
|
376
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)^---[ \t]*(?:\r?\n|$)/m);
|
|
377
|
+
if (!fmMatch || fmMatch.index !== 0) {
|
|
378
|
+
return /^---[ \t]*(?:\r?\n|$)/.test(content) ? [] : null;
|
|
395
379
|
}
|
|
396
380
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
.map(line => line.match(/^[ \t]+-[ \t]+(\S+)/)?.[1])
|
|
406
|
-
.filter(Boolean);
|
|
407
|
-
return items.length > 0 ? items : null;
|
|
381
|
+
let metadata;
|
|
382
|
+
try {
|
|
383
|
+
const document = yaml.parseDocument(fmMatch[1]);
|
|
384
|
+
if (document.errors.length > 0) return [];
|
|
385
|
+
if (!document.contents) return null; // Empty frontmatter has no restrictions.
|
|
386
|
+
metadata = document.toJS();
|
|
387
|
+
} catch {
|
|
388
|
+
return [];
|
|
408
389
|
}
|
|
390
|
+
if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) return [];
|
|
391
|
+
// The yaml package leaves merge keys unresolved, so platforms could arrive only
|
|
392
|
+
// through `<<`; without an explicit key that is ambiguous, so fail closed.
|
|
393
|
+
if (!Object.hasOwn(metadata, 'platforms')) return Object.hasOwn(metadata, '<<') ? [] : null;
|
|
409
394
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
395
|
+
const platforms = metadata.platforms;
|
|
396
|
+
const items = typeof platforms === 'string' ? [platforms] : platforms;
|
|
397
|
+
if (!Array.isArray(items) || !items.every(item => typeof item === 'string')) return [];
|
|
398
|
+
const normalized = items.map(item => item.trim());
|
|
399
|
+
if (normalized.some(item => !item)) return [];
|
|
400
|
+
return normalized.length === 1 && normalized[0] === 'all' ? null : normalized;
|
|
414
401
|
}
|
|
415
402
|
|
|
416
403
|
/**
|
|
@@ -762,7 +749,7 @@ export function deployFiles(files, destDir, opts, transformFn) {
|
|
|
762
749
|
|
|
763
750
|
// Read and transform source content (needed for content-equality check
|
|
764
751
|
// and the collision-vs-duplicate distinction)
|
|
765
|
-
const srcContent = fs.readFileSync(f, 'utf8');
|
|
752
|
+
const srcContent = injectBoundRules(fs.readFileSync(f, 'utf8'), f, opts);
|
|
766
753
|
let transformedContent = transformFn ? transformFn(f, srcContent, opts) : srcContent;
|
|
767
754
|
|
|
768
755
|
// Rule triggers are index metadata, not something the reading agent needs.
|
|
@@ -901,7 +888,7 @@ export function deployFiles(files, destDir, opts, transformFn) {
|
|
|
901
888
|
if (dryRun) console.log(`[dry-run] deploy ${a.src} -> ${a.dest} (${a.reason})`);
|
|
902
889
|
else writeFile(a.dest, a.content, false);
|
|
903
890
|
if (verbose) console.log(`deployed ${path.basename(a.src)} -> ${path.relative(process.cwd(), a.dest)} (${a.reason})`);
|
|
904
|
-
deployedEntries.push({ filename: path.basename(a.dest), hash: a.hash, frameworkSlug: a.frameworkSlug });
|
|
891
|
+
deployedEntries.push({ filename: path.basename(a.dest), hash: a.hash, frameworkSlug: a.frameworkSlug, sourcePath: path.resolve(a.src) });
|
|
905
892
|
} else if (a.type === 'skip') {
|
|
906
893
|
if (verbose) console.log(`skip (${a.reason}): ${path.basename(a.dest)}`);
|
|
907
894
|
// Preserve existing sidecar entries for skipped files
|
|
@@ -1113,7 +1100,7 @@ export function deploySkillsWithKernelRouting(
|
|
|
1113
1100
|
// Standard-dir cleanup (#1217): when we're NOT copying standard
|
|
1114
1101
|
// skills, anything AIWG-named under standardDestDir is a legacy
|
|
1115
1102
|
// mirror from a rc.13-or-earlier deploy. Prune to clean up.
|
|
1116
|
-
let prunedFromStandardDir =
|
|
1103
|
+
let prunedFromStandardDir = pruneMissingStandardSkills(standardDestDir, opts);
|
|
1117
1104
|
if (
|
|
1118
1105
|
!copyStandardSkills &&
|
|
1119
1106
|
standardDestDir &&
|
|
@@ -1550,6 +1537,32 @@ export function pruneStaleAiwgFiles(destDir, desiredStems, opts = {}) {
|
|
|
1550
1537
|
return removed;
|
|
1551
1538
|
}
|
|
1552
1539
|
|
|
1540
|
+
/** Source-scoped cleanup also works when a removed standard skill is absent from this deploy's input. */
|
|
1541
|
+
function pruneMissingStandardSkills(destDir, opts) {
|
|
1542
|
+
if (!destDir || !opts?.srcRoot || opts.dryRun || !fs.existsSync(destDir)) return 0;
|
|
1543
|
+
const sourceRoot = path.resolve(opts.srcRoot);
|
|
1544
|
+
let pruned = 0;
|
|
1545
|
+
for (const entry of fs.readdirSync(destDir, { withFileTypes: true })) {
|
|
1546
|
+
if (!entry.isDirectory()) continue;
|
|
1547
|
+
const skillDir = path.join(destDir, entry.name);
|
|
1548
|
+
const receipt = readSidecarManifest(skillDir);
|
|
1549
|
+
if (!receipt?.skillSource || !receipt.managed?.['SKILL.md']) continue;
|
|
1550
|
+
const relative = path.relative(sourceRoot, receipt.skillSource);
|
|
1551
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) continue;
|
|
1552
|
+
try {
|
|
1553
|
+
fs.statSync(path.join(receipt.skillSource, 'SKILL.md'));
|
|
1554
|
+
continue;
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') continue;
|
|
1557
|
+
}
|
|
1558
|
+
if (releaseSkillOwnership(skillDir, {
|
|
1559
|
+
frameworkSlug: receipt.managed['SKILL.md'].frameworkSlug,
|
|
1560
|
+
skillSource: receipt.skillSource,
|
|
1561
|
+
}, opts)) pruned++;
|
|
1562
|
+
}
|
|
1563
|
+
return pruned;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1553
1566
|
/**
|
|
1554
1567
|
* Deploy a skill directory (copy recursively).
|
|
1555
1568
|
*
|
|
@@ -1574,6 +1587,10 @@ export function deploySkillDir(skillDir, destDir, opts) {
|
|
|
1574
1587
|
}
|
|
1575
1588
|
|
|
1576
1589
|
const destSkillDir = path.join(destDir, skillName);
|
|
1590
|
+
const previous = readSidecarManifest(destSkillDir);
|
|
1591
|
+
const frameworkSlug = extractFrameworkSlug(skillMdPath);
|
|
1592
|
+
if (!canDeploySkill(previous, skillDir, opts)) return;
|
|
1593
|
+
const managed = {};
|
|
1577
1594
|
if (!dryRun) ensureDir(destSkillDir);
|
|
1578
1595
|
|
|
1579
1596
|
function copyRecursive(src, dest) {
|
|
@@ -1601,6 +1618,15 @@ export function deploySkillDir(skillDir, destDir, opts) {
|
|
|
1601
1618
|
}
|
|
1602
1619
|
}
|
|
1603
1620
|
|
|
1621
|
+
if (entry.name === 'SKILL.md') srcContent = injectBoundRules(srcContent, srcPath, opts);
|
|
1622
|
+
|
|
1623
|
+
const relative = path.relative(destSkillDir, destPath);
|
|
1624
|
+
managed[relative] = {
|
|
1625
|
+
hash: `sha256:${contentHash(srcContent)}`,
|
|
1626
|
+
source: opts.deploySource || 'bundled',
|
|
1627
|
+
version: opts.deployVersion || 'unknown',
|
|
1628
|
+
...(frameworkSlug ? { frameworkSlug } : {}),
|
|
1629
|
+
};
|
|
1604
1630
|
if (fs.existsSync(destPath)) {
|
|
1605
1631
|
const destContent = fs.readFileSync(destPath, 'utf8');
|
|
1606
1632
|
if (destContent === srcContent && !force) {
|
|
@@ -1620,6 +1646,8 @@ export function deploySkillDir(skillDir, destDir, opts) {
|
|
|
1620
1646
|
}
|
|
1621
1647
|
|
|
1622
1648
|
copyRecursive(skillDir, destSkillDir);
|
|
1649
|
+
pruneRecordedSkillFiles(destSkillDir, previous?.managed, new Set(Object.keys(managed)), opts);
|
|
1650
|
+
writeSidecarManifest(destSkillDir, { managed, skillSource: path.resolve(skillDir) }, dryRun);
|
|
1623
1651
|
|
|
1624
1652
|
// Drop a `.aiwg-managed` marker so future cleanup runs can identify
|
|
1625
1653
|
// AIWG-deployed skills regardless of frontmatter shape (some providers
|
|
@@ -1811,7 +1839,7 @@ export function buildRemotesTopologyBlock(targetDir) {
|
|
|
1811
1839
|
|
|
1812
1840
|
function getUrl(remote) {
|
|
1813
1841
|
try {
|
|
1814
|
-
return
|
|
1842
|
+
return boundedExecFileSync('git', ['-C', targetDir, 'remote', 'get-url', '--', remote], 'quick', {
|
|
1815
1843
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
1816
1844
|
encoding: 'utf8',
|
|
1817
1845
|
}).trim();
|
|
@@ -2350,7 +2378,7 @@ export function getAddonCommandFiles(srcRoot, excludeAddons = [], options = {})
|
|
|
2350
2378
|
}
|
|
2351
2379
|
|
|
2352
2380
|
/**
|
|
2353
|
-
* Get
|
|
2381
|
+
* Get skill directories from a direct addon/framework source or all addons
|
|
2354
2382
|
* @param {string} srcRoot - Source root directory
|
|
2355
2383
|
* @param {string[]} excludeAddons - Addon names to exclude (default: none)
|
|
2356
2384
|
* @returns {string[]} - Array of skill directory paths
|
|
@@ -2358,6 +2386,8 @@ export function getAddonCommandFiles(srcRoot, excludeAddons = [], options = {})
|
|
|
2358
2386
|
export function getAddonSkillDirs(srcRoot, excludeAddons = []) {
|
|
2359
2387
|
const addons = discoverAddons(srcRoot);
|
|
2360
2388
|
const dirs = [];
|
|
2389
|
+
const directDir = getDirectSourceDir(srcRoot, excludeAddons);
|
|
2390
|
+
if (directDir) dirs.push(...listSkillDirs(directDir));
|
|
2361
2391
|
|
|
2362
2392
|
for (const addon of addons) {
|
|
2363
2393
|
if (excludeAddons.includes(addon.name)) continue;
|
|
@@ -2371,6 +2401,21 @@ export function getAddonSkillDirs(srcRoot, excludeAddons = []) {
|
|
|
2371
2401
|
return dirs;
|
|
2372
2402
|
}
|
|
2373
2403
|
|
|
2404
|
+
// `aiwg use <addon>` passes the component itself as --source. Keep bulk
|
|
2405
|
+
// repository discovery unchanged, even if the repo has a top-level skills/.
|
|
2406
|
+
function getDirectSourceDir(srcRoot, excludeAddons) {
|
|
2407
|
+
if (fs.existsSync(path.join(srcRoot, 'agentic', 'code')) ||
|
|
2408
|
+
excludeAddons.includes(path.basename(path.resolve(srcRoot)))) return null;
|
|
2409
|
+
const dir = path.join(srcRoot, 'skills');
|
|
2410
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) return null;
|
|
2411
|
+
const relative = path.relative(fs.realpathSync(srcRoot), fs.realpathSync(dir));
|
|
2412
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
2413
|
+
console.warn(`Warning: Skipping direct skills directory ${dir}: resolves outside source root ${srcRoot}`);
|
|
2414
|
+
return null;
|
|
2415
|
+
}
|
|
2416
|
+
return dir;
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2374
2419
|
/**
|
|
2375
2420
|
* Get all rule files from all addons
|
|
2376
2421
|
* @param {string} srcRoot - Source root directory
|
|
@@ -2400,15 +2445,8 @@ export function ruleEnforcementLevel(content) {
|
|
|
2400
2445
|
* deployment dispatchable; `AIWG_RULES_INLINE_BUDGET_TOKENS=0` disables the
|
|
2401
2446
|
* budget, any other value overrides it.
|
|
2402
2447
|
*/
|
|
2403
|
-
export const DEFAULT_RULES_INLINE_BUDGET_TOKENS = 64_000;
|
|
2404
|
-
const RULE_CHARS_PER_TOKEN = 4;
|
|
2405
|
-
|
|
2406
2448
|
export function resolveRulesInlineBudgetTokens(env = process.env) {
|
|
2407
|
-
|
|
2408
|
-
if (raw === undefined || raw === '') return DEFAULT_RULES_INLINE_BUDGET_TOKENS;
|
|
2409
|
-
const parsed = Number(raw);
|
|
2410
|
-
if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_RULES_INLINE_BUDGET_TOKENS;
|
|
2411
|
-
return parsed;
|
|
2449
|
+
return resolveRulesInlineBudget({}, env);
|
|
2412
2450
|
}
|
|
2413
2451
|
|
|
2414
2452
|
/** Sidecar recording which rules the inline budget moved on demand (#2562). */
|
|
@@ -2424,96 +2462,13 @@ export function readRuleBudgetSidecar(destDir) {
|
|
|
2424
2462
|
}
|
|
2425
2463
|
}
|
|
2426
2464
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
* then one per addon), so the budget is enforced against what is actually on
|
|
2432
|
-
* disk after each pass rather than against any single pass's file list. When
|
|
2433
|
-
* the inlined set exceeds the budget, the largest HIGH rules (then unlabelled
|
|
2434
|
-
* ones; never CRITICAL or the indexes) are removed from the directory and
|
|
2435
|
-
* recorded in the sidecar; the next pass skips re-deploying them and the
|
|
2436
|
-
* on-demand index lists them as binding rules fetched via `aiwg show rule`.
|
|
2437
|
-
* A changed budget invalidates the sidecar so the set is recomputed.
|
|
2438
|
-
*
|
|
2439
|
-
* Returns `{ demoted, removed }` — all demoted stems (sidecar state) and the
|
|
2440
|
-
* stems removed by this call.
|
|
2441
|
-
*/
|
|
2442
|
-
export function reconcileInlineRuleBudget(destDir, budgetTokens = resolveRulesInlineBudgetTokens(), opts = {}) {
|
|
2443
|
-
const sidecarPath = path.join(destDir, RULE_BUDGET_SIDECAR);
|
|
2444
|
-
if (!budgetTokens || budgetTokens <= 0) {
|
|
2445
|
-
if (fs.existsSync(sidecarPath) && !opts.dryRun) fs.rmSync(sidecarPath, { force: true });
|
|
2446
|
-
return { demoted: [], removed: [] };
|
|
2447
|
-
}
|
|
2448
|
-
const previous = readRuleBudgetSidecar(destDir);
|
|
2449
|
-
const carried = previous && previous.budgetTokens === budgetTokens ? previous.demoted : [];
|
|
2450
|
-
let files = [];
|
|
2451
|
-
try {
|
|
2452
|
-
files = fs.readdirSync(destDir, { withFileTypes: true })
|
|
2453
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
2454
|
-
.map((entry) => path.join(destDir, entry.name))
|
|
2455
|
-
.filter((file) => {
|
|
2456
|
-
const base = path.basename(file);
|
|
2457
|
-
if (base === 'RULES-INDEX.md' || base === 'RULES-ONDEMAND.md') return false;
|
|
2458
|
-
try { return MANAGED_MARKER_RE.test(fs.readFileSync(file, 'utf8')); } catch { return false; }
|
|
2459
|
-
});
|
|
2460
|
-
} catch {
|
|
2461
|
-
return { demoted: carried, removed: [] };
|
|
2462
|
-
}
|
|
2463
|
-
const { demoted } = applyInlineRuleBudget(files, budgetTokens);
|
|
2464
|
-
const removed = demoted.map((file) => artifactStem(path.basename(file)));
|
|
2465
|
-
if (!opts.dryRun) {
|
|
2466
|
-
for (const file of demoted) fs.rmSync(file, { force: true });
|
|
2467
|
-
}
|
|
2468
|
-
const all = [...new Set([...carried, ...removed])].sort();
|
|
2469
|
-
if (!opts.dryRun) {
|
|
2470
|
-
if (all.length > 0) {
|
|
2471
|
-
fs.writeFileSync(sidecarPath, `${JSON.stringify({ budgetTokens, demoted: all }, null, 2)}\n`, 'utf8');
|
|
2472
|
-
} else if (fs.existsSync(sidecarPath)) {
|
|
2473
|
-
fs.rmSync(sidecarPath, { force: true });
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
return { demoted: all, removed };
|
|
2465
|
+
// Compatibility exports: budgets never change selection or retain demotions.
|
|
2466
|
+
export function reconcileInlineRuleBudget(destDir, budgetTokens, opts = {}) {
|
|
2467
|
+
if (!opts.dryRun) fs.rmSync(path.join(destDir, RULE_BUDGET_SIDECAR), { force: true });
|
|
2468
|
+
return { demoted: [], removed: [] };
|
|
2477
2469
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
* Fit an always-on rule set under the inline budget (#2562).
|
|
2481
|
-
*
|
|
2482
|
-
* CRITICAL rules and the generated indexes are never demoted. When the
|
|
2483
|
-
* remaining set still exceeds the budget, HIGH rules are demoted largest-first
|
|
2484
|
-
* (fewest rules leave the always-on set), then rules with no declared level.
|
|
2485
|
-
* Demoted rules stay reachable via `aiwg show rule <name>` and are listed in
|
|
2486
|
-
* RULES-ONDEMAND.md under their own heading. Returns `{ inline, demoted }`
|
|
2487
|
-
* with the original order preserved for `inline`.
|
|
2488
|
-
*/
|
|
2489
|
-
export function applyInlineRuleBudget(ruleFiles, budgetTokens = resolveRulesInlineBudgetTokens()) {
|
|
2490
|
-
const files = [...(ruleFiles || [])];
|
|
2491
|
-
if (!budgetTokens || budgetTokens <= 0) return { inline: files, demoted: [] };
|
|
2492
|
-
const sized = files.map((file) => {
|
|
2493
|
-
const base = path.basename(file);
|
|
2494
|
-
let content = '';
|
|
2495
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { /* unreadable → keep inline */ }
|
|
2496
|
-
const level = base === 'RULES-INDEX.md' || base === 'RULES-ONDEMAND.md' ? 'critical' : ruleEnforcementLevel(content);
|
|
2497
|
-
return { file, tokens: Math.ceil(Buffer.byteLength(content, 'utf8') / RULE_CHARS_PER_TOKEN), level };
|
|
2498
|
-
});
|
|
2499
|
-
let total = sized.reduce((sum, item) => sum + item.tokens, 0);
|
|
2500
|
-
if (total <= budgetTokens) return { inline: files, demoted: [] };
|
|
2501
|
-
const demotable = sized
|
|
2502
|
-
.filter((item) => item.level !== 'critical')
|
|
2503
|
-
.sort((a, b) => {
|
|
2504
|
-
const rank = (level) => (level === 'high' ? 0 : level === null ? 1 : 2);
|
|
2505
|
-
return rank(a.level) - rank(b.level) || b.tokens - a.tokens;
|
|
2506
|
-
});
|
|
2507
|
-
const demoted = new Set();
|
|
2508
|
-
for (const item of demotable) {
|
|
2509
|
-
if (total <= budgetTokens) break;
|
|
2510
|
-
demoted.add(item.file);
|
|
2511
|
-
total -= item.tokens;
|
|
2512
|
-
}
|
|
2513
|
-
return {
|
|
2514
|
-
inline: files.filter((file) => !demoted.has(file)),
|
|
2515
|
-
demoted: files.filter((file) => demoted.has(file)),
|
|
2516
|
-
};
|
|
2470
|
+
export function applyInlineRuleBudget(ruleFiles) {
|
|
2471
|
+
return { inline: [...(ruleFiles || [])], demoted: [] };
|
|
2517
2472
|
}
|
|
2518
2473
|
|
|
2519
2474
|
/**
|
|
@@ -2527,10 +2482,14 @@ export function isAlwaysOnRule(filePath) {
|
|
|
2527
2482
|
const base = path.basename(filePath);
|
|
2528
2483
|
if (base === 'RULES-INDEX.md' || base === 'RULES-ONDEMAND.md') return true;
|
|
2529
2484
|
try {
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2485
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
2486
|
+
const parsed = parseRuleFrontmatter(content);
|
|
2487
|
+
if (!parsed.valid) throw new Error(`${filePath}: ${parsed.diagnostics.map(d => d.message).join('; ')}`);
|
|
2488
|
+
const activation = parsed.rule.tagged ? parsed.rule.activation : inferRuleActivation(ruleEnforcementLevel(content));
|
|
2489
|
+
return activation === 'kernel' || activation === 'paths';
|
|
2490
|
+
} catch (error) {
|
|
2491
|
+
if (error.code === 'ENOENT') return true;
|
|
2492
|
+
throw error;
|
|
2534
2493
|
}
|
|
2535
2494
|
}
|
|
2536
2495
|
|
|
@@ -2548,7 +2507,9 @@ export function listOnDemandRuleFiles(srcRoot, excludeAddons = []) {
|
|
|
2548
2507
|
for (const f of listMdFiles(dir)) {
|
|
2549
2508
|
const b = path.basename(f);
|
|
2550
2509
|
if (b === 'RULES-INDEX.md' || b === 'RULES-ONDEMAND.md') continue;
|
|
2551
|
-
|
|
2510
|
+
const parsed = parseRuleFrontmatter(fs.readFileSync(f, 'utf8'));
|
|
2511
|
+
if (!parsed.valid) throw new Error(`${f}: invalid rule frontmatter`);
|
|
2512
|
+
if (!parsed.rule.tagged && !isAlwaysOnRule(f)) out.push(f);
|
|
2552
2513
|
}
|
|
2553
2514
|
};
|
|
2554
2515
|
for (const addon of discoverAddons(aiwgRoot)) {
|
|
@@ -2661,19 +2622,23 @@ export function getAddonRuleFiles(srcRoot, excludeAddons = [], options = {}) {
|
|
|
2661
2622
|
for (const addon of addons) {
|
|
2662
2623
|
if (excludeAddons.includes(addon.name)) continue;
|
|
2663
2624
|
|
|
2664
|
-
// Skip addons with consolidated rule indexes — their rules are
|
|
2665
|
-
// included via assembleRulesIndex() instead of individual files
|
|
2666
|
-
if (addon.manifest?.consolidation?.deployIndexOnly) continue;
|
|
2667
|
-
|
|
2668
2625
|
const rulesDir = path.join(addon.path, 'rules');
|
|
2669
2626
|
if (fs.existsSync(rulesDir)) {
|
|
2670
|
-
|
|
2627
|
+
for (const file of listMdFiles(rulesDir)) {
|
|
2628
|
+
// Consolidation remains a legacy inventory policy. Explicit activation
|
|
2629
|
+
// owns delivery, including the desired set used by the outer prune.
|
|
2630
|
+
if (addon.manifest?.consolidation?.deployIndexOnly) {
|
|
2631
|
+
const parsed = parseRuleFrontmatter(fs.readFileSync(file, 'utf8'));
|
|
2632
|
+
if (!parsed.valid) throw new Error(`${file}: invalid rule frontmatter`);
|
|
2633
|
+
if (!parsed.rule.tagged) continue;
|
|
2634
|
+
}
|
|
2635
|
+
files.push(file);
|
|
2636
|
+
}
|
|
2671
2637
|
}
|
|
2672
2638
|
}
|
|
2673
2639
|
|
|
2674
|
-
//
|
|
2675
|
-
//
|
|
2676
|
-
// desired-set (computeAllArtifactBasenames) exclude them for every provider.
|
|
2640
|
+
// Activation selects bodies; only untagged rules use the old severity tier.
|
|
2641
|
+
// The deploy enumeration and prune desired set must select the same bodies.
|
|
2677
2642
|
return files.filter(isAlwaysOnRule);
|
|
2678
2643
|
}
|
|
2679
2644
|
|
|
@@ -3365,3 +3330,25 @@ export const ProviderInterface = {
|
|
|
3365
3330
|
// ── File Extension ────────────────────────────────────────────────
|
|
3366
3331
|
getFileExtension(type) { return '.md'; }
|
|
3367
3332
|
};
|
|
3333
|
+
|
|
3334
|
+
/** Replace only the generated binding block; keep authored bytes intact. */
|
|
3335
|
+
export function replaceBoundRulesBlock(content, rules = []) {
|
|
3336
|
+
const clean = content.replace(/\n?<!-- AIWG:bound-rules:start -->[\s\S]*?<!-- AIWG:bound-rules:end -->\n?/g, '');
|
|
3337
|
+
if (!rules.length) return clean;
|
|
3338
|
+
const unique = [...new Map(rules.map(rule => [rule.name, rule])).values()]
|
|
3339
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
3340
|
+
return `${clean}${clean.endsWith('\n') ? '' : '\n'}\n<!-- AIWG:bound-rules:start -->\n## Bound rules\n\nRequired reading on every invocation: fetch and follow every bound rule below before starting governed work. A summary or discovery pointer does not discharge this obligation.\n\n${unique.map(rule =>
|
|
3341
|
+
`- ${rule.name} — ${rule.summary}\n Fetch and follow before governed work: \`aiwg show rule ${rule.name}\`.`
|
|
3342
|
+
).join('\n')}\n<!-- AIWG:bound-rules:end -->\n`;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
export function injectBoundRules(content, source, opts = {}) {
|
|
3346
|
+
if (!opts.ruleDelivery) return content;
|
|
3347
|
+
return replaceBoundRulesBlock(content, opts.ruleDelivery.bindings.get(path.resolve(source)) || []);
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
/** All provider output is staged; the complete startup guard runs before promotion. */
|
|
3351
|
+
export async function withRuleDeployment(opts, provider, deploy) {
|
|
3352
|
+
const { deployWithRuleDelivery } = await import('./rule-delivery.mjs');
|
|
3353
|
+
return deployWithRuleDelivery(opts, provider, deploy);
|
|
3354
|
+
}
|
|
@@ -29,6 +29,7 @@ import path from 'path';
|
|
|
29
29
|
import { tmpdir } from 'os';
|
|
30
30
|
import { classifyModelRole, modelForRole } from './model-role.mjs';
|
|
31
31
|
import {
|
|
32
|
+
withRuleDeployment,
|
|
32
33
|
ensureDir,
|
|
33
34
|
listMdFiles,
|
|
34
35
|
listMdFilesRecursive,
|
|
@@ -49,9 +50,7 @@ import {
|
|
|
49
50
|
getAddonRuleFiles,
|
|
50
51
|
listOnDemandRuleFiles,
|
|
51
52
|
writeOnDemandRuleIndex,
|
|
52
|
-
readRuleBudgetSidecar,
|
|
53
53
|
reconcileInlineRuleBudget,
|
|
54
|
-
resolveRulesInlineBudgetTokens,
|
|
55
54
|
assembleRulesIndex,
|
|
56
55
|
normalizeDeploymentMode,
|
|
57
56
|
collectFrameworkArtifacts,
|
|
@@ -521,6 +520,10 @@ export function getFileExtension(type) {
|
|
|
521
520
|
* Orchestrates deployment of agents, commands, skills, and rules
|
|
522
521
|
*/
|
|
523
522
|
export async function deploy(opts) {
|
|
523
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async function deploySelected(opts) {
|
|
524
527
|
const {
|
|
525
528
|
srcRoot,
|
|
526
529
|
target,
|
|
@@ -619,7 +622,7 @@ export async function deploy(opts) {
|
|
|
619
622
|
// Deploy based on flags — track counts for summary
|
|
620
623
|
const counts = { agents: 0, commands: 0, skills: 0, rules: 0, souls: 0 };
|
|
621
624
|
|
|
622
|
-
if (!commandsOnly && !skillsOnly) {
|
|
625
|
+
if (!commandsOnly && !skillsOnly && !rulesOnly) {
|
|
623
626
|
// Apply filters if specified
|
|
624
627
|
const filteredAgents = filterAgentFiles(agentFiles, opts);
|
|
625
628
|
if (verbose && (opts.filter || opts.filterRole)) {
|
|
@@ -664,17 +667,7 @@ export async function deploy(opts) {
|
|
|
664
667
|
pruneStaleAiwgSkills(kernelDestDir, computeAllKernelNames(srcRoot), opts);
|
|
665
668
|
}
|
|
666
669
|
|
|
667
|
-
const inlineBudgetTokens = resolveRulesInlineBudgetTokens();
|
|
668
|
-
let demotedRuleNames = [];
|
|
669
670
|
if (shouldDeployRules || rulesOnly) {
|
|
670
|
-
// Inline budget (#2562): rules a previous pass already moved on demand are
|
|
671
|
-
// not re-inlined; the directory is reconciled against the budget after
|
|
672
|
-
// this pass deploys (see below).
|
|
673
|
-
const sidecar = readRuleBudgetSidecar(path.join(target, paths.rules));
|
|
674
|
-
if (sidecar && sidecar.budgetTokens === inlineBudgetTokens && sidecar.demoted.length > 0) {
|
|
675
|
-
const skip = new Set(sidecar.demoted);
|
|
676
|
-
ruleFiles = ruleFiles.filter((f) => !skip.has(path.basename(f).replace(/\.md$/, '')));
|
|
677
|
-
}
|
|
678
671
|
// Try assembled rules index (combines all component indexes)
|
|
679
672
|
const assembled = assembleRulesIndex(srcRoot);
|
|
680
673
|
if (assembled) {
|
|
@@ -707,17 +700,8 @@ export async function deploy(opts) {
|
|
|
707
700
|
// On-demand index (#1673): list the MEDIUM/LOW rules that were tier-gated
|
|
708
701
|
// out of the always-on set so agents can fetch them via `aiwg show rule`.
|
|
709
702
|
const rulesDestDir = path.join(target, paths.rules);
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
// in RULES-ONDEMAND.md with their fetch hint.
|
|
713
|
-
const budget = reconcileInlineRuleBudget(rulesDestDir, inlineBudgetTokens, opts);
|
|
714
|
-
demotedRuleNames = budget.demoted;
|
|
715
|
-
if (budget.removed.length > 0 && !opts.quiet) {
|
|
716
|
-
console.log(` Inline rule budget: ${budget.removed.length} HIGH rule(s) moved on demand to fit ${inlineBudgetTokens.toLocaleString()} tokens: ${budget.removed.join(', ')} (see RULES-ONDEMAND.md)`);
|
|
717
|
-
}
|
|
718
|
-
const onDemandCount = writeOnDemandRuleIndex(rulesDestDir, listOnDemandRuleFiles(srcRoot), {
|
|
719
|
-
...opts, demotedNames: demotedRuleNames, inlineBudgetTokens,
|
|
720
|
-
});
|
|
703
|
+
reconcileInlineRuleBudget(rulesDestDir, undefined, opts);
|
|
704
|
+
const onDemandCount = writeOnDemandRuleIndex(rulesDestDir, listOnDemandRuleFiles(srcRoot), opts);
|
|
721
705
|
if (verbose && onDemandCount > 0) {
|
|
722
706
|
console.log(` On-demand rules (not inlined): ${onDemandCount} → RULES-ONDEMAND.md`);
|
|
723
707
|
}
|
|
@@ -38,6 +38,7 @@ import { spawn } from 'child_process';
|
|
|
38
38
|
import { load as loadYaml } from 'js-yaml';
|
|
39
39
|
import { classifyModelRole, modelForRole } from './model-role.mjs';
|
|
40
40
|
import {
|
|
41
|
+
withRuleDeployment,
|
|
41
42
|
ensureDir,
|
|
42
43
|
listMdFiles,
|
|
43
44
|
listMdFilesRecursive,
|
|
@@ -269,7 +270,8 @@ export async function deployCommands(targetDir, srcRoot, opts) {
|
|
|
269
270
|
|
|
270
271
|
const child = spawn('node', [scriptPath, ...args], {
|
|
271
272
|
stdio: 'inherit',
|
|
272
|
-
cwd: helperRoot
|
|
273
|
+
cwd: helperRoot,
|
|
274
|
+
env: opts.deploymentHome ? { ...process.env, HOME: opts.deploymentHome } : process.env
|
|
273
275
|
});
|
|
274
276
|
|
|
275
277
|
child.on('close', (code) => {
|
|
@@ -318,7 +320,8 @@ export async function deploySkills(targetDir, srcRoot, opts) {
|
|
|
318
320
|
|
|
319
321
|
const child = spawn('node', [scriptPath, ...args], {
|
|
320
322
|
stdio: 'inherit',
|
|
321
|
-
cwd: helperRoot
|
|
323
|
+
cwd: helperRoot,
|
|
324
|
+
env: opts.deploymentHome ? { ...process.env, HOME: opts.deploymentHome } : process.env
|
|
322
325
|
});
|
|
323
326
|
|
|
324
327
|
child.on('close', (code) => {
|
|
@@ -332,7 +335,7 @@ export async function deploySkills(targetDir, srcRoot, opts) {
|
|
|
332
335
|
// Self-heal: prune AIWG-managed skill dirs left behind in the legacy
|
|
333
336
|
// ~/.codex/skills/ home location by pre-fix versions, so codex-rs stops
|
|
334
337
|
// listing each skill twice.
|
|
335
|
-
pruneLegacyCodexSkills(opts);
|
|
338
|
+
pruneLegacyCodexSkills(opts, opts.legacyCodexSkills || legacyHomeSkillsDir);
|
|
336
339
|
}
|
|
337
340
|
|
|
338
341
|
/**
|
|
@@ -398,17 +401,16 @@ export function deployRules(ruleFiles, targetDir, opts) {
|
|
|
398
401
|
* Aggregate agents to single AGENTS.md file
|
|
399
402
|
*/
|
|
400
403
|
export function aggregateToAgentsMd(agentFiles, destPath, opts) {
|
|
401
|
-
const
|
|
402
|
-
for (const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
blocks.push(content);
|
|
404
|
+
const lines = ['# AIWG agent definitions', '', 'Read the selected definition before invoking an agent.', ''];
|
|
405
|
+
for (const file of agentFiles) {
|
|
406
|
+
const { metadata } = parseFrontmatter(fs.readFileSync(file, 'utf8'));
|
|
407
|
+
const name = metadata.name || path.basename(file, '.md');
|
|
408
|
+
lines.push(`- ${name}: .codex/agents/${path.basename(file, '.md')}.toml`);
|
|
407
409
|
}
|
|
408
|
-
const out =
|
|
410
|
+
const out = `${lines.join('\n')}\n`;
|
|
409
411
|
if (opts.dryRun) console.log(`[dry-run] write ${destPath}`);
|
|
410
412
|
else fs.writeFileSync(destPath, out, 'utf8');
|
|
411
|
-
|
|
413
|
+
|
|
412
414
|
}
|
|
413
415
|
|
|
414
416
|
// ============================================================================
|
|
@@ -536,6 +538,10 @@ export function getFileExtension(type) {
|
|
|
536
538
|
* Main deployment function for Codex provider
|
|
537
539
|
*/
|
|
538
540
|
export async function deploy(opts) {
|
|
541
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async function deploySelected(opts) {
|
|
539
545
|
const {
|
|
540
546
|
srcRoot,
|
|
541
547
|
target,
|
|
@@ -628,6 +634,7 @@ export async function deploy(opts) {
|
|
|
628
634
|
// Aggregate to single AGENTS.md
|
|
629
635
|
const destPath = path.join(target, 'AGENTS.md');
|
|
630
636
|
console.log(`\nAggregating ${agentFiles.length} agents to AGENTS.md...`);
|
|
637
|
+
deployAgents(agentFiles, target, opts);
|
|
631
638
|
aggregateToAgentsMd(agentFiles, destPath, opts);
|
|
632
639
|
} else {
|
|
633
640
|
console.log(`\nDeploying ${agentFiles.length} agents...`);
|