Skip to content

chore(deps): Bump actions/upload-artifact from 5 to 7 in /.github/workflows#4

Open
dependabot[bot] wants to merge 2847 commits into
mainfrom
dependabot/github_actions/dot-github/workflows/actions/upload-artifact-7
Open

chore(deps): Bump actions/upload-artifact from 5 to 7 in /.github/workflows#4
dependabot[bot] wants to merge 2847 commits into
mainfrom
dependabot/github_actions/dot-github/workflows/actions/upload-artifact-7

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 23, 2026

Copy link
Copy Markdown
Contributor

Bumps actions/upload-artifact from 5 to 7.

Release notes

Sourced from actions/upload-artifact's releases.

v7.0.0

v7 What's new

Direct Uploads

Adds support for uploading single files directly (unzipped). Callers can set the new archive parameter to false to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The name parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.

ESM

To support new versions of the @actions/* packages, we've upgraded the package to ESM.

What's Changed

New Contributors

Full Changelog: actions/upload-artifact@v6...v7.0.0

v6.0.0

v6 - What's new

[!IMPORTANT] actions/upload-artifact@v6 now runs on Node.js 24 (runs.using: node24) and requires a minimum Actions Runner version of 2.327.1. If you are using self-hosted runners, ensure they are updated before upgrading.

Node.js 24

This release updates the runtime to Node.js 24. v5 had preliminary support for Node.js 24, however this action was by default still running on Node.js 20. Now this action by default will run on Node.js 24.

What's Changed

Full Changelog: actions/upload-artifact@v5.0.0...v6.0.0

Commits
  • 043fb46 Merge pull request #797 from actions/yacaovsnc/update-dependency
  • 634250c Include changes in typespec/ts-http-runtime 0.3.5
  • e454baa Readme: bump all the example versions to v7 (#796)
  • 74fad66 Update the readme with direct upload details (#795)
  • bbbca2d Support direct file uploads (#764)
  • 589182c Upgrade the module to ESM and bump dependencies (#762)
  • 47309c9 Merge pull request #754 from actions/Link-/add-proxy-integration-tests
  • 02a8460 Add proxy integration test
  • b7c566a Merge pull request #745 from actions/upload-artifact-v6-release
  • e516bc8 docs: correct description of Node.js 24 support in README
  • Additional commits viewable in compare view

wave-builder Bot and others added 30 commits April 16, 2026 01:45
… (#3224)

The big fix is not spawning a goroutine per process. other fixes are
more minor, but improve the quality and clean up some edge cases.
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.41.0 to
0.42.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/term/commit/52b71d3344c86b384ed34ebf73f1e6f37044fe79"><code>52b71d3</code></a>
go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a
href="https://github.com/golang/term/compare/v0.41.0...v0.42.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/term&package-manager=go_modules&previous-version=0.41.0&new-version=0.42.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from
0.49.0 to 0.50.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/crypto/commit/03ca0dcccbd37ba6be80adf74dde8d78a4d72817"><code>03ca0dc</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/crypto/commit/8400f4a938077a7a7817ab7d163d148e371b320b"><code>8400f4a</code></a>
ssh: respect signer's algorithm preference in
pickSignatureAlgorithm</li>
<li><a
href="https://github.com/golang/crypto/commit/81c6cb34a8fc386ed53293cd79e3c0c232ee7366"><code>81c6cb3</code></a>
ssh: swap cbcMinPaddingSize to cbcMinPacketSize to get encLength</li>
<li>See full diff in <a
href="https://github.com/golang/crypto/compare/v0.49.0...v0.50.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
lots of updates for tsunami and builder window:
* jsfuncs
* devtools windows
* devtools proper cleanup (fixes crashes)
* scrollbar fixes
* lock AI models -- gpt-5.4, builder prompts, etc
- package.json / electron-builder.config.cjs: name, productName,
  appId, author, homepage, macOS Info.plist permission prompts.
- pkg/wavebase, emain/emain-platform: data dir namespace switches
  from waveterm[-dev] to weft[-dev], Electron app.setName now "Weft".
- pkg/wconfig/defaultconfig/settings.json: telemetry and autoupdate
  default to off; web:defaulturl points to the fork.
- pkg/wcloud: endpoint constants emptied, empty endpoint in dev no
  longer returns an error so no remote call is ever attempted.
- Taskfile.yml: drop WCLOUD_* env vars from dev tasks.
- User-visible log/dialog strings ("Wave" -> "Weft").

Keeps the Go import path github.com/wavetermdev/waveterm untouched
to avoid a repo-wide refactor; that can happen separately later.
- pkg/util/shellutil, pkg/blockcontroller, cmd/test-conn: TERM_PROGRAM
  env var that Weft sets in spawned shells is now "weft" (no inbound
  consumers of the old value exist in-tree).
- cmd/test-conn/testutil.go: fall-back config/data dir paths for the
  test harness use "weft[-dev]" to match the main app.
- frontend/app/onboarding/fakechat.tsx: sample log paths in the
  onboarding chat updated to the new weft-dev location.
- package-lock.json: regenerated so the lockfile name matches package.json.
GitHub repo was renamed from s-zx/waveterm to s-zx/weft, so every
link surfaced to the user gets updated in one pass:

- package.json homepage, pkg/wconfig/defaultconfig/settings.json
  web:defaulturl, pkg/wcore/layout.go default web block URL.
- frontend/app/modals/about.tsx: GitHub / website / acknowledgements
  buttons in the About modal.
- frontend/app/onboarding/{onboarding,onboarding-starask,
  onboarding-upgrade-minor}.tsx: every "star us on GitHub"-style
  link plus the visible "(wavetermdev/waveterm)" label.
- BUILD.md clone example.

Go import paths (github.com/wavetermdev/waveterm/...) and the
marketing text in README*.md / RELEASES.md are intentionally left
alone — those are separate from the URL-visibility cleanup.
Foundation for the Warp-style block UI (M1.1 step 1):

- db/migrations-wstore/000012_cmdblock.{up,down}.sql creates a flat
  table `db_cmdblock`. Each row records one shell-command lifecycle
  (OSC 16162;A through D) tied to its parent terminal block.
- pkg/cmdblock/types.go defines CmdBlock with state + command meta +
  offsets into the parent blockfile. Output bytes are NOT duplicated
  here — we only remember where in the existing BlockFile_Term each
  command's stdout lives so the frontend can replay a slice.
- pkg/cmdblock/store.go exposes MakePromptStarted, MarkCommandSubmitted,
  MarkCommandDone, GetByBlockID, LatestForBlock, DeleteByBlockID built
  on the existing wstore.WithTx / TxWrap API used by the rest of the
  codebase.

No call sites wired up yet; the parser + shellcontroller hook lands
in the next commit once this migration is confirmed to apply cleanly
against a weft-dev database.
The parser state-machine scans PTY byte chunks for ESC]16162;<cmd>[;json]<ST>
sequences and emits one Event per completed sequence.  Partial sequences are
retained across Feed() calls so a terminator split across reads is handled
correctly.  Absolute stream offsets are preserved so downstream code can align
events to byte ranges in the parent blockfile.

parser_test.go covers:
- BEL and ESC-backslash terminators
- JSON payload extraction
- Split-across-feed boundaries
- Multiple events in a single chunk
- Ignoring OSC 7 / other OSC numbers
- Bounded memory on malformed input (no terminator arrives)
- Offset accumulation across multiple chunks
pkg/cmdblock/tracker.go translates parser events into store calls,
keeping the OID of the in-flight cmdblock per shell session.
pkg/blockcontroller/shellcontroller.go creates a Tracker alongside
the PTY read loop and calls OnBytes after every successful
HandleAppendBlockFile, so every chunk that reaches the blockfile
also feeds the OSC 16162 parser.

Verified end-to-end against a fresh weft-dev DB:
- shell startup produces seq=1 state=prompt with a valid offset
- running `ls` flips it to state=done with exit 0, duration 14ms,
  and cmd/output offsets pointing at the right byte ranges in
  BlockFile_Term
- seq auto-increments across consecutive commands in the same block
To break a package cycle (wshrpc -> cmdblock -> wstore -> filestore ->
wshrpc), the CmdBlock struct moves into a new leaf package
pkg/cmdblock/cbtypes. The cmdblock package keeps the store/parser/
tracker code and re-exports the type + state constants so existing
callers compile unchanged.

- pkg/cmdblock/cbtypes/types.go: leaf package with the wire type.
- pkg/cmdblock/types.go: type alias + constant re-exports.
- pkg/wshrpc/wshrpctypes.go: new GetCmdBlocksCommand + request type,
  returns []*cbtypes.CmdBlock.
- pkg/wshrpc/wshserver/wshserver.go: handler delegates to
  cmdblock.GetByBlockID.
- cmd/generatego/main-generatego.go: add cbtypes to the import list
  consulted by the generator so the generated wshclient.go compiles.
- frontend/types/gotypes.d.ts, frontend/app/store/wshclientapi.ts,
  pkg/wshrpc/wshclient/wshclient.go: regenerated via task generate.

Verified end-to-end: dev rebuild is green, existing cmdblock rows
persist across the rebuild, and new prompts continue to land as
state=prompt rows for both live terminals.
Bug observed against a real shell: hitting Enter on an empty prompt
still triggers the precmd path in zsh/bash/fish, which sends a new
OSC 16162;D carrying the previous exit code and then a fresh A. The
tracker was finalizing the existing state=prompt row into state=done
with no cmd, flooding the list with empty "DONE exit 0 0ms" noise.

- pkg/cmdblock/store.go: MarkCommandDone now checks the current
  state; if still "prompt" (no C ever fired), it deletes the row
  instead of updating it, so empty enters leave no trace.

First cut of the frontend view:

- frontend/app/view/termblocks/{termblocks.tsx,termblocks.scss} —
  new view type that polls GetCmdBlocksCommand every 1.5s and
  renders the rows as a scrolling list with #seq badge, state,
  shell, exit code, duration, cmd, and the raw prompt/cmd/output
  byte offsets.
- frontend/app/block/blockregistry.ts: register "termblocks" so
  `wsh setmeta view=termblocks` on any terminal block flips it into
  the new visualizer.

Verified end-to-end against the running app with 18 real commands:
rows render, exit-code badges color-code red/green, offsets match
the blockfile. xterm per block is still on the roadmap — this is
text-only for now.
- pkg/wshrpc/wshrpctypes.go + wshserver/wshserver.go: add
  ReadBlockFileRangeCommand(blockid, name, offset, size) ->
  {offset, data64}.  Thin wrapper over filestore.WFS.ReadAt.
- cmd/generatego + generated bindings regenerated.
- frontend/app/view/termblocks/termblocks.tsx: for every done row
  with output offsets, fetch the byte range, base64-decode, strip
  CSI/OSC escape sequences with a cheap regex, and render under
  the cmd line as a <pre>.  Cache results per oid so the
  1.5s poll doesn't refetch finished blocks.
- Temporary "Back to Terminal" button in the header so a block
  that ends up with view=termblocks persisted across restarts
  can still be escaped without an external workaround.

Next: xterm.js per block (real ANSI) + bottom input composer.
- Filter state==="prompt" out of the displayed list; those rows are
  the anchor the next OSC C attaches to, not a user-meaningful
  command yet.  Keeps them in the DB, just not in the UI.
- Stash the scroll container in a ref and jump scrollTop to
  scrollHeight when the last visible block's oid changes, so
  pressing Enter in the input actually brings the new output
  into view instead of leaving it below the fold.
Backend:
- pkg/cmdblock/cbtypes: new CmdBlockChunkEvent type.
- pkg/wps/wpstypes: Event_CmdBlockRow + Event_CmdBlockChunk constants,
  registered in AllEvents.
- pkg/tsgen/tsgenevent: wired both events to their reflect types so
  the generated TS unions know about them.
- pkg/cmdblock/tracker: tracks the current row's state so it can
  emit cmdblock:chunk for every PTY chunk that lands while the row
  is "running". Also publishes cmdblock:row on A/C/D so every row
  transition reaches the frontend within one WebSocket round-trip.
- pkg/cmdblock/store: add internal getByOID helper so tracker can
  refetch a row after a store mutation and publish the final shape.
- Regenerated bindings.

Frontend:
- frontend/app/view/termblocks/termblocks.tsx: subscribe to both
  events scoped to the parent block id. applyRow merges/appends
  into the list atom; applyChunk appends to the per-oid Uint8Array
  cache so xterm can keep growing in place. Poll interval slowed
  to 10s as a safety net.
- XtermOutput rewritten to mount the Terminal once and write only
  the new byte tail on each bytes change, so live chunks keep the
  same xterm instance (previous version disposed/recreated on every
  frame which would have flickered and lost scroll position).
- Ctrl-C while the input is focused now sends a raw 0x03 to the
  PTY and clears the input box (Cmd-C on macOS is untouched so
  copy-selection still works).
- New little ⊗ button next to the input sends the same interrupt,
  so a stuck `less` / runaway loop can be killed by clicking too.
- Model gains a thin sendBytes helper that both submitInput and
  sendInterrupt go through.
Backend:
- cbtypes: new CmdBlockAltScreenEvent (blockid, oid, enter).
- wps: Event_CmdBlockAltScreen registered.
- tsgen: wired to cbtypes.CmdBlockAltScreenEvent.
- tracker.go: detectAltScreen scans each PTY chunk for
  DECSET/DECRST 1049 (ESC[?1049h / l) and publishes the
  transition.  Uses LastIndex to pick the dominant toggle when
  a chunk contains both sequences.

Frontend:
- AltScreenXterm: full-height interactive xterm (stdin enabled,
  cursor blinks, onData -> model.sendBytes) with a ResizeObserver
  so fit tracks the container.  onData routed through a ref so
  the Terminal is created exactly once.
- termblocks.tsx: subscribe to cmdblock:altscreen.  When the atom
  is non-empty, swap the block list for a single AltScreenXterm
  bound to the currently running block; on exit, fall back to the
  list automatically.
- Matching SCSS for the full-bleed alt-screen container.

Header still shows "Back to Terminal" so a wedged TUI is always
recoverable even if the exit sequence never arrives.
The alt-screen early return sat between the hook calls at the top
of the component and the useMemo/useEffect lower down, so swapping
into or out of alt mode produced a "Rendered fewer hooks than
expected" error.  Move all hook calls above the conditional return
and let the scroll effect short-circuit when inAltScreen is true.
vim (and any other curses app) reads the PTY's TIOCGWINSZ to know
how big the screen is.  Until now the alt-screen xterm fit itself
locally but never told the backend, so vim kept drawing against
the stale shell-startup dimensions.  Insert/normal mode redraws
therefore wrote outside the visible area, which showed up as text
"disappearing" on ESC.

- Model gains sendResize(rows, cols) that issues
  ControllerInputCommand with just termsize populated.
- AltScreenXterm now fits, reads term.rows/cols, and pushes them
  via onResize after mount, on every ResizeObserver callback, and
  on xterm's own onResize (font load, etc.).
…nning

Two Warp-parity fixes:

1. The xterm in each finished (or streaming) block rendered its
   cursor as a blinking square, which Warp avoids.  Setting the
   theme's cursor + cursorAccent to transparent makes the cursor
   invisible regardless of whether xterm internally considers
   itself focused.

2. While any block is in the "running" state the bottom row now
   shows a pulsing "Running: <cmd>  ⊗ Stop" panel instead of the
   input, mirroring Warp's behaviour where the input returns only
   after the foreground command exits.  Stop sends SIGINT.
…fault view

Running-block UX (matches Warp):
- Drop the Stop-panel compromise.  While a block is in state=running
  its xterm becomes interactive — disableStdin off, cursorBlink on,
  auto-focused, onData -> sendBytes, onResize -> sendResize.
  Ctrl-C (or q in less, :q in vim, …) therefore flows straight
  through xterm's key handler into the PTY.  The bottom input row
  is hidden entirely during this period and returns when D fires.
- Done blocks keep a fully transparent cursor and additionally
  emit DECTCEM-off before writing bytes, so stray shell prompt
  draws don't reintroduce a blinking square.
- XtermOutput accepts interactive/onData/onResize props to cover
  both modes from one component.

Default view:
- pkg/wcore/layout.go starter layout spawns a termblocks block
  instead of term.
- pkg/wconfig/defaultconfig/settings.json sets
  app:defaultnewblock to "termblocks".
- frontend/app/store/keymodel.ts honors the new default and
  propagates cmd:cwd when the focused block is either term or
  termblocks.

Wipe the weft-dev data dir (or just create a fresh tab) to see
the new starter layout; existing persisted blocks keep whatever
view they were last assigned.
Two fixes aimed at the "input doesn't respond" failure mode:

1. Tracker startup now runs MarkRunningAsInterrupted for its parent
   block id.  Any row left in state=running from a previous weft
   session is finalized as state=done with exit_code=-2 so the
   frontend's "find a running block" check doesn't latch onto a
   zombie and permanently hide the input row.

2. Model implements giveFocus() and keeps a ref to the bottom
   <input>. The block frame calls giveFocus when the block takes
   focus, so clicking anywhere on the block now routes keystrokes
   into the input without needing to click directly on it.
…pawns

Found the "input has no effect" bug: wavesrv only starts the shell
controller when the frontend explicitly asks it to via
ControllerResyncCommand.  The term view does that from
termwrap.resyncController; termblocks had no equivalent, so
controller=shell meta existed without a live PTY and every Enter
went into a void.

Fire ControllerResyncCommand once from the model constructor,
matching the behaviour of the term view.  ⌘T / fresh blocks / and
the long-broken persisted ones all now get a real shell as soon
as the termblocks view loads.
Strip out all the "3 commands · block 20c70eb4 · #seq prompt@N …"
metadata that was useful for debugging but ugly in daily use.

Each row now shows:

  ~/Documents/weft  (0.06s)      -- muted meta: cwd + duration
  ls                              -- bold highlight cmd
  <xterm output flush to the container, no card>

- Cwd resolved per block via cmd:cwd block meta (falls back to empty
  when shell integration hasn't landed OSC 7 yet), shortened to ~
  against the user's home directory pulled from the electron preload.
- Duration uses ms / s / m+s scales.
- Running rows show a pulsing cyan bar on the left edge + a small
  "RUNNING" label; errored rows get a static red bar + "✕ exit N".
- Dropped the container header, the offsets footer, and the row
  state/shell/#seq pills.
Adds a slim pill row at the bottom, pulling context from:
- cmd:cwd block meta (already tracked via OSC 7) — shortened to ~
- new GetGitInfoCommand backend RPC that shells out to git inside
  the cwd (rev-parse, status --porcelain, diff --numstat, rev-list
  for ahead/behind).  Each git sub-call is wrapped in a short
  per-command context so large monorepos don't wedge the RPC.
- pkg/cmdblock/gitinfo.go hosts the LookupGitInfo logic.
- Frontend polls GetGitInfoCommand every 4s + on every cwd change.

Chips: 📁 ~/Documents/weft    main↑1  ±3 files +42 -7
@dependabot dependabot Bot added github_actions Pull requests that update GitHub Actions code dependencies Pull requests that update a dependency file labels May 23, 2026
Jason-Shen2 and others added 20 commits May 24, 2026 00:16
…onRepo

Task #8 of the Option D rearchitecture (agent loop in Electron main).
Wires the crest integration layer on top of the pi source committed
in 2a4945b: pane gets a session via pi's JsonlSessionRepo, the
session is bound to its creation cwd, each send refreshes the system
prompt with the latest pane cwd via a minimal PaneHarness adapter.

Design lock-in
  docs/agent-runtime-architecture.md (397 lines, 10 sections):
    §3 — why pi as foundation and the "pi design wins by default"
          posture (codified after one wrong-shaped runtime.ts iteration)
    §4 — session model + cwd-grouped JSONL storage (warp vs pi compared)
    §5 — pane ↔ session binding via block.meta["agent:session"]
    §6 — pane lifecycle (open / first send / restart / cross-pane)
    §7 — decisions log, 10 entries each with reasoning
    §9 — pi file refs + warp file:line citations

Schema (Go + generated TS)
  pkg/waveobj/wtypemeta.go: AgentChatID dropped, AgentSessionMeta added.
  AgentSessionMeta = {id, createdAt, cwd, path} — structurally a subset
  of pi's JsonlSessionMetadata so round-trip is identity. createdAt is
  camelCase (Y1 exception, doc §7.2); rest of crest stays lowercase
  until task #15 migrates project-wide.
  pkg/waveobj/metaconsts.go regenerated via task generate.

emain/agent integration layer (219 LOC non-test, target was <250)
  sessions.ts (108 lines):
    - getSessionsRepo() — process-wide JsonlSessionRepo singleton
    - createPaneSession(cwd) — mints fresh session, returns metadata
      shape that goes straight into block.meta
    - openPaneSession(metadata) — re-opens by AgentSessionMeta
    - listSessionsForCwd(cwd) — backs the future "resume recent" banner
    - defaultSessionsDir() — mirrors Go's GetWaveConfigDir resolution
  build-system-prompt.ts (40 lines):
    - buildSystemPrompt(SystemPromptInputs) → string
    - Composes base instruction + cwd + git branch + connection +
      last 5 cmds. Called per turn via AgentHarness function-form
      systemPrompt so cwd updates between sends are reflected.
  harness-factory.ts (71 lines):
    - buildPaneHarness({session, model, ...}) → {harness, update(inputs)}
    - The PaneHarness is a 30-line adapter that exposes the env.cwd
      mutation seam pi leaves implicit. NOT a runtime wrapper —
      subscribe/prompt/abort/message storage are direct AgentHarness
      usage. update() refreshes env.cwd + the system-prompt closure
      so warp-style "session stays put, exchange carries latest cwd"
      semantics work.

terminal-view.tsx — chatId persistence reverted to in-memory useMemo
  The earlier persistence path referenced agent:chatid in block.meta,
  which is now removed from the schema. The legacy useChat + Go-backend
  path stays alive until task #12 (usePiChat); in the meantime an
  in-memory UUID is enough.

_spike.ts — rewritten to drive AgentHarness through a real session
  Mints sessions into a tmp dir (does not pollute real config home),
  builds PaneHarness with model + cwd + git, subscribes via
  AgentHarness.subscribe (not .on() — that one is reserved for
  AgentHarness-OWN hooks), runs prompt(), prints event tally + final
  stopReason + persisted JSONL line count.

Tests
  emain/agent/sessions.test.ts — 15 tests:
    - 6 session round-trip cases (mint, header, reopen, list, empty)
    - 1 shape-conformance (AgentSessionMeta ≡ JsonlSessionMetadata)
    - 3 defaultSessionsDir env resolution branches
    - 5 buildSystemPrompt rendering cases (cwd-only, git, connection,
      cmd cap, no-cmds)
  No tests touch LLM providers. Full suite: 126/126 pass (was 111
  pre-#8; +15 here; -16 from the earlier wrong-shaped runtime.test.ts
  that was deleted in the reset).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task #9. Wires the per-pane harness cache + ipcMain handlers + preload
surface so the renderer can talk to the integrated agent runtime
without touching wavesrv. No renderer code consumes this yet —
usePiChat (task #12) is the first consumer.

New: emain/agent-ipc.ts (~210 LOC)
  - harnessCache: Map<sessionPath, PaneHarness>
  - subscriptions: per-(sender, sessionPath) tracking + auto-release
    on sender 'destroyed'
  - registerAgentIpcHandlers() wires:
      handle "agent:create-session"      (cwd) → AgentSessionMeta
      handle "agent:list-sessions-for-cwd" (cwd) → AgentSessionMeta[]
      handle "agent:send"                (opts) → {sessionMetadata}
                                          (returns immediately; prompt
                                           runs in background)
      on     "agent:abort"               (sessionPath)
      on     "agent:subscribe"           (sessionPath)
      on     "agent:unsubscribe"         (sessionPath)
  - Single "agent:event" channel carries {sessionPath, event} —
    mirrors the dir-watch pattern (renderer strings never embed in
    channel names, security per emain-ipc.ts:518 comment).

Wired in: emain/emain-ipc.ts initIpcHandlers() calls
  registerAgentIpcHandlers() before the rest of the init body.

Preload: emain/preload.ts
  - Single ipcRenderer.on("agent:event") dispatcher fans events to
    per-sessionPath callback sets (same shape as dirWatchCallbacks).
  - exposeInMainWorld api.agent namespace:
      createSession(cwd) → Promise<AgentSessionMeta>
      listSessionsForCwd(cwd) → Promise<AgentSessionMeta[]>
      send(opts) → Promise<{sessionMetadata}>
      abort(sessionPath)
      subscribe(sessionPath, callback) → unsubscribe fn

Types: frontend/types/custom.d.ts
  - ElectronApi.agent: matching surface declaration
  - AgentSendOptions: send-payload shape (provider/model/reasoning +
    pane context + optional sessionMetadata)

Send semantics
  send() returns immediately with the resolved sessionMetadata so the
  renderer can write block.meta and begin streaming. The prompt() call
  fires in background; AgentHarness emits the assistant message stream
  + any errors through "agent:event". This matches the architecture
  doc §5.2 + §6.3 contract.

What's NOT in this commit
  - Renderer-side hook (usePiChat) — task #12; the legacy useChat /
    HTTP-to-wavesrv path stays live until that lands.
  - Crest-specific tools — task #10; AgentHarness is built with
    tools: [] for now.
  - Permissions hook — task #11; no beforeToolCall yet.
  - Integration test against an actual LLM — task #14.

Verification
  - tsc --noEmit -p tsconfig.json: 0 new errors in emain/ (58
    pre-existing project-wide).
  - vitest run: 126/126 (no test changes; existing surface intact).
  - npx tsx emain/agent/_spike.ts: imports + harness construction
    still load cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task #11. Replaces the deleted Go pkg/agent/permissions/ posture-and-
rules engine (1500 LOC) with a 50-LOC allowlist + bench-mode bypass on
top of pi's AgentHarness "tool_call" event hook. See
docs/agent-runtime-architecture.md §7.9 for the decision rationale.

What this enforces in v1
  - When allowAll is true (the default and the only value the IPC
    currently sets), every tool call passes. There is no approval UI
    yet, so the agent stays functional and the hook is effectively a
    no-op slot.
  - When allowAll is false + allowedTools provided, only listed tool
    names pass; others get { block: true, reason: '"<name>" is not
    allowed for this session.' }. The reason surfaces as the tool
    result content (inline in the agent block).
  - Bench mode: process.env.CREST_AGENT_BENCH=1 forces allowAll, used
    by the eval harness so test runs aren't gated.

Files
  emain/agent/permissions.ts (~80 lines)
    - PermissionsConfig: { allowedTools?, allowAll? }
    - buildPermissionsHook(config) → ToolCallHook compatible with
      AgentHarness's .on("tool_call", handler) registration.
    - isBenchMode() — reads CREST_AGENT_BENCH from env.
  emain/agent/permissions.test.ts — 8 tests covering allow/block/bench.
  emain/agent/harness-factory.ts — BuildPaneHarnessOptions.toolCallHook
    threads through to harness.on("tool_call", hook).
  emain/agent-ipc.ts — wires the hook in ensurePaneHarness():
    bench → allowAll; else allowedTools from send opts; else
    allowAll (v1 default). SendOptions gains an optional allowedTools
    field for future renderer-side configuration.

Design notes
  - AgentHarness's tool gate is `.on("tool_call", ...)`, NOT the bare
    Agent constructor's beforeToolCall option — the harness emits a
    slimmer ToolCallEvent { toolName, toolCallId, input } and expects
    a ToolCallResult { block?, reason? } back. The hook shape mirrors
    that exactly so we don't add an adapter layer.
  - The interactive "approve this tool call?" UI is a future feature
    (task ~#12.5 or beyond). When wired, the hook will return a
    Promise that resolves after the renderer sends a click. The
    current synchronous Promise path is forward-compatible.
  - Per-tool-args matching (the dropped posture engine's main feature)
    is intentionally NOT in v1. Add when there's a concrete need; the
    rebuilt engine should be a separate file, not woven into this
    permissions stub.

Verification
  - vitest run: 134/134 (was 126; +8 permissions tests).
  - tsc --noEmit -p tsconfig.json: 0 new errors in emain/ (58
    pre-existing project-wide).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task #10 (partial). Six pure-Node tools as pi AgentTool definitions,
wired through agent-ipc.ts buildPaneHarness so the agent can do real
coding work in v1: read files, write files, surgical multi-edit, list
directories, fetch URLs, run shell commands.

Files
  emain/agent/tools/_paths.ts        expandHome + requireAbsolute helpers
  emain/agent/tools/read-file.ts     read_file (parallel, offset/limit)
  emain/agent/tools/write-file.ts    write_file (mkdir -p parent)
  emain/agent/tools/multi-edit.ts    multi_edit (atomic, unique or replaceAll)
  emain/agent/tools/list-dir.ts      list_dir (type-marked, capped)
  emain/agent/tools/web-fetch.ts     web_fetch (Node fetch, 1MB cap, timeout)
  emain/agent/tools/shell-exec.ts    shell_exec (/bin/sh -c, 64KB/stream cap,
                                       SIGTERM-then-SIGKILL on timeout/abort)
  emain/agent/tools/index.ts         getDefaultTools() + DEFAULT_TOOL_NAMES
  emain/agent/tools/tools.test.ts    29 tests (including loopback HTTP for
                                       web_fetch — fully offline & deterministic)

Wiring
  emain/agent-ipc.ts ensurePaneHarness() now passes tools:
  getDefaultTools() to buildPaneHarness. Permissions hook from task #11
  gates the tools (default v1 policy is allowAll, so they're all
  available; a future renderer-side setting can flip to the explicit
  allowlist by passing opts.allowedTools).

What's NOT in this commit (deferred from the original 24-tool scope)
  Tools that need crest-specific renderer / wavesrv state via wshrpc:
    ask_user_question, browser, create_block, focus_block,
    get_scrollback, headless_shell_exec, transfer_to_user
  Tools that need design decisions (auth, sandboxing, sub-agent
  semantics) before porting:
    cmd_history, dangerous, file_tracker, long_running_*, spawn_task,
    todo, write_plan, search (ripgrep dep)
  These are documented as TODO in tools/index.ts and the autonomous
  handoff doc. The 6 we did port cover the minimum viable agent.

Design notes
  - Schemas via typebox (Type.Object/String/Number/Optional/Array) —
    matches pi's harness/types.ts convention. Static<typeof schema>
    drives the execute() params type.
  - All tools require absolute or ~-prefixed paths to avoid ambiguity
    with the harness env's cwd (which is the pane cwd at harness
    construction time, not at tool-call time).
  - Output bytes are capped per-tool (read_file by lines via
    offset/limit, list_dir maxEntries, web_fetch 1MB, shell_exec
    64KB/stream) so a runaway tool doesn't blow the LLM context.
  - shell_exec is executionMode: "sequential" to avoid concurrent
    state-mutating shell commands within one assistant turn; other
    tools are "parallel" where harmless.
  - web_fetch tests spin up a loopback http.Server on a random port
    rather than mocking fetch — same code path the real tool uses
    against any URL, no network needed for CI.

Verification
  - vitest run: 163/163 (was 134; +29 tool tests).
  - tsc --noEmit -p tsconfig.json: 0 new errors in emain/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements the React hook + reducer that consumes the agent IPC bridge
(window.api.agent). Conservative scope for the autonomous handoff:
ship the hook in isolation, do NOT touch AgentChatHost /
agent-block-element / terminal-model / package.json yet.

Rationale for the split
  Replacing useChat in the live agent path is risky:
    - ai-sdk's UIMessage parts shape ≠ pi's AgentMessage content shape
    - agent-block-element renders the parts loop; one wrong assumption
      could break the entire agent panel rendering
    - terminal-model's apply* methods are tied to current shape
  Doing all of that without human review during an autonomous session
  is exactly the kind of blast-radius the user warned about. The
  hook itself is self-contained and easy to drop in; the wiring is
  the dangerous half.

What this ships
  frontend/app/store/use-pi-chat.ts (~290 LOC)
    - usePiChat(opts) → { messages, status, errorMessage,
                          sessionMetadata, send, abort }
    - opts: { initialSession?, onSessionMinted?, paneContext,
             modelSelection, allowedTools? }
    - Subscribes via window.api.agent.subscribe AFTER it has a
      sessionPath; pre-session sends are still supported (they mint
      a session, the effect picks it up next render).
    - Status transitions: agent_start/turn_start → streaming;
      assistant message_end w/ stopReason:error → error;
      agent_end → idle.
    - Surfaces minted sessionMetadata via onSessionMinted callback so
      the consumer can write it to block.meta["agent:session"].
    - Pure reducer (reducePiChatEvent) exported for testing and reuse.

  frontend/app/store/use-pi-chat.test.tsx (~80 LOC, 8 tests)
    - Tests the pure reducer end-to-end: message_start append,
      message_update tail-replace, message_end finalization,
      agent_end authoritative snapshot, missing-payload no-ops,
      unknown-event no-ops.
    - Hook-lifecycle tests (renderHook + waitFor) are NOT included
      because @testing-library/react isn't installed. When the wiring
      task adds it, the hook tests should cover:
        - subscribe on initialSession; unsubscribe on unmount
        - send round-trip: sessionMetadata minted + onSessionMinted called
        - send error path: status flips to error with err.message
        - abort: calls window.api.agent.abort with current sessionPath

  frontend/types/custom.d.ts
    - AgentSendOptions gains the allowedTools?: string[] field
      (renderer can pre-approve a tool subset per pane).

What's NOT in this commit (left for the wiring task)
  - AgentChatHost: still uses @ai-sdk/react useChat; the new hook
    is unused by production code.
  - agent-block-element: still consumes UIMessagePart shape.
  - terminal-model.applyAgentParts / applyAgentText: unchanged.
  - terminal-view: still mints chatId via useMemo; needs to mint
    sessions via window.api.agent.createSession (or let usePiChat
    handle minting on first send + writing the result to
    block.meta["agent:session"] via onSessionMinted).
  - package.json: @ai-sdk/react still a dep.

Wiring checklist for the human review pass (also documented in the
use-pi-chat.ts module-doc):
  1. Swap AgentChatHost from useChat to usePiChat; drop transport prop.
  2. Rewrite agent-block-element's parts loop to walk
     AgentMessage.content (text / toolCall / toolResult / etc.)
     instead of UIMessagePart parts.
  3. Update terminal-model apply* APIs (or stop using them — pi
     events stream directly to the hook, no Jotai-atom hop required).
  4. Update terminal-view to pass onSessionMinted that writes
     block.meta["agent:session"] = meta.
  5. Remove @ai-sdk/react + provider deps from package.json.
  6. Smoke test end-to-end against each of OpenAI/Anthropic/Google/OpenRouter.

Verification
  - vitest run: 171/171 (was 163; +8 reducer tests).
  - tsc --noEmit -p tsconfig.json: 0 new errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…up plan

Snapshot for the morning review. Records what landed in the
autonomous session (tasks #9, #10-partial, #11, #12-half), what was
explicitly NOT done and why (high-blast-radius wiring, deferred tool
designs, missing API-key access), the architecture invariants the
new code commits to, and a recommended pickup order keyed to how
much time the user has when they come back.

Read this first in the morning. The architecture story itself is
already in docs/agent-runtime-architecture.md; this doc is just the
"where we are right now" companion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step 1/6 of task #12 wiring. Pure helper that converts a flat
AgentMessage[] into PiRun[], one entry per user-initiated send.
Each run carries the user message + every subsequent non-user message
(assistant + toolResult) until the next user message, plus a derived
status (streaming | done | error) from the last assistant's stopReason.

This is the unit AgentBlockElement will render against in the
upcoming rewrite. runId is "run-{i}" where i is the user message's
array index — stable for React keying within a session; rebuilds
cleanly if compaction shifts indices later.

13 tests cover: empty input, leading-noise defense, streaming /
done / error status derivation, multi-user multi-run, tool-call +
toolResult co-location, mid-stream status, error mid-tool-loop,
"status reads LAST assistant" guarantee, edge cases.

Next steps (will commit separately):
  2. New ToolUseCard against pi shape
  3. New AgentBlockElement consuming PiRun
  4. AgentChatHost rewrite + TerminalModel agent path deletion
  5. terminal-view + cmdblock-input adaptation
  6. Drop @ai-sdk/react + smoke test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step 2/6 of task #12. Lean replacement for ToolUseCard — renders one
pi toolCall + paired toolResult (linked by toolUseId). Three states:
running / done / error. Click header to expand input JSON + result.

Intentionally drops:
  - approval flow (needs-approval / user-approved / user-denied)
  - askquestion UI takeover
  - citations
  - diff view (originalcontent / modifiedcontent)
  - file-jump / open-block linking
  - suggestions / suggested rules

These were Wave-era UX bound to tools we deprecated (ask_user_question,
dangerous, transfer_to_user, file_tracker, write_plan, etc. — see the
deferred-tools decision). When a future tool needs richer display
it'll own a custom card variant rather than retrofit this one.

The old tool-use-card.tsx + its 5 satellite files (tool-action-header,
tool-ask-card, tool-command-card, tool-diff-card, citation-chips —
~1180 LOC total) become dead after step 4 wires the new AgentBlockElement.
Deletion in step 6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Steps 3+4+5 of task #12 in one commit (intentionally co-located so
the project compiles at every commit boundary). After this, the
renderer is fully driven by usePiChat → slicePiRuns → AgentBlockElement
on the pi AgentMessage shape; the ai-sdk WaveUIMessage path and
TerminalModel's agent-state Jotai atoms are gone.

Engine layer (terminal-model + Block)
  - engine/types.ts:
      Removed AgentPayload (assistantText / parts / status etc.) and
      replaced with AgentBlockRef = { runId, createdAt }. Agent state
      lives on the React side now; the engine only carries a marker.
  - engine/block.ts:
      Replaced block.agentPayload with block.agentRef.
      Deleted appendAgentText / setAgentText / setAgentStatus (the
      mutators the ai-sdk useChat → applyAgentDelta bridge called).
  - engine/blocks.ts:
      appendAgentBlock(runId) — single-arg factory; no userText or
      payload bookkeeping. Block id = `agent_${runId}`.
  - terminal-model.ts:
      Removed agentChatStatusAtom, agentChatIdAtom, agentModelOverrideAtom,
      agentPartsAtom (~4 jotai atoms gone).
      Removed submitAgentMessage, applyAgentDelta, applyAgentText,
      applyAgentParts, applyAgentStatus (~5 methods, ~60 LOC).
      Added appendAgentRun(runId) — idempotent, just appends a marker
      block and bumps revision.
  - Removed WaveUIMessagePart import.

Renderer
  - agent-chat-host.tsx (full rewrite, 224 → ~165 LOC):
      Uses usePiChat with model selection / pane context / session
      metadata from terminal-view. Watches chat.messages, slices into
      runs via slicePiRuns, calls model.appendAgentRun for newly-seen
      runIds, fires onRunsChange to feed BlockListElement. Exposes a
      stable AgentChatHostApi (send / abort / getRuns) via onReady.
      Refuses to send when selection unresolved — surfaces specific
      resolver error via onUserError.
  - agent-block-element.tsx (full rewrite, 328 → ~245 LOC):
      Takes a PiRun. Walks run.responseMessages, accumulates text from
      assistant.content[type=text], emits a ToolCallCard for each
      assistant.content[type=toolCall] paired with the matching
      toolResult message (looked up by toolUseId). Header status comes
      from run.status; error footer from run.errorMessage. Markdown
      rendering preserved via react-markdown.
  - block-list-element.tsx:
      agentChatId prop replaced with agentRunsById: Map<runId, PiRun>.
      Agent block branch: look up run via block.agentRef.runId, render
      placeholder if not yet in map (handles first message_start
      in-flight or pane reopened pre-load), else mount AgentBlockElement.
  - terminal-view.tsx:
      Replaced chatId useMemo with block.meta["agent:session"] (read
      via useOrefMetaKeyAtom). onSessionMinted writes back when first
      send mints metadata.
      Replaced agentSubmitRef with agentApiRef holding the full
      AgentChatHostApi.
      Added agentRunsById state, updated via AgentChatHost.onRunsChange.
      Removed aiConfig / aiConfigError / chatId props passed to
      AgentChatHost; replaced with modelSelection / paneContext /
      sessionMetadata / selectionError shape matching the new contract.

Test layer
  - engine/agent-flow.test.ts: DELETED — tested the old payload mutator
    API which no longer exists. slicePiRuns + AgentBlockElement integration
    is covered by slice-pi-runs.test.ts + the rewrite covers the rest.
  - engine/blocks.test.ts: rewritten — new appendAgentBlock(runId)
    signature, asserts agentRef.runId + agent_${runId} id format.
  - engine/block-handler.test.ts: defensive-guard test now asserts
    agentRef.runId is preserved (instead of agentPayload.assistantText).
  - terminal-model.test.ts: agent-section rewritten — covers
    appendAgentRun idempotency, revision bump, empty-runId no-op.

Preview env
  - preview-electron-api.ts: stubbed api.agent.* so the preview
    pages still satisfy ElectronApi after the task #9 IPC addition.

What's still dead-but-present (cleanup in next commit):
  - tool-use-card.tsx + tool-action-header / tool-command-card /
    tool-diff-card / tool-ask-card / citation-chips (~1180 LOC) —
    no longer imported by anything; deleting in step 6 cleanup.
  - aitypes.ts WaveUIMessage / WaveUIMessagePart / WaveUIDataToolUse —
    same.
  - @ai-sdk/react in package.json — deletable next commit.

Verification
  - tsc --noEmit -p tsconfig.json: 58 pre-existing errors unchanged,
    0 new errors in the agent path.
  - vitest run: 172/172 pass.
  - Manual smoke deferred to step 6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step 6/6 of task #12. With AgentChatHost + AgentBlockElement
now driven by usePiChat (commit c0222e1), nothing imports the
following any more — delete:

  frontend/app/store/aitypes.ts                          (~150 LOC)
    WaveUIMessage / WaveUIMessagePart / WaveUIDataToolUse +
    Citation / SuggestedRule / AskUserQuestion* / ApprovalDestination
    types. Pi shape replaces all of this end-to-end.

  frontend/app/term/render/tool-use-card.tsx             (~275 LOC)
  frontend/app/term/render/tool-action-header.tsx        (~91 LOC)
  frontend/app/term/render/tool-command-card.tsx         (~61 LOC)
  frontend/app/term/render/tool-diff-card.tsx            (~170 LOC)
  frontend/app/term/render/tool-ask-card.tsx             (~451 LOC)
  frontend/app/term/render/citation-chips.tsx            (~132 LOC)
    Wave-era rich tool-card UX (approval flow, askquestion takeover,
    file/line citations, diff view). These supported the 11 tools
    deferred-to-deprecated in task #10 (ask_user_question, dangerous,
    transfer_to_user, file_tracker, write_plan, etc.); no surviving
    code path needs them. The new ToolCallCard (committed dc9cd6e)
    is the lean replacement: name + input preview + collapsible
    result, no approval / citation / askquestion machinery.

Total dead-code deletion: ~1330 LOC across 7 files.

npm deps removed:
  @ai-sdk/react  (the React useChat hook crest used pre-pi)
  ai             (the underlying ai-sdk core)
  + 16 transitive dependencies via npm uninstall.

Verification
  - tsc --noEmit -p tsconfig.json: 58 pre-existing errors unchanged.
  - vitest run: 172/172 pass.

Task #12 (usePiChat + drop @ai-sdk/react) is now complete. Tasks
#13 (delete Go agent stack) and #14 (E2E regression) unblocked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ee model

One-off runner that exercises the full integrated agent stack
(sessions + AgentHarness + pi-ai openai-completions provider + tools)
against a real OpenRouter free model. Used for the post-#12 manual
smoke; keep for future regression checks against OpenRouter
specifically (the registry-driven providers have their own paths).

Usage:
  OPENROUTER_API_KEY=sk-or-v1-... \
    npx tsx emain/agent/_test-openrouter.ts ["prompt text"]
  # override model:
  OPENROUTER_MODEL=openai/gpt-oss-20b:free ...

Confirmed working today:
  - text-only round-trip (single-word reply)
  - tool-calling round-trip: agent invokes list_dir, gets real
    filesystem output, summarizes; 2 turns, 130 streaming chunks,
    5-line JSONL session, stopReason: stop, $0 cost (free tier).

Implementation notes
  - Constructs Model<"openai-completions"> by hand because OpenRouter's
    :free model variants aren't in pi-ai's models.generated.ts (LiteLLM
    doesn't enumerate them).
  - baseUrl is "https://openrouter.ai/api/v1" — the openai SDK pi
    delegates to appends /chat/completions itself. The crest catalog
    has the same field overspecified for the OLD Go HTTP path (it
    strips the suffix); when task #13 deletes that path we should
    normalize the catalog format too.
  - Sessions dir is sandboxed to os.tmpdir() — doesn't touch the
    real ~/.config/crest{-dev}/sessions/ tree.

Delete this file once task #14 has a real E2E regression harness
covering all 4 providers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renderer's model picker now calls window.api.ai.listProviderModels
instead of the Go ListProviderModelsCommand wshrpc. Closes the last
crest-side dependency on pkg/aiusechat for AI surfacing — clears the
way for deleting the Go agent stack in a follow-up.

- emain/aiconfig/list-provider-models.ts — port of listmodels.go
  (3 backends: openai-compat / anthropic-messages / google-gemini)
- emain/aiconfig/secrets.ts — direct safeStorage reader for the
  encrypted secrets file (no Go roundtrip needed from main process)
- emain/aiconfig-ipc.ts — ipcMain handler that resolves tokensecretname

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renderer now reads and writes ~/.config/crest/ai.json via
getApi().ai.{getUserConfig, writeUserConfig} instead of the Go
Get/WriteAIUserConfigCommand wshrpcs. Together with the listmodels
port (b42f5e9), the renderer no longer depends on pkg/aiusechat for
anything — the Go agent stack can be deleted in the next commit.

- emain/aiconfig/user-config.ts — port of pkg/aiusechat/aiconfig.go
  (atomic write via tmp-then-rename, shape validation, sentinel
  status for missing vs malformed)
- emain/aiconfig-ipc.ts — ai:get-user-config + ai:write-user-config
- frontend/app/store/ai-types.ts — define AIUserConfig + related types
  locally so the renderer stops depending on the Go-generated gotype
- pre-emptively add explicit imports of the new local types in
  ai-resolver, model-picker, cmdblock-input, ai-setup-wizard so the
  gotype removal in the next commit's `task generate` doesn't break
  the build

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The aifilediff view existed solely to render file diffs inside the
Wave-era tool-approval UI (the WaveAIGetToolDiffCommand-backed flow
that lived alongside tool-ask-card / tool-use-card). That UI was
removed in e51c45f when we switched to the pi native shape — the
view has had no live caller since then.

Deletes the view, its previews, and BlockRegistry / vtab references.
Clears the last frontend consumer of WaveAIGetToolDiffCommand so the
RPC + its Go implementation can be removed with the rest of the
aiusechat stack in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…RPCs

The pi-native agent runtime in emain/ replaces every responsibility
the Go agent stack used to own. Renderer has been routing through
the new electron-main IPC since commits b42f5e9 (listmodels) and
9774a61 (ai.json). Nothing in the live app references the Go side
anymore — out it goes.

Deletes:
- pkg/agent/                        (the agent loop, MCP, permissions,
                                     sandbox, checkpoint, eval harness)
- pkg/aiusechat/                    (4 hand-rolled provider backends,
                                     chatstore, tool-approval flow,
                                     AI user-config IO, listmodels)
- pkg/web/web.go                    (5 dead routes: post-chat-message,
                                     post-agent-message, agent-rewind,
                                     agent-worktree, wave/aichat)
- 7 wshrpc commands                 (GetAIUserConfig, WriteAIUserConfig,
                                     ListProviderModels, GetWaveAIChat,
                                     WaveAIToolApprove, WaveAIGetToolDiff,
                                     WaveAIEnableTelemetry, WaveAIAddContext)
- cmd/wsh/cmd/wshcmd-ai.go          (Wave-era sidebar CLI)
- cmd/testai, cmd/testopenai,
  cmd/testsummarize                 (dev test utilities pointing at
                                     the deleted backends)
- cmd/server/main-server.go         (drops the agentmcp shutdown call)

Also regenerates wshclient.go / gotypes.d.ts / wshclientapi.ts via
`task generate` after dropping the uctypes import from
cmd/generatego/main-generatego.go.

Wave-era settings.json keys (ai:mcpservers / ai:permissions) remain in
pkg/wconfig so old config files still parse — they're dormant now;
the new agent runtime ignores them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mark tasks #8#13 complete with their commit hashes and document the
post-#13 surface: all AI state and IO now lives in TS (emain/aiconfig/
+ emain/agent/), with the Go side retaining only general-purpose
secret writes via SetSecretsCommand.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Post-#13 follow-ups found in a verification sweep:

- .github/workflows/agent-tests.yml ran `go test ./pkg/agent/...
  ./pkg/aiusechat/...` — both packages are gone, so the job would fail
  on every push. Repointed it at the vitest suite that now covers the
  TS agent runtime (emain/agent, emain/aiconfig, frontend stores).
- ai-types.ts comments still described the deleted /api/post-agent-message
  wire path and the pkg/aiusechat/aiconfig.go mirror struct. Updated to
  describe the current reality (IPC carries {provider, model, reasoning};
  pi-ai resolves the endpoint) and dropped the now-unused AIConfigRequest
  alias.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the one-off _test-openrouter.ts with a parameterized harness
that runs a fixed scenario matrix against every provider that has an
API key in the environment.

- eval/providers.ts  — provider matrix (anthropic/openai/google via
  pi-ai registry; openrouter hand-built for free-tier models)
- eval/scenarios.ts  — 5 representative scenarios with behavior-based
  checks: text-only, list-dir, read-file, shell-exec, multi-step.
  Checks assert on what the agent *did* (which tools ran, did the
  final text carry the marker) rather than exact LLM output.
- eval/run-regression.ts — runner. Skips keyless providers, exits
  non-zero on any failure so CI can gate once keys are wired in.
  Filter via ONLY=<providers> / SCENARIOS=<ids>.
- eval/scenarios.test.ts — offline vitest pinning the check logic
  (13 cases). The live runner needs network+keys; the pure check
  functions don't, and a buggy check would silently pass a broken
  agent — so they're tested deterministically.

Live run:
  ANTHROPIC_API_KEY=... OPENAI_API_KEY=... GEMINI_API_KEY=... \
    OPENROUTER_API_KEY=... npx tsx emain/agent/eval/run-regression.ts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verified the full scenario matrix (text-only / list-dir / read-file /
shell-exec / multi-step) passes 5/5 against openai/gpt-oss-20b:free —
end-to-end tool calling confirmed on OpenRouter.

llama-3.3-70b:free returns upstream 429s under even light load, which
fails every scenario for reasons unrelated to the agent. Switch the
default to the model that actually works so re-runs aren't blocked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On every push to main, three jobs were failing:

- Docsite CI/CD called a Taskfile target (docsite:build:public) that no
  longer exists in crest — it deployed Wave's documentation website,
  which crest (a POC) doesn't have.
- TestDriver.ai Build/Run drove a paid UI-testing service tied to
  Wave's account; its build also surfaced the in-progress edgeflowjs
  integration break (embedder.worker.ts imports unexported symbols),
  which belongs in the edgeFlow.js feedback loop, not a CI gate.
- Agent Tests (the vitest suite) failed on one flaky test —
  shell_exec "times out long-running commands" exceeded vitest's 5s
  budget on the slower CI runner (the tool floors timeoutMs at 1000ms
  and allows a 2000ms SIGKILL grace). Bumped that test's budget to 20s.

Deletes deploy-docsite.yml, testdriver-build.yml, testdriver.yml and
removes their now-dangling entries from merge-gatekeeper's ignore list.
After this, a normal push to main runs only Agent Tests + CodeQL.

(Separate, not addressed here: harbor-nightly terminal-bench runs daily
and is currently failing — likely needs rework for the new TS agent or
an API-key secret.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dependabot dependabot Bot force-pushed the dependabot/github_actions/dot-github/workflows/actions/upload-artifact-7 branch from 0815553 to c757e9b Compare May 24, 2026 19:24
Jason-Shen2 and others added 3 commits May 24, 2026 21:31
The daily terminal-bench benchmark predates the TS-agent rewrite and
has been failing nightly. Removing it for now — agent benchmarking can
be reintroduced against the new emain/agent runtime when wanted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The classifier worker was written against three edgeflowjs APIs that
0.2.0 never shipped, which broke the production Vite build with
"setOnnxModule is not exported by edgeflowjs":

- setOnnxModule / configureOnnxAssets — don't exist in the package.
- runInferenceNamed — implemented in core/runtime.js but never
  re-exported from any entry point in the exports map.

On top of that, edgeflowjs's onnx backend only sets
ort.env.wasm.wasmPaths when `typeof window !== "undefined"`, which is
always false in a Web Worker — so it leaves ORT's asset paths
unconfigured in exactly the context this code runs in.

Fix, consumer-side (the sibling edgeFlow.js repo isn't available to
patch the library):

- Configure ort.env.wasm.{wasmPaths,numThreads} directly on the
  statically-imported ORT module. ESM modules are singletons, so
  edgeflowjs's internal `import("onnxruntime-web/wasm")` resolves to
  the same instance and inherits the config; the static import also
  forces Vite to bundle ORT into the worker chunk.
- Replace runInferenceNamed with the public runInference, ordering the
  input tensors to match model.metadata.inputs (the backend maps
  inputs positionally to the model's input names).

Verified: `electron-vite build --mode production` now succeeds and
emits ort-wasm-simd-threaded.wasm into the bundle. Detailed
TODO(edgeflow) marker left for the edgeFlow.js integration loop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot changed the title chore(deps): Bump actions/upload-artifact from 4 to 7 in /.github/workflows chore(deps): Bump actions/upload-artifact from 5 to 7 in /.github/workflows May 24, 2026
@dependabot dependabot Bot force-pushed the dependabot/github_actions/dot-github/workflows/actions/upload-artifact-7 branch from c757e9b to f75227e Compare May 24, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants