Skip to content

Commit cc360e3

Browse files
feat(Wind): Load product.json at build time for configuration
Implement Atom I5: refactor ResolveConfiguration to fetch product identity from /product.json (generated by Maintain/Script/ResolveProductConfig.sh from .env.Land variables) instead of hardcoded strings. - Add LoadProductJson() async function that fetches /product.json with fallback to minimal defaults - Update product configuration fields (nameShort, nameLong, applicationName, version, commit, urlProtocol, dataFolderName, serverApplicationName) to use resolved values - Preserve backward compatibility: network failures fall through to base defaults allowing degraded boot with version mismatch warning This enables single-source-of-truth product identity without hardcoded version strings in the codebase. The Target/ build outputs are regenerated to reflect the new configuration resolution.
1 parent 72a2860 commit cc360e3

12 files changed

Lines changed: 172 additions & 67 deletions

File tree

CHANGELOG.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
All notable changes to Wind (UI Service Layer) are documented here.
44
Format: [Keep a Changelog](https://keepachangelog.com/).
55

6-
## [v2.1] Q2 2026: Full Workbench Lift
6+
## [v2.1] - Q2 2026: Full Workbench Lift
77

88
### Added
99

@@ -18,13 +18,13 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
1818
- TauriMainProcessService verified: 24 VS Code IPC channels routed to Mountain
1919
- ResolveConfiguration confirmed loading real Mountain paths
2020

21-
## [v2.0] Q1 2026: Editor Launch Sprint
21+
## [v2.0] - Q1 2026: Editor Launch Sprint
2222

2323
### April 8-16: Tauri IPC Bridge Sprint
2424

2525
#### Added
2626

27-
- `Source/Service/TauriMainProcessService.ts` (232 lines, April 8) IPC
27+
- `Source/Service/TauriMainProcessService.ts` (232 lines, April 8) - IPC
2828
routing with 24 channel routes and 14 stub channels:
2929
- Routed: localFilesystem, storage, configuration, textFile, extensions,
3030
commands, terminal, output, notification, progress, quickInput, workspaces,
@@ -35,9 +35,9 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
3535
sharedProcess, utilityProcessWorker, meteredConnection, webContentExtractor,
3636
browserElements, NativeMcpDiscoveryHelper, sandboxHelper, mcpGateway,
3737
browserViewGroup, externalTerminal
38-
- `Source/Polyfills/IPCRendererShim.ts` (373 lines) binary IPC protocol
38+
- `Source/Polyfills/IPCRendererShim.ts` (373 lines) - binary IPC protocol
3939
(created then consolidated)
40-
- `Source/Function/DevLog.ts` (72 lines, April 9) development logging with
40+
- `Source/Function/DevLog.ts` (72 lines, April 9) - development logging with
4141
short mode and fire-and-forget semantics
4242
- MessageChannel for extension host IPC: Preload.ts +58 lines, init data →
4343
Initialized byte ([1]) → Ready byte ([2]) after 50ms
@@ -64,15 +64,15 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
6464

6565
#### Added
6666

67-
- `Source/Preload.ts` (99 lines) Tauri/Electron bridge
68-
- `Source/Bootstrap/Types/` 30+ VS Code type mirror files:
67+
- `Source/Preload.ts` (99 lines) - Tauri/Electron bridge
68+
- `Source/Bootstrap/Types/` - 30+ VS Code type mirror files:
6969
BootstrapTypes.ts, Type/ subtree (BootstrapConfig, EnvironmentData, Mode,
7070
Platform, StageResult, etc.)
71-
- `Source/Bootstrap/Types/VSCode/` VSCodeConfigurationType,
71+
- `Source/Bootstrap/Types/VSCode/` - VSCodeConfigurationType,
7272
VSCodeLoggerType, VSCodeWorkbenchOptionsType
7373
- TypeScript 5.9.3 → 6.0.2 upgrade (March 24)
7474

75-
## [v1.3] Q4 2025: Dependency Maintenance
75+
## [v1.3] - Q4 2025: Dependency Maintenance
7676

7777
### Changed
7878

@@ -81,14 +81,14 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
8181
- @effect/language-service: 0.60.x → 0.63.2
8282
- No major Application/ restructures; module count stable
8383

84-
## [v1.2] Q3 2025: Full Stack Integration
84+
## [v1.2] - Q3 2025: Full Stack Integration
8585

8686
### Added
8787

8888
- 100+ Application service modules following Define/Implement/Problem pattern:
89-
- `Source/Application/{Service}/Define.ts` interface
90-
- `Source/Application/{Service}/Implement.ts` Effect-TS implementation
91-
- `Source/Application/{Service}/Problem.ts` error types
89+
- `Source/Application/{Service}/Define.ts` - interface
90+
- `Source/Application/{Service}/Implement.ts` - Effect-TS implementation
91+
- `Source/Application/{Service}/Problem.ts` - error types
9292
- Services: Command, Configuration, Dialog, Editor, EditorGroup, File,
9393
FileSystem, Host, IPC, LanguageFeature, Logger, Marker, Notification,
9494
Policy, UntitledTextEditor, and more
@@ -100,16 +100,16 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
100100
- solid-js 1.9.x stable
101101
- @types/node 24.x
102102

103-
## [v1.1] Q2 2025: Architecture Buildout
103+
## [v1.1] - Q2 2025: Architecture Buildout
104104

105-
**May 30, 2025: the pivot point Effect-TS + Application layer born.**
105+
**May 30, 2025: the pivot point - Effect-TS + Application layer born.**
106106

107107
### Added
108108

109-
- `Source/Effect/` directory Effect-TS service composition layer
110-
- `Source/Application/` directory 50+ service modules (Dialog, FileDialog,
109+
- `Source/Effect/` directory - Effect-TS service composition layer
110+
- `Source/Application/` directory - 50+ service modules (Dialog, FileDialog,
111111
etc.) with Effect-TS-driven patterns
112-
- `Source/Configuration/ESBuild/` build config restructure
112+
- `Source/Configuration/ESBuild/` - build config restructure
113113
- effect, @effect/platform, @effect/experimental, @effect/language-service
114114
dependencies
115115

@@ -118,7 +118,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
118118
- Source/Element/Preview.scss
119119
- SolidJS evaluation concluded
120120

121-
## [v1.0] Q1 2025: Integration Phase
121+
## [v1.0] - Q1 2025: Integration Phase
122122

123123
### Changed
124124

@@ -127,7 +127,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
127127
- CODE_OF_CONDUCT.md, CONTRIBUTING.md governance refresh
128128
- Target gen/delete cycles (CI/CD integration testing)
129129

130-
## [v0.2] Q4 2024: Architecture Solidification
130+
## [v0.2] - Q4 2024: Architecture Solidification
131131

132132
### Added
133133

@@ -141,7 +141,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
141141
- solid-devtools: 0.31.2 → 0.31.7
142142
- CSS custom properties: `--Mute` action-form convention
143143

144-
## [v0.1] Q3 2024: Rapid Development
144+
## [v0.1] - Q3 2024: Rapid Development
145145

146146
### Changed
147147

@@ -151,18 +151,18 @@ Format: [Keep a Changelog](https://keepachangelog.com/).
151151
- @playform/build: 0.1.2 → 0.1.7
152152
- No new architectural folders; pure refinement
153153

154-
## [v0.0] Q2 2024: Project Inception
154+
## [v0.0] - Q2 2024: Project Inception
155155

156156
### Added
157157

158-
- `Source/Context/` React-style context primitives (Action, Connection,
158+
- `Source/Context/` - React-style context primitives (Action, Connection,
159159
Environment, Session, Store)
160-
- `Source/Element/` SolidJS components (Editor.tsx, Button, Anchor, Tip,
160+
- `Source/Element/` - SolidJS components (Editor.tsx, Button, Anchor, Tip,
161161
Footer)
162-
- `Source/Library/` helper functions (Create, Pad, Persist, Environment)
163-
- `Source/Function/` utilities (Merge)
164-
- `Source/Stylesheet/` SCSS (Element/*, Mixin/*)
165-
- `Source/Variable/` ESBuild config, StringURL constant
162+
- `Source/Library/` - helper functions (Create, Pad, Persist, Environment)
163+
- `Source/Function/` - utilities (Merge)
164+
- `Source/Stylesheet/` - SCSS (Element/*, Mixin/*)
165+
- `Source/Variable/` - ESBuild config, StringURL constant
166166

167167
### Dependencies (First Release)
168168

Source/Effect/Workspaces/Implementation/WorkspacesStub.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const StubWorkspacesService: WorkspacesService = {
77
AddFolder: (_uri, _name) => Effect.void,
88
RemoveFolder: (_uri) => Effect.void,
99
GetName: () => Effect.succeed(undefined),
10-
// The stub never emits tests that want change events should build a
10+
// The stub never emits - tests that want change events should build a
1111
// custom layer with `Stream.fromIterable` of scripted events.
1212
OnChange: () => Stream.empty,
1313
};

Source/Effect/Workspaces/Interface/WorkspacesService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface WorkspacesService {
4040
/**
4141
* Stream of workspace folder mutations emitted by Mountain. Consumers that
4242
* cache `GetFolders()` results should subscribe to this stream to
43-
* invalidate and re-fetch otherwise their view drifts from Cocoon's
43+
* invalidate and re-fetch - otherwise their view drifts from Cocoon's
4444
* `vscode.workspace.workspaceFolders` after File → Open Folder.
4545
*
4646
* The Tauri channel is `sky://workspaces/changed`. Mountain fires it from

Source/Effect/Workspaces/Live.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export const LiveWorkspacesServiceLayer = Layer.effect(
110110
* `sky://workspaces/changed` from
111111
* `UpdateWorkspaceFoldersAndBroadcast`. Map each event's raw
112112
* payload into a typed `WorkspacesChangeEvent` and drop entries
113-
* we can't parse Mountain is the source of truth for folder
113+
* we can't parse - Mountain is the source of truth for folder
114114
* shape, but defensive parsing keeps the stream alive if a
115115
* future field is introduced.
116116
*/

Source/Function/Install/Function/ResolveConfiguration.ts

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,77 @@ const DevLog = (Tag: string, ..._Args: unknown[]): void => {
1414
try { performance.mark(`land:config:${Tag}`); } catch {}
1515
};
1616

17+
/**
18+
* Atom I5: fetch the resolved /product.json generated at build time by
19+
* Maintain/Script/ResolveProductConfig.sh from .env.Land's Product* vars.
20+
* Single source of truth — no hardcoded identity or version strings here.
21+
* Network failures fall through to minimal defaults so the workbench still
22+
* boots in degraded mode (with a visible version mismatch warning).
23+
*/
24+
type LandProduct = {
25+
nameShort: string;
26+
nameLong: string;
27+
applicationName: string;
28+
dataFolderName: string;
29+
version: string;
30+
commit: string;
31+
quality?: string;
32+
urlProtocol: string;
33+
serverApplicationName: string;
34+
embedderIdentifier?: string;
35+
};
36+
const LoadProductJson = async (): Promise<LandProduct> => {
37+
const Base: LandProduct = {
38+
nameShort: "Land",
39+
nameLong: "Land Editor",
40+
applicationName: "land",
41+
dataFolderName: ".land",
42+
version: "1.118.0",
43+
commit: "dev",
44+
urlProtocol: "land",
45+
serverApplicationName: "land-server",
46+
};
47+
try {
48+
const Response = await fetch("/product.json");
49+
if (Response.ok) {
50+
const Body = (await Response.json()) as Partial<LandProduct>;
51+
// exactOptionalPropertyTypes: only include optional keys if
52+
// the incoming value is a non-empty string. Undefined
53+
// assignments fail strict type-check.
54+
const Result: LandProduct = {
55+
nameShort: Body.nameShort ?? Base.nameShort,
56+
nameLong: Body.nameLong ?? Base.nameLong,
57+
applicationName: Body.applicationName ?? Base.applicationName,
58+
dataFolderName: Body.dataFolderName ?? Base.dataFolderName,
59+
version: Body.version ?? Base.version,
60+
commit: Body.commit ?? Base.commit,
61+
urlProtocol: Body.urlProtocol ?? Base.urlProtocol,
62+
serverApplicationName:
63+
Body.serverApplicationName ?? Base.serverApplicationName,
64+
};
65+
if (typeof Body.quality === "string") Result.quality = Body.quality;
66+
if (typeof Body.embedderIdentifier === "string")
67+
Result.embedderIdentifier = Body.embedderIdentifier;
68+
return Result;
69+
}
70+
DevLog("config", "product.json fetch non-ok:", Response.status);
71+
} catch (Error) {
72+
DevLog("config", "product.json fetch threw:", Error);
73+
}
74+
return Base;
75+
};
76+
1777
/**
1878
* Resolves the VSCode sandbox configuration.
1979
* Returns ISandboxConfiguration (for browser workbench) but includes
2080
* additional fields that DesktopMain (INativeWindowConfiguration) reads.
2181
* The extra fields are silently ignored by the browser workbench.
2282
*/
2383
export async function ResolveConfiguration(): Promise<ISandboxConfiguration> {
84+
// Atom I5: resolve product identity from /product.json so every
85+
// consumer of this function gets the build-time-generated values.
86+
const Product = await LoadProductJson();
87+
2488
const FileRoot =
2589
typeof globalThis._VSCODE_FILE_ROOT === "string"
2690
? globalThis._VSCODE_FILE_ROOT
@@ -96,15 +160,17 @@ export async function ResolveConfiguration(): Promise<ISandboxConfiguration> {
96160
USER: Paths.homeDir?.split("/").pop() || "user",
97161
},
98162
product: {
99-
nameShort: "FIDDEE",
100-
nameLong: "FIDDEE",
101-
applicationName: "land",
102-
version: "0.0.1",
103-
commit: "dev",
163+
// Atom I5: every field below is sourced from /product.json
164+
// (generated from .env.Land at build time). See LoadProductJson.
165+
nameShort: Product.nameShort,
166+
nameLong: Product.nameLong,
167+
applicationName: Product.applicationName,
168+
version: Product.version,
169+
commit: Product.commit,
104170
date: new Date().toISOString(),
105-
urlProtocol: "land",
106-
dataFolderName: "land",
107-
serverApplicationName: "land-server",
171+
urlProtocol: Product.urlProtocol,
172+
dataFolderName: Product.dataFolderName,
173+
serverApplicationName: Product.serverApplicationName,
108174
extensionProperties: {},
109175
defaultChatAgent: {
110176
extensionId: "vscode",
@@ -259,7 +325,7 @@ export async function ResolveConfiguration(): Promise<ISandboxConfiguration> {
259325
userDataDir: Paths.userDataDir || undefined,
260326
logsPath: LogsLocation || undefined,
261327

262-
// Extension paths tells VS Code's NativeExtensionsScannerService where
328+
// Extension paths - tells VS Code's NativeExtensionsScannerService where
263329
// to find built-in and user-installed extensions on disk.
264330
// appRoot + /extensions = builtinExtensionsPath (VS Code convention)
265331
builtinExtensionsPath: `${AppRoot}/extensions`,

Source/Polyfills/IPCRendererShim.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ class IPCRendererImpl implements IpcRenderer {
762762
* Invoke main process and get response
763763
*/
764764
async invoke<T = unknown>(channel: string, ...args: unknown[]): Promise<T> {
765-
// Native-host dialog channels VS Code's workbench calls
765+
// Native-host dialog channels - VS Code's workbench calls
766766
// `nativeHostService.showOpenDialog(options)` which ultimately does
767767
// `ipcRenderer.invoke('nativeHost:showOpenDialog', options)` (and the
768768
// `vscode:*` variant on the desktop workbench). We bridge these to

Source/Polyfills/NativeModulePolyfill.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ function createDialog(): Dialog {
416416
// Electron's showOpenDialog uses `properties: ['openDirectory' | 'openFile'
417417
// | 'multiSelections' | 'createDirectory']`; Tauri's dialog.open uses
418418
// `{ directory, multiple, canCreateDirectories }`. VS Code calls the
419-
// polyfill with Electron-style options, so we translate here without
419+
// polyfill with Electron-style options, so we translate here - without
420420
// this, "Open Folder" shows a FILE picker (or nothing, on some Tauri
421421
// versions) because Tauri sees no `directory: true`.
422422
const TranslateOpenOptions = (
@@ -471,7 +471,7 @@ function createDialog(): Dialog {
471471
};
472472
}
473473
} catch (error) {
474-
// Tauri plugin missing or permission denied log for visibility
474+
// Tauri plugin missing or permission denied - log for visibility
475475
// so "Open Folder" silent failures are grep-able.
476476
try {
477477
console.warn(

Source/Preload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const ipcMessagePort = {
264264
try {
265265
performance.mark("land:exthost:handshake:initialized-sent");
266266
} catch {}
267-
console.warn("[Extension Host] Handshake complete Initialized sent");
267+
console.warn("[Extension Host] Handshake complete - Initialized sent");
268268
} else {
269269
console.warn("[Extension Host] Handshake: ignoring control byte", Length > 0 ? new Uint8Array(Data instanceof ArrayBuffer ? Data : Data)[0] : "empty");
270270
}

0 commit comments

Comments
 (0)