@code-yeongyu/senpi 2026.11.6-1 → 2026.11.6-2
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 +35 -0
- package/dist/bundle/chunks/{chunk-5MWHZH2O.js → chunk-2FDW2LQL.js} +1 -1
- package/dist/bundle/chunks/{chunk-GG2JO3CL.js → chunk-4E7GDG4H.js} +1 -1
- package/dist/bundle/chunks/{chunk-K5JLYACP.js → chunk-4GKU755E.js} +1 -1
- package/dist/bundle/chunks/{chunk-437VLZQZ.js → chunk-7III44PV.js} +1 -1
- package/dist/bundle/chunks/chunk-7PSBD5KS.js +9 -0
- package/dist/bundle/chunks/{chunk-KFWHLVVH.js → chunk-C7OKUC7L.js} +1 -1
- package/dist/bundle/chunks/{chunk-CX32K5KD.js → chunk-CF5OGBC4.js} +7 -7
- package/dist/bundle/chunks/{chunk-7TGZJH6Z.js → chunk-D5MRJWUK.js} +40 -39
- package/dist/bundle/chunks/{chunk-E6L5VZSM.js → chunk-DSWDJ7HT.js} +1 -1
- package/dist/bundle/chunks/{chunk-6NMTFURP.js → chunk-ECW7VBMB.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CSLJLM6.js → chunk-GKAYPJ4E.js} +2 -2
- package/dist/bundle/chunks/{chunk-KCGUUIUS.js → chunk-GNSMNSL7.js} +1 -1
- package/dist/bundle/chunks/{chunk-V3JSQ3PG.js → chunk-GSKCWXXG.js} +1 -1
- package/dist/bundle/chunks/{chunk-USKWGPA6.js → chunk-GTJJ73DE.js} +1 -1
- package/dist/bundle/chunks/{chunk-HHSYTDKO.js → chunk-HLM46XEB.js} +2 -2
- package/dist/bundle/chunks/{chunk-A4F4J2KH.js → chunk-I3PHVJAS.js} +2 -2
- package/dist/bundle/chunks/{chunk-LAMRXFHZ.js → chunk-LNPAT22L.js} +1 -1
- package/dist/bundle/chunks/chunk-NH7SYIGN.js +2 -0
- package/dist/bundle/chunks/{chunk-ZIIDIVTG.js → chunk-R2Z7CX77.js} +1 -1
- package/dist/bundle/chunks/{chunk-32I42CEY.js → chunk-RQ6CHXQ2.js} +1 -1
- package/dist/bundle/chunks/chunk-SJI6UB23.js +2 -0
- package/dist/bundle/chunks/{chunk-KUIEHAPR.js → chunk-T2SMQPRE.js} +1 -1
- package/dist/bundle/chunks/{chunk-IPG434JT.js → chunk-TIPKAMSS.js} +1 -1
- package/dist/bundle/chunks/{chunk-RI5ABX7A.js → chunk-TMXRR3N7.js} +2 -2
- package/dist/bundle/chunks/chunk-VD7AKTGP.js +3 -0
- package/dist/bundle/chunks/{chunk-22JICYKS.js → chunk-WAOGBBZR.js} +1 -1
- package/dist/bundle/chunks/{chunk-6MHCFJDB.js → chunk-WGRKM3N6.js} +2 -2
- package/dist/bundle/chunks/{chunk-WF5R2VSP.js → chunk-X5ZVYNOL.js} +1 -1
- package/dist/bundle/chunks/{chunk-H2FBGZNP.js → chunk-XCMII2VQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-5JUCTKYS.js → chunk-YK3ZZCHI.js} +1 -1
- package/dist/bundle/chunks/{cli-main-ZQBSX5H5.js → cli-main-T74YJGIF.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-7U7354GG.js → hand-entry-AYRUGE2A.js} +2 -2
- package/dist/bundle/chunks/{headless-host-7LKTG76U.js → headless-host-ES74ZB6M.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-NLSWH2CA.js → help-fast-path-TMTGLOBG.js} +1 -1
- package/dist/bundle/chunks/{host-command-3YRFN35E.js → host-command-YRXZE4TV.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-6XLVIECJ.js → host-lifecycle-6VCXMPDW.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +1 -1
- package/dist/bundle/chunks/{host-session-command-F7USXUZV.js → host-session-command-N7IN7ZDV.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-4RF3PUQ2.js → interactive-mode-B5SQDLH7.js} +1 -1
- package/dist/bundle/chunks/{list-tips-H6VGDFTS.js → list-tips-DU57HHKA.js} +1 -1
- package/dist/bundle/chunks/{main-G2SRZYQN.js → main-UQFVFCNY.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-RPN54GUC.js → multi-session-host-XSUJDHFZ.js} +5 -5
- package/dist/bundle/chunks/{openai-codex-responses-MJZKUS6I.js → openai-codex-responses-7V6LTDRU.js} +2 -2
- package/dist/bundle/chunks/{package-manager-cli-D2VFD463.js → package-manager-cli-GLUNPQJU.js} +1 -1
- package/dist/bundle/chunks/{role-37WVG42T.js → role-RRFFHZF5.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-QELPMM4N.js → rotation-stream-BN2YK2MC.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-P4D3DVYD.js → rpc-mode-JYN3E7P7.js} +1 -1
- package/dist/bundle/chunks/rpc-monitor-source-C6VQ3BC4.js +3 -0
- package/dist/bundle/chunks/{run-attached-tui-CGA6O5FR.js → run-attached-tui-W236SEOR.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-XWSNOAGG.js → schedule-command-B2EJTBOE.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-YIMLHGLG.js +3 -0
- package/dist/bundle/chunks/{session-picker-OA2AUVZG.js → session-picker-E6ZONUJB.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +294 -292
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli/project-trust-headless.d.ts +13 -0
- package/dist/cli/project-trust-headless.js +35 -0
- package/dist/cli/project-trust.js +13 -50
- package/dist/cli/schedule-delivery.d.ts +4 -0
- package/dist/cli/schedule-delivery.js +6 -0
- package/dist/cli/schedule-runner.js +8 -0
- package/dist/cli/session-opening.d.ts +19 -0
- package/dist/cli/session-opening.js +47 -1
- package/dist/core/agent-session-runtime.d.ts +12 -0
- package/dist/core/agent-session-runtime.js +41 -0
- package/dist/core/agent-session.js +13 -22
- package/dist/core/egress/api-table.d.ts +121 -0
- package/dist/core/egress/api-table.js +41 -0
- package/dist/core/egress/classify.d.ts +19 -0
- package/dist/core/egress/classify.js +197 -0
- package/dist/core/egress/credential-fields.d.ts +18 -0
- package/dist/core/egress/credential-fields.js +83 -0
- package/dist/core/egress/custody-sidecar.d.ts +44 -0
- package/dist/core/egress/custody-sidecar.js +91 -0
- package/dist/core/egress/device-custody.d.ts +12 -0
- package/dist/core/egress/device-custody.js +82 -0
- package/dist/core/egress/endpoint.d.ts +33 -0
- package/dist/core/egress/endpoint.js +115 -0
- package/dist/core/execute-tool-on-host.d.ts +26 -0
- package/dist/core/execute-tool-on-host.js +96 -0
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +15 -0
- package/dist/core/extensions/builtin/goal/index.js +15 -3
- package/dist/core/extensions/builtin/goal/stop-pause.d.ts +2 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +5 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.d.ts +10 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.js +34 -6
- package/dist/core/extensions/builtin/herdr/index.js +6 -2
- package/dist/core/extensions/builtin/mcp/service.d.ts +9 -1
- package/dist/core/extensions/builtin/mcp/service.js +32 -1
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.d.ts +43 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.js +158 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.js +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.d.ts +5 -2
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.js +19 -4
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.js +15 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.d.ts +10 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.js +28 -2
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.d.ts +59 -0
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.js +15 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.js +14 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor-rpc.js +8 -1
- package/dist/core/extensions/loader.js +8 -0
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/foreign-session-holders.d.ts +1 -1
- package/dist/core/foreign-session-holders.js +3 -3
- package/dist/core/session-import/jsonl-import.d.ts +8 -12
- package/dist/core/session-import/jsonl-import.js +99 -40
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.js +7 -2
- package/dist/core/session-store/durable-binding.d.ts +2 -0
- package/dist/core/session-store/durable-binding.js +26 -4
- package/dist/core/settings-manager.d.ts +20 -0
- package/dist/core/settings-manager.js +51 -0
- package/dist/core/trust-manager.d.ts +1 -18
- package/dist/core/trust-manager.js +3 -124
- package/dist/core/trust-requiring-resources.d.ts +21 -0
- package/dist/core/trust-requiring-resources.js +189 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/main.js +42 -12
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/session-control-commands.js +2 -0
- package/dist/modes/rpc/connection-handler.js +17 -0
- package/dist/modes/rpc/connection-question-bridge.js +7 -4
- package/dist/modes/rpc/effect-commands.d.ts +24 -0
- package/dist/modes/rpc/host-boot-extensions.d.ts +4 -0
- package/dist/modes/rpc/host-boot-extensions.js +17 -0
- package/dist/modes/rpc/host-lifecycle-shutdown.js +11 -2
- package/dist/modes/rpc/loopless-runtime-settings.js +5 -1
- package/dist/modes/rpc/method-classes-schema-session.d.ts +33 -0
- package/dist/modes/rpc/method-classes-schema-session.js +4 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +33 -0
- package/dist/modes/rpc/method-classes.d.ts +4 -0
- package/dist/modes/rpc/method-classes.js +7 -0
- package/dist/modes/rpc/multi-session-host.d.ts +2 -0
- package/dist/modes/rpc/multi-session-host.js +7 -2
- package/dist/modes/rpc/project-workspace-commands.d.ts +60 -0
- package/dist/modes/rpc/project-workspace-commands.js +145 -0
- package/dist/modes/rpc/rpc-error-types.d.ts +11 -1
- package/dist/modes/rpc/rpc-error-types.js +10 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +15 -0
- package/dist/modes/rpc/session-attachment-gate.js +2 -0
- package/dist/modes/rpc/session-command-activity.js +2 -0
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +41 -2
- package/docs/extensions.md +17 -1
- package/docs/rpc.md +121 -4
- package/docs/terminal-tools.md +8 -0
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-FUQJK2TU.js +0 -2
- package/dist/bundle/chunks/chunk-POZMRM6V.js +0 -2
- package/dist/bundle/chunks/chunk-XBG63MJZ.js +0 -8
- package/dist/bundle/chunks/chunk-YP47G4YP.js +0 -3
- package/dist/bundle/chunks/rpc-monitor-source-KKN2UP4T.js +0 -3
- package/dist/bundle/chunks/session-control-endpoint-OST7WAKP.js +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2026.11.6-2] - 2026-11-07
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Custody field classification for the provider surface (models.json, auth.json credentials, the credential pool), the URL secret marking rule with an `Endpoint` split, per-api custody facts, and a `custody.json` sidecar reader and atomic writer, for hosted brains; nothing is wired into a runtime path yet and existing configurations are unchanged ([#5893](https://github.com/code-yeongyu/senpi/pull/5893))
|
|
10
|
+
- `monitor` rpc targets can name a session on another device (`<device>/<session>`, `<device>/*`) when an extension registers a source with `pi.registerRpcRemoteSource`; lines read like local ones, a turn end is reported once, and a persistent watch resumes from the source's cursor after a restart ([#6151](https://github.com/code-yeongyu/senpi/pull/6151))
|
|
11
|
+
- `agent_start` and `agent_settled` carry `turnId`, including the settle a session closed mid-turn owes ([#6151](https://github.com/code-yeongyu/senpi/pull/6151))
|
|
12
|
+
- RPC: `get_project_trust`, `set_project_trust`, `get_project_settings` and `set_project_setting` let a client trust the session's workspace with the same choices and storage as `/trust`, and read or write its project settings file, so per-workspace settings, skills, prompts, extensions and MCP servers work over RPC as in the terminal ([#6177](https://github.com/code-yeongyu/senpi/pull/6177), fixes #6176)
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `pi.executeTool()` runs its call on the session's prepared pipeline, the same in-process executor model-issued calls run on, and the call produces an execution-pipeline receipt (`{ pipeline: "prepared", toolCallId }`) through the session's witness sink. Errors, blocks, updates, abort and the result are unchanged ([#5852](https://github.com/code-yeongyu/senpi/pull/5852)).
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Quitting the TUI in the middle of a turn ends that turn first. The closing process no longer sends another model request, and an active goal stops as interrupted, so reopening the session asks before it continues ([#5753](https://github.com/code-yeongyu/senpi/issues/5753))
|
|
21
|
+
- A JSONL import that only extends a durable session appends the new entries instead of rewriting the session, so it keeps an entry another writer appended meanwhile, also after a burst of appends such as a message and its tool result ([#5955](https://github.com/code-yeongyu/senpi/pull/5955)).
|
|
22
|
+
- `/resume` of a session whose process died mid-goal, or opening it at launch with `--continue`/`--session`, now asks "Resume blocked goal?" before any goal continuation runs, instead of continuing the goal behind the first message. Over RPC the goal stays blocked until the client resumes it (#5755).
|
|
23
|
+
- `--session`, `--continue`, `--resume`, `--rebind` and `--session-id` no longer open a session another live process is running as a second writer, and a refused start leaves that session's file exactly as it was (no migration rewrite, no torn-tail truncation, no move). Without a terminal to ask (print, JSON, RPC, no TTY) startup exits 76 naming the holder; an interactive terminal asks whether to take over (the holder is stopped first, as `/resume` does) or cancel. A scheduled prompt whose session is opened just before delivery stays pending and is retried instead of being marked failed ([#5970](https://github.com/code-yeongyu/senpi/pull/5970), fixes #5756)
|
|
24
|
+
- Alt+Q (restore queued messages), Alt+V and Alt+Z work again on WSL in Windows Terminal 1.25+, where the terminal negotiates the Kitty keyboard protocol but the keys still arrive in the legacy ESC-prefixed form ([#6058](https://github.com/code-yeongyu/senpi/issues/6058)).
|
|
25
|
+
- A question that already has its winning answer refuses a late `extension_ui_progress` draft with `question_already_resolved` instead of overwriting the answer it is settling with (senpi#5960)
|
|
26
|
+
- When shutdown recovery after a pre-signal failure throws, both errors are logged exactly once — the recovery error where it happens, the original by the shutdown handler — and the original is still reported instead of being replaced by the recovery error ([#3067](https://github.com/code-yeongyu/senpi/issues/3067), [#6144](https://github.com/code-yeongyu/senpi/pull/6144)).
|
|
27
|
+
- A `--multi-session` RPC host whose launch carries a private descriptor table (`SENPI_PRIVATE_FDS`) now loads its extensions once at boot, so an extension can claim its private channel before any session opens ([#6148](https://github.com/code-yeongyu/senpi/pull/6148))
|
|
28
|
+
- Deterministic compaction recovery keeps a valid reasoning-effort change (`configurationUpdate`) in the retained suffix instead of omitting it as not replay-safe ([#8566](https://github.com/code-yeongyu/senpi/issues/8566), [#6149](https://github.com/code-yeongyu/senpi/pull/6149)).
|
|
29
|
+
- A herdr pane no longer stays `working` after its turn while only a persistent monitor or a background terminal session is live; it reports `idle` and names them (one-shot monitors with a deadline still read `working`). Partly reverses #2077 ([#6153](https://github.com/code-yeongyu/senpi/pull/6153))
|
|
30
|
+
- The terminal (TUI) control endpoint's `get_protocol_info` now carries `method_classes`, the same table and digest as an rpc host, so a remote client can classify commands to a TUI-held session ([#6158](https://github.com/code-yeongyu/senpi/issues/6158))
|
|
31
|
+
- `agent_start` and `agent_settled` no longer carry `turnId` on the RPC wire (it leaked past the legacy-wire contract); a remote `monitor` watch reports each `agent_settled` it receives, and its resync still reports each settled turn once ([#6166](https://github.com/code-yeongyu/senpi/pull/6166))
|
|
32
|
+
- A caller that passes no session id no longer receives a peer session's MCP wire status while more than one session is live, and a release with no reason no longer leaves the released session's status in the single-session fallback; `getServerSnapshots` accepts an optional session id to scope to that session's servers (API-only for now: no production caller passes one yet) ([#3001](https://github.com/code-yeongyu/senpi/issues/3001), [#6169](https://github.com/code-yeongyu/senpi/pull/6169)).
|
|
33
|
+
- RPC `prompt`, `steer` and `follow_up` with a missing or non-string `message` are refused with `message must be a string.` instead of failing with a raw `TypeError` ([#6171](https://github.com/code-yeongyu/senpi/issues/6171))
|
|
34
|
+
- The RPC project trust commands no longer run synchronous filesystem probes on the shared host's session path ([#6187](https://github.com/code-yeongyu/senpi/pull/6187))
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
3
38
|
## [2026.11.6-1] - 2026-11-06
|
|
4
39
|
|
|
5
40
|
### Breaking Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CUSTOM_UNSUPPORTED_CAPABILITY,DEFAULT_PROBE_TIMEOUT_MS,DEFAULT_STOP_TIMEOUT_MS,ENDPOINT_OWNER_FENCE_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,RPC_CLIENT_CAPABILITIES_ENV,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SIGKILL_GRACE_MS,STARTUP_DECISION_BUDGET_MS,STOP_WAIT_BUDGET_MS,announceStop,anyGenerationLive,busyLegacyHostDetail,computeRuntimeBuildId,decideHostAction,delay,describeSessions,electPointer,engineBuildIdentity,ensureLockWaitDetail,ensureSender,gcEndpoint,gcHostEndpoints,holdProtocolInfo,holdSessionCount,hostLaunchProfile,isNodeErrorCode,judgeStaleEngine,matchesPidFileOrUnknown,observeProtocolInfo,parseHostStopGeneration,probeProtocolInfo,probeSocketReachable,provenLegacyOwner,recordEscalation,resolvePidFileOwnership,retireIdleLegacyHost,signalGeneration,signalPid,socketHostLaunchProfile,staleStopGeneration,startStartupController,startupEnvelope,startupTimeoutDetail,stopHost,stopManagedHost,stopSpawnedChild}from"./chunk-HHSYTDKO.js";import{endpointKindOfSocket,listHostEndpoints}from"./chunk-Y7Z7XPUF.js";import{isSessionRuntimeKind,isToolRuntimeKind,toolRuntimeCapability}from"./chunk-54YTJCYZ.js";import{requestOnSocket}from"./chunk-I5ASHSLZ.js";import{rpcKeyRoot,withRpcKeyRoot}from"./chunk-2CNSCMYC.js";import{MCP_PRESENTER_BOOTSTRAP_FD,presenterBootstrapStream,relayPresenterBootstrap}from"./chunk-7WYJAYHH.js";import{ALIAS_LINK,ALIAS_OWNER,ALIAS_PREFIX,INTERNAL_HOST_DIR_PREFIX,INTERNAL_SUPERVISOR_FLAG,OWNER_WATCH_FD,bindAliasRoots,internalHostDirRoots,keepOwnerPipe,loopLagErrorMs,readAliasOwnerStartTime,resolveCliMainPath,runtimeExecArgv,settleCandidateAdoption}from"./chunk-A4F4J2KH.js";import{DEFAULT_HOST_IDLE_EXIT_MS,acquireHostEnsureLock,childStalledStopMaxMs,claimOwnerIsLive,clearHostRegistration,hostChildAlive,hostEnsureLockOptions,hostEnsureLockTarget,hostLoopStalled,isHostCrash,provenOwner,pruneDeadGenerations,readGenerationRows,readHostCrashRecords,readHostProcessMetrics,readHostRegistration,readSessionPathClaims,releaseGeneration,stallRefusalWindowMs,writeGenerationRecord,writeHostRegistration,writtenByThisProcess}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,callerHostOwner,claimHostOwner,createDaemonDirectories,createHostDaemonPaths,ensureEndpointIdentity,generationPaths,hostDaemonDirectoryPaths,parseJson,parseShardSocket,readFileOrUndefined,readHostOwner,readHostSettings,readJsonObject,sameEndpoint,sameHostOwner,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,writeHostOwner,writeHostSettings,writeJsonAtomic,writeStateFile}from"./chunk-YI6KRJDC.js";import{OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-DBQBJTMF.js";import{envSlotVarNames}from"./chunk-ADT36P7E.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{adoptedEngineTrust}from"./chunk-EVTTLPIY.js";import{providerCredentialEnvNames}from"./chunk-Z6TEQEZO.js";import{spawnWithPrivateFds}from"./chunk-5JUCTKYS.js";import{ADOPTION_GRANT_FILE,STARTUP_ATTEMPT_FILE,encodeStartupHandOff,releaseStartupFillers,startupGrantLine,withStartupPipe}from"./chunk-KUIEHAPR.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,HOST_STARTUP_EVENTS_ENV}from"./chunk-RUGTHELO.js";import{MAX_SOCKET_PATH_BYTES,generationBindPath,socketEntryListenerState,statSocketIdentity}from"./chunk-5XHOHZIR.js";import{acquireOwnershipSafeLock,ensureSocketSecret,isBusy,socketSecretPath}from"./chunk-HW6AAS3R.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-SODMQEHO.js";import{ProcessIdentityUnreadableError,processIsLive,processMatchesPidFile,readProcessStartTime,waitForStartTime}from"./chunk-O5RYI3IW.js";import{writeSync as writeSync2}from"node:fs";import{join as join9,resolve as resolve5}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path2=>["--extension",path2])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^BSK_(HOME|BIN)$/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],PROVIDER_CREDENTIAL_ENV_NAMES=new Set([...providerCredentialEnvNames(),...envSlotVarNames()]),WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","OMO_BROWSER_ENGINE","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID","SENPI_RPC_HOST_STARTUP_EVENTS","SENPI_RPC_INTERNAL_KEY_STDIN","SENPI_RPC_HOST_WATCH_PSTART","SENPI_RPC_HOST_WATCH_PSTART_TICKS","SENPI_RPC_HOST_LIFETIME_FIFO","SENPI_RPC_SOCKET_SECRET_FILE","SENPI_ENGINE_TRUST","SENPI_ENGINE_TRUST_HOP"]);function isTransientDaemonEnvName(name){return TRANSIENT_ENV_NAMES.has(name)}function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?PROVIDER_CREDENTIAL_ENV_NAMES.has(name)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||PROVIDER_CREDENTIAL_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{mkdir,writeFile as writeFile4}from"node:fs/promises";import{dirname as dirname4}from"node:path";var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}function decideEnsureAction(options,startedByUs,protocol){if(options.upgrade!=="if-engine-differs"||isHostGenerationProcess())return decideHostAction(ensureClient(options,startedByUs),protocol,"never");let decision=decideHostAction(ensureClient(options,startedByUs),protocol,"upgrade");return decision.action==="fallback"?{action:"reuse",reason:"compatible",upgradeable:!1}:decision}function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:[...REQUIRED_HOST_CAPABILITIES,...requestedToolRuntime(options.hostArgs??[])],identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function requestedToolRuntime(hostArgs){for(let index=0;index<hostArgs.length;index++){let arg=hostArgs[index]??"",value=arg==="--tool-runtime"?hostArgs[index+1]:arg.startsWith("--tool-runtime=")?arg.slice(15):void 0;if(value!==void 0&&isToolRuntimeKind(value))return[toolRuntimeCapability(value)]}return[]}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}import{lstat}from"node:fs/promises";async function refuseIfStalled(paths,instanceId,socket,protocol){let generation=generationPaths(paths,instanceId);if(await hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:stallRefusalWindowMs()})&&await hostChildAlive(generation)!==!1)throw new HostEnsureRefusedError(socket,"host_stalled",protocol)}async function refuseIfForeignHeld(paths,registered,socket,protocol){if(!await publicEndpointAccepts(socket))return;let holder=await readHostHolder(paths,registered);throw new HostEnsureRefusedError(socket,"foreign_writer",protocol,void 0,holder)}async function readHostHolder(paths,registered){let record=parseJson(await readFileOrUndefined(generationPaths(paths,registered.instanceId).pidFile))??{};return{pid:registered.record.pid,instanceId:registered.instanceId,generation:registered.generation,processStartTime:registered.record.processStartTime,engineVersion:typeof record.engineVersion=="string"?record.engineVersion:null,launchProfileId:typeof record.launchProfileId=="string"?record.launchProfileId:null,writerPid:registered.writer?.pid??null}}var FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS=2e3;async function publicEndpointAccepts(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!0;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:probeSocketReachable(socket,FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS)}async function unregisteredEndpointHeld(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!1;let entry=await lstat(socket).then(found=>found.isSocket()?"socket":"not-socket",cause=>cause instanceof Error&&"code"in cause&&cause.code==="ENOENT"?"absent":"unknown");return entry==="absent"?!1:entry!=="socket"?!0:(await socketEntryListenerState(socket)).verdict==="live"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile2}from"node:fs/promises";import{existsSync}from"node:fs";import{basename,dirname as dirname2,join as join2,resolve as resolve2}from"node:path";import{fileURLToPath}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null,bundledSupervisor=resolveBundledSupervisorEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...runtimeExecArgv(),sibling,...supervisorArgs]}:bundledSupervisor!==null?{command:process.execPath,args:[...runtimeExecArgv(),bundledSupervisor,INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:{command:process.execPath,args:[...runtimeExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}var BUNDLED_SUPERVISOR_ENTRY="host-supervisor.js";function resolveBundledSupervisorEntryPath(){let entry=join2(dirname2(resolveCliMainPath()),BUNDLED_SUPERVISOR_ENTRY);return existsSync(entry)?entry:void 0}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath(import.meta.url);if(basename(dirname2(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname2(modulePath),`host-lifecycle${extension}`);return existsSync(sibling)?sibling:void 0}import{randomBytes}from"node:crypto";var MAX_STARTUP_EVENTS_PER_PRODUCER=32,STARTUP_MILESTONE_PRODUCER={supervisor_bootstrap:"supervisor",supervisor_setup:"supervisor",host_opaque:"supervisor",host_bootstrap:"host",host_runtime:"host",internal_ready:"supervisor",observer_ready:"supervisor",public_published:"supervisor"};function newStartupAttempt(){return randomBytes(16).toString("hex")}function startupEventIngress(controller,binding,role){let lastSeq=0,records=0,failProtocol=reason=>(controller.fail(new Error(`RPC host startup protocol failure (${role}): ${reason}`)),"protocol_failure");return line=>{if(Buffer.byteLength(line,"utf8")>4096)return failProtocol("record exceeds 4096 bytes");let record=parseRecord(line);if(!record)return failProtocol("malformed record");if(!sameBinding(record.binding,binding))return"discarded";if(record.role!==role)return failProtocol(`record claims role ${String(record.role)}`);if(record.seq<=lastSeq)return"ignored";if(record.seq!==lastSeq+1)return failProtocol(`sequence gap after ${lastSeq}`);if(records+=1,records>MAX_STARTUP_EVENTS_PER_PRODUCER)return failProtocol("too many records");lastSeq=record.seq;let milestone=record.milestone;if(!isProducerMilestone(milestone))return failProtocol(`unknown milestone ${String(milestone)}`);if(STARTUP_MILESTONE_PRODUCER[milestone]!==role)return failProtocol(`${role} cannot report ${milestone}`);let verdict=milestone==="host_opaque"?controller.declareOpaqueHost():controller.complete(milestone);return verdict!=="rejected"?verdict:controller.terminal?"ignored":failProtocol(`${milestone} reported before its phase was granted`)}}function attachStartupEvents(stream,controller,binding){let supervisor=startupEventIngress(controller,binding,"supervisor"),host=startupEventIngress(controller,binding,"host"),maxLine=2*4096+64,pending="";stream.setEncoding("utf8"),stream.on("data",chunk=>{if(!controller.terminal){pending+=chunk;for(let newline=pending.indexOf(`
|
|
2
|
+
import{CUSTOM_UNSUPPORTED_CAPABILITY,DEFAULT_PROBE_TIMEOUT_MS,DEFAULT_STOP_TIMEOUT_MS,ENDPOINT_OWNER_FENCE_CAPABILITY,EXTENSION_EVENTS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HOST_PROTOCOL_VERSION,HostEnsureRefusedError,REQUIRED_HOST_CAPABILITIES,RPC_CLIENT_CAPABILITIES_ENV,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SIGKILL_GRACE_MS,STARTUP_DECISION_BUDGET_MS,STOP_WAIT_BUDGET_MS,announceStop,anyGenerationLive,busyLegacyHostDetail,computeRuntimeBuildId,decideHostAction,delay,describeSessions,electPointer,engineBuildIdentity,ensureLockWaitDetail,ensureSender,gcEndpoint,gcHostEndpoints,holdProtocolInfo,holdSessionCount,hostLaunchProfile,isNodeErrorCode,judgeStaleEngine,matchesPidFileOrUnknown,observeProtocolInfo,parseHostStopGeneration,probeProtocolInfo,probeSocketReachable,provenLegacyOwner,recordEscalation,resolvePidFileOwnership,retireIdleLegacyHost,signalGeneration,signalPid,socketHostLaunchProfile,staleStopGeneration,startStartupController,startupEnvelope,startupTimeoutDetail,stopHost,stopManagedHost,stopSpawnedChild}from"./chunk-HLM46XEB.js";import{endpointKindOfSocket,listHostEndpoints}from"./chunk-Y7Z7XPUF.js";import{isSessionRuntimeKind,isToolRuntimeKind,toolRuntimeCapability}from"./chunk-54YTJCYZ.js";import{requestOnSocket}from"./chunk-I5ASHSLZ.js";import{rpcKeyRoot,withRpcKeyRoot}from"./chunk-2CNSCMYC.js";import{MCP_PRESENTER_BOOTSTRAP_FD,presenterBootstrapStream,relayPresenterBootstrap}from"./chunk-7WYJAYHH.js";import{ALIAS_LINK,ALIAS_OWNER,ALIAS_PREFIX,INTERNAL_HOST_DIR_PREFIX,INTERNAL_SUPERVISOR_FLAG,OWNER_WATCH_FD,bindAliasRoots,internalHostDirRoots,keepOwnerPipe,loopLagErrorMs,readAliasOwnerStartTime,resolveCliMainPath,runtimeExecArgv,settleCandidateAdoption}from"./chunk-I3PHVJAS.js";import{DEFAULT_HOST_IDLE_EXIT_MS,acquireHostEnsureLock,childStalledStopMaxMs,claimOwnerIsLive,clearHostRegistration,hostChildAlive,hostEnsureLockOptions,hostEnsureLockTarget,hostLoopStalled,isHostCrash,provenOwner,pruneDeadGenerations,readGenerationRows,readHostCrashRecords,readHostProcessMetrics,readHostRegistration,readSessionPathClaims,releaseGeneration,stallRefusalWindowMs,writeGenerationRecord,writeHostRegistration,writtenByThisProcess}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_DIR_ENV,HOST_STATE_FILE_MODE,callerHostOwner,claimHostOwner,createDaemonDirectories,createHostDaemonPaths,ensureEndpointIdentity,generationPaths,hostDaemonDirectoryPaths,parseJson,parseShardSocket,readFileOrUndefined,readHostOwner,readHostSettings,readJsonObject,sameEndpoint,sameHostOwner,sessionDirectoryRemoved,shardKey,shardSocketPathForKey,writeHostOwner,writeHostSettings,writeJsonAtomic,writeStateFile}from"./chunk-YI6KRJDC.js";import{OBSERVE_REQUEST_FIELD,gcRpcPublicKeys}from"./chunk-DBQBJTMF.js";import{envSlotVarNames}from"./chunk-ADT36P7E.js";import{external_exports}from"./chunk-KUPQO7MC.js";import{adoptedEngineTrust}from"./chunk-EVTTLPIY.js";import{providerCredentialEnvNames}from"./chunk-Z6TEQEZO.js";import{spawnWithPrivateFds}from"./chunk-YK3ZZCHI.js";import{ADOPTION_GRANT_FILE,STARTUP_ATTEMPT_FILE,encodeStartupHandOff,releaseStartupFillers,startupGrantLine,withStartupPipe}from"./chunk-T2SMQPRE.js";import{HOST_GENERATION_ENV,HOST_INSTANCE_ID_ENV,HOST_STARTUP_EVENTS_ENV}from"./chunk-RUGTHELO.js";import{MAX_SOCKET_PATH_BYTES,generationBindPath,socketEntryListenerState,statSocketIdentity}from"./chunk-5XHOHZIR.js";import{acquireOwnershipSafeLock,ensureSocketSecret,isBusy,socketSecretPath}from"./chunk-HW6AAS3R.js";import{APP_NAME,ENV_AGENT_DIR,envValue,getAgentDir,isBunBinary}from"./chunk-SODMQEHO.js";import{ProcessIdentityUnreadableError,processIsLive,processMatchesPidFile,readProcessStartTime,waitForStartTime}from"./chunk-O5RYI3IW.js";import{writeSync as writeSync2}from"node:fs";import{join as join9,resolve as resolve5}from"node:path";import{readFile,realpath,stat}from"node:fs/promises";import{dirname,isAbsolute,relative,resolve}from"node:path";var SPEC_ENV_NAME=/^(SENPI|OMO|PI)_[A-Z0-9_]+$/u,HostLaunchSpecError=class extends Error{constructor(reason,detail){super(`${reason}: ${detail}`),this.name="HostLaunchSpecError",this.reason=reason,this.detail=detail}},DEFAULT_HOST_LAUNCH_SPEC={hostArgs:[],policy:{},env:{}};async function loadHostLaunchSpec(specPath,platform=process.platform){let absolute=resolve(specPath);await assertTrustedFile(absolute,platform);let spec=parseHostLaunchSpec(await readSpecText(absolute)),env=trustedEnv(spec.env),extensions=await resolveExtensions(spec.core.extensions,dirname(absolute));return{hostArgs:["--session-runtime",spec.core.session_runtime,...extensions.flatMap(path2=>["--extension",path2])],policy:{...spec.tunables?.idleExitMs!==void 0&&{idleExitMs:spec.tunables.idleExitMs},...spec.tunables?.coldStart!==void 0&&{coldStart:spec.tunables.coldStart}},env}}function parseHostLaunchSpec(text){let parsed;try{parsed=JSON.parse(text)}catch(error){throw new HostLaunchSpecError("launch_spec_invalid",error instanceof Error?error.message:"not JSON")}if(!isRecord(parsed))throw new HostLaunchSpecError("launch_spec_invalid","the spec is not a JSON object");if(parsed.spec_version!==1)throw new HostLaunchSpecError("launch_spec_invalid",`unsupported spec_version ${String(parsed.spec_version)}`);let core=parsed.core;if(!isRecord(core))throw new HostLaunchSpecError("launch_spec_invalid","core must be an object");if(typeof core.session_runtime!="string"||!isSessionRuntimeKind(core.session_runtime))throw new HostLaunchSpecError("launch_spec_invalid","core.session_runtime must be in-process or worker");if(core.multi_session!==!0)throw new HostLaunchSpecError("launch_spec_invalid","core.multi_session must be true");if(!Array.isArray(core.extensions)||!core.extensions.every(entry=>typeof entry=="string"))throw new HostLaunchSpecError("launch_spec_invalid","core.extensions must be an array of strings");let tunables=parsedTunables(parsed.tunables);return{spec_version:1,core:{session_runtime:core.session_runtime,multi_session:!0,extensions:core.extensions},...tunables&&{tunables},...isRecord(parsed.env)&&{env:parsedEnv(parsed.env)}}}async function readSpecText(absolute){try{return await readFile(absolute,"utf8")}catch(error){throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}}async function assertTrustedFile(absolute,platform){if(platform==="win32")return;let stats=await stat(absolute).catch(error=>{throw new HostLaunchSpecError("launch_spec_unreadable",error instanceof Error?error.message:absolute)}),uid=process.getuid?.();if(uid!==void 0&&stats.uid!==uid)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is owned by uid ${stats.uid}, not ${uid}`);if((stats.mode&18)!==0)throw new HostLaunchSpecError("launch_spec_insecure",`${absolute} is group/world writable (mode ${(stats.mode&511).toString(8)})`)}function trustedEnv(env){for(let name of Object.keys(env??{}))if(!SPEC_ENV_NAME.test(name))throw new HostLaunchSpecError("launch_spec_env_denied",`${name} is outside ${SPEC_ENV_NAME.source}`);return env??{}}async function resolveExtensions(extensions,specDir){let rootReal=await realpath(specDir).catch(()=>specDir),resolved=[];for(let entry of extensions){let target=resolve(specDir,entry);if(escapes(specDir,target))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} resolves outside ${specDir}`);let real=await realpath(target).catch(()=>{});if(real===void 0)throw new HostLaunchSpecError("launch_spec_missing_extension",`${target} does not exist`);if(escapes(rootReal,real))throw new HostLaunchSpecError("launch_spec_path_escape",`${entry} links outside ${specDir}`);resolved.push(real)}return resolved}function escapes(root,target){let step=relative(root,target);return step.startsWith("..")||isAbsolute(step)}function parsedTunables(value){if(!isRecord(value))return;let idleExitMs=value.idleExitMs,coldStart=value.coldStart;return{...typeof idleExitMs=="number"&&Number.isFinite(idleExitMs)&&idleExitMs>0&&{idleExitMs},...(coldStart==="transient"||coldStart==="persistent")&&{coldStart}}}function parsedEnv(value){let env={};for(let[name,entry]of Object.entries(value)){if(typeof entry!="string")throw new HostLaunchSpecError("launch_spec_invalid",`env.${name} must be a string`);env[name]=entry}return env}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{join}from"node:path";var ALLOWED_ENV_NAMES=[/^(PATH|HOME|USER|LOGNAME|SHELL|TMPDIR|TERM|LANG)$/u,/^(LC|XDG)_/u,/^(SENPI|OMO|PI)_/u,/^BSK_(HOME|BIN)$/u,/^(HTTPS?_PROXY|NO_PROXY)$/u,/^[A-Z0-9_]+_API_KEY$/u,/^(ANTHROPIC|OPENAI|GOOGLE|GEMINI|AZURE|AWS|OPENROUTER|XAI|MISTRAL|DEEPSEEK|GROQ|CEREBRAS|MINIMAX)_/u],PROVIDER_CREDENTIAL_ENV_NAMES=new Set([...providerCredentialEnvNames(),...envSlotVarNames()]),WINDOWS_SYSTEM_ENV_NAMES=new Set(["SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","PATHEXT","TEMP","TMP","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","HOMEDRIVE","HOMEPATH","NUMBER_OF_PROCESSORS","PROCESSOR_ARCHITECTURE","OS"]),TRANSIENT_ENV_NAMES=new Set(["PI_SESSION_ID","PI_SESSION_FILE","PI_SESSION_CWD","PI_GOAL_STORE_FILE","PI_PROVIDER","PI_MODEL","PI_REASONING_LEVEL","OMO_BROWSER_ENGINE","PI_PROMPT_CACHE_SAFE_WAIT_SECONDS","SENPI_PY_KERNEL_PARENT_PID","SENPI_RPC_HOST_WATCH_FD","SENPI_RPC_HOST_WATCH_PPID","SENPI_RPC_HOST_SCRATCH_DIR","SENPI_RPC_HOST_CLEANUP_PATHS","SENPI_RPC_HOST_PUBLIC_SOCKET","SENPI_RPC_HOST_INSTANCE_ID","SENPI_RPC_HOST_GENERATION","SENPI_RPC_HOST_DAEMON_DIR","SENPI_RPC_HOST_EXPECTED_RUNTIME_BUILD_ID","SENPI_RPC_HOST_STARTUP_EVENTS","SENPI_RPC_INTERNAL_KEY_STDIN","SENPI_RPC_HOST_WATCH_PSTART","SENPI_RPC_HOST_WATCH_PSTART_TICKS","SENPI_RPC_HOST_LIFETIME_FIFO","SENPI_RPC_SOCKET_SECRET_FILE","SENPI_ENGINE_TRUST","SENPI_ENGINE_TRUST_HOP"]);function isTransientDaemonEnvName(name){return TRANSIENT_ENV_NAMES.has(name)}function daemonEnvIsAllowed(name,platform=process.platform){let upper=name.toUpperCase();return TRANSIENT_ENV_NAMES.has(platform==="win32"?upper:name)?!1:platform!=="win32"?PROVIDER_CREDENTIAL_ENV_NAMES.has(name)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(name)):WINDOWS_SYSTEM_ENV_NAMES.has(upper)||PROVIDER_CREDENTIAL_ENV_NAMES.has(upper)||ALLOWED_ENV_NAMES.some(pattern=>pattern.test(upper))}function daemonEnvOverrides(processEnv,specEnv={},platform=process.platform){let overrides={};for(let name of Object.keys(processEnv))daemonEnvIsAllowed(name,platform)||(overrides[name]=null);for(let[name,value]of Object.entries(specEnv))daemonEnvIsAllowed(name,platform)&&(overrides[name]=value);return overrides}function daemonEnvironment(processEnv,overrides={},forced={},platform=process.platform){let env={};for(let[name,value]of Object.entries(processEnv))value!==void 0&&daemonEnvIsAllowed(name,platform)&&(env[name]=value);for(let[name,value]of Object.entries(overrides))daemonEnvIsAllowed(name,platform)&&(deleteEnvironmentName(env,name,platform),value!==null&&(env[name]=value));for(let[name,value]of Object.entries(forced))deleteEnvironmentName(env,name,platform),env[name]=value;return env}function daemonEnvKeys(processEnv,specEnv={},platform=process.platform){let kept=Object.keys(processEnv).filter(name=>daemonEnvIsAllowed(name,platform)),explicit=Object.keys(specEnv).filter(name=>daemonEnvIsAllowed(name,platform));return[...new Set([...kept,...explicit])].sort()}async function writeDaemonEnvKeys(paths,keys){await writeStateFile(daemonEnvKeysFile(paths),{env_keys:keys})}async function readDaemonEnvKeys(paths){let keys=parseJson(await readFileOrUndefined(daemonEnvKeysFile(paths)))?.env_keys;return Array.isArray(keys)?keys.filter(key=>typeof key=="string"):[]}function daemonEnvKeysFile(paths){return join(paths.dir,"env-keys.json")}function deleteEnvironmentName(env,name,platform){if(platform!=="win32"){delete env[name];return}let upper=name.toUpperCase();for(let existing of Object.keys(env))existing.toUpperCase()===upper&&delete env[existing]}import{mkdir,writeFile as writeFile4}from"node:fs/promises";import{dirname as dirname4}from"node:path";var hostGenerationScopes=0;function isHostGenerationProcess(){return hostGenerationScopes>0}async function runAsHostGenerationProcess(action){hostGenerationScopes+=1;try{return await action()}finally{hostGenerationScopes-=1}}function decideEnsureAction(options,startedByUs,protocol){if(options.upgrade!=="if-engine-differs"||isHostGenerationProcess())return decideHostAction(ensureClient(options,startedByUs),protocol,"never");let decision=decideHostAction(ensureClient(options,startedByUs),protocol,"upgrade");return decision.action==="fallback"?{action:"reuse",reason:"compatible",upgradeable:!1}:decision}function ensureClient(options,startedByUs){return{protocolVersion:HOST_PROTOCOL_VERSION,requiredCapabilities:[...REQUIRED_HOST_CAPABILITIES,...requestedToolRuntime(options.hostArgs??[])],identity:engineBuildIdentity(),...options.upgrade==="if-engine-differs"?{launchProfile:hostLaunchProfile(hostChildArgv(options.hostArgs??[]),process.cwd())}:{},startedByUs,platform:process.platform}}function requestedToolRuntime(hostArgs){for(let index=0;index<hostArgs.length;index++){let arg=hostArgs[index]??"",value=arg==="--tool-runtime"?hostArgs[index+1]:arg.startsWith("--tool-runtime=")?arg.slice(15):void 0;if(value!==void 0&&isToolRuntimeKind(value))return[toolRuntimeCapability(value)]}return[]}function hostChildArgv(hostArgs){return["--mode","rpc","--multi-session",...hostArgs]}function isCompatible(protocol){return decideHostAction(ensureClient({socket:""},!1),protocol,"never").action==="reuse"}import{lstat}from"node:fs/promises";async function refuseIfStalled(paths,instanceId,socket,protocol){let generation=generationPaths(paths,instanceId);if(await hostLoopStalled(generation,{now:Date.now(),errorMs:loopLagErrorMs(),windowMs:stallRefusalWindowMs()})&&await hostChildAlive(generation)!==!1)throw new HostEnsureRefusedError(socket,"host_stalled",protocol)}async function refuseIfForeignHeld(paths,registered,socket,protocol){if(!await publicEndpointAccepts(socket))return;let holder=await readHostHolder(paths,registered);throw new HostEnsureRefusedError(socket,"foreign_writer",protocol,void 0,holder)}async function readHostHolder(paths,registered){let record=parseJson(await readFileOrUndefined(generationPaths(paths,registered.instanceId).pidFile))??{};return{pid:registered.record.pid,instanceId:registered.instanceId,generation:registered.generation,processStartTime:registered.record.processStartTime,engineVersion:typeof record.engineVersion=="string"?record.engineVersion:null,launchProfileId:typeof record.launchProfileId=="string"?record.launchProfileId:null,writerPid:registered.writer?.pid??null}}var FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS=2e3;async function publicEndpointAccepts(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!0;let entry=await statSocketIdentity(socket).then(identity=>identity===void 0?"absent":"present",()=>"unknown");return entry==="absent"?!1:entry==="unknown"?!0:probeSocketReachable(socket,FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS)}async function unregisteredEndpointHeld(socket){if(process.platform==="win32"||socket.startsWith("\0"))return!1;let entry=await lstat(socket).then(found=>found.isSocket()?"socket":"not-socket",cause=>cause instanceof Error&&"code"in cause&&cause.code==="ENOENT"?"absent":"unknown");return entry==="absent"?!1:entry!=="socket"?!0:(await socketEntryListenerState(socket)).verdict==="live"}import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{open,readFile as readFile2}from"node:fs/promises";import{existsSync}from"node:fs";import{basename,dirname as dirname2,join as join2,resolve as resolve2}from"node:path";import{fileURLToPath}from"node:url";var PINNED_HOST_CLIENT_CAPABILITIES=[EXTENSION_EVENTS_CAPABILITY,CUSTOM_UNSUPPORTED_CAPABILITY];function defaultHostLaunch(supervisorArgs,compiled=isBunBinary,sibling=resolveHostLifecycleEntryPath()??null,bundledSupervisor=resolveBundledSupervisorEntryPath()??null){return compiled?{command:process.execPath,args:[INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:sibling!==null?{command:process.execPath,args:[...runtimeExecArgv(),sibling,...supervisorArgs]}:bundledSupervisor!==null?{command:process.execPath,args:[...runtimeExecArgv(),bundledSupervisor,INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}:{command:process.execPath,args:[...runtimeExecArgv(),resolveCliMainPath(),INTERNAL_SUPERVISOR_FLAG,...supervisorArgs]}}var BUNDLED_SUPERVISOR_ENTRY="host-supervisor.js";function resolveBundledSupervisorEntryPath(){let entry=join2(dirname2(resolveCliMainPath()),BUNDLED_SUPERVISOR_ENTRY);return existsSync(entry)?entry:void 0}function resolveHostLifecycleEntryPath(){let modulePath=fileURLToPath(import.meta.url);if(basename(dirname2(modulePath))==="chunks")return;let extension=modulePath.endsWith(".ts")?".ts":".js",sibling=resolve2(dirname2(modulePath),`host-lifecycle${extension}`);return existsSync(sibling)?sibling:void 0}import{randomBytes}from"node:crypto";var MAX_STARTUP_EVENTS_PER_PRODUCER=32,STARTUP_MILESTONE_PRODUCER={supervisor_bootstrap:"supervisor",supervisor_setup:"supervisor",host_opaque:"supervisor",host_bootstrap:"host",host_runtime:"host",internal_ready:"supervisor",observer_ready:"supervisor",public_published:"supervisor"};function newStartupAttempt(){return randomBytes(16).toString("hex")}function startupEventIngress(controller,binding,role){let lastSeq=0,records=0,failProtocol=reason=>(controller.fail(new Error(`RPC host startup protocol failure (${role}): ${reason}`)),"protocol_failure");return line=>{if(Buffer.byteLength(line,"utf8")>4096)return failProtocol("record exceeds 4096 bytes");let record=parseRecord(line);if(!record)return failProtocol("malformed record");if(!sameBinding(record.binding,binding))return"discarded";if(record.role!==role)return failProtocol(`record claims role ${String(record.role)}`);if(record.seq<=lastSeq)return"ignored";if(record.seq!==lastSeq+1)return failProtocol(`sequence gap after ${lastSeq}`);if(records+=1,records>MAX_STARTUP_EVENTS_PER_PRODUCER)return failProtocol("too many records");lastSeq=record.seq;let milestone=record.milestone;if(!isProducerMilestone(milestone))return failProtocol(`unknown milestone ${String(milestone)}`);if(STARTUP_MILESTONE_PRODUCER[milestone]!==role)return failProtocol(`${role} cannot report ${milestone}`);let verdict=milestone==="host_opaque"?controller.declareOpaqueHost():controller.complete(milestone);return verdict!=="rejected"?verdict:controller.terminal?"ignored":failProtocol(`${milestone} reported before its phase was granted`)}}function attachStartupEvents(stream,controller,binding){let supervisor=startupEventIngress(controller,binding,"supervisor"),host=startupEventIngress(controller,binding,"host"),maxLine=2*4096+64,pending="";stream.setEncoding("utf8"),stream.on("data",chunk=>{if(!controller.terminal){pending+=chunk;for(let newline=pending.indexOf(`
|
|
3
3
|
`);newline>=0;newline=pending.indexOf(`
|
|
4
4
|
`)){let line=pending.slice(0,newline);pending=pending.slice(newline+1);let relayed=unwrapStartupRelay(line);if(relayed===void 0?supervisor(line):host(relayed),controller.terminal)return}pending.length>maxLine&&supervisor(pending)}}),stream.on("error",()=>{}),"unref"in stream&&typeof stream.unref=="function"&&stream.unref()}function unwrapStartupRelay(line){if(line.startsWith('{"relay":'))try{let frame=JSON.parse(line);if(typeof frame!="object"||frame===null)return;let{relay,line:inner}=frame;return relay==="host"&&typeof inner=="string"?inner:void 0}catch{return}}function parseRecord(line){let value;try{value=JSON.parse(line)}catch{return}if(typeof value!="object"||value===null)return;let record=value;if(record.v===1&&!(typeof record.seq!="number"||!Number.isSafeInteger(record.seq)||record.seq<1))return{binding:record.binding,role:record.role,seq:record.seq,milestone:record.milestone}}function sameBinding(candidate,binding){if(typeof candidate!="object"||candidate===null)return!1;let other=candidate;return other.attempt===binding.attempt&&other.endpoint===binding.endpoint&&other.instanceId===binding.instanceId&&other.generation===binding.generation&&other.launchKind===binding.launchKind&&other.predecessor===binding.predecessor}function isProducerMilestone(value){return typeof value=="string"&&Object.hasOwn(STARTUP_MILESTONE_PRODUCER,value)}import{rm,stat as stat2}from"node:fs/promises";import{join as join3}from"node:path";var STARTUP_INTENT_FILE="startup-intent.json",STARTUP_INTENT_VERSION=1;function startupIntentPath(daemonDir){return join3(daemonDir,STARTUP_INTENT_FILE)}function writeStartupIntent(daemonDir,intent){return writeJsonAtomic(startupIntentPath(daemonDir),{version:STARTUP_INTENT_VERSION,...intent})}async function readStartupIntent(daemonDir){let modified=await stat2(startupIntentPath(daemonDir)).then(entry=>entry.mtimeMs,()=>{});if(modified===void 0)return;let record=await readJsonObject(startupIntentPath(daemonDir)),launcher=pidFileOf(record?.launcher),child=record?.child===void 0?void 0:pidFileOf(record.child);return!record||record.version!==STARTUP_INTENT_VERSION||typeof record.attempt!="string"||typeof record.instanceId!="string"||typeof record.generation!="number"||typeof record.writtenAt!="number"||!launcher||child===null?{unreadable:!0,writtenAt:modified}:{attempt:record.attempt,instanceId:record.instanceId,generation:record.generation,launcher,writtenAt:record.writtenAt,...child?{child}:{}}}function clearStartupIntent(daemonDir){return rm(startupIntentPath(daemonDir),{force:!0})}async function readStartupAttemptRecord(generationDir,attempt){let record=await readJsonObject(join3(generationDir,STARTUP_ATTEMPT_FILE));if(record?.attempt===attempt)return pidFileOf(record)??void 0}async function reconcileStartupIntent(intent,options){if(intent===void 0)return"none";let expiredOr=verdict=>options.now-intent.writtenAt>=options.expiryMs?"expired":verdict;if("unreadable"in intent)return expiredOr("unknown");let candidate=intent.child??await options.attemptRecord(intent.instanceId,intent.attempt);if(!candidate)return expiredOr("unknown");let live=await options.matches(candidate).catch(()=>{});return live===void 0?expiredOr("unknown"):live?"candidate_live":"candidate_gone"}async function settleStartupIntent(paths,socket,readStartTime=readProcessStartTime){let expiryMs=startupEnvelope(childStalledStopMaxMs()).settled,verdict=await reconcileStartupIntent(await readStartupIntent(paths.dir),{matches:record=>processMatchesPidFile(record,readStartTime),attemptRecord:(instanceId,attempt)=>readStartupAttemptRecord(generationPaths(paths,instanceId).dir,attempt),expiryMs,now:Date.now()});if(verdict==="none")return;if(verdict==="candidate_gone"||verdict==="expired")return clearStartupIntent(paths.dir);let detail=verdict==="candidate_live"?`a previous start of this endpoint is still running and never registered (${startupIntentPath(paths.dir)})`:`a previous start of this endpoint cannot be identified; ${startupIntentPath(paths.dir)} is kept until its candidate is proven gone or ${expiryMs}ms after it was written`;throw new HostEnsureRefusedError(socket,verdict==="candidate_live"?"host_stalled":"endpoint_occupied",void 0,detail)}function pidFileOf(value){if(typeof value!="object"||value===null)return null;let{pid,processStartTime}=value;return typeof pid!="number"||!Number.isInteger(pid)||pid<=0||processStartTime!==null&&typeof processStartTime!="string"?null:{pid,processStartTime}}import{Readable}from"node:stream";var SPAWNED_HOST_PROBE_TIMEOUT_MS=1e4;async function pollProtocolInfo(socket,timeoutMs,isCompatible2,childExit){let deadline=Date.now()+timeoutMs,lastProtocol;for(;Date.now()<=deadline;){let probe=holdProtocolInfo(socket,Math.min(SPAWNED_HOST_PROBE_TIMEOUT_MS,Math.max(1,deadline-Date.now()))),raced=childExit?await Promise.race([probe,childExit]):await probe;if(isChildExit(raced)){let held=await probe;if(!held)return{ready:!1,protocol:lastProtocol,exited:raced};if(lastProtocol=held.info,isCompatible2(held.info))return{ready:!0,protocol:held.info,hold:held.hold};held.hold.release()}else if(raced){if(lastProtocol=raced.info,isCompatible2(raced.info))return{ready:!0,protocol:raced.info,hold:raced.hold};raced.hold.release()}await delay2(50)}return{ready:!1,protocol:lastProtocol}}function isChildExit(value){return!!value&&"code"in value&&"signal"in value}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function monotonicStartupClock(){return{now:()=>performance.now(),scheduleAt:(at,fire)=>setTimeout(fire,Math.max(0,at-performance.now())),cancel:handle=>clearTimeout(handle)}}function beginStartupAttempt(options){let successor=options.successorOf!==void 0,launchKind=options.coordinated?successor?"successor":"initial":"legacy",budgetMs=options.decisionBudgetMs??STARTUP_DECISION_BUDGET_MS,binding={attempt:options.attempt,endpoint:options.socket,instanceId:options.instanceId,generation:options.generation,launchKind:successor?"successor":"initial",predecessor:options.successorOf??null},controller=startStartupController({launchKind,clock:options.clock??monotonicStartupClock(),decisionBudgetMs:budgetMs}),coordinated=options.coordinated,fillers=[];return{controller,binding,coordinated,get env(){return coordinated?{[HOST_STARTUP_EVENTS_ENV]:encodeStartupHandOff({binding,role:"supervisor",budgetMs,fillers})}:{}},stdio(base){if(!coordinated)return[...base];let filled=withStartupPipe(base);return fillers=filled.fillers,filled.stdio},attach(child,childExit){releaseStartupFillers(child,fillers);let stream=child.stdio[16];coordinated&&stream instanceof Readable&&attachStartupEvents(stream,controller,binding),childExit.then(exit=>{!controller.terminal&&controller.phase!=="public_verified"&&controller.fail(new Error(exitMessage(exit)))})}}}function exitMessage(exit){return`RPC socket host exited with ${exitStatus(exit)} before answering get_protocol_info`}function exitStatus(exit){return`code ${exit.code??"null"}${exit.signal?` (${exit.signal})`:""}`}function answerMessage(protocol,exited){return protocol.lifecycle!=="stopping"?incompatibleMessage(protocol):`RPC socket host answered get_protocol_info with lifecycle "stopping": it began stopping before this start verified it${exited?`, and then exited with ${exitStatus(exited)}`:""}`}function incompatibleMessage(protocol){return`RPC socket host answered get_protocol_info with protocolVersion ${protocol.protocolVersion}, serverVersion ${protocol.serverVersion} and capabilities ${JSON.stringify(protocol.capabilities)}, but is incompatible with protocol version ${HOST_PROTOCOL_VERSION} and required capabilities ${JSON.stringify(REQUIRED_HOST_CAPABILITIES)}`}async function driveStartupToReady(options){let{controller}=options.attempt,failure=async()=>{let outcome=await controller.settled();if(outcome.kind==="ready")throw new Error("startup controller reported READY on a failure path");return{ready:!1,outcome}};if(options.attempt.coordinated&&(!await controller.whenPhase("presenter_resolved")||await Promise.race([(options.presenterEnrollment??Promise.resolve()).then(()=>"resolved"),controller.settled().then(()=>"terminal")])==="terminal"||controller.complete("presenter_resolved")!=="accepted"))return failure();let result=await pollProtocolInfo(options.socket,Math.max(1,controller.remainingMs()),options.isCompatible,options.childExit);if(result.ready)return controller.complete("public_verified")!=="accepted"?(result.hold.release(),failure()):(options.attempt.coordinated||await options.presenterEnrollment,{ready:!0,hold:result.hold});let explicit=result.protocol?new Error(answerMessage(result.protocol,result.exited)):result.exited?new Error(exitMessage(result.exited)):void 0;if(!explicit)return failure();controller.fail(explicit);let settled=await controller.settled();return{ready:!1,outcome:settled.kind==="failed"?settled:{kind:"failed",phase:"public_verified",cause:explicit,elapsedMs:settled.elapsedMs}}}function createStartupFinalizer(options){let settled;return outcome=>(settled??=finalize(outcome),settled);async function finalize(outcome){let{clock}=options,timer,expired=new Promise(resolveExpired=>{timer=clock.scheduleAt(clock.now()+options.cleanupBudgetMs,()=>resolveExpired("expired"))}),ran=options.cleanup().then(()=>"completed",error=>error instanceof Error?error:new Error(String(error))),result=await Promise.race([ran,expired]);clock.cancel(timer);let cleanup=result==="completed"?"completed":"incomplete",original=outcome.kind==="timeout"?startupTimeoutDetail(outcome,cleanup):outcome.cause.message,appended=result instanceof Error?`
|
|
5
5
|
cleanup failed: ${result.message}`:result==="expired"?`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{getShellConfig}from"./chunk-E6L5VZSM.js";import{rememberResolvedReferenceValue}from"./chunk-DLAY7CIU.js";import{Compile}from"./chunk-YUVC7SJB.js";import{ConfigReferenceError}from"./chunk-OKMHSVCA.js";import{sanitizeProviderDiagnostic}from"./chunk-JGKH3D6W.js";import{attachProviderDiagnostic}from"./chunk-3SASTB6Y.js";import{typebox_exports}from"./chunk-MIENF2YK.js";var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error");attachProviderDiagnostic(failure,sanitizeProviderDiagnostic(event.error.providerDiagnostic));let status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}var FileReferenceSchema=typebox_exports.Object({$file:typebox_exports.String({minLength:1})},{additionalProperties:!1}),EnvReferenceSchema=typebox_exports.Object({$env:typebox_exports.String({pattern:"^[A-Za-z_][A-Za-z0-9_]*$"})},{additionalProperties:!1}),ConcatReferenceSchema=typebox_exports.Object({$concat:typebox_exports.Array(typebox_exports.Union([typebox_exports.String(),FileReferenceSchema,EnvReferenceSchema]))},{additionalProperties:!1}),ConfigReferenceSchema=typebox_exports.Union([FileReferenceSchema,EnvReferenceSchema,ConcatReferenceSchema]),ConfigValueSchema=typebox_exports.Union([typebox_exports.String(),ConfigReferenceSchema]),NonemptyConfigValueSchema=typebox_exports.Union([typebox_exports.String({minLength:1}),ConfigReferenceSchema]),validateReference=Compile(ConfigReferenceSchema);function isConfigReference(value){return validateReference.Check(value)}function assertConfigValue(value,field){if(typeof value!="string"&&!isConfigReference(value))throw new ConfigReferenceError(field,value,"malformed")}function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}var warnedVariables=new Set;function warnOpaqueConfigEnvironment(name,value){value!==void 0&&/\{(?:file|env):/.test(value)&&!warnedVariables.has(name)&&(warnedVariables.add(name),console.warn(`${name}: environment value contains reference-looking text; inserted literally`))}function warnMissingConfigEnvironment(name){warnedVariables.has(name)||(warnedVariables.add(name),console.warn(`${name}: configuration environment variable is unset`))}import{dirname as dirname2}from"node:path";import{constants}from"node:fs";import{lstat,open,readlink}from"node:fs/promises";import{homedir}from"node:os";import{dirname,isAbsolute,join,parse,sep}from"node:path";var MAX_BYTES=65536,readableWarnings=new Set;function fail(input,reason){throw new ConfigReferenceError(input.field,input.reference,reason)}function checkOwner(input,stat){process.platform!=="win32"&&stat.uid!==0&&stat.uid!==process.getuid?.()&&fail(input,"unsafe-owner")}function checkWritable(input,stat,ancestor){process.platform==="win32"||stat.isSymbolicLink()||(stat.mode&18)===0||ancestor&&stat.isDirectory()&&(stat.mode&512)!==0||fail(input,"unsafe-permissions")}function sameFile(left,right){return left.dev===right.dev&&left.ino===right.ino}function absolutePath(input){let declared=input.reference.$file;return declared.startsWith("~/")||process.platform==="win32"&&declared.startsWith("~\\")?`${homedir()}${sep}${declared.slice(2)}`:isAbsolute(declared)?declared:`${input.baseDir}${sep}${declared}`}async function walk(input){let absolute=absolutePath(input),current=parse(absolute).root,pending=absolute.slice(current.length).split(sep).filter(Boolean),stat=await lstat(current),links=0;checkOwner(input,stat),checkWritable(input,stat,!0);for(let part=pending.shift();part!==void 0;part=pending.shift()){if(part===".")continue;stat.isDirectory()||fail(input,"non-regular");let next=part===".."?dirname(current):join(current,part),nextStat=await lstat(next);if(checkOwner(input,nextStat),process.platform!=="win32"&&(stat.mode&18)!==0&&!nextStat.isSymbolicLink()&&(nextStat.mode&18)!==0&&fail(input,"unsafe-permissions"),checkWritable(input,nextStat,pending.length>0),nextStat.isSymbolicLink()){++links>40&&fail(input,"unreadable");let target=await readlink(next);sameFile(nextStat,await lstat(next))||fail(input,"changed");let targetPath=isAbsolute(target)?target:`${current}${sep}${target}`;current=parse(targetPath).root,pending=[...targetPath.slice(current.length).split(sep).filter(Boolean),...pending],stat=await lstat(current),checkOwner(input,stat),checkWritable(input,stat,!0)}else current=next,stat=nextStat}return stat.isFile()||fail(input,"non-regular"),{path:current,stat}}async function readConfigReferenceFile(input){try{let walked=await walk(input),flags=constants.O_RDONLY|(constants.O_NOFOLLOW??0)|(constants.O_NONBLOCK??0),handle=await open(walked.path,flags);try{let stat=await handle.stat();sameFile(walked.stat,stat)||fail(input,"changed"),stat.isFile()||fail(input,"non-regular"),checkOwner(input,stat),checkWritable(input,stat,!1),stat.size>MAX_BYTES&&fail(input,"oversize");let buffer=Buffer.alloc(MAX_BYTES+1),length=0;for(;length<buffer.length;){let{bytesRead}=await handle.read(buffer,length,buffer.length-length,length);if(bytesRead===0)break;length+=bytesRead}length>MAX_BYTES&&fail(input,"oversize");let value;try{value=new TextDecoder("utf-8",{fatal:!0}).decode(buffer.subarray(0,length)).trim()}catch{fail(input,"invalid-utf8")}return value.length===0&&fail(input,"empty"),process.platform!=="win32"&&(stat.mode&36)!==0&&!readableWarnings.has(walked.path)&&(readableWarnings.add(walked.path),console.warn(`${input.field}: reference file is readable by other users`)),value}finally{await handle.close()}}catch(error){if(error instanceof ConfigReferenceError)throw error;let code=Reflect.get(Object(error),"code");fail(input,code==="ENOENT"||code==="ENOTDIR"?"missing":"unreadable")}}var origins=new WeakMap;function rememberConfigReferenceOrigin(value,context){typeof value!="string"&&origins.set(value,context)}function configReferenceContext(value,context){return context??(typeof value=="string"?void 0:origins.get(value))}function assertConfigReferenceAuthority(value,context){if(typeof value=="string")return;let source=configReferenceContext(value,context);if(source?.authority!=="trusted")throw new ConfigReferenceError(source?.field??"configuration value",value,"forbidden");assertConfigValue(value,source.field)}async function resolveConfigReference(value,context,env){let source=configReferenceContext(value,context);if(assertConfigReferenceAuthority(value,source),source===void 0)throw new ConfigReferenceError("configuration value",value,"forbidden");if("$file"in value){let text=await readConfigReferenceFile({field:source.field,reference:value,baseDir:source.baseDir??dirname2(source.origin)});return rememberResolvedReferenceValue(text),text}if("$env"in value){let result2=(env??source.env??process.env)[value.$env];if(warnOpaqueConfigEnvironment(value.$env,result2),result2===void 0)throw new ConfigReferenceError(source.field,value,"unset");if(result2==="")throw new ConfigReferenceError(source.field,value,"empty");return rememberResolvedReferenceValue(result2),result2}let parts=[];for(let part of value.$concat)parts.push(typeof part=="string"?part:await resolveConfigReference(part,source,env));let result=parts.join("");if(result==="")throw new ConfigReferenceError(source.field,value,"empty");return rememberResolvedReferenceValue(result),result}import{spawn}from"child_process";var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{signalSpawnedChild(child,"SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(signalSpawnedChild(child,"SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){let value=env?.[name]||process.env[name]||void 0;return warnOpaqueConfigEnvironment(name,value),value}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0){warnMissingConfigEnvironment(part.name);return}resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){if(typeof config!="string")return"$env"in config?[config.$env]:"$concat"in config?[...new Set(config.$concat.flatMap(part=>typeof part!="string"&&"$env"in part?[part.$env]:[]))]:[];let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return typeof config=="string"&&parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return typeof config!="string"||getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let resolvedValue=await resolveConfigValueUncached(config,env,context);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;for(let value of Object.values(headers))assertConfigReferenceAuthority(value);let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}export{ConfigValueSchema,NonemptyConfigValueSchema,isConfigReference,warnOpaqueConfigEnvironment,warnMissingConfigEnvironment,rememberConfigReferenceOrigin,assertConfigReferenceAuthority,resolveConfigReference,sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent};
|
|
2
|
+
import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{getShellConfig}from"./chunk-DSWDJ7HT.js";import{rememberResolvedReferenceValue}from"./chunk-DLAY7CIU.js";import{Compile}from"./chunk-YUVC7SJB.js";import{ConfigReferenceError}from"./chunk-OKMHSVCA.js";import{sanitizeProviderDiagnostic}from"./chunk-JGKH3D6W.js";import{attachProviderDiagnostic}from"./chunk-3SASTB6Y.js";import{typebox_exports}from"./chunk-MIENF2YK.js";var PRE_COMMIT_EVENT_TYPES=new Set(["start","text_start","thinking_start","toolcall_start"]);function isCommittedRotationOutput(event){return!PRE_COMMIT_EVENT_TYPES.has(event.type)}function isRotationStreamStart(event){return event.type==="start"}function rotationErrorFromEvent(event){if(event.type!=="error")return;let failure=new Error(event.error.errorMessage??"provider stream error");attachProviderDiagnostic(failure,sanitizeProviderDiagnostic(event.error.providerDiagnostic));let status=event.error.providerDiagnostic?.httpStatus;return status===void 0?failure:Object.assign(failure,{status})}var FileReferenceSchema=typebox_exports.Object({$file:typebox_exports.String({minLength:1})},{additionalProperties:!1}),EnvReferenceSchema=typebox_exports.Object({$env:typebox_exports.String({pattern:"^[A-Za-z_][A-Za-z0-9_]*$"})},{additionalProperties:!1}),ConcatReferenceSchema=typebox_exports.Object({$concat:typebox_exports.Array(typebox_exports.Union([typebox_exports.String(),FileReferenceSchema,EnvReferenceSchema]))},{additionalProperties:!1}),ConfigReferenceSchema=typebox_exports.Union([FileReferenceSchema,EnvReferenceSchema,ConcatReferenceSchema]),ConfigValueSchema=typebox_exports.Union([typebox_exports.String(),ConfigReferenceSchema]),NonemptyConfigValueSchema=typebox_exports.Union([typebox_exports.String({minLength:1}),ConfigReferenceSchema]),validateReference=Compile(ConfigReferenceSchema);function isConfigReference(value){return validateReference.Check(value)}function assertConfigValue(value,field){if(typeof value!="string"&&!isConfigReference(value))throw new ConfigReferenceError(field,value,"malformed")}function sleep(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(new Error("Aborted"));return}let timeout=setTimeout(resolve,ms);signal?.addEventListener("abort",()=>{clearTimeout(timeout),reject(new Error("Aborted"))})})}var warnedVariables=new Set;function warnOpaqueConfigEnvironment(name,value){value!==void 0&&/\{(?:file|env):/.test(value)&&!warnedVariables.has(name)&&(warnedVariables.add(name),console.warn(`${name}: environment value contains reference-looking text; inserted literally`))}function warnMissingConfigEnvironment(name){warnedVariables.has(name)||(warnedVariables.add(name),console.warn(`${name}: configuration environment variable is unset`))}import{dirname as dirname2}from"node:path";import{constants}from"node:fs";import{lstat,open,readlink}from"node:fs/promises";import{homedir}from"node:os";import{dirname,isAbsolute,join,parse,sep}from"node:path";var MAX_BYTES=65536,readableWarnings=new Set;function fail(input,reason){throw new ConfigReferenceError(input.field,input.reference,reason)}function checkOwner(input,stat){process.platform!=="win32"&&stat.uid!==0&&stat.uid!==process.getuid?.()&&fail(input,"unsafe-owner")}function checkWritable(input,stat,ancestor){process.platform==="win32"||stat.isSymbolicLink()||(stat.mode&18)===0||ancestor&&stat.isDirectory()&&(stat.mode&512)!==0||fail(input,"unsafe-permissions")}function sameFile(left,right){return left.dev===right.dev&&left.ino===right.ino}function absolutePath(input){let declared=input.reference.$file;return declared.startsWith("~/")||process.platform==="win32"&&declared.startsWith("~\\")?`${homedir()}${sep}${declared.slice(2)}`:isAbsolute(declared)?declared:`${input.baseDir}${sep}${declared}`}async function walk(input){let absolute=absolutePath(input),current=parse(absolute).root,pending=absolute.slice(current.length).split(sep).filter(Boolean),stat=await lstat(current),links=0;checkOwner(input,stat),checkWritable(input,stat,!0);for(let part=pending.shift();part!==void 0;part=pending.shift()){if(part===".")continue;stat.isDirectory()||fail(input,"non-regular");let next=part===".."?dirname(current):join(current,part),nextStat=await lstat(next);if(checkOwner(input,nextStat),process.platform!=="win32"&&(stat.mode&18)!==0&&!nextStat.isSymbolicLink()&&(nextStat.mode&18)!==0&&fail(input,"unsafe-permissions"),checkWritable(input,nextStat,pending.length>0),nextStat.isSymbolicLink()){++links>40&&fail(input,"unreadable");let target=await readlink(next);sameFile(nextStat,await lstat(next))||fail(input,"changed");let targetPath=isAbsolute(target)?target:`${current}${sep}${target}`;current=parse(targetPath).root,pending=[...targetPath.slice(current.length).split(sep).filter(Boolean),...pending],stat=await lstat(current),checkOwner(input,stat),checkWritable(input,stat,!0)}else current=next,stat=nextStat}return stat.isFile()||fail(input,"non-regular"),{path:current,stat}}async function readConfigReferenceFile(input){try{let walked=await walk(input),flags=constants.O_RDONLY|(constants.O_NOFOLLOW??0)|(constants.O_NONBLOCK??0),handle=await open(walked.path,flags);try{let stat=await handle.stat();sameFile(walked.stat,stat)||fail(input,"changed"),stat.isFile()||fail(input,"non-regular"),checkOwner(input,stat),checkWritable(input,stat,!1),stat.size>MAX_BYTES&&fail(input,"oversize");let buffer=Buffer.alloc(MAX_BYTES+1),length=0;for(;length<buffer.length;){let{bytesRead}=await handle.read(buffer,length,buffer.length-length,length);if(bytesRead===0)break;length+=bytesRead}length>MAX_BYTES&&fail(input,"oversize");let value;try{value=new TextDecoder("utf-8",{fatal:!0}).decode(buffer.subarray(0,length)).trim()}catch{fail(input,"invalid-utf8")}return value.length===0&&fail(input,"empty"),process.platform!=="win32"&&(stat.mode&36)!==0&&!readableWarnings.has(walked.path)&&(readableWarnings.add(walked.path),console.warn(`${input.field}: reference file is readable by other users`)),value}finally{await handle.close()}}catch(error){if(error instanceof ConfigReferenceError)throw error;let code=Reflect.get(Object(error),"code");fail(input,code==="ENOENT"||code==="ENOTDIR"?"missing":"unreadable")}}var origins=new WeakMap;function rememberConfigReferenceOrigin(value,context){typeof value!="string"&&origins.set(value,context)}function configReferenceContext(value,context){return context??(typeof value=="string"?void 0:origins.get(value))}function assertConfigReferenceAuthority(value,context){if(typeof value=="string")return;let source=configReferenceContext(value,context);if(source?.authority!=="trusted")throw new ConfigReferenceError(source?.field??"configuration value",value,"forbidden");assertConfigValue(value,source.field)}async function resolveConfigReference(value,context,env){let source=configReferenceContext(value,context);if(assertConfigReferenceAuthority(value,source),source===void 0)throw new ConfigReferenceError("configuration value",value,"forbidden");if("$file"in value){let text=await readConfigReferenceFile({field:source.field,reference:value,baseDir:source.baseDir??dirname2(source.origin)});return rememberResolvedReferenceValue(text),text}if("$env"in value){let result2=(env??source.env??process.env)[value.$env];if(warnOpaqueConfigEnvironment(value.$env,result2),result2===void 0)throw new ConfigReferenceError(source.field,value,"unset");if(result2==="")throw new ConfigReferenceError(source.field,value,"empty");return rememberResolvedReferenceValue(result2),result2}let parts=[];for(let part of value.$concat)parts.push(typeof part=="string"?part:await resolveConfigReference(part,source,env));let result=parts.join("");if(result==="")throw new ConfigReferenceError(source.field,value,"empty");return rememberResolvedReferenceValue(result),result}import{spawn}from"child_process";var COMMAND_EXECUTION_MAX_ATTEMPTS=3,COMMAND_EXECUTION_BACKOFF_MS=[250,1e3],COMMAND_TIMEOUT_MS=1e4,COMMAND_MAX_OUTPUT_BYTES=1024*1024;function runCommandProcess(file,args,options){return new Promise(resolveOutcome=>{let spawnOptions={shell:options.shell,windowsHide:!0,...options.env===void 0?{}:{env:{...process.env,...options.env}}},child=options.stdin===void 0?spawn(file,[...args],{...spawnOptions,stdio:["ignore","pipe","ignore"]}):spawn(file,[...args],{...spawnOptions,stdio:["pipe","pipe","ignore"]}),stdout="",settled=!1,finish=outcome=>{settled||(settled=!0,clearTimeout(timer),resolveOutcome(outcome))},timer=setTimeout(()=>{signalSpawnedChild(child,"SIGTERM"),child.unref(),finish({executed:!0,value:void 0})},COMMAND_TIMEOUT_MS);child.stdout.setEncoding("utf-8"),child.stdout.on("data",chunk=>{stdout+=chunk,!(stdout.length<=COMMAND_MAX_OUTPUT_BYTES)&&(signalSpawnedChild(child,"SIGTERM"),finish({executed:!0,value:void 0}))}),child.on("error",error=>finish({executed:error.code!=="ENOENT",value:void 0})),child.on("close",code=>{let value=stdout.trim();finish({executed:!0,value:code===0&&value?value:void 0})}),child.stdin?.end(options.stdin)})}async function executeWithConfiguredShell(command,env){try{let{shell,args,commandTransport}=getShellConfig(),commandFromStdin=commandTransport==="stdin";return await runCommandProcess(shell,commandFromStdin?args:[...args,command],{shell:!1,...commandFromStdin?{stdin:command}:{},...env===void 0?{}:{env}})}catch{return{executed:!1,value:void 0}}}async function executeCommandOnce(command,env){if(process.platform==="win32"){let configured=await executeWithConfiguredShell(command,env);if(configured.executed)return configured.value}return(await runCommandProcess(command,[],{shell:!0,...env===void 0?{}:{env}})).value}async function runConfigCommand(commandConfig,env){let command=commandConfig.slice(1);for(let attempt=0;attempt<COMMAND_EXECUTION_MAX_ATTEMPTS;attempt++){let value=await executeCommandOnce(command,env);if(value!==void 0)return value;let backoffMs=COMMAND_EXECUTION_BACKOFF_MS[attempt];backoffMs!==void 0&&await sleep(backoffMs)}}var commandResultCache=new Map,ENV_VAR_NAME_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,ENV_VAR_NAME_PREFIX_RE=/^[A-Za-z_][A-Za-z0-9_]*/;function appendLiteral(parts,value){if(!value)return;let previousPart=parts[parts.length-1];if(previousPart?.type==="literal"){previousPart.value+=value;return}parts.push({type:"literal",value})}function parseConfigValueTemplate(config){let parts=[],index=0;for(;index<config.length;){let dollarIndex=config.indexOf("$",index);if(dollarIndex<0){appendLiteral(parts,config.slice(index));break}appendLiteral(parts,config.slice(index,dollarIndex));let nextChar=config[dollarIndex+1];if(nextChar==="$"||nextChar==="!"){appendLiteral(parts,nextChar),index=dollarIndex+2;continue}if(nextChar==="{"){let endIndex=config.indexOf("}",dollarIndex+2);if(endIndex<0){appendLiteral(parts,"$"),index=dollarIndex+1;continue}let name=config.slice(dollarIndex+2,endIndex);ENV_VAR_NAME_RE.test(name)?parts.push({type:"env",name}):appendLiteral(parts,config.slice(dollarIndex,endIndex+1)),index=endIndex+1;continue}let match=config.slice(dollarIndex+1).match(ENV_VAR_NAME_PREFIX_RE);if(match){parts.push({type:"env",name:match[0]}),index=dollarIndex+1+match[0].length;continue}appendLiteral(parts,"$"),index=dollarIndex+1}return parts}function parseConfigValueReference(config){return config.startsWith("!")?{type:"command",config}:{type:"template",parts:parseConfigValueTemplate(config)}}function resolveEnvConfigValue(name,env){let value=env?.[name]||process.env[name]||void 0;return warnOpaqueConfigEnvironment(name,value),value}function getTemplateEnvVarNames(parts){let names=[];for(let part of parts)part.type!=="env"||names.includes(part.name)||names.push(part.name);return names}function resolveTemplate(parts,env){let resolved="";for(let part of parts){if(part.type==="literal"){resolved+=part.value;continue}let envValue=resolveEnvConfigValue(part.name,env);if(envValue===void 0){warnMissingConfigEnvironment(part.name);return}resolved+=envValue}return resolved}function getConfigValueEnvVarNames(config){if(typeof config!="string")return"$env"in config?[config.$env]:"$concat"in config?[...new Set(config.$concat.flatMap(part=>typeof part!="string"&&"$env"in part?[part.$env]:[]))]:[];let reference=parseConfigValueReference(config);return reference.type==="template"?getTemplateEnvVarNames(reference.parts):[]}function getMissingConfigValueEnvVarNames(config,env){return getConfigValueEnvVarNames(config).filter(name=>resolveEnvConfigValue(name,env)===void 0)}function isCommandConfigValue(config){return typeof config=="string"&&parseConfigValueReference(config).type==="command"}function isConfigValueConfigured(config,env){return typeof config!="string"||getMissingConfigValueEnvVarNames(config,env).length===0}function resolveConfigValue(config,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let reference=parseConfigValueReference(config);return reference.type==="command"?env===void 0?executeCommand(reference.config):runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}function executeCommand(commandConfig){let cached=commandResultCache.get(commandConfig);if(cached)return cached;let result=runConfigCommand(commandConfig);return commandResultCache.set(commandConfig,result),result}function resolveConfigValueUncached(config,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let reference=parseConfigValueReference(config);return reference.type==="command"?runConfigCommand(reference.config,env):Promise.resolve(resolveTemplate(reference.parts,env))}async function resolveConfigValueOrThrow(config,description,env,context){if(typeof config!="string")return resolveConfigReference(config,context,env);let resolvedValue=await resolveConfigValueUncached(config,env,context);if(resolvedValue!==void 0)return resolvedValue;let reference=parseConfigValueReference(config);if(reference.type==="command")throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);if(reference.type==="template"){let missingEnvVars=getMissingConfigValueEnvVarNames(config,env);if(missingEnvVars.length===1)throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);if(missingEnvVars.length>1)throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`)}throw new Error(`Failed to resolve ${description}`)}async function resolveHeadersOrThrow(headers,description,env){if(!headers)return;for(let value of Object.values(headers))assertConfigReferenceAuthority(value);let resolved={};for(let[key,value]of Object.entries(headers))resolved[key]=await resolveConfigValueOrThrow(value,`${description} header "${key}"`,env);return Object.keys(resolved).length>0?resolved:void 0}export{ConfigValueSchema,NonemptyConfigValueSchema,isConfigReference,warnOpaqueConfigEnvironment,warnMissingConfigEnvironment,rememberConfigReferenceOrigin,assertConfigReferenceAuthority,resolveConfigReference,sleep,getConfigValueEnvVarNames,isCommandConfigValue,isConfigValueConfigured,resolveConfigValue,resolveConfigValueOrThrow,resolveHeadersOrThrow,isCommittedRotationOutput,isRotationStreamStart,rotationErrorFromEvent};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{KeybindingsManager,TUI_KEYBINDINGS,isWarpWslSession}from"./chunk-RI5ABX7A.js";import{getAgentDir,stripBom}from"./chunk-SODMQEHO.js";import{existsSync,readFileSync as readFileSync2}from"fs";import{join}from"path";import{readFileSync}from"node:fs";function isWSL(env=process.env,procVersionPath="/proc/version"){if(env.WSL_DISTRO_NAME||env.WSL_INTEROP||env.WSLENV)return!0;try{let release=readFileSync(procVersionPath,"utf-8");return/microsoft|wsl/i.test(release)}catch{return!1}}function useWindowsKeybindings(platform=process.platform,env=process.env,procVersionPath){return platform==="win32"||platform==="linux"&&isWSL(env,procVersionPath)}var windowsKeybindings=useWindowsKeybindings(),QUESTION_ANSWER_PRIMARY_KEY="alt+up",QUESTION_ANSWER_FALLBACK_KEY="alt+a",KEYBINDINGS={...TUI_KEYBINDINGS,"tui.editor.undo":{...TUI_KEYBINDINGS["tui.editor.undo"],defaultKeys:process.platform==="win32"?"ctrl+z":windowsKeybindings?"alt+z":"ctrl+-"},"tui.altScreen.previousPrompt":{...TUI_KEYBINDINGS["tui.altScreen.previousPrompt"],defaultKeys:windowsKeybindings?"ctrl+up":["ctrl+shift+up","ctrl+up"]},"tui.altScreen.nextPrompt":{...TUI_KEYBINDINGS["tui.altScreen.nextPrompt"],defaultKeys:windowsKeybindings?"ctrl+down":["ctrl+shift+down","ctrl+down"]},"tui.altScreen.search":{...TUI_KEYBINDINGS["tui.altScreen.search"],defaultKeys:windowsKeybindings?"ctrl+f":"ctrl+shift+f"},"app.interrupt":{defaultKeys:"escape",description:"Cancel or abort"},"app.clear":{defaultKeys:"ctrl+c",description:"Clear editor"},"app.exit":{defaultKeys:"ctrl+d",description:"Exit when editor is empty"},"app.suspend":{defaultKeys:process.platform==="win32"?[]:"ctrl+z",description:"Suspend to background"},"app.thinking.cycle":{defaultKeys:"shift+tab",description:"Cycle thinking level"},"app.thinking.save":{defaultKeys:"ctrl+s",description:"Save thinking level"},"app.model.cycleForward":{defaultKeys:"ctrl+p",description:"Cycle to next model"},"app.model.cycleBackward":{defaultKeys:windowsKeybindings?"alt+p":"shift+ctrl+p",description:"Cycle to previous model"},"app.model.select":{defaultKeys:"ctrl+l",description:"Open model selector"},"app.history.search":{defaultKeys:"ctrl+r",description:"Search prompt history across sessions"},"app.tools.expand":{defaultKeys:"ctrl+o",description:"Toggle tool output"},"app.thinking.toggle":{defaultKeys:"ctrl+t",description:"Toggle thinking blocks"},"app.session.toggleNamedFilter":{defaultKeys:"ctrl+n",description:"Toggle named session filter"},"app.editor.external":{defaultKeys:"ctrl+g",description:"Open external editor"},"app.message.copy":{defaultKeys:"ctrl+x",description:"Copy selection or last assistant message"},"app.message.followUp":{defaultKeys:windowsKeybindings?"ctrl+q":"alt+enter",description:"Queue follow-up message"},"app.message.dequeue":{defaultKeys:windowsKeybindings?"alt+q":"alt+up",description:"Restore queued messages"},"app.question.answer":{defaultKeys:[QUESTION_ANSWER_PRIMARY_KEY,QUESTION_ANSWER_FALLBACK_KEY],description:"Open the pending question"},"app.question.next":{defaultKeys:"alt+down",description:"Show the next pending question"},"app.clipboard.pasteImage":{defaultKeys:isWarpWslSession()?["ctrl+v","alt+v"]:windowsKeybindings?"alt+v":"ctrl+v",description:"Paste files on macOS, images, or text from clipboard"},"app.session.new":{defaultKeys:[],description:"Start a new session"},"app.session.tree":{defaultKeys:[],description:"Open session tree"},"app.session.fork":{defaultKeys:[],description:"Fork current session"},"app.session.resume":{defaultKeys:[],description:"Resume a session"},"app.session.renameCurrent":{defaultKeys:[],description:"Rename the current session"},"app.tree.foldOrUp":{defaultKeys:process.platform==="darwin"?["alt+left","ctrl+left"]:["ctrl+left","alt+left"],description:"Fold tree branch or move up"},"app.tree.unfoldOrDown":{defaultKeys:process.platform==="darwin"?["alt+right","ctrl+right"]:["ctrl+right","alt+right"],description:"Unfold tree branch or move down"},"app.tree.editLabel":{defaultKeys:"shift+l",description:"Edit tree label"},"app.tree.editMessage":{defaultKeys:"ctrl+e",description:"Edit the selected assistant response, or reopen a user message in the editor"},"app.tree.toggleLabelTimestamp":{defaultKeys:"shift+t",description:"Toggle tree label timestamps"},"app.session.togglePath":{defaultKeys:"ctrl+p",description:"Toggle session path display"},"app.session.toggleSort":{defaultKeys:"ctrl+s",description:"Toggle session sort mode"},"app.session.rename":{defaultKeys:"ctrl+r",description:"Rename session"},"app.session.delete":{defaultKeys:"ctrl+d",description:"Delete session"},"app.session.deleteNoninvasive":{defaultKeys:"ctrl+backspace",description:"Delete session when query is empty"},"app.models.save":{defaultKeys:"ctrl+s",description:"Save model selection"},"app.models.toggleFavorite":{defaultKeys:"ctrl+f",description:"Toggle favorite model"},"app.models.enableAll":{defaultKeys:"ctrl+a",description:"Enable all models"},"app.models.clearAll":{defaultKeys:"ctrl+x",description:"Clear all models"},"app.models.toggleProvider":{defaultKeys:"ctrl+p",description:"Toggle all models for provider"},"app.models.reorderUp":{defaultKeys:"alt+up",description:"Move model up in order"},"app.models.reorderDown":{defaultKeys:"alt+down",description:"Move model down in order"},"app.tree.filter.default":{defaultKeys:"ctrl+d",description:"Tree filter: default view"},"app.tree.filter.noTools":{defaultKeys:"ctrl+t",description:"Tree filter: hide tool results"},"app.tree.filter.userOnly":{defaultKeys:"ctrl+u",description:"Tree filter: user messages only"},"app.tree.filter.labeledOnly":{defaultKeys:"ctrl+l",description:"Tree filter: labeled entries only"},"app.tree.filter.all":{defaultKeys:"ctrl+a",description:"Tree filter: show all entries"},"app.tree.filter.cycleForward":{defaultKeys:"ctrl+o",description:"Tree filter: cycle forward"},"app.tree.filter.cycleBackward":{defaultKeys:"shift+ctrl+o",description:"Tree filter: cycle backward"}},KEYBINDING_NAME_MIGRATIONS={cursorUp:"tui.editor.cursorUp",cursorDown:"tui.editor.cursorDown",cursorLeft:"tui.editor.cursorLeft",cursorRight:"tui.editor.cursorRight",cursorWordLeft:"tui.editor.cursorWordLeft",cursorWordRight:"tui.editor.cursorWordRight",cursorLineStart:"tui.editor.cursorLineStart",cursorLineEnd:"tui.editor.cursorLineEnd",jumpForward:"tui.editor.jumpForward",jumpBackward:"tui.editor.jumpBackward",pageUp:"tui.editor.pageUp",pageDown:"tui.editor.pageDown",deleteCharBackward:"tui.editor.deleteCharBackward",deleteCharForward:"tui.editor.deleteCharForward",deleteWordBackward:"tui.editor.deleteWordBackward",deleteWordForward:"tui.editor.deleteWordForward",deleteToLineStart:"tui.editor.deleteToLineStart",deleteToLineEnd:"tui.editor.deleteToLineEnd",yank:"tui.editor.yank",yankPop:"tui.editor.yankPop",undo:"tui.editor.undo",newLine:"tui.input.newLine",submit:"tui.input.submit",tab:"tui.input.tab",copy:"tui.input.copy",selectUp:"tui.select.up",selectDown:"tui.select.down",selectPageUp:"tui.select.pageUp",selectPageDown:"tui.select.pageDown",selectConfirm:"tui.select.confirm",selectCancel:"tui.select.cancel",interrupt:"app.interrupt",clear:"app.clear",exit:"app.exit",suspend:"app.suspend",cycleThinkingLevel:"app.thinking.cycle",cycleModelForward:"app.model.cycleForward",cycleModelBackward:"app.model.cycleBackward",selectModel:"app.model.select",expandTools:"app.tools.expand",toggleThinking:"app.thinking.toggle",toggleSessionNamedFilter:"app.session.toggleNamedFilter",externalEditor:"app.editor.external",followUp:"app.message.followUp",dequeue:"app.message.dequeue",pasteImage:"app.clipboard.pasteImage",newSession:"app.session.new",tree:"app.session.tree",fork:"app.session.fork",resume:"app.session.resume",treeFoldOrUp:"app.tree.foldOrUp",treeUnfoldOrDown:"app.tree.unfoldOrDown",treeEditLabel:"app.tree.editLabel",treeEditMessage:"app.tree.editMessage",treeToggleLabelTimestamp:"app.tree.toggleLabelTimestamp",toggleSessionPath:"app.session.togglePath",toggleSessionSort:"app.session.toggleSort",renameSession:"app.session.rename",deleteSession:"app.session.delete",deleteSessionNoninvasive:"app.session.deleteNoninvasive"};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function hasOwn(value,key){return Object.hasOwn(value,key)}function isLegacyKeybindingName(key){return key in KEYBINDING_NAME_MIGRATIONS}function toKeybindingsConfig(value){let config={};for(let[key,binding]of Object.entries(value)){if(typeof binding=="string"){config[key]=binding;continue}Array.isArray(binding)&&binding.every(entry=>typeof entry=="string")&&(config[key]=binding)}return config}function migrateKeybindingsConfig(rawConfig){let config={},migrated=!1;for(let[key,value]of Object.entries(rawConfig)){let nextKey=isLegacyKeybindingName(key)?KEYBINDING_NAME_MIGRATIONS[key]:key;if(nextKey!==key&&(migrated=!0),key!==nextKey&&hasOwn(rawConfig,nextKey)){migrated=!0;continue}config[nextKey]=value}return{config:orderKeybindingsConfig(config),migrated}}function orderKeybindingsConfig(config){let ordered={};for(let keybinding of Object.keys(KEYBINDINGS))hasOwn(config,keybinding)&&(ordered[keybinding]=config[keybinding]);let extras=Object.keys(config).filter(key=>!hasOwn(ordered,key)).sort();for(let key of extras)ordered[key]=config[key];return ordered}function loadRawConfig(path){if(existsSync(path))try{let parsed=JSON.parse(stripBom(readFileSync2(path,"utf-8")));return isRecord(parsed)?parsed:void 0}catch{return}}var KeybindingsManager2=class _KeybindingsManager extends KeybindingsManager{constructor(userBindings={},configPath){super(KEYBINDINGS,userBindings),this.configPath=configPath}static create(agentDir=getAgentDir()){let configPath=join(agentDir,"keybindings.json"),userBindings=_KeybindingsManager.loadFromFile(configPath);return new _KeybindingsManager(userBindings,configPath)}reload(){this.configPath&&this.setUserBindings(_KeybindingsManager.loadFromFile(this.configPath))}getEffectiveConfig(){return this.getResolvedBindings()}static loadFromFile(path){let rawConfig=loadRawConfig(path);return rawConfig?toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config):{}}};export{isWSL,QUESTION_ANSWER_PRIMARY_KEY,QUESTION_ANSWER_FALLBACK_KEY,KEYBINDINGS,migrateKeybindingsConfig,KeybindingsManager2 as KeybindingsManager};
|
|
2
|
+
import{KeybindingsManager,TUI_KEYBINDINGS,isWarpWslSession}from"./chunk-TMXRR3N7.js";import{getAgentDir,stripBom}from"./chunk-SODMQEHO.js";import{existsSync,readFileSync as readFileSync2}from"fs";import{join}from"path";import{readFileSync}from"node:fs";function isWSL(env=process.env,procVersionPath="/proc/version"){if(env.WSL_DISTRO_NAME||env.WSL_INTEROP||env.WSLENV)return!0;try{let release=readFileSync(procVersionPath,"utf-8");return/microsoft|wsl/i.test(release)}catch{return!1}}function useWindowsKeybindings(platform=process.platform,env=process.env,procVersionPath){return platform==="win32"||platform==="linux"&&isWSL(env,procVersionPath)}var windowsKeybindings=useWindowsKeybindings(),QUESTION_ANSWER_PRIMARY_KEY="alt+up",QUESTION_ANSWER_FALLBACK_KEY="alt+a",KEYBINDINGS={...TUI_KEYBINDINGS,"tui.editor.undo":{...TUI_KEYBINDINGS["tui.editor.undo"],defaultKeys:process.platform==="win32"?"ctrl+z":windowsKeybindings?"alt+z":"ctrl+-"},"tui.altScreen.previousPrompt":{...TUI_KEYBINDINGS["tui.altScreen.previousPrompt"],defaultKeys:windowsKeybindings?"ctrl+up":["ctrl+shift+up","ctrl+up"]},"tui.altScreen.nextPrompt":{...TUI_KEYBINDINGS["tui.altScreen.nextPrompt"],defaultKeys:windowsKeybindings?"ctrl+down":["ctrl+shift+down","ctrl+down"]},"tui.altScreen.search":{...TUI_KEYBINDINGS["tui.altScreen.search"],defaultKeys:windowsKeybindings?"ctrl+f":"ctrl+shift+f"},"app.interrupt":{defaultKeys:"escape",description:"Cancel or abort"},"app.clear":{defaultKeys:"ctrl+c",description:"Clear editor"},"app.exit":{defaultKeys:"ctrl+d",description:"Exit when editor is empty"},"app.suspend":{defaultKeys:process.platform==="win32"?[]:"ctrl+z",description:"Suspend to background"},"app.thinking.cycle":{defaultKeys:"shift+tab",description:"Cycle thinking level"},"app.thinking.save":{defaultKeys:"ctrl+s",description:"Save thinking level"},"app.model.cycleForward":{defaultKeys:"ctrl+p",description:"Cycle to next model"},"app.model.cycleBackward":{defaultKeys:windowsKeybindings?"alt+p":"shift+ctrl+p",description:"Cycle to previous model"},"app.model.select":{defaultKeys:"ctrl+l",description:"Open model selector"},"app.history.search":{defaultKeys:"ctrl+r",description:"Search prompt history across sessions"},"app.tools.expand":{defaultKeys:"ctrl+o",description:"Toggle tool output"},"app.thinking.toggle":{defaultKeys:"ctrl+t",description:"Toggle thinking blocks"},"app.session.toggleNamedFilter":{defaultKeys:"ctrl+n",description:"Toggle named session filter"},"app.editor.external":{defaultKeys:"ctrl+g",description:"Open external editor"},"app.message.copy":{defaultKeys:"ctrl+x",description:"Copy selection or last assistant message"},"app.message.followUp":{defaultKeys:windowsKeybindings?"ctrl+q":"alt+enter",description:"Queue follow-up message"},"app.message.dequeue":{defaultKeys:windowsKeybindings?"alt+q":"alt+up",description:"Restore queued messages"},"app.question.answer":{defaultKeys:[QUESTION_ANSWER_PRIMARY_KEY,QUESTION_ANSWER_FALLBACK_KEY],description:"Open the pending question"},"app.question.next":{defaultKeys:"alt+down",description:"Show the next pending question"},"app.clipboard.pasteImage":{defaultKeys:isWarpWslSession()?["ctrl+v","alt+v"]:windowsKeybindings?"alt+v":"ctrl+v",description:"Paste files on macOS, images, or text from clipboard"},"app.session.new":{defaultKeys:[],description:"Start a new session"},"app.session.tree":{defaultKeys:[],description:"Open session tree"},"app.session.fork":{defaultKeys:[],description:"Fork current session"},"app.session.resume":{defaultKeys:[],description:"Resume a session"},"app.session.renameCurrent":{defaultKeys:[],description:"Rename the current session"},"app.tree.foldOrUp":{defaultKeys:process.platform==="darwin"?["alt+left","ctrl+left"]:["ctrl+left","alt+left"],description:"Fold tree branch or move up"},"app.tree.unfoldOrDown":{defaultKeys:process.platform==="darwin"?["alt+right","ctrl+right"]:["ctrl+right","alt+right"],description:"Unfold tree branch or move down"},"app.tree.editLabel":{defaultKeys:"shift+l",description:"Edit tree label"},"app.tree.editMessage":{defaultKeys:"ctrl+e",description:"Edit the selected assistant response, or reopen a user message in the editor"},"app.tree.toggleLabelTimestamp":{defaultKeys:"shift+t",description:"Toggle tree label timestamps"},"app.session.togglePath":{defaultKeys:"ctrl+p",description:"Toggle session path display"},"app.session.toggleSort":{defaultKeys:"ctrl+s",description:"Toggle session sort mode"},"app.session.rename":{defaultKeys:"ctrl+r",description:"Rename session"},"app.session.delete":{defaultKeys:"ctrl+d",description:"Delete session"},"app.session.deleteNoninvasive":{defaultKeys:"ctrl+backspace",description:"Delete session when query is empty"},"app.models.save":{defaultKeys:"ctrl+s",description:"Save model selection"},"app.models.toggleFavorite":{defaultKeys:"ctrl+f",description:"Toggle favorite model"},"app.models.enableAll":{defaultKeys:"ctrl+a",description:"Enable all models"},"app.models.clearAll":{defaultKeys:"ctrl+x",description:"Clear all models"},"app.models.toggleProvider":{defaultKeys:"ctrl+p",description:"Toggle all models for provider"},"app.models.reorderUp":{defaultKeys:"alt+up",description:"Move model up in order"},"app.models.reorderDown":{defaultKeys:"alt+down",description:"Move model down in order"},"app.tree.filter.default":{defaultKeys:"ctrl+d",description:"Tree filter: default view"},"app.tree.filter.noTools":{defaultKeys:"ctrl+t",description:"Tree filter: hide tool results"},"app.tree.filter.userOnly":{defaultKeys:"ctrl+u",description:"Tree filter: user messages only"},"app.tree.filter.labeledOnly":{defaultKeys:"ctrl+l",description:"Tree filter: labeled entries only"},"app.tree.filter.all":{defaultKeys:"ctrl+a",description:"Tree filter: show all entries"},"app.tree.filter.cycleForward":{defaultKeys:"ctrl+o",description:"Tree filter: cycle forward"},"app.tree.filter.cycleBackward":{defaultKeys:"shift+ctrl+o",description:"Tree filter: cycle backward"}},KEYBINDING_NAME_MIGRATIONS={cursorUp:"tui.editor.cursorUp",cursorDown:"tui.editor.cursorDown",cursorLeft:"tui.editor.cursorLeft",cursorRight:"tui.editor.cursorRight",cursorWordLeft:"tui.editor.cursorWordLeft",cursorWordRight:"tui.editor.cursorWordRight",cursorLineStart:"tui.editor.cursorLineStart",cursorLineEnd:"tui.editor.cursorLineEnd",jumpForward:"tui.editor.jumpForward",jumpBackward:"tui.editor.jumpBackward",pageUp:"tui.editor.pageUp",pageDown:"tui.editor.pageDown",deleteCharBackward:"tui.editor.deleteCharBackward",deleteCharForward:"tui.editor.deleteCharForward",deleteWordBackward:"tui.editor.deleteWordBackward",deleteWordForward:"tui.editor.deleteWordForward",deleteToLineStart:"tui.editor.deleteToLineStart",deleteToLineEnd:"tui.editor.deleteToLineEnd",yank:"tui.editor.yank",yankPop:"tui.editor.yankPop",undo:"tui.editor.undo",newLine:"tui.input.newLine",submit:"tui.input.submit",tab:"tui.input.tab",copy:"tui.input.copy",selectUp:"tui.select.up",selectDown:"tui.select.down",selectPageUp:"tui.select.pageUp",selectPageDown:"tui.select.pageDown",selectConfirm:"tui.select.confirm",selectCancel:"tui.select.cancel",interrupt:"app.interrupt",clear:"app.clear",exit:"app.exit",suspend:"app.suspend",cycleThinkingLevel:"app.thinking.cycle",cycleModelForward:"app.model.cycleForward",cycleModelBackward:"app.model.cycleBackward",selectModel:"app.model.select",expandTools:"app.tools.expand",toggleThinking:"app.thinking.toggle",toggleSessionNamedFilter:"app.session.toggleNamedFilter",externalEditor:"app.editor.external",followUp:"app.message.followUp",dequeue:"app.message.dequeue",pasteImage:"app.clipboard.pasteImage",newSession:"app.session.new",tree:"app.session.tree",fork:"app.session.fork",resume:"app.session.resume",treeFoldOrUp:"app.tree.foldOrUp",treeUnfoldOrDown:"app.tree.unfoldOrDown",treeEditLabel:"app.tree.editLabel",treeEditMessage:"app.tree.editMessage",treeToggleLabelTimestamp:"app.tree.toggleLabelTimestamp",toggleSessionPath:"app.session.togglePath",toggleSessionSort:"app.session.toggleSort",renameSession:"app.session.rename",deleteSession:"app.session.delete",deleteSessionNoninvasive:"app.session.deleteNoninvasive"};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function hasOwn(value,key){return Object.hasOwn(value,key)}function isLegacyKeybindingName(key){return key in KEYBINDING_NAME_MIGRATIONS}function toKeybindingsConfig(value){let config={};for(let[key,binding]of Object.entries(value)){if(typeof binding=="string"){config[key]=binding;continue}Array.isArray(binding)&&binding.every(entry=>typeof entry=="string")&&(config[key]=binding)}return config}function migrateKeybindingsConfig(rawConfig){let config={},migrated=!1;for(let[key,value]of Object.entries(rawConfig)){let nextKey=isLegacyKeybindingName(key)?KEYBINDING_NAME_MIGRATIONS[key]:key;if(nextKey!==key&&(migrated=!0),key!==nextKey&&hasOwn(rawConfig,nextKey)){migrated=!0;continue}config[nextKey]=value}return{config:orderKeybindingsConfig(config),migrated}}function orderKeybindingsConfig(config){let ordered={};for(let keybinding of Object.keys(KEYBINDINGS))hasOwn(config,keybinding)&&(ordered[keybinding]=config[keybinding]);let extras=Object.keys(config).filter(key=>!hasOwn(ordered,key)).sort();for(let key of extras)ordered[key]=config[key];return ordered}function loadRawConfig(path){if(existsSync(path))try{let parsed=JSON.parse(stripBom(readFileSync2(path,"utf-8")));return isRecord(parsed)?parsed:void 0}catch{return}}var KeybindingsManager2=class _KeybindingsManager extends KeybindingsManager{constructor(userBindings={},configPath){super(KEYBINDINGS,userBindings),this.configPath=configPath}static create(agentDir=getAgentDir()){let configPath=join(agentDir,"keybindings.json"),userBindings=_KeybindingsManager.loadFromFile(configPath);return new _KeybindingsManager(userBindings,configPath)}reload(){this.configPath&&this.setUserBindings(_KeybindingsManager.loadFromFile(this.configPath))}getEffectiveConfig(){return this.getResolvedBindings()}static loadFromFile(path){let rawConfig=loadRawConfig(path);return rawConfig?toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config):{}}};export{isWSL,QUESTION_ANSWER_PRIMARY_KEY,QUESTION_ANSWER_FALLBACK_KEY,KEYBINDINGS,migrateKeybindingsConfig,KeybindingsManager2 as KeybindingsManager};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{CONFIG_COMMAND_ARGV,HOST_COMMAND_ARGV,SCHEDULE_COMMAND_ARGV,exitAfterOutput,isPackageCommandArgv}from"./chunk-
|
|
2
|
+
import{CONFIG_COMMAND_ARGV,HOST_COMMAND_ARGV,SCHEDULE_COMMAND_ARGV,exitAfterOutput,isPackageCommandArgv}from"./chunk-ECW7VBMB.js";import{APP_NAME,CONFIG_DIR_NAME,CONFIG_FLAT_LAYOUT,ENV_PREFIX,brandEnvNames,getAgentDir}from"./chunk-SODMQEHO.js";import{homedir}from"node:os";try{process.cwd()}catch{let fallback=homedir();process.chdir(fallback),console.error(`the current working directory no longer exists; continuing from ${fallback}`)}import{homedir as homedir2}from"node:os";import{join}from"node:path";async function dispatchAgentDirectoryCommand(args){if(!(args[0]!=="config"||args[1]!=="agent-dir")){(args.length!==3||args[2]!=="--json")&&await exitAfterOutput(`${JSON.stringify({version:1,ok:!1,code:"invalid_arguments",message:`Usage: ${APP_NAME} config agent-dir --json`})}
|
|
3
3
|
`,2);try{let dir=getAgentDir(),selector=brandEnvNames("CODING_AGENT_DIR").find(name=>process.env[name]!==void 0),explicit=selector!==void 0&&process.env[selector]?selector:void 0,homeDefault=CONFIG_FLAT_LAYOUT?join(homedir2(),CONFIG_DIR_NAME):join(homedir2(),CONFIG_DIR_NAME,"agent"),rule=explicit!==void 0?"environment":dir===homeDefault?"home-default":"project-local";await exitAfterOutput(`${JSON.stringify({version:1,ok:!0,dir,source:explicit??(rule==="project-local"?"project-local":"default"),rule,brandedPrefix:ENV_PREFIX})}
|
|
4
4
|
`,0)}catch(error){await exitAfterOutput(`${JSON.stringify({version:1,ok:!1,code:"selection_failed",message:error instanceof Error?error.message:"Unable to resolve the agent directory."})}
|
|
5
5
|
`,1)}}}import*as nodeModule from"node:module";async function enableStartupCompileCache(){let enable=nodeModule.enableCompileCache;if(typeof enable!="function")return;let args=process.argv.slice(2);if(!isPackageCommandArgv(args)&&args[0]!==CONFIG_COMMAND_ARGV&&(args.includes("--version")||args.includes("-v")))return;let scheduleWatch=!1;if(args[0]===SCHEDULE_COMMAND_ARGV&&args[1]==="run")for(let index=2;index<args.length;index++){let arg=args[index];arg==="--watch"?scheduleWatch=!0:["--exec","--poll-seconds","--timeout-seconds","--concurrency"].includes(arg??"")&&index++}if(!(isPackageCommandArgv(args)||args[0]===HOST_COMMAND_ARGV||args[0]===SCHEDULE_COMMAND_ARGV&&!scheduleWatch)){if(!scheduleWatch&&args.some(arg=>["--help","-h","--export","--list-models","--list-tips"].includes(arg)))try{let{parseArgs}=await import("./args-M6UAKT4T.js"),parsed=parseArgs(args);if(parsed.version||parsed.export||parsed.listModels!==void 0||parsed.listTips||parsed.help&&!(parsed.mode==="rpc"&&parsed.multiSession))return}catch{}try{let result=enable();result.directory!==void 0&&process.env.NODE_COMPILE_CACHE===void 0&&(process.env.NODE_COMPILE_CACHE=result.directory)}catch{}}}export{dispatchAgentDirectoryCommand,enableStartupCompileCache};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
+
import{parseEntryLine,resolveMovedPath}from"./chunk-GTJJ73DE.js";import{source_default}from"./chunk-26UBFF6N.js";import{advanceSessionFence}from"./chunk-SOMFLLPD.js";import{killWindowsProcessTree}from"./chunk-DSWDJ7HT.js";import{APP_NAME}from"./chunk-SODMQEHO.js";import{ownProcessStartedAtMs,processBootAtMs,sameBoot}from"./chunk-QN2BHP3M.js";import{processStartTimeMs,sameProcessStartMs}from"./chunk-O5RYI3IW.js";import{randomUUID}from"node:crypto";import{mkdir,readdir,readFile,rename,rm,stat,writeFile}from"node:fs/promises";import{dirname,join}from"node:path";var InvalidScheduledJobError=class extends Error{constructor(message){super(message),this.name="InvalidScheduledJobError"}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function requireString(raw,key){let value=raw[key];if(typeof value!="string"||value.length===0)throw new InvalidScheduledJobError(`scheduled job field "${key}" must be a non-empty string`);return value}function requireCount(raw,key){let value=raw[key];if(typeof value!="number"||!Number.isSafeInteger(value)||value<0)throw new InvalidScheduledJobError(`scheduled job field "${key}" must be a non-negative integer`);return value}function nullableCount(raw,key){return raw[key]===null||raw[key]===void 0?null:requireCount(raw,key)}function nullableString(raw,key){let value=raw[key];if(value==null)return null;if(typeof value!="string")throw new InvalidScheduledJobError(`scheduled job field "${key}" must be a string`);return value}function parseScheduledJob(raw){if(!isRecord(raw))throw new InvalidScheduledJobError("scheduled job must be a JSON object");if(raw.version!==1)throw new InvalidScheduledJobError(`unsupported scheduled job version: ${JSON.stringify(raw.version)}`);let id=requireString(raw,"id");if(!/^sch_[a-z0-9]{12}$/.test(id))throw new InvalidScheduledJobError(`invalid scheduled job id: ${id}`);let everyMs=nullableCount(raw,"everyMs");if(everyMs!==null&&everyMs<60*1e3)throw new InvalidScheduledJobError("scheduled job recurrence must be at least 60s");if(everyMs!==null&&everyMs>316224e5)throw new InvalidScheduledJobError("scheduled job recurrence must be at most 366 days");let prompt=requireString(raw,"prompt");if(Buffer.byteLength(prompt,"utf8")>16384)throw new InvalidScheduledJobError("scheduled job prompt exceeds 16384 bytes");let createdAt=requireCount(raw,"createdAt"),dueAt=requireCount(raw,"dueAt");return{version:1,id,sessionId:requireString(raw,"sessionId"),sessionFile:nullableString(raw,"sessionFile"),cwd:requireString(raw,"cwd"),prompt,createdAt,dueAt,everyMs,fireCount:requireCount(raw,"fireCount"),lastFiredAt:nullableCount(raw,"lastFiredAt"),lastError:nullableString(raw,"lastError")}}function nextRecurringDueAt(dueAt,everyMs,now){if(dueAt>now)return dueAt;let missed=Math.floor((now-dueAt)/everyMs)+1;return dueAt+missed*everyMs}function formatScheduledMessage(job,firedAt){let recurrence=job.everyMs===null?"":`, repeats every ${Math.round(job.everyMs/1e3)}s`;return`[Scheduled prompt ${job.id}: created ${new Date(job.createdAt).toISOString()}, due ${new Date(job.dueAt).toISOString()}, fired ${new Date(firedAt).toISOString()}${recurrence}]
|
|
3
|
+
${job.prompt}`}var STATE_DIRS=["pending","firing","failed"],JOB_ID=/^sch_[a-z0-9]{12}$/,RECORD_FILE=/^(sch_[a-z0-9]{12})(?:@(\d+)(?:~(\d+)-(\d+))?)?\.json$/;function scheduleDir(agentDir){return join(agentDir,"schedule")}function isScheduledJobId(id){return JOB_ID.test(id)}function isFileSystemError(error,code){return error instanceof Error&&"code"in error&&error.code===code}async function ensureDir(dir){await mkdir(dir,{recursive:!0,mode:448})}async function writeAtomic(filePath,contents){await ensureDir(dirname(filePath));let tempPath=join(dirname(filePath),`.schedule-${randomUUID()}.tmp`);try{await writeFile(tempPath,contents,{encoding:"utf8",mode:384}),await rename(tempPath,filePath)}catch(error){throw await rm(tempPath,{force:!0}),error}}function serialize(job){return`${JSON.stringify(job,null,2)}
|
|
4
|
+
`}async function readJobFile(path,expectedId){if((await stat(path)).size>65536)throw new InvalidScheduledJobError(`scheduled job file exceeds ${65536} bytes`);let parsed;try{parsed=JSON.parse(await readFile(path,"utf8"))}catch(error){throw isFileSystemError(error,"ENOENT")?error:new InvalidScheduledJobError("scheduled job file is not valid JSON")}let job=parseScheduledJob(parsed);if(job.id!==expectedId)throw new InvalidScheduledJobError(`scheduled job id ${job.id} does not match its file`);return job}async function listScheduledJobs(dir){let jobs=[],invalid=[];for(let state of STATE_DIRS){let names;try{names=await readdir(join(dir,state))}catch(error){if(isFileSystemError(error,"ENOENT"))continue;throw error}for(let name of names.sort()){let match=RECORD_FILE.exec(name);if(match===null)continue;let[,id,occurrence,pid,startedAt]=match,file=join(state,name);if(!(state==="pending"?occurrence===void 0:state==="firing"?pid!==void 0:occurrence!==void 0&&pid===void 0)||id===void 0){invalid.push({state,file,error:`unexpected record name for ${state}/`});continue}try{let job=await readJobFile(join(dir,file),id);jobs.push({state,job,file,...occurrence===void 0?{}:{occurrence:Number(occurrence)},...pid===void 0||startedAt===void 0?{}:{owner:{pid:Number(pid),processStartedAtMs:Number(startedAt)}}})}catch(error){if(isFileSystemError(error,"ENOENT"))continue;invalid.push({state,file,error:error instanceof Error?error.message:String(error)})}}}return jobs.sort((a,b)=>a.job.dueAt-b.job.dueAt),{jobs,invalid}}async function createScheduledJob(dir,input,now){let job=parseScheduledJob({version:1,id:`sch_${randomUUID().replace(/-/g,"").slice(0,12)}`,...input,createdAt:now,fireCount:0,lastFiredAt:null});return await writeAtomic(join(dir,"pending",`${job.id}.json`),serialize(job)),job}function tombstonePath(dir,id){return join(dir,"cancelled",id)}async function isCancelled(dir,id){try{return await stat(tombstonePath(dir,id)),!0}catch(error){if(isFileSystemError(error,"ENOENT"))return!1;throw error}}function runnersDir(dir){return join(dir,"runners")}import{randomUUID as randomUUID2}from"node:crypto";import{link,readdir as readdir2,rename as rename2,rm as rm2,stat as stat2,writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var TOMBSTONE_RETENTION_MS=1440*60*1e3;async function cancelScheduledJob(dir,id,options={}){if(!isScheduledJobId(id))return;let records=(await listScheduledJobs(dir)).jobs.filter(record=>record.job.id===id),representative=records.find(record=>record.state==="pending")??records[0];if(representative===void 0||options.sessionId!==void 0&&representative.job.sessionId!==options.sessionId)return;await writeAtomic(tombstonePath(dir,id),`${new Date().toISOString()}
|
|
5
|
+
`);let inFlight=(await occurrenceNumbers(dir,"firing",id)).length>0;await rm2(join2(dir,"pending",`${id}.json`),{force:!0});let failed=records.filter(record=>record.state==="failed");for(let record of failed)await rm2(join2(dir,record.file),{force:!0});return{job:representative.job,inFlight,removedFailed:failed.length}}function occurrenceFile(id,occurrence,owner){return join2("firing",`${id}@${occurrence}~${owner.pid}-${owner.processStartedAtMs}.json`)}async function restorePending(dir,record,id){let pending=join2(dir,"pending",`${id}.json`);try{await link(join2(dir,record),pending)}catch(error){if(!isFileSystemError(error,"EEXIST"))throw error}await rm2(join2(dir,record),{force:!0}),await isCancelled(dir,id)&&await rm2(pending,{force:!0})}async function claimOccurrence(dir,job,owner){let record=occurrenceFile(job.id,job.fireCount+1,owner);await ensureDir(join2(dir,"firing"));try{await rename2(join2(dir,"pending",`${job.id}.json`),join2(dir,record))}catch(error){if(isFileSystemError(error,"ENOENT"))return;throw error}if(await isCancelled(dir,job.id)){await rm2(join2(dir,record),{force:!0});return}if((await readJobFile(join2(dir,record),job.id)).fireCount!==job.fireCount){await restorePending(dir,record,job.id);return}return record}async function rearmRecurringJob(dir,next){if(await isCancelled(dir,next.id))return;let path=join2(dir,"pending",`${next.id}.json`);await writeAtomic(path,serialize(next)),await isCancelled(dir,next.id)&&await rm2(path,{force:!0})}async function occurrenceNumbers(dir,state,id){let names;try{names=await readdir2(join2(dir,state))}catch(error){if(isFileSystemError(error,"ENOENT"))return[];throw error}let prefix=`${id}@`;return names.filter(name=>name.startsWith(prefix)).map(name=>Number.parseInt(name.slice(prefix.length),10)).filter(occurrence=>Number.isSafeInteger(occurrence))}async function restoreAbandonedSchedule(dir,job,occurrence,now){if(job.everyMs===null||await isCancelled(dir,job.id))return;let pending=join2(dir,"pending",`${job.id}.json`);if(await stat2(pending).then(()=>!0,()=>!1)||[...await occurrenceNumbers(dir,"firing",job.id),...await occurrenceNumbers(dir,"failed",job.id)].some(n=>n>occurrence))return;let next={...job,fireCount:occurrence,dueAt:nextRecurringDueAt(job.dueAt,job.everyMs,now),lastError:null};await ensureDir(join2(dir,"pending"));let temp=join2(dir,"pending",`.schedule-${randomUUID2()}.tmp`);try{await writeFile2(temp,serialize(next),{encoding:"utf8",mode:384}),await link(temp,pending)}catch(error){if(!isFileSystemError(error,"EEXIST"))throw error;return}finally{await rm2(temp,{force:!0})}if(await isCancelled(dir,job.id)){await rm2(pending,{force:!0});return}return next}async function settleOccurrence(dir,record,job,occurrence,outcome){if(!outcome.ok&&!await isCancelled(dir,job.id)){let failed=join2(dir,"failed",`${job.id}@${occurrence}.json`);await writeAtomic(failed,serialize({...job,lastError:outcome.error})),await isCancelled(dir,job.id)&&await rm2(failed,{force:!0});let older=(await occurrenceNumbers(dir,"failed",job.id)).sort((a,b)=>b-a);for(let stale of older.slice(10))await rm2(join2(dir,"failed",`${job.id}@${stale}.json`),{force:!0})}await rm2(join2(dir,record),{force:!0})}async function pruneTombstones(dir,listing,now){let names;try{names=await readdir2(join2(dir,"cancelled"))}catch(error){if(isFileSystemError(error,"ENOENT"))return;throw error}let live=new Set(listing.jobs.filter(record=>record.state!=="failed").map(record=>record.job.id));for(let id of names){if(!isScheduledJobId(id)||live.has(id))continue;let info=await stat2(tombstonePath(dir,id)).catch(()=>{});info!==void 0&&now-info.mtimeMs>TOMBSTONE_RETENTION_MS&&await rm2(tombstonePath(dir,id),{force:!0})}}import{mkdir as mkdir2,readdir as readdir3,stat as stat4}from"node:fs/promises";import{join as join3}from"node:path";import{randomUUID as randomUUID3}from"node:crypto";import{link as link2,open,readFile as readFile3,rename as rename3,stat as stat3,unlink}from"node:fs/promises";import{execFile}from"node:child_process";import{readFile as readFile2}from"node:fs/promises";var LINUX_CLOCK_TICKS_PER_SECOND=100;async function linuxProcessStartMs(pid){let[stat6,systemStat]=await Promise.all([readFile2(`/proc/${pid}/stat`,"utf8"),readFile2("/proc/stat","utf8")]),afterComm=stat6.slice(stat6.lastIndexOf(")")+2).split(" "),startTicks=Number(afterComm[19]),bootSeconds=Number(/^btime (\d+)/m.exec(systemStat)?.[1]);if(!(!Number.isFinite(startTicks)||!Number.isFinite(bootSeconds)))return Math.round((bootSeconds+startTicks/LINUX_CLOCK_TICKS_PER_SECOND)*1e3)}function execText(command,args,env){return new Promise((resolve,reject)=>{execFile(command,[...args],{encoding:"utf8",timeout:5e3,windowsHide:!0,...env===void 0?{}:{env}},(error,stdout)=>{error?reject(error):resolve(stdout)})})}async function darwinProcessStartMs(pid){let text=(await execText("ps",["-o","lstart=","-p",String(pid)],{...process.env,LC_ALL:"C",LANG:"C"})).trim();if(text.length!==0)return processStartTimeMs(text)}async function windowsProcessStartMs(pid){let script=`(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().ToString('o')`,text=(await execText("powershell",["-NoProfile","-NonInteractive","-Command",script])).trim();return processStartTimeMs(text)}async function readProcessStartMs(pid){try{switch(process.platform){case"linux":return await linuxProcessStartMs(pid);case"darwin":return await darwinProcessStartMs(pid);case"win32":return await windowsProcessStartMs(pid);default:return}}catch{return}}function errorCode(error){if(typeof error=="object"&&error!==null&&"code"in error&&typeof error.code=="string")return error.code}async function unlinkIfPresent(path){try{await unlink(path)}catch(error){if(errorCode(error)!=="ENOENT")throw error}}async function readLeaseText(path){try{return await readFile3(path,"utf8")}catch(error){if(errorCode(error)==="ENOENT")return;throw error}}async function writeTemp(path,content,mode){let temp=`${path}.${process.pid}.${randomUUID3().slice(0,8)}.tmp`,file=await open(temp,"wx",mode);try{await file.writeFile(content,"utf8")}finally{await file.close()}return temp}async function publishExclusive(path,content,options={}){let temp=await writeTemp(path,content,options.mode);try{await link2(temp,path)}catch(error){let code=errorCode(error);if(code!=="ENOTSUP"&&code!=="EOPNOTSUPP"&&code!=="EPERM")throw error;let file=await open(path,"wx",options.mode);try{await file.writeFile(content,"utf8")}finally{await file.close()}}finally{await unlinkIfPresent(temp)}}async function publishReplace(path,content,options={}){let temp=await writeTemp(path,content,options.mode);try{await rename3(temp,path)}catch(error){throw await unlinkIfPresent(temp),error}}function pidAlive(pid){try{return process.kill(pid,0),!0}catch(error){return errorCode(error)==="EPERM"}}var UNREADABLE_LOCK_STALE_MS=3e4;function readLockHolder(raw){try{let parsed=JSON.parse(raw);if(typeof parsed!="object"||parsed===null||!("pid"in parsed)||!("bootAtMs"in parsed)||!("processStartedAtMs"in parsed))return;let{pid,bootAtMs,processStartedAtMs}=parsed;return typeof pid!="number"||typeof bootAtMs!="number"||typeof processStartedAtMs!="number"?void 0:{pid,bootAtMs,processStartedAtMs}}catch{return}}async function reclaimLockState(lock,probes={}){let raw=await readLeaseText(lock);if(raw===void 0)return{state:"free"};let holder=readLockHolder(raw);if(holder===void 0)return await stat3(lock).then(info=>Date.now()-info.mtimeMs,()=>0)>UNREADABLE_LOCK_STALE_MS?{state:"stale",raw}:{state:"held"};if(!sameBoot(holder.bootAtMs,processBootAtMs()))return{state:"stale",raw};if(holder.pid===process.pid)return sameProcessStartMs(holder.processStartedAtMs,ownProcessStartedAtMs())?{state:"held",holder}:{state:"stale",raw};if(!(probes.isProcessAlive??pidAlive)(holder.pid))return{state:"stale",raw};let observed=await(probes.readProcessStartMs??readProcessStartMs)(holder.pid).catch(()=>{});return observed===void 0?{state:"held",holder,unproven:!0}:sameProcessStartMs(holder.processStartedAtMs,observed)?{state:"held",holder}:{state:"stale",raw}}async function breakStaleLock(lock,raw){let aside=`${lock}.${process.pid}.${randomUUID3().slice(0,8)}.broken`;try{await rename3(lock,aside)}catch(error){if(errorCode(error)==="ENOENT")return;throw error}let moved=await readFile3(aside,"utf8");if(moved!==raw)try{await publishExclusive(lock,moved)}catch(error){if(errorCode(error)!=="EEXIST")throw error}await unlinkIfPresent(aside)}async function takeReclaimLock(lock,probes){let mine=JSON.stringify({pid:process.pid,bootAtMs:processBootAtMs(),processStartedAtMs:ownProcessStartedAtMs()});for(let attempt=0;attempt<3;attempt+=1){try{return await publishExclusive(lock,mine),mine}catch(error){if(errorCode(error)!=="EEXIST")throw error}let seen=await reclaimLockState(lock,probes);if(seen.state==="held")return{holder:seen.holder};seen.state==="stale"&&await breakStaleLock(lock,seen.raw)}return{}}async function reclaimInspected(path,inspected,probes={}){let lock=`${path}.lock`,taken=await takeReclaimLock(lock,probes);if(typeof taken!="string")return{outcome:"busy",...taken.holder?{holder:taken.holder}:{}};try{return await readLeaseText(path)!==inspected?{outcome:"changed"}:(await unlinkIfPresent(path),{outcome:"removed"})}finally{await readLeaseText(lock)===taken&&await unlinkIfPresent(lock)}}var RUNNER_HEARTBEAT_STALE_MS=12e4,RUNNER_HEARTBEAT_INTERVAL_MS=3e4,DEFAULT_MAX_DELIVERY_MS=9e5,PRIVATE={mode:384};function ownRunnerIdentity(){return{pid:process.pid,processStartedAtMs:ownProcessStartedAtMs()}}function leasePath(dir,pid){return join3(runnersDir(dir),`${pid}.json`)}async function writeRunnerLease(dir,lease,now){await mkdir2(runnersDir(dir),{recursive:!0,mode:448});let identity=ownRunnerIdentity();await publishReplace(leasePath(dir,identity.pid),JSON.stringify({...identity,bootAtMs:processBootAtMs(),beatAt:now,...lease}),PRIVATE)}async function removeRunnerLease(dir){await unlinkIfPresent(leasePath(dir,process.pid))}function parseLease(raw){try{let parsed=JSON.parse(raw);if(typeof parsed!="object"||parsed===null)return;let beatAt="beatAt"in parsed?parsed.beatAt:void 0;if(typeof beatAt!="number")return;let watch="watch"in parsed&&parsed.watch===!0,exec="exec"in parsed&&typeof parsed.exec=="string"?parsed.exec:null;return{beatAt,watch,exec}}catch{return}}async function liveRunners(dir){let names;try{names=await readdir3(runnersDir(dir))}catch(error){if(error instanceof Error&&"code"in error&&error.code==="ENOENT")return[];throw error}let runners=[];for(let name of names){if(!/^\d+\.json$/.test(name))continue;let path=join3(runnersDir(dir),name),state=await reclaimLockState(path);if(state.state==="stale"&&await breakStaleLock(path,state.raw),state.state!=="held"||state.holder===void 0)continue;let raw=await readLeaseText(path),lease=raw===void 0?void 0:parseLease(raw);lease!==void 0&&runners.push({pid:state.holder.pid,processStartedAtMs:state.holder.processStartedAtMs,...lease})}return runners}async function isWatchRunnerAvailable(dir,now){return(await liveRunners(dir)).some(runner=>runner.watch&&now-runner.beatAt<=RUNNER_HEARTBEAT_STALE_MS)}function isOwnerAmong(owner,runners){return runners.some(runner=>runner.pid===owner.pid&&sameProcessStartMs(runner.processStartedAtMs,owner.processStartedAtMs))}function sessionLockPath(dir,sessionId){return join3(dir,"sessions",`${encodeURIComponent(sessionId)}.lock`)}function isDeliveryGroupAlive(pid){try{return process.kill(process.platform==="win32"?pid:-pid,0),!0}catch(error){return errorCode(error)==="EPERM"}}function isPidAlive(pid){try{return process.kill(pid,0),!0}catch(error){return errorCode(error)==="EPERM"}}async function orphanedDelivery(raw,lockAgeMs,probes){let parsed;try{parsed=JSON.parse(raw)}catch{return}if(typeof parsed!="object"||parsed===null)return;let field=key=>key in parsed?Reflect.get(parsed,key):void 0,boot=field("bootAtMs");if(typeof boot!="number"||!sameBoot(boot,processBootAtMs()))return;let pid=field("deliveryPid"),startedAt=field("deliveryStartedAtMs");if(typeof pid!="number"||typeof startedAt!="number"){let maxDeliveryMs=field("maxDeliveryMs"),runner=field("pid");return field("gated")===!1&&typeof maxDeliveryMs=="number"&&lockAgeMs<=maxDeliveryMs&&typeof runner=="number"?runner:void 0}if(!isDeliveryGroupAlive(pid))return;if(!isPidAlive(pid))return pid;let leaderStart=await(probes.readProcessStartMs??readProcessStartMs)(pid).catch(()=>{});return leaderStart!==void 0&&sameProcessStartMs(startedAt,leaderStart)?pid:void 0}async function acquireSessionDeliveryLock(dir,sessionId,options={}){let probes=options,path=sessionLockPath(dir,sessionId),identity={pid:process.pid,bootAtMs:processBootAtMs(),processStartedAtMs:ownProcessStartedAtMs(),gated:options.gated??process.platform!=="win32",maxDeliveryMs:options.maxDeliveryMs??DEFAULT_MAX_DELIVERY_MS},mine=JSON.stringify(identity);for(let attempt=0;attempt<3;attempt+=1){try{await publishExclusive(path,mine,PRIVATE);let tail=Promise.resolve(),serialized=operation=>{let run=tail.then(operation);return tail=run.catch(()=>{}),run};return{acquired:!0,attachDelivery:pid=>serialized(async()=>{let startedAt=Math.floor(Date.now()/1e3)*1e3;if(await readLeaseText(path)!==mine)throw new Error("session delivery lock was lost");let next=JSON.stringify({...identity,deliveryPid:pid,deliveryStartedAtMs:startedAt});await publishReplace(path,next,PRIVATE),mine=next}),release:()=>serialized(async()=>{await readLeaseText(path)===mine&&await unlinkIfPresent(path)})}}catch(error){let code=errorCode(error);if(code==="ENOENT"){await mkdir2(join3(dir,"sessions"),{recursive:!0,mode:448});continue}if(code!=="EEXIST")throw error}let state=await reclaimLockState(path);if(state.state==="held")return{acquired:!1,heldByPid:state.holder?.pid};if(state.state==="stale"){let lockAgeMs=await stat4(path).then(info=>Date.now()-info.mtimeMs,()=>0),delivering=await orphanedDelivery(state.raw,lockAgeMs,probes);if(delivering!==void 0)return{acquired:!1,heldByPid:delivering};await breakStaleLock(path,state.raw)}}return{acquired:!1,heldByPid:void 0}}import{createReadStream}from"node:fs";import{stat as stat5}from"node:fs/promises";import{createInterface}from"node:readline";import{randomUUID as randomUUID5}from"node:crypto";import{existsSync,mkdirSync,readFileSync,renameSync,rmdirSync,statSync,unlinkSync,writeFileSync}from"node:fs";import{mkdir as mkdir4}from"node:fs/promises";import{dirname as dirname3,join as join6}from"node:path";var SessionHeldError=class extends Error{constructor(sessionFile,holders){let who=holders.map(h=>h.cwd?`pid ${h.pid} in ${h.cwd}`:`pid ${h.pid}`).join("; ");super(`This session is open in another ${APP_NAME} process (${who}). Quit it there, then try again.`),this.code="ESESSIONHELD",this.name="SessionHeldError",this.sessionFile=sessionFile,this.holders=holders}},SessionMovingError=class extends Error{constructor(sessionFile,moverPid){let who=moverPid===void 0?"another process":`another process (pid ${moverPid})`;super(`Session ${sessionFile} is being moved by ${who}. Try again in a moment.`),this.code="ESESSIONMOVING",this.name="SessionMovingError",this.moverPid=moverPid}},SessionMovedError=class extends Error{constructor(sessionFile){super(`Session ${sessionFile} no longer exists: another process moved it. Resume it from its new location.`),this.code="ESESSIONMOVED",this.name="SessionMovedError"}};import{readdir as readdir4}from"node:fs/promises";import{join as join4}from"node:path";var HOLDER_RECORD=/^\d+\.json$/;function parseCwd(raw){let parsed=JSON.parse(raw);if(!(typeof parsed!="object"||parsed===null||!("cwd"in parsed)))return typeof parsed.cwd=="string"?parsed.cwd:void 0}async function fenced(fenceSession){return fenceSession===void 0?!1:fenceSession().then(()=>!0,()=>!1)}function holderGeneration(parsed){return typeof parsed!="object"||parsed===null?{}:{..."host_instance"in parsed&&typeof parsed.host_instance=="string"?{host_instance:parsed.host_instance}:{},..."host_daemon_dir"in parsed&&typeof parsed.host_daemon_dir=="string"?{host_daemon_dir:parsed.host_daemon_dir}:{}}}async function liveHolders(dir,probes={},fenceSession){let holders=[];for(let name of await readdir4(dir)){if(!HOLDER_RECORD.test(name))continue;let path=join4(dir,name),before=await readLeaseText(path),state=await reclaimLockState(path,probes);if(state.state==="stale"&&await breakStaleLock(path,state.raw),state.state!=="held"||state.holder===void 0)continue;let raw=await readLeaseText(path),stable=raw!==void 0&&raw===before,parsed=stable?JSON.parse(raw):void 0;if(stable&&state.unproven===!0&&await probes.holderEnded?.(holderGeneration(parsed))===!0&&await fenced(fenceSession)){await breakStaleLock(path,raw);continue}let endpoint=typeof parsed=="object"&&parsed!==null&&"host_instance"in parsed&&typeof parsed.host_instance=="string"?{host_instance:parsed.host_instance,..."host_socket"in parsed&&typeof parsed.host_socket=="string"?{host_socket:parsed.host_socket}:{}}:{};holders.push({pid:state.holder.pid,cwd:stable?parseCwd(raw):void 0,...endpoint,...probes.markUnproven===!0&&state.unproven===!0?{unproven:!0}:{}})}return holders}import{randomUUID as randomUUID4}from"node:crypto";import{mkdir as mkdir3,readFile as readFile4,rename as rename4,rm as rm3,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname2,join as join5}from"node:path";var InvalidSidecarStoreError=class extends Error{constructor(message,options){super(message,options),this.name="InvalidSidecarStoreError"}},UnsupportedSidecarStoreVersionError=class extends Error{constructor(message){super(message),this.name="UnsupportedSidecarStoreVersionError"}},mutationTails=new Map,snapshots=new Map;function encodedSessionId(sessionId){return encodeURIComponent(sessionId)}function sidecarFilePath(ref){return join5(ref.baseDir,`${encodedSessionId(ref.sessionId)}.json`)}function createSidecarStore(options){let ref={baseDir:options.baseDir,sessionId:options.sessionId},filePath=sidecarFilePath(ref);async function read(){let raw;try{raw=await readFile4(filePath,"utf8")}catch(error){if(isFileSystemError2(error,"ENOENT"))return null;throw error}let state=parsePayload(raw,options,ref);return snapshots.set(filePath,state),state}async function write(state){await mkdir3(dirname2(filePath),{recursive:!0}),await writeAtomic2(filePath,`${JSON.stringify(state,null,2)}
|
|
6
|
+
`,options.tempPrefix),snapshots.set(filePath,state)}function mutate(fn){return serializeByKey(filePath,async()=>{let next=await fn(await read());return await write(next),next})}return{filePath,read,write,mutate,snapshot:()=>snapshots.get(filePath),clear:()=>{snapshots.delete(filePath)}}}async function writeAtomic2(filePath,contents,tempPrefix){let tempPath=join5(dirname2(filePath),`.${tempPrefix}-${randomUUID4()}.tmp`);try{await writeFile3(tempPath,contents,{encoding:"utf8",mode:384}),await rename4(tempPath,filePath)}catch(error){try{await rm3(tempPath,{force:!0})}catch(cleanupError){throw new AggregateError([error,cleanupError],"sidecar store write failed and its temporary file could not be removed")}throw error}}function parsePayload(raw,options,ref){let parsed;try{parsed=JSON.parse(raw)}catch(error){throw new InvalidSidecarStoreError("sidecar store contains unparseable JSON",{cause:error})}if(!isRecord2(parsed))throw new InvalidSidecarStoreError("sidecar store must be a JSON object");if(parsed.version!==options.version)throw new UnsupportedSidecarStoreVersionError(`unsupported sidecar store version: ${JSON.stringify(parsed.version)} (expected ${options.version})`);if(typeof parsed.sessionId!="string"||parsed.sessionId.length===0)throw new InvalidSidecarStoreError("sidecar store is missing a sessionId");if(parsed.sessionId!==ref.sessionId)throw new InvalidSidecarStoreError(`sidecar store sessionId ${parsed.sessionId} does not match the session it was loaded for`);return options.parse(parsed,ref)}function serializeByKey(key,operation){let run=(mutationTails.get(key)??Promise.resolve()).then(operation),tail=run.then(()=>{},()=>{});return mutationTails.set(key,tail),tail.then(()=>{mutationTails.get(key)===tail&&mutationTails.delete(key)}),run}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isFileSystemError2(error,code){return error instanceof Error&&"code"in error&&error.code===code}var HOLDERS_DIR="session-holders",MOVE_LOCK="move.lock",MOVE_LOCK_STALE_MS=3e4,DEFAULT_MOVE_LOCK_WAIT_MS=5e3,MOVE_LOCK_RETRY_MS=100;function holdersDir(sessionFile,sessionId){return join6(dirname3(resolveMovedPath(sessionFile)),HOLDERS_DIR,encodedSessionId(sessionId))}function identityRecord(cwd,endpoint){return JSON.stringify({pid:process.pid,bootAtMs:processBootAtMs(),processStartedAtMs:ownProcessStartedAtMs(),...cwd===void 0?{}:{cwd},...endpoint})}function unlinkIfPresentSync(path){try{unlinkSync(path)}catch(error){if(errorCode(error)!=="ENOENT")throw error}}function removeDirIfEmpty(dir){try{rmdirSync(dir)}catch(error){let code=errorCode(error);if(code!=="ENOENT"&&code!=="ENOTEMPTY"&&code!=="EEXIST")throw error}}var holderRecordRefCounts=new Map,exitCleanupInstalled=!1;function installExitCleanup(){exitCleanupInstalled||(exitCleanupInstalled=!0,process.once("exit",()=>{for(let record of holderRecordRefCounts.keys())unlinkIfPresentSync(record)}))}function pidAlive2(pid){try{return process.kill(pid,0),!0}catch(error){return errorCode(error)==="EPERM"}}function activeMover(lock){let raw,ageMs;try{raw=readFileSync(lock,"utf8"),ageMs=Date.now()-statSync(lock).mtimeMs}catch(error){if(errorCode(error)==="ENOENT")return;throw error}if(ageMs>MOVE_LOCK_STALE_MS)return;let pid=parsePid(raw);return pid===void 0?{pid}:pid===process.pid||pidAlive2(pid)?{pid}:void 0}function parsePid(raw){try{let parsed=JSON.parse(raw);return typeof parsed!="object"||parsed===null||!("pid"in parsed)?void 0:typeof parsed.pid=="number"?parsed.pid:void 0}catch(error){if(error instanceof SyntaxError)return;throw error}}function holdSessionFile(sessionFile,sessionId,options){let dir=holdersDir(sessionFile,sessionId),record=join6(dir,`${process.pid}.json`),shared=holderRecordRefCounts.get(record)??0;shared===0&&(publishHolderRecord(dir,record,identityRecord(options.cwd,options.holderEndpoint)),installExitCleanup()),holderRecordRefCounts.set(record,shared+1);let released=!1,release=()=>{if(released)return;released=!0;let left=(holderRecordRefCounts.get(record)??1)-1;if(left>0){holderRecordRefCounts.set(record,left);return}holderRecordRefCounts.delete(record),unlinkIfPresentSync(record),removeDirIfEmpty(dir)},mover=activeMover(join6(dir,MOVE_LOCK));if(mover!==void 0)throw release(),new SessionMovingError(sessionFile,mover.pid);if(options.expectExisting&&!existsSync(resolveMovedPath(sessionFile)))throw release(),new SessionMovedError(sessionFile);return{release}}function publishHolderRecord(dir,record,content){for(let attempt=0;;attempt+=1){let temp=`${record}.${randomUUID5().slice(0,8)}.tmp`;try{mkdirSync(dir,{recursive:!0}),writeFileSync(temp,content),renameSync(temp,record);return}catch(error){if(errorCode(error)!=="ENOENT"||attempt>0)throw error}}}async function liveSessionHolders(sessionFile,sessionId,probes={}){try{return await liveHolders(holdersDir(sessionFile,sessionId),probes,()=>advanceSessionFence(sessionFile))}catch(error){if(errorCode(error)==="ENOENT")return[];throw error}}async function createLockDir(dir,tolerateEnoent){try{return await mkdir4(dir,{recursive:!0}),!1}catch(error){if(!tolerateEnoent||errorCode(error)!=="ENOENT")throw error;return!0}}async function takeMoveLock(sessionFile,lock,waitMs){let mine=identityRecord(),deadline=Date.now()+waitMs,lockDirVanished=!1;for(;;){try{return await publishExclusive(lock,mine),mine}catch(error){let code=errorCode(error);if(code==="ENOENT"){lockDirVanished=await createLockDir(dirname3(lock),!lockDirVanished);continue}if(code!=="EEXIST")throw error}let state=await reclaimLockState(lock);if(state.state==="stale"){await breakStaleLock(lock,state.raw);continue}if(state.state!=="free"){if(Date.now()>=deadline)throw new SessionMovingError(sessionFile,state.holder?.pid);await new Promise(resolve=>setTimeout(resolve,MOVE_LOCK_RETRY_MS))}}}async function withSessionMoveLock(sessionFile,sessionId,move,options={}){let dir=holdersDir(sessionFile,sessionId),lock=join6(dir,MOVE_LOCK),mine=await takeMoveLock(sessionFile,lock,options.waitMs??DEFAULT_MOVE_LOCK_WAIT_MS);try{let holders=await liveHolders(dir);if(holders.length>0)throw new SessionHeldError(sessionFile,holders);return await move()}finally{await readLeaseText(lock)===mine&&await unlinkIfPresent(lock),removeDirIfEmpty(dir)}}async function sessionIdFromFile(sessionFile){try{if(!(await stat5(sessionFile)).isFile())return;let stream=createReadStream(sessionFile,{encoding:"utf8"}),lines=createInterface({input:stream,crlfDelay:Number.POSITIVE_INFINITY});try{for await(let line of lines){let entry=parseEntryLine(line);if(entry!==null)return entry.type==="session"&&typeof entry.id=="string"?entry.id:void 0}return}finally{lines.close(),stream.destroy()}}catch(cause){if(errorCode(cause)==="ENOENT")return;throw cause}}async function foreignSessionHolders(sessionFile,sessionId,probes){if(sessionFile===void 0)return[];let path=resolveMovedPath(sessionFile),id=sessionId??await sessionIdFromFile(path);return id===void 0?[]:(await liveSessionHolders(path,id,probes)).filter(holder=>holder.pid!==process.pid)}function describeSessionHolders(holders){return holders.map(({pid,cwd})=>`pid ${pid}${cwd===void 0?"":` in ${JSON.stringify(cwd)}`}`).join("; ")}var SESSION_HOLDER_LOOKUP_FAILED="Unable to inspect session holders; continuing without holder information.";async function checkSessionHolders(sessionFile){try{return{holders:await foreignSessionHolders(sessionFile,void 0,{markUnproven:!0})}}catch{return{lookupFailed:!0}}}var HOLDER_EXIT_POLL_MS=100;function takeOverRefusal(holders,retry="then /resume again"){if(holders.some(holder=>holder.host_instance!==void 0))return`It is open in a multi-session host; close it there, ${retry}.`;if(holders.some(holder=>holder.unproven===!0))return`The other process could not be verified; quit it there, ${retry}.`}async function stopSessionHolders(sessionFile,confirmed,timeoutMs=1e4){let confirmedPids=new Set(confirmed.map(({pid})=>pid)),current=(await foreignSessionHolders(sessionFile,void 0,{markUnproven:!0})).filter(({pid})=>confirmedPids.has(pid));if(takeOverRefusal(current)!==void 0)return!1;for(let{pid}of current)try{process.kill(pid,"SIGTERM")}catch(cause){if(errorCode(cause)!=="ESRCH")throw cause}let stopping=new Set(current.map(({pid})=>pid)),deadline=Date.now()+timeoutMs;for(;;){let holders=await foreignSessionHolders(sessionFile);if(!holders.some(({pid})=>stopping.has(pid)))return holders.length===0;if(Date.now()>=deadline)return!1;await new Promise(resolve=>setTimeout(resolve,HOLDER_EXIT_POLL_MS))}}async function sessionHolderWarning(sessionFile,sessionId){let holders;try{holders=await foreignSessionHolders(sessionFile,sessionId)}catch{return SESSION_HOLDER_LOOKUP_FAILED}if(holders.length!==0)return`This session is also open in another process (${describeSessionHolders(holders)}). Concurrent writes may corrupt its history; quit the other process before continuing.`}async function prepareSessionOpening(manager,mode){if(mode==="interactive"){let warning=await sessionHolderWarning(manager.getSessionFile(),manager.getSessionId());warning!==void 0&&console.error(source_default.yellow(`Warning: ${warning}`))}}var SESSION_HELD_EXIT_CODE=76,RETRY="then open it again";async function admitStartupSession(sessionFile,io){if(sessionFile===void 0)return"open";let check=await(io.lookup??checkSessionHolders)(sessionFile);if("lookupFailed"in check)return io.err(source_default.yellow(`Warning: ${SESSION_HOLDER_LOOKUP_FAILED}`)),"open";let{holders}=check;if(holders.length===0)return"open";let held=`This session is open in another process (${describeSessionHolders(holders)}); opening it here would start a second run of the same session.`,refusal=takeOverRefusal(holders,RETRY);if(!io.canAsk||refusal!==void 0)return io.err(source_default.red(`Not opened: ${held} ${refusal??`Quit it there, ${RETRY}.`}`)),"refused";if(!await io.confirm(`${held}
|
|
7
|
+
Take over (stop it there)?`))return io.err(`Not opened: the session is open in another process (${describeSessionHolders(holders)}).`),"cancelled";let stopped;try{stopped=await stopSessionHolders(sessionFile,holders)}catch(error){return io.err(source_default.red(`Not opened: could not stop the other process (${error instanceof Error?error.message:String(error)}).`)),"refused"}return stopped?"open":(io.err(source_default.red(`Not opened: the session is still open in another process; quit it there, ${RETRY}.`)),"refused")}import{spawn}from"node:child_process";import{existsSync as existsSync2}from"node:fs";function movedJobPaths(job){return{sessionFile:job.sessionFile===null?null:resolveMovedPath(job.sessionFile),cwd:resolveMovedPath(job.cwd)}}async function deferWhileSessionOpen(job){if(job.sessionFile===null||!existsSync2(job.sessionFile))return;let holders=await liveSessionHolders(job.sessionFile,job.sessionId);if(holders.length!==0)return`session is open in pid ${holders.map(holder=>holder.pid).join(", ")}; waiting until it closes`}var STDERR_TAIL_CHARS=2e3,POSIX_GATE='IFS= read -r _ <&3 || exit 75; exec 3<&-; exec "$0" "$@"';function killTree(pid){if(process.platform==="win32"){killWindowsProcessTree(pid);return}try{process.kill(-pid,"SIGKILL")}catch{}}function runDeliveryProcess(launch,timeoutMs,context={}){return new Promise(resolve=>{let posix=process.platform!=="win32",child=posix?spawn("/bin/sh",["-c",POSIX_GATE,launch.command,...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe","pipe"],detached:!0}):spawn(launch.command,[...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe"],windowsHide:!0,windowsVerbatimArguments:launch.windowsVerbatimArguments===!0}),stderr="",failure,timer=setTimeout(()=>{failure??=`delivery timed out after ${Math.round(timeoutMs/1e3)}s`,child.pid!==void 0&&killTree(child.pid)},timeoutMs);child.stderr?.on("data",chunk=>{stderr=(stderr+chunk.toString("utf8")).slice(-STDERR_TAIL_CHARS)}),child.stdin?.on("error",()=>{});let gate=posix?child.stdio[3]:null;gate?.on("error",()=>{}),child.on("error",error=>{failure??=error.message}),child.on("close",(code,signal)=>{if(clearTimeout(timer),failure!==void 0)resolve({ok:!1,error:failure});else if(code===0)resolve({ok:!0});else if(launch.sessionHeldExitCode!==void 0&&code===launch.sessionHeldExitCode){let reason=stderr.trim()||"the session is open in another process";resolve({ok:!1,error:reason,sessionHeld:!0})}else{let status=code===null?`signal ${signal}`:`exit code ${code}`;resolve({ok:!1,error:stderr.trim()?`${status}: ${stderr.trim()}`:status})}});let pid=child.pid;pid!==void 0&&Promise.resolve(context.onSpawn?.(pid)).then(()=>{gate!=null&&"end"in gate&&gate.end(`go
|
|
8
|
+
`),child.stdin?.end(launch.stdin??"")},error=>{failure??=`could not register the delivery: ${error instanceof Error?error.message:String(error)}`,killTree(pid)})})}function eventEnv(event){return{...process.env,SENPI_SCHEDULE_ID:event.id,SENPI_SCHEDULE_SESSION_ID:event.sessionId,SENPI_SCHEDULE_SESSION_FILE:event.sessionFile??"",SENPI_SCHEDULE_CWD:event.cwd}}function execHookDelivery(command,timeoutMs){let shell=process.platform==="win32"?{command:process.env.ComSpec??"cmd.exe",args:["/d","/s","/c",`"${command}"`],windowsVerbatimArguments:!0}:{command:"/bin/sh",args:["-c",command]};return(event,context)=>runDeliveryProcess({...shell,env:eventEnv(event),stdin:`${JSON.stringify(event)}
|
|
9
|
+
`,cwd:process.cwd()},timeoutMs,context)}function sessionResumeDelivery(senpi,timeoutMs){return async(event,context)=>existsSync2(event.cwd)?event.sessionFile!==null&&!existsSync2(event.sessionFile)?{ok:!1,error:`session file no longer exists: ${event.sessionFile}`}:runDeliveryProcess({command:senpi.command,args:[...senpi.args,"-p","--session",event.sessionFile??event.sessionId,event.message],cwd:event.cwd,env:eventEnv(event),sessionHeldExitCode:SESSION_HELD_EXIT_CODE},timeoutMs,context):{ok:!1,error:`working directory no longer exists: ${event.cwd}`}}import{join as join7}from"node:path";var DEFERRED_RETRY_MS=15e3,ABANDONED_OCCURRENCE_ERROR="the runner exited while delivering this occurrence; outcome unknown, not retried";async function recoverAbandoned(options,records){let firing=records.filter(record=>record.state==="firing");if(firing.length===0)return{events:[],restoredDueAt:[]};let runners=await(options.runners??(()=>liveRunners(options.dir)))(),events=[],restoredDueAt=[];for(let record of firing){if(record.owner===void 0||record.occurrence===void 0||record.owner.pid===options.owner.pid&&record.owner.processStartedAtMs===options.owner.processStartedAtMs||isOwnerAmong(record.owner,runners))continue;let restored=await restoreAbandonedSchedule(options.dir,record.job,record.occurrence,options.now());restored!==void 0&&restoredDueAt.push(restored.dueAt),await settleOccurrence(options.dir,record.file,record.job,record.occurrence,{ok:!1,error:ABANDONED_OCCURRENCE_ERROR}),events.push({event:"abandoned",id:record.job.id,sessionId:record.job.sessionId,occurrence:record.occurrence,error:ABANDONED_OCCURRENCE_ERROR})}return{events,restoredDueAt}}async function freshPendingJob(options,id){let job=await readJobFile(join7(options.dir,"pending",`${id}.json`),id).catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});if(!(job===void 0||job.dueAt>options.now()||await isCancelled(options.dir,id)))return job}async function fireOne(options,listed){let lock=await acquireSessionDeliveryLock(options.dir,listed.sessionId,{maxDeliveryMs:options.deliveryTimeoutMs});if(!lock.acquired){let holder=lock.heldByPid===void 0?"another runner":`process ${lock.heldByPid}`;return{event:"deferred",id:listed.id,sessionId:listed.sessionId,reason:`${holder} is delivering to this session`}}try{let job=await freshPendingJob(options,listed.id);if(job===void 0)return;let deferReason=await options.shouldDefer?.({...job,...movedJobPaths(job)});return deferReason!==void 0?{event:"deferred",id:job.id,sessionId:job.sessionId,reason:deferReason}:await deliverClaimed(options,job,pid=>lock.attachDelivery(pid))}finally{await lock.release()}}async function deliverClaimed(options,job,onSpawn){let record=await claimOccurrence(options.dir,job,options.owner);if(record===void 0)return;let occurrence=job.fireCount+1,firedAt=options.now(),nextDueAt;if(job.everyMs!==null){nextDueAt=nextRecurringDueAt(job.dueAt,job.everyMs,firedAt);try{await rearmRecurringJob(options.dir,{...job,fireCount:occurrence,lastFiredAt:firedAt,dueAt:nextDueAt})}catch(error){throw await restorePending(options.dir,record,job.id),error}}let result;try{result=await options.deliver({type:"scheduled_prompt",id:job.id,sessionId:job.sessionId,...movedJobPaths(job),prompt:job.prompt,message:formatScheduledMessage(job,firedAt),dueAt:job.dueAt,firedAt,everyMs:job.everyMs,fireCount:occurrence},{onSpawn})}catch(error){result={ok:!1,error:error instanceof Error?error.message:String(error)}}return!result.ok&&result.sessionHeld===!0?(job.everyMs!==null&&await rearmRecurringJob(options.dir,job),await restorePending(options.dir,record,job.id),{event:"deferred",id:job.id,sessionId:job.sessionId,reason:result.error}):(await settleOccurrence(options.dir,record,{...job,fireCount:occurrence,lastFiredAt:firedAt},occurrence,result),{event:"fired",id:job.id,sessionId:job.sessionId,occurrence,outcome:result.ok?"delivered":"failed",...result.ok?{}:{error:result.error},firedAt,dueAt:job.dueAt,...nextDueAt===void 0||await isCancelled(options.dir,job.id)?{}:{nextDueAt}})}async function runDueJobs(options){let listing=await listScheduledJobs(options.dir),events=listing.invalid.map(invalid=>({event:"invalid",...invalid})),jobs=options.sessionId===void 0?listing.jobs:listing.jobs.filter(record=>record.job.sessionId===options.sessionId),recovery=await recoverAbandoned(options,jobs);events.push(...recovery.events),await pruneTombstones(options.dir,listing,options.now());let nextDueAt,noteNext=dueAt=>{nextDueAt=nextDueAt===void 0?dueAt:Math.min(nextDueAt,dueAt)};for(let dueAt of recovery.restoredDueAt)noteNext(dueAt);let bySession=new Map;for(let{state,job}of jobs){if(state!=="pending")continue;if(job.dueAt>options.now()){noteNext(job.dueAt);continue}if(await isCancelled(options.dir,job.id))continue;let queue=bySession.get(job.sessionId)??[];queue.push(job),bySession.set(job.sessionId,queue)}let queues=[...bySession.values()],workers=Math.max(1,Math.min(options.concurrency??4,queues.length)),next=0;return await Promise.all(Array.from({length:workers},async()=>{for(;next<queues.length;){let queue=queues[next++]??[];for(let job of queue){let event;try{event=await fireOne(options,job)}catch(error){let message=error instanceof Error?error.message:String(error);events.push({event:"error",id:job.id,sessionId:job.sessionId,error:message}),noteNext(options.now()+DEFERRED_RETRY_MS);break}if(event!==void 0&&(events.push(event),event.event==="fired"&&event.nextDueAt!==void 0&¬eNext(event.nextDueAt),event.event==="deferred")){noteNext(options.now()+DEFERRED_RETRY_MS);break}}}})),{events,nextDueAt}}export{InvalidSidecarStoreError,UnsupportedSidecarStoreVersionError,encodedSessionId,sidecarFilePath,createSidecarStore,serializeByKey,scheduleDir,ensureDir,listScheduledJobs,createScheduledJob,cancelScheduledJob,readProcessStartMs,errorCode,unlinkIfPresent,readLeaseText,publishExclusive,publishReplace,reclaimLockState,breakStaleLock,reclaimInspected,RUNNER_HEARTBEAT_STALE_MS,RUNNER_HEARTBEAT_INTERVAL_MS,ownRunnerIdentity,writeRunnerLease,removeRunnerLease,liveRunners,isWatchRunnerAvailable,SessionHeldError,holdSessionFile,liveSessionHolders,withSessionMoveLock,foreignSessionHolders,describeSessionHolders,SESSION_HOLDER_LOOKUP_FAILED,checkSessionHolders,takeOverRefusal,stopSessionHolders,sessionHolderWarning,prepareSessionOpening,SESSION_HELD_EXIT_CODE,admitStartupSession,deferWhileSessionOpen,execHookDelivery,sessionResumeDelivery,DEFERRED_RETRY_MS,runDueJobs};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{DynamicBorder,getEditorTheme,keyDisplayText,keyHint,observeVisibleStderrWrites,rawKeyHint,restoreStderr,sharedMarkdownTheme,takeOverStderr,theme}from"./chunk-32I42CEY.js";import{userWordBlocks}from"./chunk-22YXCY7K.js";import{isWSL}from"./chunk-K5JLYACP.js";import{usageLimitScope}from"./chunk-C7HEEBFH.js";import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{appendHiddenTuiStdout}from"./chunk-MSDBBOB2.js";import{CURSOR_MARKER,Container,Editor,Input,Markdown,MouseRegion,ProcessTerminal,ScrollView,Spacer,Text,TuiAltScreen,TuiMainScreen,VStack,getKeybindings,getNativeClipboard,isWarpWslSession,matchesKey,nextRenderRevision,truncateToWidth,visibleWidth}from"./chunk-RI5ABX7A.js";import{redactSensitiveOutput}from"./chunk-BPNSOZ2C.js";import{SERVER_FALLBACK_ABORTED_DIAGNOSTIC}from"./chunk-Z6TEQEZO.js";import{ACCOUNT_LIMIT_NEXT_STEP_LEAD,describeProviderFailureForUser,stripTurnRetrySuppressionPrefix}from"./chunk-OKMHSVCA.js";import{getDebugLogPath,stripBom}from"./chunk-SODMQEHO.js";import{typebox_exports}from"./chunk-MIENF2YK.js";var CODEX_OPTION=typebox_exports.Object({label:typebox_exports.String({description:"User-facing label (1-5 words)."}),description:typebox_exports.String({description:"One short sentence explaining impact/tradeoff if selected."})},{additionalProperties:!1}),CODEX_QUESTION=typebox_exports.Object({id:typebox_exports.String({pattern:"^[a-z][a-z0-9]*(_[a-z0-9]+)*$",description:"Stable identifier for mapping answers (snake_case)."}),header:typebox_exports.String({minLength:1,maxLength:12,description:"Short header label shown in the UI (12 or fewer chars)."}),question:typebox_exports.String({minLength:1,description:"Single-sentence prompt shown to the user."}),options:typebox_exports.Array(CODEX_OPTION,{minItems:2,maxItems:3,description:'Provide 2-3 mutually exclusive choices. Put the recommended option first and suffix its label with "(Recommended)". Do not include an "Other" option in this list; the client will add a free-form "Other" option automatically.'}),multiSelect:typebox_exports.Optional(typebox_exports.Boolean({description:"Set to true to allow the user to select multiple options instead of just one."}))},{additionalProperties:!1}),CODEX_PARAMS=typebox_exports.Object({questions:typebox_exports.Array(CODEX_QUESTION,{minItems:1,maxItems:3,description:"Questions to show the user. Prefer 1 and do not exceed 3"}),wait_for_answer:typebox_exports.Boolean({description:"Set true to pause here until the user answers; set false to keep working and receive the answer later as a user message."}),required:typebox_exports.Optional(typebox_exports.Boolean({description:"Set true when the answer decides whether you take an action (for example, which of two irreversible paths to take, or whether to proceed): with no answer, that action is not taken."}))},{additionalProperties:!1}),CLAUDE_OPTION=typebox_exports.Object({label:typebox_exports.String({description:"The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice."}),description:typebox_exports.Optional(typebox_exports.String({description:"Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications."}))}),CLAUDE_QUESTION=typebox_exports.Object({question:typebox_exports.String({minLength:1,description:'The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?"'}),header:typebox_exports.String({minLength:1,maxLength:12,description:'Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".'}),options:typebox_exports.Optional(typebox_exports.Array(CLAUDE_OPTION,{minItems:2,maxItems:4,description:"The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). There should be no Other option, that will be provided automatically."})),multiSelect:typebox_exports.Boolean({description:"Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive."})}),CLAUDE_PARAMS=typebox_exports.Object({questions:typebox_exports.Array(CLAUDE_QUESTION,{minItems:1,maxItems:4,description:"Questions to ask the user (1-4 questions)"}),waitForAnswer:typebox_exports.Boolean({description:"Set true to pause here until the user answers; set false to keep working and receive the answer later as a user message."}),required:typebox_exports.Optional(typebox_exports.Boolean({description:"Set true when the answer decides whether you take an action (for example, which of two irreversible paths to take, or whether to proceed): with no answer, that action is not taken."}))});var WAIT_FLAG_STEER_TEXT="This call omitted wait_for_answer (or waitForAnswer). Set true to pause here until the user answers, false to keep working and receive the answer later as a user message.",DEFAULT_ASK_USER_TIMEOUT_MS=1800*1e3,HEADER_MAX=12,SNAKE_CASE=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,LIMITS={codex:{maxQuestions:3,minOptions:2,maxOptions:3,optionsRequired:!0},claude:{maxQuestions:4,minOptions:2,maxOptions:4,optionsRequired:!1}},AskUserSchemaError=class extends Error{constructor(message){super(message),this.name="AskUserSchemaError"}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function readWaitFlag(variant,args){let value=args[variant==="codex"?"wait_for_answer":"waitForAnswer"];if(typeof value!="boolean")throw new AskUserSchemaError(WAIT_FLAG_STEER_TEXT);return value}function parseOptions(raw,min,max,required,requireDescription){if(raw===void 0){if(required)throw new AskUserSchemaError(`options must contain ${min} to ${max} items`);return[]}if(!Array.isArray(raw))throw new AskUserSchemaError("options must be an array");if(raw.length<min||raw.length>max)throw new AskUserSchemaError(required?`options must contain ${min} to ${max} items`:`options must contain ${min} to ${max} items when present`);let options=[];for(let item of raw){if(!isRecord(item))throw new AskUserSchemaError("each option must be an object");let label=typeof item.label=="string"?item.label.trim():"";if(label.length===0)throw new AskUserSchemaError("option label must be non-empty");let description=typeof item.description=="string"?item.description.trim():void 0;if(requireDescription&&(description===void 0||description.length===0))throw new AskUserSchemaError("option description is required");options.push(description===void 0||description.length===0?{label}:{label,description})}return options}function parseQuestion(variant,raw,index){if(!isRecord(raw))throw new AskUserSchemaError("each question must be an object");let limits=LIMITS[variant],header=typeof raw.header=="string"?raw.header.trim():"";if(header.length===0)throw new AskUserSchemaError("header must be non-empty");if(header.length>HEADER_MAX)throw new AskUserSchemaError("header must be 12 or fewer characters");let question=typeof raw.question=="string"?raw.question.trim():"";if(question.length===0)throw new AskUserSchemaError("question must be non-empty");let options=parseOptions(raw.options,limits.minOptions,limits.maxOptions,limits.optionsRequired,variant==="codex"),id;if(variant==="claude")id=`q${index+1}`;else if(id=typeof raw.id=="string"?raw.id.trim():"",!SNAKE_CASE.test(id))throw new AskUserSchemaError("id must be snake_case");let multiSelect;if(variant==="claude"){if(typeof raw.multiSelect!="boolean")throw new AskUserSchemaError("multiSelect is required");multiSelect=raw.multiSelect}else multiSelect=raw.multiSelect===!0;return{id,header,question,options,multiSelect}}function toCanonical(variant,args,options){if(!isRecord(args))throw new AskUserSchemaError(WAIT_FLAG_STEER_TEXT);let waitForAnswer=readWaitFlag(variant,args);if(args.required!==void 0&&typeof args.required!="boolean")throw new AskUserSchemaError("required must be a boolean when present");let limits=LIMITS[variant];if(!Array.isArray(args.questions)||args.questions.length<1||args.questions.length>limits.maxQuestions)throw new AskUserSchemaError(`questions must contain 1 to ${limits.maxQuestions} items`);return{requestId:options?.requestId??crypto.randomUUID(),questions:args.questions.map((question,index)=>parseQuestion(variant,question,index)),waitForAnswer,timeoutMs:options?.timeoutMs??DEFAULT_ASK_USER_TIMEOUT_MS,...args.required===!0?{required:!0}:{}}}var INLINE_WORDS={comment:text=>text,typed:(_header,text)=>text},reference=label=>`(see [${label}] below)`;function separatedWords(requestId){let words=[],place=(base,text)=>{let taken=words.filter(word=>word.label===base||word.label.startsWith(`${base} (`)).length,label=taken===0?base:`${base} (${taken+1})`;return words.push({label,text}),reference(label)};return{words,comment:text=>place(`The user's comment for question ${requestId}`,text),typed:(header,text)=>place(`The user's answer to ${header} for question ${requestId}`,text)}}function resolveUserWordReferences(text,words){return words.reduce((resolved,word)=>resolved.split(reference(word.label)).join(word.text),text)}function readUserWordBlocks(content){let texts=content.flatMap(block=>block.type==="text"?[block.text]:[]);if(texts.length%2!==0)return;let words=[];for(let index=0;index<texts.length;index+=2){let label=/^\[(.+)\]$/s.exec(texts[index]??"")?.[1],text=texts[index+1];if(label===void 0||text===void 0)return;words.push({label,text})}return words}function headerFor(id,questions){return questions.find(question=>question.id===id)?.header??id}function questionTextFor(id,questions){return questions.find(question=>question.id===id)?.question??id}function typedText(answer){if(answer.selected.length>0)return;let text=answer.text?.trim();return text===void 0||text.length===0?void 0:text}function answerBody(answer,header,words=INLINE_WORDS,offered=[]){if(!answer)return;if(answer.selected.length>0)return answer.selected.join(", ");let text=typedText(answer);if(text!==void 0)return offered.some(option=>option.label===text)?text:words.typed(header,text)}function answeredLines(response,questions,words){let lines=[],seen=new Set;for(let question of questions){let body=answerBody(response.answers[question.id],question.header,words,question.options);body!==void 0&&(lines.push(`${question.header}: ${body}`),seen.add(question.id))}for(let[id,answer]of Object.entries(response.answers)){if(seen.has(id))continue;let header=headerFor(id,questions),body=answerBody(answer,header,words);body!==void 0&&lines.push(`${header}: ${body}`)}return lines}function unansweredLine(response,questions){let unanswered=response.unanswered.map(id=>headerFor(id,questions));return unanswered.length>0?[`Unanswered: ${unanswered.join(", ")}`]:[]}var CANCELLED_BY_USER="The user cancelled the question after answering part of it.",CANCELLED_AFTER_ANSWERS="The question was cancelled after part of it was answered.";function isCancelledWithAnswersLine(line){return line===CANCELLED_BY_USER||line===CANCELLED_AFTER_ANSWERS}function showsPartialAnswers(response){return response.status!=="cancelled"||response.cancelOrigin!=="user"&&response.cancelOrigin!=="ui_failure"?!1:Object.values(response.answers).some(answer=>answerBody(answer,"")!==void 0)}function selectedBlock(prefix,selected){return selected.length===1?[`${prefix} ${selected[0]}`]:[prefix,...selected]}var GATED_NO_ANSWER="No answer: do not take the action it gates. Keep that action pending and end the turn.";function formatGatedNoAnswer(response,questions,words,cancellationReason){let lines=[cancellationReason??(response.status==="timed_out"?`The user did not answer within ${Math.round((response.autoResolvedAfterMs??DEFAULT_ASK_USER_TIMEOUT_MS)/6e4)} minutes. (\uC0AC\uC6A9\uC790\uAC00 \uB2F5\uBCC0\uC744 \uC548\uD558\uACE0 timeout \uC73C\uB85C \uC885\uB8CC\uB428)`:response.status==="cancelled"?"The user dismissed the question.":response.status==="orphaned-after-restart"?"The pending question could not be resumed after a restart.":"This session has no user attached (subagent or headless).")],selected=answeredLines(response,questions,words);return selected.length>0&&lines.push(...selectedBlock("Before going idle the user had selected (not an answer):",selected)),lines.push(GATED_NO_ANSWER),lines.join(`
|
|
2
|
+
import{DynamicBorder,getEditorTheme,keyDisplayText,keyHint,observeVisibleStderrWrites,rawKeyHint,restoreStderr,sharedMarkdownTheme,takeOverStderr,theme}from"./chunk-RQ6CHXQ2.js";import{userWordBlocks}from"./chunk-22YXCY7K.js";import{isWSL}from"./chunk-4GKU755E.js";import{usageLimitScope}from"./chunk-C7HEEBFH.js";import{signalSpawnedChild}from"./chunk-KLAX467B.js";import{appendHiddenTuiStdout}from"./chunk-MSDBBOB2.js";import{CURSOR_MARKER,Container,Editor,Input,Markdown,MouseRegion,ProcessTerminal,ScrollView,Spacer,Text,TuiAltScreen,TuiMainScreen,VStack,getKeybindings,getNativeClipboard,isWarpWslSession,matchesKey,nextRenderRevision,truncateToWidth,visibleWidth}from"./chunk-TMXRR3N7.js";import{redactSensitiveOutput}from"./chunk-BPNSOZ2C.js";import{SERVER_FALLBACK_ABORTED_DIAGNOSTIC}from"./chunk-Z6TEQEZO.js";import{ACCOUNT_LIMIT_NEXT_STEP_LEAD,describeProviderFailureForUser,stripTurnRetrySuppressionPrefix}from"./chunk-OKMHSVCA.js";import{getDebugLogPath,stripBom}from"./chunk-SODMQEHO.js";import{typebox_exports}from"./chunk-MIENF2YK.js";var CODEX_OPTION=typebox_exports.Object({label:typebox_exports.String({description:"User-facing label (1-5 words)."}),description:typebox_exports.String({description:"One short sentence explaining impact/tradeoff if selected."})},{additionalProperties:!1}),CODEX_QUESTION=typebox_exports.Object({id:typebox_exports.String({pattern:"^[a-z][a-z0-9]*(_[a-z0-9]+)*$",description:"Stable identifier for mapping answers (snake_case)."}),header:typebox_exports.String({minLength:1,maxLength:12,description:"Short header label shown in the UI (12 or fewer chars)."}),question:typebox_exports.String({minLength:1,description:"Single-sentence prompt shown to the user."}),options:typebox_exports.Array(CODEX_OPTION,{minItems:2,maxItems:3,description:'Provide 2-3 mutually exclusive choices. Put the recommended option first and suffix its label with "(Recommended)". Do not include an "Other" option in this list; the client will add a free-form "Other" option automatically.'}),multiSelect:typebox_exports.Optional(typebox_exports.Boolean({description:"Set to true to allow the user to select multiple options instead of just one."}))},{additionalProperties:!1}),CODEX_PARAMS=typebox_exports.Object({questions:typebox_exports.Array(CODEX_QUESTION,{minItems:1,maxItems:3,description:"Questions to show the user. Prefer 1 and do not exceed 3"}),wait_for_answer:typebox_exports.Boolean({description:"Set true to pause here until the user answers; set false to keep working and receive the answer later as a user message."}),required:typebox_exports.Optional(typebox_exports.Boolean({description:"Set true when the answer decides whether you take an action (for example, which of two irreversible paths to take, or whether to proceed): with no answer, that action is not taken."}))},{additionalProperties:!1}),CLAUDE_OPTION=typebox_exports.Object({label:typebox_exports.String({description:"The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice."}),description:typebox_exports.Optional(typebox_exports.String({description:"Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications."}))}),CLAUDE_QUESTION=typebox_exports.Object({question:typebox_exports.String({minLength:1,description:'The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?"'}),header:typebox_exports.String({minLength:1,maxLength:12,description:'Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".'}),options:typebox_exports.Optional(typebox_exports.Array(CLAUDE_OPTION,{minItems:2,maxItems:4,description:"The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). There should be no Other option, that will be provided automatically."})),multiSelect:typebox_exports.Boolean({description:"Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive."})}),CLAUDE_PARAMS=typebox_exports.Object({questions:typebox_exports.Array(CLAUDE_QUESTION,{minItems:1,maxItems:4,description:"Questions to ask the user (1-4 questions)"}),waitForAnswer:typebox_exports.Boolean({description:"Set true to pause here until the user answers; set false to keep working and receive the answer later as a user message."}),required:typebox_exports.Optional(typebox_exports.Boolean({description:"Set true when the answer decides whether you take an action (for example, which of two irreversible paths to take, or whether to proceed): with no answer, that action is not taken."}))});var WAIT_FLAG_STEER_TEXT="This call omitted wait_for_answer (or waitForAnswer). Set true to pause here until the user answers, false to keep working and receive the answer later as a user message.",DEFAULT_ASK_USER_TIMEOUT_MS=1800*1e3,HEADER_MAX=12,SNAKE_CASE=/^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,LIMITS={codex:{maxQuestions:3,minOptions:2,maxOptions:3,optionsRequired:!0},claude:{maxQuestions:4,minOptions:2,maxOptions:4,optionsRequired:!1}},AskUserSchemaError=class extends Error{constructor(message){super(message),this.name="AskUserSchemaError"}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function readWaitFlag(variant,args){let value=args[variant==="codex"?"wait_for_answer":"waitForAnswer"];if(typeof value!="boolean")throw new AskUserSchemaError(WAIT_FLAG_STEER_TEXT);return value}function parseOptions(raw,min,max,required,requireDescription){if(raw===void 0){if(required)throw new AskUserSchemaError(`options must contain ${min} to ${max} items`);return[]}if(!Array.isArray(raw))throw new AskUserSchemaError("options must be an array");if(raw.length<min||raw.length>max)throw new AskUserSchemaError(required?`options must contain ${min} to ${max} items`:`options must contain ${min} to ${max} items when present`);let options=[];for(let item of raw){if(!isRecord(item))throw new AskUserSchemaError("each option must be an object");let label=typeof item.label=="string"?item.label.trim():"";if(label.length===0)throw new AskUserSchemaError("option label must be non-empty");let description=typeof item.description=="string"?item.description.trim():void 0;if(requireDescription&&(description===void 0||description.length===0))throw new AskUserSchemaError("option description is required");options.push(description===void 0||description.length===0?{label}:{label,description})}return options}function parseQuestion(variant,raw,index){if(!isRecord(raw))throw new AskUserSchemaError("each question must be an object");let limits=LIMITS[variant],header=typeof raw.header=="string"?raw.header.trim():"";if(header.length===0)throw new AskUserSchemaError("header must be non-empty");if(header.length>HEADER_MAX)throw new AskUserSchemaError("header must be 12 or fewer characters");let question=typeof raw.question=="string"?raw.question.trim():"";if(question.length===0)throw new AskUserSchemaError("question must be non-empty");let options=parseOptions(raw.options,limits.minOptions,limits.maxOptions,limits.optionsRequired,variant==="codex"),id;if(variant==="claude")id=`q${index+1}`;else if(id=typeof raw.id=="string"?raw.id.trim():"",!SNAKE_CASE.test(id))throw new AskUserSchemaError("id must be snake_case");let multiSelect;if(variant==="claude"){if(typeof raw.multiSelect!="boolean")throw new AskUserSchemaError("multiSelect is required");multiSelect=raw.multiSelect}else multiSelect=raw.multiSelect===!0;return{id,header,question,options,multiSelect}}function toCanonical(variant,args,options){if(!isRecord(args))throw new AskUserSchemaError(WAIT_FLAG_STEER_TEXT);let waitForAnswer=readWaitFlag(variant,args);if(args.required!==void 0&&typeof args.required!="boolean")throw new AskUserSchemaError("required must be a boolean when present");let limits=LIMITS[variant];if(!Array.isArray(args.questions)||args.questions.length<1||args.questions.length>limits.maxQuestions)throw new AskUserSchemaError(`questions must contain 1 to ${limits.maxQuestions} items`);return{requestId:options?.requestId??crypto.randomUUID(),questions:args.questions.map((question,index)=>parseQuestion(variant,question,index)),waitForAnswer,timeoutMs:options?.timeoutMs??DEFAULT_ASK_USER_TIMEOUT_MS,...args.required===!0?{required:!0}:{}}}var INLINE_WORDS={comment:text=>text,typed:(_header,text)=>text},reference=label=>`(see [${label}] below)`;function separatedWords(requestId){let words=[],place=(base,text)=>{let taken=words.filter(word=>word.label===base||word.label.startsWith(`${base} (`)).length,label=taken===0?base:`${base} (${taken+1})`;return words.push({label,text}),reference(label)};return{words,comment:text=>place(`The user's comment for question ${requestId}`,text),typed:(header,text)=>place(`The user's answer to ${header} for question ${requestId}`,text)}}function resolveUserWordReferences(text,words){return words.reduce((resolved,word)=>resolved.split(reference(word.label)).join(word.text),text)}function readUserWordBlocks(content){let texts=content.flatMap(block=>block.type==="text"?[block.text]:[]);if(texts.length%2!==0)return;let words=[];for(let index=0;index<texts.length;index+=2){let label=/^\[(.+)\]$/s.exec(texts[index]??"")?.[1],text=texts[index+1];if(label===void 0||text===void 0)return;words.push({label,text})}return words}function headerFor(id,questions){return questions.find(question=>question.id===id)?.header??id}function questionTextFor(id,questions){return questions.find(question=>question.id===id)?.question??id}function typedText(answer){if(answer.selected.length>0)return;let text=answer.text?.trim();return text===void 0||text.length===0?void 0:text}function answerBody(answer,header,words=INLINE_WORDS,offered=[]){if(!answer)return;if(answer.selected.length>0)return answer.selected.join(", ");let text=typedText(answer);if(text!==void 0)return offered.some(option=>option.label===text)?text:words.typed(header,text)}function answeredLines(response,questions,words){let lines=[],seen=new Set;for(let question of questions){let body=answerBody(response.answers[question.id],question.header,words,question.options);body!==void 0&&(lines.push(`${question.header}: ${body}`),seen.add(question.id))}for(let[id,answer]of Object.entries(response.answers)){if(seen.has(id))continue;let header=headerFor(id,questions),body=answerBody(answer,header,words);body!==void 0&&lines.push(`${header}: ${body}`)}return lines}function unansweredLine(response,questions){let unanswered=response.unanswered.map(id=>headerFor(id,questions));return unanswered.length>0?[`Unanswered: ${unanswered.join(", ")}`]:[]}var CANCELLED_BY_USER="The user cancelled the question after answering part of it.",CANCELLED_AFTER_ANSWERS="The question was cancelled after part of it was answered.";function isCancelledWithAnswersLine(line){return line===CANCELLED_BY_USER||line===CANCELLED_AFTER_ANSWERS}function showsPartialAnswers(response){return response.status!=="cancelled"||response.cancelOrigin!=="user"&&response.cancelOrigin!=="ui_failure"?!1:Object.values(response.answers).some(answer=>answerBody(answer,"")!==void 0)}function selectedBlock(prefix,selected){return selected.length===1?[`${prefix} ${selected[0]}`]:[prefix,...selected]}var GATED_NO_ANSWER="No answer: do not take the action it gates. Keep that action pending and end the turn.";function formatGatedNoAnswer(response,questions,words,cancellationReason){let lines=[cancellationReason??(response.status==="timed_out"?`The user did not answer within ${Math.round((response.autoResolvedAfterMs??DEFAULT_ASK_USER_TIMEOUT_MS)/6e4)} minutes. (\uC0AC\uC6A9\uC790\uAC00 \uB2F5\uBCC0\uC744 \uC548\uD558\uACE0 timeout \uC73C\uB85C \uC885\uB8CC\uB428)`:response.status==="cancelled"?"The user dismissed the question.":response.status==="orphaned-after-restart"?"The pending question could not be resumed after a restart.":"This session has no user attached (subagent or headless).")],selected=answeredLines(response,questions,words);return selected.length>0&&lines.push(...selectedBlock("Before going idle the user had selected (not an answer):",selected)),lines.push(GATED_NO_ANSWER),lines.join(`
|
|
3
3
|
`)}function formatGatedCancellation(reason,response,requestId,questions){return formatGatedNoAnswer(response,questions,separatedWords(requestId),reason)}function formatBody(response,questions,words,required=!1){if(required&&response.status!=="answered"&&response.status!=="comment-submitted")return formatGatedNoAnswer(response,questions,words);switch(response.status){case"answered":return[...answeredLines(response,questions,words),...unansweredLine(response,questions)].join(`
|
|
4
4
|
`);case"comment-submitted":{let comment=response.comment?.trim()??"";return[`The user responded: ${comment.length>0?words.comment(comment):""}`,...answeredLines(response,questions,words),...unansweredLine(response,questions)].join(`
|
|
5
5
|
`)}case"timed_out":{let lines=[`The user did not answer within ${Math.round((response.autoResolvedAfterMs??DEFAULT_ASK_USER_TIMEOUT_MS)/6e4)} minutes. (\uC0AC\uC6A9\uC790\uAC00 \uB2F5\uBCC0\uC744 \uC548\uD558\uACE0 timeout \uC73C\uB85C \uC885\uB8CC\uB428)`],selected=answeredLines(response,questions,words);return selected.length>0&&lines.push(...selectedBlock("Before going idle the user had selected:",selected),...unansweredLine(response,questions)),lines.push("Continue the work to completion on your best judgment; do not ask this question again this turn."),lines.join(`
|