@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,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rosetta Stone — Pure Contracts and Deterministic Normalization Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module re-exports schema-derived interfaces from `../schemas.ts` and provides
|
|
5
|
+
* deterministic normalization utilities for the Rosetta Stone translation engine.
|
|
6
|
+
*
|
|
7
|
+
* CONSTRAINTS:
|
|
8
|
+
* - NO filesystem, process, clock, random, Git, or network imports
|
|
9
|
+
* - ALL public data shapes remain owned by `src/schemas.ts` — only re-export, never redefine
|
|
10
|
+
* - Pure functions only
|
|
11
|
+
*
|
|
12
|
+
* Requirements: 5.6, 12.1, 12.2, 12.3, 12.6, 12.7
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16
|
+
// Re-export schema-derived types (owned by ../schemas.ts)
|
|
17
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
|
|
19
|
+
export type {
|
|
20
|
+
AppliedDefault,
|
|
21
|
+
AppliedNormalization,
|
|
22
|
+
CanonicalCapability,
|
|
23
|
+
CanonicalDiagnosticLocation,
|
|
24
|
+
CanonicalOutputOptions,
|
|
25
|
+
CanonicalSchemaVersion,
|
|
26
|
+
CanonicalVersionRange,
|
|
27
|
+
ContractVersion,
|
|
28
|
+
DegradationDetail,
|
|
29
|
+
DegradationRecord,
|
|
30
|
+
DetectionCandidate,
|
|
31
|
+
DetectionContract,
|
|
32
|
+
DetectionEvidence,
|
|
33
|
+
DetectionRule,
|
|
34
|
+
DetectionRuleKind,
|
|
35
|
+
DiagnosticsEnvelope,
|
|
36
|
+
Direction,
|
|
37
|
+
FormatContract,
|
|
38
|
+
FormatIdentifier,
|
|
39
|
+
FormatOptionDefinition,
|
|
40
|
+
FormatSecurityPolicy,
|
|
41
|
+
FormatSelection,
|
|
42
|
+
InboundTranslationRequest,
|
|
43
|
+
InspectionReportEnvelope,
|
|
44
|
+
JsonValue,
|
|
45
|
+
LifecycleMetadata,
|
|
46
|
+
LifecycleStatus,
|
|
47
|
+
NormalizationRule,
|
|
48
|
+
NormalizedRelativePath,
|
|
49
|
+
OutboundTranslationRequest,
|
|
50
|
+
OutputFile,
|
|
51
|
+
PathConvention,
|
|
52
|
+
PlanOperation,
|
|
53
|
+
ProvenanceRecord,
|
|
54
|
+
RegistryFailure,
|
|
55
|
+
ResolvedFormatSummary,
|
|
56
|
+
RosettaCompatibilityEntry,
|
|
57
|
+
RosettaCompatibilityProfile,
|
|
58
|
+
RosettaSeverity,
|
|
59
|
+
SchemaReference,
|
|
60
|
+
SourceDiagnosticLocation,
|
|
61
|
+
SourceDocument,
|
|
62
|
+
SourceLocation,
|
|
63
|
+
TranscodeTranslationRequest,
|
|
64
|
+
TranslationDiagnostic,
|
|
65
|
+
TranslationPhase,
|
|
66
|
+
TranslationPlan,
|
|
67
|
+
TranslationProfile,
|
|
68
|
+
TranslationRequest,
|
|
69
|
+
TranslationResult,
|
|
70
|
+
VariantContract,
|
|
71
|
+
} from "../schemas";
|
|
72
|
+
|
|
73
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
74
|
+
// Translation Phase Ordering
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Canonical ordering of translation phases. Used for diagnostic sorting.
|
|
79
|
+
* Matches the enum order in TranslationPhaseSchema.
|
|
80
|
+
*/
|
|
81
|
+
export const TRANSLATION_PHASE_ORDER: readonly string[] = [
|
|
82
|
+
"request",
|
|
83
|
+
"registry",
|
|
84
|
+
"detection",
|
|
85
|
+
"source-validation",
|
|
86
|
+
"source-translation",
|
|
87
|
+
"canonical-validation",
|
|
88
|
+
"compatibility",
|
|
89
|
+
"target-translation",
|
|
90
|
+
"plan-validation",
|
|
91
|
+
"redaction",
|
|
92
|
+
] as const;
|
|
93
|
+
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
95
|
+
// Immutable Context Type Helpers
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
import type { JsonValue } from "../schemas";
|
|
99
|
+
|
|
100
|
+
/** Immutable record type for readonly translation contexts */
|
|
101
|
+
export type ImmutableRecord<K extends string, V> = Readonly<Record<K, V>>;
|
|
102
|
+
|
|
103
|
+
/** Immutable context for translation operations */
|
|
104
|
+
export type ImmutableContext = Readonly<Record<string, JsonValue>>;
|
|
105
|
+
|
|
106
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
107
|
+
// Code-Point Ordering Comparator
|
|
108
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Compare two strings by Unicode code points (not locale).
|
|
112
|
+
* Uses simple char-by-char comparison with code point values.
|
|
113
|
+
*
|
|
114
|
+
* This ensures deterministic ordering independent of locale settings.
|
|
115
|
+
*/
|
|
116
|
+
export function codePointCompare(a: string, b: string): number {
|
|
117
|
+
const minLen = Math.min(a.length, b.length);
|
|
118
|
+
for (let i = 0; i < minLen; i++) {
|
|
119
|
+
const aCode = a.codePointAt(i) as number;
|
|
120
|
+
const bCode = b.codePointAt(i) as number;
|
|
121
|
+
if (aCode !== bCode) {
|
|
122
|
+
return aCode - bCode;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return a.length - b.length;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
129
|
+
// Stable JSON Serialization
|
|
130
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Recursively sort object keys by code-point order and serialize to JSON
|
|
134
|
+
* with 2-space indentation. Produces deterministic output regardless of
|
|
135
|
+
* object key insertion order.
|
|
136
|
+
*/
|
|
137
|
+
export function stableJsonStringify(value: unknown): string {
|
|
138
|
+
return JSON.stringify(sortKeysDeep(value), null, 2);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Recursively sort all object keys by code-point order.
|
|
143
|
+
* Arrays are preserved as-is (order is semantic).
|
|
144
|
+
*/
|
|
145
|
+
function sortKeysDeep(value: unknown): unknown {
|
|
146
|
+
if (value === null || value === undefined) {
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
return value.map(sortKeysDeep);
|
|
151
|
+
}
|
|
152
|
+
if (typeof value === "object") {
|
|
153
|
+
const sorted: Record<string, unknown> = {};
|
|
154
|
+
const keys = Object.keys(value as Record<string, unknown>).sort(
|
|
155
|
+
codePointCompare,
|
|
156
|
+
);
|
|
157
|
+
for (const key of keys) {
|
|
158
|
+
sorted[key] = sortKeysDeep((value as Record<string, unknown>)[key]);
|
|
159
|
+
}
|
|
160
|
+
return sorted;
|
|
161
|
+
}
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
166
|
+
// Stable YAML Key Ordering
|
|
167
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Sort keys by a priority table first (preserving priority order),
|
|
171
|
+
* then remaining keys by code-point order.
|
|
172
|
+
*
|
|
173
|
+
* @param keys - The keys to sort
|
|
174
|
+
* @param priorityOrder - Optional ordered list of priority keys
|
|
175
|
+
* @returns Sorted keys array
|
|
176
|
+
*/
|
|
177
|
+
export function yamlKeyOrder(
|
|
178
|
+
keys: string[],
|
|
179
|
+
priorityOrder?: string[],
|
|
180
|
+
): string[] {
|
|
181
|
+
if (!priorityOrder || priorityOrder.length === 0) {
|
|
182
|
+
return [...keys].sort(codePointCompare);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const prioritySet = new Set(priorityOrder);
|
|
186
|
+
const priorityKeys: string[] = [];
|
|
187
|
+
const remainingKeys: string[] = [];
|
|
188
|
+
|
|
189
|
+
for (const key of keys) {
|
|
190
|
+
if (prioritySet.has(key)) {
|
|
191
|
+
priorityKeys.push(key);
|
|
192
|
+
} else {
|
|
193
|
+
remainingKeys.push(key);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Sort priority keys by their position in the priority table
|
|
198
|
+
priorityKeys.sort(
|
|
199
|
+
(a, b) => priorityOrder.indexOf(a) - priorityOrder.indexOf(b),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Sort remaining keys by code-point order
|
|
203
|
+
remainingKeys.sort(codePointCompare);
|
|
204
|
+
|
|
205
|
+
return [...priorityKeys, ...remainingKeys];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
209
|
+
// Canonical Comparison Normalization
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Deep-clone and normalize a value for canonical comparison.
|
|
214
|
+
* Recursively sorts object keys by code-point order.
|
|
215
|
+
* Arrays are preserved in their original order (semantic ordering).
|
|
216
|
+
*
|
|
217
|
+
* Used to compare two values for semantic equivalence regardless of
|
|
218
|
+
* object key insertion order.
|
|
219
|
+
*/
|
|
220
|
+
export function normalizeForComparison(value: unknown): unknown {
|
|
221
|
+
return sortKeysDeep(structuredClone(value));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
225
|
+
// Deep Freeze Utility
|
|
226
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Recursively Object.freeze all nested objects and arrays.
|
|
230
|
+
* Returns the same reference, now deeply frozen.
|
|
231
|
+
*/
|
|
232
|
+
export function deepFreeze<T>(obj: T): Readonly<T> {
|
|
233
|
+
if (obj === null || obj === undefined || typeof obj !== "object") {
|
|
234
|
+
return obj;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Object.freeze(obj);
|
|
238
|
+
|
|
239
|
+
const entries = Object.getOwnPropertyNames(obj);
|
|
240
|
+
for (const key of entries) {
|
|
241
|
+
const value = (obj as Record<string, unknown>)[key];
|
|
242
|
+
if (
|
|
243
|
+
value !== null &&
|
|
244
|
+
value !== undefined &&
|
|
245
|
+
typeof value === "object" &&
|
|
246
|
+
!Object.isFrozen(value)
|
|
247
|
+
) {
|
|
248
|
+
deepFreeze(value);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return obj;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
256
|
+
// Diagnostic Sorting Comparator
|
|
257
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
258
|
+
|
|
259
|
+
import type { TranslationDiagnostic } from "../schemas";
|
|
260
|
+
|
|
261
|
+
/** Severity rank: error = 0, warning = 1, info = 2 */
|
|
262
|
+
const SEVERITY_RANK: Record<string, number> = {
|
|
263
|
+
error: 0,
|
|
264
|
+
warning: 1,
|
|
265
|
+
info: 2,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Compare two translation diagnostics for deterministic sorting.
|
|
270
|
+
*
|
|
271
|
+
* Sort order:
|
|
272
|
+
* 1. Severity (error > warning > info)
|
|
273
|
+
* 2. Phase order (per TRANSLATION_PHASE_ORDER)
|
|
274
|
+
* 3. Path (source location path, code-point order)
|
|
275
|
+
* 4. Location (line, then column)
|
|
276
|
+
* 5. Code (diagnostic code, code-point order)
|
|
277
|
+
* 6. Format identifier (code-point order)
|
|
278
|
+
*/
|
|
279
|
+
export function compareDiagnostics(
|
|
280
|
+
a: TranslationDiagnostic,
|
|
281
|
+
b: TranslationDiagnostic,
|
|
282
|
+
): number {
|
|
283
|
+
// 1. Severity
|
|
284
|
+
const sevA = SEVERITY_RANK[a.severity] ?? 3;
|
|
285
|
+
const sevB = SEVERITY_RANK[b.severity] ?? 3;
|
|
286
|
+
if (sevA !== sevB) return sevA - sevB;
|
|
287
|
+
|
|
288
|
+
// 2. Phase order
|
|
289
|
+
const phaseA = TRANSLATION_PHASE_ORDER.indexOf(a.phase);
|
|
290
|
+
const phaseB = TRANSLATION_PHASE_ORDER.indexOf(b.phase);
|
|
291
|
+
if (phaseA !== phaseB) return phaseA - phaseB;
|
|
292
|
+
|
|
293
|
+
// 3. Path (from source location)
|
|
294
|
+
const pathA = a.source?.path ?? "";
|
|
295
|
+
const pathB = b.source?.path ?? "";
|
|
296
|
+
const pathCmp = codePointCompare(pathA, pathB);
|
|
297
|
+
if (pathCmp !== 0) return pathCmp;
|
|
298
|
+
|
|
299
|
+
// 4. Location (line, then column)
|
|
300
|
+
const lineA = a.source?.line ?? 0;
|
|
301
|
+
const lineB = b.source?.line ?? 0;
|
|
302
|
+
if (lineA !== lineB) return lineA - lineB;
|
|
303
|
+
const colA = a.source?.column ?? 0;
|
|
304
|
+
const colB = b.source?.column ?? 0;
|
|
305
|
+
if (colA !== colB) return colA - colB;
|
|
306
|
+
|
|
307
|
+
// 5. Code
|
|
308
|
+
const codeCmp = codePointCompare(a.code, b.code);
|
|
309
|
+
if (codeCmp !== 0) return codeCmp;
|
|
310
|
+
|
|
311
|
+
// 6. Format identifier
|
|
312
|
+
const fmtA = a.formatId ?? "";
|
|
313
|
+
const fmtB = b.formatId ?? "";
|
|
314
|
+
return codePointCompare(fmtA, fmtB);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
318
|
+
// Plan File Sorting Comparator
|
|
319
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Compare plan files by normalized relative path using code-point ordering.
|
|
323
|
+
*/
|
|
324
|
+
export function comparePlanFiles(
|
|
325
|
+
a: { relativePath: string },
|
|
326
|
+
b: { relativePath: string },
|
|
327
|
+
): number {
|
|
328
|
+
return codePointCompare(a.relativePath, b.relativePath);
|
|
329
|
+
}
|