@join-pantheon/cli 0.27.0 → 0.29.0
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/accounts.js +13 -2
- package/dist/agents.js +377 -9
- package/dist/cli.js +419 -182
- package/dist/client.js +91 -8
- package/dist/config.js +15 -0
- package/dist/doctor.js +35 -6
- package/dist/grants.js +16 -1
- package/dist/hooks-install.js +4 -2
- package/dist/host-env.js +51 -6
- package/dist/install.js +216 -16
- package/dist/kiro-files.js +23 -6
- package/dist/ledger.js +8 -2
- package/dist/machine.js +273 -54
- package/dist/mcp-supervisor.js +5 -0
- package/dist/mcp.js +33 -6
- package/dist/network.js +595 -0
- package/dist/pending.js +14 -7
- package/dist/quickstart.js +180 -21
- package/dist/refusal.js +29 -0
- package/dist/relay.js +686 -440
- package/dist/roster-file.js +19 -3
- package/dist/run-failure.js +18 -7
- package/dist/service.js +173 -40
- package/dist/setup-guide.js +21 -4
- package/dist/store.js +9 -3
- package/dist/update-check.js +2 -1
- package/dist/upgrade.js +2 -1
- package/dist/which.js +71 -7
- package/dist/workdir.js +7 -1
- package/dist/worker.js +524 -99
- package/helper/macos/menubar.swift +11 -3
- package/package.json +2 -1
package/dist/which.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { accessSync, constants, existsSync, statSync } from "node:fs";
|
|
3
|
-
import { posix, win32 } from "node:path";
|
|
2
|
+
import { accessSync, constants, existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { dirname, join, posix, resolve, win32 } from "node:path";
|
|
4
4
|
import { platform } from "node:os";
|
|
5
5
|
export const DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.PS1";
|
|
6
6
|
const isWindows = (os = platform()) => os === "win32";
|
|
@@ -76,15 +76,79 @@ export function spawnShape(binary, os = platform()) {
|
|
|
76
76
|
return { command: binary, shell: false };
|
|
77
77
|
return { command: binary, shell: /\.(cmd|bat)$/i.test(binary) };
|
|
78
78
|
}
|
|
79
|
-
export function npmSpawn(args, os = platform(), resolveNpm = () => which("npm", os)) {
|
|
79
|
+
export function npmSpawn(args, os = platform(), resolveNpm = () => which("npm", os), proxyEnv = {}) {
|
|
80
|
+
const env = Object.keys(proxyEnv).length ? { env: { ...process.env, ...proxyEnv } } : {};
|
|
80
81
|
if (!isWindows(os))
|
|
81
|
-
return { command: "npm", args: [...args], options: {} };
|
|
82
|
-
|
|
82
|
+
return { command: "npm", args: [...args], options: { ...env } };
|
|
83
|
+
const s = agentSpawn(resolveNpm() ?? "npm.cmd", args, os);
|
|
84
|
+
return { ...s, options: { ...s.options, ...env } };
|
|
83
85
|
}
|
|
84
|
-
const
|
|
85
|
-
export
|
|
86
|
+
const CMD_UNSAFE = /["%!^&|<>\r\n\0]/;
|
|
87
|
+
export const cmdSafe = (a) => !CMD_UNSAFE.test(a);
|
|
88
|
+
const cmdQuote = (a) => {
|
|
89
|
+
if (!cmdSafe(a))
|
|
90
|
+
throw new CmdLineUnsafe(a);
|
|
91
|
+
return /[\s&|<>^()]/.test(a) || a === "" ? `"${a.replace(/(\\+)$/, "$1$1")}"` : a;
|
|
92
|
+
};
|
|
93
|
+
export class CmdLineUnsafe extends Error {
|
|
94
|
+
arg;
|
|
95
|
+
constructor(arg, binary, why) {
|
|
96
|
+
super(`${binary ? `${binary} ${why ?? "is a Windows command script Pantheon could not read"}, and ` : ""}this text cannot be passed through cmd.exe safely (it contains a quote, a %, a !, a cmd.exe operator or a line break) — it was not run`);
|
|
97
|
+
this.arg = arg;
|
|
98
|
+
this.name = "CmdLineUnsafe";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function inspectCmdShim(shim, read = (f) => { try {
|
|
102
|
+
return readFileSync(f, "utf8");
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
} }, exists = existsSync, depth = 0) {
|
|
107
|
+
const text = read(shim);
|
|
108
|
+
if (text === null)
|
|
109
|
+
return { why: "is a Windows command script Pantheon could not read" };
|
|
110
|
+
if (text.length > 64 * 1024)
|
|
111
|
+
return { why: "was read but not recognised as a package manager's shim (it is too large to be one)" };
|
|
112
|
+
const dir = dirname(shim);
|
|
113
|
+
const re = /"%(?:~dp0|dp0%)\\?([^"%\r\n]+)"[ \t]*%\*[ \t]*\)?[ \t]*\r?$/gm;
|
|
114
|
+
let rel = null;
|
|
115
|
+
for (let m = re.exec(text); m; m = re.exec(text))
|
|
116
|
+
rel = m[1];
|
|
117
|
+
if (!rel)
|
|
118
|
+
return { why: "was read but not recognised as a package manager's shim" };
|
|
119
|
+
const parts = rel.split(/[\\/]+/).filter(Boolean);
|
|
120
|
+
if (!parts.length)
|
|
121
|
+
return { why: "was read but not recognised as a package manager's shim" };
|
|
122
|
+
const target = resolve(dir, ...parts);
|
|
123
|
+
if (!exists(target))
|
|
124
|
+
return { why: `was read, but what it runs is not there (${target})` };
|
|
125
|
+
if (/\.exe$/i.test(target))
|
|
126
|
+
return { command: target, args: [] };
|
|
127
|
+
if (/\.(?:cmd|bat)$/i.test(target)) {
|
|
128
|
+
if (depth >= 4)
|
|
129
|
+
return { why: "was read, but it runs shims that run shims too deep to follow" };
|
|
130
|
+
return inspectCmdShim(target, read, exists, depth + 1);
|
|
131
|
+
}
|
|
132
|
+
const js = /\.(?:c|m)?js$/i.test(target);
|
|
133
|
+
if (!js && (/\.[A-Za-z0-9]+$/.test(target) || !/\bnode(?:\.exe)?\b/i.test(text))) {
|
|
134
|
+
return { why: `was read, but it runs ${target}, which is not something Pantheon can start without cmd.exe` };
|
|
135
|
+
}
|
|
136
|
+
const localNode = join(dir, "node.exe");
|
|
137
|
+
return { command: exists(localNode) ? localNode : process.execPath, args: [target] };
|
|
138
|
+
}
|
|
139
|
+
export function resolveCmdShim(shim, read, exists) {
|
|
140
|
+
const r = inspectCmdShim(shim, read, exists);
|
|
141
|
+
return "command" in r ? r : null;
|
|
142
|
+
}
|
|
143
|
+
export function agentSpawn(binary, args, os = platform(), shim = (f) => inspectCmdShim(f)) {
|
|
86
144
|
if (!isWindows(os) || !/\.(cmd|bat)$/i.test(binary))
|
|
87
145
|
return { command: binary, args: [...args], options: {} };
|
|
146
|
+
if (!args.every(cmdSafe) || !cmdSafe(binary)) {
|
|
147
|
+
const direct = shim(binary);
|
|
148
|
+
if (!direct || !("command" in direct))
|
|
149
|
+
throw new CmdLineUnsafe(args.find((a) => !cmdSafe(a)) ?? binary, binary, direct?.why);
|
|
150
|
+
return { command: direct.command, args: [...direct.args, ...args], options: {} };
|
|
151
|
+
}
|
|
88
152
|
const line = [binary, ...args].map(cmdQuote).join(" ");
|
|
89
153
|
return {
|
|
90
154
|
command: process.env.ComSpec || "cmd.exe",
|
package/dist/workdir.js
CHANGED
|
@@ -9,6 +9,12 @@ export function gitActivity(path) {
|
|
|
9
9
|
}
|
|
10
10
|
return 0;
|
|
11
11
|
}
|
|
12
|
+
export function mentions(text, name) {
|
|
13
|
+
if (!name)
|
|
14
|
+
return false;
|
|
15
|
+
const esc = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16
|
+
return new RegExp(`(^|[^A-Za-z0-9._-])${esc}(?=$|[\\/]|\\.git(?![A-Za-z0-9_-])|\\.(?![A-Za-z0-9_-])|[^A-Za-z0-9._-])`).test(text);
|
|
17
|
+
}
|
|
12
18
|
export function pickWorkdir(bindings, hints, team, activity = gitActivity, exists = existsSync) {
|
|
13
19
|
const live = bindings.filter((b) => exists(b.path));
|
|
14
20
|
if (!live.length) {
|
|
@@ -17,7 +23,7 @@ export function pickWorkdir(bindings, hints, team, activity = gitActivity, exist
|
|
|
17
23
|
note: `no folder on this machine is bound to "${team}", so this opens in your home folder. To fix it, run pantheon use ${team} --here inside the repo.`,
|
|
18
24
|
};
|
|
19
25
|
}
|
|
20
|
-
const named = live.filter((b) => hints.some((h) => (b.origin ? h
|
|
26
|
+
const named = live.filter((b) => hints.some((h) => (b.origin ? mentions(h, b.origin) : false) || mentions(h, b.path)));
|
|
21
27
|
const pool = named.length ? named : live;
|
|
22
28
|
const chosen = [...pool].sort((x, y) => (activity(y.path) - activity(x.path)) || (y.bound_at - x.bound_at))[0];
|
|
23
29
|
const others = live.filter((b) => b.path !== chosen.path).map((b) => basename(b.path));
|