agentic-numerical-control 0.1.0 → 0.1.2
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/LICENSE +21 -0
- package/dist/server/autostart.js +19 -10
- package/dist/server/cli.js +21 -3
- package/package.json +6 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Edward Coventry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/server/autostart.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
// Start the app when the user logs in
|
|
2
|
-
// agent on macOS, a systemd user service on Linux.
|
|
3
|
-
|
|
1
|
+
// Start the app when the user logs in, without admin rights: the per-user Run
|
|
2
|
+
// key on Windows, a launchd agent on macOS, a systemd user service on Linux.
|
|
3
|
+
// Each runs `<cli> start --log`.
|
|
4
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
4
5
|
import fs from "node:fs";
|
|
5
6
|
import os from "node:os";
|
|
6
7
|
import path from "node:path";
|
|
8
|
+
import { STATE_DIR } from "./paths.js";
|
|
7
9
|
import { PRODUCT } from "./product.js";
|
|
8
10
|
const LABEL = `com.${PRODUCT.name}.agent`;
|
|
11
|
+
const RUN_KEY = String.raw `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`;
|
|
12
|
+
const LAUNCHER = path.join(STATE_DIR, "start.cmd");
|
|
9
13
|
function quiet(file, args) {
|
|
10
14
|
try {
|
|
11
15
|
execFileSync(file, args, { stdio: "ignore" });
|
|
@@ -20,13 +24,18 @@ function command(cliPath) {
|
|
|
20
24
|
export function enableAutostart(cliPath) {
|
|
21
25
|
const cmd = command(cliPath);
|
|
22
26
|
if (process.platform === "win32") {
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
// A short launcher keeps the Run entry well under its length limit;
|
|
28
|
+
// conhost --headless runs it without a visible window. Logon-triggered
|
|
29
|
+
// scheduled tasks would need admin rights, the Run key does not.
|
|
30
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
31
|
+
fs.writeFileSync(LAUNCHER, `@${cmd.map((c) => `"${c}"`).join(" ")}\r\n`);
|
|
32
|
+
execFileSync("reg", ["add", RUN_KEY, "/v", PRODUCT.displayName, "/t", "REG_SZ", "/d", `conhost.exe --headless "${LAUNCHER}"`, "/f"], {
|
|
26
33
|
stdio: "ignore",
|
|
27
34
|
});
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
// Start now as well. A detached conhost exits at once (it has no console to
|
|
36
|
+
// host), so run Node itself detached; it needs no console and logs to file.
|
|
37
|
+
spawn(cmd[0], cmd.slice(1), { detached: true, stdio: "ignore", windowsHide: true }).unref();
|
|
38
|
+
return "Windows sign-in startup entry (no admin needed)";
|
|
30
39
|
}
|
|
31
40
|
if (process.platform === "darwin") {
|
|
32
41
|
const plist = path.join(os.homedir(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
@@ -63,8 +72,8 @@ WantedBy=default.target
|
|
|
63
72
|
}
|
|
64
73
|
export function disableAutostart() {
|
|
65
74
|
if (process.platform === "win32") {
|
|
66
|
-
quiet("
|
|
67
|
-
|
|
75
|
+
quiet("reg", ["delete", RUN_KEY, "/v", PRODUCT.displayName, "/f"]);
|
|
76
|
+
fs.rmSync(LAUNCHER, { force: true });
|
|
68
77
|
}
|
|
69
78
|
else if (process.platform === "darwin") {
|
|
70
79
|
const plist = path.join(os.homedir(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
package/dist/server/cli.js
CHANGED
|
@@ -23,6 +23,19 @@ import { createServer } from "./server.js";
|
|
|
23
23
|
import { updateIfAvailable } from "./update.js";
|
|
24
24
|
const TOKEN_FILE = path.join(STATE_DIR, "token");
|
|
25
25
|
const LOG_FILE = path.join(STATE_DIR, "agent.log");
|
|
26
|
+
const PID_FILE = path.join(STATE_DIR, "agent.pid");
|
|
27
|
+
/** Stops a background copy started at login or by an earlier setup, if running. */
|
|
28
|
+
function stopRunning() {
|
|
29
|
+
try {
|
|
30
|
+
const pid = Number(fs.readFileSync(PID_FILE, "utf-8"));
|
|
31
|
+
if (pid && pid !== process.pid)
|
|
32
|
+
process.kill(pid);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// not running
|
|
36
|
+
}
|
|
37
|
+
fs.rmSync(PID_FILE, { force: true });
|
|
38
|
+
}
|
|
26
39
|
const CLI_PATH = fileURLToPath(import.meta.url);
|
|
27
40
|
/**
|
|
28
41
|
* The local HTTP endpoint is served only at /mcp/<token>, so other programs
|
|
@@ -98,10 +111,12 @@ const [command = "start", ...rest] = process.argv.slice(2);
|
|
|
98
111
|
switch (command) {
|
|
99
112
|
case "setup": {
|
|
100
113
|
console.log(`\n ${PRODUCT.displayName} ${VERSION}`);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
else
|
|
114
|
+
const link = readLink();
|
|
115
|
+
if (link?.cloudUrl === PRODUCT.cloudUrl)
|
|
104
116
|
console.log(" This PC is already linked.");
|
|
117
|
+
else
|
|
118
|
+
await pair(PRODUCT.cloudUrl);
|
|
119
|
+
stopRunning();
|
|
105
120
|
const how = enableAutostart(CLI_PATH);
|
|
106
121
|
console.log(` Running now, and at every login (${how}).`);
|
|
107
122
|
console.log(` Put G-code files in: ${JOBS_DIR}`);
|
|
@@ -111,6 +126,8 @@ switch (command) {
|
|
|
111
126
|
case "start": {
|
|
112
127
|
if (rest.includes("--log"))
|
|
113
128
|
logToFile();
|
|
129
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
130
|
+
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
114
131
|
if (await updateIfAvailable())
|
|
115
132
|
process.exit(0);
|
|
116
133
|
linkCncjs();
|
|
@@ -129,6 +146,7 @@ switch (command) {
|
|
|
129
146
|
}
|
|
130
147
|
case "unlink": {
|
|
131
148
|
disableAutostart();
|
|
149
|
+
stopRunning();
|
|
132
150
|
fs.rmSync(DEVICE_FILE, { force: true });
|
|
133
151
|
console.log(`Unlinked this PC and stopped ${PRODUCT.displayName} starting at login.`);
|
|
134
152
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-numerical-control",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Agentic Numerical Control: see and run CNC jobs from your AI assistant. A 3D toolpath viewer, live machine status and job control for CNCjs/GRBL machines.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc --noEmit -p tsconfig.app.json && cross-env INPUT=viewer.html vite build && tsc -p tsconfig.build.json",
|
|
@@ -64,5 +64,9 @@
|
|
|
64
64
|
"claude",
|
|
65
65
|
"gcode",
|
|
66
66
|
"toolpath"
|
|
67
|
-
]
|
|
67
|
+
],
|
|
68
|
+
"repository": {
|
|
69
|
+
"type": "git",
|
|
70
|
+
"url": "git+https://github.com/EdwardCoventry/agentic-numerical-control.git"
|
|
71
|
+
}
|
|
68
72
|
}
|