@nextclaw/nextclaw-ncp-runtime-stdio-client 0.2.12 → 0.2.14-beta.0

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.
@@ -18,6 +18,7 @@ type StdioRuntimeResolvedConfig = {
18
18
  args: string[];
19
19
  cwd?: string;
20
20
  env?: StdioRuntimeEnv;
21
+ resetSessionMetadataOnPromptTimeout?: string[];
21
22
  startupTimeoutMs: number;
22
23
  probeTimeoutMs: number;
23
24
  requestTimeoutMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-config.utils.d.ts","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"mappings":";;;cAGa,0BAAA;AAAA,KAWD,eAAA,GAAkB,MAAA;AAAA,KAClB,uBAAA;AAAA,KACA,wBAAA;AAAA,KAEA,mBAAA;EACV,aAAA;EACA,aAAA,GAAgB,uBAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,KAAA,GAAQ,aAAA,CAAc,UAAA;AAAA;AAAA,KAGZ,0BAAA;EACV,WAAA,EAAa,uBAAA;EACb,YAAA,EAAc,wBAAA;EACd,OAAA;EACA,IAAA;EACA,GAAA;EACA,GAAA,GAAM,eAAA;EACN,gBAAA;EACA,cAAA;EACA,gBAAA;AAAA;AAAA,cAyDW,0BAAA;EAAA,iBACkB,MAAA;cAAA,MAAA,GAAQ,MAAA;EAErC,OAAA,QAAc,0BAAA;EAAA,QA6CN,kBAAA;EAAA,QAQA,mBAAA;AAAA;AAAA,iBASM,0BAAA,CAA2B,MAAA;EACzC,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA;AAAA,iBAaY,0BAAA,CAA2B,MAAA;EACzC,OAAA,GAAU,MAAA;EACV,SAAA,GAAY,eAAA;EACZ,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA"}
1
+ {"version":3,"file":"stdio-runtime-config.utils.d.ts","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"mappings":";;;cAGa,0BAAA;AAAA,KAWD,eAAA,GAAkB,MAAA;AAAA,KAClB,uBAAA;AAAA,KACA,wBAAA;AAAA,KAEA,mBAAA;EACV,aAAA;EACA,aAAA,GAAgB,uBAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,KAAA,GAAQ,aAAA,CAAc,UAAA;AAAA;AAAA,KAGZ,0BAAA;EACV,WAAA,EAAa,uBAAA;EACb,YAAA,EAAc,wBAAA;EACd,OAAA;EACA,IAAA;EACA,GAAA;EACA,GAAA,GAAM,eAAA;EACN,mCAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;AAAA;AAAA,cAkGW,0BAAA;EAAA,iBACkB,MAAA;cAAA,MAAA,GAAQ,MAAA;EAErC,OAAA,QAAc,0BAAA;EAAA,QAmDN,kBAAA;EAAA,QAQA,mBAAA;AAAA;AAAA,iBASM,0BAAA,CAA2B,MAAA;EACzC,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA;AAAA,iBAaY,0BAAA,CAA2B,MAAA;EACzC,OAAA,GAAU,MAAA;EACV,SAAA,GAAY,eAAA;EACZ,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA"}
@@ -41,6 +41,30 @@ function readStringRecord(value) {
41
41
  }
42
42
  return Object.keys(output).length > 0 ? output : void 0;
43
43
  }
44
+ function readCommandOverrides(value) {
45
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
46
+ const overrides = {};
47
+ for (const [rawCommand, rawOverride] of Object.entries(value)) {
48
+ const commandKey = readString(rawCommand);
49
+ if (!commandKey || !rawOverride || typeof rawOverride !== "object" || Array.isArray(rawOverride)) continue;
50
+ const overrideRecord = rawOverride;
51
+ const command = readString(overrideRecord.command);
52
+ const args = readStringArray(overrideRecord.args);
53
+ const cwd = readString(overrideRecord.cwd);
54
+ const env = readStringRecord(overrideRecord.env);
55
+ if (!command && !args && !cwd && !env) continue;
56
+ overrides[commandKey] = {
57
+ ...command ? { command } : {},
58
+ ...args ? { args } : {},
59
+ ...cwd ? { cwd } : {},
60
+ ...env ? { env } : {}
61
+ };
62
+ }
63
+ return overrides;
64
+ }
65
+ function readCommandOverride(command) {
66
+ return readCommandOverrides(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_COMMAND_OVERRIDES))[command];
67
+ }
44
68
  var StdioRuntimeConfigResolver = class {
45
69
  constructor(source = {}) {
46
70
  this.source = source;
@@ -50,13 +74,19 @@ var StdioRuntimeConfigResolver = class {
50
74
  const processScope = this.resolveProcessScope();
51
75
  const command = readString(this.source.command) ?? readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);
52
76
  if (!command) throw new Error("[narp-stdio] missing stdio command");
77
+ const override = readCommandOverride(command);
78
+ const args = override?.args ?? readStringArray(this.source.args) ?? readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ?? [];
79
+ const cwd = override?.cwd ?? readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD);
80
+ const env = override?.env ?? readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV));
81
+ const resetSessionMetadataOnPromptTimeout = readStringArray(this.source.resetSessionMetadataOnPromptTimeout);
53
82
  return {
54
83
  wireDialect,
55
84
  processScope,
56
- command,
57
- args: readStringArray(this.source.args) ?? readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ?? [],
58
- ...readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD) ? { cwd: readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD) } : {},
59
- ...readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV)) ? { env: readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV)) } : {},
85
+ command: override?.command ?? command,
86
+ args,
87
+ ...cwd ? { cwd } : {},
88
+ ...env ? { env } : {},
89
+ ...resetSessionMetadataOnPromptTimeout ? { resetSessionMetadataOnPromptTimeout } : {},
60
90
  startupTimeoutMs: readPositiveInteger(this.source.startupTimeoutMs) ?? readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ?? DEFAULT_STARTUP_TIMEOUT_MS,
61
91
  probeTimeoutMs: readPositiveInteger(this.source.probeTimeoutMs) ?? DEFAULT_PROBE_TIMEOUT_MS,
62
92
  requestTimeoutMs: readPositiveInteger(this.source.requestTimeoutMs) ?? DEFAULT_REQUEST_TIMEOUT_MS
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-config.utils.js","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"sourcesContent":["import type { OpenAITool, NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { createRuntimeChildEnv } from \"@nextclaw/core\";\n\nexport const NARP_STDIO_PROMPT_META_KEY = \"nextclaw_narp\";\nconst DEFAULT_STARTUP_TIMEOUT_MS = 10_000;\nconst DEFAULT_PROBE_TIMEOUT_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\nconst DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS = {\n model: \"NEXTCLAW_MODEL\",\n apiBase: \"NEXTCLAW_API_BASE\",\n apiKey: \"NEXTCLAW_API_KEY\",\n headers: \"NEXTCLAW_HEADERS_JSON\",\n} as const;\n\nexport type StdioRuntimeEnv = Record<string, string>;\nexport type StdioRuntimeWireDialect = \"acp\";\nexport type StdioRuntimeProcessScope = \"per-session\";\n\nexport type NarpStdioPromptMeta = {\n correlationId?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n sessionMetadata?: Record<string, unknown>;\n tools?: ReadonlyArray<OpenAITool>;\n};\n\nexport type StdioRuntimeResolvedConfig = {\n wireDialect: StdioRuntimeWireDialect;\n processScope: StdioRuntimeProcessScope;\n command: string;\n args: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n startupTimeoutMs: number;\n probeTimeoutMs: number;\n requestTimeoutMs: number;\n};\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function readPositiveInteger(value: unknown): number | undefined {\n const parsed =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number.NaN;\n if (!Number.isFinite(parsed)) {\n return undefined;\n }\n const normalized = Math.trunc(parsed);\n return normalized > 0 ? normalized : undefined;\n}\n\nexport function readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const output: string[] = [];\n for (const entry of value) {\n const normalized = readString(entry);\n if (!normalized) {\n continue;\n }\n output.push(normalized);\n }\n return output.length > 0 ? output : undefined;\n}\n\nexport function readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n\n const output: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n const normalizedValue = readString(entryValue);\n if (!normalizedValue) {\n continue;\n }\n output[entryKey] = normalizedValue;\n }\n return Object.keys(output).length > 0 ? output : undefined;\n}\n\nexport class StdioRuntimeConfigResolver {\n constructor(private readonly source: Record<string, unknown> = {}) {}\n\n resolve = (): StdioRuntimeResolvedConfig => {\n const wireDialect = this.resolveWireDialect();\n const processScope = this.resolveProcessScope();\n const command =\n readString(this.source.command) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);\n if (!command) {\n throw new Error(\"[narp-stdio] missing stdio command\");\n }\n\n return {\n wireDialect,\n processScope,\n command,\n args:\n readStringArray(this.source.args) ??\n readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ??\n [],\n ...(readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD)\n ? {\n cwd:\n readString(this.source.cwd) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_CWD),\n }\n : {}),\n ...(readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV))\n ? {\n env:\n readStringRecord(this.source.env) ??\n readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV)),\n }\n : {}),\n startupTimeoutMs:\n readPositiveInteger(this.source.startupTimeoutMs) ??\n readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ??\n DEFAULT_STARTUP_TIMEOUT_MS,\n probeTimeoutMs:\n readPositiveInteger(this.source.probeTimeoutMs) ??\n DEFAULT_PROBE_TIMEOUT_MS,\n requestTimeoutMs:\n readPositiveInteger(this.source.requestTimeoutMs) ??\n DEFAULT_REQUEST_TIMEOUT_MS,\n };\n };\n\n private resolveWireDialect = (): StdioRuntimeWireDialect => {\n const wireDialect = readString(this.source.wireDialect) ?? \"acp\";\n if (wireDialect !== \"acp\") {\n throw new Error(`[narp-stdio] unsupported wireDialect \"${wireDialect}\"`);\n }\n return \"acp\";\n };\n\n private resolveProcessScope = (): StdioRuntimeProcessScope => {\n const processScope = readString(this.source.processScope) ?? \"per-session\";\n if (processScope !== \"per-session\") {\n throw new Error(`[narp-stdio] unsupported processScope \"${processScope}\"`);\n }\n return \"per-session\";\n };\n}\n\nexport function buildRuntimeRouteBridgeEnv(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n const { providerRoute } = params;\n if (!providerRoute) {\n return {};\n }\n return {\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.model]: providerRoute.model,\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiBase]: providerRoute.apiBase ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiKey]: providerRoute.apiKey ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.headers]: JSON.stringify(providerRoute.headers ?? {}),\n };\n}\n\nexport function buildStdioRuntimeLaunchEnv(params: {\n baseEnv?: Record<string, string | undefined>;\n configEnv?: StdioRuntimeEnv;\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n return {\n ...createRuntimeChildEnv(params.baseEnv ?? process.env, params.configEnv, {\n inheritBaseEnv: true,\n }),\n ...buildRuntimeRouteBridgeEnv({\n providerRoute: params.providerRoute,\n }),\n };\n}\n\nfunction parseJsonArray(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonObject(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stdio-runtime-config.utils.js","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"sourcesContent":["import type { OpenAITool, NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { createRuntimeChildEnv } from \"@nextclaw/core\";\n\nexport const NARP_STDIO_PROMPT_META_KEY = \"nextclaw_narp\";\nconst DEFAULT_STARTUP_TIMEOUT_MS = 10_000;\nconst DEFAULT_PROBE_TIMEOUT_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\nconst DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS = {\n model: \"NEXTCLAW_MODEL\",\n apiBase: \"NEXTCLAW_API_BASE\",\n apiKey: \"NEXTCLAW_API_KEY\",\n headers: \"NEXTCLAW_HEADERS_JSON\",\n} as const;\n\nexport type StdioRuntimeEnv = Record<string, string>;\nexport type StdioRuntimeWireDialect = \"acp\";\nexport type StdioRuntimeProcessScope = \"per-session\";\n\nexport type NarpStdioPromptMeta = {\n correlationId?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n sessionMetadata?: Record<string, unknown>;\n tools?: ReadonlyArray<OpenAITool>;\n};\n\nexport type StdioRuntimeResolvedConfig = {\n wireDialect: StdioRuntimeWireDialect;\n processScope: StdioRuntimeProcessScope;\n command: string;\n args: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n resetSessionMetadataOnPromptTimeout?: string[];\n startupTimeoutMs: number;\n probeTimeoutMs: number;\n requestTimeoutMs: number;\n};\n\ntype StdioRuntimeCommandOverride = {\n command?: string;\n args?: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n};\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function readPositiveInteger(value: unknown): number | undefined {\n const parsed =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number.NaN;\n if (!Number.isFinite(parsed)) {\n return undefined;\n }\n const normalized = Math.trunc(parsed);\n return normalized > 0 ? normalized : undefined;\n}\n\nexport function readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const output: string[] = [];\n for (const entry of value) {\n const normalized = readString(entry);\n if (!normalized) {\n continue;\n }\n output.push(normalized);\n }\n return output.length > 0 ? output : undefined;\n}\n\nexport function readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n\n const output: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n const normalizedValue = readString(entryValue);\n if (!normalizedValue) {\n continue;\n }\n output[entryKey] = normalizedValue;\n }\n return Object.keys(output).length > 0 ? output : undefined;\n}\n\nfunction readCommandOverrides(value: unknown): Record<string, StdioRuntimeCommandOverride> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n const overrides: Record<string, StdioRuntimeCommandOverride> = {};\n for (const [rawCommand, rawOverride] of Object.entries(value)) {\n const commandKey = readString(rawCommand);\n if (!commandKey || !rawOverride || typeof rawOverride !== \"object\" || Array.isArray(rawOverride)) {\n continue;\n }\n const overrideRecord = rawOverride as Record<string, unknown>;\n const command = readString(overrideRecord.command);\n const args = readStringArray(overrideRecord.args);\n const cwd = readString(overrideRecord.cwd);\n const env = readStringRecord(overrideRecord.env);\n if (!command && !args && !cwd && !env) {\n continue;\n }\n overrides[commandKey] = {\n ...(command ? { command } : {}),\n ...(args ? { args } : {}),\n ...(cwd ? { cwd } : {}),\n ...(env ? { env } : {}),\n };\n }\n return overrides;\n}\n\nfunction readCommandOverride(command: string): StdioRuntimeCommandOverride | undefined {\n const rawOverrides = parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_COMMAND_OVERRIDES);\n return readCommandOverrides(rawOverrides)[command];\n}\n\nexport class StdioRuntimeConfigResolver {\n constructor(private readonly source: Record<string, unknown> = {}) {}\n\n resolve = (): StdioRuntimeResolvedConfig => {\n const wireDialect = this.resolveWireDialect();\n const processScope = this.resolveProcessScope();\n const command =\n readString(this.source.command) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);\n if (!command) {\n throw new Error(\"[narp-stdio] missing stdio command\");\n }\n\n const override = readCommandOverride(command);\n const args =\n override?.args ??\n readStringArray(this.source.args) ??\n readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ??\n [];\n const cwd =\n override?.cwd ??\n readString(this.source.cwd) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_CWD);\n const env =\n override?.env ??\n readStringRecord(this.source.env) ??\n readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV));\n const resetSessionMetadataOnPromptTimeout = readStringArray(\n this.source.resetSessionMetadataOnPromptTimeout,\n );\n\n return {\n wireDialect,\n processScope,\n command: override?.command ?? command,\n args,\n ...(cwd ? { cwd } : {}),\n ...(env ? { env } : {}),\n ...(resetSessionMetadataOnPromptTimeout\n ? { resetSessionMetadataOnPromptTimeout }\n : {}),\n startupTimeoutMs:\n readPositiveInteger(this.source.startupTimeoutMs) ??\n readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ??\n DEFAULT_STARTUP_TIMEOUT_MS,\n probeTimeoutMs:\n readPositiveInteger(this.source.probeTimeoutMs) ??\n DEFAULT_PROBE_TIMEOUT_MS,\n requestTimeoutMs:\n readPositiveInteger(this.source.requestTimeoutMs) ??\n DEFAULT_REQUEST_TIMEOUT_MS,\n };\n };\n\n private resolveWireDialect = (): StdioRuntimeWireDialect => {\n const wireDialect = readString(this.source.wireDialect) ?? \"acp\";\n if (wireDialect !== \"acp\") {\n throw new Error(`[narp-stdio] unsupported wireDialect \"${wireDialect}\"`);\n }\n return \"acp\";\n };\n\n private resolveProcessScope = (): StdioRuntimeProcessScope => {\n const processScope = readString(this.source.processScope) ?? \"per-session\";\n if (processScope !== \"per-session\") {\n throw new Error(`[narp-stdio] unsupported processScope \"${processScope}\"`);\n }\n return \"per-session\";\n };\n}\n\nexport function buildRuntimeRouteBridgeEnv(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n const { providerRoute } = params;\n if (!providerRoute) {\n return {};\n }\n return {\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.model]: providerRoute.model,\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiBase]: providerRoute.apiBase ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiKey]: providerRoute.apiKey ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.headers]: JSON.stringify(providerRoute.headers ?? {}),\n };\n}\n\nexport function buildStdioRuntimeLaunchEnv(params: {\n baseEnv?: Record<string, string | undefined>;\n configEnv?: StdioRuntimeEnv;\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n return {\n ...createRuntimeChildEnv(params.baseEnv ?? process.env, params.configEnv, {\n inheritBaseEnv: true,\n }),\n ...buildRuntimeRouteBridgeEnv({\n providerRoute: params.providerRoute,\n }),\n };\n}\n\nfunction parseJsonArray(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonObject(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
@@ -3,9 +3,9 @@ function buildSpawnFailureMessage(params) {
3
3
  const { command, cwd, error } = params;
4
4
  return `[narp-stdio] failed to start stdio runtime command "${command}"${cwd ? ` (cwd: ${cwd})` : ""}: ${error.message}`;
5
5
  }
6
- function normalizeRuntimeError(error) {
6
+ function normalizeRuntimeError(error, diagnostics = {}) {
7
7
  if (isNcpError(error)) return error;
8
- const message = error instanceof Error ? error.message : String(error);
8
+ const message = formatRuntimeErrorMessage(error, diagnostics);
9
9
  const lowered = message.toLowerCase();
10
10
  return {
11
11
  code: lowered.includes("abort") || lowered.includes("cancel") ? "abort-error" : "runtime-error",
@@ -17,6 +17,11 @@ function isAbortLikeRuntimeError(error) {
17
17
  const lowered = (error instanceof Error ? error.message : String(error)).toLowerCase();
18
18
  return lowered.includes("abort") || lowered.includes("cancel");
19
19
  }
20
+ function formatRuntimeErrorMessage(error, diagnostics = {}) {
21
+ const message = error instanceof Error ? error.message : String(error);
22
+ const stderr = diagnostics.stderr?.trim();
23
+ return stderr && !message.includes(stderr) ? `${message}. stderr=${stderr}` : message;
24
+ }
20
25
  function isNcpError(value) {
21
26
  if (!value || typeof value !== "object") return false;
22
27
  return typeof value.code === "string" && typeof value.message === "string";
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-error.utils.js","names":[],"sources":["../src/stdio-runtime-error.utils.ts"],"sourcesContent":["import type { NcpError } from \"@nextclaw/ncp\";\n\nexport function buildSpawnFailureMessage(params: {\n command: string;\n cwd?: string;\n error: Error;\n}): string {\n const { command, cwd, error } = params;\n const cwdSuffix = cwd ? ` (cwd: ${cwd})` : \"\";\n return `[narp-stdio] failed to start stdio runtime command \"${command}\"${cwdSuffix}: ${error.message}`;\n}\n\nexport function normalizeRuntimeError(error: unknown): NcpError {\n if (isNcpError(error)) {\n return error;\n }\n const message = error instanceof Error ? error.message : String(error);\n const lowered = message.toLowerCase();\n return {\n code: lowered.includes(\"abort\") || lowered.includes(\"cancel\")\n ? \"abort-error\"\n : \"runtime-error\",\n message,\n };\n}\n\nexport function isAbortLikeRuntimeError(error: unknown): boolean {\n if (isNcpError(error)) {\n return error.code === \"abort-error\";\n }\n const message = error instanceof Error ? error.message : String(error);\n const lowered = message.toLowerCase();\n return lowered.includes(\"abort\") || lowered.includes(\"cancel\");\n}\n\nfunction isNcpError(value: unknown): value is NcpError {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n return typeof (value as NcpError).code === \"string\" && typeof (value as NcpError).message === \"string\";\n}\n"],"mappings":";AAEA,SAAgB,yBAAyB,QAI9B;CACT,MAAM,EAAE,SAAS,KAAK,UAAU;AAEhC,QAAO,uDAAuD,QAAQ,GADpD,MAAM,UAAU,IAAI,KAAK,GACwC,IAAI,MAAM;;AAG/F,SAAgB,sBAAsB,OAA0B;AAC9D,KAAI,WAAW,MAAM,CACnB,QAAO;CAET,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;CACtE,MAAM,UAAU,QAAQ,aAAa;AACrC,QAAO;EACL,MAAM,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS,GACzD,gBACA;EACJ;EACD;;AAGH,SAAgB,wBAAwB,OAAyB;AAC/D,KAAI,WAAW,MAAM,CACnB,QAAO,MAAM,SAAS;CAGxB,MAAM,WADU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAC9C,aAAa;AACrC,QAAO,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS;;AAGhE,SAAS,WAAW,OAAmC;AACrD,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;AAET,QAAO,OAAQ,MAAmB,SAAS,YAAY,OAAQ,MAAmB,YAAY"}
1
+ {"version":3,"file":"stdio-runtime-error.utils.js","names":[],"sources":["../src/stdio-runtime-error.utils.ts"],"sourcesContent":["import type { NcpError } from \"@nextclaw/ncp\";\n\nexport function buildSpawnFailureMessage(params: {\n command: string;\n cwd?: string;\n error: Error;\n}): string {\n const { command, cwd, error } = params;\n const cwdSuffix = cwd ? ` (cwd: ${cwd})` : \"\";\n return `[narp-stdio] failed to start stdio runtime command \"${command}\"${cwdSuffix}: ${error.message}`;\n}\n\nexport function normalizeRuntimeError(\n error: unknown,\n diagnostics: { stderr?: string } = {},\n): NcpError {\n if (isNcpError(error)) {\n return error;\n }\n const message = formatRuntimeErrorMessage(error, diagnostics);\n const lowered = message.toLowerCase();\n return {\n code: lowered.includes(\"abort\") || lowered.includes(\"cancel\")\n ? \"abort-error\"\n : \"runtime-error\",\n message,\n };\n}\n\nexport function isAbortLikeRuntimeError(error: unknown): boolean {\n if (isNcpError(error)) {\n return error.code === \"abort-error\";\n }\n const message = error instanceof Error ? error.message : String(error);\n const lowered = message.toLowerCase();\n return lowered.includes(\"abort\") || lowered.includes(\"cancel\");\n}\n\nexport function formatRuntimeErrorMessage(\n error: unknown,\n diagnostics: { stderr?: string } = {},\n): string {\n const message = error instanceof Error ? error.message : String(error);\n const stderr = diagnostics.stderr?.trim();\n return stderr && !message.includes(stderr) ? `${message}. stderr=${stderr}` : message;\n}\n\nfunction isNcpError(value: unknown): value is NcpError {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n return typeof (value as NcpError).code === \"string\" && typeof (value as NcpError).message === \"string\";\n}\n"],"mappings":";AAEA,SAAgB,yBAAyB,QAI9B;CACT,MAAM,EAAE,SAAS,KAAK,UAAU;AAEhC,QAAO,uDAAuD,QAAQ,GADpD,MAAM,UAAU,IAAI,KAAK,GACwC,IAAI,MAAM;;AAG/F,SAAgB,sBACd,OACA,cAAmC,EAAE,EAC3B;AACV,KAAI,WAAW,MAAM,CACnB,QAAO;CAET,MAAM,UAAU,0BAA0B,OAAO,YAAY;CAC7D,MAAM,UAAU,QAAQ,aAAa;AACrC,QAAO;EACL,MAAM,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS,GACzD,gBACA;EACJ;EACD;;AAGH,SAAgB,wBAAwB,OAAyB;AAC/D,KAAI,WAAW,MAAM,CACnB,QAAO,MAAM,SAAS;CAGxB,MAAM,WADU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAC9C,aAAa;AACrC,QAAO,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS;;AAGhE,SAAgB,0BACd,OACA,cAAmC,EAAE,EAC7B;CACR,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;CACtE,MAAM,SAAS,YAAY,QAAQ,MAAM;AACzC,QAAO,UAAU,CAAC,QAAQ,SAAS,OAAO,GAAG,GAAG,QAAQ,WAAW,WAAW;;AAGhF,SAAS,WAAW,OAAmC;AACrD,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;AAET,QAAO,OAAQ,MAAmB,SAAS,YAAY,OAAQ,MAAmB,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-probe.utils.d.ts","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"mappings":";;;iBAuBsB,iBAAA,CAAkB,MAAA,EAAQ,0BAAA,GAA6B,OAAA"}
1
+ {"version":3,"file":"stdio-runtime-probe.utils.d.ts","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"mappings":";;;iBAwBsB,iBAAA,CAAkB,MAAA,EAAQ,0BAAA,GAA6B,OAAA"}
@@ -3,6 +3,7 @@ import { buildSpawnFailureMessage } from "./stdio-runtime-error.utils.js";
3
3
  import { spawn } from "node:child_process";
4
4
  import { Readable, Writable } from "node:stream";
5
5
  import * as acp from "@agentclientprotocol/sdk";
6
+ import { tmpdir } from "node:os";
6
7
  //#region src/stdio-runtime-probe.utils.ts
7
8
  const createProbeClientBridge = () => ({
8
9
  sessionUpdate: async () => void 0,
@@ -37,16 +38,17 @@ async function probeStdioRuntime(config) {
37
38
  });
38
39
  const stream = acp.ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
39
40
  const connection = new acp.ClientSideConnection(() => createProbeClientBridge(), stream);
41
+ const newSessionParams = {
42
+ cwd: config.cwd ?? tmpdir(),
43
+ mcpServers: []
44
+ };
40
45
  try {
41
46
  const session = await Promise.race([(async () => {
42
47
  await withTimeout(connection.initialize({
43
48
  protocolVersion: acp.PROTOCOL_VERSION,
44
49
  clientCapabilities: {}
45
50
  }), config.probeTimeoutMs, `[narp-stdio] probe timed out initializing stdio runtime`);
46
- return withTimeout(connection.newSession({
47
- cwd: config.cwd ?? process.cwd(),
48
- mcpServers: []
49
- }), config.probeTimeoutMs, `[narp-stdio] probe timed out creating remote session`);
51
+ return withTimeout(connection.newSession(newSessionParams), config.probeTimeoutMs, `[narp-stdio] probe timed out creating remote session`);
50
52
  })(), spawnErrorPromise]);
51
53
  await connection.cancel({ sessionId: session.sessionId }).catch(() => void 0);
52
54
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-probe.utils.js","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n buildStdioRuntimeLaunchEnv,\n type StdioRuntimeResolvedConfig,\n} from \"./stdio-runtime-config.utils.js\";\nimport { buildSpawnFailureMessage } from \"./stdio-runtime-error.utils.js\";\n\ntype ProbeClientBridge = {\n sessionUpdate: (params: { sessionId: string; update: unknown }) => Promise<void>;\n requestPermission: () => Promise<{ outcome: { outcome: \"cancelled\" } }>;\n readTextFile: () => Promise<{ content: string }>;\n writeTextFile: () => Promise<Record<string, never>>;\n};\n\nconst createProbeClientBridge = (): ProbeClientBridge => ({\n sessionUpdate: async () => undefined,\n requestPermission: async () => ({ outcome: { outcome: \"cancelled\" } }),\n readTextFile: async () => ({ content: \"\" }),\n writeTextFile: async () => ({}),\n});\n\nexport async function probeStdioRuntime(config: StdioRuntimeResolvedConfig): Promise<void> {\n const child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: buildStdioRuntimeLaunchEnv({\n configEnv: config.env,\n }),\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.once(\"error\", (error) => {\n reject(new Error(buildSpawnFailureMessage({ command: config.command, cwd: config.cwd, error })));\n });\n });\n\n let stderr = \"\";\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderr = `${stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(child.stdin),\n Readable.toWeb(child.stdout),\n );\n const connection = new acp.ClientSideConnection(\n () => createProbeClientBridge(),\n stream,\n );\n\n try {\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n connection.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out initializing stdio runtime`,\n );\n return withTimeout(\n connection.newSession({\n cwd: config.cwd ?? process.cwd(),\n mcpServers: [],\n }),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out creating remote session`,\n );\n })(),\n spawnErrorPromise,\n ]);\n await connection.cancel({ sessionId: session.sessionId }).catch(() => undefined);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"[narp-stdio] stdio runtime probe failed\";\n throw new Error(`${message}. stderr=${stderr}`.trim());\n } finally {\n child.kill(\"SIGTERM\");\n }\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: NodeJS.Timeout | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":";;;;;;AAgBA,MAAM,iCAAoD;CACxD,eAAe,YAAY,KAAA;CAC3B,mBAAmB,aAAa,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE;CACrE,cAAc,aAAa,EAAE,SAAS,IAAI;CAC1C,eAAe,aAAa,EAAE;CAC/B;AAED,eAAsB,kBAAkB,QAAmD;CACzF,MAAM,QAAQ,MAAM,OAAO,SAAS,OAAO,MAAM;EAC/C,KAAK,OAAO;EACZ,KAAK,2BAA2B,EAC9B,WAAW,OAAO,KACnB,CAAC;EACF,OAAO;GAAC;GAAQ;GAAQ;GAAO;EAAE,aAAa;EAC/C,CAAC;CACF,MAAM,oBAAoB,IAAI,SAAgB,GAAG,WAAW;AAC1D,QAAM,KAAK,UAAU,UAAU;AAC7B,UAAO,IAAI,MAAM,yBAAyB;IAAE,SAAS,OAAO;IAAS,KAAK,OAAO;IAAK;IAAO,CAAC,CAAC,CAAC;IAChG;GACF;CAEF,IAAI,SAAS;AACb,OAAM,OAAO,YAAY,OAAO;AAChC,OAAM,OAAO,GAAG,SAAS,UAAkB;AACzC,WAAS,GAAG,SAAS,QAAQ,MAAM,KAAM;GACzC;CAEF,MAAM,SAAS,IAAI,aACjB,SAAS,MAAM,MAAM,MAAM,EAC3B,SAAS,MAAM,MAAM,OAAO,CAC7B;CACD,MAAM,aAAa,IAAI,IAAI,2BACnB,yBAAyB,EAC/B,OACD;AAED,KAAI;EACF,MAAM,UAAU,MAAM,QAAQ,KAAK,EAChC,YAAY;AACX,SAAM,YACJ,WAAW,WAAW;IACpB,iBAAiB,IAAI;IACrB,oBAAoB,EAAE;IACvB,CAAC,EACF,OAAO,gBACP,0DACD;AACD,UAAO,YACL,WAAW,WAAW;IACpB,KAAK,OAAO,OAAO,QAAQ,KAAK;IAChC,YAAY,EAAE;IACf,CAAC,EACF,OAAO,gBACP,uDACD;MACC,EACJ,kBACD,CAAC;AACF,QAAM,WAAW,OAAO,EAAE,WAAW,QAAQ,WAAW,CAAC,CAAC,YAAY,KAAA,EAAU;UACzE,OAAO;EACd,MAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,QAAM,IAAI,MAAM,GAAG,QAAQ,WAAW,SAAS,MAAM,CAAC;WAC9C;AACR,QAAM,KAAK,UAAU;;;AAIzB,eAAe,YACb,SACA,WACA,SACY;CACZ,IAAI;CACJ,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;AACvD,kBAAgB,iBAAiB,OAAO,IAAI,MAAM,QAAQ,CAAC,EAAE,UAAU;GACvE;AACF,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,eAAe,CAAC;WAC5C;AACR,MAAI,cACF,cAAa,cAAc"}
1
+ {"version":3,"file":"stdio-runtime-probe.utils.js","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { tmpdir } from \"node:os\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n buildStdioRuntimeLaunchEnv,\n type StdioRuntimeResolvedConfig,\n} from \"./stdio-runtime-config.utils.js\";\nimport { buildSpawnFailureMessage } from \"./stdio-runtime-error.utils.js\";\n\ntype ProbeClientBridge = {\n sessionUpdate: (params: { sessionId: string; update: unknown }) => Promise<void>;\n requestPermission: () => Promise<{ outcome: { outcome: \"cancelled\" } }>;\n readTextFile: () => Promise<{ content: string }>;\n writeTextFile: () => Promise<Record<string, never>>;\n};\n\nconst createProbeClientBridge = (): ProbeClientBridge => ({\n sessionUpdate: async () => undefined,\n requestPermission: async () => ({ outcome: { outcome: \"cancelled\" } }),\n readTextFile: async () => ({ content: \"\" }),\n writeTextFile: async () => ({}),\n});\n\nexport async function probeStdioRuntime(config: StdioRuntimeResolvedConfig): Promise<void> {\n const child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: buildStdioRuntimeLaunchEnv({\n configEnv: config.env,\n }),\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.once(\"error\", (error) => {\n reject(new Error(buildSpawnFailureMessage({ command: config.command, cwd: config.cwd, error })));\n });\n });\n\n let stderr = \"\";\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderr = `${stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(child.stdin),\n Readable.toWeb(child.stdout),\n );\n const connection = new acp.ClientSideConnection(\n () => createProbeClientBridge(),\n stream,\n );\n const newSessionParams = {\n cwd: config.cwd ?? tmpdir(),\n mcpServers: [],\n };\n\n try {\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n connection.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out initializing stdio runtime`,\n );\n return withTimeout(\n connection.newSession(newSessionParams),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out creating remote session`,\n );\n })(),\n spawnErrorPromise,\n ]);\n await connection.cancel({ sessionId: session.sessionId }).catch(() => undefined);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"[narp-stdio] stdio runtime probe failed\";\n throw new Error(`${message}. stderr=${stderr}`.trim());\n } finally {\n child.kill(\"SIGTERM\");\n }\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: NodeJS.Timeout | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,iCAAoD;CACxD,eAAe,YAAY,KAAA;CAC3B,mBAAmB,aAAa,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE;CACrE,cAAc,aAAa,EAAE,SAAS,IAAI;CAC1C,eAAe,aAAa,EAAE;CAC/B;AAED,eAAsB,kBAAkB,QAAmD;CACzF,MAAM,QAAQ,MAAM,OAAO,SAAS,OAAO,MAAM;EAC/C,KAAK,OAAO;EACZ,KAAK,2BAA2B,EAC9B,WAAW,OAAO,KACnB,CAAC;EACF,OAAO;GAAC;GAAQ;GAAQ;GAAO;EAAE,aAAa;EAC/C,CAAC;CACF,MAAM,oBAAoB,IAAI,SAAgB,GAAG,WAAW;AAC1D,QAAM,KAAK,UAAU,UAAU;AAC7B,UAAO,IAAI,MAAM,yBAAyB;IAAE,SAAS,OAAO;IAAS,KAAK,OAAO;IAAK;IAAO,CAAC,CAAC,CAAC;IAChG;GACF;CAEF,IAAI,SAAS;AACb,OAAM,OAAO,YAAY,OAAO;AAChC,OAAM,OAAO,GAAG,SAAS,UAAkB;AACzC,WAAS,GAAG,SAAS,QAAQ,MAAM,KAAM;GACzC;CAEF,MAAM,SAAS,IAAI,aACjB,SAAS,MAAM,MAAM,MAAM,EAC3B,SAAS,MAAM,MAAM,OAAO,CAC7B;CACD,MAAM,aAAa,IAAI,IAAI,2BACnB,yBAAyB,EAC/B,OACD;CACD,MAAM,mBAAmB;EACvB,KAAK,OAAO,OAAO,QAAQ;EAC3B,YAAY,EAAE;EACf;AAED,KAAI;EACF,MAAM,UAAU,MAAM,QAAQ,KAAK,EAChC,YAAY;AACX,SAAM,YACJ,WAAW,WAAW;IACpB,iBAAiB,IAAI;IACrB,oBAAoB,EAAE;IACvB,CAAC,EACF,OAAO,gBACP,0DACD;AACD,UAAO,YACL,WAAW,WAAW,iBAAiB,EACvC,OAAO,gBACP,uDACD;MACC,EACJ,kBACD,CAAC;AACF,QAAM,WAAW,OAAO,EAAE,WAAW,QAAQ,WAAW,CAAC,CAAC,YAAY,KAAA,EAAU;UACzE,OAAO;EACd,MAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,QAAM,IAAI,MAAM,GAAG,QAAQ,WAAW,SAAS,MAAM,CAAC;WAC9C;AACR,QAAM,KAAK,UAAU;;;AAIzB,eAAe,YACb,SACA,WACA,SACY;CACZ,IAAI;CACJ,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;AACvD,kBAAgB,iBAAiB,OAAO,IAAI,MAAM,QAAQ,CAAC,EAAE,UAAU;GACvE;AACF,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,eAAe,CAAC;WAC5C;AACR,MAAI,cACF,cAAa,cAAc"}
@@ -3,7 +3,6 @@ import { NcpAgentConversationStateManager, NcpAgentRunInput, NcpAgentRunOptions,
3
3
 
4
4
  //#region src/stdio-runtime.service.d.ts
5
5
  type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {
6
- sessionId: string;
7
6
  stateManager?: NcpAgentConversationStateManager;
8
7
  resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;
9
8
  resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;KA4BY,iCAAA,GAAoC,0BAAA;EAC9C,SAAA;EACA,YAAA,GAAe,gCAAA;EACf,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,aAAA,CAAc,UAAA;EAC1D,oBAAA,IAAwB,KAAA,EAAO,gBAAA,KAAqB,uBAAA;AAAA;AAAA,cA+wBzC,2BAAA,YAAuC,eAAA;EAAA,iBAGrB,MAAA;EAAA,iBAFZ,OAAA;cAEY,MAAA,EAAQ,iCAAA;EAIrC,GAAA,GACE,IAAA,EAAM,2BAAA,EACN,KAAA,EAAO,gBAAA,EACP,OAAA,GAAU,kBAAA,KACT,cAAA,CAAe,gBAAA;EAclB,OAAA,QAAoB,OAAA;AAAA"}
1
+ {"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;KAgCY,iCAAA,GAAoC,0BAAA;EAC9C,YAAA,GAAe,gCAAA;EACf,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,aAAA,CAAc,UAAA;EAC1D,oBAAA,IAAwB,KAAA,EAAO,gBAAA,KAAqB,uBAAA;AAAA;AAAA,cAq0BzC,2BAAA,YAAuC,eAAA;EAAA,iBAGrB,MAAA;EAAA,iBAFZ,OAAA;cAEY,MAAA,EAAQ,iCAAA;EAIrC,GAAA,GACE,IAAA,EAAM,2BAAA,EACN,KAAA,EAAO,gBAAA,EACP,OAAA,GAAU,kBAAA,KACT,cAAA,CAAe,gBAAA;EAelB,OAAA,QAAoB,OAAA;AAAA"}
@@ -1,5 +1,7 @@
1
- import { NARP_STDIO_PROMPT_META_KEY, buildStdioRuntimeLaunchEnv, readString } from "./stdio-runtime-config.utils.js";
1
+ import { NARP_STDIO_PROMPT_META_KEY, buildStdioRuntimeLaunchEnv } from "./stdio-runtime-config.utils.js";
2
2
  import { buildSpawnFailureMessage, isAbortLikeRuntimeError, normalizeRuntimeError } from "./stdio-runtime-error.utils.js";
3
+ import { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents } from "./utils/stdio-runtime-recovery.utils.js";
4
+ import { extractPromptText, resolveModelId } from "./utils/stdio-runtime-input.utils.js";
3
5
  import { resolveToolNameFromAcpUpdate } from "./stdio-runtime-tool-name.utils.js";
4
6
  import { randomUUID } from "node:crypto";
5
7
  import { spawn } from "node:child_process";
@@ -157,16 +159,21 @@ var StdioRuntimeSession = class {
157
159
  connection = null;
158
160
  promptInFlight = false;
159
161
  remoteSessionId = null;
162
+ remoteSessionCwd = null;
160
163
  clientBridge = new StdioRuntimeClientBridge();
161
164
  stderr = "";
162
165
  pendingProviderRoute;
163
- constructor(config, sessionId) {
166
+ constructor(config) {
164
167
  this.config = config;
165
- this.sessionId = sessionId;
166
168
  }
167
169
  ensureStarted = async (params) => {
168
- this.pendingProviderRoute = params?.providerRoute;
169
- if (this.connection && this.remoteSessionId) return;
170
+ const { cwd, providerRoute } = params;
171
+ this.pendingProviderRoute = providerRoute;
172
+ if (this.connection && this.remoteSessionId) {
173
+ if (this.remoteSessionCwd === cwd) return;
174
+ await this.dispose();
175
+ }
176
+ if (!cwd) throw new Error("[narp-stdio] missing execution cwd for stdio runtime session");
170
177
  const env = buildStdioRuntimeLaunchEnv({
171
178
  configEnv: this.config.env,
172
179
  providerRoute: this.pendingProviderRoute
@@ -200,15 +207,16 @@ var StdioRuntimeSession = class {
200
207
  await withTimeout(this.connection?.initialize({
201
208
  protocolVersion: acp.PROTOCOL_VERSION,
202
209
  clientCapabilities: {}
203
- }) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, `[narp-stdio] timed out initializing stdio runtime for session ${this.sessionId}`);
210
+ }) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, "[narp-stdio] timed out initializing stdio runtime");
204
211
  return withTimeout(this.connection?.newSession({
205
- cwd: this.config.cwd ?? process.cwd(),
212
+ cwd,
206
213
  mcpServers: []
207
- }) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, `[narp-stdio] timed out creating remote session for ${this.sessionId}`);
214
+ }) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, "[narp-stdio] timed out creating remote stdio session");
208
215
  })(), spawnErrorPromise])).sessionId;
216
+ this.remoteSessionCwd = cwd;
209
217
  };
210
218
  runPrompt = async (params) => {
211
- const { meta, modelId, onUpdate, signal, text } = params;
219
+ const { meta, modelId, onUpdate, sessionId, signal, text } = params;
212
220
  if (!this.connection || !this.remoteSessionId) throw new Error("[narp-stdio] stdio runtime connection not started");
213
221
  if (this.promptInFlight) throw new Error("[narp-stdio] concurrent prompt is not supported for one stdio session");
214
222
  this.promptInFlight = true;
@@ -231,7 +239,7 @@ var StdioRuntimeSession = class {
231
239
  text
232
240
  }],
233
241
  _meta: { [NARP_STDIO_PROMPT_META_KEY]: meta }
234
- }), this.config.requestTimeoutMs, `[narp-stdio] prompt timed out for session ${this.sessionId}`);
242
+ }), this.config.requestTimeoutMs, `[narp-stdio] prompt timed out for session ${sessionId}`);
235
243
  } finally {
236
244
  releaseAbort();
237
245
  detach();
@@ -259,20 +267,26 @@ var StdioRuntimeSession = class {
259
267
  };
260
268
  };
261
269
  readStderr = () => this.stderr;
270
+ readPromptTimeoutMetadataResetKeys = () => this.config.resetSessionMetadataOnPromptTimeout;
262
271
  dispose = async () => {
263
272
  await this.cancel();
264
273
  const child = this.child;
265
274
  this.connection = null;
266
275
  this.remoteSessionId = null;
276
+ this.remoteSessionCwd = null;
267
277
  this.child = null;
268
278
  if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) return;
279
+ const exited = new Promise((resolve) => {
280
+ child.once("exit", () => resolve());
281
+ child.once("error", () => resolve());
282
+ });
269
283
  const forceKill = setTimeout(() => {
270
284
  child.kill("SIGKILL");
271
285
  }, 3e3);
272
- child.once("exit", () => {
273
- clearTimeout(forceKill);
274
- });
286
+ forceKill.unref();
275
287
  child.kill("SIGTERM");
288
+ await exited;
289
+ clearTimeout(forceKill);
276
290
  };
277
291
  };
278
292
  var StdioRuntimeRunController = class {
@@ -299,6 +313,7 @@ var StdioRuntimeRunController = class {
299
313
  if (!requestMessage) throw new Error("[narp-stdio] runtime.run requires at least one input message");
300
314
  const assistantMessageId = createAssistantMessageId(requestMessage.id);
301
315
  const promptPromise = this.session.runPrompt({
316
+ sessionId: this.input.sessionId,
302
317
  text: extractPromptText(requestMessage),
303
318
  meta: {
304
319
  ...this.input.correlationId ? { correlationId: this.input.correlationId } : {},
@@ -318,6 +333,7 @@ var StdioRuntimeRunController = class {
318
333
  try {
319
334
  yield* this.drainPromptUpdates(assistantMessageId, promptState);
320
335
  if (this.shouldExitForAbort(options, promptState.error)) return;
336
+ if (promptState.error) throw promptState.error;
321
337
  yield* this.emitCompletionEvents(assistantMessageId);
322
338
  } catch (error) {
323
339
  if (this.shouldExitForAbort(options, error)) return;
@@ -395,7 +411,15 @@ var StdioRuntimeRunController = class {
395
411
  });
396
412
  };
397
413
  emitFailureEvents = async function* (assistantMessageId, error) {
398
- const ncpError = normalizeRuntimeError(error);
414
+ const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });
415
+ for (const recoveryEvent of createPromptTimeoutRecoveryEvents({
416
+ correlationId: this.input.correlationId,
417
+ error,
418
+ messageId: assistantMessageId,
419
+ resetKeys: this.session.readPromptTimeoutMetadataResetKeys(),
420
+ runId: this.runId,
421
+ sessionId: this.input.sessionId
422
+ })) yield* this.emitEvent(recoveryEvent);
399
423
  yield* this.emitEvent({
400
424
  type: NcpEventType.MessageFailed,
401
425
  payload: {
@@ -426,9 +450,27 @@ var StdioRuntimeRunController = class {
426
450
  case "agent_thought_chunk": return this.emitReasoningDelta(update.content, messageId);
427
451
  case "tool_call": return this.emitToolCallStart(update, messageId);
428
452
  case "tool_call_update": return this.emitToolCallUpdate(update);
453
+ case "session_info_update": return this.emitSessionInfoUpdate(update, messageId);
429
454
  default: return [];
430
455
  }
431
456
  };
457
+ emitSessionInfoUpdate = (update, messageId) => {
458
+ const patch = readSessionMetadataPatch(update._meta);
459
+ if (!patch) return [];
460
+ return [{
461
+ type: NcpEventType.RunMetadata,
462
+ payload: {
463
+ sessionId: this.input.sessionId,
464
+ messageId,
465
+ runId: this.runId,
466
+ ...this.input.correlationId ? { correlationId: this.input.correlationId } : {},
467
+ metadata: {
468
+ kind: SESSION_METADATA_PATCH_KIND,
469
+ sessionMetadataPatch: patch
470
+ }
471
+ }
472
+ }];
473
+ };
432
474
  emitTextDelta = (content, messageId) => this.emitContentDelta({
433
475
  content,
434
476
  messageId,
@@ -577,26 +619,26 @@ var StdioRuntimeNcpAgentRuntime = class {
577
619
  session;
578
620
  constructor(config) {
579
621
  this.config = config;
580
- this.session = new StdioRuntimeSession(config, config.sessionId);
622
+ this.session = new StdioRuntimeSession(config);
581
623
  }
582
624
  run = async function* (input, options) {
583
- await this.session.ensureStarted({ providerRoute: this.config.resolveProviderRoute?.(input) });
625
+ await this.session.ensureStarted({
626
+ cwd: input.executionContext?.cwd,
627
+ providerRoute: this.config.resolveProviderRoute?.(input)
628
+ });
584
629
  yield* new StdioRuntimeRunController(this.session, input, this.config.stateManager, this.config.resolveTools, this.config.resolveProviderRoute).execute(options);
585
630
  };
586
631
  dispose = async () => {
587
632
  await this.session.dispose();
588
633
  };
589
634
  };
590
- function extractPromptText(message) {
591
- const text = (message.parts ?? []).map((part) => {
592
- if (part.type === "text" || part.type === "reasoning" || part.type === "rich-text") return part.text ?? "";
593
- return "";
594
- }).join("\n").trim();
595
- return text.length > 0 ? text : "[empty message]";
635
+ function readSessionMetadataPatch(meta) {
636
+ const narpMeta = isRecord(meta) ? meta[NARP_STDIO_PROMPT_META_KEY] : void 0;
637
+ const patch = isRecord(narpMeta) ? narpMeta.sessionMetadataPatch : void 0;
638
+ return isRecord(patch) && Object.keys(patch).length > 0 ? structuredClone(patch) : null;
596
639
  }
597
- function resolveModelId(params) {
598
- const { metadata, providerRoute } = params;
599
- return providerRoute?.model ?? readString(metadata?.preferred_model) ?? readString(metadata?.preferredModel) ?? readString(metadata?.model);
640
+ function isRecord(value) {
641
+ return typeof value === "object" && value !== null && !Array.isArray(value);
600
642
  }
601
643
  function resolveToolName(update) {
602
644
  return resolveToolNameFromAcpUpdate(update);
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime.service.js","names":[],"sources":["../src/stdio-runtime.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport type {\n NcpAgentConversationStateManager,\n NcpAgentRunInput,\n NcpAgentRunOptions,\n NcpAgentRuntime,\n NcpEndpointEvent,\n NcpProviderRuntimeRoute,\n OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { NcpEventType } from \"@nextclaw/ncp\";\nimport type { StdioRuntimeResolvedConfig, NarpStdioPromptMeta } from \"./stdio-runtime-config.utils.js\";\nimport {\n NARP_STDIO_PROMPT_META_KEY,\n buildStdioRuntimeLaunchEnv,\n readString,\n} from \"./stdio-runtime-config.utils.js\";\nimport {\n buildSpawnFailureMessage,\n isAbortLikeRuntimeError,\n normalizeRuntimeError,\n} from \"./stdio-runtime-error.utils.js\";\nimport { resolveToolNameFromAcpUpdate } from \"./stdio-runtime-tool-name.utils.js\";\ntype AcpClientUpdate = acp.SessionUpdate;\nconst HERMES_ACP_ROUTE_BRIDGE_ENV = \"NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE\";\nexport type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {\n sessionId: string;\n stateManager?: NcpAgentConversationStateManager;\n resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;\n resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;\n};\n\ntype AcpToolState = {\n toolName: string;\n args?: string;\n completed: boolean;\n};\n\ntype PromptExecutionState = { settled: boolean; error: unknown };\n\nclass UpdateBuffer {\n private readonly updates: AcpClientUpdate[] = [];\n private waiters = new Set<() => void>();\n\n push = (update: AcpClientUpdate): void => {\n this.updates.push(update);\n this.flush();\n };\n\n shift = (): AcpClientUpdate | undefined => this.updates.shift();\n\n hasItems = (): boolean => this.updates.length > 0;\n\n waitForChange = async (): Promise<void> => {\n if (this.updates.length > 0) {\n return;\n }\n await new Promise<void>((resolve) => {\n this.waiters.add(resolve);\n });\n };\n\n notify = (): void => {\n this.flush();\n };\n\n private flush = (): void => {\n if (this.waiters.size === 0) {\n return;\n }\n const waiters = [...this.waiters];\n this.waiters.clear();\n for (const waiter of waiters) {\n waiter();\n }\n };\n}\n\nclass PromptUpdateCollector {\n private readonly parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"tool-invocation\"; toolCallId: string; toolName: string; state: \"partial-call\" | \"call\"; args: string }\n > = [];\n private readonly toolIndex = new Map<string, number>();\n\n apply = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendPart(\"text\", event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendPart(\"reasoning\", event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n args: \"\",\n state: \"partial-call\",\n });\n return;\n case NcpEventType.MessageToolCallArgs:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: event.payload.args,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: `${tool.args}${event.payload.delta}`,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallEnd:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n state: \"call\",\n });\n }\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): Array<Record<string, unknown>> => structuredClone(this.parts);\n\n private appendPart = (type: \"text\" | \"reasoning\", text: string): void => {\n if (!text) {\n return;\n }\n const last = this.parts.at(-1);\n if (last?.type === type) {\n last.text = `${last.text}${text}`;\n return;\n }\n this.parts.push({ type, text });\n };\n\n private upsertTool = (nextTool: {\n toolCallId: string;\n toolName: string;\n args: string;\n state: \"partial-call\" | \"call\";\n }): void => {\n const existingIndex = this.toolIndex.get(nextTool.toolCallId);\n if (typeof existingIndex === \"number\") {\n const existing = this.parts[existingIndex];\n if (existing?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existing,\n ...nextTool,\n };\n return;\n }\n\n this.toolIndex.set(nextTool.toolCallId, this.parts.length);\n this.parts.push({\n type: \"tool-invocation\",\n ...nextTool,\n });\n };\n\n private readTool = (toolCallId: string): { toolName: string; args: string } => {\n const index = this.toolIndex.get(toolCallId);\n const part = typeof index === \"number\" ? this.parts[index] : null;\n if (part?.type !== \"tool-invocation\") {\n return { toolName: \"unknown\", args: \"\" };\n }\n return { toolName: part.toolName, args: part.args };\n };\n}\n\nclass StdioRuntimeClientBridge {\n private activeSessionId: string | null = null;\n private updateHandler: ((update: AcpClientUpdate) => void) | null = null;\n\n attach = (params: {\n sessionId: string;\n onUpdate: (update: AcpClientUpdate) => void;\n }): (() => void) => {\n this.activeSessionId = params.sessionId;\n this.updateHandler = params.onUpdate;\n return () => {\n if (this.activeSessionId !== params.sessionId) {\n return;\n }\n this.activeSessionId = null;\n this.updateHandler = null;\n };\n };\n\n sessionUpdate = async (params: { sessionId: string; update: AcpClientUpdate }): Promise<void> => {\n if (params.sessionId !== this.activeSessionId) {\n return;\n }\n this.updateHandler?.(params.update);\n };\n\n requestPermission = async (): Promise<{\n outcome: { outcome: \"cancelled\" };\n }> => ({\n outcome: { outcome: \"cancelled\" },\n });\n\n readTextFile = async (): Promise<{ content: string }> => ({ content: \"\" });\n\n writeTextFile = async (): Promise<Record<string, never>> => ({});\n}\n\nclass StdioRuntimeSession {\n private child: ChildProcessWithoutNullStreams | null = null;\n private connection: acp.ClientSideConnection | null = null;\n private promptInFlight = false;\n private remoteSessionId: string | null = null;\n private readonly clientBridge = new StdioRuntimeClientBridge();\n private stderr = \"\";\n private pendingProviderRoute: NcpProviderRuntimeRoute | undefined;\n\n constructor(\n private readonly config: StdioRuntimeResolvedConfig,\n private readonly sessionId: string,\n ) {}\n\n ensureStarted = async (params?: {\n providerRoute?: NcpProviderRuntimeRoute;\n }): Promise<void> => {\n this.pendingProviderRoute = params?.providerRoute;\n if (this.connection && this.remoteSessionId) {\n return;\n }\n\n const env = buildStdioRuntimeLaunchEnv({\n configEnv: this.config.env,\n providerRoute: this.pendingProviderRoute,\n });\n\n this.child = spawn(this.config.command, this.config.args, {\n cwd: this.config.cwd,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n this.child?.once(\"error\", (error) => {\n reject(\n new Error(\n buildSpawnFailureMessage({\n command: this.config.command,\n cwd: this.config.cwd,\n error,\n }),\n ),\n );\n });\n });\n this.child.stderr.setEncoding(\"utf8\");\n this.child.stderr.on(\"data\", (chunk: string) => {\n this.stderr = `${this.stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(this.child.stdin),\n Readable.toWeb(this.child.stdout),\n );\n this.connection = new acp.ClientSideConnection(() => this.clientBridge, stream);\n\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n this.connection?.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n `[narp-stdio] timed out initializing stdio runtime for session ${this.sessionId}`,\n );\n\n return withTimeout(\n this.connection?.newSession({\n cwd: this.config.cwd ?? process.cwd(),\n mcpServers: [],\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n `[narp-stdio] timed out creating remote session for ${this.sessionId}`,\n );\n })(),\n spawnErrorPromise,\n ]);\n this.remoteSessionId = session.sessionId;\n };\n\n runPrompt = async (params: {\n text: string;\n meta: NarpStdioPromptMeta;\n modelId?: string;\n signal?: AbortSignal;\n onUpdate: (update: AcpClientUpdate) => void;\n }): Promise<acp.PromptResponse> => {\n const { meta, modelId, onUpdate, signal, text } = params;\n if (!this.connection || !this.remoteSessionId) {\n throw new Error(\"[narp-stdio] stdio runtime connection not started\");\n }\n if (this.promptInFlight) {\n throw new Error(\"[narp-stdio] concurrent prompt is not supported for one stdio session\");\n }\n\n this.promptInFlight = true;\n const detach = this.clientBridge.attach({\n sessionId: this.remoteSessionId,\n onUpdate,\n });\n const releaseAbort = this.bindAbortSignal(signal);\n\n try {\n if (modelId && this.config.env?.[HERMES_ACP_ROUTE_BRIDGE_ENV] !== \"1\") {\n try {\n // Hermes ACP must switch on prompt-scoped providerRoute, not modelId alone.\n await this.connection.unstable_setSessionModel({\n sessionId: this.remoteSessionId,\n modelId,\n });\n } catch {\n // Not all ACP agents implement unstable session model switching.\n }\n }\n\n return await withTimeout(\n this.connection.prompt({\n sessionId: this.remoteSessionId,\n prompt: [{ type: \"text\", text }],\n _meta: {\n [NARP_STDIO_PROMPT_META_KEY]: meta,\n },\n }),\n this.config.requestTimeoutMs,\n `[narp-stdio] prompt timed out for session ${this.sessionId}`,\n );\n } finally {\n releaseAbort();\n detach();\n this.promptInFlight = false;\n }\n };\n\n cancel = async (): Promise<void> => {\n if (!this.connection || !this.remoteSessionId) {\n return;\n }\n try {\n await this.connection.cancel({\n sessionId: this.remoteSessionId,\n });\n } catch {\n // Best effort.\n }\n };\n\n private bindAbortSignal = (signal?: AbortSignal): (() => void) => {\n if (!signal) {\n return () => undefined;\n }\n\n const onAbort = (): void => {\n void this.cancel();\n };\n\n if (signal.aborted) {\n onAbort();\n return () => undefined;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n return () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n };\n\n readStderr = (): string => this.stderr;\n\n dispose = async (): Promise<void> => {\n await this.cancel();\n const child = this.child;\n this.connection = null;\n this.remoteSessionId = null;\n this.child = null;\n if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) {\n return;\n }\n\n const forceKill = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, 3_000);\n child.once(\"exit\", () => {\n clearTimeout(forceKill);\n });\n child.kill(\"SIGTERM\");\n };\n}\n\nclass StdioRuntimeRunController {\n private readonly buffer = new UpdateBuffer();\n private readonly collector = new PromptUpdateCollector();\n private readonly toolStates = new Map<string, AcpToolState>();\n private textStarted = false;\n private reasoningStarted = false;\n private readonly resolvedTools: ReadonlyArray<OpenAITool>;\n private readonly resolvedProviderRoute: NcpProviderRuntimeRoute | undefined;\n private readonly runId: string;\n\n constructor(\n private readonly session: StdioRuntimeSession,\n private readonly input: NcpAgentRunInput,\n private readonly stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\n this.resolvedTools = resolveTools?.(input) ?? [];\n this.resolvedProviderRoute = resolveProviderRoute?.(input);\n this.runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? `narp-stdio:${input.sessionId}:${randomUUID()}`;\n }\n execute = async function* (\n this: StdioRuntimeRunController,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const requestMessage = this.input.messages.at(-1);\n if (!requestMessage) {\n throw new Error(\"[narp-stdio] runtime.run requires at least one input message\");\n }\n\n const assistantMessageId = createAssistantMessageId(requestMessage.id);\n const promptPromise = this.session.runPrompt({\n text: extractPromptText(requestMessage),\n meta: {\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n ...(this.resolvedProviderRoute ? { providerRoute: this.resolvedProviderRoute } : {}),\n ...(this.input.metadata ? { sessionMetadata: this.input.metadata } : {}),\n ...(this.resolvedTools.length > 0 ? { tools: this.resolvedTools } : {}),\n },\n modelId: resolveModelId({\n providerRoute: this.resolvedProviderRoute,\n metadata: this.input.metadata,\n }),\n signal: options?.signal,\n onUpdate: (update) => this.buffer.push(update),\n });\n const promptState = this.trackPromptState(promptPromise);\n\n yield* this.emitRunStartedEvents(assistantMessageId);\n\n try {\n yield* this.drainPromptUpdates(assistantMessageId, promptState);\n if (this.shouldExitForAbort(options, promptState.error)) {\n return;\n }\n yield* this.emitCompletionEvents(assistantMessageId);\n } catch (error) {\n if (this.shouldExitForAbort(options, error)) {\n return;\n }\n yield* this.emitFailureEvents(assistantMessageId, error);\n }\n };\n private trackPromptState = (\n promptPromise: Promise<acp.PromptResponse>,\n ): PromptExecutionState => {\n const promptState: PromptExecutionState = {\n settled: false,\n error: null,\n };\n\n promptPromise\n .then(() => {\n promptState.settled = true;\n this.buffer.notify();\n })\n .catch((error) => {\n promptState.settled = true;\n promptState.error = error;\n this.buffer.notify();\n });\n\n return promptState;\n };\n private emitRunStartedEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: assistantMessageId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunStarted,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private drainPromptUpdates = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n promptState: PromptExecutionState,\n ): AsyncGenerator<NcpEndpointEvent> {\n while (!promptState.settled || this.buffer.hasItems()) {\n const update = this.buffer.shift();\n if (!update) {\n await this.buffer.waitForChange();\n continue;\n }\n for (const event of this.translateUpdate(update, assistantMessageId)) {\n yield* this.emitEvent(event);\n }\n }\n };\n private shouldExitForAbort = (\n options: NcpAgentRunOptions | undefined,\n error: unknown,\n ): boolean => options?.signal?.aborted === true || isAbortLikeRuntimeError(error);\n private emitCompletionEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n for (const terminalEvent of this.createTerminalEvents(assistantMessageId)) {\n yield* this.emitEvent(terminalEvent);\n }\n\n if (!this.collector.hasParts()) {\n throw new Error(\n `[narp-stdio] ACP prompt completed without any assistant content for session ${this.input.sessionId}. stderr=${this.session.readStderr()}`,\n );\n }\n\n yield* this.emitEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId: this.input.sessionId,\n correlationId: this.input.correlationId,\n message: {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: this.collector.buildParts() as never,\n timestamp: new Date().toISOString(),\n },\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunFinished,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private emitFailureEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n error: unknown,\n ): AsyncGenerator<NcpEndpointEvent> {\n const ncpError = normalizeRuntimeError(error);\n yield* this.emitEvent({\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n correlationId: this.input.correlationId,\n error: ncpError,\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunError,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n error: ncpError.message,\n },\n });\n };\n private emitEvent = async function* (\n this: StdioRuntimeRunController,\n event: NcpEndpointEvent,\n ): AsyncGenerator<NcpEndpointEvent> {\n this.collector.apply(event);\n await this.stateManager?.dispatch(event);\n yield event;\n };\n private translateUpdate = (\n update: AcpClientUpdate,\n messageId: string,\n ): NcpEndpointEvent[] => {\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return this.emitTextDelta(update.content, messageId);\n case \"agent_thought_chunk\":\n return this.emitReasoningDelta(update.content, messageId);\n case \"tool_call\":\n return this.emitToolCallStart(update, messageId);\n case \"tool_call_update\":\n return this.emitToolCallUpdate(update);\n default:\n return [];\n }\n };\n\n private emitTextDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.textStarted,\n markStarted: () => {\n this.textStarted = true;\n },\n startType: NcpEventType.MessageTextStart,\n deltaType: NcpEventType.MessageTextDelta,\n });\n\n private emitReasoningDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.reasoningStarted,\n markStarted: () => {\n this.reasoningStarted = true;\n },\n startType: NcpEventType.MessageReasoningStart,\n deltaType: NcpEventType.MessageReasoningDelta,\n });\n\n private emitContentDelta = (params: {\n content: { type: string; text?: string };\n messageId: string;\n started: boolean;\n markStarted: () => void;\n startType: NcpEventType.MessageTextStart | NcpEventType.MessageReasoningStart;\n deltaType: NcpEventType.MessageTextDelta | NcpEventType.MessageReasoningDelta;\n }): NcpEndpointEvent[] => {\n const { content, deltaType, markStarted, messageId, started, startType } = params;\n if (content.type !== \"text\" || !content.text) {\n return [];\n }\n const events: NcpEndpointEvent[] = [];\n if (!started) {\n markStarted();\n events.push({\n type: startType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n }\n events.push({\n type: deltaType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n delta: content.text,\n },\n });\n return events;\n };\n\n private emitToolCallStart = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const toolName = resolveToolName(update);\n const args = serializeToolArgs(update.rawInput);\n this.toolStates.set(update.toolCallId, {\n toolName,\n args,\n completed: false,\n });\n return [\n {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n toolCallId: update.toolCallId,\n toolName,\n },\n },\n {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args,\n },\n },\n ];\n };\n\n private emitToolCallUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call_update\" }>,\n ): NcpEndpointEvent[] => {\n const existing = this.toolStates.get(update.toolCallId);\n if (!existing) {\n return [];\n }\n\n const nextArgs = serializeToolArgs(update.rawInput);\n const argsChanged = typeof update.rawInput !== \"undefined\" && nextArgs !== existing.args;\n const events: NcpEndpointEvent[] = [];\n if (argsChanged) {\n existing.args = nextArgs;\n events.push({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args: nextArgs,\n },\n });\n }\n\n if (update.status === \"completed\" || update.status === \"failed\") {\n if (!existing.completed) {\n existing.completed = true;\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n },\n });\n }\n if (typeof update.rawOutput !== \"undefined\") {\n events.push({\n type: NcpEventType.MessageToolCallResult,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n content: update.rawOutput,\n },\n });\n }\n }\n return events;\n };\n\n private createTerminalEvents = (messageId: string): NcpEndpointEvent[] => {\n const events: NcpEndpointEvent[] = [];\n if (this.textStarted) {\n events.push({\n type: NcpEventType.MessageTextEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.textStarted = false;\n }\n if (this.reasoningStarted) {\n events.push({\n type: NcpEventType.MessageReasoningEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.reasoningStarted = false;\n }\n for (const [toolCallId, state] of this.toolStates.entries()) {\n if (state.completed) {\n continue;\n }\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId,\n },\n });\n state.completed = true;\n }\n return events;\n };\n}\n\nexport class StdioRuntimeNcpAgentRuntime implements NcpAgentRuntime {\n private readonly session: StdioRuntimeSession;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {\n this.session = new StdioRuntimeSession(config, config.sessionId);\n }\n\n run = async function* (\n this: StdioRuntimeNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.session.ensureStarted({\n providerRoute: this.config.resolveProviderRoute?.(input),\n });\n const controller = new StdioRuntimeRunController(\n this.session,\n input,\n this.config.stateManager,\n this.config.resolveTools,\n this.config.resolveProviderRoute,\n );\n yield* controller.execute(options);\n };\n\n dispose = async (): Promise<void> => {\n await this.session.dispose();\n };\n}\n\nfunction extractPromptText(message: { parts?: Array<{ type: string; text?: string }> }): string {\n const text = (message.parts ?? [])\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text ?? \"\";\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nfunction resolveModelId(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n metadata?: Record<string, unknown>;\n}): string | undefined {\n const { metadata, providerRoute } = params;\n return (\n providerRoute?.model ??\n readString(metadata?.preferred_model) ??\n readString(metadata?.preferredModel) ??\n readString(metadata?.model)\n );\n}\nfunction resolveToolName(\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n): string {\n return resolveToolNameFromAcpUpdate(update);\n}\n\nfunction createAssistantMessageId(requestMessageId: string): string {\n const normalizedRequestId = requestMessageId.trim() || \"request\";\n return `assistant:${normalizedRequestId}:${randomUUID()}`;\n}\n\nfunction serializeToolArgs(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"undefined\") {\n return \"{}\";\n }\n return JSON.stringify(value);\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n try {\n return await Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(new Error(message));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stdio-runtime.service.js","names":[],"sources":["../src/stdio-runtime.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n NcpEventType,\n type NcpAgentConversationStateManager,\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n type NcpProviderRuntimeRoute,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\nimport type { StdioRuntimeResolvedConfig, NarpStdioPromptMeta } from \"./stdio-runtime-config.utils.js\";\nimport {\n NARP_STDIO_PROMPT_META_KEY,\n buildStdioRuntimeLaunchEnv,\n} from \"./stdio-runtime-config.utils.js\";\nimport {\n buildSpawnFailureMessage,\n isAbortLikeRuntimeError,\n normalizeRuntimeError,\n} from \"./stdio-runtime-error.utils.js\";\nimport {\n createPromptTimeoutRecoveryEvents,\n SESSION_METADATA_PATCH_KIND,\n} from \"./utils/stdio-runtime-recovery.utils.js\";\nimport { extractPromptText, resolveModelId } from \"./utils/stdio-runtime-input.utils.js\";\nimport { resolveToolNameFromAcpUpdate } from \"./stdio-runtime-tool-name.utils.js\";\ntype AcpClientUpdate = acp.SessionUpdate;\nconst HERMES_ACP_ROUTE_BRIDGE_ENV = \"NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE\";\nexport type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {\n stateManager?: NcpAgentConversationStateManager;\n resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;\n resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;\n};\ntype AcpToolState = {\n toolName: string;\n args?: string;\n completed: boolean;\n};\n\ntype PromptExecutionState = { settled: boolean; error: unknown };\n\nclass UpdateBuffer {\n private readonly updates: AcpClientUpdate[] = [];\n private waiters = new Set<() => void>();\n\n push = (update: AcpClientUpdate): void => {\n this.updates.push(update);\n this.flush();\n };\n\n shift = (): AcpClientUpdate | undefined => this.updates.shift();\n\n hasItems = (): boolean => this.updates.length > 0;\n\n waitForChange = async (): Promise<void> => {\n if (this.updates.length > 0) {\n return;\n }\n await new Promise<void>((resolve) => {\n this.waiters.add(resolve);\n });\n };\n\n notify = (): void => {\n this.flush();\n };\n\n private flush = (): void => {\n if (this.waiters.size === 0) {\n return;\n }\n const waiters = [...this.waiters];\n this.waiters.clear();\n for (const waiter of waiters) {\n waiter();\n }\n };\n}\n\nclass PromptUpdateCollector {\n private readonly parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"tool-invocation\"; toolCallId: string; toolName: string; state: \"partial-call\" | \"call\"; args: string }\n > = [];\n private readonly toolIndex = new Map<string, number>();\n\n apply = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendPart(\"text\", event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendPart(\"reasoning\", event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n args: \"\",\n state: \"partial-call\",\n });\n return;\n case NcpEventType.MessageToolCallArgs:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: event.payload.args,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: `${tool.args}${event.payload.delta}`,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallEnd:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n state: \"call\",\n });\n }\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): Array<Record<string, unknown>> => structuredClone(this.parts);\n\n private appendPart = (type: \"text\" | \"reasoning\", text: string): void => {\n if (!text) {\n return;\n }\n const last = this.parts.at(-1);\n if (last?.type === type) {\n last.text = `${last.text}${text}`;\n return;\n }\n this.parts.push({ type, text });\n };\n\n private upsertTool = (nextTool: {\n toolCallId: string;\n toolName: string;\n args: string;\n state: \"partial-call\" | \"call\";\n }): void => {\n const existingIndex = this.toolIndex.get(nextTool.toolCallId);\n if (typeof existingIndex === \"number\") {\n const existing = this.parts[existingIndex];\n if (existing?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existing,\n ...nextTool,\n };\n return;\n }\n\n this.toolIndex.set(nextTool.toolCallId, this.parts.length);\n this.parts.push({\n type: \"tool-invocation\",\n ...nextTool,\n });\n };\n\n private readTool = (toolCallId: string): { toolName: string; args: string } => {\n const index = this.toolIndex.get(toolCallId);\n const part = typeof index === \"number\" ? this.parts[index] : null;\n if (part?.type !== \"tool-invocation\") {\n return { toolName: \"unknown\", args: \"\" };\n }\n return { toolName: part.toolName, args: part.args };\n };\n}\n\nclass StdioRuntimeClientBridge {\n private activeSessionId: string | null = null;\n private updateHandler: ((update: AcpClientUpdate) => void) | null = null;\n\n attach = (params: {\n sessionId: string;\n onUpdate: (update: AcpClientUpdate) => void;\n }): (() => void) => {\n this.activeSessionId = params.sessionId;\n this.updateHandler = params.onUpdate;\n return () => {\n if (this.activeSessionId !== params.sessionId) {\n return;\n }\n this.activeSessionId = null;\n this.updateHandler = null;\n };\n };\n\n sessionUpdate = async (params: { sessionId: string; update: AcpClientUpdate }): Promise<void> => {\n if (params.sessionId !== this.activeSessionId) {\n return;\n }\n this.updateHandler?.(params.update);\n };\n\n requestPermission = async (): Promise<{\n outcome: { outcome: \"cancelled\" };\n }> => ({\n outcome: { outcome: \"cancelled\" },\n });\n\n readTextFile = async (): Promise<{ content: string }> => ({ content: \"\" });\n\n writeTextFile = async (): Promise<Record<string, never>> => ({});\n}\n\nclass StdioRuntimeSession {\n private child: ChildProcessWithoutNullStreams | null = null;\n private connection: acp.ClientSideConnection | null = null;\n private promptInFlight = false;\n private remoteSessionId: string | null = null;\n private remoteSessionCwd: string | null = null;\n private readonly clientBridge = new StdioRuntimeClientBridge();\n private stderr = \"\";\n private pendingProviderRoute: NcpProviderRuntimeRoute | undefined;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {}\n\n ensureStarted = async (params: {\n cwd?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n }): Promise<void> => {\n const { cwd, providerRoute } = params;\n this.pendingProviderRoute = providerRoute;\n if (this.connection && this.remoteSessionId) {\n if (this.remoteSessionCwd === cwd) {\n return;\n }\n await this.dispose();\n }\n if (!cwd) {\n throw new Error(\"[narp-stdio] missing execution cwd for stdio runtime session\");\n }\n\n const env = buildStdioRuntimeLaunchEnv({\n configEnv: this.config.env,\n providerRoute: this.pendingProviderRoute,\n });\n\n this.child = spawn(this.config.command, this.config.args, {\n cwd: this.config.cwd,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n this.child?.once(\"error\", (error) => {\n reject(\n new Error(\n buildSpawnFailureMessage({\n command: this.config.command,\n cwd: this.config.cwd,\n error,\n }),\n ),\n );\n });\n });\n this.child.stderr.setEncoding(\"utf8\");\n this.child.stderr.on(\"data\", (chunk: string) => {\n this.stderr = `${this.stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(this.child.stdin),\n Readable.toWeb(this.child.stdout),\n );\n this.connection = new acp.ClientSideConnection(() => this.clientBridge, stream);\n\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n this.connection?.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out initializing stdio runtime\",\n );\n\n return withTimeout(\n this.connection?.newSession({\n cwd,\n mcpServers: [],\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out creating remote stdio session\",\n );\n })(),\n spawnErrorPromise,\n ]);\n this.remoteSessionId = session.sessionId;\n this.remoteSessionCwd = cwd;\n };\n\n runPrompt = async (params: {\n sessionId: string;\n text: string;\n meta: NarpStdioPromptMeta;\n modelId?: string;\n signal?: AbortSignal;\n onUpdate: (update: AcpClientUpdate) => void;\n }): Promise<acp.PromptResponse> => {\n const { meta, modelId, onUpdate, sessionId, signal, text } = params;\n if (!this.connection || !this.remoteSessionId) {\n throw new Error(\"[narp-stdio] stdio runtime connection not started\");\n }\n if (this.promptInFlight) {\n throw new Error(\"[narp-stdio] concurrent prompt is not supported for one stdio session\");\n }\n\n this.promptInFlight = true;\n const detach = this.clientBridge.attach({\n sessionId: this.remoteSessionId,\n onUpdate,\n });\n const releaseAbort = this.bindAbortSignal(signal);\n\n try {\n if (modelId && this.config.env?.[HERMES_ACP_ROUTE_BRIDGE_ENV] !== \"1\") {\n try {\n // Hermes ACP must switch on prompt-scoped providerRoute, not modelId alone.\n await this.connection.unstable_setSessionModel({\n sessionId: this.remoteSessionId,\n modelId,\n });\n } catch {\n // Not all ACP agents implement unstable session model switching.\n }\n }\n\n return await withTimeout(\n this.connection.prompt({\n sessionId: this.remoteSessionId,\n prompt: [{ type: \"text\", text }],\n _meta: {\n [NARP_STDIO_PROMPT_META_KEY]: meta,\n },\n }),\n this.config.requestTimeoutMs,\n `[narp-stdio] prompt timed out for session ${sessionId}`,\n );\n } finally {\n releaseAbort();\n detach();\n this.promptInFlight = false;\n }\n };\n\n cancel = async (): Promise<void> => {\n if (!this.connection || !this.remoteSessionId) {\n return;\n }\n try {\n await this.connection.cancel({\n sessionId: this.remoteSessionId,\n });\n } catch {\n // Best effort.\n }\n };\n\n private bindAbortSignal = (signal?: AbortSignal): (() => void) => {\n if (!signal) {\n return () => undefined;\n }\n\n const onAbort = (): void => {\n void this.cancel();\n };\n\n if (signal.aborted) {\n onAbort();\n return () => undefined;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n return () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n };\n\n readStderr = (): string => this.stderr;\n\n readPromptTimeoutMetadataResetKeys = (): readonly string[] | undefined =>\n this.config.resetSessionMetadataOnPromptTimeout;\n\n dispose = async (): Promise<void> => {\n await this.cancel();\n const child = this.child;\n this.connection = null;\n this.remoteSessionId = null;\n this.remoteSessionCwd = null;\n this.child = null;\n if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) {\n return;\n }\n\n const exited = new Promise<void>((resolve) => {\n child.once(\"exit\", () => resolve());\n child.once(\"error\", () => resolve());\n });\n const forceKill = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, 3_000);\n forceKill.unref();\n child.kill(\"SIGTERM\");\n await exited;\n clearTimeout(forceKill);\n };\n}\n\nclass StdioRuntimeRunController {\n private readonly buffer = new UpdateBuffer();\n private readonly collector = new PromptUpdateCollector();\n private readonly toolStates = new Map<string, AcpToolState>();\n private textStarted = false;\n private reasoningStarted = false;\n private readonly resolvedTools: ReadonlyArray<OpenAITool>;\n private readonly resolvedProviderRoute: NcpProviderRuntimeRoute | undefined;\n private readonly runId: string;\n\n constructor(\n private readonly session: StdioRuntimeSession,\n private readonly input: NcpAgentRunInput,\n private readonly stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\n this.resolvedTools = resolveTools?.(input) ?? [];\n this.resolvedProviderRoute = resolveProviderRoute?.(input);\n this.runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? `narp-stdio:${input.sessionId}:${randomUUID()}`;\n }\n execute = async function* (\n this: StdioRuntimeRunController,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const requestMessage = this.input.messages.at(-1);\n if (!requestMessage) {\n throw new Error(\"[narp-stdio] runtime.run requires at least one input message\");\n }\n\n const assistantMessageId = createAssistantMessageId(requestMessage.id);\n const promptPromise = this.session.runPrompt({\n sessionId: this.input.sessionId,\n text: extractPromptText(requestMessage),\n meta: {\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n ...(this.resolvedProviderRoute ? { providerRoute: this.resolvedProviderRoute } : {}),\n ...(this.input.metadata ? { sessionMetadata: this.input.metadata } : {}),\n ...(this.resolvedTools.length > 0 ? { tools: this.resolvedTools } : {}),\n },\n modelId: resolveModelId({\n providerRoute: this.resolvedProviderRoute,\n metadata: this.input.metadata,\n }),\n signal: options?.signal,\n onUpdate: (update) => this.buffer.push(update),\n });\n const promptState = this.trackPromptState(promptPromise);\n\n yield* this.emitRunStartedEvents(assistantMessageId);\n\n try {\n yield* this.drainPromptUpdates(assistantMessageId, promptState);\n if (this.shouldExitForAbort(options, promptState.error)) {\n return;\n }\n if (promptState.error) throw promptState.error;\n yield* this.emitCompletionEvents(assistantMessageId);\n } catch (error) {\n if (this.shouldExitForAbort(options, error)) {\n return;\n }\n yield* this.emitFailureEvents(assistantMessageId, error);\n }\n };\n private trackPromptState = (\n promptPromise: Promise<acp.PromptResponse>,\n ): PromptExecutionState => {\n const promptState: PromptExecutionState = {\n settled: false,\n error: null,\n };\n\n promptPromise\n .then(() => {\n promptState.settled = true;\n this.buffer.notify();\n })\n .catch((error) => {\n promptState.settled = true;\n promptState.error = error;\n this.buffer.notify();\n });\n\n return promptState;\n };\n private emitRunStartedEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: assistantMessageId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunStarted,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private drainPromptUpdates = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n promptState: PromptExecutionState,\n ): AsyncGenerator<NcpEndpointEvent> {\n while (!promptState.settled || this.buffer.hasItems()) {\n const update = this.buffer.shift();\n if (!update) {\n await this.buffer.waitForChange();\n continue;\n }\n for (const event of this.translateUpdate(update, assistantMessageId)) {\n yield* this.emitEvent(event);\n }\n }\n };\n private shouldExitForAbort = (\n options: NcpAgentRunOptions | undefined,\n error: unknown,\n ): boolean => options?.signal?.aborted === true || isAbortLikeRuntimeError(error);\n private emitCompletionEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n for (const terminalEvent of this.createTerminalEvents(assistantMessageId)) {\n yield* this.emitEvent(terminalEvent);\n }\n\n if (!this.collector.hasParts()) {\n throw new Error(\n `[narp-stdio] ACP prompt completed without any assistant content for session ${this.input.sessionId}. stderr=${this.session.readStderr()}`,\n );\n }\n\n yield* this.emitEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId: this.input.sessionId,\n correlationId: this.input.correlationId,\n message: {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: this.collector.buildParts() as never,\n timestamp: new Date().toISOString(),\n },\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunFinished,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private emitFailureEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n error: unknown,\n ): AsyncGenerator<NcpEndpointEvent> {\n const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });\n for (const recoveryEvent of createPromptTimeoutRecoveryEvents({\n correlationId: this.input.correlationId,\n error,\n messageId: assistantMessageId,\n resetKeys: this.session.readPromptTimeoutMetadataResetKeys(),\n runId: this.runId,\n sessionId: this.input.sessionId,\n })) {\n yield* this.emitEvent(recoveryEvent);\n }\n yield* this.emitEvent({\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n correlationId: this.input.correlationId,\n error: ncpError,\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunError,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n error: ncpError.message,\n },\n });\n };\n private emitEvent = async function* (\n this: StdioRuntimeRunController,\n event: NcpEndpointEvent,\n ): AsyncGenerator<NcpEndpointEvent> {\n this.collector.apply(event);\n await this.stateManager?.dispatch(event);\n yield event;\n };\n private translateUpdate = (\n update: AcpClientUpdate,\n messageId: string,\n ): NcpEndpointEvent[] => {\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return this.emitTextDelta(update.content, messageId);\n case \"agent_thought_chunk\":\n return this.emitReasoningDelta(update.content, messageId);\n case \"tool_call\":\n return this.emitToolCallStart(update, messageId);\n case \"tool_call_update\":\n return this.emitToolCallUpdate(update);\n case \"session_info_update\":\n return this.emitSessionInfoUpdate(update, messageId);\n default:\n return [];\n }\n };\n\n private emitSessionInfoUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"session_info_update\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const patch = readSessionMetadataPatch(update._meta);\n if (!patch) {\n return [];\n }\n return [\n {\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n runId: this.runId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: patch,\n },\n },\n },\n ];\n };\n\n private emitTextDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.textStarted,\n markStarted: () => {\n this.textStarted = true;\n },\n startType: NcpEventType.MessageTextStart,\n deltaType: NcpEventType.MessageTextDelta,\n });\n\n private emitReasoningDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.reasoningStarted,\n markStarted: () => {\n this.reasoningStarted = true;\n },\n startType: NcpEventType.MessageReasoningStart,\n deltaType: NcpEventType.MessageReasoningDelta,\n });\n\n private emitContentDelta = (params: {\n content: { type: string; text?: string };\n messageId: string;\n started: boolean;\n markStarted: () => void;\n startType: NcpEventType.MessageTextStart | NcpEventType.MessageReasoningStart;\n deltaType: NcpEventType.MessageTextDelta | NcpEventType.MessageReasoningDelta;\n }): NcpEndpointEvent[] => {\n const { content, deltaType, markStarted, messageId, started, startType } = params;\n if (content.type !== \"text\" || !content.text) {\n return [];\n }\n const events: NcpEndpointEvent[] = [];\n if (!started) {\n markStarted();\n events.push({\n type: startType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n }\n events.push({\n type: deltaType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n delta: content.text,\n },\n });\n return events;\n };\n\n private emitToolCallStart = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const toolName = resolveToolName(update);\n const args = serializeToolArgs(update.rawInput);\n this.toolStates.set(update.toolCallId, {\n toolName,\n args,\n completed: false,\n });\n return [\n {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n toolCallId: update.toolCallId,\n toolName,\n },\n },\n {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args,\n },\n },\n ];\n };\n\n private emitToolCallUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call_update\" }>,\n ): NcpEndpointEvent[] => {\n const existing = this.toolStates.get(update.toolCallId);\n if (!existing) {\n return [];\n }\n\n const nextArgs = serializeToolArgs(update.rawInput);\n const argsChanged = typeof update.rawInput !== \"undefined\" && nextArgs !== existing.args;\n const events: NcpEndpointEvent[] = [];\n if (argsChanged) {\n existing.args = nextArgs;\n events.push({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args: nextArgs,\n },\n });\n }\n\n if (update.status === \"completed\" || update.status === \"failed\") {\n if (!existing.completed) {\n existing.completed = true;\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n },\n });\n }\n if (typeof update.rawOutput !== \"undefined\") {\n events.push({\n type: NcpEventType.MessageToolCallResult,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n content: update.rawOutput,\n },\n });\n }\n }\n return events;\n };\n\n private createTerminalEvents = (messageId: string): NcpEndpointEvent[] => {\n const events: NcpEndpointEvent[] = [];\n if (this.textStarted) {\n events.push({\n type: NcpEventType.MessageTextEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.textStarted = false;\n }\n if (this.reasoningStarted) {\n events.push({\n type: NcpEventType.MessageReasoningEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.reasoningStarted = false;\n }\n for (const [toolCallId, state] of this.toolStates.entries()) {\n if (state.completed) {\n continue;\n }\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId,\n },\n });\n state.completed = true;\n }\n return events;\n };\n}\n\nexport class StdioRuntimeNcpAgentRuntime implements NcpAgentRuntime {\n private readonly session: StdioRuntimeSession;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {\n this.session = new StdioRuntimeSession(config);\n }\n\n run = async function* (\n this: StdioRuntimeNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.session.ensureStarted({\n cwd: input.executionContext?.cwd,\n providerRoute: this.config.resolveProviderRoute?.(input),\n });\n const controller = new StdioRuntimeRunController(\n this.session,\n input,\n this.config.stateManager,\n this.config.resolveTools,\n this.config.resolveProviderRoute,\n );\n yield* controller.execute(options);\n };\n\n dispose = async (): Promise<void> => {\n await this.session.dispose();\n };\n}\n\nfunction readSessionMetadataPatch(meta: unknown): Record<string, unknown> | null {\n const narpMeta = isRecord(meta)\n ? meta[NARP_STDIO_PROMPT_META_KEY]\n : undefined;\n const patch = isRecord(narpMeta)\n ? narpMeta.sessionMetadataPatch\n : undefined;\n return isRecord(patch) && Object.keys(patch).length > 0\n ? structuredClone(patch)\n : null;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction resolveToolName(\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n): string {\n return resolveToolNameFromAcpUpdate(update);\n}\n\nfunction createAssistantMessageId(requestMessageId: string): string {\n const normalizedRequestId = requestMessageId.trim() || \"request\";\n return `assistant:${normalizedRequestId}:${randomUUID()}`;\n}\n\nfunction serializeToolArgs(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"undefined\") {\n return \"{}\";\n }\n return JSON.stringify(value);\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n try {\n return await Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(new Error(message));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { readString } from "../stdio-runtime-config.utils.js";
2
+ //#region src/utils/stdio-runtime-input.utils.ts
3
+ function extractPromptText(message) {
4
+ const text = (message.parts ?? []).map((part) => {
5
+ if (part.type === "text" || part.type === "reasoning" || part.type === "rich-text") return part.text ?? "";
6
+ return "";
7
+ }).join("\n").trim();
8
+ return text.length > 0 ? text : "[empty message]";
9
+ }
10
+ function resolveModelId(params) {
11
+ const { metadata, providerRoute } = params;
12
+ const modelId = providerRoute?.model ?? readString(metadata?.preferred_model) ?? readString(metadata?.preferredModel) ?? readString(metadata?.model);
13
+ return modelId === "__nextclaw_runtime_default__" ? void 0 : modelId;
14
+ }
15
+ //#endregion
16
+ export { extractPromptText, resolveModelId };
17
+
18
+ //# sourceMappingURL=stdio-runtime-input.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-runtime-input.utils.js","names":[],"sources":["../../src/utils/stdio-runtime-input.utils.ts"],"sourcesContent":["import type { NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { readString } from \"../stdio-runtime-config.utils.js\";\n\nexport function extractPromptText(message: { parts?: Array<{ type: string; text?: string }> }): string {\n const text = (message.parts ?? [])\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text ?? \"\";\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nexport function resolveModelId(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n metadata?: Record<string, unknown>;\n}): string | undefined {\n const { metadata, providerRoute } = params;\n const modelId =\n providerRoute?.model ??\n readString(metadata?.preferred_model) ??\n readString(metadata?.preferredModel) ??\n readString(metadata?.model);\n return modelId === \"__nextclaw_runtime_default__\" ? undefined : modelId;\n}\n"],"mappings":";;AAGA,SAAgB,kBAAkB,SAAqE;CACrG,MAAM,QAAQ,QAAQ,SAAS,EAAE,EAC9B,KAAK,SAAS;AACb,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,eAAe,KAAK,SAAS,YACrE,QAAO,KAAK,QAAQ;AAEtB,SAAO;GACP,CACD,KAAK,KAAK,CACV,MAAM;AACT,QAAO,KAAK,SAAS,IAAI,OAAO;;AAGlC,SAAgB,eAAe,QAGR;CACrB,MAAM,EAAE,UAAU,kBAAkB;CACpC,MAAM,UACJ,eAAe,SACf,WAAW,UAAU,gBAAgB,IACrC,WAAW,UAAU,eAAe,IACpC,WAAW,UAAU,MAAM;AAC7B,QAAO,YAAY,iCAAiC,KAAA,IAAY"}
@@ -0,0 +1,27 @@
1
+ import { NcpEventType } from "@nextclaw/ncp";
2
+ //#region src/utils/stdio-runtime-recovery.utils.ts
3
+ const SESSION_METADATA_PATCH_KIND = "session_metadata_patch";
4
+ function createPromptTimeoutRecoveryEvents(params) {
5
+ const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;
6
+ if (!resetKeys?.length || !isPromptTimeoutError(error)) return [];
7
+ return [{
8
+ type: NcpEventType.RunMetadata,
9
+ payload: {
10
+ sessionId,
11
+ messageId,
12
+ runId,
13
+ ...correlationId ? { correlationId } : {},
14
+ metadata: {
15
+ kind: SESSION_METADATA_PATCH_KIND,
16
+ sessionMetadataPatch: Object.fromEntries(resetKeys.map((key) => [key, null]))
17
+ }
18
+ }
19
+ }];
20
+ }
21
+ function isPromptTimeoutError(error) {
22
+ return (error instanceof Error ? error.message : String(error)).includes("[narp-stdio] prompt timed out");
23
+ }
24
+ //#endregion
25
+ export { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents };
26
+
27
+ //# sourceMappingURL=stdio-runtime-recovery.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-runtime-recovery.utils.js","names":[],"sources":["../../src/utils/stdio-runtime-recovery.utils.ts"],"sourcesContent":["import { NcpEventType, type NcpEndpointEvent } from \"@nextclaw/ncp\";\n\nexport const SESSION_METADATA_PATCH_KIND = \"session_metadata_patch\";\n\nexport function createPromptTimeoutRecoveryEvents(params: {\n correlationId?: string;\n error: unknown;\n messageId: string;\n resetKeys?: readonly string[];\n runId: string;\n sessionId: string;\n}): NcpEndpointEvent[] {\n const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;\n if (!resetKeys?.length || !isPromptTimeoutError(error)) {\n return [];\n }\n return [\n {\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId,\n messageId,\n runId,\n ...(correlationId ? { correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: Object.fromEntries(\n resetKeys.map((key) => [key, null]),\n ),\n },\n },\n },\n ];\n}\n\nfunction isPromptTimeoutError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return message.includes(\"[narp-stdio] prompt timed out\");\n}\n"],"mappings":";;AAEA,MAAa,8BAA8B;AAE3C,SAAgB,kCAAkC,QAO3B;CACrB,MAAM,EAAE,eAAe,OAAO,WAAW,WAAW,OAAO,cAAc;AACzE,KAAI,CAAC,WAAW,UAAU,CAAC,qBAAqB,MAAM,CACpD,QAAO,EAAE;AAEX,QAAO,CACL;EACE,MAAM,aAAa;EACnB,SAAS;GACP;GACA;GACA;GACA,GAAI,gBAAgB,EAAE,eAAe,GAAG,EAAE;GAC1C,UAAU;IACR,MAAM;IACN,sBAAsB,OAAO,YAC3B,UAAU,KAAK,QAAQ,CAAC,KAAK,KAAK,CAAC,CACpC;IACF;GACF;EACF,CACF;;AAGH,SAAS,qBAAqB,OAAyB;AAErD,SADgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EACvD,SAAS,gCAAgC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/nextclaw-ncp-runtime-stdio-client",
3
- "version": "0.2.12",
3
+ "version": "0.2.14-beta.0",
4
4
  "private": false,
5
5
  "description": "Optional NCP runtime adapter backed by a protocol-aware stdio agent command.",
6
6
  "type": "module",
@@ -17,8 +17,8 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "@agentclientprotocol/sdk": "^0.19.0",
20
- "@nextclaw/core": "0.14.3",
21
- "@nextclaw/ncp": "0.6.2"
20
+ "@nextclaw/core": "0.14.5-beta.0",
21
+ "@nextclaw/ncp": "0.6.4-beta.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.17.6",