@codesys/mcp-toolkit 1.5.7 → 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.
Files changed (109) hide show
  1. package/CHANGELOG.md +153 -183
  2. package/LICENSE +21 -21
  3. package/README.md +224 -107
  4. package/dist/actions.d.ts +28 -0
  5. package/dist/actions.js +98 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/bridge/bridge.d.ts +105 -0
  8. package/dist/bridge/bridge.js +400 -0
  9. package/dist/bridge/bridge.js.map +1 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.js +196 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/codesys/cache.d.ts +48 -0
  14. package/dist/codesys/cache.js +82 -0
  15. package/dist/codesys/cache.js.map +1 -0
  16. package/dist/codesys/changes.d.ts +57 -0
  17. package/dist/codesys/changes.js +133 -0
  18. package/dist/codesys/changes.js.map +1 -0
  19. package/dist/codesys/decl.d.ts +45 -0
  20. package/dist/codesys/decl.js +251 -0
  21. package/dist/codesys/decl.js.map +1 -0
  22. package/dist/codesys/devices.d.ts +34 -0
  23. package/dist/codesys/devices.js +82 -0
  24. package/dist/codesys/devices.js.map +1 -0
  25. package/dist/codesys/diff.d.ts +13 -0
  26. package/dist/codesys/diff.js +61 -0
  27. package/dist/codesys/diff.js.map +1 -0
  28. package/dist/codesys/install.d.ts +40 -0
  29. package/dist/codesys/install.js +144 -0
  30. package/dist/codesys/install.js.map +1 -0
  31. package/dist/codesys/library-browse.d.ts +19 -0
  32. package/dist/codesys/library-browse.js +57 -0
  33. package/dist/codesys/library-browse.js.map +1 -0
  34. package/dist/codesys/outline.d.ts +32 -0
  35. package/dist/codesys/outline.js +219 -0
  36. package/dist/codesys/outline.js.map +1 -0
  37. package/dist/codesys/simulation.d.ts +34 -0
  38. package/dist/codesys/simulation.js +57 -0
  39. package/dist/codesys/simulation.js.map +1 -0
  40. package/dist/codesys/st.d.ts +36 -0
  41. package/dist/codesys/st.js +69 -0
  42. package/dist/codesys/st.js.map +1 -0
  43. package/dist/daemon.d.ts +46 -0
  44. package/dist/daemon.js +173 -0
  45. package/dist/daemon.js.map +1 -0
  46. package/dist/driver.d.ts +25 -0
  47. package/dist/driver.js +33 -0
  48. package/dist/driver.js.map +1 -0
  49. package/dist/panel/sim-panel.html +357 -0
  50. package/dist/panel/viewer.html +126 -0
  51. package/dist/panel-types.d.ts +20 -0
  52. package/dist/panel-types.js +3 -0
  53. package/dist/panel-types.js.map +1 -0
  54. package/dist/panel.d.ts +27 -0
  55. package/dist/panel.js +208 -0
  56. package/dist/panel.js.map +1 -0
  57. package/dist/server.d.ts +5 -0
  58. package/dist/server.js +33 -941
  59. package/dist/server.js.map +1 -0
  60. package/dist/tools.d.ts +103 -0
  61. package/dist/tools.js +793 -0
  62. package/dist/tools.js.map +1 -0
  63. package/dist/viewer.d.ts +14 -0
  64. package/dist/viewer.js +125 -0
  65. package/dist/viewer.js.map +1 -0
  66. package/package.json +37 -21
  67. package/watcher/mcp_compat.py +147 -0
  68. package/watcher/mcp_ops.py +1178 -0
  69. package/watcher/mcp_sim.py +246 -0
  70. package/watcher/watcher.py +255 -0
  71. package/.claude/settings.local.json +0 -29
  72. package/CLAUDE.md +0 -26
  73. package/CONTRIBUTING.md +0 -72
  74. package/README.md.enhanced +0 -155
  75. package/codesys-mcp-toolkit-1.2.0.tgz +0 -0
  76. package/codesys-mcp-toolkit-1.2.1.tgz +0 -0
  77. package/codesys-mcp-toolkit-1.5.7.tgz +0 -0
  78. package/dist/bin.js +0 -75
  79. package/dist/check_session_paths.js +0 -149
  80. package/dist/codesys_interop.js +0 -435
  81. package/dist/direct_session_command.js +0 -293
  82. package/dist/scriptLoader.js +0 -165
  83. package/dist/scripts/check_status.py +0 -21
  84. package/dist/scripts/compile_project.py +0 -65
  85. package/dist/scripts/create_method.py +0 -80
  86. package/dist/scripts/create_pou.py +0 -102
  87. package/dist/scripts/create_project.py +0 -116
  88. package/dist/scripts/create_property.py +0 -78
  89. package/dist/scripts/ensure_project_open.py +0 -154
  90. package/dist/scripts/find_object_by_path.py +0 -111
  91. package/dist/scripts/get_pou_code.py +0 -91
  92. package/dist/scripts/get_project_structure.py +0 -72
  93. package/dist/scripts/open_project.py +0 -25
  94. package/dist/scripts/save_project.py +0 -29
  95. package/dist/scripts/session_status.py +0 -281
  96. package/dist/scripts/set_pou_code.py +0 -109
  97. package/dist/scripts/start_session.py +0 -809
  98. package/dist/scripts/stop_session.py +0 -324
  99. package/dist/sessionManager.js +0 -798
  100. package/docs/configuration.md +0 -141
  101. package/docs/index.md +0 -26
  102. package/docs/installation.md +0 -84
  103. package/docs/session_management.md +0 -110
  104. package/examples/README.md +0 -78
  105. package/examples/sample_config.json +0 -32
  106. package/replacements_session_status.txt +0 -16
  107. package/scriptDoc.txt +0 -8679
  108. package/scripts/build.js +0 -25
  109. 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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"}
@@ -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"}