neo-mcp-daemon 1.0.1
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/README.md +64 -0
- package/bin/neo-mcp-daemon +2 -0
- package/dist/auth.d.ts +11 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +32 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon.d.ts +15 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +177 -0
- package/dist/daemon.js.map +1 -0
- package/dist/executor.d.ts +31 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +220 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +17 -0
- package/dist/paths.js.map +1 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# test-neo-mcp-daemon
|
|
2
|
+
|
|
3
|
+
Local execution daemon for [Neo](https://heyneo.so) — written in TypeScript/Node.js, no Python required.
|
|
4
|
+
|
|
5
|
+
The daemon polls the Neo backend for commands (write files, run subprocesses, list files) and executes them on your machine. It is started automatically by the Neo MCP server when you submit a task.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 18+
|
|
10
|
+
- A Neo API key (`sk-v1-...`)
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Automatic (recommended)
|
|
15
|
+
|
|
16
|
+
The Neo MCP server starts the daemon automatically when you submit your first task. No manual steps needed.
|
|
17
|
+
|
|
18
|
+
### Manual start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
NEO_SECRET_KEY=sk-v1-... npx test-neo-mcp-daemon
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
By default the daemon uses your home directory as the workspace. You can pass a path:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
NEO_SECRET_KEY=sk-v1-... npx test-neo-mcp-daemon /path/to/project
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Docker
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
docker run --rm \
|
|
34
|
+
-e NEO_SECRET_KEY=sk-v1-... \
|
|
35
|
+
-v "$HOME":/root \
|
|
36
|
+
-v "$HOME/.neo":/root/.neo \
|
|
37
|
+
test-neo-mcp-daemon
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Environment variables
|
|
41
|
+
|
|
42
|
+
| Variable | Default | Description |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `NEO_SECRET_KEY` | — | **Required.** Your Neo API key (`sk-v1-...`) |
|
|
45
|
+
| `NEO_ENV` | `prod` | Set to `staging` to use the staging backend |
|
|
46
|
+
| `NEO_API_URL` | auto | Explicit backend URL override (takes priority over `NEO_ENV`) |
|
|
47
|
+
| `NEO_DEPLOYMENT_ID` | auto | Override the deployment UUID (derived from API key by default) |
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
1. Derives a stable deployment UUID from your API key (SHA-256 → UUID v5) — same key always maps to the same UUID, no config files needed
|
|
52
|
+
2. Registers with the Neo backend under that UUID
|
|
53
|
+
3. Polls `GET /v2/poll/{deployment_id}` for commands
|
|
54
|
+
4. Dispatches commands locally: `write_code`, `run_subprocess`, `get_file`, `list_files`, `get_job_status`, `terminate_job`, `create_session`
|
|
55
|
+
5. POSTs results back to `POST /v2/poll/response`
|
|
56
|
+
|
|
57
|
+
## Path safety
|
|
58
|
+
|
|
59
|
+
The daemon only allows file operations within:
|
|
60
|
+
- Your home directory (`~`)
|
|
61
|
+
- The system temp directory (`/tmp` on Linux/macOS, `%TEMP%` on Windows)
|
|
62
|
+
- The workspace directory passed on the command line
|
|
63
|
+
|
|
64
|
+
All other absolute paths are blocked.
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive a stable deployment UUID from an API key.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm matches Python daemon exactly:
|
|
5
|
+
* SHA-256(key)[:16] formatted as UUID with RFC 4122 version=5, variant=1.
|
|
6
|
+
* Same key → same UUID on every call, across Python and Node daemons.
|
|
7
|
+
*/
|
|
8
|
+
export declare function deriveDeploymentId(secretKey: string): string;
|
|
9
|
+
/** Return the NEO_SECRET_KEY API key used for all requests. */
|
|
10
|
+
export declare function getAuthToken(): string;
|
|
11
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAgB5D;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveDeploymentId = deriveDeploymentId;
|
|
4
|
+
exports.getAuthToken = getAuthToken;
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
/**
|
|
7
|
+
* Derive a stable deployment UUID from an API key.
|
|
8
|
+
*
|
|
9
|
+
* Algorithm matches Python daemon exactly:
|
|
10
|
+
* SHA-256(key)[:16] formatted as UUID with RFC 4122 version=5, variant=1.
|
|
11
|
+
* Same key → same UUID on every call, across Python and Node daemons.
|
|
12
|
+
*/
|
|
13
|
+
function deriveDeploymentId(secretKey) {
|
|
14
|
+
const hash = (0, crypto_1.createHash)('sha256').update(secretKey).digest();
|
|
15
|
+
const bytes = Buffer.from(hash.subarray(0, 16));
|
|
16
|
+
// Apply RFC 4122 version 5 and variant bits — mirrors Python's uuid.UUID(bytes=..., version=5)
|
|
17
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x50; // version 5 (0101xxxx)
|
|
18
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1 (10xxxxxx)
|
|
19
|
+
const hex = bytes.toString('hex');
|
|
20
|
+
return [
|
|
21
|
+
hex.slice(0, 8),
|
|
22
|
+
hex.slice(8, 12),
|
|
23
|
+
hex.slice(12, 16),
|
|
24
|
+
hex.slice(16, 20),
|
|
25
|
+
hex.slice(20, 32),
|
|
26
|
+
].join('-');
|
|
27
|
+
}
|
|
28
|
+
/** Return the NEO_SECRET_KEY API key used for all requests. */
|
|
29
|
+
function getAuthToken() {
|
|
30
|
+
return process.env['NEO_SECRET_KEY'] ?? '';
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;AASA,gDAgBC;AAGD,oCAEC;AA9BD,mCAAoC;AAEpC;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,SAAiB;IAClD,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7D,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAEhD,+FAA+F;IAC/F,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,uBAAuB;IAC5D,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,uBAAuB;IAE5D,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,SAAgB,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment configuration.
|
|
3
|
+
* NEO_ENV=staging → https://alpha.heyneo.so
|
|
4
|
+
* NEO_ENV=prod → https://master.heyneo.so (default)
|
|
5
|
+
* NEO_API_URL → explicit override (takes priority)
|
|
6
|
+
*/
|
|
7
|
+
export declare const NEO_API_URL: string;
|
|
8
|
+
export declare const NEO_ENV: string;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,eAAO,MAAM,WAAW,QAA4C,CAAC;AACrE,eAAO,MAAM,OAAO,QAAO,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Environment configuration.
|
|
4
|
+
* NEO_ENV=staging → https://alpha.heyneo.so
|
|
5
|
+
* NEO_ENV=prod → https://master.heyneo.so (default)
|
|
6
|
+
* NEO_API_URL → explicit override (takes priority)
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.NEO_ENV = exports.NEO_API_URL = void 0;
|
|
10
|
+
const _env = (process.env['NEO_ENV'] ?? 'prod').toLowerCase();
|
|
11
|
+
const _defaultUrl = _env === 'staging' ? 'https://alpha.heyneo.so' : 'https://master.heyneo.so';
|
|
12
|
+
exports.NEO_API_URL = process.env['NEO_API_URL'] ?? _defaultUrl;
|
|
13
|
+
exports.NEO_ENV = _env;
|
|
14
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;AAC9D,MAAM,WAAW,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,0BAA0B,CAAC;AAEnF,QAAA,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC;AACxD,QAAA,OAAO,GAAG,IAAI,CAAC"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Neo npm daemon — main poll loop.
|
|
3
|
+
*
|
|
4
|
+
* Polls GET /v2/poll/{deployment_id} for commands and dispatches them via executor.ts.
|
|
5
|
+
* Sends results back via POST /v2/poll/response.
|
|
6
|
+
*
|
|
7
|
+
* Auth: NEO_SECRET_KEY API key used as Bearer token for all requests.
|
|
8
|
+
* Same wire protocol as the Python daemon.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runDaemon(opts?: {
|
|
11
|
+
workspace?: string;
|
|
12
|
+
deploymentId?: string;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+GH,wBAAsB,SAAS,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoF7H"}
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Neo npm daemon — main poll loop.
|
|
4
|
+
*
|
|
5
|
+
* Polls GET /v2/poll/{deployment_id} for commands and dispatches them via executor.ts.
|
|
6
|
+
* Sends results back via POST /v2/poll/response.
|
|
7
|
+
*
|
|
8
|
+
* Auth: NEO_SECRET_KEY API key used as Bearer token for all requests.
|
|
9
|
+
* Same wire protocol as the Python daemon.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runDaemon = runDaemon;
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
const auth_js_1 = require("./auth.js");
|
|
16
|
+
const config_js_1 = require("./config.js");
|
|
17
|
+
const executor_js_1 = require("./executor.js");
|
|
18
|
+
const paths_js_1 = require("./paths.js");
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Deployment ID
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
function getOrCreateDeploymentId() {
|
|
23
|
+
if (process.env['NEO_DEPLOYMENT_ID'])
|
|
24
|
+
return process.env['NEO_DEPLOYMENT_ID'];
|
|
25
|
+
const sk = process.env['NEO_SECRET_KEY'];
|
|
26
|
+
if (sk)
|
|
27
|
+
return (0, auth_js_1.deriveDeploymentId)(sk);
|
|
28
|
+
(0, fs_1.mkdirSync)(paths_js_1.DAEMON_DIR, { recursive: true });
|
|
29
|
+
try {
|
|
30
|
+
const { readFileSync } = require('fs');
|
|
31
|
+
const uid = readFileSync(paths_js_1.STANDALONE_UUID_FILE, 'utf8').trim();
|
|
32
|
+
if (uid)
|
|
33
|
+
return uid;
|
|
34
|
+
}
|
|
35
|
+
catch { /* not found */ }
|
|
36
|
+
const { randomUUID } = require('crypto');
|
|
37
|
+
const uid = randomUUID();
|
|
38
|
+
(0, fs_1.writeFileSync)(paths_js_1.STANDALONE_UUID_FILE, uid);
|
|
39
|
+
return uid;
|
|
40
|
+
}
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Sandbox log — so Python server.py _discover_sandbox_id() finds this daemon
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
function writeSandboxLog(deploymentId) {
|
|
45
|
+
(0, fs_1.mkdirSync)(paths_js_1.DAEMON_DIR, { recursive: true });
|
|
46
|
+
(0, fs_1.appendFileSync)(paths_js_1.DAEMON_LOG, JSON.stringify({ sandboxId: deploymentId, source: 'npm-daemon' }) + '\n');
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Thread workspace persistence
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
function loadThreadWorkspaces() {
|
|
52
|
+
try {
|
|
53
|
+
const { readFileSync } = require('fs');
|
|
54
|
+
return JSON.parse(readFileSync(paths_js_1.WORKSPACES_FILE, 'utf8'));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function saveThreadWorkspaces(workspaces) {
|
|
61
|
+
(0, fs_1.mkdirSync)(paths_js_1.DAEMON_DIR, { recursive: true });
|
|
62
|
+
(0, fs_1.writeFileSync)(paths_js_1.WORKSPACES_FILE, JSON.stringify(workspaces, null, 2));
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// HTTP helpers
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
async function pollBackend(depId, token) {
|
|
68
|
+
try {
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
const timeout = setTimeout(() => controller.abort(), 15_000);
|
|
71
|
+
const res = await fetch(`${config_js_1.NEO_API_URL}/v2/poll/${depId}?max_messages=10&wait_time=5`, { headers: { 'Authorization': `Bearer ${token}` }, signal: controller.signal });
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
if (res.status === 401) {
|
|
74
|
+
console.error('ERROR: Auth rejected (401). Check that NEO_SECRET_KEY is set correctly.');
|
|
75
|
+
return { commands: [], token };
|
|
76
|
+
}
|
|
77
|
+
if (res.status === 404 || !res.ok)
|
|
78
|
+
return { commands: [], token };
|
|
79
|
+
const data = await res.json();
|
|
80
|
+
const commands = Array.isArray(data) ? data : (data.messages ?? []);
|
|
81
|
+
return { commands, token };
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return { commands: [], token };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function sendResponse(depId, token, response) {
|
|
88
|
+
try {
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
const timeout = setTimeout(() => controller.abort(), 30_000);
|
|
91
|
+
await fetch(`${config_js_1.NEO_API_URL}/v2/poll/response`, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
94
|
+
body: JSON.stringify({ ...response, sandbox_id: response['sandbox_id'] ?? depId }),
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
});
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
}
|
|
99
|
+
catch { /* best-effort */ }
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Main daemon loop
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
async function runDaemon(opts = {}) {
|
|
105
|
+
const ws = (0, path_1.resolve)(opts.workspace ?? process.cwd());
|
|
106
|
+
const depId = opts.deploymentId ?? getOrCreateDeploymentId();
|
|
107
|
+
let token = (0, auth_js_1.getAuthToken)();
|
|
108
|
+
if (!token) {
|
|
109
|
+
console.error('ERROR: NEO_SECRET_KEY is not set.\n' +
|
|
110
|
+
'Set your API key: export NEO_SECRET_KEY=sk-v1-...');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
// Write sandbox log so server.py discovers this daemon
|
|
114
|
+
writeSandboxLog(depId);
|
|
115
|
+
// Write PID files: per-deployment (for is_running() checks) + global npm PID
|
|
116
|
+
(0, fs_1.mkdirSync)(paths_js_1.DAEMON_DIR, { recursive: true });
|
|
117
|
+
const pid = String(process.pid);
|
|
118
|
+
(0, fs_1.writeFileSync)((0, paths_js_1.pidFileForDeployment)(depId), pid);
|
|
119
|
+
(0, fs_1.writeFileSync)(paths_js_1.NPM_PID_FILE, pid);
|
|
120
|
+
const threadWorkspaces = loadThreadWorkspaces();
|
|
121
|
+
console.log('Neo npm daemon ready');
|
|
122
|
+
console.log(` deployment_id : ${depId}`);
|
|
123
|
+
console.log(` workspace : ${ws}`);
|
|
124
|
+
console.log(` backend : ${config_js_1.NEO_API_URL}`);
|
|
125
|
+
console.log(` pid : ${process.pid}`);
|
|
126
|
+
console.log('Polling for commands...\n');
|
|
127
|
+
// Cleanup on exit
|
|
128
|
+
const ac = new AbortController();
|
|
129
|
+
function shutdown() {
|
|
130
|
+
console.log('\nDaemon shutting down.');
|
|
131
|
+
for (const f of [(0, paths_js_1.pidFileForDeployment)(depId), paths_js_1.NPM_PID_FILE]) {
|
|
132
|
+
try {
|
|
133
|
+
require('fs').unlinkSync(f);
|
|
134
|
+
}
|
|
135
|
+
catch { /* already gone */ }
|
|
136
|
+
}
|
|
137
|
+
ac.abort();
|
|
138
|
+
}
|
|
139
|
+
// Callers (tests) can pass an AbortSignal to stop the loop without process.exit
|
|
140
|
+
opts.signal?.addEventListener('abort', shutdown);
|
|
141
|
+
process.on('SIGTERM', () => { shutdown(); process.exit(0); });
|
|
142
|
+
process.on('SIGINT', () => { shutdown(); process.exit(0); });
|
|
143
|
+
let backoff = 1_000; // ms
|
|
144
|
+
while (!ac.signal.aborted) {
|
|
145
|
+
const { commands, token: updatedToken } = await pollBackend(depId, token);
|
|
146
|
+
token = updatedToken;
|
|
147
|
+
if (commands.length > 0) {
|
|
148
|
+
backoff = 1_000;
|
|
149
|
+
for (const cmd of commands) {
|
|
150
|
+
const tid = cmd.thread_id;
|
|
151
|
+
const effectiveWs = (tid && threadWorkspaces[tid]) ? threadWorkspaces[tid] : ws;
|
|
152
|
+
const result = await (0, executor_js_1.dispatch)(cmd, effectiveWs);
|
|
153
|
+
const response = { ...result };
|
|
154
|
+
if (tid) {
|
|
155
|
+
response['thread_id'] = tid;
|
|
156
|
+
if (!threadWorkspaces[tid]) {
|
|
157
|
+
threadWorkspaces[tid] = effectiveWs;
|
|
158
|
+
saveThreadWorkspaces(threadWorkspaces);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (cmd.response_queue_name) {
|
|
162
|
+
response['response_queue_name'] = cmd.response_queue_name;
|
|
163
|
+
}
|
|
164
|
+
await sendResponse(depId, token, response);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// Interruptible sleep — exits immediately when signal fires
|
|
169
|
+
await new Promise(r => {
|
|
170
|
+
const t = setTimeout(r, backoff);
|
|
171
|
+
ac.signal.addEventListener('abort', () => { clearTimeout(t); r(); }, { once: true });
|
|
172
|
+
});
|
|
173
|
+
backoff = Math.min(backoff * 1.5, 10_000);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# 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,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action handlers — mirrors Python daemon's DaemonActionHandlers exactly.
|
|
3
|
+
* Supported actions: create_session, write_code, get_file, run_subprocess,
|
|
4
|
+
* get_job_status, terminate_job, list_files
|
|
5
|
+
*/
|
|
6
|
+
export interface Command {
|
|
7
|
+
action: string;
|
|
8
|
+
request_id: string;
|
|
9
|
+
thread_id?: string;
|
|
10
|
+
response_queue_name?: string;
|
|
11
|
+
session_id?: string;
|
|
12
|
+
payload?: Record<string, unknown>;
|
|
13
|
+
filename?: string;
|
|
14
|
+
code?: string;
|
|
15
|
+
workdir?: string;
|
|
16
|
+
file_path?: string;
|
|
17
|
+
command?: string;
|
|
18
|
+
job_id?: string;
|
|
19
|
+
directory?: string;
|
|
20
|
+
max_depth?: number;
|
|
21
|
+
include_hidden?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface ActionResult {
|
|
24
|
+
request_id: string;
|
|
25
|
+
status: string;
|
|
26
|
+
data?: Record<string, unknown>;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function safeResolve(workspace: string, pathStr: string): string | null;
|
|
30
|
+
export declare function dispatch(cmd: Command, workspace: string): Promise<ActionResult>;
|
|
31
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmBD,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW7E;AAyKD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAkBrF"}
|
package/dist/executor.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Action handlers — mirrors Python daemon's DaemonActionHandlers exactly.
|
|
4
|
+
* Supported actions: create_session, write_code, get_file, run_subprocess,
|
|
5
|
+
* get_job_status, terminate_job, list_files
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.safeResolve = safeResolve;
|
|
9
|
+
exports.dispatch = dispatch;
|
|
10
|
+
const crypto_1 = require("crypto");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const fs_1 = require("fs");
|
|
13
|
+
const os_1 = require("os");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
// Directories skipped during file listing — matches Python/TS daemon
|
|
16
|
+
const SKIP_DIRS = new Set([
|
|
17
|
+
'venv', 'node_modules', 'env', '.venv', '__pycache__', '.git',
|
|
18
|
+
'.tox', 'dist', 'build',
|
|
19
|
+
]);
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Job registry
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const _jobs = new Map();
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Path safety — mirrors Python _safe_resolve()
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
function safeResolve(workspace, pathStr) {
|
|
28
|
+
const home = (0, os_1.homedir)();
|
|
29
|
+
const tmp = (0, os_1.tmpdir)();
|
|
30
|
+
// On macOS, /tmp is a symlink to /private/tmp — include both so resolve() never surprises us
|
|
31
|
+
const allowed = new Set([workspace, home, tmp, (0, path_1.resolve)(tmp)].filter(Boolean));
|
|
32
|
+
if ((0, path_1.isAbsolute)(pathStr)) {
|
|
33
|
+
const r = (0, path_1.resolve)(pathStr);
|
|
34
|
+
return [...allowed].some(a => r === a || r.startsWith(a + '/')) ? r : null;
|
|
35
|
+
}
|
|
36
|
+
const r = (0, path_1.resolve)((0, path_1.join)(workspace, pathStr));
|
|
37
|
+
return r === workspace || r.startsWith(workspace + '/') ? r : null;
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Action handlers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
function hCreateSession(cmd) {
|
|
43
|
+
const sid = cmd.session_id ??
|
|
44
|
+
cmd.payload?.['session_id'] ??
|
|
45
|
+
(0, crypto_1.randomUUID)();
|
|
46
|
+
return {
|
|
47
|
+
request_id: cmd.request_id,
|
|
48
|
+
status: 'success',
|
|
49
|
+
data: { coding_session_id: sid },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function hWriteCode(cmd, workspace) {
|
|
53
|
+
const { filename, code } = cmd;
|
|
54
|
+
if (!filename || code === undefined) {
|
|
55
|
+
return { request_id: cmd.request_id, status: 'error', error: 'filename and code are required' };
|
|
56
|
+
}
|
|
57
|
+
const workdir = cmd.workdir ?? '';
|
|
58
|
+
// Use resolve() not join() so absolute workdir replaces workspace (mirrors Python os.path.join behaviour)
|
|
59
|
+
const base = workdir ? ((0, path_1.isAbsolute)(workdir) ? workdir : (0, path_1.join)(workspace, workdir)) : workspace;
|
|
60
|
+
const full = safeResolve(base, filename) ?? safeResolve(workspace, filename);
|
|
61
|
+
if (!full) {
|
|
62
|
+
console.warn(`[write_code] BLOCKED path=${filename} (outside workspace/tmp)`);
|
|
63
|
+
return { request_id: cmd.request_id, status: 'error', error: `Path escapes allowed directories: ${filename}` };
|
|
64
|
+
}
|
|
65
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(full), { recursive: true });
|
|
66
|
+
(0, fs_1.writeFileSync)(full, code, 'utf8');
|
|
67
|
+
console.log(`[write_code] wrote ${full}`);
|
|
68
|
+
return {
|
|
69
|
+
request_id: cmd.request_id,
|
|
70
|
+
status: 'success',
|
|
71
|
+
data: { file_path: full, workdir: workdir || workspace },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function hGetFile(cmd, workspace) {
|
|
75
|
+
const fp = cmd.file_path;
|
|
76
|
+
if (!fp) {
|
|
77
|
+
return { request_id: cmd.request_id, status: 'error', error: 'file_path is required' };
|
|
78
|
+
}
|
|
79
|
+
const full = safeResolve(workspace, fp);
|
|
80
|
+
if (!full || !(0, fs_1.existsSync)(full) || !(0, fs_1.statSync)(full).isFile()) {
|
|
81
|
+
return { request_id: cmd.request_id, status: 'error', error: `File not found: ${fp}` };
|
|
82
|
+
}
|
|
83
|
+
const content = (0, fs_1.readFileSync)(full, 'utf8');
|
|
84
|
+
return {
|
|
85
|
+
request_id: cmd.request_id,
|
|
86
|
+
status: 'success',
|
|
87
|
+
data: { file_content: content, file_path: full },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function hRunSubprocess(cmd, workspace) {
|
|
91
|
+
const { command } = cmd;
|
|
92
|
+
if (!command) {
|
|
93
|
+
return { request_id: cmd.request_id, status: 'error', error: 'command is required' };
|
|
94
|
+
}
|
|
95
|
+
// Ensure workspace exists before spawning — cwd must exist or spawn throws ENOENT
|
|
96
|
+
(0, fs_1.mkdirSync)(workspace, { recursive: true });
|
|
97
|
+
console.log(`[run_subprocess] cwd=${workspace} cmd=${command.slice(0, 120)}`);
|
|
98
|
+
const jobId = (0, crypto_1.randomUUID)();
|
|
99
|
+
const proc = (0, child_process_1.spawn)(command, { shell: true, cwd: workspace });
|
|
100
|
+
const job = { proc, stdout: '', stderr: '', exitCode: null };
|
|
101
|
+
_jobs.set(jobId, job);
|
|
102
|
+
proc.stdout.on('data', (chunk) => { job.stdout += chunk.toString(); });
|
|
103
|
+
proc.stderr.on('data', (chunk) => { job.stderr += chunk.toString(); });
|
|
104
|
+
proc.on('close', (code) => { job.exitCode = code ?? -1; });
|
|
105
|
+
return {
|
|
106
|
+
request_id: cmd.request_id,
|
|
107
|
+
status: 'success',
|
|
108
|
+
data: { job_id: jobId, detached: true, message: 'Job started in background' },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function hGetJobStatus(cmd) {
|
|
112
|
+
const { job_id } = cmd;
|
|
113
|
+
const job = job_id ? _jobs.get(job_id) : undefined;
|
|
114
|
+
if (!job) {
|
|
115
|
+
return { request_id: cmd.request_id, status: 'error', error: `Job not found: ${job_id ?? ''}` };
|
|
116
|
+
}
|
|
117
|
+
const done = job.exitCode !== null;
|
|
118
|
+
return {
|
|
119
|
+
request_id: cmd.request_id,
|
|
120
|
+
status: done ? 'completed' : 'pending',
|
|
121
|
+
data: {
|
|
122
|
+
job_id,
|
|
123
|
+
stdout: job.stdout,
|
|
124
|
+
stderr: job.stderr,
|
|
125
|
+
exit_code: job.exitCode,
|
|
126
|
+
completed: done,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function hTerminateJob(cmd) {
|
|
131
|
+
const { job_id } = cmd;
|
|
132
|
+
const job = job_id ? _jobs.get(job_id) : undefined;
|
|
133
|
+
if (!job) {
|
|
134
|
+
return { request_id: cmd.request_id, status: 'error', error: `Job not found: ${job_id ?? ''}` };
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
job.proc.kill('SIGTERM');
|
|
138
|
+
}
|
|
139
|
+
catch { /* already exited */ }
|
|
140
|
+
job.exitCode = -15; // SIGTERM
|
|
141
|
+
job.stderr += '\n[terminated by daemon]';
|
|
142
|
+
return {
|
|
143
|
+
request_id: cmd.request_id,
|
|
144
|
+
status: 'success',
|
|
145
|
+
data: { job_id, terminated: true },
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function hListFiles(cmd, workspace) {
|
|
149
|
+
const payload = cmd.payload ?? {};
|
|
150
|
+
const directory = cmd.directory ?? payload['directory'] ?? workspace;
|
|
151
|
+
const maxDepth = Number(cmd.max_depth ?? payload['max_depth'] ?? 10);
|
|
152
|
+
const includeHidden = Boolean(cmd.include_hidden ?? payload['include_hidden'] ?? false);
|
|
153
|
+
const target = (0, path_1.isAbsolute)(directory)
|
|
154
|
+
? (0, path_1.resolve)(directory)
|
|
155
|
+
: (safeResolve(workspace, directory) ?? workspace);
|
|
156
|
+
if (!(0, fs_1.existsSync)(target) || !(0, fs_1.statSync)(target).isDirectory()) {
|
|
157
|
+
return { request_id: cmd.request_id, status: 'error', error: `Directory not found: ${directory}` };
|
|
158
|
+
}
|
|
159
|
+
const lines = [`${target}|d|0`];
|
|
160
|
+
function walk(dir, depth) {
|
|
161
|
+
if (depth > maxDepth)
|
|
162
|
+
return;
|
|
163
|
+
let entries;
|
|
164
|
+
try {
|
|
165
|
+
entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
if (!includeHidden && entry.name.startsWith('.'))
|
|
173
|
+
continue;
|
|
174
|
+
const fullPath = (0, path_1.join)(dir, entry.name);
|
|
175
|
+
if (entry.isDirectory()) {
|
|
176
|
+
lines.push(`${fullPath}|d|0`);
|
|
177
|
+
if (!SKIP_DIRS.has(entry.name))
|
|
178
|
+
walk(fullPath, depth + 1);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
let size = 0;
|
|
182
|
+
try {
|
|
183
|
+
size = (0, fs_1.statSync)(fullPath).size;
|
|
184
|
+
}
|
|
185
|
+
catch { /* ignore */ }
|
|
186
|
+
lines.push(`${fullPath}|f|${size}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
walk(target, 1);
|
|
191
|
+
return {
|
|
192
|
+
request_id: cmd.request_id,
|
|
193
|
+
status: 'success',
|
|
194
|
+
data: { stdout: lines.join('\n'), file_count: lines.length, directory: target },
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// Dispatch
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
async function dispatch(cmd, workspace) {
|
|
201
|
+
console.log(`[dispatch] action=${cmd.action} request_id=${cmd.request_id}`);
|
|
202
|
+
try {
|
|
203
|
+
switch (cmd.action) {
|
|
204
|
+
case 'create_session': return hCreateSession(cmd);
|
|
205
|
+
case 'write_code': return hWriteCode(cmd, workspace);
|
|
206
|
+
case 'get_file': return hGetFile(cmd, workspace);
|
|
207
|
+
case 'run_subprocess': return hRunSubprocess(cmd, workspace);
|
|
208
|
+
case 'get_job_status': return hGetJobStatus(cmd);
|
|
209
|
+
case 'terminate_job': return hTerminateJob(cmd);
|
|
210
|
+
case 'list_files': return hListFiles(cmd, workspace);
|
|
211
|
+
default:
|
|
212
|
+
return { request_id: cmd.request_id, status: 'error', error: `Unknown action: ${cmd.action}` };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
console.error(`[dispatch] error in ${cmd.action}:`, err);
|
|
217
|
+
return { request_id: cmd.request_id, status: 'error', error: String(err) };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* neo-mcp-daemon — entry point
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx neo-mcp-daemon [/path/to/workspace] [--deployment-id UUID]
|
|
7
|
+
*
|
|
8
|
+
* Environment:
|
|
9
|
+
* NEO_SECRET_KEY — API key (sk-v1-...) — primary auth
|
|
10
|
+
* NEO_DEPLOYMENT_ID — optional UUID override
|
|
11
|
+
* NEO_API_URL — optional, defaults to https://master.heyneo.so
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* neo-mcp-daemon — entry point
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx neo-mcp-daemon [/path/to/workspace] [--deployment-id UUID]
|
|
8
|
+
*
|
|
9
|
+
* Environment:
|
|
10
|
+
* NEO_SECRET_KEY — API key (sk-v1-...) — primary auth
|
|
11
|
+
* NEO_DEPLOYMENT_ID — optional UUID override
|
|
12
|
+
* NEO_API_URL — optional, defaults to https://master.heyneo.so
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const daemon_js_1 = require("./daemon.js");
|
|
16
|
+
function parseArgs() {
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
let workspace;
|
|
19
|
+
let deploymentId;
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
if (args[i] === '--deployment-id' && args[i + 1]) {
|
|
22
|
+
deploymentId = args[++i];
|
|
23
|
+
}
|
|
24
|
+
else if (args[i] && !args[i].startsWith('-')) {
|
|
25
|
+
workspace = args[i];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { workspace, deploymentId };
|
|
29
|
+
}
|
|
30
|
+
const { workspace, deploymentId } = parseArgs();
|
|
31
|
+
(0, daemon_js_1.runDaemon)({ workspace, deploymentId }).catch(err => {
|
|
32
|
+
console.error('Fatal daemon error:', err);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;GAUG;;AAEH,2CAAwC;AAExC,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,SAA6B,CAAC;IAClC,IAAI,YAAgC,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,iBAAiB,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACjD,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAAC;AAChD,IAAA,qBAAS,EAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjD,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const NEO_HOME: string;
|
|
2
|
+
export declare const DAEMON_DIR: string;
|
|
3
|
+
export declare const STANDALONE_UUID_FILE: string;
|
|
4
|
+
export declare const DAEMON_LOG: string;
|
|
5
|
+
export declare const NPM_PID_FILE: string;
|
|
6
|
+
export declare const WORKSPACES_FILE: string;
|
|
7
|
+
/** Per-deployment PID file — matches Python daemon's naming for compatibility. */
|
|
8
|
+
export declare function pidFileForDeployment(deploymentId: string): string;
|
|
9
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,QAA0B,CAAC;AAChD,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,oBAAoB,QAA+C,CAAC;AACjF,eAAO,MAAM,UAAU,QAAiC,CAAC;AACzD,eAAO,MAAM,YAAY,QAAqC,CAAC;AAC/D,eAAO,MAAM,eAAe,QAA6C,CAAC;AAE1E,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjE"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WORKSPACES_FILE = exports.NPM_PID_FILE = exports.DAEMON_LOG = exports.STANDALONE_UUID_FILE = exports.DAEMON_DIR = exports.NEO_HOME = void 0;
|
|
4
|
+
exports.pidFileForDeployment = pidFileForDeployment;
|
|
5
|
+
const os_1 = require("os");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
exports.NEO_HOME = (0, path_1.join)((0, os_1.homedir)(), '.neo');
|
|
8
|
+
exports.DAEMON_DIR = (0, path_1.join)(exports.NEO_HOME, 'daemon');
|
|
9
|
+
exports.STANDALONE_UUID_FILE = (0, path_1.join)(exports.DAEMON_DIR, 'standalone_deployment_id');
|
|
10
|
+
exports.DAEMON_LOG = (0, path_1.join)(exports.DAEMON_DIR, 'daemon.log');
|
|
11
|
+
exports.NPM_PID_FILE = (0, path_1.join)(exports.DAEMON_DIR, 'npm_daemon.pid');
|
|
12
|
+
exports.WORKSPACES_FILE = (0, path_1.join)(exports.DAEMON_DIR, 'thread-workspaces.json');
|
|
13
|
+
/** Per-deployment PID file — matches Python daemon's naming for compatibility. */
|
|
14
|
+
function pidFileForDeployment(deploymentId) {
|
|
15
|
+
return (0, path_1.join)(exports.DAEMON_DIR, `daemon_${deploymentId.slice(0, 8)}.pid`);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":";;;AAWA,oDAEC;AAbD,2BAA6B;AAC7B,+BAA4B;AAEf,QAAA,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAA,YAAO,GAAE,EAAE,MAAM,CAAC,CAAC;AACnC,QAAA,UAAU,GAAG,IAAA,WAAI,EAAC,gBAAQ,EAAE,QAAQ,CAAC,CAAC;AACtC,QAAA,oBAAoB,GAAG,IAAA,WAAI,EAAC,kBAAU,EAAE,0BAA0B,CAAC,CAAC;AACpE,QAAA,UAAU,GAAG,IAAA,WAAI,EAAC,kBAAU,EAAE,YAAY,CAAC,CAAC;AAC5C,QAAA,YAAY,GAAG,IAAA,WAAI,EAAC,kBAAU,EAAE,gBAAgB,CAAC,CAAC;AAClD,QAAA,eAAe,GAAG,IAAA,WAAI,EAAC,kBAAU,EAAE,wBAAwB,CAAC,CAAC;AAE1E,kFAAkF;AAClF,SAAgB,oBAAoB,CAAC,YAAoB;IACvD,OAAO,IAAA,WAAI,EAAC,kBAAU,EAAE,UAAU,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "neo-mcp-daemon",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Neo local execution daemon — runs AI/ML tasks locally, no Python required",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"neo-mcp-daemon": "bin/neo-mcp-daemon"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"prepublishOnly": "npm run build && npm test"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"bin",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"neo",
|
|
25
|
+
"mcp",
|
|
26
|
+
"daemon",
|
|
27
|
+
"ai",
|
|
28
|
+
"ml",
|
|
29
|
+
"local-execution"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.0.0",
|
|
34
|
+
"typescript": "^5.5.0",
|
|
35
|
+
"vitest": "^2.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|