Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,14 @@ export async function add_site(target: string, options: AddOptions) {
// dashboard doesn't invent an ad-hoc group id for it.
if (config.group === 'default') {
const site_groups = server_config.site_groups ?? []
if (!site_groups.some((group) => group.id === 'default')) {
// After the first import, server.yaml holds the server's id for the
// Default group rather than the `default` slug. Point this site at that
// group instead of adding a second "Default".
const existing_default = site_groups.find((group) => group.id !== 'default' && group.name.toLowerCase() === 'default')
if (existing_default) {
config.group = existing_default.id
await write_site_config(site_dir, config)
} else if (!site_groups.some((group) => group.id === 'default')) {
server_config = {
...server_config,
site_groups: [...site_groups, { id: 'default', name: 'Default', index: site_groups.length }]
Expand Down
1 change: 1 addition & 0 deletions src/commands/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ Without the MCP server, read \`sites/*/blocks/*/fields.yaml\` and \`sites/*/page
- \`primo dev\` — start the local CMS and dev server. Run from the workspace root. It runs until stopped; from scripts or agents, run it in the background and stop it by PID.
- \`primo new [name]\` — scaffold a new site under \`sites/\`. In an interactive terminal it then starts the CMS; add \`--skip-dev\` to only create files.
- \`primo add <name>\` — register an existing \`sites/<name>\` folder with the CMS (mints its site_id and imports its records). Creating the folder alone doesn't register it. Stop \`primo dev\` first, then start it again afterwards. A folder copied from another site gets fresh ids automatically.
- \`primo preview --dir sites/<name>\` — build that site's preview (needs \`primo dev\` running). Until a site's preview is built, its preview URL shows the CMS instead; rebuild after edits to see them there.
- File edits sync automatically while \`primo dev\` is running. Structural changes (block schema, component) may trigger a browser reload.

## Shared library
Expand Down
13 changes: 12 additions & 1 deletion src/utils/server-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,18 @@ export async function read_server_config(base_dir: string): Promise<ServerConfig

export const DEFAULT_PORT = 3000

// One entry per group id. Older paths could append a second copy of a group
// (same server id, next index) when a site still referenced the local
// `default` slug; drop repeats and close the index gaps they leave.
function dedupe_site_groups(groups: SiteGroupConfig[] | undefined): SiteGroupConfig[] | undefined {
if (!groups) return groups
const seen = new Set<string>()
const unique = groups.filter(group => !seen.has(group.id) && !!seen.add(group.id))
if (unique.length === groups.length) return groups
return unique.map((group, index) => ({ ...group, index }))
}

export async function write_server_config(base_dir: string, config: ServerConfig): Promise<void> {
const normalized = normalize_server_config(config)
const normalized = normalize_server_config({ ...config, site_groups: dedupe_site_groups(config.site_groups) })
await fs.writeFile(get_server_config_path(base_dir), dump_yaml(normalized, { lineWidth: -1, noRefs: true }))
}
12 changes: 12 additions & 0 deletions tests/group-writeback.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,15 @@ describe('apply_server_group_id', () => {
}
})
})

test('write_server_config keeps one entry per group id and heals existing duplicates', async () => {
const { write_server_config, read_server_config } = await import('../dist/utils/server-config.js')
const dir = await (await import('node:fs/promises')).mkdtemp((await import('node:path')).join((await import('node:os')).tmpdir(), 'groups-'))
await write_server_config(dir, { site_groups: [
{ id: 'okwtvqfzrek51by', name: 'Default', index: 0 },
{ id: 'okwtvqfzrek51by', name: 'Default', index: 1 },
{ id: 'clientsgroup001', name: 'Clients', index: 2 }
] })
const { site_groups } = await read_server_config(dir)
assert.deepEqual(site_groups.map(g => [g.id, g.index]), [['okwtvqfzrek51by', 0], ['clientsgroup001', 1]])
})
Loading