@aiwg/cli 2026.10.3 → 2026.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/agentic/code/providers/model-capabilities.v1.json +96 -4
- package/bin/aiwg.mjs +50 -27
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +69 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +286 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +130 -0
- package/dist/src/artifacts/index-refresh.js +591 -0
- package/dist/src/artifacts/index-worker.mjs +11 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +19 -2
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +19 -12
- package/dist/src/cli/handlers/diagnose.js +4 -3
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +4 -1
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/models.js +104 -8
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/refresh.js +12 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +1 -2
- package/dist/src/cli/handlers/script-runner.js +3 -2
- package/dist/src/cli/handlers/session.js +19 -9
- package/dist/src/cli/handlers/sessions.js +137 -43
- package/dist/src/cli/handlers/setup-manifest.js +39 -44
- package/dist/src/cli/handlers/setup.js +41 -0
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +57 -2
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +294 -55
- package/dist/src/cli/handlers/utilities.js +26 -10
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +87 -37
- package/dist/src/config/cli.js +111 -5
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +2 -1
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +13 -8
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +2 -15
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +5 -13
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +131 -28
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/gates/providers/loader.js +61 -17
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +14 -2
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +78 -3
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +7 -1
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +36 -11
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +1 -1
- package/dist/src/mcp/helpers.mjs +3 -2
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/registry.js +3 -93
- package/dist/src/mcp/registry.mjs +3 -87
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +37 -375
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tools/decision.mjs +12 -11
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +12 -2
- package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
- package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
- package/dist/src/mission-protocol/codecs.js +8 -0
- package/dist/src/models/config-loader.js +7 -2
- package/dist/src/models/model-capabilities.v1.json +96 -4
- package/dist/src/models/model-discovery.js +76 -11
- package/dist/src/models/provider-policy.js +101 -7
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/resolver.js +12 -10
- package/dist/src/models/worker-direct-readiness.js +65 -44
- package/dist/src/models/worker-dispatch-offer.js +3 -3
- package/dist/src/models/worker-health-readiness.js +16 -3
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +135 -28
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +43 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +12 -4
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/mission-conductor.js +38 -12
- package/dist/src/serve/worker-invocation.js +30 -10
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/sessions/adapter-registry.js +23 -19
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +95 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +10 -10
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot.js +24 -13
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
- package/dist/src/sessions/adapters/muse.js +150 -93
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +29 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +16 -8
- package/dist/src/sessions/batch-import.js +252 -12
- package/dist/src/sessions/contracts.js +50 -3
- package/dist/src/sessions/coverage-preflight.js +27 -2
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +60 -38
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +145 -26
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +105 -0
- package/dist/src/sessions/repository.js +151 -54
- package/dist/src/sessions/workspace-discovery.js +292 -60
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/package.json +15 -2
- package/schemas/models/model-catalog.v1.schema.json +1 -1
- package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
- package/tools/_resolve-impl.mjs +13 -15
- package/tools/agents/deploy-agents.mjs +49 -21
- package/tools/agents/providers/base.mjs +104 -134
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/hermes.mjs +57 -47
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +6 -4
- package/tools/providers/omp-transport.mjs +4 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
- package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
- package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { renderCredentialMaps } from './credentials.mjs';
|
|
2
|
+
import { getMcpInjectionDefinition, normalizeRuntimeProviderId } from '../providers/provider-definitions.mjs';
|
|
3
|
+
|
|
4
|
+
export function buildServerConfig(server, provider) {
|
|
5
|
+
const mcpDefinition = getMcpInjectionDefinition(provider);
|
|
6
|
+
// TOML providers render references through their own named keys in
|
|
7
|
+
// buildServerToml; unconditional interpolation would refuse them here even
|
|
8
|
+
// though the TOML writer handles them.
|
|
9
|
+
const { env, headers } = mcpDefinition?.serverConfigFormat === 'toml'
|
|
10
|
+
? {}
|
|
11
|
+
: renderCredentialMaps(server, normalizeRuntimeProviderId(provider) || provider);
|
|
12
|
+
|
|
13
|
+
switch (mcpDefinition?.serverConfigFormat) {
|
|
14
|
+
case 'claude-code': {
|
|
15
|
+
if (server.type === 'stdio') {
|
|
16
|
+
return {
|
|
17
|
+
command: server.command,
|
|
18
|
+
args: server.args || [],
|
|
19
|
+
...(env ? { env } : {}),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Claude Code skips a url entry that has no type.
|
|
23
|
+
return {
|
|
24
|
+
type: server.type,
|
|
25
|
+
url: server.url,
|
|
26
|
+
...(headers ? { headers } : {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
case 'antigravity': {
|
|
30
|
+
if (server.type === 'stdio') {
|
|
31
|
+
return { command: server.command, args: server.args || [], ...(env ? { env } : {}) };
|
|
32
|
+
}
|
|
33
|
+
return { serverUrl: server.url, ...(headers ? { headers } : {}) };
|
|
34
|
+
}
|
|
35
|
+
case 'standard': {
|
|
36
|
+
if (server.type === 'stdio') {
|
|
37
|
+
return {
|
|
38
|
+
command: server.command,
|
|
39
|
+
args: server.args || [],
|
|
40
|
+
...(env ? { env } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
url: server.url,
|
|
45
|
+
...(headers ? { headers } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
case 'factory': {
|
|
50
|
+
if (server.type === 'stdio') {
|
|
51
|
+
return {
|
|
52
|
+
type: 'stdio',
|
|
53
|
+
command: server.command,
|
|
54
|
+
args: server.args || [],
|
|
55
|
+
disabled: false,
|
|
56
|
+
...(env ? { env } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
type: server.type,
|
|
61
|
+
url: server.url,
|
|
62
|
+
disabled: false,
|
|
63
|
+
...(headers ? { headers } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case 'opencode': {
|
|
68
|
+
if (server.type === 'stdio') {
|
|
69
|
+
// opencode names a local server's variables `environment`.
|
|
70
|
+
return {
|
|
71
|
+
type: 'local',
|
|
72
|
+
command: [server.command, ...(server.args || [])],
|
|
73
|
+
...(env ? { environment: env } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
type: 'remote',
|
|
78
|
+
url: server.url,
|
|
79
|
+
...(headers ? { headers } : {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
case 'toml':
|
|
84
|
+
return {};
|
|
85
|
+
|
|
86
|
+
default:
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
}
|
package/dist/src/mcp/server.mjs
CHANGED
|
@@ -16,8 +16,6 @@ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mc
|
|
|
16
16
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
17
17
|
import { z } from 'zod';
|
|
18
18
|
import fs from 'fs/promises';
|
|
19
|
-
import { constants } from 'node:fs';
|
|
20
|
-
import { randomUUID } from 'node:crypto';
|
|
21
19
|
import path from 'path';
|
|
22
20
|
import { fileURLToPath } from 'url';
|
|
23
21
|
import { registerWriterProfileResources } from './tools/writer-profiles.mjs';
|
|
@@ -26,6 +24,7 @@ import { registerCommandRunTool } from './tools/command-run.mjs';
|
|
|
26
24
|
import { registerInteractionTools } from './tools/interaction.mjs';
|
|
27
25
|
import { parseToolsets, registerOptInToolsets, KNOWN_TOOLSETS } from './tools/subsystems.mjs';
|
|
28
26
|
import { AIWG_ROOT, findProjectRoot, resolveProjectAiwgDir } from './helpers.mjs';
|
|
27
|
+
import { pinContainedRoot as pinArtifactRoot, openContainedFile as openArtifact, readContainedFile, listContainedFiles, validateContainedPath } from '../utils/contained-filesystem.mjs';
|
|
29
28
|
|
|
30
29
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
31
30
|
|
|
@@ -35,317 +34,6 @@ const FRAMEWORKS = {
|
|
|
35
34
|
'media-marketing-kit': path.join(AIWG_ROOT, 'agentic/code/frameworks/media-marketing-kit')
|
|
36
35
|
};
|
|
37
36
|
|
|
38
|
-
function assertArtifactContained(root, target) {
|
|
39
|
-
const relative = path.relative(root, target);
|
|
40
|
-
if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
41
|
-
throw new Error('Artifact path must stay beneath the artifact root');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function rootedArtifactAccess() {
|
|
46
|
-
return process.platform === 'linux' && constants.O_NOFOLLOW && constants.O_DIRECTORY;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** A root pinned as missing must be created by us, never adopted later. */
|
|
50
|
-
async function createArtifactRoot(store) {
|
|
51
|
-
let parent;
|
|
52
|
-
let directory;
|
|
53
|
-
let verified = false;
|
|
54
|
-
try {
|
|
55
|
-
let entry = store.configured;
|
|
56
|
-
if (rootedArtifactAccess()) {
|
|
57
|
-
parent = await fs.open(store.projectRoot, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
58
|
-
if (await fs.realpath(`/proc/self/fd/${parent.fd}`) !== store.projectRoot) {
|
|
59
|
-
throw new Error('Project root changed during artifact creation');
|
|
60
|
-
}
|
|
61
|
-
entry = `/proc/self/fd/${parent.fd}/.aiwg`;
|
|
62
|
-
}
|
|
63
|
-
// EEXIST is a refusal, including a symlink or directory installed since pinning.
|
|
64
|
-
await fs.mkdir(entry);
|
|
65
|
-
const created = await fs.lstat(entry);
|
|
66
|
-
if (created.isSymbolicLink() || !created.isDirectory()) throw new Error('Artifact root changed during creation');
|
|
67
|
-
// Windows cannot open directory handles through fs.open; its fallback
|
|
68
|
-
// uses static identity checks, as do the subsequent artifact operations.
|
|
69
|
-
if (process.platform !== 'win32') {
|
|
70
|
-
directory = await fs.open(entry, constants.O_RDONLY | (constants.O_DIRECTORY || 0) | (constants.O_NOFOLLOW || 0));
|
|
71
|
-
}
|
|
72
|
-
const opened = directory ? await directory.stat() : await fs.stat(entry);
|
|
73
|
-
const current = await fs.lstat(entry);
|
|
74
|
-
if (current.isSymbolicLink() || !opened.isDirectory()
|
|
75
|
-
|| opened.dev !== created.dev || opened.ino !== created.ino
|
|
76
|
-
|| opened.dev !== current.dev || opened.ino !== current.ino
|
|
77
|
-
|| await fs.realpath(store.configured) !== store.root) {
|
|
78
|
-
throw new Error('Artifact root changed during creation');
|
|
79
|
-
}
|
|
80
|
-
store.identity = opened;
|
|
81
|
-
verified = true;
|
|
82
|
-
} finally {
|
|
83
|
-
const closed = await Promise.allSettled([...(directory ? [directory.close()] : []), ...(parent ? [parent.close()] : [])]);
|
|
84
|
-
const failure = closed.find(result => result.status === 'rejected');
|
|
85
|
-
if (verified && failure) throw failure.reason;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** Pin an existing store once; only a missing local default may be bootstrapped. */
|
|
90
|
-
async function pinArtifactRoot(configured, projectRoot) {
|
|
91
|
-
try {
|
|
92
|
-
const root = await fs.realpath(configured);
|
|
93
|
-
const identity = await fs.stat(root);
|
|
94
|
-
const store = { configured, projectRoot, root, identity };
|
|
95
|
-
await verifyArtifactRoot(store);
|
|
96
|
-
return store;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
if (error.code === 'ENOENT' && configured === path.join(projectRoot, '.aiwg')) {
|
|
99
|
-
const existing = await fs.lstat(configured).catch(missing => {
|
|
100
|
-
if (missing.code !== 'ENOENT') throw missing;
|
|
101
|
-
});
|
|
102
|
-
if (!existing) return { configured, projectRoot, root: configured, identity: null };
|
|
103
|
-
// A symlink (or other unexpected node) present where the default root
|
|
104
|
-
// should be created must not become the containment root later.
|
|
105
|
-
return {
|
|
106
|
-
configured,
|
|
107
|
-
projectRoot,
|
|
108
|
-
root: configured,
|
|
109
|
-
error: new Error('Default artifact root is not a creatable directory'),
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// Keep discovery available, but never adopt a store that was unavailable
|
|
113
|
-
// at startup (including a dangling alias) on a later request.
|
|
114
|
-
return { configured, projectRoot, root: configured, error };
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async function verifyArtifactRoot(store) {
|
|
119
|
-
if (store.error) throw store.error;
|
|
120
|
-
const canonical = await fs.realpath(store.configured);
|
|
121
|
-
const current = await fs.stat(store.configured);
|
|
122
|
-
if (canonical !== store.root || !current.isDirectory()
|
|
123
|
-
|| current.dev !== store.identity.dev || current.ino !== store.identity.ino) {
|
|
124
|
-
throw new Error('Artifact root changed since it was pinned');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function pinnedArtifactRoot(store, write) {
|
|
129
|
-
if (store.error) throw store.error;
|
|
130
|
-
if (!store.identity) {
|
|
131
|
-
if (!write) throw new Error('Default artifact root has not been created');
|
|
132
|
-
// Serialize first-write initialization so concurrent requests share one
|
|
133
|
-
// identity. Creation still rejects symlinks and uses a project descriptor.
|
|
134
|
-
store.initialization ||= createArtifactRoot(store);
|
|
135
|
-
await store.initialization;
|
|
136
|
-
}
|
|
137
|
-
await verifyArtifactRoot(store);
|
|
138
|
-
return store.root;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Resolve existing aliases before creating anything; dangling symlinks fail closed. */
|
|
142
|
-
async function resolveArtifactPath(store, artifactPath, { write = false } = {}) {
|
|
143
|
-
if (!artifactPath || path.isAbsolute(artifactPath) || path.win32.isAbsolute(artifactPath)
|
|
144
|
-
|| /^[A-Za-z]:/.test(artifactPath)
|
|
145
|
-
|| (process.platform === 'win32' && artifactPath.split(/[\\/]/).some(part => part !== '.'
|
|
146
|
-
&& (/[<>:"|?*\x00-\x1f]/.test(part) || /[. ]$/.test(part)
|
|
147
|
-
|| /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part))))
|
|
148
|
-
|| artifactPath.split(/[\\/]/).includes('..')) {
|
|
149
|
-
throw new Error('Artifact path must be relative and contain no .. segments');
|
|
150
|
-
}
|
|
151
|
-
if (write && artifactPath.split(/[\\/]/).some(part => /^\.aiwg-location[. ]*(?::.*)?$/i.test(part))) {
|
|
152
|
-
throw new Error('Refusing to write an artifact location pointer');
|
|
153
|
-
}
|
|
154
|
-
const root = await pinnedArtifactRoot(store, write);
|
|
155
|
-
const target = path.resolve(root, artifactPath);
|
|
156
|
-
assertArtifactContained(root, target);
|
|
157
|
-
if (!rootedArtifactAccess()) {
|
|
158
|
-
let componentPath = root;
|
|
159
|
-
for (const component of path.relative(root, target).split(path.sep)) {
|
|
160
|
-
componentPath = path.join(componentPath, component);
|
|
161
|
-
const info = await fs.lstat(componentPath).catch(error => {
|
|
162
|
-
if (error.code !== 'ENOENT') throw error;
|
|
163
|
-
});
|
|
164
|
-
if (info?.isSymbolicLink()) throw new Error('Refusing artifact symlink component');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
let ancestor = path.dirname(target);
|
|
168
|
-
const missing = [];
|
|
169
|
-
while (true) {
|
|
170
|
-
try {
|
|
171
|
-
// lstat distinguishes a missing directory from a dangling symlink.
|
|
172
|
-
await fs.lstat(ancestor);
|
|
173
|
-
break;
|
|
174
|
-
} catch (error) {
|
|
175
|
-
if (error.code !== 'ENOENT') throw error;
|
|
176
|
-
missing.unshift(path.basename(ancestor));
|
|
177
|
-
ancestor = path.dirname(ancestor);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const realAncestor = await fs.realpath(ancestor);
|
|
181
|
-
if (realAncestor !== root) assertArtifactContained(root, realAncestor);
|
|
182
|
-
const fullPath = path.resolve(realAncestor, ...missing, path.basename(target));
|
|
183
|
-
assertArtifactContained(root, fullPath);
|
|
184
|
-
let info;
|
|
185
|
-
try {
|
|
186
|
-
info = await fs.lstat(fullPath);
|
|
187
|
-
} catch (error) {
|
|
188
|
-
if (error.code !== 'ENOENT') throw error;
|
|
189
|
-
}
|
|
190
|
-
if (info) {
|
|
191
|
-
if (write && info.isSymbolicLink()) throw new Error('Refusing to write through an artifact symlink');
|
|
192
|
-
const realTarget = await fs.realpath(fullPath);
|
|
193
|
-
assertArtifactContained(root, realTarget);
|
|
194
|
-
if (!write) return { root, fullPath: realTarget };
|
|
195
|
-
}
|
|
196
|
-
return { root, fullPath };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Linux procfs descriptor paths anchor each lookup to an opened directory.
|
|
201
|
-
* Other platforms use static containment checks. Writes use a fresh inode;
|
|
202
|
-
* failed verification closes handles without unsafe pathname cleanup.
|
|
203
|
-
* Concurrent same-user relocation after verification is not a sandbox boundary.
|
|
204
|
-
*/
|
|
205
|
-
async function openArtifact(store, artifactPath, { write = false } = {}) {
|
|
206
|
-
const { root, fullPath } = await resolveArtifactPath(store, artifactPath, { write });
|
|
207
|
-
if (!rootedArtifactAccess()) return openStaticArtifact(store, root, fullPath, { write });
|
|
208
|
-
const directories = [];
|
|
209
|
-
let file;
|
|
210
|
-
let transferred = false;
|
|
211
|
-
const descriptorPath = handle => `/proc/self/fd/${handle.fd}`;
|
|
212
|
-
async function verify(handle, { rootHandle = false, directory = false, entry } = {}) {
|
|
213
|
-
const actual = await fs.realpath(descriptorPath(handle));
|
|
214
|
-
if (rootHandle) {
|
|
215
|
-
if (actual !== root) throw new Error('Artifact root changed during access');
|
|
216
|
-
} else {
|
|
217
|
-
assertArtifactContained(root, actual);
|
|
218
|
-
}
|
|
219
|
-
const [opened, current] = await Promise.all([handle.stat(), fs.lstat(entry || actual)]);
|
|
220
|
-
if (rootHandle) {
|
|
221
|
-
await verifyArtifactRoot(store);
|
|
222
|
-
if (opened.dev !== store.identity.dev || opened.ino !== store.identity.ino) {
|
|
223
|
-
throw new Error('Artifact root changed since it was pinned');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (current.isSymbolicLink() || opened.dev !== current.dev || opened.ino !== current.ino
|
|
227
|
-
|| (directory ? !opened.isDirectory() : !opened.isFile())) {
|
|
228
|
-
throw new Error('Artifact changed during access or is not a regular file/directory');
|
|
229
|
-
}
|
|
230
|
-
if (!directory && (opened.nlink > 1 || current.nlink > 1)) {
|
|
231
|
-
throw new Error('Refusing multiply-linked artifact file');
|
|
232
|
-
}
|
|
233
|
-
return actual;
|
|
234
|
-
}
|
|
235
|
-
async function close() {
|
|
236
|
-
const closed = await Promise.allSettled([...(file ? [file.close()] : []), ...directories.map(handle => handle.close())]);
|
|
237
|
-
const failure = closed.find(result => result.status === 'rejected');
|
|
238
|
-
if (failure) throw failure.reason;
|
|
239
|
-
}
|
|
240
|
-
try {
|
|
241
|
-
let parent = await fs.open(root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
242
|
-
directories.push(parent);
|
|
243
|
-
await verify(parent, { rootHandle: true, directory: true });
|
|
244
|
-
const components = path.relative(root, fullPath).split(path.sep);
|
|
245
|
-
const name = components.pop();
|
|
246
|
-
for (const component of components) {
|
|
247
|
-
const entry = path.join(descriptorPath(parent), component);
|
|
248
|
-
let child;
|
|
249
|
-
try {
|
|
250
|
-
child = await fs.open(entry, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
251
|
-
} catch (error) {
|
|
252
|
-
if (!write || error.code !== 'ENOENT') throw error;
|
|
253
|
-
await verify(parent, { rootHandle: directories.length === 1, directory: true });
|
|
254
|
-
try {
|
|
255
|
-
await fs.mkdir(entry);
|
|
256
|
-
} catch (mkdirError) {
|
|
257
|
-
if (mkdirError.code !== 'EEXIST') throw mkdirError;
|
|
258
|
-
}
|
|
259
|
-
child = await fs.open(entry, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
260
|
-
}
|
|
261
|
-
directories.push(child);
|
|
262
|
-
await verify(child, { directory: true });
|
|
263
|
-
parent = child;
|
|
264
|
-
}
|
|
265
|
-
const parentOptions = { rootHandle: directories.length === 1, directory: true };
|
|
266
|
-
await verify(parent, parentOptions);
|
|
267
|
-
const destination = path.join(descriptorPath(parent), name);
|
|
268
|
-
async function verifyDestination() {
|
|
269
|
-
const info = await fs.lstat(destination).catch(error => {
|
|
270
|
-
if (error.code !== 'ENOENT') throw error;
|
|
271
|
-
});
|
|
272
|
-
if (info && (info.isSymbolicLink() || !info.isFile())) {
|
|
273
|
-
throw new Error('Refusing to replace an artifact symlink or nonregular file');
|
|
274
|
-
}
|
|
275
|
-
return info;
|
|
276
|
-
}
|
|
277
|
-
const targetInfo = write ? await verifyDestination() : undefined;
|
|
278
|
-
const finalMode = targetInfo ? targetInfo.mode & 0o7777 : 0o666 & ~process.umask();
|
|
279
|
-
const entry = write ? path.join(descriptorPath(parent), `.aiwg-write-${randomUUID()}.tmp`) : destination;
|
|
280
|
-
file = await fs.open(entry,
|
|
281
|
-
(write ? constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL : constants.O_RDONLY)
|
|
282
|
-
| constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600);
|
|
283
|
-
await verify(file, { entry });
|
|
284
|
-
transferred = true;
|
|
285
|
-
return {
|
|
286
|
-
handle: file,
|
|
287
|
-
fullPath,
|
|
288
|
-
close,
|
|
289
|
-
async commit() {
|
|
290
|
-
await verify(directories[0], { rootHandle: true, directory: true });
|
|
291
|
-
await verify(file, { entry });
|
|
292
|
-
await verify(parent, parentOptions);
|
|
293
|
-
await verifyDestination();
|
|
294
|
-
await file.chmod(finalMode);
|
|
295
|
-
await fs.rename(entry, destination);
|
|
296
|
-
},
|
|
297
|
-
};
|
|
298
|
-
} finally {
|
|
299
|
-
if (!transferred) await Promise.allSettled([close()]);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** Static checks for platforms without Linux descriptor paths. */
|
|
304
|
-
async function openStaticArtifact(store, root, fullPath, { write }) {
|
|
305
|
-
// Inspect the lexical path as well as the resolved path: contained aliases
|
|
306
|
-
// must not hide symlink components on this fallback.
|
|
307
|
-
async function check(target, { allowMissing = false } = {}) {
|
|
308
|
-
const relative = path.relative(root, target);
|
|
309
|
-
assertArtifactContained(root, target);
|
|
310
|
-
let current = root;
|
|
311
|
-
for (const component of relative.split(path.sep)) {
|
|
312
|
-
current = path.join(current, component);
|
|
313
|
-
const info = await fs.lstat(current).catch(error => {
|
|
314
|
-
if (!allowMissing || error.code !== 'ENOENT') throw error;
|
|
315
|
-
});
|
|
316
|
-
if (!info) continue;
|
|
317
|
-
if (info.isSymbolicLink()) throw new Error('Refusing artifact symlink component');
|
|
318
|
-
assertArtifactContained(root, await fs.realpath(current));
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
await check(fullPath, { allowMissing: write });
|
|
322
|
-
if (write) await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
323
|
-
const target = await fs.lstat(fullPath).catch(error => {
|
|
324
|
-
if (!write || error.code !== 'ENOENT') throw error;
|
|
325
|
-
});
|
|
326
|
-
if (target && (!target.isFile() || target.isSymbolicLink())) throw new Error('Artifact must be a regular file');
|
|
327
|
-
if (!write && target.nlink > 1) throw new Error('Refusing multiply-linked artifact file');
|
|
328
|
-
const entry = write ? path.join(path.dirname(fullPath), `.aiwg-write-${randomUUID()}.tmp`) : fullPath;
|
|
329
|
-
const finalMode = target ? target.mode & 0o7777 : 0o666 & ~process.umask();
|
|
330
|
-
const handle = await fs.open(entry, write ? constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL : constants.O_RDONLY, 0o600);
|
|
331
|
-
try {
|
|
332
|
-
const opened = await handle.stat();
|
|
333
|
-
if (!opened.isFile() || opened.nlink > 1) throw new Error('Refusing nonregular or multiply-linked artifact file');
|
|
334
|
-
return {
|
|
335
|
-
handle, fullPath, close: () => handle.close(),
|
|
336
|
-
async commit() {
|
|
337
|
-
await verifyArtifactRoot(store);
|
|
338
|
-
await check(fullPath, { allowMissing: true });
|
|
339
|
-
await handle.chmod(finalMode);
|
|
340
|
-
await fs.rename(entry, fullPath);
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
} catch (error) {
|
|
344
|
-
await handle.close().catch(() => {});
|
|
345
|
-
throw error;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
37
|
/**
|
|
350
38
|
* Create and configure the AIWG MCP Server
|
|
351
39
|
*/
|
|
@@ -364,7 +52,28 @@ export async function createServer() {
|
|
|
364
52
|
// discover, skill-list, skill-show, command-list, command-show,
|
|
365
53
|
// rule-list, rule-show, agent-show, template-list, template-show
|
|
366
54
|
// ============================================
|
|
367
|
-
|
|
55
|
+
const corpusStore = await pinArtifactRoot(path.resolve(AIWG_ROOT));
|
|
56
|
+
registerDiscoveryTools(server, { corpusStore });
|
|
57
|
+
async function readCorpus(relative) {
|
|
58
|
+
const content = await readContainedFile(corpusStore, relative);
|
|
59
|
+
if (content === null) throw new Error('Corpus file not found');
|
|
60
|
+
return content;
|
|
61
|
+
}
|
|
62
|
+
function frameworkName(framework) {
|
|
63
|
+
validateContainedPath(framework);
|
|
64
|
+
return Object.hasOwn(FRAMEWORKS, framework) ? framework : 'sdlc-complete';
|
|
65
|
+
}
|
|
66
|
+
async function scanCorpusDirectory(relative, type) {
|
|
67
|
+
const entries = await listContainedFiles(corpusStore, `${relative}/`);
|
|
68
|
+
return entries.filter(entry => entry.path.endsWith('.md')).map(entry => {
|
|
69
|
+
const local = path.relative(relative, entry.path);
|
|
70
|
+
const name = path.basename(local, '.md');
|
|
71
|
+
return {
|
|
72
|
+
name, path: path.join(corpusStore.root, entry.path), uri: `aiwg://${type}/${name}`,
|
|
73
|
+
...(path.dirname(local) !== '.' ? { category: local.split(path.sep)[0] } : {}),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
368
77
|
registerWriterProfileResources(server);
|
|
369
78
|
|
|
370
79
|
// ============================================
|
|
@@ -544,12 +253,10 @@ export async function createServer() {
|
|
|
544
253
|
}, async ({ template, variables = {} }) => {
|
|
545
254
|
try {
|
|
546
255
|
// Determine framework and template path
|
|
256
|
+
validateContainedPath(template);
|
|
547
257
|
const [framework, ...pathParts] = template.split('/');
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
// Read template
|
|
552
|
-
let content = await fs.readFile(templatePath, 'utf-8');
|
|
258
|
+
const relative = `agentic/code/frameworks/${frameworkName(framework)}/templates/${pathParts.join('/')}`;
|
|
259
|
+
let content = await readCorpus(relative);
|
|
553
260
|
|
|
554
261
|
// Simple variable substitution
|
|
555
262
|
for (const [key, value] of Object.entries(variables)) {
|
|
@@ -646,8 +353,7 @@ export async function createServer() {
|
|
|
646
353
|
mimeType: 'application/json'
|
|
647
354
|
},
|
|
648
355
|
async () => {
|
|
649
|
-
const
|
|
650
|
-
const catalog = await scanDirectory(promptsDir, 'prompts');
|
|
356
|
+
const catalog = await scanCorpusDirectory('agentic/code/addons/aiwg-utils/prompts', 'prompts');
|
|
651
357
|
return {
|
|
652
358
|
contents: [{
|
|
653
359
|
uri: 'aiwg://prompts/catalog',
|
|
@@ -668,10 +374,9 @@ export async function createServer() {
|
|
|
668
374
|
},
|
|
669
375
|
async () => {
|
|
670
376
|
const catalogs = {};
|
|
671
|
-
for (const
|
|
672
|
-
const templatesDir = path.join(fwPath, 'templates');
|
|
377
|
+
for (const fw of Object.keys(FRAMEWORKS)) {
|
|
673
378
|
try {
|
|
674
|
-
catalogs[fw] = await
|
|
379
|
+
catalogs[fw] = await scanCorpusDirectory(`agentic/code/frameworks/${fw}/templates`, 'templates');
|
|
675
380
|
} catch {
|
|
676
381
|
catalogs[fw] = [];
|
|
677
382
|
}
|
|
@@ -696,10 +401,9 @@ export async function createServer() {
|
|
|
696
401
|
},
|
|
697
402
|
async () => {
|
|
698
403
|
const catalogs = {};
|
|
699
|
-
for (const
|
|
700
|
-
const agentsDir = path.join(fwPath, 'agents');
|
|
404
|
+
for (const fw of Object.keys(FRAMEWORKS)) {
|
|
701
405
|
try {
|
|
702
|
-
catalogs[fw] = await
|
|
406
|
+
catalogs[fw] = await scanCorpusDirectory(`agentic/code/frameworks/${fw}/agents`, 'agents');
|
|
703
407
|
} catch {
|
|
704
408
|
catalogs[fw] = [];
|
|
705
409
|
}
|
|
@@ -722,14 +426,9 @@ export async function createServer() {
|
|
|
722
426
|
description: 'Retrieve specific AIWG prompt template'
|
|
723
427
|
},
|
|
724
428
|
async (uri, { category, name }) => {
|
|
725
|
-
const promptPath = path.join(
|
|
726
|
-
AIWG_ROOT,
|
|
727
|
-
'agentic/code/addons/aiwg-utils/prompts',
|
|
728
|
-
category,
|
|
729
|
-
`${name}.md`
|
|
730
|
-
);
|
|
731
429
|
try {
|
|
732
|
-
|
|
430
|
+
validateContainedPath(category); validateContainedPath(name);
|
|
431
|
+
const content = await readCorpus(`agentic/code/addons/aiwg-utils/prompts/${category}/${name}.md`);
|
|
733
432
|
return {
|
|
734
433
|
contents: [{
|
|
735
434
|
uri: uri.href,
|
|
@@ -756,14 +455,9 @@ export async function createServer() {
|
|
|
756
455
|
description: 'Retrieve specific AIWG template'
|
|
757
456
|
},
|
|
758
457
|
async (uri, { framework, category, name }) => {
|
|
759
|
-
const templatePath = path.join(
|
|
760
|
-
FRAMEWORKS[framework] || FRAMEWORKS['sdlc-complete'],
|
|
761
|
-
'templates',
|
|
762
|
-
category,
|
|
763
|
-
`${name}.md`
|
|
764
|
-
);
|
|
765
458
|
try {
|
|
766
|
-
|
|
459
|
+
validateContainedPath(category); validateContainedPath(name);
|
|
460
|
+
const content = await readCorpus(`agentic/code/frameworks/${frameworkName(framework)}/templates/${category}/${name}.md`);
|
|
767
461
|
return {
|
|
768
462
|
contents: [{
|
|
769
463
|
uri: uri.href,
|
|
@@ -790,13 +484,9 @@ export async function createServer() {
|
|
|
790
484
|
description: 'Retrieve specific AIWG agent definition'
|
|
791
485
|
},
|
|
792
486
|
async (uri, { framework, name }) => {
|
|
793
|
-
const agentPath = path.join(
|
|
794
|
-
FRAMEWORKS[framework] || FRAMEWORKS['sdlc-complete'],
|
|
795
|
-
'agents',
|
|
796
|
-
`${name}.md`
|
|
797
|
-
);
|
|
798
487
|
try {
|
|
799
|
-
|
|
488
|
+
validateContainedPath(name);
|
|
489
|
+
const content = await readCorpus(`agentic/code/frameworks/${frameworkName(framework)}/agents/${name}.md`);
|
|
800
490
|
return {
|
|
801
491
|
contents: [{
|
|
802
492
|
uri: uri.href,
|
|
@@ -962,34 +652,6 @@ If retry fails, prepare structured escalation:
|
|
|
962
652
|
// HELPER FUNCTIONS
|
|
963
653
|
// ============================================
|
|
964
654
|
|
|
965
|
-
/**
|
|
966
|
-
* Scan directory for files
|
|
967
|
-
*/
|
|
968
|
-
async function scanDirectory(dir, type) {
|
|
969
|
-
const results = [];
|
|
970
|
-
try {
|
|
971
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
972
|
-
for (const entry of entries) {
|
|
973
|
-
if (entry.isDirectory()) {
|
|
974
|
-
const subResults = await scanDirectory(path.join(dir, entry.name), type);
|
|
975
|
-
results.push(...subResults.map(r => ({
|
|
976
|
-
...r,
|
|
977
|
-
category: entry.name
|
|
978
|
-
})));
|
|
979
|
-
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
980
|
-
results.push({
|
|
981
|
-
name: entry.name.replace('.md', ''),
|
|
982
|
-
path: path.join(dir, entry.name),
|
|
983
|
-
uri: `aiwg://${type}/${entry.name.replace('.md', '')}`
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
} catch {
|
|
988
|
-
// Directory doesn't exist
|
|
989
|
-
}
|
|
990
|
-
return results;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
655
|
/**
|
|
994
656
|
* Start the MCP server with stdio transport
|
|
995
657
|
*/
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Tests the server by spawning it and sending JSON-RPC messages via stdio.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { signalChild } from '../process/signal-child.mjs';
|
|
9
10
|
import { spawn } from 'child_process';
|
|
10
11
|
import { fileURLToPath } from 'url';
|
|
11
12
|
import path from 'path';
|
|
@@ -254,7 +255,7 @@ async function main() {
|
|
|
254
255
|
});
|
|
255
256
|
|
|
256
257
|
// Cleanup
|
|
257
|
-
server
|
|
258
|
+
signalChild(server);
|
|
258
259
|
|
|
259
260
|
// Summary
|
|
260
261
|
console.log('');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function tomlString(value: unknown): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function stripMcpServers(text: string): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ConfigWrite } from './config-file.mjs';
|
|
2
|
+
|
|
3
|
+
export interface ToolFilters {
|
|
4
|
+
deny: string[];
|
|
5
|
+
allow: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ToolFilterPlan {
|
|
9
|
+
serverFields: Record<string, Record<string, unknown>>;
|
|
10
|
+
tomlLines: Record<string, string[]>;
|
|
11
|
+
topLevel: { tools?: Record<string, boolean> };
|
|
12
|
+
claudePermissions: { deny: string[]; allow: string[] } | null;
|
|
13
|
+
warnings: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveToolFilters(
|
|
17
|
+
profile: { providerOverrides?: Record<string, { toolDeny?: string[]; toolAllow?: string[] }> } | undefined,
|
|
18
|
+
provider: string,
|
|
19
|
+
): ToolFilters;
|
|
20
|
+
export function hasToolFilters(filters: ToolFilters | undefined | null): boolean;
|
|
21
|
+
export function parseToolPattern(pattern: string): { server: string; tool: string } | null;
|
|
22
|
+
export function planToolFilters(provider: string, serverNames: string[], filters: ToolFilters): ToolFilterPlan;
|
|
23
|
+
export function applyJsonToolFilterPlan(
|
|
24
|
+
config: Record<string, unknown>,
|
|
25
|
+
serversKey: string,
|
|
26
|
+
plan: ToolFilterPlan,
|
|
27
|
+
): Record<string, unknown>;
|
|
28
|
+
export function claudeSettingsPath(projectDir?: string, scope?: 'user' | 'project'): string;
|
|
29
|
+
export interface ClaudePermissionOptions {
|
|
30
|
+
dryRun?: boolean;
|
|
31
|
+
userScope?: boolean;
|
|
32
|
+
projectRoot?: string;
|
|
33
|
+
managedDir?: string;
|
|
34
|
+
sidecar?: boolean;
|
|
35
|
+
mcpPath?: string;
|
|
36
|
+
}
|
|
37
|
+
export function prepareClaudePermissions(
|
|
38
|
+
settingsPath: string,
|
|
39
|
+
permissions: { deny: string[]; allow: string[] },
|
|
40
|
+
options?: ClaudePermissionOptions,
|
|
41
|
+
): Promise<{ merged: Record<string, unknown>; active: boolean; warnings: string[]; writes: ConfigWrite[]; commit(): Promise<void> }>;
|
|
42
|
+
export function mergeClaudePermissions(
|
|
43
|
+
settingsPath: string,
|
|
44
|
+
permissions: { deny: string[]; allow: string[] },
|
|
45
|
+
options?: ClaudePermissionOptions,
|
|
46
|
+
): Promise<Record<string, unknown>>;
|