Commit Graph
5 Commits
Author SHA1 Message Date
Tianyi Cui 233032b8f4 fix(experimental): close the mods bridge review findings
- Disposal cancels detached runs before the engine waits for timer callbacks,
  so a callback parked in a $ call ends instead of blocking unload.
- A forgotten band wakes and ends its watch streams; a refresh asked for
  during a pass joins one more pass that settles after it; the Web band drops
  an ended stream so the next subscriber opens a fresh one.
- $ has Claude Code's namespaces: an unserved member rejects with
  'no implementation for <namespace>.<member>' instead of a TypeError.
- A .catch handler's next makes the rewrite check; a tool rename is refused
  like an argument rewrite; a null op answer is reported as no answer;
  defineMod returns its disposer from apply; the live turn record is copied
  before the chain freezes it; prompt.submit is raised only for batches with
  a human message and names the submitting mod as origin.
- $.http.fetch bounds the body while streaming; bandColumns/bandRows are
  Config; the client package drops its stale gateway edges; the source
  overlay lives in the package and anchors its entries to the file, and the
  dsh installation no longer depends on the experimental packages.
2026-10-03 05:18:32 +08:00
Tianyi Cui 57126d8baf feat(experimental): draw the mods' AbovePrompt band and expose it over a Remote
The bridge keeps one band per session: ui.render is raised through the
mods in load order, the tree's buttons keep their onPress host-side behind
per-drawing action ids, a $.state read during a render subscribes the band
to that slot, and $.ui.open/close/invalidate, the end of a tool.call chain,
and turn.complete redraw it. ClaudeCodeMods is a TypertRemoteService:
watchBand streams snapshots, pressBand runs a button and redraws. null is
an accepted hook answer (a surface drawn empty).
2026-10-03 02:17:21 +08:00
Tianyi Cui f1715c67ec refactor(experimental): make mods DSH plugins and drop the persistence change
A mod is now a plugin built with defineMod() around its register(on,
options); the bridge is the ClaudeCodeMods service (ctx.claudeCodeMods)
that keeps the loaded mods and raises their events. The plugin.json /
hooks.json loader, pluginDirs, and dynamic imports are gone.

prompt.submit context becomes text blocks appended to the human's own
prompt message and $.prompt.submit queues a user-sourced message, so the
bridge adds no message source kind: the persistence record and the
regenerated schema are removed and the artifacts match master again.

Engine correctness from the review round: next() is memoized and every
started run beneath is awaited before a hook's answer settles; a rewritten
tool argument skips the hook with a report pointing at the pre-tool input
rewrite proposal; timers belong to the session whose event started them;
$.tool.call injects a tool's deferred contexts; $.clock.sleep honors the
event signal; a built-in tool answered with { result } is validated against
its output schema before it becomes an error-shaped result; hooks on events
this host never raises are reported at load.

Examples: the three mods from the Claude Code blog post under examples/,
Token Weather and its test unchanged, Blast Radius and Replay Theater
completed from the published fragments, run by their own tests through a
claude-code/testing alias over the new test kit ($.ui.mount/find/press).
2026-10-03 01:38:21 +08:00
Tianyi Cui 600034d653 fix(experimental): harden the mods bridge after review
- prompt.submit sees and rewrites only the human's own messages, gains the
  rewritten text on an image-only prompt, and keeps only typed result fields
- a mod's $.tool.call reaches only the mods loaded before it, attributed to
  the caller, instead of re-entering every mod through the pipeline
- a .catch handler shares the failed hook's beneath state so nothing beneath
  runs twice; a late next from an abandoned handler is ignored
- hook results are validated before use; detached runs report rejections
- session.end keeps $.state readable until its hooks settle; agent creation
  cancellation abandons a waiting session.start hook; agents is read lazily
- a success a hook marks isError becomes a failure; replacement entries clear
  on tools/result; per-agent registrations drop with the agent
- $.store writes are serialized per plugin and bounded in UTF-8 bytes;
  $.http.fetch bodies are bounded; timers refuse rescheduling after unload
  and unload awaits running callbacks; regex matchers reset lastIndex
2026-10-02 13:18:17 +08:00
Tianyi Cui 35873604ad feat(experimental): add Claude Code mods bridge
Add @deepseek-ai/dsh-experimental-claude-code-mods, an alpha bridge that
loads Claude Code mods (plugin directories whose hooks/hooks.json names a
hooks module), runs register(on, options) unchanged, and raises the mod
events from harness extension points: session.start on agent/created,
prompt.submit and turn.start on agent/pre-step, tool.call around
tools/execute, turn.complete on turn/end, session.end on agent/disposed,
and command.run from registered commands. The $ mods API is served over
composed services (commands, tools, user-questions, fs, subprocess,
storage domain, projections); unserved members fail by name.

Includes a middleware chain with Claude Code's failure rules and budget
clock, a claude-code/testing-style test kit, fixtures from the mods
tutorial, full-loop and Loader composition tests, the attribution-only
claude-code-mods message source with its persistence record, and the
regenerated catalogs.
2026-10-02 11:10:41 +08:00