@4pm/cli 1.5.37 → 1.5.40
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 +255 -138
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5713,14 +5713,14 @@ var require_react_development = __commonJS({
|
|
|
5713
5713
|
var thenableResult = result;
|
|
5714
5714
|
var wasAwaited = false;
|
|
5715
5715
|
var thenable = {
|
|
5716
|
-
then: function(
|
|
5716
|
+
then: function(resolve10, reject) {
|
|
5717
5717
|
wasAwaited = true;
|
|
5718
5718
|
thenableResult.then(function(returnValue2) {
|
|
5719
5719
|
popActScope(prevActScopeDepth);
|
|
5720
5720
|
if (actScopeDepth === 0) {
|
|
5721
|
-
recursivelyFlushAsyncActWork(returnValue2,
|
|
5721
|
+
recursivelyFlushAsyncActWork(returnValue2, resolve10, reject);
|
|
5722
5722
|
} else {
|
|
5723
|
-
|
|
5723
|
+
resolve10(returnValue2);
|
|
5724
5724
|
}
|
|
5725
5725
|
}, function(error2) {
|
|
5726
5726
|
popActScope(prevActScopeDepth);
|
|
@@ -5750,20 +5750,20 @@ var require_react_development = __commonJS({
|
|
|
5750
5750
|
ReactCurrentActQueue.current = null;
|
|
5751
5751
|
}
|
|
5752
5752
|
var _thenable = {
|
|
5753
|
-
then: function(
|
|
5753
|
+
then: function(resolve10, reject) {
|
|
5754
5754
|
if (ReactCurrentActQueue.current === null) {
|
|
5755
5755
|
ReactCurrentActQueue.current = [];
|
|
5756
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
5756
|
+
recursivelyFlushAsyncActWork(returnValue, resolve10, reject);
|
|
5757
5757
|
} else {
|
|
5758
|
-
|
|
5758
|
+
resolve10(returnValue);
|
|
5759
5759
|
}
|
|
5760
5760
|
}
|
|
5761
5761
|
};
|
|
5762
5762
|
return _thenable;
|
|
5763
5763
|
} else {
|
|
5764
5764
|
var _thenable2 = {
|
|
5765
|
-
then: function(
|
|
5766
|
-
|
|
5765
|
+
then: function(resolve10, reject) {
|
|
5766
|
+
resolve10(returnValue);
|
|
5767
5767
|
}
|
|
5768
5768
|
};
|
|
5769
5769
|
return _thenable2;
|
|
@@ -5779,7 +5779,7 @@ var require_react_development = __commonJS({
|
|
|
5779
5779
|
actScopeDepth = prevActScopeDepth;
|
|
5780
5780
|
}
|
|
5781
5781
|
}
|
|
5782
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
5782
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve10, reject) {
|
|
5783
5783
|
{
|
|
5784
5784
|
var queue = ReactCurrentActQueue.current;
|
|
5785
5785
|
if (queue !== null) {
|
|
@@ -5788,16 +5788,16 @@ var require_react_development = __commonJS({
|
|
|
5788
5788
|
enqueueTask(function() {
|
|
5789
5789
|
if (queue.length === 0) {
|
|
5790
5790
|
ReactCurrentActQueue.current = null;
|
|
5791
|
-
|
|
5791
|
+
resolve10(returnValue);
|
|
5792
5792
|
} else {
|
|
5793
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
5793
|
+
recursivelyFlushAsyncActWork(returnValue, resolve10, reject);
|
|
5794
5794
|
}
|
|
5795
5795
|
});
|
|
5796
5796
|
} catch (error2) {
|
|
5797
5797
|
reject(error2);
|
|
5798
5798
|
}
|
|
5799
5799
|
} else {
|
|
5800
|
-
|
|
5800
|
+
resolve10(returnValue);
|
|
5801
5801
|
}
|
|
5802
5802
|
}
|
|
5803
5803
|
}
|
|
@@ -28560,8 +28560,22 @@ function normalizeLocale(value) {
|
|
|
28560
28560
|
|
|
28561
28561
|
// vendor/@4pm/constants/project-template.ts
|
|
28562
28562
|
var PROJECT_TEMPLATE = {
|
|
28563
|
-
version: "1.0.
|
|
28563
|
+
version: "1.0.2",
|
|
28564
28564
|
changelog: [
|
|
28565
|
+
{
|
|
28566
|
+
version: "1.0.2",
|
|
28567
|
+
date: "2026-09-16",
|
|
28568
|
+
summary: "AI_DONE.md changed to a Markdown table \u2014 catch-up entry for projects scaffolded before the conversion.",
|
|
28569
|
+
notes: [
|
|
28570
|
+
"AI_DONE.md's Done and Incidents sections are Markdown tables (| Timestamp | ID | Task description | Files | Notes | and | Timestamp | Note |), matching the other autonomous books.",
|
|
28571
|
+
"The conversion itself shipped with the baseline scaffold, but was never recorded as a template version, so the 1.0.1 changelog assumed AI_DONE was already tabular. Projects scaffolded before it still carry the old two-section prose layout even at 1.0.1; this entry lets them detect the drift and convert AI_DONE on the next Update."
|
|
28572
|
+
],
|
|
28573
|
+
files: [
|
|
28574
|
+
"AI_DONE.md",
|
|
28575
|
+
".claude/templates/AI_DONE.empty.md",
|
|
28576
|
+
".claude/templates/AI_DONE.sample.md"
|
|
28577
|
+
]
|
|
28578
|
+
},
|
|
28565
28579
|
{
|
|
28566
28580
|
version: "1.0.1",
|
|
28567
28581
|
date: "2026-09-13",
|
|
@@ -29621,7 +29635,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
|
|
|
29621
29635
|
// src/core/ws-client.ts
|
|
29622
29636
|
init_wrapper();
|
|
29623
29637
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
29624
|
-
import { basename as
|
|
29638
|
+
import { basename as basename7, join as join28 } from "path";
|
|
29625
29639
|
import { existsSync as existsSync15, mkdirSync as mkdirSync7 } from "fs";
|
|
29626
29640
|
|
|
29627
29641
|
// vendor/@4pm/utils/helpers.ts
|
|
@@ -33978,6 +33992,16 @@ var fsMutateRequestSchema = external_exports.object({
|
|
|
33978
33992
|
from: external_exports.string().max(1024).optional(),
|
|
33979
33993
|
to: external_exports.string().max(1024).optional()
|
|
33980
33994
|
});
|
|
33995
|
+
var FS_TRANSFER_MAX_BYTES = 10 * 1024 * 1024;
|
|
33996
|
+
var FS_TRANSFER_MAX_BASE64 = Math.ceil(FS_TRANSFER_MAX_BYTES * 4 / 3) + 16;
|
|
33997
|
+
var fsUploadRequestSchema = external_exports.object({
|
|
33998
|
+
/** Destination path relative to the physic-project root; a `..` escaping the root is rejected on the cli. */
|
|
33999
|
+
path: external_exports.string().min(1).max(1024),
|
|
34000
|
+
/** File bytes, base64-encoded (capped to the transfer limit). */
|
|
34001
|
+
contentBase64: external_exports.string().min(1).max(FS_TRANSFER_MAX_BASE64),
|
|
34002
|
+
/** Optional MIME type from the browser (informational). */
|
|
34003
|
+
contentType: external_exports.string().max(255).optional()
|
|
34004
|
+
});
|
|
33981
34005
|
var taskApproveRequestSchema = external_exports.object({
|
|
33982
34006
|
taskId: external_exports.string().min(1).max(64),
|
|
33983
34007
|
approved: external_exports.boolean()
|
|
@@ -34578,6 +34602,12 @@ var WsChannels = {
|
|
|
34578
34602
|
// server → cli (reply): create/rename/move/delete a file or folder in the project tree,
|
|
34579
34603
|
// each op path-clamped to the physic root (machine-0059, ADR-0260, `project.files_write`).
|
|
34580
34604
|
FS_MUTATE: "fs.mutate",
|
|
34605
|
+
// server → cli (reply): move file bytes between browser and worker as base64, root-clamped +
|
|
34606
|
+
// size-capped (machine-0061/0062, ADR-0278). `fs.upload` writes an uploaded/pasted file into the
|
|
34607
|
+
// tree (`project.files_write`); `fs.download` reads a file's raw bytes for the browser to save
|
|
34608
|
+
// (`project.read`). Binary transfer the text-only fs.read/fs.write can't carry.
|
|
34609
|
+
FS_UPLOAD: "fs.upload",
|
|
34610
|
+
FS_DOWNLOAD: "fs.download",
|
|
34581
34611
|
GIT_DIFF: "git.diff",
|
|
34582
34612
|
GIT_ENV: "git.env",
|
|
34583
34613
|
// server → cli (reply): read/write the paired profile's config.json (machine-0025/0026,
|
|
@@ -34890,8 +34920,8 @@ function resolveInstallTimeoutMs(sec) {
|
|
|
34890
34920
|
return sec && sec > 0 ? sec * 1e3 : TOOL_INSTALL_TIMEOUT_DEFAULT_MS;
|
|
34891
34921
|
}
|
|
34892
34922
|
function sleep(ms) {
|
|
34893
|
-
return new Promise((
|
|
34894
|
-
const t2 = setTimeout(
|
|
34923
|
+
return new Promise((resolve10) => {
|
|
34924
|
+
const t2 = setTimeout(resolve10, ms);
|
|
34895
34925
|
t2.unref?.();
|
|
34896
34926
|
});
|
|
34897
34927
|
}
|
|
@@ -34913,14 +34943,14 @@ function classifyToolFailure(code, out) {
|
|
|
34913
34943
|
return { reason: "other", retryable: false };
|
|
34914
34944
|
}
|
|
34915
34945
|
function run(cmd, args, onLine, timeoutMs = 18e4) {
|
|
34916
|
-
return new Promise((
|
|
34946
|
+
return new Promise((resolve10) => {
|
|
34917
34947
|
let out = "";
|
|
34918
34948
|
let buf = "";
|
|
34919
34949
|
let child = null;
|
|
34920
34950
|
const done = (code) => {
|
|
34921
34951
|
clearTimeout(timer);
|
|
34922
34952
|
if (onLine && buf.trim()) onLine(buf.trim());
|
|
34923
|
-
|
|
34953
|
+
resolve10({ code, out });
|
|
34924
34954
|
};
|
|
34925
34955
|
const timer = setTimeout(() => {
|
|
34926
34956
|
child?.kill();
|
|
@@ -35624,16 +35654,16 @@ async function fetchUsage(token) {
|
|
|
35624
35654
|
}
|
|
35625
35655
|
}
|
|
35626
35656
|
function runUsageCli(dir2, aiCli2) {
|
|
35627
|
-
return new Promise((
|
|
35657
|
+
return new Promise((resolve10) => {
|
|
35628
35658
|
let out = "";
|
|
35629
35659
|
let child = null;
|
|
35630
35660
|
const finish = () => {
|
|
35631
35661
|
clearTimeout(timer);
|
|
35632
|
-
|
|
35662
|
+
resolve10(out);
|
|
35633
35663
|
};
|
|
35634
35664
|
const timer = setTimeout(() => {
|
|
35635
35665
|
child?.kill();
|
|
35636
|
-
|
|
35666
|
+
resolve10(out);
|
|
35637
35667
|
}, 3e4);
|
|
35638
35668
|
timer.unref?.();
|
|
35639
35669
|
try {
|
|
@@ -36194,7 +36224,7 @@ function parseModeratedAnswer(text) {
|
|
|
36194
36224
|
return { body: text.trim() };
|
|
36195
36225
|
}
|
|
36196
36226
|
function runClaudeOnce(cmd, profile, prompt, extraEnv, imageDir) {
|
|
36197
|
-
return new Promise((
|
|
36227
|
+
return new Promise((resolve10, reject) => {
|
|
36198
36228
|
const isClaude = cmd.includes("claude");
|
|
36199
36229
|
const args = [
|
|
36200
36230
|
"-p",
|
|
@@ -36227,7 +36257,7 @@ function runClaudeOnce(cmd, profile, prompt, extraEnv, imageDir) {
|
|
|
36227
36257
|
child.on("close", (code) => {
|
|
36228
36258
|
clearTimeout(timer);
|
|
36229
36259
|
out += parser.flush();
|
|
36230
|
-
|
|
36260
|
+
resolve10({ code: code ?? -1, out, err, usage: parser.usage() });
|
|
36231
36261
|
});
|
|
36232
36262
|
child.stdin.write(prompt);
|
|
36233
36263
|
child.stdin.end();
|
|
@@ -36361,10 +36391,10 @@ async function crontabList() {
|
|
|
36361
36391
|
}
|
|
36362
36392
|
}
|
|
36363
36393
|
async function crontabSet(content) {
|
|
36364
|
-
return new Promise((
|
|
36394
|
+
return new Promise((resolve10) => {
|
|
36365
36395
|
const child = spawn5("crontab", ["-"], { stdio: ["pipe", "ignore", "ignore"] });
|
|
36366
|
-
child.on("error", () =>
|
|
36367
|
-
child.on("close", (code) =>
|
|
36396
|
+
child.on("error", () => resolve10(false));
|
|
36397
|
+
child.on("close", (code) => resolve10(code === 0));
|
|
36368
36398
|
child.stdin.end(content.endsWith("\n") ? content : content + "\n");
|
|
36369
36399
|
});
|
|
36370
36400
|
}
|
|
@@ -36488,14 +36518,14 @@ function detectContainerized() {
|
|
|
36488
36518
|
}
|
|
36489
36519
|
}
|
|
36490
36520
|
function canReach(host, port) {
|
|
36491
|
-
return new Promise((
|
|
36521
|
+
return new Promise((resolve10) => {
|
|
36492
36522
|
const socket = connect({ host, port });
|
|
36493
36523
|
let done = false;
|
|
36494
36524
|
const finish = (ok) => {
|
|
36495
36525
|
if (done) return;
|
|
36496
36526
|
done = true;
|
|
36497
36527
|
socket.destroy();
|
|
36498
|
-
|
|
36528
|
+
resolve10(ok);
|
|
36499
36529
|
};
|
|
36500
36530
|
socket.setTimeout(PROBE_TIMEOUT_MS);
|
|
36501
36531
|
socket.once("connect", () => finish(true));
|
|
@@ -36667,7 +36697,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
36667
36697
|
});
|
|
36668
36698
|
child.stdout?.on("data", (data) => batcher.push(data.toString("utf8")));
|
|
36669
36699
|
child.stderr?.on("data", (data) => batcher.push(data.toString("utf8")));
|
|
36670
|
-
await new Promise((
|
|
36700
|
+
await new Promise((resolve10) => {
|
|
36671
36701
|
child.on("close", (exitCode) => {
|
|
36672
36702
|
clearTimers();
|
|
36673
36703
|
batcher.flush();
|
|
@@ -36680,7 +36710,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
36680
36710
|
// server settles the command as failed and the web surfaces the note instead of spinning.
|
|
36681
36711
|
exitCode: timedOut ? 124 : exitCode ?? -1
|
|
36682
36712
|
});
|
|
36683
|
-
|
|
36713
|
+
resolve10();
|
|
36684
36714
|
});
|
|
36685
36715
|
child.on("error", (err) => {
|
|
36686
36716
|
clearTimers();
|
|
@@ -36692,7 +36722,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
36692
36722
|
done: true,
|
|
36693
36723
|
exitCode: -1
|
|
36694
36724
|
});
|
|
36695
|
-
|
|
36725
|
+
resolve10();
|
|
36696
36726
|
});
|
|
36697
36727
|
});
|
|
36698
36728
|
}
|
|
@@ -36714,15 +36744,15 @@ function isOutOfCredits(text) {
|
|
|
36714
36744
|
);
|
|
36715
36745
|
}
|
|
36716
36746
|
function runAttempt(commandId, cmd, args, stdin, cwd2, env3, onChunk, timeoutMs) {
|
|
36717
|
-
return new Promise((
|
|
36747
|
+
return new Promise((resolve10) => {
|
|
36718
36748
|
runCommand(
|
|
36719
36749
|
{ commandId, cmd, args, path: cwd2, env: env3 },
|
|
36720
36750
|
(out) => {
|
|
36721
36751
|
if (out.chunk) onChunk(out.chunk);
|
|
36722
|
-
if (out.done)
|
|
36752
|
+
if (out.done) resolve10(out.exitCode ?? -1);
|
|
36723
36753
|
},
|
|
36724
36754
|
{ stdin, ...timeoutMs > 0 ? { timeoutMs } : {} }
|
|
36725
|
-
).catch(() =>
|
|
36755
|
+
).catch(() => resolve10(-1));
|
|
36726
36756
|
});
|
|
36727
36757
|
}
|
|
36728
36758
|
async function runAiFailover(plan, commandId, cwd2, handlers, timeoutMs = 0) {
|
|
@@ -37220,7 +37250,7 @@ function buildPrompt2(input) {
|
|
|
37220
37250
|
].join("\n");
|
|
37221
37251
|
}
|
|
37222
37252
|
function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
|
|
37223
|
-
return new Promise((
|
|
37253
|
+
return new Promise((resolve10, reject) => {
|
|
37224
37254
|
const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
|
|
37225
37255
|
const env3 = {
|
|
37226
37256
|
...process.env,
|
|
@@ -37243,7 +37273,7 @@ function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
|
|
|
37243
37273
|
});
|
|
37244
37274
|
child.on("close", (code) => {
|
|
37245
37275
|
clearTimeout(timer);
|
|
37246
|
-
|
|
37276
|
+
resolve10({ code: code ?? -1, out, err });
|
|
37247
37277
|
});
|
|
37248
37278
|
child.stdin.write(prompt);
|
|
37249
37279
|
child.stdin.end();
|
|
@@ -37930,6 +37960,79 @@ async function mutateFs(root, req) {
|
|
|
37930
37960
|
}
|
|
37931
37961
|
}
|
|
37932
37962
|
|
|
37963
|
+
// src/core/fs-transfer.ts
|
|
37964
|
+
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 sep5 } from "path";
|
|
37966
|
+
function resolveInRoot3(root, relPath) {
|
|
37967
|
+
if (!root) return null;
|
|
37968
|
+
const base = resolve5(root);
|
|
37969
|
+
const target = resolve5(base, relPath || ".");
|
|
37970
|
+
return target === base || target.startsWith(base + sep5) ? target : null;
|
|
37971
|
+
}
|
|
37972
|
+
var MIME_BY_EXT = {
|
|
37973
|
+
".png": "image/png",
|
|
37974
|
+
".jpg": "image/jpeg",
|
|
37975
|
+
".jpeg": "image/jpeg",
|
|
37976
|
+
".gif": "image/gif",
|
|
37977
|
+
".webp": "image/webp",
|
|
37978
|
+
".svg": "image/svg+xml",
|
|
37979
|
+
".bmp": "image/bmp",
|
|
37980
|
+
".ico": "image/x-icon",
|
|
37981
|
+
".pdf": "application/pdf",
|
|
37982
|
+
".zip": "application/zip",
|
|
37983
|
+
".json": "application/json",
|
|
37984
|
+
".txt": "text/plain",
|
|
37985
|
+
".md": "text/markdown",
|
|
37986
|
+
".csv": "text/csv",
|
|
37987
|
+
".html": "text/html",
|
|
37988
|
+
".xml": "application/xml"
|
|
37989
|
+
};
|
|
37990
|
+
function guessMime(path) {
|
|
37991
|
+
return MIME_BY_EXT[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
37992
|
+
}
|
|
37993
|
+
async function uploadBinaryFile(root, relPath, contentBase64) {
|
|
37994
|
+
const target = resolveInRoot3(root, relPath);
|
|
37995
|
+
if (!target) {
|
|
37996
|
+
return { ok: false, path: relPath, bytes: 0, error: "path escapes the project root" };
|
|
37997
|
+
}
|
|
37998
|
+
let buf;
|
|
37999
|
+
try {
|
|
38000
|
+
buf = Buffer.from(contentBase64, "base64");
|
|
38001
|
+
} catch {
|
|
38002
|
+
return { ok: false, path: target, bytes: 0, error: "invalid base64 payload" };
|
|
38003
|
+
}
|
|
38004
|
+
if (buf.byteLength > FS_TRANSFER_MAX_BYTES) {
|
|
38005
|
+
return { ok: false, path: target, bytes: 0, error: `file too large (max ${FS_TRANSFER_MAX_BYTES} bytes)` };
|
|
38006
|
+
}
|
|
38007
|
+
try {
|
|
38008
|
+
await mkdir4(dirname5(target), { recursive: true });
|
|
38009
|
+
await writeFile4(target, buf);
|
|
38010
|
+
return { ok: true, path: target, bytes: buf.byteLength };
|
|
38011
|
+
} catch (err) {
|
|
38012
|
+
return { ok: false, path: target, bytes: 0, error: err instanceof Error ? err.message : String(err) };
|
|
38013
|
+
}
|
|
38014
|
+
}
|
|
38015
|
+
async function downloadBinaryFile(root, relPath) {
|
|
38016
|
+
const target = resolveInRoot3(root, relPath);
|
|
38017
|
+
if (!target) return { error: "path escapes the project root" };
|
|
38018
|
+
try {
|
|
38019
|
+
const info = await stat2(target);
|
|
38020
|
+
if (!info.isFile()) return { error: "not a file" };
|
|
38021
|
+
if (info.size > FS_TRANSFER_MAX_BYTES) {
|
|
38022
|
+
return { error: `file too large (max ${FS_TRANSFER_MAX_BYTES} bytes)` };
|
|
38023
|
+
}
|
|
38024
|
+
const buf = await readFile4(target);
|
|
38025
|
+
return {
|
|
38026
|
+
contentBase64: buf.toString("base64"),
|
|
38027
|
+
contentType: guessMime(target),
|
|
38028
|
+
name: basename4(target),
|
|
38029
|
+
size: buf.byteLength
|
|
38030
|
+
};
|
|
38031
|
+
} catch (err) {
|
|
38032
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
38033
|
+
}
|
|
38034
|
+
}
|
|
38035
|
+
|
|
37933
38036
|
// src/core/ws-client/handlers/fs.ts
|
|
37934
38037
|
function handleFsChannels(ctx, message, payload) {
|
|
37935
38038
|
switch (message.channel) {
|
|
@@ -37957,24 +38060,38 @@ function handleFsChannels(ctx, message, payload) {
|
|
|
37957
38060
|
);
|
|
37958
38061
|
return true;
|
|
37959
38062
|
}
|
|
38063
|
+
case WsChannels.FS_UPLOAD: {
|
|
38064
|
+
const req = payload;
|
|
38065
|
+
void uploadBinaryFile(ctx.physicRoot, req.path, req.contentBase64).then(
|
|
38066
|
+
(reply) => ctx.send(WsChannels.FS_UPLOAD, reply, message.id)
|
|
38067
|
+
);
|
|
38068
|
+
return true;
|
|
38069
|
+
}
|
|
38070
|
+
case WsChannels.FS_DOWNLOAD: {
|
|
38071
|
+
const req = payload;
|
|
38072
|
+
void downloadBinaryFile(ctx.physicRoot, req.path).then(
|
|
38073
|
+
(reply) => ctx.send(WsChannels.FS_DOWNLOAD, reply, message.id)
|
|
38074
|
+
);
|
|
38075
|
+
return true;
|
|
38076
|
+
}
|
|
37960
38077
|
default:
|
|
37961
38078
|
return false;
|
|
37962
38079
|
}
|
|
37963
38080
|
}
|
|
37964
38081
|
|
|
37965
38082
|
// src/core/git-diff.ts
|
|
37966
|
-
import { readFile as
|
|
38083
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
37967
38084
|
import { execFile as execFile4 } from "child_process";
|
|
37968
|
-
import { basename as
|
|
38085
|
+
import { basename as basename5, dirname as dirname6, resolve as resolve6 } from "path";
|
|
37969
38086
|
import { promisify as promisify4 } from "util";
|
|
37970
38087
|
var run4 = promisify4(execFile4);
|
|
37971
38088
|
async function gitDiff(path) {
|
|
37972
|
-
const target =
|
|
37973
|
-
const dir2 =
|
|
37974
|
-
const base =
|
|
38089
|
+
const target = resolve6(path);
|
|
38090
|
+
const dir2 = dirname6(target);
|
|
38091
|
+
const base = basename5(target);
|
|
37975
38092
|
let newContent = "";
|
|
37976
38093
|
try {
|
|
37977
|
-
newContent = await
|
|
38094
|
+
newContent = await readFile5(target, "utf8");
|
|
37978
38095
|
} catch {
|
|
37979
38096
|
}
|
|
37980
38097
|
let oldContent = "";
|
|
@@ -38023,7 +38140,7 @@ ${stderr}`;
|
|
|
38023
38140
|
|
|
38024
38141
|
// src/core/git-ssh-key.ts
|
|
38025
38142
|
import { execFile as execFile6 } from "child_process";
|
|
38026
|
-
import { readFile as
|
|
38143
|
+
import { readFile as readFile6, rm as rm2, mkdir as mkdir5 } from "fs/promises";
|
|
38027
38144
|
import { join as join17 } from "path";
|
|
38028
38145
|
import { promisify as promisify6 } from "util";
|
|
38029
38146
|
var run6 = promisify6(execFile6);
|
|
@@ -38034,7 +38151,7 @@ function keyPaths(profileDir2) {
|
|
|
38034
38151
|
}
|
|
38035
38152
|
async function readPublicKey(pub) {
|
|
38036
38153
|
try {
|
|
38037
|
-
return (await
|
|
38154
|
+
return (await readFile6(pub, "utf8")).trim();
|
|
38038
38155
|
} catch {
|
|
38039
38156
|
return null;
|
|
38040
38157
|
}
|
|
@@ -38056,7 +38173,7 @@ async function configureGit(key) {
|
|
|
38056
38173
|
}
|
|
38057
38174
|
async function generate(profileDir2) {
|
|
38058
38175
|
const { dir: dir2, key, pub } = keyPaths(profileDir2);
|
|
38059
|
-
await
|
|
38176
|
+
await mkdir5(dir2, { recursive: true });
|
|
38060
38177
|
await rm2(key, { force: true });
|
|
38061
38178
|
await rm2(pub, { force: true });
|
|
38062
38179
|
await run6("ssh-keygen", ["-t", "ed25519", "-f", key, "-N", "", "-C", "4pm-deploy-key"], {
|
|
@@ -38092,16 +38209,16 @@ async function manageSshKey(op, profileDir2) {
|
|
|
38092
38209
|
// src/core/git-history.ts
|
|
38093
38210
|
import { readdir as readdir3 } from "fs/promises";
|
|
38094
38211
|
import { execFile as execFile7 } from "child_process";
|
|
38095
|
-
import { resolve as
|
|
38212
|
+
import { resolve as resolve7, sep as sep6 } from "path";
|
|
38096
38213
|
import { promisify as promisify7 } from "util";
|
|
38097
38214
|
var run7 = promisify7(execFile7);
|
|
38098
38215
|
var FS = "";
|
|
38099
38216
|
var RS = "";
|
|
38100
38217
|
function resolveRepo(root, repo) {
|
|
38101
38218
|
if (!root) return null;
|
|
38102
|
-
const base =
|
|
38103
|
-
const requested =
|
|
38104
|
-
return requested === base || requested.startsWith(base +
|
|
38219
|
+
const base = resolve7(root);
|
|
38220
|
+
const requested = resolve7(base, repo && repo.trim() ? repo : ".");
|
|
38221
|
+
return requested === base || requested.startsWith(base + sep6) ? requested : base;
|
|
38105
38222
|
}
|
|
38106
38223
|
async function git(cwd2, args) {
|
|
38107
38224
|
try {
|
|
@@ -38117,13 +38234,13 @@ async function git(cwd2, args) {
|
|
|
38117
38234
|
}
|
|
38118
38235
|
async function gitRepos(root) {
|
|
38119
38236
|
if (!root) return { repos: [] };
|
|
38120
|
-
const base =
|
|
38237
|
+
const base = resolve7(root);
|
|
38121
38238
|
const found = /* @__PURE__ */ new Set();
|
|
38122
38239
|
const repos = [];
|
|
38123
38240
|
const add = async (dir2) => {
|
|
38124
38241
|
const inside = await git(dir2, ["rev-parse", "--show-toplevel"]);
|
|
38125
38242
|
const top = inside.trim();
|
|
38126
|
-
if (!top || found.has(top) || !(top === base || top.startsWith(base +
|
|
38243
|
+
if (!top || found.has(top) || !(top === base || top.startsWith(base + sep6))) return;
|
|
38127
38244
|
found.add(top);
|
|
38128
38245
|
const subdir = top === base ? "" : top.slice(base.length + 1);
|
|
38129
38246
|
const remote = (await git(top, ["remote", "get-url", "origin"])).trim();
|
|
@@ -38134,13 +38251,13 @@ async function gitRepos(root) {
|
|
|
38134
38251
|
const lvl1 = await readdir3(base, { withFileTypes: true });
|
|
38135
38252
|
for (const d of lvl1) {
|
|
38136
38253
|
if (!d.isDirectory() || d.name === ".git" || d.name === "node_modules") continue;
|
|
38137
|
-
const p1 =
|
|
38254
|
+
const p1 = resolve7(base, d.name);
|
|
38138
38255
|
await add(p1);
|
|
38139
38256
|
try {
|
|
38140
38257
|
const lvl2 = await readdir3(p1, { withFileTypes: true });
|
|
38141
38258
|
for (const d2 of lvl2) {
|
|
38142
38259
|
if (!d2.isDirectory() || d2.name === ".git" || d2.name === "node_modules") continue;
|
|
38143
|
-
await add(
|
|
38260
|
+
await add(resolve7(p1, d2.name));
|
|
38144
38261
|
}
|
|
38145
38262
|
} catch {
|
|
38146
38263
|
}
|
|
@@ -38443,10 +38560,10 @@ import { mkdirSync as mkdirSync6, rmSync as rmSync6 } from "fs";
|
|
|
38443
38560
|
import { join as join20 } from "path";
|
|
38444
38561
|
|
|
38445
38562
|
// src/core/scaffold.ts
|
|
38446
|
-
import { cp, mkdir as
|
|
38563
|
+
import { cp, mkdir as mkdir6, writeFile as writeFile5 } from "fs/promises";
|
|
38447
38564
|
import { existsSync as existsSync12 } from "fs";
|
|
38448
38565
|
import { execFile as execFile9 } from "child_process";
|
|
38449
|
-
import { dirname as
|
|
38566
|
+
import { dirname as dirname7, join as join19, resolve as resolve8 } from "path";
|
|
38450
38567
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
38451
38568
|
import { promisify as promisify9 } from "util";
|
|
38452
38569
|
var run9 = promisify9(execFile9);
|
|
@@ -38481,16 +38598,16 @@ async function provisionRepos(target, repos, emit, opts = {}) {
|
|
|
38481
38598
|
await run9("git", ["clone", repo.url, dir2], { timeout: 12e4 });
|
|
38482
38599
|
} else {
|
|
38483
38600
|
emit("git", `Initializing sub-repo ${subDirName(repo)}\u2026`);
|
|
38484
|
-
await
|
|
38601
|
+
await mkdir6(dir2, { recursive: true });
|
|
38485
38602
|
await run9("git", ["init"], { cwd: dir2, timeout: 2e4 });
|
|
38486
38603
|
}
|
|
38487
38604
|
}
|
|
38488
38605
|
}
|
|
38489
38606
|
function sampleDir() {
|
|
38490
38607
|
if (process.env.SCAFFOLD_SAMPLE_DIR) return process.env.SCAFFOLD_SAMPLE_DIR;
|
|
38491
|
-
const here =
|
|
38492
|
-
const bundled =
|
|
38493
|
-
for (const candidate of [bundled,
|
|
38608
|
+
const here = dirname7(fileURLToPath3(import.meta.url));
|
|
38609
|
+
const bundled = resolve8(here, "project-sample");
|
|
38610
|
+
for (const candidate of [bundled, resolve8(here, "../project-sample"), resolve8(here, "../../project-sample")]) {
|
|
38494
38611
|
if (existsSync12(candidate)) return candidate;
|
|
38495
38612
|
}
|
|
38496
38613
|
return bundled;
|
|
@@ -38502,14 +38619,14 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
|
|
|
38502
38619
|
onProgress?.({ projectId: payload.projectId, step, message });
|
|
38503
38620
|
};
|
|
38504
38621
|
try {
|
|
38505
|
-
const root = process.env.SCAFFOLD_ROOT ?
|
|
38622
|
+
const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
|
|
38506
38623
|
const target = join19(root, payload.projectName);
|
|
38507
|
-
await
|
|
38624
|
+
await mkdir6(target, { recursive: true });
|
|
38508
38625
|
emit("copy", "Copying the sample template\u2026");
|
|
38509
38626
|
await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
|
|
38510
38627
|
if (payload.spec) {
|
|
38511
38628
|
emit("spec", "Writing project.spec.json\u2026");
|
|
38512
|
-
await
|
|
38629
|
+
await writeFile5(
|
|
38513
38630
|
join19(target, "project.spec.json"),
|
|
38514
38631
|
JSON.stringify(payload.spec, null, 2),
|
|
38515
38632
|
"utf8"
|
|
@@ -38528,15 +38645,15 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
|
|
|
38528
38645
|
}
|
|
38529
38646
|
async function writeTemplateMarker(target) {
|
|
38530
38647
|
const dir2 = join19(target, ".4pm");
|
|
38531
|
-
await
|
|
38648
|
+
await mkdir6(dir2, { recursive: true });
|
|
38532
38649
|
const marker = { templateVersion: PROJECT_TEMPLATE.version, scaffoldedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
38533
|
-
await
|
|
38650
|
+
await writeFile5(join19(dir2, ".4pm.json"), JSON.stringify(marker, null, 2) + "\n", "utf8");
|
|
38534
38651
|
}
|
|
38535
38652
|
async function aiInit(target, spec, emit) {
|
|
38536
38653
|
emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
|
|
38537
38654
|
const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
|
|
38538
38655
|
if (subagents.length > 0) {
|
|
38539
|
-
await
|
|
38656
|
+
await mkdir6(join19(target, ".claude", "agents"), { recursive: true });
|
|
38540
38657
|
for (const sa of subagents) {
|
|
38541
38658
|
const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
38542
38659
|
if (!name) continue;
|
|
@@ -38546,7 +38663,7 @@ name: ${name}
|
|
|
38546
38663
|
|
|
38547
38664
|
${(sa.description || "").trim()}
|
|
38548
38665
|
`;
|
|
38549
|
-
await
|
|
38666
|
+
await writeFile5(join19(target, ".claude", "agents", `${name}.md`), body, "utf8");
|
|
38550
38667
|
}
|
|
38551
38668
|
}
|
|
38552
38669
|
const specJson = JSON.stringify(spec);
|
|
@@ -38564,7 +38681,7 @@ ${specJson}`
|
|
|
38564
38681
|
async function generateFile(path, prompt) {
|
|
38565
38682
|
try {
|
|
38566
38683
|
const text = await aiGenerate(prompt);
|
|
38567
|
-
if (text.trim()) await
|
|
38684
|
+
if (text.trim()) await writeFile5(path, text.trim() + "\n", "utf8");
|
|
38568
38685
|
} catch {
|
|
38569
38686
|
}
|
|
38570
38687
|
}
|
|
@@ -38575,9 +38692,9 @@ async function addProject(payload, profileDir2, onProgress) {
|
|
|
38575
38692
|
onProgress?.({ projectId: payload.projectId, step, message });
|
|
38576
38693
|
};
|
|
38577
38694
|
try {
|
|
38578
|
-
const root = process.env.SCAFFOLD_ROOT ?
|
|
38695
|
+
const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
|
|
38579
38696
|
const target = join19(root, payload.projectName);
|
|
38580
|
-
await
|
|
38697
|
+
await mkdir6(target, { recursive: true });
|
|
38581
38698
|
const repos = payload.repos ?? [];
|
|
38582
38699
|
if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
|
|
38583
38700
|
onProgress?.({ projectId: payload.projectId, step: "done", message: "Project added.", done: true });
|
|
@@ -38672,7 +38789,7 @@ Extra focus from the author: ${req.prompt}` : "";
|
|
|
38672
38789
|
].join("\n");
|
|
38673
38790
|
}
|
|
38674
38791
|
function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
|
|
38675
|
-
return new Promise((
|
|
38792
|
+
return new Promise((resolve10, reject) => {
|
|
38676
38793
|
const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
|
|
38677
38794
|
const env3 = {
|
|
38678
38795
|
...process.env,
|
|
@@ -38695,7 +38812,7 @@ function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
|
|
|
38695
38812
|
});
|
|
38696
38813
|
child.on("close", (code) => {
|
|
38697
38814
|
clearTimeout(timer);
|
|
38698
|
-
|
|
38815
|
+
resolve10({ code: code ?? -1, out, err });
|
|
38699
38816
|
});
|
|
38700
38817
|
child.stdin.write(prompt);
|
|
38701
38818
|
child.stdin.end();
|
|
@@ -38874,7 +38991,7 @@ function handleToolsChannels(ctx, message, payload) {
|
|
|
38874
38991
|
}
|
|
38875
38992
|
|
|
38876
38993
|
// src/core/agents.ts
|
|
38877
|
-
import { readFile as
|
|
38994
|
+
import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir7, readdir as readdir4, rm as rm3 } from "fs/promises";
|
|
38878
38995
|
import { join as join21 } from "path";
|
|
38879
38996
|
var AGENTS_REL = ".claude/agents";
|
|
38880
38997
|
var SKILLS_REL = ".claude/skills";
|
|
@@ -38884,7 +39001,7 @@ function safeName(name) {
|
|
|
38884
39001
|
}
|
|
38885
39002
|
async function readText2(path, fallback = "") {
|
|
38886
39003
|
try {
|
|
38887
|
-
return await
|
|
39004
|
+
return await readFile7(path, "utf8");
|
|
38888
39005
|
} catch {
|
|
38889
39006
|
return fallback;
|
|
38890
39007
|
}
|
|
@@ -38943,8 +39060,8 @@ async function writeAgent(root, req) {
|
|
|
38943
39060
|
}
|
|
38944
39061
|
if (req.content === void 0) return { ok: false, error: "content is required" };
|
|
38945
39062
|
const path = itemPath(root, req.kind, n);
|
|
38946
|
-
await
|
|
38947
|
-
await
|
|
39063
|
+
await mkdir7(join21(path, ".."), { recursive: true });
|
|
39064
|
+
await writeFile6(path, req.content, "utf8");
|
|
38948
39065
|
return { ok: true };
|
|
38949
39066
|
} catch (err) {
|
|
38950
39067
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -38952,21 +39069,21 @@ async function writeAgent(root, req) {
|
|
|
38952
39069
|
}
|
|
38953
39070
|
|
|
38954
39071
|
// src/core/secrets.ts
|
|
38955
|
-
import { readFile as
|
|
39072
|
+
import { readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
|
|
38956
39073
|
import { join as join22 } from "path";
|
|
38957
39074
|
var SECURITY_REL = "AI_SECURITY.md";
|
|
38958
39075
|
var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
|
|
38959
39076
|
var SECRETS_REL = "project.secrets.json";
|
|
38960
39077
|
async function readText3(path, fallback = "") {
|
|
38961
39078
|
try {
|
|
38962
|
-
return await
|
|
39079
|
+
return await readFile8(path, "utf8");
|
|
38963
39080
|
} catch {
|
|
38964
39081
|
return fallback;
|
|
38965
39082
|
}
|
|
38966
39083
|
}
|
|
38967
39084
|
async function readSecretsObject(root) {
|
|
38968
39085
|
try {
|
|
38969
|
-
const v = JSON.parse(await
|
|
39086
|
+
const v = JSON.parse(await readFile8(join22(root, SECRETS_REL), "utf8"));
|
|
38970
39087
|
return v && typeof v === "object" ? v : {};
|
|
38971
39088
|
} catch {
|
|
38972
39089
|
return {};
|
|
@@ -38999,14 +39116,14 @@ async function readSecrets(root) {
|
|
|
38999
39116
|
async function writeSecrets(root, req) {
|
|
39000
39117
|
try {
|
|
39001
39118
|
if (req.kind === "security") {
|
|
39002
|
-
await
|
|
39119
|
+
await writeFile7(join22(root, SECURITY_REL), req.content, "utf8");
|
|
39003
39120
|
} else if (req.kind === "placeholder") {
|
|
39004
|
-
await
|
|
39121
|
+
await writeFile7(join22(root, PLACEHOLDER_REL), req.content, "utf8");
|
|
39005
39122
|
} else {
|
|
39006
39123
|
const secrets = await readSecretsObject(root);
|
|
39007
39124
|
if (req.kind === "secret") secrets[req.key] = req.value;
|
|
39008
39125
|
else delete secrets[req.key];
|
|
39009
|
-
await
|
|
39126
|
+
await writeFile7(join22(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
|
|
39010
39127
|
}
|
|
39011
39128
|
return { ok: true };
|
|
39012
39129
|
} catch (err) {
|
|
@@ -39015,8 +39132,8 @@ async function writeSecrets(root, req) {
|
|
|
39015
39132
|
}
|
|
39016
39133
|
|
|
39017
39134
|
// src/core/agent-tools.ts
|
|
39018
|
-
import { readFile as
|
|
39019
|
-
import { dirname as
|
|
39135
|
+
import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
39136
|
+
import { dirname as dirname8, join as join23 } from "path";
|
|
39020
39137
|
var SHARED_REL = ".claude/settings.json";
|
|
39021
39138
|
var LOCAL_REL = ".claude/settings.local.json";
|
|
39022
39139
|
var SECRETS_DENY = "Read(./project.secrets.json)";
|
|
@@ -39026,7 +39143,7 @@ function fileFor(root, scope) {
|
|
|
39026
39143
|
}
|
|
39027
39144
|
async function readSettingsObject(path) {
|
|
39028
39145
|
try {
|
|
39029
|
-
const v = JSON.parse(await
|
|
39146
|
+
const v = JSON.parse(await readFile9(path, "utf8"));
|
|
39030
39147
|
return v && typeof v === "object" ? v : {};
|
|
39031
39148
|
} catch {
|
|
39032
39149
|
return {};
|
|
@@ -39049,8 +39166,8 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
39049
39166
|
const next = normalizePermissions(permissions);
|
|
39050
39167
|
if (scope === "shared" && !next.deny.includes(SECRETS_DENY)) next.deny = [...next.deny, SECRETS_DENY];
|
|
39051
39168
|
obj.permissions = next;
|
|
39052
|
-
await
|
|
39053
|
-
await
|
|
39169
|
+
await mkdir8(dirname8(path), { recursive: true });
|
|
39170
|
+
await writeFile8(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
|
|
39054
39171
|
return { ok: true };
|
|
39055
39172
|
} catch (err) {
|
|
39056
39173
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -39059,8 +39176,8 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
39059
39176
|
|
|
39060
39177
|
// src/core/packages.ts
|
|
39061
39178
|
import { createHash as createHash4 } from "crypto";
|
|
39062
|
-
import { readFile as
|
|
39063
|
-
import { dirname as
|
|
39179
|
+
import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir9, readdir as readdir5, rm as rm4, stat as stat3 } from "fs/promises";
|
|
39180
|
+
import { dirname as dirname9, join as join24, relative } from "path";
|
|
39064
39181
|
var AGENTS_REL2 = ".claude/agents";
|
|
39065
39182
|
var SKILLS_REL2 = ".claude/skills";
|
|
39066
39183
|
var MANIFEST_REL = ".claude/.4pm-packages.json";
|
|
@@ -39069,7 +39186,7 @@ function safeName2(name) {
|
|
|
39069
39186
|
}
|
|
39070
39187
|
async function readMaybe(path) {
|
|
39071
39188
|
try {
|
|
39072
|
-
return await
|
|
39189
|
+
return await readFile10(path);
|
|
39073
39190
|
} catch {
|
|
39074
39191
|
return null;
|
|
39075
39192
|
}
|
|
@@ -39124,7 +39241,7 @@ async function artifactSha256(root, kind, slug) {
|
|
|
39124
39241
|
async function artifactExists(root, kind, slug) {
|
|
39125
39242
|
const target = kind === "subagent" ? join24(root, AGENTS_REL2, `${slug}.md`) : join24(root, SKILLS_REL2, slug);
|
|
39126
39243
|
try {
|
|
39127
|
-
await
|
|
39244
|
+
await stat3(target);
|
|
39128
39245
|
return true;
|
|
39129
39246
|
} catch {
|
|
39130
39247
|
return false;
|
|
@@ -39141,34 +39258,34 @@ async function readManifest(root) {
|
|
|
39141
39258
|
}
|
|
39142
39259
|
async function writeManifest(root, manifest) {
|
|
39143
39260
|
const path = join24(root, MANIFEST_REL);
|
|
39144
|
-
await
|
|
39145
|
-
await
|
|
39261
|
+
await mkdir9(dirname9(path), { recursive: true });
|
|
39262
|
+
await writeFile9(path, JSON.stringify(manifest, null, 2), "utf8");
|
|
39146
39263
|
}
|
|
39147
39264
|
async function writeArtifactFiles(root, kind, slug, files) {
|
|
39148
39265
|
const byPath = new Map(files.map((f) => [f.path, Buffer.from(f.contentBase64, "base64")]));
|
|
39149
39266
|
if (kind === "subagent") {
|
|
39150
39267
|
const agent = byPath.get("agent.md");
|
|
39151
39268
|
if (agent) {
|
|
39152
|
-
await
|
|
39153
|
-
await
|
|
39269
|
+
await mkdir9(join24(root, AGENTS_REL2), { recursive: true });
|
|
39270
|
+
await writeFile9(join24(root, AGENTS_REL2, `${slug}.md`), agent);
|
|
39154
39271
|
}
|
|
39155
39272
|
const short = byPath.get("short-memory.md");
|
|
39156
39273
|
if (short) {
|
|
39157
|
-
await
|
|
39158
|
-
await
|
|
39274
|
+
await mkdir9(join24(root, AGENTS_REL2, "short-memory"), { recursive: true });
|
|
39275
|
+
await writeFile9(join24(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
|
|
39159
39276
|
}
|
|
39160
39277
|
const long = byPath.get("long-memory.md");
|
|
39161
39278
|
if (long) {
|
|
39162
|
-
await
|
|
39163
|
-
await
|
|
39279
|
+
await mkdir9(join24(root, AGENTS_REL2, "long-memory"), { recursive: true });
|
|
39280
|
+
await writeFile9(join24(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
|
|
39164
39281
|
}
|
|
39165
39282
|
} else {
|
|
39166
39283
|
const base = join24(root, SKILLS_REL2, slug);
|
|
39167
39284
|
for (const [rel, buf] of byPath) {
|
|
39168
39285
|
if (rel.includes("..") || rel.startsWith("/")) continue;
|
|
39169
39286
|
const dest = join24(base, rel);
|
|
39170
|
-
await
|
|
39171
|
-
await
|
|
39287
|
+
await mkdir9(dirname9(dest), { recursive: true });
|
|
39288
|
+
await writeFile9(dest, buf);
|
|
39172
39289
|
}
|
|
39173
39290
|
}
|
|
39174
39291
|
}
|
|
@@ -39247,8 +39364,8 @@ async function removePackage(root, slug) {
|
|
|
39247
39364
|
}
|
|
39248
39365
|
|
|
39249
39366
|
// src/core/graph.ts
|
|
39250
|
-
import { readFile as
|
|
39251
|
-
import { join as join25, relative as relative2, dirname as
|
|
39367
|
+
import { readFile as readFile11, readdir as readdir6 } from "fs/promises";
|
|
39368
|
+
import { join as join25, relative as relative2, dirname as dirname10, resolve as resolve9, extname as extname2, basename as basename6 } from "path";
|
|
39252
39369
|
var MAX_FILES = 2e3;
|
|
39253
39370
|
var MAX_NODES = 3e3;
|
|
39254
39371
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
|
|
@@ -39284,11 +39401,11 @@ function orphansOf(nodes, edges) {
|
|
|
39284
39401
|
return nodes.filter((n) => !hasInbound.has(n.id)).map((n) => n.id);
|
|
39285
39402
|
}
|
|
39286
39403
|
async function buildDocs(root) {
|
|
39287
|
-
const files = await walk(root, (p) =>
|
|
39404
|
+
const files = await walk(root, (p) => extname2(p) === ".md");
|
|
39288
39405
|
const ids = new Set(files.map((f) => relative2(root, f).split("\\").join("/")));
|
|
39289
39406
|
const nodes = files.map((f) => {
|
|
39290
39407
|
const rel = relative2(root, f).split("\\").join("/");
|
|
39291
|
-
return { id: rel, label:
|
|
39408
|
+
return { id: rel, label: basename6(rel), kind: "doc", file: rel };
|
|
39292
39409
|
});
|
|
39293
39410
|
const edges = [];
|
|
39294
39411
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -39296,14 +39413,14 @@ async function buildDocs(root) {
|
|
|
39296
39413
|
const rel = relative2(root, f).split("\\").join("/");
|
|
39297
39414
|
let text = "";
|
|
39298
39415
|
try {
|
|
39299
|
-
text = await
|
|
39416
|
+
text = await readFile11(f, "utf8");
|
|
39300
39417
|
} catch {
|
|
39301
39418
|
continue;
|
|
39302
39419
|
}
|
|
39303
39420
|
for (const m of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
|
|
39304
39421
|
const href = (m[1] ?? "").split("#")[0].trim();
|
|
39305
39422
|
if (!href || !href.endsWith(".md") || href.startsWith("http")) continue;
|
|
39306
|
-
const target = relative2(root,
|
|
39423
|
+
const target = relative2(root, resolve9(dirname10(f), href)).split("\\").join("/");
|
|
39307
39424
|
if (ids.has(target) && target !== rel) {
|
|
39308
39425
|
const key = `${rel}->${target}`;
|
|
39309
39426
|
if (!seen.has(key)) {
|
|
@@ -39326,7 +39443,7 @@ var DEF_PATTERNS = [
|
|
|
39326
39443
|
// Go
|
|
39327
39444
|
];
|
|
39328
39445
|
async function buildCode(root) {
|
|
39329
|
-
const files = await walk(root, (p) => CODE_EXT.has(
|
|
39446
|
+
const files = await walk(root, (p) => CODE_EXT.has(extname2(p)));
|
|
39330
39447
|
const nodes = [];
|
|
39331
39448
|
const nameToIds = /* @__PURE__ */ new Map();
|
|
39332
39449
|
const fileDefs = /* @__PURE__ */ new Map();
|
|
@@ -39335,7 +39452,7 @@ async function buildCode(root) {
|
|
|
39335
39452
|
const rel = relative2(root, f).split("\\").join("/");
|
|
39336
39453
|
let text = "";
|
|
39337
39454
|
try {
|
|
39338
|
-
text = await
|
|
39455
|
+
text = await readFile11(f, "utf8");
|
|
39339
39456
|
} catch {
|
|
39340
39457
|
continue;
|
|
39341
39458
|
}
|
|
@@ -39387,7 +39504,7 @@ async function buildGraph(root, mode) {
|
|
|
39387
39504
|
}
|
|
39388
39505
|
|
|
39389
39506
|
// src/core/rag.ts
|
|
39390
|
-
import { readFile as
|
|
39507
|
+
import { readFile as readFile12, writeFile as writeFile10, statfs as statfs2, mkdir as mkdir10 } from "fs/promises";
|
|
39391
39508
|
import { existsSync as existsSync13 } from "fs";
|
|
39392
39509
|
import { execFile as execFile10, spawn as spawn9 } from "child_process";
|
|
39393
39510
|
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
@@ -39412,7 +39529,7 @@ async function detectPython() {
|
|
|
39412
39529
|
}
|
|
39413
39530
|
async function installLog(root) {
|
|
39414
39531
|
try {
|
|
39415
|
-
const text = await
|
|
39532
|
+
const text = await readFile12(join26(root, RAG_REL, "install.log"), "utf8");
|
|
39416
39533
|
return text.split("\n").filter((l) => l.length > 0).slice(-200);
|
|
39417
39534
|
} catch {
|
|
39418
39535
|
return [];
|
|
@@ -39474,7 +39591,7 @@ async function ragStatus(root) {
|
|
|
39474
39591
|
};
|
|
39475
39592
|
let modelName = "";
|
|
39476
39593
|
try {
|
|
39477
|
-
modelName = (await
|
|
39594
|
+
modelName = (await readFile12(join26(root, RAG_REL, ".installed"), "utf8")).trim();
|
|
39478
39595
|
} catch {
|
|
39479
39596
|
modelName = "";
|
|
39480
39597
|
}
|
|
@@ -39494,7 +39611,7 @@ async function ragStatus(root) {
|
|
|
39494
39611
|
async function readIndexMeta(root) {
|
|
39495
39612
|
const indexing = existsSync13(join26(root, RAG_REL, ".indexing"));
|
|
39496
39613
|
try {
|
|
39497
|
-
const m = JSON.parse(await
|
|
39614
|
+
const m = JSON.parse(await readFile12(join26(root, RAG_REL, ".index.json"), "utf8"));
|
|
39498
39615
|
return {
|
|
39499
39616
|
present: true,
|
|
39500
39617
|
indexing,
|
|
@@ -39561,8 +39678,8 @@ if __name__ == "__main__":
|
|
|
39561
39678
|
elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
|
|
39562
39679
|
`;
|
|
39563
39680
|
async function ensureEngine(root) {
|
|
39564
|
-
await
|
|
39565
|
-
await
|
|
39681
|
+
await mkdir10(join26(root, RAG_REL), { recursive: true }).catch(() => void 0);
|
|
39682
|
+
await writeFile10(join26(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
|
|
39566
39683
|
}
|
|
39567
39684
|
async function ragReindex(root) {
|
|
39568
39685
|
const py = await detectPython();
|
|
@@ -39610,7 +39727,7 @@ async function ragInstall(root, model) {
|
|
|
39610
39727
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
39611
39728
|
if (existsSync13(join26(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
39612
39729
|
try {
|
|
39613
|
-
await
|
|
39730
|
+
await mkdir10(join26(root, RAG_REL), { recursive: true });
|
|
39614
39731
|
} catch {
|
|
39615
39732
|
}
|
|
39616
39733
|
const script = `
|
|
@@ -40118,14 +40235,14 @@ var WsClient = class {
|
|
|
40118
40235
|
*/
|
|
40119
40236
|
awaitConnected(timeoutMs) {
|
|
40120
40237
|
if (this.sessionKey && this.bus.status === "connected") return Promise.resolve(true);
|
|
40121
|
-
return new Promise((
|
|
40238
|
+
return new Promise((resolve10) => {
|
|
40122
40239
|
const waiter = () => {
|
|
40123
40240
|
clearTimeout(timer);
|
|
40124
|
-
|
|
40241
|
+
resolve10(true);
|
|
40125
40242
|
};
|
|
40126
40243
|
const timer = setTimeout(() => {
|
|
40127
40244
|
this.connectWaiters = this.connectWaiters.filter((w) => w !== waiter);
|
|
40128
|
-
|
|
40245
|
+
resolve10(false);
|
|
40129
40246
|
}, timeoutMs);
|
|
40130
40247
|
this.connectWaiters.push(waiter);
|
|
40131
40248
|
});
|
|
@@ -40152,16 +40269,16 @@ var WsClient = class {
|
|
|
40152
40269
|
this.forceReconnect = false;
|
|
40153
40270
|
return Promise.resolve();
|
|
40154
40271
|
}
|
|
40155
|
-
return new Promise((
|
|
40272
|
+
return new Promise((resolve10) => {
|
|
40156
40273
|
const timer = setTimeout(() => {
|
|
40157
40274
|
this.wakeReconnect = null;
|
|
40158
|
-
|
|
40275
|
+
resolve10();
|
|
40159
40276
|
}, ms);
|
|
40160
40277
|
this.wakeReconnect = () => {
|
|
40161
40278
|
clearTimeout(timer);
|
|
40162
40279
|
this.wakeReconnect = null;
|
|
40163
40280
|
this.forceReconnect = false;
|
|
40164
|
-
|
|
40281
|
+
resolve10();
|
|
40165
40282
|
};
|
|
40166
40283
|
});
|
|
40167
40284
|
}
|
|
@@ -40215,7 +40332,7 @@ var WsClient = class {
|
|
|
40215
40332
|
* One WS session: token → connect → handshake → handle messages until close.
|
|
40216
40333
|
*/
|
|
40217
40334
|
connectOnce() {
|
|
40218
|
-
return new Promise((
|
|
40335
|
+
return new Promise((resolve10, reject) => {
|
|
40219
40336
|
void (async () => {
|
|
40220
40337
|
this.sessionEstablished = false;
|
|
40221
40338
|
this.bus.setStatus("connecting");
|
|
@@ -40309,7 +40426,7 @@ var WsClient = class {
|
|
|
40309
40426
|
if (code === CLOSE_DRAINING) {
|
|
40310
40427
|
this.bus.log(t("error.serverDraining"));
|
|
40311
40428
|
}
|
|
40312
|
-
|
|
40429
|
+
resolve10();
|
|
40313
40430
|
});
|
|
40314
40431
|
socket.on("error", (err) => {
|
|
40315
40432
|
this.clearHeartbeat();
|
|
@@ -40435,7 +40552,7 @@ var WsClient = class {
|
|
|
40435
40552
|
* Used for quota.check before spawning an AI cli (ADR-0020).
|
|
40436
40553
|
*/
|
|
40437
40554
|
request(channel, data) {
|
|
40438
|
-
return new Promise((
|
|
40555
|
+
return new Promise((resolve10, reject) => {
|
|
40439
40556
|
if (!this.socket || !this.sessionKey) {
|
|
40440
40557
|
reject(new Error("Not connected to the server."));
|
|
40441
40558
|
return;
|
|
@@ -40455,7 +40572,7 @@ var WsClient = class {
|
|
|
40455
40572
|
}, 15e3);
|
|
40456
40573
|
timer.unref?.();
|
|
40457
40574
|
this.pending.set(envelope.id, {
|
|
40458
|
-
resolve: (value) =>
|
|
40575
|
+
resolve: (value) => resolve10(value),
|
|
40459
40576
|
timer
|
|
40460
40577
|
});
|
|
40461
40578
|
this.socket.send(JSON.stringify(envelope));
|
|
@@ -40581,7 +40698,7 @@ var WsClient = class {
|
|
|
40581
40698
|
const working = getWorkingProfile(this.context.profileDir, aiCli2);
|
|
40582
40699
|
const configured = claudeHomeDirs(config);
|
|
40583
40700
|
const dirs = working ? [working, ...configured.filter((d) => d !== working)] : configured;
|
|
40584
|
-
const profile = working ?
|
|
40701
|
+
const profile = working ? basename7(working) : dirs[0] ? basename7(dirs[0]) : "default";
|
|
40585
40702
|
const api = await checkClaudeUsage(dirs, aiCli2);
|
|
40586
40703
|
const snapshot = api ?? {
|
|
40587
40704
|
plan: "?",
|
|
@@ -46490,8 +46607,8 @@ var Ink = class {
|
|
|
46490
46607
|
}
|
|
46491
46608
|
}
|
|
46492
46609
|
async waitUntilExit() {
|
|
46493
|
-
this.exitPromise ||= new Promise((
|
|
46494
|
-
this.resolveExitPromise =
|
|
46610
|
+
this.exitPromise ||= new Promise((resolve10, reject) => {
|
|
46611
|
+
this.resolveExitPromise = resolve10;
|
|
46495
46612
|
this.rejectExitPromise = reject;
|
|
46496
46613
|
});
|
|
46497
46614
|
return this.exitPromise;
|
|
@@ -47544,7 +47661,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
47544
47661
|
logger.error("ws.run.crash", { message: e.message, stack: e.stack });
|
|
47545
47662
|
if (client.isStopped) return;
|
|
47546
47663
|
bus.log(t("start.recovered", { message: e.message }), "error");
|
|
47547
|
-
await new Promise((
|
|
47664
|
+
await new Promise((resolve10) => setTimeout(resolve10, 1e3));
|
|
47548
47665
|
}
|
|
47549
47666
|
}
|
|
47550
47667
|
};
|
|
@@ -47590,7 +47707,7 @@ import { join as join33 } from "path";
|
|
|
47590
47707
|
// src/core/control-client.ts
|
|
47591
47708
|
import { connect as connect2 } from "net";
|
|
47592
47709
|
function connectControl(socketPath, bus) {
|
|
47593
|
-
return new Promise((
|
|
47710
|
+
return new Promise((resolve10, reject) => {
|
|
47594
47711
|
const socket = connect2(socketPath);
|
|
47595
47712
|
socket.setEncoding("utf8");
|
|
47596
47713
|
let ready = false;
|
|
@@ -47637,7 +47754,7 @@ function connectControl(socketPath, bus) {
|
|
|
47637
47754
|
bus.setTokens(frame.tokens);
|
|
47638
47755
|
for (const entry of frame.transcript) bus.pushEntry(entry);
|
|
47639
47756
|
ready = true;
|
|
47640
|
-
|
|
47757
|
+
resolve10({ info: frame.info, close });
|
|
47641
47758
|
break;
|
|
47642
47759
|
case "transcript":
|
|
47643
47760
|
bus.pushEntry(frame.entry);
|
|
@@ -47717,18 +47834,18 @@ async function runAttach(profileDir2, profileName) {
|
|
|
47717
47834
|
// src/commands/ai-login.ts
|
|
47718
47835
|
import { spawn as spawn11 } from "child_process";
|
|
47719
47836
|
import { mkdirSync as mkdirSync8 } from "fs";
|
|
47720
|
-
import { basename as
|
|
47837
|
+
import { basename as basename8 } from "path";
|
|
47721
47838
|
function runProviderLogin(cmd, envVar, dir2) {
|
|
47722
|
-
return new Promise((
|
|
47839
|
+
return new Promise((resolve10) => {
|
|
47723
47840
|
const child = spawn11(cmd, [], {
|
|
47724
47841
|
stdio: "inherit",
|
|
47725
47842
|
env: { ...process.env, [envVar]: dir2 }
|
|
47726
47843
|
});
|
|
47727
47844
|
child.on("error", (err) => {
|
|
47728
47845
|
console.error(t("aiLogin.launchFailed", { cmd, message: err.message }));
|
|
47729
|
-
|
|
47846
|
+
resolve10(1);
|
|
47730
47847
|
});
|
|
47731
|
-
child.on("exit", (code) =>
|
|
47848
|
+
child.on("exit", (code) => resolve10(code ?? 0));
|
|
47732
47849
|
});
|
|
47733
47850
|
}
|
|
47734
47851
|
async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
@@ -47740,7 +47857,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
|
47740
47857
|
return;
|
|
47741
47858
|
}
|
|
47742
47859
|
const selected = aiFilter ? credentials.filter(
|
|
47743
|
-
(c, i) => c.profile === aiFilter ||
|
|
47860
|
+
(c, i) => c.profile === aiFilter || basename8(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
|
|
47744
47861
|
) : credentials;
|
|
47745
47862
|
if (selected.length === 0) {
|
|
47746
47863
|
console.log(t("aiLogin.noMatch", { filter: aiFilter ?? "", list: credentials.map((c) => c.profile).join(", ") }));
|
|
@@ -47868,10 +47985,10 @@ function Picker({
|
|
|
47868
47985
|
] });
|
|
47869
47986
|
}
|
|
47870
47987
|
function selectFromList(items, title) {
|
|
47871
|
-
return new Promise((
|
|
47988
|
+
return new Promise((resolve10) => {
|
|
47872
47989
|
let chosen = null;
|
|
47873
47990
|
const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Picker, { items, title, onDone: (v) => chosen = v }));
|
|
47874
|
-
void app.waitUntilExit().then(() =>
|
|
47991
|
+
void app.waitUntilExit().then(() => resolve10(chosen));
|
|
47875
47992
|
});
|
|
47876
47993
|
}
|
|
47877
47994
|
|