oh-my-opencode 5.0.0-beta.86 → 5.0.0-beta.88
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/hyperplan/SKILL.md +1 -1
- package/.opencode/skills/hyperplan/SKILL.md +1 -1
- package/dist/cli/index.js +102 -79
- package/dist/cli-node/index.js +102 -79
- package/dist/index.js +439 -420
- package/dist/skills/browser/ATTRIBUTION.md +26 -14
- package/dist/skills/browser/SKILL.md +65 -52
- package/dist/skills/browser/references/commands.md +81 -66
- package/dist/skills/browser/references/install.md +31 -34
- package/dist/skills/browser/references/owned-engine/README.md +41 -21
- package/dist/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
- package/dist/skills/browser/references/owned-engine/ladder.md +24 -22
- package/dist/skills/browser/references/owned-engine/network.md +35 -15
- package/dist/skills/browser/references/recipes/1password.md +13 -11
- package/dist/skills/browser/references/remote.md +5 -4
- package/dist/skills/browser/runtime/omowright/index.js +1534 -0
- package/dist/skills/browser/runtime/omowright/manifest.json +9 -0
- package/dist/skills/browser/runtime/omowright/page-bundle.js +1395 -0
- package/dist/skills/browser/scripts/browser-doctor.mjs +37 -32
- package/dist/skills/browser/scripts/browser-install.mjs +31 -44
- package/dist/skills/browser/scripts/omowright.mjs +25 -0
- package/dist/skills/debugging/SKILL.md +2 -2
- package/dist/skills/debugging/references/methodology/06-fix.md +3 -3
- package/dist/skills/debugging/references/methodology/08-qa.md +1 -1
- package/dist/skills/debugging/references/tools/browser-qa.md +104 -0
- package/dist/skills/frontend/SKILL.md +1 -1
- package/dist/skills/frontend/references/design/ambience-skill.md +2 -1
- package/dist/skills/frontend/references/design/clone-from-url.md +1 -1
- package/dist/skills/frontend/references/design/design-system-architecture.md +30 -7
- package/dist/skills/frontend/references/design/interaction-skill.md +17 -5
- package/dist/skills/programming/SKILL.md +12 -18
- package/dist/skills/programming/references/rust/README.md +43 -15
- package/dist/skills/programming/references/rust/api-design.md +81 -0
- package/dist/skills/programming/references/rust/async-tokio.md +60 -28
- package/dist/skills/programming/references/rust/axum-stack.md +1 -13
- package/dist/skills/programming/references/rust/cargo-strict.md +44 -8
- package/dist/skills/programming/references/rust/clap-stack.md +8 -3
- package/dist/skills/programming/references/rust/concurrency.md +66 -52
- package/dist/skills/programming/references/rust/libraries.md +35 -25
- package/dist/skills/programming/references/rust/macros.md +63 -0
- package/dist/skills/programming/references/rust/one-liners.md +5 -3
- package/dist/skills/programming/references/rust/proptest-insta.md +8 -0
- package/dist/skills/programming/references/rust/type-state.md +50 -12
- package/dist/skills/programming/references/rust/unsafe-discipline.md +34 -6
- package/dist/skills/programming/references/rust/zero-cost-safety.md +62 -52
- package/dist/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
- package/dist/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
- package/dist/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
- package/dist/skills/programming/scripts/rust/check-no-excuse-rules.test.ts +83 -0
- package/dist/skills/programming/scripts/rust/new-project.py +31 -28
- package/dist/skills/review-work/SKILL.md +1 -1
- package/dist/skills/ultimate-browsing/SKILL.md +27 -20
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +1 -1
- package/dist/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +5 -11
- package/dist/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
- package/dist/skills/ulw-execute/SKILL.md +4 -4
- package/dist/skills/visual-qa/SKILL.md +1 -1
- package/dist/skills/visual-qa/references/browser-setup.md +46 -46
- package/dist/tui.js +6 -3
- package/package.json +15 -14
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -0
- 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/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/dist/.omo-runtime-manifest.json +2 -2
- 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/bundled-rules/hephaestus/gpt-6.md +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/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/README.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +63 -89
- 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/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +2 -2
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +63 -89
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +2 -3
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -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-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/post-tool-use-recording-spawn-admission.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-guarding-ulw-loop-spawns.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-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-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.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 +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +8 -2
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +2 -2
- package/packages/omo-codex/plugin/skills/browser/ATTRIBUTION.md +26 -14
- package/packages/omo-codex/plugin/skills/browser/SKILL.md +65 -52
- package/packages/omo-codex/plugin/skills/browser/references/commands.md +81 -66
- package/packages/omo-codex/plugin/skills/browser/references/install.md +31 -34
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +41 -21
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/ladder.md +24 -22
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/network.md +35 -15
- package/packages/omo-codex/plugin/skills/browser/references/recipes/1password.md +13 -11
- package/packages/omo-codex/plugin/skills/browser/references/remote.md +5 -4
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/index.js +1534 -0
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +9 -0
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/page-bundle.js +1395 -0
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-doctor.mjs +37 -32
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-install.mjs +31 -44
- package/packages/omo-codex/plugin/skills/browser/scripts/omowright.mjs +25 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +3 -3
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/08-qa.md +1 -1
- package/packages/omo-codex/plugin/skills/debugging/references/tools/browser-qa.md +104 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/ambience-skill.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +30 -7
- package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +17 -5
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -18
- package/packages/omo-codex/plugin/skills/programming/references/rust/README.md +43 -15
- package/packages/omo-codex/plugin/skills/programming/references/rust/api-design.md +81 -0
- package/packages/omo-codex/plugin/skills/programming/references/rust/async-tokio.md +60 -28
- package/packages/omo-codex/plugin/skills/programming/references/rust/axum-stack.md +1 -13
- package/packages/omo-codex/plugin/skills/programming/references/rust/cargo-strict.md +44 -8
- package/packages/omo-codex/plugin/skills/programming/references/rust/clap-stack.md +8 -3
- package/packages/omo-codex/plugin/skills/programming/references/rust/concurrency.md +66 -52
- package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +35 -25
- package/packages/omo-codex/plugin/skills/programming/references/rust/macros.md +63 -0
- package/packages/omo-codex/plugin/skills/programming/references/rust/one-liners.md +5 -3
- package/packages/omo-codex/plugin/skills/programming/references/rust/proptest-insta.md +8 -0
- package/packages/omo-codex/plugin/skills/programming/references/rust/type-state.md +50 -12
- package/packages/omo-codex/plugin/skills/programming/references/rust/unsafe-discipline.md +34 -6
- package/packages/omo-codex/plugin/skills/programming/references/rust/zero-cost-safety.md +62 -52
- package/packages/omo-codex/plugin/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
- package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
- package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +31 -28
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +27 -20
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +5 -11
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +63 -89
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +2 -3
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +46 -46
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -2
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +4 -2
- package/packages/prompts-core/prompts/ultrawork/codex.md +63 -89
- package/packages/shared-skills/skills/browser/ATTRIBUTION.md +26 -14
- package/packages/shared-skills/skills/browser/SKILL.md +65 -52
- package/packages/shared-skills/skills/browser/references/commands.md +81 -66
- package/packages/shared-skills/skills/browser/references/install.md +31 -34
- package/packages/shared-skills/skills/browser/references/owned-engine/README.md +41 -21
- package/packages/shared-skills/skills/browser/references/owned-engine/frames-and-humans.md +33 -20
- package/packages/shared-skills/skills/browser/references/owned-engine/ladder.md +24 -22
- package/packages/shared-skills/skills/browser/references/owned-engine/network.md +35 -15
- package/packages/shared-skills/skills/browser/references/recipes/1password.md +13 -11
- package/packages/shared-skills/skills/browser/references/remote.md +5 -4
- package/packages/shared-skills/skills/browser/runtime/omowright/index.js +1534 -0
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +9 -0
- package/packages/shared-skills/skills/browser/runtime/omowright/page-bundle.js +1395 -0
- package/packages/shared-skills/skills/browser/scripts/browser-doctor.mjs +37 -32
- package/packages/shared-skills/skills/browser/scripts/browser-install.mjs +31 -44
- package/packages/shared-skills/skills/browser/scripts/omowright.mjs +25 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +2 -2
- package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +3 -3
- package/packages/shared-skills/skills/debugging/references/methodology/08-qa.md +1 -1
- package/packages/shared-skills/skills/debugging/references/tools/browser-qa.md +104 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/ambience-skill.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +30 -7
- package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +17 -5
- package/packages/shared-skills/skills/programming/SKILL.md +12 -18
- package/packages/shared-skills/skills/programming/references/rust/README.md +43 -15
- package/packages/shared-skills/skills/programming/references/rust/api-design.md +81 -0
- package/packages/shared-skills/skills/programming/references/rust/async-tokio.md +60 -28
- package/packages/shared-skills/skills/programming/references/rust/axum-stack.md +1 -13
- package/packages/shared-skills/skills/programming/references/rust/cargo-strict.md +44 -8
- package/packages/shared-skills/skills/programming/references/rust/clap-stack.md +8 -3
- package/packages/shared-skills/skills/programming/references/rust/concurrency.md +66 -52
- package/packages/shared-skills/skills/programming/references/rust/libraries.md +35 -25
- package/packages/shared-skills/skills/programming/references/rust/macros.md +63 -0
- package/packages/shared-skills/skills/programming/references/rust/one-liners.md +5 -3
- package/packages/shared-skills/skills/programming/references/rust/proptest-insta.md +8 -0
- package/packages/shared-skills/skills/programming/references/rust/type-state.md +50 -12
- package/packages/shared-skills/skills/programming/references/rust/unsafe-discipline.md +34 -6
- package/packages/shared-skills/skills/programming/references/rust/zero-cost-safety.md +62 -52
- package/packages/shared-skills/skills/programming/references/rust-ub/miri-sanitizers-loom.md +1 -1
- package/packages/shared-skills/skills/programming/references/rust-ub/ub-taxonomy.md +6 -3
- package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.sh +86 -75
- package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.test.ts +83 -0
- package/packages/shared-skills/skills/programming/scripts/rust/new-project.py +31 -28
- package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +27 -20
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +32 -100
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +5 -11
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +20 -37
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +4 -4
- package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
- package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +46 -46
- package/dist/skills/browser/scripts/browser-env.mjs +0 -41
- package/dist/skills/debugging/references/tools/playwright-cli.md +0 -112
- package/dist/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-env.mjs +0 -41
- package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +0 -112
- package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
- package/packages/shared-skills/skills/browser/scripts/browser-env.mjs +0 -41
- package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +0 -112
- package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.py +0 -296
|
@@ -1,41 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { loadOmowright } from "./omowright.mjs"
|
|
3
|
+
|
|
4
|
+
const { entry, omowright } = await loadOmowright()
|
|
5
|
+
const report = await omowright.bskDoctor({ waitForBrowserMs: 0 })
|
|
6
|
+
|
|
7
|
+
const state = report.ready
|
|
8
|
+
? "ready"
|
|
9
|
+
: !report.cli.installed
|
|
10
|
+
? "no-cli"
|
|
11
|
+
: !report.daemon.running
|
|
12
|
+
? "no-daemon"
|
|
13
|
+
: report.browsers.length === 0
|
|
14
|
+
? "no-browser-support"
|
|
15
|
+
: "no-extension"
|
|
4
16
|
|
|
5
17
|
const REMEDIES = {
|
|
6
|
-
ready: "
|
|
7
|
-
"no-
|
|
8
|
-
"no-
|
|
9
|
-
"no-
|
|
18
|
+
ready: "Attached engine is live: const { connectBrowserSkill } = await import(omowrightEntry); const session = await connectBrowserSkill({ name: \"<task>\", focused: false })",
|
|
19
|
+
"no-cli": "Run node \"<skill-root>/scripts/browser-install.mjs\" — it installs the CLI, starts the daemon and registers the extension; then tell the user the single step it prints.",
|
|
20
|
+
"no-daemon": "Run node \"<skill-root>/scripts/browser-install.mjs\" (it starts the daemon through `bsk status`), then re-run this doctor.",
|
|
21
|
+
"no-extension": report.nextStep ?? "Register the extension with browser-install.mjs, then relay its human step to the user and re-run this doctor.",
|
|
22
|
+
"no-browser-support": "No Chromium-family browser profile was found on this machine. Say so and stop; do not substitute another engine.",
|
|
10
23
|
}
|
|
11
24
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
status = await readStatus(cli)
|
|
22
|
-
} catch (error) {
|
|
23
|
-
return { state: "no-extension", platform: platform(), cli, detail: `status failed: ${error.message}` }
|
|
24
|
-
}
|
|
25
|
-
const browsers = connectedBrowsers(status)
|
|
26
|
-
if (browsers.length === 0) return { state: "no-extension", platform: platform(), cli }
|
|
27
|
-
return { state: "ready", platform: platform(), cli, browsers: browsers.length }
|
|
25
|
+
const summary = {
|
|
26
|
+
state,
|
|
27
|
+
omowright: entry,
|
|
28
|
+
cli: report.cli,
|
|
29
|
+
daemon: { running: report.daemon.running, version: report.daemon.version ?? null, protocolVersion: report.daemon.protocolVersion ?? null, error: report.daemon.error ?? null },
|
|
30
|
+
browsersDetected: report.browsers.map((browser) => ({ id: browser.id, userDataDir: browser.userDataDir, extensionRegistered: browser.extensionRegistered })),
|
|
31
|
+
browsersConnected: report.browsersConnected.map((browser) => ({ instanceId: browser.instance_id, name: browser.browser_name, version: browser.browser_version })),
|
|
32
|
+
nextStep: report.nextStep,
|
|
33
|
+
remedy: REMEDIES[state],
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (json) {
|
|
33
|
-
console.log(JSON.stringify({ ...report, remedy: REMEDIES[report.state] }, null, 2))
|
|
36
|
+
if (process.argv.includes("--json")) {
|
|
37
|
+
console.log(JSON.stringify(summary, null, 2))
|
|
34
38
|
} else {
|
|
35
|
-
console.log(`state: ${
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
console.log(
|
|
39
|
+
console.log(`state: ${state}`)
|
|
40
|
+
console.log(`omowright: ${entry}`)
|
|
41
|
+
console.log(`cli: ${report.cli.installed ? `${report.cli.bskBin} (${report.cli.version})` : "not installed"}`)
|
|
42
|
+
console.log(`daemon: ${report.daemon.running ? `running (${report.daemon.version}, protocol ${report.daemon.protocolVersion})` : `not running${report.daemon.error ? ` — ${report.daemon.error}` : ""}`}`)
|
|
43
|
+
console.log(`browsers detected: ${summary.browsersDetected.map((b) => `${b.id}${b.extensionRegistered ? " (extension registered)" : ""}`).join(", ") || "none"}`)
|
|
44
|
+
console.log(`browsers connected: ${summary.browsersConnected.map((b) => `${b.name} ${b.version} [${b.instanceId}]`).join(", ") || "none"}`)
|
|
45
|
+
console.log(`\n${REMEDIES[state]}`)
|
|
40
46
|
}
|
|
41
|
-
process.exit(report.state === "ready" ? 0 : 1)
|
|
@@ -1,51 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { platform } from "node:os"
|
|
4
|
-
import { resolveCli, STORE_LISTINGS, SUPPORTED_PLATFORMS } from "./browser-env.mjs"
|
|
2
|
+
import { loadOmowright } from "./omowright.mjs"
|
|
5
3
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
4
|
+
const json = process.argv.includes("--json")
|
|
5
|
+
const waitArg = process.argv.find((arg) => arg.startsWith("--wait-ms="))
|
|
6
|
+
const waitTotalMs = waitArg ? Number(waitArg.slice("--wait-ms=".length)) : 0
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return new Promise((resolve) => {
|
|
17
|
-
const child = spawn(file, args, { stdio: "inherit", windowsHide: true })
|
|
18
|
-
child.on("error", () => resolve(1))
|
|
19
|
-
child.on("close", (code) => resolve(code ?? 1))
|
|
20
|
-
})
|
|
21
|
-
}
|
|
8
|
+
const { omowright } = await loadOmowright()
|
|
9
|
+
const steps = []
|
|
10
|
+
const result = await omowright.bskOnboard({
|
|
11
|
+
onHumanStep: (step) => steps.push(step),
|
|
12
|
+
waitForBrowserMs: waitTotalMs > 0 ? Math.min(15_000, waitTotalMs) : 0,
|
|
13
|
+
waitTotalMs,
|
|
14
|
+
})
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
const summary = {
|
|
17
|
+
ready: result.ready,
|
|
18
|
+
cli: result.cli,
|
|
19
|
+
installerRan: result.install !== null,
|
|
20
|
+
daemon: { running: result.daemon.running, version: result.daemon.version ?? null, error: result.daemon.error ?? null },
|
|
21
|
+
registrations: result.registrations.map((r) => ({ browser: r.browser, registered: r.registered, alreadyPresent: r.alreadyPresent ?? false, reason: r.reason ?? null, needsRestart: r.needsRestart ?? null, humanStep: r.humanStep ?? null })),
|
|
22
|
+
browsersConnected: result.browsersConnected.map((b) => ({ instanceId: b.instance_id, name: b.browser_name, version: b.browser_version })),
|
|
23
|
+
humanStep: result.humanStep,
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
if (
|
|
29
|
-
console.log(
|
|
30
|
-
|
|
26
|
+
if (json) {
|
|
27
|
+
console.log(JSON.stringify(summary, null, 2))
|
|
28
|
+
} else if (result.ready) {
|
|
29
|
+
console.log(`attached engine ready: ${summary.browsersConnected.map((b) => `${b.name} ${b.version}`).join(", ")}`)
|
|
30
|
+
} else {
|
|
31
|
+
console.log(`cli: ${result.cli.installed ? `${result.cli.bskBin} (${result.cli.version})` : "install failed"}`)
|
|
32
|
+
console.log(`daemon: ${result.daemon.running ? "running" : `not running${result.daemon.error ? ` — ${result.daemon.error}` : ""}`}`)
|
|
33
|
+
for (const r of summary.registrations) {
|
|
34
|
+
console.log(`extension for ${r.browser}: ${r.registered ? (r.alreadyPresent ? "already registered" : "registered") : `not registered (${r.reason})`}`)
|
|
35
|
+
}
|
|
36
|
+
console.log(`\nTell the user exactly this, then re-run browser-doctor.mjs:\n ${result.humanStep}`)
|
|
31
37
|
}
|
|
32
|
-
|
|
33
|
-
const command = installCommand()
|
|
34
|
-
console.log(`installing the bsk CLI with the upstream installer:\n ${command.display}\n`)
|
|
35
|
-
const code = await spawnInstaller(command)
|
|
36
|
-
if (code !== 0) {
|
|
37
|
-
console.error(`\ninstaller exited ${code}. Report this instead of retrying blindly.`)
|
|
38
|
-
process.exit(code)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
console.log([
|
|
42
|
-
"",
|
|
43
|
-
"CLI installed. Two things remain, and only the user can do the first:",
|
|
44
|
-
"",
|
|
45
|
-
"1. Install the browser extension from the store, then enable it:",
|
|
46
|
-
` Chrome: ${STORE_LISTINGS.chrome}`,
|
|
47
|
-
` Edge: ${STORE_LISTINGS.edge}`,
|
|
48
|
-
"2. Re-run: node \"<skill-root>/scripts/browser-doctor.mjs\"",
|
|
49
|
-
"",
|
|
50
|
-
"If PATH does not pick up the CLI in this shell, use its absolute path under ~/.local/bin.",
|
|
51
|
-
].join("\n"))
|
|
38
|
+
process.exitCode = result.ready ? 0 : 2
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { dirname, join } from "node:path"
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
4
|
+
|
|
5
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const skillRoot = dirname(scriptDir)
|
|
7
|
+
|
|
8
|
+
export function resolveOmowrightEntry(env = process.env) {
|
|
9
|
+
const candidates = [
|
|
10
|
+
env.OMOWRIGHT_ROOT ? join(env.OMOWRIGHT_ROOT, "index.js") : undefined,
|
|
11
|
+
join(skillRoot, "runtime", "omowright", "index.js"),
|
|
12
|
+
join(skillRoot, "..", "..", "..", "..", "node_modules", "omowright", "src", "index.js"),
|
|
13
|
+
].filter((candidate) => candidate !== undefined)
|
|
14
|
+
return candidates.find((candidate) => existsSync(candidate))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function loadOmowright(env = process.env) {
|
|
18
|
+
const entry = resolveOmowrightEntry(env)
|
|
19
|
+
if (entry === undefined) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
"omowright is not staged in this skill; run `node packages/shared-skills/stage-omowright-runtime.mjs` in a checkout, or set OMOWRIGHT_ROOT to a directory holding its bundled index.js",
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
return { entry, omowright: await import(pathToFileURL(entry).href) }
|
|
25
|
+
}
|
|
@@ -49,7 +49,7 @@ These are not "optional extras". They are the correct tool in their domain, and
|
|
|
49
49
|
|
|
50
50
|
| Tool | Use when | Reference |
|
|
51
51
|
|---|---|---|
|
|
52
|
-
| **
|
|
52
|
+
| **omowright** | Any browser-served web UI bug. Any flow that requires clicking/typing/navigating. Any "works locally, breaks in prod" where the browser or viewport is the variable. **For Phase 8 QA of any browser product, you MUST drive a real browser through omowright — not curl, not imagination.** | 📖 **[references/tools/browser-qa.md](references/tools/browser-qa.md)** |
|
|
53
53
|
| **Ghidra** | Any binary without trustworthy source — third-party closed libs, malware, vendored binaries whose behavior contradicts docs, CTF, firmware. **Use Ghidra's decompiler before `strings`/`objdump` guessing. It turns machine code into readable C.** | 📖 **[references/tools/ghidra.md](references/tools/ghidra.md)** |
|
|
54
54
|
| **pwndbg** | Any native binary debugging session. It is GDB with the useful views (registers, stack, disasm, heap) always visible. **If you'd reach for plain `gdb`, reach for `pwndbg` instead — it is strictly a superset.** | 📖 **[references/tools/pwndbg.md](references/tools/pwndbg.md)** |
|
|
55
55
|
| **pwntools** | Any time you need a reproducible interaction with a binary or network service — crafted payloads, exploit automation, fuzz harness, CTF scripting. | 📖 **[references/tools/pwntools.md](references/tools/pwntools.md)** |
|
|
@@ -97,7 +97,7 @@ These are not phases — read them when the situation calls for them:
|
|
|
97
97
|
<safety>
|
|
98
98
|
1. **Runtime state is the only source of truth.** A hypothesis without an observed value is a guess. Do not fix guesses.
|
|
99
99
|
2. **Every debug artifact is journaled before it is created.** Journal-then-modify, not modify-then-remember-maybe.
|
|
100
|
-
3. **Never ship a fix without
|
|
100
|
+
3. **Never ship a fix without its reproduction.** The failing case captured BEFORE the fix, the same case passing after it, or the fix is unverified. Where the repository keeps tests for this behavior, that case is the regression test.
|
|
101
101
|
4. **Never declare done on type-check/compile alone.** Types catch declaration bugs. Only running the actual user scenario catches the actual user bug.
|
|
102
102
|
5. **Never ask the user a question that runtime evidence can already answer.** Escalation is for genuine ambiguity.
|
|
103
103
|
6. **Never silently swallow errors while debugging.** If the system swallows errors, that is often the bug itself. Make them loud temporarily; restore at cleanup.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Phase 6 + 7 — Root Cause Confirmation &
|
|
1
|
+
# Phase 6 + 7 — Root Cause Confirmation & Reproduction-Locked Fix
|
|
2
2
|
|
|
3
3
|
A cause is not "confirmed" until you can toggle the bug by toggling the cause. Every other level of evidence is correlation, and correlation-driven fixes ship bugs.
|
|
4
4
|
|
|
@@ -51,7 +51,7 @@ The "mechanism" field is the acid test. If you can't write the causal chain from
|
|
|
51
51
|
|
|
52
52
|
Red, green, refactor. No shortcuts.
|
|
53
53
|
|
|
54
|
-
### 1. Red —
|
|
54
|
+
### 1. Red — the reproduction as a test
|
|
55
55
|
|
|
56
56
|
Write a test that fails *specifically because of this bug*. Requirements:
|
|
57
57
|
|
|
@@ -117,6 +117,6 @@ Full suite: <N tests, <M failures — should be 0>
|
|
|
117
117
|
|
|
118
118
|
## The red-green discipline summary
|
|
119
119
|
|
|
120
|
-
No
|
|
120
|
+
No captured failure → no proof the fix addresses the reported bug. Only proof it doesn't break tests that already existed. Keep the reproduction as a test where the repository keeps tests for this behavior; otherwise the captured before/after run is the proof.
|
|
121
121
|
|
|
122
122
|
A test written *after* the fix might still pass with the fix reverted. If that's the case, the test doesn't lock the bug — it locks something else. Always verify the test fails without the fix and passes with it. The journal should show both outputs.
|
|
@@ -14,7 +14,7 @@ Pick the row that matches the product. Do what it says. Do not substitute.
|
|
|
14
14
|
|---|---|
|
|
15
15
|
| **CLI tool** | Open `tmux`, run the actual command end-to-end, capture output. Paste the session transcript into the journal. Include exit code, stdout, stderr, side-effect check (files created/modified). |
|
|
16
16
|
| **HTTP API** | Start the real server, hit endpoints with `curl` or `httpie`, inspect response status + body + headers. Hit the specific endpoint that reproduced the bug. If there's auth, use real auth. |
|
|
17
|
-
| **Browser-served web app** | **Drive a real browser
|
|
17
|
+
| **Browser-served web app** | **Drive a real browser through omowright.** See [tools/browser-qa.md](../tools/browser-qa.md). Navigate the exact page/flow that reproduced the bug. Capture screenshot + DOM + network evidence. **Do not substitute with curl** — browsers have state (cookies, localStorage, service workers, client-side JS, viewport-dependent CSS) that curl does not have. |
|
|
18
18
|
| **Agent / LLM pipeline** | Run the same user prompt that originally failed. Capture the full turn — tool calls, messages, usage counters. **Confirm non-zero usage** (zero usage = still failing silently, see silent-failure check below). |
|
|
19
19
|
| **Background worker / job queue** | Trigger the job through the normal entry point (API call, cron tick, message publish), tail the worker logs, observe completion state in the queue or DB. Don't just call the worker function directly — the trigger path matters. |
|
|
20
20
|
| **MCP server** | Invoke the tool via its actual client (Claude Desktop, Cursor, etc. if available) or `mcp-cli`, not just the HTTP probe endpoint. The MCP handshake itself is sometimes where bugs live. |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Browser QA — omowright from js eval
|
|
2
|
+
|
|
3
|
+
A browser UI bug needs a rendered browser, not curl. omowright is staged inside the `browser`
|
|
4
|
+
skill; load it from a js-eval cell and pick the engine the bug lives in:
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
const { loadOmowright } = await import("<browser-skill-root>/scripts/omowright.mjs")
|
|
8
|
+
const { omowright } = await loadOmowright()
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| The bug needs | Engine |
|
|
12
|
+
|---|---|
|
|
13
|
+
| A public page, a fresh profile, a pinned viewport, traces, network capture | **owned** — `connectPipe` (or `connectCloakProfile` when the site scores bots) |
|
|
14
|
+
| The user's login, their cookies, their open tabs | **attached** — `connectBrowserSkill()`; never a clone of their profile |
|
|
15
|
+
|
|
16
|
+
Chrome must already be installed for the owned engine; report an absent executable rather than
|
|
17
|
+
downloading a managed browser.
|
|
18
|
+
|
|
19
|
+
## The four things you'll actually use
|
|
20
|
+
|
|
21
|
+
### 1. Reproduce with a flight trace
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
const profile = mkdtempSync(join(tmpdir(), "debug-repro-"))
|
|
25
|
+
const browser = await omowright.connectPipe({ browserPath, browserArgs: ["--headless", `--user-data-dir=${profile}`], storageRoot: profile })
|
|
26
|
+
const page = await browser.newTab("about:blank")
|
|
27
|
+
const trace = omowright.createTrace(page, { dir: traceDir }) // trace.jsonl + trace.har + before/after screenshots
|
|
28
|
+
const consoleErrors = []
|
|
29
|
+
page.on("console", (entry) => { if (entry.type === "error") consoleErrors.push(entry.text) })
|
|
30
|
+
try {
|
|
31
|
+
await trace.step("open", () => page.goto(url, { waitUntil: "load" }))
|
|
32
|
+
await trace.step("submit", async () => {
|
|
33
|
+
const { tree } = await page.snapshot({ interactive: true }) // read, then act on a fresh ref
|
|
34
|
+
await page.locator("e5").fill(value)
|
|
35
|
+
await page.locator("e7").click()
|
|
36
|
+
await page.waitForURL(/\/done/, { timeout: 10_000 })
|
|
37
|
+
})
|
|
38
|
+
await Bun.write(pngPath, await page.screenshot())
|
|
39
|
+
} finally {
|
|
40
|
+
await trace.stop()
|
|
41
|
+
await browser.close()
|
|
42
|
+
rmSync(profile, { recursive: true, force: true })
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
A screenshot alone is not a reproduction assertion. Read the snapshot for the exact observable
|
|
47
|
+
state (a role, a name, a value) and fail the step when it is absent.
|
|
48
|
+
|
|
49
|
+
### 2. Read the network instead of guessing
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
const snoop = omowright.createNetworkSnoop(page)
|
|
53
|
+
const hit = await snoop.waitFor({ url: /\/api\/submit/ }, { timeoutMs: 10_000 }) // subscribe BEFORE the click
|
|
54
|
+
console.log(hit.status, hit.body?.slice(0, 500))
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Subscribe before triggering the action, then await that specific response; do not sleep or wait
|
|
58
|
+
for generic idleness. `createRoutes(page)` fails one request on purpose to test an error path.
|
|
59
|
+
|
|
60
|
+
### 3. Reproduce in the user's browser
|
|
61
|
+
|
|
62
|
+
When the bug only happens signed in:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const session = await omowright.connectBrowserSkill({ name: "debug repro", focused: false })
|
|
66
|
+
try {
|
|
67
|
+
await session.navigate(url)
|
|
68
|
+
const { tree, css } = await omowright.bskSnapshot(session, { interactive: true })
|
|
69
|
+
await session.click({ selector: css.e7 })
|
|
70
|
+
const errors = await session.console({ since: 0 })
|
|
71
|
+
const shot = await session.screenshot()
|
|
72
|
+
} finally {
|
|
73
|
+
await session.stop()
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The value of this engine is the state that curl and a fresh profile do not have — cookies,
|
|
78
|
+
localStorage, service workers. Never read credentials through `evaluate`, never clear the
|
|
79
|
+
profile's data.
|
|
80
|
+
|
|
81
|
+
### 4. Viewport and device emulation
|
|
82
|
+
|
|
83
|
+
`emulate(page, "iphone-14")` applies viewport, device scale factor, user agent and touch
|
|
84
|
+
together; `emulate(page, { width: 375, height: 667, deviceScaleFactor: 2, mobile: true, hasTouch: true })`
|
|
85
|
+
for a custom preset. Match the reference's pixel scale as well as its viewport.
|
|
86
|
+
|
|
87
|
+
## Headless vs headed during debugging
|
|
88
|
+
|
|
89
|
+
Drop `--headless` from `browserArgs` with an available display when reproducing headed-only
|
|
90
|
+
behavior. State which mode produced the evidence; do not claim a headless capture proves
|
|
91
|
+
desktop-browser permissions or window behavior.
|
|
92
|
+
|
|
93
|
+
## Gotchas
|
|
94
|
+
|
|
95
|
+
- Wait for state, not time: a snapshot ref, `waitForURL`, or a snooped response is the signal.
|
|
96
|
+
- Refs die on every new snapshot; read again after any navigation or large DOM change.
|
|
97
|
+
- Fresh task-owned profiles avoid cached state leaking between runs.
|
|
98
|
+
- Auth belongs to the attached engine, never to a copy of the live browser profile.
|
|
99
|
+
- Give every run its own output directory and a bounded process lifetime.
|
|
100
|
+
|
|
101
|
+
## Phase 9 cleanup specifics
|
|
102
|
+
|
|
103
|
+
`browser.close()` / `session.stop()` even on failure, stop the fixture server, and remove only this
|
|
104
|
+
run's profile directory. Preserve requested PNG/trace evidence; keep auth-bearing traces private.
|
|
@@ -147,7 +147,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
|
|
|
147
147
|
| Situation | Load |
|
|
148
148
|
|---|---|
|
|
149
149
|
| 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) |
|
|
150
|
-
| Driving a browser for the Design QA phase | `visual-qa` skill:
|
|
150
|
+
| Driving a browser for the Design QA phase | `visual-qa` skill: omowright from js eval (owned engine for renders, attached engine for signed-in pages) |
|
|
151
151
|
| Pure TypeScript/logic work with zero visual surface | `programming` skill alone — this skill adds nothing there |
|
|
152
152
|
|
|
153
153
|
## Activation
|
|
@@ -113,7 +113,8 @@ react-bits optimizes for the demo page. The project optimizes for `perfection/RE
|
|
|
113
113
|
- **Accessibility contract.** Decorative canvases and effect layers get `aria-hidden="true"`. Split or scrambled text keeps the full string readable: one `aria-label` on the wrapper, or a visually hidden copy, so screen readers never hear one glyph at a time.
|
|
114
114
|
- **Tokens, not demo colors.** Every color, gradient stop, and intensity traces to a `DESIGN.md` token. The catalog's violet, pink, and cyan defaults are placeholders.
|
|
115
115
|
- **Budget and load order.** WebGL and GSAP-heavy components load lazily (`React.lazy` / `next/dynamic`) after the LCP element; the hero's LCP is the headline or the poster image, never the canvas. Ship a static poster fallback behind a WebGL capability check. Record the chunk size in `DESIGN.md` accepted debt.
|
|
116
|
-
- **
|
|
116
|
+
- **Comfort for large-area motion.** A moving layer that fills the viewport is read by peripheral vision as the world moving: keep the surrounding chrome still as a fixed reference frame, keep the moving layer low-contrast and translucent, concentrate motion toward the center rather than the viewport edges, and never run a slow oscillation near 0.2 Hz (one cycle every ~5 s).
|
|
117
|
+
- **One atmosphere per page.** A background is the hero's one signature moment; a text reveal marks arrival; a card effect signals affordance. Two atmospheres on one page, or a reveal on every paragraph, is slop even when each piece is well built.
|
|
117
118
|
|
|
118
119
|
## 5. Dependency rules
|
|
119
120
|
|
|
@@ -8,7 +8,7 @@ A `DESIGN.md` whose every token, interaction state, and motion value was read fr
|
|
|
8
8
|
|
|
9
9
|
## Phase 1 — Extract the runtime truth (never guess a value)
|
|
10
10
|
|
|
11
|
-
Drive a real browser from js eval
|
|
11
|
+
Drive a real browser with omowright from js eval (staged in the `browser` skill): `connectPipe` on a task-owned profile for a public page, `connectCloakProfile` when the source is bot-scored, `connectBrowserSkill()` when it needs the user's login — then `page.evaluate` / `session.evaluate` for `getComputedStyle`. Do NOT parse CSS files — minification, CORS, CSS-in-JS, and Tailwind utilities make source unreliable. `getComputedStyle` returns what the browser ACTUALLY rendered, so it is the only source of truth.
|
|
12
12
|
|
|
13
13
|
Sweep the page and read, for every meaningful element and every repeated pattern:
|
|
14
14
|
|
package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md
CHANGED
|
@@ -60,8 +60,7 @@ rather than borders, creating layers you feel more than see."
|
|
|
60
60
|
| Status/info | --status-info | #2563EB | #3B82F6 | Informational |
|
|
61
61
|
|
|
62
62
|
### Rules
|
|
63
|
-
-
|
|
64
|
-
- Accent is used ONLY for interactive elements. Never decorative.
|
|
63
|
+
- Accent marks the one or two most likely actions on a screen, on the control's background rather than its glyph or label. Peer choices differ by style, never by size. Nothing decorative carries accent.
|
|
65
64
|
- Never introduce a color not in this table. Extend the table first.
|
|
66
65
|
|
|
67
66
|
## 3. Typography
|
|
@@ -148,12 +147,22 @@ code; do not invent future components just to fill the section.
|
|
|
148
147
|
| Emphasis | 400-600ms | cubic-bezier(0.16, 1, 0.3, 1) | Page transition, hero entry |
|
|
149
148
|
| Scroll-driven | tied to scroll | linear | Parallax, progress, reveal |
|
|
150
149
|
|
|
150
|
+
### Feedback thresholds
|
|
151
|
+
|
|
152
|
+
| Event | Feedback | Timing |
|
|
153
|
+
|-------|----------|--------|
|
|
154
|
+
| Press, tap, drag start | State change on the element itself | Same frame; a drag image once the pointer has moved a few px |
|
|
155
|
+
| Hover-revealed controls | Controls appear, then leave with the pointer | After hover intent, not on pointer entry |
|
|
156
|
+
| Async action started | Placeholder or disabled control at once; spinner or skeleton only past ~1 s | An indicator never flashes for sub-second work |
|
|
157
|
+
| Long wait | Determinate progress at an even pace; indeterminate only when the total is unknown | Never swap indicator shape mid-task or front-load to 90% |
|
|
158
|
+
| Outcome | Failure reported next to the object; success shown by the changed state itself | Toast only for outcomes not visible in place |
|
|
159
|
+
|
|
151
160
|
### Rules
|
|
152
|
-
- Only animate `transform` and `
|
|
153
|
-
- Every interactive element has hover
|
|
154
|
-
-
|
|
161
|
+
- Only animate `transform`, `opacity`, and `filter`. Never animate layout properties.
|
|
162
|
+
- Every interactive element has hover, active, and focus states. Selected/focused/active is encoded with ink-alpha washes and a glyph (check) — never a coloured accent border or outline. `focus-visible` rings are the only coloured edge.
|
|
163
|
+
- A surface that changes size, position, or content animates from its old geometry to the new one; never unmount and remount it. Nothing reflows under the pointer while the user is typing or dragging.
|
|
155
164
|
- Scroll-triggered animations use `IntersectionObserver`, not scroll listeners.
|
|
156
|
-
- Reduced motion:
|
|
165
|
+
- Reduced motion means reduce, not remove: under `prefers-reduced-motion`, positional, scale, and depth motion becomes a cross-fade; fades, gesture-tracked motion, and progress indicators stay.
|
|
157
166
|
|
|
158
167
|
## 7. Depth & Surface
|
|
159
168
|
|
|
@@ -176,6 +185,19 @@ If borders:
|
|
|
176
185
|
If tonal-shift:
|
|
177
186
|
Surfaces use progressively lighter/darker shades. No borders, no shadows.
|
|
178
187
|
|
|
188
|
+
### Radius
|
|
189
|
+
|
|
190
|
+
| Token | Value | Usage |
|
|
191
|
+
|-------|-------|-------|
|
|
192
|
+
| --radius-sm | [e.g. 6px] | Inputs, chips, small controls |
|
|
193
|
+
| --radius-md | [e.g. 12px] | Cards, panels, popovers |
|
|
194
|
+
| --radius-lg | [e.g. 20px] | Sheets, modals, hero containers |
|
|
195
|
+
| --radius-full | 9999px | Pills, avatars |
|
|
196
|
+
|
|
197
|
+
### Rules
|
|
198
|
+
- Nested corners are concentric: inner radius = outer radius minus the padding between them, never the same value at both depths.
|
|
199
|
+
- Elevation reads only when scale, shadow, and highlight change together; a shadow change alone does not lift a surface.
|
|
200
|
+
|
|
179
201
|
## 8. Accessibility Constraints & Accepted Debt
|
|
180
202
|
|
|
181
203
|
### Constraints
|
|
@@ -220,7 +242,8 @@ After every component implementation, check:
|
|
|
220
242
|
- [ ] Interactive elements have all required states from Section 5 and Section 6.
|
|
221
243
|
- [ ] Depth treatment matches the chosen strategy from Section 7.
|
|
222
244
|
- [ ] Component reused 2+ times? Documented in Section 5.
|
|
223
|
-
- [ ] Motion follows the timing
|
|
245
|
+
- [ ] Motion follows the timing and feedback-threshold tables, and every animation has its reduced-motion path.
|
|
246
|
+
- [ ] Radii come from the Section 7 scale; nested corners are concentric.
|
|
224
247
|
- [ ] Component visual QA passed for each primitive and required state before product screens were composed.
|
|
225
248
|
- [ ] Section 8 accessibility constraints hold for the new component; any new debt is recorded in Section 8, not silently accepted.
|
|
226
249
|
- [ ] Survives content stress: empty, long label, unbroken string. Reflows to one readable column at 375px with no horizontal scroll of primary content.
|
|
@@ -125,11 +125,23 @@ This table is the edge of this catalog. Hero atmospheres, animated or shader bac
|
|
|
125
125
|
|
|
126
126
|
These sharpen the shared axioms for interaction work; none of them replace the style skill.
|
|
127
127
|
|
|
128
|
-
- **Motion serves meaning.** Every animation maps to a real interaction, state change, or affordance
|
|
129
|
-
|
|
128
|
+
- **Motion serves meaning, and each meaning has its motion.** Every animation maps to a real interaction, state change, or affordance; a hover that changes nothing is slop. Pick the motion from the meaning, not from the catalog's most striking demo:
|
|
129
|
+
|
|
130
|
+
| Meaning | Motion | Not |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| Press acknowledged | Scale or wash on the element, same frame | A ripple that arrives after the action fires |
|
|
133
|
+
| Something is in progress | A moving indicator | A static one, which reads as frozen |
|
|
134
|
+
| Something is live or new | A brief highlight or subtle pulse, once | A permanent loop |
|
|
135
|
+
| Something arrived from elsewhere | Enter from the direction of its origin | A fade-in from nowhere |
|
|
136
|
+
| Something moved | It travels there | Disappear here, appear there |
|
|
137
|
+
| An unfamiliar control exists | A one-time introduction on first appearance | Continuous decoration |
|
|
138
|
+
|
|
139
|
+
- **Transitions keep identity.** A surface that resizes, repositions, or swaps content animates from its old geometry to the new one (`layoutId` shared layout or a measured-height morph); the user must never suspect a replacement. When items move and others appear, move first, then add. Keep one element still as the anchor while the rest animates. Nothing reflows under the pointer while the user is typing or dragging. A panel leaves the way it came: a sheet that rose from the bottom dismisses downward, and the reverse gesture undoes the forward one.
|
|
140
|
+
- **Reduced motion is part of the component, not an afterthought.** Every beui.dev component ships a reduced-motion path; match that bar, and reduce rather than remove: under `prefers-reduced-motion: reduce`, positional, scale, and depth motion becomes a cross-fade (the `loader` pattern's opacity-pulse swap is the model); fades, gesture-tracked motion, and progress indicators stay; blur never animates its start or end. Any state that motion conveys is also announced (`aria-live`, a label change). React Native: respect the system reduce-motion setting.
|
|
130
141
|
- **GPU-composited properties only** — `transform`, `opacity`, `filter`. Never animate layout properties; morph layout through shared-layout (`layoutId`) or measured height primitives instead.
|
|
131
|
-
- **Springs move things; easings tint things.** Spatial movement (position, scale, layout morphs) wants spring physics so it stays interruptible and retargetable. Color, opacity, and blur want short duration + easing. Do not put a fixed-duration tween on a gesture-driven surface.
|
|
132
|
-
- **Interruptibility is non-negotiable.** A press, hover-out, or route change mid-animation must retarget smoothly, never queue or block input. This is the practical reason beui.dev uses springs — copy that property, not just the bounce.
|
|
142
|
+
- **Springs move things; easings tint things; continuous input tracks.** Spatial movement (position, scale, layout morphs) wants spring physics so it stays interruptible and retargetable. Color, opacity, and blur want short duration + easing. Discrete input (a tap, a keypress) animates; continuous input (a drag, a wheel, a slider) follows the pointer 1:1 with no interpolation, then settles with a spring on release. Do not put a fixed-duration tween on a gesture-driven surface.
|
|
143
|
+
- **Interruptibility is non-negotiable.** A press, hover-out, or route change mid-animation must retarget smoothly, never queue or block input, and never snap to the end state. This is the practical reason beui.dev uses springs — copy that property, not just the bounce.
|
|
144
|
+
- **One event, one feedback.** Feedback lives on the object that changed. Do not stack a spinner over a control that already shows progress, re-animate a native control, or confirm routine success with a toast: success is assumed and shown by the changed state; failure is always reported, next to the object, with the cause. Prefer undo to a confirmation dialog; a dialog is for uncommon and irreversible loss only, its buttons name the outcome ("Delete", "Keep editing"), and neither Cancel nor the destructive action takes the default (Enter) role. Send the request when the input lands, not when the acknowledging animation ends.
|
|
133
145
|
- **Motion never regresses input latency or stream rendering.** Measure with the `perfection` ruleset when in doubt; a virtualized list's measurement contract beats a pretty reveal.
|
|
134
146
|
- **Library choice is a project decision, not a default.** beui.dev assumes Motion (motion.dev) + Tailwind. If the project already has a motion stack, adapt the mechanism to it. If it has none: CSS transitions/WAAPI cover micro-interactions; adding a library is justified by shared-layout or spring-physics needs and gets recorded (with bundle cost) in `DESIGN.md`. Check `package.json` before importing anything.
|
|
135
147
|
|
|
@@ -143,4 +155,4 @@ These sharpen the shared axioms for interaction work; none of them replace the s
|
|
|
143
155
|
|
|
144
156
|
## 6. Verification
|
|
145
157
|
|
|
146
|
-
Interaction work is verified through `/visual-qa` with motion actually driven and inspected — hover, press, open/close, swipe, and theme transitions exercised on the rendered surface,
|
|
158
|
+
Interaction work is verified through `/visual-qa` with motion actually driven and inspected — hover, press, open/close, swipe, and theme transitions exercised on the rendered surface, an interruption pass (retarget mid-animation, dismiss mid-open) proving nothing snaps or blocks, and a reduced-motion pass (emulate `prefers-reduced-motion: reduce`) proving the fallback exists. Timing-sensitive changes record a short screen capture, not just stills.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: programming
|
|
3
|
-
description: "Applies strict, modern language practice (typed errors, exhaustive match,
|
|
3
|
+
description: "Applies strict, modern language practice (typed errors, exhaustive match, tests that can fail) for Python, Rust, TypeScript, and Go. Use for work on .py, .rs, .ts, or .go files."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Programming
|
|
@@ -47,23 +47,15 @@ These are not style preferences. They are the seven axioms every recipe in `refe
|
|
|
47
47
|
|
|
48
48
|
5. **Trust framework guarantees. Validate only at boundaries.** No null checks for values the type system already proves non-null. No `try/except` around code that cannot raise. No `unwrap`/`!`/`as` to paper over a contract you should have encoded in types. No defensive layer for a scenario you cannot name.
|
|
49
49
|
|
|
50
|
-
6. **
|
|
50
|
+
6. **Tests are the behavior of record, and only tests that can fail count.** READ the tests covering the area BEFORE you change it: do they encode the intent, cover this path, pass? One wrong before your change is a FINDING — never edit it green. Reproduce a bug before fixing it. The run proves the change; add a test ONLY where the repository keeps tests for this behavior AND a regression would otherwise pass unnoticed — sized like its neighbors, never restating the change. See the test discipline below.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
54
|
-
##
|
|
55
|
-
|
|
56
|
-
**Every change follows the red → green → refactor loop.** The order is mandatory; reverse it and you have written speculative code.
|
|
57
|
-
|
|
58
|
-
### The order
|
|
59
|
-
|
|
60
|
-
1. **Red.** Write a failing test that names the behavior in `Given / When / Then`. Run it. *Confirm it fails for the right reason* — not a typo, not an import error. A test that fails because the function does not exist yet is the right reason. A test that fails because of a missing import is not.
|
|
61
|
-
2. **Green.** Write the minimum code to make the test pass. Resist adding the second case until the first passes. The second case is the next red.
|
|
62
|
-
3. **Refactor.** With the test green, restructure ruthlessly. The test is your safety net. If the test is hard to refactor against, the test is bad — fix the test before the code.
|
|
54
|
+
## TEST DISCIPLINE
|
|
63
55
|
|
|
64
56
|
### The shape of the test pyramid
|
|
65
57
|
|
|
66
|
-
|
|
58
|
+
Where the repository keeps these rungs, test at the cheapest rung that observes the behavior:
|
|
67
59
|
|
|
68
60
|
| Rung | Count | Purpose | Speed budget |
|
|
69
61
|
|---|---|---|---|
|
|
@@ -71,7 +63,7 @@ Every feature ships with all three rungs, sized in this proportion:
|
|
|
71
63
|
| **Integration** | some | The real adapter against the real downstream (DB, queue, HTTP) — via `testcontainers`, `httptest`, or equivalent. NEVER a unit test pretending to be integration. | < 1 s each |
|
|
72
64
|
| **E2E scenario** | few | One narrative per user-visible outcome. Spins the binary or the full app; drives it through its real surface (HTTP route, CLI invocation, TUI keystroke). Asserts the *observable outcome*, not internal state. | seconds, run on CI |
|
|
73
65
|
|
|
74
|
-
|
|
66
|
+
A user-visible outcome you never drove through its real surface is unverified — a green unit suite does not stand in for that run.
|
|
75
67
|
|
|
76
68
|
### Given / When / Then is mandatory
|
|
77
69
|
|
|
@@ -121,7 +113,7 @@ If no machine consumes the text, there is no seam: write NO test and say so in t
|
|
|
121
113
|
|
|
122
114
|
| Anti-pattern | Why it fails | Fix |
|
|
123
115
|
|---|---|---|
|
|
124
|
-
|
|
|
116
|
+
| A test that restates the change (pins a constant, a string, a rename, a call) | Cannot fail for any regression; certifies the diff, not the behavior. | The run is the proof. Delete the test. |
|
|
125
117
|
| One mega-test asserting 12 things | First failure hides the next 11. | Split by `Then` clause — one assertion class per test. |
|
|
126
118
|
| Mocking every collaborator | Test passes regardless of real behavior. | Use a fake or the real thing. Mock only true unmockables. |
|
|
127
119
|
| `time.sleep(0.1)` to "let it finish" | Flake guaranteed. | Subscribe to the completion signal; bounded await. |
|
|
@@ -143,7 +135,7 @@ Apply unless the per-language reference overrides with something stricter.
|
|
|
143
135
|
| Immutable by default | `@dataclass(frozen=True, slots=True)` / Pydantic `frozen=True` | every binding is `let` (not `let mut`) unless mutation is the documented purpose | every field is `readonly`; arrays are `readonly T[]` | value types, unexported fields, no mutation methods unless mutation is the purpose |
|
|
144
136
|
| Branded primitives | `UserId = NewType("UserId", int)` | `struct UserId(u64);` (newtype tuple) | `type UserId = Brand<string, "UserId">` | `type UserID string` + smart constructor with unexported field |
|
|
145
137
|
| Exhaustive variant matching | `match` + `assert_never` | `match` (compiler-enforced) | `switch` + `assertNever` | sealed interface + type switch + **`exhaustive` linter** (the compiler will not help) |
|
|
146
|
-
| No untyped escape hatches | no `Any` in public sigs, no `cast`, no `# type: ignore` | no `unwrap`/`expect` outside
|
|
138
|
+
| No untyped escape hatches | no `Any` in public sigs, no `cast`, no `# type: ignore` | no `unwrap`/`expect` outside tests (invariant `expect` only behind `#[expect(clippy::expect_used, reason)]`), no numeric `as`, no `#[allow]` (silence with `#[expect(lint, reason)]`) | no `any`, no `as` (except `as const`, `satisfies`), no `!`, no `@ts-ignore`, no `@ts-expect-error` | no `interface{}` / bare `any` in domain sigs; no `_ = err`; no `//nolint` without reason |
|
|
147
139
|
| No bare error strings | typed exception dataclass with `__str__` | `thiserror` enum (lib) or `anyhow` with `.context(...)` (app) | `Error` subclass with typed fields | sentinel `errors.New` + typed `*XError` struct; wrap with `%w`; check via `errors.Is/As` |
|
|
148
140
|
| Boundary catch only | catch the exact exception you expect; broad `except Exception` only in `main()`, with logging + re-raise | `?` everywhere; never `panic!` in library code | `catch` must narrow with `instanceof` and re-throw or convert; no empty catch | every `(T, error)` checked; `panic` only in `main`/tests; one `httperr.Write` funnel in handlers |
|
|
149
141
|
| Resources via RAII | `with` (sync) / `async with` (async) | `Drop` impl or RAII guard | `using`/`await using` (TC39 explicit resource management) | `defer x.Close()` immediately after acquisition; `bodyclose`/`sqlclosecheck` linters enforce |
|
|
@@ -189,7 +181,7 @@ A bare default constructor for any of these (no timeouts, no pool tuning, no sch
|
|
|
189
181
|
| UB / soundness gate | (n/a) | **nightly miri** with strict provenance + Tree Borrows pass | (n/a) | **`nilaway`** + `-race` detector + `goleak` are the equivalent gate |
|
|
190
182
|
| Disposable scripts | **PEP 723** inline metadata + `uv run script.py` | **rust-script** with inline `Cargo.toml` block | `bun run script.ts` | `//go:build ignore` + `go run script.go` |
|
|
191
183
|
| Bootstrap a new project | `scripts/python/new-project.py` | `scripts/rust/new-project.py` | `scripts/typescript/new-project.ts` | `scripts/go/new-project.py` |
|
|
192
|
-
| Pre-commit / CI gate | `ruff check . && basedpyright && pytest` | `cargo
|
|
184
|
+
| Pre-commit / CI gate | `ruff check . && basedpyright && pytest` | `cargo clippy --all-targets -- -D warnings && cargo nextest run && cargo test --doc && cargo +nightly miri nextest run` | `bunx biome check . && bunx tsc --noEmit && bun test` | `gofumpt -l . && golangci-lint run ./... && nilaway ./... && go test -race -shuffle=on -count=1 ./...` |
|
|
193
185
|
|
|
194
186
|
A `tsconfig.json` with `"strict": true` alone is **not** strict. The reference enumerates the additional flags. Same for `pyproject.toml` and `Cargo.toml` - the references contain the canonical full configuration.
|
|
195
187
|
|
|
@@ -281,7 +273,7 @@ After every code-writing session, answer these out loud (in your reply) before d
|
|
|
281
273
|
1. **Single responsibility?** Can I name what this file owns in one short noun phrase? If the answer needs the word "and", split.
|
|
282
274
|
2. **Boundary purity?** Did I parse untrusted input into a typed value at the boundary, or did I pass `dict[str, Any]` / `serde_json::Value` / `unknown` past the boundary? If the latter, fix it.
|
|
283
275
|
3. **Variant discrimination?** Did I use `if`/`elif`/`else` (or `switch` without `assertNever`, or `match` without `assert_never`) anywhere to discriminate on a tagged type or enum? If yes, rewrite as exhaustive match.
|
|
284
|
-
4. **Escape hatches?** Any `Any`, `# type: ignore`, `unwrap`, `expect` outside
|
|
276
|
+
4. **Escape hatches?** Any `Any`, `# type: ignore`, `unwrap`, `expect` outside tests, `as` numeric cast, `!`, `@ts-ignore`, `@ts-expect-error`, a Rust `#[allow]` instead of `#[expect(lint, reason)]`? If yes, fix the type or document why with a comment.
|
|
285
277
|
5. **Defensive layer?** Any null check, try/except, or `isinstance` guarding a value the type system already proves? If yes, delete.
|
|
286
278
|
6. **Helpers for one-off?** Any function, class, or trait introduced for a single caller that will never get a second caller? If yes, inline — axiom 0 should have caught it pre-write; this is the backstop.
|
|
287
279
|
7. **Tests?** Is the behavior I just introduced locked by a test that would fail if I revert this commit?
|
|
@@ -349,7 +341,9 @@ These two skills are not optional cosmetics. They are the recovery path for the
|
|
|
349
341
|
| Concurrency primitives (locks, atomics, channels, loom) | `references/rust/concurrency.md` |
|
|
350
342
|
| axum + sqlx + tracing + tower HTTP stack | `references/rust/axum-stack.md` |
|
|
351
343
|
| clap + color-eyre + tracing + indicatif CLI stack | `references/rust/clap-stack.md` |
|
|
352
|
-
|
|
|
344
|
+
| Public API design (naming, conversions, traits, rustdoc sections) | `references/rust/api-design.md` |
|
|
345
|
+
| Declarative and procedural macros | `references/rust/macros.md` |
|
|
346
|
+
| Property tests (proptest) + snapshot tests (insta), test placement, doctests | `references/rust/proptest-insta.md` |
|
|
353
347
|
| Disposable `rust-script` scripts | `references/rust/one-liners.md` |
|
|
354
348
|
| Canonical library defaults | `references/rust/libraries.md` |
|
|
355
349
|
| **ANY `unsafe` / FFI / `MaybeUninit` / lock-free work** | **`references/rust-ub/` (full directory)** |
|