@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.
Files changed (110) hide show
  1. package/CHANGELOG.md +153 -189
  2. package/LICENSE +21 -21
  3. package/README.md +269 -152
  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 -974
  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 +66 -51
  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/codesys-mcp-toolkit-1.5.8.tgz +0 -0
  79. package/dist/bin.js +0 -75
  80. package/dist/check_session_paths.js +0 -149
  81. package/dist/codesys_interop.js +0 -435
  82. package/dist/direct_session_command.js +0 -293
  83. package/dist/scriptLoader.js +0 -165
  84. package/dist/scripts/check_status.py +0 -21
  85. package/dist/scripts/compile_project.py +0 -65
  86. package/dist/scripts/create_method.py +0 -80
  87. package/dist/scripts/create_pou.py +0 -102
  88. package/dist/scripts/create_project.py +0 -116
  89. package/dist/scripts/create_property.py +0 -78
  90. package/dist/scripts/ensure_project_open.py +0 -154
  91. package/dist/scripts/find_object_by_path.py +0 -111
  92. package/dist/scripts/get_pou_code.py +0 -91
  93. package/dist/scripts/get_project_structure.py +0 -72
  94. package/dist/scripts/open_project.py +0 -25
  95. package/dist/scripts/save_project.py +0 -29
  96. package/dist/scripts/session_status.py +0 -281
  97. package/dist/scripts/set_pou_code.py +0 -109
  98. package/dist/scripts/start_session.py +0 -809
  99. package/dist/scripts/stop_session.py +0 -324
  100. package/dist/sessionManager.js +0 -798
  101. package/docs/configuration.md +0 -141
  102. package/docs/index.md +0 -26
  103. package/docs/installation.md +0 -84
  104. package/docs/session_management.md +0 -110
  105. package/examples/README.md +0 -78
  106. package/examples/sample_config.json +0 -32
  107. package/replacements_session_status.txt +0 -16
  108. package/scriptDoc.txt +0 -8679
  109. package/scripts/build.js +0 -25
  110. package/scripts/fix_fstrings.py +0 -76
package/dist/cli.js ADDED
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * codesys-mcp-tool: stdio MCP server for CODESYS V3.5.
4
+ *
5
+ * Options (v1 names kept where they existed):
6
+ * --codesys-path <exe> CODESYS.exe (default: newest install under Program Files)
7
+ * --codesys-profile <name> profile, e.g. "CODESYS V3.5 SP21" (default: the install's newest)
8
+ * --workspace <dir> base folder for relative project paths (default: cwd)
9
+ * --project <file> open this project once CODESYS is up
10
+ * --session-dir <dir> where session folders go (default: %TEMP%\codesys-mcp-toolkit)
11
+ * --no-autostart start CODESYS on the first tool call instead of at launch
12
+ * --no-autosave don't save after each change (use save_project)
13
+ * --viewer-port <port> port of the browser viewer on 127.0.0.1 (default 5180, next free one if taken)
14
+ * --no-viewer don't serve the browser viewer
15
+ * --no-shared run CODESYS in this process instead of the shared session
16
+ *
17
+ * By default every process started with the same options shares one session
18
+ * (one CODESYS, one viewer): see daemon.ts.
19
+ */
20
+ import { spawn } from "node:child_process";
21
+ import { openSync, statSync } from "node:fs";
22
+ import { parseArgs } from "node:util";
23
+ import { tmpdir } from "node:os";
24
+ import { dirname, join, resolve } from "node:path";
25
+ import { fileURLToPath } from "node:url";
26
+ import { serveStdio, StdioServerTransport } from "@modelcontextprotocol/server/stdio";
27
+ import { CodesysBridge, pruneSessions } from "./bridge/bridge.js";
28
+ import { ensureWorkspace, resolveCodesys } from "./codesys/install.js";
29
+ import { createServer, VERSION } from "./server.js";
30
+ import { ChangeStore } from "./codesys/changes.js";
31
+ import { ProjectCache } from "./codesys/cache.js";
32
+ import { Driver } from "./driver.js";
33
+ import { startViewer } from "./viewer.js";
34
+ import { connectDaemon, serveDaemon, sessionKey } from "./daemon.js";
35
+ const log = (m) => process.stderr.write(`[codesys-mcp] ${m}\n`);
36
+ /** Options from when the toolkit simulated in truST. Still accepted, so existing client setups keep starting. */
37
+ const REMOVED_OPTIONS = ["trust-runtime", "mirror-dir", "no-sim"];
38
+ async function main() {
39
+ const { values } = parseArgs({
40
+ options: {
41
+ "codesys-path": { type: "string" },
42
+ "codesys-profile": { type: "string" },
43
+ "codesys-additional-folder": { type: "string" },
44
+ workspace: { type: "string" },
45
+ project: { type: "string" },
46
+ "session-dir": { type: "string" },
47
+ "no-autostart": { type: "boolean" },
48
+ "no-autosave": { type: "boolean" },
49
+ "viewer-port": { type: "string" },
50
+ "no-viewer": { type: "boolean" },
51
+ "no-shared": { type: "boolean" },
52
+ "trust-runtime": { type: "string" },
53
+ "mirror-dir": { type: "string" },
54
+ "no-sim": { type: "boolean" },
55
+ // internal: run as the shared session's owner (see daemon.ts)
56
+ daemon: { type: "string" },
57
+ version: { type: "boolean" },
58
+ help: { type: "boolean", short: "h" },
59
+ },
60
+ strict: true,
61
+ });
62
+ if (values.version) {
63
+ process.stdout.write(`${VERSION}\n`);
64
+ return;
65
+ }
66
+ if (values.help) {
67
+ process.stdout.write("codesys-mcp-tool [--codesys-path <CODESYS.exe>] [--codesys-profile <name>] [--codesys-additional-folder <dir>] [--workspace <dir>] [--project <file>] [--session-dir <dir>] [--no-autostart] [--no-autosave] [--viewer-port <port>] [--no-viewer] [--no-shared]\n");
68
+ return;
69
+ }
70
+ const stateDir = process.env.CODESYS_MCP_STATE_DIR ?? join(process.env.LOCALAPPDATA ?? tmpdir(), "codesys-mcp-toolkit");
71
+ const cliFile = fileURLToPath(import.meta.url);
72
+ // Processes with the same options (and the same build) share a session.
73
+ const forward = process.argv.slice(2).filter((a) => a !== "--no-shared" && !a.startsWith("--daemon"));
74
+ const key = sessionKey({
75
+ args: forward,
76
+ cwd: process.cwd(),
77
+ version: VERSION,
78
+ build: statSync(cliFile).mtimeMs,
79
+ env: [],
80
+ });
81
+ if (values.daemon === undefined && !values["no-shared"]) {
82
+ try {
83
+ const c = await connectDaemon({
84
+ dir: stateDir,
85
+ key,
86
+ spawnDaemon: (logFile) => {
87
+ const out = openSync(logFile, "a");
88
+ spawn(process.execPath, [cliFile, ...forward, `--daemon=${key}`], { detached: true, stdio: ["ignore", out, out], windowsHide: true, cwd: process.cwd(), env: process.env }).unref();
89
+ },
90
+ });
91
+ log(`${c.spawned ? "started" : "joined"} the shared CODESYS session (pid ${c.info.pid}; log ${c.log})`);
92
+ process.stdin.pipe(c.socket);
93
+ c.socket.pipe(process.stdout);
94
+ c.socket.on("close", () => process.exit(0));
95
+ process.stdin.on("end", () => c.socket.end());
96
+ return;
97
+ }
98
+ catch (e) {
99
+ log(`shared session unavailable (${e.message}); running in this process`);
100
+ }
101
+ }
102
+ const codesys = resolveCodesys(values["codesys-path"], values["codesys-profile"], values["codesys-additional-folder"]);
103
+ const watcherSource = join(dirname(fileURLToPath(import.meta.url)), "..", "watcher");
104
+ const sessionRoot = values["session-dir"] ?? join(tmpdir(), "codesys-mcp-toolkit");
105
+ await pruneSessions(sessionRoot);
106
+ const bridge = new CodesysBridge({
107
+ command: codesys.exe,
108
+ profile: codesys.profile,
109
+ additionalFolder: codesys.install.additionalFolder,
110
+ watcherSource,
111
+ sessionRoot,
112
+ log,
113
+ });
114
+ const ctx = {
115
+ bridge,
116
+ autosave: !values["no-autosave"],
117
+ workspace: ensureWorkspace(resolve(values.workspace ?? process.cwd()), log),
118
+ templatesDir: codesys.install.templatesDir,
119
+ codesys: { exe: codesys.exe, profile: codesys.profile, label: codesys.install.label },
120
+ startWaitMs: 90_000,
121
+ log,
122
+ };
123
+ ctx.changes = new ChangeStore(join(process.env.LOCALAPPDATA ?? tmpdir(), "codesys-mcp-toolkit", "checkpoints"));
124
+ ctx.cache = new ProjectCache();
125
+ ctx.driver = new Driver();
126
+ const ignored = REMOVED_OPTIONS.filter((o) => values[o] !== undefined);
127
+ if (ignored.length)
128
+ log(`ignoring ${ignored.map((o) => `--${o}`).join(", ")}: truST support was removed`);
129
+ if (codesys.warning)
130
+ log(`warning: ${codesys.warning}`);
131
+ log(`v${VERSION}: ${codesys.install.label} (${codesys.reason}), profile "${codesys.profile}"${codesys.install.additionalFolder ? `, add-ons in ${codesys.install.additionalFolder}` : ""}, sessions in ${sessionRoot}`);
132
+ if (!values["no-viewer"]) {
133
+ try {
134
+ ctx.viewer = await startViewer(ctx, { port: values["viewer-port"] ? Number(values["viewer-port"]) : undefined, log });
135
+ }
136
+ catch (e) {
137
+ log(`viewer not started: ${e.message}`);
138
+ }
139
+ }
140
+ let stopping = false;
141
+ let closeShared;
142
+ let handle;
143
+ const shutdown = async () => {
144
+ if (stopping)
145
+ return;
146
+ stopping = true;
147
+ closeShared?.();
148
+ await bridge.stop().catch(() => undefined);
149
+ await handle?.close();
150
+ process.exit(0);
151
+ };
152
+ if (values.daemon !== undefined) {
153
+ // The shared session's owner: serve every client that connects, stop when idle.
154
+ const idleMs = Number(process.env.CODESYS_MCP_IDLE_MS ?? 120_000);
155
+ const owner = await serveDaemon({
156
+ dir: stateDir,
157
+ key: values.daemon || key,
158
+ idleMs,
159
+ log,
160
+ onIdle: () => {
161
+ log(`no clients for ${Math.round(idleMs / 1000)} s: stopping`);
162
+ void shutdown();
163
+ },
164
+ onConnection: async (socket) => {
165
+ const server = createServer(ctx);
166
+ socket.on("close", () => void server.close().catch(() => undefined));
167
+ await server.connect(new StdioServerTransport(socket, socket));
168
+ },
169
+ });
170
+ closeShared = owner.close;
171
+ log(`shared session ${owner.info.key} on 127.0.0.1:${owner.info.port} (pid ${process.pid})`);
172
+ }
173
+ else {
174
+ handle = serveStdio(() => createServer(ctx));
175
+ process.stdin.on("close", shutdown);
176
+ }
177
+ if (!values["no-autostart"]) {
178
+ bridge
179
+ .start()
180
+ .then(async () => {
181
+ if (values.project) {
182
+ const r = await bridge.call("project.open", { path: resolve(ctx.workspace, values.project) }, { timeoutMs: 300_000 });
183
+ ctx.project = { path: r.path, application: r.application };
184
+ log(`opened ${r.path}`);
185
+ }
186
+ })
187
+ .catch((e) => log(`CODESYS start failed: ${e.message}`));
188
+ }
189
+ process.on("SIGINT", shutdown);
190
+ process.on("SIGTERM", shutdown);
191
+ }
192
+ main().catch((e) => {
193
+ log(`fatal: ${e.message}`);
194
+ process.exit(1);
195
+ });
196
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * What the server knows about the open project, for the workspace panel.
3
+ *
4
+ * The panel must never call CODESYS itself: the bridge runs one request at a
5
+ * time, so panel polling would stall the model's tool calls. Instead the
6
+ * tools keep this cache current as a side effect of their own calls (open,
7
+ * export, write, create, delete, rename, compile), and the panel reads it.
8
+ */
9
+ import type { TreeNode } from "./st.js";
10
+ export interface CompileResult {
11
+ at: string;
12
+ errors: number;
13
+ warnings: number;
14
+ messages: {
15
+ severity: string;
16
+ text: string;
17
+ object?: string | null;
18
+ position?: string | null;
19
+ length?: number;
20
+ code?: string;
21
+ }[];
22
+ }
23
+ export interface Focus {
24
+ /** Object path the model last touched. */
25
+ path: string;
26
+ action: "read" | "write" | "create" | "delete" | "rename" | "revert";
27
+ at: string;
28
+ }
29
+ export declare class ProjectCache {
30
+ project?: string;
31
+ nodes?: TreeNode[];
32
+ /** Bumped on every change, so the panel refetches only when needed. */
33
+ version: number;
34
+ compile?: CompileResult;
35
+ focus?: Focus;
36
+ reset(project?: string): void;
37
+ setAll(nodes: TreeNode[]): void;
38
+ /** Replace or add one object (and keep the order: new ones go after their parent's last child). */
39
+ upsert(node: TreeNode): void;
40
+ /** Remove an object and everything under it. */
41
+ remove(path: string): void;
42
+ rename(path: string, newName: string): void;
43
+ /** Something the workspace shows changed without a node change (e.g. the review baseline). */
44
+ bump(): void;
45
+ touch(path: string, action: Focus["action"]): void;
46
+ setCompile(c: CompileResult): void;
47
+ get(path: string): TreeNode | undefined;
48
+ }
@@ -0,0 +1,82 @@
1
+ export class ProjectCache {
2
+ project;
3
+ nodes;
4
+ /** Bumped on every change, so the panel refetches only when needed. */
5
+ version = 0;
6
+ compile;
7
+ focus;
8
+ reset(project) {
9
+ this.project = project;
10
+ this.nodes = undefined;
11
+ this.compile = undefined;
12
+ this.focus = undefined;
13
+ this.version++;
14
+ }
15
+ setAll(nodes) {
16
+ this.nodes = nodes;
17
+ this.version++;
18
+ }
19
+ /** Replace or add one object (and keep the order: new ones go after their parent's last child). */
20
+ upsert(node) {
21
+ if (!this.nodes)
22
+ return;
23
+ const key = node.path.toLowerCase();
24
+ const i = this.nodes.findIndex((n) => n.path.toLowerCase() === key);
25
+ if (i >= 0)
26
+ this.nodes[i] = { ...this.nodes[i], ...node };
27
+ else {
28
+ const parent = node.path.includes("/") ? node.path.slice(0, node.path.lastIndexOf("/")).toLowerCase() : "";
29
+ let at = this.nodes.length;
30
+ for (let k = this.nodes.length - 1; k >= 0; k--) {
31
+ const p = this.nodes[k].path.toLowerCase();
32
+ if (p === parent || p.startsWith(parent ? parent + "/" : "")) {
33
+ at = k + 1;
34
+ break;
35
+ }
36
+ }
37
+ this.nodes.splice(at, 0, node);
38
+ }
39
+ this.version++;
40
+ }
41
+ /** Remove an object and everything under it. */
42
+ remove(path) {
43
+ if (!this.nodes)
44
+ return;
45
+ const key = path.toLowerCase();
46
+ this.nodes = this.nodes.filter((n) => n.path.toLowerCase() !== key && !n.path.toLowerCase().startsWith(key + "/"));
47
+ this.version++;
48
+ }
49
+ rename(path, newName) {
50
+ if (!this.nodes)
51
+ return;
52
+ const key = path.toLowerCase();
53
+ const parent = path.includes("/") ? path.slice(0, path.lastIndexOf("/") + 1) : "";
54
+ const to = parent + newName;
55
+ this.nodes = this.nodes.map((n) => {
56
+ const p = n.path.toLowerCase();
57
+ if (p === key)
58
+ return { ...n, path: to, name: newName };
59
+ if (p.startsWith(key + "/"))
60
+ return { ...n, path: to + n.path.slice(path.length) };
61
+ return n;
62
+ });
63
+ this.version++;
64
+ }
65
+ /** Something the workspace shows changed without a node change (e.g. the review baseline). */
66
+ bump() {
67
+ this.version++;
68
+ }
69
+ touch(path, action) {
70
+ this.focus = { path, action, at: new Date().toISOString() };
71
+ this.version++;
72
+ }
73
+ setCompile(c) {
74
+ this.compile = c;
75
+ this.version++;
76
+ }
77
+ get(path) {
78
+ const key = path.toLowerCase();
79
+ return this.nodes?.find((n) => n.path.toLowerCase() === key);
80
+ }
81
+ }
82
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/codesys/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { TreeNode } from "./st.js";
2
+ export { formatDiff, lineDiff, type DiffOp } from "./diff.js";
3
+ export interface SnapObject {
4
+ path: string;
5
+ name: string;
6
+ kind: TreeNode["kind"];
7
+ sub?: string;
8
+ st?: boolean;
9
+ declaration?: string;
10
+ implementation?: string;
11
+ /** PLCopenXML of a graphical body (SFC, CFC, LD, FBD), to recreate it. */
12
+ xml?: string;
13
+ }
14
+ export interface Checkpoint {
15
+ name: string;
16
+ at: string;
17
+ project: string;
18
+ objects: SnapObject[];
19
+ }
20
+ export declare function snapshot(nodes: TreeNode[]): SnapObject[];
21
+ export interface ObjectChange {
22
+ path: string;
23
+ kind: string;
24
+ change: "added" | "removed" | "modified";
25
+ decl?: {
26
+ plus: number;
27
+ minus: number;
28
+ };
29
+ impl?: {
30
+ plus: number;
31
+ minus: number;
32
+ };
33
+ }
34
+ export declare function diffObjects(before: SnapObject[], after: SnapObject[]): ObjectChange[];
35
+ export declare class ChangeStore {
36
+ readonly root: string;
37
+ /** Projects that already have a session-start checkpoint in this process. */
38
+ private started;
39
+ constructor(root: string);
40
+ dir(project: string): string;
41
+ private file;
42
+ save(project: string, name: string, nodes: TreeNode[]): Promise<Checkpoint>;
43
+ load(project: string, name: string): Promise<Checkpoint | undefined>;
44
+ list(project: string): Promise<{
45
+ name: string;
46
+ at: string;
47
+ objects: number;
48
+ }[]>;
49
+ /** Take the session-start checkpoint once per project per process. */
50
+ sessionStart(project: string, exportNodes: () => Promise<TreeNode[]>): Promise<boolean>;
51
+ /** The review baseline (what the user has accepted); falls back to session-start. */
52
+ review(project: string): Promise<Checkpoint | undefined>;
53
+ /** Accept the current state of an object and everything under it into the review baseline. */
54
+ accept(project: string, path: string, now: SnapObject[]): Promise<number>;
55
+ }
56
+ /** Name of the checkpoint the workspace's diffs and badges compare against. */
57
+ export declare const REVIEW = "review";
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Change tracking for CODESYS edits: checkpoints (snapshots of every ST
3
+ * object's text), diffs against them, and what's needed to revert.
4
+ * Checkpoints live on disk per project, so they survive a server restart.
5
+ */
6
+ import { createHash } from "node:crypto";
7
+ import { existsSync } from "node:fs";
8
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
9
+ import { basename, join } from "node:path";
10
+ import { countDiff as count, lineDiff } from "./diff.js";
11
+ export { formatDiff, lineDiff } from "./diff.js";
12
+ /** Object kinds whose text is tracked (folders are tracked for structure only). */
13
+ const TRACKED = new Set(["pou", "method", "property", "accessor", "action", "dut", "gvl", "interface", "interface_method", "folder"]);
14
+ export function snapshot(nodes) {
15
+ return nodes
16
+ .filter((n) => TRACKED.has(n.kind))
17
+ .map((n) => ({
18
+ path: n.path,
19
+ name: n.name,
20
+ kind: n.kind,
21
+ ...(n.sub ? { sub: n.sub } : {}),
22
+ ...(n.st === false ? { st: false } : {}),
23
+ ...(n.declaration !== undefined ? { declaration: n.declaration } : {}),
24
+ ...(n.implementation !== undefined ? { implementation: n.implementation } : {}),
25
+ ...(n.xml !== undefined ? { xml: n.xml } : {}),
26
+ }));
27
+ }
28
+ const norm = (s) => (s ?? "").replace(/\r\n?/g, "\n").replace(/\s+$/, "");
29
+ export function diffObjects(before, after) {
30
+ const b = new Map(before.map((o) => [o.path.toLowerCase(), o]));
31
+ const a = new Map(after.map((o) => [o.path.toLowerCase(), o]));
32
+ const out = [];
33
+ for (const [k, o] of a) {
34
+ const old = b.get(k);
35
+ if (!old) {
36
+ out.push({ path: o.path, kind: o.kind, change: "added" });
37
+ continue;
38
+ }
39
+ const d = norm(old.declaration) === norm(o.declaration) ? undefined : count(lineDiff(norm(old.declaration), norm(o.declaration)));
40
+ const i = norm(old.implementation) === norm(o.implementation) ? undefined : count(lineDiff(norm(old.implementation), norm(o.implementation)));
41
+ if (d || i)
42
+ out.push({ path: o.path, kind: o.kind, change: "modified", ...(d ? { decl: d } : {}), ...(i ? { impl: i } : {}) });
43
+ }
44
+ for (const [k, o] of b)
45
+ if (!a.has(k))
46
+ out.push({ path: o.path, kind: o.kind, change: "removed" });
47
+ return out.sort((x, y) => x.path.localeCompare(y.path));
48
+ }
49
+ export class ChangeStore {
50
+ root;
51
+ /** Projects that already have a session-start checkpoint in this process. */
52
+ started = new Set();
53
+ constructor(root) {
54
+ this.root = root;
55
+ }
56
+ dir(project) {
57
+ const base = basename(project).replace(/\.project$/i, "").replace(/[^A-Za-z0-9_.-]/g, "_");
58
+ const h = createHash("sha256").update(project.toLowerCase()).digest("hex").slice(0, 8);
59
+ return join(this.root, `${base}-${h}`);
60
+ }
61
+ file(project, name) {
62
+ return join(this.dir(project), `${name.replace(/[^A-Za-z0-9_.-]/g, "_")}.json`);
63
+ }
64
+ async save(project, name, nodes) {
65
+ const cp = { name, at: new Date().toISOString(), project, objects: snapshot(nodes) };
66
+ await mkdir(this.dir(project), { recursive: true });
67
+ await writeFile(this.file(project, name), JSON.stringify(cp), "utf8");
68
+ return cp;
69
+ }
70
+ async load(project, name) {
71
+ const f = this.file(project, name);
72
+ if (!existsSync(f))
73
+ return undefined;
74
+ return JSON.parse(await readFile(f, "utf8"));
75
+ }
76
+ async list(project) {
77
+ const d = this.dir(project);
78
+ if (!existsSync(d))
79
+ return [];
80
+ const out = [];
81
+ for (const f of await readdir(d)) {
82
+ if (!f.endsWith(".json"))
83
+ continue;
84
+ try {
85
+ const cp = JSON.parse(await readFile(join(d, f), "utf8"));
86
+ out.push({ name: cp.name, at: cp.at, objects: cp.objects.length });
87
+ }
88
+ catch {
89
+ /* skip unreadable */
90
+ }
91
+ }
92
+ return out.sort((x, y) => x.at.localeCompare(y.at));
93
+ }
94
+ /** Take the session-start checkpoint once per project per process. */
95
+ async sessionStart(project, exportNodes) {
96
+ const key = project.toLowerCase();
97
+ if (this.started.has(key))
98
+ return false;
99
+ this.started.add(key);
100
+ try {
101
+ const nodes = await exportNodes();
102
+ await this.save(project, "session-start", nodes);
103
+ // The review baseline starts as the session start; Accept moves it per object.
104
+ await this.save(project, REVIEW, nodes);
105
+ return true;
106
+ }
107
+ catch {
108
+ this.started.delete(key);
109
+ return false;
110
+ }
111
+ }
112
+ /** The review baseline (what the user has accepted); falls back to session-start. */
113
+ async review(project) {
114
+ return (await this.load(project, REVIEW)) ?? (await this.load(project, "session-start"));
115
+ }
116
+ /** Accept the current state of an object and everything under it into the review baseline. */
117
+ async accept(project, path, now) {
118
+ const cp = await this.review(project);
119
+ if (!cp)
120
+ throw new Error("No review baseline yet: open the project first.");
121
+ const key = path.replace(/^\/+/, "").toLowerCase();
122
+ const inTree = (o) => o.path.toLowerCase() === key || o.path.toLowerCase().startsWith(key + "/");
123
+ const kept = cp.objects.filter((o) => !inTree(o));
124
+ const taken = now.filter(inTree);
125
+ const objects = [...kept, ...taken];
126
+ await mkdir(this.dir(project), { recursive: true });
127
+ await writeFile(this.file(project, REVIEW), JSON.stringify({ ...cp, name: REVIEW, at: new Date().toISOString(), objects }), "utf8");
128
+ return taken.length;
129
+ }
130
+ }
131
+ /** Name of the checkpoint the workspace's diffs and badges compare against. */
132
+ export const REVIEW = "review";
133
+ //# sourceMappingURL=changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changes.js","sourceRoot":"","sources":["../../src/codesys/changes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A tolerant parser for CODESYS ST declarations: headers (kind, name,
3
+ * EXTENDS / IMPLEMENTS, return type, modifiers), variable sections with
4
+ * names, types, initial values, AT addresses and comments, enum members and
5
+ * struct fields. Used for the outline and the I/O list; it never rejects
6
+ * input, it just extracts what it recognises.
7
+ */
8
+ export type SectionKind = "VAR_INPUT" | "VAR_OUTPUT" | "VAR_IN_OUT" | "VAR" | "VAR_TEMP" | "VAR_STAT" | "VAR_INST" | "VAR_GLOBAL" | "VAR_EXTERNAL" | "VAR_CONFIG";
9
+ export interface VarDecl {
10
+ name: string;
11
+ type: string;
12
+ init?: string;
13
+ at?: string;
14
+ comment?: string;
15
+ section: SectionKind;
16
+ constant?: boolean;
17
+ retain?: boolean;
18
+ persistent?: boolean;
19
+ }
20
+ export interface Header {
21
+ keyword: string;
22
+ name?: string;
23
+ modifiers: string[];
24
+ extends?: string[];
25
+ implements?: string[];
26
+ returnType?: string;
27
+ attributes: string[];
28
+ }
29
+ export interface ParsedDecl {
30
+ header: Header;
31
+ vars: VarDecl[];
32
+ /** Enum members with optional values (DUT enums). */
33
+ enumMembers?: {
34
+ name: string;
35
+ value?: string;
36
+ }[];
37
+ /** Base type of an enum (`(A, B) INT`) or an alias target. */
38
+ baseType?: string;
39
+ /** STRUCT / UNION fields (DUTs). */
40
+ fields?: VarDecl[];
41
+ dutKind?: "enum" | "struct" | "union" | "alias";
42
+ }
43
+ export declare function parseDeclaration(decl: string | undefined): ParsedDecl;
44
+ /** One-line signature, e.g. `METHOD Reset(bHard : BOOL) : BOOL`. */
45
+ export declare function signature(p: ParsedDecl, name?: string): string;