@shapeshift-labs/frontier-lang-compiler 0.2.57 → 0.2.58

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/README.md CHANGED
@@ -455,15 +455,20 @@ console.log(rustCandidate.sourceMap.mappings[0]?.semanticSymbolId); // generated
455
455
 
456
456
  `compileNativeSource` returns the import result, projection, target loss matrix cell, combined losses, readiness, evidence, output hash, and generated-output source maps. Same-language preserved output uses exact source mappings when the hash matches; generated stubs use declaration-level spans; adapter output uses adapter-supplied maps when present and otherwise gets an estimated fallback. Admission queues should treat `ok` as "code was emitted", not as merge approval; `readiness`, `targetCoverage`, and source-map precision carry the merge signal.
457
457
 
458
- Native projections and compile results also carry a `frontier.lang.nativeRoundtripEvidence` record under `evidence[].metadata.roundtripEvidence` and `metadata.roundtripEvidence`. That payload records import readiness/loss counts, universal AST validation and source-map precision, projection mode/hash verification, target adapter identity, target coverage, output source-map precision, and blocking/review loss ids in one coordinator-sortable JSON shape:
458
+ Native projections and compile results also carry a `frontier.lang.nativeRoundtripEvidence` record under `evidence[].metadata.roundtripEvidence` and `metadata.roundtripEvidence`. That payload records import readiness/loss counts, universal AST validation and source-map precision, projection mode/hash verification, target adapter identity, target coverage, output source-map precision, blocking/review loss ids, and a compact audit signal in one coordinator-sortable JSON shape:
459
459
 
460
460
  ```js
461
461
  const roundtrip = rustCandidate.metadata.roundtripEvidence;
462
462
  console.log(roundtrip.status); // "blocked", "stub-only", "preserved-source", or "target-adapter"
463
+ console.log(roundtrip.audit.disposition); // "reversible", "preserved-source", "stub-only", or "adapter-projected"
464
+ console.log(roundtrip.audit.claim); // bounded evidence label, not a semantic equivalence proof
465
+ console.log(roundtrip.audit.semanticEquivalenceClaim); // false
463
466
  console.log(roundtrip.output.sourceMaps.precision); // "exact", "declaration", "estimated", or "none"
464
467
  console.log(roundtrip.losses.blockingLossIds);
465
468
  ```
466
469
 
470
+ `roundtrip.audit` separates what was emitted from whether it can be merged: hash-verified same-language output with exact generated source maps is marked `reversible`, preserved source without generated exact maps stays `preserved-source`, generated declarations are `stub-only`, and host-owned target adapters are `adapter-projected`. Blocked and needs-review readiness still flow through `status`, `semanticMergeReadiness`, `reviewRequired`, loss ids, and source-map precision; the audit signal always keeps `autoMergeClaim: false` and `semanticEquivalenceClaim: false`.
471
+
467
472
  Provide a target projection adapter when the host owns real native-to-target translation semantics:
468
473
 
469
474
  ```js
@@ -107,6 +107,20 @@ export type NativeRoundtripEvidenceStatus = NativeImportRoundtripReadinessStatus
107
107
 
108
108
  export type NativeRoundtripSourceMapPrecision = SourceMapMappingRecord['precision'] | 'line' | 'declaration' | 'estimated' | 'unknown' | 'none' | string;
109
109
 
110
+ export type NativeRoundtripAuditDisposition =
111
+ | 'reversible'
112
+ | 'preserved-source'
113
+ | 'stub-only'
114
+ | 'adapter-projected'
115
+ | 'review-required';
116
+
117
+ export type NativeRoundtripAuditClaim =
118
+ | 'source-text-reversible'
119
+ | 'source-preserved'
120
+ | 'declaration-stubs-only'
121
+ | 'host-adapter-projected'
122
+ | 'review-required';
123
+
110
124
  export interface NativeRoundtripSourceMapEvidence {
111
125
  readonly total: number;
112
126
  readonly ids: readonly string[];
@@ -120,6 +134,30 @@ export interface NativeRoundtripSourceMapEvidence {
120
134
  readonly targetPaths: readonly string[];
121
135
  }
122
136
 
137
+ export interface NativeRoundtripAuditSignal {
138
+ readonly schema: 'frontier.lang.nativeRoundtripAuditSignal';
139
+ readonly version: 1;
140
+ readonly disposition: NativeRoundtripAuditDisposition;
141
+ readonly claim: NativeRoundtripAuditClaim;
142
+ readonly sourceLanguage?: FrontierSourceLanguage | string;
143
+ readonly target?: CompileTarget | string;
144
+ readonly sameLanguage: boolean;
145
+ readonly outputMode?: NativeSourceCompileOutputMode;
146
+ readonly projectionMode?: NativeSourceProjectionMode;
147
+ readonly sourceHashVerified: boolean;
148
+ readonly outputSourceMapPrecision: NativeRoundtripSourceMapPrecision;
149
+ readonly universalSourceMapPrecision: NativeRoundtripSourceMapPrecision;
150
+ readonly targetProjectionAdapterId?: string;
151
+ readonly targetCoverageLossClass?: ProjectionTargetLossClass | string;
152
+ readonly reviewRequired: boolean;
153
+ readonly semanticMergeReadiness: SemanticMergeReadiness;
154
+ readonly semanticEquivalenceClaim: false;
155
+ readonly autoMergeClaim: false;
156
+ readonly blockingLossCount: number;
157
+ readonly reviewLossCount: number;
158
+ readonly reasonCodes: readonly string[];
159
+ }
160
+
123
161
  export interface NativeRoundtripEvidenceMetadata {
124
162
  readonly status: NativeRoundtripEvidenceStatus;
125
163
  readonly semanticMergeReadiness: SemanticMergeReadiness;
@@ -127,6 +165,7 @@ export interface NativeRoundtripEvidenceMetadata {
127
165
  readonly sourcePath?: string;
128
166
  readonly language?: FrontierSourceLanguage | string;
129
167
  readonly target?: CompileTarget | string;
168
+ readonly audit: NativeRoundtripAuditSignal;
130
169
  readonly import: {
131
170
  readonly id?: string;
132
171
  readonly readiness: SemanticMergeReadiness;
@@ -0,0 +1,134 @@
1
+ import{createParadigmSemanticsLayer,createProofSpecLayer}from'@shapeshift-labs/frontier-lang-kernel';
2
+
3
+ export function createLightweightSemanticLayers(input) {
4
+ const evidenceIds = (input.evidence ?? []).map((record) => record.id).filter(Boolean);
5
+ const symbols = input.semanticIndex?.symbols ?? [];
6
+ const mappings = (input.sourceMaps ?? []).flatMap((sourceMap) => sourceMap.mappings ?? []);
7
+ const lossIds = (input.losses ?? []).map((loss) => loss.id).filter(Boolean);
8
+ const firstSubject = symbols[0]?.id ?? input.nativeSource?.id ?? input.nativeAst?.id;
9
+ const firstSubjectKind = symbols[0]?.id ? 'semanticSymbol' : input.nativeSource?.id ? 'nativeSource' : 'nativeAst';
10
+ const proof = createProofSpecLayer({
11
+ id: `proof_lightweight_${input.importIdPart}`,
12
+ invariants: [proofInvariant(input, firstSubject, firstSubjectKind, evidenceIds, lossIds)],
13
+ obligations: proofObligations(input, firstSubject, firstSubjectKind, evidenceIds, lossIds),
14
+ artifacts: [{
15
+ id: `proof_artifact_review_${input.importIdPart}`,
16
+ kind: 'manualReview',
17
+ evidenceIds,
18
+ lossIds,
19
+ summary: 'Lightweight import requires host parser, checker, tests, or human review before semantic merge.'
20
+ }],
21
+ assumptions: [{
22
+ id: `proof_assumption_lightweight_${input.importIdPart}`,
23
+ scope: 'native-import',
24
+ subjectId: input.nativeSource?.id,
25
+ subjectKind: 'nativeSource',
26
+ evidenceIds,
27
+ statement: 'Native source text and scanner evidence are preserved, but executable semantics are not proven.'
28
+ }],
29
+ evidence: input.evidence ?? []
30
+ });
31
+ const paradigmSemantics = createParadigmSemanticsLayer({
32
+ id: `paradigm_lightweight_${input.importIdPart}`,
33
+ bindingScopes: [{
34
+ id: `binding_scope_${input.importIdPart}`,
35
+ kind: 'moduleScope',
36
+ nativeSourceId: input.nativeSource?.id,
37
+ evidenceIds,
38
+ sourcePath: input.sourcePath,
39
+ sourceHash: input.sourceHash
40
+ }],
41
+ bindings: symbols.slice(0, 40).map((symbol) => ({
42
+ id: `binding_${symbol.id}`,
43
+ kind: 'nativeDeclarationBinding',
44
+ bindingScopeId: `binding_scope_${input.importIdPart}`,
45
+ semanticSymbolId: symbol.id,
46
+ nativeSourceId: input.nativeSource?.id,
47
+ evidenceIds
48
+ })),
49
+ evaluationModels: [evaluationModel(input, evidenceIds)],
50
+ effectRegions: effectRegions(input, evidenceIds),
51
+ loweringRecords: mappings.slice(0, 40).map((mapping) => ({
52
+ id: `lowering_${mapping.id}`,
53
+ kind: 'nativeSourceToFrontierSemanticIndex',
54
+ sourceMapId: mapping.sourceMapId,
55
+ sourceMapMappingId: mapping.id,
56
+ semanticSymbolId: mapping.semanticSymbolId,
57
+ nativeAstNodeId: mapping.nativeAstNodeId,
58
+ evidenceIds,
59
+ lossIds
60
+ })),
61
+ macroExpansions: macroBoundaryRecords(input, evidenceIds, lossIds),
62
+ reflectionBoundaries: reflectionBoundaryRecords(input, evidenceIds, lossIds),
63
+ evidence: input.evidence ?? []
64
+ });
65
+ return { proof, paradigmSemantics };
66
+ }
67
+
68
+ function proofInvariant(input, subjectId, subjectKind, evidenceIds, lossIds) {
69
+ return {
70
+ id: `proof_invariant_source_hash_${input.importIdPart}`,
71
+ kind: 'sourceHashFreshness',
72
+ subjectId,
73
+ subjectKind,
74
+ evidenceIds,
75
+ lossIds,
76
+ statement: 'Semantic merge candidates must match the preserved source hash before admission.'
77
+ };
78
+ }
79
+
80
+ function proofObligations(input, subjectId, subjectKind, evidenceIds, lossIds) {
81
+ return [
82
+ {
83
+ id: `proof_obligation_review_${input.importIdPart}`,
84
+ kind: 'semanticMergeReview',
85
+ status: 'open',
86
+ subjectId,
87
+ subjectKind,
88
+ contractIds: [`proof_invariant_source_hash_${input.importIdPart}`],
89
+ evidenceIds,
90
+ lossIds,
91
+ statement: 'Review ownership, source maps, losses, and focused tests before applying this semantic patch.'
92
+ },
93
+ {
94
+ id: `proof_obligation_external_semantics_${input.importIdPart}`,
95
+ kind: 'externalSemanticEquivalence',
96
+ status: 'external-tool-required',
97
+ subjectId,
98
+ subjectKind,
99
+ evidenceIds,
100
+ lossIds,
101
+ statement: 'Cross-language executable equivalence requires a target checker, oracle, or proof artifact.'
102
+ }
103
+ ];
104
+ }
105
+
106
+ function evaluationModel(input, evidenceIds) {
107
+ const language = String(input.language ?? 'unknown').toLowerCase();
108
+ const kind = ['javascript', 'typescript', 'python', 'ruby', 'php', 'lua'].includes(language)
109
+ ? 'dynamicRuntime'
110
+ : ['rust', 'c', 'cpp', 'c++', 'zig'].includes(language)
111
+ ? 'compileTimeOwnershipRuntime'
112
+ : 'languageRuntime';
113
+ return { id: `evaluation_model_${input.importIdPart}`, kind, nativeSourceId: input.nativeSource?.id, evidenceIds };
114
+ }
115
+
116
+ function effectRegions(input, evidenceIds) {
117
+ const predicates = new Set((input.semanticIndex?.relations ?? []).map((relation) => relation.predicate));
118
+ return [...predicates].filter((predicate) => ['calls', 'imports', 'uses', 'requires'].includes(predicate)).map((predicate) => ({
119
+ id: `effect_region_${input.importIdPart}_${predicate}`,
120
+ kind: `${predicate}DependencyEffect`,
121
+ nativeSourceId: input.nativeSource?.id,
122
+ evidenceIds
123
+ }));
124
+ }
125
+
126
+ function macroBoundaryRecords(input, evidenceIds, lossIds) {
127
+ const hasMacroLoss = (input.losses ?? []).some((loss) => ['macroExpansion', 'preprocessor', 'metaprogramming'].includes(loss.kind));
128
+ return hasMacroLoss ? [{ id: `macro_boundary_${input.importIdPart}`, kind: 'reviewRequiredMacroBoundary', nativeSourceId: input.nativeSource?.id, evidenceIds, lossIds }] : [];
129
+ }
130
+
131
+ function reflectionBoundaryRecords(input, evidenceIds, lossIds) {
132
+ const hasReflectionLoss = (input.losses ?? []).some((loss) => ['dynamicRuntime', 'reflection', 'opaqueNative'].includes(loss.kind));
133
+ return hasReflectionLoss ? [{ id: `reflection_boundary_${input.importIdPart}`, kind: 'reviewRequiredDynamicBoundary', nativeSourceId: input.nativeSource?.id, evidenceIds, lossIds }] : [];
134
+ }
@@ -24,7 +24,26 @@ export function createNativeRoundtripEvidence(importResult,options={}) {
24
24
  const outputMode=options.outputMode??options.targetProjection?.outputMode??projection?.mode;
25
25
  const sourceHashVerified=Boolean(projection?.sourceHash&&projection?.outputHash===projection.sourceHash)||projection?.metadata?.sourceHashVerified===true;
26
26
  const status=semanticMerge==='blocked'?'blocked':outputMode==='target-adapter'?'target-adapter':projection?.mode==='native-source-stubs'||outputMode==='target-stubs'?'stub-only':sourceHashVerified?'preserved-source':'needs-review';
27
+ const universalSourceMapEvidence=summarizeSourceMaps(universalSourceMaps);
27
28
  const sourceMapEvidence=summarizeSourceMaps(hasOutputSourceMaps?outputSourceMaps:universalSourceMaps);
29
+ const sourceLanguage=projection?.language??importResult.language;
30
+ const target=options.target??options.targetCoverage?.target??options.targetProjection?.target;
31
+ const audit=createRoundtripAudit({
32
+ status,
33
+ semanticMerge,
34
+ sourceLanguage,
35
+ target,
36
+ sameLanguage:Boolean(sourceLanguage&&target&&String(sourceLanguage)===String(target)),
37
+ outputMode,
38
+ projectionMode:projection?.mode,
39
+ sourceHashVerified,
40
+ hasOutputSourceMaps,
41
+ sourceMapEvidence,
42
+ universalSourceMapEvidence,
43
+ targetProjection:options.targetProjection,
44
+ targetCoverage:options.targetCoverage,
45
+ lossSummary
46
+ });
28
47
  const metadata={
29
48
  schema:'frontier.lang.nativeRoundtripEvidence',
30
49
  version:1,
@@ -33,8 +52,9 @@ export function createNativeRoundtripEvidence(importResult,options={}) {
33
52
  semanticMergeReadiness:semanticMerge,
34
53
  reviewRequired:semanticMerge!=='ready',
35
54
  sourcePath:projection?.sourcePath??importResult.sourcePath,
36
- language:projection?.language??importResult.language,
37
- target:options.target??options.targetCoverage?.target??options.targetProjection?.target,
55
+ language:sourceLanguage,
56
+ target,
57
+ audit,
38
58
  import:{
39
59
  id:importResult.id,
40
60
  readiness:importReadiness,
@@ -49,7 +69,7 @@ export function createNativeRoundtripEvidence(importResult,options={}) {
49
69
  issues:universalIssues,
50
70
  nativeSources:universalAst?.nativeSources?.length??importResult.nativeSources?.length??(importResult.nativeSource?1:0),
51
71
  semanticSymbols:(importResult.semanticIndex??universalAst?.semanticIndex)?.symbols?.length??0,
52
- sourceMaps:summarizeSourceMaps(universalSourceMaps)
72
+ sourceMaps:universalSourceMapEvidence
53
73
  },
54
74
  projection:{
55
75
  id:projection?.id,
@@ -115,3 +135,55 @@ function summarizeSourceMaps(sourceMaps){
115
135
  }
116
136
  function normalizePrecision(value){const precision=String(value??'unknown');return Object.prototype.hasOwnProperty.call(precisionRank,precision)?precision:'unknown';}
117
137
  function worstPrecision(precisions){if(!precisions.length)return'none';return precisions.reduce((worst,next)=>precisionRank[next]>precisionRank[worst]?next:worst,'exact');}
138
+ function createRoundtripAudit(input){
139
+ const disposition=roundtripAuditDisposition(input);
140
+ return{
141
+ schema:'frontier.lang.nativeRoundtripAuditSignal',
142
+ version:1,
143
+ disposition,
144
+ claim:roundtripAuditClaim(disposition),
145
+ sourceLanguage:input.sourceLanguage,
146
+ target:input.target,
147
+ sameLanguage:input.sameLanguage,
148
+ outputMode:input.outputMode,
149
+ projectionMode:input.projectionMode,
150
+ sourceHashVerified:input.sourceHashVerified,
151
+ outputSourceMapPrecision:input.sourceMapEvidence.precision,
152
+ universalSourceMapPrecision:input.universalSourceMapEvidence.precision,
153
+ targetProjectionAdapterId:input.targetProjection?.adapter?.id,
154
+ targetCoverageLossClass:input.targetCoverage?.lossClass,
155
+ reviewRequired:input.semanticMerge!=='ready',
156
+ semanticMergeReadiness:input.semanticMerge,
157
+ semanticEquivalenceClaim:false,
158
+ autoMergeClaim:false,
159
+ blockingLossCount:input.lossSummary.blockingLossIds.length,
160
+ reviewLossCount:input.lossSummary.reviewLossIds.length,
161
+ reasonCodes:uniqueStrings([
162
+ `status:${input.status}`,
163
+ `semantic:${input.semanticMerge}`,
164
+ `output:${input.outputMode??'unknown'}`,
165
+ `projection:${input.projectionMode??'unknown'}`,
166
+ input.sourceHashVerified?'source-hash:verified':'source-hash:unverified',
167
+ `output-source-map:${input.sourceMapEvidence.precision}`,
168
+ `universal-source-map:${input.universalSourceMapEvidence.precision}`,
169
+ input.targetCoverage?.lossClass?`target-loss:${input.targetCoverage.lossClass}`:undefined,
170
+ input.targetProjection?.adapter?.id?`target-adapter:${input.targetProjection.adapter.id}`:undefined,
171
+ input.lossSummary.blockingLossIds.length?'losses:blocking':undefined,
172
+ input.lossSummary.reviewLossIds.length?'losses:review':undefined
173
+ ])
174
+ };
175
+ }
176
+ function roundtripAuditDisposition(input){
177
+ if(input.outputMode==='target-adapter')return'adapter-projected';
178
+ if(input.projectionMode==='native-source-stubs'||input.outputMode==='target-stubs')return'stub-only';
179
+ if(input.sourceHashVerified&&input.outputMode==='preserved-source'&&input.hasOutputSourceMaps&&input.sourceMapEvidence.precision==='exact')return'reversible';
180
+ if(input.sourceHashVerified||input.projectionMode==='preserved-source')return'preserved-source';
181
+ return'review-required';
182
+ }
183
+ function roundtripAuditClaim(disposition){
184
+ if(disposition==='reversible')return'source-text-reversible';
185
+ if(disposition==='preserved-source')return'source-preserved';
186
+ if(disposition==='stub-only')return'declaration-stubs-only';
187
+ if(disposition==='adapter-projected')return'host-adapter-projected';
188
+ return'review-required';
189
+ }
@@ -1,5 +1,6 @@
1
1
  import{commonGeneratedTargetPath,idFragment}from'../../native-import-utils.js';import{inferSourceMapMappings,normalizeSourceMapMappings,normalizeSourceMaps}from'../../native-source-maps.js';import{createKernelSourcePreservationRecords,summarizeKernelSourcePreservationRecords}from'../../semantic-import-source-preservation.js';import{createDocument,createImportResult,createNativeAstRecord,createPatch,createSourceMapRecord,createUniversalAstEnvelope,hashSemanticValue,nativeSourceNode}from'@shapeshift-labs/frontier-lang-kernel';
2
2
  import{attachInputUniversalDialectRegistry}from'../../universal-dialect-registry.js';
3
+ import{createLightweightSemanticLayers}from'./createLightweightSemanticLayers.js';
3
4
  import{attachNativeImportLossSummary}from'./attachNativeImportLossSummary.js';import{createLightweightNativeImport}from'./createLightweightNativeImport.js';import{createNativeSourcePreservation}from'./createNativeSourcePreservation.js';import{hasNativeExactAstEvidence}from'./hasNativeExactAstEvidence.js';import{normalizeNativeLossRecords}from'./normalizeNativeLossRecords.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';import{unverifiedNativeAstLosses}from'./unverifiedNativeAstLosses.js';import{withNativeImportReadiness}from'./withNativeImportReadiness.js';
4
5
  export function importNativeSource(input) {
5
6
  const language = input.language ?? input.nativeAst?.language;
@@ -216,6 +217,7 @@ export function importNativeSource(input) {
216
217
  });
217
218
  const kernelSourcePreservationSummary = summarizeKernelSourcePreservationRecords(sourcePreservationRecords);
218
219
  const resultSourceMapMappings = sourceMaps.flatMap((sourceMap) => sourceMap.mappings ?? []);
220
+ const semanticLayers=input.semanticLayers??createLightweightSemanticLayers({importIdPart,language,sourcePath,sourceHash,nativeSource,nativeAst,semanticIndex,sourceMaps,losses,evidence,sourcePreservationRecords});
219
221
  let universalAst = createUniversalAstEnvelope({
220
222
  id: input.universalAstId ?? `universal_ast_${importIdPart}`,
221
223
  document,
@@ -224,6 +226,7 @@ export function importNativeSource(input) {
224
226
  sourceMaps,
225
227
  losses,
226
228
  evidence,
229
+ proof:input.proof??input.universalAstProof??semanticLayers.proof,paradigmSemantics:input.paradigmSemantics??input.universalAstParadigmSemantics??semanticLayers.paradigmSemantics,
227
230
  metadata: {
228
231
  sourceLanguage: language,
229
232
  sourcePath,
@@ -41,7 +41,9 @@ export function renderWorkbenchHtml(initialState) {
41
41
  <h2>TypeScript</h2>
42
42
  <span id="typescriptStatus">source</span>
43
43
  </div>
44
- <textarea id="typescriptInput" spellcheck="false" aria-label="TypeScript source"></textarea>
44
+ <div class="paneBody editorBody">
45
+ <textarea id="typescriptInput" spellcheck="false" aria-label="TypeScript source"></textarea>
46
+ </div>
45
47
  </section>
46
48
 
47
49
  <section class="pane graphPane" data-view-panel="frontier">
@@ -52,8 +54,8 @@ export function renderWorkbenchHtml(initialState) {
52
54
  <button data-frontier-tab="json" aria-pressed="false">JSON</button>
53
55
  </div>
54
56
  </div>
55
- <div id="graphView" class="graphView"></div>
56
- <pre id="frontierJson" class="codeBlock" hidden></pre>
57
+ <div id="graphView" class="paneBody graphView"></div>
58
+ <pre id="frontierJson" class="paneBody codeBlock" hidden></pre>
57
59
  </section>
58
60
 
59
61
  <section class="pane outputPane" data-view-panel="rust">
@@ -61,7 +63,9 @@ export function renderWorkbenchHtml(initialState) {
61
63
  <h2>Rust</h2>
62
64
  <span id="rustStatus">target</span>
63
65
  </div>
64
- <textarea id="rustInput" spellcheck="false" aria-label="Rust source"></textarea>
66
+ <div class="paneBody editorBody">
67
+ <textarea id="rustInput" spellcheck="false" aria-label="Rust source"></textarea>
68
+ </div>
65
69
  </section>
66
70
  </section>
67
71
  </main>
@@ -25,6 +25,7 @@ export function workbenchStyles() {
25
25
  * { box-sizing: border-box; }
26
26
  html, body { height: 100%; margin: 0; }
27
27
  body {
28
+ width: 100%;
28
29
  background: var(--bg);
29
30
  color: var(--text);
30
31
  font-family: var(--ui);
@@ -33,6 +34,7 @@ body {
33
34
 
34
35
  .appShell {
35
36
  height: 100vh;
37
+ height: 100dvh;
36
38
  overflow: hidden;
37
39
  }
38
40
 
@@ -97,23 +99,37 @@ body {
97
99
  display: grid;
98
100
  grid-template-columns: repeat(4, minmax(0, 1fr));
99
101
  background: #0f1214;
102
+ overflow: hidden;
100
103
  }
101
104
  .statusStrip div {
102
105
  min-width: 0;
106
+ min-height: 0;
103
107
  padding: 8px 14px;
104
108
  border-right: 1px solid var(--line);
109
+ overflow: hidden;
105
110
  }
106
111
  .label {
107
112
  display: block;
108
113
  color: var(--faint);
109
114
  font-size: 10px;
115
+ line-height: 1.1;
110
116
  text-transform: uppercase;
111
117
  }
112
- .statusStrip strong { font-size: 13px; font-weight: 650; }
118
+ .statusStrip strong {
119
+ display: block;
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ white-space: nowrap;
123
+ font-size: 13px;
124
+ font-weight: 650;
125
+ line-height: 1.2;
126
+ }
113
127
 
114
128
  .workspace {
115
129
  position: fixed;
116
130
  inset: var(--chrome-height) 0 0 0;
131
+ height: calc(100vh - var(--chrome-height));
132
+ height: calc(100dvh - var(--chrome-height));
117
133
  min-height: 0;
118
134
  display: grid;
119
135
  grid-template-columns: minmax(270px, 0.95fr) minmax(330px, 1.1fr) minmax(300px, 1fr);
@@ -131,6 +147,20 @@ body {
131
147
  }
132
148
  .pane:last-child { border-right: 0; }
133
149
  .pane.isSource .paneHeader { box-shadow: inset 0 -2px 0 var(--green); }
150
+ .paneBody {
151
+ grid-row: 2;
152
+ grid-column: 1;
153
+ min-width: 0;
154
+ min-height: 0;
155
+ height: 100%;
156
+ max-height: 100%;
157
+ overflow: auto;
158
+ overscroll-behavior: contain;
159
+ scrollbar-gutter: stable;
160
+ }
161
+ .editorBody {
162
+ overflow: hidden;
163
+ }
134
164
  .paneHeader {
135
165
  justify-content: space-between;
136
166
  padding: 0 12px;
@@ -140,6 +170,7 @@ body {
140
170
  .paneHeader span { color: var(--muted); font-size: 12px; font-family: var(--mono); }
141
171
 
142
172
  textarea, .codeBlock {
173
+ display: block;
143
174
  width: 100%;
144
175
  height: 100%;
145
176
  min-height: 0;
@@ -160,18 +191,10 @@ textarea, .codeBlock {
160
191
  }
161
192
 
162
193
  .graphView {
163
- grid-row: 2;
164
- grid-column: 1;
165
- min-height: 0;
166
- max-height: 100%;
167
- overflow: auto;
168
- overscroll-behavior: contain;
169
194
  padding: 12px;
170
195
  }
171
- #frontierJson {
172
- grid-row: 2;
173
- grid-column: 1;
174
- min-width: 0;
196
+ #graphView[hidden], #frontierJson[hidden] {
197
+ display: none;
175
198
  }
176
199
  .graphGrid {
177
200
  display: grid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.57",
3
+ "version": "0.2.58",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",