@code-yeongyu/senpi 2026.8.30-3 → 2026.8.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +3 -0
- package/dist/core/agent-session.d.ts +26 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +67 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts +9 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js +10 -3
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +4 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +14 -1
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust-state-json.d.ts +5 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.js +76 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts +7 -1
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust-storage.js +60 -8
- package/dist/core/extensions/builtin/hooks/trust-storage.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust.d.ts +1 -2
- package/dist/core/extensions/builtin/hooks/trust.d.ts.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust.js +1 -72
- package/dist/core/extensions/builtin/hooks/trust.js.map +1 -1
- package/dist/core/extensions/builtin/ttsr/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ttsr/index.js +4 -0
- package/dist/core/extensions/builtin/ttsr/index.js.map +1 -1
- package/dist/core/extensions/builtin/ttsr/manager.d.ts +2 -0
- package/dist/core/extensions/builtin/ttsr/manager.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ttsr/manager.js +28 -1
- package/dist/core/extensions/builtin/ttsr/manager.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/retry-fallback/controller.d.ts +14 -0
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +33 -3
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/retry-fallback/log.js +1 -1
- package/dist/core/retry-fallback/log.js.map +1 -1
- package/dist/core/session-activity.d.ts +47 -0
- package/dist/core/session-activity.d.ts.map +1 -0
- package/dist/core/session-activity.js +58 -0
- package/dist/core/session-activity.js.map +1 -0
- package/dist/core/session-manager.d.ts +8 -12
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +118 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-resident-store.d.ts +8 -1
- package/dist/core/session-resident-store.d.ts.map +1 -1
- package/dist/core/session-resident-store.js +12 -5
- package/dist/core/session-resident-store.js.map +1 -1
- package/dist/modes/app-server/daemon.js +3 -3
- package/dist/modes/app-server/daemon.js.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts +3 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +26 -4
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +24 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +12 -5
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +149 -12
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/custom-capability.d.ts +1 -0
- package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
- package/dist/modes/rpc/custom-capability.js +1 -0
- package/dist/modes/rpc/custom-capability.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +3 -3
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +10 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +15 -2
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.d.ts +38 -0
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +55 -5
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/ownership-safe-lock.d.ts +14 -0
- package/dist/modes/rpc/ownership-safe-lock.d.ts.map +1 -0
- package/dist/modes/rpc/ownership-safe-lock.js +87 -0
- package/dist/modes/rpc/ownership-safe-lock.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +12 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +1 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts +2 -1
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +1 -0
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +54 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +174 -2
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +18 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +88 -8
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +11 -1
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +25 -0
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/widget-line-renderer.d.ts +17 -0
- package/dist/modes/rpc/widget-line-renderer.d.ts.map +1 -0
- package/dist/modes/rpc/widget-line-renderer.js +73 -0
- package/dist/modes/rpc/widget-line-renderer.js.map +1 -0
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +11 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/docs/app-server.md +2 -2
- package/docs/containerization.md +2 -2
- package/docs/development.md +7 -7
- package/docs/extensions.md +4 -4
- package/docs/grok-neo.md +1 -1
- package/docs/index.md +1 -1
- package/docs/packages.md +2 -2
- package/docs/quickstart.md +4 -4
- package/docs/release-guide.md +21 -21
- package/docs/rpc.md +59 -4
- package/docs/sdk.md +1 -1
- package/docs/skills.md +2 -2
- package/docs/terminal-tools.md +1 -1
- package/docs/termux.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/AGENTS.md +1 -1
- package/examples/sdk/README.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +16 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/skill-contribution.ts +71 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +3 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/SKILL.md +44 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/breaking-changes.md +75 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/build.md +114 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/dev-tooling.md +34 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/http-networking.md +113 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/install.md +93 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/node-compat-platforms.md +36 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/performance.md +33 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/runtime-apis.md +156 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/security.md +52 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/test.md +103 -0
- package/node_modules/@earendil-works/pi-agent-core/README.md +3 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +6 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +7 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +316 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.js +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +24 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +20 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/README.md +6 -3
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/README.md +5 -4
- package/node_modules/@earendil-works/pi-tui/native/darwin/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/native/win32/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
package/docs/rpc.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# RPC Mode
|
|
2
2
|
|
|
3
|
+
Shared-host clients may advertise the `rendered_components` capability to receive factory-rendered widget, header, and footer records. In a shared session, component rendering uses the minimum width reported by currently attached connections, defaulting to 80 when none report a width; disconnected connections no longer contribute.
|
|
4
|
+
|
|
3
5
|
The shared Unix socket host uses `<agentDir>/rpc-host-daemon/host.pid` and `settings.json` as its ownership state. Clients attach to a compatible existing host regardless of which client surface started it; only incompatible unmanaged owners are refused.
|
|
4
6
|
|
|
5
7
|
RPC mode enables headless operation of the coding agent via a JSON protocol over stdin/stdout. This is useful for embedding the agent in other applications, IDEs, or custom UIs.
|
|
@@ -61,6 +63,18 @@ every open session, each tagged with its routing `sessionId`. Correlated respons
|
|
|
61
63
|
only to the connection that issued the command. This lets a non-owner observe a foreign turn without requiring a
|
|
62
64
|
separate subscription protocol.
|
|
63
65
|
|
|
66
|
+
### Client information and rendered components
|
|
67
|
+
|
|
68
|
+
Clients may send `set_client_info` with `{ sessionId, width, capabilities? }`. Advertising `rendered_components` registers
|
|
69
|
+
that connection to receive factory-rendered `setWidget`, `setHeader`, and `setFooter` records. Those records are filtered
|
|
70
|
+
per connection; array/undefined widget records and dialog requests retain their existing delivery semantics. Width is
|
|
71
|
+
shared per session using the minimum of attached clients, and a closed or dropped connection no longer contributes its
|
|
72
|
+
width or capability registration. Snapshot replay preserves rendered-component provenance and applies the same capability
|
|
73
|
+
filter to late joiners; a client that registers `rendered_components` while a snapshot is active receives its retained
|
|
74
|
+
factory-rendered records. On a shared socket host, `rendered_components` is registration-only: it is never inherited from the host environment and must be sent in `set_client_info` for each client connection. Registration applies to the sessions attached by that connection; closing one session removes only that session's width and capability association, while socket disposal removes all associations. Clients must re-register `width` and `capabilities` after every reconnect. When the last
|
|
75
|
+
capable connection leaves a still-attached binding, live component renderers and footer data providers are disposed but
|
|
76
|
+
their factories are retained; a later capable connection recreates and re-renders them.
|
|
77
|
+
|
|
64
78
|
### Session auto-titling
|
|
65
79
|
|
|
66
80
|
Auto-generated session titles are on by default only for interactive launches. RPC hosts opt in with
|
|
@@ -126,12 +140,37 @@ internal directory. The supervisor also exports `SENPI_RPC_HOST_WATCH_PPID` as a
|
|
|
126
140
|
set only by the supervisor: a host started any other way (plain `senpi --mode rpc --listen …`, embedders, hand-started
|
|
127
141
|
hosts) sees neither variable and is unaffected. A host whose supervisor is alive is never touched by this binding.
|
|
128
142
|
|
|
143
|
+
### Shared host occupancy (idle eviction, session cap, empty-host exit)
|
|
144
|
+
|
|
145
|
+
Every open session owns a complete runtime (a lone idle session measures 340-510 MB RSS), so the host enforces three
|
|
146
|
+
occupancy bounds itself, independent of the supervisor and of client cooperation:
|
|
147
|
+
|
|
148
|
+
- **Idle eviction**: a session with no routed command and no session-owned work for
|
|
149
|
+
`SENPI_RPC_SESSION_IDLE_EVICTION_MS` (default 30 minutes) is closed through the exact `close_session` sequence
|
|
150
|
+
(abort → waitForIdle → dispose, all attachments drained, path reservation released) and every attached connection
|
|
151
|
+
receives that handle's `session_closed` broadcast plus a final `close_session` response record. "Session-owned
|
|
152
|
+
work" is the complete activity contract, not just a streaming turn: an agent run, a running bash command,
|
|
153
|
+
background terminal jobs and any other published wake source (terminal monitors, loop-guard holds), compaction,
|
|
154
|
+
and barrier-held session work all defer eviction, and the idle clock restarts when that work settles. An evicted
|
|
155
|
+
session resumes like any other: the next `open_session` with the same `sessionPath` reopens it.
|
|
156
|
+
- **Session cap**: `open_session` beyond `SENPI_RPC_MAX_SESSIONS` concurrently opening/open sessions (default 8)
|
|
157
|
+
fails with `too_many_sessions`. Attaching to an already-hosted session (`attached: true`) adds no runtime and never
|
|
158
|
+
counts against the cap, so resume and second-surface flows keep working while at it.
|
|
159
|
+
- **Empty-host exit**: when the registry holds zero sessions AND no client is connected, continuously for
|
|
160
|
+
`SENPI_RPC_HOST_EMPTY_EXIT_MS` (default 15 minutes), the host exits through its clean shutdown path (flush, socket
|
|
161
|
+
removal), for stdio and `--listen` hosts alike. A connected client counts as occupancy even with no session open,
|
|
162
|
+
so the host never drops a live socket under itself. Supervised hosts stay clean either way: a supervisor reads a
|
|
163
|
+
child exit of 0 without a signal as an intentional idle stop and exits 0 with the same cleanup, not as a crash.
|
|
164
|
+
|
|
165
|
+
Values are positive integers; invalid values fall through to the defaults. These bounds run inside the host process,
|
|
166
|
+
so they hold even for embedders and hand-started hosts that have no supervisor.
|
|
167
|
+
|
|
129
168
|
### D1 normative table (multi-session mode)
|
|
130
169
|
|
|
131
170
|
| Command | Params | Success data | Notes |
|
|
132
171
|
| --- | --- | --- | --- |
|
|
133
172
|
| `get_protocol_info` | - | `{ protocolVersion: 1, serverVersion: string, capabilities: string[], mode: "classic"\|"multi" }` | Answered in BOTH modes; side-effect-free; the capability probe. Multi-session hosts include `multi_session` plus the negotiated launch capabilities. |
|
|
134
|
-
| `open_session` | `sessionPath?`, `cwd?`, `provider?`, `modelId?`, `thinkingLevel?`, `permissionPreset?` (all optional; paths MUST be absolute) | `{ sessionId, state: RpcSessionState, attached?: true }` | `sessionPath` = today's `--session` semantics (open-if-exists else create persisting there, `session-manager.ts:926-940`); `provider`/`modelId` applied only on create (resume restores the session's model — mirrors `SenpiSessionRuntime.ts:198-200`); params form the immutable launch profile (D8). When the path is already held by a fully-open session, the open ATTACHES to it: same routing handle, `attached: true`, one more attachment counted; the runtime is torn down only when the last attachment closes. |
|
|
173
|
+
| `open_session` | `sessionPath?`, `cwd?`, `provider?`, `modelId?`, `thinkingLevel?`, `permissionPreset?` (all optional; paths MUST be absolute) | `{ sessionId, state: RpcSessionState, attached?: true }` | `sessionPath` = today's `--session` semantics (open-if-exists else create persisting there, `session-manager.ts:926-940`); `provider`/`modelId` applied only on create (resume restores the session's model — mirrors `SenpiSessionRuntime.ts:198-200`); params form the immutable launch profile (D8). When the path is already held by a fully-open session, the open ATTACHES to it: same routing handle, `attached: true`, one more attachment counted; the runtime is torn down only when the last attachment closes. Fails with `too_many_sessions` at the occupancy cap (see [Shared host occupancy](#shared-host-occupancy-idle-eviction-session-cap-empty-host-exit)); idle sessions past the eviction window are closed by the host itself. |
|
|
135
174
|
| `close_session` | `sessionId` | `{}` | Aborts active work, awaits agent idle + settled persistence, flushes queued events, detaches subscriptions; its response is the LAST record tagged with that handle — no events after (test-pinned). |
|
|
136
175
|
| `list_sessions` | - | `{ sessions: [{ sessionId, durableSessionId, sessionPath, cwd, name, status }] }` | Includes `opening`/`closing` entries with their status. |
|
|
137
176
|
| every existing command | + `sessionId` (REQUIRED in multi mode) | unchanged | Routed to that session. |
|
|
@@ -150,6 +189,7 @@ In the response `error` field, machine-matchable:
|
|
|
150
189
|
- `missing_session_id` (session-scoped command without `sessionId` in multi mode)
|
|
151
190
|
- `multi_session_disabled` (`open_session` in classic mode)
|
|
152
191
|
- `invalid_path` (relative `sessionPath`/`cwd`)
|
|
192
|
+
- `too_many_sessions` (`open_session` while `SENPI_RPC_MAX_SESSIONS` sessions are already opening/open; attaching to a live session never fails this way)
|
|
153
193
|
- `open_failed: <detail>`
|
|
154
194
|
|
|
155
195
|
### Tagging
|
|
@@ -1668,13 +1708,13 @@ Extensions can request user interaction via `ctx.ui.select()`, `ctx.ui.confirm()
|
|
|
1668
1708
|
There are two categories of extension UI methods:
|
|
1669
1709
|
|
|
1670
1710
|
- **Dialog methods** (`select`, `confirm`, `input`, `editor`): emit an `extension_ui_request` on stdout and block until the client sends back an `extension_ui_response` on stdin with the matching `id`.
|
|
1671
|
-
- **Fire-and-forget methods** (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`): emit an `extension_ui_request` on stdout but do not expect a response. The client can display the information or ignore it.
|
|
1711
|
+
- **Fire-and-forget methods** (`notify`, `setStatus`, `setWidget`, `setHeader`, `setFooter`, `setTitle`, `set_editor_text`): emit an `extension_ui_request` on stdout but do not expect a response. The client can display the information or ignore it.
|
|
1672
1712
|
|
|
1673
1713
|
If a dialog method includes a `timeout` field, the agent-side will auto-resolve with a default value when the timeout expires. The client does not need to track timeouts.
|
|
1674
1714
|
|
|
1675
1715
|
Some `ExtensionUIContext` methods are not supported or degraded in RPC mode because they require direct TUI access:
|
|
1676
1716
|
- `custom()` returns `undefined`
|
|
1677
|
-
- `setWorkingMessage()`, `setWorkingIndicator()`, `
|
|
1717
|
+
- `setWorkingMessage()`, `setWorkingIndicator()`, `setEditorComponent()`, `setToolsExpanded()` are no-ops. `setFooter()` and `setHeader()` render factory components for clients advertising `rendered_components`.
|
|
1678
1718
|
- `getEditorText()` returns `""`
|
|
1679
1719
|
- `getToolsExpanded()` returns `false`
|
|
1680
1720
|
- `pasteToEditor()` delegates to `setEditorText()` (no paste/collapse handling)
|
|
@@ -1801,7 +1841,22 @@ Set or clear a widget (block of text lines) displayed above or below the editor.
|
|
|
1801
1841
|
}
|
|
1802
1842
|
```
|
|
1803
1843
|
|
|
1804
|
-
Send `widgetLines: undefined` (or omit it) to clear the widget. The `widgetPlacement` field is `"aboveEditor"` (default) or `"belowEditor"`.
|
|
1844
|
+
Send `widgetLines: undefined` (or omit it) to clear the widget. The `widgetPlacement` field is `"aboveEditor"` (default) or `"belowEditor"`. Component factories are rendered by the host using the attached client's terminal width.
|
|
1845
|
+
|
|
1846
|
+
#### setHeader / setFooter
|
|
1847
|
+
|
|
1848
|
+
Set or clear the extension header or footer using rendered text lines. Clients that do not understand these additive methods ignore them.
|
|
1849
|
+
|
|
1850
|
+
```json
|
|
1851
|
+
{
|
|
1852
|
+
"type": "extension_ui_request",
|
|
1853
|
+
"id": "uuid-10",
|
|
1854
|
+
"method": "setHeader",
|
|
1855
|
+
"widgetLines": ["Header line"]
|
|
1856
|
+
}
|
|
1857
|
+
```
|
|
1858
|
+
|
|
1859
|
+
Omit `widgetLines` to restore the built-in surface. Attached clients send `set_client_info` with their terminal width after attach and on resize; hosts default to width 80 when no width is supplied.
|
|
1805
1860
|
|
|
1806
1861
|
#### setTitle
|
|
1807
1862
|
|
package/docs/sdk.md
CHANGED
|
@@ -36,7 +36,7 @@ await session.prompt("What files are in the current directory?");
|
|
|
36
36
|
## Installation
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
|
|
39
|
+
bun add @earendil-works/pi-coding-agent
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
The SDK is included in the main package. No separate installation needed.
|
package/docs/skills.md
CHANGED
|
@@ -132,7 +132,7 @@ description: What this skill does and when to use it. Be specific.
|
|
|
132
132
|
|
|
133
133
|
Run once before first use:
|
|
134
134
|
```bash
|
|
135
|
-
cd /path/to/skill &&
|
|
135
|
+
cd /path/to/skill && bun install
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
## Usage
|
|
@@ -249,7 +249,7 @@ description: Web search and content extraction via Brave Search API. Use for sea
|
|
|
249
249
|
## Setup
|
|
250
250
|
|
|
251
251
|
```bash
|
|
252
|
-
cd /path/to/brave-search &&
|
|
252
|
+
cd /path/to/brave-search && bun install
|
|
253
253
|
```
|
|
254
254
|
|
|
255
255
|
## Search
|
package/docs/terminal-tools.md
CHANGED
|
@@ -50,7 +50,7 @@ server. Nothing outlives the watch, so no cleanup.
|
|
|
50
50
|
|
|
51
51
|
```js
|
|
52
52
|
monitor({ description: "full test suite",
|
|
53
|
-
command: "if
|
|
53
|
+
command: "if bunx vitest run; then printf 'OK\n'; else code=$?; printf 'FAILED_%s\n' \"$code\"; exit \"$code\"; fi",
|
|
54
54
|
filter: "^(OK|FAILED_)" })
|
|
55
55
|
```
|
|
56
56
|
|
package/docs/termux.md
CHANGED
package/docs/tui.md
CHANGED
|
@@ -472,7 +472,7 @@ interface MyTheme {
|
|
|
472
472
|
Set `PI_TUI_WRITE_LOG` to capture the raw ANSI stream written to stdout.
|
|
473
473
|
|
|
474
474
|
```bash
|
|
475
|
-
PI_TUI_WRITE_LOG=/tmp/tui-ansi.log
|
|
475
|
+
PI_TUI_WRITE_LOG=/tmp/tui-ansi.log bunx tsx packages/tui/test/chat-simple.ts
|
|
476
476
|
```
|
|
477
477
|
|
|
478
478
|
## Performance
|
package/examples/AGENTS.md
CHANGED
|
@@ -48,5 +48,5 @@ Largest examples carry real complexity, not toy scope: `extensions/overlay-qa-te
|
|
|
48
48
|
## VALIDATION
|
|
49
49
|
|
|
50
50
|
- Run the focused tests for the public API demonstrated by the example.
|
|
51
|
-
- Typecheck examples through root `
|
|
51
|
+
- Typecheck examples through root `bun run check`.
|
|
52
52
|
- Interactive examples require real CLI or visual QA when their behavior changes.
|
package/examples/sdk/README.md
CHANGED
|
@@ -12,6 +12,22 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.8.31] - 2026-08-31
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- The codemode extension now bundles the `bun-1-4` skill and contributes it via `resources_discover` only
|
|
22
|
+
when the js eval kernel itself runs bun >= 1.4 (`process.versions.bun`); node-kernel sessions never
|
|
23
|
+
receive the skill, regardless of any bun binary on PATH.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
### Removed
|
|
30
|
+
|
|
15
31
|
## [2026.8.30-3] - 2026-08-30
|
|
16
32
|
|
|
17
33
|
### Breaking Changes
|
|
@@ -202,10 +202,10 @@ namespace to prevent recursive execution.
|
|
|
202
202
|
|
|
203
203
|
```bash
|
|
204
204
|
cd packages/senpi-codemode
|
|
205
|
-
|
|
205
|
+
bun run test
|
|
206
206
|
|
|
207
207
|
cd ../..
|
|
208
|
-
|
|
208
|
+
bun run check
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
Direct real-surface QA drivers live in `scripts/qa-*.ts`: kernel cells
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-codemode",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.31",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Source-only senpi extension package for codemode evaluation tools",
|
|
6
6
|
"type": "module",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/parser": "8.0.4",
|
|
34
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.
|
|
34
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.31",
|
|
35
35
|
"typebox": "1.3.18"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
38
|
+
"@code-yeongyu/senpi": "2026.8.31"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
41
|
+
"@code-yeongyu/senpi": "2026.8.31"
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|
|
44
44
|
"senpi",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const BUN_SKILL_BASE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
let loggedMissingBunSkill = false;
|
|
8
|
+
|
|
9
|
+
export const BUN_SKILL_MIN_VERSION = "1.4.0";
|
|
10
|
+
|
|
11
|
+
/** Reads the js eval kernel's bun version; undefined on a node kernel. */
|
|
12
|
+
export type BunKernelVersionSource = () => string | undefined;
|
|
13
|
+
|
|
14
|
+
const kernelBunVersion: BunKernelVersionSource = () => process.versions.bun;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* True when the version is at least `BUN_SKILL_MIN_VERSION`: parses the leading
|
|
18
|
+
* `<major>.<minor>` integers of the string and gates on major > 1 || (major === 1 && minor >= 4).
|
|
19
|
+
* Unparseable or missing versions never enable the skill.
|
|
20
|
+
*/
|
|
21
|
+
export function bunVersionSupportsSkill(version: string | undefined): boolean {
|
|
22
|
+
if (version === undefined) return false;
|
|
23
|
+
const match = /^(\d+)\.(\d+)/.exec(version);
|
|
24
|
+
if (match === null) return false;
|
|
25
|
+
const major = Number.parseInt(match[1]!, 10);
|
|
26
|
+
const minor = Number.parseInt(match[2]!, 10);
|
|
27
|
+
return major > 1 || (major === 1 && minor >= 4);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Absolute path of the bundled bun-1-4 SKILL.md, or undefined (logged once) when it is not shipped. */
|
|
31
|
+
export function bundledBunSkillPath(baseDir: string = BUN_SKILL_BASE_DIR): string | undefined {
|
|
32
|
+
const candidate = join(baseDir, "..", "skill", "bun-1-4", "SKILL.md");
|
|
33
|
+
if (existsSync(candidate)) return candidate;
|
|
34
|
+
if (!loggedMissingBunSkill) {
|
|
35
|
+
loggedMissingBunSkill = true;
|
|
36
|
+
console.debug(`[senpi-codemode] bundled bun-1-4 skill not found at ${candidate}; skipping contribution`);
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Builds the `resources_discover` handler that contributes the bundled bun-1-4 skill
|
|
43
|
+
* only when the in-process js eval kernel itself runs bun >= 1.4 (`process.versions.bun`).
|
|
44
|
+
* A node kernel never receives the skill, regardless of any bun binary on PATH.
|
|
45
|
+
*/
|
|
46
|
+
export function createBunSkillDiscoverHandler(
|
|
47
|
+
getKernelBunVersion: BunKernelVersionSource = kernelBunVersion,
|
|
48
|
+
baseDir?: string,
|
|
49
|
+
): () => { skillPaths: string[] } | undefined {
|
|
50
|
+
return () => {
|
|
51
|
+
if (!bunVersionSupportsSkill(getKernelBunVersion())) return undefined;
|
|
52
|
+
const skillPath = bundledBunSkillPath(baseDir);
|
|
53
|
+
return skillPath === undefined ? undefined : { skillPaths: [skillPath] };
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function registerBunSkillContribution(
|
|
58
|
+
pi: {
|
|
59
|
+
on(
|
|
60
|
+
event: "resources_discover",
|
|
61
|
+
handler: (
|
|
62
|
+
event: unknown,
|
|
63
|
+
ctx: unknown,
|
|
64
|
+
) => Promise<{ skillPaths?: string[] } | undefined> | { skillPaths?: string[] } | undefined,
|
|
65
|
+
): void;
|
|
66
|
+
},
|
|
67
|
+
getKernelBunVersion?: BunKernelVersionSource,
|
|
68
|
+
baseDir?: string,
|
|
69
|
+
): void {
|
|
70
|
+
pi.on("resources_discover", createBunSkillDiscoverHandler(getKernelBunVersion, baseDir));
|
|
71
|
+
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { jsRuntimeInfo, jsRuntimeLabel } from "./extension/runtime-info.ts";
|
|
17
17
|
import type { CodemodeSessionManager, CreateCodemodeSessionManagerOptions } from "./extension/session-manager.ts";
|
|
18
18
|
import { SessionManagerProxy } from "./extension/session-manager-proxy.ts";
|
|
19
|
+
import { registerBunSkillContribution } from "./extension/skill-contribution.ts";
|
|
19
20
|
import { WAKE_SOURCE_STATE_EVENT, type WakeSourceState } from "./extension/wake-source-state.ts";
|
|
20
21
|
import { EvalDetachedCellManager, type EvalDetachedCellStatusEntry } from "./tool/detached-cell-manager.ts";
|
|
21
22
|
import {
|
|
@@ -40,7 +41,7 @@ type CodemodeEvent = SessionLifecycleEvent | "model_select";
|
|
|
40
41
|
export interface CodemodeExtensionAPI {
|
|
41
42
|
registerTool(tool: ReturnType<typeof createEvalTool>): void;
|
|
42
43
|
registerRemovedToolHint(name: string, hint: string): void;
|
|
43
|
-
on(event: CodemodeEvent, handler: (event: unknown, ctx: ExtensionContext) =>
|
|
44
|
+
on(event: CodemodeEvent | "resources_discover", handler: (event: unknown, ctx: ExtensionContext) => unknown): void;
|
|
44
45
|
executeTool: AgentExecuteTool;
|
|
45
46
|
getActiveTools(): string[];
|
|
46
47
|
getAllTools(): readonly EvalSchemaToolInfo[];
|
|
@@ -168,6 +169,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
168
169
|
"wait",
|
|
169
170
|
'wait was removed; detached eval cells notify when complete. Use eval({ action: "peek"|"stop", cell_id }) to inspect or stop one.',
|
|
170
171
|
);
|
|
172
|
+
registerBunSkillContribution(pi);
|
|
171
173
|
|
|
172
174
|
pi.on("session_start", async (event, ctx) => {
|
|
173
175
|
const previousCells = activeCells;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bun-1-4
|
|
3
|
+
description: "MUST USE whenever writing or running JavaScript/TypeScript with Bun — including JS through the eval tool, bun -e one-liners, scratch scripts, servers, CLIs, tests, bundling, or package management. Bun 1.4 replaced 15+ npm deps with builtins: consult BEFORE npm-installing sharp, puppeteer/playwright (scraping), marked, node-cron, node-pty, concurrently, serve-static, tar, json5, fast-xml-parser, string-width — Bun ships it. Triggers: bun, Bun.serve, bun test, bun build, bun install, bun run, JS 스크립트, 번들링, 이미지 리사이즈, 헤드리스 브라우저, 크론, PTY, eval js."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Bun 1.4 — Use the Builtins First
|
|
7
|
+
|
|
8
|
+
Bun 1.4 (2026) ships builtins that replace most utility npm packages. **Before adding a dependency or writing a workaround, check the capability map below — if Bun ships it, use the builtin.** This skill is loaded because this session's `eval` js kernel runs Bun >= 1.4; on other machines or pinned projects, confirm with `bun --version` ([v1.3.x]/[v1.4.0] tags in the references give exact minimums). Release post: <https://bun.com/blog/bun-v1.4>
|
|
9
|
+
|
|
10
|
+
## Capability map — what you can do now
|
|
11
|
+
|
|
12
|
+
| You want to... | Use | Replaces | Ref = `references/<name>.md` |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| Resize/convert/rotate images | `Bun.file(p).image().resize().webp().write()` | sharp | runtime-apis |
|
|
15
|
+
| Headless browser: navigate, click, screenshot, evaluate, CDP | `new Bun.WebView()` | puppeteer, playwright (scraping) | runtime-apis |
|
|
16
|
+
| Markdown → HTML / React / ANSI | `Bun.markdown.html() / .react() / .render()` | marked, react-markdown | runtime-apis |
|
|
17
|
+
| Schedule cron jobs | `Bun.cron()` | node-cron | runtime-apis |
|
|
18
|
+
| Drive a PTY (bash, vim, TUIs) from JS | `Bun.spawn([...], { terminal })` | node-pty | runtime-apis |
|
|
19
|
+
| Run package scripts concurrently, glob-matched | `bun run --parallel "build:*"` | concurrently, npm-run-all | runtime-apis |
|
|
20
|
+
| Parse JSON5 / JSONL / JSONC / XML / TOML; tarballs | `Bun.JSON5/.JSONL/.JSONC/.XML/.TOML`, `Bun.Archive` | json5, ndjson, jsonc-parser, fast-xml-parser, @iarna/toml, tar | runtime-apis |
|
|
21
|
+
| ANSI-aware terminal text: width, slice, wrap | `Bun.stringWidth()`, `Bun.sliceAnsi()`, `Bun.wrapAnsi()` | string-width, slice-ansi, wrap-ansi | runtime-apis |
|
|
22
|
+
| Call C libraries 3x faster, plain strings back | `bun:ffi` (`buffer_length`, `cstring`) | — | runtime-apis |
|
|
23
|
+
| Serve a static dir (ETag/Range/304 handled) | `Bun.serve({ routes: { "/x/*": { dir } } })` | express.static, serve-static, sirv | http-networking |
|
|
24
|
+
| HTTP/3 server; `fetch` protocol/compress/proxy | `http3: true`, `fetch(url, { protocol, compress, proxy })` | — | http-networking |
|
|
25
|
+
| Tests across CPU workers / CI shards / changed files / flaky retry | `bun test --parallel --shard=1/3 --changed=main --retry` | jest/vitest infra | test |
|
|
26
|
+
| Kill "passes alone, fails in suite" bugs | `bun test --isolate` | vitest default behavior | test |
|
|
27
|
+
| React Compiler auto-memoization | `bun build --react-compiler` | babel-plugin-react-compiler | build |
|
|
28
|
+
| Embed assets/dirs into a single-file executable | `bun build --compile --asset ./public` | pkg hacks | build |
|
|
29
|
+
| Compile-time feature flags, in-memory bundling, metafile | `bun:bundle feature()`, `files:{}`, `metafile: true` | esbuild define/plugins | build |
|
|
30
|
+
| Diff package versions, fix vulns, dedupe/prune, license audit | `bun pm diff`, `bun audit fix`, `bun dedupe`, `bun prune`, `bun pm licenses` | npm-diff, npm audit fix | install |
|
|
31
|
+
| 7x faster CI installs (global virtual store) | `linker = "isolated"` in bunfig.toml | pnpm store | install |
|
|
32
|
+
| Profile CPU/heap/bundle as grep-able Markdown | `bun --cpu-prof-md`, `--heap-prof-md`, `bun build --metafile-md` | Chrome DevTools round-trip | dev-tooling |
|
|
33
|
+
| Native REPL; render Markdown in terminal | `bun repl`, `bun ./README.md` | node repl, glow | runtime-apis |
|
|
34
|
+
| Run Playwright, vitest, Next.js 16, OpenTelemetry, dd-trace | they now just work | Node.js | node-compat-platforms |
|
|
35
|
+
|
|
36
|
+
Free wins (no code change): 2x lower CPU, 13-48% less server memory, 2-2.5x faster startup — full numbers in [performance](references/performance.md).
|
|
37
|
+
|
|
38
|
+
## Operating rules
|
|
39
|
+
|
|
40
|
+
1. **Eval-first.** The `eval` js kernel runs on Bun (that is why this skill is present): call `Bun.*` APIs directly inside js cells. Reach for `bash` or a spawned `bun <file>` / `bun -e` only for CLI surfaces (`bun test`, `bun build`, `bun pm`) or work that needs a separate process.
|
|
41
|
+
2. **Builtin-first.** The Replaces column above is a ban list for new dependencies, in production code, test helpers, and one-off scripts alike.
|
|
42
|
+
3. **Read the matching reference before using an unfamiliar API** — signatures and caveats (e.g. `Bun.markdown` HTML is unsanitized, HTTP/3 is experimental) live there, not here.
|
|
43
|
+
4. **Upgrading a project to 1.4 or debugging behavior that changed?** Read [breaking-changes](references/breaking-changes.md) first — YAML/TOML strictness, `.xml`/`.css` import semantics, `Bun.$` globbing, fetch header combining, and WebSocket close timing all changed.
|
|
44
|
+
5. **TLS errors after upgrade are usually intentional** — 1.4 tightened certificate verification across `fetch`, `tls.connect`, `Bun.connect`, `RedisClient`. See [security](references/security.md) before loosening anything.
|
package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/breaking-changes.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Upgrading to Bun 1.4 — Behavior Changes
|
|
2
|
+
|
|
3
|
+
Blog: [#upgrading-to-1-4](https://bun.com/blog/bun-v1.4#upgrading-to-1-4). Most code is unaffected. Scan the Top 5, then the table for whatever subsystem you touched.
|
|
4
|
+
|
|
5
|
+
## Top 5 most likely to bite
|
|
6
|
+
|
|
7
|
+
1. **Node.js 26**: `NODE_MODULE_VERSION` is 147 (native addons need a 147 build); `res.writeHeader()` removed → use `res.writeHead()`; paused-mode `readable.read()` returns ONE chunk → loop until `null`.
|
|
8
|
+
2. **New monorepos default to the isolated linker** (`configVersion: 1`). Existing lockfiles keep hoisted. Opt out: `linker = "hoisted"` in bunfig.toml.
|
|
9
|
+
3. **Bun invoked as `node`** (`bun --bun`, `bunx --bun`, node symlink) no longer loads `.env` files. Pass `--env-file` to keep them.
|
|
10
|
+
4. **`Bun.YAML` is YAML 1.2**: `yes`/`no`/`on`/`off` are strings. GitHub Actions `on:` parses as `"on"`.
|
|
11
|
+
5. **`Bun.TOML` / `bunfig.toml` are strict**: unquoted strings, missing newlines, ints past `MAX_SAFE_INTEGER` → `SyntaxError` at startup. Quote your values.
|
|
12
|
+
|
|
13
|
+
## Module resolution / loaders
|
|
14
|
+
|
|
15
|
+
| Change | Migration |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `.xml` imports return the parsed document (was: file path) | `--loader .xml:file` to keep the path |
|
|
18
|
+
| `.css` imports at runtime export `{}` (was: absolute path) | — |
|
|
19
|
+
| `import "."` / `".."` resolve as directories (index/main), matching Node | name the sibling file explicitly |
|
|
20
|
+
| `"jsx": "react-jsx"` emits `jsx` (was: `jsxDEV` unless production) | use `"react-jsxdev"` for the dev runtime |
|
|
21
|
+
| `useDefineForClassFields: false` now honored like tsc | remove the option to keep old output |
|
|
22
|
+
|
|
23
|
+
## Bun APIs
|
|
24
|
+
|
|
25
|
+
| Change | Migration |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `Bun.$` globs only patterns written in the template — `${...}` interpolated globs are literal | write the pattern in the template: `` $`echo **/*` `` |
|
|
28
|
+
| `Bun.cron.parse()` / in-process `Bun.cron()` use LOCAL time (was UTC) | pass `{ tz: "UTC" }` |
|
|
29
|
+
| `Bun.Socket#setKeepAlive(true, delay)`: `delay` is milliseconds now | pass ms, not seconds |
|
|
30
|
+
| `Bun.mmap({ offset })`: view starts at `offset` exactly (was page-rounded) | remove `offset % pageSize` compensation |
|
|
31
|
+
| `bun:ffi`: `cstring` values are plain strings; `CString` has no `.ptr` | keep the original pointer to free |
|
|
32
|
+
| `Bun.serve({ inspector })` removed | `bun --inspect` |
|
|
33
|
+
| `server.publish()`/`ws.publish()` return `0` (dropped) / `-1` (backpressure) | treat 0/-1 specially |
|
|
34
|
+
| `server.stop()` waits for in-flight requests, closes idle connections | `stop(true)` to force |
|
|
35
|
+
| `Bun.sql`: MySQL `DATETIME`/`TIMESTAMP` decoded as UTC; MariaDB 10.5+ JSON columns parsed to objects | remove offset corrections and `JSON.parse()` calls |
|
|
36
|
+
| `Bun.randomUUIDv7()`, `Bun.udpSocket()`, `Bun.password`, `Bun.spawn` timeout/killSignal/argv0 | invalid inputs now throw instead of silently clamping |
|
|
37
|
+
|
|
38
|
+
## fetch / WebSocket / HTTP
|
|
39
|
+
|
|
40
|
+
| Change | Migration |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Duplicate headers combined with `, ` per Fetch spec (was: last wins) | parse combined values |
|
|
43
|
+
| `clone()` throws after body read (`Body is disturbed or locked`) | clone BEFORE reading |
|
|
44
|
+
| Network errors are `TypeError` (`.code` still set); failed body read sets `bodyUsed` | retry with a NEW fetch() |
|
|
45
|
+
| `redirect: "error"` rejects only on 301/302/303/307/308 (304 resolves now) | — |
|
|
46
|
+
| global `WebSocket` no longer accepts `agent` (ws module's does) | import from "ws" |
|
|
47
|
+
| `WebSocket#close()` queues the close event — `readyState` is CLOSING when it returns | await the `close` event |
|
|
48
|
+
| `close()`/`ping()`/`pong()` validate codes/reason/payload sizes | shorten/fix values |
|
|
49
|
+
| Handshake fails (1002) when requested subprotocol isn't negotiated | fix server echo or drop `protocols` |
|
|
50
|
+
|
|
51
|
+
## node: modules
|
|
52
|
+
|
|
53
|
+
| Change | Migration |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `fs.rmdir` rejects `{ recursive: true }` | `fs.rm(path, { recursive: true, force: true })` |
|
|
56
|
+
| `dns.lookup()` uses the system resolver (getaddrinfo) on Linux — split-DNS/VPN names now resolve | `Bun.dns.lookup(name, { backend: "c-ares" })` for old behavior |
|
|
57
|
+
| fs/dns/pbkdf2 callback exceptions are `uncaughtException` (was unhandledRejection) | move the handler |
|
|
58
|
+
| `dgram`: second `bind()` and post-`close()` calls throw synchronously | try/catch |
|
|
59
|
+
| `tls.createServer({ requestCert: true })` rejects unverified client certs by default | `rejectUnauthorized: false` to admit them |
|
|
60
|
+
| `X509Certificate` serial/modulus are UPPERCASE hex | normalize case when pinning |
|
|
61
|
+
| `child_process.spawn()` ignores `options.encoding` (always Buffers) | `child.stdout.setEncoding()` |
|
|
62
|
+
| `process.title` defaults to `argv[0]`; warnings print as `(node:PID) [CODE] ...` | — |
|
|
63
|
+
|
|
64
|
+
## bun test
|
|
65
|
+
|
|
66
|
+
- `jest.resetAllMocks()` drops implementations (matches Jest) — use `clearAllMocks()` for history-only.
|
|
67
|
+
- `toContain()` uses `===` (not `Object.is`); `toEqual()` compares Temporal by value.
|
|
68
|
+
|
|
69
|
+
## Misc
|
|
70
|
+
|
|
71
|
+
- x64 builds are baseline-only (no more separate haswell build; `-baseline` URLs still work).
|
|
72
|
+
- `Temporal` defined by default (`BUN_JSC_useTemporal=0` to disable).
|
|
73
|
+
- `bun.lock` is `lockfileVersion: 2`; nested/version-scoped overrides produce v3 (older Bun can't read v3).
|
|
74
|
+
- `bun feedback` removed; `Bun.password.hash()` argon2 requires `memoryCost >= 8`.
|
|
75
|
+
- Full exhaustive list: [Other behavior changes](https://bun.com/blog/bun-v1.4#other-behavior-changes) and the [Changelog](https://bun.com/blog/bun-v1.4#changelog).
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# bun build / Bun.build() in 1.4
|
|
2
|
+
|
|
3
|
+
## Built-in React Compiler [v1.4.0]
|
|
4
|
+
|
|
5
|
+
Blog: [#built-in-react-compiler](https://bun.com/blog/bun-v1.4#built-in-react-compiler)
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
await Bun.build({ entrypoints: ["./src/index.tsx"], outdir: "./dist", reactCompiler: true });
|
|
9
|
+
// or: bun build --react-compiler
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
React's auto-memoization compiler runs inside Bun's parser — no Babel/SWC round-trip. On ~860 components: +71ms build cost, ~20x faster than the Babel plugin (9.15s); full `--compile` build 3.6x faster.
|
|
13
|
+
|
|
14
|
+
## Barrel import optimization [v1.3.10]
|
|
15
|
+
|
|
16
|
+
Blog: [#barrel-import-optimization](https://bun.com/blog/bun-v1.4#barrel-import-optimization)
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
await Bun.build({ entrypoints: ["./src/index.tsx"], optimizeImports: ["antd", "@mui/material"] });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`import { Button } from "antd"` skips the hundreds of files behind names you didn't import. Automatic for packages with `"sideEffects": false`; opt others in with `optimizeImports`.
|
|
23
|
+
|
|
24
|
+
## Compile-time feature flags: bun:bundle [v1.3.5]
|
|
25
|
+
|
|
26
|
+
Blog: [#compile-time-feature-flags-with-bun-bundle](https://bun.com/blog/bun-v1.4#compile-time-feature-flags-with-bun-bundle)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { feature } from "bun:bundle";
|
|
30
|
+
if (feature("SUPER_SECRET")) { console.log("enabled"); }
|
|
31
|
+
// bun build --feature=SUPER_SECRET index.ts (also works in bun run and bun test)
|
|
32
|
+
// Bun.build({ features: ["SUPER_SECRET"] })
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Becomes `true`/`false` at build time; dead branch removed.
|
|
36
|
+
|
|
37
|
+
## In-memory files [v1.3.6]
|
|
38
|
+
|
|
39
|
+
Blog: [#in-memory-files-in-bun-build](https://bun.com/blog/bun-v1.4#in-memory-files-in-bun-build)
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
await Bun.build({
|
|
43
|
+
entrypoints: ["/app/index.ts"],
|
|
44
|
+
files: {
|
|
45
|
+
"/app/index.ts": `import { greet } from "./greet.ts"; console.log(greet("World"));`,
|
|
46
|
+
"/app/greet.ts": `export function greet(n: string) { return "Hello, " + n; }`,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Strings, Blobs, or TypedArrays; virtual paths override disk. Ideal for codegen and stubbing modules in tests.
|
|
52
|
+
|
|
53
|
+
## Single-file HTML [v1.3.10]
|
|
54
|
+
|
|
55
|
+
Blog: [#single-file-html-with-compile-target-browser](https://bun.com/blog/bun-v1.4#single-file-html-with-compile-target-browser)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
bun build ./index.html --compile --target=browser --outdir=dist
|
|
59
|
+
# → dist/index.html — every script/stylesheet/asset inlined, opens from file://
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## --asset: embed files/dirs into executables [v1.4.0]
|
|
63
|
+
|
|
64
|
+
Blog: [#asset](https://bun.com/blog/bun-v1.4#asset)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
bun build ./build/index.js --compile \
|
|
68
|
+
--asset ./build/client --asset ./build/prerendered \
|
|
69
|
+
--outfile server
|
|
70
|
+
./server # every route + static asset served from the binary
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Keeps original filenames; `path.join(import.meta.dir, ...)` works. `node:fs` treats `/$bunfs/` as a real tree (`existsSync`, `readdirSync` recursive/withFileTypes, ...), so static-file servers run unmodified inside the binary.
|
|
74
|
+
|
|
75
|
+
## Bytecode for ES modules [v1.3.9]
|
|
76
|
+
|
|
77
|
+
Blog: [#bytecode-compilation-for-es-modules](https://bun.com/blog/bun-v1.4#bytecode-compilation-for-es-modules)
|
|
78
|
+
|
|
79
|
+
`--bytecode --format=esm` (requires `--compile`) enables top-level await, `import.meta`, dynamic imports, and code splitting in bytecode-compiled binaries (previously CJS-only).
|
|
80
|
+
|
|
81
|
+
## metafile: true and --metafile-md [v1.3.6 / v1.3.8]
|
|
82
|
+
|
|
83
|
+
Blog: [#metafile-true](https://bun.com/blog/bun-v1.4#metafile-true), [#metafile-md](https://bun.com/blog/bun-v1.4#metafile-md)
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const result = await Bun.build({ entrypoints: ["./index.js"], metafile: true });
|
|
87
|
+
result.metafile.inputs; result.metafile.outputs; // esbuild metafile format — works with esbuild.github.io/analyze
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bun build entry.js --metafile-md=analysis.md --outdir=dist # Markdown bundle report: largest modules,
|
|
92
|
+
# per-entry breakdowns, dependency chains — grep it or hand to an LLM
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Standard TC39 decorators [v1.3.10]
|
|
96
|
+
|
|
97
|
+
Blog: [#standard-tc39-decorators](https://bun.com/blog/bun-v1.4#standard-tc39-decorators)
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
function logged(value, { kind, name }) {
|
|
101
|
+
if (kind === "method") return function (...args) { console.log(`calling ${name}`); return value.call(this, ...args); };
|
|
102
|
+
}
|
|
103
|
+
class C { @logged greet() {} }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Active when `experimentalDecorators` is off in tsconfig. Classes, methods, fields, accessors, private members; passes esbuild's decorator test suite.
|
|
107
|
+
|
|
108
|
+
## Code splitting: 14x faster on huge graphs [v1.4.0]
|
|
109
|
+
|
|
110
|
+
Reachability walk is now BFS O(V+E); a 20,000-module DAG links in 320ms (was 4.65s). Tree-shaking/TLA/CSS-order passes use explicit stacks, so linear chains of thousands of modules link without stack growth.
|
|
111
|
+
|
|
112
|
+
## Compile gotcha (v1.3.4 change)
|
|
113
|
+
|
|
114
|
+
`bun build --compile` binaries no longer auto-load `tsconfig.json` / `package.json` from the runtime cwd. Opt back in with `--compile-autoload-tsconfig` / `--compile-autoload-package-json`. `.env` and `bunfig.toml` still auto-load.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Bun 1.4 Dev Tooling & Observability
|
|
2
|
+
|
|
3
|
+
Blog: [#dev-tooling](https://bun.com/blog/bun-v1.4#dev-tooling), [#observability](https://bun.com/blog/bun-v1.4#observability)
|
|
4
|
+
|
|
5
|
+
## Markdown profilers — built for terminals and LLMs
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun --cpu-prof-md ./app.ts # CPU profile as Markdown: hot functions by self time,
|
|
9
|
+
# call tree, who-calls-whom. grep it, paste into a bug or an LLM.
|
|
10
|
+
bun --heap-prof-md ./app.ts # heap profile as Markdown: total size, types by retained size,
|
|
11
|
+
# largest objects, retention chains. Includes grep recipes in the header.
|
|
12
|
+
bun build ./src/index.ts --outdir ./dist --metafile-md=./dist/meta.md # bundle-size analysis as Markdown
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- `bun --cpu-prof` / `--heap-prof` still write `.cpuprofile` / V8-compatible `.heapsnapshot` for Chrome DevTools / VS Code.
|
|
16
|
+
- `BUN_CPU_PROFILE=1` turns on the CPU profiler for a process you cannot pass flags to (e.g. a framework-spawned worker).
|
|
17
|
+
- **Agent workflow: when a Bun process is slow or leaking, run the `-md` variants and read the report directly — no DevTools round-trip.**
|
|
18
|
+
|
|
19
|
+
## Async stack traces [v1.4.0]
|
|
20
|
+
|
|
21
|
+
Errors from async native APIs (`fs.promises`, `Bun.file()`, S3, DNS, crypto, `fetch`) point at the `await` in your code, not native frames.
|
|
22
|
+
|
|
23
|
+
## Process lifetime & env flags
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun --no-orphans app.ts # exit when parent dies; SIGKILL every descendant on exit (Linux/macOS/Windows)
|
|
27
|
+
bun --no-env-file app.ts # skip automatic .env loading (or env = false in bunfig.toml) — use in prod/CI
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## APM / tracing works now
|
|
31
|
+
|
|
32
|
+
- **`node:inspector`**: a `Session` can start/stop CPU profiles while the app runs (`Profiler.start`/`Profiler.stop`).
|
|
33
|
+
- **Datadog**: `dd-trace` traces requests; `@datadog/pprof` profiles continuously (required V8 C++ APIs implemented).
|
|
34
|
+
- **OpenTelemetry**: `@opentelemetry/instrumentation-http` and `-fs` export spans; `shimmer` and `require-in-the-middle` can patch bundled code.
|