maqcli 0.6.0 → 0.6.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/dist/core/command-catalog.js +1 -0
- package/dist/core/launcher.js +1 -1
- package/dist/core/update.d.ts +40 -0
- package/dist/core/update.js +75 -0
- package/dist/index.js +27 -1
- package/dist/server/daemon.js +1 -1
- package/package.json +1 -1
|
@@ -42,6 +42,7 @@ export const maqCommands = [
|
|
|
42
42
|
{ name: "flow", category: "control", summary: "Scheduled agent sessions (run under the daemon).", usage: "maq flow [list|add|remove]", needsInput: "none", args: [] },
|
|
43
43
|
{ name: "audit", category: "control", summary: "Verify a run's hash-chained audit log.", usage: "maq audit verify <run-dir>", needsInput: "none", args: [] },
|
|
44
44
|
{ name: "security", category: "system", summary: "Enforced security rules (protected paths, egress allowlist, injection scanning) + recent findings.", usage: "maq security [report|rules|scan <path>]", needsInput: "none", args: [] },
|
|
45
|
+
{ name: "update", category: "system", summary: "Check npm for a newer maqcli and self-update.", usage: "maq update [--check]", needsInput: "none", args: [{ name: "check", type: "boolean", description: "only check, don't install" }] },
|
|
45
46
|
];
|
|
46
47
|
/** Catalog of AI worker CLIs' own commands/flags (verified 2026-07-01). */
|
|
47
48
|
export const aiCliCatalog = [
|
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.1" });
|
|
357
357
|
try {
|
|
358
358
|
const { host, port } = await daemon.listen();
|
|
359
359
|
const url = `http://${host}:${port}/`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-update — lets a user run `maq update` from inside the CLI instead of
|
|
3
|
+
* remembering the npm incantation. Checks the npm registry for the latest
|
|
4
|
+
* published version, compares it to the running version, and (unless
|
|
5
|
+
* --check-only) re-installs globally via npm.
|
|
6
|
+
*
|
|
7
|
+
* Network access here is a deliberate, user-initiated exception to the
|
|
8
|
+
* default-deny egress posture (core/security.ts) — it only ever talks to the
|
|
9
|
+
* npm registry, and only when the user explicitly runs this command.
|
|
10
|
+
*/
|
|
11
|
+
export interface VersionInfo {
|
|
12
|
+
current: string;
|
|
13
|
+
latest: string | null;
|
|
14
|
+
upToDate: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Returns true if `latest` is strictly newer than `current`. */
|
|
18
|
+
export declare function isNewer(current: string, latest: string): boolean;
|
|
19
|
+
/** Query the npm registry for the latest published version of `maqcli`. */
|
|
20
|
+
export declare function fetchLatestVersion(registryUrl?: string, timeoutMs?: number): Promise<string>;
|
|
21
|
+
/** Compare the running version against the registry; never throws. */
|
|
22
|
+
export declare function checkForUpdate(currentVersion: string): Promise<VersionInfo>;
|
|
23
|
+
export interface UpdateOutcome {
|
|
24
|
+
ok: boolean;
|
|
25
|
+
message: string;
|
|
26
|
+
version?: VersionInfo;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Perform the update: check the registry, and if a newer version exists,
|
|
30
|
+
* run `npm install -g maqcli@<latest>`. `runner` is injectable for tests —
|
|
31
|
+
* it defaults to execSafe (shell:false, argument array; never string-built).
|
|
32
|
+
*/
|
|
33
|
+
export declare function performUpdate(currentVersion: string, opts?: {
|
|
34
|
+
checkOnly?: boolean;
|
|
35
|
+
runner?: (cmd: string, args: string[]) => Promise<{
|
|
36
|
+
code: number | null;
|
|
37
|
+
stdout: string;
|
|
38
|
+
stderr: string;
|
|
39
|
+
}>;
|
|
40
|
+
}): Promise<UpdateOutcome>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-update — lets a user run `maq update` from inside the CLI instead of
|
|
3
|
+
* remembering the npm incantation. Checks the npm registry for the latest
|
|
4
|
+
* published version, compares it to the running version, and (unless
|
|
5
|
+
* --check-only) re-installs globally via npm.
|
|
6
|
+
*
|
|
7
|
+
* Network access here is a deliberate, user-initiated exception to the
|
|
8
|
+
* default-deny egress posture (core/security.ts) — it only ever talks to the
|
|
9
|
+
* npm registry, and only when the user explicitly runs this command.
|
|
10
|
+
*/
|
|
11
|
+
import { execSafe } from "./exec.js";
|
|
12
|
+
/** Parse "x.y.z" into a comparable tuple; non-numeric parts sort as 0. */
|
|
13
|
+
function parseSemver(v) {
|
|
14
|
+
const parts = v.replace(/^v/, "").split(".").map((p) => parseInt(p, 10));
|
|
15
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
16
|
+
}
|
|
17
|
+
/** Returns true if `latest` is strictly newer than `current`. */
|
|
18
|
+
export function isNewer(current, latest) {
|
|
19
|
+
const a = parseSemver(current);
|
|
20
|
+
const b = parseSemver(latest);
|
|
21
|
+
for (let i = 0; i < 3; i++) {
|
|
22
|
+
if (b[i] > a[i])
|
|
23
|
+
return true;
|
|
24
|
+
if (b[i] < a[i])
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
/** Query the npm registry for the latest published version of `maqcli`. */
|
|
30
|
+
export async function fetchLatestVersion(registryUrl = "https://registry.npmjs.org/maqcli/latest", timeoutMs = 8000) {
|
|
31
|
+
const res = await fetch(registryUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
throw new Error(`registry returned ${res.status}`);
|
|
34
|
+
const body = (await res.json());
|
|
35
|
+
if (!body.version)
|
|
36
|
+
throw new Error("registry response missing a version field");
|
|
37
|
+
return body.version;
|
|
38
|
+
}
|
|
39
|
+
/** Compare the running version against the registry; never throws. */
|
|
40
|
+
export async function checkForUpdate(currentVersion) {
|
|
41
|
+
try {
|
|
42
|
+
const latest = await fetchLatestVersion();
|
|
43
|
+
return { current: currentVersion, latest, upToDate: !isNewer(currentVersion, latest) };
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
return { current: currentVersion, latest: null, upToDate: true, error: e.message };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Perform the update: check the registry, and if a newer version exists,
|
|
51
|
+
* run `npm install -g maqcli@<latest>`. `runner` is injectable for tests —
|
|
52
|
+
* it defaults to execSafe (shell:false, argument array; never string-built).
|
|
53
|
+
*/
|
|
54
|
+
export async function performUpdate(currentVersion, opts = {}) {
|
|
55
|
+
const version = await checkForUpdate(currentVersion);
|
|
56
|
+
if (version.error) {
|
|
57
|
+
return { ok: false, message: `could not check for updates: ${version.error}`, version };
|
|
58
|
+
}
|
|
59
|
+
if (version.upToDate) {
|
|
60
|
+
return { ok: true, message: `already up to date (v${version.current})`, version };
|
|
61
|
+
}
|
|
62
|
+
if (opts.checkOnly) {
|
|
63
|
+
return { ok: true, message: `update available: v${version.current} -> v${version.latest}`, version };
|
|
64
|
+
}
|
|
65
|
+
const runner = opts.runner ?? (async (cmd, args) => execSafe(cmd, args, { timeoutMs: 120000 }));
|
|
66
|
+
const outcome = await runner("npm", ["install", "-g", `maqcli@${version.latest}`]);
|
|
67
|
+
if (outcome.code !== 0) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
message: `update to v${version.latest} failed (exit ${outcome.code}): ${outcome.stderr.slice(0, 400) || outcome.stdout.slice(0, 400)}`,
|
|
71
|
+
version,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, message: `updated v${version.current} -> v${version.latest}`, version };
|
|
75
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -43,9 +43,10 @@ import { runInit } from "./core/init-wizard.js";
|
|
|
43
43
|
import { CostTracker } from "./core/cost-tracker.js";
|
|
44
44
|
import { runLauncher } from "./core/launcher.js";
|
|
45
45
|
import { runOrchestration } from "./core/orchestrator.js";
|
|
46
|
+
import { performUpdate } from "./core/update.js";
|
|
46
47
|
import { checkProtectedPath, scanForInjection, securityLog, securityRules, } from "./core/security.js";
|
|
47
48
|
import { readFileSync, statSync } from "node:fs";
|
|
48
|
-
const VERSION = "0.6.
|
|
49
|
+
const VERSION = "0.6.1";
|
|
49
50
|
async function main(argv) {
|
|
50
51
|
const [command, ...rest] = argv;
|
|
51
52
|
switch (command) {
|
|
@@ -79,6 +80,8 @@ async function main(argv) {
|
|
|
79
80
|
return cmdOrchestrate(rest);
|
|
80
81
|
case "security":
|
|
81
82
|
return cmdSecurity(rest);
|
|
83
|
+
case "update":
|
|
84
|
+
return cmdUpdate(rest);
|
|
82
85
|
case "verify":
|
|
83
86
|
return cmdVerify(rest);
|
|
84
87
|
case "serve":
|
|
@@ -426,6 +429,28 @@ function cmdSecurity(args) {
|
|
|
426
429
|
return 0;
|
|
427
430
|
}
|
|
428
431
|
/** Machine-readable rule set — shared shape with the daemon's GET /v1/security. */
|
|
432
|
+
async function cmdUpdate(args) {
|
|
433
|
+
const { values } = parseArgs({
|
|
434
|
+
args,
|
|
435
|
+
options: { ...commonFlags(), check: { type: "boolean", default: false } },
|
|
436
|
+
allowPositionals: true,
|
|
437
|
+
});
|
|
438
|
+
logger.out(`current version: ${VERSION}`);
|
|
439
|
+
logger.out(values.check ? "checking npm for a newer version…" : "checking npm and updating if a newer version is available…");
|
|
440
|
+
const outcome = await performUpdate(VERSION, { checkOnly: values.check });
|
|
441
|
+
if (values.json) {
|
|
442
|
+
logger.out(JSON.stringify(outcome, null, 0));
|
|
443
|
+
return outcome.ok ? 0 : 1;
|
|
444
|
+
}
|
|
445
|
+
logger.out(outcome.message);
|
|
446
|
+
if (outcome.ok && outcome.version && !outcome.version.upToDate && !values.check) {
|
|
447
|
+
logger.out("restart your terminal (or open a new one) to pick up the updated binary.");
|
|
448
|
+
}
|
|
449
|
+
if (outcome.ok && outcome.version && !outcome.version.upToDate && values.check) {
|
|
450
|
+
logger.out("run 'maq update' (without --check) to install it.");
|
|
451
|
+
}
|
|
452
|
+
return outcome.ok ? 0 : 1;
|
|
453
|
+
}
|
|
429
454
|
async function cmdServe(args) {
|
|
430
455
|
const { values } = parseArgs({
|
|
431
456
|
args,
|
|
@@ -1177,6 +1202,7 @@ function printHelp() {
|
|
|
1177
1202
|
' completion <shell> Shell completions (bash/zsh/fish/powershell)',
|
|
1178
1203
|
" audit verify <run-dir> Verify a run's hash-chained audit log",
|
|
1179
1204
|
" security [report|rules|scan <path>|add|remove] Enforced security rules + recent findings",
|
|
1205
|
+
" update [--check] Check npm for a newer maqcli and self-update",
|
|
1180
1206
|
" config [get|set|path|reset] Read or update ~/.maqcli/config.json",
|
|
1181
1207
|
" version | help [<topic>]",
|
|
1182
1208
|
"",
|
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.1";
|
|
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.1",
|
|
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": {
|