oh-my-opencode 4.14.0 → 4.14.2

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 (140) hide show
  1. package/.agents/skills/codex-qa/references/isolation.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/cli/doctor/framework/types.d.ts +2 -0
  4. package/dist/cli/index.js +223 -1447
  5. package/dist/cli-node/index.js +223 -1447
  6. package/dist/index.js +4255 -714
  7. package/dist/plugin/native-skills.d.ts +9 -0
  8. package/dist/plugin/system-transform.d.ts +1 -1
  9. package/dist/skills/frontend/ATTRIBUTION.md +7 -1
  10. package/dist/skills/frontend/SKILL.md +4 -3
  11. package/dist/skills/frontend/references/design/README.md +4 -3
  12. package/dist/skills/frontend/references/design/_INDEX.md +5 -3
  13. package/dist/skills/frontend/references/design/aside.md +209 -0
  14. package/dist/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
  15. package/dist/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  16. package/dist/skills/lcx-doctor/SKILL.md +48 -13
  17. package/dist/skills/lcx-doctor/agents/openai.yaml +1 -1
  18. package/dist/skills/lcx-report-bug/SKILL.md +44 -13
  19. package/dist/skills/lcx-report-bug/agents/openai.yaml +1 -1
  20. package/dist/skills/visual-qa/SKILL.md +5 -5
  21. package/dist/skills/visual-qa/references/agent-browser-setup.md +5 -4
  22. package/dist/skills/visual-qa/scripts/cli.test.ts +7 -2
  23. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +10 -2
  24. package/dist/skills/visual-qa/scripts/visual-qa.mjs +530 -0
  25. package/dist/tools/delegate-task/skill-resolver.d.ts +1 -0
  26. package/dist/tools/delegate-task/types.d.ts +2 -0
  27. package/dist/tools/skill/types.d.ts +1 -0
  28. package/package.json +26 -13
  29. package/packages/git-bash-mcp/dist/cli.js +2 -0
  30. package/packages/lsp-daemon/dist/cli.js +15 -4
  31. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +1 -0
  32. package/packages/lsp-daemon/dist/ensure-daemon.js +9 -3
  33. package/packages/lsp-daemon/dist/index.js +15 -4
  34. package/packages/lsp-daemon/dist/paths.d.ts +1 -0
  35. package/packages/lsp-daemon/dist/paths.js +6 -1
  36. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  37. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +4 -7
  38. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +1 -1
  40. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +123 -10
  41. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +123 -10
  42. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +126 -9
  44. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +141 -0
  45. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  46. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  47. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +90 -25
  49. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +2 -0
  50. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +2 -0
  51. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +56 -0
  52. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  53. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +2 -5
  54. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +2 -0
  55. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +65 -0
  56. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +6 -1
  57. package/packages/omo-codex/plugin/components/rules/dist/cli.js +8 -106
  58. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  59. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -17
  60. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  61. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +17 -5
  63. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +63 -1
  64. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +80 -50
  65. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  66. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
  67. package/packages/omo-codex/plugin/components/ultrawork/directive.md +4 -12
  68. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  69. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +7 -33
  70. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +4 -12
  71. package/packages/omo-codex/plugin/components/ulw-loop/package.json +4 -2
  72. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
  73. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +4 -4
  74. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/sample-quality-gate.json +7 -7
  75. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +3 -1
  76. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-doc.test.ts +2 -2
  77. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +7 -6
  78. package/packages/omo-codex/plugin/package-lock.json +16 -56
  79. package/packages/omo-codex/plugin/package.json +1 -1
  80. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +7 -1
  81. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -3
  82. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +4 -3
  83. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +5 -3
  84. package/packages/omo-codex/plugin/skills/frontend/references/design/aside.md +209 -0
  85. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
  86. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  87. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +48 -13
  88. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  89. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +44 -13
  90. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  91. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +17 -5
  92. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +63 -1
  93. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +80 -50
  94. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
  95. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +4 -4
  96. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +5 -5
  97. package/packages/omo-codex/plugin/skills/visual-qa/references/agent-browser-setup.md +5 -4
  98. package/packages/omo-codex/plugin/skills/visual-qa/scripts/visual-qa.mjs +530 -0
  99. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +23 -0
  100. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +38 -2
  101. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +12 -11
  102. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +99 -1
  103. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +62 -8
  104. package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +1 -0
  105. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +102 -0
  106. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +41 -1
  107. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +93 -0
  108. package/packages/omo-codex/scripts/install-bin-links.test.mjs +6 -0
  109. package/packages/omo-codex/scripts/install-cache-copy.test.mjs +28 -0
  110. package/packages/omo-codex/scripts/install-config-autonomous-features.test.mjs +43 -3
  111. package/packages/omo-codex/scripts/install-delegated-command.test.mjs +93 -0
  112. package/packages/omo-codex/scripts/install-dist/install-local.mjs +169 -41
  113. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +21 -2
  114. package/packages/omo-codex/scripts/install-local.test.mjs +0 -1
  115. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +7 -1
  116. package/packages/shared-skills/skills/frontend/SKILL.md +4 -3
  117. package/packages/shared-skills/skills/frontend/references/design/README.md +4 -3
  118. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +5 -3
  119. package/packages/shared-skills/skills/frontend/references/design/aside.md +209 -0
  120. package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
  121. package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  122. package/packages/shared-skills/skills/lcx-doctor/SKILL.md +48 -13
  123. package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +1 -1
  124. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +44 -13
  125. package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +1 -1
  126. package/packages/shared-skills/skills/visual-qa/SKILL.md +5 -5
  127. package/packages/shared-skills/skills/visual-qa/references/agent-browser-setup.md +5 -4
  128. package/packages/shared-skills/skills/visual-qa/scripts/cli.test.ts +7 -2
  129. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +10 -2
  130. package/packages/shared-skills/skills/visual-qa/scripts/visual-qa.mjs +530 -0
  131. package/dist/cli/sparkshell-appserver-websocket.d.ts +0 -4
  132. package/dist/cli/sparkshell-appserver.d.ts +0 -16
  133. package/dist/cli/sparkshell-condense.d.ts +0 -10
  134. package/dist/cli/sparkshell-parse.d.ts +0 -24
  135. package/dist/cli/sparkshell-session-context.d.ts +0 -20
  136. package/dist/cli/sparkshell-spark.d.ts +0 -23
  137. package/dist/cli/sparkshell.d.ts +0 -33
  138. package/dist/shared/sparkshell-awareness.d.ts +0 -5
  139. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +0 -106
  140. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +0 -355
@@ -75,11 +75,104 @@ test("#given a dry-run doctor #when delegating #then routes to the Codex LazyCod
75
75
  // then
76
76
  assert.equal(ran, false);
77
77
  assert.match(logged, /^codex exec /);
78
+ assert.match(logged, /--sandbox danger-full-access/);
79
+ assert.doesNotMatch(logged, /--model/);
80
+ assert.doesNotMatch(logged, /gpt-5\.5-codex-mini/);
81
+ assert.doesNotMatch(logged, /--sandbox read-only/);
78
82
  assert.match(logged, /Use \$omo:lcx-doctor/);
83
+ assert.match(logged, /LAZYCODEX_SOURCE_ROOT/);
84
+ assert.match(logged, /\$\{TMPDIR:-\/tmp\}\/lazycodex-sources/);
79
85
  assert.match(logged, /Requested doctor arguments: --json/);
80
86
  assert.doesNotMatch(logged, /oh-my-openagent omo doctor/);
81
87
  });
82
88
 
89
+ test("#given doctor without model override #when delegating #then uses the configured Codex default model", async () => {
90
+ // given
91
+ const parsed = { kind: "command", command: "doctor", args: ["--json"] };
92
+
93
+ // when
94
+ const invocation = buildDelegatedOmoInvocation(parsed);
95
+
96
+ // then
97
+ assert.equal(invocation.command, "codex");
98
+ assert.equal(invocation.args.includes("--model"), false);
99
+ assert.equal(invocation.args.some((arg) => arg.includes("gpt-5.5-codex-mini")), false);
100
+ });
101
+
102
+ test("#given explicit doctor model override #when delegating #then passes only that model to Codex exec", async () => {
103
+ // given
104
+ const parsed = { kind: "command", command: "doctor", args: ["--model", "gpt-5.5", "--json"] };
105
+
106
+ // when
107
+ const invocation = buildDelegatedOmoInvocation(parsed);
108
+
109
+ // then
110
+ assert.equal(invocation.command, "codex");
111
+ assert.deepEqual(invocation.args.slice(0, 9), [
112
+ "exec",
113
+ "--ephemeral",
114
+ "--sandbox",
115
+ "danger-full-access",
116
+ "--skip-git-repo-check",
117
+ "--cd",
118
+ ".",
119
+ "--model",
120
+ "gpt-5.5",
121
+ ]);
122
+ assert.match(invocation.args.at(-1), /Requested doctor arguments: --json/);
123
+ assert.doesNotMatch(invocation.args.at(-1), /--model/);
124
+ });
125
+
126
+ test("#given doctor source-root override #when delegating #then passes it to the Codex workflow environment", async () => {
127
+ // given
128
+ const parsed = { kind: "command", command: "doctor", args: ["--source-root", "/var/tmp/lcx-sources", "--json"] };
129
+
130
+ // when
131
+ const invocation = buildDelegatedOmoInvocation(parsed);
132
+
133
+ // then
134
+ assert.equal(invocation.env?.LAZYCODEX_SOURCE_ROOT, "/var/tmp/lcx-sources");
135
+ assert.deepEqual(invocation.args.slice(0, 7), [
136
+ "exec",
137
+ "--ephemeral",
138
+ "--sandbox",
139
+ "danger-full-access",
140
+ "--skip-git-repo-check",
141
+ "--cd",
142
+ ".",
143
+ ]);
144
+ assert.match(invocation.args.at(-1), /Requested doctor arguments: --json/);
145
+ assert.doesNotMatch(invocation.args.at(-1), /--source-root/);
146
+ });
147
+
148
+ test("#given dry-run install without explicit platform #when delegating #then logs one Windows-safe Codex install command", async () => {
149
+ // given
150
+ const parsed = {
151
+ kind: "command",
152
+ command: "install",
153
+ dryRun: true,
154
+ noTui: true,
155
+ skipAuth: false,
156
+ autonomousPermissions: true,
157
+ repoRoot: undefined,
158
+ args: [],
159
+ };
160
+ const logged = [];
161
+
162
+ // when
163
+ await runDelegatedOmoCommand(parsed, {
164
+ cwd: "/tmp/project",
165
+ log: (line) => {
166
+ logged.push(line);
167
+ },
168
+ runCommand: async () => {},
169
+ });
170
+
171
+ // then
172
+ assert.deepEqual(logged, [
173
+ "npx --yes oh-my-openagent@latest install --platform=codex --no-tui --codex-autonomous",
174
+ ]);
175
+ });
83
176
  test("#given doctor recursion guard is active #when lazycodex doctor delegates #then rejects before launching Codex", async () => {
84
177
  // given
85
178
  const parsed = { kind: "command", command: "doctor", args: [] };
@@ -5907,7 +5907,7 @@ var package_default;
5907
5907
  var init_package = __esm(() => {
5908
5908
  package_default = {
5909
5909
  name: "@oh-my-opencode/omo-codex",
5910
- version: "4.14.0",
5910
+ version: "4.14.2",
5911
5911
  type: "module",
5912
5912
  private: true,
5913
5913
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -6603,10 +6603,9 @@ function posixRuntimeWrapper(cliPath, codexHome, binDir, nodeCliPath) {
6603
6603
  "#!/bin/sh",
6604
6604
  `# ${RUNTIME_WRAPPER_MARKER}`,
6605
6605
  `export CODEX_HOME="\${CODEX_HOME:-${escapedCodexHome}}"`,
6606
- 'export OMO_SPARKSHELL_APP_SERVER_SOCKET="${OMO_SPARKSHELL_APP_SERVER_SOCKET:-$CODEX_HOME/app-server-control/app-server-control.sock}"',
6607
6606
  'if [ "$1" = "ulw-loop" ] && [ -x "' + escapedUlwLoopBin + '" ]; then',
6608
6607
  " shift",
6609
- ' exec "' + escapedUlwLoopBin + '" "$@"',
6608
+ ' exec "' + escapedUlwLoopBin + '" ulw-loop "$@"',
6610
6609
  "fi",
6611
6610
  `if [ "\${OMO_RUNTIME:-}" = "node" ] && [ -f "${nodeCli}" ]; then`,
6612
6611
  ` exec node "${nodeCli}" "$@"`,
@@ -6645,11 +6644,10 @@ function windowsRuntimeWrapper(cliPath, codexHome, binDir, nodeCliPath) {
6645
6644
  "@echo off",
6646
6645
  `rem ${RUNTIME_WRAPPER_MARKER}`,
6647
6646
  `if not defined CODEX_HOME set "CODEX_HOME=${codexHome}"`,
6648
- 'if not defined OMO_SPARKSHELL_APP_SERVER_SOCKET set "OMO_SPARKSHELL_APP_SERVER_SOCKET=%CODEX_HOME%\\app-server-control\\app-server-control.sock"',
6649
6647
  ...windowsNodeDiscoveryLines(),
6650
6648
  `if "%~1"=="ulw-loop" if exist "${ulwLoopBin}" (`,
6651
6649
  " shift /1",
6652
- ` "${ulwLoopBin}" %*`,
6650
+ ` "${ulwLoopBin}" ulw-loop %*`,
6653
6651
  " exit /b %ERRORLEVEL%",
6654
6652
  ")",
6655
6653
  `if "%OMO_RUNTIME%"=="node" if defined OMO_NODE_BINARY if exist "${nodeCliPath}" (`,
@@ -6882,7 +6880,7 @@ async function existingNonSymlink(path) {
6882
6880
  }
6883
6881
  }
6884
6882
  // packages/omo-codex/src/install/codex-cache-install.ts
6885
- import { cp as cp2, mkdir as mkdir3, readFile as readFile7, rename, rm as rm3 } from "node:fs/promises";
6883
+ import { cp as cp2, mkdir as mkdir3, readFile as readFile7, readdir as readdir3, rename, rm as rm3 } from "node:fs/promises";
6886
6884
  import { basename as basename3, dirname as dirname4, join as join11, sep as sep5 } from "node:path";
6887
6885
 
6888
6886
  // packages/omo-codex/src/install/codex-cache-bundled-mcps.ts
@@ -7442,10 +7440,12 @@ async function installCachedPlugin(input) {
7442
7440
  await copyDirectory(input.sourcePath, tempPath);
7443
7441
  await rewriteCachedPackageLocalFileDependencies(tempPath, input.sourcePath);
7444
7442
  await copyBundledMcpRuntimeDists({ pluginRoot: tempPath, sourceRoot: input.sourcePath });
7443
+ await copyRootRuntimeDists({ pluginRoot: tempPath, sourcePath: input.sourcePath });
7445
7444
  await maybeRunNpmInstall(tempPath, input.runCommand, ["ci", "--omit=dev"]);
7446
7445
  await removeCachedManagedNpmBinShims(tempPath);
7447
7446
  if (input.buildSource === false)
7448
7447
  await maybeRunNpmSyncSkills(tempPath, input.runCommand);
7448
+ await assertNoRemovedSparkshellPromptReferences(tempPath);
7449
7449
  await rewriteCachedMcpManifest(tempPath, input.sourcePath);
7450
7450
  await rewriteCachedManifestRoot(tempPath, tempPath, targetPath);
7451
7451
  await assertHookCommandTargets(tempPath);
@@ -7524,8 +7524,83 @@ function shouldCopyPluginPath(path, root) {
7524
7524
  const parts = relative4.split(sep5);
7525
7525
  return !parts.some((part) => part === ".git" || part === "node_modules");
7526
7526
  }
7527
+ var removedSparkshellReferencePattern = /\b(?:sparkshell|spark[-_\s]+shell)\b/i;
7528
+ var removedSparkshellPromptSurfaceDirs = new Set([".codex-plugin", "agents", "bundled-rules", "hooks", "skills"]);
7529
+ var removedSparkshellPromptSurfaceFiles = new Set(["directive.md", "plugin.json"]);
7530
+ var removedSparkshellTextFilePattern = /\.(?:json|md|toml|ya?ml)$/i;
7531
+ async function assertNoRemovedSparkshellPromptReferences(pluginRoot) {
7532
+ for (const filePath of await listRemovedSparkshellPromptSurfaceFiles(pluginRoot, "")) {
7533
+ const content = await readFile7(join11(pluginRoot, filePath), "utf8");
7534
+ if (!removedSparkshellReferencePattern.test(content))
7535
+ continue;
7536
+ throw new Error(`removed sparkshell reference found in Codex plugin prompt surface: ${filePath}`);
7537
+ }
7538
+ }
7539
+ async function listRemovedSparkshellPromptSurfaceFiles(pluginRoot, relativeDirectory) {
7540
+ const directory = relativeDirectory === "" ? pluginRoot : join11(pluginRoot, relativeDirectory);
7541
+ const entries = await readdir3(directory, { withFileTypes: true });
7542
+ const files = [];
7543
+ for (const entry of entries) {
7544
+ const relativePath = relativeDirectory === "" ? entry.name : join11(relativeDirectory, entry.name);
7545
+ if (entry.isDirectory()) {
7546
+ if (shouldDescendIntoRemovedSparkshellPromptSurface(relativePath)) {
7547
+ files.push(...await listRemovedSparkshellPromptSurfaceFiles(pluginRoot, relativePath));
7548
+ }
7549
+ continue;
7550
+ }
7551
+ if (shouldCheckRemovedSparkshellPromptFile(relativePath))
7552
+ files.push(relativePath);
7553
+ }
7554
+ return files.sort();
7555
+ }
7556
+ function shouldDescendIntoRemovedSparkshellPromptSurface(relativePath) {
7557
+ const parts = relativePath.split(sep5);
7558
+ if (parts.some((part) => part === ".git" || part === "dist" || part === "node_modules"))
7559
+ return false;
7560
+ if (parts[0] === "components") {
7561
+ if (parts.length <= 2)
7562
+ return true;
7563
+ return removedSparkshellPromptSurfaceDirs.has(parts[2]);
7564
+ }
7565
+ return removedSparkshellPromptSurfaceDirs.has(parts[0]);
7566
+ }
7567
+ function shouldCheckRemovedSparkshellPromptFile(relativePath) {
7568
+ if (!removedSparkshellTextFilePattern.test(relativePath))
7569
+ return false;
7570
+ const parts = relativePath.split(sep5);
7571
+ const fileName = parts.at(-1) ?? "";
7572
+ if (parts[0] === "components") {
7573
+ if (parts.length === 3)
7574
+ return removedSparkshellPromptSurfaceFiles.has(fileName);
7575
+ return parts.length > 3 && removedSparkshellPromptSurfaceDirs.has(parts[2]);
7576
+ }
7577
+ return removedSparkshellPromptSurfaceDirs.has(parts[0]);
7578
+ }
7579
+ async function copyRootRuntimeDists(input) {
7580
+ const repoRoot = repoRootForCodexPluginSource(input.sourcePath);
7581
+ if (repoRoot === null)
7582
+ return;
7583
+ for (const runtimePath of ["dist/cli", "dist/cli-node"]) {
7584
+ const sourcePath = join11(repoRoot, runtimePath);
7585
+ if (!await fileExistsStrict(join11(sourcePath, "index.js")))
7586
+ continue;
7587
+ await mkdir3(dirname4(join11(input.pluginRoot, runtimePath)), { recursive: true });
7588
+ await cp2(sourcePath, join11(input.pluginRoot, runtimePath), { recursive: true });
7589
+ }
7590
+ }
7591
+ function repoRootForCodexPluginSource(sourcePath) {
7592
+ const codexPackageRoot = dirname4(sourcePath);
7593
+ const packagesRoot = dirname4(codexPackageRoot);
7594
+ if (basename3(sourcePath) !== "plugin")
7595
+ return null;
7596
+ if (basename3(codexPackageRoot) !== "omo-codex")
7597
+ return null;
7598
+ if (basename3(packagesRoot) !== "packages")
7599
+ return null;
7600
+ return dirname4(packagesRoot);
7601
+ }
7527
7602
  // packages/omo-codex/src/install/codex-cache-prune.ts
7528
- import { lstat as lstat4, readdir as readdir3, rm as rm4, stat as stat3 } from "node:fs/promises";
7603
+ import { lstat as lstat4, readdir as readdir4, rm as rm4, stat as stat3 } from "node:fs/promises";
7529
7604
  import { join as join12 } from "node:path";
7530
7605
  async function pruneMarketplaceCache(input) {
7531
7606
  const cacheRoot = join12(input.codexHome, "plugins", "cache", input.marketplaceName);
@@ -7553,11 +7628,11 @@ async function pruneMarketplacePluginCaches(input) {
7553
7628
  }
7554
7629
  async function readCacheEntries(path) {
7555
7630
  const emptyEntries = [];
7556
- return readCacheRoot(path, () => readdir3(path, { withFileTypes: true }), emptyEntries);
7631
+ return readCacheRoot(path, () => readdir4(path, { withFileTypes: true }), emptyEntries);
7557
7632
  }
7558
7633
  async function readCacheEntryNames(path) {
7559
7634
  const emptyNames = [];
7560
- return readCacheRoot(path, () => readdir3(path), emptyNames);
7635
+ return readCacheRoot(path, () => readdir4(path), emptyNames);
7561
7636
  }
7562
7637
  async function readCacheRoot(path, readEntries, fallback) {
7563
7638
  try {
@@ -8117,7 +8192,7 @@ function ensureMarketplaceBlock(config, marketplaceName, source) {
8117
8192
  }
8118
8193
 
8119
8194
  // packages/omo-codex/src/install/codex-config-permissions.ts
8120
- var AUTONOMOUS_FEATURES = ["multi_agent", "child_agents_md", "unified_exec", "goals"];
8195
+ var AUTONOMOUS_FEATURES = ["multi_agent", "unified_exec", "goals"];
8121
8196
  function ensureAutonomousPermissions(config) {
8122
8197
  let next = replaceOrInsertRootSetting(config, "approval_policy", JSON.stringify("never"));
8123
8198
  next = replaceOrInsertRootSetting(next, "sandbox_mode", JSON.stringify("danger-full-access"));
@@ -8537,7 +8612,6 @@ async function updateCodexConfig(input) {
8537
8612
  config = ensureFeatureEnabled(config, "plugins");
8538
8613
  config = ensureFeatureEnabled(config, "plugin_hooks");
8539
8614
  config = ensureFeatureEnabled(config, "multi_agent");
8540
- config = ensureFeatureEnabled(config, "child_agents_md");
8541
8615
  config = removeUnsupportedCodexMultiAgentModeConfig(config);
8542
8616
  config = ensureCodexReasoningConfig(config, await readCodexModelCatalog(input.repoRoot));
8543
8617
  config = ensureCodexMultiAgentV2Config(config);
@@ -8720,7 +8794,7 @@ function toCodexResolution(resolution) {
8720
8794
  }
8721
8795
 
8722
8796
  // packages/omo-codex/src/install/link-cached-plugin-agents.ts
8723
- import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile13, readdir as readdir4, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
8797
+ import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile13, readdir as readdir5, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
8724
8798
  import { basename as basename5, join as join19 } from "node:path";
8725
8799
 
8726
8800
  // packages/omo-codex/src/install/retired-managed-agent-purge.ts
@@ -8788,7 +8862,7 @@ async function capturePreservedAgentReasoning(input) {
8788
8862
  if (!await exists4(agentsDir))
8789
8863
  return new Map;
8790
8864
  const preserved = new Map;
8791
- const agentEntries = await readdir4(agentsDir, { withFileTypes: true });
8865
+ const agentEntries = await readdir5(agentsDir, { withFileTypes: true });
8792
8866
  for (const entry of agentEntries) {
8793
8867
  if (!entry.name.endsWith(".toml"))
8794
8868
  continue;
@@ -8806,7 +8880,7 @@ async function capturePreservedAgentServiceTier(input) {
8806
8880
  if (!await exists4(agentsDir))
8807
8881
  return new Map;
8808
8882
  const preserved = new Map;
8809
- const agentEntries = await readdir4(agentsDir, { withFileTypes: true });
8883
+ const agentEntries = await readdir5(agentsDir, { withFileTypes: true });
8810
8884
  for (const entry of agentEntries) {
8811
8885
  if (!entry.name.endsWith(".toml"))
8812
8886
  continue;
@@ -8863,7 +8937,7 @@ async function discoverBundledAgents(pluginRoot) {
8863
8937
  const componentsRoot = join19(pluginRoot, "components");
8864
8938
  if (!await exists4(componentsRoot))
8865
8939
  return [];
8866
- const componentEntries = await readdir4(componentsRoot, { withFileTypes: true });
8940
+ const componentEntries = await readdir5(componentsRoot, { withFileTypes: true });
8867
8941
  const agents = [];
8868
8942
  for (const entry of componentEntries) {
8869
8943
  if (!entry.isDirectory())
@@ -8871,7 +8945,7 @@ async function discoverBundledAgents(pluginRoot) {
8871
8945
  const agentsRoot = join19(componentsRoot, entry.name, "agents");
8872
8946
  if (!await exists4(agentsRoot))
8873
8947
  continue;
8874
- const agentEntries = await readdir4(agentsRoot, { withFileTypes: true });
8948
+ const agentEntries = await readdir5(agentsRoot, { withFileTypes: true });
8875
8949
  for (const file2 of agentEntries) {
8876
8950
  if (!file2.isFile() || !file2.name.endsWith(".toml"))
8877
8951
  continue;
@@ -9178,7 +9252,7 @@ function shouldCopyMarketplaceSourcePath(path, root) {
9178
9252
  }
9179
9253
 
9180
9254
  // packages/omo-codex/src/install/lazycodex-version-stamp.ts
9181
- import { readdir as readdir5, readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
9255
+ import { readdir as readdir6, readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
9182
9256
  import { join as join22 } from "node:path";
9183
9257
  async function readDistributionManifest(repoRoot) {
9184
9258
  try {
@@ -9271,7 +9345,7 @@ async function stampHookStatusMessages(path, version) {
9271
9345
  async function stampComponentVersions(input) {
9272
9346
  let entries;
9273
9347
  try {
9274
- entries = await readdir5(join22(input.pluginRoot, "components"));
9348
+ entries = await readdir6(join22(input.pluginRoot, "components"));
9275
9349
  } catch (error) {
9276
9350
  if (error instanceof Error)
9277
9351
  return;
@@ -9534,7 +9608,7 @@ function formatUnknownError(error) {
9534
9608
  }
9535
9609
 
9536
9610
  // packages/omo-codex/src/install/lsp-daemon-reaper.ts
9537
- import { readFile as readFile17, readdir as readdir6, rm as rm8 } from "node:fs/promises";
9611
+ import { readFile as readFile17, readdir as readdir7, rm as rm8 } from "node:fs/promises";
9538
9612
  import { connect } from "node:net";
9539
9613
  import { join as join24 } from "node:path";
9540
9614
  async function reapLspDaemons(codexHome, deps = {}) {
@@ -9544,7 +9618,7 @@ async function reapLspDaemons(codexHome, deps = {}) {
9544
9618
  const reaped = [];
9545
9619
  let entries;
9546
9620
  try {
9547
- entries = await readdir6(daemonRoot);
9621
+ entries = await readdir7(daemonRoot);
9548
9622
  } catch {
9549
9623
  return reaped;
9550
9624
  }
@@ -13554,7 +13628,7 @@ async function runCodexInstaller(options = {}) {
13554
13628
  if (runtimeLink !== null)
13555
13629
  log2(`Linked ${runtimeLink.name} -> ${runtimeLink.target}`);
13556
13630
  else
13557
- log2(`Warning: skipped the omo runtime wrapper because ${join31(repoRoot, "dist", "cli", "index.js")} is missing; omo sparkshell/ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
13631
+ log2(`Warning: skipped the omo runtime wrapper because ${join31(repoRoot, "dist", "cli", "index.js")} is missing; omo ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
13558
13632
  }
13559
13633
  pluginSources.push({ name: entry.name, sourcePath });
13560
13634
  installed.push(plugin);
@@ -13855,6 +13929,7 @@ function formatLazyCodexInstallHelp() {
13855
13929
  "Usage: lazycodex-ai install [--no-tui] [--codex-autonomous|--no-codex-autonomous] [--repo-root <path>]",
13856
13930
  " lazycodex-ai uninstall [--project <path>]",
13857
13931
  " lazycodex-ai update [--dry-run] [--repo-root <path>]",
13932
+ " lazycodex-ai doctor [--source-root <path>] [--model <model>] [--json|--status|--verbose]",
13858
13933
  " lazycodex-ai version",
13859
13934
  " lazycodex-ai <command> [args...]",
13860
13935
  "",
@@ -13884,20 +13959,22 @@ async function runDelegatedOmoCommand(parsed, options) {
13884
13959
  function buildDelegatedOmoInvocation(parsed) {
13885
13960
  if (parsed.command === "doctor")
13886
13961
  return buildLazyCodexDoctorInvocation(parsed.args);
13887
- const args = ["--yes", "--package", "oh-my-openagent", "omo", parsed.command];
13888
13962
  if (parsed.command === "install") {
13889
- args.push("--platform=codex");
13963
+ const args2 = ["--yes", "oh-my-openagent@latest", parsed.command, "--platform=codex"];
13890
13964
  if (parsed.noTui)
13891
- args.push("--no-tui");
13965
+ args2.push("--no-tui");
13892
13966
  if (parsed.skipAuth)
13893
- args.push("--skip-auth");
13967
+ args2.push("--skip-auth");
13894
13968
  if (parsed.autonomousPermissions !== false)
13895
- args.push("--codex-autonomous");
13969
+ args2.push("--codex-autonomous");
13896
13970
  if (parsed.autonomousPermissions === false)
13897
- args.push("--no-codex-autonomous");
13971
+ args2.push("--no-codex-autonomous");
13898
13972
  if (parsed.repoRoot)
13899
- args.push(`--repo-root=${parsed.repoRoot}`);
13900
- } else if (parsed.command === "cleanup") {
13973
+ args2.push(`--repo-root=${parsed.repoRoot}`);
13974
+ return { command: "npx", args: args2, delegatesToOmo: true };
13975
+ }
13976
+ const args = ["--yes", "--package", "oh-my-openagent", "omo", parsed.command];
13977
+ if (parsed.command === "cleanup") {
13901
13978
  args.push("--platform=codex", ...parsed.args);
13902
13979
  } else {
13903
13980
  args.push(...parsed.args);
@@ -13905,21 +13982,26 @@ function buildDelegatedOmoInvocation(parsed) {
13905
13982
  return { command: "npx", args, delegatesToOmo: true };
13906
13983
  }
13907
13984
  function buildLazyCodexDoctorInvocation(doctorArgs) {
13985
+ const doctorOptions = parseLazyCodexDoctorOptions(doctorArgs);
13986
+ const codexArgs = [
13987
+ "exec",
13988
+ "--ephemeral",
13989
+ "--sandbox",
13990
+ "danger-full-access",
13991
+ "--skip-git-repo-check",
13992
+ "--cd",
13993
+ "."
13994
+ ];
13995
+ if (doctorOptions.model !== undefined)
13996
+ codexArgs.push("--model", doctorOptions.model);
13997
+ codexArgs.push(buildLazyCodexDoctorPrompt(doctorOptions.args));
13908
13998
  return {
13909
13999
  command: "codex",
13910
- args: [
13911
- "exec",
13912
- "--ephemeral",
13913
- "--sandbox",
13914
- "read-only",
13915
- "--skip-git-repo-check",
13916
- "--cd",
13917
- ".",
13918
- buildLazyCodexDoctorPrompt(doctorArgs)
13919
- ],
14000
+ args: codexArgs,
13920
14001
  delegatesToOmo: false,
13921
14002
  env: {
13922
- LAZYCODEX_DOCTOR_LCX_ACTIVE: "1"
14003
+ LAZYCODEX_DOCTOR_LCX_ACTIVE: "1",
14004
+ ...doctorOptions.sourceRoot === undefined ? {} : { LAZYCODEX_SOURCE_ROOT: doctorOptions.sourceRoot }
13923
14005
  }
13924
14006
  };
13925
14007
  }
@@ -13927,12 +14009,58 @@ function buildLazyCodexDoctorPrompt(doctorArgs) {
13927
14009
  return [
13928
14010
  "Use $omo:lcx-doctor to diagnose this LazyCodex/Codex installation.",
13929
14011
  "This command is already the lazycodex doctor surface; never invoke lazycodex doctor from inside the doctor workflow.",
13930
- "Sync the latest LazyCodex and OpenAI Codex sources into /tmp, inventory the local installation,",
14012
+ "Use the resolved source root from LAZYCODEX_SOURCE_ROOT when set; otherwise use ${TMPDIR:-/tmp}/lazycodex-sources.",
14013
+ "Validate cached source checkouts before reuse, quarantine corrupt caches, and do not rely on /tmp/lazycodex-source.",
14014
+ "Sync the latest LazyCodex and OpenAI Codex sources there, inventory the local installation,",
13931
14015
  "probe the Codex plugin/cache/hooks/MCP state, and report PASS/WARN/FAIL findings with evidence and remediations.",
13932
14016
  buildDoctorOutputInstruction(doctorArgs),
13933
14017
  doctorArgs.length > 0 ? `Requested doctor arguments: ${doctorArgs.join(" ")}` : "Requested doctor arguments: none"
13934
14018
  ].join(" ");
13935
14019
  }
14020
+ function parseLazyCodexDoctorOptions(doctorArgs) {
14021
+ const args = [];
14022
+ let model;
14023
+ let sourceRoot;
14024
+ let index = 0;
14025
+ while (index < doctorArgs.length) {
14026
+ const arg = doctorArgs[index];
14027
+ if (arg === "--model") {
14028
+ const value = doctorArgs[index + 1];
14029
+ if (typeof value !== "string" || value.trim().length === 0)
14030
+ throw new Error("--model requires a value");
14031
+ model = value;
14032
+ index += 2;
14033
+ continue;
14034
+ }
14035
+ if (typeof arg === "string" && arg.startsWith("--model=")) {
14036
+ const value = arg.slice("--model=".length);
14037
+ if (value.trim().length === 0)
14038
+ throw new Error("--model requires a value");
14039
+ model = value;
14040
+ index += 1;
14041
+ continue;
14042
+ }
14043
+ if (arg === "--source-root") {
14044
+ const value = doctorArgs[index + 1];
14045
+ if (typeof value !== "string" || value.trim().length === 0)
14046
+ throw new Error("--source-root requires a path");
14047
+ sourceRoot = value;
14048
+ index += 2;
14049
+ continue;
14050
+ }
14051
+ if (typeof arg === "string" && arg.startsWith("--source-root=")) {
14052
+ const value = arg.slice("--source-root=".length);
14053
+ if (value.trim().length === 0)
14054
+ throw new Error("--source-root requires a path");
14055
+ sourceRoot = value;
14056
+ index += 1;
14057
+ continue;
14058
+ }
14059
+ args.push(arg);
14060
+ index += 1;
14061
+ }
14062
+ return { args, ...model === undefined ? {} : { model }, ...sourceRoot === undefined ? {} : { sourceRoot } };
14063
+ }
13936
14064
  function buildDoctorOutputInstruction(doctorArgs) {
13937
14065
  if (doctorArgs.includes("--json")) {
13938
14066
  return "Return exactly one JSON object with summary, environment, checks, remediations, and knownIssues fields; do not wrap it in Markdown.";
@@ -69,7 +69,7 @@ test("#given dry-run install flags #when running the Node installer entrypoint #
69
69
  ).trim();
70
70
 
71
71
  // then
72
- assert.equal(output, "npx --yes --package oh-my-openagent omo install --platform=codex --no-tui --codex-autonomous");
72
+ assert.equal(output, "npx --yes oh-my-openagent@latest install --platform=codex --no-tui --codex-autonomous");
73
73
  });
74
74
 
75
75
  test("#given dry-run install opt-out #when running the Node installer entrypoint #then preserves existing Codex permission settings", () => {
@@ -84,7 +84,21 @@ test("#given dry-run install opt-out #when running the Node installer entrypoint
84
84
  ).trim();
85
85
 
86
86
  // then
87
- assert.equal(output, "npx --yes --package oh-my-openagent omo install --platform=codex --no-tui --no-codex-autonomous");
87
+ assert.equal(output, "npx --yes oh-my-openagent@latest install --platform=codex --no-tui --no-codex-autonomous");
88
+ });
89
+
90
+ test("#given explicit non-Codex dry-run platform #when running the Node installer entrypoint #then rejects it", () => {
91
+ // given
92
+ const scriptPath = fileURLToPath(new URL("./install-local.mjs", import.meta.url));
93
+
94
+ // when/then
95
+ assert.throws(
96
+ () =>
97
+ execFileSync(process.execPath, [scriptPath, "--dry-run", "install", "--platform=gemini", "--no-tui"], {
98
+ encoding: "utf8",
99
+ }),
100
+ /lazycodex-ai installs the Codex Light edition only/,
101
+ );
88
102
  });
89
103
 
90
104
  test("#given dry-run doctor #when running the Node installer entrypoint #then prints Codex LazyCodex doctor workflow command", () => {
@@ -98,7 +112,12 @@ test("#given dry-run doctor #when running the Node installer entrypoint #then pr
98
112
 
99
113
  // then
100
114
  assert.match(output, /^codex exec /);
115
+ assert.match(output, /--sandbox danger-full-access/);
116
+ assert.doesNotMatch(output, /--model/);
117
+ assert.doesNotMatch(output, /gpt-5\.5-codex-mini/);
118
+ assert.doesNotMatch(output, /--sandbox read-only/);
101
119
  assert.match(output, /Use \$omo:lcx-doctor/);
120
+ assert.match(output, /\$\{TMPDIR:-\/tmp\}\/lazycodex-sources/);
102
121
  assert.match(output, /Requested doctor arguments: --json/);
103
122
  assert.match(output, /Return exactly one JSON object/);
104
123
  assert.doesNotMatch(output, /oh-my-openagent omo doctor/);
@@ -69,7 +69,6 @@ test("#given custom CODEX_HOME and PATH without omo #when installing locally wit
69
69
  new RegExp(escapeRegExp(escapePosixDoubleQuoted(toPosixPath(join(repoRoot, "dist", "cli", "index.js"))))),
70
70
  );
71
71
  assert.match(wrapper, /CODEX_HOME/);
72
- assert.match(wrapper, /OMO_SPARKSHELL_APP_SERVER_SOCKET/);
73
72
  assert.match(wrapper, /omo-ulw-loop/);
74
73
  });
75
74
 
@@ -186,10 +186,16 @@ SOFTWARE.
186
186
 
187
187
  ## 5. Project-original files
188
188
 
189
- `frontend/SKILL.md`, `frontend/references/design/README.md`, `_INDEX.md`,
189
+ `frontend/SKILL.md`, `frontend/references/design/README.md`, `_INDEX.md`, `aside.md`,
190
190
  `design-system-architecture.md`, `react-dev-tooling-skill.md`,
191
191
  `frontend/references/perfection/README.md`, `react-perf-tooling.md`, and
192
192
  `frontend/scripts/perfection/lighthouse-audit.py` are original to this project and require
193
193
  no third-party attribution. The perfection docs and script only invoke third-party tools
194
194
  (react-scan, react-doctor, react-grab, playwright-lighthouse, lighthouse, chrome-launcher)
195
195
  at runtime; no source from those tools is vendored, so their licenses are not carried here.
196
+
197
+ `frontend/references/design/aside.md` is a project-original synthesis from live browser
198
+ capture evidence and a local reconnaissance run following the MIT-licensed
199
+ `JCodesMore/ai-website-cloner-template` workflow; it is not copied from Aside or from the
200
+ template. Aside names, trademarks, product text, and visual assets remain the property of
201
+ their respective owners and are referenced only for descriptive design-analysis purposes.
@@ -33,7 +33,7 @@ When `references/designpowers/README.md` is loaded for implementation, redesign,
33
33
 
34
34
  ## Ruleset 1 — design (`references/design/`)
35
35
 
36
- The reference library has one architecture file, 12 taste skills (Layer A — *how to execute*), and 69 brand design systems (Layer B — *what it should look like*). Most non-trivial tasks load **one Layer A + one Layer B**. `README.md` carries the full routing flow, stacking rules, anti-patterns, and the mandatory browser-based Design QA phase; `_INDEX.md` catalogs all 81 files with mood-to-brand mappings — read it whenever routing is not obvious from the tables below.
36
+ The reference library has one architecture file, 12 taste skills (Layer A — *how to execute*), and 70 brand design systems (Layer B — *what it should look like*). Most non-trivial tasks load **one Layer A + one Layer B**. `README.md` carries the full routing flow, stacking rules, anti-patterns, and the mandatory browser-based Design QA phase; `_INDEX.md` catalogs all 83 files with mood-to-brand mappings — read it whenever routing is not obvious from the tables below.
37
37
 
38
38
  ### Layer 0 — architecture
39
39
 
@@ -58,7 +58,7 @@ The reference library has one architecture file, 12 taste skills (Layer A — *h
58
58
 
59
59
  ### Layer B — brand design systems (orthogonal to Layer A; stack freely)
60
60
 
61
- When the user names a brand or site — "Linear-style", "like Stripe's landing" — load `references/design/<brand>.md` as the token source of truth (palette, type scale, components, do/don'ts). Coverage includes `apple` `stripe` `linear.app` `notion` `vercel` `claude` `figma` `airbnb` `nike` `tesla` `spotify` `raycast` `revolut` and ~56 more; the full list with mood shortcuts is in `_INDEX.md`. Extract the tokens and apply them to the project's own content — never copy logos or trademarked imagery. If the named brand is missing, fall back to a Layer A mood match or the `open-design` skill.
61
+ When the user names a brand or site — "Linear-style", "like Stripe's landing", "Aside-style browser agent" — load `references/design/<brand>.md` as the token source of truth (palette, type scale, components, do/don'ts). Coverage includes `aside` `apple` `stripe` `linear.app` `notion` `vercel` `claude` `figma` `airbnb` `nike` `tesla` `spotify` `raycast` `revolut` and ~56 more; the full list with mood shortcuts is in `_INDEX.md`. Extract the tokens and apply them to the project's own content — never copy logos or trademarked imagery. If the named brand is missing, fall back to a Layer A mood match or the `open-design` skill.
62
62
 
63
63
  ### React dev tooling
64
64
 
@@ -102,6 +102,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
102
102
  | Request | Load |
103
103
  |---|---|
104
104
  | "Build a landing page" (no direction given) | `design/README.md` + `design/_INDEX.md` shortlist → exactly one Layer B reference + `design/taste-skill.md` + `perfection/README.md` |
105
+ | "Aside-style AI browser / browser agent page" | `design/README.md` + `design/aside.md` + `design/taste-skill.md` + `perfection/README.md` |
105
106
  | "Linear-style landing page" | `design/README.md` + `design/linear.app.md` + `design/taste-skill.md` + `perfection/README.md` |
106
107
  | "Premium SaaS hero like Stripe" | `design/README.md` + `design/stripe.md` + `design/soft-skill.md` + `perfection/README.md` |
107
108
  | "Improve this existing dashboard" | `design/README.md` + `design/redesign-skill.md` + `perfection/README.md` |
@@ -125,7 +126,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
125
126
 
126
127
  | Situation | Load |
127
128
  |---|---|
128
- | Brand/style not among the 69 in `references/design/`, or the user says "Open Design" | `open-design` skill — the local nexu-io/open-design library (137+ design skills, 150+ design systems) |
129
+ | Brand/style not among the 70 in `references/design/`, or the user says "Open Design" | `open-design` skill — the local nexu-io/open-design library (137+ design skills, 150+ design systems) |
129
130
  | Driving a browser for the Design QA phase | `agent-browser` skill |
130
131
  | Pure TypeScript/logic work with zero visual surface | `programming` skill alone — this skill adds nothing there |
131
132
 
@@ -16,9 +16,9 @@ Two things ship flat most often, and both read as "clean but generic": the **her
16
16
  The library lives flat in this directory (`references/design/`, max depth 1) and has two conceptual layers, and **most non-trivial tasks load one from each layer**:
17
17
 
18
18
  - **Layer A — taste skills (12 files):** how to execute. Discipline, motion physics, spacing rules, anti-slop guardrails, output completeness. Filenames end in `-skill.md` or start with `imagegen-`.
19
- - **Layer B — design systems (69 files):** what it should look like. Concrete color/type/component tokens for one specific brand aesthetic. Filenames are brand names (`claude.md`, `notion.md`, `stripe.md`, ).
19
+ - **Layer B — design systems (70 files):** what it should look like. Concrete color/type/component tokens for one specific brand aesthetic. Filenames are brand names (`aside.md`, `claude.md`, `notion.md`, `stripe.md`, ...).
20
20
 
21
- A combined directory of all 81 reference files is at `_INDEX.md`. **Read that index before loading anything** unless the routing is obvious — it has the full mood-mapping and stacking rules in one place.
21
+ A combined directory of all 83 reference files is at `_INDEX.md`. **Read that index before loading anything** unless the routing is obvious — it has the full mood-mapping and stacking rules in one place.
22
22
 
23
23
  ## Open Design Library
24
24
 
@@ -94,7 +94,7 @@ Run through this in order and stop at the first match. Do not skip — earlier r
94
94
 
95
95
  ### Step 1 — Did the user name a specific brand or site?
96
96
 
97
- Phrasings: "make it look like Linear", "Stripe-style buttons", "Notion-feel sidebar", "like {brand}'s landing page", or pasting a screenshot of a known brand site.
97
+ Phrasings: "make it look like Linear", "Stripe-style buttons", "Notion-feel sidebar", "Aside-style browser agent", "like {brand}'s landing page", or pasting a screenshot of a known brand site.
98
98
 
99
99
  **Action:** Open `_INDEX.md`, find the brand under "Layer B — Design Systems", then load `<brand>.md`. Use it as the project's design system source of truth (color hex values, type scale, component specs, do/don'ts).
100
100
 
@@ -201,6 +201,7 @@ Once references are loaded, before writing any UI code:
201
201
  | User asks for... | Load these |
202
202
  |---|---|
203
203
  | "Build me a landing page" (no other info) | `_INDEX.md` shortlist → exactly one Layer B reference + `taste-skill.md` |
204
+ | "Build me an Aside-style AI browser / agent page" | `aside.md` + `taste-skill.md` |
204
205
  | "Build me a Linear-style landing page" | `linear.app.md` + `taste-skill.md` |
205
206
  | "Make it Notion-like and minimal" | `notion.md` + `minimalist-skill.md` |
206
207
  | "Premium SaaS hero, like Stripe" | `stripe.md` + `soft-skill.md` |