@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.
- package/CHANGELOG.md +410 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/bridge/mcp-server.cjs +14171 -0
- package/package.json +98 -0
- package/src/adapters/capabilities.ts +178 -0
- package/src/adapters/claude-code.ts +110 -0
- package/src/adapters/cline.ts +98 -0
- package/src/adapters/codex.ts +173 -0
- package/src/adapters/copilot.ts +106 -0
- package/src/adapters/cursor.ts +97 -0
- package/src/adapters/degradation.ts +95 -0
- package/src/adapters/index.ts +324 -0
- package/src/adapters/kiro-frontmatter.ts +139 -0
- package/src/adapters/kiro-inclusion.ts +86 -0
- package/src/adapters/kiro.ts +412 -0
- package/src/adapters/qdeveloper.ts +115 -0
- package/src/adapters/types.ts +81 -0
- package/src/adapters/windsurf.ts +96 -0
- package/src/admin.ts +283 -0
- package/src/asset-conventions.ts +118 -0
- package/src/attribution-backfill.ts +319 -0
- package/src/attribution-report.ts +95 -0
- package/src/attribution.ts +239 -0
- package/src/backends/github.ts +194 -0
- package/src/backends/http.ts +122 -0
- package/src/backends/index.ts +39 -0
- package/src/backends/local.ts +47 -0
- package/src/backends/s3.ts +157 -0
- package/src/backends/types.ts +59 -0
- package/src/base-cache.ts +270 -0
- package/src/browse-ui.ts +3754 -0
- package/src/browse.ts +1038 -0
- package/src/build.ts +1108 -0
- package/src/catalog.ts +204 -0
- package/src/cli-deprecated.ts +29 -0
- package/src/cli.ts +773 -0
- package/src/collection-admin.ts +287 -0
- package/src/collection-builder.ts +464 -0
- package/src/collections.ts +116 -0
- package/src/compatibility.ts +105 -0
- package/src/config.ts +743 -0
- package/src/eval/rubrics/kiro-progressive-steering.ts +841 -0
- package/src/eval.ts +1169 -0
- package/src/file-writer.ts +61 -0
- package/src/format-registry.ts +141 -0
- package/src/guild/auto-updater.ts +163 -0
- package/src/guild/backend-resolver.ts +49 -0
- package/src/guild/cli.ts +592 -0
- package/src/guild/collection-expander.ts +47 -0
- package/src/guild/global-cache.ts +247 -0
- package/src/guild/hook-generator.ts +100 -0
- package/src/guild/manifest.ts +154 -0
- package/src/guild/path-utils.ts +12 -0
- package/src/guild/sync.ts +622 -0
- package/src/guild/version-resolver.ts +42 -0
- package/src/help/metadata.ts +445 -0
- package/src/help/renderer.ts +265 -0
- package/src/help/typo-suggester.ts +25 -0
- package/src/hooks/expression.ts +493 -0
- package/src/hooks/pipeline.ts +141 -0
- package/src/import.ts +773 -0
- package/src/importers/claude-code.ts +134 -0
- package/src/importers/cline.ts +103 -0
- package/src/importers/codex.ts +140 -0
- package/src/importers/copilot.ts +103 -0
- package/src/importers/cursor.ts +105 -0
- package/src/importers/index.ts +390 -0
- package/src/importers/kiro.ts +110 -0
- package/src/importers/qdeveloper.ts +103 -0
- package/src/importers/types.ts +54 -0
- package/src/importers/windsurf.ts +104 -0
- package/src/install.ts +1005 -0
- package/src/manifest-admin.ts +306 -0
- package/src/mcp-bridge.ts +240 -0
- package/src/mutation/delta.ts +50 -0
- package/src/mutation/history.ts +66 -0
- package/src/mutation/operators.ts +524 -0
- package/src/mutation/runner.ts +332 -0
- package/src/new.ts +106 -0
- package/src/outcomes/collision.ts +127 -0
- package/src/outcomes/normalize.ts +208 -0
- package/src/outcomes/registry.ts +173 -0
- package/src/parser.ts +446 -0
- package/src/provenance-backfill-cli.ts +319 -0
- package/src/provenance-backfill.ts +520 -0
- package/src/publish.ts +354 -0
- package/src/reconcile-orchestrator.ts +502 -0
- package/src/reconcile-report-renderer.ts +176 -0
- package/src/resolve-body.ts +15 -0
- package/src/rosetta/builtins/compatibility-profiles.ts +297 -0
- package/src/rosetta/builtins/contracts.ts +1033 -0
- package/src/rosetta/builtins/pretty-printers/claude-code-native.ts +122 -0
- package/src/rosetta/builtins/pretty-printers/cline-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/codex-native.ts +127 -0
- package/src/rosetta/builtins/pretty-printers/copilot-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/cursor-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/index.ts +81 -0
- package/src/rosetta/builtins/pretty-printers/kiro-native.ts +166 -0
- package/src/rosetta/builtins/pretty-printers/kiro-power.ts +108 -0
- package/src/rosetta/builtins/pretty-printers/kiro-skill.ts +88 -0
- package/src/rosetta/builtins/pretty-printers/qdeveloper-native.ts +51 -0
- package/src/rosetta/builtins/pretty-printers/superpowers.ts +97 -0
- package/src/rosetta/builtins/pretty-printers/windsurf-native.ts +50 -0
- package/src/rosetta/builtins/sources/claude-code-native.ts +348 -0
- package/src/rosetta/builtins/sources/cline-native.ts +176 -0
- package/src/rosetta/builtins/sources/codex-native.ts +343 -0
- package/src/rosetta/builtins/sources/copilot-native.ts +178 -0
- package/src/rosetta/builtins/sources/cursor-native.ts +176 -0
- package/src/rosetta/builtins/sources/index.ts +95 -0
- package/src/rosetta/builtins/sources/kiro-native.ts +462 -0
- package/src/rosetta/builtins/sources/kiro-power.ts +285 -0
- package/src/rosetta/builtins/sources/kiro-skill.ts +230 -0
- package/src/rosetta/builtins/sources/qdeveloper-native.ts +181 -0
- package/src/rosetta/builtins/sources/superpowers.ts +240 -0
- package/src/rosetta/builtins/sources/windsurf-native.ts +176 -0
- package/src/rosetta/builtins/targets/claude-code.ts +181 -0
- package/src/rosetta/builtins/targets/cline.ts +87 -0
- package/src/rosetta/builtins/targets/codex.ts +226 -0
- package/src/rosetta/builtins/targets/copilot.ts +103 -0
- package/src/rosetta/builtins/targets/cursor.ts +87 -0
- package/src/rosetta/builtins/targets/index.ts +60 -0
- package/src/rosetta/builtins/targets/kiro.ts +278 -0
- package/src/rosetta/builtins/targets/qdeveloper.ts +103 -0
- package/src/rosetta/builtins/targets/windsurf.ts +87 -0
- package/src/rosetta/canonical.ts +729 -0
- package/src/rosetta/compatibility.ts +432 -0
- package/src/rosetta/contracts.ts +329 -0
- package/src/rosetta/detector.ts +724 -0
- package/src/rosetta/diagnostics.ts +630 -0
- package/src/rosetta/engine-bootstrap.ts +103 -0
- package/src/rosetta/engine.ts +744 -0
- package/src/rosetta/index.ts +381 -0
- package/src/rosetta/inspection.ts +530 -0
- package/src/rosetta/plan.ts +448 -0
- package/src/rosetta/provenance-digest.ts +369 -0
- package/src/rosetta/reconcile.ts +812 -0
- package/src/rosetta/redaction.ts +467 -0
- package/src/rosetta/registry.ts +712 -0
- package/src/rosetta/renderers.ts +571 -0
- package/src/rosetta/request-guard.ts +335 -0
- package/src/rosetta/resolution.ts +419 -0
- package/src/rosetta/source-accounting.ts +233 -0
- package/src/rosetta/templates.ts +129 -0
- package/src/rosetta-cli.ts +717 -0
- package/src/rosetta-docs-generator.ts +793 -0
- package/src/rosetta-profiles-cli.ts +367 -0
- package/src/schemas.ts +1712 -0
- package/src/spec-coordination.ts +1141 -0
- package/src/temper.ts +747 -0
- package/src/template-bundle-loader.ts +312 -0
- package/src/template-engine.ts +53 -0
- package/src/translation-application-policy.ts +496 -0
- package/src/translation-orchestrator.ts +1013 -0
- package/src/translation-plan-applier.ts +473 -0
- package/src/tutorial.ts +305 -0
- package/src/validate.ts +1093 -0
- package/src/versioning.ts +553 -0
- package/src/wizard.ts +660 -0
- package/src/workspace.ts +237 -0
- package/templates/eval-contexts/claude-code.md.njk +6 -0
- package/templates/eval-contexts/cline.md.njk +6 -0
- package/templates/eval-contexts/copilot.md.njk +6 -0
- package/templates/eval-contexts/cursor.md.njk +6 -0
- package/templates/eval-contexts/kiro.md.njk +10 -0
- package/templates/eval-contexts/qdeveloper.md.njk +6 -0
- package/templates/eval-contexts/windsurf.md.njk +6 -0
- package/templates/harness-adapters/_base/attribution-footer.md.njk +17 -0
- package/templates/harness-adapters/_base/base.md.njk +16 -0
- package/templates/harness-adapters/claude-code/claude.md.njk +1 -0
- package/templates/harness-adapters/claude-code/mcp.json.njk +1 -0
- package/templates/harness-adapters/claude-code/settings.json.njk +1 -0
- package/templates/harness-adapters/claude-code/skill-library-index.md.njk +13 -0
- package/templates/harness-adapters/claude-code/skill.md.njk +19 -0
- package/templates/harness-adapters/cline/hook.sh.njk +4 -0
- package/templates/harness-adapters/cline/mcp.json.njk +1 -0
- package/templates/harness-adapters/cline/rule.md.njk +1 -0
- package/templates/harness-adapters/codex/agents-md.md.njk +6 -0
- package/templates/harness-adapters/codex/agents-pointer.md.njk +16 -0
- package/templates/harness-adapters/codex/skill.md.njk +27 -0
- package/templates/harness-adapters/copilot/agents.md.njk +1 -0
- package/templates/harness-adapters/copilot/instructions.md.njk +1 -0
- package/templates/harness-adapters/copilot/scoped.md.njk +6 -0
- package/templates/harness-adapters/cursor/mcp.json.njk +1 -0
- package/templates/harness-adapters/cursor/rule.md.njk +6 -0
- package/templates/harness-adapters/kiro/hook.json.njk +1 -0
- package/templates/harness-adapters/kiro/mcp.json.njk +1 -0
- package/templates/harness-adapters/kiro/power-steering.md.njk +3 -0
- package/templates/harness-adapters/kiro/power.md.njk +12 -0
- package/templates/harness-adapters/kiro/steering.md.njk +16 -0
- package/templates/harness-adapters/qdeveloper/agent.md.njk +1 -0
- package/templates/harness-adapters/qdeveloper/mcp.json.njk +1 -0
- package/templates/harness-adapters/qdeveloper/rule.md.njk +1 -0
- package/templates/harness-adapters/windsurf/mcp.json.njk +1 -0
- package/templates/harness-adapters/windsurf/rule.md.njk +1 -0
- package/templates/harness-adapters/windsurf/workflow.md.njk +1 -0
- package/templates/knowledge/hooks.yaml.njk +4 -0
- package/templates/knowledge/knowledge.md.njk +53 -0
- package/templates/knowledge/mcp-servers.yaml.njk +2 -0
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rosetta Stone — Translation Engine
|
|
3
|
+
*
|
|
4
|
+
* Coordinates request guard, registry resolution, format detection, source
|
|
5
|
+
* translation, canonical parsing/validation, compatibility evaluation, target
|
|
6
|
+
* translation, and plan validation across inbound, outbound, and transcode modes.
|
|
7
|
+
*
|
|
8
|
+
* Derives success/partial/failure status and eligible/policy-required/withheld
|
|
9
|
+
* application states. Converts unexpected implementation failures to redacted
|
|
10
|
+
* RS_TRANSLATOR_INTERNAL diagnostics — no stack or source content enters output.
|
|
11
|
+
*
|
|
12
|
+
* CONSTRAINTS:
|
|
13
|
+
* - NO filesystem, process, clock, random, Git, or network imports
|
|
14
|
+
* - Pure module — never applies effects
|
|
15
|
+
*
|
|
16
|
+
* Requirements: 1.1, 1.2, 4.6, 4.7, 4.8, 8.1, 8.7, 12.4, 12.5
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
type AppliedDefault,
|
|
21
|
+
type AppliedNormalization,
|
|
22
|
+
type DegradationRecord,
|
|
23
|
+
type FormatContract,
|
|
24
|
+
type FormatIdentifier,
|
|
25
|
+
type KnowledgeArtifact,
|
|
26
|
+
KnowledgeArtifactSchema,
|
|
27
|
+
type TranslationDiagnostic,
|
|
28
|
+
type TranslationPlan,
|
|
29
|
+
type TranslationRequest,
|
|
30
|
+
type TranslationResult,
|
|
31
|
+
} from "../schemas";
|
|
32
|
+
|
|
33
|
+
import {
|
|
34
|
+
evaluateCompatibility,
|
|
35
|
+
identifyUsedCapabilities,
|
|
36
|
+
promoteInStrictMode,
|
|
37
|
+
resolveEffectiveProfile,
|
|
38
|
+
} from "./compatibility";
|
|
39
|
+
import type { DetectionRequest, DetectionResult } from "./detector";
|
|
40
|
+
import { detect } from "./detector";
|
|
41
|
+
import {
|
|
42
|
+
convertInternalError,
|
|
43
|
+
createDiagnostic,
|
|
44
|
+
getBlockingDiagnostics,
|
|
45
|
+
hasBlockingDiagnostics,
|
|
46
|
+
sortDiagnostics,
|
|
47
|
+
} from "./diagnostics";
|
|
48
|
+
import type { InspectionContext, InspectionReport } from "./inspection";
|
|
49
|
+
import { buildInspectionReport } from "./inspection";
|
|
50
|
+
import { validatePlan } from "./plan";
|
|
51
|
+
import type {
|
|
52
|
+
SourceTranslatorContext,
|
|
53
|
+
TargetTranslationOutput,
|
|
54
|
+
TargetTranslatorContext,
|
|
55
|
+
TranslationRegistrySnapshot,
|
|
56
|
+
} from "./registry";
|
|
57
|
+
import { guardRequest } from "./request-guard";
|
|
58
|
+
import { resolveVariant } from "./resolution";
|
|
59
|
+
import type { ImmutableTemplateBundle } from "./templates";
|
|
60
|
+
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
62
|
+
// RosettaStone Interface
|
|
63
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The public RosettaStone translation interface.
|
|
67
|
+
*/
|
|
68
|
+
export interface RosettaStone {
|
|
69
|
+
detect(request: DetectionRequest): DetectionResult;
|
|
70
|
+
translate(request: TranslationRequest): TranslationResult;
|
|
71
|
+
inspect(request: TranslationRequest): InspectionReport;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
75
|
+
// RosettaEngine Class
|
|
76
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The main Rosetta Stone translation engine.
|
|
80
|
+
*
|
|
81
|
+
* Coordinates all phases of translation without applying any effects.
|
|
82
|
+
* Returns diagnostics and plans; never writes, prompts, or performs I/O.
|
|
83
|
+
*/
|
|
84
|
+
export class RosettaEngine implements RosettaStone {
|
|
85
|
+
private readonly registry: TranslationRegistrySnapshot;
|
|
86
|
+
private readonly templates: ImmutableTemplateBundle;
|
|
87
|
+
|
|
88
|
+
constructor(
|
|
89
|
+
registry: TranslationRegistrySnapshot,
|
|
90
|
+
templates: ImmutableTemplateBundle,
|
|
91
|
+
) {
|
|
92
|
+
this.registry = registry;
|
|
93
|
+
this.templates = templates;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
97
|
+
// detect — format detection only
|
|
98
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
99
|
+
|
|
100
|
+
detect(request: DetectionRequest): DetectionResult {
|
|
101
|
+
try {
|
|
102
|
+
return detect(request);
|
|
103
|
+
} catch (error: unknown) {
|
|
104
|
+
const diagnostic = convertInternalError(error, "detection");
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
candidates: [],
|
|
108
|
+
diagnostics: [diagnostic],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
114
|
+
// translate — core translation pipeline
|
|
115
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
116
|
+
|
|
117
|
+
translate(request: TranslationRequest): TranslationResult {
|
|
118
|
+
const diagnostics: TranslationDiagnostic[] = [];
|
|
119
|
+
const defaults: AppliedDefault[] = [];
|
|
120
|
+
const normalizations: AppliedNormalization[] = [];
|
|
121
|
+
const degradations: DegradationRecord[] = [];
|
|
122
|
+
|
|
123
|
+
let plan: TranslationPlan | undefined;
|
|
124
|
+
let canonical: KnowledgeArtifact | undefined;
|
|
125
|
+
let sourceFormatContract: FormatContract | undefined;
|
|
126
|
+
let targetFormatContract: FormatContract | undefined;
|
|
127
|
+
let _detectionResult: DetectionResult | undefined;
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
// ─── Phase 1: Guard the request ───────────────────────────────
|
|
131
|
+
const guardResult = guardRequest(request);
|
|
132
|
+
if (!guardResult.ok) {
|
|
133
|
+
diagnostics.push(...guardResult.diagnostics);
|
|
134
|
+
return this.buildResult(
|
|
135
|
+
diagnostics,
|
|
136
|
+
defaults,
|
|
137
|
+
normalizations,
|
|
138
|
+
degradations,
|
|
139
|
+
plan,
|
|
140
|
+
canonical,
|
|
141
|
+
sourceFormatContract,
|
|
142
|
+
targetFormatContract,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
const guarded = guardResult.request;
|
|
146
|
+
|
|
147
|
+
// ─── Phase 2: Resolve format from registry ────────────────────
|
|
148
|
+
if (guarded.mode === "inbound" || guarded.mode === "transcode") {
|
|
149
|
+
const sourceResolution = this.resolveSourceFormat(guarded);
|
|
150
|
+
diagnostics.push(...sourceResolution.diagnostics);
|
|
151
|
+
if (sourceResolution.detection) {
|
|
152
|
+
_detectionResult = sourceResolution.detection;
|
|
153
|
+
}
|
|
154
|
+
if (!sourceResolution.contract) {
|
|
155
|
+
return this.buildResult(
|
|
156
|
+
diagnostics,
|
|
157
|
+
defaults,
|
|
158
|
+
normalizations,
|
|
159
|
+
degradations,
|
|
160
|
+
plan,
|
|
161
|
+
canonical,
|
|
162
|
+
sourceFormatContract,
|
|
163
|
+
targetFormatContract,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
sourceFormatContract = sourceResolution.contract;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (guarded.mode === "outbound" || guarded.mode === "transcode") {
|
|
170
|
+
const targetResolution = this.registry.resolve(
|
|
171
|
+
guarded.target.formatId,
|
|
172
|
+
"target",
|
|
173
|
+
);
|
|
174
|
+
if (!targetResolution.ok) {
|
|
175
|
+
diagnostics.push(...targetResolution.diagnostics);
|
|
176
|
+
return this.buildResult(
|
|
177
|
+
diagnostics,
|
|
178
|
+
defaults,
|
|
179
|
+
normalizations,
|
|
180
|
+
degradations,
|
|
181
|
+
plan,
|
|
182
|
+
canonical,
|
|
183
|
+
sourceFormatContract,
|
|
184
|
+
targetFormatContract,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
diagnostics.push(...targetResolution.diagnostics);
|
|
188
|
+
targetFormatContract = targetResolution.contract;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ─── Phase 3: Inbound — source translate + canonical validate ─
|
|
192
|
+
if (
|
|
193
|
+
(guarded.mode === "inbound" || guarded.mode === "transcode") &&
|
|
194
|
+
sourceFormatContract
|
|
195
|
+
) {
|
|
196
|
+
const sourceResult = this.runSourceTranslation(
|
|
197
|
+
guarded,
|
|
198
|
+
sourceFormatContract,
|
|
199
|
+
);
|
|
200
|
+
diagnostics.push(...sourceResult.diagnostics);
|
|
201
|
+
|
|
202
|
+
if (hasBlockingDiagnostics(sourceResult.diagnostics)) {
|
|
203
|
+
return this.buildResult(
|
|
204
|
+
diagnostics,
|
|
205
|
+
defaults,
|
|
206
|
+
normalizations,
|
|
207
|
+
degradations,
|
|
208
|
+
plan,
|
|
209
|
+
canonical,
|
|
210
|
+
sourceFormatContract,
|
|
211
|
+
targetFormatContract,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Parse and validate canonical
|
|
216
|
+
if (sourceResult.candidate) {
|
|
217
|
+
const canonicalResult = this.validateCanonical(
|
|
218
|
+
sourceResult.candidate,
|
|
219
|
+
);
|
|
220
|
+
diagnostics.push(...canonicalResult.diagnostics);
|
|
221
|
+
|
|
222
|
+
if (hasBlockingDiagnostics(canonicalResult.diagnostics)) {
|
|
223
|
+
return this.buildResult(
|
|
224
|
+
diagnostics,
|
|
225
|
+
defaults,
|
|
226
|
+
normalizations,
|
|
227
|
+
degradations,
|
|
228
|
+
plan,
|
|
229
|
+
canonical,
|
|
230
|
+
sourceFormatContract,
|
|
231
|
+
targetFormatContract,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
canonical = canonicalResult.artifact;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// For outbound, the canonical artifact comes from the request
|
|
239
|
+
if (guarded.mode === "outbound") {
|
|
240
|
+
canonical = guarded.artifact as KnowledgeArtifact;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ─── Phase 4: Outbound — compatibility + target translation ────
|
|
244
|
+
if (
|
|
245
|
+
(guarded.mode === "outbound" || guarded.mode === "transcode") &&
|
|
246
|
+
targetFormatContract &&
|
|
247
|
+
canonical
|
|
248
|
+
) {
|
|
249
|
+
// Evaluate compatibility
|
|
250
|
+
const compatResult = this.runCompatibility(
|
|
251
|
+
canonical,
|
|
252
|
+
targetFormatContract,
|
|
253
|
+
guarded.strict,
|
|
254
|
+
);
|
|
255
|
+
diagnostics.push(...compatResult.diagnostics);
|
|
256
|
+
degradations.push(...compatResult.degradations);
|
|
257
|
+
|
|
258
|
+
if (hasBlockingDiagnostics(compatResult.diagnostics)) {
|
|
259
|
+
return this.buildResult(
|
|
260
|
+
diagnostics,
|
|
261
|
+
defaults,
|
|
262
|
+
normalizations,
|
|
263
|
+
degradations,
|
|
264
|
+
plan,
|
|
265
|
+
canonical,
|
|
266
|
+
sourceFormatContract,
|
|
267
|
+
targetFormatContract,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Run target translation
|
|
272
|
+
const targetResult = this.runTargetTranslation(
|
|
273
|
+
canonical,
|
|
274
|
+
guarded,
|
|
275
|
+
targetFormatContract,
|
|
276
|
+
);
|
|
277
|
+
diagnostics.push(...targetResult.diagnostics);
|
|
278
|
+
|
|
279
|
+
if (hasBlockingDiagnostics(targetResult.diagnostics)) {
|
|
280
|
+
return this.buildResult(
|
|
281
|
+
diagnostics,
|
|
282
|
+
defaults,
|
|
283
|
+
normalizations,
|
|
284
|
+
degradations,
|
|
285
|
+
plan,
|
|
286
|
+
canonical,
|
|
287
|
+
sourceFormatContract,
|
|
288
|
+
targetFormatContract,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
plan = targetResult.plan;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ─── Phase 5: Validate the plan ───────────────────────────────
|
|
296
|
+
if (plan) {
|
|
297
|
+
const planResult = validatePlan(plan);
|
|
298
|
+
diagnostics.push(...planResult.diagnostics);
|
|
299
|
+
|
|
300
|
+
if (!planResult.valid) {
|
|
301
|
+
plan = undefined;
|
|
302
|
+
} else if (planResult.plan) {
|
|
303
|
+
plan = planResult.plan;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ─── Phase 6: Determine application state ─────────────────────
|
|
308
|
+
return this.buildResult(
|
|
309
|
+
diagnostics,
|
|
310
|
+
defaults,
|
|
311
|
+
normalizations,
|
|
312
|
+
degradations,
|
|
313
|
+
plan,
|
|
314
|
+
canonical,
|
|
315
|
+
sourceFormatContract,
|
|
316
|
+
targetFormatContract,
|
|
317
|
+
);
|
|
318
|
+
} catch (error: unknown) {
|
|
319
|
+
// Unexpected implementation failure — convert to redacted diagnostic
|
|
320
|
+
diagnostics.push(convertInternalError(error, "request"));
|
|
321
|
+
return this.buildResult(
|
|
322
|
+
diagnostics,
|
|
323
|
+
defaults,
|
|
324
|
+
normalizations,
|
|
325
|
+
degradations,
|
|
326
|
+
plan,
|
|
327
|
+
canonical,
|
|
328
|
+
sourceFormatContract,
|
|
329
|
+
targetFormatContract,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
335
|
+
// inspect — builds inspection report from translation results
|
|
336
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
337
|
+
|
|
338
|
+
inspect(request: TranslationRequest): InspectionReport {
|
|
339
|
+
try {
|
|
340
|
+
const result = this.translate(request);
|
|
341
|
+
const context = this.buildInspectionContext(request, result);
|
|
342
|
+
return buildInspectionReport(context);
|
|
343
|
+
} catch (error: unknown) {
|
|
344
|
+
// Even inspection failures are redacted
|
|
345
|
+
const diagnostic = convertInternalError(error, "request");
|
|
346
|
+
const fallbackContext: InspectionContext = {
|
|
347
|
+
request: {
|
|
348
|
+
direction: request.mode === "outbound" ? "target" : "source",
|
|
349
|
+
strict: request.strict,
|
|
350
|
+
dryRun: true,
|
|
351
|
+
},
|
|
352
|
+
diagnostics: [diagnostic],
|
|
353
|
+
options: { effective: {}, origins: {}, defaults: {} },
|
|
354
|
+
previewAvailable: false,
|
|
355
|
+
previewUnavailableReason: "Internal error during inspection",
|
|
356
|
+
format: {
|
|
357
|
+
formatId: "unknown",
|
|
358
|
+
contractVersion: "1.0",
|
|
359
|
+
lifecycle: "active",
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
return buildInspectionReport(fallbackContext);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
367
|
+
// Private Helpers
|
|
368
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Resolve source format: explicit or auto-detect.
|
|
372
|
+
*/
|
|
373
|
+
private resolveSourceFormat(request: TranslationRequest): {
|
|
374
|
+
contract: FormatContract | undefined;
|
|
375
|
+
diagnostics: TranslationDiagnostic[];
|
|
376
|
+
detection?: DetectionResult;
|
|
377
|
+
} {
|
|
378
|
+
if (request.mode !== "inbound" && request.mode !== "transcode") {
|
|
379
|
+
return { contract: undefined, diagnostics: [] };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const source = request.source;
|
|
383
|
+
const explicitId = source.formatId as FormatIdentifier | undefined;
|
|
384
|
+
|
|
385
|
+
const detectionRequest: DetectionRequest = {
|
|
386
|
+
documents: request.sourceDocuments,
|
|
387
|
+
registrySnapshot: this.registry,
|
|
388
|
+
explicitFormatId: explicitId,
|
|
389
|
+
direction: "source",
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const detectionResult = detect(detectionRequest);
|
|
393
|
+
|
|
394
|
+
if (!detectionResult.ok) {
|
|
395
|
+
return {
|
|
396
|
+
contract: undefined,
|
|
397
|
+
diagnostics: detectionResult.diagnostics,
|
|
398
|
+
detection: detectionResult,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Resolve the selected format from the registry
|
|
403
|
+
const resolution = this.registry.resolve(
|
|
404
|
+
detectionResult.selected,
|
|
405
|
+
"source",
|
|
406
|
+
);
|
|
407
|
+
if (!resolution.ok) {
|
|
408
|
+
return {
|
|
409
|
+
contract: undefined,
|
|
410
|
+
diagnostics: [
|
|
411
|
+
...detectionResult.diagnostics,
|
|
412
|
+
...resolution.diagnostics,
|
|
413
|
+
],
|
|
414
|
+
detection: detectionResult,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
contract: resolution.contract,
|
|
420
|
+
diagnostics: [...detectionResult.diagnostics, ...resolution.diagnostics],
|
|
421
|
+
detection: detectionResult,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Run source translation phase — delegates to the registered translator.
|
|
427
|
+
*/
|
|
428
|
+
private runSourceTranslation(
|
|
429
|
+
request: TranslationRequest,
|
|
430
|
+
contract: FormatContract,
|
|
431
|
+
): {
|
|
432
|
+
candidate?: Record<string, unknown>;
|
|
433
|
+
diagnostics: TranslationDiagnostic[];
|
|
434
|
+
} {
|
|
435
|
+
if (request.mode !== "inbound" && request.mode !== "transcode") {
|
|
436
|
+
return { diagnostics: [] };
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const translator = this.registry.getSourceTranslator(contract.id);
|
|
440
|
+
if (!translator) {
|
|
441
|
+
return {
|
|
442
|
+
diagnostics: [
|
|
443
|
+
createDiagnostic("RS_TRANSLATOR_INTERNAL", {
|
|
444
|
+
formatId: contract.id,
|
|
445
|
+
message: `No source translator registered for format "${contract.id}".`,
|
|
446
|
+
}),
|
|
447
|
+
],
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const context: SourceTranslatorContext = {
|
|
452
|
+
format: contract,
|
|
453
|
+
canonicalSchemaVersion: request.canonicalSchemaVersion,
|
|
454
|
+
options: request.source.options ?? {},
|
|
455
|
+
callerContext: request.callerContext,
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
const output = translator(request.sourceDocuments, context);
|
|
460
|
+
return {
|
|
461
|
+
candidate: output.candidate,
|
|
462
|
+
diagnostics: [...output.diagnostics],
|
|
463
|
+
};
|
|
464
|
+
} catch (error: unknown) {
|
|
465
|
+
return {
|
|
466
|
+
diagnostics: [convertInternalError(error, "source-translation")],
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Validate a candidate against the canonical schema using the canonical parser.
|
|
473
|
+
*/
|
|
474
|
+
private validateCanonical(candidate: Record<string, unknown>): {
|
|
475
|
+
artifact: KnowledgeArtifact | undefined;
|
|
476
|
+
diagnostics: TranslationDiagnostic[];
|
|
477
|
+
} {
|
|
478
|
+
try {
|
|
479
|
+
const result = KnowledgeArtifactSchema.safeParse(candidate);
|
|
480
|
+
if (!result.success) {
|
|
481
|
+
const artifactName =
|
|
482
|
+
typeof candidate.name === "string" && candidate.name.length > 0
|
|
483
|
+
? candidate.name
|
|
484
|
+
: "unknown";
|
|
485
|
+
const diagnostics: TranslationDiagnostic[] = result.error.issues.map(
|
|
486
|
+
(issue) =>
|
|
487
|
+
createDiagnostic("RS_CANONICAL_INVALID", {
|
|
488
|
+
message: `Canonical validation failed at "${issue.path.join(".")}": ${issue.message}`,
|
|
489
|
+
canonical: {
|
|
490
|
+
artifactName,
|
|
491
|
+
fieldPath: issue.path.join(".") || "root",
|
|
492
|
+
},
|
|
493
|
+
}),
|
|
494
|
+
);
|
|
495
|
+
return { artifact: undefined, diagnostics };
|
|
496
|
+
}
|
|
497
|
+
return { artifact: result.data as KnowledgeArtifact, diagnostics: [] };
|
|
498
|
+
} catch (error: unknown) {
|
|
499
|
+
return {
|
|
500
|
+
artifact: undefined,
|
|
501
|
+
diagnostics: [convertInternalError(error, "canonical-validation")],
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Run compatibility evaluation against the target format.
|
|
508
|
+
*/
|
|
509
|
+
private runCompatibility(
|
|
510
|
+
artifact: KnowledgeArtifact,
|
|
511
|
+
contract: FormatContract,
|
|
512
|
+
strict: boolean,
|
|
513
|
+
): {
|
|
514
|
+
diagnostics: TranslationDiagnostic[];
|
|
515
|
+
degradations: DegradationRecord[];
|
|
516
|
+
} {
|
|
517
|
+
try {
|
|
518
|
+
const profile = resolveEffectiveProfile(contract);
|
|
519
|
+
const usedCapabilities = identifyUsedCapabilities(artifact);
|
|
520
|
+
let evaluation = evaluateCompatibility(
|
|
521
|
+
profile,
|
|
522
|
+
usedCapabilities,
|
|
523
|
+
artifact,
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
if (strict) {
|
|
527
|
+
evaluation = promoteInStrictMode(evaluation);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
diagnostics: [...evaluation.diagnostics],
|
|
532
|
+
degradations: [...evaluation.degradations],
|
|
533
|
+
};
|
|
534
|
+
} catch (error: unknown) {
|
|
535
|
+
return {
|
|
536
|
+
diagnostics: [convertInternalError(error, "compatibility")],
|
|
537
|
+
degradations: [],
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Run target translation — delegates to the registered translator.
|
|
544
|
+
*/
|
|
545
|
+
private runTargetTranslation(
|
|
546
|
+
artifact: KnowledgeArtifact,
|
|
547
|
+
request: TranslationRequest,
|
|
548
|
+
contract: FormatContract,
|
|
549
|
+
): { plan?: TranslationPlan; diagnostics: TranslationDiagnostic[] } {
|
|
550
|
+
if (request.mode !== "outbound" && request.mode !== "transcode") {
|
|
551
|
+
return { diagnostics: [] };
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const translator = this.registry.getTargetTranslator(contract.id);
|
|
555
|
+
if (!translator) {
|
|
556
|
+
return {
|
|
557
|
+
diagnostics: [
|
|
558
|
+
createDiagnostic("RS_TRANSLATOR_INTERNAL", {
|
|
559
|
+
formatId: contract.id,
|
|
560
|
+
message: `No target translator registered for format "${contract.id}".`,
|
|
561
|
+
}),
|
|
562
|
+
],
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Resolve variant
|
|
567
|
+
const variantResolution = resolveVariant(contract, {
|
|
568
|
+
explicitVariant: request.target.variant,
|
|
569
|
+
contractDefault: contract.defaultVariant,
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const context: TargetTranslatorContext = {
|
|
573
|
+
format: contract,
|
|
574
|
+
variant: variantResolution.variant ?? contract.defaultVariant ?? "",
|
|
575
|
+
canonicalSchemaVersion: request.canonicalSchemaVersion,
|
|
576
|
+
options: request.target.options ?? {},
|
|
577
|
+
callerContext: request.callerContext,
|
|
578
|
+
templates: this.templates,
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
try {
|
|
582
|
+
const output: TargetTranslationOutput = translator(
|
|
583
|
+
artifact as unknown as Record<string, unknown>,
|
|
584
|
+
context,
|
|
585
|
+
);
|
|
586
|
+
return {
|
|
587
|
+
plan: output.plan as TranslationPlan | undefined,
|
|
588
|
+
diagnostics: [...output.diagnostics],
|
|
589
|
+
};
|
|
590
|
+
} catch (error: unknown) {
|
|
591
|
+
return {
|
|
592
|
+
diagnostics: [convertInternalError(error, "target-translation")],
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Build the final TranslationResult with status and application state.
|
|
599
|
+
*/
|
|
600
|
+
private buildResult(
|
|
601
|
+
diagnostics: TranslationDiagnostic[],
|
|
602
|
+
defaults: AppliedDefault[],
|
|
603
|
+
normalizations: AppliedNormalization[],
|
|
604
|
+
degradations: DegradationRecord[],
|
|
605
|
+
plan: TranslationPlan | undefined,
|
|
606
|
+
canonical: KnowledgeArtifact | undefined,
|
|
607
|
+
sourceFormat: FormatContract | undefined,
|
|
608
|
+
targetFormat: FormatContract | undefined,
|
|
609
|
+
): TranslationResult {
|
|
610
|
+
const sorted = sortDiagnostics(diagnostics);
|
|
611
|
+
const blocking = getBlockingDiagnostics(sorted);
|
|
612
|
+
const hasBlocking = blocking.length > 0;
|
|
613
|
+
|
|
614
|
+
// Derive status
|
|
615
|
+
const status = hasBlocking
|
|
616
|
+
? "failure"
|
|
617
|
+
: sorted.some((d) => d.severity === "warning")
|
|
618
|
+
? "partial"
|
|
619
|
+
: "success";
|
|
620
|
+
|
|
621
|
+
// Derive application state
|
|
622
|
+
let applicationState: "eligible" | "policy-required" | "withheld";
|
|
623
|
+
if (hasBlocking || !plan) {
|
|
624
|
+
applicationState = "withheld";
|
|
625
|
+
} else if (sorted.some((d) => d.severity === "warning")) {
|
|
626
|
+
applicationState = "policy-required";
|
|
627
|
+
} else {
|
|
628
|
+
applicationState = "eligible";
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Update plan's applicationState if present
|
|
632
|
+
if (plan) {
|
|
633
|
+
plan = { ...plan, applicationState };
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return {
|
|
637
|
+
schemaVersion: "1.0",
|
|
638
|
+
status,
|
|
639
|
+
registryVersion: this.registry.version,
|
|
640
|
+
...(sourceFormat && {
|
|
641
|
+
sourceFormat: {
|
|
642
|
+
formatId: sourceFormat.id,
|
|
643
|
+
contractVersion: sourceFormat.contractVersion,
|
|
644
|
+
lifecycle: sourceFormat.lifecycle.status,
|
|
645
|
+
},
|
|
646
|
+
}),
|
|
647
|
+
...(targetFormat && {
|
|
648
|
+
targetFormat: {
|
|
649
|
+
formatId: targetFormat.id,
|
|
650
|
+
contractVersion: targetFormat.contractVersion,
|
|
651
|
+
lifecycle: targetFormat.lifecycle.status,
|
|
652
|
+
},
|
|
653
|
+
}),
|
|
654
|
+
...(canonical && { canonical }),
|
|
655
|
+
...(plan && { plan }),
|
|
656
|
+
diagnostics: sorted,
|
|
657
|
+
defaults,
|
|
658
|
+
normalizations,
|
|
659
|
+
degradations,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Build InspectionContext from a request and its translation result.
|
|
665
|
+
*/
|
|
666
|
+
private buildInspectionContext(
|
|
667
|
+
request: TranslationRequest,
|
|
668
|
+
result: TranslationResult,
|
|
669
|
+
): InspectionContext {
|
|
670
|
+
const direction = request.mode === "outbound" ? "target" : "source";
|
|
671
|
+
|
|
672
|
+
return {
|
|
673
|
+
request: {
|
|
674
|
+
direction,
|
|
675
|
+
sourceFormat: result.sourceFormat?.formatId,
|
|
676
|
+
targetFormat: result.targetFormat?.formatId,
|
|
677
|
+
strict: request.strict,
|
|
678
|
+
dryRun: true,
|
|
679
|
+
},
|
|
680
|
+
format: {
|
|
681
|
+
formatId:
|
|
682
|
+
result.targetFormat?.formatId ??
|
|
683
|
+
result.sourceFormat?.formatId ??
|
|
684
|
+
"unknown",
|
|
685
|
+
contractVersion:
|
|
686
|
+
result.targetFormat?.contractVersion ??
|
|
687
|
+
result.sourceFormat?.contractVersion ??
|
|
688
|
+
"1.0",
|
|
689
|
+
lifecycle:
|
|
690
|
+
result.targetFormat?.lifecycle ??
|
|
691
|
+
result.sourceFormat?.lifecycle ??
|
|
692
|
+
"active",
|
|
693
|
+
},
|
|
694
|
+
artifact: result.canonical
|
|
695
|
+
? {
|
|
696
|
+
schemaVersion: "1.0",
|
|
697
|
+
name: result.canonical.name,
|
|
698
|
+
type: result.canonical.frontmatter.type,
|
|
699
|
+
harnesses: result.canonical.frontmatter.harnesses,
|
|
700
|
+
hookCount: result.canonical.hooks.length,
|
|
701
|
+
mcpServerCount: result.canonical.mcpServers.length,
|
|
702
|
+
workflowCount: result.canonical.workflows.length,
|
|
703
|
+
bodyOverrideCount: Object.keys(result.canonical.bodyOverrides)
|
|
704
|
+
.length,
|
|
705
|
+
}
|
|
706
|
+
: undefined,
|
|
707
|
+
options: { effective: {}, origins: {}, defaults: {} },
|
|
708
|
+
compatibility:
|
|
709
|
+
result.degradations.length > 0
|
|
710
|
+
? {
|
|
711
|
+
fullCount: 0,
|
|
712
|
+
partialCount: result.degradations.filter(
|
|
713
|
+
(d) => d.action !== "omit",
|
|
714
|
+
).length,
|
|
715
|
+
noneCount: result.degradations.filter((d) => d.action === "omit")
|
|
716
|
+
.length,
|
|
717
|
+
degradations: result.degradations,
|
|
718
|
+
strictPromoted: request.strict,
|
|
719
|
+
}
|
|
720
|
+
: undefined,
|
|
721
|
+
diagnostics: result.diagnostics,
|
|
722
|
+
plan: result.plan,
|
|
723
|
+
previewAvailable: result.plan !== undefined,
|
|
724
|
+
previewUnavailableReason: result.plan ? undefined : "No plan produced",
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
730
|
+
// Factory Function
|
|
731
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Create a new RosettaEngine instance.
|
|
735
|
+
*
|
|
736
|
+
* @param registry - Immutable registry snapshot with registered format contracts
|
|
737
|
+
* @param templates - Immutable template bundle for target translations
|
|
738
|
+
*/
|
|
739
|
+
export function createEngine(
|
|
740
|
+
registry: TranslationRegistrySnapshot,
|
|
741
|
+
templates: ImmutableTemplateBundle,
|
|
742
|
+
): RosettaEngine {
|
|
743
|
+
return new RosettaEngine(registry, templates);
|
|
744
|
+
}
|