@4pm/cli 1.3.0 → 1.3.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/index.js +175 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28549,7 +28549,7 @@ ${INSECURE_URL_WARNING}
|
|
|
28549
28549
|
}
|
|
28550
28550
|
|
|
28551
28551
|
// src/commands/start.ts
|
|
28552
|
-
import { spawn as
|
|
28552
|
+
import { spawn as spawn9 } from "child_process";
|
|
28553
28553
|
import { join as join30 } from "path";
|
|
28554
28554
|
|
|
28555
28555
|
// src/core/update.ts
|
|
@@ -28780,6 +28780,21 @@ function isValidRoleSet(roles) {
|
|
|
28780
28780
|
return true;
|
|
28781
28781
|
}
|
|
28782
28782
|
|
|
28783
|
+
// vendor/@4pm/constants/worker-tools.ts
|
|
28784
|
+
var WORKER_TOOL_CATALOG = [
|
|
28785
|
+
{ id: "git", label: "Git", category: "vcs", versionArg: "--version", installPackage: null },
|
|
28786
|
+
{ id: "node", label: "Node.js", category: "runtime", versionArg: "--version", installPackage: null },
|
|
28787
|
+
{ id: "npm", label: "npm", category: "runtime", versionArg: "--version", installPackage: null },
|
|
28788
|
+
{ id: "pnpm", label: "pnpm", category: "runtime", versionArg: "--version", installPackage: "pnpm" },
|
|
28789
|
+
{ id: "claude", label: "Claude Code", category: "ai-cli", versionArg: "--version", installPackage: "@anthropic-ai/claude-code" },
|
|
28790
|
+
{ id: "codex", label: "Codex", category: "ai-cli", versionArg: "--version", installPackage: "@openai/codex" },
|
|
28791
|
+
{ id: "gh", label: "GitHub CLI", category: "vcs", versionArg: "--version", installPackage: null },
|
|
28792
|
+
{ id: "glab", label: "GitLab CLI", category: "vcs", versionArg: "--version", installPackage: null }
|
|
28793
|
+
];
|
|
28794
|
+
var WORKER_TOOL_PREREQUISITE_IDS = WORKER_TOOL_CATALOG.filter(
|
|
28795
|
+
(t) => t.installPackage === null
|
|
28796
|
+
).map((t) => t.id);
|
|
28797
|
+
|
|
28783
28798
|
// vendor/@4pm/constants/ws.ts
|
|
28784
28799
|
var WsChannel = {
|
|
28785
28800
|
COMMAND_DISPATCH: "command.dispatch",
|
|
@@ -32962,6 +32977,12 @@ var listMachineLinksQuerySchema = baseRequestSchema.extend({
|
|
|
32962
32977
|
var updateMachineLinkRequestSchema = external_exports.object({
|
|
32963
32978
|
hashcode3ExpiresAt: external_exports.string().datetime().nullable()
|
|
32964
32979
|
});
|
|
32980
|
+
var workerToolInstallSchema = external_exports.object({
|
|
32981
|
+
/** Catalog id or npm package name (validated npm-name shape on the cli). */
|
|
32982
|
+
name: external_exports.string().trim().min(1).max(214),
|
|
32983
|
+
/** Package manager to run the global install with. */
|
|
32984
|
+
manager: external_exports.enum(["npm", "pnpm"])
|
|
32985
|
+
});
|
|
32965
32986
|
var configWriteRequestSchema = external_exports.object({
|
|
32966
32987
|
config: external_exports.string().max(256 * 1024)
|
|
32967
32988
|
});
|
|
@@ -33346,6 +33367,15 @@ var WsChannels = {
|
|
|
33346
33367
|
// ADR-0141) — the machine-user Settings tab syncs the worker cli's config.
|
|
33347
33368
|
CONFIG_READ: "config.read",
|
|
33348
33369
|
CONFIG_WRITE: "config.write",
|
|
33370
|
+
// worker tools management (ADR-0206) — the Tools tab. `tools.list` probes the default
|
|
33371
|
+
// catalog + extra globals (reply); `tools.install`/`tools.uninstall` start a streamed op
|
|
33372
|
+
// (reply = accepted/rejected), then the cli pushes `tools.progress` lines and one
|
|
33373
|
+
// `tools.done` per opId back to the server (relayed to the browser over SSE).
|
|
33374
|
+
TOOLS_LIST: "tools.list",
|
|
33375
|
+
TOOLS_INSTALL: "tools.install",
|
|
33376
|
+
TOOLS_UNINSTALL: "tools.uninstall",
|
|
33377
|
+
TOOLS_PROGRESS: "tools.progress",
|
|
33378
|
+
TOOLS_DONE: "tools.done",
|
|
33349
33379
|
// autonomous mode control (ADR-0152): read settings+status+books+approvals, tail logs, and
|
|
33350
33380
|
// write {settings|approvals|userTodo|cron} — the dashboard drives the worker's autonomous engine.
|
|
33351
33381
|
AUTONOMOUS_READ: "autonomous.read",
|
|
@@ -36200,6 +36230,120 @@ function applyConfigText(profileDir2, text) {
|
|
|
36200
36230
|
return { ok: true };
|
|
36201
36231
|
}
|
|
36202
36232
|
|
|
36233
|
+
// src/core/worker-tools.ts
|
|
36234
|
+
import { spawn as spawn8 } from "child_process";
|
|
36235
|
+
var NPM_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
36236
|
+
function run10(cmd, args, onLine, timeoutMs = 18e4) {
|
|
36237
|
+
return new Promise((resolve8) => {
|
|
36238
|
+
let out = "";
|
|
36239
|
+
let buf = "";
|
|
36240
|
+
let child = null;
|
|
36241
|
+
const done = (code) => {
|
|
36242
|
+
clearTimeout(timer);
|
|
36243
|
+
if (onLine && buf.trim()) onLine(buf.trim());
|
|
36244
|
+
resolve8({ code, out });
|
|
36245
|
+
};
|
|
36246
|
+
const timer = setTimeout(() => {
|
|
36247
|
+
child?.kill();
|
|
36248
|
+
if (onLine) onLine(`timed out after ${Math.round(timeoutMs / 1e3)}s`);
|
|
36249
|
+
done(124);
|
|
36250
|
+
}, timeoutMs);
|
|
36251
|
+
timer.unref?.();
|
|
36252
|
+
const feed = (d) => {
|
|
36253
|
+
const text = d.toString("utf8");
|
|
36254
|
+
out += text;
|
|
36255
|
+
if (!onLine) return;
|
|
36256
|
+
buf += text;
|
|
36257
|
+
let nl;
|
|
36258
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
36259
|
+
const line = buf.slice(0, nl).replace(/\r$/, "");
|
|
36260
|
+
buf = buf.slice(nl + 1);
|
|
36261
|
+
onLine(line);
|
|
36262
|
+
}
|
|
36263
|
+
};
|
|
36264
|
+
try {
|
|
36265
|
+
child = spawn8(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
36266
|
+
child.stdout?.on("data", feed);
|
|
36267
|
+
child.stderr?.on("data", feed);
|
|
36268
|
+
child.on("exit", (code) => done(code ?? 0));
|
|
36269
|
+
child.on("error", () => done(127));
|
|
36270
|
+
} catch {
|
|
36271
|
+
done(127);
|
|
36272
|
+
}
|
|
36273
|
+
});
|
|
36274
|
+
}
|
|
36275
|
+
async function detectOne(cmd, versionArg) {
|
|
36276
|
+
const { code, out } = await run10(cmd, [versionArg], void 0, 15e3);
|
|
36277
|
+
if (code !== 0) return null;
|
|
36278
|
+
const first = out.split("\n").map((l) => l.trim()).find(Boolean);
|
|
36279
|
+
return first ?? "";
|
|
36280
|
+
}
|
|
36281
|
+
async function listExtras() {
|
|
36282
|
+
const { out } = await run10("npm", ["ls", "-g", "--depth=0", "--json"], void 0, 2e4);
|
|
36283
|
+
if (!out.trim()) return [];
|
|
36284
|
+
let deps = {};
|
|
36285
|
+
try {
|
|
36286
|
+
deps = JSON.parse(out).dependencies ?? {};
|
|
36287
|
+
} catch {
|
|
36288
|
+
return [];
|
|
36289
|
+
}
|
|
36290
|
+
const catalogPkgs = new Set(
|
|
36291
|
+
WORKER_TOOL_CATALOG.map((t) => t.installPackage).filter((p) => !!p)
|
|
36292
|
+
);
|
|
36293
|
+
return Object.entries(deps).filter(([name]) => !catalogPkgs.has(name)).map(([name, info]) => ({
|
|
36294
|
+
id: name,
|
|
36295
|
+
label: name,
|
|
36296
|
+
category: "runtime",
|
|
36297
|
+
installed: true,
|
|
36298
|
+
version: info.version ?? null,
|
|
36299
|
+
installable: true
|
|
36300
|
+
}));
|
|
36301
|
+
}
|
|
36302
|
+
async function detectWorkerTools() {
|
|
36303
|
+
const catalog = await Promise.all(
|
|
36304
|
+
WORKER_TOOL_CATALOG.map(async (t) => {
|
|
36305
|
+
const version = await detectOne(t.id, t.versionArg);
|
|
36306
|
+
return {
|
|
36307
|
+
id: t.id,
|
|
36308
|
+
label: t.label,
|
|
36309
|
+
category: t.category,
|
|
36310
|
+
installed: version !== null,
|
|
36311
|
+
version,
|
|
36312
|
+
installable: t.installPackage !== null
|
|
36313
|
+
};
|
|
36314
|
+
})
|
|
36315
|
+
);
|
|
36316
|
+
const extras = await listExtras().catch(() => []);
|
|
36317
|
+
return { catalog, extras };
|
|
36318
|
+
}
|
|
36319
|
+
function resolvePackage(name, op) {
|
|
36320
|
+
const entry = WORKER_TOOL_CATALOG.find((t) => t.id === name);
|
|
36321
|
+
if (entry) {
|
|
36322
|
+
if (entry.installPackage === null) {
|
|
36323
|
+
return { error: `"${name}" is a prerequisite and cannot be ${op}ed from here.` };
|
|
36324
|
+
}
|
|
36325
|
+
return { pkg: entry.installPackage };
|
|
36326
|
+
}
|
|
36327
|
+
if (WORKER_TOOL_PREREQUISITE_IDS.includes(name)) {
|
|
36328
|
+
return { error: `"${name}" is a prerequisite and cannot be ${op}ed from here.` };
|
|
36329
|
+
}
|
|
36330
|
+
if (!NPM_NAME.test(name)) return { error: `Invalid package name: "${name}".` };
|
|
36331
|
+
return { pkg: name };
|
|
36332
|
+
}
|
|
36333
|
+
function opArgs(op, manager, pkg) {
|
|
36334
|
+
if (manager === "pnpm") return [op === "install" ? "add" : "remove", "-g", pkg];
|
|
36335
|
+
return [op === "install" ? "install" : "uninstall", "-g", pkg];
|
|
36336
|
+
}
|
|
36337
|
+
async function runWorkerToolOp(op, name, manager, onLine) {
|
|
36338
|
+
const resolved = resolvePackage(name, op);
|
|
36339
|
+
if (resolved.error || !resolved.pkg) {
|
|
36340
|
+
return { ok: false, exitCode: 1, error: resolved.error ?? "Invalid package." };
|
|
36341
|
+
}
|
|
36342
|
+
onLine(`$ ${manager} ${opArgs(op, manager, resolved.pkg).join(" ")}`);
|
|
36343
|
+
const { code } = await run10(manager, opArgs(op, manager, resolved.pkg), onLine);
|
|
36344
|
+
return { ok: code === 0, exitCode: code, error: code === 0 ? void 0 : `${manager} exited ${code}` };
|
|
36345
|
+
}
|
|
36346
|
+
|
|
36203
36347
|
// src/core/ws-client.ts
|
|
36204
36348
|
var HEARTBEAT_MS = 3e4;
|
|
36205
36349
|
var USAGE_POLL_MS = 5 * 6e4;
|
|
@@ -36929,6 +37073,31 @@ var WsClient = class {
|
|
|
36929
37073
|
this.send(WsChannels.CONFIG_WRITE, res, message.id);
|
|
36930
37074
|
break;
|
|
36931
37075
|
}
|
|
37076
|
+
case WsChannels.TOOLS_LIST:
|
|
37077
|
+
void detectWorkerTools().then(
|
|
37078
|
+
(reply) => this.send(WsChannels.TOOLS_LIST, reply, message.id)
|
|
37079
|
+
);
|
|
37080
|
+
break;
|
|
37081
|
+
case WsChannels.TOOLS_INSTALL:
|
|
37082
|
+
case WsChannels.TOOLS_UNINSTALL: {
|
|
37083
|
+
const req = payload;
|
|
37084
|
+
const op = message.channel === WsChannels.TOOLS_INSTALL ? "install" : "uninstall";
|
|
37085
|
+
this.send(message.channel, { started: true }, message.id);
|
|
37086
|
+
void runWorkerToolOp(
|
|
37087
|
+
op,
|
|
37088
|
+
req.name,
|
|
37089
|
+
req.manager,
|
|
37090
|
+
(line) => this.send(WsChannels.TOOLS_PROGRESS, { opId: req.opId, line })
|
|
37091
|
+
).then(
|
|
37092
|
+
(res) => this.send(WsChannels.TOOLS_DONE, {
|
|
37093
|
+
opId: req.opId,
|
|
37094
|
+
ok: res.ok,
|
|
37095
|
+
exitCode: res.exitCode,
|
|
37096
|
+
error: res.error
|
|
37097
|
+
})
|
|
37098
|
+
);
|
|
37099
|
+
break;
|
|
37100
|
+
}
|
|
36932
37101
|
case WsChannels.GIT_DIFF:
|
|
36933
37102
|
void gitDiff(payload.path).then(
|
|
36934
37103
|
(reply) => this.send(WsChannels.GIT_DIFF, reply, message.id)
|
|
@@ -40021,7 +40190,7 @@ var src_default = Yoga;
|
|
|
40021
40190
|
|
|
40022
40191
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
|
|
40023
40192
|
var import_react_reconciler = __toESM(require_react_reconciler(), 1);
|
|
40024
|
-
var
|
|
40193
|
+
var import_constants6 = __toESM(require_constants2(), 1);
|
|
40025
40194
|
import process3 from "process";
|
|
40026
40195
|
|
|
40027
40196
|
// ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
@@ -41263,7 +41432,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
41263
41432
|
scheduleTimeout: setTimeout,
|
|
41264
41433
|
cancelTimeout: clearTimeout,
|
|
41265
41434
|
noTimeout: -1,
|
|
41266
|
-
getCurrentEventPriority: () =>
|
|
41435
|
+
getCurrentEventPriority: () => import_constants6.DefaultEventPriority,
|
|
41267
41436
|
beforeActiveInstanceBlur() {
|
|
41268
41437
|
},
|
|
41269
41438
|
afterActiveInstanceBlur() {
|
|
@@ -44664,7 +44833,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
44664
44833
|
if (result.action === "updated") {
|
|
44665
44834
|
logger.info("update.updated", { version: result.version });
|
|
44666
44835
|
console.log("Restarting with the new version\u2026");
|
|
44667
|
-
const child =
|
|
44836
|
+
const child = spawn9(process.execPath, process.argv.slice(1), {
|
|
44668
44837
|
stdio: "inherit",
|
|
44669
44838
|
env: { ...process.env, FOURPM_NO_UPDATE: "1" }
|
|
44670
44839
|
});
|
|
@@ -44881,12 +45050,12 @@ async function runAttach(profileDir2, profileName) {
|
|
|
44881
45050
|
}
|
|
44882
45051
|
|
|
44883
45052
|
// src/commands/ai-login.ts
|
|
44884
|
-
import { spawn as
|
|
45053
|
+
import { spawn as spawn10 } from "child_process";
|
|
44885
45054
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
44886
45055
|
import { basename as basename5 } from "path";
|
|
44887
45056
|
function runProviderLogin(cmd, envVar, dir2) {
|
|
44888
45057
|
return new Promise((resolve8) => {
|
|
44889
|
-
const child =
|
|
45058
|
+
const child = spawn10(cmd, [], {
|
|
44890
45059
|
stdio: "inherit",
|
|
44891
45060
|
env: { ...process.env, [envVar]: dir2 }
|
|
44892
45061
|
});
|