Files
orca/src/shared/jcode-runtime-dir.ts
T
Neilandczzczz a7b9358c47 fix(jcode): address CodeRabbit review on #22539
- Windows posted no payload at all: the shared builder reads `payload@-` from
  stdin, which the gate has already drained and observer hooks never receive, so
  every Windows event was dropped. Write the env var to a temp file and pipe it.
- The daemon pre-warm never fired for daemon-host spawns, which is the default
  local path; it now runs there too, and from the final env so the daemon gets the
  hook port and token.
- A failed runtime-dir mkdir took down every local terminal, jcode or not.
- removeJcodeManagedHooks matched the raw line, so a user hook whose comment
  mentioned the managed script was deleted; matching on Windows never worked.
- A managed entry left by a copied home or a platform switch is now repointed
  instead of being reported as user-owned forever.
- The OSC colour skip only checked launchAgent, so a command- or telemetry-named
  jcode pane still leaked the reply into its composer.
- `['hooks']` and a commented scalar are recognised, instead of appending a
  second [hooks] table that makes jcode reject the whole config.
- A failed tool's error is marked as tool output rather than agent prose.
- The vault keeps a session's stored name, counts its tokens, and skips
  background_task and [Scheduled task] turns.

Co-authored-by: czzczz <chanzrz_zbf@foxmail.com>
2026-10-03 01:49:40 -07:00

64 lines
2.7 KiB
TypeScript

// Why: jcode runs one server/client daemon per runtime dir (the daemon lock,
// socket, and debug socket all live there). Orca stamps a per-pane runtime dir
// so every Orca-launched jcode pane gets its own daemon, and jcode's lifecycle
// hooks (which fire inside the daemon) inherit that pane's ORCA_PANE_KEY
// instead of the first pane's. Without this, a second jcode pane connects the
// first pane's daemon and its status is attributed to the wrong tab.
import { createHash } from 'node:crypto'
import { mkdir } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
export const JCODE_RUNTIME_DIR_ENV_KEY = 'JCODE_RUNTIME_DIR'
// Why: the socket file is `<runtimeDir>/jcode.sock`, and unix socket paths are
// capped at SUN_LEN (104 bytes). TMPDIR alone can be ~50 chars, so the full
// pane key (73 chars) never fits; a deterministic 16-hex hash keeps the path
// short while staying per-pane unique and stable across restarts.
export function buildJcodeRuntimeDir(paneKey: string): string {
const hash = createHash('sha256').update(paneKey).digest('hex').slice(0, 16)
return join(tmpdir(), 'orca-jcode', hash)
}
/** jcode's daemon model is unix-socket based; Windows support is unverified. */
export function shouldInjectJcodeRuntimeDir(platform: NodeJS.Platform): boolean {
return platform !== 'win32'
}
/** The per-pane jcode runtime-dir env value, or undefined on unsupported platforms. */
export function buildJcodeRuntimeDirEnv(
paneKey: string,
platform: NodeJS.Platform = process.platform
): Record<string, string> | undefined {
return shouldInjectJcodeRuntimeDir(platform)
? { [JCODE_RUNTIME_DIR_ENV_KEY]: buildJcodeRuntimeDir(paneKey) }
: undefined
}
/**
* Ensures the per-pane jcode runtime dir exists before a PTY spawn (jcode fails
* fast when it is missing) and returns the env to merge into the spawn env.
* Async so the spawn hot path never blocks on a filesystem syscall.
*
* Why a failure returns undefined rather than throwing: this dir is stamped on
* EVERY local pane, not only jcode ones, so letting an EACCES on a shared
* /tmp/orca-jcode or a read-only TMPDIR propagate would stop a plain shell from
* opening. Without the dir jcode falls back to its own default daemon, which is
* the behaviour Orca had before per-pane isolation.
*/
export async function ensureJcodeRuntimeDir(
paneKey: string,
platform: NodeJS.Platform = process.platform
): Promise<Record<string, string> | undefined> {
const env = buildJcodeRuntimeDirEnv(paneKey, platform)
if (!env) {
return undefined
}
try {
await mkdir(env[JCODE_RUNTIME_DIR_ENV_KEY], { recursive: true })
} catch {
return undefined
}
return env
}