Commit graph

5 commits

Author SHA1 Message Date
patriceckhart
8cd8410ace Use ASCII ellipses throughout 2026-05-22 17:19:29 +02:00
patriceckhart
a5fad05fa3 docs(ext): refresh examples and help text
Adds the todo panel example under examples/extensions, updates example manifests and READMEs to match the current extension API, and surfaces extension install/load commands in zot --help.
2026-04-22 20:50:55 +02:00
patriceckhart
83b64e2562 examples: scratchpad notes persist to .zot/scratchpad-notes.jsonl
Notes are now project-local and survive zot restarts. The
extension reads its cwd from the hello_ack handshake, then:

  - on /note    appends one line of {"at":..,"text":..} JSONL
                under <cwd>/.zot/scratchpad-notes.jsonl
  - on /notes   reads the in-memory cache (loaded on hello_ack)
  - on /clear-notes truncates the file and clears the cache
  - on read_notes (tool) returns the cached set

Single-writer assumption (one zot session per cwd at a time);
two concurrent zot processes writing to the same file would
interleave but JSONL line boundaries stay intact under POSIX
PIPE_BUF semantics. Good enough for an example.

Verified end-to-end: round 1 writes two notes via the slash
command, round 2 (fresh extension process, same cwd) loads
them and surfaces them via both /notes and the read_notes
tool.
2026-04-19 15:16:06 +02:00
patriceckhart
619ed587cd perf(extensions): parallel discovery + auto-ready idle watchdog
Three independent fixes to startup latency:

1) Discover spawns extensions in parallel.
   Before: each spawn synchronously waited on its child's hello
   frame; multiple slow runtimes (e.g. tsx) added linearly.
   After: every loadOne runs on its own goroutine; total time
   collapses to max(spawn_time) instead of sum.

2) WaitForReady waits in parallel.
   Before: one extension at a time, so a slow ready (or no ready
   at all from a legacy SDK) blocked every other extension's wait
   too.
   After: one goroutine per extension, all sharing a single
   deadline; total = max(per-ext wait), not sum.

3) Auto-ready idle watchdog for legacy extensions.
   Phase-1 SDK builds didn't send the ready sentinel introduced
   in phase 2. Without it, WaitForReady burned the full 3s grace
   on every startup for every legacy extension. Fix: read loop
   stamps lastFrameTime on each frame; a per-extension watchdog
   closes readyCh as soon as no new frame has arrived for 250ms.
   Native binaries register + go quiet within microseconds, so
   this fires almost immediately. Newer extensions still trip
   the explicit ready path before the watchdog matters.

Also updates the scratchpad example to invoke `tsx` directly
instead of `npx --yes tsx`, with the README explaining how to
install tsx globally and how to fall back to npx (and what it
costs in startup time).

Measured impact on a machine with 4 extensions installed
(guard / hello / weather / scratchpad):

  before: 4.2-4.9s per zot launch
  after:  ~200ms per zot launch (cold-cache first run ~780ms)

The dominant remaining cost in the 200ms is normal node + tsx
boot for scratchpad, which only matters because it's still in
the spawn fan-out — Go extensions add nothing measurable.
2026-04-19 15:13:19 +02:00
patriceckhart
5dbbcb9040 feat(extensions): typescript example + path-aware exec resolution
examples/extensions/scratchpad: real .ts (not .js) extension, no
build step, no SDK. Runs via `npx --yes tsx index.ts` so authors
can use TypeScript without forcing a global install. Demonstrates:

  /note <text>   slash command (typed CommandResponse)
  /notes         slash command (display action)
  /clear-notes   slash command
  read_notes     LLM-callable tool (typed ToolResult)

Plus a typed wire-format subset inline so the file shows what the
protocol actually looks like from the consumer side. Pure node +
tsx, zero npm deps beyond tsx itself (~5 MB cached on first call).

Manager fix: extension exec paths are now resolved by shape:

  absolute               used as-is
  starts with ./ or ../  joined to ext.Dir
  contains a separator   joined to ext.Dir (other relative form)
  bare name (no sep)     left as-is so $PATH lookup works

Before this, "exec": "npx" was being looked up at
extensions/scratchpad/npx and failing with a "no such file or
directory" error. With the fix, "node", "npx", "python3", "tsx",
etc. resolve via $PATH like users intuitively expect.

Bumped WaitForReady grace from 500ms to 3s so slow runtimes
(npx tsx cold-start ≈ 1.4s) get their register_tool frames
in before the agent's tool registry is built. Extensions that
send ready quickly still release the wait immediately; the
extra grace only applies to laggards.

Verified end-to-end live against anthropic:
  prompt: "Use the read_notes tool now and tell me what's in the
           scratchpad"
  -> [tool_call] read_notes({})
  -> [tool_result] (scratchpad is empty)
  -> "The scratchpad is empty."
2026-04-19 15:06:00 +02:00