Conversation
… glyphs, hook policy and action majors Phase 1 of the Vibe output plan. The default terminal output does not change. - createRenderer resolves one glyph set (emoji | ascii | unicode) and exposes it as renderer.glyphs and renderer.glyphMode. unicode is reachable only through the explicit `glyphs: "unicode"` option and carries no Extended_Pictographic mark. New string builders: table, tree, flow, code, ref, list, phase, close and paint; magenta and blue join the palette; visualWidth, padRight, wrap and wrapBoxed are exported. - visualWidth measures box drawing, arrows and the tick as one cell (real wide ranges, Emoji_Presentation and U+FE0F) instead of everything from U+1100 up as two. - header and verdict wrap long content to the inner width instead of breaking the right border. Content that fits is byte-identical to before, pinned by tests/fixtures/render-fancy-golden.json, generated from develop at 1ac7087. - The three eval headers passed "\\u{1F9EA}" as a literal and printed the escape sequence in emoji mode. - The generated pre-commit hook gates under --policy standard, so a company or high-risk policy in .otitorc.json no longer fails every local commit. - The init workflow template pins actions/checkout, setup-node and upload-artifact at v7, the majors otito-ci.yml runs on, with a drift test.
feat(render): glyph modes, Vibe primitives and box wrapping; fix eval glyphs, hook policy and action majors
…lden snapshots
Phase 2 of the Vibe output plan. Nothing visible changes.
- The ~50 `renderer.emoji ? "…" : "…"` ternaries in context-engine, impact,
pass-local, pass-pr, review, render/route and output.js now read
renderer.glyphs (item, tip, box.arrow, status, verdict) or ask the new
renderer.pick({ emoji, ascii, unicode }) for a one-off decoration, so every
mark follows the glyph mode instead of one boolean (O7). renderer.emoji is
no longer read outside fancy.js; a test scans src/lib to keep it that way.
- otito report builds a renderer from the same --emoji/--color/--theme
preferences every other command honours (O9); the report prints no glyphs
yet, so its output is unchanged.
- tests/fixtures/formatters-golden.json records every terminal formatter's
output for stored input in emoji and ascii modes, with and without colour,
generated by tests/golden/generate-formatters.mjs on the formatters as they
were before this change (O10). tests/formatters-golden.test.js re-renders
the stored input and compares byte for byte.
refactor(render): take every formatter's marks from the glyph set; golden snapshots
… and boxes Phase 3 of the Vibe output plan: the default flips and the shared layers take the Vibe shape. - The default glyph set is unicode: no emoji in an interactive terminal. CI, NO_EMOJI, --no-emoji, emoji: false, the minimal theme and, new, TERM=dumb keep ASCII; --emoji, emoji: true and OTITO_EMOJI=1 opt back into the emoji look. The high-contrast theme keeps its bright palette and stops forcing emoji. TERM=dumb is detected in fancy.js, not in config. - O13: header and verdict content lines are padded to width - 6, so every line of a box is as wide as its borders. Both golden fixtures were regenerated on purpose; in the formatter fixture the bespoke formatters change only in box content lines, two cells narrower, same text. - formatTerminalSummary prints facts as a table under "At a glance", file lists as a tree, other sections as "- " lists, and the closing line last. Writers are verified by the handler that wrote, so formatters stay pure. - renderDocument aligns Markdown tables by padding (O11), only when every row has the same number of cells after honouring \| and code spans, and appends meta.close. printDocument commands pass their closing line. - config list/get, telemetry, deps, structure, attest, dashboard and obsidian print in the shared shape and end with a closing line. - otito help documents --emoji, --no-emoji, --color, --no-color and --theme once, as global flags.
feat(render): plain Unicode by default, closing lines, aligned tables and boxes
…e grade Claude Code delivers a finished background task through UserPromptSubmit, and the route-prompt hook routed it like a request. On 2026-09-27, 79 of the 146 decisions in ~/.otito/route-decisions.jsonl were prompts the harness wrote, matched by hash to the queue records in the transcripts: 75 <task-notification>, 3 <bash-input> and 1 <ci-monitor-event>. isRoutable now returns false for those three. A <system-reminder> in front of a prompt is looked past, because all 22 logged prompts that opened with one had a request behind it. <pasted_content>, <create-pr-command> and <cross-session-message> still route. route-outcomes hashes the harness prompts it finds in each session's user and queue records, leaves decisions with those hashes out of the grade and reports the count. A harness prompt in a transcript is no longer a prompt or a follow-up. The log itself is untouched.
fix(route): skip harness prompts in the hook and leave them out of the grade
…cript
A context pack for bashbop-event-web listed `yarn lint`, `yarn test`,
`yarn test:e2e` and `yarn build` and no type check: its type check is
`tsc:check`, which the harness's fixed script list did not name and whose
reason `name.includes("type") || name === "tsc"` did not match. `otito pr`
had `tsc:check` on its list and dropped it for want of a reason, and the
quality job and pre-commit hook from `otito init` never saw it.
The harness, the PR review and init now share src/lib/package-scripts.js.
A script is a type check when `tsc`, `typecheck`, `type-check` or
`check-types` are whole segments of its name (`tsc:check`, `check:tsc`,
`tsc-check`, `tscCheck`), so `tsconfig:sync` and `prototype` are not.
A package with none of the listed type-check names gets every type check
it defines in the list's type-check slot; one that has one gets the same
list as before. Watch and build variants, and a type check run with
`--watch` or `tsc -w`, are left out.
An end-to-end script gives way to its headless sibling when the package
has one, so event-web's pack lists `yarn test:e2e:headless` instead of
`playwright test --headed`.
fix(harness): list tsc:check-style type checks and the headless e2e script
…okens, list runnable tests only Four ranking defects found reviewing otito's use on bashbop-event-web (2026-09-27), fixed once for context_pack and change_impact in src/lib/ranking-rules.js: - Translation catalogs are demoted (x0.3) unless the request is about copy, wording, i18n or translation, and the locales of one catalog share one entry (`siblings`); folded locales keep the catalog's role. - The extension of a file named in the request no longer scores. - A path or basename named in the request is pinned above unnamed candidates as a required owner; a named symbol pins its exported, imported definition and boosts its other definitions. - Tests and suggested tests list only files a runner executes. contextEngineVersion and impactEngineVersion 3 -> 4. New fixture evals/fixtures/multi-locale-web and retrieval case; the 21 earlier cases are unchanged.
…catalogs-pins # Conflicts: # CHANGELOG.md
fix(ranking): pin named files, fold locale catalogs, drop extension tokens, list runnable tests only
… budget "an MCP tool call reaches a live canvas without waiting on it" asserted elapsed < 900 ms, which timed the whole context_pack dispatch. Under coverage with 64 copies in parallel it failed 6 of 64 runs (911-996 ms) while the canvas tap behaved correctly. A response that waits on the canvas cannot arrive while the send is held: the canvas only replies after release(), so the send settles first, at the latest when the tap aborts it after SEND_TIMEOUT_MS. The test now wraps fetch to record the canvas send's state, with handlers attached before the tap's, and asserts the send is still pending when the response is written. It then releases the canvas and awaits the send, which replaces the 10 ms polling loop before the received assertions. Against a mutant where callTool awaits the send, the test fails with "send failed: TimeoutError". A canvas-side "answered" flag alone passes against that mutant, because release() only runs in t.after.
test(canvas-tap): assert the held send is still pending, not a 900 ms budget
…sleading doctor next-step otito install now prompts a human at a TTY to choose plan/global/link mode, opening with a short pitch (greeting pulled from local git config user.name, no network) on why otito's grounded, deterministic local context is useful. --yes, --json, CI, agents, and any explicit --global/--link stay fully non-interactive, unchanged. Also drops "run otito doctor to verify the install" from install's next steps: doctor never checks the otito binary itself, only unrelated tools (node, git, gh, rg, npx, opensrc, code-structure); the install step already verifies its own binary via commandExists.
feat(install): interactive TTY setup with personalized pitch, drop misleading doctor next-step
…tion, not just headers
bullet() and every formatter that hand-built a line as
`${renderer.glyphs.item} text` (the shared summary, context_pack's
Commands, change_impact's suggested tests/risk hotspots, pass/pass-pr's
context evidence) now dim the marker when colour is on, matching how a
box border is dimmed. Colour off (piped output, NO_COLOR, CI) renders
byte-identical to before.
Regenerated tests/fixtures/render-fancy-golden.json and
tests/fixtures/formatters-golden.json; reviewed the diff, every changed
line is a bullet/item marker gaining \x1b[2m...\x1b[0m and nothing else moved.
Inspired-by-not-copied-from, but the name itself adds nothing a reader needs; reworded the two in-repo mentions to describe what the renderer work actually is instead of naming it.
feat(render): dim list and bullet markers so colour reaches every section
Minor release: renderer colour/tables/glyph-mode primitives, list and bullet items now dim their marker, otito install prompts interactively at a TTY with a personalized pitch. No command, field, or schema removed. CHANGELOG.md: [Unreleased] entries moved under [3.3.0] - 2026-09-27. package.json/package-lock.json bumped via `npm version minor --no-git-tag-version`; server.json, docs/index.md, RELEASE.md and docs/assets/otito-how-it-works.html resynced by the version script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merging develop into main. No version bump — package.json stays 3.2.0 on both sides, so this does not trigger the auto-tag-release workflow or an npm publish.
Notable since the last develop→main merge (#229):
otito installnow prompts interactively at a TTY (plan/global/link) with a short personalized pitch;--yes/--json/CI/agents unaffected (feat(install): interactive TTY setup with personalized pitch, drop misleading doctor next-step #237)Test plan
npm run typecheck/npm run lint/npm test(787/787) all green on develop as of the latest merge