Skip to content

Commit a26b7e6

Browse files
committed
refactor: remove homeScreenName handling from manifest and related commands
- Eliminated homeScreenName management from the manifest and various commands, including add, init, pull, and push. - Updated related tests to reflect the removal of homeScreenName assertions and ensure consistency in manifest structure. - Simplified manifest options by removing unnecessary parameters related to homeScreenName.
1 parent 8193240 commit a26b7e6

11 files changed

Lines changed: 30 additions & 233 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ ensemble update
110110

111111
- **Manifest behavior**
112112
- For `widget`, `script`, `action`, and `translation`, `.manifest.json` is updated to include the new artifact.
113-
- For the **first screen**, the CLI will offer to set it as `homeScreenName` in `.manifest.json`.
113+
- Screens do not change `.manifest.json`.
114114

115115
## Usage
116116

src/commands/add.ts

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import fs from 'fs/promises';
22
import path from 'path';
33
import prompts from 'prompts';
44

5-
import { loadProjectConfig } from '../config/projectConfig.js';
6-
import { resolveAppContext } from '../config/projectConfig.js';
5+
import { loadProjectConfig, resolveAppContext } from '../config/projectConfig.js';
76
import { getValidAuthSession } from '../auth/session.js';
87
import { uploadAssetToStudio } from '../cloud/assetClient.js';
98
import { upsertEnvConfig } from '../core/envConfig.js';
10-
import { upsertManifestEntry, type RootManifest } from '../core/manifest.js';
9+
import { upsertManifestEntry } from '../core/manifest.js';
1110
import { ui } from '../core/ui.js';
1211
import { withSpinner } from '../lib/spinner.js';
1312

@@ -153,42 +152,6 @@ async function addAsset(
153152
};
154153
}
155154

156-
async function maybeSetHomeScreenName(
157-
projectRoot: string,
158-
screenName: string,
159-
interactive: boolean
160-
): Promise<boolean> {
161-
const manifestPath = path.join(projectRoot, '.manifest.json');
162-
let manifest: RootManifest = {};
163-
try {
164-
const raw = await fs.readFile(manifestPath, 'utf8');
165-
manifest = JSON.parse(raw) as RootManifest;
166-
} catch {
167-
manifest = {};
168-
}
169-
170-
if (manifest.homeScreenName && typeof manifest.homeScreenName === 'string') {
171-
return false;
172-
}
173-
174-
let shouldSet = true;
175-
if (interactive) {
176-
const { setHome } = await prompts({
177-
type: 'confirm',
178-
name: 'setHome',
179-
message: `Set "${screenName}" as homeScreenName (no homeScreenName set yet)?`,
180-
initial: true,
181-
});
182-
shouldSet = setHome === true;
183-
}
184-
185-
if (!shouldSet) return false;
186-
187-
manifest.homeScreenName = screenName;
188-
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
189-
return true;
190-
}
191-
192155
function screenTemplate(name: string): string {
193156
return `View:
194157
styles:
@@ -381,13 +344,10 @@ export async function addCommand(
381344
);
382345
}
383346

384-
const homeUpdated =
385-
kind === 'screen' ? await maybeSetHomeScreenName(projectRoot, name, interactive) : false;
386-
387347
ui.success(
388348
`Created ${kind} "${name}" at ${path.relative(
389349
projectRoot,
390350
filePath
391-
)}${updateManifest ? ' and updated .manifest.json' : ''}${homeUpdated ? ' (set as homeScreenName)' : ''}.`
351+
)}${updateManifest ? ' and updated .manifest.json' : ''}.`
392352
);
393353
}

src/commands/init.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import fs from 'fs/promises';
2-
import path from 'path';
31
import prompts from 'prompts';
42

53
import { checkAppAccess, fetchRootScreenName } from '../cloud/firestoreClient.js';
@@ -58,23 +56,6 @@ export async function initCommand(): Promise<void> {
5856
description: access.app.description,
5957
...(appHome !== undefined && { appHome }),
6058
});
61-
62-
if (appHome) {
63-
const manifestPath = path.join(process.cwd(), '.manifest.json');
64-
let manifest: Record<string, unknown> = {};
65-
try {
66-
const raw = await fs.readFile(manifestPath, 'utf8');
67-
manifest = JSON.parse(raw) as Record<string, unknown>;
68-
} catch {
69-
manifest = {};
70-
}
71-
72-
if (typeof manifest.homeScreenName !== 'string') {
73-
manifest.homeScreenName = appHome;
74-
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
75-
ui.note(`Updated .manifest.json: homeScreenName set to "${appHome}".`);
76-
}
77-
}
7859
ui.success(`Initialized Ensemble config and linked alias "${alias}" to app "${appId}".`);
7960
ui.note(`You can now run \`ensemble push --app ${alias}\` or \`ensemble pull --app ${alias}\`.`);
8061
}

src/commands/pull.ts

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ import { resolveAppContext } from '../config/projectConfig.js';
1717
import { getValidAuthSession } from '../auth/session.js';
1818
import { withSpinner } from '../lib/spinner.js';
1919
import { applyCloudStateToFs } from '../core/applyToFs.js';
20-
import {
21-
type RootManifest,
22-
getCloudHomeScreenName,
23-
type BuildManifestOptions,
24-
} from '../core/manifest.js';
20+
import { type RootManifest } from '../core/manifest.js';
2521
import { writeVerboseJson } from '../core/debugFiles.js';
2622
import { computePullPlan, type PullSummary } from '../core/sync.js';
2723
import { applyCloudAssetsToFs, buildEnvConfigForCloudAssets } from '../core/pullAssets.js';
@@ -324,41 +320,9 @@ export async function pullCommand(options: PullOptions = {}): Promise<void> {
324320
return;
325321
}
326322

327-
const appHome = appConfig.appHome as string | undefined;
328-
const cloudHome = getCloudHomeScreenName(cloudApp);
329-
const existingHome = manifestExisting.homeScreenName;
330-
const hasHomeConflict =
331-
typeof existingHome === 'string' && cloudHome && appHome && cloudHome !== appHome;
332-
333-
let manifestOptions: BuildManifestOptions = {
334-
appHomeFromConfig: appHome,
335-
};
336-
if (hasHomeConflict && process.stdout.isTTY && process.stdin.isTTY) {
337-
const choices: { title: string; value: string }[] = [
338-
{ title: `Keep current (${existingHome})`, value: existingHome },
339-
...(cloudHome && cloudHome !== existingHome
340-
? [{ title: `Use cloud (${cloudHome})`, value: cloudHome }]
341-
: []),
342-
...(appHome && appHome !== existingHome
343-
? [{ title: `Use config appHome (${appHome})`, value: appHome }]
344-
: []),
345-
].filter((c, i, a) => a.findIndex((x) => x.value === c.value) === i);
346-
347-
const { homeChoice } = await prompts({
348-
type: 'select',
349-
name: 'homeChoice',
350-
message: `homeScreenName conflict: .manifest has "${existingHome}", cloud has "${cloudHome ?? 'none'}"${appHome ? `, ensemble.config.json appHome is "${appHome}"` : ''}. Choose:`,
351-
choices,
352-
initial: 0,
353-
});
354-
if (homeChoice !== undefined) {
355-
manifestOptions = { ...manifestOptions, homeScreenNameOverride: homeChoice };
356-
}
357-
}
358-
359323
await withSpinner('Writing local files...', async () => {
360324
await applyCloudStateToFs(projectRoot, cloudApp, localFiles, enabledByProp, {
361-
manifestOptions,
325+
manifestOptions: {},
362326
onProgress: (completed, total) => {
363327
// eslint-disable-next-line no-console
364328
console.log(`Writing files... (${completed}/${total})`);

src/commands/push.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { getValidAuthSession } from '../auth/session.js';
2020
import { withSpinner } from '../lib/spinner.js';
2121
import { writeVerboseJson } from '../core/debugFiles.js';
2222
import { computePushPlan, type PushSummary, type PushCounts } from '../core/sync.js';
23-
import { buildAndWriteManifest, getCloudHomeScreenName } from '../core/manifest.js';
23+
import { buildAndWriteManifest } from '../core/manifest.js';
2424
import { ui } from '../core/ui.js';
2525

2626
export interface PushOptions {
@@ -34,6 +34,11 @@ export interface PushOptions {
3434

3535
const DESTRUCTIVE_CHANGE_PROMPT_THRESHOLD = 25;
3636

37+
function getCloudHomeScreenName(cloudApp: CloudApp): string | undefined {
38+
const screens = (cloudApp.screens ?? []).filter((s) => s.isArchived !== true);
39+
return screens.find((s) => s.isRoot === true)?.name ?? screens[0]?.name;
40+
}
41+
3742
/** Firestore/YAML artifact changes only (not asset uploads via studio function). */
3843
function yamlArtifactChangeTotal(summary: PushSummary): number {
3944
const k = summary.byKind;
@@ -448,13 +453,9 @@ export async function pushCommand(options: PushOptions = {}): Promise<void> {
448453

449454
if (manifestNeedsRefresh && bundle) {
450455
// Only refresh manifest when artifact changes can affect its contents.
451-
// Use appHome from config (what we pushed), not cloud's root.
452456
try {
453457
await withSpinner('Refreshing local manifest...', async () => {
454-
await buildAndWriteManifest(root, bundle as CloudApp, {
455-
appHomeFromConfig: appHome,
456-
...(appHome && { homeScreenNameOverride: appHome }),
457-
});
458+
await buildAndWriteManifest(root, bundle as CloudApp, {});
458459
});
459460
} catch (manifestErr) {
460461
if (verbose) {

src/commands/release.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,9 @@ export async function releaseUseCommand(options: ReleaseUseOptions = {}): Promis
373373
const snapshot = JSON.parse(snapshotJson) as CloudApp;
374374

375375
const localFiles = await collectAppFiles(projectRoot);
376-
const appHome = appConfig.appHome as string | undefined;
377376
await withSpinner('Writing local files...', () =>
378377
applyCloudStateToFs(projectRoot, snapshot, localFiles, enabledByProp, {
379-
manifestOptions: { appHomeFromConfig: appHome },
378+
manifestOptions: {},
380379
onProgress: (completed, total) => {
381380
if (total > 0 && completed % 25 === 0) {
382381
// eslint-disable-next-line no-console

src/core/manifest.ts

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,11 @@ export type RootManifest = Record<string, unknown> & {
77
scripts?: { name: string }[];
88
widgets?: { name: string }[];
99
actions?: { name: string }[];
10-
homeScreenName?: string;
1110
defaultLanguage?: string;
1211
languages?: string[];
1312
};
1413

15-
/** Get the screen name that cloud has as root (isRoot: true). */
16-
export function getCloudHomeScreenName(cloudApp: CloudApp): string | undefined {
17-
const screens = (cloudApp.screens ?? []).filter((s) => s.isArchived !== true);
18-
return screens.find((s) => s.isRoot === true)?.name ?? screens[0]?.name;
19-
}
20-
21-
export interface BuildManifestOptions {
22-
/** appHome from ensemble.config.json for the current app. */
23-
appHomeFromConfig?: string;
24-
/** When provided (e.g. from user prompt after conflict), use this value. Otherwise preserve existing if set. */
25-
homeScreenNameOverride?: string;
26-
}
14+
export type BuildManifestOptions = Record<string, never>;
2715

2816
/** Preserve existing manifest entries by name and order; only add minimal { name } for new ones. */
2917
function mergeByName<T extends { name: string }>(
@@ -50,7 +38,7 @@ export function buildManifestObject(
5038
cloudApp: CloudApp,
5139
options: BuildManifestOptions = {}
5240
): RootManifest {
53-
const { appHomeFromConfig, homeScreenNameOverride } = options;
41+
void options;
5442

5543
const cloudWidgetNames = (cloudApp.widgets ?? [])
5644
.filter((w) => w.isArchived !== true)
@@ -67,18 +55,6 @@ export function buildManifestObject(
6755
.map((a) => a.name);
6856
const actions = mergeByName(existing.actions, cloudActionNames);
6957

70-
const screens = (cloudApp.screens ?? []).filter((s) => s.isArchived !== true);
71-
const cloudHome = screens.find((s) => s.isRoot === true)?.name ?? screens[0]?.name;
72-
73-
let homeScreenName: string | undefined;
74-
if (homeScreenNameOverride) {
75-
homeScreenName = homeScreenNameOverride;
76-
} else if (typeof existing.homeScreenName === 'string') {
77-
homeScreenName = existing.homeScreenName;
78-
} else {
79-
homeScreenName = appHomeFromConfig ?? cloudHome;
80-
}
81-
8258
const translations = (cloudApp.translations ?? []).filter((t) => t.isArchived !== true);
8359
const languages = translations.map((t) => t.name);
8460
const defaultLanguage =
@@ -91,7 +67,6 @@ export function buildManifestObject(
9167
widgets,
9268
scripts,
9369
actions,
94-
...(homeScreenName ? { homeScreenName } : {}),
9570
...(languages.length > 0 ? { languages } : {}),
9671
...(defaultLanguage ? { defaultLanguage } : {}),
9772
};

tests/commands/pushPull.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ describe('push/pull integration (commands)', () => {
143143
{
144144
scripts: [],
145145
widgets: [],
146-
homeScreenName: 'Home',
147146
defaultLanguage: 'ar',
148147
languages: ['ar', 'en'],
149148
},
@@ -483,13 +482,11 @@ describe('push/pull integration (commands)', () => {
483482
const manifest = JSON.parse(manifestRaw) as {
484483
widgets?: { name: string }[];
485484
scripts?: { name: string }[];
486-
homeScreenName?: string;
487485
defaultLanguage?: string;
488486
languages?: string[];
489487
};
490488
expect(manifest.widgets?.some((w) => w.name === 'W1')).toBe(true);
491489
expect(manifest.scripts?.some((s) => s.name === 'S1')).toBe(true);
492-
expect(manifest.homeScreenName).toBe('Home');
493490
expect(manifest.defaultLanguage).toBe('ar');
494491
expect(manifest.languages).toEqual(['ar', 'en']);
495492

tests/core/applyToFs.test.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,21 @@ describe('applyCloudStateToFs', () => {
182182
};
183183

184184
await applyCloudStateToFs(projectRoot, cloudApp, localFiles, allEnabled, {
185-
manifestOptions: { appHomeFromConfig: 'Home' },
185+
manifestOptions: {},
186186
});
187187

188188
const manifestPath = path.join(projectRoot, '.manifest.json');
189189
const raw = await fs.readFile(manifestPath, 'utf8');
190190
const manifest = JSON.parse(raw) as {
191-
homeScreenName?: string;
192191
scripts?: unknown[];
193192
widgets?: unknown[];
193+
actions?: unknown[];
194+
languages?: unknown[];
195+
defaultLanguage?: unknown;
194196
};
195-
expect(manifest.homeScreenName).toBe('Home');
197+
expect(typeof manifest).toBe('object');
198+
// Ensure it's valid JSON and a root object; specific fields are asserted elsewhere.
199+
expect(Array.isArray(manifest.scripts ?? [])).toBe(true);
196200
});
197201

198202
it('invokes onProgress every 25 completed tasks', async () => {

0 commit comments

Comments
 (0)