@4pm/cli 1.5.42 → 1.8.4
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 +108 -29
- 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 },
|
|
@@ -29636,7 +29667,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
|
|
|
29636
29667
|
init_wrapper();
|
|
29637
29668
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
29638
29669
|
import { basename as basename7, join as join28 } from "path";
|
|
29639
|
-
import { existsSync as
|
|
29670
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7 } from "fs";
|
|
29640
29671
|
|
|
29641
29672
|
// vendor/@4pm/utils/helpers.ts
|
|
29642
29673
|
function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
|
|
@@ -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({
|
|
@@ -38100,29 +38139,54 @@ function resolveInRoot5(root, relPath) {
|
|
|
38100
38139
|
const target = resolve6(base, relPath || ".");
|
|
38101
38140
|
return target === base || target.startsWith(base + sep7) ? target : null;
|
|
38102
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
|
+
}
|
|
38103
38149
|
async function gitDiff(root, path) {
|
|
38104
38150
|
const target = resolveInRoot5(root, path);
|
|
38105
38151
|
if (!target) {
|
|
38106
|
-
return { path, oldContent: "", newContent: "" };
|
|
38152
|
+
return { path, oldContent: "", newContent: "", isBinary: false };
|
|
38107
38153
|
}
|
|
38108
38154
|
const dir2 = dirname6(target);
|
|
38109
38155
|
const base = basename5(target);
|
|
38110
|
-
let
|
|
38156
|
+
let newBuf = null;
|
|
38111
38157
|
try {
|
|
38112
|
-
|
|
38158
|
+
newBuf = await readFile5(target);
|
|
38113
38159
|
} catch {
|
|
38114
38160
|
}
|
|
38115
|
-
let
|
|
38161
|
+
let oldBuf = null;
|
|
38116
38162
|
try {
|
|
38117
38163
|
const { stdout } = await run4("git", ["show", `HEAD:./${base}`], {
|
|
38118
38164
|
cwd: dir2,
|
|
38119
38165
|
timeout: 15e3,
|
|
38120
|
-
maxBuffer:
|
|
38166
|
+
maxBuffer: FS_TRANSFER_MAX_BYTES + 1024,
|
|
38167
|
+
encoding: "buffer"
|
|
38121
38168
|
});
|
|
38122
|
-
|
|
38169
|
+
oldBuf = stdout;
|
|
38123
38170
|
} catch {
|
|
38124
38171
|
}
|
|
38125
|
-
|
|
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
|
+
};
|
|
38126
38190
|
}
|
|
38127
38191
|
|
|
38128
38192
|
// src/core/git-env.ts
|
|
@@ -38574,7 +38638,7 @@ function handleMiscChannels(ctx, message, payload) {
|
|
|
38574
38638
|
}
|
|
38575
38639
|
|
|
38576
38640
|
// src/core/ws-client/handlers/project.ts
|
|
38577
|
-
import { mkdirSync as mkdirSync6, rmSync as rmSync6 } from "fs";
|
|
38641
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, renameSync, rmSync as rmSync6 } from "fs";
|
|
38578
38642
|
import { join as join20 } from "path";
|
|
38579
38643
|
|
|
38580
38644
|
// src/core/scaffold.ts
|
|
@@ -38597,6 +38661,10 @@ async function provisionRepos(target, repos, emit, opts = {}) {
|
|
|
38597
38661
|
for (const repo of repos) {
|
|
38598
38662
|
if (repo.primary) {
|
|
38599
38663
|
if (opts.clonePrimary && repo.url) {
|
|
38664
|
+
if (existsSync12(join19(target, ".git"))) {
|
|
38665
|
+
emit("git", `Primary repo already present \u2014 skipping clone.`);
|
|
38666
|
+
continue;
|
|
38667
|
+
}
|
|
38600
38668
|
emit("git", `Cloning ${repo.url}\u2026`);
|
|
38601
38669
|
await run9("git", ["clone", repo.url, target], { timeout: 12e4 });
|
|
38602
38670
|
continue;
|
|
@@ -38612,6 +38680,10 @@ async function provisionRepos(target, repos, emit, opts = {}) {
|
|
|
38612
38680
|
}
|
|
38613
38681
|
const dir2 = join19(target, subDirName(repo));
|
|
38614
38682
|
if (repo.url) {
|
|
38683
|
+
if (existsSync12(join19(dir2, ".git"))) {
|
|
38684
|
+
emit("git", `Sub-repo ${subDirName(repo)} already present \u2014 skipping clone.`);
|
|
38685
|
+
continue;
|
|
38686
|
+
}
|
|
38615
38687
|
emit("git", `Cloning sub-repo ${repo.url}\u2026`);
|
|
38616
38688
|
await run9("git", ["clone", repo.url, dir2], { timeout: 12e4 });
|
|
38617
38689
|
} else {
|
|
@@ -38727,12 +38799,19 @@ function handleProjectChannels(ctx, message, payload) {
|
|
|
38727
38799
|
switch (message.channel) {
|
|
38728
38800
|
case WsChannels.PHYSIC_SYNC: {
|
|
38729
38801
|
const sync = payload;
|
|
38730
|
-
|
|
38731
|
-
|
|
38802
|
+
const oldName = sync.oldName;
|
|
38803
|
+
const oldPath = oldName ? join20(ctx.profileDir, oldName) : null;
|
|
38804
|
+
const newPath = join20(ctx.profileDir, sync.newName);
|
|
38805
|
+
if (oldName) {
|
|
38806
|
+
const oldRoot = ctx.physicFolderPath(oldName);
|
|
38732
38807
|
if (oldRoot) void uninstallCron(oldRoot).catch(() => void 0);
|
|
38733
38808
|
}
|
|
38734
|
-
if (
|
|
38735
|
-
|
|
38809
|
+
if (oldPath && oldName !== sync.newName && existsSync13(oldPath) && !existsSync13(newPath)) {
|
|
38810
|
+
renameSync(oldPath, newPath);
|
|
38811
|
+
} else {
|
|
38812
|
+
if (oldPath && oldName !== sync.newName && existsSync13(oldPath)) rmSync6(oldPath, { recursive: true, force: true });
|
|
38813
|
+
mkdirSync6(newPath, { recursive: true });
|
|
38814
|
+
}
|
|
38736
38815
|
ctx.physicRoot = ctx.physicFolderPath(sync.newName);
|
|
38737
38816
|
ctx.bus.setProject(sync.newName);
|
|
38738
38817
|
ctx.bus.log(t("project.folderSynced", { name: sync.newName }));
|
|
@@ -39523,7 +39602,7 @@ async function buildGraph(root, mode) {
|
|
|
39523
39602
|
|
|
39524
39603
|
// src/core/rag.ts
|
|
39525
39604
|
import { readFile as readFile12, writeFile as writeFile10, statfs as statfs2, mkdir as mkdir10 } from "fs/promises";
|
|
39526
|
-
import { existsSync as
|
|
39605
|
+
import { existsSync as existsSync14 } from "fs";
|
|
39527
39606
|
import { execFile as execFile10, spawn as spawn9 } from "child_process";
|
|
39528
39607
|
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
39529
39608
|
import { join as join26 } from "path";
|
|
@@ -39616,7 +39695,7 @@ async function ragStatus(root) {
|
|
|
39616
39695
|
const modelPresent = modelName.length > 0;
|
|
39617
39696
|
return {
|
|
39618
39697
|
installed: fastembed && sqliteVec && modelPresent,
|
|
39619
|
-
installing:
|
|
39698
|
+
installing: existsSync14(join26(root, RAG_REL, ".installing")),
|
|
39620
39699
|
python: { found: py.found, version: py.version },
|
|
39621
39700
|
deps: { pip, fastembed, sqliteVec },
|
|
39622
39701
|
model: { present: modelPresent, name: modelName },
|
|
@@ -39627,7 +39706,7 @@ async function ragStatus(root) {
|
|
|
39627
39706
|
};
|
|
39628
39707
|
}
|
|
39629
39708
|
async function readIndexMeta(root) {
|
|
39630
|
-
const indexing =
|
|
39709
|
+
const indexing = existsSync14(join26(root, RAG_REL, ".indexing"));
|
|
39631
39710
|
try {
|
|
39632
39711
|
const m = JSON.parse(await readFile12(join26(root, RAG_REL, ".index.json"), "utf8"));
|
|
39633
39712
|
return {
|
|
@@ -39702,8 +39781,8 @@ async function ensureEngine(root) {
|
|
|
39702
39781
|
async function ragReindex(root) {
|
|
39703
39782
|
const py = await detectPython();
|
|
39704
39783
|
if (!py.found) return { ok: false, started: false, error: "python3 not found" };
|
|
39705
|
-
if (!
|
|
39706
|
-
if (
|
|
39784
|
+
if (!existsSync14(join26(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
|
|
39785
|
+
if (existsSync14(join26(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
|
|
39707
39786
|
await ensureEngine(root);
|
|
39708
39787
|
const script = `
|
|
39709
39788
|
set +e
|
|
@@ -39723,7 +39802,7 @@ rm -f "${RAG_REL}/.indexing"
|
|
|
39723
39802
|
async function ragQuery(root, queryText, k = 8) {
|
|
39724
39803
|
const py = await detectPython();
|
|
39725
39804
|
if (!py.found) return { results: [], error: "python3 not found" };
|
|
39726
|
-
if (!
|
|
39805
|
+
if (!existsSync14(join26(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
|
|
39727
39806
|
await ensureEngine(root);
|
|
39728
39807
|
try {
|
|
39729
39808
|
const { stdout } = await run10(
|
|
@@ -39743,7 +39822,7 @@ async function ragInstall(root, model) {
|
|
|
39743
39822
|
}
|
|
39744
39823
|
const py = await detectPython();
|
|
39745
39824
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
39746
|
-
if (
|
|
39825
|
+
if (existsSync14(join26(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
39747
39826
|
try {
|
|
39748
39827
|
await mkdir10(join26(root, RAG_REL), { recursive: true });
|
|
39749
39828
|
} catch {
|
|
@@ -39772,7 +39851,7 @@ rm -f "${RAG_REL}/.installing"
|
|
|
39772
39851
|
}
|
|
39773
39852
|
|
|
39774
39853
|
// src/core/config-sync.ts
|
|
39775
|
-
import { existsSync as
|
|
39854
|
+
import { existsSync as existsSync15, readFileSync as readFileSync15 } from "fs";
|
|
39776
39855
|
import { join as join27 } from "path";
|
|
39777
39856
|
var SERVER_MANAGED_KEYS = [
|
|
39778
39857
|
"physicPath",
|
|
@@ -39791,7 +39870,7 @@ var SERVER_MANAGED_KEYS = [
|
|
|
39791
39870
|
];
|
|
39792
39871
|
function readConfigText(profileDir2) {
|
|
39793
39872
|
const path = join27(profileDir2, "config.json");
|
|
39794
|
-
if (
|
|
39873
|
+
if (existsSync15(path)) {
|
|
39795
39874
|
try {
|
|
39796
39875
|
return readFileSync15(path, "utf8");
|
|
39797
39876
|
} catch {
|
|
@@ -40644,7 +40723,7 @@ var WsClient = class {
|
|
|
40644
40723
|
/** Create the physic folder at an absolute path if missing (best-effort). */
|
|
40645
40724
|
ensurePhysicFolderPath(folder) {
|
|
40646
40725
|
try {
|
|
40647
|
-
if (!
|
|
40726
|
+
if (!existsSync16(folder)) {
|
|
40648
40727
|
mkdirSync7(folder, { recursive: true });
|
|
40649
40728
|
this.bus.log(t("project.createdFolder", { folder }));
|
|
40650
40729
|
}
|
|
@@ -40674,7 +40753,7 @@ var WsClient = class {
|
|
|
40674
40753
|
projects: [],
|
|
40675
40754
|
version: CLI_VERSION,
|
|
40676
40755
|
physicPath,
|
|
40677
|
-
physicPathExists: physicPath ?
|
|
40756
|
+
physicPathExists: physicPath ? existsSync16(physicPath) : void 0,
|
|
40678
40757
|
// Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
|
|
40679
40758
|
autonomousRunning: physicPath ? isAutonomousRunning(physicPath) : false,
|
|
40680
40759
|
// The machine-user AI-run limit (0 = unlimited) + profile count so a dispatch can resolve the
|
|
@@ -43309,7 +43388,7 @@ var src_default = Yoga;
|
|
|
43309
43388
|
|
|
43310
43389
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
|
|
43311
43390
|
var import_react_reconciler = __toESM(require_react_reconciler(), 1);
|
|
43312
|
-
var
|
|
43391
|
+
var import_constants11 = __toESM(require_constants2(), 1);
|
|
43313
43392
|
import process3 from "process";
|
|
43314
43393
|
|
|
43315
43394
|
// ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
@@ -44551,7 +44630,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
44551
44630
|
scheduleTimeout: setTimeout,
|
|
44552
44631
|
cancelTimeout: clearTimeout,
|
|
44553
44632
|
noTimeout: -1,
|
|
44554
|
-
getCurrentEventPriority: () =>
|
|
44633
|
+
getCurrentEventPriority: () => import_constants11.DefaultEventPriority,
|
|
44555
44634
|
beforeActiveInstanceBlur() {
|
|
44556
44635
|
},
|
|
44557
44636
|
afterActiveInstanceBlur() {
|
|
@@ -46993,7 +47072,7 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
46993
47072
|
var import_react26 = __toESM(require_react(), 1);
|
|
46994
47073
|
|
|
46995
47074
|
// src/core/input-history.ts
|
|
46996
|
-
import { existsSync as
|
|
47075
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
|
|
46997
47076
|
import { join as join31 } from "path";
|
|
46998
47077
|
var MAX_HISTORY = 200;
|
|
46999
47078
|
function historyPath(profileDir2) {
|
|
@@ -47001,7 +47080,7 @@ function historyPath(profileDir2) {
|
|
|
47001
47080
|
}
|
|
47002
47081
|
function loadInputHistory(profileDir2) {
|
|
47003
47082
|
const path = historyPath(profileDir2);
|
|
47004
|
-
if (!
|
|
47083
|
+
if (!existsSync18(path)) return [];
|
|
47005
47084
|
try {
|
|
47006
47085
|
const data = JSON.parse(readFileSync18(path, "utf8"));
|
|
47007
47086
|
return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
|