@code-yeongyu/senpi 2026.10.10-3 → 2026.10.10-4

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/bundle/chunks/{app-server-command-DVWM37GF.js → app-server-command-N3L2LNP7.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-MT2C4I5R.js → chunk-MP2DMTI7.js} +38 -37
  4. package/dist/bundle/chunks/chunk-USRAHAW4.js +14 -0
  5. package/dist/bundle/chunks/{chunk-CTERKXVZ.js → chunk-ZSYRWQWG.js} +2 -2
  6. package/dist/bundle/chunks/{cli-main-B4S4DGBX.js → cli-main-CHDR33FZ.js} +1 -1
  7. package/dist/bundle/chunks/{interactive-mode-QOFA64JL.js → interactive-mode-RVEM62WX.js} +1 -1
  8. package/dist/bundle/chunks/{multi-session-host-E5RDPWQN.js → multi-session-host-CFND7CXH.js} +1 -1
  9. package/dist/bundle/chunks/{package-manager-cli-YGTWXRG5.js → package-manager-cli-NWNECBF7.js} +1 -1
  10. package/dist/bundle/chunks/{rpc-mode-HDAGQ4X3.js → rpc-mode-JQFUDLNB.js} +1 -1
  11. package/dist/bundle/chunks/session-control-endpoint-HMB5T5VD.js +3 -0
  12. package/dist/bundle/chunks/session-worker.js +53 -52
  13. package/dist/bundle/cli.js +1 -1
  14. package/dist/bundle/index.js +1 -1
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/bundle/runtime-manifest.json +1 -1
  17. package/dist/core/extensions/session-control-types.d.ts +25 -0
  18. package/dist/core/extensions/session-control-types.js +16 -0
  19. package/dist/core/external-admission.js +7 -1
  20. package/dist/core/resource-loader.js +63 -2
  21. package/dist/core/session-rebind.js +16 -1
  22. package/dist/modes/interactive/components/extension-editor.js +4 -0
  23. package/dist/modes/interactive/components/remote-delivery-message.d.ts +6 -3
  24. package/dist/modes/interactive/components/remote-delivery-message.js +32 -3
  25. package/dist/modes/interactive/interactive-mode.d.ts +17 -0
  26. package/dist/modes/interactive/interactive-mode.js +58 -29
  27. package/dist/modes/interactive/interactive-stderr-guard.d.ts +8 -0
  28. package/dist/modes/interactive/interactive-stderr-guard.js +70 -0
  29. package/dist/modes/interactive/session-control-commands.d.ts +2 -1
  30. package/dist/modes/interactive/session-control-commands.js +21 -7
  31. package/dist/modes/interactive/session-control-session-commands.d.ts +22 -0
  32. package/dist/modes/interactive/session-control-session-commands.js +47 -0
  33. package/dist/modes/interactive/stdout-fd-redirect.d.ts +12 -0
  34. package/dist/modes/interactive/stdout-fd-redirect.js +114 -0
  35. package/dist/modes/rpc/connection-handler.js +6 -15
  36. package/dist/modes/rpc/rpc-types.d.ts +13 -0
  37. package/dist/modes/rpc/session-control-actions-data.d.ts +17 -0
  38. package/dist/modes/rpc/session-control-actions-data.js +38 -0
  39. package/docs/extensions.md +1 -1
  40. package/docs/rpc.md +38 -4
  41. package/package.json +6 -6
  42. package/dist/bundle/chunks/chunk-PDSG6VER.js +0 -14
  43. package/dist/bundle/chunks/session-control-endpoint-NABTZHCZ.js +0 -3
@@ -1684,7 +1684,7 @@ runtime's steering or follow-up queue like the user's queued input. The protocol
1684
1684
  |---|---|---|
1685
1685
  | `registerControlEndpoint({ inboxDir, drain, isSessionReferenced? })` | `Promise<SessionControlRegistration>` | POSIX interactive session: binds the `tui` control endpoint and answers `{ status: "registered", socket, dispose }`. On a multi-session host with a public socket it binds nothing and `socket` is the host's. Otherwise `{ status: "unsupported", reason: "unsupported_platform" \| "unsupported_mode" }`, or `{ status: "failed", reason }` when a registration step failed. `drain(event)` runs on every [`session_control_wake`](#session_control_wake) edge and answers `{ admitted: [{ delivery_id, kind }] }`. `inboxDir` is created 0700 and its entry creations and deletions wake the drain. At clean exit a header-only session file is removed unless `isSessionReferenced()` answers `true`. |
1686
1686
  | `admissionGate()` | `{ can_admit, hold_reason?, editor_revision, turn_epoch }` | Read-only pre-check; `hold_reason` is `draft` while the user composes or their submission is still on its way into the runtime. |
1687
- | `admitExternalMessage({ delivery_id, text, deliverAs, expected_turn_id? })` | `{ kind, turn_epoch }` | Decides and acts in one synchronous call. `kind` is `started`, `queued`, `steered`, `turn_conflict` (stale epoch, or a steer without one), `held_draft` (nothing enqueued; retry on the next wake) or `already_admitted` (also for a delivery whose entry the file refused, until the run that refused it has settled and the file's last write succeeded). The delivery becomes a `custom` entry `session_control_delivery` whose `details.delivery_id` proves it was applied. Throws once a host started handing the session over (`release_session`). |
1687
+ | `admitExternalMessage({ delivery_id, text, deliverAs, expected_turn_id?, sender?, display_text? })` | `{ kind, turn_epoch }` | Decides and acts in one synchronous call. `kind` is `started`, `queued`, `steered`, `turn_conflict` (stale epoch, or a steer without one), `held_draft` (nothing enqueued; retry on the next wake) or `already_admitted` (also for a delivery whose entry the file refused, until the run that refused it has settled and the file's last write succeeded). The delivery becomes a `custom` entry `session_control_delivery` whose `details.delivery_id` proves it was applied. Throws once a host started handing the session over (`release_session`). `sender` (`{ kind: "agent", session_id, name? }`, `{ kind: "command_line", user? }` or `{ kind: "external", platform, author? }`) and `display_text` (the message as written) go to the entry's `details`: the terminal labels the message by its sender over `display_text`, while the model reads `text`. |
1688
1688
  | `listAdmittedDeliveries()` | `{ pending, emitted, failed? }` | The process-lifetime ledger: `pending` is held by the runtime, `emitted` has its transcript entry written, `failed` (present only when non-empty, `[{ delivery_id, error }]`) had its entry refused by the session file: no longer held, still with its sender, admissible again once the run that refused it has settled and the file's last write succeeded. |
1689
1689
  | `persistHeaderNow()` | `Promise<void>` | Writes the session header now, so the session id is durable before anything exposes it. |
1690
1690
 
package/docs/rpc.md CHANGED
@@ -1147,10 +1147,11 @@ registrant opens no socket and writes no registry directory.
1147
1147
  `endpoint_kind: "tui"`, `owner` and `alive`, probing it for at most 1.5 s. `senpi host gc` reaps a dead one on
1148
1148
  the same evidence as a host. `ensure`, `handoff` and `stop` refuse it with `unsupported_endpoint_kind` (exit 3)
1149
1149
  before connecting, because a terminal endpoint is owned by its terminal process.
1150
- - **Commands.** The command set is read-mostly. Anything not listed below is answered `unsupported` as data. No
1151
- command can prompt, steer, queue a follow-up, open a session, run a command or change a model.
1152
- - `get_protocol_info`: `mode: "tui"`, `capabilities: ["tui_control"]`, `generation: 0` and the endpoint's
1153
- `instanceId`.
1150
+ - **Commands.** Anything not listed below is answered `unsupported` as data. No command can prompt, steer, queue a
1151
+ follow-up, open a session or run a command.
1152
+ - `get_protocol_info`: `mode: "tui"`, `capabilities: ["tui_control"]`, `generation: 0`, the endpoint's
1153
+ `instanceId`, and `commands`: every command this endpoint accepts. A terminal from before the session
1154
+ controls below lists no `commands`.
1154
1155
  - `list_sessions`: exactly one row, `kind: "interactive"`, `surface: "tui"`, `attachments: 1`.
1155
1156
  - `get_state`: the RPC session state plus `turn_epoch`, `blocking_question`, `compacting`,
1156
1157
  `editor_has_draft` and `state_version`.
@@ -1166,6 +1167,21 @@ registrant opens no socket and writes no registry directory.
1166
1167
  question (a pending question id from the `question` feed); without it, `id` does. The answer settles by
1167
1168
  the host's rule (see `question`) and the reply carries the frame's `id`, as on a host (see "Extension
1168
1169
  UI Responses").
1170
+ - The session controls run the pane's own paths, so validation, the footer and persistence are the ones the
1171
+ user gets doing it in that terminal:
1172
+ - `get_available_models` and `get_available_thinking_levels`: the same answers as a host's.
1173
+ - `set_model { provider, modelId }`: the `/model` switch (the footer, the remembered default model, the
1174
+ pane's status line). An unknown model is refused `Model not found: <provider>/<modelId>`; a switch the
1175
+ session refuses answers its reason. Success answers the model, as on a host.
1176
+ - `set_thinking_level { level, scope? }`: the thinking-level selector. `scope: "turn"` sets this session's
1177
+ level; otherwise the level is also remembered for the model (the selector's Ctrl+S). A level the active
1178
+ model cannot run is refused `Thinking level <level> is not supported by the active model.` and nothing
1179
+ changes, for either scope. A host refuses it only for `scope: "turn"`; for the default scope a host clamps it
1180
+ to a level the model runs.
1181
+ - `interrupt { turnId? }`: Esc on a running turn - queued input returns to the editor, the turn aborts and
1182
+ settles before the answer. Answers `{ interrupted: true, turnId }` with the `turn_epoch` it stopped. An idle
1183
+ session answers `{ interrupted: false }`; a `turnId` that is not the running turn answers
1184
+ `{ interrupted: false, turnId }` with the running one and leaves it alone. The session stays open.
1169
1185
  - `prompt`, `steer` and `follow_up` are `unsupported`.
1170
1186
  - **Admission.** A message from another session enters only through the registrant's drain, which calls
1171
1187
  `pi.session.admitExternalMessage({ delivery_id, text, deliverAs, expected_turn_id? })`. One synchronous call
@@ -1726,6 +1742,24 @@ Response:
1726
1742
  {"type": "response", "command": "abort", "success": true}
1727
1743
  ```
1728
1744
 
1745
+
1746
+ #### interrupt
1747
+
1748
+ Stop the running turn and only that one, with the terminal control endpoint's contract (see "Interactive sessions
1749
+ expose a control endpoint"). `turnId` (the `turn_epoch` of `get_state`) is optional.
1750
+
1751
+ ```json
1752
+ {"type": "interrupt", "turnId": "3"}
1753
+ ```
1754
+
1755
+ Response: `{ interrupted: true, turnId }` once the turn has stopped; `{ interrupted: false }` when the session is
1756
+ idle; `{ interrupted: false, turnId }` (the running turn) when `turnId` names another turn. Unlike `abort`, it
1757
+ answers after the turn settled.
1758
+
1759
+ ```json
1760
+ {"type": "response", "command": "interrupt", "success": true, "data": {"interrupted": true, "turnId": "3"}}
1761
+ ```
1762
+
1729
1763
  #### clear_queue
1730
1764
 
1731
1765
  Remove queued steering and follow-up messages and return their text.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi",
3
- "version": "2026.10.10-3",
3
+ "version": "2026.10.10-4",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -57,9 +57,9 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@earendil-works/chord": "0.99.1",
60
- "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.10.10-3",
61
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.10-3",
62
- "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.10.10-3",
60
+ "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.10.10-4",
61
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.10-4",
62
+ "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.10.10-4",
63
63
  "@silvia-odwyer/photon-node": "0.3.4",
64
64
  "chalk": "6.0.0",
65
65
  "cross-spawn": "7.0.6",
@@ -78,8 +78,8 @@
78
78
  "yaml": "2.9.1",
79
79
  "@anthropic-ai/claude-agent-sdk": "0.3.289",
80
80
  "@anthropic-ai/sdk": "0.127.0",
81
- "@code-yeongyu/senpi-codemode": "2026.10.10-3",
82
- "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.10.10-3",
81
+ "@code-yeongyu/senpi-codemode": "2026.10.10-4",
82
+ "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.10.10-4",
83
83
  "@modelcontextprotocol/sdk": "1.30.0",
84
84
  "@mozilla/readability": "0.6.0",
85
85
  "linkedom": "0.18.13",