oh-my-opencode 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/dist/index.js +1467 -1389
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/frontend/SKILL.md +6 -6
- package/dist/skills/frontend/references/design/README.md +2 -2
- package/dist/skills/frontend/references/perfection/README.md +2 -2
- package/dist/skills/frontend/scripts/perfection/accent-stripes/declarations.ts +22 -13
- package/dist/skills/frontend/scripts/perfection/accent-stripes/findings.ts +7 -6
- package/dist/skills/frontend/scripts/perfection/accent-stripes/lint.ts +18 -24
- package/dist/skills/frontend/scripts/perfection/accent-stripes/markup.ts +14 -7
- package/dist/skills/frontend/scripts/perfection/accent-stripes/selector.ts +5 -1
- package/dist/skills/frontend/scripts/perfection/accent-stripes/tailwind.ts +32 -14
- package/dist/skills/frontend/scripts/perfection/check-accent-stripes.test.ts +15 -6
- package/dist/skills/frontend/scripts/perfection/check-accent-stripes.ts +1 -1
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/inline-ok.tsx +1 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/neutral-and-flat.css +1 -1
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/tailwind-ok.tsx +5 -2
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/negative/uniform-and-rings.css +2 -2
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.css +4 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/accent-outlines.tsx +8 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/{negative → positive}/flat-stripe-side.tsx +3 -1
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/report-callouts.html +8 -0
- package/dist/skills/frontend/scripts/perfection/fixtures/accent-stripes/positive/square-surfaces.css +8 -0
- package/dist/skills/ulw-research/SKILL.md +10 -2
- package/dist/skills/ulw-research/references/deliverable-phase.md +10 -0
- package/dist/skills/ulw-research/references/report-visualization.md +23 -0
- package/dist/tui.js +108 -26
- package/package.json +14 -14
- package/packages/lsp-core/src/lsp/fixtures/disposed-stdin-epipe-probe.ts +28 -0
- package/packages/lsp-core/src/lsp/process-pipe-errors.test.ts +21 -0
- package/packages/lsp-core/src/lsp/process.ts +16 -0
- 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
|
@@ -37,6 +37,8 @@ Run this skill only when the user explicitly demands it: the word "ulw-research"
|
|
|
37
37
|
|
|
38
38
|
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.
|
|
39
39
|
|
|
40
|
+
**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.
|
|
41
|
+
|
|
40
42
|
## Authority while active
|
|
41
43
|
|
|
42
44
|
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.
|
|
@@ -55,6 +57,8 @@ The research is done when all of these hold:
|
|
|
55
57
|
- 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.
|
|
56
58
|
- 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.
|
|
57
59
|
- 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.
|
|
60
|
+
- When the harness can show an HTML page inline, the report was shown inline before the artifact paths.
|
|
61
|
+
- 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.
|
|
58
62
|
- 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.
|
|
59
63
|
- 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.
|
|
60
64
|
|
|
@@ -159,7 +163,7 @@ Never block collection on the shape of the deliverable, and never guess it eithe
|
|
|
159
163
|
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.
|
|
160
164
|
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.
|
|
161
165
|
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.
|
|
162
|
-
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"`.
|
|
166
|
+
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.
|
|
163
167
|
|
|
164
168
|
Phase 5 opens by turning the recorded fields into `design-spec.md`.
|
|
165
169
|
|
|
@@ -334,6 +338,8 @@ Asset workers (background, parallel, each fed `design-spec.md`) — visuals are
|
|
|
334
338
|
|
|
335
339
|
**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.
|
|
336
340
|
|
|
341
|
+
**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.
|
|
342
|
+
|
|
337
343
|
**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.
|
|
338
344
|
|
|
339
345
|
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.
|
|
@@ -349,7 +355,7 @@ Nothing reaches the user until the gates pass. Record each result with `node "$S
|
|
|
349
355
|
|
|
350
356
|
**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).
|
|
351
357
|
|
|
352
|
-
Then resolve every manifest row (`outcome set <format> delivered --path <file>` or `blocked_capability` / `skipped` / `failed` with `--reason`) and deliver: the artifact
|
|
358
|
+
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.
|
|
353
359
|
|
|
354
360
|
### The closing briefing — every run ends with it
|
|
355
361
|
|
|
@@ -414,4 +420,6 @@ High-yield combinations: official docs (`site:<docs domain>`), GitHub implementa
|
|
|
414
420
|
| Chasing an interesting find with no ENTER trigger | Excursions need a named trigger; everything else stays a queued lead |
|
|
415
421
|
| 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 |
|
|
416
422
|
| 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 |
|
|
423
|
+
| 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 |
|
|
424
|
+
| 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 |
|
|
417
425
|
| 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 |
|
package/dist/tui.js
CHANGED
|
@@ -70106,10 +70106,29 @@ var init_harness = __esm(() => {
|
|
|
70106
70106
|
OMO_CONFIG_LEGACY_HARNESS_IDS = Object.keys(OMO_CONFIG_LEGACY_HARNESS_ALIASES);
|
|
70107
70107
|
});
|
|
70108
70108
|
|
|
70109
|
+
// packages/omo-config-core/src/schema/memory-agreements.ts
|
|
70110
|
+
var OMO_MEMORY_AGREEMENTS_DEFAULTS, OmoMemoryAgreementsSchema, OmoMemoryAgreementsLayerSchema;
|
|
70111
|
+
var init_memory_agreements = __esm(() => {
|
|
70112
|
+
init_zod();
|
|
70113
|
+
OMO_MEMORY_AGREEMENTS_DEFAULTS = { enabled: true, needs_human_threshold: 3, max_items: 64 };
|
|
70114
|
+
OmoMemoryAgreementsSchema = object({
|
|
70115
|
+
enabled: boolean2().default(OMO_MEMORY_AGREEMENTS_DEFAULTS.enabled),
|
|
70116
|
+
needs_human_threshold: number2().int().min(1).default(OMO_MEMORY_AGREEMENTS_DEFAULTS.needs_human_threshold),
|
|
70117
|
+
max_items: number2().int().min(8).max(256).default(OMO_MEMORY_AGREEMENTS_DEFAULTS.max_items)
|
|
70118
|
+
}).strict();
|
|
70119
|
+
OmoMemoryAgreementsLayerSchema = object({
|
|
70120
|
+
enabled: boolean2().optional(),
|
|
70121
|
+
needs_human_threshold: number2().int().min(1).optional(),
|
|
70122
|
+
max_items: number2().int().min(8).max(256).optional()
|
|
70123
|
+
}).strict();
|
|
70124
|
+
});
|
|
70125
|
+
|
|
70109
70126
|
// packages/omo-config-core/src/schema/memory.ts
|
|
70110
|
-
var OmoMemoryReflectionTriggerSchema, OmoMemoryReflectionSchema, OmoMemorySyncSchema, OmoMemorySearchSchema, OmoMemoryRecallEventCapsSchema, OmoMemoryRecallSchema, OmoMemoryNudgeSchema, OmoMemoryFactsSchema, OmoMemoryDreamSchema, OmoMemoryPeopleSchema, OmoMemorySoulSchema, OmoMemoryWriteNoticeSchema, OmoMemoryReflectionTriggerLayerSchema, OmoMemoryReflectionLayerSchema, OmoMemorySyncLayerSchema, OmoMemorySearchLayerSchema, OmoMemoryRecallEventCapsLayerSchema, OmoMemoryRecallLayerSchema, OmoMemoryNudgeLayerSchema, OmoMemoryFactsLayerSchema, OmoMemoryDreamLayerSchema, OmoMemoryPeopleLayerSchema, OmoMemorySoulLayerSchema, OmoMemoryWriteNoticeLayerSchema, OmoMemoryProjectionSchema, OmoMemoryProjectionLayerSchema, OmoMemoryAgentOverridesSchema, OmoMemorySettingsSchema, OmoMemorySettingsLayerSchema;
|
|
70127
|
+
var OmoMemoryReflectionTriggerSchema, OmoMemoryReflectionSchema, OmoMemorySyncSchema, OmoMemorySearchSchema, OmoMemoryRecallEventCapsSchema, OmoMemoryRecallSchema, OmoMemoryNudgeSchema, OmoMemoryFactsSchema, OmoMemoryDreamSchema, OmoMemoryPeopleSchema, OmoMemorySoulSchema, OmoMemoryWriteNoticeSchema, OmoMemoryReflectionTriggerLayerSchema, OmoMemoryReflectionLayerSchema, OmoMemorySyncLayerSchema, OmoMemorySearchLayerSchema, OmoMemoryRecallEventCapsLayerSchema, OmoMemoryRecallLayerSchema, OmoMemoryNudgeLayerSchema, OmoMemoryFactsLayerSchema, OmoMemoryDreamLayerSchema, OmoMemoryPeopleLayerSchema, OmoMemorySoulLayerSchema, OmoMemoryWriteNoticeLayerSchema, OmoMemoryProjectionSchema, OmoMemoryProjectionLayerSchema, OmoMemoryAgentOverridesSchema, OmoMemoryAutoIdentitySchema, OmoMemorySettingsSchema, OmoMemorySettingsLayerSchema;
|
|
70111
70128
|
var init_memory = __esm(() => {
|
|
70112
70129
|
init_zod();
|
|
70130
|
+
init_memory_agreements();
|
|
70131
|
+
init_memory_agreements();
|
|
70113
70132
|
OmoMemoryReflectionTriggerSchema = object({
|
|
70114
70133
|
step_count: number2().int().nonnegative().default(25),
|
|
70115
70134
|
on_compaction: boolean2().default(true)
|
|
@@ -70252,6 +70271,7 @@ var init_memory = __esm(() => {
|
|
|
70252
70271
|
facts: OmoMemoryFactsLayerSchema.optional(),
|
|
70253
70272
|
dream: OmoMemoryDreamLayerSchema.optional(),
|
|
70254
70273
|
people: OmoMemoryPeopleLayerSchema.optional(),
|
|
70274
|
+
agreements: OmoMemoryAgreementsLayerSchema.optional(),
|
|
70255
70275
|
soul: OmoMemorySoulLayerSchema.optional(),
|
|
70256
70276
|
write_notice: OmoMemoryWriteNoticeLayerSchema.optional(),
|
|
70257
70277
|
sync: OmoMemorySyncLayerSchema.optional(),
|
|
@@ -70260,9 +70280,11 @@ var init_memory = __esm(() => {
|
|
|
70260
70280
|
projection: OmoMemoryProjectionLayerSchema.optional(),
|
|
70261
70281
|
compile_warn_tokens: number2().int().positive().optional()
|
|
70262
70282
|
}).strict();
|
|
70283
|
+
OmoMemoryAutoIdentitySchema = _enum(["path", "git"]);
|
|
70263
70284
|
OmoMemorySettingsSchema = object({
|
|
70264
70285
|
enabled: boolean2().default(true),
|
|
70265
70286
|
agent: string2().min(1).default("auto"),
|
|
70287
|
+
auto_identity: OmoMemoryAutoIdentitySchema.default("path"),
|
|
70266
70288
|
reflection: OmoMemoryReflectionSchema.default({
|
|
70267
70289
|
enabled: true,
|
|
70268
70290
|
trigger: { step_count: 25, on_compaction: true },
|
|
@@ -70282,6 +70304,7 @@ var init_memory = __esm(() => {
|
|
|
70282
70304
|
auto_select_max_chars: 150000
|
|
70283
70305
|
}),
|
|
70284
70306
|
people: OmoMemoryPeopleSchema.default({ enabled: true, max_entries: 40, max_entry_chars: 200 }),
|
|
70307
|
+
agreements: OmoMemoryAgreementsSchema.default(OMO_MEMORY_AGREEMENTS_DEFAULTS),
|
|
70285
70308
|
soul: OmoMemorySoulSchema.default({ edit_notice: true }),
|
|
70286
70309
|
write_notice: OmoMemoryWriteNoticeSchema.default({ enabled: true }),
|
|
70287
70310
|
sync: OmoMemorySyncSchema.default({ enabled: true }),
|
|
@@ -70303,11 +70326,13 @@ var init_memory = __esm(() => {
|
|
|
70303
70326
|
OmoMemorySettingsLayerSchema = object({
|
|
70304
70327
|
enabled: boolean2().optional(),
|
|
70305
70328
|
agent: string2().min(1).optional(),
|
|
70329
|
+
auto_identity: OmoMemoryAutoIdentitySchema.optional(),
|
|
70306
70330
|
reflection: OmoMemoryReflectionLayerSchema.optional(),
|
|
70307
70331
|
nudge: OmoMemoryNudgeLayerSchema.optional(),
|
|
70308
70332
|
facts: OmoMemoryFactsLayerSchema.optional(),
|
|
70309
70333
|
dream: OmoMemoryDreamLayerSchema.optional(),
|
|
70310
70334
|
people: OmoMemoryPeopleLayerSchema.optional(),
|
|
70335
|
+
agreements: OmoMemoryAgreementsLayerSchema.optional(),
|
|
70311
70336
|
soul: OmoMemorySoulLayerSchema.optional(),
|
|
70312
70337
|
write_notice: OmoMemoryWriteNoticeLayerSchema.optional(),
|
|
70313
70338
|
sync: OmoMemorySyncLayerSchema.optional(),
|
|
@@ -70351,6 +70376,7 @@ var init_model_profile = __esm(() => {
|
|
|
70351
70376
|
init_fallback_models();
|
|
70352
70377
|
OmoModelProfileInputSchema = object({
|
|
70353
70378
|
display_name: string2().optional(),
|
|
70379
|
+
caution: string2().optional(),
|
|
70354
70380
|
family: _enum(["daily", "geeky"]).optional(),
|
|
70355
70381
|
tier: _enum(["normal", "heavy"]).optional(),
|
|
70356
70382
|
models: array(union([string2(), OmoFallbackModelObjectSchema])).optional()
|
|
@@ -70644,7 +70670,7 @@ var init_gateway = __esm(() => {
|
|
|
70644
70670
|
});
|
|
70645
70671
|
|
|
70646
70672
|
// packages/omo-config-core/src/schema/config.ts
|
|
70647
|
-
var OmoOpenCodeHarnessConfigSchema, OmoDisabledSkillsSchema, OmoTypedHarnessConfigSchema, OmoConfigProfileSchema, OmoConfigSchema, OmoConfigLayerSchema;
|
|
70673
|
+
var OmoOpenCodeHarnessConfigSchema, OmoDisabledSkillsSchema, OmoExcludedModelsSchema, OmoTypedHarnessConfigSchema, OmoConfigProfileSchema, OmoConfigSchema, OmoConfigLayerSchema;
|
|
70648
70674
|
var init_config = __esm(() => {
|
|
70649
70675
|
init_zod();
|
|
70650
70676
|
init_agent();
|
|
@@ -70662,6 +70688,7 @@ var init_config = __esm(() => {
|
|
|
70662
70688
|
init_gateway();
|
|
70663
70689
|
OmoOpenCodeHarnessConfigSchema = record(string2(), unknown());
|
|
70664
70690
|
OmoDisabledSkillsSchema = array(string2());
|
|
70691
|
+
OmoExcludedModelsSchema = array(string2());
|
|
70665
70692
|
OmoTypedHarnessConfigSchema = object({
|
|
70666
70693
|
formatOnMutation: OmoFormatOnMutationLayerSchema.optional(),
|
|
70667
70694
|
gateway: OmoGatewaySectionSchema.optional(),
|
|
@@ -70677,7 +70704,8 @@ var init_config = __esm(() => {
|
|
|
70677
70704
|
telemetry: OmoTelemetrySettingsLayerSchema.optional(),
|
|
70678
70705
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
70679
70706
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
70680
|
-
disabled_skills: OmoDisabledSkillsSchema.optional()
|
|
70707
|
+
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
70708
|
+
exclude_models: OmoExcludedModelsSchema.optional()
|
|
70681
70709
|
}).strict();
|
|
70682
70710
|
OmoConfigProfileSchema = object({
|
|
70683
70711
|
formatOnMutation: OmoFormatOnMutationLayerSchema.optional(),
|
|
@@ -70694,6 +70722,7 @@ var init_config = __esm(() => {
|
|
|
70694
70722
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
70695
70723
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
70696
70724
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
70725
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
70697
70726
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
70698
70727
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
70699
70728
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -70716,6 +70745,7 @@ var init_config = __esm(() => {
|
|
|
70716
70745
|
side_panel: OmoSidePanelSettingsSchema.optional(),
|
|
70717
70746
|
computer: OmoComputerSettingsSchema.optional(),
|
|
70718
70747
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
70748
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
70719
70749
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
70720
70750
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
70721
70751
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -70741,6 +70771,7 @@ var init_config = __esm(() => {
|
|
|
70741
70771
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
70742
70772
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
70743
70773
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
70774
|
+
exclude_models: OmoExcludedModelsSchema.optional(),
|
|
70744
70775
|
"[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
|
|
70745
70776
|
"[native]": OmoTypedHarnessConfigSchema.optional(),
|
|
70746
70777
|
"[senpi]": OmoTypedHarnessConfigSchema.optional(),
|
|
@@ -70943,7 +70974,51 @@ var init_diagnostic_lines = __esm(() => {
|
|
|
70943
70974
|
});
|
|
70944
70975
|
|
|
70945
70976
|
// packages/omo-config-core/src/loader/disabled-skills.ts
|
|
70946
|
-
|
|
70977
|
+
function toRecord(value) {
|
|
70978
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
70979
|
+
return;
|
|
70980
|
+
return value;
|
|
70981
|
+
}
|
|
70982
|
+
function namesAt(record, key) {
|
|
70983
|
+
const value = record?.[key];
|
|
70984
|
+
if (!Array.isArray(value))
|
|
70985
|
+
return [];
|
|
70986
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
|
|
70987
|
+
}
|
|
70988
|
+
function harnessBlockKeys(harness) {
|
|
70989
|
+
const canonical = canonicalHarnessName(harness);
|
|
70990
|
+
const legacy = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([name]) => harnessBlockKey(name));
|
|
70991
|
+
return [harnessBlockKey(canonical), ...legacy];
|
|
70992
|
+
}
|
|
70993
|
+
function scopesOf(config, harness) {
|
|
70994
|
+
if (harness === undefined)
|
|
70995
|
+
return [config];
|
|
70996
|
+
return [config, ...harnessBlockKeys(harness).map((key) => toRecord(config[key]))];
|
|
70997
|
+
}
|
|
70998
|
+
function collectExcludedModels(options) {
|
|
70999
|
+
return collectUnionedList("exclude_models", options);
|
|
71000
|
+
}
|
|
71001
|
+
function collectUnionedList(key, options) {
|
|
71002
|
+
const names = new Set;
|
|
71003
|
+
for (const layer of options.layers) {
|
|
71004
|
+
const config = toRecord(layer.config);
|
|
71005
|
+
if (config === undefined)
|
|
71006
|
+
continue;
|
|
71007
|
+
const profile = options.profile === undefined ? undefined : toRecord(toRecord(config["profiles"])?.[options.profile]);
|
|
71008
|
+
const scopes = [
|
|
71009
|
+
...scopesOf(config, options.harness),
|
|
71010
|
+
...profile === undefined ? [] : scopesOf(profile, options.harness)
|
|
71011
|
+
];
|
|
71012
|
+
for (const scope of scopes) {
|
|
71013
|
+
for (const name of namesAt(scope, key))
|
|
71014
|
+
names.add(name.trim());
|
|
71015
|
+
}
|
|
71016
|
+
}
|
|
71017
|
+
return [...names];
|
|
71018
|
+
}
|
|
71019
|
+
var init_disabled_skills = __esm(() => {
|
|
71020
|
+
init_schema();
|
|
71021
|
+
});
|
|
70947
71022
|
|
|
70948
71023
|
// packages/omo-config-core/src/loader/merge.ts
|
|
70949
71024
|
function isUnsafeObjectKey2(key) {
|
|
@@ -71179,7 +71254,7 @@ function stripUnrecognizedKeys(record, issues) {
|
|
|
71179
71254
|
}
|
|
71180
71255
|
return { issuePaths, stripped };
|
|
71181
71256
|
}
|
|
71182
|
-
function
|
|
71257
|
+
function toRecord2(value) {
|
|
71183
71258
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
71184
71259
|
return null;
|
|
71185
71260
|
const record = {};
|
|
@@ -71190,7 +71265,7 @@ function toRecord(value) {
|
|
|
71190
71265
|
}
|
|
71191
71266
|
function validateConfigLayer(path, data) {
|
|
71192
71267
|
const sanitized = sanitizeUnsafeKeys(data);
|
|
71193
|
-
const record =
|
|
71268
|
+
const record = toRecord2(sanitized.value);
|
|
71194
71269
|
const unsafeIssuePaths = sanitized.issues.flatMap((issue) => issue.keys.map((key) => [...issue.path, key].join(".")));
|
|
71195
71270
|
const unsafeDiagnostics = unsafeIssuePaths.length === 0 ? [] : [{ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${unsafeIssuePaths.join(", ")}`, path, issuePaths: unsafeIssuePaths }];
|
|
71196
71271
|
const validation = OmoConfigLayerSchema.safeParse(sanitized.value);
|
|
@@ -71340,7 +71415,7 @@ function resolveOmoProfileName(options = {}) {
|
|
|
71340
71415
|
const env = options.env ?? process.env;
|
|
71341
71416
|
return profileName(options.profile) ?? profileName(env["OMO_PROFILE"]) ?? profileName(env["OCX_PROFILE"]) ?? profileNameFromOpenCodeConfigDir(env["OPENCODE_CONFIG_DIR"]);
|
|
71342
71417
|
}
|
|
71343
|
-
function
|
|
71418
|
+
function toRecord3(value) {
|
|
71344
71419
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
71345
71420
|
return;
|
|
71346
71421
|
return Object.fromEntries(Object.entries(value));
|
|
@@ -71361,13 +71436,13 @@ function harnessLayer(config, harness) {
|
|
|
71361
71436
|
const legacyKeys = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([legacy]) => harnessBlockKey(legacy));
|
|
71362
71437
|
let layer = {};
|
|
71363
71438
|
for (const key of [...legacyKeys, harnessBlockKey(canonical)]) {
|
|
71364
|
-
layer = mergeOmoConfigRecords(layer,
|
|
71439
|
+
layer = mergeOmoConfigRecords(layer, toRecord3(config[key]) ?? {});
|
|
71365
71440
|
}
|
|
71366
71441
|
return layer;
|
|
71367
71442
|
}
|
|
71368
71443
|
function resolveOmoConfigView(options) {
|
|
71369
|
-
const profiles =
|
|
71370
|
-
const profile = options.profile === undefined ? undefined :
|
|
71444
|
+
const profiles = toRecord3(options.config["profiles"]);
|
|
71445
|
+
const profile = options.profile === undefined ? undefined : toRecord3(profiles?.[options.profile]);
|
|
71371
71446
|
const diagnostics = profile === undefined && options.profile !== undefined ? [{
|
|
71372
71447
|
kind: "profile",
|
|
71373
71448
|
message: `Activated omo profile "${options.profile}" does not exist; using the base configuration`,
|
|
@@ -71508,9 +71583,15 @@ function loadOmoConfig(options = {}) {
|
|
|
71508
71583
|
});
|
|
71509
71584
|
const finalInput = mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config);
|
|
71510
71585
|
const finalConfig = OmoConfigSchema.safeParse(finalInput);
|
|
71586
|
+
const excludeModels = collectExcludedModels({
|
|
71587
|
+
layers,
|
|
71588
|
+
...options.harness === undefined ? {} : { harness: options.harness },
|
|
71589
|
+
...resolved.profile === undefined ? {} : { profile: resolved.profile }
|
|
71590
|
+
});
|
|
71591
|
+
const withExcludedModels = (config) => excludeModels.length === 0 ? config : { ...config, exclude_models: [...excludeModels] };
|
|
71511
71592
|
if (finalConfig.success) {
|
|
71512
71593
|
return {
|
|
71513
|
-
config: stripResolutionControlKeys(finalConfig.data),
|
|
71594
|
+
config: withExcludedModels(stripResolutionControlKeys(finalConfig.data)),
|
|
71514
71595
|
diagnostics: [...diagnostics, ...resolved.diagnostics],
|
|
71515
71596
|
layers,
|
|
71516
71597
|
...resolved.profile === undefined ? {} : { profile: resolved.profile },
|
|
@@ -71523,7 +71604,7 @@ function loadOmoConfig(options = {}) {
|
|
|
71523
71604
|
});
|
|
71524
71605
|
if (pruned.ok) {
|
|
71525
71606
|
return {
|
|
71526
|
-
config: stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config)),
|
|
71607
|
+
config: withExcludedModels(stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config))),
|
|
71527
71608
|
diagnostics: [...diagnostics, ...resolved.diagnostics, ...invalidValueDiagnostics(MERGED_OMO_CONFIG_PATH, pruned.dropped)],
|
|
71528
71609
|
layers,
|
|
71529
71610
|
...resolved.profile === undefined ? {} : { profile: resolved.profile },
|
|
@@ -71542,6 +71623,7 @@ var DEFAULT_RAW_CONFIG;
|
|
|
71542
71623
|
var init_loader2 = __esm(() => {
|
|
71543
71624
|
init_main();
|
|
71544
71625
|
init_schema();
|
|
71626
|
+
init_disabled_skills();
|
|
71545
71627
|
init_layer_validation();
|
|
71546
71628
|
init_merge();
|
|
71547
71629
|
init_paths();
|
|
@@ -75014,7 +75096,7 @@ init_shared();
|
|
|
75014
75096
|
// package.json
|
|
75015
75097
|
var package_default = {
|
|
75016
75098
|
name: "oh-my-opencode",
|
|
75017
|
-
version: "5.1.
|
|
75099
|
+
version: "5.1.42",
|
|
75018
75100
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
75019
75101
|
main: "./dist/index.js",
|
|
75020
75102
|
types: "dist/index.d.ts",
|
|
@@ -75191,7 +75273,7 @@ var package_default = {
|
|
|
75191
75273
|
},
|
|
75192
75274
|
devDependencies: {
|
|
75193
75275
|
"@clack/prompts": "^1.8.1",
|
|
75194
|
-
"@code-yeongyu/senpi": "2026.10.
|
|
75276
|
+
"@code-yeongyu/senpi": "2026.10.21-2",
|
|
75195
75277
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
75196
75278
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
75197
75279
|
"@oh-my-opencode/ast-grep-mcp": "workspace:*",
|
|
@@ -75252,18 +75334,18 @@ var package_default = {
|
|
|
75252
75334
|
typescript: "^7.0.2"
|
|
75253
75335
|
},
|
|
75254
75336
|
optionalDependencies: {
|
|
75255
|
-
"oh-my-opencode-darwin-arm64": "5.1.
|
|
75256
|
-
"oh-my-opencode-darwin-x64": "5.1.
|
|
75257
|
-
"oh-my-opencode-darwin-x64-baseline": "5.1.
|
|
75258
|
-
"oh-my-opencode-linux-arm64": "5.1.
|
|
75259
|
-
"oh-my-opencode-linux-arm64-musl": "5.1.
|
|
75260
|
-
"oh-my-opencode-linux-x64": "5.1.
|
|
75261
|
-
"oh-my-opencode-linux-x64-baseline": "5.1.
|
|
75262
|
-
"oh-my-opencode-linux-x64-musl": "5.1.
|
|
75263
|
-
"oh-my-opencode-linux-x64-musl-baseline": "5.1.
|
|
75264
|
-
"oh-my-opencode-windows-arm64": "5.1.
|
|
75265
|
-
"oh-my-opencode-windows-x64": "5.1.
|
|
75266
|
-
"oh-my-opencode-windows-x64-baseline": "5.1.
|
|
75337
|
+
"oh-my-opencode-darwin-arm64": "5.1.42",
|
|
75338
|
+
"oh-my-opencode-darwin-x64": "5.1.42",
|
|
75339
|
+
"oh-my-opencode-darwin-x64-baseline": "5.1.42",
|
|
75340
|
+
"oh-my-opencode-linux-arm64": "5.1.42",
|
|
75341
|
+
"oh-my-opencode-linux-arm64-musl": "5.1.42",
|
|
75342
|
+
"oh-my-opencode-linux-x64": "5.1.42",
|
|
75343
|
+
"oh-my-opencode-linux-x64-baseline": "5.1.42",
|
|
75344
|
+
"oh-my-opencode-linux-x64-musl": "5.1.42",
|
|
75345
|
+
"oh-my-opencode-linux-x64-musl-baseline": "5.1.42",
|
|
75346
|
+
"oh-my-opencode-windows-arm64": "5.1.42",
|
|
75347
|
+
"oh-my-opencode-windows-x64": "5.1.42",
|
|
75348
|
+
"oh-my-opencode-windows-x64-baseline": "5.1.42"
|
|
75267
75349
|
},
|
|
75268
75350
|
overrides: {
|
|
75269
75351
|
hono: "^4.13.8",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.42",
|
|
4
4
|
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
},
|
|
178
178
|
"devDependencies": {
|
|
179
179
|
"@clack/prompts": "^1.8.1",
|
|
180
|
-
"@code-yeongyu/senpi": "2026.10.
|
|
180
|
+
"@code-yeongyu/senpi": "2026.10.21-2",
|
|
181
181
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
182
182
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
183
183
|
"@oh-my-opencode/ast-grep-mcp": "workspace:*",
|
|
@@ -238,18 +238,18 @@
|
|
|
238
238
|
"typescript": "^7.0.2"
|
|
239
239
|
},
|
|
240
240
|
"optionalDependencies": {
|
|
241
|
-
"oh-my-opencode-darwin-arm64": "5.1.
|
|
242
|
-
"oh-my-opencode-darwin-x64": "5.1.
|
|
243
|
-
"oh-my-opencode-darwin-x64-baseline": "5.1.
|
|
244
|
-
"oh-my-opencode-linux-arm64": "5.1.
|
|
245
|
-
"oh-my-opencode-linux-arm64-musl": "5.1.
|
|
246
|
-
"oh-my-opencode-linux-x64": "5.1.
|
|
247
|
-
"oh-my-opencode-linux-x64-baseline": "5.1.
|
|
248
|
-
"oh-my-opencode-linux-x64-musl": "5.1.
|
|
249
|
-
"oh-my-opencode-linux-x64-musl-baseline": "5.1.
|
|
250
|
-
"oh-my-opencode-windows-arm64": "5.1.
|
|
251
|
-
"oh-my-opencode-windows-x64": "5.1.
|
|
252
|
-
"oh-my-opencode-windows-x64-baseline": "5.1.
|
|
241
|
+
"oh-my-opencode-darwin-arm64": "5.1.42",
|
|
242
|
+
"oh-my-opencode-darwin-x64": "5.1.42",
|
|
243
|
+
"oh-my-opencode-darwin-x64-baseline": "5.1.42",
|
|
244
|
+
"oh-my-opencode-linux-arm64": "5.1.42",
|
|
245
|
+
"oh-my-opencode-linux-arm64-musl": "5.1.42",
|
|
246
|
+
"oh-my-opencode-linux-x64": "5.1.42",
|
|
247
|
+
"oh-my-opencode-linux-x64-baseline": "5.1.42",
|
|
248
|
+
"oh-my-opencode-linux-x64-musl": "5.1.42",
|
|
249
|
+
"oh-my-opencode-linux-x64-musl-baseline": "5.1.42",
|
|
250
|
+
"oh-my-opencode-windows-arm64": "5.1.42",
|
|
251
|
+
"oh-my-opencode-windows-x64": "5.1.42",
|
|
252
|
+
"oh-my-opencode-windows-x64-baseline": "5.1.42"
|
|
253
253
|
},
|
|
254
254
|
"overrides": {
|
|
255
255
|
"hono": "^4.13.8",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Reproduces the Windows teardown race from #9601 on any OS: the transport
|
|
2
|
+
// disposes its JSON-RPC connection, then the server's stdin pipe fails with
|
|
3
|
+
// EPIPE. Windows reports that failure asynchronously, after dispose removed the
|
|
4
|
+
// connection's listener, so the stream is destroyed with the error here to get
|
|
5
|
+
// the same event order deterministically. The probe exits 0 only when the error
|
|
6
|
+
// was handled; an unhandled 'error' event crashes it with a non-zero exit.
|
|
7
|
+
import { JsonRpcConnection } from "../json-rpc-connection.js";
|
|
8
|
+
import { spawnProcess } from "../process.js";
|
|
9
|
+
|
|
10
|
+
const server = spawnProcess([process.execPath, "-e", "process.stdin.on('close', () => process.exit(0)).resume()"], {
|
|
11
|
+
cwd: process.cwd(),
|
|
12
|
+
env: process.env,
|
|
13
|
+
});
|
|
14
|
+
const connection = new JsonRpcConnection(server.stdout, server.stdin);
|
|
15
|
+
connection.listen();
|
|
16
|
+
connection.dispose();
|
|
17
|
+
|
|
18
|
+
const stdinClosed = new Promise<void>((resolve) => server.stdin.once("close", () => resolve()));
|
|
19
|
+
const epipe = Object.assign(new Error("EPIPE: broken pipe, write"), { code: "EPIPE", syscall: "write", errno: -4047 });
|
|
20
|
+
if (!("destroy" in server.stdin) || typeof server.stdin.destroy !== "function") {
|
|
21
|
+
throw new Error("server stdin is not destroyable");
|
|
22
|
+
}
|
|
23
|
+
server.stdin.destroy(epipe);
|
|
24
|
+
await stdinClosed;
|
|
25
|
+
|
|
26
|
+
server.kill("SIGKILL");
|
|
27
|
+
await server.exited;
|
|
28
|
+
process.stdout.write("PROBE_SURVIVED\n");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "bun:test";
|
|
6
|
+
|
|
7
|
+
const probePath = join(dirname(fileURLToPath(import.meta.url)), "fixtures", "disposed-stdin-epipe-probe.ts");
|
|
8
|
+
|
|
9
|
+
describe("spawned LSP server pipes", () => {
|
|
10
|
+
it("handles an EPIPE on server stdin after the connection is disposed", () => {
|
|
11
|
+
// given a server whose JSON-RPC connection was disposed during cleanup
|
|
12
|
+
// when its stdin pipe then fails with EPIPE (the Windows teardown order)
|
|
13
|
+
const result = spawnSync(process.execPath, [probePath], { encoding: "utf8", timeout: 15_000 });
|
|
14
|
+
|
|
15
|
+
// then the failure is reported as ignored cleanup noise, never raised as unhandled
|
|
16
|
+
expect(result.stderr).not.toContain("Unhandled");
|
|
17
|
+
expect(result.stderr).toContain("[lsp] ignored server stdin failure during cleanup: EPIPE");
|
|
18
|
+
expect(result.stdout).toContain("PROBE_SURVIVED");
|
|
19
|
+
expect(result.status).toBe(0);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -56,6 +56,19 @@ export function validateCwd(cwd: string): { valid: boolean; error?: string } {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// The child's pipes outlive every JsonRpcConnection that borrows them: a
|
|
60
|
+
// connection detaches its listeners on dispose, yet a write issued before
|
|
61
|
+
// dispose can still fail later (on Windows a closed pipe reports EPIPE
|
|
62
|
+
// asynchronously). An 'error' event with no listener is raised as an unhandled
|
|
63
|
+
// error, so each pipe keeps this guard for its whole life. It reports only when
|
|
64
|
+
// no other owner is listening, so an attached connection keeps sole reporting.
|
|
65
|
+
function guardPipeErrors(stream: NodeJS.EventEmitter, pipe: string): void {
|
|
66
|
+
stream.on("error", (error: Error) => {
|
|
67
|
+
if (stream.listenerCount("error") > 1) return;
|
|
68
|
+
reportBestEffortCleanupError(`server ${pipe}`, error);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
function wrap(proc: ChildProcess): SpawnedProcess {
|
|
60
73
|
const exitedPromise = new Promise<number>((resolve) => {
|
|
61
74
|
proc.once("close", (code) => resolve(code ?? 0));
|
|
@@ -65,6 +78,9 @@ function wrap(proc: ChildProcess): SpawnedProcess {
|
|
|
65
78
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
66
79
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
67
80
|
}
|
|
81
|
+
guardPipeErrors(proc.stdin, "stdin");
|
|
82
|
+
guardPipeErrors(proc.stdout, "stdout");
|
|
83
|
+
guardPipeErrors(proc.stderr, "stderr");
|
|
68
84
|
|
|
69
85
|
return {
|
|
70
86
|
stdin: proc.stdin,
|
|
@@ -1404,6 +1404,13 @@ function validateCwd(cwd) {
|
|
|
1404
1404
|
};
|
|
1405
1405
|
}
|
|
1406
1406
|
}
|
|
1407
|
+
function guardPipeErrors(stream, pipe) {
|
|
1408
|
+
stream.on("error", (error) => {
|
|
1409
|
+
if (stream.listenerCount("error") > 1)
|
|
1410
|
+
return;
|
|
1411
|
+
reportBestEffortCleanupError(`server ${pipe}`, error);
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1407
1414
|
function wrap(proc) {
|
|
1408
1415
|
const exitedPromise = new Promise((resolve) => {
|
|
1409
1416
|
proc.once("close", (code) => resolve(code ?? 0));
|
|
@@ -1412,6 +1419,9 @@ function wrap(proc) {
|
|
|
1412
1419
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
1413
1420
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
1414
1421
|
}
|
|
1422
|
+
guardPipeErrors(proc.stdin, "stdin");
|
|
1423
|
+
guardPipeErrors(proc.stdout, "stdout");
|
|
1424
|
+
guardPipeErrors(proc.stderr, "stderr");
|
|
1415
1425
|
return {
|
|
1416
1426
|
stdin: proc.stdin,
|
|
1417
1427
|
stdout: proc.stdout,
|
|
@@ -1640,6 +1640,13 @@ function validateCwd(cwd) {
|
|
|
1640
1640
|
};
|
|
1641
1641
|
}
|
|
1642
1642
|
}
|
|
1643
|
+
function guardPipeErrors(stream, pipe) {
|
|
1644
|
+
stream.on("error", (error) => {
|
|
1645
|
+
if (stream.listenerCount("error") > 1)
|
|
1646
|
+
return;
|
|
1647
|
+
reportBestEffortCleanupError(`server ${pipe}`, error);
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1643
1650
|
function wrap(proc) {
|
|
1644
1651
|
const exitedPromise = new Promise((resolve) => {
|
|
1645
1652
|
proc.once("close", (code) => resolve(code ?? 0));
|
|
@@ -1648,6 +1655,9 @@ function wrap(proc) {
|
|
|
1648
1655
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
1649
1656
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
1650
1657
|
}
|
|
1658
|
+
guardPipeErrors(proc.stdin, "stdin");
|
|
1659
|
+
guardPipeErrors(proc.stdout, "stdout");
|
|
1660
|
+
guardPipeErrors(proc.stderr, "stderr");
|
|
1651
1661
|
return {
|
|
1652
1662
|
stdin: proc.stdin,
|
|
1653
1663
|
stdout: proc.stdout,
|
|
@@ -465,6 +465,13 @@ function validateCwd(cwd) {
|
|
|
465
465
|
};
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
|
+
function guardPipeErrors(stream, pipe) {
|
|
469
|
+
stream.on("error", (error) => {
|
|
470
|
+
if (stream.listenerCount("error") > 1)
|
|
471
|
+
return;
|
|
472
|
+
reportBestEffortCleanupError(`server ${pipe}`, error);
|
|
473
|
+
});
|
|
474
|
+
}
|
|
468
475
|
function wrap(proc) {
|
|
469
476
|
const exitedPromise = new Promise((resolve) => {
|
|
470
477
|
proc.once("close", (code) => resolve(code ?? 0));
|
|
@@ -473,6 +480,9 @@ function wrap(proc) {
|
|
|
473
480
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
474
481
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
475
482
|
}
|
|
483
|
+
guardPipeErrors(proc.stdin, "stdin");
|
|
484
|
+
guardPipeErrors(proc.stdout, "stdout");
|
|
485
|
+
guardPipeErrors(proc.stderr, "stderr");
|
|
476
486
|
return {
|
|
477
487
|
stdin: proc.stdin,
|
|
478
488
|
stdout: proc.stdout,
|