oh-my-opencode 4.19.2 → 4.19.3

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.
Files changed (157) hide show
  1. package/.agents/command/publish.md +95 -28
  2. package/.agents/skills/publish/SKILL.md +20 -6
  3. package/.opencode/command/publish.md +95 -28
  4. package/THIRD-PARTY-NOTICES.md +7 -7
  5. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +1 -1
  6. package/dist/cli/config-migrate.d.ts +8 -0
  7. package/dist/cli/doctor/checks/legacy-config-leftovers.d.ts +10 -0
  8. package/dist/cli/doctor/checks/model-resolution-config.d.ts +1 -1
  9. package/dist/cli/doctor/checks/tools-lsp.d.ts +1 -1
  10. package/dist/cli/doctor/framework/constants.d.ts +1 -1
  11. package/dist/cli/index.js +95557 -92944
  12. package/dist/cli-node/index.js +95539 -92926
  13. package/dist/config/validate.d.ts +2 -1
  14. package/dist/config-migration/deep-diff.d.ts +1 -0
  15. package/dist/config-migration/discovery-paths.d.ts +11 -0
  16. package/dist/config-migration/discovery-roots.d.ts +7 -0
  17. package/dist/config-migration/discovery.d.ts +4 -0
  18. package/dist/config-migration/index.d.ts +9 -0
  19. package/dist/config-migration/legacy-history.d.ts +3 -0
  20. package/dist/config-migration/migration-executor.d.ts +4 -0
  21. package/dist/config-migration/migration-plans.d.ts +14 -0
  22. package/dist/config-migration/record-values.d.ts +4 -0
  23. package/dist/config-migration/schema-url.d.ts +1 -0
  24. package/dist/config-migration/transform-config-jsonc.d.ts +2 -0
  25. package/dist/config-migration/transform-opencode.d.ts +2 -0
  26. package/dist/config-migration/transform-types.d.ts +24 -0
  27. package/dist/config-migration/types.d.ts +39 -0
  28. package/dist/features/builtin-commands/templates/hyperplan.d.ts +1 -1
  29. package/dist/hooks/auto-update-checker/constants.d.ts +3 -3
  30. package/dist/index.js +10424 -8161
  31. package/dist/plugin-config/omo-config-chain.d.ts +14 -0
  32. package/dist/plugin-config/unknown-key-diagnostics.d.ts +5 -0
  33. package/dist/plugin-config.d.ts +2 -2
  34. package/dist/shared/agent-display-names.d.ts +1 -1
  35. package/dist/shared/jsonc-parser.d.ts +1 -1
  36. package/dist/shared/migration.d.ts +5 -1
  37. package/dist/shared/opencode-config-dir-types.d.ts +0 -1
  38. package/dist/shared/plugin-identity.d.ts +6 -8
  39. package/dist/shared/project-discovery-dirs.d.ts +0 -1
  40. package/dist/skills/frontend/ATTRIBUTION.md +7 -0
  41. package/dist/skills/frontend/SKILL.md +4 -1
  42. package/dist/skills/frontend/references/design/README.md +8 -0
  43. package/dist/skills/frontend/references/design/_INDEX.md +14 -1
  44. package/dist/skills/frontend/references/design/interaction-skill.md +144 -0
  45. package/dist/startup-migration.d.ts +28 -0
  46. package/dist/testing/create-plugin-module.d.ts +4 -0
  47. package/dist/tui.js +5356 -4643
  48. package/package.json +13 -13
  49. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +19 -3
  50. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +11 -2
  51. package/packages/omo-codex/THIRD-PARTY-NOTICES.md +2 -2
  52. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  53. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  54. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +11 -5
  56. package/packages/omo-codex/plugin/components/codegraph/NOTICE +1 -1
  57. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +10153 -2571
  58. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +7311 -572
  59. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  60. package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +33 -0
  61. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +36 -10
  62. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +164 -159
  63. package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +34 -0
  64. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +20 -2
  65. package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +106 -0
  66. package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +145 -0
  67. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +21 -0
  68. package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +139 -0
  69. package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +15 -0
  70. package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +32 -0
  71. package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +109 -0
  72. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +148 -0
  73. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +126 -175
  74. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +4 -4
  75. package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +160 -0
  76. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +12 -138
  77. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +28 -24
  78. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +3 -3
  79. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +2 -2
  80. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +5 -5
  81. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -3
  82. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
  83. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +45 -0
  84. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +2 -2
  85. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +70 -13
  86. package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +58 -0
  87. package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +104 -0
  88. package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +4 -2
  89. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +116 -0
  90. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +58 -57
  91. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  92. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  93. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  94. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  95. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  96. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  97. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  98. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  99. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/rules/dist/cli.js +31 -14
  101. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  102. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  103. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  104. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  105. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  106. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  107. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  108. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  109. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  110. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  111. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  112. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +17 -0
  114. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  123. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  126. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  134. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  136. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  137. package/packages/omo-codex/plugin/package-lock.json +42 -41
  138. package/packages/omo-codex/plugin/package.json +1 -1
  139. package/packages/omo-codex/plugin/shared/src/config-loader.ts +165 -16
  140. package/packages/omo-codex/plugin/shared/src/config-migration.ts +162 -0
  141. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +186 -9
  142. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +7 -0
  143. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -1
  144. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +8 -0
  145. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +14 -1
  146. package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +144 -0
  147. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +17 -0
  148. package/packages/omo-codex/scripts/install-dist/install-local.mjs +1 -1
  149. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +7 -0
  150. package/packages/shared-skills/skills/frontend/SKILL.md +4 -1
  151. package/packages/shared-skills/skills/frontend/references/design/README.md +8 -0
  152. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +14 -1
  153. package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +144 -0
  154. package/dist/plugin-config/layered-config-loader.d.ts +0 -2
  155. package/dist/plugin-config/single-config-loader.d.ts +0 -4
  156. package/dist/shared/migrate-legacy-config-file.d.ts +0 -1
  157. package/dist/shared/migration/config-migration.d.ts +0 -1
@@ -1,9 +1,14 @@
1
1
  import { afterEach, describe, expect, it } from "bun:test"
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"
3
3
  import { tmpdir } from "node:os"
4
- import { join } from "node:path"
4
+ import { join, posix } from "node:path"
5
5
 
6
- import { getCodexOmoConfig } from "../src/config-loader.ts"
6
+ import { parse } from "jsonc-parser"
7
+
8
+ import { runMigrations, type MigrationBoundary } from "../../../../omo-config-core/src/index.ts"
9
+ import { createLegacyConfigMigrationPlans } from "../../../../omo-opencode/src/config-migration/index.ts"
10
+
11
+ import { getCodexOmoConfig, runCodexStartupMigration } from "../src/config-loader.ts"
7
12
 
8
13
  const temporaryDirectories: string[] = []
9
14
 
@@ -14,11 +19,51 @@ function createTemporaryDirectory(prefix: string): string {
14
19
  }
15
20
 
16
21
  function writeOmoConfig(homeDir: string, content: string): void {
22
+ const configDir = join(homeDir, ".omo")
23
+ mkdirSync(configDir, { recursive: true })
24
+ writeFileSync(join(configDir, "omo.jsonc"), content)
25
+ }
26
+
27
+ function writeLegacyOmoConfig(homeDir: string, content: string): void {
17
28
  const configDir = join(homeDir, ".omo")
18
29
  mkdirSync(configDir, { recursive: true })
19
30
  writeFileSync(join(configDir, "config.jsonc"), content)
20
31
  }
21
32
 
33
+ function isRecord(value: unknown): value is Record<string, unknown> {
34
+ return typeof value === "object" && value !== null && !Array.isArray(value)
35
+ }
36
+
37
+ function readOmoJson(homeDir: string): Record<string, unknown> {
38
+ const value: unknown = parse(readFileSync(join(homeDir, ".omo", "omo.jsonc"), "utf-8"))
39
+ if (!isRecord(value)) throw new Error("Expected an omo JSONC object")
40
+ return value
41
+ }
42
+
43
+ function writeOpenCodeConfig(homeDir: string): void {
44
+ const configDir = join(homeDir, ".config", "opencode")
45
+ mkdirSync(configDir, { recursive: true })
46
+ writeFileSync(join(configDir, "oh-my-openagent.jsonc"), '{"agents":{"finder":{"model":"provider/finder"}}}')
47
+ }
48
+
49
+ function runOpenCodeMigration(homeDir: string, cwd: string, onBoundary?: (boundary: MigrationBoundary) => void): void {
50
+ runMigrations({
51
+ discover: () => createLegacyConfigMigrationPlans({
52
+ cwd,
53
+ environment: { HOME: homeDir, XDG_CONFIG_HOME: join(homeDir, ".config") },
54
+ homeDir,
55
+ pathOperations: posix,
56
+ }),
57
+ env: { HOME: homeDir },
58
+ ...(onBoundary === undefined ? {} : { onBoundary }),
59
+ })
60
+ }
61
+
62
+ function migrationIds(homeDir: string): readonly string[] {
63
+ const migrations = readOmoJson(homeDir)["_migrations"]
64
+ return Array.isArray(migrations) ? migrations.filter((entry): entry is string => typeof entry === "string") : []
65
+ }
66
+
22
67
  afterEach(() => {
23
68
  for (const directory of temporaryDirectories.splice(0)) {
24
69
  rmSync(directory, { recursive: true, force: true })
@@ -86,6 +131,20 @@ describe("getCodexOmoConfig", () => {
86
131
  expect(result.codegraph?.excluded_roots).toEqual(["/tmp/omo-research", "/private/tmp/omo-research"])
87
132
  })
88
133
 
134
+ it("#given codex SOT sets the SessionStart cooldown #when loading config #then the configured base interval is returned", () => {
135
+ // given
136
+ const homeDir = createTemporaryDirectory("omo-codex-shared-cooldown-home-")
137
+ const cwd = createTemporaryDirectory("omo-codex-shared-cooldown-project-")
138
+ writeOmoConfig(homeDir, JSON.stringify({ "[codex]": { codegraph: { session_start_cooldown_ms: 900_000 } } }))
139
+
140
+ // when
141
+ const result = getCodexOmoConfig({ cwd, homeDir, env: {} })
142
+
143
+ // then
144
+ expect(result.codegraph?.session_start_cooldown_ms).toBe(900_000)
145
+ expect(result.warnings).toEqual([])
146
+ })
147
+
89
148
  it("#given no codegraph.daemon key #when loading config #then daemon defaults to on", () => {
90
149
  // given
91
150
  const homeDir = createTemporaryDirectory("omo-codex-shared-daemon-default-home-")
@@ -125,24 +184,24 @@ describe("getCodexOmoConfig", () => {
125
184
 
126
185
  // then
127
186
  expect(result.codegraph?.daemon).toBe(true)
128
- expect(result.warnings).toContain("config.[codex].codegraph.daemon must be a boolean")
187
+ expect(result.warnings).toContain(`Invalid omo config at ${join(homeDir, ".omo", "omo.jsonc")}: [codex].codegraph.daemon`)
129
188
  })
130
189
 
131
190
  it("#given legacy env override and SOT value #when loading config #then env wins over the SOT", () => {
132
191
  // given
133
192
  const homeDir = createTemporaryDirectory("omo-codex-shared-env-")
134
193
  const cwd = createTemporaryDirectory("omo-codex-project-env-")
135
- writeOmoConfig(homeDir, JSON.stringify({ codegraph: { enabled: true } }))
194
+ writeOmoConfig(homeDir, JSON.stringify({ codegraph: { enabled: false } }))
136
195
 
137
196
  // when
138
197
  const result = getCodexOmoConfig({
139
198
  cwd,
140
199
  homeDir,
141
- env: { CODEX_CODEGRAPH_ENABLED: "0" },
200
+ env: { CODEX_CODEGRAPH_ENABLED: "1" },
142
201
  })
143
202
 
144
203
  // then
145
- expect(result.codegraph?.enabled).toBe(false)
204
+ expect(result.codegraph?.enabled).toBe(true)
146
205
  })
147
206
 
148
207
  it("#given no SOT files #when loading config #then returns built-in defaults and missing global source", () => {
@@ -163,8 +222,8 @@ describe("getCodexOmoConfig", () => {
163
222
  expect(result.sources).toContainEqual({
164
223
  exists: false,
165
224
  loaded: false,
166
- path: join(homeDir, ".omo", "config.jsonc"),
167
- scope: "global",
225
+ path: join(homeDir, ".omo", "omo.jsonc"),
226
+ scope: "user",
168
227
  })
169
228
  })
170
229
 
@@ -180,4 +239,122 @@ describe("getCodexOmoConfig", () => {
180
239
  // then
181
240
  expect(result.warnings).toContain("codegraph.watch_debounce_ms is not supported for harness codex")
182
241
  })
242
+
243
+ it("#given only legacy config.jsonc #when codex starts #then migrates once with a backup before loading the unified codex view", () => {
244
+ // given
245
+ const homeDir = createTemporaryDirectory("omo-codex-legacy-upgrade-")
246
+ writeLegacyOmoConfig(homeDir, JSON.stringify({ "[codex]": { codegraph: { daemon: false } } }))
247
+ const legacyPath = join(homeDir, ".omo", "config.jsonc")
248
+
249
+ // when
250
+ const first = getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
251
+ const backupDirectories = readdirSync(join(homeDir, ".omo")).filter((entry) => entry.startsWith("migration-backup-"))
252
+ const second = getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
253
+
254
+ // then
255
+ expect(first.codegraph?.daemon).toBe(false)
256
+ expect(first.warnings.some((warning) => warning.startsWith("omo-codex: migrated legacy configuration from ")
257
+ && warning.endsWith("/.omo/config.jsonc"))).toBe(true)
258
+ expect(readOmoJson(homeDir)["_migrations"]).toEqual(["2026-07-codex-config-jsonc"])
259
+ expect(existsSync(legacyPath)).toBe(false)
260
+ expect(backupDirectories).toHaveLength(1)
261
+ expect(existsSync(join(homeDir, ".omo", backupDirectories[0] ?? "", ".omo", "config.jsonc"))).toBe(true)
262
+ expect(second.warnings.some((warning) => warning.startsWith("omo-codex: migrated legacy configuration from "))).toBe(false)
263
+ expect(readdirSync(join(homeDir, ".omo")).filter((entry) => entry.startsWith("migration-backup-"))).toEqual(backupDirectories)
264
+ })
265
+
266
+ it("#given a legacy migration conflict #when codex starts #then exposes the migration summary and conflict through loader warnings", () => {
267
+ // given
268
+ const homeDir = createTemporaryDirectory("omo-codex-legacy-conflict-")
269
+ writeOmoConfig(homeDir, JSON.stringify({ codegraph: { enabled: true } }))
270
+ writeLegacyOmoConfig(homeDir, JSON.stringify({ codegraph: { enabled: false } }))
271
+
272
+ // when
273
+ const result = getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
274
+
275
+ // then
276
+ expect(result.warnings.some((warning) => warning.startsWith("omo-codex: migrated legacy configuration from ")
277
+ && warning.endsWith("/.omo/config.jsonc"))).toBe(true)
278
+ expect(result.warnings).toContain("omo-codex: configuration migration: skipped: codegraph.enabled legacy=false kept=true")
279
+ })
280
+
281
+ it("#given overlapping [omo] and [senpi] blocks in legacy config #when Codex migrates #then the transform conflict is reported", () => {
282
+ // given
283
+ const homeDir = createTemporaryDirectory("omo-codex-legacy-senpi-conflict-")
284
+ writeLegacyOmoConfig(homeDir, JSON.stringify({
285
+ "[omo]": { agents: { oracle: { model: "legacy" } } },
286
+ "[senpi]": { agents: { oracle: { model: "current" } } },
287
+ }))
288
+
289
+ // when
290
+ const result = runCodexStartupMigration({ cwd: homeDir, environment: { HOME: homeDir }, homeDir })
291
+
292
+ // then
293
+ expect(result.results[0]?.diagnostics).toContain("conflict: [senpi] legacy [omo] kept [senpi]")
294
+ })
295
+
296
+ it("#given a malformed migration journal #when codex starts #then exposes the recovery failure through loader warnings", () => {
297
+ // given
298
+ const homeDir = createTemporaryDirectory("omo-codex-recovery-warning-")
299
+ const migrationDir = join(homeDir, ".omo")
300
+ mkdirSync(migrationDir, { recursive: true })
301
+ writeFileSync(join(migrationDir, ".migration-journal.json"), "not-json")
302
+
303
+ // when
304
+ const result = getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
305
+
306
+ // then
307
+ expect(result.warnings.some((warning) => warning.startsWith("omo-codex: configuration migration: "))).toBe(true)
308
+ })
309
+
310
+ it("#given codex starts before opencode #when both legacy source groups exist #then each distinct migration id is applied once", () => {
311
+ // given
312
+ const homeDir = createTemporaryDirectory("omo-codex-order-codex-first-")
313
+ writeLegacyOmoConfig(homeDir, JSON.stringify({ "[codex]": { codegraph: { daemon: false } } }))
314
+ writeOpenCodeConfig(homeDir)
315
+ const openCodeSource = join(homeDir, ".config", "opencode", "oh-my-openagent.jsonc")
316
+
317
+ // when
318
+ getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
319
+ const remainsAfterCodexStartup = existsSync(openCodeSource)
320
+ runOpenCodeMigration(homeDir, homeDir)
321
+
322
+ // then
323
+ expect(remainsAfterCodexStartup).toBe(true)
324
+ expect(existsSync(openCodeSource)).toBe(false)
325
+ expect(migrationIds(homeDir)).toEqual(["2026-07-codex-config-jsonc", "2026-07-opencode-config-unification"])
326
+ })
327
+
328
+ it("#given opencode starts before codex #when both legacy source groups exist #then each distinct migration id is applied once", () => {
329
+ // given
330
+ const homeDir = createTemporaryDirectory("omo-codex-order-opencode-first-")
331
+ writeLegacyOmoConfig(homeDir, JSON.stringify({ "[codex]": { codegraph: { daemon: false } } }))
332
+ writeOpenCodeConfig(homeDir)
333
+
334
+ // when
335
+ runOpenCodeMigration(homeDir, homeDir)
336
+ getCodexOmoConfig({ cwd: homeDir, homeDir, env: {} })
337
+
338
+ // then
339
+ expect(migrationIds(homeDir)).toEqual(["2026-07-opencode-config-unification", "2026-07-codex-config-jsonc"])
340
+ })
341
+
342
+ it("#given concurrent codex and opencode starts #when opencode owns the shared lock #then both migration ids are applied exactly once", () => {
343
+ // given
344
+ const homeDir = createTemporaryDirectory("omo-codex-order-concurrent-")
345
+ writeLegacyOmoConfig(homeDir, JSON.stringify({ "[codex]": { codegraph: { daemon: false } } }))
346
+ writeOpenCodeConfig(homeDir)
347
+ let codexResult: ReturnType<typeof runCodexStartupMigration> | undefined
348
+
349
+ // when
350
+ runOpenCodeMigration(homeDir, homeDir, (boundary) => {
351
+ if (boundary !== "journal-written" || codexResult !== undefined) return
352
+ codexResult = runCodexStartupMigration({ cwd: homeDir, homeDir })
353
+ })
354
+
355
+ // then
356
+ if (codexResult === undefined) throw new Error("Expected concurrent Codex migration attempt")
357
+ expect(codexResult.error).toBe("Configuration migration is already running")
358
+ expect(migrationIds(homeDir)).toEqual(["2026-07-opencode-config-unification", "2026-07-codex-config-jsonc"])
359
+ })
183
360
  })
@@ -210,6 +210,13 @@ no Lazyweb source, documentation text, or screenshot content is vendored. Lazywe
210
210
  remain the property of their owner, and the guide grants no license to ship, trace, or
211
211
  commit reference screenshots harvested through it.
212
212
 
213
+ `frontend/references/design/interaction-skill.md` is a project-original, curl-only
214
+ operating guide for consulting the beui.dev animated-component registry during interaction
215
+ and motion work, written from live endpoint verification; no beui.dev source code,
216
+ documentation text, or component implementations are vendored. beui.dev names remain the
217
+ property of their owner, and the guide instructs reading component source for mechanism
218
+ extraction only, not vendoring it into references or projects.
219
+
213
220
  `frontend/references/design/clone-from-url.md` is a project-original runtime-extraction
214
221
  workflow guide. Its browser + `getComputedStyle` clone approach follows the same
215
222
  MIT-licensed `JCodesMore/ai-website-cloner-template` clone-website workflow that `aside.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: frontend
3
- description: "MUST USE for frontend/web UI/UX/visual work: building, styling, redesigning pages/components, React setup, performance audits, visual QA, taste, and polish. Routes four rulesets: design taste router and brand references; perfection for Playwright/Chromium Lighthouse/Core Web Vitals; ui-ux-db palettes/fonts/guidelines; designpowers personas/accessibility/critique/handoff; plus curl-only lazyweb real-app-screen research for design direction. Triggers: frontend, UI, UX, design, redesign, styling, layout, animation, motion, premium, luxury, minimal, brutalist, Awwwards, DESIGN.md, mockup, React, Lighthouse, accessibility, WCAG, Core Web Vitals, looks generic, make it pretty, like X brand, lazyweb, design research."
3
+ description: "MUST USE for frontend/web UI/UX/visual work: building, styling, redesigning pages/components, React setup, performance audits, visual QA, taste, and polish. Routes four rulesets: design taste router and brand references; perfection for Playwright/Chromium Lighthouse/Core Web Vitals; ui-ux-db palettes/fonts/guidelines; designpowers personas/accessibility/critique/handoff; plus curl-only lazyweb real-app-screen research and the beui.dev interaction catalog. Triggers: frontend, UI, UX, design, redesign, styling, layout, animation, motion, interaction, micro-interaction, make it feel alive, premium, luxury, minimal, brutalist, Awwwards, DESIGN.md, mockup, React, Lighthouse, accessibility, WCAG, Core Web Vitals, looks generic, make it pretty, like X brand, lazyweb, design research."
4
4
  ---
5
5
 
6
6
  # Frontend
@@ -14,6 +14,7 @@ This file is a router, not a rulebook. The rules live in four rulesets under `re
14
14
  | Request involves… | Read |
15
15
  |---|---|
16
16
  | ANY UI implementation, styling, redesign, mockup, or visual decision | `references/design/README.md` FIRST. It enforces two mandatory gates — the Design System Gate (a `DESIGN.md` must exist before any component is written) and the React Dev Tooling Gate (react-grab / react-scan / react-doctor installed by default) — then routes to the taste and brand references below. |
17
+ | Interaction or motion work — micro-interactions, animated components, transitions, gestures, hover/press/state feedback, "make it feel alive" | ALSO `references/design/interaction-skill.md`. The beui.dev catalog is the mandatory interaction reference: find the nearest pattern, read its real source through the file's curl recipe, and adapt the mechanism to `DESIGN.md` motion tokens. It stacks on the routed style skill — never replaces it. |
17
18
  | Writing or modifying frontend code, OR auditing performance / SEO / accessibility / quality | ALSO `references/perfection/README.md`. Lighthouse 100 in every category, measured on real Playwright Chromium (never the `lighthouse` CLI), achieved through architecture — never by dropping animations or hiding content. |
18
19
  | Looking up a concrete style, color palette, font pairing, chart type, landing-page structure, or UX guideline — or generating a project design system from keywords | `references/ui-ux-db/README.md`. A searchable CSV database with a CLI; a lookup tool, not a posture. Load on demand; `design` stays the source of truth for taste and the `DESIGN.md` contract. |
19
20
  | ANY implementation or redesign that creates or updates `DESIGN.md` — plus explicit operating-layer asks (personas, critique, debt, handoff, synthetic user testing) | `references/designpowers/README.md` + `references/designpowers/lane-c-review.md`. An internal frontend ruleset, not a separate skill: lane-c is the Phase Final flatness/critique reviewer, and its accessibility-constraints and accepted-debt language fills the required `DESIGN.md` sections. Load other lanes only when their phase applies. |
@@ -61,6 +62,7 @@ The reference library has one architecture file, 12 taste skills (Layer A — *h
61
62
  | `image-to-code-skill.md` | "Generate the design first, then code it." Pair with one imagegen file below. |
62
63
  | `output-skill.md` | Stacks on any style skill when output is incomplete — placeholders, `// TODO`, half-done components. |
63
64
  | `stitch-skill.md` | Stacks on any style skill for Google Stitch compatibility or a `DESIGN.md` doc export. A complete worked export ships as `stitch-design-example.md`. |
65
+ | `interaction-skill.md` | Stacks on any style skill when work adds or changes interaction or motion. beui.dev-anchored: read the mapped component's source before designing an interaction; reduced motion always. |
64
66
  | `imagegen-frontend-web.md` / `imagegen-frontend-mobile.md` / `imagegen-brandkit.md` | Image-only output (mockup, app-screen concepts, brand board). These NEVER write code — switch to `image-to-code-skill.md` if code is wanted. |
65
67
 
66
68
  ### Layer B — brand design systems (orthogonal to Layer A; stack freely)
@@ -113,6 +115,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
113
115
  | "Linear-style landing page" | `design/README.md` + `design/linear.app.md` + `design/taste-skill.md` + `perfection/README.md` |
114
116
  | "Premium SaaS hero like Stripe" | `design/README.md` + `design/stripe.md` + `design/soft-skill.md` + `perfection/README.md` |
115
117
  | "Improve this existing dashboard" | `design/README.md` + `design/redesign-skill.md` + `perfection/README.md` |
118
+ | "Add micro-interactions" / "animate this" / "make it feel alive" / "polish the interactions" | `design/README.md` + `design/interaction-skill.md` on top of the current style skill + `perfection/README.md` |
116
119
  | "Build this screenshot / Imagen mock / Stitch output exactly" | `design/README.md` + `design/image-to-code-skill.md` + `perfection/README.md` + `/visual-qa` reference-fidelity mode |
117
120
  | "Audit my site" / "make this page faster" | `perfection/README.md` (+ `perfection/react-perf-tooling.md` if React) |
118
121
  | "Mockup image of a fintech app" — no code | `design/imagegen-frontend-mobile.md` (+ a Layer B brand if named) |
@@ -175,6 +175,12 @@ Triggers: dashboard, settings, mail/inbox, list-detail, command surface, split p
175
175
 
176
176
  **Action:** Add `layout-skill.md` on top of whatever style skill you selected in Steps 1-2. It carries scroll-ownership doctrine, the two silently-failing CSS contracts (`min-block-size: 0` scroll shells, `minmax(min(…),100%)` grids), the named-primitive vocabulary, container-vs-viewport routing, and the content-stress matrix. It adds no visual direction — the style skill still owns taste. Skip it for pure scroll-the-document marketing pages, where `taste-skill` layout guidance already fits.
177
177
 
178
+ ### Step 9 — Does the work add or change interaction or motion?
179
+
180
+ Triggers: micro-interactions, animated components, transitions, gestures, hover/press/focus/state feedback, loading/success/error morphs, animated tabs/menus/modals/drawers/toasts — or "make it feel alive", "polish the interactions", "add micro-interactions".
181
+
182
+ **Action:** Add `interaction-skill.md` on top of whatever style skill you selected. It anchors interaction design to the beui.dev catalog: find the nearest pattern, read its real source through the file's curl recipe, extract the mechanism (spring config, layout strategy, enter/exit order, reduced-motion path), and adapt the values to `DESIGN.md`. It owns interaction mechanics only — no visual direction — so it stacks cleanly, like `layout-skill.md`.
183
+
178
184
  ## Stacking rules (read this once, internalize it)
179
185
 
180
186
  1. **At most one Layer A *style* skill at a time.** A layout cannot be both `minimalist-skill` and `brutalist-skill` simultaneously — they encode opposite spacing and typography philosophies. Pick one.
@@ -184,6 +190,7 @@ Triggers: dashboard, settings, mail/inbox, list-detail, command surface, split p
184
190
  5. **`image-to-code-skill.md` pairs with one imagegen skill** for the full flow.
185
191
  6. **Layer B (brand DESIGN.md) is orthogonal to Layer A.** You can pair any Layer A skill with any Layer B brand. Use Layer B as the source of color/type/component tokens; let Layer A drive the execution discipline.
186
192
  7. **`layout-skill.md` stacks on top of any style skill** for app-shell / dashboard / split-pane work. It owns spatial structure and scroll ownership only — no visual direction — so it never conflicts with the style skill you picked.
193
+ 8. **`interaction-skill.md` stacks on top of any style skill** for interaction/motion work. It owns interaction mechanics — springs, layout morphs, enter/exit orchestration, reduced motion — and no visual direction, so it never conflicts with the style skill either.
187
194
 
188
195
  ## Anti-patterns — do not do these
189
196
 
@@ -227,6 +234,7 @@ Once references are loaded, before writing any UI code:
227
234
  | "Also output a DESIGN.md doc" | Add `stitch-skill.md` to current stack |
228
235
  | "Build a dashboard / settings / inbox / app shell" | one style skill (usually `taste-skill.md`) + `layout-skill.md` |
229
236
  | "Panel won't scroll / footer pushed off-screen / mobile overflow" | Add `layout-skill.md` to current stack |
237
+ | "Add micro-interactions / animate this / make it feel alive" | Add `interaction-skill.md` to current stack |
230
238
 
231
239
  ## Phase Final — Design QA (MANDATORY, runs after implementation)
232
240
 
@@ -5,7 +5,7 @@ All reference files live flat in this directory. Three layers:
5
5
  - **Layer A — taste skills** (12 files): how to execute. Discipline, motion, spacing, anti-slop, output completeness.
6
6
  - **Layer B — design systems** (70 files): what it should look like. Brand-specific color/type/component tokens.
7
7
 
8
- **Phase 0 runs first** (check/create `DESIGN.md`), then most non-trivial tasks load **one Layer A + one Layer B** together. See the routing flow in the sibling `README.md`.
8
+ **Phase 0 runs first** (check/create `DESIGN.md`), then most non-trivial tasks load **one Layer A + one Layer B** together. See the routing flow in the sibling `README.md`. Specialized phases (interaction and motion, app-shell layout, URL clones, real-product screen research) load the matching project-original operating reference — see the final section of this index.
9
9
 
10
10
  ---
11
11
 
@@ -52,6 +52,19 @@ From [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill).
52
52
 
53
53
  ---
54
54
 
55
+ ## Operating references — interaction, layout, and research workflows (project-original)
56
+
57
+ Beyond the 12-file Layer A library, the design ruleset carries project-original operating references for specialized phases. They stack on the routed Layer A + Layer B pair; they never replace a style skill, and they are not counted in the library totals above.
58
+
59
+ | File | Purpose | Load when |
60
+ |---|---|---|
61
+ | `interaction-skill.md` | Interaction mechanics anchored to the beui.dev catalog: find the nearest pattern, read its real source through the curl recipe, extract the mechanism (spring config, layout strategy, enter/exit order, reduced-motion path), and adapt it to `DESIGN.md` motion tokens. | Any work adding or changing interaction or motion — micro-interactions, animated components, transitions, gestures, hover/press/state feedback, loading/success/error morphs, "make it feel alive". |
62
+ | `layout-skill.md` | Layout mechanics: scroll ownership, the two silent CSS contracts, named primitives, content-stress matrix. Zero visual direction. | App shells, dashboards, split panes, or a layout that breaks under real content. |
63
+ | `lazyweb.md` | Curl-only real-product screen research for design direction. | Greenfield design research lanes. |
64
+ | `clone-from-url.md` | Runtime extraction workflow (browser + `getComputedStyle`) for cloning a named site. | A live site or URL is the visual reference. |
65
+
66
+ ---
67
+
55
68
  ## Layer B — Design Systems (70)
56
69
 
57
70
  Most Layer B files are materialized from [VoltAgent/awesome-design-md](https://github.com/VoltAgent/awesome-design-md), based on [Google Stitch DESIGN.md format](https://stitch.withgoogle.com/docs/design-md/overview/). Project-original entries such as `aside.md` are listed here only when `ATTRIBUTION.md` and `frontend-refs-manifest.mjs` mark them as original. Each file captures one website's complete visual language: color palette, typography, components, layout principles, depth, do/don't, responsive behavior, and an agent prompt guide.
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: interaction-skill
3
+ description: "Layer A interaction-mechanics reference anchored to the beui.dev catalog. Stacks on any style skill whenever work adds or changes motion or interaction — micro-interactions, animated components, transitions, gestures, hover/press/state feedback, loading/success/error morphs, 'make it feel alive'. Mandates reading the mapped beui.dev component source before designing an interaction; owns interaction mechanics and reduced-motion discipline; owns zero visual taste. Load it alongside a style skill; it does not replace one."
4
+ ---
5
+
6
+ # Interaction Mechanics — beui.dev-Anchored
7
+
8
+ Style skills decide how a surface looks. This file decides how it *moves and responds* — spring physics, layout morphs, enter/exit orchestration, gesture feel, and reduced-motion discipline. It stacks on top of any Layer A style skill and any Layer B brand, exactly like `layout-skill.md`, and adds ZERO visual direction: color, type, and material still come from the style skill and `DESIGN.md`.
9
+
10
+ Load this whenever the deliverable includes interaction feel: micro-interactions, animated components, transitions, hover/press/focus/state feedback, gestures, loading/success/error morphs, animated tabs/menus/modals/drawers/toasts — or the user says "make it feel alive", "polish the interactions", "add micro-interactions".
11
+
12
+ ## 1. The reference contract — never design an interaction from memory
13
+
14
+ [beui.dev](https://beui.dev) is the interaction benchmark: free, open-source animated React components (Motion + Tailwind CSS) where every component ships reduced-motion support and the full TypeScript source is one `curl` away. Improvised interaction design produces slop motion the same way freestyled styling produces generic SaaS slop, and the fix is the same: consult the reference before designing.
15
+
16
+ The contract, in order:
17
+
18
+ 1. **Find the nearest pattern** in the catalog (section 3). The live catalog is `https://beui.dev/llms.txt`; refresh from it when a pattern seems missing from the tables below.
19
+ 2. **Read its real source** through the recipe (section 2). Never guess spring values, exit orchestration, or gesture thresholds from a preview description.
20
+ 3. **Extract the mechanism**, not the pixels: the spring config, the layout strategy (`layoutId` shared layout vs height morph vs clip-path), what animates in what order on enter/exit, where blur crossfades sit, and what the reduced-motion path swaps to.
21
+ 4. **Adapt to the project.** Concrete durations, easings, and spring params come from the project `DESIGN.md` Motion & Interaction section. Where beui.dev and `DESIGN.md` disagree, `DESIGN.md` wins. A value that is not in `DESIGN.md` gets added there first, then used.
22
+ 5. **No matching pattern?** Compose from the nearest two, or state explicitly that the interaction is novel and record its mechanism in `DESIGN.md` before building it.
23
+
24
+ ## 2. Consultation recipe (curl-only, verified 2026-07)
25
+
26
+ All endpoints are public, no auth, no browser:
27
+
28
+ ```bash
29
+ curl -s https://beui.dev/llms.txt # full catalog: every component + one-line feel
30
+ curl -s https://beui.dev/r # registry index (JSON): slugs, categories, endpoints
31
+ curl -s https://beui.dev/r/{slug} # component detail (JSON): files, dependencies, dates
32
+ curl -s https://beui.dev/r/{slug}/raw # component source (TypeScript) — the thing to read
33
+ curl -s https://beui.dev/components/{category}/{slug}.md # component doc page as markdown
34
+ ```
35
+
36
+ Categories are `motion` (primitives) and `blocks` (composed patterns). When the user wants the component itself rather than the mechanism, a shadcn-style item registry exists at `https://beui.dev/r/{slug}.json`. Read source to learn; do not vendor beui.dev files into reference docs, and do not paste whole components into a project when only the mechanism is needed.
37
+
38
+ ## 3. Catalog — pattern routing map
39
+
40
+ ### Buttons, state feedback, and progress
41
+
42
+ | Pattern (slug) | Mechanism | Reach for it when |
43
+ |---|---|---|
44
+ | `button` | Spring press; StatefulButton idle → loading → success/error with blur-swap slots and morphing width; MagneticButton cursor pull | Any submit/CTA that has async states — never leave a button state-less |
45
+ | `action-swap` | Text/icon swap with blur motion | Copy → check, send → stop, any label that changes meaning in place |
46
+ | `expanding-arrow-button` | Expanding, hold-to-confirm, and slide CTA interactions | Expressive marketing CTAs, destructive hold-to-confirm |
47
+ | `animated-badge` | Animated state icons, pulse feedback | Connection/status dots, live activity indicators |
48
+ | `loader` | 17 variants incl. terminal-ascii; reduced motion swaps every transform for an opacity pulse | Any loading state; copy its reduced-motion contract even when hand-rolling |
49
+ | `otp-input` | Gliding focus ring, per-slot digit roll, error shake, success check draw | Code entry, verification flows |
50
+ | `file-upload` | Progress rows, retry/remove, reduced-motion-safe state changes | Upload queues, long-running item lists |
51
+ | `feedback-widget` | Trigger morphs into a popup with sending/success/retry states | Corner feedback affordances, inline report flows |
52
+
53
+ ### Selection and form controls
54
+
55
+ | Pattern (slug) | Mechanism | Reach for it when |
56
+ |---|---|---|
57
+ | `switch` | Spring-driven thumb with press feedback | Boolean toggles |
58
+ | `checkbox` | Draw-on checkmark, indeterminate support | Multi-select, tree selection |
59
+ | `radio` | Gliding `layoutId` indicator dot | Single-select groups |
60
+ | `input` | Label, icons, error shake, success check draw | Validated text entry |
61
+ | `select` | Panel bouncily unfolds from the trigger; Morph variant grows the trigger into the panel | Dropdown selection with spatial continuity |
62
+ | `range-slider` | Bouncy vertical-bar thumb gliding between snapped steps | Stepped value entry |
63
+ | `wheel-picker` | iOS-style 3D drum on native momentum scroll with notch snap | Date/time or option drums, mobile-feel pickers |
64
+ | `availability-scheduler` | Per-day spring toggles, blur-slide range add/remove | Schedule/slot editors |
65
+
66
+ ### Navigation and wayfinding
67
+
68
+ | Pattern (slug) | Mechanism | Reach for it when |
69
+ |---|---|---|
70
+ | `tabs` | Pill/segment/underline with a spring `layoutId` indicator | Tab bars, view-mode selectors |
71
+ | `expandable-tabs` | Active icon tab expands to a labelled pill; panel morphs height, slides direction-aware | Compact tab bars with rich panels |
72
+ | `shared-layout-bg` | Pill glides between hovered items via shared layout, blur enter/exit | Sidebar/menu hover and active states |
73
+ | `dock` | macOS-style grouped actions with a gliding active pill | Toolbars, grouped action rails |
74
+ | `bounce-sidebar` | Active dot jumps between destinations on a curved spring path | Vertical navigation with a playful indicator |
75
+ | `preview-rail` | Compact ticks form a hover pyramid and reveal a floating destination preview | Dense navigation rails, session/thread switchers |
76
+ | `expandable-action-bar` | Icon actions expand into labelled controls on hover/focus | Compact action clusters |
77
+ | `overflow-actions` | Connected pill rail springs open to reveal extra controls | Primary-plus-overflow action groups |
78
+ | `command-palette` | Fuzzy filter with a spring-animated active row | Cmd-K surfaces |
79
+ | `bloom-menu` | Button morphs into a menu blooming iris-out from center with radial stagger | Radial/launcher menus |
80
+
81
+ ### Overlays and surfaces
82
+
83
+ | Pattern (slug) | Mechanism | Reach for it when |
84
+ |---|---|---|
85
+ | `tooltip` | Blur enter/exit, spring spawn | Hover/focus hints |
86
+ | `popover` | Gooey SVG-filter ooze from the trigger; Morph variant clip-morphs from the trigger corner | Anchored panels that should feel attached to their trigger |
87
+ | `context-menu` | Pointer-origin clip morph, gliding active row, keyboard nav, typeahead, long-press | Right-click and long-press menus |
88
+ | `morphing-modal` | One panel morphs height between inner views, blur cross-fade on content | Multi-step dialogs, settings panes |
89
+ | `center-morph-modal` | Surface unfolds from its exact center toward every edge and folds back | Focused confirm/detail modals |
90
+ | `drawer` | Spring side panel, backdrop blur, body scroll lock, esc-to-close | Side panels, inspector panes |
91
+ | `bottom-sheet` | Draggable sheet with snap points, inertia, glass surface | Mobile-feel sheets on any platform |
92
+ | `dynamic-island` | Pill morphs between live-activity views with bouncy shell resize and blur crossfades | Live status surfaces, compact expanding widgets |
93
+ | `notification-stack` | Cards spring from a stacked summary into a readable list on hover/focus/tap | Notification centers, grouped alerts |
94
+ | `animated-toast-stack` | Status morphs, swipe dismissal, layout-aware stacking | Toast systems — layout-aware stacking is the bar |
95
+ | `theme-toggle` | Full-page clip-path reveal via the View Transition API | Theme switching that should feel like one gesture |
96
+
97
+ ### Content, data, and gestures
98
+
99
+ | Pattern (slug) | Mechanism | Reach for it when |
100
+ |---|---|---|
101
+ | `bouncy-accordion` | Single-open accordion with weighted spring layout, reduced-motion-safe reveals | Disclosure groups, expandable rows |
102
+ | `table` | Virtualized 10k+ rows, sortable, resizable, minimal reduced-motion-safe motion | Data grids — proof that restraint is also a motion decision |
103
+ | `infinite-masonry` | Virtualized variable-height masonry with progressive load | Media/card walls |
104
+ | `swipeable-list` | Rows swipe to reveal contextual actions | Mobile-style lists with hidden actions |
105
+ | `pull-to-refresh` | Drag resistance, threshold feedback, async refresh | Refreshable feeds |
106
+ | `marquee` | Infinite horizontal/vertical scroll, pause on hover | Logo walls, tickers |
107
+ | `text-animation` | Spring reveals, chromatic sweeps, shimmer loading, letter-cascade swaps | Hero copy, streaming/loading text |
108
+ | `number` | Count-up values, rolling digit tickers | Metrics, token/cost counters |
109
+ | `cylinder-carousel` | Items line a 3D cylinder with springy glide and snap | Showcase carousels |
110
+ | `knockout-bracket` | Animated tournament fixtures paging through rounds | Bracket/progression views |
111
+ | `prediction-market` / `swap` / `wallet-card` | Trade tickets, morphing swap views, morphing account surfaces | Finance-shaped composite widgets |
112
+ | `not-found` | Five animated 404 styles | Error pages that keep the product's feel |
113
+
114
+ ### Ambience and scroll
115
+
116
+ | Pattern (slug) | Mechanism | Reach for it when |
117
+ |---|---|---|
118
+ | `tilt-card` | 3D perspective tilt with cursor-tracked glare | Hero/product cards that should feel physical |
119
+ | `shader-background` | Canvas shader variants (mesh gradient, grain, warp, waves…); reduced motion freezes them | Atmospheric backgrounds with dimension |
120
+ | `scroll-animation` | Lenis smooth-scroll provider plus a reading-progress indicator | Scroll-driven storytelling |
121
+
122
+ ## 4. Mechanics rules
123
+
124
+ These sharpen the shared axioms for interaction work; none of them replace the style skill.
125
+
126
+ - **Motion serves meaning.** Every animation maps to a real interaction, state change, or affordance. A hover that changes nothing is slop — beui.dev patterns all animate *state*, never decoration.
127
+ - **Reduced motion is part of the component, not an afterthought.** Every beui.dev component ships a reduced-motion path; match that bar. Web: `prefers-reduced-motion: reduce` disables or replaces every transform-based animation (the `loader` pattern's opacity-pulse swap is the model). React Native: respect the system reduce-motion setting.
128
+ - **GPU-composited properties only** — `transform`, `opacity`, `filter`. Never animate layout properties; morph layout through shared-layout (`layoutId`) or measured height primitives instead.
129
+ - **Springs move things; easings tint things.** Spatial movement (position, scale, layout morphs) wants spring physics so it stays interruptible and retargetable. Color, opacity, and blur want short duration + easing. Do not put a fixed-duration tween on a gesture-driven surface.
130
+ - **Interruptibility is non-negotiable.** A press, hover-out, or route change mid-animation must retarget smoothly, never queue or block input. This is the practical reason beui.dev uses springs — copy that property, not just the bounce.
131
+ - **Motion never regresses input latency or stream rendering.** Measure with the `perfection` ruleset when in doubt; a virtualized list's measurement contract beats a pretty reveal.
132
+ - **Library choice is a project decision, not a default.** beui.dev assumes Motion (motion.dev) + Tailwind. If the project already has a motion stack, adapt the mechanism to it. If it has none: CSS transitions/WAAPI cover micro-interactions; adding a library is justified by shared-layout or spring-physics needs and gets recorded (with bundle cost) in `DESIGN.md`. Check `package.json` before importing anything.
133
+
134
+ ## 5. DESIGN.md integration
135
+
136
+ `design-system-architecture.md` defines a Motion & Interaction section in every `DESIGN.md`. This file feeds it:
137
+
138
+ - Extracted spring configs, durations, and easings land there as named tokens before components use them.
139
+ - Each shipped interaction traces to a catalog pattern (or a recorded novel mechanism) plus its reduced-motion behavior.
140
+ - New reusable interaction patterns (used 2+ times) get documented back into `DESIGN.md` Section 5 with their states, like any other primitive.
141
+
142
+ ## 6. Verification
143
+
144
+ Interaction work is verified through `/visual-qa` with motion actually driven and inspected — hover, press, open/close, swipe, and theme transitions exercised on the rendered surface, plus a reduced-motion pass (emulate `prefers-reduced-motion: reduce`) proving the fallback exists. Timing-sensitive changes record a short screen capture, not just stills.
@@ -34,6 +34,23 @@ This skill is intentionally compact. The full workflow lives in `references/full
34
34
  - Fallback only when the child is completed without the deliverable, ack-only after `followup_task`, explicitly `BLOCKED:`, or no longer running. Then record inconclusive and respawn a smaller `fork_turns: "none"` task with the missing deliverable.
35
35
  - Use `git-master` for git-tracked edits: inspect recent and touched-path commit history, then commit each verified work unit atomically in the repository's observed language, scope, and message style with only that unit's files staged. Never carry verified units into a later omnibus commit.
36
36
 
37
+ ## Team mode: decide it, do not default to it
38
+
39
+ Solo execution with parallel background `task` workers is the default. A team (`team_create`) adds per-member briefing, shared-state, and relay overhead, so it must be paid for by the work's shape. Decide ONCE, when the plan's work units are known, and record the verdict plus its reason in the notepad.
40
+
41
+ Stand up a team when BOTH hold:
42
+
43
+ 1. **The units' scopes overlap in a way you cannot cleanly cut.** They touch the same module, contract, or migration, so one unit's discovery changes what another should do. Fire-and-forget workers cannot exchange that mid-flight; teammates can, because the lead relays it.
44
+ 2. **Running them at the same time actually finishes sooner.** The units are each substantial and none is merely waiting on another's output. Two units where the second only consumes the first's result are a sequence, not a team.
45
+
46
+ When the units are genuinely independent — separate files, no shared contract — spawn parallel background `task` workers instead and avoid the team coordination overhead entirely. When the work is one cohesive unit, do it yourself. Overlap alone is not enough: near-identical units that would collide on the same lines are faster done in sequence by one worker.
47
+
48
+ Under team mode, isolate and land per unit:
49
+
50
+ - **One git worktree per member**, never a shared checkout — concurrent members editing one working tree corrupt each other's diffs and evidence. Give each member its own branch off the base and its own worktree path.
51
+ - **Merge per work unit, as each unit is verified.** A member's unit lands when its own evidence is captured and its gates are green; it does not wait for the slowest sibling. Integrate each merged unit back into the base the others branch from, so overlapping members rebase onto real merged work rather than guessing at it.
52
+ - **Conflicts are the lead's job.** When two members' units touch the same lines, the lead decides the order they land and tells the later member what changed; members never resolve a sibling's conflict blind.
53
+
37
54
  ## Codex Tool Mapping
38
55
 
39
56
  Codex exposes ONE subagent surface per session — check your tool list. GPT-5.6 (sol/terra) get the flat MultiAgentV2 tools (primary); GPT-5.5 and gpt-5.6-luna get the namespaced `multi_agent_v1.*` set (fallback row). The workflow's orchestration examples map to:
@@ -5903,7 +5903,7 @@ var package_default;
5903
5903
  var init_package = __esm(() => {
5904
5904
  package_default = {
5905
5905
  name: "@oh-my-opencode/omo-codex",
5906
- version: "4.19.2",
5906
+ version: "4.19.3",
5907
5907
  type: "module",
5908
5908
  private: true,
5909
5909
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -210,6 +210,13 @@ no Lazyweb source, documentation text, or screenshot content is vendored. Lazywe
210
210
  remain the property of their owner, and the guide grants no license to ship, trace, or
211
211
  commit reference screenshots harvested through it.
212
212
 
213
+ `frontend/references/design/interaction-skill.md` is a project-original, curl-only
214
+ operating guide for consulting the beui.dev animated-component registry during interaction
215
+ and motion work, written from live endpoint verification; no beui.dev source code,
216
+ documentation text, or component implementations are vendored. beui.dev names remain the
217
+ property of their owner, and the guide instructs reading component source for mechanism
218
+ extraction only, not vendoring it into references or projects.
219
+
213
220
  `frontend/references/design/clone-from-url.md` is a project-original runtime-extraction
214
221
  workflow guide. Its browser + `getComputedStyle` clone approach follows the same
215
222
  MIT-licensed `JCodesMore/ai-website-cloner-template` clone-website workflow that `aside.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: frontend
3
- description: "MUST USE for frontend/web UI/UX/visual work: building, styling, redesigning pages/components, React setup, performance audits, visual QA, taste, and polish. Routes four rulesets: design taste router and brand references; perfection for Playwright/Chromium Lighthouse/Core Web Vitals; ui-ux-db palettes/fonts/guidelines; designpowers personas/accessibility/critique/handoff; plus curl-only lazyweb real-app-screen research for design direction. Triggers: frontend, UI, UX, design, redesign, styling, layout, animation, motion, premium, luxury, minimal, brutalist, Awwwards, DESIGN.md, mockup, React, Lighthouse, accessibility, WCAG, Core Web Vitals, looks generic, make it pretty, like X brand, lazyweb, design research."
3
+ description: "MUST USE for frontend/web UI/UX/visual work: building, styling, redesigning pages/components, React setup, performance audits, visual QA, taste, and polish. Routes four rulesets: design taste router and brand references; perfection for Playwright/Chromium Lighthouse/Core Web Vitals; ui-ux-db palettes/fonts/guidelines; designpowers personas/accessibility/critique/handoff; plus curl-only lazyweb real-app-screen research and the beui.dev interaction catalog. Triggers: frontend, UI, UX, design, redesign, styling, layout, animation, motion, interaction, micro-interaction, make it feel alive, premium, luxury, minimal, brutalist, Awwwards, DESIGN.md, mockup, React, Lighthouse, accessibility, WCAG, Core Web Vitals, looks generic, make it pretty, like X brand, lazyweb, design research."
4
4
  ---
5
5
 
6
6
  # Frontend
@@ -14,6 +14,7 @@ This file is a router, not a rulebook. The rules live in four rulesets under `re
14
14
  | Request involves… | Read |
15
15
  |---|---|
16
16
  | ANY UI implementation, styling, redesign, mockup, or visual decision | `references/design/README.md` FIRST. It enforces two mandatory gates — the Design System Gate (a `DESIGN.md` must exist before any component is written) and the React Dev Tooling Gate (react-grab / react-scan / react-doctor installed by default) — then routes to the taste and brand references below. |
17
+ | Interaction or motion work — micro-interactions, animated components, transitions, gestures, hover/press/state feedback, "make it feel alive" | ALSO `references/design/interaction-skill.md`. The beui.dev catalog is the mandatory interaction reference: find the nearest pattern, read its real source through the file's curl recipe, and adapt the mechanism to `DESIGN.md` motion tokens. It stacks on the routed style skill — never replaces it. |
17
18
  | Writing or modifying frontend code, OR auditing performance / SEO / accessibility / quality | ALSO `references/perfection/README.md`. Lighthouse 100 in every category, measured on real Playwright Chromium (never the `lighthouse` CLI), achieved through architecture — never by dropping animations or hiding content. |
18
19
  | Looking up a concrete style, color palette, font pairing, chart type, landing-page structure, or UX guideline — or generating a project design system from keywords | `references/ui-ux-db/README.md`. A searchable CSV database with a CLI; a lookup tool, not a posture. Load on demand; `design` stays the source of truth for taste and the `DESIGN.md` contract. |
19
20
  | ANY implementation or redesign that creates or updates `DESIGN.md` — plus explicit operating-layer asks (personas, critique, debt, handoff, synthetic user testing) | `references/designpowers/README.md` + `references/designpowers/lane-c-review.md`. An internal frontend ruleset, not a separate skill: lane-c is the Phase Final flatness/critique reviewer, and its accessibility-constraints and accepted-debt language fills the required `DESIGN.md` sections. Load other lanes only when their phase applies. |
@@ -61,6 +62,7 @@ The reference library has one architecture file, 12 taste skills (Layer A — *h
61
62
  | `image-to-code-skill.md` | "Generate the design first, then code it." Pair with one imagegen file below. |
62
63
  | `output-skill.md` | Stacks on any style skill when output is incomplete — placeholders, `// TODO`, half-done components. |
63
64
  | `stitch-skill.md` | Stacks on any style skill for Google Stitch compatibility or a `DESIGN.md` doc export. A complete worked export ships as `stitch-design-example.md`. |
65
+ | `interaction-skill.md` | Stacks on any style skill when work adds or changes interaction or motion. beui.dev-anchored: read the mapped component's source before designing an interaction; reduced motion always. |
64
66
  | `imagegen-frontend-web.md` / `imagegen-frontend-mobile.md` / `imagegen-brandkit.md` | Image-only output (mockup, app-screen concepts, brand board). These NEVER write code — switch to `image-to-code-skill.md` if code is wanted. |
65
67
 
66
68
  ### Layer B — brand design systems (orthogonal to Layer A; stack freely)
@@ -113,6 +115,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
113
115
  | "Linear-style landing page" | `design/README.md` + `design/linear.app.md` + `design/taste-skill.md` + `perfection/README.md` |
114
116
  | "Premium SaaS hero like Stripe" | `design/README.md` + `design/stripe.md` + `design/soft-skill.md` + `perfection/README.md` |
115
117
  | "Improve this existing dashboard" | `design/README.md` + `design/redesign-skill.md` + `perfection/README.md` |
118
+ | "Add micro-interactions" / "animate this" / "make it feel alive" / "polish the interactions" | `design/README.md` + `design/interaction-skill.md` on top of the current style skill + `perfection/README.md` |
116
119
  | "Build this screenshot / Imagen mock / Stitch output exactly" | `design/README.md` + `design/image-to-code-skill.md` + `perfection/README.md` + `/visual-qa` reference-fidelity mode |
117
120
  | "Audit my site" / "make this page faster" | `perfection/README.md` (+ `perfection/react-perf-tooling.md` if React) |
118
121
  | "Mockup image of a fintech app" — no code | `design/imagegen-frontend-mobile.md` (+ a Layer B brand if named) |