@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.
- package/README.md +5 -5
- package/dist/{agent-workflow-DY-hfAap.d.ts → agent-workflow-BqEC_Foh.d.ts} +5 -6
- package/dist/{analysis-ktWFu4BY.d.ts → analysis-C7GrmB17.d.ts} +3 -4
- package/dist/{common-D6TFl6l_.d.ts → common-oafVB-wX.d.ts} +1 -2
- package/dist/{constituenta-HTnFtmxt.d.ts → constituenta-CwJogNKY.d.ts} +4 -5
- package/dist/{diagnostic-CODFUU-Q.d.ts → diagnostic-CtxXifJY.d.ts} +4 -3
- package/dist/{diagnostic-assembly-B-6vIA5I.js → diagnostic-assembly-B-r0NyHL.js} +3 -2
- package/dist/diagnostic-assembly-B-r0NyHL.js.map +1 -0
- package/dist/{evaluation-6A7rK4t7.d.ts → evaluation-BHv2xNwf.d.ts} +3 -4
- package/dist/index.d.ts +11 -10
- package/dist/index.js +1 -1
- package/dist/mappers/model-adapter.d.ts +9 -4
- package/dist/mappers/model-adapter.js +29 -4
- package/dist/mappers/model-adapter.js.map +1 -1
- package/dist/mappers/schema-adapter.d.ts +5 -5
- package/dist/mappers/schema-adapter.js +1 -1
- package/dist/mappers/types.d.ts +5 -4
- package/dist/mappers/types.js +1 -1
- package/dist/mappers/types.js.map +1 -1
- package/dist/{model-value-BUhr2IjA.d.ts → model-value-C0QA-ji2.d.ts} +2 -3
- package/dist/models/agent-workflow.d.ts +1 -1
- package/dist/models/analysis.d.ts +1 -1
- package/dist/models/common.d.ts +1 -1
- package/dist/models/constituenta.d.ts +1 -1
- package/dist/models/diagnostic.d.ts +1 -1
- package/dist/models/diagnostic.js +1 -1
- package/dist/models/evaluation.d.ts +1 -1
- package/dist/models/index.d.ts +10 -10
- package/dist/models/index.js +1 -1
- package/dist/models/model-value.d.ts +1 -1
- package/dist/models/rstool-agent.d.ts +1 -1
- package/dist/models/rstool-agent.js +1 -1
- package/dist/models/session.d.ts +1 -1
- package/dist/models/tool-contract.d.ts +1 -1
- package/dist/models/tool-contract.js +1 -1
- package/dist/models/tool-contract.js.map +1 -1
- package/dist/{models-BKmWx92e.js → models-D06g8LId.js} +8 -7
- package/dist/{models-BKmWx92e.js.map → models-D06g8LId.js.map} +1 -1
- package/dist/{rsform-builder-DKwZfJvN.js → rsform-builder-BlXEe5Ow.js} +2 -2
- package/dist/{rsform-builder-DKwZfJvN.js.map → rsform-builder-BlXEe5Ow.js.map} +1 -1
- package/dist/{rstool-agent-D-w4DlEo.d.ts → rstool-agent-DLq0mtym.d.ts} +9 -10
- package/dist/session/session-store.d.ts +3 -2
- package/dist/session/session-store.js +1 -1
- package/dist/{session-Uc_vHrq9.d.ts → session-OaLqLq0H.d.ts} +3 -4
- package/dist/{tool-contract-i0v2gbWs.d.ts → tool-contract-ZVyh7hhp.d.ts} +10 -11
- package/dist/wrapper/client.d.ts +12 -5
- package/dist/wrapper/client.js +79 -12
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/stdio-wrapper.d.ts +1 -1
- package/dist/wrapper/stdio-wrapper.js +18 -10
- package/dist/wrapper/stdio-wrapper.js.map +1 -1
- package/docs/CONCEPTUAL-SCHEMA.md +1 -1
- package/docs/CONSTRUCTIONS.md +372 -0
- package/docs/DIAGNOSTICS.md +70 -28
- package/docs/DOMAIN.md +7 -2
- package/docs/MODEL-TESTING.md +48 -0
- package/docs/README.md +1 -0
- package/docs/SYNTAX.md +1 -1
- package/docs/TYPIFICATION.md +11 -2
- package/examples/diagnostics-utils.ts +3 -4
- package/package.json +20 -19
- package/skills/README.md +1 -1
- package/skills/rstool-helper/EXAMPLES.md +24 -0
- package/skills/rstool-helper/GUIDE.md +49 -22
- package/skills/rstool-helper/REFERENCE.md +24 -5
- package/skills/rstool-helper/SKILL.md +7 -4
- package/src/mappers/diagnostic-assembly.ts +5 -2
- package/src/mappers/model-adapter.ts +34 -1
- package/src/mappers/types.ts +1 -0
- package/src/models/rstool-agent.test.ts +95 -0
- package/src/models/tool-contract.ts +1 -1
- package/src/wrapper/client.test.ts +43 -4
- package/src/wrapper/client.ts +95 -16
- package/src/wrapper/stdio-handler.test.ts +43 -0
- package/src/wrapper/stdio-handler.ts +19 -5
- package/dist/diagnostic-assembly-B-6vIA5I.js.map +0 -1
package/dist/wrapper/client.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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,
|
|
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
|
|
102
|
-
if (!
|
|
168
|
+
const entry = this.pending.get(id);
|
|
169
|
+
if (!entry) return;
|
|
103
170
|
this.pending.delete(id);
|
|
104
|
-
|
|
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":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as RSToolAgent } from "../models-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|