mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
* refactor: split agent config and auth services * chore: repoint wsl and global-fetch guards at split module paths * fix: restore merge-base Claude CLI error propagation Drop the secret-redaction rewriting added to Claude CLI error paths in the refactor: spawn errors again reject with the original Error (preserving .code/.errno/.syscall/.stack) and command output/auth-status logs are no longer rewritten.
100 lines
5.0 KiB
TypeScript
100 lines
5.0 KiB
TypeScript
export function getStatusPluginEndpointSource(): string[] {
|
|
return [
|
|
'// Why: process-lifetime guard so a recurring parse error on a malformed',
|
|
"// endpoint file does not spam OpenCode's stderr once per hook post.",
|
|
'// This guard lives inside the plugin source because the plugin runs in',
|
|
"// OpenCode's Node process (not Orca's) and has no access to server.ts's",
|
|
'// equivalent warnedVersions / warnedEnvs Sets.',
|
|
'let warnedBadEndpoint = false;',
|
|
'',
|
|
'// Why: message.part.updated can fire many times per second during a',
|
|
'// streaming assistant reply, and each post() calls resolveHookCoords()',
|
|
'// which reads the endpoint file. The file only changes on Orca restart',
|
|
'// (rare), so a stat+mtime check is substantially cheaper than a full',
|
|
'// readFileSync+parse on every streamed part. On stat error we fall',
|
|
'// through to parse so the fail-open behavior is preserved.',
|
|
'let cachedEndpointKey = "";',
|
|
'let cachedEndpointValues = null;',
|
|
'',
|
|
'function readEndpointFile() {',
|
|
' const path = process.env.ORCA_AGENT_HOOK_ENDPOINT;',
|
|
' if (!path) return null;',
|
|
' try {',
|
|
' const fs = require("fs");',
|
|
' try {',
|
|
' const stat = fs.statSync(path);',
|
|
' // Why: cache key combines mtime + size + inode. renameSync (used by',
|
|
' // writeEndpointFile on the Orca side) allocates a fresh inode on',
|
|
' // POSIX and a new Windows file ID on NTFS, so ino changes on every',
|
|
' // legitimate rewrite even when mtimeMs resolution is coarse and size',
|
|
' // happens to match.',
|
|
' const cacheKey = stat.mtimeMs + ":" + stat.size + ":" + stat.ino;',
|
|
' if (cacheKey === cachedEndpointKey && cachedEndpointValues) {',
|
|
' return cachedEndpointValues;',
|
|
' }',
|
|
' const contents = fs.readFileSync(path, "utf8");',
|
|
' const out = {};',
|
|
' for (const line of contents.split(/\\r?\\n/)) {',
|
|
' // Why: Windows endpoint.cmd uses `set KEY=VALUE`; Unix endpoint.env',
|
|
' // uses `KEY=VALUE`. Making `set ` optional lets the same parser',
|
|
' // handle both without platform detection in the plugin. Allow',
|
|
' // digits in the key for forward-compat with future ORCA_AGENT_HOOK_*',
|
|
' // names that may contain numerics, and strip a trailing CR so',
|
|
' // mixed-EOL files with lone `\\r` do not leak CR into the value.',
|
|
' const m = line.match(/^(?:set\\s+)?([A-Z0-9_]+)=(.*)$/);',
|
|
' if (m) out[m[1]] = m[2].replace(/\\r$/, "");',
|
|
' }',
|
|
' cachedEndpointKey = cacheKey;',
|
|
' cachedEndpointValues = out;',
|
|
' return out;',
|
|
' } catch (ioErr) {',
|
|
' // Why: any stat or read failure (file yanked mid-read, permission',
|
|
' // race, unlink between stat and readFileSync) must invalidate the',
|
|
' // cache so a transient failure does not lock in a stale parse for',
|
|
' // the remaining process lifetime; rethrow to the outer catch.',
|
|
' cachedEndpointKey = "";',
|
|
' cachedEndpointValues = null;',
|
|
' throw ioErr;',
|
|
' }',
|
|
' } catch (err) {',
|
|
' // Why: warn once per process if the file exists but is unreadable or',
|
|
' // malformed — a persistent, silently-swallowed parse error would',
|
|
' // otherwise leave the plugin falling back to stale process.env on',
|
|
' // every post with no signal. ENOENT / missing env var is the normal',
|
|
' // pre-install case; stay silent for it.',
|
|
' if (err && err.code !== "ENOENT" && !warnedBadEndpoint) {',
|
|
' warnedBadEndpoint = true;',
|
|
' console.warn("[orca-hook] failed to parse endpoint file:", err.message);',
|
|
' }',
|
|
' return null;',
|
|
' }',
|
|
'}',
|
|
'',
|
|
'function resolveHookCoords() {',
|
|
' // Why: prefer the on-disk endpoint file over process.env because env was',
|
|
' // frozen when OpenCode was fork()ed — stale after an Orca restart. The',
|
|
' // file is rewritten on every Orca start(), so sourcing it per post lets',
|
|
' // a long-running OpenCode session reach the current server. Falls back',
|
|
' // to process.env when the file is absent (first-run / pre-endpoint-file / Orca',
|
|
' // never started writing the file).',
|
|
' const fileEnv = readEndpointFile() || {};',
|
|
' return {',
|
|
' port: fileEnv.ORCA_AGENT_HOOK_PORT || process.env.ORCA_AGENT_HOOK_PORT,',
|
|
' token: fileEnv.ORCA_AGENT_HOOK_TOKEN || process.env.ORCA_AGENT_HOOK_TOKEN,',
|
|
' env: fileEnv.ORCA_AGENT_HOOK_ENV || process.env.ORCA_AGENT_HOOK_ENV || "",',
|
|
' version: fileEnv.ORCA_AGENT_HOOK_VERSION || process.env.ORCA_AGENT_HOOK_VERSION || "",',
|
|
' };',
|
|
'}',
|
|
'',
|
|
'function hookEndpointKey() {',
|
|
' const coords = resolveHookCoords();',
|
|
' return [coords.port || "", coords.token || "", coords.env, coords.version].join("\\u0000");',
|
|
'}',
|
|
'',
|
|
'function getStatusType(event) {',
|
|
' return event?.properties?.status?.type ?? event?.status?.type ?? null;',
|
|
'}',
|
|
''
|
|
]
|
|
}
|