lazycodex-ai 5.1.40 → 5.1.42
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/README.de.md +118 -0
- package/README.es.md +118 -0
- package/README.fr.md +118 -0
- package/README.it.md +118 -0
- package/README.ja.md +2 -1
- package/README.ko.md +2 -1
- package/README.md +3 -2
- package/README.pt-br.md +118 -0
- package/README.ru.md +2 -1
- package/README.zh-cn.md +2 -1
- package/dist/cli/index.js +115 -27
- package/dist/cli/service-auth/index.d.ts +3 -0
- package/dist/cli-node/index.js +115 -27
- package/package.json +1 -1
- package/packages/lsp-daemon/dist/cli.js +10 -0
- package/packages/lsp-daemon/dist/client.js +10 -0
- package/packages/lsp-daemon/dist/index.js +10 -0
- package/packages/lsp-tools-mcp/dist/cli.js +10 -0
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +10 -0
- package/packages/lsp-tools-mcp/dist/mcp.js +10 -0
- package/packages/lsp-tools-mcp/dist/tools.js +10 -0
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +84 -9
- 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 +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +10 -0
- 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/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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- 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/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- 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/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/declarations.ts +22 -13
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/findings.ts +7 -6
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/lint.ts +18 -24
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/markup.ts +14 -7
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/selector.ts +5 -1
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/tailwind.ts +32 -14
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-accent-stripes.ts +1 -1
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/inline-ok.tsx +1 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/neutral-and-flat.css +1 -1
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/tailwind-ok.tsx +5 -2
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/uniform-and-rings.css +2 -2
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.css +4 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.tsx +8 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/{negative → positive}/flat-stripe-side.tsx +3 -1
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/report-callouts.html +8 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/square-surfaces.css +8 -0
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +10 -2
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +10 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-visualization.md +23 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +86 -11
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +6 -6
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/perfection/README.md +2 -2
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/declarations.ts +22 -13
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/findings.ts +7 -6
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/lint.ts +18 -24
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/markup.ts +14 -7
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/selector.ts +5 -1
- package/packages/shared-skills/skills/frontend/scripts/perfection/accent-stripes/tailwind.ts +32 -14
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-accent-stripes.test.ts +15 -6
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-accent-stripes.ts +1 -1
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/inline-ok.tsx +1 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/neutral-and-flat.css +1 -1
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/tailwind-ok.tsx +5 -2
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/uniform-and-rings.css +2 -2
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.css +4 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.tsx +8 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/{negative → positive}/flat-stripe-side.tsx +3 -1
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/report-callouts.html +8 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/square-surfaces.css +8 -0
- package/packages/shared-skills/skills/ulw-research/SKILL.md +10 -2
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +10 -0
- package/packages/shared-skills/skills/ulw-research/references/report-visualization.md +23 -0
package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/accent-stripes/tailwind.ts
CHANGED
|
@@ -43,11 +43,15 @@ const SIDE_TOUCHES: Readonly<Record<string, readonly Corner[]>> = {
|
|
|
43
43
|
}
|
|
44
44
|
const ALL: readonly Corner[] = ["tl", "tr", "br", "bl"]
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return (width
|
|
46
|
+
const SIDE = /^(?:[tlrbsexy]|bs|be)-/
|
|
47
|
+
|
|
48
|
+
function isWide(width: string | undefined): boolean {
|
|
49
|
+
if (!width) return false
|
|
50
|
+
return ((/^\d+$/.test(width) ? Number.parseInt(width, 10) : arbitraryPx(width)) ?? 0) >= MIN_STRIPE_PX
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isWideSide(util: string): boolean {
|
|
54
|
+
return isWide(/^border-(?:[tlrbsexy]|bs|be)-(\d+|\[[^\]]+\])$/.exec(util)?.[1])
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
function roundedCorners(utils: readonly string[]): Set<Corner> {
|
|
@@ -65,14 +69,30 @@ function roundedCorners(utils: readonly string[]): Set<Corner> {
|
|
|
65
69
|
return corners
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
function
|
|
69
|
-
const m = /^border(?:-(?:[tlrbsexy]|bs|be))?-(.+)$/.exec(util)
|
|
70
|
-
const fragment = m?.[1]
|
|
72
|
+
function colorIsChromatic(fragment: string | undefined): boolean {
|
|
71
73
|
if (!fragment || BORDER_STYLE.has(fragment) || /^\d+$/.test(fragment)) return false
|
|
72
74
|
if (fragment.startsWith("[") && arbitraryPx(fragment) !== undefined) return false
|
|
73
75
|
return classifyUtilityColor(fragment) === "chromatic"
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
function borderColorIsChromatic(util: string): boolean {
|
|
79
|
+
return colorIsChromatic(/^border(?:-(?:[tlrbsexy]|bs|be))?-(.+)$/.exec(util)?.[1])
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function hasOutline(utils: readonly string[]): boolean {
|
|
83
|
+
const border = utils.some((u) => isWide(/^border-(\d+|\[[^\]]+\])$/.exec(u)?.[1]))
|
|
84
|
+
const borderColor = utils.some((u) => {
|
|
85
|
+
const fragment = /^border-(.+)$/.exec(u)?.[1]
|
|
86
|
+
return fragment !== undefined && !SIDE.test(fragment) && colorIsChromatic(fragment)
|
|
87
|
+
})
|
|
88
|
+
const ring = utils.some((u) => isWide(/^ring-(\d+|\[[^\]]+\])$/.exec(u)?.[1]))
|
|
89
|
+
const ringColor = utils.some((u) => {
|
|
90
|
+
const fragment = /^ring-(.+)$/.exec(u)?.[1]
|
|
91
|
+
return fragment !== undefined && !/^(?:inset|offset-)/.test(fragment) && colorIsChromatic(fragment)
|
|
92
|
+
})
|
|
93
|
+
return (border && borderColor) || (ring && ringColor)
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
function thinBar(utils: readonly string[], axis: "w" | "h"): boolean {
|
|
77
97
|
return utils.some((u) => {
|
|
78
98
|
const m = new RegExp(`^${axis}-(px|0\\.5|1|1\\.5|2|\\[[^\\]]+\\])$`).exec(u)
|
|
@@ -93,14 +113,12 @@ function isPseudoBar(utils: readonly string[]): boolean {
|
|
|
93
113
|
return chromaticBg && ((thinBar(utils, "w") && longBar(utils, "h")) || (thinBar(utils, "h") && longBar(utils, "w")))
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
export function checkClassSet(tokens: readonly string[]): RuleId[] {
|
|
116
|
+
export function checkClassSet(tokens: readonly string[], hostRounded = false): RuleId[] {
|
|
97
117
|
const utilities = tokens.map(toUtility).filter((u): u is Utility => u !== undefined)
|
|
98
118
|
const base = utilities.filter((u) => u.layer === "base").map((u) => u.util)
|
|
99
|
-
const corners = roundedCorners(base)
|
|
100
|
-
if (corners.size === 0) return []
|
|
101
119
|
const found: RuleId[] = []
|
|
102
|
-
|
|
103
|
-
if (
|
|
120
|
+
if (base.some(isWideSide) && base.some(borderColorIsChromatic)) found.push("edge-stripe")
|
|
121
|
+
else if ((hostRounded || roundedCorners(base).size > 0) && hasOutline(base)) found.push("accent-outline")
|
|
104
122
|
const shadows = base.filter((u) => u.startsWith("shadow-[") && u.endsWith("]"))
|
|
105
123
|
if (shadows.some((u) => isInsetShadowStripe(u.slice("shadow-[".length, -1).replace(/_/g, " ")))) {
|
|
106
124
|
found.push("inset-shadow-stripe")
|
|
@@ -113,5 +131,5 @@ export function checkClassSet(tokens: readonly string[]): RuleId[] {
|
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
export function looksLikeClassList(text: string): boolean {
|
|
116
|
-
return /(?:^|\s)(?:[\w-]+:)*rounded/.test(text)
|
|
134
|
+
return /(?:^|\s)(?:[\w-]+:)*(?:rounded|border-|ring-|shadow-\[|(?:before|after):)/.test(text)
|
|
117
135
|
}
|
package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-accent-stripes.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
// Flags
|
|
2
|
+
// Flags coloured one-side bars on any box and accent outlines on rounded cards in CSS, Tailwind and JSX.
|
|
3
3
|
// Usage: bun check-accent-stripes.ts [--json] <file-or-dir>... Exit 0 clean, 1 findings, 2 usage.
|
|
4
4
|
import { readdirSync, readFileSync, statSync } from "node:fs"
|
|
5
5
|
import { join } from "node:path"
|
|
@@ -3,5 +3,6 @@ export const Ok = () => (
|
|
|
3
3
|
<div style={{ borderRadius: 8, border: "1px solid #e5e7eb" }}>Card</div>
|
|
4
4
|
<div style={{ borderRadius: 8, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.1)" }}>Ring</div>
|
|
5
5
|
<p>Don't stripe {"rounded"} cards.</p>
|
|
6
|
+
<table><tbody><tr><td style={{ borderLeft: "4px solid #6366f1" }}>Sorted</td></tr></tbody></table>
|
|
6
7
|
</>
|
|
7
8
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.list-item { border-bottom: 1px solid #e5e7eb; }
|
|
2
2
|
.panel { border-radius: 12px; border-top: 1px solid rgba(0, 0, 0, 0.08); }
|
|
3
3
|
.quiet { border-radius: 12px; border-left: 4px solid #e5e7eb; }
|
|
4
|
-
|
|
4
|
+
blockquote { border-left: 3px solid #d4d4d8; padding-left: 16px; }
|
|
5
5
|
.token { border-radius: 8px; border-left: 2px solid var(--color-border); }
|
|
6
6
|
.ink { border-radius: 8px; border-left: 2px solid var(--text-primary); }
|
|
@@ -4,8 +4,11 @@ export const Ok = () => (
|
|
|
4
4
|
<div className="rounded-xl border-l-4 border-l-zinc-300 p-4">Neutral edge</div>
|
|
5
5
|
<button className="rounded-md focus-visible:ring-2 focus-visible:ring-blue-500">Go</button>
|
|
6
6
|
<input className="rounded-md border-b-2 aria-invalid:border-b-red-500 invalid:border-red-500" />
|
|
7
|
-
<
|
|
8
|
-
<
|
|
7
|
+
<blockquote className="border-l-2 border-zinc-300 pl-4">Neutral quote rule</blockquote>
|
|
8
|
+
<button className="rounded-md border border-indigo-500 px-3">Outline button</button>
|
|
9
9
|
<div className="rounded-lg bg-blue-50 p-4 text-blue-900">Tonal surface</div>
|
|
10
|
+
<input className="border-b-2 border-indigo-500" />
|
|
11
|
+
<select className="rounded-md border-2 border-indigo-500" />
|
|
12
|
+
<table><tbody><tr><td className="border-l-4 border-indigo-500">Sorted</td></tr></tbody></table>
|
|
10
13
|
</div>
|
|
11
14
|
)
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
.
|
|
2
|
-
.
|
|
1
|
+
.outline-button { border-radius: 6px; border: 1px solid var(--primary); }
|
|
2
|
+
.neutral-frame { border-radius: 8px; border: 2px solid #e5e7eb; }
|
|
3
3
|
.lift { border-radius: 12px; box-shadow: 0 4px 12px rgb(0 0 0 / 0.12); }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const Plans = () => (
|
|
2
|
+
<>
|
|
3
|
+
<div className="rounded-xl border-2 border-indigo-500 p-6">Pro</div>
|
|
4
|
+
<div className="rounded-2xl p-6 ring-2 ring-primary">Team</div>
|
|
5
|
+
<div className="rounded-lg focus:ring-2 focus:ring-blue-500">Focused</div>
|
|
6
|
+
<div style={{ borderRadius: 12, border: "2px solid #6366f1" }}>Inline</div>
|
|
7
|
+
</>
|
|
8
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const styles = css`
|
|
2
2
|
.alert { border-left: 4px solid #dc2626; border-radius: 0 6px 6px 0; }
|
|
3
3
|
`
|
|
4
4
|
|
|
@@ -7,5 +7,7 @@ export const Quotes = () => (
|
|
|
7
7
|
<blockquote className="rounded-r-lg border-l-4 border-blue-500 pl-4">Square on the stripe side</blockquote>
|
|
8
8
|
<aside className="rounded-xl rounded-l-none border-l-4 border-sky-500">Left corners squared</aside>
|
|
9
9
|
<style>{`.note { border-left: 4px solid #16a34a; border-top-right-radius: 8px; border-bottom-right-radius: 8px; }`}</style>
|
|
10
|
+
<div className="border-l-4 border-blue-500 pl-4">Flat quote, no corners</div>
|
|
11
|
+
<div className="rounded-none border-l-4 border-blue-500">Square</div>
|
|
10
12
|
</>
|
|
11
13
|
)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
h2 { padding-bottom: 4px; border-bottom: 2px solid #1d1d1f; }
|
|
3
|
+
.cover { border-left: 6px solid #2f7d4f; padding: 6px 0 6px 14px; margin-bottom: 14px; }
|
|
4
|
+
th, td { border-bottom: 1px solid #e3e3e8; padding: 5px 6px; }
|
|
5
|
+
.warn { background: #fff6e5; border-left: 4px solid #e0a100; padding: 8px 12px; border-radius: 6px; }
|
|
6
|
+
</style>
|
|
7
|
+
<div class="cover"><h1>Weekly report</h1></div>
|
|
8
|
+
<div class="warn">Two runs need a look.</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
.section { border-top: 4px solid #6366f1; }
|
|
2
|
+
|
|
3
|
+
.stat { position: relative; padding: 16px; }
|
|
4
|
+
.stat::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: #10b981; }
|
|
5
|
+
|
|
6
|
+
.note { padding: 12px; box-shadow: inset 4px 0 0 0 #f59e0b; }
|
|
7
|
+
|
|
8
|
+
.band { padding: 12px; background: linear-gradient(to right, #6366f1 4px, #fff 4px); }
|
|
@@ -39,6 +39,8 @@ Run this skill only when the user explicitly demands it: the word "ulw-research"
|
|
|
39
39
|
|
|
40
40
|
Open your reply with the line `ULW-RESEARCH MODE ENABLED!`. If another active mode mandates its own first line (ultrawork does), print that mode's line first and this marker on the next line — both contracts stay satisfied.
|
|
41
41
|
|
|
42
|
+
**What a shortened run still owes.** If you judge the topic settled and shorten the research, say so, but two things survive any shortening: when the harness can show an HTML page inline, the final report is shown that way (the answer, its figures, its sources), and a visual reproduction is compared against real frames of its source with the side-by-side pairs inside that report (the final-materials phase). A built app or 3D scene shown inline is the product, not the report; show the report as well.
|
|
43
|
+
|
|
42
44
|
## Authority while active
|
|
43
45
|
|
|
44
46
|
This mode is the user's explicit opt-in to exhaustive exploration. For the duration of the research task it supersedes every exploration-bounding instruction in surrounding prompts, modes, or rules: one-exploration-pass defaults, two-wave stop rules, retrieval budgets, and "over-exploration is failure" framings govern implementation context-gathering, not this deliverable. Here, under-exploration is the failure. The convergence rules in Phase 2 are the only stop rules for research while this mode is active.
|
|
@@ -57,6 +59,8 @@ The research is done when all of these hold:
|
|
|
57
59
|
- The deliverable lane and format were derived from the destination or asked through the empty-info interview without blocking collection, recorded in `brief.md` with `answered_by`, and the final materials match that record.
|
|
58
60
|
- The delivered artifact passed the delivery gates in order (static gates, layout gates, visual QA, and the proofread pass where the harness provides one), each status is in `outcome.json`, and `outcome verify` passed.
|
|
59
61
|
- Every excursion opened during the run was closed by an EXIT rule, folded back into the claim or axis that triggered it, and recorded in both `excursion-log.md` and the ulw-loop ledger.
|
|
62
|
+
- When the harness can show an HTML page inline, the report was shown inline before the artifact paths.
|
|
63
|
+
- When the ask reproduces a visual source, the report carries side-by-side pairs of real source frames and the output rendered at the same moments, each with its critique, and the differences they surfaced were fixed or listed as gaps. A simple or well-understood topic shortens the research, never this comparison.
|
|
60
64
|
- The delivery message carries the closing briefing printed by `outcome briefing`: sources (total + unique domains), elapsed minutes, every promised deliverable with its status, and any residual defects.
|
|
61
65
|
- The session journal reconstructs what was searched, found, and expanded, wave by wave, and it was written in real time rather than reconstructed at the end.
|
|
62
66
|
|
|
@@ -161,7 +165,7 @@ Never block collection on the shape of the deliverable, and never guess it eithe
|
|
|
161
165
|
1. **Derive first.** Name the lane (`template-strict`, `template-vibe`, `no-format`, `edit-existing`) and the promised formats from the request and its destination (the reference's section 3). When the request refers to an existing deliverable, decide its state with `node "$SKILL_DIR/scripts/report-tools.mjs" outcome state --deliverable <path> --session-dir "$SESSION_DIR"`: `partial` resumes the skeleton on disk, `complete` means edit-existing and never a regenerated report. `$SKILL_DIR` is this skill's own directory, the folder containing this SKILL.md.
|
|
162
166
|
2. **Read the requester's format memory** with the memory tool when the harness exposes one: the pointer `system/human/report-style.md`, then `reference/human-report-style.md`; take the choice recorded for the most similar context (same destination kind and audience) as the first option.
|
|
163
167
|
3. **Ask only what is still missing**: at most the reference's three questions (destination and format, audience and length, template lineage) in one call to the harness question tool (`ask_user_question` or `request_user_input`), non-blocking where the harness supports it, each with its default first, a free-text "describe the format" path, and "don't care, you decide". Collection starts without waiting; a late answer is folded in until the assembly worker starts, and after that it becomes a re-render request.
|
|
164
|
-
4. **Record it.** Write `## Deliverable` into `brief.md` (lane, state, formats, destination, audience, template, format description, each with `answered_by: user|default|request`) and open the manifest in the same step: `node "$SKILL_DIR/scripts/report-tools.mjs" outcome init --promised <formats> --lane <lane> --session-dir "$SESSION_DIR"`.
|
|
168
|
+
4. **Record it.** Write `## Deliverable` into `brief.md` (lane, state, formats, destination, audience, template, format description, each with `answered_by: user|default|request`) and open the manifest in the same step: `node "$SKILL_DIR/scripts/report-tools.mjs" outcome init --promised <formats> --lane <lane> --session-dir "$SESSION_DIR"`. When the ask is to recreate, reproduce, or rebuild something visual, add `Reference compare: required` with the source (URL or file) and the moments to compare; the comparison runs on every round of the build, not only at the end.
|
|
165
169
|
|
|
166
170
|
Phase 5 opens by turning the recorded fields into `design-spec.md`.
|
|
167
171
|
|
|
@@ -336,6 +340,8 @@ Asset workers (background, parallel, each fed `design-spec.md`) — visuals are
|
|
|
336
340
|
|
|
337
341
|
**Every final report is visual — binding.** It carries at least one data visualization of the run's own findings (a chart drawn from the data table, next to the claim it supports), a diagram wherever structure matters, and the topic's own screenshots and video, embedded or linked with attribution; every figure is captioned, sourced, and given alt text. Mermaid for flows, timelines, and relations; generated charts for numbers; image generation only where an illustration genuinely helps; PlotNeuralNet for paper-format reports that describe model architectures. Every asset lane reads [references/report-visualization.md](references/report-visualization.md) first: which tool fits which finding, the render commands, the quality bar, and the checklist the gates apply. A light-tier post still carries one visual when it reports numbers or structure.
|
|
338
342
|
|
|
343
|
+
**Visual reproductions are compared against the source — binding.** When the ask is to recreate, reproduce, or rebuild something visual (a clip in 3D, an interface from a screenshot, a figure), real frames or captures from the source are the reference: extract them at the moments that define the source, render the output at the same moments and viewpoints, compose side-by-side pairs, critique every pair by looking at it, fix the largest differences, and compare again within the repair bound. The final pairs, and the first-round pairs in the correction log, go into the report. Procedure: [references/report-visualization.md](references/report-visualization.md), section 3, Reference compare. A reproduction checked only against itself is unverified.
|
|
344
|
+
|
|
339
345
|
**Verify the asset manifest before rendering.** List every asset the document references, assert each file exists and is non-empty on disk, and re-render whatever is missing. A document that renders with three broken diagrams is a document you will publish twice.
|
|
340
346
|
|
|
341
347
|
Assembly worker — `task(category="deep-low", load_skills=["frontend", "visual-qa", "open-design", "data-scientist", "imagegen", "ulw-loop"], run_in_background=true, ...)`: before writing, read every available design and visualization skill and apply it — the report is a designed artifact, not a text dump; the worker's prompt carries `design-spec.md`. Use the template the user approved; absent a stronger house style the default skeleton is executive summary → key findings by theme → detailed analysis (quotes under 20 words with attribution, charts, Mermaid graphs, generated visuals, SHA-pinned permalinks, verification results) → comparative analysis when options compete → numbered sources with access dates → methodology appendix (workers, waves, searches, verifications, debate rounds) → correction log naming what verification overturned. Write it long and specific: every claim cites `[Source N]`, and the sources section lists every source the run actually used rather than a curated few.
|
|
@@ -350,7 +356,7 @@ Nothing reaches the user until the gates pass. Record each result with `node "$S
|
|
|
350
356
|
|
|
351
357
|
**Repair is bounded.** After every gate run that found defects, ask `node "$SKILL_DIR/scripts/report-tools.mjs" repair decide --state "$SESSION_DIR/repair-state.json" --defects "$SESSION_DIR/defects.json" --artifact-bytes <bytes> --renders <pages> --session-dir "$SESSION_DIR"` and obey it: `repair` means fix and re-run; `deliver` means stop and ship with the residual defects the manifest now lists; `block` means a content-integrity defect remains (or there is no usable artifact), so do not deliver: tell the user what blocks it and record the row as `failed` with the reason. Never repair past a stop decision (3 attempts, a 2-attempt plateau, an oscillation, or 15 minutes; the reference's section 8).
|
|
352
358
|
|
|
353
|
-
Then resolve every manifest row (`outcome set <format> delivered --path <file>` or `blocked_capability` / `skipped` / `failed` with `--reason`) and deliver: the artifact
|
|
359
|
+
Then resolve every manifest row (`outcome set <format> delivered --path <file>` or `blocked_capability` / `skipped` / `failed` with `--reason`) and deliver. **Show the report inline first when the harness can.** When this session has a tool that shows an HTML page inline in the conversation (`show_html_page`, `html_render`), the requester's first view of the result is the report itself: the gated `report.html` when it fits the tool, otherwise an inline edition built from the same synthesis and assets, with the reference-compare pairs when the run has them ([references/deliverable-phase.md](references/deliverable-phase.md), section 9, Showing the report inline). Then give the artifact paths and a compact chat-readable summary of what the report says — the answer in a few sentences, the numbers that matter, and what to look at first. This holds on every tier, a chat answer included, and when the thing built is itself a page (an app, a 3D scene), showing it does not replace the report page. Without an inline page tool, deliver the artifact paths plus that summary. The document is the deliverable; the summary is what gets it read.
|
|
354
360
|
|
|
355
361
|
### The closing briefing — every run ends with it
|
|
356
362
|
|
|
@@ -415,4 +421,6 @@ High-yield combinations: official docs (`site:<docs domain>`), GitHub implementa
|
|
|
415
421
|
| Chasing an interesting find with no ENTER trigger | Excursions need a named trigger; everything else stays a queued lead |
|
|
416
422
|
| An excursion that never came back, or drifted into a new mission | EXIT rules are unconditional; depth 3 means promote it to an axis or record it as a gap |
|
|
417
423
|
| An excursion whose result was never folded back | Every EXIT writes what it changed in the top-level answer, `none` included, and mirrors into the loop ledger |
|
|
424
|
+
| Ending with file paths while an inline HTML page tool is available | Show the report inline first (the gated `report.html` or its inline edition), then the paths and the summary |
|
|
425
|
+
| A visual reproduction checked only against itself | Reference compare: real source frames next to renders at the same moments, a critique per pair, fixes, and the pairs in the report |
|
|
418
426
|
| Delivering without the closing briefing | Paste the block `outcome briefing` prints; never compute or recall its numbers by hand |
|
|
@@ -166,6 +166,16 @@ node "$SKILL_DIR/scripts/report-tools.mjs" outcome briefing --session-dir "$SESS
|
|
|
166
166
|
- `finish` stamps the finish time, the elapsed minutes from the session directory's start stamp, and the source and domain counts from `sources-ledger.md`.
|
|
167
167
|
- `briefing` prints the closing block from the manifest and the ledger: sources and distinct domains, elapsed minutes, every deliverable with its status, the gate results, the residual defects, and the repair summary. That text is the closing briefing, pasted as printed, never filled in from memory.
|
|
168
168
|
|
|
169
|
+
### Showing the report inline
|
|
170
|
+
|
|
171
|
+
When the session has a tool that shows a self-contained HTML page inline in the conversation (`show_html_page` in OmO, `html_render` on hosts that offer it), the requester sees the report there first, after `verify` passes and before the closing briefing. A path to a file the requester has to go and open is not the first thing they read.
|
|
172
|
+
|
|
173
|
+
- **Which page.** The gated `report.html` itself when the promised deliverable is a self-contained HTML report within the tool's size limit. Otherwise (a PDF, DOCX, LaTeX, or slide deliverable, or an HTML report over the limit) build an inline edition from the same `SYNTHESIS.md` and the same assets: the answer, the headline figures, the reference-compare pairs when the run has them, the key findings with their citations, the numbered sources, and the paths of the promised artifacts. Run `check` on the inline edition like any HTML deliverable.
|
|
174
|
+
- **Self-contained.** No network: styles and scripts inline, no remote fonts, no CDN. Pass local images as absolute file paths (the tool inlines them) or as data URIs. Render it once at the reply width and at 390 px before showing it, and pass the measured height. When the session has the `visualize` skill, follow its inline-page constraints.
|
|
175
|
+
- **Every tier, and always the report.** A light-tier chat answer with no promised document still ends with an inline page: the answer, its figures, the reference-compare pairs, and the sources. When the thing built is itself a page (an app, a 3D scene, a demo), show it too, but it never stands in for the report page, and a page that only links or redirects to a file is not a report.
|
|
176
|
+
- **Not a manifest format.** The inline page never replaces or resolves a promised format; every manifest row still ends `delivered`, `blocked_capability`, `skipped`, or `failed` with its own artifact.
|
|
177
|
+
- **No inline tool.** Deliver the artifact paths and the chat summary as before.
|
|
178
|
+
|
|
169
179
|
## 10. Command reference
|
|
170
180
|
|
|
171
181
|
Invoke every command as `node "$SKILL_DIR/scripts/report-tools.mjs" <command>`. Exit codes for all of them: `0` pass, `1` semantic failure, `2` usage or IO error.
|
|
@@ -25,6 +25,7 @@ A report that ships with none of these is incomplete. The static gate raises `re
|
|
|
25
25
|
| A product, interface, or page the report discusses | A screenshot captured while reading the source, through the browser skill | PNG |
|
|
26
26
|
| A concept that has no data and no structure, a cover | The image-generation skill, only when it helps the reader understand | PNG |
|
|
27
27
|
| A source video or talk | An embed (web) or a still frame plus link and timestamp (paginated) | iframe or PNG |
|
|
28
|
+
| A reproduction of a visual source (a clip rebuilt in 3D, an interface rebuilt from a screenshot, a figure redrawn) | Reference-compare pairs: a real source frame next to the output rendered at the same moment and viewpoint | PNG per pair |
|
|
28
29
|
|
|
29
30
|
Image generation never draws data, numbers, diagrams with labels, or anything the reader could mistake for evidence. Its caption says it is an illustration.
|
|
30
31
|
|
|
@@ -86,6 +87,27 @@ pdftocairo -svg arch.pdf "$SESSION_DIR/assets/arch.svg" # for an HTML report;
|
|
|
86
87
|
- Capture product and page screenshots through the browser skill while the source is open, at a readable width, and crop to the part the claim is about. Caption with the source and the access date.
|
|
87
88
|
- Embed a video in a web report with the platform's embed and a timestamp; in a paginated report, use a still frame from the moment the claim refers to, with the link and timestamp in the caption.
|
|
88
89
|
|
|
90
|
+
### Reference compare (visual reproductions)
|
|
91
|
+
|
|
92
|
+
When the deliverable reproduces a visual source (recreate a clip in 3D, rebuild an interface from a screenshot, redraw a figure), the source is the test oracle. An output checked only against itself looks finished to its author and wrong to anyone who has seen the original, so the run compares the two directly and shows the comparison.
|
|
93
|
+
|
|
94
|
+
1. **Pick the moments.** Choose 4 to 8 moments that carry the identity of the source: the start and end state, the peak of each motion, distinctive poses, camera framings, and the shot the requester pointed at. Record each in `$SESSION_DIR/compare/moments.json` with its timestamp (or region, for a still), what it shows, and the camera or viewport.
|
|
95
|
+
2. **Extract real frames from the source.** For a video, download only the sections you need, then cut one frame per moment. Run the download as a background job; a long download outlives a single tool call.
|
|
96
|
+
```bash
|
|
97
|
+
mkdir -p "$SESSION_DIR/compare"
|
|
98
|
+
uvx yt-dlp -f 'bv*[height<=720]/b[height<=720]' --download-sections '*<start>-<end>' --force-keyframes-at-cuts --remux-video mp4 -o "$SESSION_DIR/compare/source-<start>.%(ext)s" '<url>'
|
|
99
|
+
ffmpeg -y -v error -ss <seconds into the section> -i "$SESSION_DIR/compare/source-<start>.mp4" -frames:v 1 "$SESSION_DIR/compare/ref-<n>.png"
|
|
100
|
+
```
|
|
101
|
+
For an image, use the original file. For a page or interface, capture it through the browser skill at the viewport the output targets. Never substitute a thumbnail, a generated image, or a description for the real frame.
|
|
102
|
+
3. **Render the output at the same moment and viewpoint.** Match the time into the motion, the camera position and field of view, the framing, and the aspect ratio. For a 3D scene, move the camera to the source shot instead of capturing the scene's default camera. Save `out-<n>.png`.
|
|
103
|
+
4. **Compose each pair.** Reference on the left, output on the right, scaled to the same height:
|
|
104
|
+
```bash
|
|
105
|
+
ffmpeg -y -v error -i "$SESSION_DIR/compare/ref-<n>.png" -i "$SESSION_DIR/compare/out-<n>.png" -filter_complex "[0:v]scale=-2:540[a];[1:v]scale=-2:540[b];[a][b]hstack=inputs=2" "$SESSION_DIR/compare/pair-<n>-r<round>.png"
|
|
106
|
+
```
|
|
107
|
+
5. **Critique every pair by looking at it.** Open each pair image and write `$SESSION_DIR/compare/critique-r<round>.md`: per pair, every visible difference ranked by how much a viewer would notice it (silhouette and proportions, pose and orientation, motion path and timing, camera and framing, scale against the surroundings, color and lighting, missing or extra elements), each with its likely cause and the fix.
|
|
108
|
+
6. **Fix and compare again.** Fix the largest differences first, re-render the same moments, compose the next round, and critique again. Stop after 3 rounds or after 2 rounds that close no listed difference, the same bound the repair loop uses; every difference still open becomes a residual gap in the report.
|
|
109
|
+
7. **Put the comparison in the report.** A "Reference comparison" section holds the final pair for each moment as a captioned figure: the moment and timestamp, the source with attribution and link, what now matches, and what still differs. The first-round pairs go in the correction log next to their final pairs, so the reader sees what the comparison changed. Alt text describes both halves.
|
|
110
|
+
|
|
89
111
|
### Generated illustrations
|
|
90
112
|
|
|
91
113
|
Use the image-generation skill only for a cover or a concept illustration that helps the reader, prompted from the design spec's palette and register. Never let generated images carry text, numbers, or logos the reader could read as fact.
|
|
@@ -123,4 +145,5 @@ The static gate (`report-tools check`) enforces the machine-checkable rows; visu
|
|
|
123
145
|
| Each major quantitative finding has a chart and each structural finding has a diagram | visual QA |
|
|
124
146
|
| Diagram and chart text renders in the spec font and is legible at phone width | visual QA |
|
|
125
147
|
| Source videos and screenshots are embedded or linked with attribution where the topic has them | visual QA |
|
|
148
|
+
| A visual reproduction carries reference-compare pairs (final and first round) and a critique for every pair | visual QA |
|
|
126
149
|
| Generated illustrations carry no fake data or text and are captioned as illustrations | visual QA |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// omo-codex-install:
|
|
2
|
+
// omo-codex-install:4d55fdfa5d8b8b2fa08c2b8d004c4fa2b39e08b429c29148b9f810ce43827a22:e7a2266fd69e56b66a85bbbb1c3d99018a8b8647bb2c30a5afb575cff97118dc
|
|
3
3
|
var __esm = (fn, res, err) => () => {
|
|
4
4
|
if (fn)
|
|
5
5
|
try {
|
|
@@ -10036,7 +10036,7 @@ var package_default;
|
|
|
10036
10036
|
var init_package = __esm(() => {
|
|
10037
10037
|
package_default = {
|
|
10038
10038
|
name: "@oh-my-opencode/omo-codex",
|
|
10039
|
-
version: "5.1.
|
|
10039
|
+
version: "5.1.42",
|
|
10040
10040
|
type: "module",
|
|
10041
10041
|
private: true,
|
|
10042
10042
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -19486,6 +19486,19 @@ var OmoHarnessIdSchema = _enum(OMO_CONFIG_HARNESS_IDS);
|
|
|
19486
19486
|
var OMO_CONFIG_LEGACY_HARNESS_ALIASES = { senpi: "native" };
|
|
19487
19487
|
var OMO_CONFIG_LEGACY_HARNESS_IDS = Object.keys(OMO_CONFIG_LEGACY_HARNESS_ALIASES);
|
|
19488
19488
|
|
|
19489
|
+
// packages/omo-config-core/src/schema/memory-agreements.ts
|
|
19490
|
+
var OMO_MEMORY_AGREEMENTS_DEFAULTS = { enabled: true, needs_human_threshold: 3, max_items: 64 };
|
|
19491
|
+
var OmoMemoryAgreementsSchema = object({
|
|
19492
|
+
enabled: boolean2().default(OMO_MEMORY_AGREEMENTS_DEFAULTS.enabled),
|
|
19493
|
+
needs_human_threshold: number2().int().min(1).default(OMO_MEMORY_AGREEMENTS_DEFAULTS.needs_human_threshold),
|
|
19494
|
+
max_items: number2().int().min(8).max(256).default(OMO_MEMORY_AGREEMENTS_DEFAULTS.max_items)
|
|
19495
|
+
}).strict();
|
|
19496
|
+
var OmoMemoryAgreementsLayerSchema = object({
|
|
19497
|
+
enabled: boolean2().optional(),
|
|
19498
|
+
needs_human_threshold: number2().int().min(1).optional(),
|
|
19499
|
+
max_items: number2().int().min(8).max(256).optional()
|
|
19500
|
+
}).strict();
|
|
19501
|
+
|
|
19489
19502
|
// packages/omo-config-core/src/schema/memory.ts
|
|
19490
19503
|
var OmoMemoryReflectionTriggerSchema = object({
|
|
19491
19504
|
step_count: number2().int().nonnegative().default(25),
|
|
@@ -19629,6 +19642,7 @@ var OmoMemoryAgentOverridesSchema = object({
|
|
|
19629
19642
|
facts: OmoMemoryFactsLayerSchema.optional(),
|
|
19630
19643
|
dream: OmoMemoryDreamLayerSchema.optional(),
|
|
19631
19644
|
people: OmoMemoryPeopleLayerSchema.optional(),
|
|
19645
|
+
agreements: OmoMemoryAgreementsLayerSchema.optional(),
|
|
19632
19646
|
soul: OmoMemorySoulLayerSchema.optional(),
|
|
19633
19647
|
write_notice: OmoMemoryWriteNoticeLayerSchema.optional(),
|
|
19634
19648
|
sync: OmoMemorySyncLayerSchema.optional(),
|
|
@@ -19637,9 +19651,11 @@ var OmoMemoryAgentOverridesSchema = object({
|
|
|
19637
19651
|
projection: OmoMemoryProjectionLayerSchema.optional(),
|
|
19638
19652
|
compile_warn_tokens: number2().int().positive().optional()
|
|
19639
19653
|
}).strict();
|
|
19654
|
+
var OmoMemoryAutoIdentitySchema = _enum(["path", "git"]);
|
|
19640
19655
|
var OmoMemorySettingsSchema = object({
|
|
19641
19656
|
enabled: boolean2().default(true),
|
|
19642
19657
|
agent: string2().min(1).default("auto"),
|
|
19658
|
+
auto_identity: OmoMemoryAutoIdentitySchema.default("path"),
|
|
19643
19659
|
reflection: OmoMemoryReflectionSchema.default({
|
|
19644
19660
|
enabled: true,
|
|
19645
19661
|
trigger: { step_count: 25, on_compaction: true },
|
|
@@ -19659,6 +19675,7 @@ var OmoMemorySettingsSchema = object({
|
|
|
19659
19675
|
auto_select_max_chars: 150000
|
|
19660
19676
|
}),
|
|
19661
19677
|
people: OmoMemoryPeopleSchema.default({ enabled: true, max_entries: 40, max_entry_chars: 200 }),
|
|
19678
|
+
agreements: OmoMemoryAgreementsSchema.default(OMO_MEMORY_AGREEMENTS_DEFAULTS),
|
|
19662
19679
|
soul: OmoMemorySoulSchema.default({ edit_notice: true }),
|
|
19663
19680
|
write_notice: OmoMemoryWriteNoticeSchema.default({ enabled: true }),
|
|
19664
19681
|
sync: OmoMemorySyncSchema.default({ enabled: true }),
|
|
@@ -19680,11 +19697,13 @@ var OmoMemorySettingsSchema = object({
|
|
|
19680
19697
|
var OmoMemorySettingsLayerSchema = object({
|
|
19681
19698
|
enabled: boolean2().optional(),
|
|
19682
19699
|
agent: string2().min(1).optional(),
|
|
19700
|
+
auto_identity: OmoMemoryAutoIdentitySchema.optional(),
|
|
19683
19701
|
reflection: OmoMemoryReflectionLayerSchema.optional(),
|
|
19684
19702
|
nudge: OmoMemoryNudgeLayerSchema.optional(),
|
|
19685
19703
|
facts: OmoMemoryFactsLayerSchema.optional(),
|
|
19686
19704
|
dream: OmoMemoryDreamLayerSchema.optional(),
|
|
19687
19705
|
people: OmoMemoryPeopleLayerSchema.optional(),
|
|
19706
|
+
agreements: OmoMemoryAgreementsLayerSchema.optional(),
|
|
19688
19707
|
soul: OmoMemorySoulLayerSchema.optional(),
|
|
19689
19708
|
write_notice: OmoMemoryWriteNoticeLayerSchema.optional(),
|
|
19690
19709
|
sync: OmoMemorySyncLayerSchema.optional(),
|
|
@@ -19717,6 +19736,7 @@ function isRecord6(value) {
|
|
|
19717
19736
|
}
|
|
19718
19737
|
var OmoModelProfileInputSchema = object({
|
|
19719
19738
|
display_name: string2().optional(),
|
|
19739
|
+
caution: string2().optional(),
|
|
19720
19740
|
family: _enum(["daily", "geeky"]).optional(),
|
|
19721
19741
|
tier: _enum(["normal", "heavy"]).optional(),
|
|
19722
19742
|
models: array(union([string2(), OmoFallbackModelObjectSchema])).optional()
|
|
@@ -19988,6 +20008,7 @@ var OmoGatewaySectionSchema = record(string2(), unknown()).describe("Chat-surfac
|
|
|
19988
20008
|
// packages/omo-config-core/src/schema/config.ts
|
|
19989
20009
|
var OmoOpenCodeHarnessConfigSchema = record(string2(), unknown());
|
|
19990
20010
|
var OmoDisabledSkillsSchema = array(string2());
|
|
20011
|
+
var OmoExcludedModelsSchema = array(string2());
|
|
19991
20012
|
var OmoTypedHarnessConfigSchema = object({
|
|
19992
20013
|
formatOnMutation: OmoFormatOnMutationLayerSchema.optional(),
|
|
19993
20014
|
gateway: OmoGatewaySectionSchema.optional(),
|
|
@@ -20003,7 +20024,8 @@ var OmoTypedHarnessConfigSchema = object({
|
|
|
20003
20024
|
telemetry: OmoTelemetrySettingsLayerSchema.optional(),
|
|
20004
20025
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
20005
20026
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
20006
|
-
disabled_skills: OmoDisabledSkillsSchema.optional()
|
|
20027
|
+
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
20028
|
+
exclude_models: OmoExcludedModelsSchema.optional()
|
|
20007
20029
|
}).strict();
|
|
20008
20030
|
var OmoConfigProfileSchema = object({
|
|
20009
20031
|
formatOnMutation: OmoFormatOnMutationLayerSchema.optional(),
|
|
@@ -20020,6 +20042,7 @@ var OmoConfigProfileSchema = object({
|
|
|
20020
20042
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
20021
20043
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
20022
20044
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
20045
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
20023
20046
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
20024
20047
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
20025
20048
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -20042,6 +20065,7 @@ var OmoConfigSchema = object({
|
|
|
20042
20065
|
side_panel: OmoSidePanelSettingsSchema.optional(),
|
|
20043
20066
|
computer: OmoComputerSettingsSchema.optional(),
|
|
20044
20067
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
20068
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
20045
20069
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
20046
20070
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
20047
20071
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -20067,6 +20091,7 @@ var OmoConfigLayerSchema = object({
|
|
|
20067
20091
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
20068
20092
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
20069
20093
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
20094
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
20070
20095
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
20071
20096
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
20072
20097
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -20190,6 +20215,50 @@ var DEFAULT_READ_FILE_SYSTEM = {
|
|
|
20190
20215
|
realpathSync: realpathSync2
|
|
20191
20216
|
};
|
|
20192
20217
|
|
|
20218
|
+
// packages/omo-config-core/src/loader/disabled-skills.ts
|
|
20219
|
+
function toRecord(value) {
|
|
20220
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
20221
|
+
return;
|
|
20222
|
+
return value;
|
|
20223
|
+
}
|
|
20224
|
+
function namesAt(record, key) {
|
|
20225
|
+
const value = record?.[key];
|
|
20226
|
+
if (!Array.isArray(value))
|
|
20227
|
+
return [];
|
|
20228
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
|
|
20229
|
+
}
|
|
20230
|
+
function harnessBlockKeys(harness) {
|
|
20231
|
+
const canonical = canonicalHarnessName(harness);
|
|
20232
|
+
const legacy = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([name]) => harnessBlockKey(name));
|
|
20233
|
+
return [harnessBlockKey(canonical), ...legacy];
|
|
20234
|
+
}
|
|
20235
|
+
function scopesOf(config, harness) {
|
|
20236
|
+
if (harness === undefined)
|
|
20237
|
+
return [config];
|
|
20238
|
+
return [config, ...harnessBlockKeys(harness).map((key) => toRecord(config[key]))];
|
|
20239
|
+
}
|
|
20240
|
+
function collectExcludedModels(options) {
|
|
20241
|
+
return collectUnionedList("exclude_models", options);
|
|
20242
|
+
}
|
|
20243
|
+
function collectUnionedList(key, options) {
|
|
20244
|
+
const names = new Set;
|
|
20245
|
+
for (const layer of options.layers) {
|
|
20246
|
+
const config = toRecord(layer.config);
|
|
20247
|
+
if (config === undefined)
|
|
20248
|
+
continue;
|
|
20249
|
+
const profile = options.profile === undefined ? undefined : toRecord(toRecord(config["profiles"])?.[options.profile]);
|
|
20250
|
+
const scopes = [
|
|
20251
|
+
...scopesOf(config, options.harness),
|
|
20252
|
+
...profile === undefined ? [] : scopesOf(profile, options.harness)
|
|
20253
|
+
];
|
|
20254
|
+
for (const scope of scopes) {
|
|
20255
|
+
for (const name of namesAt(scope, key))
|
|
20256
|
+
names.add(name.trim());
|
|
20257
|
+
}
|
|
20258
|
+
}
|
|
20259
|
+
return [...names];
|
|
20260
|
+
}
|
|
20261
|
+
|
|
20193
20262
|
// node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
20194
20263
|
function createScanner(text, ignoreTrivia = false) {
|
|
20195
20264
|
const len = text.length;
|
|
@@ -21262,7 +21331,7 @@ function stripUnrecognizedKeys(record, issues) {
|
|
|
21262
21331
|
}
|
|
21263
21332
|
return { issuePaths, stripped };
|
|
21264
21333
|
}
|
|
21265
|
-
function
|
|
21334
|
+
function toRecord2(value) {
|
|
21266
21335
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
21267
21336
|
return null;
|
|
21268
21337
|
const record = {};
|
|
@@ -21277,7 +21346,7 @@ var validateLayerRecord = (record) => {
|
|
|
21277
21346
|
};
|
|
21278
21347
|
function validateConfigLayer(path, data) {
|
|
21279
21348
|
const sanitized = sanitizeUnsafeKeys(data);
|
|
21280
|
-
const record =
|
|
21349
|
+
const record = toRecord2(sanitized.value);
|
|
21281
21350
|
const unsafeIssuePaths = sanitized.issues.flatMap((issue) => issue.keys.map((key) => [...issue.path, key].join(".")));
|
|
21282
21351
|
const unsafeDiagnostics = unsafeIssuePaths.length === 0 ? [] : [{ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${unsafeIssuePaths.join(", ")}`, path, issuePaths: unsafeIssuePaths }];
|
|
21283
21352
|
const validation = OmoConfigLayerSchema.safeParse(sanitized.value);
|
|
@@ -21417,7 +21486,7 @@ function resolveOmoProfileName(options = {}) {
|
|
|
21417
21486
|
const env = options.env ?? process.env;
|
|
21418
21487
|
return profileName(options.profile) ?? profileName(env["OMO_PROFILE"]) ?? profileName(env["OCX_PROFILE"]) ?? profileNameFromOpenCodeConfigDir(env["OPENCODE_CONFIG_DIR"]);
|
|
21419
21488
|
}
|
|
21420
|
-
function
|
|
21489
|
+
function toRecord3(value) {
|
|
21421
21490
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
21422
21491
|
return;
|
|
21423
21492
|
return Object.fromEntries(Object.entries(value));
|
|
@@ -21438,13 +21507,13 @@ function harnessLayer(config, harness) {
|
|
|
21438
21507
|
const legacyKeys = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([legacy]) => harnessBlockKey(legacy));
|
|
21439
21508
|
let layer = {};
|
|
21440
21509
|
for (const key of [...legacyKeys, harnessBlockKey(canonical)]) {
|
|
21441
|
-
layer = mergeOmoConfigRecords(layer,
|
|
21510
|
+
layer = mergeOmoConfigRecords(layer, toRecord3(config[key]) ?? {});
|
|
21442
21511
|
}
|
|
21443
21512
|
return layer;
|
|
21444
21513
|
}
|
|
21445
21514
|
function resolveOmoConfigView(options) {
|
|
21446
|
-
const profiles =
|
|
21447
|
-
const profile = options.profile === undefined ? undefined :
|
|
21515
|
+
const profiles = toRecord3(options.config["profiles"]);
|
|
21516
|
+
const profile = options.profile === undefined ? undefined : toRecord3(profiles?.[options.profile]);
|
|
21448
21517
|
const diagnostics = profile === undefined && options.profile !== undefined ? [{
|
|
21449
21518
|
kind: "profile",
|
|
21450
21519
|
message: `Activated omo profile "${options.profile}" does not exist; using the base configuration`,
|
|
@@ -21585,9 +21654,15 @@ function loadOmoConfig(options = {}) {
|
|
|
21585
21654
|
});
|
|
21586
21655
|
const finalInput = mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config);
|
|
21587
21656
|
const finalConfig = OmoConfigSchema.safeParse(finalInput);
|
|
21657
|
+
const excludeModels = collectExcludedModels({
|
|
21658
|
+
layers,
|
|
21659
|
+
...options.harness === undefined ? {} : { harness: options.harness },
|
|
21660
|
+
...resolved.profile === undefined ? {} : { profile: resolved.profile }
|
|
21661
|
+
});
|
|
21662
|
+
const withExcludedModels = (config) => excludeModels.length === 0 ? config : { ...config, exclude_models: [...excludeModels] };
|
|
21588
21663
|
if (finalConfig.success) {
|
|
21589
21664
|
return {
|
|
21590
|
-
config: stripResolutionControlKeys(finalConfig.data),
|
|
21665
|
+
config: withExcludedModels(stripResolutionControlKeys(finalConfig.data)),
|
|
21591
21666
|
diagnostics: [...diagnostics, ...resolved.diagnostics],
|
|
21592
21667
|
layers,
|
|
21593
21668
|
...resolved.profile === undefined ? {} : { profile: resolved.profile },
|
|
@@ -21600,7 +21675,7 @@ function loadOmoConfig(options = {}) {
|
|
|
21600
21675
|
});
|
|
21601
21676
|
if (pruned.ok) {
|
|
21602
21677
|
return {
|
|
21603
|
-
config: stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config)),
|
|
21678
|
+
config: withExcludedModels(stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config))),
|
|
21604
21679
|
diagnostics: [...diagnostics, ...resolved.diagnostics, ...invalidValueDiagnostics(MERGED_OMO_CONFIG_PATH, pruned.dropped)],
|
|
21605
21680
|
layers,
|
|
21606
21681
|
...resolved.profile === undefined ? {} : { profile: resolved.profile },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: frontend
|
|
3
|
-
description: "Builds, styles, and polishes web UI
|
|
3
|
+
description: "Builds, styles, and polishes anything drawn with HTML, CSS, or SVG: web UI, pages, components, HTML reports rendered to PDF or print, figures, PNG/SVG diagrams, slides, and images for Notion or Slack. Use for any styling, layout, animation, or visual-quality task, or when asked to make something look or feel a certain way."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Frontend
|
|
@@ -25,12 +25,12 @@ This file is a router, not a rulebook. The rules live in four rulesets under `re
|
|
|
25
25
|
|
|
26
26
|
**For implementation work, design + perfection load together.** Beauty with a 2 MB bundle fails; Lighthouse 100 that looks like AI slop fails. Both win or neither does.
|
|
27
27
|
|
|
28
|
-
## Draft guard — read before the first line of
|
|
28
|
+
## Draft guard — read before the first line of HTML or CSS
|
|
29
29
|
|
|
30
30
|
Some tells regenerate by default, so they are kept out of the first draft rather than left for QA to find.
|
|
31
31
|
|
|
32
|
-
- **No coloured
|
|
33
|
-
- **Lint before visual QA.** Run `bun $SKILL_DIR/scripts/perfection/check-accent-stripes.ts <changed files or dirs>` on every stylesheet and
|
|
32
|
+
- **No coloured bar on one side of a box, rounded or square, and no accent outline on a rounded card, decorative or state.** A card, callout, warning, cover block, stat tile, testimonial, alert, or list row never carries a coloured stripe on one side: `border-left: 4px solid <accent>` or `border-l-4 border-indigo-500`, a coloured `::before`/`::after` bar inside it, an inset `box-shadow` stripe, or a hard-stop gradient band or gradient `border-image` along one edge. A rounded card never wears a 2px-or-wider accent outline either (`border: 2px solid var(--primary)`, `ring-2 ring-indigo-500`, an inset ring). Both read as generated whether they decorate the box or mark it selected, focused, or active, and an accent underline under a heading, tab, or link counts too: use a neutral 1px rule, or set the text itself in the accent ink. Give the card its identity another way: a tonal surface (one ink at a low alpha, or the next step of the surface ramp), an eyebrow or heading set in the accent ink, a leading glyph, or more space between groups. Encode state with one ink at many alphas (hover/selected/active washes), a check glyph for selection, and tonal layering for focus. The coloured edges that stay allowed: keyboard `focus-visible` rings, validation states on form inputs, neutral 1px hairlines and dividers between rows or sections, table rules, and a blockquote's neutral rule. This covers pre-existing instances on any surface you touch.
|
|
33
|
+
- **Lint before visual QA.** Run `bun $SKILL_DIR/scripts/perfection/check-accent-stripes.ts <changed files or dirs>` on every stylesheet, component, and HTML file you wrote, including a report or figure you will print, screenshot, or render to an image. It reads CSS/SCSS/Less, HTML, JSX/TSX, Vue, Svelte, Astro, Tailwind classes (including `@apply` and `cva`/`cn` strings), inline styles, and styled-components. Exit 1 means a stripe is in the draft: remove the stripe, do not argue with the finding.
|
|
34
34
|
|
|
35
35
|
## Design System and Component Workflow
|
|
36
36
|
|
|
@@ -145,7 +145,7 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
|
|
|
145
145
|
- **Concrete reference = contract.** When a screenshot, mockup, or annotated reference exists, match its pixels, copy, component structure, and responsive intent unless the user accepts a deviation.
|
|
146
146
|
- **Never weaken UX OR flatten the surface to buy points.** No dropping animations, hiding content, simplifying interactions, or replacing rendered/lit material with flat fills and flat geometric primitives for a Lighthouse score or a deadline. Hit 100 AND keep the surface dimensional — both, or neither.
|
|
147
147
|
- **No emojis as icons.** SVG icon sets only (Lucide, Heroicons, Radix, Phosphor).
|
|
148
|
-
- **No coloured
|
|
148
|
+
- **No coloured edge bars, no accent outlines on cards.** A decorative accent stripe on a callout, rounded or square, and a `border-l-2 border-primary` stripe on a selected row are the same tell, and so is a primary-tinted outline on a focused card. The Draft guard above carries the replacements and the allowed exceptions; `check-accent-stripes.ts` must exit 0 before `/visual-qa`. Applies to code you write AND to pre-existing instances on any surface you touch — sweep them out.
|
|
149
149
|
- **GPU-composited animation only** — `transform`, `opacity`, `filter`; never animate layout properties.
|
|
150
150
|
- **Slop animation is forbidden — motion serves meaning.** Every animation or hover must map to a real interaction, state change, or affordance. A hover that changes nothing, motion on a non-interactive element, or a decorative micro-animation with no informational purpose is slop — do not add it.
|
|
151
151
|
- **Done is the `/visual-qa` gate, not your own glance.** A frontend design task is verified through `/visual-qa` - its HIG-based checklist, its capture matrix (every page and every sibling surface, phone and desktop, light and dark, scrolled-end, motion driven and inspected) and its dual-oracle completion gate on fresh evidence. This skill does not keep its own list of visual checks; the verifier owns it.
|
|
@@ -160,4 +160,4 @@ Domains: `product` `style` `typography` `color` `landing` `chart` `ux` `react` `
|
|
|
160
160
|
|
|
161
161
|
## Activation
|
|
162
162
|
|
|
163
|
-
Use for any frontend, web UI, UX, visual, design, styling, layout, animation, performance, accessibility, or SEO work — building, redesigning, auditing, or generating mockups. Not for backend, CLI, or pure-logic tasks with no visual surface.
|
|
163
|
+
Use for any frontend, web UI, UX, visual, design, styling, layout, animation, performance, accessibility, or SEO work, and for every HTML/CSS/SVG artifact that ends up as a PDF, print page, report, figure, diagram, slide, or image — building, redesigning, auditing, or generating mockups. Not for backend, CLI, or pure-logic tasks with no visual surface.
|