@codesys/mcp-toolkit 1.5.8 → 2.0.0-alpha.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 +224 -107
- 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 +37 -21
- 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
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One shared CODESYS session per configuration.
|
|
3
|
+
*
|
|
4
|
+
* Claude Desktop can start the server several times (one process per chat
|
|
5
|
+
* surface). Each process used to launch its own CODESYS, so the panel card
|
|
6
|
+
* could talk to a process that never opened the project. Now the first
|
|
7
|
+
* process starts a background owner (the same CLI with --daemon) that runs
|
|
8
|
+
* CODESYS and the browser viewer; every stdio process just pipes its
|
|
9
|
+
* MCP traffic to the owner over a local socket. The owner stops itself when
|
|
10
|
+
* no client has been connected for a while.
|
|
11
|
+
*
|
|
12
|
+
* The owner listens on 127.0.0.1 only and requires a random token, which is
|
|
13
|
+
* in a file under the user's profile.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
16
|
+
import { mkdirSync, openSync, closeSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
17
|
+
import net from "node:net";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
export function sessionKey(parts) {
|
|
20
|
+
return createHash("sha256").update(JSON.stringify(parts)).digest("hex").slice(0, 12);
|
|
21
|
+
}
|
|
22
|
+
export function daemonPaths(dir, key) {
|
|
23
|
+
return { info: join(dir, `daemon-${key}.json`), lock: join(dir, `daemon-${key}.lock`), log: join(dir, `daemon-${key}.log`) };
|
|
24
|
+
}
|
|
25
|
+
function readInfo(file) {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function alive(pid) {
|
|
34
|
+
try {
|
|
35
|
+
process.kill(pid, 0);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
return e.code === "EPERM";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
43
|
+
/**
|
|
44
|
+
* Run the owner's listener. Each client that sends the token on its first line
|
|
45
|
+
* is handed to onConnection with the rest of its stream. onIdle runs once no
|
|
46
|
+
* client has been connected for idleMs.
|
|
47
|
+
*/
|
|
48
|
+
export async function serveDaemon(o) {
|
|
49
|
+
const token = randomUUID();
|
|
50
|
+
const paths = daemonPaths(o.dir, o.key);
|
|
51
|
+
let clients = 0;
|
|
52
|
+
let idle;
|
|
53
|
+
const armIdle = () => {
|
|
54
|
+
clearTimeout(idle);
|
|
55
|
+
if (clients === 0)
|
|
56
|
+
idle = setTimeout(o.onIdle, o.idleMs);
|
|
57
|
+
};
|
|
58
|
+
const server = net.createServer((socket) => {
|
|
59
|
+
socket.on("error", () => undefined);
|
|
60
|
+
let buf = Buffer.alloc(0);
|
|
61
|
+
const onData = (d) => {
|
|
62
|
+
buf = Buffer.concat([buf, d]);
|
|
63
|
+
const nl = buf.indexOf(10);
|
|
64
|
+
if (nl < 0) {
|
|
65
|
+
if (buf.length > 256)
|
|
66
|
+
socket.destroy();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
socket.off("data", onData);
|
|
70
|
+
socket.pause();
|
|
71
|
+
if (buf.subarray(0, nl).toString("utf8").trim() !== token) {
|
|
72
|
+
socket.destroy();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const rest = buf.subarray(nl + 1);
|
|
76
|
+
if (rest.length)
|
|
77
|
+
socket.unshift(rest);
|
|
78
|
+
clients++;
|
|
79
|
+
clearTimeout(idle);
|
|
80
|
+
socket.on("close", () => {
|
|
81
|
+
clients--;
|
|
82
|
+
armIdle();
|
|
83
|
+
});
|
|
84
|
+
o.onConnection(socket)
|
|
85
|
+
.then(() => socket.resume())
|
|
86
|
+
.catch((e) => {
|
|
87
|
+
o.log(`client failed: ${e.message}`);
|
|
88
|
+
socket.destroy();
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
socket.on("data", onData);
|
|
92
|
+
});
|
|
93
|
+
await new Promise((res, rej) => {
|
|
94
|
+
server.once("error", rej);
|
|
95
|
+
server.listen(0, "127.0.0.1", () => res());
|
|
96
|
+
});
|
|
97
|
+
const info = { pid: process.pid, port: server.address().port, token, key: o.key, started: new Date().toISOString() };
|
|
98
|
+
mkdirSync(o.dir, { recursive: true });
|
|
99
|
+
try {
|
|
100
|
+
// Exclusive: if two owners race, the second one gives up.
|
|
101
|
+
writeFileSync(paths.info, JSON.stringify(info), { flag: "wx", mode: 0o600 });
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
server.close();
|
|
105
|
+
throw new Error(`another process owns this session (${paths.info})`);
|
|
106
|
+
}
|
|
107
|
+
armIdle();
|
|
108
|
+
return {
|
|
109
|
+
info,
|
|
110
|
+
close: () => {
|
|
111
|
+
server.close();
|
|
112
|
+
// Only remove the file if it is still ours.
|
|
113
|
+
if (readInfo(paths.info)?.token === token)
|
|
114
|
+
rmSync(paths.info, { force: true });
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function tryConnect(info) {
|
|
119
|
+
return new Promise((resolve) => {
|
|
120
|
+
const s = net.connect(info.port, "127.0.0.1");
|
|
121
|
+
s.once("connect", () => {
|
|
122
|
+
s.write(`${info.token}\n`);
|
|
123
|
+
resolve(s);
|
|
124
|
+
});
|
|
125
|
+
s.once("error", () => resolve(undefined));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Connect to the owner of this session, starting it if there is none.
|
|
130
|
+
* Several processes may start at the same moment; a lock file makes exactly
|
|
131
|
+
* one of them spawn the owner, and the rest wait for it.
|
|
132
|
+
*/
|
|
133
|
+
export async function connectDaemon(o) {
|
|
134
|
+
const paths = daemonPaths(o.dir, o.key);
|
|
135
|
+
mkdirSync(o.dir, { recursive: true });
|
|
136
|
+
const deadline = Date.now() + (o.waitMs ?? 20_000);
|
|
137
|
+
let spawned = false;
|
|
138
|
+
while (Date.now() < deadline) {
|
|
139
|
+
const info = readInfo(paths.info);
|
|
140
|
+
if (info) {
|
|
141
|
+
const socket = await tryConnect(info);
|
|
142
|
+
if (socket) {
|
|
143
|
+
if (spawned)
|
|
144
|
+
rmSync(paths.lock, { force: true });
|
|
145
|
+
return { socket, info, spawned, log: paths.log };
|
|
146
|
+
}
|
|
147
|
+
if (!alive(info.pid))
|
|
148
|
+
rmSync(paths.info, { force: true });
|
|
149
|
+
}
|
|
150
|
+
else if (!spawned) {
|
|
151
|
+
try {
|
|
152
|
+
closeSync(openSync(paths.lock, "wx"));
|
|
153
|
+
spawned = true;
|
|
154
|
+
o.spawnDaemon(paths.log);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Someone else is starting it; a lock older than 30 s is left over from a crash.
|
|
158
|
+
try {
|
|
159
|
+
if (Date.now() - statSync(paths.lock).mtimeMs > 30_000)
|
|
160
|
+
rmSync(paths.lock, { force: true });
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
/* gone already */
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
await sleep(150);
|
|
168
|
+
}
|
|
169
|
+
if (spawned)
|
|
170
|
+
rmSync(paths.lock, { force: true });
|
|
171
|
+
throw new Error(`no shared session came up within ${Math.round((o.waitMs ?? 20_000) / 1000)} s (see ${paths.log})`);
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/driver.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who drives: Claude or the user. "Pause Claude" in the panel holds Claude's
|
|
3
|
+
* tools that change the project or the simulation, so the user can explore
|
|
4
|
+
* without Claude acting at the same time. Reads stay allowed.
|
|
5
|
+
*/
|
|
6
|
+
/** The panel view that fits what Claude is doing. "review" is decided by the panel. */
|
|
7
|
+
export type View = "code";
|
|
8
|
+
/** Which view a tool belongs to (undefined for reads, which don't move the panel). */
|
|
9
|
+
export declare function viewOf(tool: string): View | undefined;
|
|
10
|
+
export declare class Driver {
|
|
11
|
+
held: boolean;
|
|
12
|
+
since?: string;
|
|
13
|
+
/** What Claude did last that moves the panel, and when (ms since epoch). */
|
|
14
|
+
phase?: {
|
|
15
|
+
view: View;
|
|
16
|
+
tool: string;
|
|
17
|
+
at: number;
|
|
18
|
+
};
|
|
19
|
+
/** When Claude last called any tool (ms since epoch). */
|
|
20
|
+
lastCallAt?: number;
|
|
21
|
+
/** Called for every tool Claude calls. */
|
|
22
|
+
note(tool: string): void;
|
|
23
|
+
hold(on: boolean): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function heldMessage(d: Driver, tool: string): string;
|
package/dist/driver.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who drives: Claude or the user. "Pause Claude" in the panel holds Claude's
|
|
3
|
+
* tools that change the project or the simulation, so the user can explore
|
|
4
|
+
* without Claude acting at the same time. Reads stay allowed.
|
|
5
|
+
*/
|
|
6
|
+
const CODE_TOOLS = new Set(["open_project", "create_project", "write_object", "create_object", "delete_object", "rename_object", "revert_object", "compile", "add_library", "remove_library", "configure_task"]);
|
|
7
|
+
/** Which view a tool belongs to (undefined for reads, which don't move the panel). */
|
|
8
|
+
export function viewOf(tool) {
|
|
9
|
+
return CODE_TOOLS.has(tool) ? "code" : undefined;
|
|
10
|
+
}
|
|
11
|
+
export class Driver {
|
|
12
|
+
held = false;
|
|
13
|
+
since;
|
|
14
|
+
/** What Claude did last that moves the panel, and when (ms since epoch). */
|
|
15
|
+
phase;
|
|
16
|
+
/** When Claude last called any tool (ms since epoch). */
|
|
17
|
+
lastCallAt;
|
|
18
|
+
/** Called for every tool Claude calls. */
|
|
19
|
+
note(tool) {
|
|
20
|
+
this.lastCallAt = Date.now();
|
|
21
|
+
const view = viewOf(tool);
|
|
22
|
+
if (view)
|
|
23
|
+
this.phase = { view, tool, at: this.lastCallAt };
|
|
24
|
+
}
|
|
25
|
+
hold(on) {
|
|
26
|
+
this.held = on;
|
|
27
|
+
this.since = on ? new Date().toISOString() : undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function heldMessage(d, tool) {
|
|
31
|
+
return `paused_by_user: The user paused Claude in the panel (since ${d.since}), so ${tool} is held. Wait for them to resume, or ask in the chat what they found. Reading tools still work.`;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEjN,sFAAsF;AACtF,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACnD,CAAC;AAED,MAAM,OAAO,MAAM;IACjB,IAAI,GAAG,KAAK,CAAC;IACb,KAAK,CAAU;IACf,4EAA4E;IAC5E,KAAK,CAA4C;IAEjD,yDAAyD;IACzD,UAAU,CAAU;IAEpB,0CAA0C;IAC1C,IAAI,CAAC,IAAY;QACf,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,IAAI;YAAE,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC,EAAW;QACd,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;CACF;AAED,MAAM,UAAU,WAAW,CAAC,CAAS,EAAE,IAAY;IACjD,OAAO,8DAA8D,CAAC,CAAC,KAAK,SAAS,IAAI,kGAAkG,CAAC;AAC9L,CAAC"}
|