Skip to content

[pull] main from remorses:main#2

Open
pull[bot] wants to merge 455 commits intotrustmedis:mainfrom
remorses:main
Open

[pull] main from remorses:main#2
pull[bot] wants to merge 455 commits intotrustmedis:mainfrom
remorses:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 25, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

@pull pull Bot locked and limited conversation to collaborators Mar 25, 2026
@pull pull Bot added ⤵️ pull merge-conflict Resolve conflicts manually labels Mar 25, 2026
remorses added 26 commits March 30, 2026 22:44
normalizeMarkdown now strips [current git branch is ...] and detached
HEAD warnings. The order of this line relative to user text varies
between local and CI, causing snapshot mismatches.
thread-message-queue: replaced exact snapshot with ordering invariants.
The echo reply and footer interleave non-deterministically on CI.
Now asserts user message ordering + footer presence instead of exact
message sequence.

queue-advanced-question: replaced internal Map polling
(waitForPendingQuestion/waitForNoPendingQuestion) with user-visible
message waits (waitForBotMessageContaining). The internal Map timing
was too sensitive on slower CI hardware. 12s timeout for question
message appearance.
queue-advanced-question text test: replaced exact snapshot + count
assertion with flexible contains checks. On CI, the deterministic
matcher fires a second time on the follow-up turn (rawPromptIncludes
scans full history), causing a duplicate question.

queue-question-select-drain: replaced waitForPendingQuestion Map
polling with visible message wait (12s), then read the Map after the
message is confirmed visible.
Same issue as other question tests — deterministic matcher fires again
on the drained message turn (rawPromptIncludes scans full history),
adding a duplicate question. Use invariant checks instead of exact
snapshot.
The papa reply and footer interleave non-deterministically, same
pattern as the other queue tests fixed earlier.
The root command already accepted --projects-dir to override where new projects
are created, but the `project create` subcommand didn't — so running it
standalone always used the default <data-dir>/projects path.

Now `kimaki project create my-app --projects-dir /custom/path` works as
expected.

Ref #86
Removes the catch-all `'*': 'ask'` rule from both the server-level
config (`externalDirectoryPermissions`) and the session-level
`buildSessionPermissions()`. This was forcing all unknown external
directories to `ask`, overriding whatever the user set in their
project or global opencode.json.

The specific directory allowlists (tmpdir, ~/.config/opencode,
~/.kimaki, project dir, worktree origin) are kept — only the
wildcard default is removed.

Closes #90
Closes #92
…swers the question and does not continue the parent task
Replace the @openauthjs/openauth/pkce import with a ~15-line inline
implementation using Web Crypto API (crypto.getRandomValues + crypto.subtle.digest).

This is the same approach used by the pi-mono ground truth:
https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/utils/oauth/pkce.ts

The @openauthjs/openauth package was only used for generatePKCE(). Inlining it
removes 11 transitive dependencies from the tree.

Note: discord/package.json and pnpm-lock.yaml also have the dependency removal
but are not included in this commit because they contain other unrelated changes.
…us with opusscript, update @libsql/client, marked, domhandler, htmlparser2

Dependency updates across the workspace:

- **Replace js-yaml with yaml (v2.8.3):** yaml is actively maintained, has
  built-in TypeScript types (no @types/ needed), and supports YAML 1.2.
  Updated all 7 source files: yaml.load → YAML.parse, yaml.dump → YAML.stringify.
  Removed @types/js-yaml devDependency.

- **Replace @discordjs/opus with opusscript (v0.0.8):** @discordjs/opus pulls in
  @discordjs/node-pre-gyp → tar (deprecated). opusscript is a pure JS Opus
  implementation via Emscripten — no native bindings, no node-pre-gyp, no tar.
  prism-media auto-detects opusscript as the opus backend (confirmed working).
  Trade-off: ~10x slower encode/decode, but negligible for voice transcription
  where AI/network latency dominates.

- **Update @libsql/client** from 0.15.15 → 0.17.2 across discord,
  discord-digital-twin, opencode-cached-provider, slack-digital-twin.

- **Update marked** from 16.3.0 → 17.0.5

- **Update domhandler** from 5.0.3 → 6.0.1

- **Update htmlparser2** from 10.0.0 → 12.0.0

- **Remove @openauthjs/openauth** (replaced by inline PKCE in anthropic-auth-plugin)
Per-session injection guard JSON files were written to os.tmpdir(), which
can be cleared by the OS at any time and is not guaranteed to persist across
reboots or process restarts.

Move the directory to `<dataDir>/injection-guard/<sessionId>.json` so it
lives alongside other kimaki persistent state. The injection guard plugin
already reads KIMAKI_DATA_DIR from env, so no plugin change needed.

Also skip writing the file entirely when scanPatterns is empty — no reason
to create a JSON file just to store an empty array.
…ion end

When a session went idle, `flushBufferedPartsForMessages` was being called
with `repulseTyping` defaulting to true, which meant every part sent during
the final flush re-armed the 7-second typing pulse — causing the bot to appear
to be typing even after the last assistant message and footer were visible.

Fix by:
- Adding `repulseTyping` param to `sendPartMessage`, `flushBufferedParts`,
  and `flushBufferedPartsForMessages` (default true to preserve existing
  behaviour everywhere except the idle flush path)
- Passing `repulseTyping: false` when flushing parts in the onIdle handler
- Calling `this.stopTyping()` explicitly after the final flush, so the
  indicator drops before the footer message is sent rather than timing out
  naturally after 7 s
The previous tests embedded `[bot typing]` markers directly in
toMatchInlineSnapshot, making them extremely brittle — any change to
typing pulse timing or message ordering would break the snapshot
even if the underlying behaviour was correct.

Replace with explicit positional checks:
- assert `[bot typing]` appears between expected message boundaries
  (e.g. after user clicks permission button, before the footer)
- assert no `[bot typing]` appears after the final footer
- keep a clean snapshot (without showTyping) as the primary message-content
  assertion so golden-value drift is obvious

This is the test-side companion to the stopTyping fix in
thread-session-runtime.ts.
thread-message-queue.e2e.test.ts: the burst-message count checks
(`burstBotMessages.length >= beforeBotCount + 1`) were fragile — they
could pass when interrupted sessions left stray bot messages counted in
the baseline, and were not testing anything the footer/content assertions
don't already cover. Removed.

queue-question-select-drain.e2e.test.ts: add an early throw after the
`expect(pending).toBeTruthy()` check so TypeScript knows `pending` is
non-null for the rest of the test, eliminating the implicit nullable access.
- **Remove undici from package.json:** undici resolves to discord.js's
  bundled v6 at runtime. Added src/undici.d.ts with minimal type declarations
  for setGlobalDispatcher and Agent (used for SSE connection pooling).

- **Remove @sentry/node:** was effectively a no-op (guarded by
  KIMAKI_SENTRY env var that's never set). Rewrote sentry.ts as stub
  exports so 20+ files importing notifyError/initSentry/AppError continue
  to compile unchanged. Removes 56 transitive dependencies.

- **Move @types/ws to devDependencies:** types packages belong in dev.
When a user sends a new message while an ask-question select is still pending, treat that message as a normal follow-up instead of trying to answer the question from raw Discord message content. This avoids consuming voice-message text content before transcription runs and keeps the session input aligned with what the user actually said.

Update the existing queue-advanced question e2e to inspect session.messages() directly, reproducing the bug with a voice message that also carries Discord text content and asserting that the model receives the transcription rather than the raw message text.
Anthropic OAuth plugin now supports storing multiple accounts and
automatically rotating to the next one on rate-limit (429) or auth
failures (401/403).

New internals:
- AccountStore persisted at ~/.local/share/opencode/anthropic-oauth-accounts.json
- rememberAnthropicOAuth() called after every successful OAuth login
- shouldRotateAuth() detects rate-limit and auth errors from response
- rotateAnthropicAccount() switches to next account and updates auth state
- removeAccount() with proper promotion of next active account
- pendingRefresh changed from single Promise to Map keyed by refresh token
  so concurrent refreshes for different accounts don't collide
- Request retry: on rotation-eligible failures, rotate account, refresh
  token, and retry the request once before returning the error response

New CLI commands (hidden):
- kimaki anthropic-accounts list — show stored accounts with active marker
- kimaki anthropic-accounts remove <index> — remove account from rotation pool

File-lock based concurrency via withAuthStateLock() (renamed from
withAuthRefreshLock) protects both token refresh and account store writes.
errore convention: catch blocks should create typed Error instances with
`{ cause: e }` instead of casting the unknown catch value with `as Error`.
This preserves the original stack trace in the cause chain and gives each
error site a descriptive message for debugging.

Files updated:
- hrana-server.ts: SIGTERM/SIGKILL error handling in evictExistingInstance
- voice-handler.ts: thread rename failure after voice transcription
- worktrees.ts: git checkout/branch-delete cleanup in mergeWorktree
- thread-session-runtime.ts: scheduled task session start source persistence
- thread-message-queue: additional footer line in ordering test
- unnest-code-blocks: checkbox duplication in task list fenced code test
remorses added 30 commits April 19, 2026 16:08
Refresh the synced tuistory, profano, and zele skills from their source repos so the local skill catalog matches the latest upstream guidance. This updates the usage rules and source-of-truth references agents should follow before using those tools.

Session: ses_259b9e277ffeXi82xFVbnpkodv
Update the user-facing tuistory guidance across skills, docs, and runtime prompt content so background-process instructions consistently use bunx-based tuistory commands and explicitly start with `bunx tuistory --help`. This keeps the recommendations aligned with the real workflow I validated in-session: tuistory handled launch, wait, read, snapshot, session listing, and shutdown correctly for a long-running server, while the website dev failures came from the website process itself rather than tuistory.

Session: ses_259b9e277ffeXi82xFVbnpkodv
Stop rewriting .dev.vars during website local development by switching the dev script from Doppler mount mode to direct environment injection. This keeps Cloudflare/Vite from watching a file that changes under its feet, which removes the restart storm and the follow-on JSON parse, fetch, and websocket noise seen during startup and tuistory validation.

Session: ses_259b9e277ffeXi82xFVbnpkodv
…atterns

Add a new section to the goke skill covering interactive prompts with @clack/prompts:

- Basic usage for select() and confirm()
- **IMPORTANT** callout: always guard with process.stdin.isTTY — clack hangs or
  renders garbage in non-TTY (agent/CI) environments
- Select prompts pattern: mirror every select as a CLI option (e.g. --method)
  so agents can pass the choice directly; in non-TTY without the option, exit
  with a clear error telling the user how to rerun non-interactively
- Confirm prompts pattern: use --force to skip; exit with error in non-TTY
  without --force instead of silently proceeding or hanging

Session: ses_25450370cffeDCwfAP9b7xFXmv
Render callout accent blocks as Discord Components V2 containers so important sections stand out visually in bot replies.
This also lets callouts recursively include existing markdown table rendering and HTML-backed action buttons, and updates the system prompt with color-coded examples for warnings, TODOs, tool failures, gist summaries, and action-required notes.

Session: ses_254441211ffeECObWN50mCZmTZ
Keep the callout instructions concise by listing the recommended accent color for each use case instead of embedding a full example for every item.
This makes the prompt easier to scan while preserving the guidance for warnings, TODOs, tool failures, gist summaries, and action-required notes.

Session: ses_254441211ffeECObWN50mCZmTZ
… identity block

Previously sanitizeAnthropicSystemText used process.cwd() to re-inject the
<environment><cwd> tag after stripping the OpenCode identity block. This is
the opencode server's cwd, which is wrong for multi-session and worktree
setups where each session operates in a different directory.

Now we extract the cwd that OpenCode already embedded in the identity block
(<cwd>/path</cwd>) before stripping it, preserving the correct per-session
directory. Falls back to process.cwd() only if the tag is missing.

Also adds a soft cwd guidance line so agents understand they should scope
file operations to their session directory.

Session: ses_24b4ebd47ffeag1cbc6epwzN5n
Explain that Kimaki's custom <callout> block should be preferred over semantic HTML like <aside> when the goal is a visually highlighted warning or summary. Add copyable examples for gist, action-required, and command-failure boxes so models have clearer patterns to imitate.

Session: ses_24ac6f350ffeRts2bQy2t9klqF
Introduce a dedicated /fork-subagent command that lists recent task child sessions from the parent event log, showing the subagent name alongside the task description so the newest subagent runs are easy to inspect.

When selected, the command forks the full child session into a new Discord thread and replays the complete conversation, including the initial user prompt, so the forked thread preserves the original task context and can be continued directly.

Session: ses_24acad3baffebANhHsbwbpFNSf
The system prompt drift plugin emitted large diff-based toasts that were mirrored into Discord threads. Those messages could exceed Discord's 4000 character limit and fail with Invalid Form Body, so the simplest fix is to remove the plugin entirely.

Session: ses_24a6f5624ffeZ01uvUufTXgg0W
Refresh the vendored skill instructions so local guidance matches the latest source repositories for goke, npm-package, tuistory, and zele.

Session: ses_249b08d4affeBgEpOYM9zDi6l0
Restore the goke skill guidance for interactive @clack/prompts flows so agents keep the non-TTY option and force patterns when working on goke CLIs. Update zele and the traforo submodule pointer so the docs consistently point to tuistory instead of tmux where that workflow is now preferred.

Session: ses_249b08d4affeBgEpOYM9zDi6l0
Move the tracked bundled skills to the repository root and keep cli/skills as a generated publish artifact so the npm package still ships the same files without relying on a symlink. Update skill discovery, build scripts, docs, and ignore rules so local development uses root skills while build and prepublish copy them into the CLI package.

Session: ses_249b08d4affeBgEpOYM9zDi6l0
Replace the dedicated prepare-skills TypeScript helper with a package.json script so the build stays simple while still copying root skills into cli/skills before generate and publish.

Session: ses_249b08d4affeBgEpOYM9zDi6l0
Remove the extra bundled-skills helper and go back to the simple runtime assumption that cli/skills is present. Update sync-skills to write both the canonical root skills folder and the packaged cli/skills copy so runtime lookup stays simple while the repo keeps the root source of truth.

Session: ses_249b08d4affeBgEpOYM9zDi6l0
Adds remorses/sigillo to the sync-skills source list and copies the
SKILL.md into skills/. The skill loads whenever working with sigillo
secrets management, sigillo run/setup/login, or integrating Sigillo
into CI/Cloudflare/Docker/Vercel deployments.

Session: ses_2495a57abffeLYHpoc51Ef1DwE
Session: ses_246b5ad04ffepQI798QgRV8zcb
The orphaned opencode leak comes from hard-killing kimaki before its cleanup handlers can stop child processes. Give the existing instance a 6 second SIGTERM grace period and stop escalating to SIGKILL so shutdown can finish normally instead of leaving detached children behind.

If the old process is still around after the grace period, log it and let the next startup attempt handle the retry instead of force-killing the tree. This keeps the change minimal while directly addressing issue #110.

Fixes #110

Session: ses_2452a2131ffe3M4X8tauZupjGe
Instead of sleeping a fixed 6 second grace period, poll the old process once per second and stop as soon as it exits. This keeps startup fast when shutdown is quick while still avoiding SIGKILL and giving cleanup handlers time to stop child processes.

Raise the poll request timeout from 500ms to 2000ms so a shutting-down instance has enough time to answer before being treated as gone.

Session: ses_2452a2131ffe3M4X8tauZupjGe
Reuse the same assistant-only replay path as /fork so forked subagent threads render the existing Discord message style instead of injecting synthetic user or assistant section headers.

This also removes the extra blank-line-per-tool output by dropping the custom full-session formatter and falling back to the same chunking logic used by normal forked session previews.

Session: ses_24acad3baffebANhHsbwbpFNSf
formatPart was prepending ⬥ to text starting with <callout because < was not
in the markdown starters list. This broke splitTablesFromMarkdown which expects
the line to start with <callout to parse it as a Discord Container component.

Added /^<callout[\s>]/i to the startsWithMarkdown check so callout blocks get
the newline prefix (same as headings) instead of ⬥, letting the callout parser
recognize them correctly.

Session: ses_243c2e017ffe5odQihPiwkdKOp
… system prompt format

OpenCode changed the system prompt environment block from
<environment><cwd>/path</cwd></environment> to <env>\nWorking directory: /path\n</env>.

The old regex only matched the <cwd> XML tag, so project directory extraction
was silently falling back to process.cwd() (the opencode server cwd), which is
wrong for multi-session/worktree setups.

Now tries "Working directory:" first, falls back to <cwd> for older versions.

Session: ses_24184b46cffeQISyqDv45aPS0I
Subagent sessions (Task tool) use a different prompt structure than main
sessions. They don't contain the OPENCODE_IDENTITY marker ("You are
OpenCode...") or the ANTHROPIC_PROMPT_MARKER ("Skills provide...").
Instead, opencode appends "You are powered by the model named ..." plus
an <env> block directly after the custom agent prompt.

The sanitizeAnthropicSystemText function now handles both patterns:

1. Main session: strip from OPENCODE_IDENTITY to ANTHROPIC_PROMPT_MARKER
2. Subagent: strip from "You are powered by the model named" to </env>

Both paths share a new replaceBlockWithCompactEnv helper that extracts
the working directory and replaces the stripped block with a compact
<environment><cwd>...</cwd></environment> tag.

Session: ses_23ed55f3affeViG9ga7maSfluf
Session: ses_23ece6322ffewLgIA8U8dQIvT3
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

⤵️ pull merge-conflict Resolve conflicts manually

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant