@aiwg/cli 2026.10.4 → 2026.10.6
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/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
- package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
- package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
- package/agentic/code/providers/model-capabilities.v1.json +74 -50
- package/bin/aiwg.mjs +3 -1
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/citation-parser.js +8 -1
- package/dist/src/artifacts/cli.js +72 -9
- package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
- package/dist/src/artifacts/fortemi-core-sync.js +26 -8
- package/dist/src/artifacts/graph-query.js +18 -8
- package/dist/src/artifacts/index-adapters.js +339 -0
- package/dist/src/artifacts/index-builder.js +146 -16
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-preparation.js +91 -26
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +130 -56
- package/dist/src/artifacts/index-status.js +20 -5
- package/dist/src/artifacts/index-worker.mjs +9 -7
- package/dist/src/artifacts/memory-maintenance.js +503 -0
- package/dist/src/artifacts/prebuilt-relations.js +3 -1
- package/dist/src/artifacts/query-engine.js +263 -108
- package/dist/src/artifacts/relations-builder.js +2 -2
- package/dist/src/artifacts/source-graph.js +2 -2
- package/dist/src/artifacts/types.js +9 -1
- package/dist/src/cli/handlers/decision.js +19 -1
- package/dist/src/cli/handlers/guided-setup.js +470 -0
- package/dist/src/cli/handlers/help.js +2 -2
- package/dist/src/cli/handlers/housekeeper.js +1110 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/init.js +41 -6
- package/dist/src/cli/handlers/local-executor.js +5 -3
- package/dist/src/cli/handlers/mc.js +509 -53
- package/dist/src/cli/handlers/models.js +32 -2
- package/dist/src/cli/handlers/ralph-launcher.js +76 -4
- package/dist/src/cli/handlers/rules.js +1 -1
- package/dist/src/cli/handlers/script-runner.js +73 -2
- package/dist/src/cli/handlers/serve.js +5 -3
- package/dist/src/cli/handlers/sessions.js +40 -6
- package/dist/src/cli/handlers/setup.js +428 -1
- package/dist/src/cli/handlers/skill-lint.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +118 -8
- package/dist/src/cli/handlers/use.js +279 -93
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/prompt-utils.js +8 -0
- package/dist/src/cli/router.js +16 -1
- package/dist/src/config/aiwg-config.js +42 -0
- package/dist/src/config/cli.js +7 -3
- package/dist/src/config/decision-config.js +14 -1
- package/dist/src/config/native-sandbox-warnings.js +25 -0
- package/dist/src/contributors/validation.js +6 -5
- package/dist/src/decision/admission.js +7 -3
- package/dist/src/decision/benchmark.js +469 -0
- package/dist/src/decision/ledger.js +22 -3
- package/dist/src/decision/pricing.js +147 -0
- package/dist/src/decision/qualification/gate-evidence.js +18 -15
- package/dist/src/decision/qualification/load-staged.js +539 -0
- package/dist/src/decision/qualification/load.js +109 -33
- package/dist/src/decision/qualification/runner.js +5 -2
- package/dist/src/decision/review/service.js +6 -4
- package/dist/src/decision/review/validate.js +23 -2
- package/dist/src/decision/savings.js +8 -3
- package/dist/src/discovery/index.js +492 -0
- package/dist/src/discovery/interview.js +233 -0
- package/dist/src/discovery/plan-apply.js +571 -0
- package/dist/src/discovery/plan-store.js +171 -0
- package/dist/src/discovery/plan-types.js +2 -0
- package/dist/src/discovery/plan-validation.js +139 -0
- package/dist/src/discovery/types.js +2 -0
- package/dist/src/extensions/commands/definitions.js +49 -9
- package/dist/src/extensions/manifest.js +71 -44
- package/dist/src/extensions/project-local-discovery.js +1 -1
- package/dist/src/extensions/project-quickref.js +18 -17
- package/dist/src/extensions/validation.js +32 -29
- package/dist/src/housekeeper/daemon-config.js +148 -0
- package/dist/src/housekeeper/ipc.js +84 -0
- package/dist/src/housekeeper/lifecycle.js +148 -0
- package/dist/src/housekeeper/platform.js +35 -0
- package/dist/src/housekeeper/status.js +70 -0
- package/dist/src/housekeeper/units.js +114 -0
- package/dist/src/jobs/flow.js +22 -21
- package/dist/src/lint/rule-activation.js +20 -5
- package/dist/src/lint/runner.js +1 -1
- package/dist/src/mcp/cli.mjs +5 -6
- package/dist/src/mcp/config-file.mjs +6 -2
- package/dist/src/mcp/config-layers.mjs +23 -7
- package/dist/src/mcp/profiles.js +18 -31
- package/dist/src/mcp/profiles.mjs +18 -32
- package/dist/src/mcp/registry.js +7 -27
- package/dist/src/mcp/registry.mjs +7 -28
- package/dist/src/mcp/server.mjs +34 -1
- package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
- package/dist/src/mcp/tools/command-run.mjs +3 -2
- package/dist/src/mcp/tools/decision.mjs +49 -48
- package/dist/src/mcp/tools/discovery.mjs +46 -21
- package/dist/src/mcp/tools/orchestration.mjs +22 -22
- package/dist/src/mcp/tools/subsystems.mjs +9 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
- package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
- package/dist/src/memory/audit.js +719 -0
- package/dist/src/memory/canonical-context.js +392 -13
- package/dist/src/memory/canonical-maintenance.js +95 -0
- package/dist/src/memory/cli-result.js +22 -0
- package/dist/src/memory/cli.js +176 -0
- package/dist/src/memory/context-pack.js +57 -6
- package/dist/src/memory/cost.js +512 -0
- package/dist/src/memory/firewall-classification.d.mts +7 -0
- package/dist/src/memory/firewall-classification.mjs +32 -0
- package/dist/src/memory/index.js +8 -0
- package/dist/src/memory/line-maintenance.js +68 -0
- package/dist/src/memory/maintenance-cli.js +286 -0
- package/dist/src/memory/maintenance-contract.js +136 -0
- package/dist/src/memory/maintenance-index.js +18 -0
- package/dist/src/memory/maintenance-owner.js +2 -0
- package/dist/src/memory/maintenance-record.js +138 -0
- package/dist/src/memory/maintenance.js +254 -0
- package/dist/src/memory/provider-memory-adapter.js +154 -0
- package/dist/src/memory/recommend-cli.js +83 -0
- package/dist/src/memory/recommend.js +269 -0
- package/dist/src/memory/scheduled.js +81 -0
- package/dist/src/memory/taxonomy.js +44 -0
- package/dist/src/mission-protocol/codecs.js +19 -9
- package/dist/src/models/config-loader.js +11 -1
- package/dist/src/models/model-capabilities.v1.json +74 -50
- package/dist/src/models/provider-policy.js +125 -62
- package/dist/src/models/resolver.js +45 -8
- package/dist/src/models/worker-installation.d.mts +7 -0
- package/dist/src/models/worker-installation.mjs +169 -37
- package/dist/src/models/wrapper-route.js +1 -1
- package/dist/src/output-modes/registry.js +8 -7
- package/dist/src/plugin/metadata-validator.js +1 -1
- package/dist/src/providers/deploy-version.d.mts +1 -0
- package/dist/src/providers/deploy-version.mjs +17 -0
- package/dist/src/providers/provider-definitions.js +19 -16
- package/dist/src/providers/skill-ownership.d.mts +11 -2
- package/dist/src/providers/skill-ownership.mjs +35 -17
- package/dist/src/rules/activation.d.mts +11 -2
- package/dist/src/rules/activation.mjs +82 -6
- package/dist/src/rules/inventory.js +1 -1
- package/dist/src/rules/rule-frontmatter.schema.json +2 -0
- package/dist/src/schema/zod-validation.d.mts +6 -0
- package/dist/src/schema/zod-validation.mjs +50 -0
- package/dist/src/serve/executor-registry.js +297 -20
- package/dist/src/serve/executor-token.d.mts +1 -0
- package/dist/src/serve/executor-token.mjs +8 -0
- package/dist/src/serve/shared-host-scheduler.js +1102 -31
- package/dist/src/serve/worker-invocation.js +114 -15
- package/dist/src/sessions/adapters/claude.js +19 -18
- package/dist/src/sessions/adapters/codex.js +33 -19
- package/dist/src/sessions/adapters/copilot.js +14 -13
- package/dist/src/sessions/adapters/cursor.js +19 -18
- package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
- package/dist/src/sessions/adapters/factory.js +11 -10
- package/dist/src/sessions/adapters/generic.js +32 -23
- package/dist/src/sessions/adapters/grokbot.js +35 -35
- package/dist/src/sessions/adapters/hermes.js +20 -19
- package/dist/src/sessions/adapters/muse.js +50 -49
- package/dist/src/sessions/adapters/omp.js +5 -4
- package/dist/src/sessions/adapters/openclaw.js +30 -29
- package/dist/src/sessions/adapters/opencode.js +26 -26
- package/dist/src/sessions/adapters/openhuman.js +24 -23
- package/dist/src/sessions/adapters/pi.js +5 -4
- package/dist/src/sessions/adapters/windsurf.js +8 -8
- package/dist/src/sessions/analytics.js +10 -9
- package/dist/src/sessions/batch-contracts.js +1 -1
- package/dist/src/sessions/batch-import.js +202 -2
- package/dist/src/sessions/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +73 -54
- package/dist/src/sessions/coverage-preflight.js +26 -1
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/policy.js +18 -7
- package/dist/src/sessions/refresh.js +2 -3
- package/dist/src/sessions/repository.js +4 -2
- package/dist/src/sessions/workspace-discovery.js +92 -26
- package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
- package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
- package/dist/src/update/checker.d.mts +4 -0
- package/dist/src/update/checker.mjs +14 -0
- package/dist/src/writing/exemplar-selection.js +6 -6
- package/dist/src/writing/voice-evaluation.js +24 -23
- package/dist/src/writing/writer-migration.js +14 -13
- package/dist/src/writing/writer-profile.js +19 -18
- package/dist/src/writing/writing-brief.js +18 -17
- package/dist/src/writing/writing-receipt.js +47 -46
- package/package.json +5 -2
- package/schemas/decision/DecisionReview.schema.json +78 -1
- package/schemas/mission-v1.schema.json +3 -0
- package/tools/agents/deploy-agents.mjs +67 -39
- package/tools/agents/providers/antigravity.mjs +6 -1
- package/tools/agents/providers/base.mjs +19 -13
- package/tools/agents/providers/claude.mjs +1 -1
- package/tools/agents/providers/codex.mjs +50 -56
- package/tools/agents/providers/copilot.mjs +8 -2
- package/tools/agents/providers/cursor.mjs +1 -1
- package/tools/agents/providers/deepseek-harness.mjs +1 -1
- package/tools/agents/providers/factory.mjs +7 -1
- package/tools/agents/providers/grok-build.mjs +18 -2
- package/tools/agents/providers/grokbot.mjs +1 -1
- package/tools/agents/providers/hermes.mjs +7 -13
- package/tools/agents/providers/muse-hooks.mjs +21 -14
- package/tools/agents/providers/muse.mjs +7 -2
- package/tools/agents/providers/omp.mjs +28 -4
- package/tools/agents/providers/opencode.mjs +14 -5
- package/tools/agents/providers/openhuman.mjs +1 -1
- package/tools/agents/providers/pi.mjs +1 -1
- package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
- package/tools/agents/providers/rule-delivery.mjs +263 -71
- package/tools/agents/providers/windsurf.mjs +7 -0
- package/tools/cli/workspace-status.mjs +5 -0
- package/tools/commands/deploy-prompts-codex.mjs +11 -8
- package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
- package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
- package/tools/ralph-external/process-monitor.mjs +7 -4
- package/tools/ralph-external/session-launcher.mjs +280 -32
- package/tools/skills/deploy-skills-codex.mjs +11 -7
- package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
|
@@ -104,7 +104,7 @@ export function listMdFiles(dir, excludePatterns = []) {
|
|
|
104
104
|
const excluded = [...defaultExcluded, ...excludePatterns];
|
|
105
105
|
return fs
|
|
106
106
|
.readdirSync(dir, { withFileTypes: true })
|
|
107
|
-
.filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.md') && !e.name.toLowerCase().endsWith('.soul.md') && !excluded.includes(e.name))
|
|
107
|
+
.filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.md') && !e.name.toLowerCase().endsWith('.soul.md') && !e.name.toLowerCase().endsWith('.core.md') && !excluded.includes(e.name))
|
|
108
108
|
.map((e) => path.join(dir, e.name));
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -2474,7 +2474,7 @@ export function applyInlineRuleBudget(ruleFiles) {
|
|
|
2474
2474
|
/**
|
|
2475
2475
|
* Tier gate (#1673, enforcement-tiered deployment ADR). Only CRITICAL and HIGH
|
|
2476
2476
|
* rules are inlined into a provider's always-on rule directory; MEDIUM/LOW are
|
|
2477
|
-
* left on-demand (reachable via `aiwg show rule <name
|
|
2477
|
+
* left on-demand (reachable via `aiwg show rule <name> --body` and the assembled
|
|
2478
2478
|
* RULES-INDEX pointer index). Index files and rules with no enforcement marker
|
|
2479
2479
|
* default to always-on, so an un-triaged or structural file is never dropped.
|
|
2480
2480
|
*/
|
|
@@ -2558,17 +2558,17 @@ export function renderOnDemandRuleSection(onDemandFiles, opts = {}) {
|
|
|
2558
2558
|
'on demand:',
|
|
2559
2559
|
'',
|
|
2560
2560
|
'```bash',
|
|
2561
|
-
'aiwg show rule <name>',
|
|
2561
|
+
'aiwg show rule <name> --body',
|
|
2562
2562
|
'```',
|
|
2563
2563
|
'',
|
|
2564
|
-
...names.map((n) => `- \`${n}\` — \`aiwg show rule ${n}\``),
|
|
2564
|
+
...names.map((n) => `- \`${n}\` — \`aiwg show rule ${n} --body\``),
|
|
2565
2565
|
].join('\n');
|
|
2566
2566
|
}
|
|
2567
2567
|
|
|
2568
2568
|
/**
|
|
2569
2569
|
* Write a compact on-demand rule index (#1673) into a provider's rule dir.
|
|
2570
2570
|
* Lists the MEDIUM/LOW rules that are NOT inlined at startup, with the
|
|
2571
|
-
* `aiwg show rule <name
|
|
2571
|
+
* `aiwg show rule <name> --body` fetch hint. Removes a stale index when empty.
|
|
2572
2572
|
*/
|
|
2573
2573
|
export function writeOnDemandRuleIndex(destDir, onDemandFiles, opts = {}) {
|
|
2574
2574
|
const indexPath = path.join(destDir, 'RULES-ONDEMAND.md');
|
|
@@ -2588,10 +2588,10 @@ export function writeOnDemandRuleIndex(destDir, onDemandFiles, opts = {}) {
|
|
|
2588
2588
|
'fetch any rule body on demand:',
|
|
2589
2589
|
'',
|
|
2590
2590
|
'```bash',
|
|
2591
|
-
'aiwg show rule <name>',
|
|
2591
|
+
'aiwg show rule <name> --body',
|
|
2592
2592
|
'```',
|
|
2593
2593
|
'',
|
|
2594
|
-
...names.map((n) => `- \`${n}\` — \`aiwg show rule ${n}\``),
|
|
2594
|
+
...names.map((n) => `- \`${n}\` — \`aiwg show rule ${n} --body\``),
|
|
2595
2595
|
'',
|
|
2596
2596
|
];
|
|
2597
2597
|
if (demotedNames.length > 0) {
|
|
@@ -2605,7 +2605,7 @@ export function writeOnDemandRuleIndex(destDir, onDemandFiles, opts = {}) {
|
|
|
2605
2605
|
'(AIWG_RULES_INLINE_BUDGET_TOKENS) and break subagent dispatch with "Prompt is too long".',
|
|
2606
2606
|
'Fetch any of them before work they govern:',
|
|
2607
2607
|
'',
|
|
2608
|
-
...demotedNames.map((n) => `- \`${n}\` — \`aiwg show rule ${n}\``),
|
|
2608
|
+
...demotedNames.map((n) => `- \`${n}\` — \`aiwg show rule ${n} --body\``),
|
|
2609
2609
|
'',
|
|
2610
2610
|
);
|
|
2611
2611
|
}
|
|
@@ -2803,7 +2803,9 @@ export function getAddonFiles(srcRoot, options = {}) {
|
|
|
2803
2803
|
// ============================================================================
|
|
2804
2804
|
|
|
2805
2805
|
/**
|
|
2806
|
-
* Load rules manifest from source directory
|
|
2806
|
+
* Load rules manifest from source directory.
|
|
2807
|
+
* Inventory metadata only: delivery is decided by rule `activation` (rule-delivery.mjs);
|
|
2808
|
+
* the former manifest `tiers` deploy policy was never consulted and was removed (#3450).
|
|
2807
2809
|
* @param {string} srcRoot - Source root directory
|
|
2808
2810
|
* @returns {object|null} - Parsed manifest or null if not found
|
|
2809
2811
|
*/
|
|
@@ -3168,8 +3170,9 @@ export function migrateCommandsDirectory(commandsDir, opts = {}) {
|
|
|
3168
3170
|
const rel = path.relative(process.cwd(), commandsDir);
|
|
3169
3171
|
// The condition is a property of the directory, not of each deployed unit;
|
|
3170
3172
|
// emit it once per run no matter how many units pass through.
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
+
const warned = opts.warnedCommandsDirs || warnedCommandsDirs;
|
|
3174
|
+
if (warned.has(commandsDir)) return false;
|
|
3175
|
+
warned.add(commandsDir);
|
|
3173
3176
|
|
|
3174
3177
|
const stale = listManagedCommandFiles(commandsDir);
|
|
3175
3178
|
if (stale.length === 0) return false;
|
|
@@ -3338,7 +3341,7 @@ export function replaceBoundRulesBlock(content, rules = []) {
|
|
|
3338
3341
|
const unique = [...new Map(rules.map(rule => [rule.name, rule])).values()]
|
|
3339
3342
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
3340
3343
|
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}\`.`
|
|
3344
|
+
`- ${rule.name} — ${rule.summary}\n Fetch and follow before governed work: \`aiwg show rule ${rule.name} --body\`.`
|
|
3342
3345
|
).join('\n')}\n<!-- AIWG:bound-rules:end -->\n`;
|
|
3343
3346
|
}
|
|
3344
3347
|
|
|
@@ -3347,8 +3350,11 @@ export function injectBoundRules(content, source, opts = {}) {
|
|
|
3347
3350
|
return replaceBoundRulesBlock(content, opts.ruleDelivery.bindings.get(path.resolve(source)) || []);
|
|
3348
3351
|
}
|
|
3349
3352
|
|
|
3350
|
-
/**
|
|
3353
|
+
/** Rule delivery stages output and guards startup before promotion. Deferred
|
|
3354
|
+
* kernel passes leave rule delivery to the final source in the invocation. */
|
|
3351
3355
|
export async function withRuleDeployment(opts, provider, deploy) {
|
|
3356
|
+
if (opts.kernelOnly && opts.deferRuleProjection && provider.name !== 'warp'
|
|
3357
|
+
&& !globalThis[Symbol.for('aiwg.provider-preparation-hook.v1')]) return deploy(opts);
|
|
3352
3358
|
const { deployWithRuleDelivery } = await import('./rule-delivery.mjs');
|
|
3353
3359
|
return deployWithRuleDelivery(opts, provider, deploy);
|
|
3354
3360
|
}
|
|
@@ -416,7 +416,7 @@ export async function postDeploy(targetDir, opts) {
|
|
|
416
416
|
}
|
|
417
417
|
|
|
418
418
|
// Hook file architecture: write AIWG.md and wire @AIWG.md into CLAUDE.md
|
|
419
|
-
if (opts.srcRoot) {
|
|
419
|
+
if (opts.srcRoot && opts.contextFiles !== false) {
|
|
420
420
|
deployHookFile(targetDir, opts);
|
|
421
421
|
}
|
|
422
422
|
}
|
|
@@ -35,6 +35,7 @@ const staticModelCatalog = _require('../../../agentic/code/providers/model-catal
|
|
|
35
35
|
import path from 'path';
|
|
36
36
|
import os from 'os';
|
|
37
37
|
import { spawn } from 'child_process';
|
|
38
|
+
import { pathToFileURL } from 'node:url';
|
|
38
39
|
import { load as loadYaml } from 'js-yaml';
|
|
39
40
|
import { classifyModelRole, modelForRole } from './model-role.mjs';
|
|
40
41
|
import {
|
|
@@ -66,7 +67,6 @@ import {
|
|
|
66
67
|
parseFrontmatter,
|
|
67
68
|
resolveAiwgRoot
|
|
68
69
|
} from './base.mjs';
|
|
69
|
-
const modelCatalog = loadRuntimeModelCatalog(staticModelCatalog);
|
|
70
70
|
|
|
71
71
|
function resolveCodexHelperRoot(srcRoot) {
|
|
72
72
|
const resolved = resolveAiwgRoot(srcRoot);
|
|
@@ -101,7 +101,6 @@ export const kernelSkillsPath = '.agents/skills/';
|
|
|
101
101
|
// Legacy home-dir skills location written by AIWG versions prior to the #766
|
|
102
102
|
// regression fix. Pruned on every codex skill deploy so codex-rs stops listing
|
|
103
103
|
// each AIWG skill twice. Never touches non-AIWG (unmarked) skills.
|
|
104
|
-
const legacyHomeSkillsDir = path.join(os.homedir(), '.codex', 'skills');
|
|
105
104
|
|
|
106
105
|
export const support = {
|
|
107
106
|
agents: 'native',
|
|
@@ -125,6 +124,7 @@ export const capabilities = {
|
|
|
125
124
|
* Map model shorthand to OpenAI/GPT format
|
|
126
125
|
*/
|
|
127
126
|
export function mapModel(originalModel, modelCfg, modelsConfig) {
|
|
127
|
+
const modelCatalog = modelCfg.modelCatalog || loadRuntimeModelCatalog(staticModelCatalog);
|
|
128
128
|
const gptModels = {
|
|
129
129
|
'opus': modelCatalog.providers.codex.roles.reasoning.id,
|
|
130
130
|
'sonnet': modelCatalog.providers.codex.roles.coding.id,
|
|
@@ -204,7 +204,7 @@ export function renderAgentToml(srcPath, content, models) {
|
|
|
204
204
|
*/
|
|
205
205
|
export function transformAgent(srcPath, content, opts) {
|
|
206
206
|
const { reasoningModel, codingModel, efficiencyModel } = opts;
|
|
207
|
-
const catalogModels = modelCatalog.providers.codex.roles;
|
|
207
|
+
const catalogModels = (opts.modelCatalog || loadRuntimeModelCatalog(staticModelCatalog)).providers.codex.roles;
|
|
208
208
|
|
|
209
209
|
const models = {
|
|
210
210
|
reasoning: reasoningModel || catalogModels.reasoning.id,
|
|
@@ -239,6 +239,27 @@ export function deployAgents(agentFiles, targetDir, opts) {
|
|
|
239
239
|
}, transformAgent);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/** Run the helper in this pass; retain process isolation for troubleshooting. */
|
|
243
|
+
async function runCodexDeployer(scriptPath, args, helperRoot, opts) {
|
|
244
|
+
if (process.env.AIWG_DEPLOY_SUBPROCESS !== '1') {
|
|
245
|
+
const deployer = await import(pathToFileURL(scriptPath).href);
|
|
246
|
+
await deployer.main(args, { homeDir: opts.deploymentHome || os.homedir() });
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
await new Promise((resolve, reject) => {
|
|
250
|
+
const child = spawn('node', [scriptPath, ...args], {
|
|
251
|
+
stdio: 'inherit',
|
|
252
|
+
cwd: helperRoot,
|
|
253
|
+
env: opts.deploymentHome ? { ...process.env, HOME: opts.deploymentHome } : process.env,
|
|
254
|
+
});
|
|
255
|
+
child.on('close', code => {
|
|
256
|
+
if (code === 0) resolve();
|
|
257
|
+
else reject(new Error(`${path.basename(scriptPath)} exited with code ${code}`));
|
|
258
|
+
});
|
|
259
|
+
child.on('error', reject);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
242
263
|
/**
|
|
243
264
|
* Deploy commands via external script
|
|
244
265
|
*
|
|
@@ -257,30 +278,16 @@ export async function deployCommands(targetDir, srcRoot, opts) {
|
|
|
257
278
|
|
|
258
279
|
console.log('Delegating command deployment to deploy-prompts-codex.mjs (~/.codex/prompts/)...');
|
|
259
280
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const child = spawn('node', [scriptPath, ...args], {
|
|
272
|
-
stdio: 'inherit',
|
|
273
|
-
cwd: helperRoot,
|
|
274
|
-
env: opts.deploymentHome ? { ...process.env, HOME: opts.deploymentHome } : process.env
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
child.on('close', (code) => {
|
|
278
|
-
if (code === 0) resolve();
|
|
279
|
-
else reject(new Error(`deploy-prompts-codex.mjs exited with code ${code}`));
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
child.on('error', reject);
|
|
283
|
-
});
|
|
281
|
+
// NOTE: Do NOT pass --target - Codex prompts belong in ~/.codex/prompts/ (home)
|
|
282
|
+
const args = ['--source', srcRoot];
|
|
283
|
+
if (opts.dryRun) args.push('--dry-run');
|
|
284
|
+
if (opts.force) args.push('--force');
|
|
285
|
+
if (opts.mode) args.push('--mode', opts.mode);
|
|
286
|
+
if (opts.copyStandardSkills === true) args.push('--copy-all');
|
|
287
|
+
// A copy-all the deployer forced on the caller's behalf (project-local
|
|
288
|
+
// bundles) still honors the startup listing cap (#2561).
|
|
289
|
+
if (opts.listingBudget === true) args.push('--listing-budget');
|
|
290
|
+
await runCodexDeployer(scriptPath, args, helperRoot, opts);
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
/**
|
|
@@ -305,37 +312,23 @@ export async function deploySkills(targetDir, srcRoot, opts) {
|
|
|
305
312
|
const crossAgentSkillsDir = path.join(targetDir, '.agents', 'skills');
|
|
306
313
|
console.log(`Deploying skills to ${crossAgentSkillsDir} (.agents/skills — codex-scanned path)...`);
|
|
307
314
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const child = spawn('node', [scriptPath, ...args], {
|
|
322
|
-
stdio: 'inherit',
|
|
323
|
-
cwd: helperRoot,
|
|
324
|
-
env: opts.deploymentHome ? { ...process.env, HOME: opts.deploymentHome } : process.env
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
child.on('close', (code) => {
|
|
328
|
-
if (code === 0) resolve();
|
|
329
|
-
else reject(new Error(`deploy-skills-codex.mjs exited with code ${code}`));
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
child.on('error', reject);
|
|
333
|
-
});
|
|
315
|
+
const args = ['--source', srcRoot, '--target', crossAgentSkillsDir];
|
|
316
|
+
// Overflow past Codex's startup listing cap lands here instead of being
|
|
317
|
+
// deployed over the cap (#2561); the index still reaches these skills.
|
|
318
|
+
args.push('--standard-target', path.join(targetDir, ...paths.skills.split('/').filter(Boolean)));
|
|
319
|
+
if (opts.dryRun) args.push('--dry-run');
|
|
320
|
+
if (opts.force) args.push('--force');
|
|
321
|
+
if (opts.mode) args.push('--mode', opts.mode);
|
|
322
|
+
if (opts.copyStandardSkills === true) args.push('--copy-all');
|
|
323
|
+
// A copy-all the deployer forced on the caller's behalf (project-local
|
|
324
|
+
// bundles) still honors the startup listing cap (#2561).
|
|
325
|
+
if (opts.listingBudget === true) args.push('--listing-budget');
|
|
326
|
+
await runCodexDeployer(scriptPath, args, helperRoot, opts);
|
|
334
327
|
|
|
335
328
|
// Self-heal: prune AIWG-managed skill dirs left behind in the legacy
|
|
336
329
|
// ~/.codex/skills/ home location by pre-fix versions, so codex-rs stops
|
|
337
330
|
// listing each skill twice.
|
|
338
|
-
pruneLegacyCodexSkills(opts, opts.legacyCodexSkills ||
|
|
331
|
+
pruneLegacyCodexSkills(opts, opts.legacyCodexSkills || path.join(os.homedir(), '.codex', 'skills'));
|
|
339
332
|
}
|
|
340
333
|
|
|
341
334
|
/**
|
|
@@ -346,7 +339,7 @@ export async function deploySkills(targetDir, srcRoot, opts) {
|
|
|
346
339
|
* the `.aiwg-managed` marker are removed — user-authored skills are never
|
|
347
340
|
* touched. The now-empty legacy dir is removed if AIWG owned everything in it.
|
|
348
341
|
*/
|
|
349
|
-
export function pruneLegacyCodexSkills(opts = {}, legacyDir =
|
|
342
|
+
export function pruneLegacyCodexSkills(opts = {}, legacyDir = path.join(os.homedir(), '.codex', 'skills')) {
|
|
350
343
|
let entries;
|
|
351
344
|
try {
|
|
352
345
|
entries = fs.readdirSync(legacyDir, { withFileTypes: true });
|
|
@@ -401,6 +394,7 @@ export function deployRules(ruleFiles, targetDir, opts) {
|
|
|
401
394
|
* Aggregate agents to single AGENTS.md file
|
|
402
395
|
*/
|
|
403
396
|
export function aggregateToAgentsMd(agentFiles, destPath, opts) {
|
|
397
|
+
if (opts.contextFiles === false) return 0;
|
|
404
398
|
const lines = ['# AIWG agent definitions', '', 'Read the selected definition before invoking an agent.', ''];
|
|
405
399
|
for (const file of agentFiles) {
|
|
406
400
|
const { metadata } = parseFrontmatter(fs.readFileSync(file, 'utf8'));
|
|
@@ -518,7 +512,7 @@ export async function postDeploy(targetDir, opts) {
|
|
|
518
512
|
initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
|
|
519
513
|
|
|
520
514
|
if (opts.createAgentsMd) {
|
|
521
|
-
createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
515
|
+
if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
522
516
|
}
|
|
523
517
|
}
|
|
524
518
|
|
|
@@ -27,6 +27,7 @@ let fs;
|
|
|
27
27
|
try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
|
|
28
28
|
import path from 'path';
|
|
29
29
|
import {
|
|
30
|
+
withRuleDeployment,
|
|
30
31
|
ensureDir,
|
|
31
32
|
listMdFiles,
|
|
32
33
|
listMdFilesRecursive,
|
|
@@ -429,6 +430,7 @@ export function deploySkills(skillDirs, targetDir, opts) {
|
|
|
429
430
|
* Deploy rules to .github/instructions/ as .instructions.md files
|
|
430
431
|
*/
|
|
431
432
|
export function deployRules(ruleFiles, targetDir, opts) {
|
|
433
|
+
if (opts.ruleDelivery) return [];
|
|
432
434
|
const destDir = path.join(targetDir, paths.rules);
|
|
433
435
|
ensureDir(destDir, opts.dryRun);
|
|
434
436
|
cleanupOldRuleFiles(destDir, opts);
|
|
@@ -495,8 +497,8 @@ export function createCopilotInstructions(target, srcRoot, dryRun) {
|
|
|
495
497
|
export async function postDeploy(targetDir, opts) {
|
|
496
498
|
initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
|
|
497
499
|
|
|
498
|
-
//
|
|
499
|
-
createCopilotInstructions(targetDir, opts.srcRoot, opts.dryRun);
|
|
500
|
+
// copilot-instructions.md is Copilot's context file: --no-context-files leaves it alone.
|
|
501
|
+
if (opts.contextFiles !== false) createCopilotInstructions(targetDir, opts.srcRoot, opts.dryRun);
|
|
500
502
|
}
|
|
501
503
|
|
|
502
504
|
// ============================================================================
|
|
@@ -517,6 +519,10 @@ export function getFileExtension(type) {
|
|
|
517
519
|
// ============================================================================
|
|
518
520
|
|
|
519
521
|
export async function deploy(opts) {
|
|
522
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
async function deploySelected(opts) {
|
|
520
526
|
const {
|
|
521
527
|
srcRoot,
|
|
522
528
|
target,
|
|
@@ -414,7 +414,7 @@ export async function postDeploy(targetDir, opts) {
|
|
|
414
414
|
initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
|
|
415
415
|
|
|
416
416
|
if (opts.createAgentsMd) {
|
|
417
|
-
createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
417
|
+
if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
// PUW-019 (#1120): wire environment.json + worktrees.json templates.
|
|
@@ -46,7 +46,7 @@ export function deployCordisPatch(target, opts) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export async function postDeploy(target, opts) {
|
|
49
|
-
if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) createAgentsMd(target, opts.srcRoot, opts.dryRun);
|
|
49
|
+
if (opts.contextFiles !== false && (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly))) createAgentsMd(target, opts.srcRoot, opts.dryRun);
|
|
50
50
|
if (!opts.quiet) console.log('DeepSeek Harness: runtime credentials remain environment-only; use a reviewed ephemeral route patch.');
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -25,6 +25,7 @@ let fs;
|
|
|
25
25
|
try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
|
|
26
26
|
import path from 'path';
|
|
27
27
|
import {
|
|
28
|
+
withRuleDeployment,
|
|
28
29
|
ensureDir,
|
|
29
30
|
listMdFiles,
|
|
30
31
|
listMdFilesRecursive,
|
|
@@ -576,6 +577,7 @@ export function deploySkills(skillDirs, targetDir, opts) {
|
|
|
576
577
|
* Deploy rules to .factory/rules/
|
|
577
578
|
*/
|
|
578
579
|
export function deployRules(ruleFiles, targetDir, opts) {
|
|
580
|
+
if (opts.ruleDelivery) return [];
|
|
579
581
|
const destDir = path.join(targetDir, paths.rules);
|
|
580
582
|
ensureDir(destDir, opts.dryRun);
|
|
581
583
|
cleanupOldRuleFiles(destDir, opts);
|
|
@@ -816,7 +818,7 @@ export async function postDeploy(targetDir, opts) {
|
|
|
816
818
|
|
|
817
819
|
// Create/update AGENTS.md if requested
|
|
818
820
|
if (opts.createAgentsMd) {
|
|
819
|
-
createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
821
|
+
if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
820
822
|
}
|
|
821
823
|
}
|
|
822
824
|
|
|
@@ -945,6 +947,10 @@ export function getFileExtension(type) {
|
|
|
945
947
|
* Main deployment function for Factory provider
|
|
946
948
|
*/
|
|
947
949
|
export async function deploy(opts) {
|
|
950
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath, transformSkillMd: transformSkillFrontmatter }, deploySelected);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
async function deploySelected(opts) {
|
|
948
954
|
const {
|
|
949
955
|
srcRoot,
|
|
950
956
|
target,
|
|
@@ -16,6 +16,8 @@ import fs from 'node:fs';
|
|
|
16
16
|
import { createHash, randomUUID } from 'node:crypto';
|
|
17
17
|
import yaml from 'js-yaml';
|
|
18
18
|
import {
|
|
19
|
+
withRuleDeployment,
|
|
20
|
+
replaceBoundRulesBlock,
|
|
19
21
|
createAgentsMdFromTemplate,
|
|
20
22
|
deploySkillsWithKernelRouting,
|
|
21
23
|
collectFrameworkArtifacts,
|
|
@@ -224,7 +226,17 @@ function matchesSkillSource(source, target) {
|
|
|
224
226
|
if (relative.endsWith(path.sep)) return true;
|
|
225
227
|
let content = fs.readFileSync(path.join(source, relative), 'utf8');
|
|
226
228
|
if (relative === 'SKILL.md') content = injectPlatformInContent(content, 'grok-build');
|
|
227
|
-
|
|
229
|
+
const deployed = fs.readFileSync(path.join(target, relative), 'utf8');
|
|
230
|
+
if (content === deployed) return true;
|
|
231
|
+
if (relative !== 'SKILL.md' || !deployed.includes('<!-- AIWG:bound-rules:start -->')) return false;
|
|
232
|
+
// Activation projection appends generated bindings. Verify the complete
|
|
233
|
+
// deployed bytes against the receipt before comparing the authored body;
|
|
234
|
+
// an operator edit (including inside the binding block) must survive.
|
|
235
|
+
const receipt = JSON.parse(fs.readFileSync(path.join(target, '.aiwg-manifest.json'), 'utf8'));
|
|
236
|
+
const digest = `sha256:${createHash('sha256').update(deployed).digest('hex')}`;
|
|
237
|
+
return receipt.skillSource === path.resolve(source)
|
|
238
|
+
&& receipt.managed?.[relative]?.hash === digest
|
|
239
|
+
&& replaceBoundRulesBlock(content, []).trimEnd() === replaceBoundRulesBlock(deployed, []).trimEnd();
|
|
228
240
|
});
|
|
229
241
|
} catch { return false; }
|
|
230
242
|
}
|
|
@@ -326,7 +338,7 @@ export function uninstall(target, opts = {}) {
|
|
|
326
338
|
|
|
327
339
|
export async function postDeploy(target, opts = {}) {
|
|
328
340
|
if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) {
|
|
329
|
-
createAgentsMd(target, opts.srcRoot, opts.dryRun);
|
|
341
|
+
if (opts.contextFiles !== false) createAgentsMd(target, opts.srcRoot, opts.dryRun);
|
|
330
342
|
}
|
|
331
343
|
if (!opts.quiet) {
|
|
332
344
|
const home = resolveGrokHome(opts.env || process.env);
|
|
@@ -344,6 +356,10 @@ export function getFileExtension() {
|
|
|
344
356
|
}
|
|
345
357
|
|
|
346
358
|
export async function deploy(opts) {
|
|
359
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function deploySelected(opts) {
|
|
347
363
|
const mode = normalizeDeploymentMode(opts.mode);
|
|
348
364
|
if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) {
|
|
349
365
|
assertSafeAgentsMd(opts.target);
|
|
@@ -171,7 +171,7 @@ export async function postDeploy(targetDir, opts = {}) {
|
|
|
171
171
|
opts.createAgentsMd ||
|
|
172
172
|
(!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)
|
|
173
173
|
) {
|
|
174
|
-
createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
174
|
+
if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
175
175
|
}
|
|
176
176
|
if (!opts.quiet) {
|
|
177
177
|
const root = resolveGrokbotSkillsDir(opts.env || process.env);
|
|
@@ -224,9 +224,9 @@ export function assertContextBudget(content, name = 'AGENTS.md', rules = []) {
|
|
|
224
224
|
* priming on every Hermes turn (#1318 / S7; skill-discovery added #1347).
|
|
225
225
|
*
|
|
226
226
|
* The full rule bodies are reachable without MCP via `aiwg discover` and
|
|
227
|
-
* `aiwg show rule <name
|
|
227
|
+
* `aiwg show rule <name> --body`; MCP exposes the same path through `rule-list` and
|
|
228
228
|
* `rule-show` when configured (#1320). The bodies exceed Hermes's 20K context
|
|
229
|
-
* cap if inlined verbatim (anti-laziness alone
|
|
229
|
+
* cap if inlined verbatim (anti-laziness alone was 32K chars; it now ships as a compact core body, #3450), so we inline
|
|
230
230
|
* compressed directives only and point to CLI/MCP for the full text.
|
|
231
231
|
*
|
|
232
232
|
* Selection criteria: rules tagged CRITICAL/HIGH enforcement level whose
|
|
@@ -240,7 +240,7 @@ const CRITICAL_RULE_DIRECTIVES = `## CRITICAL Rules (always apply)
|
|
|
240
240
|
These are the highest-enforcement AIWG rules. Full bodies are reachable without
|
|
241
241
|
MCP:
|
|
242
242
|
- Find rules: \`aiwg discover "rule <topic>" --type rule\`
|
|
243
|
-
- Fetch a rule: \`aiwg show rule <name
|
|
243
|
+
- Fetch a rule: \`aiwg show rule <name> --body\`
|
|
244
244
|
|
|
245
245
|
If the optional MCP sidecar is configured, the same surface is available through
|
|
246
246
|
\`mcp_aiwg_rule_list\` and \`mcp_aiwg_rule_show\`.
|
|
@@ -260,13 +260,6 @@ Never add AI-tool attribution to commits, PRs, code, or docs. No \`Co-Authored-B
|
|
|
260
260
|
no "Generated with", no "Written by [AI tool]". The AI is a tool; tools don't sign
|
|
261
261
|
their output. Applies to ALL platforms (Claude, Codex, Copilot, Cursor, etc.).
|
|
262
262
|
|
|
263
|
-
### Rule: anti-laziness
|
|
264
|
-
Never delete tests to make them pass. Never skip/disable tests. Never remove
|
|
265
|
-
features instead of fixing them. Never weaken assertions to be meaningless.
|
|
266
|
-
Never suppress CI/pipeline signals (\`continue-on-error\`, \`|| true\`, \`set +e\`).
|
|
267
|
-
If stuck after 3 honest attempts: escalate with full context, don't shortcut.
|
|
268
|
-
Within scope: leave nothing half-done — code + tests + docs + verification.
|
|
269
|
-
|
|
270
263
|
### Rule: citation-policy
|
|
271
264
|
Never fabricate citations, DOIs, URLs, or page numbers. Only cite sources that
|
|
272
265
|
exist in the research corpus (.aiwg/research/sources/). Match claim strength
|
|
@@ -331,6 +324,7 @@ function mergeHermesContext(file, generated, kind) {
|
|
|
331
324
|
}
|
|
332
325
|
|
|
333
326
|
export function generateAgentsMd(agentCount, skillCount, targetDir, opts) {
|
|
327
|
+
if (opts.contextFiles === false) return;
|
|
334
328
|
const { dryRun } = opts;
|
|
335
329
|
|
|
336
330
|
// Startup is reserved for rule contracts. Workflow routing, artifact catalogs,
|
|
@@ -339,7 +333,7 @@ export function generateAgentsMd(agentCount, skillCount, targetDir, opts) {
|
|
|
339
333
|
const header = `# AIWG Integration
|
|
340
334
|
|
|
341
335
|
Skills: \`$HERMES_HOME/skills/\` (kernel), \`$HERMES_HOME/skills/.aiwg/\` (standard).
|
|
342
|
-
Find: \`aiwg discover "rule <topic>" --type rule\`. Fetch: \`aiwg show rule <name
|
|
336
|
+
Find: \`aiwg discover "rule <topic>" --type rule\`. Fetch: \`aiwg show rule <name> --body\`.
|
|
343
337
|
MCP is optional; \`mcp_aiwg_rule_show\` exposes the same rule catalog.
|
|
344
338
|
`;
|
|
345
339
|
|
|
@@ -533,7 +527,7 @@ async function deploySelected(opts) {
|
|
|
533
527
|
// Generate AGENTS.md (with inlined CRITICAL rule priming, #1318/#1532)
|
|
534
528
|
// AND .hermes.md thin pointer (resolves #1319 doc-debt, was claimed in
|
|
535
529
|
// CHANGELOG but not previously implemented).
|
|
536
|
-
if (!skillsOnly && !opts.commandsOnly && !opts.rulesOnly) {
|
|
530
|
+
if (opts.contextFiles !== false && !skillsOnly && !opts.commandsOnly && !opts.rulesOnly) {
|
|
537
531
|
const artifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
|
|
538
532
|
includeAgents: true,
|
|
539
533
|
includeCommands: false,
|
|
@@ -560,7 +554,7 @@ async function deploySelected(opts) {
|
|
|
560
554
|
if (!opts.quiet) {
|
|
561
555
|
console.log('');
|
|
562
556
|
console.log(`Skills root: ${kernelSkillsPath}`);
|
|
563
|
-
console.log('Rules are in AGENTS.md as compressed directives; full bodies via `aiwg show rule <name
|
|
557
|
+
console.log('Rules are in AGENTS.md as compressed directives; full bodies via `aiwg show rule <name> --body`.');
|
|
564
558
|
console.log('Optional: configure config.yaml to connect AIWG MCP server.');
|
|
565
559
|
console.log('See: docs/integrations/hermes-quickstart.md (optional MCP setup)');
|
|
566
560
|
}
|
|
@@ -43,9 +43,7 @@
|
|
|
43
43
|
* Servers inherit the operator's process environment; pass `MUSE_SESSION_ID`
|
|
44
44
|
* through at runtime instead of hardcoding a session id into `env`.
|
|
45
45
|
*
|
|
46
|
-
*
|
|
47
|
-
* muse-paths.mjs only) so provider-policy-style import graphs never pull it
|
|
48
|
-
* in transitively.
|
|
46
|
+
* MCP writes use the shared config writer, resolved for source and packaged installs.
|
|
49
47
|
*
|
|
50
48
|
* @issue #228
|
|
51
49
|
*/
|
|
@@ -53,9 +51,13 @@
|
|
|
53
51
|
import fs from 'node:fs';
|
|
54
52
|
import os from 'node:os';
|
|
55
53
|
import path from 'node:path';
|
|
54
|
+
import { randomUUID } from 'node:crypto';
|
|
55
|
+
import { importImpl } from '../../_resolve-impl.mjs';
|
|
56
56
|
import { stripJsonComments } from './base.mjs';
|
|
57
57
|
import { resolveMuseXdgSkillsDir, museXdgSkillsDirRemediation } from './muse-paths.mjs';
|
|
58
58
|
|
|
59
|
+
const { assertConfigDestination, writeConfigAtomic, writeConfigTransaction } = await importImpl(import.meta.url, 'mcp/config-file.mjs');
|
|
60
|
+
|
|
59
61
|
// ---------------------------------------------------------------------------
|
|
60
62
|
// Shared JSON helpers
|
|
61
63
|
// ---------------------------------------------------------------------------
|
|
@@ -631,7 +633,7 @@ export function mergeMcpProfile(existingDoc, opts = {}) {
|
|
|
631
633
|
* preserving unknown keys, timestamped backup before writing, atomic write,
|
|
632
634
|
* dry-run diff with zero writes, fail closed on unparseable settings.
|
|
633
635
|
*/
|
|
634
|
-
export function deployMuseMcp(opts = {}) {
|
|
636
|
+
export async function deployMuseMcp(opts = {}) {
|
|
635
637
|
const { dryRun = false, quiet = false, mcp = false, env = process.env, userHome = os.homedir() } = opts;
|
|
636
638
|
const log = quiet ? () => {} : (msg) => console.log(msg);
|
|
637
639
|
|
|
@@ -642,6 +644,8 @@ export function deployMuseMcp(opts = {}) {
|
|
|
642
644
|
|
|
643
645
|
const settingsPath = assertMuseUserSettingsPath(env, userHome);
|
|
644
646
|
const configDir = path.dirname(settingsPath);
|
|
647
|
+
await assertConfigDestination(settingsPath);
|
|
648
|
+
await assertConfigDestination(path.join(configDir, MUSE_MCP_SIDECAR_NAME));
|
|
645
649
|
const { doc: existingDoc, raw: existingRaw, existed } = readSettingsDoc(settingsPath);
|
|
646
650
|
const sidecar = readMcpSidecar(configDir);
|
|
647
651
|
const profile = aiwgMcpServerProfile();
|
|
@@ -680,14 +684,15 @@ export function deployMuseMcp(opts = {}) {
|
|
|
680
684
|
return { settingsPath, changed: true, plan, wrote: false, warnings };
|
|
681
685
|
}
|
|
682
686
|
|
|
683
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
684
687
|
let backupPath = null;
|
|
685
688
|
if (existed) {
|
|
686
|
-
backupPath = `${settingsPath}.aiwg-backup-${new Date().toISOString().replace(/[:.]/g, '-')}`;
|
|
687
|
-
|
|
689
|
+
backupPath = `${settingsPath}.aiwg-backup-${new Date().toISOString().replace(/[:.]/g, '-')}-${randomUUID()}`;
|
|
690
|
+
await writeConfigAtomic(backupPath, existingRaw, { userScope: true });
|
|
688
691
|
}
|
|
689
|
-
|
|
690
|
-
|
|
692
|
+
await writeConfigTransaction([
|
|
693
|
+
{ file: settingsPath, content: afterText, options: { userScope: true } },
|
|
694
|
+
{ file: sidecar.path, content: canonicalJson({ version: 1, servers: ['aiwg'] }), options: { userScope: true } },
|
|
695
|
+
]);
|
|
691
696
|
|
|
692
697
|
log(`Muse MCP: merged AIWG stdio profile into ${settingsPath}`);
|
|
693
698
|
for (const step of plan) log(` ${step}`);
|
|
@@ -700,11 +705,13 @@ export function deployMuseMcp(opts = {}) {
|
|
|
700
705
|
* Removal path: drop the AIWG-managed `aiwg` server key (only when recorded
|
|
701
706
|
* in the sidecar) and delete the sidecar. Operator servers are never touched.
|
|
702
707
|
*/
|
|
703
|
-
export function pruneMuseMcp(opts = {}) {
|
|
708
|
+
export async function pruneMuseMcp(opts = {}) {
|
|
704
709
|
const { dryRun = false, quiet = false, env = process.env, userHome = os.homedir() } = opts;
|
|
705
710
|
const log = quiet ? () => {} : (msg) => console.log(msg);
|
|
706
711
|
const settingsPath = assertMuseUserSettingsPath(env, userHome);
|
|
707
712
|
const configDir = path.dirname(settingsPath);
|
|
713
|
+
await assertConfigDestination(settingsPath);
|
|
714
|
+
await assertConfigDestination(path.join(configDir, MUSE_MCP_SIDECAR_NAME));
|
|
708
715
|
|
|
709
716
|
if (!fs.existsSync(settingsPath)) {
|
|
710
717
|
log(`Muse MCP: no ${settingsPath}; nothing to prune.`);
|
|
@@ -731,10 +738,10 @@ export function pruneMuseMcp(opts = {}) {
|
|
|
731
738
|
return { settingsPath, pruned: true, wrote: false };
|
|
732
739
|
}
|
|
733
740
|
|
|
734
|
-
const backupPath = `${settingsPath}.aiwg-backup-${new Date().toISOString().replace(/[:.]/g, '-')}`;
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
if (
|
|
741
|
+
const backupPath = `${settingsPath}.aiwg-backup-${new Date().toISOString().replace(/[:.]/g, '-')}-${randomUUID()}`;
|
|
742
|
+
await writeConfigAtomic(backupPath, existingRaw, { userScope: true });
|
|
743
|
+
await writeConfigAtomic(settingsPath, canonicalJson(merged), { userScope: true });
|
|
744
|
+
if (await assertConfigDestination(sidecar.path)) fs.unlinkSync(sidecar.path);
|
|
738
745
|
log(`Muse MCP: removed mcp_servers.aiwg from ${settingsPath} (backup: ${backupPath}).`);
|
|
739
746
|
return { settingsPath, pruned: true, wrote: true, backupPath };
|
|
740
747
|
}
|
|
@@ -35,6 +35,7 @@ import fs from 'node:fs';
|
|
|
35
35
|
import os from 'node:os';
|
|
36
36
|
import path from 'node:path';
|
|
37
37
|
import {
|
|
38
|
+
withRuleDeployment,
|
|
38
39
|
collectFrameworkArtifacts,
|
|
39
40
|
createAgentsMdFromTemplate,
|
|
40
41
|
deploySkillsWithKernelRouting,
|
|
@@ -226,7 +227,7 @@ export async function postDeploy(targetDir, opts = {}) {
|
|
|
226
227
|
// bridge, managed hooks, and an opted-in MCP profile must not be skipped.
|
|
227
228
|
const fullDeploy = !opts.commandsOnly && !opts.rulesOnly && (!opts.skillsOnly || opts.kernelOnly === true);
|
|
228
229
|
if (opts.createAgentsMd || fullDeploy) {
|
|
229
|
-
createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
230
|
+
if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
// #228 — managed project hooks (.muse/hooks.json). Default on, mirroring
|
|
@@ -240,7 +241,7 @@ export async function postDeploy(targetDir, opts = {}) {
|
|
|
240
241
|
// #228 — optional MCP settings profile. Explicit opt-in only (--mcp);
|
|
241
242
|
// default `aiwg use --provider muse` never touches user settings.
|
|
242
243
|
if (fullDeploy && opts.mcp === true) {
|
|
243
|
-
deployMuseMcp(opts);
|
|
244
|
+
await deployMuseMcp(opts);
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
if (!opts.quiet) {
|
|
@@ -265,6 +266,10 @@ export async function postDeploy(targetDir, opts = {}) {
|
|
|
265
266
|
}
|
|
266
267
|
|
|
267
268
|
export async function deploy(opts = {}) {
|
|
269
|
+
return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function deploySelected(opts) {
|
|
268
273
|
const {
|
|
269
274
|
srcRoot,
|
|
270
275
|
target,
|