@codesys/mcp-toolkit 1.5.8 → 2.0.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/CHANGELOG.md +153 -189
- package/LICENSE +21 -21
- package/README.md +269 -152
- package/dist/actions.d.ts +28 -0
- package/dist/actions.js +98 -0
- package/dist/actions.js.map +1 -0
- package/dist/bridge/bridge.d.ts +105 -0
- package/dist/bridge/bridge.js +400 -0
- package/dist/bridge/bridge.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/codesys/cache.d.ts +48 -0
- package/dist/codesys/cache.js +82 -0
- package/dist/codesys/cache.js.map +1 -0
- package/dist/codesys/changes.d.ts +57 -0
- package/dist/codesys/changes.js +133 -0
- package/dist/codesys/changes.js.map +1 -0
- package/dist/codesys/decl.d.ts +45 -0
- package/dist/codesys/decl.js +251 -0
- package/dist/codesys/decl.js.map +1 -0
- package/dist/codesys/devices.d.ts +34 -0
- package/dist/codesys/devices.js +82 -0
- package/dist/codesys/devices.js.map +1 -0
- package/dist/codesys/diff.d.ts +13 -0
- package/dist/codesys/diff.js +61 -0
- package/dist/codesys/diff.js.map +1 -0
- package/dist/codesys/install.d.ts +40 -0
- package/dist/codesys/install.js +144 -0
- package/dist/codesys/install.js.map +1 -0
- package/dist/codesys/library-browse.d.ts +19 -0
- package/dist/codesys/library-browse.js +57 -0
- package/dist/codesys/library-browse.js.map +1 -0
- package/dist/codesys/outline.d.ts +32 -0
- package/dist/codesys/outline.js +219 -0
- package/dist/codesys/outline.js.map +1 -0
- package/dist/codesys/simulation.d.ts +34 -0
- package/dist/codesys/simulation.js +57 -0
- package/dist/codesys/simulation.js.map +1 -0
- package/dist/codesys/st.d.ts +36 -0
- package/dist/codesys/st.js +69 -0
- package/dist/codesys/st.js.map +1 -0
- package/dist/daemon.d.ts +46 -0
- package/dist/daemon.js +173 -0
- package/dist/daemon.js.map +1 -0
- package/dist/driver.d.ts +25 -0
- package/dist/driver.js +33 -0
- package/dist/driver.js.map +1 -0
- package/dist/panel/sim-panel.html +357 -0
- package/dist/panel/viewer.html +126 -0
- package/dist/panel-types.d.ts +20 -0
- package/dist/panel-types.js +3 -0
- package/dist/panel-types.js.map +1 -0
- package/dist/panel.d.ts +27 -0
- package/dist/panel.js +208 -0
- package/dist/panel.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +33 -974
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +103 -0
- package/dist/tools.js +793 -0
- package/dist/tools.js.map +1 -0
- package/dist/viewer.d.ts +14 -0
- package/dist/viewer.js +125 -0
- package/dist/viewer.js.map +1 -0
- package/package.json +66 -51
- package/watcher/mcp_compat.py +147 -0
- package/watcher/mcp_ops.py +1178 -0
- package/watcher/mcp_sim.py +246 -0
- package/watcher/watcher.py +255 -0
- package/.claude/settings.local.json +0 -29
- package/CLAUDE.md +0 -26
- package/CONTRIBUTING.md +0 -72
- package/README.md.enhanced +0 -155
- package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
- package/codesys-mcp-toolkit-1.2.1.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.7.tgz +0 -0
- package/codesys-mcp-toolkit-1.5.8.tgz +0 -0
- package/dist/bin.js +0 -75
- package/dist/check_session_paths.js +0 -149
- package/dist/codesys_interop.js +0 -435
- package/dist/direct_session_command.js +0 -293
- package/dist/scriptLoader.js +0 -165
- package/dist/scripts/check_status.py +0 -21
- package/dist/scripts/compile_project.py +0 -65
- package/dist/scripts/create_method.py +0 -80
- package/dist/scripts/create_pou.py +0 -102
- package/dist/scripts/create_project.py +0 -116
- package/dist/scripts/create_property.py +0 -78
- package/dist/scripts/ensure_project_open.py +0 -154
- package/dist/scripts/find_object_by_path.py +0 -111
- package/dist/scripts/get_pou_code.py +0 -91
- package/dist/scripts/get_project_structure.py +0 -72
- package/dist/scripts/open_project.py +0 -25
- package/dist/scripts/save_project.py +0 -29
- package/dist/scripts/session_status.py +0 -281
- package/dist/scripts/set_pou_code.py +0 -109
- package/dist/scripts/start_session.py +0 -809
- package/dist/scripts/stop_session.py +0 -324
- package/dist/sessionManager.js +0 -798
- package/docs/configuration.md +0 -141
- package/docs/index.md +0 -26
- package/docs/installation.md +0 -84
- package/docs/session_management.md +0 -110
- package/examples/README.md +0 -78
- package/examples/sample_config.json +0 -32
- package/replacements_session_status.txt +0 -16
- package/scriptDoc.txt +0 -8679
- package/scripts/build.js +0 -25
- package/scripts/fix_fstrings.py +0 -76
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export interface BridgeOptions {
|
|
2
|
+
/** Executable: CODESYS.exe in production, python in tests. */
|
|
3
|
+
command: string;
|
|
4
|
+
/** Full argument list; when omitted, CODESYS arguments are built from profile/noUI. */
|
|
5
|
+
args?: (scriptPath: string) => string[];
|
|
6
|
+
profile?: string;
|
|
7
|
+
/** CODESYS's additional folder (SP22 keeps its add-ons there, e.g. Scripting). */
|
|
8
|
+
additionalFolder?: string;
|
|
9
|
+
/** Run CODESYS without UI (default true). */
|
|
10
|
+
noUI?: boolean;
|
|
11
|
+
/** Folder that holds watcher.py and its modules (copied into the session). */
|
|
12
|
+
watcherSource: string;
|
|
13
|
+
/** Base folder for session folders. */
|
|
14
|
+
sessionRoot: string;
|
|
15
|
+
/** Extra environment (tests point PYTHONPATH at a fake scriptengine). */
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
startupTimeoutMs?: number;
|
|
18
|
+
defaultTimeoutMs?: number;
|
|
19
|
+
/** Extra time after a busy op's deadline before the watcher counts as hung. */
|
|
20
|
+
hungGraceMs?: number;
|
|
21
|
+
/** An idle heartbeat older than this means the watcher is hung. */
|
|
22
|
+
staleHeartbeatMs?: number;
|
|
23
|
+
log?: (msg: string) => void;
|
|
24
|
+
}
|
|
25
|
+
export type BridgeState = "stopped" | "starting" | "ready" | "dead";
|
|
26
|
+
export interface Heartbeat {
|
|
27
|
+
pid: number;
|
|
28
|
+
ts: number;
|
|
29
|
+
state: "idle" | "busy" | "stopped" | "crashed";
|
|
30
|
+
op?: string | null;
|
|
31
|
+
id?: string | null;
|
|
32
|
+
deadline?: number | null;
|
|
33
|
+
count?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface BridgeHealth {
|
|
36
|
+
state: BridgeState;
|
|
37
|
+
pid?: number;
|
|
38
|
+
sessionDir?: string;
|
|
39
|
+
startedAt?: string;
|
|
40
|
+
readyAfterMs?: number;
|
|
41
|
+
heartbeat?: Heartbeat & {
|
|
42
|
+
ageMs: number;
|
|
43
|
+
};
|
|
44
|
+
verdict: "healthy" | "busy" | "hung" | "dead" | "starting" | "stopped";
|
|
45
|
+
/** Version of the CODESYS Scripting add-on, once CODESYS has started. */
|
|
46
|
+
scripting?: string;
|
|
47
|
+
calls: number;
|
|
48
|
+
lastError?: string;
|
|
49
|
+
restarts: number;
|
|
50
|
+
}
|
|
51
|
+
export declare class BridgeError extends Error {
|
|
52
|
+
code: string;
|
|
53
|
+
detail?: string | undefined;
|
|
54
|
+
constructor(code: string, message: string, detail?: string | undefined);
|
|
55
|
+
}
|
|
56
|
+
/** What to do about a start-up failure CODESYS explains in its output. */
|
|
57
|
+
export declare function startupHint(output: string): string;
|
|
58
|
+
export declare class CodesysBridge {
|
|
59
|
+
private opts;
|
|
60
|
+
private child?;
|
|
61
|
+
private state;
|
|
62
|
+
private startPromise?;
|
|
63
|
+
private sessionDir?;
|
|
64
|
+
private queue;
|
|
65
|
+
private seq;
|
|
66
|
+
private calls;
|
|
67
|
+
private restarts;
|
|
68
|
+
private startedAt?;
|
|
69
|
+
private readyAt?;
|
|
70
|
+
private scripting?;
|
|
71
|
+
private lastError?;
|
|
72
|
+
private exitInfo?;
|
|
73
|
+
/** The end of CODESYS's own console output (for start-up errors). */
|
|
74
|
+
private output;
|
|
75
|
+
constructor(options: BridgeOptions);
|
|
76
|
+
get currentState(): BridgeState;
|
|
77
|
+
/** Start CODESYS + watcher (idempotent). Resolves when the watcher is ready. */
|
|
78
|
+
start(): Promise<void>;
|
|
79
|
+
/** Wait at most `ms` for the bridge to be ready; false if still starting. */
|
|
80
|
+
waitReady(ms: number): Promise<boolean>;
|
|
81
|
+
private doStart;
|
|
82
|
+
/** Run one watcher op. Calls are serialised; the watcher is single-threaded. */
|
|
83
|
+
call<T = unknown>(op: string, args?: Record<string, unknown>, opts?: {
|
|
84
|
+
timeoutMs?: number;
|
|
85
|
+
}): Promise<T>;
|
|
86
|
+
private exchange;
|
|
87
|
+
readHeartbeat(): (Heartbeat & {
|
|
88
|
+
ageMs: number;
|
|
89
|
+
}) | undefined;
|
|
90
|
+
/** The end of what the program printed, for error messages. */
|
|
91
|
+
private consoleTail;
|
|
92
|
+
/** The title of a dialog the watcher found CODESYS waiting on (dialog.json). */
|
|
93
|
+
private pendingDialog;
|
|
94
|
+
private verdict;
|
|
95
|
+
/** Snapshot that never waits on the watcher. */
|
|
96
|
+
health(): BridgeHealth;
|
|
97
|
+
/** Ask the watcher to exit, then make sure the process is gone. */
|
|
98
|
+
stop(): Promise<void>;
|
|
99
|
+
private kill;
|
|
100
|
+
/** Last lines of watcher.log, for error messages. */
|
|
101
|
+
logTail(lines?: number): string;
|
|
102
|
+
private log;
|
|
103
|
+
}
|
|
104
|
+
/** Remove session folders older than `maxAgeMs` (our own folders only). */
|
|
105
|
+
export declare function pruneSessions(root: string, maxAgeMs?: number): Promise<void>;
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent CODESYS bridge.
|
|
3
|
+
*
|
|
4
|
+
* Starts CODESYS once with `--runscript=watcher.py` and talks to the watcher
|
|
5
|
+
* through a file queue in a session folder:
|
|
6
|
+
* requests/<id>.json (written tmp + rename by us)
|
|
7
|
+
* results/<id>.json (written tmp + rename by the watcher)
|
|
8
|
+
* heartbeat.json (idle/busy + deadline, rewritten every second when idle)
|
|
9
|
+
* ready.json (written once the watcher loop runs)
|
|
10
|
+
* watcher.log
|
|
11
|
+
*
|
|
12
|
+
* Requests carry an op name and JSON arguments only; no code is generated.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn, execFile } from "node:child_process";
|
|
15
|
+
import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, statSync } from "node:fs";
|
|
16
|
+
import { readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { randomBytes } from "node:crypto";
|
|
19
|
+
export class BridgeError extends Error {
|
|
20
|
+
code;
|
|
21
|
+
detail;
|
|
22
|
+
constructor(code, message, detail) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.detail = detail;
|
|
26
|
+
this.name = "BridgeError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
30
|
+
/** What to do about a start-up failure CODESYS explains in its output. */
|
|
31
|
+
export function startupHint(output) {
|
|
32
|
+
if (/no script engine implementation/i.test(output))
|
|
33
|
+
return "This CODESYS installation has no scripting engine: add the \"CODESYS Scripting\" add-on to it with the CODESYS Installer. SP22 and later keep add-ons in an additional folder (CODESYS\\AdditionalFolders\\Default), which the toolkit passes as --additionalfolder: check it, or pass --codesys-additional-folder.\n";
|
|
34
|
+
if (/must specify a profile/i.test(output))
|
|
35
|
+
return "CODESYS didn't accept the profile: check --codesys-profile (a file name in CODESYS\\Profiles, without .profile.xml).\n";
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
const FILE_IN_USE = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
39
|
+
/**
|
|
40
|
+
* Run a file operation, retrying while Windows reports the file as in use (another
|
|
41
|
+
* process such as the watcher, an antivirus scan or the indexer has it open). That
|
|
42
|
+
* lasts milliseconds; after `totalMs` the last error is thrown. Other errors throw at once.
|
|
43
|
+
*/
|
|
44
|
+
async function retryFs(fn, totalMs = 3_000) {
|
|
45
|
+
const until = Date.now() + totalMs;
|
|
46
|
+
for (let delay = 5;; delay = Math.min(delay * 2, 100)) {
|
|
47
|
+
try {
|
|
48
|
+
return await fn();
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (!FILE_IN_USE.has(e.code ?? "") || Date.now() + delay > until)
|
|
52
|
+
throw e;
|
|
53
|
+
await sleep(delay);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export class CodesysBridge {
|
|
58
|
+
opts;
|
|
59
|
+
child;
|
|
60
|
+
state = "stopped";
|
|
61
|
+
startPromise;
|
|
62
|
+
sessionDir;
|
|
63
|
+
queue = Promise.resolve();
|
|
64
|
+
seq = 0;
|
|
65
|
+
calls = 0;
|
|
66
|
+
restarts = 0;
|
|
67
|
+
startedAt;
|
|
68
|
+
readyAt;
|
|
69
|
+
scripting;
|
|
70
|
+
lastError;
|
|
71
|
+
exitInfo;
|
|
72
|
+
/** The end of CODESYS's own console output (for start-up errors). */
|
|
73
|
+
output = "";
|
|
74
|
+
constructor(options) {
|
|
75
|
+
this.opts = {
|
|
76
|
+
noUI: true,
|
|
77
|
+
startupTimeoutMs: 300_000,
|
|
78
|
+
defaultTimeoutMs: 60_000,
|
|
79
|
+
hungGraceMs: 15_000,
|
|
80
|
+
staleHeartbeatMs: 15_000,
|
|
81
|
+
...options,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
get currentState() {
|
|
85
|
+
return this.state;
|
|
86
|
+
}
|
|
87
|
+
/** Start CODESYS + watcher (idempotent). Resolves when the watcher is ready. */
|
|
88
|
+
start() {
|
|
89
|
+
if (this.state === "ready")
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
if (this.startPromise)
|
|
92
|
+
return this.startPromise;
|
|
93
|
+
this.startPromise = this.doStart().finally(() => {
|
|
94
|
+
this.startPromise = undefined;
|
|
95
|
+
});
|
|
96
|
+
return this.startPromise;
|
|
97
|
+
}
|
|
98
|
+
/** Wait at most `ms` for the bridge to be ready; false if still starting. */
|
|
99
|
+
async waitReady(ms) {
|
|
100
|
+
if (this.state === "ready")
|
|
101
|
+
return true;
|
|
102
|
+
const p = this.start();
|
|
103
|
+
let timer;
|
|
104
|
+
const t = new Promise((r) => (timer = setTimeout(() => r(false), ms)));
|
|
105
|
+
try {
|
|
106
|
+
return await Promise.race([p.then(() => true), t]);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async doStart() {
|
|
113
|
+
if (this.state === "dead")
|
|
114
|
+
this.restarts++;
|
|
115
|
+
this.state = "starting";
|
|
116
|
+
this.exitInfo = undefined;
|
|
117
|
+
this.startedAt = Date.now();
|
|
118
|
+
this.readyAt = undefined;
|
|
119
|
+
const id = `${new Date().toISOString().replace(/[:.]/g, "-")}-${process.pid}-${randomBytes(3).toString("hex")}`;
|
|
120
|
+
const dir = join(this.opts.sessionRoot, id);
|
|
121
|
+
const scripts = join(dir, "scripts");
|
|
122
|
+
mkdirSync(join(dir, "requests"), { recursive: true });
|
|
123
|
+
mkdirSync(join(dir, "results"), { recursive: true });
|
|
124
|
+
mkdirSync(scripts, { recursive: true });
|
|
125
|
+
for (const f of readdirSync(this.opts.watcherSource)) {
|
|
126
|
+
if (f.endsWith(".py"))
|
|
127
|
+
copyFileSync(join(this.opts.watcherSource, f), join(scripts, f));
|
|
128
|
+
}
|
|
129
|
+
this.sessionDir = dir;
|
|
130
|
+
const script = join(scripts, "watcher.py");
|
|
131
|
+
const args = this.opts.args
|
|
132
|
+
? this.opts.args(script)
|
|
133
|
+
: [
|
|
134
|
+
...(this.opts.profile ? [`--profile="${this.opts.profile}"`] : []),
|
|
135
|
+
...(this.opts.noUI ? ["--noUI"] : []),
|
|
136
|
+
`--runscript="${script}"`,
|
|
137
|
+
...(this.opts.additionalFolder ? [`--additionalfolder="${this.opts.additionalFolder}"`] : []),
|
|
138
|
+
];
|
|
139
|
+
this.log(`starting ${this.opts.command} ${args.join(" ")}`);
|
|
140
|
+
const child = spawn(this.opts.command, args, {
|
|
141
|
+
env: {
|
|
142
|
+
...process.env,
|
|
143
|
+
...this.opts.env,
|
|
144
|
+
CODESYS_MCP_DIR: dir,
|
|
145
|
+
CODESYS_MCP_SCRIPTS: scripts,
|
|
146
|
+
CODESYS_MCP_PARENT_PID: String(process.pid),
|
|
147
|
+
},
|
|
148
|
+
// stdout/stderr are kept (the last 4 KB) so a failed start can say why.
|
|
149
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
150
|
+
windowsHide: true,
|
|
151
|
+
// CODESYS wants --option="value with spaces"; pass our own quoting through.
|
|
152
|
+
windowsVerbatimArguments: !this.opts.args,
|
|
153
|
+
});
|
|
154
|
+
this.child = child;
|
|
155
|
+
this.output = "";
|
|
156
|
+
const keep = (d) => {
|
|
157
|
+
this.output = (this.output + d.toString()).slice(-4096);
|
|
158
|
+
};
|
|
159
|
+
child.stdout?.on("data", keep);
|
|
160
|
+
child.stderr?.on("data", keep);
|
|
161
|
+
child.on("exit", (code, signal) => {
|
|
162
|
+
this.exitInfo = `exit code ${code ?? "?"}${signal ? ` signal ${signal}` : ""}`;
|
|
163
|
+
this.log(`CODESYS process ${child.pid} ended: ${this.exitInfo}`);
|
|
164
|
+
if (this.child === child) {
|
|
165
|
+
this.state = "dead";
|
|
166
|
+
this.child = undefined;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
child.on("error", (err) => {
|
|
170
|
+
this.exitInfo = err.message;
|
|
171
|
+
this.lastError = `spawn failed: ${err.message}`;
|
|
172
|
+
if (this.child === child) {
|
|
173
|
+
this.state = "dead";
|
|
174
|
+
this.child = undefined;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
const readyFile = join(dir, "ready.json");
|
|
178
|
+
const deadline = Date.now() + this.opts.startupTimeoutMs;
|
|
179
|
+
while (Date.now() < deadline) {
|
|
180
|
+
if (existsSync(readyFile)) {
|
|
181
|
+
this.state = "ready";
|
|
182
|
+
this.readyAt = Date.now();
|
|
183
|
+
try {
|
|
184
|
+
this.scripting = JSON.parse(readFileSync(readyFile, "utf8").replace(/^/, "")).scripting ?? undefined;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
this.scripting = undefined; // only used for display
|
|
188
|
+
}
|
|
189
|
+
this.log(`watcher ready after ${this.readyAt - this.startedAt}ms (pid ${child.pid})${this.scripting ? `, Scripting ${this.scripting}` : ""}`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (this.state === "dead") {
|
|
193
|
+
await sleep(200); // let the last output arrive
|
|
194
|
+
const msg = `CODESYS exited during startup (${this.exitInfo}). ${startupHint(this.output)}${this.consoleTail()}${this.logTail()}`;
|
|
195
|
+
this.lastError = msg;
|
|
196
|
+
throw new BridgeError("startup_failed", msg);
|
|
197
|
+
}
|
|
198
|
+
await sleep(100);
|
|
199
|
+
}
|
|
200
|
+
await this.kill("startup timeout");
|
|
201
|
+
const msg = `CODESYS did not start the watcher within ${Math.round(this.opts.startupTimeoutMs / 1000)}s. ${startupHint(this.output)}${this.consoleTail()}${this.logTail()}`;
|
|
202
|
+
this.lastError = msg;
|
|
203
|
+
throw new BridgeError("startup_timeout", msg);
|
|
204
|
+
}
|
|
205
|
+
/** Run one watcher op. Calls are serialised; the watcher is single-threaded. */
|
|
206
|
+
call(op, args = {}, opts = {}) {
|
|
207
|
+
const run = async () => {
|
|
208
|
+
await this.start();
|
|
209
|
+
return this.exchange(op, args, opts.timeoutMs ?? this.opts.defaultTimeoutMs);
|
|
210
|
+
};
|
|
211
|
+
const p = this.queue.then(run, run);
|
|
212
|
+
this.queue = p.catch(() => undefined);
|
|
213
|
+
return p;
|
|
214
|
+
}
|
|
215
|
+
async exchange(op, args, timeoutMs) {
|
|
216
|
+
const dir = this.sessionDir;
|
|
217
|
+
const id = `${String(++this.seq).padStart(8, "0")}-${randomBytes(2).toString("hex")}`;
|
|
218
|
+
const reqPath = join(dir, "requests", `${id}.json`);
|
|
219
|
+
const resPath = join(dir, "results", `${id}.json`);
|
|
220
|
+
await retryFs(() => writeFile(`${reqPath}.tmp`, JSON.stringify({ id, op, args, deadline_ms: timeoutMs }), "utf8"));
|
|
221
|
+
await retryFs(() => rename(`${reqPath}.tmp`, reqPath));
|
|
222
|
+
this.calls++;
|
|
223
|
+
const started = Date.now();
|
|
224
|
+
let lastCheck = 0;
|
|
225
|
+
for (;;) {
|
|
226
|
+
if (existsSync(resPath)) {
|
|
227
|
+
const raw = await retryFs(() => readFile(resPath, "utf8"));
|
|
228
|
+
await unlink(resPath).catch(() => undefined);
|
|
229
|
+
const res = JSON.parse(raw.replace(/^/, ""));
|
|
230
|
+
if (res.ok)
|
|
231
|
+
return res.result;
|
|
232
|
+
const e = res.error ?? { code: "unknown", message: "watcher returned no error details" };
|
|
233
|
+
throw new BridgeError(e.code, e.message, e.detail);
|
|
234
|
+
}
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
if (this.state === "dead") {
|
|
237
|
+
const msg = `CODESYS stopped while running '${op}' (${this.exitInfo ?? "unknown reason"}). ${this.consoleTail()}${this.logTail()}`;
|
|
238
|
+
this.lastError = msg;
|
|
239
|
+
throw new BridgeError("watcher_died", msg);
|
|
240
|
+
}
|
|
241
|
+
if (now - lastCheck > 1000) {
|
|
242
|
+
lastCheck = now;
|
|
243
|
+
const dialog = this.pendingDialog();
|
|
244
|
+
if (dialog) {
|
|
245
|
+
await this.kill(`dialog "${dialog}" during '${op}'`);
|
|
246
|
+
const msg = `CODESYS opened a dialog ("${dialog}") during '${op}' and is waiting for an answer, which a session without a window can't give. CODESYS was stopped and will restart on the next call; unsaved changes are lost. Do the same step once in the CODESYS window and answer the dialog there, then try again.`;
|
|
247
|
+
this.lastError = msg;
|
|
248
|
+
throw new BridgeError("dialog", msg);
|
|
249
|
+
}
|
|
250
|
+
const v = this.verdict();
|
|
251
|
+
if (v === "hung") {
|
|
252
|
+
await this.kill(`hung during '${op}'`);
|
|
253
|
+
const msg = `CODESYS stopped responding during '${op}' and was restarted on the next call. Unsaved changes are lost.`;
|
|
254
|
+
this.lastError = msg;
|
|
255
|
+
throw new BridgeError("hung", msg);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (now - started > timeoutMs + this.opts.hungGraceMs) {
|
|
259
|
+
await this.kill(`timeout in '${op}'`);
|
|
260
|
+
const msg = `'${op}' took longer than ${Math.round(timeoutMs / 1000)}s; CODESYS was stopped and will restart on the next call.`;
|
|
261
|
+
this.lastError = msg;
|
|
262
|
+
throw new BridgeError("timeout", msg);
|
|
263
|
+
}
|
|
264
|
+
await sleep(now - started < 1000 ? 10 : 40);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
readHeartbeat() {
|
|
268
|
+
if (!this.sessionDir)
|
|
269
|
+
return undefined;
|
|
270
|
+
try {
|
|
271
|
+
const hb = JSON.parse(readFileSync(join(this.sessionDir, "heartbeat.json"), "utf8").replace(/^/, ""));
|
|
272
|
+
return { ...hb, ageMs: Math.max(0, Date.now() - hb.ts * 1000) };
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** The end of what the program printed, for error messages. */
|
|
279
|
+
consoleTail() {
|
|
280
|
+
const said = this.output.trim();
|
|
281
|
+
return said ? `CODESYS said: ${said.slice(-800)}\n` : "";
|
|
282
|
+
}
|
|
283
|
+
/** The title of a dialog the watcher found CODESYS waiting on (dialog.json). */
|
|
284
|
+
pendingDialog() {
|
|
285
|
+
if (!this.sessionDir)
|
|
286
|
+
return undefined;
|
|
287
|
+
const file = join(this.sessionDir, "dialog.json");
|
|
288
|
+
if (!existsSync(file))
|
|
289
|
+
return undefined;
|
|
290
|
+
try {
|
|
291
|
+
return JSON.parse(readFileSync(file, "utf8").replace(/^/, "")).title ?? "untitled";
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return undefined; // held for a moment: the next check reads it
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
verdict() {
|
|
298
|
+
if (this.state === "stopped")
|
|
299
|
+
return "stopped";
|
|
300
|
+
if (this.state === "dead")
|
|
301
|
+
return "dead";
|
|
302
|
+
if (this.state === "starting")
|
|
303
|
+
return "starting";
|
|
304
|
+
const hb = this.readHeartbeat();
|
|
305
|
+
if (!hb)
|
|
306
|
+
return "healthy";
|
|
307
|
+
if (hb.state === "crashed" || hb.state === "stopped")
|
|
308
|
+
return "dead";
|
|
309
|
+
if (hb.state === "busy") {
|
|
310
|
+
if (hb.deadline && Date.now() > hb.deadline * 1000 + this.opts.hungGraceMs)
|
|
311
|
+
return "hung";
|
|
312
|
+
return "busy";
|
|
313
|
+
}
|
|
314
|
+
return hb.ageMs > this.opts.staleHeartbeatMs ? "hung" : "healthy";
|
|
315
|
+
}
|
|
316
|
+
/** Snapshot that never waits on the watcher. */
|
|
317
|
+
health() {
|
|
318
|
+
return {
|
|
319
|
+
state: this.state,
|
|
320
|
+
pid: this.child?.pid,
|
|
321
|
+
sessionDir: this.sessionDir,
|
|
322
|
+
startedAt: this.startedAt ? new Date(this.startedAt).toISOString() : undefined,
|
|
323
|
+
readyAfterMs: this.readyAt && this.startedAt ? this.readyAt - this.startedAt : undefined,
|
|
324
|
+
scripting: this.scripting,
|
|
325
|
+
heartbeat: this.readHeartbeat(),
|
|
326
|
+
verdict: this.verdict(),
|
|
327
|
+
calls: this.calls,
|
|
328
|
+
lastError: this.lastError,
|
|
329
|
+
restarts: this.restarts,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/** Ask the watcher to exit, then make sure the process is gone. */
|
|
333
|
+
async stop() {
|
|
334
|
+
if (this.state === "ready" && this.child) {
|
|
335
|
+
try {
|
|
336
|
+
await this.exchange("shutdown", {}, 5_000);
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
/* fall through to kill */
|
|
340
|
+
}
|
|
341
|
+
const until = Date.now() + 10_000;
|
|
342
|
+
while (this.child && Date.now() < until)
|
|
343
|
+
await sleep(100);
|
|
344
|
+
}
|
|
345
|
+
await this.kill("stop");
|
|
346
|
+
this.state = "stopped";
|
|
347
|
+
}
|
|
348
|
+
async kill(reason) {
|
|
349
|
+
const child = this.child;
|
|
350
|
+
if (!child?.pid) {
|
|
351
|
+
if (this.state !== "stopped")
|
|
352
|
+
this.state = "dead";
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.log(`killing CODESYS ${child.pid}: ${reason}`);
|
|
356
|
+
if (process.platform === "win32") {
|
|
357
|
+
await new Promise((r) => execFile("taskkill", ["/PID", String(child.pid), "/T", "/F"], () => r()));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
child.kill("SIGKILL");
|
|
361
|
+
}
|
|
362
|
+
const until = Date.now() + 5_000;
|
|
363
|
+
while (this.child === child && Date.now() < until)
|
|
364
|
+
await sleep(50);
|
|
365
|
+
this.child = undefined;
|
|
366
|
+
this.state = "dead";
|
|
367
|
+
}
|
|
368
|
+
/** Last lines of watcher.log, for error messages. */
|
|
369
|
+
logTail(lines = 5) {
|
|
370
|
+
if (!this.sessionDir)
|
|
371
|
+
return "";
|
|
372
|
+
try {
|
|
373
|
+
const txt = readFileSync(join(this.sessionDir, "watcher.log"), "utf8").trim().split(/\r?\n/);
|
|
374
|
+
return `watcher.log: ${txt.slice(-lines).join(" | ")}`;
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return "(no watcher.log yet)";
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
log(msg) {
|
|
381
|
+
this.opts.log?.(`[bridge] ${msg}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/** Remove session folders older than `maxAgeMs` (our own folders only). */
|
|
385
|
+
export async function pruneSessions(root, maxAgeMs = 2 * 24 * 3600_000) {
|
|
386
|
+
if (!existsSync(root))
|
|
387
|
+
return;
|
|
388
|
+
for (const name of readdirSync(root)) {
|
|
389
|
+
const p = join(root, name);
|
|
390
|
+
try {
|
|
391
|
+
if (statSync(p).isDirectory() && Date.now() - statSync(p).mtimeMs > maxAgeMs && existsSync(join(p, "scripts", "watcher.py"))) {
|
|
392
|
+
await rm(p, { recursive: true, force: true });
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
/* ignore */
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/bridge/bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED