@rsconcept/rstool 1.7.0 → 1.9.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.
Files changed (76) hide show
  1. package/README.md +5 -5
  2. package/dist/{agent-workflow-DY-hfAap.d.ts → agent-workflow-BqEC_Foh.d.ts} +5 -6
  3. package/dist/{analysis-ktWFu4BY.d.ts → analysis-C7GrmB17.d.ts} +3 -4
  4. package/dist/{common-D6TFl6l_.d.ts → common-oafVB-wX.d.ts} +1 -2
  5. package/dist/{constituenta-HTnFtmxt.d.ts → constituenta-CwJogNKY.d.ts} +4 -5
  6. package/dist/{diagnostic-CODFUU-Q.d.ts → diagnostic-CtxXifJY.d.ts} +4 -3
  7. package/dist/{diagnostic-assembly-B-6vIA5I.js → diagnostic-assembly-B-r0NyHL.js} +3 -2
  8. package/dist/diagnostic-assembly-B-r0NyHL.js.map +1 -0
  9. package/dist/{evaluation-6A7rK4t7.d.ts → evaluation-BHv2xNwf.d.ts} +3 -4
  10. package/dist/index.d.ts +11 -10
  11. package/dist/index.js +1 -1
  12. package/dist/mappers/model-adapter.d.ts +9 -4
  13. package/dist/mappers/model-adapter.js +29 -4
  14. package/dist/mappers/model-adapter.js.map +1 -1
  15. package/dist/mappers/schema-adapter.d.ts +5 -5
  16. package/dist/mappers/schema-adapter.js +1 -1
  17. package/dist/mappers/types.d.ts +5 -4
  18. package/dist/mappers/types.js +1 -1
  19. package/dist/mappers/types.js.map +1 -1
  20. package/dist/{model-value-BUhr2IjA.d.ts → model-value-C0QA-ji2.d.ts} +2 -3
  21. package/dist/models/agent-workflow.d.ts +1 -1
  22. package/dist/models/analysis.d.ts +1 -1
  23. package/dist/models/common.d.ts +1 -1
  24. package/dist/models/constituenta.d.ts +1 -1
  25. package/dist/models/diagnostic.d.ts +1 -1
  26. package/dist/models/diagnostic.js +1 -1
  27. package/dist/models/evaluation.d.ts +1 -1
  28. package/dist/models/index.d.ts +10 -10
  29. package/dist/models/index.js +1 -1
  30. package/dist/models/model-value.d.ts +1 -1
  31. package/dist/models/rstool-agent.d.ts +1 -1
  32. package/dist/models/rstool-agent.js +1 -1
  33. package/dist/models/session.d.ts +1 -1
  34. package/dist/models/tool-contract.d.ts +1 -1
  35. package/dist/models/tool-contract.js +1 -1
  36. package/dist/models/tool-contract.js.map +1 -1
  37. package/dist/{models-BKmWx92e.js → models-D06g8LId.js} +8 -7
  38. package/dist/{models-BKmWx92e.js.map → models-D06g8LId.js.map} +1 -1
  39. package/dist/{rsform-builder-DKwZfJvN.js → rsform-builder-BlXEe5Ow.js} +2 -2
  40. package/dist/{rsform-builder-DKwZfJvN.js.map → rsform-builder-BlXEe5Ow.js.map} +1 -1
  41. package/dist/{rstool-agent-D-w4DlEo.d.ts → rstool-agent-DLq0mtym.d.ts} +9 -10
  42. package/dist/session/session-store.d.ts +3 -2
  43. package/dist/session/session-store.js +1 -1
  44. package/dist/{session-Uc_vHrq9.d.ts → session-OaLqLq0H.d.ts} +3 -4
  45. package/dist/{tool-contract-i0v2gbWs.d.ts → tool-contract-ZVyh7hhp.d.ts} +10 -11
  46. package/dist/wrapper/client.d.ts +12 -5
  47. package/dist/wrapper/client.js +79 -12
  48. package/dist/wrapper/client.js.map +1 -1
  49. package/dist/wrapper/stdio-wrapper.d.ts +1 -1
  50. package/dist/wrapper/stdio-wrapper.js +18 -10
  51. package/dist/wrapper/stdio-wrapper.js.map +1 -1
  52. package/docs/CONCEPTUAL-SCHEMA.md +1 -1
  53. package/docs/CONSTRUCTIONS.md +372 -0
  54. package/docs/DIAGNOSTICS.md +70 -28
  55. package/docs/DOMAIN.md +7 -2
  56. package/docs/MODEL-TESTING.md +48 -0
  57. package/docs/README.md +1 -0
  58. package/docs/SYNTAX.md +1 -1
  59. package/docs/TYPIFICATION.md +11 -2
  60. package/examples/diagnostics-utils.ts +3 -4
  61. package/package.json +20 -19
  62. package/skills/README.md +1 -1
  63. package/skills/rstool-helper/EXAMPLES.md +24 -0
  64. package/skills/rstool-helper/GUIDE.md +49 -22
  65. package/skills/rstool-helper/REFERENCE.md +24 -5
  66. package/skills/rstool-helper/SKILL.md +7 -4
  67. package/src/mappers/diagnostic-assembly.ts +5 -2
  68. package/src/mappers/model-adapter.ts +34 -1
  69. package/src/mappers/types.ts +1 -0
  70. package/src/models/rstool-agent.test.ts +95 -0
  71. package/src/models/tool-contract.ts +1 -1
  72. package/src/wrapper/client.test.ts +43 -4
  73. package/src/wrapper/client.ts +95 -16
  74. package/src/wrapper/stdio-handler.test.ts +43 -0
  75. package/src/wrapper/stdio-handler.ts +19 -5
  76. package/dist/diagnostic-assembly-B-6vIA5I.js.map +0 -1
@@ -1,7 +1,37 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
1
3
  import { spawn } from "node:child_process";
2
4
  import readline from "node:readline";
3
5
  //#region src/wrapper/client.ts
4
6
  /**
7
+ * Rewrite Windows npm/npx shims to `node <npm-cli.js>` so spawn() never needs a shell.
8
+ * Node 20+ refuses to exec `.cmd` files without `shell: true` (CVE-2024-27980).
9
+ */
10
+ function resolveSpawn(command, args) {
11
+ if (process.platform !== "win32") return {
12
+ command,
13
+ args
14
+ };
15
+ const base = (command.replaceAll("\\", "/").split("/").pop() ?? command).toLowerCase();
16
+ if (base === "npm" || base === "npm.cmd") return {
17
+ command: process.execPath,
18
+ args: [bundledNpmBin("npm-cli.js"), ...args]
19
+ };
20
+ if (base === "npx" || base === "npx.cmd") return {
21
+ command: process.execPath,
22
+ args: [bundledNpmBin("npx-cli.js"), ...args]
23
+ };
24
+ return {
25
+ command,
26
+ args
27
+ };
28
+ }
29
+ function bundledNpmBin(bin) {
30
+ const cli = join(dirname(process.execPath), "node_modules", "npm", "bin", bin);
31
+ if (!existsSync(cli)) throw new Error(`Cannot resolve ${bin} next to Node at ${process.execPath}`);
32
+ return cli;
33
+ }
34
+ /**
5
35
  * JSON-RPC client for the `rstool-wrapper` stdio process.
6
36
  *
7
37
  * Sends one JSON request per line on stdin and reads one JSON response per line from stdout.
@@ -11,13 +41,17 @@ var RSToolWrapperClient = class {
11
41
  input;
12
42
  pending = /* @__PURE__ */ new Map();
13
43
  requestCounter = 1;
44
+ /** Set once the child cannot start or has exited; every later request fails with this error. */
45
+ failure = null;
46
+ closing = false;
14
47
  /**
15
48
  * @param options - Spawn configuration; defaults run `npm run wrapper` in the current directory.
16
49
  */
17
50
  constructor(options = {}) {
18
- this.process = spawn(options.command ?? "npm", options.args ?? ["run", "wrapper"], {
51
+ const resolved = resolveSpawn(options.command ?? "npm", options.args ?? ["run", "wrapper"]);
52
+ this.process = spawn(resolved.command, resolved.args, {
19
53
  cwd: options.cwd ?? process.cwd(),
20
- shell: options.shell ?? true,
54
+ windowsHide: true,
21
55
  stdio: [
22
56
  "pipe",
23
57
  "pipe",
@@ -29,8 +63,21 @@ var RSToolWrapperClient = class {
29
63
  crlfDelay: Infinity
30
64
  });
31
65
  this.input.on("line", (line) => this.handleLine(line));
66
+ this.process.on("error", (error) => this.fail(error));
67
+ this.process.stdin.on("error", (error) => this.fail(error));
68
+ this.process.on("exit", (code, signal) => {
69
+ if (this.closing) {
70
+ this.fail(/* @__PURE__ */ new Error("Wrapper closed"));
71
+ return;
72
+ }
73
+ this.fail(/* @__PURE__ */ new Error(`Wrapper exited before responding (code ${code ?? "null"}, signal ${signal ?? "null"})`));
74
+ });
32
75
  }
33
- /** Block until the wrapper emits its initial `{ ready: true }` event. */
76
+ /**
77
+ * Block until the wrapper emits its initial `{ ready: true }` event.
78
+ *
79
+ * @throws When the wrapper process cannot be started or exits before becoming ready.
80
+ */
34
81
  async waitUntilReady() {
35
82
  for (;;) {
36
83
  const line = await this.readOneEvent();
@@ -48,17 +95,21 @@ var RSToolWrapperClient = class {
48
95
  *
49
96
  * @param method - Stdio method name (matches {@link RSToolAgentContract} operations).
50
97
  * @param params - Method parameters object.
51
- * @throws When the wrapper responds with `ok: false`.
98
+ * @throws When the wrapper responds with `ok: false`, cannot be started, or exits before responding.
52
99
  */
53
100
  async call(method, params = {}) {
101
+ if (this.failure) throw this.failure;
54
102
  const id = String(this.requestCounter++);
55
103
  const payload = JSON.stringify({
56
104
  id,
57
105
  method,
58
106
  params
59
107
  });
60
- const responsePromise = new Promise((resolve) => {
61
- this.pending.set(id, resolve);
108
+ const responsePromise = new Promise((resolve, reject) => {
109
+ this.pending.set(id, {
110
+ resolve,
111
+ reject
112
+ });
62
113
  });
63
114
  this.process.stdin.write(`${payload}\n`);
64
115
  const response = await responsePromise;
@@ -67,11 +118,13 @@ var RSToolWrapperClient = class {
67
118
  }
68
119
  /** Close stdin and terminate the wrapper process. */
69
120
  async close() {
121
+ this.closing = true;
70
122
  this.input.close();
71
- this.process.stdin.end();
72
- if (!this.process.killed) this.process.kill();
123
+ if (!this.process.stdin.destroyed) this.process.stdin.end();
124
+ if (this.process.exitCode === null && !this.process.killed) this.process.kill();
73
125
  }
74
126
  async readOneEvent() {
127
+ if (this.failure) throw this.failure;
75
128
  return new Promise((resolve, reject) => {
76
129
  const onLine = (line) => {
77
130
  cleanup();
@@ -79,16 +132,30 @@ var RSToolWrapperClient = class {
79
132
  };
80
133
  const onExit = () => {
81
134
  cleanup();
82
- reject(/* @__PURE__ */ new Error("Wrapper exited before ready"));
135
+ reject(this.failure ?? /* @__PURE__ */ new Error("Wrapper exited before ready"));
136
+ };
137
+ const onError = (error) => {
138
+ cleanup();
139
+ reject(error);
83
140
  };
84
141
  const cleanup = () => {
85
142
  this.input.off("line", onLine);
86
143
  this.process.off("exit", onExit);
144
+ this.process.off("error", onError);
87
145
  };
88
146
  this.input.on("line", onLine);
89
147
  this.process.on("exit", onExit);
148
+ this.process.on("error", onError);
90
149
  });
91
150
  }
151
+ /** Records the terminal failure and rejects every outstanding request. */
152
+ fail(error) {
153
+ if (this.failure) return;
154
+ this.failure = error;
155
+ const outstanding = [...this.pending.values()];
156
+ this.pending.clear();
157
+ for (const entry of outstanding) entry.reject(error);
158
+ }
92
159
  handleLine(line) {
93
160
  let parsed;
94
161
  try {
@@ -98,10 +165,10 @@ var RSToolWrapperClient = class {
98
165
  }
99
166
  if (parsed.id === null || parsed.id === void 0) return;
100
167
  const id = String(parsed.id);
101
- const resolver = this.pending.get(id);
102
- if (!resolver) return;
168
+ const entry = this.pending.get(id);
169
+ if (!entry) return;
103
170
  this.pending.delete(id);
104
- resolver(parsed);
171
+ entry.resolve(parsed);
105
172
  }
106
173
  };
107
174
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../src/wrapper/client.ts"],"sourcesContent":["import { spawn, type ChildProcessByStdio } from 'node:child_process';\nimport readline from 'node:readline';\nimport { type Readable, type Writable } from 'node:stream';\n\n/** One JSON line emitted by the stdio wrapper (request response or ready event). */\nexport interface WrapperResponse<T = unknown> {\n id: string | number | null;\n ok: boolean;\n result?: T;\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\n/** Options for spawning the `rstool-wrapper` child process. */\nexport interface RSToolWrapperClientOptions {\n /** Executable to spawn. Default: `npm`. */\n command?: string;\n /** Arguments passed to `command`. Default: `['run', 'wrapper']`. */\n args?: string[];\n /** Working directory for the child process. Default: `process.cwd()`. */\n cwd?: string;\n /** Whether to run the command in a shell. Default: `true`. */\n shell?: boolean;\n}\n\n/**\n * JSON-RPC client for the `rstool-wrapper` stdio process.\n *\n * Sends one JSON request per line on stdin and reads one JSON response per line from stdout.\n */\nexport class RSToolWrapperClient {\n private process: ChildProcessByStdio<Writable, Readable, null>;\n private input: readline.Interface;\n private pending = new Map<string, (value: WrapperResponse) => void>();\n private requestCounter = 1;\n\n /**\n * @param options - Spawn configuration; defaults run `npm run wrapper` in the current directory.\n */\n public constructor(options: RSToolWrapperClientOptions = {}) {\n this.process = spawn(options.command ?? 'npm', options.args ?? ['run', 'wrapper'], {\n cwd: options.cwd ?? process.cwd(),\n shell: options.shell ?? true,\n stdio: ['pipe', 'pipe', 'inherit']\n });\n this.input = readline.createInterface({\n input: this.process.stdout,\n crlfDelay: Infinity\n });\n this.input.on('line', line => this.handleLine(line));\n }\n\n /** Block until the wrapper emits its initial `{ ready: true }` event. */\n public async waitUntilReady(): Promise<void> {\n for (;;) {\n const line = await this.readOneEvent();\n let response: WrapperResponse<{ ready: boolean }> | null = null;\n try {\n response = JSON.parse(line) as WrapperResponse<{ ready: boolean }>;\n } catch {\n continue;\n }\n if (response.ok && response.result?.ready) {\n return;\n }\n }\n }\n\n /**\n * Invoke a wrapper method and return its `result` field.\n *\n * @param method - Stdio method name (matches {@link RSToolAgentContract} operations).\n * @param params - Method parameters object.\n * @throws When the wrapper responds with `ok: false`.\n */\n public async call<T>(method: string, params: unknown = {}): Promise<T> {\n const id = String(this.requestCounter++);\n const payload = JSON.stringify({ id, method, params });\n const responsePromise = new Promise<WrapperResponse>(resolve => {\n this.pending.set(id, resolve);\n });\n this.process.stdin.write(`${payload}\\n`);\n const response = await responsePromise;\n if (!response.ok) {\n throw new Error(`${response.error?.code ?? 'UNKNOWN'}: ${response.error?.message ?? 'Request failed'}`);\n }\n return response.result as T;\n }\n\n /** Close stdin and terminate the wrapper process. */\n public async close(): Promise<void> {\n this.input.close();\n this.process.stdin.end();\n if (!this.process.killed) {\n this.process.kill();\n }\n }\n\n private async readOneEvent(): Promise<string> {\n return new Promise((resolve, reject) => {\n const onLine = (line: string) => {\n cleanup();\n resolve(line);\n };\n const onExit = () => {\n cleanup();\n reject(new Error('Wrapper exited before ready'));\n };\n const cleanup = () => {\n this.input.off('line', onLine);\n this.process.off('exit', onExit);\n };\n this.input.on('line', onLine);\n this.process.on('exit', onExit);\n });\n }\n\n private handleLine(line: string): void {\n let parsed: WrapperResponse;\n try {\n parsed = JSON.parse(line) as WrapperResponse;\n } catch {\n return;\n }\n if (parsed.id === null || parsed.id === undefined) {\n return;\n }\n const id = String(parsed.id);\n const resolver = this.pending.get(id);\n if (!resolver) {\n return;\n }\n this.pending.delete(id);\n resolver(parsed);\n }\n}\n"],"mappings":";;;;;;;;AAiCA,IAAa,sBAAb,MAAiC;CAC/B;CACA;CACA,0BAAkB,IAAI,IAA8C;CACpE,iBAAyB;;;;CAKzB,YAAmB,UAAsC,CAAC,GAAG;EAC3D,KAAK,UAAU,MAAM,QAAQ,WAAW,OAAO,QAAQ,QAAQ,CAAC,OAAO,SAAS,GAAG;GACjF,KAAK,QAAQ,OAAO,QAAQ,IAAI;GAChC,OAAO,QAAQ,SAAS;GACxB,OAAO;IAAC;IAAQ;IAAQ;GAAS;EACnC,CAAC;EACD,KAAK,QAAQ,SAAS,gBAAgB;GACpC,OAAO,KAAK,QAAQ;GACpB,WAAW;EACb,CAAC;EACD,KAAK,MAAM,GAAG,SAAQ,SAAQ,KAAK,WAAW,IAAI,CAAC;CACrD;;CAGA,MAAa,iBAAgC;EAC3C,SAAS;GACP,MAAM,OAAO,MAAM,KAAK,aAAa;GACrC,IAAI,WAAuD;GAC3D,IAAI;IACF,WAAW,KAAK,MAAM,IAAI;GAC5B,QAAQ;IACN;GACF;GACA,IAAI,SAAS,MAAM,SAAS,QAAQ,OAClC;EAEJ;CACF;;;;;;;;CASA,MAAa,KAAQ,QAAgB,SAAkB,CAAC,GAAe;EACrE,MAAM,KAAK,OAAO,KAAK,gBAAgB;EACvC,MAAM,UAAU,KAAK,UAAU;GAAE;GAAI;GAAQ;EAAO,CAAC;EACrD,MAAM,kBAAkB,IAAI,SAAyB,YAAW;GAC9D,KAAK,QAAQ,IAAI,IAAI,OAAO;EAC9B,CAAC;EACD,KAAK,QAAQ,MAAM,MAAM,GAAG,QAAQ,GAAG;EACvC,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,QAAQ,UAAU,IAAI,SAAS,OAAO,WAAW,kBAAkB;EAExG,OAAO,SAAS;CAClB;;CAGA,MAAa,QAAuB;EAClC,KAAK,MAAM,MAAM;EACjB,KAAK,QAAQ,MAAM,IAAI;EACvB,IAAI,CAAC,KAAK,QAAQ,QAChB,KAAK,QAAQ,KAAK;CAEtB;CAEA,MAAc,eAAgC;EAC5C,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,SAAiB;IAC/B,QAAQ;IACR,QAAQ,IAAI;GACd;GACA,MAAM,eAAe;IACnB,QAAQ;IACR,uBAAO,IAAI,MAAM,6BAA6B,CAAC;GACjD;GACA,MAAM,gBAAgB;IACpB,KAAK,MAAM,IAAI,QAAQ,MAAM;IAC7B,KAAK,QAAQ,IAAI,QAAQ,MAAM;GACjC;GACA,KAAK,MAAM,GAAG,QAAQ,MAAM;GAC5B,KAAK,QAAQ,GAAG,QAAQ,MAAM;EAChC,CAAC;CACH;CAEA,WAAmB,MAAoB;EACrC,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,QAAQ;GACN;EACF;EACA,IAAI,OAAO,OAAO,QAAQ,OAAO,OAAO,QACtC;EAEF,MAAM,KAAK,OAAO,OAAO,EAAE;EAC3B,MAAM,WAAW,KAAK,QAAQ,IAAI,EAAE;EACpC,IAAI,CAAC,UACH;EAEF,KAAK,QAAQ,OAAO,EAAE;EACtB,SAAS,MAAM;CACjB;AACF"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../src/wrapper/client.ts"],"sourcesContent":["import { spawn, type ChildProcessByStdio } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport readline from 'node:readline';\nimport { type Readable, type Writable } from 'node:stream';\n\n/** One JSON line emitted by the stdio wrapper (request response or ready event). */\nexport interface WrapperResponse<T = unknown> {\n id: string | number | null;\n ok: boolean;\n result?: T;\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\n/** Options for spawning the `rstool-wrapper` child process. */\nexport interface RSToolWrapperClientOptions {\n /** Executable to spawn. Default: `npm`. Passed as argv, not a shell string. */\n command?: string;\n /** Arguments passed to `command`. Default: `['run', 'wrapper']`. */\n args?: string[];\n /** Working directory for the child process. Default: `process.cwd()`. */\n cwd?: string;\n}\n\n/**\n * Rewrite Windows npm/npx shims to `node <npm-cli.js>` so spawn() never needs a shell.\n * Node 20+ refuses to exec `.cmd` files without `shell: true` (CVE-2024-27980).\n */\nfunction resolveSpawn(command: string, args: string[]): { command: string; args: string[] } {\n if (process.platform !== 'win32') {\n return { command, args };\n }\n const base = (command.replaceAll('\\\\', '/').split('/').pop() ?? command).toLowerCase();\n if (base === 'npm' || base === 'npm.cmd') {\n return { command: process.execPath, args: [bundledNpmBin('npm-cli.js'), ...args] };\n }\n if (base === 'npx' || base === 'npx.cmd') {\n return { command: process.execPath, args: [bundledNpmBin('npx-cli.js'), ...args] };\n }\n return { command, args };\n}\n\nfunction bundledNpmBin(bin: 'npm-cli.js' | 'npx-cli.js'): string {\n const cli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', bin);\n if (!existsSync(cli)) {\n throw new Error(`Cannot resolve ${bin} next to Node at ${process.execPath}`);\n }\n return cli;\n}\n\n/**\n * JSON-RPC client for the `rstool-wrapper` stdio process.\n *\n * Sends one JSON request per line on stdin and reads one JSON response per line from stdout.\n */\nexport class RSToolWrapperClient {\n private process: ChildProcessByStdio<Writable, Readable, null>;\n private input: readline.Interface;\n private pending = new Map<string, PendingCall>();\n private requestCounter = 1;\n /** Set once the child cannot start or has exited; every later request fails with this error. */\n private failure: Error | null = null;\n private closing = false;\n\n /**\n * @param options - Spawn configuration; defaults run `npm run wrapper` in the current directory.\n */\n public constructor(options: RSToolWrapperClientOptions = {}) {\n const resolved = resolveSpawn(options.command ?? 'npm', options.args ?? ['run', 'wrapper']);\n this.process = spawn(resolved.command, resolved.args, {\n cwd: options.cwd ?? process.cwd(),\n windowsHide: true,\n stdio: ['pipe', 'pipe', 'inherit']\n });\n this.input = readline.createInterface({\n input: this.process.stdout,\n crlfDelay: Infinity\n });\n this.input.on('line', line => this.handleLine(line));\n\n // Without these listeners a failed spawn (ENOENT, EACCES) or a broken stdin pipe\n // surfaces as an uncaught exception instead of a rejected promise.\n this.process.on('error', error => this.fail(error));\n this.process.stdin.on('error', error => this.fail(error));\n this.process.on('exit', (code, signal) => {\n if (this.closing) {\n this.fail(new Error('Wrapper closed'));\n return;\n }\n this.fail(new Error(`Wrapper exited before responding (code ${code ?? 'null'}, signal ${signal ?? 'null'})`));\n });\n }\n\n /**\n * Block until the wrapper emits its initial `{ ready: true }` event.\n *\n * @throws When the wrapper process cannot be started or exits before becoming ready.\n */\n public async waitUntilReady(): Promise<void> {\n for (;;) {\n const line = await this.readOneEvent();\n let response: WrapperResponse<{ ready: boolean }> | null = null;\n try {\n response = JSON.parse(line) as WrapperResponse<{ ready: boolean }>;\n } catch {\n continue;\n }\n if (response.ok && response.result?.ready) {\n return;\n }\n }\n }\n\n /**\n * Invoke a wrapper method and return its `result` field.\n *\n * @param method - Stdio method name (matches {@link RSToolAgentContract} operations).\n * @param params - Method parameters object.\n * @throws When the wrapper responds with `ok: false`, cannot be started, or exits before responding.\n */\n public async call<T>(method: string, params: unknown = {}): Promise<T> {\n if (this.failure) {\n throw this.failure;\n }\n const id = String(this.requestCounter++);\n const payload = JSON.stringify({ id, method, params });\n const responsePromise = new Promise<WrapperResponse>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n });\n this.process.stdin.write(`${payload}\\n`);\n const response = await responsePromise;\n if (!response.ok) {\n throw new Error(`${response.error?.code ?? 'UNKNOWN'}: ${response.error?.message ?? 'Request failed'}`);\n }\n return response.result as T;\n }\n\n /** Close stdin and terminate the wrapper process. */\n public async close(): Promise<void> {\n this.closing = true;\n this.input.close();\n if (!this.process.stdin.destroyed) {\n this.process.stdin.end();\n }\n if (this.process.exitCode === null && !this.process.killed) {\n this.process.kill();\n }\n }\n\n private async readOneEvent(): Promise<string> {\n if (this.failure) {\n throw this.failure;\n }\n return new Promise((resolve, reject) => {\n const onLine = (line: string) => {\n cleanup();\n resolve(line);\n };\n const onExit = () => {\n cleanup();\n reject(this.failure ?? new Error('Wrapper exited before ready'));\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const cleanup = () => {\n this.input.off('line', onLine);\n this.process.off('exit', onExit);\n this.process.off('error', onError);\n };\n this.input.on('line', onLine);\n this.process.on('exit', onExit);\n this.process.on('error', onError);\n });\n }\n\n /** Records the terminal failure and rejects every outstanding request. */\n private fail(error: Error): void {\n if (this.failure) {\n return;\n }\n this.failure = error;\n const outstanding = [...this.pending.values()];\n this.pending.clear();\n for (const entry of outstanding) {\n entry.reject(error);\n }\n }\n\n private handleLine(line: string): void {\n let parsed: WrapperResponse;\n try {\n parsed = JSON.parse(line) as WrapperResponse;\n } catch {\n return;\n }\n if (parsed.id === null || parsed.id === undefined) {\n return;\n }\n const id = String(parsed.id);\n const entry = this.pending.get(id);\n if (!entry) {\n return;\n }\n this.pending.delete(id);\n entry.resolve(parsed);\n }\n}\n\ninterface PendingCall {\n resolve: (value: WrapperResponse) => void;\n reject: (reason: Error) => void;\n}\n"],"mappings":";;;;;;;;;AAgCA,SAAS,aAAa,SAAiB,MAAqD;CAC1F,IAAI,QAAQ,aAAa,SACvB,OAAO;EAAE;EAAS;CAAK;CAEzB,MAAM,QAAQ,QAAQ,WAAW,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,QAAA,CAAS,YAAY;CACrF,IAAI,SAAS,SAAS,SAAS,WAC7B,OAAO;EAAE,SAAS,QAAQ;EAAU,MAAM,CAAC,cAAc,YAAY,GAAG,GAAG,IAAI;CAAE;CAEnF,IAAI,SAAS,SAAS,SAAS,WAC7B,OAAO;EAAE,SAAS,QAAQ;EAAU,MAAM,CAAC,cAAc,YAAY,GAAG,GAAG,IAAI;CAAE;CAEnF,OAAO;EAAE;EAAS;CAAK;AACzB;AAEA,SAAS,cAAc,KAA0C;CAC/D,MAAM,MAAM,KAAK,QAAQ,QAAQ,QAAQ,GAAG,gBAAgB,OAAO,OAAO,GAAG;CAC7E,IAAI,CAAC,WAAW,GAAG,GACjB,MAAM,IAAI,MAAM,kBAAkB,IAAI,mBAAmB,QAAQ,UAAU;CAE7E,OAAO;AACT;;;;;;AAOA,IAAa,sBAAb,MAAiC;CAC/B;CACA;CACA,0BAAkB,IAAI,IAAyB;CAC/C,iBAAyB;;CAEzB,UAAgC;CAChC,UAAkB;;;;CAKlB,YAAmB,UAAsC,CAAC,GAAG;EAC3D,MAAM,WAAW,aAAa,QAAQ,WAAW,OAAO,QAAQ,QAAQ,CAAC,OAAO,SAAS,CAAC;EAC1F,KAAK,UAAU,MAAM,SAAS,SAAS,SAAS,MAAM;GACpD,KAAK,QAAQ,OAAO,QAAQ,IAAI;GAChC,aAAa;GACb,OAAO;IAAC;IAAQ;IAAQ;GAAS;EACnC,CAAC;EACD,KAAK,QAAQ,SAAS,gBAAgB;GACpC,OAAO,KAAK,QAAQ;GACpB,WAAW;EACb,CAAC;EACD,KAAK,MAAM,GAAG,SAAQ,SAAQ,KAAK,WAAW,IAAI,CAAC;EAInD,KAAK,QAAQ,GAAG,UAAS,UAAS,KAAK,KAAK,KAAK,CAAC;EAClD,KAAK,QAAQ,MAAM,GAAG,UAAS,UAAS,KAAK,KAAK,KAAK,CAAC;EACxD,KAAK,QAAQ,GAAG,SAAS,MAAM,WAAW;GACxC,IAAI,KAAK,SAAS;IAChB,KAAK,qBAAK,IAAI,MAAM,gBAAgB,CAAC;IACrC;GACF;GACA,KAAK,qBAAK,IAAI,MAAM,0CAA0C,QAAQ,OAAO,WAAW,UAAU,OAAO,EAAE,CAAC;EAC9G,CAAC;CACH;;;;;;CAOA,MAAa,iBAAgC;EAC3C,SAAS;GACP,MAAM,OAAO,MAAM,KAAK,aAAa;GACrC,IAAI,WAAuD;GAC3D,IAAI;IACF,WAAW,KAAK,MAAM,IAAI;GAC5B,QAAQ;IACN;GACF;GACA,IAAI,SAAS,MAAM,SAAS,QAAQ,OAClC;EAEJ;CACF;;;;;;;;CASA,MAAa,KAAQ,QAAgB,SAAkB,CAAC,GAAe;EACrE,IAAI,KAAK,SACP,MAAM,KAAK;EAEb,MAAM,KAAK,OAAO,KAAK,gBAAgB;EACvC,MAAM,UAAU,KAAK,UAAU;GAAE;GAAI;GAAQ;EAAO,CAAC;EACrD,MAAM,kBAAkB,IAAI,SAA0B,SAAS,WAAW;GACxE,KAAK,QAAQ,IAAI,IAAI;IAAE;IAAS;GAAO,CAAC;EAC1C,CAAC;EACD,KAAK,QAAQ,MAAM,MAAM,GAAG,QAAQ,GAAG;EACvC,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,QAAQ,UAAU,IAAI,SAAS,OAAO,WAAW,kBAAkB;EAExG,OAAO,SAAS;CAClB;;CAGA,MAAa,QAAuB;EAClC,KAAK,UAAU;EACf,KAAK,MAAM,MAAM;EACjB,IAAI,CAAC,KAAK,QAAQ,MAAM,WACtB,KAAK,QAAQ,MAAM,IAAI;EAEzB,IAAI,KAAK,QAAQ,aAAa,QAAQ,CAAC,KAAK,QAAQ,QAClD,KAAK,QAAQ,KAAK;CAEtB;CAEA,MAAc,eAAgC;EAC5C,IAAI,KAAK,SACP,MAAM,KAAK;EAEb,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,SAAiB;IAC/B,QAAQ;IACR,QAAQ,IAAI;GACd;GACA,MAAM,eAAe;IACnB,QAAQ;IACR,OAAO,KAAK,2BAAW,IAAI,MAAM,6BAA6B,CAAC;GACjE;GACA,MAAM,WAAW,UAAiB;IAChC,QAAQ;IACR,OAAO,KAAK;GACd;GACA,MAAM,gBAAgB;IACpB,KAAK,MAAM,IAAI,QAAQ,MAAM;IAC7B,KAAK,QAAQ,IAAI,QAAQ,MAAM;IAC/B,KAAK,QAAQ,IAAI,SAAS,OAAO;GACnC;GACA,KAAK,MAAM,GAAG,QAAQ,MAAM;GAC5B,KAAK,QAAQ,GAAG,QAAQ,MAAM;GAC9B,KAAK,QAAQ,GAAG,SAAS,OAAO;EAClC,CAAC;CACH;;CAGA,KAAa,OAAoB;EAC/B,IAAI,KAAK,SACP;EAEF,KAAK,UAAU;EACf,MAAM,cAAc,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC;EAC7C,KAAK,QAAQ,MAAM;EACnB,KAAK,MAAM,SAAS,aAClB,MAAM,OAAO,KAAK;CAEtB;CAEA,WAAmB,MAAoB;EACrC,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,QAAQ;GACN;EACF;EACA,IAAI,OAAO,OAAO,QAAQ,OAAO,OAAO,QACtC;EAEF,MAAM,KAAK,OAAO,OAAO,EAAE;EAC3B,MAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;EACjC,IAAI,CAAC,OACH;EAEF,KAAK,QAAQ,OAAO,EAAE;EACtB,MAAM,QAAQ,MAAM;CACtB;AACF"}
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as RSToolAgent } from "../models-BKmWx92e.js";
2
+ import { t as RSToolAgent } from "../models-D06g8LId.js";
3
3
  import readline from "node:readline";
4
4
  //#region src/wrapper/stdio-handler.ts
5
5
  const STDIO_METHODS = [
@@ -39,6 +39,18 @@ function omitSessionId(input) {
39
39
  const { sessionId: _sessionId, ...rest } = input;
40
40
  return rest;
41
41
  }
42
+ /** Flat `constituentId` / `kind` / `severity` params; legacy nested `filters` object is still accepted. */
43
+ function diagnosticsFilters(input) {
44
+ const source = {
45
+ ...asObject(input.filters),
46
+ ...omitSessionId(input)
47
+ };
48
+ const filters = {};
49
+ if (typeof source.constituentId === "number") filters.constituentId = source.constituentId;
50
+ if (source.kind === "expression" || source.kind === "schema" || source.kind === "model") filters.kind = source.kind;
51
+ if (source.severity === "error" || source.severity === "warning") filters.severity = source.severity;
52
+ return Object.keys(filters).length > 0 ? filters : void 0;
53
+ }
42
54
  async function handleStdioRequest(tool, request) {
43
55
  try {
44
56
  const params = asObject(request.params);
@@ -86,15 +98,11 @@ async function handleStdioRequest(tool, request) {
86
98
  ok: true,
87
99
  result: tool.getSessionState(params.detail ?? "summary", optionalSessionId(params))
88
100
  };
89
- case "listDiagnostics": {
90
- const constituentId = params.constituentId;
91
- const filters = typeof constituentId === "number" ? { constituentId } : params.filters;
92
- return {
93
- id: request.id,
94
- ok: true,
95
- result: tool.listDiagnostics(filters, optionalSessionId(params))
96
- };
97
- }
101
+ case "listDiagnostics": return {
102
+ id: request.id,
103
+ ok: true,
104
+ result: tool.listDiagnostics(diagnosticsFilters(params), optionalSessionId(params))
105
+ };
98
106
  case "analyzeExpression": return {
99
107
  id: request.id,
100
108
  ok: true,
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-wrapper.js","names":[],"sources":["../../src/wrapper/stdio-handler.ts","../../src/wrapper/stdio-wrapper.ts"],"sourcesContent":["import type { RSToolAgent } from '../models/rstool-agent';\n\nexport interface StdioRequest {\n id: string | number;\n method: string;\n params?: unknown;\n}\n\nexport interface StdioResponse {\n id: string | number | null;\n ok: boolean;\n result?: unknown;\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\nexport const STDIO_METHODS = [\n 'ensureSession',\n 'createSession',\n 'getCurrentSession',\n 'setCurrentSession',\n 'applySchemaPatch',\n 'getSessionState',\n 'listDiagnostics',\n 'analyzeExpression',\n 'commitStep',\n 'exportSession',\n 'exportPortal',\n 'importData',\n 'setModelValues',\n 'getModelState',\n 'evaluate',\n 'recalculateModel',\n 'restoreOrder',\n 'synthesize'\n] as const;\n\nfunction asObject(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {};\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Missing or invalid \"${key}\"`);\n }\n return value;\n}\n\nfunction optionalSessionId(input: Record<string, unknown>): string | undefined {\n const value = input.sessionId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction omitSessionId(input: Record<string, unknown>): Record<string, unknown> {\n const { sessionId: _sessionId, ...rest } = input;\n return rest;\n}\n\nexport async function handleStdioRequest(tool: RSToolAgent, request: StdioRequest): Promise<StdioResponse> {\n try {\n const params = asObject(request.params);\n switch (request.method) {\n case 'ping':\n return { id: request.id, ok: true, result: { pong: true, contractVersion: tool.contractVersion } };\n case 'methods':\n return { id: request.id, ok: true, result: STDIO_METHODS };\n case 'ensureSession':\n return {\n id: request.id,\n ok: true,\n result: tool.ensureSession(params.initial as never)\n };\n case 'createSession':\n return {\n id: request.id,\n ok: true,\n result: tool.createSession(params.initial as never)\n };\n case 'getCurrentSession':\n return {\n id: request.id,\n ok: true,\n result: tool.getCurrentSession()\n };\n case 'setCurrentSession':\n return {\n id: request.id,\n ok: true,\n result: tool.setCurrentSession(requiredString(params, 'sessionId'))\n };\n case 'applySchemaPatch':\n return {\n id: request.id,\n ok: true,\n result: tool.applySchemaPatch(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'getSessionState':\n return {\n id: request.id,\n ok: true,\n result: tool.getSessionState(\n (params.detail as 'summary' | 'full' | undefined) ?? 'summary',\n optionalSessionId(params)\n )\n };\n case 'listDiagnostics': {\n const constituentId = params.constituentId;\n const filters = typeof constituentId === 'number' ? { constituentId } : (params.filters as never);\n return {\n id: request.id,\n ok: true,\n result: tool.listDiagnostics(filters, optionalSessionId(params))\n };\n }\n case 'analyzeExpression':\n return {\n id: request.id,\n ok: true,\n result: tool.analyzeExpression(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'commitStep':\n return {\n id: request.id,\n ok: true,\n result: tool.commitStep(params.message as string | undefined, optionalSessionId(params))\n };\n case 'exportSession':\n return {\n id: request.id,\n ok: true,\n result: tool.exportSession(optionalSessionId(params))\n };\n case 'exportPortal':\n return {\n id: request.id,\n ok: true,\n result: tool.exportPortal(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'importData':\n return {\n id: request.id,\n ok: true,\n result: tool.importData(params.payload as string | object, params.kind as never)\n };\n case 'setModelValues':\n return {\n id: request.id,\n ok: true,\n result: await tool.setModelValues(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'getModelState':\n return {\n id: request.id,\n ok: true,\n result: tool.getModelState(optionalSessionId(params))\n };\n case 'evaluate':\n return {\n id: request.id,\n ok: true,\n result: tool.evaluate(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'recalculateModel':\n return {\n id: request.id,\n ok: true,\n result: tool.recalculateModel(optionalSessionId(params))\n };\n case 'restoreOrder':\n return {\n id: request.id,\n ok: true,\n result: tool.restoreOrder(optionalSessionId(params))\n };\n case 'synthesize':\n return {\n id: request.id,\n ok: true,\n result: tool.synthesize(omitSessionId(params) as never, optionalSessionId(params))\n };\n default:\n return {\n id: request.id ?? null,\n ok: false,\n error: {\n code: 'METHOD_NOT_FOUND',\n message: `Unknown method: ${request.method}`\n }\n };\n }\n } catch (error) {\n return {\n id: request.id ?? null,\n ok: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: error instanceof Error ? error.message : 'Unknown error',\n details: error\n }\n };\n }\n}\n","#!/usr/bin/env node\nimport readline from 'node:readline';\n\nimport { RSToolAgent } from '../models/rstool-agent';\nimport { handleStdioRequest, type StdioRequest, type StdioResponse } from './stdio-handler';\n\nconst persistenceDir = process.env.RSTOOL_PERSISTENCE_DIR;\nconst tool = new RSToolAgent(persistenceDir ? { persistenceDir } : {});\n\nfunction writeResponse(response: StdioResponse): void {\n if (!process.stdout.writable || process.stdout.destroyed || process.stdout.writableEnded) {\n return;\n }\n try {\n process.stdout.write(`${JSON.stringify(response)}\\n`);\n } catch {\n // The client might have already closed stdout (EPIPE). Safe to ignore.\n }\n}\n\nconst input = readline.createInterface({\n input: process.stdin,\n crlfDelay: Infinity\n});\n\nwriteResponse({\n id: null,\n ok: true,\n result: {\n ready: true,\n wrapper: 'rstool-stdio',\n contractVersion: tool.contractVersion\n }\n});\n\ninput.on('line', line => {\n if (!line.trim()) {\n return;\n }\n try {\n const request = JSON.parse(line) as StdioRequest;\n if (!('id' in request) || !('method' in request)) {\n throw new Error('Request must include \"id\" and \"method\"');\n }\n void handleStdioRequest(tool, request).then(writeResponse);\n } catch (error) {\n writeResponse({\n id: null,\n ok: false,\n error: {\n code: 'BAD_REQUEST',\n message: error instanceof Error ? error.message : 'Invalid JSON'\n }\n });\n }\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"stdio-wrapper.js","names":[],"sources":["../../src/wrapper/stdio-handler.ts","../../src/wrapper/stdio-wrapper.ts"],"sourcesContent":["import type { ListDiagnosticsFilters } from '../models/diagnostic';\nimport type { RSToolAgent } from '../models/rstool-agent';\n\nexport interface StdioRequest {\n id: string | number;\n method: string;\n params?: unknown;\n}\n\nexport interface StdioResponse {\n id: string | number | null;\n ok: boolean;\n result?: unknown;\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\nexport const STDIO_METHODS = [\n 'ensureSession',\n 'createSession',\n 'getCurrentSession',\n 'setCurrentSession',\n 'applySchemaPatch',\n 'getSessionState',\n 'listDiagnostics',\n 'analyzeExpression',\n 'commitStep',\n 'exportSession',\n 'exportPortal',\n 'importData',\n 'setModelValues',\n 'getModelState',\n 'evaluate',\n 'recalculateModel',\n 'restoreOrder',\n 'synthesize'\n] as const;\n\nfunction asObject(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {};\n }\n return value as Record<string, unknown>;\n}\n\nfunction requiredString(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Missing or invalid \"${key}\"`);\n }\n return value;\n}\n\nfunction optionalSessionId(input: Record<string, unknown>): string | undefined {\n const value = input.sessionId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction omitSessionId(input: Record<string, unknown>): Record<string, unknown> {\n const { sessionId: _sessionId, ...rest } = input;\n return rest;\n}\n\n/** Flat `constituentId` / `kind` / `severity` params; legacy nested `filters` object is still accepted. */\nfunction diagnosticsFilters(input: Record<string, unknown>): ListDiagnosticsFilters | undefined {\n const source = { ...asObject(input.filters), ...omitSessionId(input) };\n const filters: ListDiagnosticsFilters = {};\n if (typeof source.constituentId === 'number') {\n filters.constituentId = source.constituentId;\n }\n if (source.kind === 'expression' || source.kind === 'schema' || source.kind === 'model') {\n filters.kind = source.kind;\n }\n if (source.severity === 'error' || source.severity === 'warning') {\n filters.severity = source.severity;\n }\n return Object.keys(filters).length > 0 ? filters : undefined;\n}\n\nexport async function handleStdioRequest(tool: RSToolAgent, request: StdioRequest): Promise<StdioResponse> {\n try {\n const params = asObject(request.params);\n switch (request.method) {\n case 'ping':\n return { id: request.id, ok: true, result: { pong: true, contractVersion: tool.contractVersion } };\n case 'methods':\n return { id: request.id, ok: true, result: STDIO_METHODS };\n case 'ensureSession':\n return {\n id: request.id,\n ok: true,\n result: tool.ensureSession(params.initial as never)\n };\n case 'createSession':\n return {\n id: request.id,\n ok: true,\n result: tool.createSession(params.initial as never)\n };\n case 'getCurrentSession':\n return {\n id: request.id,\n ok: true,\n result: tool.getCurrentSession()\n };\n case 'setCurrentSession':\n return {\n id: request.id,\n ok: true,\n result: tool.setCurrentSession(requiredString(params, 'sessionId'))\n };\n case 'applySchemaPatch':\n return {\n id: request.id,\n ok: true,\n result: tool.applySchemaPatch(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'getSessionState':\n return {\n id: request.id,\n ok: true,\n result: tool.getSessionState(\n (params.detail as 'summary' | 'full' | undefined) ?? 'summary',\n optionalSessionId(params)\n )\n };\n case 'listDiagnostics':\n return {\n id: request.id,\n ok: true,\n result: tool.listDiagnostics(diagnosticsFilters(params), optionalSessionId(params))\n };\n case 'analyzeExpression':\n return {\n id: request.id,\n ok: true,\n result: tool.analyzeExpression(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'commitStep':\n return {\n id: request.id,\n ok: true,\n result: tool.commitStep(params.message as string | undefined, optionalSessionId(params))\n };\n case 'exportSession':\n return {\n id: request.id,\n ok: true,\n result: tool.exportSession(optionalSessionId(params))\n };\n case 'exportPortal':\n return {\n id: request.id,\n ok: true,\n result: tool.exportPortal(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'importData':\n return {\n id: request.id,\n ok: true,\n result: tool.importData(params.payload as string | object, params.kind as never)\n };\n case 'setModelValues':\n return {\n id: request.id,\n ok: true,\n result: await tool.setModelValues(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'getModelState':\n return {\n id: request.id,\n ok: true,\n result: tool.getModelState(optionalSessionId(params))\n };\n case 'evaluate':\n return {\n id: request.id,\n ok: true,\n result: tool.evaluate(omitSessionId(params) as never, optionalSessionId(params))\n };\n case 'recalculateModel':\n return {\n id: request.id,\n ok: true,\n result: tool.recalculateModel(optionalSessionId(params))\n };\n case 'restoreOrder':\n return {\n id: request.id,\n ok: true,\n result: tool.restoreOrder(optionalSessionId(params))\n };\n case 'synthesize':\n return {\n id: request.id,\n ok: true,\n result: tool.synthesize(omitSessionId(params) as never, optionalSessionId(params))\n };\n default:\n return {\n id: request.id ?? null,\n ok: false,\n error: {\n code: 'METHOD_NOT_FOUND',\n message: `Unknown method: ${request.method}`\n }\n };\n }\n } catch (error) {\n return {\n id: request.id ?? null,\n ok: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: error instanceof Error ? error.message : 'Unknown error',\n details: error\n }\n };\n }\n}\n","#!/usr/bin/env node\nimport readline from 'node:readline';\n\nimport { RSToolAgent } from '../models/rstool-agent';\nimport { handleStdioRequest, type StdioRequest, type StdioResponse } from './stdio-handler';\n\nconst persistenceDir = process.env.RSTOOL_PERSISTENCE_DIR;\nconst tool = new RSToolAgent(persistenceDir ? { persistenceDir } : {});\n\nfunction writeResponse(response: StdioResponse): void {\n if (!process.stdout.writable || process.stdout.destroyed || process.stdout.writableEnded) {\n return;\n }\n try {\n process.stdout.write(`${JSON.stringify(response)}\\n`);\n } catch {\n // The client might have already closed stdout (EPIPE). Safe to ignore.\n }\n}\n\nconst input = readline.createInterface({\n input: process.stdin,\n crlfDelay: Infinity\n});\n\nwriteResponse({\n id: null,\n ok: true,\n result: {\n ready: true,\n wrapper: 'rstool-stdio',\n contractVersion: tool.contractVersion\n }\n});\n\ninput.on('line', line => {\n if (!line.trim()) {\n return;\n }\n try {\n const request = JSON.parse(line) as StdioRequest;\n if (!('id' in request) || !('method' in request)) {\n throw new Error('Request must include \"id\" and \"method\"');\n }\n void handleStdioRequest(tool, request).then(writeResponse);\n } catch (error) {\n writeResponse({\n id: null,\n ok: false,\n error: {\n code: 'BAD_REQUEST',\n message: error instanceof Error ? error.message : 'Invalid JSON'\n }\n });\n }\n});\n"],"mappings":"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"}
@@ -94,7 +94,7 @@ card(S1) = card(Pr1,2(S1))
94
94
  D1 ::= I{(ξ,σ) | ξ:∈S1; σ:=Expr(ξ)}
95
95
  ```
96
96
 
97
- а затем читать значение через `Pr2(Fi1[{α}](D1))` или `pr2(d)` при `d∈D1`.
97
+ а затем читать значение через `Pr2(Fi1[{α}](D1))` или `pr2(d)` при `d∈D1`. Как объяснить эту цепочку человеку — [CONSTRUCTIONS.md](CONSTRUCTIONS.md), раздел «Типичная цепочка».
98
98
 
99
99
  Если для каждого допустимого `ξ` значение `σ` **однозначно задаётся** выражением, это не отношение, а **терм-функция**:
100
100