@cruxy/cli 0.29.2 → 0.29.4
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/dist/agent/loop.js +6 -0
- package/dist/agent/prompts.d.ts +8 -0
- package/dist/agent/prompts.js +26 -0
- package/dist/cli/commands/mcp.js +1 -1
- package/dist/cli/commands/test.js +1 -0
- package/dist/config/credentials.d.ts +3 -4
- package/dist/config/credentials.js +74 -21
- package/dist/config/owner-only.d.ts +19 -0
- package/dist/config/owner-only.js +114 -0
- package/dist/config/schema.d.ts +77 -32
- package/dist/config/schema.js +16 -0
- package/dist/errors/constructors.d.ts +9 -0
- package/dist/errors/constructors.js +27 -0
- package/dist/errors/types.d.ts +12 -0
- package/dist/errors/types.js +18 -0
- package/dist/indexing/service.js +4 -1
- package/dist/lsp/transport.js +5 -5
- package/dist/mcp/transport.js +6 -6
- package/dist/memory/types.d.ts +2 -2
- package/dist/sandbox/docker-runtime.js +7 -15
- package/dist/testing/run-tests-tool.js +1 -0
- package/dist/testing/runner.js +7 -17
- package/dist/testing/types.d.ts +6 -1
- package/dist/tools/shell/exec.js +8 -19
- package/dist/tools/shell/resolve-shell.d.ts +81 -0
- package/dist/tools/shell/resolve-shell.js +158 -0
- package/dist/utils/child-tree.d.ts +9 -11
- package/dist/utils/child-tree.js +11 -25
- package/dist/utils/process-tree.d.ts +16 -0
- package/dist/utils/process-tree.js +84 -0
- package/package.json +4 -2
package/dist/utils/child-tree.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* The process-EXIT backstop for long-lived child trees (C.12 LSP servers, C.27
|
|
3
|
+
* MCP servers). The platform-aware spawn/kill primitives themselves now live in
|
|
4
|
+
* {@link ./process-tree.js} — {@link killTree} is re-exported here unchanged so
|
|
5
|
+
* existing LSP/MCP importers keep their import path, and so this backstop and
|
|
6
|
+
* those transports reap trees the SAME way on every platform (negative-PID
|
|
7
|
+
* `SIGKILL` on POSIX, `taskkill /T /F` on win32 — no more orphaned grandchildren
|
|
8
|
+
* on Windows).
|
|
7
9
|
*
|
|
8
10
|
* A per-session graceful shutdown covers the normal path, but a hard exit
|
|
9
11
|
* (Ctrl-C, an uncaught throw) would otherwise orphan these trees. So every live
|
|
@@ -15,26 +17,10 @@
|
|
|
15
17
|
* and MCP (newline-delimited JSON) share the SAME backstop, so `killTrackedTrees`
|
|
16
18
|
* on exit reaps both and there is a single source of truth for "no orphans".
|
|
17
19
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export function killTree(pid) {
|
|
24
|
-
if (pid === undefined)
|
|
25
|
-
return;
|
|
26
|
-
try {
|
|
27
|
-
process.kill(-pid, "SIGKILL");
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
try {
|
|
31
|
-
process.kill(pid, "SIGKILL");
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
/* already exited */
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
20
|
+
import { killTree } from "./process-tree.js";
|
|
21
|
+
// Re-exported so LSP/MCP transports (and their tests) keep importing `killTree`
|
|
22
|
+
// from here; the implementation is the shared, platform-aware one.
|
|
23
|
+
export { killTree };
|
|
38
24
|
const livePids = new Set();
|
|
39
25
|
let handlersInstalled = false;
|
|
40
26
|
/**
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Spawn a child as the head of a killable process tree, applying the
|
|
4
|
+
* platform-correct grouping options on top of the caller's own (`shell`, `cwd`,
|
|
5
|
+
* `stdio`, `env`, …). Any `detached`/`windowsHide` the caller passes is
|
|
6
|
+
* overridden — grouping is this module's responsibility, not the call site's.
|
|
7
|
+
*/
|
|
8
|
+
export declare function spawnTree(command: string, args?: readonly string[], options?: SpawnOptions): ChildProcess;
|
|
9
|
+
/**
|
|
10
|
+
* Kill a child's ENTIRE process tree — the child and every descendant it
|
|
11
|
+
* spawned. POSIX: negative-PID `SIGKILL` targets the process group created by
|
|
12
|
+
* {@link spawnTree}'s `detached`. win32: `taskkill /PID <pid> /T /F` walks the
|
|
13
|
+
* OS tree (`/T`) and force-terminates it (`/F`). Fire-and-forget and
|
|
14
|
+
* error-swallowing on both paths — the tree may already be gone.
|
|
15
|
+
*/
|
|
16
|
+
export declare function killTree(pid: number | undefined): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { spawn, } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* The single platform-aware primitive for spawning a killable process tree and
|
|
4
|
+
* reaping it whole. Both halves — {@link spawnTree} and {@link killTree} — MUST
|
|
5
|
+
* come from here as a pair, because how a child is spawned decides how its tree
|
|
6
|
+
* can be killed, and the two differ by platform:
|
|
7
|
+
*
|
|
8
|
+
* - POSIX: spawn `detached` so the child leads its own process group, then kill
|
|
9
|
+
* the whole group with a negative-PID `SIGKILL`. One signal reaps the shell
|
|
10
|
+
* AND everything it forked (a `shell:true` grandchild, gopls's `go`, …).
|
|
11
|
+
* - win32: there is no process-group signalling to lean on. `detached` there
|
|
12
|
+
* means "new console / new group" — the wrong semantics, and a flashing
|
|
13
|
+
* window. So we DON'T detach (just `windowsHide`), and kill by walking the
|
|
14
|
+
* real OS parent-PID tree with `taskkill /T /F`, which a negative-PID signal
|
|
15
|
+
* could never do on Windows (it would kill only the direct child and orphan
|
|
16
|
+
* the grandchildren).
|
|
17
|
+
*
|
|
18
|
+
* This module exists because that pairing used to be copy-pasted — four
|
|
19
|
+
* POSIX-only `killTree` variants (run_command, the test runner, the LSP/MCP
|
|
20
|
+
* backstop, and the docker client), each of which silently orphaned
|
|
21
|
+
* grandchildren on Windows. There is now one implementation; a change to the
|
|
22
|
+
* kill discipline changes every path. Spawn sites likewise route through
|
|
23
|
+
* `spawnTree` (run_command, run_tests, LSP, MCP, docker) so none re-introduces
|
|
24
|
+
* the win32 `detached` console-flash the grouping logic exists to avoid.
|
|
25
|
+
*/
|
|
26
|
+
const isWindows = process.platform === "win32";
|
|
27
|
+
/**
|
|
28
|
+
* Spawn a child as the head of a killable process tree, applying the
|
|
29
|
+
* platform-correct grouping options on top of the caller's own (`shell`, `cwd`,
|
|
30
|
+
* `stdio`, `env`, …). Any `detached`/`windowsHide` the caller passes is
|
|
31
|
+
* overridden — grouping is this module's responsibility, not the call site's.
|
|
32
|
+
*/
|
|
33
|
+
export function spawnTree(command, args = [], options = {}) {
|
|
34
|
+
const grouped = isWindows
|
|
35
|
+
? { ...options, detached: false, windowsHide: true }
|
|
36
|
+
: { ...options, detached: true };
|
|
37
|
+
return spawn(command, args, grouped);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Kill a child's ENTIRE process tree — the child and every descendant it
|
|
41
|
+
* spawned. POSIX: negative-PID `SIGKILL` targets the process group created by
|
|
42
|
+
* {@link spawnTree}'s `detached`. win32: `taskkill /PID <pid> /T /F` walks the
|
|
43
|
+
* OS tree (`/T`) and force-terminates it (`/F`). Fire-and-forget and
|
|
44
|
+
* error-swallowing on both paths — the tree may already be gone.
|
|
45
|
+
*/
|
|
46
|
+
export function killTree(pid) {
|
|
47
|
+
if (pid === undefined)
|
|
48
|
+
return;
|
|
49
|
+
if (isWindows) {
|
|
50
|
+
killTreeWindows(pid);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
// Negative PID = "the whole group led by `pid`", not just `pid`.
|
|
55
|
+
process.kill(-pid, "SIGKILL");
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Already exited, or no group — nothing to kill.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reap `pid`'s tree via `taskkill`. The killer is itself a child process, so we
|
|
63
|
+
* reap IT too: `stdio: "ignore"` gives it nothing to block on, the `error`
|
|
64
|
+
* handler swallows a missing-`taskkill`/EPIPE rejection (an unhandled `error`
|
|
65
|
+
* event would otherwise crash the process), and `unref` keeps this short-lived
|
|
66
|
+
* helper from holding the event loop open. taskkill exits on its own; we neither
|
|
67
|
+
* wait for it nor let it leak.
|
|
68
|
+
*/
|
|
69
|
+
function killTreeWindows(pid) {
|
|
70
|
+
try {
|
|
71
|
+
const killer = spawn("taskkill", ["/PID", String(pid), "/T", "/F"], {
|
|
72
|
+
stdio: "ignore",
|
|
73
|
+
windowsHide: true,
|
|
74
|
+
});
|
|
75
|
+
killer.on("error", () => {
|
|
76
|
+
// taskkill unavailable (should not happen on win32) — nothing more to do.
|
|
77
|
+
});
|
|
78
|
+
killer.unref();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Even the spawn attempt failed — the tree, if any, outlives us. Nothing
|
|
82
|
+
// more we can do from here.
|
|
83
|
+
}
|
|
84
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cruxy/cli",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.4",
|
|
4
4
|
"description": "an agentic coding CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
"directory": "packages/cli"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"better-sqlite3": "^12.11.1",
|
|
33
32
|
"commander": "^12.1.0",
|
|
34
33
|
"fastembed": "^2.1.0",
|
|
35
34
|
"picocolors": "^1.1.1",
|
|
@@ -39,6 +38,9 @@
|
|
|
39
38
|
"zod-to-json-schema": "^3.23.5",
|
|
40
39
|
"@cruxy/sdk": "0.2.1"
|
|
41
40
|
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"better-sqlite3": "^12.11.1"
|
|
43
|
+
},
|
|
42
44
|
"devDependencies": {
|
|
43
45
|
"@types/better-sqlite3": "^7.6.13",
|
|
44
46
|
"@types/node": "^22.10.0",
|