maqcli 0.6.3 → 0.6.5
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/core/launcher.js +1 -1
- package/dist/core/update.d.ts +19 -5
- package/dist/core/update.js +36 -9
- package/dist/index.js +1 -1
- package/dist/server/daemon.js +1 -1
- package/package.json +1 -1
package/dist/core/launcher.js
CHANGED
|
@@ -353,7 +353,7 @@ async function connectMobile(rl) {
|
|
|
353
353
|
async function launchUi(authKey) {
|
|
354
354
|
// Reuse the daemon; open its landing page. Import lazily to avoid a cycle.
|
|
355
355
|
const { createDaemon } = await import("../server/daemon.js");
|
|
356
|
-
const daemon = createDaemon({ token: authKey, version: "0.6.
|
|
356
|
+
const daemon = createDaemon({ token: authKey, version: "0.6.5" });
|
|
357
357
|
try {
|
|
358
358
|
const { host, port } = await daemon.listen();
|
|
359
359
|
const url = `http://${host}:${port}/`;
|
package/dist/core/update.d.ts
CHANGED
|
@@ -66,22 +66,35 @@ export declare function runNpm(args: string[], opts?: {
|
|
|
66
66
|
}>;
|
|
67
67
|
/**
|
|
68
68
|
* Build the OS-appropriate command to run `npm install -g maqcli@<version>`
|
|
69
|
-
* fully detached from the current process (see module doc for why).
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* the
|
|
69
|
+
* fully detached from the current process (see module doc for why).
|
|
70
|
+
*
|
|
71
|
+
* On Windows, `cmd.exe /c "npm install..."` alone is NOT enough: even with
|
|
72
|
+
* `detached: true` + `.unref()` on the Node side, the child stays tied to the
|
|
73
|
+
* parent's console/job object, and it dies the moment the parent's console
|
|
74
|
+
* closes (a long-standing Node behavior on Windows — nodejs/node#5614). The
|
|
75
|
+
* fix is to have cmd.exe launch the real work via the `start` builtin, which
|
|
76
|
+
* creates a genuinely independent process outside the parent's job object.
|
|
77
|
+
*
|
|
78
|
+
* `start`'s own command-line parsing is notoriously fragile with nested
|
|
79
|
+
* quotes (redirection operators and quoted paths inside a quoted inner
|
|
80
|
+
* command reliably break it). Rather than fight cmd.exe's quoting rules, we
|
|
81
|
+
* write the actual work to a small, disposable .bat/.sh script on disk and
|
|
82
|
+
* have `start`/the shell launch THAT — no nested quoting at all.
|
|
73
83
|
*/
|
|
74
84
|
export declare function detachedInstallCommand(version: string, logPath: string, platform?: NodeJS.Platform): {
|
|
75
85
|
cmd: string;
|
|
76
86
|
args: string[];
|
|
87
|
+
scriptPath: string;
|
|
88
|
+
scriptContent: string;
|
|
77
89
|
};
|
|
78
90
|
/**
|
|
79
91
|
* Launch the update fully detached and return immediately — the caller
|
|
80
92
|
* (cmdUpdate) should print guidance and exit right away rather than await
|
|
81
93
|
* anything else, which is what avoids the Windows file-lock failure mode.
|
|
82
94
|
* `spawner` is injectable for tests so nothing is actually spawned there.
|
|
95
|
+
* `writer` is injectable so tests don't touch the real filesystem either.
|
|
83
96
|
*/
|
|
84
|
-
export declare function launchDetachedUpdate(version: string, logPath: string, spawner?: typeof spawn): number | undefined;
|
|
97
|
+
export declare function launchDetachedUpdate(version: string, logPath: string, spawner?: typeof spawn, writer?: (path: string, content: string) => void): number | undefined;
|
|
85
98
|
export interface UpdateOutcome {
|
|
86
99
|
ok: boolean;
|
|
87
100
|
message: string;
|
|
@@ -116,6 +129,7 @@ export declare function performUpdate(currentVersion: string, opts?: {
|
|
|
116
129
|
stderr: string;
|
|
117
130
|
}>;
|
|
118
131
|
spawner?: typeof spawn;
|
|
132
|
+
writer?: (path: string, content: string) => void;
|
|
119
133
|
logPath?: string;
|
|
120
134
|
}): Promise<UpdateOutcome>;
|
|
121
135
|
/**
|
package/dist/core/update.js
CHANGED
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
import { spawn } from "node:child_process";
|
|
44
44
|
import { tmpdir } from "node:os";
|
|
45
45
|
import { join } from "node:path";
|
|
46
|
+
import { writeFileSync, chmodSync } from "node:fs";
|
|
46
47
|
import { execSafe } from "./exec.js";
|
|
47
48
|
/** Parse "x.y.z" into a comparable tuple; non-numeric parts sort as 0. */
|
|
48
49
|
function parseSemver(v) {
|
|
@@ -97,26 +98,50 @@ export async function runNpm(args, opts = {}) {
|
|
|
97
98
|
}
|
|
98
99
|
/**
|
|
99
100
|
* Build the OS-appropriate command to run `npm install -g maqcli@<version>`
|
|
100
|
-
* fully detached from the current process (see module doc for why).
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* the
|
|
101
|
+
* fully detached from the current process (see module doc for why).
|
|
102
|
+
*
|
|
103
|
+
* On Windows, `cmd.exe /c "npm install..."` alone is NOT enough: even with
|
|
104
|
+
* `detached: true` + `.unref()` on the Node side, the child stays tied to the
|
|
105
|
+
* parent's console/job object, and it dies the moment the parent's console
|
|
106
|
+
* closes (a long-standing Node behavior on Windows — nodejs/node#5614). The
|
|
107
|
+
* fix is to have cmd.exe launch the real work via the `start` builtin, which
|
|
108
|
+
* creates a genuinely independent process outside the parent's job object.
|
|
109
|
+
*
|
|
110
|
+
* `start`'s own command-line parsing is notoriously fragile with nested
|
|
111
|
+
* quotes (redirection operators and quoted paths inside a quoted inner
|
|
112
|
+
* command reliably break it). Rather than fight cmd.exe's quoting rules, we
|
|
113
|
+
* write the actual work to a small, disposable .bat/.sh script on disk and
|
|
114
|
+
* have `start`/the shell launch THAT — no nested quoting at all.
|
|
104
115
|
*/
|
|
105
116
|
export function detachedInstallCommand(version, logPath, platform = process.platform) {
|
|
106
117
|
const pkg = `maqcli@${version}`;
|
|
107
118
|
if (platform === "win32") {
|
|
108
|
-
|
|
119
|
+
const scriptPath = join(tmpdir(), `maq-update-${Date.now()}.bat`);
|
|
120
|
+
const scriptContent = ["@echo off", `npm install -g ${pkg} > "${logPath}" 2>&1`, `start "" /min cmd.exe /c del "%~f0"`].join("\r\n");
|
|
121
|
+
return { cmd: "cmd.exe", args: ["/c", "start", "", "/min", scriptPath], scriptPath, scriptContent };
|
|
109
122
|
}
|
|
110
|
-
|
|
123
|
+
const scriptPath = join(tmpdir(), `maq-update-${Date.now()}.sh`);
|
|
124
|
+
const scriptContent = ["#!/bin/sh", `npm install -g ${pkg} > '${logPath}' 2>&1`, `rm -f "$0"`].join("\n");
|
|
125
|
+
return { cmd: "sh", args: [scriptPath], scriptPath, scriptContent };
|
|
111
126
|
}
|
|
112
127
|
/**
|
|
113
128
|
* Launch the update fully detached and return immediately — the caller
|
|
114
129
|
* (cmdUpdate) should print guidance and exit right away rather than await
|
|
115
130
|
* anything else, which is what avoids the Windows file-lock failure mode.
|
|
116
131
|
* `spawner` is injectable for tests so nothing is actually spawned there.
|
|
132
|
+
* `writer` is injectable so tests don't touch the real filesystem either.
|
|
117
133
|
*/
|
|
118
|
-
export function launchDetachedUpdate(version, logPath, spawner = spawn) {
|
|
119
|
-
const { cmd, args } = detachedInstallCommand(version, logPath);
|
|
134
|
+
export function launchDetachedUpdate(version, logPath, spawner = spawn, writer = (path, content) => writeFileSync(path, content, "utf8")) {
|
|
135
|
+
const { cmd, args, scriptPath, scriptContent } = detachedInstallCommand(version, logPath);
|
|
136
|
+
writer(scriptPath, scriptContent);
|
|
137
|
+
if (process.platform !== "win32") {
|
|
138
|
+
try {
|
|
139
|
+
chmodSync(scriptPath, 0o755);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* best-effort */
|
|
143
|
+
}
|
|
144
|
+
}
|
|
120
145
|
const child = spawner(cmd, args, { detached: true, stdio: "ignore", windowsHide: true });
|
|
121
146
|
child.on("error", () => {
|
|
122
147
|
/* best-effort; the log file (or its absence) is the source of truth */
|
|
@@ -153,7 +178,9 @@ export async function performUpdate(currentVersion, opts = {}) {
|
|
|
153
178
|
const latest = version.latest;
|
|
154
179
|
if (!opts.wait) {
|
|
155
180
|
const logPath = opts.logPath ?? defaultLogPath();
|
|
156
|
-
const pid =
|
|
181
|
+
const pid = opts.writer
|
|
182
|
+
? launchDetachedUpdate(latest, logPath, opts.spawner, opts.writer)
|
|
183
|
+
: launchDetachedUpdate(latest, logPath, opts.spawner);
|
|
157
184
|
return {
|
|
158
185
|
ok: true,
|
|
159
186
|
message: `update to v${latest} launched in the background (detached, avoids file locks). Open a new terminal in a few seconds to pick it up.`,
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ import { runOrchestration } from "./core/orchestrator.js";
|
|
|
46
46
|
import { performUpdate, installedGlobalVersion } from "./core/update.js";
|
|
47
47
|
import { checkProtectedPath, scanForInjection, securityLog, securityRules, } from "./core/security.js";
|
|
48
48
|
import { readFileSync, statSync } from "node:fs";
|
|
49
|
-
const VERSION = "0.6.
|
|
49
|
+
const VERSION = "0.6.5";
|
|
50
50
|
async function main(argv) {
|
|
51
51
|
const [command, ...rest] = argv;
|
|
52
52
|
switch (command) {
|
package/dist/server/daemon.js
CHANGED
|
@@ -52,7 +52,7 @@ export function createDaemon(opts = {}) {
|
|
|
52
52
|
const host = opts.host ?? process.env.MAQ_HOST ?? "127.0.0.1";
|
|
53
53
|
const port = opts.port ?? Number(process.env.MAQ_PORT ?? 7717);
|
|
54
54
|
const token = opts.token ?? process.env.MAQ_TOKEN ?? generateToken();
|
|
55
|
-
const version = opts.version ?? "0.6.
|
|
55
|
+
const version = opts.version ?? "0.6.5";
|
|
56
56
|
const corsOrigin = opts.corsOrigin ?? process.env.MAQ_CORS_ORIGIN;
|
|
57
57
|
const registry = opts.registry ?? new SessionRegistry();
|
|
58
58
|
const interactive = new InteractiveRegistry();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maqcli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "MAQ master orchestrator — a token-efficient, agent-agnostic supervisor CLI that sits on top of any worker CLI (AI or not) via a Scout -> Plan -> Execute -> Verify pipeline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|