@4pm/cli 1.5.40 → 1.7.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/index.js +120 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28635,6 +28635,37 @@ function isValidRoleSet(roles) {
|
|
|
28635
28635
|
return true;
|
|
28636
28636
|
}
|
|
28637
28637
|
|
|
28638
|
+
// vendor/@4pm/constants/worker-pool.ts
|
|
28639
|
+
var AiJob = {
|
|
28640
|
+
/** Spec field/section/subagent suggest (one-shot). */
|
|
28641
|
+
SPEC_SUGGEST: "spec-suggest",
|
|
28642
|
+
/** Spec review — advisory (one-shot). */
|
|
28643
|
+
SPEC_REVIEW: "spec-review",
|
|
28644
|
+
/** Spec compose + create verdict (one-shot). */
|
|
28645
|
+
SPEC_COMPOSE: "spec-compose",
|
|
28646
|
+
/** Generators: WBS/est/proposal/feasibility/report (one-shot). */
|
|
28647
|
+
DOC_GENERATE: "doc-generate",
|
|
28648
|
+
/** Console prompt — full agent. */
|
|
28649
|
+
CONSOLE_AGENT: "console-agent",
|
|
28650
|
+
/** Git merge / AI conflict resolve — full agent. */
|
|
28651
|
+
GIT_MERGE: "git-merge",
|
|
28652
|
+
/** Graph add-link/add-code/delete-unused advice (one-shot). */
|
|
28653
|
+
GRAPH_SUGGEST: "graph-suggest",
|
|
28654
|
+
/** Subagent/skill content generate (one-shot). */
|
|
28655
|
+
AGENTS_GENERATE: "agents-generate",
|
|
28656
|
+
/** Template "Analyze impact" report — read-only agent. */
|
|
28657
|
+
ANALYZE_IMPACT: "analyze-impact",
|
|
28658
|
+
/** Template "Update" → branch + PR — write-capable agent. */
|
|
28659
|
+
TEMPLATE_UPDATE: "template-update",
|
|
28660
|
+
/** Autonomous-mode self-spawn — full agent. */
|
|
28661
|
+
AUTONOMOUS: "autonomous",
|
|
28662
|
+
/** Memo → community post compose (vision) — full agent. */
|
|
28663
|
+
MEMO_COMPOSE: "memo-compose",
|
|
28664
|
+
/** Outbound input review — the reviewer cli (one-shot). */
|
|
28665
|
+
OUTBOUND_REVIEW: "outbound-review"
|
|
28666
|
+
};
|
|
28667
|
+
var AI_JOBS = Object.values(AiJob);
|
|
28668
|
+
|
|
28638
28669
|
// vendor/@4pm/constants/worker-tools.ts
|
|
28639
28670
|
var WORKER_TOOL_CATALOG = [
|
|
28640
28671
|
{ id: "git", label: "Git", category: "vcs", versionArg: "--version", installPackage: null, installable: false, updatable: false },
|
|
@@ -33828,7 +33859,15 @@ var dispatchCommandRequestSchema = external_exports.object({
|
|
|
33828
33859
|
* "AI settings" modal (per-user localStorage), layered over the profile default by the cli.
|
|
33829
33860
|
* Only meaningful with `ai:true`.
|
|
33830
33861
|
*/
|
|
33831
|
-
aiConfig: aiRunConfigSchema.optional()
|
|
33862
|
+
aiConfig: aiRunConfigSchema.optional(),
|
|
33863
|
+
/**
|
|
33864
|
+
* AI job (ADR-0284): which of the 13 AI functions this dispatch is — the caller stamps it (the
|
|
33865
|
+
* end user never picks). With `pick:"idle"` it drives the job-aware routing over the project's
|
|
33866
|
+
* worker-routing table (pools before lone machines → job priority → member index, with
|
|
33867
|
+
* exhaustion failover). Absent ⇒ the flat idle pool (backward compatible). Ignored with an
|
|
33868
|
+
* explicit `machineLinkId`.
|
|
33869
|
+
*/
|
|
33870
|
+
job: external_exports.enum(AI_JOBS).optional()
|
|
33832
33871
|
}).superRefine((v, ctx) => {
|
|
33833
33872
|
if (v.machineLinkId == null === (v.pick == null)) {
|
|
33834
33873
|
ctx.addIssue({
|
|
@@ -37844,10 +37883,19 @@ async function listDir(path, root) {
|
|
|
37844
37883
|
|
|
37845
37884
|
// src/core/fs-read.ts
|
|
37846
37885
|
import { readFile as readFile3 } from "fs/promises";
|
|
37847
|
-
import { resolve as resolve2 } from "path";
|
|
37886
|
+
import { resolve as resolve2, sep as sep3 } from "path";
|
|
37848
37887
|
var MAX_BYTES = 256 * 1024;
|
|
37849
|
-
|
|
37850
|
-
|
|
37888
|
+
function resolveInRoot(root, relPath) {
|
|
37889
|
+
if (!root) return null;
|
|
37890
|
+
const base = resolve2(root);
|
|
37891
|
+
const target = resolve2(base, relPath || ".");
|
|
37892
|
+
return target === base || target.startsWith(base + sep3) ? target : null;
|
|
37893
|
+
}
|
|
37894
|
+
async function readWorkerFile(root, path) {
|
|
37895
|
+
const target = resolveInRoot(root, path);
|
|
37896
|
+
if (!target) {
|
|
37897
|
+
return { path, content: "", truncated: false };
|
|
37898
|
+
}
|
|
37851
37899
|
try {
|
|
37852
37900
|
const buf = await readFile3(target);
|
|
37853
37901
|
const truncated = buf.byteLength > MAX_BYTES;
|
|
@@ -37860,16 +37908,16 @@ async function readWorkerFile(path) {
|
|
|
37860
37908
|
|
|
37861
37909
|
// src/core/fs-write.ts
|
|
37862
37910
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
37863
|
-
import { dirname as dirname3, resolve as resolve3, sep as
|
|
37911
|
+
import { dirname as dirname3, resolve as resolve3, sep as sep4 } from "path";
|
|
37864
37912
|
var MAX_BYTES2 = 2 * 1024 * 1024;
|
|
37865
|
-
function
|
|
37913
|
+
function resolveInRoot2(root, relPath) {
|
|
37866
37914
|
if (!root) return null;
|
|
37867
37915
|
const base = resolve3(root);
|
|
37868
37916
|
const target = resolve3(base, relPath || ".");
|
|
37869
|
-
return target === base || target.startsWith(base +
|
|
37917
|
+
return target === base || target.startsWith(base + sep4) ? target : null;
|
|
37870
37918
|
}
|
|
37871
37919
|
async function writeWorkerFile(root, relPath, content) {
|
|
37872
|
-
const target =
|
|
37920
|
+
const target = resolveInRoot2(root, relPath);
|
|
37873
37921
|
if (!target) {
|
|
37874
37922
|
return { ok: false, path: relPath, bytes: 0, error: "path escapes the project root" };
|
|
37875
37923
|
}
|
|
@@ -37888,12 +37936,12 @@ async function writeWorkerFile(root, relPath, content) {
|
|
|
37888
37936
|
|
|
37889
37937
|
// src/core/fs-mutate.ts
|
|
37890
37938
|
import { mkdir as mkdir3, writeFile as writeFile3, rename, rm, stat } from "fs/promises";
|
|
37891
|
-
import { basename as basename3, dirname as dirname4, resolve as resolve4, sep as
|
|
37939
|
+
import { basename as basename3, dirname as dirname4, resolve as resolve4, sep as sep5 } from "path";
|
|
37892
37940
|
var MAX_BYTES3 = 2 * 1024 * 1024;
|
|
37893
|
-
function
|
|
37941
|
+
function resolveInRoot3(root, rel) {
|
|
37894
37942
|
const base = resolve4(root);
|
|
37895
37943
|
const target = resolve4(base, rel || ".");
|
|
37896
|
-
return target === base || target.startsWith(base +
|
|
37944
|
+
return target === base || target.startsWith(base + sep5) ? target : null;
|
|
37897
37945
|
}
|
|
37898
37946
|
async function isDir(p) {
|
|
37899
37947
|
try {
|
|
@@ -37916,13 +37964,13 @@ async function mutateFs(root, req) {
|
|
|
37916
37964
|
try {
|
|
37917
37965
|
switch (req.op) {
|
|
37918
37966
|
case "mkdir": {
|
|
37919
|
-
const target =
|
|
37967
|
+
const target = resolveInRoot3(root, req.path ?? "");
|
|
37920
37968
|
if (!target || target === resolve4(root)) return escaped(req.path ?? "");
|
|
37921
37969
|
await mkdir3(target, { recursive: true });
|
|
37922
37970
|
return { ok: true, path: target };
|
|
37923
37971
|
}
|
|
37924
37972
|
case "create": {
|
|
37925
|
-
const target =
|
|
37973
|
+
const target = resolveInRoot3(root, req.path ?? "");
|
|
37926
37974
|
if (!target || target === resolve4(root)) return escaped(req.path ?? "");
|
|
37927
37975
|
if (await exists(target)) return { ok: false, path: target, error: "already exists" };
|
|
37928
37976
|
const content = req.content ?? "";
|
|
@@ -37934,19 +37982,19 @@ async function mutateFs(root, req) {
|
|
|
37934
37982
|
return { ok: true, path: target };
|
|
37935
37983
|
}
|
|
37936
37984
|
case "move": {
|
|
37937
|
-
const from =
|
|
37938
|
-
let to =
|
|
37985
|
+
const from = resolveInRoot3(root, req.from ?? "");
|
|
37986
|
+
let to = resolveInRoot3(root, req.to ?? "");
|
|
37939
37987
|
if (!from || !to) return escaped(req.from ?? req.to ?? "");
|
|
37940
37988
|
if (from === resolve4(root)) return { ok: false, path: from, error: "cannot move the project root" };
|
|
37941
37989
|
if (await isDir(to)) to = resolve4(to, basename3(from));
|
|
37942
|
-
if (to !== resolve4(root) && !to.startsWith(resolve4(root) +
|
|
37990
|
+
if (to !== resolve4(root) && !to.startsWith(resolve4(root) + sep5)) return escaped(req.to ?? "");
|
|
37943
37991
|
if (await exists(to)) return { ok: false, path: to, error: "destination already exists" };
|
|
37944
37992
|
await mkdir3(dirname4(to), { recursive: true });
|
|
37945
37993
|
await rename(from, to);
|
|
37946
37994
|
return { ok: true, path: to };
|
|
37947
37995
|
}
|
|
37948
37996
|
case "delete": {
|
|
37949
|
-
const target =
|
|
37997
|
+
const target = resolveInRoot3(root, req.path ?? "");
|
|
37950
37998
|
if (!target) return escaped(req.path ?? "");
|
|
37951
37999
|
if (target === resolve4(root)) return { ok: false, path: target, error: "cannot delete the project root" };
|
|
37952
38000
|
await rm(target, { recursive: true, force: true });
|
|
@@ -37962,12 +38010,12 @@ async function mutateFs(root, req) {
|
|
|
37962
38010
|
|
|
37963
38011
|
// src/core/fs-transfer.ts
|
|
37964
38012
|
import { mkdir as mkdir4, readFile as readFile4, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
37965
|
-
import { basename as basename4, dirname as dirname5, extname, resolve as resolve5, sep as
|
|
37966
|
-
function
|
|
38013
|
+
import { basename as basename4, dirname as dirname5, extname, resolve as resolve5, sep as sep6 } from "path";
|
|
38014
|
+
function resolveInRoot4(root, relPath) {
|
|
37967
38015
|
if (!root) return null;
|
|
37968
38016
|
const base = resolve5(root);
|
|
37969
38017
|
const target = resolve5(base, relPath || ".");
|
|
37970
|
-
return target === base || target.startsWith(base +
|
|
38018
|
+
return target === base || target.startsWith(base + sep6) ? target : null;
|
|
37971
38019
|
}
|
|
37972
38020
|
var MIME_BY_EXT = {
|
|
37973
38021
|
".png": "image/png",
|
|
@@ -37991,7 +38039,7 @@ function guessMime(path) {
|
|
|
37991
38039
|
return MIME_BY_EXT[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
37992
38040
|
}
|
|
37993
38041
|
async function uploadBinaryFile(root, relPath, contentBase64) {
|
|
37994
|
-
const target =
|
|
38042
|
+
const target = resolveInRoot4(root, relPath);
|
|
37995
38043
|
if (!target) {
|
|
37996
38044
|
return { ok: false, path: relPath, bytes: 0, error: "path escapes the project root" };
|
|
37997
38045
|
}
|
|
@@ -38013,7 +38061,7 @@ async function uploadBinaryFile(root, relPath, contentBase64) {
|
|
|
38013
38061
|
}
|
|
38014
38062
|
}
|
|
38015
38063
|
async function downloadBinaryFile(root, relPath) {
|
|
38016
|
-
const target =
|
|
38064
|
+
const target = resolveInRoot4(root, relPath);
|
|
38017
38065
|
if (!target) return { error: "path escapes the project root" };
|
|
38018
38066
|
try {
|
|
38019
38067
|
const info = await stat2(target);
|
|
@@ -38042,7 +38090,7 @@ function handleFsChannels(ctx, message, payload) {
|
|
|
38042
38090
|
);
|
|
38043
38091
|
return true;
|
|
38044
38092
|
case WsChannels.FS_READ:
|
|
38045
|
-
void readWorkerFile(payload.path).then(
|
|
38093
|
+
void readWorkerFile(ctx.physicRoot, payload.path).then(
|
|
38046
38094
|
(reply) => ctx.send(WsChannels.FS_READ, reply, message.id)
|
|
38047
38095
|
);
|
|
38048
38096
|
return true;
|
|
@@ -38082,29 +38130,63 @@ function handleFsChannels(ctx, message, payload) {
|
|
|
38082
38130
|
// src/core/git-diff.ts
|
|
38083
38131
|
import { readFile as readFile5 } from "fs/promises";
|
|
38084
38132
|
import { execFile as execFile4 } from "child_process";
|
|
38085
|
-
import { basename as basename5, dirname as dirname6, resolve as resolve6 } from "path";
|
|
38133
|
+
import { basename as basename5, dirname as dirname6, resolve as resolve6, sep as sep7 } from "path";
|
|
38086
38134
|
import { promisify as promisify4 } from "util";
|
|
38087
38135
|
var run4 = promisify4(execFile4);
|
|
38088
|
-
|
|
38089
|
-
|
|
38136
|
+
function resolveInRoot5(root, relPath) {
|
|
38137
|
+
if (!root) return null;
|
|
38138
|
+
const base = resolve6(root);
|
|
38139
|
+
const target = resolve6(base, relPath || ".");
|
|
38140
|
+
return target === base || target.startsWith(base + sep7) ? target : null;
|
|
38141
|
+
}
|
|
38142
|
+
function looksBinary(buf) {
|
|
38143
|
+
return buf.subarray(0, 8e3).includes(0);
|
|
38144
|
+
}
|
|
38145
|
+
function cappedBase64(buf) {
|
|
38146
|
+
if (!buf || buf.byteLength > FS_TRANSFER_MAX_BYTES) return "";
|
|
38147
|
+
return buf.toString("base64");
|
|
38148
|
+
}
|
|
38149
|
+
async function gitDiff(root, path) {
|
|
38150
|
+
const target = resolveInRoot5(root, path);
|
|
38151
|
+
if (!target) {
|
|
38152
|
+
return { path, oldContent: "", newContent: "", isBinary: false };
|
|
38153
|
+
}
|
|
38090
38154
|
const dir2 = dirname6(target);
|
|
38091
38155
|
const base = basename5(target);
|
|
38092
|
-
let
|
|
38156
|
+
let newBuf = null;
|
|
38093
38157
|
try {
|
|
38094
|
-
|
|
38158
|
+
newBuf = await readFile5(target);
|
|
38095
38159
|
} catch {
|
|
38096
38160
|
}
|
|
38097
|
-
let
|
|
38161
|
+
let oldBuf = null;
|
|
38098
38162
|
try {
|
|
38099
38163
|
const { stdout } = await run4("git", ["show", `HEAD:./${base}`], {
|
|
38100
38164
|
cwd: dir2,
|
|
38101
38165
|
timeout: 15e3,
|
|
38102
|
-
maxBuffer:
|
|
38166
|
+
maxBuffer: FS_TRANSFER_MAX_BYTES + 1024,
|
|
38167
|
+
encoding: "buffer"
|
|
38103
38168
|
});
|
|
38104
|
-
|
|
38169
|
+
oldBuf = stdout;
|
|
38105
38170
|
} catch {
|
|
38106
38171
|
}
|
|
38107
|
-
|
|
38172
|
+
const sample = newBuf ?? oldBuf;
|
|
38173
|
+
if (sample && looksBinary(sample)) {
|
|
38174
|
+
return {
|
|
38175
|
+
path: target,
|
|
38176
|
+
oldContent: "",
|
|
38177
|
+
newContent: "",
|
|
38178
|
+
isBinary: true,
|
|
38179
|
+
contentType: guessMime(target),
|
|
38180
|
+
oldContentBase64: cappedBase64(oldBuf),
|
|
38181
|
+
newContentBase64: cappedBase64(newBuf)
|
|
38182
|
+
};
|
|
38183
|
+
}
|
|
38184
|
+
return {
|
|
38185
|
+
path: target,
|
|
38186
|
+
oldContent: oldBuf ? oldBuf.toString("utf8") : "",
|
|
38187
|
+
newContent: newBuf ? newBuf.toString("utf8") : "",
|
|
38188
|
+
isBinary: false
|
|
38189
|
+
};
|
|
38108
38190
|
}
|
|
38109
38191
|
|
|
38110
38192
|
// src/core/git-env.ts
|
|
@@ -38209,7 +38291,7 @@ async function manageSshKey(op, profileDir2) {
|
|
|
38209
38291
|
// src/core/git-history.ts
|
|
38210
38292
|
import { readdir as readdir3 } from "fs/promises";
|
|
38211
38293
|
import { execFile as execFile7 } from "child_process";
|
|
38212
|
-
import { resolve as resolve7, sep as
|
|
38294
|
+
import { resolve as resolve7, sep as sep8 } from "path";
|
|
38213
38295
|
import { promisify as promisify7 } from "util";
|
|
38214
38296
|
var run7 = promisify7(execFile7);
|
|
38215
38297
|
var FS = "";
|
|
@@ -38218,7 +38300,7 @@ function resolveRepo(root, repo) {
|
|
|
38218
38300
|
if (!root) return null;
|
|
38219
38301
|
const base = resolve7(root);
|
|
38220
38302
|
const requested = resolve7(base, repo && repo.trim() ? repo : ".");
|
|
38221
|
-
return requested === base || requested.startsWith(base +
|
|
38303
|
+
return requested === base || requested.startsWith(base + sep8) ? requested : base;
|
|
38222
38304
|
}
|
|
38223
38305
|
async function git(cwd2, args) {
|
|
38224
38306
|
try {
|
|
@@ -38240,7 +38322,7 @@ async function gitRepos(root) {
|
|
|
38240
38322
|
const add = async (dir2) => {
|
|
38241
38323
|
const inside = await git(dir2, ["rev-parse", "--show-toplevel"]);
|
|
38242
38324
|
const top = inside.trim();
|
|
38243
|
-
if (!top || found.has(top) || !(top === base || top.startsWith(base +
|
|
38325
|
+
if (!top || found.has(top) || !(top === base || top.startsWith(base + sep8))) return;
|
|
38244
38326
|
found.add(top);
|
|
38245
38327
|
const subdir = top === base ? "" : top.slice(base.length + 1);
|
|
38246
38328
|
const remote = (await git(top, ["remote", "get-url", "origin"])).trim();
|
|
@@ -38327,7 +38409,7 @@ async function gitCommitDiff(root, repo, hash, path) {
|
|
|
38327
38409
|
function handleGitChannels(ctx, message, payload) {
|
|
38328
38410
|
switch (message.channel) {
|
|
38329
38411
|
case WsChannels.GIT_DIFF:
|
|
38330
|
-
void gitDiff(payload.path).then(
|
|
38412
|
+
void gitDiff(ctx.physicRoot, payload.path).then(
|
|
38331
38413
|
(reply) => ctx.send(WsChannels.GIT_DIFF, reply, message.id)
|
|
38332
38414
|
);
|
|
38333
38415
|
return true;
|
|
@@ -43291,7 +43373,7 @@ var src_default = Yoga;
|
|
|
43291
43373
|
|
|
43292
43374
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
|
|
43293
43375
|
var import_react_reconciler = __toESM(require_react_reconciler(), 1);
|
|
43294
|
-
var
|
|
43376
|
+
var import_constants11 = __toESM(require_constants2(), 1);
|
|
43295
43377
|
import process3 from "process";
|
|
43296
43378
|
|
|
43297
43379
|
// ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
@@ -44533,7 +44615,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
44533
44615
|
scheduleTimeout: setTimeout,
|
|
44534
44616
|
cancelTimeout: clearTimeout,
|
|
44535
44617
|
noTimeout: -1,
|
|
44536
|
-
getCurrentEventPriority: () =>
|
|
44618
|
+
getCurrentEventPriority: () => import_constants11.DefaultEventPriority,
|
|
44537
44619
|
beforeActiveInstanceBlur() {
|
|
44538
44620
|
},
|
|
44539
44621
|
afterActiveInstanceBlur() {
|