mova-claude-import 0.1.1
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/.github/workflows/ci.yml +42 -0
- package/.github/workflows/release-dry-run.yml +40 -0
- package/.github/workflows/release-publish.yml +43 -0
- package/.tmp_test_control_apply/proj/.claude/agents/example_agent.md +3 -0
- package/.tmp_test_control_apply/proj/.claude/commands/example_command.md +3 -0
- package/.tmp_test_control_apply/proj/.claude/hooks/example_hook.sh +2 -0
- package/.tmp_test_control_apply/proj/.claude/output-styles/example_style.md +3 -0
- package/.tmp_test_control_apply/proj/.claude/settings.json +30 -0
- package/.tmp_test_control_apply/proj/.claude/settings.local.example.json +3 -0
- package/.tmp_test_control_apply/proj/.mcp.json +3 -0
- package/.tmp_test_control_apply/proj/CLAUDE.md +13 -0
- package/.tmp_test_control_apply/proj/MOVA.md +3 -0
- package/.tmp_test_control_check/proj/.mcp.json +1 -0
- package/.tmp_test_control_check/proj/CLAUDE.md +1 -0
- package/.tmp_test_control_prefill/out1/claude_control_profile_v0.json +114 -0
- package/.tmp_test_control_prefill/out1/prefill_report_v0.json +13 -0
- package/.tmp_test_control_prefill/out2/claude_control_profile_v0.json +114 -0
- package/.tmp_test_control_prefill/out2/prefill_report_v0.json +13 -0
- package/.tmp_test_overlay/proj/.claude/skills/a.md +1 -0
- package/.tmp_test_overlay/proj/.mcp.json +1 -0
- package/.tmp_test_overlay/proj/CLAUDE.md +1 -0
- package/.tmp_test_profile/proj/.claude/skills/a.md +1 -0
- package/.tmp_test_profile/proj/.mcp.json +1 -0
- package/.tmp_test_profile/proj/CLAUDE.md +1 -0
- package/.tmp_test_scaffold_apply/proj/.claude/agents/example_agent.md +3 -0
- package/.tmp_test_scaffold_apply/proj/.claude/commands/example_command.md +3 -0
- package/.tmp_test_scaffold_apply/proj/.claude/hooks/example_hook.sh +2 -0
- package/.tmp_test_scaffold_apply/proj/.claude/output-styles/example_style.md +3 -0
- package/.tmp_test_scaffold_apply/proj/.claude/settings.json +30 -0
- package/.tmp_test_scaffold_apply/proj/.claude/settings.local.example.json +3 -0
- package/.tmp_test_scaffold_apply/proj/.mcp.json +3 -0
- package/.tmp_test_scaffold_apply/proj/CLAUDE.md +13 -0
- package/.tmp_test_scaffold_apply/proj/MOVA.md +3 -0
- package/.tmp_test_strict/mova/claude_import/v0/VERSION.json +10 -0
- package/.tmp_test_strict/mova/claude_import/v0/episode_import_run.json +20 -0
- package/.tmp_test_strict/mova/claude_import/v0/import_manifest.json +20 -0
- package/.tmp_test_strict/mova/claude_import/v0/input_policy_report_v0.json +32 -0
- package/.tmp_test_zip/out1/.claude/agents/example_agent.md +3 -0
- package/.tmp_test_zip/out1/.claude/commands/example_command.md +3 -0
- package/.tmp_test_zip/out1/.claude/commands/mova_context.md +4 -0
- package/.tmp_test_zip/out1/.claude/commands/mova_lint.md +4 -0
- package/.tmp_test_zip/out1/.claude/commands/mova_proof.md +6 -0
- package/.tmp_test_zip/out1/.claude/hooks/example_hook.sh +2 -0
- package/.tmp_test_zip/out1/.claude/output-styles/example_style.md +3 -0
- package/.tmp_test_zip/out1/.claude/settings.json +30 -0
- package/.tmp_test_zip/out1/.claude/settings.local.example.json +3 -0
- package/.tmp_test_zip/out1/.claude/skills/a/SKILL.md +1 -0
- package/.tmp_test_zip/out1/.claude/skills/mova-control-v0/SKILL.md +11 -0
- package/.tmp_test_zip/out1/.claude/skills/mova-layer-v0/SKILL.md +8 -0
- package/.tmp_test_zip/out1/.mcp.json +3 -0
- package/.tmp_test_zip/out1/CLAUDE.md +4 -0
- package/.tmp_test_zip/out1/MOVA.md +10 -0
- package/.tmp_test_zip/out1/export.zip +0 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/VERSION.json +10 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/contracts/instruction_profile_v0.json +8 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/contracts/mcp_servers_v0.json +4 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/contracts/skills_catalog_v0.json +11 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/episode_import_run.json +80 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/export_manifest_v0.json +32 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/import_manifest.json +33 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/input_policy_report_v0.json +38 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/lint_report_v0.json +6 -0
- package/.tmp_test_zip/out1/mova/claude_import/v0/redaction_report.json +4 -0
- package/.tmp_test_zip/out2/.claude/agents/example_agent.md +3 -0
- package/.tmp_test_zip/out2/.claude/commands/example_command.md +3 -0
- package/.tmp_test_zip/out2/.claude/commands/mova_context.md +4 -0
- package/.tmp_test_zip/out2/.claude/commands/mova_lint.md +4 -0
- package/.tmp_test_zip/out2/.claude/commands/mova_proof.md +6 -0
- package/.tmp_test_zip/out2/.claude/hooks/example_hook.sh +2 -0
- package/.tmp_test_zip/out2/.claude/output-styles/example_style.md +3 -0
- package/.tmp_test_zip/out2/.claude/settings.json +30 -0
- package/.tmp_test_zip/out2/.claude/settings.local.example.json +3 -0
- package/.tmp_test_zip/out2/.claude/skills/a/SKILL.md +1 -0
- package/.tmp_test_zip/out2/.claude/skills/mova-control-v0/SKILL.md +11 -0
- package/.tmp_test_zip/out2/.claude/skills/mova-layer-v0/SKILL.md +8 -0
- package/.tmp_test_zip/out2/.mcp.json +3 -0
- package/.tmp_test_zip/out2/CLAUDE.md +4 -0
- package/.tmp_test_zip/out2/MOVA.md +10 -0
- package/.tmp_test_zip/out2/export.zip +0 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/VERSION.json +10 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/contracts/instruction_profile_v0.json +8 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/contracts/mcp_servers_v0.json +4 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/contracts/skills_catalog_v0.json +11 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/episode_import_run.json +80 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/export_manifest_v0.json +32 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/import_manifest.json +33 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/input_policy_report_v0.json +38 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/lint_report_v0.json +6 -0
- package/.tmp_test_zip/out2/mova/claude_import/v0/redaction_report.json +4 -0
- package/.tmp_test_zip/proj/.claude/skills/a.md +1 -0
- package/.tmp_test_zip/proj/.mcp.json +1 -0
- package/.tmp_test_zip/proj/CLAUDE.md +1 -0
- package/README.md +86 -0
- package/create_files.js +52 -0
- package/dist/anthropic_profile_v0.d.ts +2 -0
- package/dist/anthropic_profile_v0.js +66 -0
- package/dist/claude_profile_scaffold_v0.d.ts +2 -0
- package/dist/claude_profile_scaffold_v0.js +110 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +163 -0
- package/dist/cli_entry.d.ts +1 -0
- package/dist/cli_entry.js +1 -0
- package/dist/control_apply_v0.d.ts +6 -0
- package/dist/control_apply_v0.js +86 -0
- package/dist/control_check_v0.d.ts +7 -0
- package/dist/control_check_v0.js +80 -0
- package/dist/control_contracts_v0.d.ts +8 -0
- package/dist/control_contracts_v0.js +17 -0
- package/dist/control_prefill_v0.d.ts +6 -0
- package/dist/control_prefill_v0.js +61 -0
- package/dist/export_zip_v0.d.ts +8 -0
- package/dist/export_zip_v0.js +79 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +2 -0
- package/dist/init_v0.d.ts +7 -0
- package/dist/init_v0.js +47 -0
- package/dist/input_policy_v0.d.ts +26 -0
- package/dist/input_policy_v0.js +76 -0
- package/dist/lint_v0.d.ts +18 -0
- package/dist/lint_v0.js +131 -0
- package/dist/mova_overlay_v0.d.ts +14 -0
- package/dist/mova_overlay_v0.js +65 -0
- package/dist/mova_spec_bindings_v0.d.ts +5 -0
- package/dist/mova_spec_bindings_v0.js +5 -0
- package/dist/quality_v0.d.ts +1 -0
- package/dist/quality_v0.js +223 -0
- package/dist/redaction.d.ts +14 -0
- package/dist/redaction.js +52 -0
- package/dist/run_import.d.ts +2 -0
- package/dist/run_import.js +479 -0
- package/dist/stable_json.d.ts +1 -0
- package/dist/stable_json.js +15 -0
- package/docs/ANTHROPIC_PROFILE_v0.md +38 -0
- package/docs/COMPATIBILITY_MATRIX.md +25 -0
- package/docs/CONTROL_PROFILE_GUIDE_v0.md +40 -0
- package/docs/IMPORT_SPEC_v0.md +30 -0
- package/docs/MOVA_SPEC_BINDINGS.json +21 -0
- package/docs/MOVA_SPEC_BINDINGS.md +11 -0
- package/docs/OPERATOR_GUIDE_v0.md +43 -0
- package/docs/SECURITY_MODEL_v0.md +20 -0
- package/examples/control_profile_min.json +37 -0
- package/examples/control_profile_standard.json +81 -0
- package/examples/control_profile_strict.json +68 -0
- package/fixtures/neg/bad_skill_structure/.claude/skills/bad/README.md +3 -0
- package/fixtures/neg/bad_skill_structure/CLAUDE.md +3 -0
- package/fixtures/neg/local_settings_present/.claude/settings.local.json +3 -0
- package/fixtures/neg/local_settings_present/.claude/skills/alpha/SKILL.md +6 -0
- package/fixtures/neg/local_settings_present/CLAUDE.md +3 -0
- package/fixtures/neg/secret_leak/.claude/skills/alpha/SKILL.md +6 -0
- package/fixtures/neg/secret_leak/.mcp.json +3 -0
- package/fixtures/neg/secret_leak/CLAUDE.md +3 -0
- package/fixtures/neg/strict_denied_local/.claude/settings.local.json +3 -0
- package/fixtures/neg/strict_denied_local/CLAUDE.md +3 -0
- package/fixtures/pos/basic/.claude/skills/alpha/SKILL.md +8 -0
- package/fixtures/pos/basic/.mcp.json +3 -0
- package/fixtures/pos/basic/CLAUDE.md +3 -0
- package/fixtures/pos/control_basic_project/.mcp.json +3 -0
- package/fixtures/pos/control_basic_project/CLAUDE.md +3 -0
- package/fixtures/pos/control_profile_filled/claude_control_profile_v0.json +18 -0
- package/fixtures/pos/full_scaffold_roundtrip/README.md +1 -0
- package/package.json +39 -0
- package/schemas/claude_control/v0/ds/ds.claude_control_mapping_v0.json +227 -0
- package/schemas/claude_control/v0/ds/ds.claude_control_profile_v0.json +114 -0
- package/schemas/claude_control/v0/env/env.claude_control_apply_v0.json +170 -0
- package/schemas/claude_control/v0/env/env.claude_control_import_prefill_v0.json +171 -0
- package/schemas/claude_control/v0/global/global.claude_control_precedence_v0.json +58 -0
- package/schemas/claude_control/v0/global/global.claude_control_vocab_v0.json +98 -0
- package/schemas/ds.claude_import.instruction_profile_v0.schema.json +31 -0
- package/schemas/ds.claude_import.mcp_servers_v0.schema.json +47 -0
- package/schemas/ds.claude_import.skills_catalog_v0.schema.json +48 -0
- package/src/anthropic_profile_v0.ts +68 -0
- package/src/claude_profile_scaffold_v0.ts +117 -0
- package/src/cli.ts +160 -0
- package/src/cli_entry.ts +1 -0
- package/src/control_apply_v0.ts +108 -0
- package/src/control_check_v0.ts +98 -0
- package/src/control_contracts_v0.ts +26 -0
- package/src/control_prefill_v0.ts +74 -0
- package/src/export_zip_v0.ts +90 -0
- package/src/index.ts +29 -0
- package/src/init_v0.ts +59 -0
- package/src/input_policy_v0.ts +103 -0
- package/src/lint_v0.ts +151 -0
- package/src/mova_overlay_v0.ts +79 -0
- package/src/mova_spec_bindings_v0.ts +5 -0
- package/src/quality_v0.ts +264 -0
- package/src/redaction.ts +63 -0
- package/src/run_import.ts +526 -0
- package/src/stable_json.ts +15 -0
- package/test/control_apply_apply.test.js +40 -0
- package/test/control_check_preview.test.js +38 -0
- package/test/control_prefill.test.js +30 -0
- package/test/demo_v0_smoke.test.js +37 -0
- package/test/export_zip_determinism.test.js +41 -0
- package/test/import_determinism.test.js +53 -0
- package/test/init_v0.test.js +37 -0
- package/test/overlay_v0_output.test.js +38 -0
- package/test/profile_v0_output.test.js +44 -0
- package/test/scaffold_v0_output.test.js +64 -0
- package/test/strict_input_policy.test.js +45 -0
- package/tools/demo_v0.mjs +98 -0
- package/tools/deps_audit_v0.mjs +123 -0
- package/tools/write_mova_spec_bindings_v0.mjs +122 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"properties": {
|
|
3
|
+
"profile_version": {
|
|
4
|
+
"type": "string",
|
|
5
|
+
"const": "v0"
|
|
6
|
+
},
|
|
7
|
+
"servers": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"required": [
|
|
11
|
+
"name",
|
|
12
|
+
"command"
|
|
13
|
+
],
|
|
14
|
+
"properties": {
|
|
15
|
+
"command": {
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
"args": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"env_keys": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "string"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"name": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"type": "object"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"type": "object",
|
|
40
|
+
"$id": "ds.claude_import.mcp_servers_v0",
|
|
41
|
+
"required": [
|
|
42
|
+
"profile_version",
|
|
43
|
+
"servers"
|
|
44
|
+
],
|
|
45
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
46
|
+
"additionalProperties": false
|
|
47
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"properties": {
|
|
3
|
+
"profile_version": {
|
|
4
|
+
"type": "string",
|
|
5
|
+
"const": "v0"
|
|
6
|
+
},
|
|
7
|
+
"skills": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"required": [
|
|
11
|
+
"skill_id",
|
|
12
|
+
"rel_dir",
|
|
13
|
+
"skill_md"
|
|
14
|
+
],
|
|
15
|
+
"properties": {
|
|
16
|
+
"skill_md": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
"assets": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"skill_id": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"rel_dir": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"title": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"type": "object"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"type": "object",
|
|
41
|
+
"$id": "ds.claude_import.skills_catalog_v0",
|
|
42
|
+
"required": [
|
|
43
|
+
"profile_version",
|
|
44
|
+
"skills"
|
|
45
|
+
],
|
|
46
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
47
|
+
"additionalProperties": false
|
|
48
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { stableStringify } from "./stable_json.js";
|
|
2
|
+
|
|
3
|
+
export const anthropicProfileV0RequiredFiles = [
|
|
4
|
+
"CLAUDE.md",
|
|
5
|
+
"MOVA.md",
|
|
6
|
+
".claude/settings.json",
|
|
7
|
+
".claude/commands/mova_context.md",
|
|
8
|
+
".claude/commands/mova_lint.md",
|
|
9
|
+
".claude/skills/mova-layer-v0/SKILL.md",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export function getAnthropicProfileV0Files(): Record<string, string> {
|
|
13
|
+
return {
|
|
14
|
+
"CLAUDE.md": [
|
|
15
|
+
"# CLAUDE",
|
|
16
|
+
"",
|
|
17
|
+
"This profile is generated by mova-claude-import.",
|
|
18
|
+
"",
|
|
19
|
+
"Use MOVA.md for the project rules and structure.",
|
|
20
|
+
"Use .claude/commands/mova_context.md to build context.",
|
|
21
|
+
"Use .claude/commands/mova_lint.md to run structural lint.",
|
|
22
|
+
"",
|
|
23
|
+
].join("\n"),
|
|
24
|
+
"MOVA.md": [
|
|
25
|
+
"# MOVA",
|
|
26
|
+
"",
|
|
27
|
+
"This is a clean Anthropic profile v0 output.",
|
|
28
|
+
"",
|
|
29
|
+
"Artifacts:",
|
|
30
|
+
"- mova/claude_import/v0/import_manifest.json",
|
|
31
|
+
"- mova/claude_import/v0/redaction_report.json",
|
|
32
|
+
"- mova/claude_import/v0/lint_report_v0.json",
|
|
33
|
+
"- mova/claude_import/v0/contracts/*.json",
|
|
34
|
+
"- mova/claude_import/v0/episode_import_run.json",
|
|
35
|
+
"",
|
|
36
|
+
].join("\n"),
|
|
37
|
+
".claude/settings.json": stableStringify({
|
|
38
|
+
profile_version: "v0",
|
|
39
|
+
commands: ["mova_context", "mova_lint"],
|
|
40
|
+
skills_root: ".claude/skills",
|
|
41
|
+
}) + "\n",
|
|
42
|
+
".claude/commands/mova_context.md": [
|
|
43
|
+
"# mova_context",
|
|
44
|
+
"",
|
|
45
|
+
"Summarize the project based on MOVA.md and the contracts in",
|
|
46
|
+
"mova/claude_import/v0/contracts.",
|
|
47
|
+
"",
|
|
48
|
+
].join("\n"),
|
|
49
|
+
".claude/commands/mova_lint.md": [
|
|
50
|
+
"# mova_lint",
|
|
51
|
+
"",
|
|
52
|
+
"Run structural checks and report results from",
|
|
53
|
+
"mova/claude_import/v0/lint_report_v0.json.",
|
|
54
|
+
"",
|
|
55
|
+
].join("\n"),
|
|
56
|
+
".claude/skills/mova-layer-v0/SKILL.md": [
|
|
57
|
+
"---",
|
|
58
|
+
"name: mova-layer-v0",
|
|
59
|
+
"version: v0",
|
|
60
|
+
"---",
|
|
61
|
+
"",
|
|
62
|
+
"# mova-layer-v0",
|
|
63
|
+
"",
|
|
64
|
+
"Baseline behavior for the Anthropic profile v0 output.",
|
|
65
|
+
"",
|
|
66
|
+
].join("\n"),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { stableStringify } from "./stable_json.js";
|
|
4
|
+
import { MOVA_CONTROL_ENTRY_MARKER } from "./mova_overlay_v0.js";
|
|
5
|
+
|
|
6
|
+
type ScaffoldFile = { rel: string; content: string };
|
|
7
|
+
|
|
8
|
+
async function exists(p: string): Promise<boolean> {
|
|
9
|
+
try {
|
|
10
|
+
await fs.stat(p);
|
|
11
|
+
return true;
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function writeFile(absPath: string, content: string) {
|
|
18
|
+
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
19
|
+
await fs.writeFile(absPath, content, "utf8");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function scaffoldFiles(): ScaffoldFile[] {
|
|
23
|
+
const settings = {
|
|
24
|
+
profile_version: "v0",
|
|
25
|
+
permissions: {
|
|
26
|
+
allow: [],
|
|
27
|
+
deny: [],
|
|
28
|
+
behavior: {
|
|
29
|
+
on_conflict: "deny_wins",
|
|
30
|
+
on_unknown: "report_only",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
plugins: {
|
|
34
|
+
enable: true,
|
|
35
|
+
allowed_plugin_ids: [],
|
|
36
|
+
denied_plugin_ids: [],
|
|
37
|
+
behavior: {
|
|
38
|
+
on_unknown: "report_only",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
hooks: {
|
|
42
|
+
enable: true,
|
|
43
|
+
definitions: [],
|
|
44
|
+
behavior: {
|
|
45
|
+
on_invalid_hook: "report_only",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
claude_md: {
|
|
49
|
+
inject_control_entry: true,
|
|
50
|
+
marker: MOVA_CONTROL_ENTRY_MARKER,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
rel: "CLAUDE.md",
|
|
57
|
+
content: [
|
|
58
|
+
MOVA_CONTROL_ENTRY_MARKER,
|
|
59
|
+
"## MOVA Control Entry (v0)",
|
|
60
|
+
"",
|
|
61
|
+
"This is the canonical control entry marker for Claude Code.",
|
|
62
|
+
"",
|
|
63
|
+
].join("\n"),
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
rel: ".claude/settings.json",
|
|
67
|
+
content: stableStringify(settings) + "\n",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
rel: ".claude/settings.local.example.json",
|
|
71
|
+
content: stableStringify({
|
|
72
|
+
note: "Local settings are not committed; use this as a template.",
|
|
73
|
+
}) + "\n",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
rel: ".claude/commands/example_command.md",
|
|
77
|
+
content: ["# example_command", "", "Write a brief project summary.", ""].join("\n"),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
rel: ".claude/agents/example_agent.md",
|
|
81
|
+
content: ["# example_agent", "", "Role: reviewer", ""].join("\n"),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
rel: ".claude/output-styles/example_style.md",
|
|
85
|
+
content: ["# example_style", "", "Style: concise, bullet-first.", ""].join("\n"),
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
rel: ".claude/hooks/example_hook.sh",
|
|
89
|
+
content: ["#!/usr/bin/env bash", "echo \"hook: dry check\""].join("\n") + "\n",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
rel: ".mcp.json",
|
|
93
|
+
content: stableStringify({ servers: [] }) + "\n",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
rel: "MOVA.md",
|
|
97
|
+
content: ["# MOVA", "", "Notes and operator instructions.", ""].join("\n"),
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function writeCleanClaudeProfileScaffoldV0(outDir: string) {
|
|
103
|
+
const files = scaffoldFiles();
|
|
104
|
+
for (const f of files) {
|
|
105
|
+
await writeFile(path.join(outDir, f.rel), f.content);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function ensureClaudeControlSurfacesV0(projectDir: string) {
|
|
110
|
+
const files = scaffoldFiles();
|
|
111
|
+
for (const f of files) {
|
|
112
|
+
const abs = path.join(projectDir, f.rel);
|
|
113
|
+
if (!(await exists(abs))) {
|
|
114
|
+
await writeFile(abs, f.content);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { runImport } from "./run_import.js";
|
|
2
|
+
import { initProfileV0 } from "./init_v0.js";
|
|
3
|
+
import { controlPrefillV0 } from "./control_prefill_v0.js";
|
|
4
|
+
import { controlCheckV0 } from "./control_check_v0.js";
|
|
5
|
+
import { controlApplyV0 } from "./control_apply_v0.js";
|
|
6
|
+
|
|
7
|
+
function getArg(name: string): string | undefined {
|
|
8
|
+
const idx = process.argv.indexOf(name);
|
|
9
|
+
if (idx === -1) return undefined;
|
|
10
|
+
return process.argv[idx + 1];
|
|
11
|
+
}
|
|
12
|
+
function hasFlag(name: string): boolean {
|
|
13
|
+
return process.argv.includes(name);
|
|
14
|
+
}
|
|
15
|
+
function usage(exitCode = 0) {
|
|
16
|
+
console.log([
|
|
17
|
+
"mova-claude-import (v0)",
|
|
18
|
+
"",
|
|
19
|
+
"Usage:",
|
|
20
|
+
" mova-claude-import --project <dir> [--out <dir>] [--dry-run] [--strict] [--include-local] [--include-user-settings] [--no-emit-profile] [--no-emit-overlay] [--zip] [--zip-name <name>]",
|
|
21
|
+
" mova-claude-import init --out <dir> [--zip]",
|
|
22
|
+
" mova-claude-import control prefill --project <dir> --out <dir> [--include-local]",
|
|
23
|
+
" mova-claude-import control check --project <dir> --profile <file>",
|
|
24
|
+
" mova-claude-import control apply --project <dir> --profile <file> [--mode preview|apply]",
|
|
25
|
+
"",
|
|
26
|
+
"Notes:",
|
|
27
|
+
" - CLAUDE.local.md and *.local.* are excluded unless --include-local",
|
|
28
|
+
" - user-level settings are excluded unless --include-user-settings",
|
|
29
|
+
" - profile emission is enabled by default; use --no-emit-profile to skip",
|
|
30
|
+
" - overlay emission is enabled by default; use --no-emit-overlay to skip",
|
|
31
|
+
" - zip export is disabled by default; use --zip to enable",
|
|
32
|
+
" - init creates a clean Anthropic profile v0 scaffold",
|
|
33
|
+
" - control commands run in preview by default",
|
|
34
|
+
].join("\n"));
|
|
35
|
+
process.exit(exitCode);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (hasFlag("--help") || hasFlag("-h")) usage(0);
|
|
39
|
+
if (hasFlag("--version") || hasFlag("-v")) {
|
|
40
|
+
console.log("0.0.0");
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const subcommand = process.argv[2];
|
|
45
|
+
if (subcommand === "init") {
|
|
46
|
+
const out = getArg("--out");
|
|
47
|
+
if (!out) {
|
|
48
|
+
usage(2);
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
const emitZip = hasFlag("--zip");
|
|
52
|
+
initProfileV0(out, emitZip)
|
|
53
|
+
.then((res) => {
|
|
54
|
+
process.stdout.write(JSON.stringify(res, null, 2) + "\n");
|
|
55
|
+
process.exit(0);
|
|
56
|
+
})
|
|
57
|
+
.catch((err) => {
|
|
58
|
+
console.error(err);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|
|
61
|
+
} else if (subcommand === "control") {
|
|
62
|
+
const action = process.argv[3];
|
|
63
|
+
const project = getArg("--project");
|
|
64
|
+
if (!project) {
|
|
65
|
+
usage(2);
|
|
66
|
+
process.exit(2);
|
|
67
|
+
}
|
|
68
|
+
if (action === "prefill") {
|
|
69
|
+
const out = getArg("--out");
|
|
70
|
+
if (!out) {
|
|
71
|
+
usage(2);
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
controlPrefillV0(project, out)
|
|
75
|
+
.then((res) => {
|
|
76
|
+
console.log([
|
|
77
|
+
"control prefill: ok",
|
|
78
|
+
`profile: ${res.profile_path}`,
|
|
79
|
+
`report: ${res.report_path}`,
|
|
80
|
+
].join("\n"));
|
|
81
|
+
process.exit(0);
|
|
82
|
+
})
|
|
83
|
+
.catch((err) => {
|
|
84
|
+
console.error(err);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
87
|
+
} else if (action === "check") {
|
|
88
|
+
const profile = getArg("--profile");
|
|
89
|
+
if (!profile) {
|
|
90
|
+
usage(2);
|
|
91
|
+
process.exit(2);
|
|
92
|
+
}
|
|
93
|
+
const out = getArg("--out") || project;
|
|
94
|
+
controlCheckV0(project, profile, out)
|
|
95
|
+
.then((res) => {
|
|
96
|
+
console.log([
|
|
97
|
+
"control check: ok",
|
|
98
|
+
`plan: ${res.plan_path}`,
|
|
99
|
+
`summary: ${res.summary_path}`,
|
|
100
|
+
].join("\n"));
|
|
101
|
+
process.exit(0);
|
|
102
|
+
})
|
|
103
|
+
.catch((err) => {
|
|
104
|
+
console.error(err);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
} else if (action === "apply") {
|
|
108
|
+
const profile = getArg("--profile");
|
|
109
|
+
if (!profile) {
|
|
110
|
+
usage(2);
|
|
111
|
+
process.exit(2);
|
|
112
|
+
}
|
|
113
|
+
const out = getArg("--out") || project;
|
|
114
|
+
const mode = getArg("--mode");
|
|
115
|
+
controlApplyV0(project, profile, out, mode)
|
|
116
|
+
.then((res) => {
|
|
117
|
+
console.log([
|
|
118
|
+
"control apply: ok",
|
|
119
|
+
`report: ${res.report_path}`,
|
|
120
|
+
].join("\n"));
|
|
121
|
+
process.exit(0);
|
|
122
|
+
})
|
|
123
|
+
.catch((err) => {
|
|
124
|
+
console.error(err);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
usage(2);
|
|
129
|
+
process.exit(2);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
const project = getArg("--project");
|
|
133
|
+
if (!project) {
|
|
134
|
+
usage(2);
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const out = getArg("--out") || project;
|
|
139
|
+
const emitProfile = !hasFlag("--no-emit-profile");
|
|
140
|
+
const emitOverlay = !hasFlag("--no-emit-overlay");
|
|
141
|
+
const emitZip = hasFlag("--zip");
|
|
142
|
+
const zipName = getArg("--zip-name");
|
|
143
|
+
|
|
144
|
+
runImport({
|
|
145
|
+
projectDir: project,
|
|
146
|
+
outDir: out,
|
|
147
|
+
includeLocal: hasFlag("--include-local"),
|
|
148
|
+
includeUserSettings: hasFlag("--include-user-settings"),
|
|
149
|
+
dryRun: hasFlag("--dry-run"),
|
|
150
|
+
strict: hasFlag("--strict"),
|
|
151
|
+
emitProfile,
|
|
152
|
+
emitOverlay,
|
|
153
|
+
emitZip,
|
|
154
|
+
zipName,
|
|
155
|
+
}).then((res) => {
|
|
156
|
+
process.stdout.write(JSON.stringify(res, null, 2) + "\n");
|
|
157
|
+
if (typeof res.exit_code === "number") process.exit(res.exit_code);
|
|
158
|
+
process.exit(res.ok ? 0 : 1);
|
|
159
|
+
});
|
|
160
|
+
}
|
package/src/cli_entry.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./cli.js";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { stableStringify } from "./stable_json.js";
|
|
4
|
+
import { stableSha256 } from "./redaction.js";
|
|
5
|
+
import { buildMovaControlEntryV0, MOVA_CONTROL_ENTRY_MARKER } from "./mova_overlay_v0.js";
|
|
6
|
+
import { ensureClaudeControlSurfacesV0 } from "./claude_profile_scaffold_v0.js";
|
|
7
|
+
|
|
8
|
+
type ApplyResult = {
|
|
9
|
+
run_id: string;
|
|
10
|
+
report_path: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
async function exists(p: string): Promise<boolean> {
|
|
14
|
+
try {
|
|
15
|
+
await fs.stat(p);
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function readJson(p: string) {
|
|
23
|
+
const raw = await fs.readFile(p, "utf8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function writeJson(p: string, obj: any) {
|
|
28
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
29
|
+
await fs.writeFile(p, stableStringify(obj) + "\n", "utf8");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function computeRunId(parts: string[]): string {
|
|
33
|
+
return stableSha256(parts.join("|")).slice(0, 16);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function updateClaude(content: string, marker: string, block: string): string {
|
|
37
|
+
if (content.includes(marker)) {
|
|
38
|
+
const idx = content.indexOf(marker);
|
|
39
|
+
const after = content.slice(idx);
|
|
40
|
+
const split = after.split("\n\n");
|
|
41
|
+
split[0] = block.trimEnd();
|
|
42
|
+
return content.slice(0, idx) + split.join("\n\n");
|
|
43
|
+
}
|
|
44
|
+
return `${block}\n${content}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function controlApplyV0(
|
|
48
|
+
projectDir: string,
|
|
49
|
+
profilePath: string,
|
|
50
|
+
outDir: string,
|
|
51
|
+
mode?: string
|
|
52
|
+
): Promise<ApplyResult> {
|
|
53
|
+
await ensureClaudeControlSurfacesV0(projectDir);
|
|
54
|
+
const profile = await readJson(profilePath);
|
|
55
|
+
const applyMode = mode ?? profile?.apply?.default_apply_mode ?? "preview";
|
|
56
|
+
|
|
57
|
+
const claudePath = path.join(projectDir, "CLAUDE.md");
|
|
58
|
+
const mcpPath = path.join(projectDir, ".mcp.json");
|
|
59
|
+
const claudeExists = await exists(claudePath);
|
|
60
|
+
const mcpExists = await exists(mcpPath);
|
|
61
|
+
const marker = profile?.anthropic?.claude_md?.marker ?? MOVA_CONTROL_ENTRY_MARKER;
|
|
62
|
+
|
|
63
|
+
const runId = computeRunId([profilePath, claudeExists ? "claude" : "", mcpExists ? "mcp" : "", marker, applyMode]);
|
|
64
|
+
const runBase = path.join(outDir, "mova", "claude_control", "v0", "runs", runId);
|
|
65
|
+
|
|
66
|
+
const overlayParams = {
|
|
67
|
+
contractsDir: "mova/claude_import/v0/contracts/",
|
|
68
|
+
artifactsDir: "mova/claude_import/v0/",
|
|
69
|
+
instructionProfileFile: "instruction_profile_v0.json",
|
|
70
|
+
skillsCatalogFile: "skills_catalog_v0.json",
|
|
71
|
+
mcpServersFile: "mcp_servers_v0.json",
|
|
72
|
+
lintReportFile: "lint_report_v0.json",
|
|
73
|
+
qualityReportFile: "quality_report_v0.json",
|
|
74
|
+
exportManifestFile: "export_manifest_v0.json",
|
|
75
|
+
};
|
|
76
|
+
const controlEntry = buildMovaControlEntryV0(overlayParams);
|
|
77
|
+
|
|
78
|
+
const applied = { claude_md: false, mcp_json: false, settings: false };
|
|
79
|
+
if (applyMode === "apply") {
|
|
80
|
+
if (profile?.anthropic?.claude_md?.inject_control_entry && claudeExists) {
|
|
81
|
+
const raw = await fs.readFile(claudePath, "utf8");
|
|
82
|
+
const updated = updateClaude(raw, marker, controlEntry);
|
|
83
|
+
await fs.writeFile(claudePath, updated, "utf8");
|
|
84
|
+
applied.claude_md = true;
|
|
85
|
+
}
|
|
86
|
+
if (profile?.anthropic?.mcp?.servers && mcpExists) {
|
|
87
|
+
const mcp = await readJson(mcpPath);
|
|
88
|
+
const merged = { ...mcp, servers: profile.anthropic.mcp.servers };
|
|
89
|
+
await fs.writeFile(mcpPath, stableStringify(merged) + "\n", "utf8");
|
|
90
|
+
applied.mcp_json = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const report = {
|
|
95
|
+
profile_version: "v0",
|
|
96
|
+
run_id: runId,
|
|
97
|
+
project_dir: projectDir,
|
|
98
|
+
profile_path: profilePath,
|
|
99
|
+
mode: applyMode,
|
|
100
|
+
outcome_code: applyMode === "apply" ? "APPLIED" : "PREVIEW",
|
|
101
|
+
applied,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const reportPath = path.join(runBase, "control_apply_report_v0.json");
|
|
105
|
+
await writeJson(reportPath, report);
|
|
106
|
+
|
|
107
|
+
return { run_id: runId, report_path: reportPath };
|
|
108
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { stableStringify } from "./stable_json.js";
|
|
4
|
+
import { stableSha256 } from "./redaction.js";
|
|
5
|
+
import { buildMovaControlEntryV0, MOVA_CONTROL_ENTRY_MARKER } from "./mova_overlay_v0.js";
|
|
6
|
+
|
|
7
|
+
type CheckResult = {
|
|
8
|
+
run_id: string;
|
|
9
|
+
plan_path: string;
|
|
10
|
+
summary_path: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
async function exists(p: string): Promise<boolean> {
|
|
14
|
+
try {
|
|
15
|
+
await fs.stat(p);
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function readJson(p: string) {
|
|
23
|
+
const raw = await fs.readFile(p, "utf8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function writeJson(p: string, obj: any) {
|
|
28
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
29
|
+
await fs.writeFile(p, stableStringify(obj) + "\n", "utf8");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function computeRunId(parts: string[]): string {
|
|
33
|
+
return stableSha256(parts.join("|")).slice(0, 16);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function controlCheckV0(projectDir: string, profilePath: string, outDir: string): Promise<CheckResult> {
|
|
37
|
+
const profile = await readJson(profilePath);
|
|
38
|
+
const claudePath = path.join(projectDir, "CLAUDE.md");
|
|
39
|
+
const mcpPath = path.join(projectDir, ".mcp.json");
|
|
40
|
+
|
|
41
|
+
const claudeExists = await exists(claudePath);
|
|
42
|
+
const mcpExists = await exists(mcpPath);
|
|
43
|
+
const marker = profile?.anthropic?.claude_md?.marker ?? MOVA_CONTROL_ENTRY_MARKER;
|
|
44
|
+
|
|
45
|
+
const runId = computeRunId([profilePath, claudeExists ? "claude" : "", mcpExists ? "mcp" : "", marker]);
|
|
46
|
+
const runBase = path.join(outDir, "mova", "claude_control", "v0", "runs", runId);
|
|
47
|
+
|
|
48
|
+
const overlayParams = {
|
|
49
|
+
contractsDir: "mova/claude_import/v0/contracts/",
|
|
50
|
+
artifactsDir: "mova/claude_import/v0/",
|
|
51
|
+
instructionProfileFile: "instruction_profile_v0.json",
|
|
52
|
+
skillsCatalogFile: "skills_catalog_v0.json",
|
|
53
|
+
mcpServersFile: "mcp_servers_v0.json",
|
|
54
|
+
lintReportFile: "lint_report_v0.json",
|
|
55
|
+
qualityReportFile: "quality_report_v0.json",
|
|
56
|
+
exportManifestFile: "export_manifest_v0.json",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const actions = [];
|
|
60
|
+
if (profile?.anthropic?.claude_md?.inject_control_entry) {
|
|
61
|
+
actions.push({
|
|
62
|
+
target: "CLAUDE.md",
|
|
63
|
+
action: "insert_or_update_control_entry",
|
|
64
|
+
marker,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (profile?.anthropic?.mcp?.servers && mcpExists) {
|
|
68
|
+
actions.push({
|
|
69
|
+
target: ".mcp.json",
|
|
70
|
+
action: "merge_servers",
|
|
71
|
+
summary: "merge profile servers with project mcp.json",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const plan = {
|
|
76
|
+
profile_version: "v0",
|
|
77
|
+
run_id: runId,
|
|
78
|
+
project_dir: projectDir,
|
|
79
|
+
profile_path: profilePath,
|
|
80
|
+
actions,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const summary = {
|
|
84
|
+
run_id: runId,
|
|
85
|
+
outcome_code: "PREVIEW",
|
|
86
|
+
actions_count: actions.length,
|
|
87
|
+
control_entry_preview: profile?.anthropic?.claude_md?.inject_control_entry
|
|
88
|
+
? buildMovaControlEntryV0(overlayParams)
|
|
89
|
+
: null,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const planPath = path.join(runBase, "control_plan_v0.json");
|
|
93
|
+
const summaryPath = path.join(runBase, "control_summary_v0.json");
|
|
94
|
+
await writeJson(planPath, plan);
|
|
95
|
+
await writeJson(summaryPath, summary);
|
|
96
|
+
|
|
97
|
+
return { run_id: runId, plan_path: planPath, summary_path: summaryPath };
|
|
98
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
type ControlContractsV0 = {
|
|
5
|
+
claude_control_profile: any;
|
|
6
|
+
claude_control_mapping: any;
|
|
7
|
+
claude_control_vocab: any;
|
|
8
|
+
claude_control_precedence: any;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
async function loadJson(relPath: string) {
|
|
12
|
+
const url = new URL(`../${relPath}`, import.meta.url);
|
|
13
|
+
const abs = fileURLToPath(url);
|
|
14
|
+
const raw = await fs.readFile(abs, "utf8");
|
|
15
|
+
return JSON.parse(raw);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function loadControlContractsV0(): Promise<ControlContractsV0> {
|
|
19
|
+
const base = "schemas/claude_control/v0";
|
|
20
|
+
return {
|
|
21
|
+
claude_control_profile: await loadJson(`${base}/ds/ds.claude_control_profile_v0.json`),
|
|
22
|
+
claude_control_mapping: await loadJson(`${base}/ds/ds.claude_control_mapping_v0.json`),
|
|
23
|
+
claude_control_vocab: await loadJson(`${base}/global/global.claude_control_vocab_v0.json`),
|
|
24
|
+
claude_control_precedence: await loadJson(`${base}/global/global.claude_control_precedence_v0.json`),
|
|
25
|
+
};
|
|
26
|
+
}
|