oh-my-opencode 4.16.0 → 4.16.1
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.
- package/.agents/skills/codex-qa/SKILL.md +9 -7
- package/.agents/skills/codex-qa/references/logging-debug.md +6 -4
- package/.agents/skills/opencode-qa/SKILL.md +9 -9
- package/.agents/skills/opencode-qa/references/tui-tmux.md +10 -8
- package/dist/cli/codex-ulw-loop.d.ts +8 -0
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +260 -207
- package/dist/cli-node/index.js +260 -207
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/monitor/process.d.ts +17 -1
- package/dist/index.js +1048 -1001
- package/dist/skills/frontend/SKILL.md +9 -9
- package/dist/skills/frontend/references/design/README.md +7 -3
- package/dist/skills/frontend/references/design/_INDEX.md +1 -1
- package/dist/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/dist/skills/frontend/references/designpowers/README.md +2 -2
- package/dist/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/dist/skills/start-work/SKILL.md +2 -2
- package/dist/skills/visual-qa/SKILL.md +13 -17
- package/docs/reference/web-terminal-visual-qa.md +39 -45
- package/package.json +31 -25
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +18 -10
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +18 -10
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -1
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +18 -10
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +15 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +89 -27
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +55 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-snapshot.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-snapshot.js +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.d.ts +10 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +15 -11
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +7 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +17 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +59 -11
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-snapshot.ts +38 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-types.ts +11 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +15 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +16 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +260 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-snapshot.test.ts +124 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +101 -2
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +10 -6
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +9 -9
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +7 -3
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +18 -10
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +7 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +13 -17
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +22 -9
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +52 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +65 -39
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/shared-skills/skills/frontend/SKILL.md +9 -9
- package/packages/shared-skills/skills/frontend/references/design/README.md +7 -3
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/packages/shared-skills/skills/start-work/SKILL.md +2 -2
- package/packages/shared-skills/skills/visual-qa/SKILL.md +13 -17
- package/script/qa/strip-ansi.mjs +10 -0
- package/script/qa/web-terminal-visual-qa.mjs +112 -195
- package/script/qa/xterm-live-terminal.mjs +180 -0
- package/script/qa/web-terminal-renderer.mjs +0 -218
|
@@ -96,20 +96,20 @@ var init_atomic_write = __esm(() => {
|
|
|
96
96
|
|
|
97
97
|
// packages/telemetry-core/src/activity-state.ts
|
|
98
98
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync } from "node:fs";
|
|
99
|
-
import { basename as basename6, join as
|
|
99
|
+
import { basename as basename6, join as join31 } from "node:path";
|
|
100
100
|
function resolveTelemetryStateDir(product, options = {}) {
|
|
101
101
|
const dataDir = resolveXdgDataDir(product.cacheDirName, {
|
|
102
102
|
env: options.env,
|
|
103
103
|
osProvider: options.osProvider
|
|
104
104
|
});
|
|
105
|
-
const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined :
|
|
105
|
+
const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join31(options.env.XDG_DATA_HOME, product.cacheDirName);
|
|
106
106
|
if (dataDir === xdgStateDir || xdgStateDir === undefined && basename6(dataDir) === product.cacheDirName) {
|
|
107
107
|
return dataDir;
|
|
108
108
|
}
|
|
109
|
-
return
|
|
109
|
+
return join31(dataDir, product.cacheDirName);
|
|
110
110
|
}
|
|
111
111
|
function getTelemetryActivityStateFilePath(stateDir) {
|
|
112
|
-
return
|
|
112
|
+
return join31(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
|
|
113
113
|
}
|
|
114
114
|
function getDailyActiveCaptureState(input) {
|
|
115
115
|
const state = readPostHogActivityState(input.stateDir, input.diagnostics);
|
|
@@ -180,9 +180,9 @@ var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com", DEFAULT_POSTHOG_API_KEY =
|
|
|
180
180
|
|
|
181
181
|
// packages/telemetry-core/src/diagnostics.ts
|
|
182
182
|
import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
183
|
-
import { join as
|
|
183
|
+
import { join as join32 } from "node:path";
|
|
184
184
|
function getTelemetryDiagnosticsFilePath(diagnosticsDir) {
|
|
185
|
-
return
|
|
185
|
+
return join32(diagnosticsDir, DIAGNOSTICS_FILE_NAME);
|
|
186
186
|
}
|
|
187
187
|
function writeTelemetryDiagnostic(input, options) {
|
|
188
188
|
const now = options.now ?? new Date;
|
|
@@ -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.16.
|
|
5906
|
+
version: "4.16.1",
|
|
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.",
|
|
@@ -6122,8 +6122,8 @@ var init_telemetry = __esm(() => {
|
|
|
6122
6122
|
});
|
|
6123
6123
|
|
|
6124
6124
|
// packages/omo-codex/src/install/install-local-cli.ts
|
|
6125
|
-
import { readFile as
|
|
6126
|
-
import { dirname as dirname11, join as
|
|
6125
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
6126
|
+
import { dirname as dirname11, join as join37, resolve as resolve10 } from "node:path";
|
|
6127
6127
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6128
6128
|
|
|
6129
6129
|
// packages/utils/src/runtime/spawn.ts
|
|
@@ -6456,7 +6456,7 @@ var defaultRunCommand = async (command, args, options) => {
|
|
|
6456
6456
|
};
|
|
6457
6457
|
|
|
6458
6458
|
// packages/omo-codex/src/install/install-codex.ts
|
|
6459
|
-
import { join as
|
|
6459
|
+
import { join as join33, resolve as resolve9 } from "node:path";
|
|
6460
6460
|
import { existsSync as existsSync7 } from "node:fs";
|
|
6461
6461
|
import { homedir as homedir2 } from "node:os";
|
|
6462
6462
|
|
|
@@ -9485,7 +9485,11 @@ function stampHookGroups(hooks, version) {
|
|
|
9485
9485
|
function stampHookStatusMessage(hook, version) {
|
|
9486
9486
|
if (!isPlainRecord(hook) || typeof hook.statusMessage !== "string")
|
|
9487
9487
|
return;
|
|
9488
|
-
hook.statusMessage = hook.statusMessage.replace(/^LazyCodex\([^)]+\)
|
|
9488
|
+
hook.statusMessage = hook.statusMessage.replace(/^(?:LazyCodex\([^)]+\):|\(OmO(?:\s+[^)]+)?\))\s*/, `(OmO ${normalizeHookStatusVersion(version)}) `);
|
|
9489
|
+
}
|
|
9490
|
+
function normalizeHookStatusVersion(version) {
|
|
9491
|
+
const normalized = version.trim();
|
|
9492
|
+
return normalized.length === 0 ? "local" : normalized;
|
|
9489
9493
|
}
|
|
9490
9494
|
|
|
9491
9495
|
// packages/omo-codex/src/install/codex-project-local-cleanup.ts
|
|
@@ -9802,11 +9806,32 @@ function resolveCodexInstallerBinDir(input) {
|
|
|
9802
9806
|
return resolve8(homeDir, ".local", "bin");
|
|
9803
9807
|
}
|
|
9804
9808
|
|
|
9805
|
-
// packages/omo-codex/src/install/
|
|
9809
|
+
// packages/omo-codex/src/install/codex-git-bash-hooks.ts
|
|
9810
|
+
import { readFile as readFile19, writeFile as writeFile10 } from "node:fs/promises";
|
|
9806
9811
|
import { join as join27 } from "node:path";
|
|
9812
|
+
var WINDOWS_ONLY_GIT_BASH_HOOKS = new Set([
|
|
9813
|
+
"./hooks/pre-tool-use-recommending-git-bash-mcp.json",
|
|
9814
|
+
"./hooks/post-compact-resetting-git-bash-mcp-reminder.json"
|
|
9815
|
+
]);
|
|
9816
|
+
async function removeGitBashHooksOffWindows(input) {
|
|
9817
|
+
if (input.platform === "win32")
|
|
9818
|
+
return;
|
|
9819
|
+
const manifestPath = join27(input.pluginRoot, ".codex-plugin", "plugin.json");
|
|
9820
|
+
const parsed = JSON.parse(await readFile19(manifestPath, "utf8"));
|
|
9821
|
+
if (!isPlainRecord(parsed) || !Array.isArray(parsed.hooks))
|
|
9822
|
+
return;
|
|
9823
|
+
const hooks = parsed.hooks.filter((hook) => typeof hook !== "string" || !WINDOWS_ONLY_GIT_BASH_HOOKS.has(hook));
|
|
9824
|
+
if (hooks.length === parsed.hooks.length)
|
|
9825
|
+
return;
|
|
9826
|
+
await writeFile10(manifestPath, `${JSON.stringify({ ...parsed, hooks }, null, "\t")}
|
|
9827
|
+
`);
|
|
9828
|
+
}
|
|
9829
|
+
|
|
9830
|
+
// packages/omo-codex/src/install/omo-sot-migration.ts
|
|
9831
|
+
import { join as join28 } from "node:path";
|
|
9807
9832
|
async function seedAndMigrateOmoSot(input) {
|
|
9808
9833
|
const commandEnv = { ...input.env };
|
|
9809
|
-
const scriptPath =
|
|
9834
|
+
const scriptPath = join28(input.repoRoot, "packages", "omo-codex", "plugin", "scripts", "migrate-omo-sot.mjs");
|
|
9810
9835
|
try {
|
|
9811
9836
|
await input.runCommand(process.execPath, [scriptPath, "--seed"], {
|
|
9812
9837
|
cwd: input.repoRoot,
|
|
@@ -9820,7 +9845,7 @@ async function seedAndMigrateOmoSot(input) {
|
|
|
9820
9845
|
}
|
|
9821
9846
|
|
|
9822
9847
|
// packages/omo-codex/src/install/install-ast-grep-sg.ts
|
|
9823
|
-
import { join as
|
|
9848
|
+
import { join as join30 } from "node:path";
|
|
9824
9849
|
|
|
9825
9850
|
// packages/utils/src/ast-grep/sg-manifest.ts
|
|
9826
9851
|
function normalizeRuntimePlatform(platform = process.platform) {
|
|
@@ -9840,11 +9865,11 @@ function runtimeSlug(platform = process.platform, arch = process.arch) {
|
|
|
9840
9865
|
// packages/utils/src/ast-grep/install-script.ts
|
|
9841
9866
|
import { spawn as spawn2 } from "node:child_process";
|
|
9842
9867
|
import { existsSync as existsSync4 } from "node:fs";
|
|
9843
|
-
import { join as
|
|
9868
|
+
import { join as join29 } from "node:path";
|
|
9844
9869
|
var AST_GREP_BIN_DIR_ENV_KEY = "OMO_AST_GREP_BIN_DIR";
|
|
9845
9870
|
var AST_GREP_INSTALL_TIMEOUT_MS = 30000;
|
|
9846
9871
|
function astGrepRuntimeDir(baseDir, platform = process.platform, arch = process.arch) {
|
|
9847
|
-
return
|
|
9872
|
+
return join29(baseDir, "runtime", "ast-grep", runtimeSlug(platform, arch));
|
|
9848
9873
|
}
|
|
9849
9874
|
function isMissingExecutable(error) {
|
|
9850
9875
|
if (!("code" in error))
|
|
@@ -9882,7 +9907,7 @@ function defaultSpawnProcess(command, args, options) {
|
|
|
9882
9907
|
};
|
|
9883
9908
|
}
|
|
9884
9909
|
function scriptPathForPlatform(skillDir, platform) {
|
|
9885
|
-
return
|
|
9910
|
+
return join29(skillDir, platform === "win32" ? "install.ps1" : "install.sh");
|
|
9886
9911
|
}
|
|
9887
9912
|
function invocationsForPlatform(scriptPath, platform) {
|
|
9888
9913
|
if (platform !== "win32")
|
|
@@ -9954,7 +9979,7 @@ async function installAstGrepForCodex(options) {
|
|
|
9954
9979
|
return;
|
|
9955
9980
|
const platform = options.platform ?? process.platform;
|
|
9956
9981
|
const targetDir = astGrepRuntimeDir(options.codexHome, platform, options.arch ?? process.arch);
|
|
9957
|
-
const skillDir =
|
|
9982
|
+
const skillDir = join30(plugin.path, "skills", "ast-grep");
|
|
9958
9983
|
const installer = options.installer ?? runAstGrepSkillInstall;
|
|
9959
9984
|
try {
|
|
9960
9985
|
const result = await installer({ platform, skillDir, targetDir });
|
|
@@ -9987,7 +10012,7 @@ async function runCodexInstaller(options = {}) {
|
|
|
9987
10012
|
const env2 = options.env ?? process.env;
|
|
9988
10013
|
const platform = options.platform ?? process.platform;
|
|
9989
10014
|
const repoRoot = resolve9(options.repoRoot ?? findRepoRoot({ importerDir: import.meta.dir, env: env2 }));
|
|
9990
|
-
const codexHome = resolve9(options.codexHome ?? env2.CODEX_HOME ??
|
|
10015
|
+
const codexHome = resolve9(options.codexHome ?? env2.CODEX_HOME ?? join33(homedir2(), ".codex"));
|
|
9991
10016
|
const projectDirectory = resolve9(options.projectDirectory ?? env2.OMO_CODEX_PROJECT ?? process.cwd());
|
|
9992
10017
|
const binDir = resolveCodexInstallerBinDir({ binDir: options.binDir, codexHome, env: env2 });
|
|
9993
10018
|
const runCommand = options.runCommand ?? defaultRunCommand;
|
|
@@ -10003,9 +10028,9 @@ async function runCodexInstaller(options = {}) {
|
|
|
10003
10028
|
if (!gitBashResolution.found) {
|
|
10004
10029
|
throw new Error(gitBashResolution.installHint);
|
|
10005
10030
|
}
|
|
10006
|
-
const codexPackageRoot =
|
|
10031
|
+
const codexPackageRoot = join33(repoRoot, "packages", "omo-codex");
|
|
10007
10032
|
const marketplace = await readMarketplace(repoRoot, {
|
|
10008
|
-
marketplacePath:
|
|
10033
|
+
marketplacePath: join33(codexPackageRoot, "marketplace.json")
|
|
10009
10034
|
});
|
|
10010
10035
|
const distributionManifest = await readDistributionManifest(repoRoot);
|
|
10011
10036
|
const installed = [];
|
|
@@ -10037,6 +10062,7 @@ async function runCodexInstaller(options = {}) {
|
|
|
10037
10062
|
if (marketplace.name === "sisyphuslabs" && plugin.name === "omo") {
|
|
10038
10063
|
await stampLazyCodexPluginVersion({ pluginRoot: plugin.path, version: version2 });
|
|
10039
10064
|
await writeLazyCodexInstallSnapshot({ pluginRoot: plugin.path, distributionManifest });
|
|
10065
|
+
await removeGitBashHooksOffWindows({ platform, pluginRoot: plugin.path });
|
|
10040
10066
|
}
|
|
10041
10067
|
const links = await linkCachedPluginBins({ binDir, pluginRoot: plugin.path, platform });
|
|
10042
10068
|
for (const link of links) {
|
|
@@ -10047,7 +10073,7 @@ async function runCodexInstaller(options = {}) {
|
|
|
10047
10073
|
if (runtimeLink !== null)
|
|
10048
10074
|
log(`Linked ${runtimeLink.name} -> ${runtimeLink.target}`);
|
|
10049
10075
|
else
|
|
10050
|
-
log(`Warning: skipped the omo runtime wrapper because ${
|
|
10076
|
+
log(`Warning: skipped the omo runtime wrapper because ${join33(repoRoot, "dist", "cli", "index.js")} is missing; omo ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
|
|
10051
10077
|
}
|
|
10052
10078
|
pluginSources.push({ name: entry.name, sourcePath });
|
|
10053
10079
|
installed.push(plugin);
|
|
@@ -10101,13 +10127,13 @@ async function runCodexInstaller(options = {}) {
|
|
|
10101
10127
|
});
|
|
10102
10128
|
}
|
|
10103
10129
|
await reapLspDaemons(codexHome).catch(() => []);
|
|
10104
|
-
const marketplaceRoot =
|
|
10130
|
+
const marketplaceRoot = join33(codexHome, "plugins", "cache", marketplace.name);
|
|
10105
10131
|
await writeCachedMarketplaceManifest({
|
|
10106
10132
|
marketplaceName: marketplace.name,
|
|
10107
10133
|
marketplaceRoot,
|
|
10108
10134
|
plugins: installed
|
|
10109
10135
|
});
|
|
10110
|
-
const configPath =
|
|
10136
|
+
const configPath = join33(codexHome, "config.toml");
|
|
10111
10137
|
await updateCodexConfig({
|
|
10112
10138
|
configPath,
|
|
10113
10139
|
repoRoot: codexPackageRoot,
|
|
@@ -10167,7 +10193,7 @@ function findRepoRootFromImporter(importerDir) {
|
|
|
10167
10193
|
for (let depth = 0;depth <= 7; depth += 1) {
|
|
10168
10194
|
if (isRepoRootWithCodexPlugin(current))
|
|
10169
10195
|
return current;
|
|
10170
|
-
for (const wrapperPackageRoot of [
|
|
10196
|
+
for (const wrapperPackageRoot of [join33(current, "node_modules", "oh-my-openagent"), join33(current, "oh-my-openagent")]) {
|
|
10171
10197
|
if (isRepoRootWithCodexPlugin(wrapperPackageRoot))
|
|
10172
10198
|
return wrapperPackageRoot;
|
|
10173
10199
|
}
|
|
@@ -10185,7 +10211,7 @@ function findRepoRoot(input) {
|
|
|
10185
10211
|
return findRepoRootFromImporter(input.importerDir);
|
|
10186
10212
|
}
|
|
10187
10213
|
function isRepoRootWithCodexPlugin(repoRoot) {
|
|
10188
|
-
return existsSync7(
|
|
10214
|
+
return existsSync7(join33(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
|
|
10189
10215
|
}
|
|
10190
10216
|
function codexMarketplaceSource(marketplaceRoot) {
|
|
10191
10217
|
return { sourceType: "local", source: marketplaceRoot };
|
|
@@ -10498,12 +10524,12 @@ function shellQuote(value) {
|
|
|
10498
10524
|
// packages/omo-codex/src/install/lazycodex-manual-update.ts
|
|
10499
10525
|
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
10500
10526
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
10501
|
-
import { dirname as dirname10, join as
|
|
10527
|
+
import { dirname as dirname10, join as join35 } from "node:path";
|
|
10502
10528
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
10503
10529
|
import { fileURLToPath } from "node:url";
|
|
10504
10530
|
|
|
10505
10531
|
// packages/omo-codex/src/install/lazycodex-bun-global-paths.ts
|
|
10506
|
-
import { join as
|
|
10532
|
+
import { join as join34 } from "node:path";
|
|
10507
10533
|
function isBunGlobalEntrypointPath(invokedPath, env2) {
|
|
10508
10534
|
if (typeof invokedPath !== "string" || invokedPath.trim().length === 0)
|
|
10509
10535
|
return false;
|
|
@@ -10514,8 +10540,8 @@ function resolveBunGlobalRoots(env2) {
|
|
|
10514
10540
|
const bunInstallRoot = env2.BUN_INSTALL?.trim();
|
|
10515
10541
|
const homeRoot = env2.HOME?.trim();
|
|
10516
10542
|
return [
|
|
10517
|
-
...bunInstallRoot ? [
|
|
10518
|
-
...homeRoot ? [
|
|
10543
|
+
...bunInstallRoot ? [join34(bunInstallRoot, "bin"), join34(bunInstallRoot, "install", "global", "node_modules")] : [],
|
|
10544
|
+
...homeRoot ? [join34(homeRoot, ".bun", "bin"), join34(homeRoot, ".bun", "install", "global", "node_modules")] : []
|
|
10519
10545
|
].map(normalizePathForPrefix);
|
|
10520
10546
|
}
|
|
10521
10547
|
function normalizePathForPrefix(path2) {
|
|
@@ -10608,7 +10634,7 @@ function resolveCurrentVersion(env2) {
|
|
|
10608
10634
|
if (env2.LAZYCODEX_CURRENT_VERSION?.trim())
|
|
10609
10635
|
return env2.LAZYCODEX_CURRENT_VERSION.trim();
|
|
10610
10636
|
const pluginRoot = dirname10(dirname10(fileURLToPath(import.meta.url)));
|
|
10611
|
-
return readVersionManifest(resolveInstalledVersionPath(env2, pluginRoot)) ?? readVersionManifest(
|
|
10637
|
+
return readVersionManifest(resolveInstalledVersionPath(env2, pluginRoot)) ?? readVersionManifest(join35(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join35(pluginRoot, ".codex-plugin", "plugin.json"));
|
|
10612
10638
|
}
|
|
10613
10639
|
function resolveLatestVersion(env2) {
|
|
10614
10640
|
if (env2.LAZYCODEX_LATEST_VERSION?.trim())
|
|
@@ -10724,7 +10750,7 @@ function compareVersions(left, right) {
|
|
|
10724
10750
|
function resolveInstalledVersionPath(env2, pluginRoot) {
|
|
10725
10751
|
if (env2.LAZYCODEX_INSTALLED_VERSION_FILE?.trim())
|
|
10726
10752
|
return env2.LAZYCODEX_INSTALLED_VERSION_FILE.trim();
|
|
10727
|
-
return
|
|
10753
|
+
return join35(pluginRoot, INSTALLED_VERSION_FILE);
|
|
10728
10754
|
}
|
|
10729
10755
|
function readVersionManifest(path2) {
|
|
10730
10756
|
try {
|
|
@@ -10740,15 +10766,15 @@ function readVersionManifest(path2) {
|
|
|
10740
10766
|
}
|
|
10741
10767
|
}
|
|
10742
10768
|
// packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
|
|
10743
|
-
import { readFile as
|
|
10744
|
-
import { join as
|
|
10769
|
+
import { readFile as readFile20, writeFile as writeFile11 } from "node:fs/promises";
|
|
10770
|
+
import { join as join36 } from "node:path";
|
|
10745
10771
|
var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
|
|
10746
10772
|
var CODEGRAPH_RELATIVE_ARGS2 = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
|
|
10747
10773
|
async function stampGitBashMcpEnv(input) {
|
|
10748
|
-
const manifestPath =
|
|
10774
|
+
const manifestPath = join36(input.pluginRoot, ".mcp.json");
|
|
10749
10775
|
if (!await fileExistsStrict(manifestPath))
|
|
10750
10776
|
return false;
|
|
10751
|
-
const parsed = JSON.parse(await
|
|
10777
|
+
const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
|
|
10752
10778
|
if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
|
|
10753
10779
|
return false;
|
|
10754
10780
|
let changed = stampCodegraphMcpPath(parsed["mcpServers"], input.pluginRoot);
|
|
@@ -10766,7 +10792,7 @@ async function stampGitBashMcpEnv(input) {
|
|
|
10766
10792
|
}
|
|
10767
10793
|
if (!changed)
|
|
10768
10794
|
return false;
|
|
10769
|
-
await
|
|
10795
|
+
await writeFile11(manifestPath, `${JSON.stringify(parsed, null, "\t")}
|
|
10770
10796
|
`);
|
|
10771
10797
|
return true;
|
|
10772
10798
|
}
|
|
@@ -10778,7 +10804,7 @@ function stampCodegraphMcpPath(mcpServers, pluginRoot) {
|
|
|
10778
10804
|
const entrypoint = args[0];
|
|
10779
10805
|
if (typeof entrypoint !== "string" || !CODEGRAPH_RELATIVE_ARGS2.has(entrypoint))
|
|
10780
10806
|
return false;
|
|
10781
|
-
codegraphServer["args"] = [
|
|
10807
|
+
codegraphServer["args"] = [join36(pluginRoot, "components", "codegraph", "dist", "serve.js"), ...args.slice(1)];
|
|
10782
10808
|
return true;
|
|
10783
10809
|
}
|
|
10784
10810
|
|
|
@@ -10799,7 +10825,7 @@ async function runLazyCodexInstallLocalCli(input) {
|
|
|
10799
10825
|
return 0;
|
|
10800
10826
|
}
|
|
10801
10827
|
if (parsed.kind === "version") {
|
|
10802
|
-
const packageJson = JSON.parse(await
|
|
10828
|
+
const packageJson = JSON.parse(await readFile21(join37(input.defaultRepoRoot, "package.json"), "utf8"));
|
|
10803
10829
|
const version2 = typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
10804
10830
|
input.log(`lazycodex-ai ${version2}`);
|
|
10805
10831
|
return 0;
|
|
@@ -77,8 +77,8 @@ test("#given sisyphuslabs lazycodex install #when installing locally #then stamp
|
|
|
77
77
|
assert.equal(manifest.version, "4.7.6");
|
|
78
78
|
assert.equal(packageJson.version, "4.7.6");
|
|
79
79
|
assert.equal(componentPackageJson.version, "4.7.6");
|
|
80
|
-
assert.equal(hooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking Comments");
|
|
81
|
-
assert.equal(componentHooks.hooks.UserPromptSubmit[0].hooks[0].statusMessage, "(OmO) Checking Ulw-Loop Steering");
|
|
80
|
+
assert.equal(hooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 4.7.6) Checking Comments");
|
|
81
|
+
assert.equal(componentHooks.hooks.UserPromptSubmit[0].hooks[0].statusMessage, "(OmO 4.7.6) Checking Ulw-Loop Steering");
|
|
82
82
|
assert.deepEqual(snapshot, {
|
|
83
83
|
packageName: "lazycodex-ai",
|
|
84
84
|
version: "4.7.6",
|
|
@@ -16,7 +16,7 @@ This file is a router, not a rulebook. The rules live in four rulesets under `re
|
|
|
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
17
|
| 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
18
|
| 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
|
-
|
|
|
19
|
+
| 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. |
|
|
20
20
|
|
|
21
21
|
**For implementation work, design + perfection load together.** A page that hits Lighthouse 100 but looks like AI slop has failed; a page that looks beautiful but ships a 2 MB bundle has failed. Both win or neither does.
|
|
22
22
|
|
|
@@ -28,15 +28,15 @@ Every implementation must choose one of these branches before UI code changes:
|
|
|
28
28
|
- **Static visual reference** (screenshot, generated mockup, Stitch/Imagen output, Figma export, overview, or annotated packet): load `references/design/image-to-code-skill.md` plus the relevant design/perfection files, extract the reference's exact tokens, layout geometry, copy, spacing, states, and responsive intent into `DESIGN.md`, then implement reusable primitives against that contract.
|
|
29
29
|
- **Live site or URL reference** (the user names a site to clone or gives a URL): load `references/design/clone-from-url.md`. Drive a real browser and extract the runtime truth via `getComputedStyle` — tokens, layout geometry, default/hover/focus/active states, transitions and keyframes, and downloaded assets — into `DESIGN.md`, then clone-code reusable primitives against that contract.
|
|
30
30
|
Final QA for both runs `/visual-qa` in reference-fidelity mode: compare the actual UI against the reference pixel-by-pixel and verify the code is an extensible design-system implementation, not a screenshot-matched one-off.
|
|
31
|
-
2. **Greenfield or fresh setup:** if the user gave no concrete visual reference, design
|
|
32
|
-
- **Embedded references:** use `references/design/_INDEX.md` to shortlist 2-3 plausible Layer B references, then
|
|
33
|
-
- **Lazyweb real-product screens:**
|
|
34
|
-
- **Imagen concept drafts:** generate 2-3 imagen concept drafts, each seeded with the loaded Layer A + Layer B tokens (palette, type, material); pick the strongest and treat the chosen draft as the reference-fidelity contract.
|
|
35
|
-
Synthesize every lane into `DESIGN.md`. Treat sources as source material, not mood labels: extract tokens, layout grammar, component anatomy, interaction states, motion, and taste decisions, then recombine them into project-specific primitives. Never freestyle past the selected references, never copy logos or brand-specific copy.
|
|
31
|
+
2. **Greenfield or fresh setup:** if the user gave no concrete visual reference, design research is a build step with named deliverables — not exploration to be budgeted. Exploration-stop instincts ("enough exploration", two-wave caps) do not apply here. Fire every research lane IN PARALLEL before `DESIGN.md` is written, and open `DESIGN.md` with a `## 0. Research Log` section recording each lane's deliverable — a lane with no Research Log line did not run. Skip a lane only when its tool or network is genuinely unavailable, and name the skip in `DESIGN.md`:
|
|
32
|
+
- **Embedded references:** use `references/design/_INDEX.md` to shortlist 2-3 plausible Layer B references, then read exactly one Layer A style skill and one Layer B reference in full — every line, no partial reads (they are 200-500 lines; a sliced read produces the flattened token set this gate exists to prevent). Log the shortlist, the pick, and why. Use `open-design` only when the curated set has no fit; add `ui-ux-db` lookups for palette/type/domain questions.
|
|
33
|
+
- **Lazyweb real-product screens:** READ `references/design/lazyweb.md` FIRST and run its recipe verbatim — do not improvise curl calls against lazyweb.com; the recipe mints its own anonymous token. Log the queries run, how many screens you actually VIEWED, and the layout grammar harvested — never pixel copies.
|
|
34
|
+
- **Imagen concept drafts:** generate 2-3 imagen concept drafts, each seeded with the loaded Layer A + Layer B tokens (palette, type, material); pick the strongest and treat the chosen draft as the reference-fidelity contract. Log the draft paths and the pick.
|
|
35
|
+
Synthesize every lane into `DESIGN.md`. Treat sources as source material, not mood labels: extract tokens, layout grammar, component anatomy, interaction states, motion, and taste decisions, then recombine them into project-specific primitives. Never freestyle past the selected references, never copy logos or brand-specific copy. Then run the Primitive Showcase Gate (`references/design/README.md` Phase 0) before any product screen.
|
|
36
36
|
3. **Existing project with `DESIGN.md` or a component system:** read it, follow it, and update it before implementation only when the requested work needs a new token, primitive, state, motion rule, accessibility constraint, accepted debt, or reference-fidelity requirement.
|
|
37
37
|
4. **Existing project with UI but no `DESIGN.md` and no reusable component layer:** STOP and ask the user one focused question: should you preserve the current look with copy-nearby styling, or extract a real `DESIGN.md` plus reusable components before continuing? Do not silently choose.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
For implementation, redesign, or design-system work that creates or updates `DESIGN.md`, `references/designpowers/README.md` + `lane-c-review.md` are part of the default load — feed their personas, accessibility, critique, debt, handoff, and role-reference guidance into the branch above. The resulting `DESIGN.md` is the implementation contract: tokens, typography, spacing, primitives, motion, responsive behavior, accessibility constraints, and accepted debt must be named there before code uses them. Verify component primitives, states, and final screens with real visual QA evidence; pass design-system decisions, implementation evidence, and unresolved debt into `/review-work` for significant implementation work.
|
|
40
40
|
|
|
41
41
|
## Ruleset 1 — design (`references/design/`)
|
|
42
42
|
|
|
@@ -46,7 +46,7 @@ The reference library has one architecture file, 12 taste skills (Layer A — *h
|
|
|
46
46
|
|
|
47
47
|
| File | Read when |
|
|
48
48
|
|---|---|
|
|
49
|
-
| `design-system-architecture.md` | The project has no `DESIGN.md` (defines the
|
|
49
|
+
| `design-system-architecture.md` | The project has no `DESIGN.md` (defines the structure you must create first — 8 sections plus a greenfield-only `## 0. Research Log`), or you are extracting a design system from existing UI code. |
|
|
50
50
|
|
|
51
51
|
### Layer A — taste skills (pick AT MOST ONE style skill; they encode opposing philosophies)
|
|
52
52
|
|
|
@@ -102,7 +102,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
|
|
|
102
102
|
|
|
103
103
|
## Ruleset 4 — designpowers (`references/designpowers/`)
|
|
104
104
|
|
|
105
|
-
`README.md` routes design operating-layer guidance from the pinned `Owl-Listener/designpowers` reference corpus into the existing frontend workflow. Load it when a
|
|
105
|
+
`README.md` routes design operating-layer guidance from the pinned `Owl-Listener/designpowers` reference corpus into the existing frontend workflow. Load it — together with `lane-c-review.md` — for every implementation or redesign that creates or updates `DESIGN.md`, and additionally when a task needs explicit personas, accessibility and cognitive constraints, design critique, design debt, handoff, synthetic user testing, motion guidance, or role-reference prompts. It does not replace this frontend skill, `/visual-qa`, `/ulw-plan`, `/start-work`, or `/review-work`; it supplies richer design context that must first be distilled into the project `DESIGN.md`, then used as the design-system contract for implementation and verification.
|
|
106
106
|
|
|
107
107
|
## Quick routes — most common requests
|
|
108
108
|
|
|
@@ -38,12 +38,12 @@ Before touching any UI code, before routing to any reference, before even thinki
|
|
|
38
38
|
|
|
39
39
|
1. Read `design-system-architecture.md` — it defines the exact structure.
|
|
40
40
|
2. Identify the branch: greenfield setup, existing UI with implicit patterns/components, or existing UI with no reusable component layer.
|
|
41
|
-
3. **Greenfield setup:** if the user gave no concrete visual reference, use `_INDEX.md` to shortlist 2-3 plausible Layer B references, then
|
|
41
|
+
3. **Greenfield setup:** if the user gave no concrete visual reference, use `_INDEX.md` to shortlist 2-3 plausible Layer B references, then read exactly one Layer A style skill and one Layer B brand/design-system reference in full — every line, no partial reads; use `open-design` only when the curated set has no fit. Open `DESIGN.md` with a `## 0. Research Log` recording each research lane's deliverable (embedded-reference shortlist + pick, lazyweb screens viewed, imagen drafts — see the SKILL.md workflow); a lane with no line did not run. Treat those references as source material, not mood labels: extract tokens, layout grammar, component anatomy, interaction states, motion, and taste decisions into `DESIGN.md`, then recombine them into project-specific primitives. Customize for the user's product and content, but do not freestyle past the selected references; never copy logos, trademarked assets, or brand-specific copy.
|
|
42
42
|
- **Commit a distinctive direction BEFORE extracting tokens.** In 1-2 sentences, name the atmosphere, the signature material, the color story, and the one moment a visitor will remember. For an expressive brief, sketch 2-3 genuinely different directions and pick the boldest one you can defend with the loaded reference; do not average them, because the average IS the generic default this skill exists to beat. A locked, never-revisited one-shot decision is how a page ends up flat.
|
|
43
43
|
- **The reference's distinctive material MUST survive extraction (expressive briefs).** The common failure is loading a rich reference and then distilling it into a generic dark-SaaS token set. Your `DESIGN.md` must carry the *non-default* decisions forward and name which reference each came from: the actual elevation recipe (the specific layers that make a surface read as glass/glossy, not a single blur), a multi-stop perceptual color ramp (not one brand hex reused at varied opacity), the explicit display/body/mono type choices, and one signature interaction. Self-check before writing code: if your `DESIGN.md` could describe any generic dark SaaS, you flattened the reference — go back and put the specific material in.
|
|
44
44
|
4. **Existing UI with implicit patterns/components:** extract the colors, typography, spacing, primitives, states, and motion already in use. Write `DESIGN.md` to codify what exists before changing UI code.
|
|
45
45
|
5. **Existing UI with no reusable component layer:** STOP and ask whether to preserve the current style with copy-nearby edits or extract a `DESIGN.md` plus reusable components first. Do not silently choose the cheaper path or the larger refactor.
|
|
46
|
-
6.
|
|
46
|
+
6. Finish the triage at the Primitive Showcase Gate below.
|
|
47
47
|
|
|
48
48
|
#### If YES design system exists → READ IT, FOLLOW IT
|
|
49
49
|
|
|
@@ -52,7 +52,11 @@ Before touching any UI code, before routing to any reference, before even thinki
|
|
|
52
52
|
3. If you need a token that doesn't exist, **add it to `DESIGN.md` first**, then use it.
|
|
53
53
|
4. Never introduce raw hex codes, arbitrary px values, or ad-hoc component patterns that bypass the system.
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**The Design System Gate is non-negotiable. No design system = no UI work. Period.**
|
|
56
|
+
|
|
57
|
+
### Primitive Showcase Gate (MANDATORY)
|
|
58
|
+
|
|
59
|
+
**Do not proceed to product screens until `DESIGN.md` exists, Section 5 names the reusable primitives and their states, and each primitive plus required state passes mobile/tablet/desktop visual QA in a component showcase or equivalent state harness.** Skipping this gate ships ad-hoc-styled product screens and re-enters the redesign loop.
|
|
56
60
|
|
|
57
61
|
|
|
58
62
|
## Phase 0.5 — React Dev Tooling Gate (MANDATORY for React projects)
|
|
@@ -13,7 +13,7 @@ All reference files live flat in this directory. Three layers:
|
|
|
13
13
|
|
|
14
14
|
| File | Purpose | Load when |
|
|
15
15
|
|---|---|---|
|
|
16
|
-
| `design-system-architecture.md` | Defines the
|
|
16
|
+
| `design-system-architecture.md` | Defines the `DESIGN.md` structure — 8 sections plus a greenfield-only `## 0. Research Log` (atmosphere, color tokens, typography scale, spacing system, components, motion, depth, accessibility constraints & accepted debt). Creation workflow for new and existing projects. Validation rules and memory management. | Phase 0 fires and no `DESIGN.md` exists in the project. Also load when extracting a design system from existing code. |
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md
CHANGED
|
@@ -16,11 +16,19 @@ Every frontend project MUST have a `DESIGN.md` at its root. This file is the sin
|
|
|
16
16
|
|
|
17
17
|
## DESIGN.md Structure
|
|
18
18
|
|
|
19
|
-
The file has
|
|
19
|
+
The file has 8 sections plus a greenfield-only `## 0. Research Log`. Every section is mandatory. Skip nothing.
|
|
20
20
|
|
|
21
21
|
```markdown
|
|
22
22
|
# [Project Name] Design System
|
|
23
23
|
|
|
24
|
+
## 0. Research Log (greenfield only)
|
|
25
|
+
|
|
26
|
+
One line per research lane, written before the sections below — a lane with no line did not run:
|
|
27
|
+
- Embedded refs: shortlisted [2-3 Layer B candidates] → picked [Layer A] + [Layer B] because [reason]
|
|
28
|
+
- Lazyweb: [N] queries, [M] screens viewed → [layout grammar taken]
|
|
29
|
+
- Imagen drafts: [paths] → picked [draft] as the reference-fidelity contract
|
|
30
|
+
- Skipped lanes: [lane] — [tool/network reason]
|
|
31
|
+
|
|
24
32
|
## 1. Atmosphere & Identity
|
|
25
33
|
|
|
26
34
|
One paragraph. What this product FEELS like. Not what it does — how it feels to use.
|
|
@@ -165,6 +173,19 @@ If borders:
|
|
|
165
173
|
|
|
166
174
|
If tonal-shift:
|
|
167
175
|
Surfaces use progressively lighter/darker shades. No borders, no shadows.
|
|
176
|
+
|
|
177
|
+
## 8. Accessibility Constraints & Accepted Debt
|
|
178
|
+
|
|
179
|
+
### Constraints
|
|
180
|
+
- WCAG target: [e.g. 2.2 AA] — contrast floor [4.5:1 body / 3:1 large text], visible focus on every
|
|
181
|
+
interactive element, full keyboard reachability, `prefers-reduced-motion` respected (Section 6).
|
|
182
|
+
|
|
183
|
+
### Accepted Debt
|
|
184
|
+
| Item | Location | Why accepted | Owner / Exit |
|
|
185
|
+
|------|----------|--------------|--------------|
|
|
186
|
+
| [debt] | [file/screen] | [reason + user sign-off] | [when it gets fixed] |
|
|
187
|
+
|
|
188
|
+
New debt is recorded here at the moment it is accepted — never silently.
|
|
168
189
|
```
|
|
169
190
|
|
|
170
191
|
## Creation Workflow
|
|
@@ -173,7 +194,7 @@ Surfaces use progressively lighter/darker shades. No borders, no shadows.
|
|
|
173
194
|
|
|
174
195
|
1. **Select references before taste** — no visual reference means `_INDEX.md` shortlist of 2-3 Layer B candidates, then exactly one Layer A style skill and one Layer B brand/design-system reference. Use `open-design` only when the curated set has no fit.
|
|
175
196
|
2. **Assemble from references** — extract tokens, layout grammar, component anatomy, states, motion, and taste decisions, then recombine them into project-specific primitives. Customize for the user's product; never copy logos, trademarked assets, or brand-specific copy.
|
|
176
|
-
3. **Define the system** — atmosphere, palette, typography, spacing, and one depth strategy, grounded in the selected references and product semantics.
|
|
197
|
+
3. **Define the system** — atmosphere, palette, typography, spacing, and one depth strategy, grounded in the selected references and product semantics. Sanity-check the palette and type pairing with one `ui-ux-db` domain search (CLI in `references/ui-ux-db/README.md`).
|
|
177
198
|
4. **Document initial primitives** — only components you are about to build, including variants and states.
|
|
178
199
|
5. **Write it to `DESIGN.md`** at project root.
|
|
179
200
|
6. **Build a primitive showcase first** — exercise each primitive's default, hover, active, focus, disabled, loading, empty, and error states at mobile/tablet/desktop widths before composing product screens.
|
|
@@ -199,6 +220,7 @@ After every component implementation, check:
|
|
|
199
220
|
- [ ] Component reused 2+ times? Documented in Section 5.
|
|
200
221
|
- [ ] Motion follows the timing table. No arbitrary durations.
|
|
201
222
|
- [ ] Component visual QA passed for each primitive and required state before product screens were composed.
|
|
223
|
+
- [ ] Section 8 accessibility constraints hold for the new component; any new debt is recorded in Section 8, not silently accepted.
|
|
202
224
|
|
|
203
225
|
## Memory Management
|
|
204
226
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This is an internal frontend ruleset, not a standalone skill. `/frontend` remains the only public activation point for web UI, UX, visual design, accessibility, design QA, and frontend implementation routing.
|
|
4
4
|
|
|
5
|
-
Load this reference from the frontend router
|
|
5
|
+
Load this reference from the frontend router for EVERY implementation or redesign that creates or updates `DESIGN.md`, and whenever a task needs design operating-layer guidance: personas, cognitive accessibility, critique, design debt, handoff, synthetic user testing, motion guidance, or designpowers-style role references.
|
|
6
6
|
|
|
7
7
|
The purpose of this ruleset is to enrich the existing frontend workflow while preserving its gates:
|
|
8
8
|
|
|
@@ -18,7 +18,7 @@ Read these files before applying designpowers guidance:
|
|
|
18
18
|
1. `README.md` - this frontend integration contract.
|
|
19
19
|
2. `routing.md` - how designpowers context feeds existing frontend, planning, execution, visual QA, and review routes.
|
|
20
20
|
3. `orchestration.md` - shared state, Direct/Auto prompt semantics, safeguards, and role-reference rules.
|
|
21
|
-
4. Phase lane docs
|
|
21
|
+
4. Phase lane docs — `lane-c-review.md` loads with this README for every implementation or redesign heading into Phase Final review (it is the flatness/critique reviewer); the other lanes load only when their phase applies:
|
|
22
22
|
- `lane-a-direction.md` for planning, direction, discovery, personas, taste, and accessibility constraints.
|
|
23
23
|
- `lane-b-execution.md` for execution, UI build prompts, frontend handoff, and implementation evidence.
|
|
24
24
|
- `lane-c-review.md` for visual QA, design critique, review gates, and objective evidence before judgment.
|
|
@@ -44,7 +44,7 @@ Lane B worker DoneClaims must include:
|
|
|
44
44
|
|
|
45
45
|
- Exact changed files and the `frontend` references loaded.
|
|
46
46
|
- The real-surface QA invocation required by `start-work` for the UI surface, with captured artifact path.
|
|
47
|
-
- Screenshot, browser, HTTP, or
|
|
47
|
+
- Screenshot, browser, HTTP, or xterm.js web-terminal artifacts appropriate to the visible surface.
|
|
48
48
|
- Accessibility evidence from the existing OpenAgent frontend path, such as Lighthouse, react-doctor, keyboard checks, or other plan-required checks.
|
|
49
49
|
- A short design trace: which persona, design principle, token, or state requirement each major UI decision satisfies.
|
|
50
50
|
- Cleanup receipts for any browser session, server, tmux session, temporary artifact, or process used during QA.
|
|
@@ -99,10 +99,10 @@ Each sub-task message must include:
|
|
|
99
99
|
4. Automated verification commands to run.
|
|
100
100
|
5. One Manual-QA channel, named with the exact tool and exact invocation (the literal `curl`, `send-keys`, `browser:control-in-app-browser` action, `page.click`, payload, selectors, and the binary observable that decides PASS/FAIL), not "verify it works". A LIGHT checkbox needs one real-surface proof of its deliverable, and auxiliary surfaces (CLI stdout, DB state diff, parsed config dump) are first-class when the surface is CLI- or data-shaped:
|
|
101
101
|
- HTTP call: `curl -i` against the live endpoint.
|
|
102
|
-
-
|
|
102
|
+
- Terminal / TUI: drive a real pty; `tmux send-keys` is fine for a boot/behavior smoke, but color/layout/CJK evidence goes through the xterm.js web terminal below, NEVER `tmux capture-pane`.
|
|
103
103
|
- Browser use: in Codex, use `browser:control-in-app-browser` first when available and the scenario does not need an authenticated or persistent user browser profile; otherwise drive the real page with Chrome, or agent-browser (https://github.com/vercel-labs/agent-browser) when Chrome is unavailable.
|
|
104
104
|
- Computer use: OS-level GUI automation against the running desktop app when the surface is not a page.
|
|
105
|
-
- TUI visual evidence: when a
|
|
105
|
+
- TUI visual evidence: when a TUI claim needs visual QA or PR proof, run `node script/qa/web-terminal-visual-qa.mjs --command "<cmd>" --input "{Enter}" --evidence-dir <dir>` (real pty rendered through xterm.js in Chrome) and attach `terminal.png` plus `metadata.json`.
|
|
106
106
|
6. The adversarial classes that apply to this sub-task (from the 9 ultraqa classes) and how each is probed.
|
|
107
107
|
7. Required artifact path and cleanup receipt.
|
|
108
108
|
|
|
@@ -57,32 +57,28 @@ For reference-fidelity work, repeat the capture and diff for every referenced vi
|
|
|
57
57
|
|
|
58
58
|
### TUI
|
|
59
59
|
|
|
60
|
-
1.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
tmux capture-pane -e -p > capture-ansi.txt
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
2. When the TUI evidence will be attached to a PR or reviewed visually, render
|
|
68
|
-
the capture through the browser helper from the repository root:
|
|
60
|
+
1. Render the TUI through the REAL xterm.js web terminal and screenshot it -
|
|
61
|
+
NEVER `tmux capture-pane`, which degrades truecolor and misaligns wide (CJK)
|
|
62
|
+
glyphs. Run the command in a real pty and capture the browser render from the
|
|
63
|
+
repository root:
|
|
69
64
|
|
|
70
65
|
```
|
|
71
66
|
node script/qa/web-terminal-visual-qa.mjs --title "TUI Visual QA" \
|
|
72
|
-
--
|
|
67
|
+
--command "<tui-command>" \
|
|
68
|
+
--input "{ArrowDown}" --input "{Enter}" \
|
|
73
69
|
--evidence-dir .omo/evidence/<slug>/tui-web-terminal
|
|
74
70
|
```
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
`terminal
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
metadata with cleanup receipt.
|
|
72
|
+
Replay a saved raw stream with `--from-file <capture.ansi>` instead of
|
|
73
|
+
`--command`. This produces `terminal.png` (the true-color artifact),
|
|
74
|
+
`terminal.txt`, `terminal-ansi.txt`, and `metadata.json`. Treat this as the
|
|
75
|
+
standard TUI visual artifact pattern. Outside this repo, copy the pattern:
|
|
76
|
+
real pty -> xterm.js in a browser -> PNG + metadata with cleanup receipt.
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
2. Run the width check on the produced text and keep the JSON:
|
|
83
79
|
|
|
84
80
|
```
|
|
85
|
-
node "$SKILL_DIR/scripts/visual-qa.mjs" tui-check
|
|
81
|
+
node "$SKILL_DIR/scripts/visual-qa.mjs" tui-check .omo/evidence/<slug>/tui-web-terminal/terminal.txt --cols <N>
|
|
86
82
|
```
|
|
87
83
|
|
|
88
84
|
Key fields: `maxWidth`, `overflowLines[]`, `borderMisaligned`, `wideCharColumns[]`, `hasAnsi`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Strip ANSI SGR and OSC control sequences from a terminal byte stream, leaving
|
|
2
|
+
// plain readable text. Used for the text-evidence artifact and the chrome-less
|
|
3
|
+
// fallback capture.
|
|
4
|
+
|
|
5
|
+
const ANSI_PATTERN = /\u001b\[[0-?]*[ -/]*[@-~]/g;
|
|
6
|
+
const OSC_PATTERN = /\u001b\][\s\S]*?(?:\u0007|\u001b\\|\u009c)/g;
|
|
7
|
+
|
|
8
|
+
export function stripAnsi(value) {
|
|
9
|
+
return value.replace(OSC_PATTERN, "").replace(ANSI_PATTERN, "");
|
|
10
|
+
}
|