@thinkingsage/kanon 0.8.0

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.
Files changed (199) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -0
  4. package/bridge/mcp-server.cjs +14171 -0
  5. package/package.json +98 -0
  6. package/src/adapters/capabilities.ts +178 -0
  7. package/src/adapters/claude-code.ts +110 -0
  8. package/src/adapters/cline.ts +98 -0
  9. package/src/adapters/codex.ts +173 -0
  10. package/src/adapters/copilot.ts +106 -0
  11. package/src/adapters/cursor.ts +97 -0
  12. package/src/adapters/degradation.ts +95 -0
  13. package/src/adapters/index.ts +324 -0
  14. package/src/adapters/kiro-frontmatter.ts +139 -0
  15. package/src/adapters/kiro-inclusion.ts +86 -0
  16. package/src/adapters/kiro.ts +412 -0
  17. package/src/adapters/qdeveloper.ts +115 -0
  18. package/src/adapters/types.ts +81 -0
  19. package/src/adapters/windsurf.ts +96 -0
  20. package/src/admin.ts +283 -0
  21. package/src/asset-conventions.ts +118 -0
  22. package/src/attribution-backfill.ts +319 -0
  23. package/src/attribution-report.ts +95 -0
  24. package/src/attribution.ts +239 -0
  25. package/src/backends/github.ts +194 -0
  26. package/src/backends/http.ts +122 -0
  27. package/src/backends/index.ts +39 -0
  28. package/src/backends/local.ts +47 -0
  29. package/src/backends/s3.ts +157 -0
  30. package/src/backends/types.ts +59 -0
  31. package/src/base-cache.ts +270 -0
  32. package/src/browse-ui.ts +3754 -0
  33. package/src/browse.ts +1038 -0
  34. package/src/build.ts +1108 -0
  35. package/src/catalog.ts +204 -0
  36. package/src/cli-deprecated.ts +29 -0
  37. package/src/cli.ts +773 -0
  38. package/src/collection-admin.ts +287 -0
  39. package/src/collection-builder.ts +464 -0
  40. package/src/collections.ts +116 -0
  41. package/src/compatibility.ts +105 -0
  42. package/src/config.ts +743 -0
  43. package/src/eval/rubrics/kiro-progressive-steering.ts +841 -0
  44. package/src/eval.ts +1169 -0
  45. package/src/file-writer.ts +61 -0
  46. package/src/format-registry.ts +141 -0
  47. package/src/guild/auto-updater.ts +163 -0
  48. package/src/guild/backend-resolver.ts +49 -0
  49. package/src/guild/cli.ts +592 -0
  50. package/src/guild/collection-expander.ts +47 -0
  51. package/src/guild/global-cache.ts +247 -0
  52. package/src/guild/hook-generator.ts +100 -0
  53. package/src/guild/manifest.ts +154 -0
  54. package/src/guild/path-utils.ts +12 -0
  55. package/src/guild/sync.ts +622 -0
  56. package/src/guild/version-resolver.ts +42 -0
  57. package/src/help/metadata.ts +445 -0
  58. package/src/help/renderer.ts +265 -0
  59. package/src/help/typo-suggester.ts +25 -0
  60. package/src/hooks/expression.ts +493 -0
  61. package/src/hooks/pipeline.ts +141 -0
  62. package/src/import.ts +773 -0
  63. package/src/importers/claude-code.ts +134 -0
  64. package/src/importers/cline.ts +103 -0
  65. package/src/importers/codex.ts +140 -0
  66. package/src/importers/copilot.ts +103 -0
  67. package/src/importers/cursor.ts +105 -0
  68. package/src/importers/index.ts +390 -0
  69. package/src/importers/kiro.ts +110 -0
  70. package/src/importers/qdeveloper.ts +103 -0
  71. package/src/importers/types.ts +54 -0
  72. package/src/importers/windsurf.ts +104 -0
  73. package/src/install.ts +1005 -0
  74. package/src/manifest-admin.ts +306 -0
  75. package/src/mcp-bridge.ts +240 -0
  76. package/src/mutation/delta.ts +50 -0
  77. package/src/mutation/history.ts +66 -0
  78. package/src/mutation/operators.ts +524 -0
  79. package/src/mutation/runner.ts +332 -0
  80. package/src/new.ts +106 -0
  81. package/src/outcomes/collision.ts +127 -0
  82. package/src/outcomes/normalize.ts +208 -0
  83. package/src/outcomes/registry.ts +173 -0
  84. package/src/parser.ts +446 -0
  85. package/src/provenance-backfill-cli.ts +319 -0
  86. package/src/provenance-backfill.ts +520 -0
  87. package/src/publish.ts +354 -0
  88. package/src/reconcile-orchestrator.ts +502 -0
  89. package/src/reconcile-report-renderer.ts +176 -0
  90. package/src/resolve-body.ts +15 -0
  91. package/src/rosetta/builtins/compatibility-profiles.ts +297 -0
  92. package/src/rosetta/builtins/contracts.ts +1033 -0
  93. package/src/rosetta/builtins/pretty-printers/claude-code-native.ts +122 -0
  94. package/src/rosetta/builtins/pretty-printers/cline-native.ts +50 -0
  95. package/src/rosetta/builtins/pretty-printers/codex-native.ts +127 -0
  96. package/src/rosetta/builtins/pretty-printers/copilot-native.ts +50 -0
  97. package/src/rosetta/builtins/pretty-printers/cursor-native.ts +50 -0
  98. package/src/rosetta/builtins/pretty-printers/index.ts +81 -0
  99. package/src/rosetta/builtins/pretty-printers/kiro-native.ts +166 -0
  100. package/src/rosetta/builtins/pretty-printers/kiro-power.ts +108 -0
  101. package/src/rosetta/builtins/pretty-printers/kiro-skill.ts +88 -0
  102. package/src/rosetta/builtins/pretty-printers/qdeveloper-native.ts +51 -0
  103. package/src/rosetta/builtins/pretty-printers/superpowers.ts +97 -0
  104. package/src/rosetta/builtins/pretty-printers/windsurf-native.ts +50 -0
  105. package/src/rosetta/builtins/sources/claude-code-native.ts +348 -0
  106. package/src/rosetta/builtins/sources/cline-native.ts +176 -0
  107. package/src/rosetta/builtins/sources/codex-native.ts +343 -0
  108. package/src/rosetta/builtins/sources/copilot-native.ts +178 -0
  109. package/src/rosetta/builtins/sources/cursor-native.ts +176 -0
  110. package/src/rosetta/builtins/sources/index.ts +95 -0
  111. package/src/rosetta/builtins/sources/kiro-native.ts +462 -0
  112. package/src/rosetta/builtins/sources/kiro-power.ts +285 -0
  113. package/src/rosetta/builtins/sources/kiro-skill.ts +230 -0
  114. package/src/rosetta/builtins/sources/qdeveloper-native.ts +181 -0
  115. package/src/rosetta/builtins/sources/superpowers.ts +240 -0
  116. package/src/rosetta/builtins/sources/windsurf-native.ts +176 -0
  117. package/src/rosetta/builtins/targets/claude-code.ts +181 -0
  118. package/src/rosetta/builtins/targets/cline.ts +87 -0
  119. package/src/rosetta/builtins/targets/codex.ts +226 -0
  120. package/src/rosetta/builtins/targets/copilot.ts +103 -0
  121. package/src/rosetta/builtins/targets/cursor.ts +87 -0
  122. package/src/rosetta/builtins/targets/index.ts +60 -0
  123. package/src/rosetta/builtins/targets/kiro.ts +278 -0
  124. package/src/rosetta/builtins/targets/qdeveloper.ts +103 -0
  125. package/src/rosetta/builtins/targets/windsurf.ts +87 -0
  126. package/src/rosetta/canonical.ts +729 -0
  127. package/src/rosetta/compatibility.ts +432 -0
  128. package/src/rosetta/contracts.ts +329 -0
  129. package/src/rosetta/detector.ts +724 -0
  130. package/src/rosetta/diagnostics.ts +630 -0
  131. package/src/rosetta/engine-bootstrap.ts +103 -0
  132. package/src/rosetta/engine.ts +744 -0
  133. package/src/rosetta/index.ts +381 -0
  134. package/src/rosetta/inspection.ts +530 -0
  135. package/src/rosetta/plan.ts +448 -0
  136. package/src/rosetta/provenance-digest.ts +369 -0
  137. package/src/rosetta/reconcile.ts +812 -0
  138. package/src/rosetta/redaction.ts +467 -0
  139. package/src/rosetta/registry.ts +712 -0
  140. package/src/rosetta/renderers.ts +571 -0
  141. package/src/rosetta/request-guard.ts +335 -0
  142. package/src/rosetta/resolution.ts +419 -0
  143. package/src/rosetta/source-accounting.ts +233 -0
  144. package/src/rosetta/templates.ts +129 -0
  145. package/src/rosetta-cli.ts +717 -0
  146. package/src/rosetta-docs-generator.ts +793 -0
  147. package/src/rosetta-profiles-cli.ts +367 -0
  148. package/src/schemas.ts +1712 -0
  149. package/src/spec-coordination.ts +1141 -0
  150. package/src/temper.ts +747 -0
  151. package/src/template-bundle-loader.ts +312 -0
  152. package/src/template-engine.ts +53 -0
  153. package/src/translation-application-policy.ts +496 -0
  154. package/src/translation-orchestrator.ts +1013 -0
  155. package/src/translation-plan-applier.ts +473 -0
  156. package/src/tutorial.ts +305 -0
  157. package/src/validate.ts +1093 -0
  158. package/src/versioning.ts +553 -0
  159. package/src/wizard.ts +660 -0
  160. package/src/workspace.ts +237 -0
  161. package/templates/eval-contexts/claude-code.md.njk +6 -0
  162. package/templates/eval-contexts/cline.md.njk +6 -0
  163. package/templates/eval-contexts/copilot.md.njk +6 -0
  164. package/templates/eval-contexts/cursor.md.njk +6 -0
  165. package/templates/eval-contexts/kiro.md.njk +10 -0
  166. package/templates/eval-contexts/qdeveloper.md.njk +6 -0
  167. package/templates/eval-contexts/windsurf.md.njk +6 -0
  168. package/templates/harness-adapters/_base/attribution-footer.md.njk +17 -0
  169. package/templates/harness-adapters/_base/base.md.njk +16 -0
  170. package/templates/harness-adapters/claude-code/claude.md.njk +1 -0
  171. package/templates/harness-adapters/claude-code/mcp.json.njk +1 -0
  172. package/templates/harness-adapters/claude-code/settings.json.njk +1 -0
  173. package/templates/harness-adapters/claude-code/skill-library-index.md.njk +13 -0
  174. package/templates/harness-adapters/claude-code/skill.md.njk +19 -0
  175. package/templates/harness-adapters/cline/hook.sh.njk +4 -0
  176. package/templates/harness-adapters/cline/mcp.json.njk +1 -0
  177. package/templates/harness-adapters/cline/rule.md.njk +1 -0
  178. package/templates/harness-adapters/codex/agents-md.md.njk +6 -0
  179. package/templates/harness-adapters/codex/agents-pointer.md.njk +16 -0
  180. package/templates/harness-adapters/codex/skill.md.njk +27 -0
  181. package/templates/harness-adapters/copilot/agents.md.njk +1 -0
  182. package/templates/harness-adapters/copilot/instructions.md.njk +1 -0
  183. package/templates/harness-adapters/copilot/scoped.md.njk +6 -0
  184. package/templates/harness-adapters/cursor/mcp.json.njk +1 -0
  185. package/templates/harness-adapters/cursor/rule.md.njk +6 -0
  186. package/templates/harness-adapters/kiro/hook.json.njk +1 -0
  187. package/templates/harness-adapters/kiro/mcp.json.njk +1 -0
  188. package/templates/harness-adapters/kiro/power-steering.md.njk +3 -0
  189. package/templates/harness-adapters/kiro/power.md.njk +12 -0
  190. package/templates/harness-adapters/kiro/steering.md.njk +16 -0
  191. package/templates/harness-adapters/qdeveloper/agent.md.njk +1 -0
  192. package/templates/harness-adapters/qdeveloper/mcp.json.njk +1 -0
  193. package/templates/harness-adapters/qdeveloper/rule.md.njk +1 -0
  194. package/templates/harness-adapters/windsurf/mcp.json.njk +1 -0
  195. package/templates/harness-adapters/windsurf/rule.md.njk +1 -0
  196. package/templates/harness-adapters/windsurf/workflow.md.njk +1 -0
  197. package/templates/knowledge/hooks.yaml.njk +4 -0
  198. package/templates/knowledge/knowledge.md.njk +53 -0
  199. package/templates/knowledge/mcp-servers.yaml.njk +2 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Claude Code Importer — Compatibility Facade
3
+ *
4
+ * Preserves the public `parseClaudeCode` interface while delegating pure parsing
5
+ * to the Rosetta Stone claude-code-native source translator. Handles multi-file
6
+ * grouping (CLAUDE.md, settings.json, mcp.json) deterministically.
7
+ *
8
+ * For supplementary files (settings.json, mcp.json) that lack a primary CLAUDE.md,
9
+ * a synthetic primary document is injected so the translator can produce a valid
10
+ * candidate with extracted hooks/MCP servers.
11
+ *
12
+ * Requirements: 14.2, 14.10, 14.11
13
+ */
14
+
15
+ import { readFile } from "node:fs/promises";
16
+ import { basename } from "node:path";
17
+ import { translateClaudeCodeNative } from "../rosetta/builtins/sources/claude-code-native";
18
+ import type { SourceTranslatorContext } from "../rosetta/registry";
19
+ import type {
20
+ FormatIdentifier,
21
+ NormalizedRelativePath,
22
+ SourceDocument,
23
+ } from "../schemas";
24
+ import type { ImportedFile, ImportParser } from "./types";
25
+
26
+ /**
27
+ * Derives a kebab-case artifact name from a file path.
28
+ */
29
+ function deriveArtifactName(filePath: string): string {
30
+ const base = basename(filePath);
31
+ const name = base.replace(/\.[^.]+$/, "");
32
+ return name
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9]+/g, "-")
35
+ .replace(/^-|-$/g, "");
36
+ }
37
+
38
+ /**
39
+ * Claude Code import parser.
40
+ * Handles CLAUDE.md, .claude/settings.json, and .claude/mcp.json.
41
+ * Delegates pure parsing to the Rosetta Stone claude-code-native source translator.
42
+ */
43
+ export const parseClaudeCode: ImportParser = async (
44
+ filePath: string,
45
+ ): Promise<ImportedFile> => {
46
+ const raw = await readFile(filePath, "utf-8");
47
+ const base = basename(filePath);
48
+
49
+ // Derive artifact name based on file type
50
+ let artifactName: string;
51
+ if (base.endsWith("settings.json")) {
52
+ artifactName = "claude-settings";
53
+ } else if (base.endsWith("mcp.json")) {
54
+ artifactName = "claude-mcp";
55
+ } else {
56
+ artifactName = deriveArtifactName(filePath);
57
+ }
58
+
59
+ // Build SourceDocument set for Rosetta Stone.
60
+ // For supplementary files (settings.json, mcp.json) we inject a synthetic
61
+ // CLAUDE.md so the translator can produce a candidate.
62
+ const documents: SourceDocument[] = [];
63
+
64
+ if (base.endsWith("settings.json") || base.endsWith("mcp.json")) {
65
+ // Inject a minimal synthetic CLAUDE.md as the primary document
66
+ documents.push({
67
+ path: "CLAUDE.md" as NormalizedRelativePath,
68
+ content: "",
69
+ executable: false,
70
+ });
71
+ documents.push({
72
+ path: base as NormalizedRelativePath,
73
+ content: raw,
74
+ executable: false,
75
+ });
76
+ } else {
77
+ documents.push({
78
+ path: base as NormalizedRelativePath,
79
+ content: raw,
80
+ executable: false,
81
+ });
82
+ }
83
+
84
+ // Build translator context with the artifact name hint
85
+ const context: SourceTranslatorContext = {
86
+ format: {
87
+ id: "claude-code" as FormatIdentifier,
88
+ } as SourceTranslatorContext["format"],
89
+ canonicalSchemaVersion: "1.0.0",
90
+ options: {},
91
+ callerContext: { artifactNameHint: artifactName },
92
+ };
93
+
94
+ // Delegate to Rosetta Stone
95
+ const output = translateClaudeCodeNative(documents, context);
96
+
97
+ // Map SourceTranslationOutput back to ImportedFile shape
98
+ if (output.candidate) {
99
+ const candidate = output.candidate as Record<string, unknown>;
100
+ const frontmatter = (candidate.frontmatter ?? {}) as Record<
101
+ string,
102
+ unknown
103
+ >;
104
+ const {
105
+ name: _n,
106
+ type: _t,
107
+ harnesses: _h,
108
+ ...restFrontmatter
109
+ } = frontmatter;
110
+
111
+ return {
112
+ sourcePath: filePath,
113
+ artifactName,
114
+ body: (candidate.body as string) ?? "",
115
+ frontmatter: restFrontmatter,
116
+ hooks: (candidate.hooks as ImportedFile["hooks"]) ?? [],
117
+ mcpServers: (candidate.mcpServers as ImportedFile["mcpServers"]) ?? [],
118
+ extraFields: (candidate.extraFields as Record<string, unknown>) ?? {},
119
+ };
120
+ }
121
+
122
+ // Fallback: if translation produced no candidate, return minimal result
123
+ return {
124
+ sourcePath: filePath,
125
+ artifactName,
126
+ body: "",
127
+ frontmatter: {},
128
+ hooks: [],
129
+ mcpServers: [],
130
+ extraFields: {},
131
+ };
132
+ };
133
+
134
+ export default parseClaudeCode;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Cline Importer — Compatibility Facade
3
+ *
4
+ * Preserves the public `parseCline` interface while delegating pure parsing
5
+ * to the Rosetta Stone cline-native source translator.
6
+ *
7
+ * Requirements: 14.2, 14.10, 14.11
8
+ */
9
+
10
+ import { readFile } from "node:fs/promises";
11
+ import { basename } from "node:path";
12
+ import { translateClineNative } from "../rosetta/builtins/sources/cline-native";
13
+ import type { SourceTranslatorContext } from "../rosetta/registry";
14
+ import type {
15
+ FormatIdentifier,
16
+ NormalizedRelativePath,
17
+ SourceDocument,
18
+ } from "../schemas";
19
+ import type { ImportedFile, ImportParser } from "./types";
20
+
21
+ /**
22
+ * Derives a kebab-case artifact name from a file path.
23
+ */
24
+ function deriveArtifactName(filePath: string): string {
25
+ const base = basename(filePath);
26
+ const name = base.replace(/\.md$/, "");
27
+ return name
28
+ .toLowerCase()
29
+ .replace(/[^a-z0-9]+/g, "-")
30
+ .replace(/^-|-$/g, "");
31
+ }
32
+
33
+ /**
34
+ * Cline import parser.
35
+ * Handles .clinerules/*.md files.
36
+ * Delegates pure parsing to the Rosetta Stone cline-native source translator.
37
+ */
38
+ export const parseCline: ImportParser = async (
39
+ filePath: string,
40
+ ): Promise<ImportedFile> => {
41
+ const raw = await readFile(filePath, "utf-8");
42
+ const artifactName = deriveArtifactName(filePath);
43
+
44
+ // Build SourceDocument for Rosetta Stone
45
+ const documents: SourceDocument[] = [
46
+ {
47
+ path: basename(filePath) as NormalizedRelativePath,
48
+ content: raw,
49
+ executable: false,
50
+ },
51
+ ];
52
+
53
+ // Build translator context
54
+ const context: SourceTranslatorContext = {
55
+ format: {
56
+ id: "cline" as FormatIdentifier,
57
+ } as SourceTranslatorContext["format"],
58
+ canonicalSchemaVersion: "1.0.0",
59
+ options: {},
60
+ callerContext: { artifactNameHint: artifactName },
61
+ };
62
+
63
+ // Delegate to Rosetta Stone
64
+ const output = translateClineNative(documents, context);
65
+
66
+ // Map SourceTranslationOutput back to ImportedFile shape
67
+ if (output.candidate) {
68
+ const candidate = output.candidate as Record<string, unknown>;
69
+ const frontmatter = (candidate.frontmatter ?? {}) as Record<
70
+ string,
71
+ unknown
72
+ >;
73
+ const {
74
+ name: _n,
75
+ type: _t,
76
+ harnesses: _h,
77
+ ...restFrontmatter
78
+ } = frontmatter;
79
+
80
+ return {
81
+ sourcePath: filePath,
82
+ artifactName,
83
+ body: (candidate.body as string) ?? "",
84
+ frontmatter: restFrontmatter,
85
+ hooks: (candidate.hooks as ImportedFile["hooks"]) ?? [],
86
+ mcpServers: (candidate.mcpServers as ImportedFile["mcpServers"]) ?? [],
87
+ extraFields: (candidate.extraFields as Record<string, unknown>) ?? {},
88
+ };
89
+ }
90
+
91
+ // Fallback: if translation produced no candidate, return minimal result
92
+ return {
93
+ sourcePath: filePath,
94
+ artifactName,
95
+ body: raw.trim(),
96
+ frontmatter: {},
97
+ hooks: [],
98
+ mcpServers: [],
99
+ extraFields: {},
100
+ };
101
+ };
102
+
103
+ export default parseCline;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Codex Importer — Compatibility Facade
3
+ *
4
+ * Preserves the public `parseCodex` interface while delegating pure parsing
5
+ * to the Rosetta Stone codex-native source translator. Handles multi-file
6
+ * grouping (AGENTS.md, SKILL.md files, config.toml) deterministically.
7
+ *
8
+ * For config.toml files (which are supplementary and lack a primary markdown
9
+ * document), a synthetic AGENTS.md is injected so the translator can produce
10
+ * a valid candidate with MCP servers extracted.
11
+ *
12
+ * Requirements: 14.2, 14.10, 14.11
13
+ */
14
+
15
+ import { readFile } from "node:fs/promises";
16
+ import { basename } from "node:path";
17
+ import { translateCodexNative } from "../rosetta/builtins/sources/codex-native";
18
+ import type { SourceTranslatorContext } from "../rosetta/registry";
19
+ import type {
20
+ FormatIdentifier,
21
+ NormalizedRelativePath,
22
+ SourceDocument,
23
+ } from "../schemas";
24
+ import type { ImportedFile, ImportParser } from "./types";
25
+
26
+ /**
27
+ * Derives a kebab-case artifact name from a file path.
28
+ * For SKILL.md files, prefers the parent directory name.
29
+ */
30
+ function deriveArtifactName(filePath: string): string {
31
+ const parts = filePath.split("/");
32
+ const base = basename(filePath);
33
+ let name = base.replace(/\.[^.]+$/, "");
34
+ // `.codex/skills/<name>/SKILL.md` → use the skill directory name
35
+ if (name.toLowerCase() === "skill" && parts.length >= 2) {
36
+ name = parts[parts.length - 2];
37
+ }
38
+ // `AGENTS.md` → use a stable, descriptive name
39
+ if (name.toLowerCase() === "agents") {
40
+ name = "codex-agents";
41
+ }
42
+ // `config.toml` → use "codex-mcp" as the artifact name
43
+ if (base === "config.toml") {
44
+ return "codex-mcp";
45
+ }
46
+ return name
47
+ .toLowerCase()
48
+ .replace(/[^a-z0-9]+/g, "-")
49
+ .replace(/^-|-$/g, "");
50
+ }
51
+
52
+ /**
53
+ * Codex import parser.
54
+ * Handles AGENTS.md, SKILL.md files under .codex/skills and .agents/skills,
55
+ * and `.codex/config.toml`.
56
+ * Delegates pure parsing to the Rosetta Stone codex-native source translator.
57
+ */
58
+ export const parseCodex: ImportParser = async (
59
+ filePath: string,
60
+ ): Promise<ImportedFile> => {
61
+ const raw = await readFile(filePath, "utf-8");
62
+ const artifactName = deriveArtifactName(filePath);
63
+ const base = basename(filePath);
64
+
65
+ // Build SourceDocument set for Rosetta Stone.
66
+ // For config.toml (supplementary file), we inject a synthetic primary
67
+ // document so the translator can produce a candidate with MCP servers.
68
+ const documents: SourceDocument[] = [];
69
+
70
+ if (base === "config.toml") {
71
+ // Inject a minimal synthetic AGENTS.md as the primary document
72
+ documents.push({
73
+ path: "AGENTS.md" as NormalizedRelativePath,
74
+ content: "",
75
+ executable: false,
76
+ });
77
+ documents.push({
78
+ path: base as NormalizedRelativePath,
79
+ content: raw,
80
+ executable: false,
81
+ });
82
+ } else {
83
+ documents.push({
84
+ path: base as NormalizedRelativePath,
85
+ content: raw,
86
+ executable: false,
87
+ });
88
+ }
89
+
90
+ // Build translator context
91
+ const context: SourceTranslatorContext = {
92
+ format: {
93
+ id: "codex" as FormatIdentifier,
94
+ } as SourceTranslatorContext["format"],
95
+ canonicalSchemaVersion: "1.0.0",
96
+ options: {},
97
+ callerContext: { artifactNameHint: artifactName },
98
+ };
99
+
100
+ // Delegate to Rosetta Stone
101
+ const output = translateCodexNative(documents, context);
102
+
103
+ // Map SourceTranslationOutput back to ImportedFile shape
104
+ if (output.candidate) {
105
+ const candidate = output.candidate as Record<string, unknown>;
106
+ const frontmatter = (candidate.frontmatter ?? {}) as Record<
107
+ string,
108
+ unknown
109
+ >;
110
+ const {
111
+ name: _n,
112
+ type: _t,
113
+ harnesses: _h,
114
+ ...restFrontmatter
115
+ } = frontmatter;
116
+
117
+ return {
118
+ sourcePath: filePath,
119
+ artifactName,
120
+ body: (candidate.body as string) ?? "",
121
+ frontmatter: restFrontmatter,
122
+ hooks: (candidate.hooks as ImportedFile["hooks"]) ?? [],
123
+ mcpServers: (candidate.mcpServers as ImportedFile["mcpServers"]) ?? [],
124
+ extraFields: (candidate.extraFields as Record<string, unknown>) ?? {},
125
+ };
126
+ }
127
+
128
+ // Fallback: if translation produced no candidate, return minimal result
129
+ return {
130
+ sourcePath: filePath,
131
+ artifactName,
132
+ body: "",
133
+ frontmatter: {},
134
+ hooks: [],
135
+ mcpServers: [],
136
+ extraFields: {},
137
+ };
138
+ };
139
+
140
+ export default parseCodex;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Copilot Importer — Compatibility Facade
3
+ *
4
+ * Preserves the public `parseCopilot` interface while delegating pure parsing
5
+ * to the Rosetta Stone copilot-native source translator.
6
+ *
7
+ * Requirements: 14.2, 14.10, 14.11
8
+ */
9
+
10
+ import { readFile } from "node:fs/promises";
11
+ import { basename } from "node:path";
12
+ import { translateCopilotNative } from "../rosetta/builtins/sources/copilot-native";
13
+ import type { SourceTranslatorContext } from "../rosetta/registry";
14
+ import type {
15
+ FormatIdentifier,
16
+ NormalizedRelativePath,
17
+ SourceDocument,
18
+ } from "../schemas";
19
+ import type { ImportedFile, ImportParser } from "./types";
20
+
21
+ /**
22
+ * Derives a kebab-case artifact name from a file path.
23
+ */
24
+ function deriveArtifactName(filePath: string): string {
25
+ const base = basename(filePath);
26
+ const name = base.replace(/\.instructions\.md$/, "").replace(/\.md$/, "");
27
+ return name
28
+ .toLowerCase()
29
+ .replace(/[^a-z0-9]+/g, "-")
30
+ .replace(/^-|-$/g, "");
31
+ }
32
+
33
+ /**
34
+ * Copilot import parser.
35
+ * Handles .github/copilot-instructions.md and .github/instructions/*.instructions.md.
36
+ * Delegates pure parsing to the Rosetta Stone copilot-native source translator.
37
+ */
38
+ export const parseCopilot: ImportParser = async (
39
+ filePath: string,
40
+ ): Promise<ImportedFile> => {
41
+ const raw = await readFile(filePath, "utf-8");
42
+ const artifactName = deriveArtifactName(filePath);
43
+
44
+ // Build SourceDocument for Rosetta Stone
45
+ const documents: SourceDocument[] = [
46
+ {
47
+ path: basename(filePath) as NormalizedRelativePath,
48
+ content: raw,
49
+ executable: false,
50
+ },
51
+ ];
52
+
53
+ // Build translator context
54
+ const context: SourceTranslatorContext = {
55
+ format: {
56
+ id: "copilot" as FormatIdentifier,
57
+ } as SourceTranslatorContext["format"],
58
+ canonicalSchemaVersion: "1.0.0",
59
+ options: {},
60
+ callerContext: { artifactNameHint: artifactName },
61
+ };
62
+
63
+ // Delegate to Rosetta Stone
64
+ const output = translateCopilotNative(documents, context);
65
+
66
+ // Map SourceTranslationOutput back to ImportedFile shape
67
+ if (output.candidate) {
68
+ const candidate = output.candidate as Record<string, unknown>;
69
+ const frontmatter = (candidate.frontmatter ?? {}) as Record<
70
+ string,
71
+ unknown
72
+ >;
73
+ const {
74
+ name: _n,
75
+ type: _t,
76
+ harnesses: _h,
77
+ ...restFrontmatter
78
+ } = frontmatter;
79
+
80
+ return {
81
+ sourcePath: filePath,
82
+ artifactName,
83
+ body: (candidate.body as string) ?? "",
84
+ frontmatter: restFrontmatter,
85
+ hooks: (candidate.hooks as ImportedFile["hooks"]) ?? [],
86
+ mcpServers: (candidate.mcpServers as ImportedFile["mcpServers"]) ?? [],
87
+ extraFields: (candidate.extraFields as Record<string, unknown>) ?? {},
88
+ };
89
+ }
90
+
91
+ // Fallback: if translation produced no candidate, return minimal result
92
+ return {
93
+ sourcePath: filePath,
94
+ artifactName,
95
+ body: raw.trim(),
96
+ frontmatter: {},
97
+ hooks: [],
98
+ mcpServers: [],
99
+ extraFields: {},
100
+ };
101
+ };
102
+
103
+ export default parseCopilot;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Cursor Importer — Compatibility Facade
3
+ *
4
+ * Preserves the public `parseCursor` interface while delegating pure parsing
5
+ * to the Rosetta Stone cursor-native source translator.
6
+ *
7
+ * Requirements: 14.2, 14.10, 14.11
8
+ */
9
+
10
+ import { readFile } from "node:fs/promises";
11
+ import { basename } from "node:path";
12
+ import { translateCursorNative } from "../rosetta/builtins/sources/cursor-native";
13
+ import type { SourceTranslatorContext } from "../rosetta/registry";
14
+ import type {
15
+ FormatIdentifier,
16
+ NormalizedRelativePath,
17
+ SourceDocument,
18
+ } from "../schemas";
19
+ import type { ImportedFile, ImportParser } from "./types";
20
+
21
+ /**
22
+ * Derives a kebab-case artifact name from a file path.
23
+ */
24
+ function deriveArtifactName(filePath: string): string {
25
+ const base = basename(filePath);
26
+ if (base === ".cursorrules") return "cursorrules";
27
+ const name = base.replace(/\.md$/, "");
28
+ return name
29
+ .toLowerCase()
30
+ .replace(/[^a-z0-9]+/g, "-")
31
+ .replace(/^-|-$/g, "");
32
+ }
33
+
34
+ /**
35
+ * Cursor import parser.
36
+ * Handles .cursor/rules/*.md and .cursorrules.
37
+ * Delegates pure parsing to the Rosetta Stone cursor-native source translator.
38
+ */
39
+ export const parseCursor: ImportParser = async (
40
+ filePath: string,
41
+ ): Promise<ImportedFile> => {
42
+ const raw = await readFile(filePath, "utf-8");
43
+ const artifactName = deriveArtifactName(filePath);
44
+
45
+ // Build SourceDocument for Rosetta Stone
46
+ const documents: SourceDocument[] = [
47
+ {
48
+ path: basename(filePath) as NormalizedRelativePath,
49
+ content: raw,
50
+ executable: false,
51
+ },
52
+ ];
53
+
54
+ // Build translator context
55
+ const context: SourceTranslatorContext = {
56
+ format: {
57
+ id: "cursor" as FormatIdentifier,
58
+ } as SourceTranslatorContext["format"],
59
+ canonicalSchemaVersion: "1.0.0",
60
+ options: {},
61
+ callerContext: { artifactNameHint: artifactName },
62
+ };
63
+
64
+ // Delegate to Rosetta Stone
65
+ const output = translateCursorNative(documents, context);
66
+
67
+ // Map SourceTranslationOutput back to ImportedFile shape
68
+ if (output.candidate) {
69
+ const candidate = output.candidate as Record<string, unknown>;
70
+ const frontmatter = (candidate.frontmatter ?? {}) as Record<
71
+ string,
72
+ unknown
73
+ >;
74
+ // Remove fields that are managed by the import orchestrator
75
+ const {
76
+ name: _n,
77
+ type: _t,
78
+ harnesses: _h,
79
+ ...restFrontmatter
80
+ } = frontmatter;
81
+
82
+ return {
83
+ sourcePath: filePath,
84
+ artifactName,
85
+ body: (candidate.body as string) ?? "",
86
+ frontmatter: restFrontmatter,
87
+ hooks: (candidate.hooks as ImportedFile["hooks"]) ?? [],
88
+ mcpServers: (candidate.mcpServers as ImportedFile["mcpServers"]) ?? [],
89
+ extraFields: (candidate.extraFields as Record<string, unknown>) ?? {},
90
+ };
91
+ }
92
+
93
+ // Fallback: if translation produced no candidate, return minimal result
94
+ return {
95
+ sourcePath: filePath,
96
+ artifactName,
97
+ body: raw.trim(),
98
+ frontmatter: {},
99
+ hooks: [],
100
+ mcpServers: [],
101
+ extraFields: {},
102
+ };
103
+ };
104
+
105
+ export default parseCursor;