mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
* feat(layout): add the inert workspace layout model, Loader and Serializer One model of a workspace's tab layout (all tab kinds, groups, split trees, pane bindings, titles/colors/pin, sleeping records) in src/shared/workspace-layout, with a Loader from today's stored session partition and a Serializer back to it. The structural rules check and the pure pane/group tree helpers move into the same folder so the module can run them; their callers import the new paths. Nothing in the app calls the new module yet. * fix(layout): avoid toSorted in shared code and drop an unused helper The mobile bundle includes src/shared and Hermes lacks Array#toSorted. * fix(layout): one stored home per layout fact; Loader reports every rule it applies The row's terminal id, preview flag, worktree id and execution host are now derived on save instead of kept a second time. Groups never stay empty. The Loader reports row/tab-bar disagreements, re-minted ids, worktree id and host disagreements, keeps a row stored in two workspaces where the tab bar names it, and gives a pane id repeated in a second tab a new unbound pane. The rules check runs on what the Serializer writes. Fixtures become test fixtures, and a test lists every model field with the one fact it holds. * fix(layout): derive each tab's host from its owner and keep one preview fact per editor tab An editor tab names its file's owner (an SSH target or paired runtime), every other tab its partition. Where the stored tab and file preview flags disagree the tab loads permanent, so a draft can never be replaced. A row terminal that differs from the one derived from its focused pane is now reported. * fix(layout): one binding kind, one title, one host rule; records follow a reassigned pane A legacy row with no pane layout now loads as a one-pane tab bound to its terminal (reusing the leaf its records name), so the null-panes branches and legacyPtyId are gone. A pane given a new id because two tabs shared it takes its sleeping and incarnation records, scrollback and focus with it. A terminal's live title is one fact (the tab-bar label wins on load). Every tab-bar entry names its execution host by one rule. The fact-location test is now keyed by on-disk field and checked by mutating every source. * fix(layout): one change report by construction; records without copies The Loader now picks values by fixed precedence only and reports one field-by-field diff of the stored session against what the next save writes, over the disk-field tables (now in workspace-layout-disk-fields.ts, with session fields derived from SESSION_FIELD_OWNERS). Sleeping and closed-tab records live in their workspace without the pane key, tab and worktree id their key and workspace already give; the Serializer fills them. Tab-bar entries are written in the one tab order. * fix(layout): name the change report's key-list parameter's type * refactor(layout): key pane data by leaf, check the model itself, one legacy record - Each pane's data (terminal, incarnation, title, sleeping agent) is one leaf record keyed by leaf id, and scrollback beside it is keyed the same way. Pane keys are derived only when saving. The Loader gives a repeated leaf id a new id before attaching records, so rekeyPaneRecords is gone; records naming no pane are carried as stored. - The rules check runs on the model directly (ungrouped tab, empty group, group tree that disagrees with the groups, pane data without a pane); the disk-format rules stay separate. - The row-ownership marker and topology revision move into one legacy record outside WorkspaceLayout, updated by updateLegacyPersistence after each apply. - Fixtures include a terminal tab whose tab-bar id and terminal id differ. * fix(layout): join the group ids the tree-mismatch detail names * fix(layout): leave the stored revision map as is when no repo advances
53 lines
2.0 KiB
JavaScript
53 lines
2.0 KiB
JavaScript
#!/usr/bin/env node
|
|
// Checks a profile's saved workspace layout against the structural layout rules
|
|
// (src/shared/workspace-layout/workspace-layout-rules.ts). Works on a running dev app's
|
|
// profile too. Usage: node config/scripts/check-workspace-layout-rules.mjs <userDataDir>
|
|
// Exits 1 when any rule is broken, printing one line per breach.
|
|
|
|
import { build } from 'esbuild'
|
|
import { mkdir, mkdtemp, rm } from 'node:fs/promises'
|
|
import { createRequire } from 'node:module'
|
|
import { join, resolve } from 'node:path'
|
|
|
|
const userDataDir = process.argv[2]
|
|
if (!userDataDir) {
|
|
console.error('usage: check-workspace-layout-rules.mjs <userDataDir>')
|
|
process.exit(2)
|
|
}
|
|
|
|
const root = resolve(import.meta.dirname, '..', '..')
|
|
await mkdir(join(root, '.tmp'), { recursive: true })
|
|
const scratch = await mkdtemp(join(root, '.tmp', 'layout-rules-'))
|
|
try {
|
|
const outfile = join(scratch, 'check.cjs')
|
|
await build({
|
|
stdin: {
|
|
contents: `
|
|
export { readPersistedProfileState } from './tests/e2e/helpers/persisted-profile-state'
|
|
export { partitionsFromProfileRoot } from './tests/e2e/helpers/workspace-layout-oracle-views'
|
|
export { checkWorkspaceLayoutRules } from './src/shared/workspace-layout/workspace-layout-rules'
|
|
`,
|
|
resolveDir: root,
|
|
loader: 'ts'
|
|
},
|
|
bundle: true,
|
|
platform: 'node',
|
|
format: 'cjs',
|
|
outfile,
|
|
external: ['electron', '@stablyai/playwright-test'],
|
|
logLevel: 'silent'
|
|
})
|
|
const { readPersistedProfileState, partitionsFromProfileRoot, checkWorkspaceLayoutRules } =
|
|
createRequire(import.meta.url)(outfile)
|
|
const violations = checkWorkspaceLayoutRules(
|
|
partitionsFromProfileRoot(readPersistedProfileState(resolve(userDataDir)))
|
|
)
|
|
for (const violation of violations) {
|
|
console.log(`${violation.rule}: ${violation.detail}`)
|
|
}
|
|
console.log(`${violations.length} layout rule breach(es) in ${userDataDir}`)
|
|
process.exitCode = violations.length > 0 ? 1 : 0
|
|
} finally {
|
|
await rm(scratch, { recursive: true, force: true })
|
|
}
|