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,479 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { redactText, redactJson } from "./redaction.js";
|
|
7
|
+
import Ajv from "ajv";
|
|
8
|
+
import addFormats from "ajv-formats";
|
|
9
|
+
import { getAnthropicProfileV0Files } from "./anthropic_profile_v0.js";
|
|
10
|
+
import { lintV0 } from "./lint_v0.js";
|
|
11
|
+
import { stableStringify } from "./stable_json.js";
|
|
12
|
+
import { createExportZipV0 } from "./export_zip_v0.js";
|
|
13
|
+
import { buildMovaOverlayV0, buildMovaControlEntryV0, MOVA_CONTROL_ENTRY_MARKER } from "./mova_overlay_v0.js";
|
|
14
|
+
import { scanInputPolicyV0 } from "./input_policy_v0.js";
|
|
15
|
+
import { EvidenceWriter } from "@leryk1981/mova-core-engine";
|
|
16
|
+
import { MOVA_SPEC_BINDINGS_V0 } from "./mova_spec_bindings_v0.js";
|
|
17
|
+
import { writeCleanClaudeProfileScaffoldV0 } from "./claude_profile_scaffold_v0.js";
|
|
18
|
+
async function exists(p) {
|
|
19
|
+
try {
|
|
20
|
+
await fs.stat(p);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function sha256File(p) {
|
|
28
|
+
const buf = await fs.readFile(p);
|
|
29
|
+
return crypto.createHash("sha256").update(buf).digest("hex");
|
|
30
|
+
}
|
|
31
|
+
async function readToolVersion() {
|
|
32
|
+
try {
|
|
33
|
+
const pkgPath = fileURLToPath(new URL("../package.json", import.meta.url));
|
|
34
|
+
const raw = await fs.readFile(pkgPath, "utf8");
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
return typeof parsed.version === "string" ? parsed.version : "0.0.0";
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return "0.0.0";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isLocalExcluded(rel, includeLocal) {
|
|
43
|
+
if (includeLocal)
|
|
44
|
+
return false;
|
|
45
|
+
const base = path.basename(rel);
|
|
46
|
+
if (base === "CLAUDE.local.md")
|
|
47
|
+
return true;
|
|
48
|
+
if (base.includes(".local."))
|
|
49
|
+
return true;
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
async function scanProject(opts) {
|
|
53
|
+
const projectDir = path.resolve(opts.projectDir);
|
|
54
|
+
const skipped = [];
|
|
55
|
+
const found = { skillFiles: [], skipped };
|
|
56
|
+
const claudeMd = path.join(projectDir, "CLAUDE.md");
|
|
57
|
+
if (await exists(claudeMd))
|
|
58
|
+
found.claudeMdPath = claudeMd;
|
|
59
|
+
const mcpJson = path.join(projectDir, ".mcp.json");
|
|
60
|
+
if (await exists(mcpJson))
|
|
61
|
+
found.mcpJsonPath = mcpJson;
|
|
62
|
+
const skillsRoot = path.join(projectDir, ".claude", "skills");
|
|
63
|
+
if (await exists(skillsRoot)) {
|
|
64
|
+
const stack = [skillsRoot];
|
|
65
|
+
while (stack.length) {
|
|
66
|
+
const dir = stack.pop();
|
|
67
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
68
|
+
for (const e of entries) {
|
|
69
|
+
const abs = path.join(dir, e.name);
|
|
70
|
+
const rel = path.relative(projectDir, abs).replace(/\\/g, "/");
|
|
71
|
+
if (isLocalExcluded(rel, opts.includeLocal)) {
|
|
72
|
+
skipped.push({ path: rel, reason: "excluded_by_default_local" });
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (e.isDirectory())
|
|
76
|
+
stack.push(abs);
|
|
77
|
+
else if (e.isFile() && e.name.toLowerCase().endsWith(".md"))
|
|
78
|
+
found.skillFiles.push(abs);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// placeholder for user settings exclusion
|
|
83
|
+
if (!opts.includeUserSettings) {
|
|
84
|
+
skipped.push({ path: "~/.claude/*", reason: "excluded_by_default_user_settings" });
|
|
85
|
+
}
|
|
86
|
+
found.skillFiles.sort((a, b) => a.localeCompare(b));
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
function computeRunId(hashes) {
|
|
90
|
+
const h = crypto.createHash("sha256");
|
|
91
|
+
for (const x of hashes.sort())
|
|
92
|
+
h.update(x);
|
|
93
|
+
return h.digest("hex").slice(0, 16);
|
|
94
|
+
}
|
|
95
|
+
function normalizeSkillDir(rel) {
|
|
96
|
+
const base = rel.replace(/\\/g, "/").replace(/\.md$/i, "");
|
|
97
|
+
const withoutRoot = base.replace(/^\.claude\/skills\//, "");
|
|
98
|
+
return withoutRoot.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
99
|
+
}
|
|
100
|
+
async function writeJsonFile(absPath, obj) {
|
|
101
|
+
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
102
|
+
await fs.writeFile(absPath, stableStringify(obj) + "\n", "utf8");
|
|
103
|
+
}
|
|
104
|
+
async function writeTextFile(absPath, content) {
|
|
105
|
+
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
106
|
+
await fs.writeFile(absPath, content, "utf8");
|
|
107
|
+
}
|
|
108
|
+
/** Load a JSON file and redact it */
|
|
109
|
+
async function loadAndRedactJson(p) {
|
|
110
|
+
const raw = await fs.readFile(p, "utf8");
|
|
111
|
+
const parsed = JSON.parse(raw);
|
|
112
|
+
const { redacted, hits } = redactJson(parsed);
|
|
113
|
+
return { raw, parsed, redacted, hits };
|
|
114
|
+
}
|
|
115
|
+
async function ensureClaudeControlEntry(claudePath, block, marker) {
|
|
116
|
+
const content = await fs.readFile(claudePath, "utf8");
|
|
117
|
+
if (content.includes(marker))
|
|
118
|
+
return;
|
|
119
|
+
await fs.writeFile(claudePath, `${block}\n${content}`, "utf8");
|
|
120
|
+
}
|
|
121
|
+
function orderedObject(obj) {
|
|
122
|
+
return JSON.parse(stableStringify(obj));
|
|
123
|
+
}
|
|
124
|
+
async function writeEvidenceArtifact(writer, baseDir, rel, obj) {
|
|
125
|
+
const target = await writer.writeArtifact(baseDir, rel, orderedObject(obj));
|
|
126
|
+
await fs.writeFile(target, stableStringify(obj) + "\n", "utf8");
|
|
127
|
+
}
|
|
128
|
+
async function loadMovaSpecSchema(fileName) {
|
|
129
|
+
const require = createRequire(import.meta.url);
|
|
130
|
+
const pkgPath = require.resolve("@leryk1981/mova-spec/package.json");
|
|
131
|
+
const schemaPath = path.join(path.dirname(pkgPath), "schemas", fileName);
|
|
132
|
+
const raw = await fs.readFile(schemaPath, "utf8");
|
|
133
|
+
return JSON.parse(raw);
|
|
134
|
+
}
|
|
135
|
+
async function loadMovaSpecSchemaById(schemaId) {
|
|
136
|
+
const fileName = schemaId.split("/").pop();
|
|
137
|
+
if (!fileName)
|
|
138
|
+
throw new Error(`Invalid schema id: ${schemaId}`);
|
|
139
|
+
return loadMovaSpecSchema(fileName);
|
|
140
|
+
}
|
|
141
|
+
export async function runImport(opts) {
|
|
142
|
+
const projectDir = path.resolve(opts.projectDir);
|
|
143
|
+
const outRoot = path.resolve(opts.outDir);
|
|
144
|
+
const inputPolicy = await scanInputPolicyV0(projectDir, {
|
|
145
|
+
strict: opts.strict,
|
|
146
|
+
include_local: opts.includeLocal,
|
|
147
|
+
});
|
|
148
|
+
const found = await scanProject(opts);
|
|
149
|
+
const inputs = [];
|
|
150
|
+
const redactionHits = [];
|
|
151
|
+
/** Process a text file – redact and record */
|
|
152
|
+
async function processTextFile(rel, absPath) {
|
|
153
|
+
const raw = await fs.readFile(absPath, "utf8");
|
|
154
|
+
const { redacted, hits } = redactText(raw);
|
|
155
|
+
inputs.push({ rel, sha256: await sha256File(absPath) });
|
|
156
|
+
redactionHits.push(...hits);
|
|
157
|
+
return redacted;
|
|
158
|
+
}
|
|
159
|
+
// CLAUDE.md
|
|
160
|
+
let claudeMdRedacted = "";
|
|
161
|
+
if (found.claudeMdPath) {
|
|
162
|
+
claudeMdRedacted = await processTextFile("CLAUDE.md", found.claudeMdPath);
|
|
163
|
+
}
|
|
164
|
+
// .mcp.json
|
|
165
|
+
let mcpJsonRedacted = "";
|
|
166
|
+
let mcpJsonParsed;
|
|
167
|
+
if (found.mcpJsonPath) {
|
|
168
|
+
const { parsed, redacted, hits } = await loadAndRedactJson(found.mcpJsonPath);
|
|
169
|
+
mcpJsonParsed = parsed;
|
|
170
|
+
mcpJsonRedacted = stableStringify(redacted);
|
|
171
|
+
redactionHits.push(...hits);
|
|
172
|
+
inputs.push({
|
|
173
|
+
rel: ".mcp.json",
|
|
174
|
+
sha256: await sha256File(found.mcpJsonPath),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// skill files
|
|
178
|
+
const skillRedactedMap = {};
|
|
179
|
+
for (const f of found.skillFiles) {
|
|
180
|
+
const rel = path.relative(projectDir, f).replace(/\\/g, "/");
|
|
181
|
+
const redacted = await processTextFile(rel, f);
|
|
182
|
+
skillRedactedMap[rel] = redacted;
|
|
183
|
+
}
|
|
184
|
+
const runId = computeRunId(inputs.map((x) => `${x.rel}:${x.sha256}`));
|
|
185
|
+
const movaBase = path.join(outRoot, "mova", "claude_import", "v0");
|
|
186
|
+
const evidenceWriter = new EvidenceWriter();
|
|
187
|
+
const overlayParams = {
|
|
188
|
+
contractsDir: "mova/claude_import/v0/contracts/",
|
|
189
|
+
artifactsDir: "mova/claude_import/v0/",
|
|
190
|
+
instructionProfileFile: "instruction_profile_v0.json",
|
|
191
|
+
skillsCatalogFile: "skills_catalog_v0.json",
|
|
192
|
+
mcpServersFile: "mcp_servers_v0.json",
|
|
193
|
+
lintReportFile: "lint_report_v0.json",
|
|
194
|
+
qualityReportFile: "quality_report_v0.json",
|
|
195
|
+
exportManifestFile: "export_manifest_v0.json",
|
|
196
|
+
};
|
|
197
|
+
const normalizedSkills = Object.entries(skillRedactedMap).map(([rel, body]) => ({
|
|
198
|
+
rel,
|
|
199
|
+
body,
|
|
200
|
+
normDir: normalizeSkillDir(rel),
|
|
201
|
+
title: path.basename(rel, ".md"),
|
|
202
|
+
}));
|
|
203
|
+
if (!opts.dryRun) {
|
|
204
|
+
const toolVersion = await readToolVersion();
|
|
205
|
+
const versionInfo = {
|
|
206
|
+
tool_name: "mova-claude-import",
|
|
207
|
+
tool_version: toolVersion,
|
|
208
|
+
profile_version: "anthropic_profile_v0",
|
|
209
|
+
overlay_version: "mova_control_overlay_v0",
|
|
210
|
+
input_policy_version: "input_policy_v0",
|
|
211
|
+
lint_version: "lint_v0",
|
|
212
|
+
quality_version: "quality_v0",
|
|
213
|
+
export_zip_version: "export_zip_v0",
|
|
214
|
+
};
|
|
215
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "VERSION.json", versionInfo);
|
|
216
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "input_policy_report_v0.json", inputPolicy);
|
|
217
|
+
}
|
|
218
|
+
if (opts.strict && !inputPolicy.ok) {
|
|
219
|
+
const deniedRunId = computeRunId(inputPolicy.denied.map((d) => `${d.path}:${d.kind}:${d.reason}`).sort());
|
|
220
|
+
if (!opts.dryRun) {
|
|
221
|
+
const manifest = {
|
|
222
|
+
tool: "mova-claude-import",
|
|
223
|
+
version: "v0",
|
|
224
|
+
run_id: deniedRunId,
|
|
225
|
+
project_dir: projectDir,
|
|
226
|
+
emit_profile: opts.emitProfile,
|
|
227
|
+
inputs: [],
|
|
228
|
+
imported: {
|
|
229
|
+
claude_md: false,
|
|
230
|
+
mcp_json: false,
|
|
231
|
+
skills_count: 0,
|
|
232
|
+
},
|
|
233
|
+
skipped: found.skipped,
|
|
234
|
+
input_policy_ok: false,
|
|
235
|
+
};
|
|
236
|
+
const episode = {
|
|
237
|
+
episode_id: deniedRunId,
|
|
238
|
+
recorded_at: "1970-01-01T00:00:00.000Z",
|
|
239
|
+
episode_type: "claude_import_run_v0",
|
|
240
|
+
run_id: deniedRunId,
|
|
241
|
+
ok: false,
|
|
242
|
+
result_core: {
|
|
243
|
+
imported: manifest.imported,
|
|
244
|
+
inputs_count: 0,
|
|
245
|
+
validation: null,
|
|
246
|
+
},
|
|
247
|
+
failure: {
|
|
248
|
+
reason: "input_policy_denied",
|
|
249
|
+
denied_count: inputPolicy.denied.length,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "import_manifest.json", manifest);
|
|
253
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "episode_import_run.json", episode);
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
ok: false,
|
|
257
|
+
exit_code: 2,
|
|
258
|
+
run_id: deniedRunId,
|
|
259
|
+
out_dir: outRoot,
|
|
260
|
+
imported: { claude_md: false, mcp_json: false, skills_count: 0 },
|
|
261
|
+
skipped: found.skipped,
|
|
262
|
+
lint_summary: "lint_v0: skipped",
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
let movaSpecSchemas;
|
|
266
|
+
try {
|
|
267
|
+
movaSpecSchemas = {
|
|
268
|
+
instruction_profile: await loadMovaSpecSchemaById(MOVA_SPEC_BINDINGS_V0.instruction_profile_id),
|
|
269
|
+
mcp_servers: await loadMovaSpecSchemaById(MOVA_SPEC_BINDINGS_V0.mcp_servers_id),
|
|
270
|
+
core: await loadMovaSpecSchemaById(MOVA_SPEC_BINDINGS_V0.core_schema_id),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
if (!opts.dryRun) {
|
|
275
|
+
const manifest = {
|
|
276
|
+
tool: "mova-claude-import",
|
|
277
|
+
version: "v0",
|
|
278
|
+
run_id: runId,
|
|
279
|
+
project_dir: projectDir,
|
|
280
|
+
emit_profile: opts.emitProfile,
|
|
281
|
+
inputs: [],
|
|
282
|
+
imported: {
|
|
283
|
+
claude_md: false,
|
|
284
|
+
mcp_json: false,
|
|
285
|
+
skills_count: 0,
|
|
286
|
+
},
|
|
287
|
+
skipped: found.skipped,
|
|
288
|
+
input_policy_ok: inputPolicy.ok,
|
|
289
|
+
failure: {
|
|
290
|
+
reason: "mova_spec_schema_missing",
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
const episode = {
|
|
294
|
+
episode_id: runId,
|
|
295
|
+
recorded_at: "1970-01-01T00:00:00.000Z",
|
|
296
|
+
episode_type: "claude_import_run_v0",
|
|
297
|
+
run_id: runId,
|
|
298
|
+
ok: false,
|
|
299
|
+
result_core: {
|
|
300
|
+
imported: manifest.imported,
|
|
301
|
+
inputs_count: 0,
|
|
302
|
+
validation: null,
|
|
303
|
+
},
|
|
304
|
+
failure: {
|
|
305
|
+
reason: "mova_spec_schema_missing",
|
|
306
|
+
detail: String(err?.message ?? err),
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "import_manifest.json", manifest);
|
|
310
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "episode_import_run.json", episode);
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
ok: false,
|
|
314
|
+
exit_code: 2,
|
|
315
|
+
run_id: runId,
|
|
316
|
+
out_dir: outRoot,
|
|
317
|
+
imported: { claude_md: false, mcp_json: false, skills_count: 0 },
|
|
318
|
+
skipped: found.skipped,
|
|
319
|
+
lint_summary: "lint_v0: skipped",
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (!opts.dryRun && opts.emitProfile) {
|
|
323
|
+
await writeCleanClaudeProfileScaffoldV0(outRoot);
|
|
324
|
+
if (opts.emitOverlay) {
|
|
325
|
+
const controlEntry = buildMovaControlEntryV0(overlayParams);
|
|
326
|
+
const claudePath = path.join(outRoot, "CLAUDE.md");
|
|
327
|
+
if (await exists(claudePath)) {
|
|
328
|
+
await ensureClaudeControlEntry(claudePath, controlEntry, MOVA_CONTROL_ENTRY_MARKER);
|
|
329
|
+
}
|
|
330
|
+
const overlayFiles = buildMovaOverlayV0(overlayParams);
|
|
331
|
+
for (const [rel, content] of Object.entries(overlayFiles)) {
|
|
332
|
+
await writeTextFile(path.join(outRoot, rel), content);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const profileFiles = getAnthropicProfileV0Files();
|
|
336
|
+
for (const [rel, content] of Object.entries(profileFiles)) {
|
|
337
|
+
if (rel === "CLAUDE.md" || rel === ".claude/settings.json")
|
|
338
|
+
continue;
|
|
339
|
+
await writeTextFile(path.join(outRoot, rel), content);
|
|
340
|
+
}
|
|
341
|
+
if (mcpJsonParsed) {
|
|
342
|
+
await writeJsonFile(path.join(outRoot, ".mcp.json"), mcpJsonParsed);
|
|
343
|
+
}
|
|
344
|
+
for (const skill of normalizedSkills) {
|
|
345
|
+
const outRel = path.join(".claude", "skills", skill.normDir, "SKILL.md");
|
|
346
|
+
await writeTextFile(path.join(outRoot, outRel), skill.body);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Build contracts
|
|
350
|
+
const instructionProfile = {
|
|
351
|
+
profile_version: "v0",
|
|
352
|
+
claude_md: claudeMdRedacted,
|
|
353
|
+
anchors: {
|
|
354
|
+
mova_entry: "MOVA.md",
|
|
355
|
+
normalized_project: ".",
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
const skillsCatalog = {
|
|
359
|
+
profile_version: "v0",
|
|
360
|
+
skills: normalizedSkills.map((skill) => ({
|
|
361
|
+
skill_id: skill.normDir,
|
|
362
|
+
rel_dir: `.claude/skills/${skill.normDir}`,
|
|
363
|
+
title: skill.title,
|
|
364
|
+
skill_md: skill.body,
|
|
365
|
+
})),
|
|
366
|
+
};
|
|
367
|
+
const mcpServers = {
|
|
368
|
+
profile_version: "v0",
|
|
369
|
+
servers: Array.isArray(mcpJsonParsed?.servers) ? mcpJsonParsed?.servers : [],
|
|
370
|
+
};
|
|
371
|
+
if (!opts.dryRun) {
|
|
372
|
+
await writeJsonFile(path.join(movaBase, "contracts", "instruction_profile_v0.json"), instructionProfile);
|
|
373
|
+
await writeJsonFile(path.join(movaBase, "contracts", "skills_catalog_v0.json"), skillsCatalog);
|
|
374
|
+
await writeJsonFile(path.join(movaBase, "contracts", "mcp_servers_v0.json"), mcpServers);
|
|
375
|
+
}
|
|
376
|
+
// Validation with Ajv
|
|
377
|
+
const ajv = new Ajv({ allErrors: true, strict: true, validateSchema: false });
|
|
378
|
+
addFormats(ajv);
|
|
379
|
+
const coreSchemaId = movaSpecSchemas.core?.$id ?? "https://mova.dev/schemas/ds.mova_schema_core_v1.schema.json";
|
|
380
|
+
ajv.addSchema(movaSpecSchemas.core, coreSchemaId);
|
|
381
|
+
const schemaPath = (name) => fileURLToPath(new URL(`../schemas/${name}`, import.meta.url));
|
|
382
|
+
const schemas = {
|
|
383
|
+
instruction_profile: JSON.parse(await fs.readFile(schemaPath("ds.claude_import.instruction_profile_v0.schema.json"), "utf8")),
|
|
384
|
+
skills_catalog: JSON.parse(await fs.readFile(schemaPath("ds.claude_import.skills_catalog_v0.schema.json"), "utf8")),
|
|
385
|
+
mcp_servers: JSON.parse(await fs.readFile(schemaPath("ds.claude_import.mcp_servers_v0.schema.json"), "utf8")),
|
|
386
|
+
};
|
|
387
|
+
const validateInstruction = ajv.compile(schemas.instruction_profile);
|
|
388
|
+
const validateSkills = ajv.compile(schemas.skills_catalog);
|
|
389
|
+
const validateMcp = ajv.compile(schemas.mcp_servers);
|
|
390
|
+
const validateSpecInstruction = ajv.compile(movaSpecSchemas.instruction_profile);
|
|
391
|
+
const validateSpecMcp = ajv.compile(movaSpecSchemas.mcp_servers);
|
|
392
|
+
const validationReport = {
|
|
393
|
+
instruction_profile: validateInstruction(instructionProfile),
|
|
394
|
+
skills_catalog: validateSkills(skillsCatalog),
|
|
395
|
+
mcp_servers: validateMcp(mcpServers),
|
|
396
|
+
mova_spec: {
|
|
397
|
+
instruction_profile: validateSpecInstruction(instructionProfile),
|
|
398
|
+
mcp_servers: validateSpecMcp(mcpServers),
|
|
399
|
+
errors: {
|
|
400
|
+
instruction_profile: validateSpecInstruction.errors,
|
|
401
|
+
mcp_servers: validateSpecMcp.errors,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
errors: {
|
|
405
|
+
instruction_profile: validateInstruction.errors,
|
|
406
|
+
skills_catalog: validateSkills.errors,
|
|
407
|
+
mcp_servers: validateMcp.errors,
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
const manifest = {
|
|
411
|
+
tool: "mova-claude-import",
|
|
412
|
+
version: "v0",
|
|
413
|
+
run_id: runId,
|
|
414
|
+
project_dir: projectDir,
|
|
415
|
+
emit_profile: opts.emitProfile,
|
|
416
|
+
inputs: inputs.sort((a, b) => a.rel.localeCompare(b.rel)),
|
|
417
|
+
imported: {
|
|
418
|
+
claude_md: Boolean(found.claudeMdPath),
|
|
419
|
+
mcp_json: Boolean(found.mcpJsonPath),
|
|
420
|
+
skills_count: normalizedSkills.length,
|
|
421
|
+
},
|
|
422
|
+
skipped: found.skipped,
|
|
423
|
+
input_policy_ok: inputPolicy.ok,
|
|
424
|
+
};
|
|
425
|
+
const redactionReport = {
|
|
426
|
+
hits: redactionHits,
|
|
427
|
+
note: "Only presence/len recorded, values omitted.",
|
|
428
|
+
};
|
|
429
|
+
const episode = {
|
|
430
|
+
episode_id: runId,
|
|
431
|
+
recorded_at: "1970-01-01T00:00:00.000Z",
|
|
432
|
+
episode_type: "claude_import_run_v0",
|
|
433
|
+
run_id: runId,
|
|
434
|
+
ok: true,
|
|
435
|
+
result_core: {
|
|
436
|
+
imported: manifest.imported,
|
|
437
|
+
inputs_count: manifest.inputs.length,
|
|
438
|
+
validation: validationReport,
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
if (!opts.dryRun) {
|
|
442
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "import_manifest.json", manifest);
|
|
443
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "redaction_report.json", redactionReport);
|
|
444
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "episode_import_run.json", episode);
|
|
445
|
+
}
|
|
446
|
+
let lintReport = {
|
|
447
|
+
profile_version: "v0",
|
|
448
|
+
ok: true,
|
|
449
|
+
issues: [],
|
|
450
|
+
summary: "lint_v0: ok",
|
|
451
|
+
};
|
|
452
|
+
if (!opts.dryRun) {
|
|
453
|
+
lintReport = await lintV0({
|
|
454
|
+
outRoot,
|
|
455
|
+
emitProfile: opts.emitProfile,
|
|
456
|
+
mcpExpected: Boolean(found.mcpJsonPath),
|
|
457
|
+
});
|
|
458
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "lint_report_v0.json", lintReport);
|
|
459
|
+
}
|
|
460
|
+
if (!opts.dryRun && opts.emitZip) {
|
|
461
|
+
const exportZip = await createExportZipV0(outRoot, opts.zipName);
|
|
462
|
+
const exportManifest = {
|
|
463
|
+
profile_version: "v0",
|
|
464
|
+
zip_rel_path: exportZip.zipRelPath,
|
|
465
|
+
zip_sha256: exportZip.zipSha256,
|
|
466
|
+
files_count: exportZip.files.length,
|
|
467
|
+
files: exportZip.files,
|
|
468
|
+
};
|
|
469
|
+
await writeEvidenceArtifact(evidenceWriter, movaBase, "export_manifest_v0.json", exportManifest);
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
ok: true,
|
|
473
|
+
run_id: runId,
|
|
474
|
+
out_dir: outRoot,
|
|
475
|
+
imported: manifest.imported,
|
|
476
|
+
skipped: found.skipped,
|
|
477
|
+
lint_summary: lintReport.summary,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function stableStringify(value: any): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function sortValue(value) {
|
|
2
|
+
if (Array.isArray(value))
|
|
3
|
+
return value.map(sortValue);
|
|
4
|
+
if (value && typeof value === "object") {
|
|
5
|
+
const out = {};
|
|
6
|
+
for (const key of Object.keys(value).sort()) {
|
|
7
|
+
out[key] = sortValue(value[key]);
|
|
8
|
+
}
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
export function stableStringify(value) {
|
|
14
|
+
return JSON.stringify(sortValue(value), null, 2);
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Anthropic Profile v0 (Source of Truth)
|
|
2
|
+
|
|
3
|
+
This document defines the deterministic output layout produced by the Anthropic
|
|
4
|
+
profile v0 rebuild.
|
|
5
|
+
|
|
6
|
+
Output root (<OUT>/):
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
<OUT>/
|
|
10
|
+
CLAUDE.md
|
|
11
|
+
MOVA.md
|
|
12
|
+
.mcp.json (only if present in input)
|
|
13
|
+
.claude/
|
|
14
|
+
settings.json
|
|
15
|
+
commands/
|
|
16
|
+
mova_context.md
|
|
17
|
+
mova_lint.md
|
|
18
|
+
skills/
|
|
19
|
+
mova-layer-v0/
|
|
20
|
+
SKILL.md
|
|
21
|
+
<imported skills...>/ (normalized)
|
|
22
|
+
mova/
|
|
23
|
+
claude_import/v0/
|
|
24
|
+
import_manifest.json
|
|
25
|
+
redaction_report.json
|
|
26
|
+
lint_report_v0.json
|
|
27
|
+
contracts/
|
|
28
|
+
instruction_profile_v0.json
|
|
29
|
+
skills_catalog_v0.json
|
|
30
|
+
mcp_servers_v0.json
|
|
31
|
+
episode_import_run.json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Notes:
|
|
35
|
+
- The output is fully deterministic (no timestamps, random IDs, or run-specific
|
|
36
|
+
folders).
|
|
37
|
+
- Source inputs are not copied into the output project; only normalized profile
|
|
38
|
+
artifacts and contracts are emitted.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Compatibility Matrix v0
|
|
2
|
+
|
|
3
|
+
## Runtime
|
|
4
|
+
|
|
5
|
+
- Node.js: 20.x, 22.x
|
|
6
|
+
- npm: 9+
|
|
7
|
+
|
|
8
|
+
## Required MOVA deps (enforced)
|
|
9
|
+
|
|
10
|
+
- @leryk1981/mova-spec = ^4.1.1
|
|
11
|
+
- @leryk1981/mova-core-engine = ^0.1.1
|
|
12
|
+
|
|
13
|
+
## Compatibility rules
|
|
14
|
+
|
|
15
|
+
- When updating mova-spec, run `npm run docs:bindings` and ensure `npm run quality` + `npm run quality:neg` are green.
|
|
16
|
+
- Deps gate: `npm run deps:audit` must pass.
|
|
17
|
+
|
|
18
|
+
## Exit codes
|
|
19
|
+
|
|
20
|
+
- 0: ok
|
|
21
|
+
- 2: validation/policy/bindings failures (strict deny, docs:check, deps:audit)
|
|
22
|
+
|
|
23
|
+
## Operational
|
|
24
|
+
|
|
25
|
+
- Deterministic outputs are guaranteed for identical inputs + flags.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Control Profile Guide v0
|
|
2
|
+
|
|
3
|
+
## Что это за файл
|
|
4
|
+
|
|
5
|
+
`claude_control_profile_v0.json` — единая панель управления политиками и поведением
|
|
6
|
+
Claude Code + MOVA наблюдаемости.
|
|
7
|
+
|
|
8
|
+
## Минимально необходимые поля
|
|
9
|
+
|
|
10
|
+
- `kind`, `id`, `version`, `mode`, `title`
|
|
11
|
+
- `anthropic.permissions`
|
|
12
|
+
- `anthropic.mcp`
|
|
13
|
+
- `anthropic.claude_md`
|
|
14
|
+
- `mova.overlay`
|
|
15
|
+
- `mova.observability`
|
|
16
|
+
- `apply.default_apply_mode`
|
|
17
|
+
|
|
18
|
+
## Как выбрать пример
|
|
19
|
+
|
|
20
|
+
| Профиль | Когда использовать |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| min | Быстрый старт, только базовые поля |
|
|
23
|
+
| standard | Рекомендуемый набор, полный контроль без жёсткости |
|
|
24
|
+
| strict | Более жёсткие allow‑списки, но всё ещё report‑only |
|
|
25
|
+
|
|
26
|
+
См. примеры в `examples/`.
|
|
27
|
+
|
|
28
|
+
## Apply‑flow
|
|
29
|
+
|
|
30
|
+
1) `control prefill` — создать профиль
|
|
31
|
+
2) отредактировать профиль
|
|
32
|
+
3) `control check` — получить план
|
|
33
|
+
4) `control apply` — применить при `--mode apply`
|
|
34
|
+
|
|
35
|
+
## Где смотреть отчёты
|
|
36
|
+
|
|
37
|
+
- `prefill_report_v0.json` — что было найдено при prefill
|
|
38
|
+
- `mova/claude_control/v0/runs/<run_id>/control_plan_v0.json`
|
|
39
|
+
- `mova/claude_control/v0/runs/<run_id>/control_summary_v0.json`
|
|
40
|
+
- `mova/claude_control/v0/runs/<run_id>/control_apply_report_v0.json`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# mova-claude-import v0 (free)
|
|
2
|
+
|
|
3
|
+
## Inputs (scanned)
|
|
4
|
+
- CLAUDE.md
|
|
5
|
+
- .claude/skills/**/*.md
|
|
6
|
+
- .mcp.json
|
|
7
|
+
Excluded by default:
|
|
8
|
+
- CLAUDE.local.md and *.local.*
|
|
9
|
+
- user settings (~/.claude/*) unless explicitly enabled
|
|
10
|
+
|
|
11
|
+
## Outputs (written)
|
|
12
|
+
- mova/claude_import/v0/runs/<run_id>/import_manifest.json
|
|
13
|
+
- mova/claude_import/v0/runs/<run_id>/redaction_report.json
|
|
14
|
+
- mova/claude_import/v0/episodes/* (execution episode)
|
|
15
|
+
- mova/claude_import/v0/runs/latest.json
|
|
16
|
+
- mova/claude_import/v0/runs/<run_id>/sources/... (redacted source files)
|
|
17
|
+
- mova/claude_import/v0/runs/<run_id>/contracts/... (generated contracts)
|
|
18
|
+
|
|
19
|
+
## Determinism
|
|
20
|
+
run_id = sha256(sorted(file_path + sha256(file_content)))[:16]
|
|
21
|
+
|
|
22
|
+
## Contracts (generated)
|
|
23
|
+
- instruction_profile_v0.json
|
|
24
|
+
- skills_catalog_v0.json
|
|
25
|
+
- mcp_servers_v0.json
|
|
26
|
+
|
|
27
|
+
## Plugin wrapper
|
|
28
|
+
Example Claude Code plugin is provided under:
|
|
29
|
+
- plugin/mova-import/.claude-plugin/
|
|
30
|
+
- plugin/mova-import/commands/import.md
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"spec_version": "4.1.1",
|
|
3
|
+
"bindings": [
|
|
4
|
+
{
|
|
5
|
+
"category": "instruction_profile",
|
|
6
|
+
"schema_id": "https://mova.dev/schemas/ds.instruction_profile_core_v1.schema.json",
|
|
7
|
+
"file_path": "schemas/ds.instruction_profile_core_v1.schema.json"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"category": "mcp_servers",
|
|
11
|
+
"schema_id": "https://mova.dev/schemas/ds.runtime_binding_core_v1.schema.json",
|
|
12
|
+
"file_path": "schemas/ds.runtime_binding_core_v1.schema.json"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"category": "core_schema",
|
|
16
|
+
"schema_id": "https://mova.dev/schemas/ds.mova_schema_core_v1.schema.json",
|
|
17
|
+
"file_path": "schemas/ds.mova_schema_core_v1.schema.json"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"selection_rule": "Bound to MOVA_SPEC_BINDINGS_V0 used by run_import.ts"
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# MOVA Spec Bindings v0
|
|
2
|
+
|
|
3
|
+
Spec version: 4.1.1
|
|
4
|
+
|
|
5
|
+
| Category | Chosen schema $id | File path |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| instruction_profile | https://mova.dev/schemas/ds.instruction_profile_core_v1.schema.json | schemas/ds.instruction_profile_core_v1.schema.json |
|
|
8
|
+
| mcp_servers | https://mova.dev/schemas/ds.runtime_binding_core_v1.schema.json | schemas/ds.runtime_binding_core_v1.schema.json |
|
|
9
|
+
| core_schema | https://mova.dev/schemas/ds.mova_schema_core_v1.schema.json | schemas/ds.mova_schema_core_v1.schema.json |
|
|
10
|
+
|
|
11
|
+
Selection rule: Bound to `MOVA_SPEC_BINDINGS_V0` used by `src/run_import.ts`.
|