@4pm/cli 1.4.2 → 1.4.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 +216 -103
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28550,7 +28550,7 @@ ${INSECURE_URL_WARNING}
|
|
|
28550
28550
|
|
|
28551
28551
|
// src/commands/start.ts
|
|
28552
28552
|
import { spawn as spawn9 } from "child_process";
|
|
28553
|
-
import { join as
|
|
28553
|
+
import { join as join29 } from "path";
|
|
28554
28554
|
|
|
28555
28555
|
// src/core/update.ts
|
|
28556
28556
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -28723,7 +28723,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
|
|
|
28723
28723
|
// src/core/ws-client.ts
|
|
28724
28724
|
init_wrapper();
|
|
28725
28725
|
import { randomUUID } from "crypto";
|
|
28726
|
-
import { basename as basename4, join as
|
|
28726
|
+
import { basename as basename4, join as join24 } from "path";
|
|
28727
28727
|
|
|
28728
28728
|
// vendor/@4pm/utils/helpers.ts
|
|
28729
28729
|
function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
|
|
@@ -33087,6 +33087,19 @@ var createProjectRequestSchema = external_exports.object({
|
|
|
33087
33087
|
var copyProjectRequestSchema = external_exports.object({
|
|
33088
33088
|
name: external_exports.string().min(1).max(100)
|
|
33089
33089
|
});
|
|
33090
|
+
var PROJECT_ALERT_KINDS = ["budgetPercent", "absolute"];
|
|
33091
|
+
var projectAlertRuleSchema = external_exports.object({
|
|
33092
|
+
id: external_exports.string().min(1).max(64),
|
|
33093
|
+
kind: external_exports.enum(PROJECT_ALERT_KINDS),
|
|
33094
|
+
metric: external_exports.enum([UsageMetric.AI_TOKENS, UsageMetric.COMMANDS]),
|
|
33095
|
+
threshold: external_exports.number().int().min(1),
|
|
33096
|
+
email: external_exports.union([external_exports.string().email(), external_exports.literal("")]).optional(),
|
|
33097
|
+
notifyUserId: external_exports.union([external_exports.string().uuid(), external_exports.literal("")]).optional(),
|
|
33098
|
+
enabled: external_exports.boolean().default(true)
|
|
33099
|
+
});
|
|
33100
|
+
var projectAlertsSchema = external_exports.object({
|
|
33101
|
+
rules: external_exports.array(projectAlertRuleSchema).max(20).default([])
|
|
33102
|
+
});
|
|
33090
33103
|
var DEFAULT_OUTBOUND_RULES = {
|
|
33091
33104
|
secret: [
|
|
33092
33105
|
String.raw`/\b(api[_-]?key|secret|password|passwd|access[_-]?token|bearer)\b\s*[:=]\s*\S+/i`,
|
|
@@ -33650,6 +33663,10 @@ var WsChannels = {
|
|
|
33650
33663
|
USAGE_REPORT: "usage.report",
|
|
33651
33664
|
// cli → server: Claude subscription usage snapshot (5h / weekly — ADR-0072)
|
|
33652
33665
|
MACHINE_USAGE: "machine.usage",
|
|
33666
|
+
// cli → server: last-run result of an external tool (claude/codex/gh/glab/git — ADR-0223).
|
|
33667
|
+
// One-way, sent immediately after each direct tool invocation (last-wins per tool); the
|
|
33668
|
+
// server merges it into `MachineLink.usageSnapshot.toolHealth` for the admin pool lists.
|
|
33669
|
+
TOOL_HEALTH: "tool.health",
|
|
33653
33670
|
// cli → server: durable per-command history record on finish (ADR-0072)
|
|
33654
33671
|
COMMAND_HISTORY: "command.history",
|
|
33655
33672
|
// cli → server: periodic upload of the cli's own JSONL log file (ADR-0122) — stored
|
|
@@ -33729,7 +33746,7 @@ function decryptPayload(key, payloadBase64, nonceBase64) {
|
|
|
33729
33746
|
}
|
|
33730
33747
|
|
|
33731
33748
|
// src/core/ws-client.ts
|
|
33732
|
-
import { existsSync as
|
|
33749
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, rmSync as rmSync4 } from "fs";
|
|
33733
33750
|
import { randomUUID as randomCommandId } from "crypto";
|
|
33734
33751
|
|
|
33735
33752
|
// src/core/update-scheduler.ts
|
|
@@ -33998,6 +34015,24 @@ async function runCommand(dispatch, emit) {
|
|
|
33998
34015
|
});
|
|
33999
34016
|
}
|
|
34000
34017
|
|
|
34018
|
+
// src/core/tool-health.ts
|
|
34019
|
+
var sink = null;
|
|
34020
|
+
function setToolHealthSink(fn) {
|
|
34021
|
+
sink = fn;
|
|
34022
|
+
}
|
|
34023
|
+
function reportToolResult(tool, ok, message) {
|
|
34024
|
+
try {
|
|
34025
|
+
const reason = (message ?? "").trim().slice(0, 200);
|
|
34026
|
+
sink?.({
|
|
34027
|
+
tool,
|
|
34028
|
+
ok,
|
|
34029
|
+
message: ok ? null : reason || "failed",
|
|
34030
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
34031
|
+
});
|
|
34032
|
+
} catch {
|
|
34033
|
+
}
|
|
34034
|
+
}
|
|
34035
|
+
|
|
34001
34036
|
// src/core/ai-stream.ts
|
|
34002
34037
|
function assistantText(ev) {
|
|
34003
34038
|
const parts = ev.message?.content ?? [];
|
|
@@ -34104,8 +34139,11 @@ function runAttempt(commandId, cmd, args, cwd2, env3, onChunk) {
|
|
|
34104
34139
|
async function runAiFailover(plan, commandId, cwd2, handlers) {
|
|
34105
34140
|
const total = plan.attempts.length;
|
|
34106
34141
|
let finalExit = -1;
|
|
34142
|
+
let lastCmd = plan.attempts[0]?.cmd ?? "claude";
|
|
34143
|
+
let lastCaptured = "";
|
|
34107
34144
|
for (let i = 0; i < total; i++) {
|
|
34108
34145
|
const attempt = plan.attempts[i];
|
|
34146
|
+
lastCmd = attempt.cmd;
|
|
34109
34147
|
if (total > 1) handlers.onAttemptStart(attempt.label, i, total, attempt.cmd);
|
|
34110
34148
|
const parser = createAiStreamParser(attempt.cmd);
|
|
34111
34149
|
let captured = "";
|
|
@@ -34122,17 +34160,26 @@ async function runAiFailover(plan, commandId, cwd2, handlers) {
|
|
|
34122
34160
|
captured += tail;
|
|
34123
34161
|
handlers.onChunk(tail);
|
|
34124
34162
|
}
|
|
34163
|
+
lastCaptured = captured;
|
|
34125
34164
|
if (finalExit === 0) {
|
|
34126
34165
|
const usage = parser.usage();
|
|
34127
34166
|
if (usage.tokens === 0) usage.tokens = estimateTokens(captured);
|
|
34167
|
+
reportToolResult(attempt.cmd, true);
|
|
34128
34168
|
return { exitCode: 0, workedDir: attempt.dir, workedKey: attempt.key, workedCmd: attempt.cmd, usage };
|
|
34129
34169
|
}
|
|
34130
34170
|
const reason = isAuthFailure(captured) ? "auth" : isSessionLimit(captured) ? "limit" : null;
|
|
34131
34171
|
if (!reason || i === total - 1) break;
|
|
34132
34172
|
handlers.onAttemptFail(attempt.label, reason);
|
|
34133
34173
|
}
|
|
34174
|
+
reportToolResult(lastCmd, false, summarizeAiFailure(lastCaptured, finalExit));
|
|
34134
34175
|
return { exitCode: finalExit, workedDir: null, workedKey: null, workedCmd: null, usage: { tokens: 0, input: 0, output: 0, cacheRead: 0, cacheCreation: 0 } };
|
|
34135
34176
|
}
|
|
34177
|
+
function summarizeAiFailure(captured, exitCode) {
|
|
34178
|
+
if (isAuthFailure(captured)) return "Not logged in";
|
|
34179
|
+
if (isSessionLimit(captured)) return "Usage limit reached";
|
|
34180
|
+
const firstLine = captured.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
34181
|
+
return firstLine || `exited ${exitCode}`;
|
|
34182
|
+
}
|
|
34136
34183
|
|
|
34137
34184
|
// src/core/ai-profile-state.ts
|
|
34138
34185
|
import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
@@ -35055,7 +35102,10 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
|
|
|
35055
35102
|
for (let i = 0; i < attempts.length; i++) {
|
|
35056
35103
|
try {
|
|
35057
35104
|
const { code, out, err } = await runOnce(ai.cmd, attempts[i], prompt, physicRoot, ai.env);
|
|
35058
|
-
if (code === 0 && out.trim())
|
|
35105
|
+
if (code === 0 && out.trim()) {
|
|
35106
|
+
reportToolResult(ai.cmd, true);
|
|
35107
|
+
return { bodyMarkdown: out.trim() };
|
|
35108
|
+
}
|
|
35059
35109
|
const combined = err || out;
|
|
35060
35110
|
lastReason = `exited ${code}: ${combined.slice(0, 500)}`;
|
|
35061
35111
|
if (!isAuthFailure(combined) && !isSessionLimit(combined) || i === attempts.length - 1) break;
|
|
@@ -35064,6 +35114,7 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
|
|
|
35064
35114
|
break;
|
|
35065
35115
|
}
|
|
35066
35116
|
}
|
|
35117
|
+
reportToolResult(ai.cmd, false, lastReason);
|
|
35067
35118
|
return { bodyMarkdown: "", error: lastReason };
|
|
35068
35119
|
}
|
|
35069
35120
|
|
|
@@ -35492,28 +35543,87 @@ async function removePackage(root, slug) {
|
|
|
35492
35543
|
}
|
|
35493
35544
|
}
|
|
35494
35545
|
|
|
35495
|
-
// src/core/
|
|
35496
|
-
import {
|
|
35497
|
-
import {
|
|
35498
|
-
var
|
|
35499
|
-
|
|
35500
|
-
|
|
35546
|
+
// src/core/network-probe.ts
|
|
35547
|
+
import { existsSync as existsSync9, readFileSync as readFileSync14 } from "fs";
|
|
35548
|
+
import { connect } from "net";
|
|
35549
|
+
var CANARY_TARGETS = [
|
|
35550
|
+
{ host: "1.1.1.1", port: 443 },
|
|
35551
|
+
{ host: "8.8.8.8", port: 443 }
|
|
35552
|
+
];
|
|
35553
|
+
var PROBE_TIMEOUT_MS = 2500;
|
|
35554
|
+
function detectContainerized() {
|
|
35501
35555
|
try {
|
|
35502
|
-
if (
|
|
35503
|
-
|
|
35504
|
-
|
|
35505
|
-
|
|
35506
|
-
|
|
35507
|
-
|
|
35556
|
+
if (existsSync9("/.dockerenv")) return true;
|
|
35557
|
+
const cgroup = readFileSync14("/proc/1/cgroup", "utf8");
|
|
35558
|
+
return /docker|containerd|kubepods|libpod/.test(cgroup);
|
|
35559
|
+
} catch {
|
|
35560
|
+
return false;
|
|
35561
|
+
}
|
|
35562
|
+
}
|
|
35563
|
+
function canReach(host, port) {
|
|
35564
|
+
return new Promise((resolve8) => {
|
|
35565
|
+
const socket = connect({ host, port });
|
|
35566
|
+
let done = false;
|
|
35567
|
+
const finish = (ok) => {
|
|
35568
|
+
if (done) return;
|
|
35569
|
+
done = true;
|
|
35570
|
+
socket.destroy();
|
|
35571
|
+
resolve8(ok);
|
|
35572
|
+
};
|
|
35573
|
+
socket.setTimeout(PROBE_TIMEOUT_MS);
|
|
35574
|
+
socket.once("connect", () => finish(true));
|
|
35575
|
+
socket.once("timeout", () => finish(false));
|
|
35576
|
+
socket.once("error", () => finish(false));
|
|
35577
|
+
});
|
|
35578
|
+
}
|
|
35579
|
+
async function probeOutbound() {
|
|
35580
|
+
try {
|
|
35581
|
+
const results = await Promise.all(CANARY_TARGETS.map((t) => canReach(t.host, t.port)));
|
|
35582
|
+
return results.some(Boolean) ? "open" : "restricted";
|
|
35583
|
+
} catch {
|
|
35584
|
+
return "restricted";
|
|
35585
|
+
}
|
|
35586
|
+
}
|
|
35587
|
+
function probeInbound() {
|
|
35588
|
+
const isExposed = (path, loopbackHexPrefixes) => {
|
|
35589
|
+
let body;
|
|
35590
|
+
try {
|
|
35591
|
+
body = readFileSync14(path, "utf8");
|
|
35592
|
+
} catch {
|
|
35593
|
+
return false;
|
|
35594
|
+
}
|
|
35595
|
+
for (const line of body.split("\n").slice(1)) {
|
|
35596
|
+
const cols = line.trim().split(/\s+/);
|
|
35597
|
+
const local = cols[1];
|
|
35598
|
+
const st = cols[3];
|
|
35599
|
+
if (!local || st !== "0A") continue;
|
|
35600
|
+
const addrHex = local.split(":")[0]?.toUpperCase() ?? "";
|
|
35601
|
+
if (loopbackHexPrefixes.some((p) => addrHex === p)) continue;
|
|
35602
|
+
return true;
|
|
35508
35603
|
}
|
|
35604
|
+
return false;
|
|
35605
|
+
};
|
|
35606
|
+
try {
|
|
35607
|
+
const v4 = isExposed("/proc/net/tcp", ["0100007F"]);
|
|
35608
|
+
const v6 = isExposed("/proc/net/tcp6", ["00000000000000000000000001000000"]);
|
|
35609
|
+
return v4 || v6 ? "exposed" : "isolated";
|
|
35509
35610
|
} catch {
|
|
35611
|
+
return "isolated";
|
|
35510
35612
|
}
|
|
35511
35613
|
}
|
|
35614
|
+
async function probeNetwork() {
|
|
35615
|
+
return {
|
|
35616
|
+
outbound: await probeOutbound(),
|
|
35617
|
+
inbound: probeInbound(),
|
|
35618
|
+
containerized: detectContainerized(),
|
|
35619
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
35620
|
+
};
|
|
35621
|
+
}
|
|
35512
35622
|
|
|
35513
35623
|
// src/core/git-auth.ts
|
|
35514
|
-
import { writeFileSync as
|
|
35624
|
+
import { writeFileSync as writeFileSync6 } from "fs";
|
|
35515
35625
|
import { homedir as homedir4 } from "os";
|
|
35516
|
-
import { join as
|
|
35626
|
+
import { join as join16 } from "path";
|
|
35517
35627
|
function tokenTarget(method) {
|
|
35518
35628
|
if (method === "gitlab-group-token") {
|
|
35519
35629
|
return { host: process.env.FOURPM_GIT_HOST || "gitlab.com", user: "oauth2" };
|
|
@@ -35531,7 +35641,7 @@ function applyGitAuth(method) {
|
|
|
35531
35641
|
try {
|
|
35532
35642
|
const line = `https://${target.user}:${token}@${target.host}
|
|
35533
35643
|
`;
|
|
35534
|
-
|
|
35644
|
+
writeFileSync6(join16(homedir4(), ".git-credentials"), line, { encoding: "utf8", mode: 384 });
|
|
35535
35645
|
return true;
|
|
35536
35646
|
} catch {
|
|
35537
35647
|
return false;
|
|
@@ -35540,7 +35650,7 @@ function applyGitAuth(method) {
|
|
|
35540
35650
|
|
|
35541
35651
|
// src/core/secrets.ts
|
|
35542
35652
|
import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
35543
|
-
import { join as
|
|
35653
|
+
import { join as join17 } from "path";
|
|
35544
35654
|
var SECURITY_REL = "AI_SECURITY.md";
|
|
35545
35655
|
var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
|
|
35546
35656
|
var SECRETS_REL = "project.secrets.json";
|
|
@@ -35553,7 +35663,7 @@ async function readText3(path, fallback = "") {
|
|
|
35553
35663
|
}
|
|
35554
35664
|
async function readSecretsObject(root) {
|
|
35555
35665
|
try {
|
|
35556
|
-
const v = JSON.parse(await readFile6(
|
|
35666
|
+
const v = JSON.parse(await readFile6(join17(root, SECRETS_REL), "utf8"));
|
|
35557
35667
|
return v && typeof v === "object" ? v : {};
|
|
35558
35668
|
} catch {
|
|
35559
35669
|
return {};
|
|
@@ -35572,8 +35682,8 @@ function placeholderKeys(text) {
|
|
|
35572
35682
|
}
|
|
35573
35683
|
async function readSecrets(root) {
|
|
35574
35684
|
const [security, placeholder, secrets] = await Promise.all([
|
|
35575
|
-
readText3(
|
|
35576
|
-
readText3(
|
|
35685
|
+
readText3(join17(root, SECURITY_REL)),
|
|
35686
|
+
readText3(join17(root, PLACEHOLDER_REL)),
|
|
35577
35687
|
readSecretsObject(root)
|
|
35578
35688
|
]);
|
|
35579
35689
|
const names = /* @__PURE__ */ new Set([...placeholderKeys(placeholder), ...Object.keys(secrets)]);
|
|
@@ -35586,14 +35696,14 @@ async function readSecrets(root) {
|
|
|
35586
35696
|
async function writeSecrets(root, req) {
|
|
35587
35697
|
try {
|
|
35588
35698
|
if (req.kind === "security") {
|
|
35589
|
-
await writeFile5(
|
|
35699
|
+
await writeFile5(join17(root, SECURITY_REL), req.content, "utf8");
|
|
35590
35700
|
} else if (req.kind === "placeholder") {
|
|
35591
|
-
await writeFile5(
|
|
35701
|
+
await writeFile5(join17(root, PLACEHOLDER_REL), req.content, "utf8");
|
|
35592
35702
|
} else {
|
|
35593
35703
|
const secrets = await readSecretsObject(root);
|
|
35594
35704
|
if (req.kind === "secret") secrets[req.key] = req.value;
|
|
35595
35705
|
else delete secrets[req.key];
|
|
35596
|
-
await writeFile5(
|
|
35706
|
+
await writeFile5(join17(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
|
|
35597
35707
|
}
|
|
35598
35708
|
return { ok: true };
|
|
35599
35709
|
} catch (err) {
|
|
@@ -35603,13 +35713,13 @@ async function writeSecrets(root, req) {
|
|
|
35603
35713
|
|
|
35604
35714
|
// src/core/agent-tools.ts
|
|
35605
35715
|
import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
35606
|
-
import { dirname as dirname5, join as
|
|
35716
|
+
import { dirname as dirname5, join as join18 } from "path";
|
|
35607
35717
|
var SHARED_REL = ".claude/settings.json";
|
|
35608
35718
|
var LOCAL_REL = ".claude/settings.local.json";
|
|
35609
35719
|
var SECRETS_DENY = "Read(./project.secrets.json)";
|
|
35610
35720
|
var MODES = ["default", "acceptEdits", "plan", "bypassPermissions"];
|
|
35611
35721
|
function fileFor(root, scope) {
|
|
35612
|
-
return
|
|
35722
|
+
return join18(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
|
|
35613
35723
|
}
|
|
35614
35724
|
async function readSettingsObject(path) {
|
|
35615
35725
|
try {
|
|
@@ -35646,7 +35756,7 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
35646
35756
|
|
|
35647
35757
|
// src/core/graph.ts
|
|
35648
35758
|
import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
|
|
35649
|
-
import { join as
|
|
35759
|
+
import { join as join19, relative as relative2, dirname as dirname6, resolve as resolve4, extname, basename as basename2 } from "path";
|
|
35650
35760
|
var MAX_FILES = 2e3;
|
|
35651
35761
|
var MAX_NODES = 3e3;
|
|
35652
35762
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
|
|
@@ -35666,7 +35776,7 @@ async function walk(root, accept) {
|
|
|
35666
35776
|
if (e.name.startsWith(".") && e.name !== ".claude") {
|
|
35667
35777
|
if (e.isDirectory()) continue;
|
|
35668
35778
|
}
|
|
35669
|
-
const full =
|
|
35779
|
+
const full = join19(dir2, e.name);
|
|
35670
35780
|
if (e.isDirectory()) {
|
|
35671
35781
|
if (!SKIP_DIRS.has(e.name)) stack.push(full);
|
|
35672
35782
|
} else if (accept(full)) {
|
|
@@ -35786,10 +35896,10 @@ async function buildGraph(root, mode) {
|
|
|
35786
35896
|
|
|
35787
35897
|
// src/core/rag.ts
|
|
35788
35898
|
import { readFile as readFile9, writeFile as writeFile7, statfs as statfs2, mkdir as mkdir6 } from "fs/promises";
|
|
35789
|
-
import { existsSync as
|
|
35899
|
+
import { existsSync as existsSync10 } from "fs";
|
|
35790
35900
|
import { execFile as execFile4, spawn as spawn7 } from "child_process";
|
|
35791
35901
|
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
35792
|
-
import { join as
|
|
35902
|
+
import { join as join20 } from "path";
|
|
35793
35903
|
import { promisify as promisify4 } from "util";
|
|
35794
35904
|
var run3 = promisify4(execFile4);
|
|
35795
35905
|
var RAG_REL = ".claude/rag";
|
|
@@ -35810,7 +35920,7 @@ async function detectPython() {
|
|
|
35810
35920
|
}
|
|
35811
35921
|
async function installLog(root) {
|
|
35812
35922
|
try {
|
|
35813
|
-
const text = await readFile9(
|
|
35923
|
+
const text = await readFile9(join20(root, RAG_REL, "install.log"), "utf8");
|
|
35814
35924
|
return text.split("\n").filter((l) => l.length > 0).slice(-200);
|
|
35815
35925
|
} catch {
|
|
35816
35926
|
return [];
|
|
@@ -35872,14 +35982,14 @@ async function ragStatus(root) {
|
|
|
35872
35982
|
};
|
|
35873
35983
|
let modelName = "";
|
|
35874
35984
|
try {
|
|
35875
|
-
modelName = (await readFile9(
|
|
35985
|
+
modelName = (await readFile9(join20(root, RAG_REL, ".installed"), "utf8")).trim();
|
|
35876
35986
|
} catch {
|
|
35877
35987
|
modelName = "";
|
|
35878
35988
|
}
|
|
35879
35989
|
const modelPresent = modelName.length > 0;
|
|
35880
35990
|
return {
|
|
35881
35991
|
installed: fastembed && sqliteVec && modelPresent,
|
|
35882
|
-
installing:
|
|
35992
|
+
installing: existsSync10(join20(root, RAG_REL, ".installing")),
|
|
35883
35993
|
python: { found: py.found, version: py.version },
|
|
35884
35994
|
deps: { pip, fastembed, sqliteVec },
|
|
35885
35995
|
model: { present: modelPresent, name: modelName },
|
|
@@ -35890,9 +36000,9 @@ async function ragStatus(root) {
|
|
|
35890
36000
|
};
|
|
35891
36001
|
}
|
|
35892
36002
|
async function readIndexMeta(root) {
|
|
35893
|
-
const indexing =
|
|
36003
|
+
const indexing = existsSync10(join20(root, RAG_REL, ".indexing"));
|
|
35894
36004
|
try {
|
|
35895
|
-
const m = JSON.parse(await readFile9(
|
|
36005
|
+
const m = JSON.parse(await readFile9(join20(root, RAG_REL, ".index.json"), "utf8"));
|
|
35896
36006
|
return {
|
|
35897
36007
|
present: true,
|
|
35898
36008
|
indexing,
|
|
@@ -35959,14 +36069,14 @@ if __name__ == "__main__":
|
|
|
35959
36069
|
elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
|
|
35960
36070
|
`;
|
|
35961
36071
|
async function ensureEngine(root) {
|
|
35962
|
-
await mkdir6(
|
|
35963
|
-
await writeFile7(
|
|
36072
|
+
await mkdir6(join20(root, RAG_REL), { recursive: true }).catch(() => void 0);
|
|
36073
|
+
await writeFile7(join20(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
|
|
35964
36074
|
}
|
|
35965
36075
|
async function ragReindex(root) {
|
|
35966
36076
|
const py = await detectPython();
|
|
35967
36077
|
if (!py.found) return { ok: false, started: false, error: "python3 not found" };
|
|
35968
|
-
if (!
|
|
35969
|
-
if (
|
|
36078
|
+
if (!existsSync10(join20(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
|
|
36079
|
+
if (existsSync10(join20(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
|
|
35970
36080
|
await ensureEngine(root);
|
|
35971
36081
|
const script = `
|
|
35972
36082
|
set +e
|
|
@@ -35986,12 +36096,12 @@ rm -f "${RAG_REL}/.indexing"
|
|
|
35986
36096
|
async function ragQuery(root, queryText, k = 8) {
|
|
35987
36097
|
const py = await detectPython();
|
|
35988
36098
|
if (!py.found) return { results: [], error: "python3 not found" };
|
|
35989
|
-
if (!
|
|
36099
|
+
if (!existsSync10(join20(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
|
|
35990
36100
|
await ensureEngine(root);
|
|
35991
36101
|
try {
|
|
35992
36102
|
const { stdout } = await run3(
|
|
35993
36103
|
py.bin,
|
|
35994
|
-
[
|
|
36104
|
+
[join20(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k, 1), 20))],
|
|
35995
36105
|
{ cwd: root, timeout: 3e4, maxBuffer: 4 * 1024 * 1024 }
|
|
35996
36106
|
);
|
|
35997
36107
|
const parsed = JSON.parse(stdout.trim() || '{"results":[]}');
|
|
@@ -36003,9 +36113,9 @@ async function ragQuery(root, queryText, k = 8) {
|
|
|
36003
36113
|
async function ragInstall(root, model) {
|
|
36004
36114
|
const py = await detectPython();
|
|
36005
36115
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
36006
|
-
if (
|
|
36116
|
+
if (existsSync10(join20(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
36007
36117
|
try {
|
|
36008
|
-
await mkdir6(
|
|
36118
|
+
await mkdir6(join20(root, RAG_REL), { recursive: true });
|
|
36009
36119
|
} catch {
|
|
36010
36120
|
}
|
|
36011
36121
|
const script = `
|
|
@@ -36093,12 +36203,12 @@ ${stderr}`;
|
|
|
36093
36203
|
// src/core/git-ssh-key.ts
|
|
36094
36204
|
import { execFile as execFile7 } from "child_process";
|
|
36095
36205
|
import { readFile as readFile11, rm as rm3, mkdir as mkdir7 } from "fs/promises";
|
|
36096
|
-
import { join as
|
|
36206
|
+
import { join as join21 } from "path";
|
|
36097
36207
|
import { promisify as promisify7 } from "util";
|
|
36098
36208
|
var run6 = promisify7(execFile7);
|
|
36099
36209
|
function keyPaths(profileDir2) {
|
|
36100
|
-
const dir2 =
|
|
36101
|
-
const key =
|
|
36210
|
+
const dir2 = join21(profileDir2, ".ssh");
|
|
36211
|
+
const key = join21(dir2, "id_4pm");
|
|
36102
36212
|
return { dir: dir2, key, pub: `${key}.pub` };
|
|
36103
36213
|
}
|
|
36104
36214
|
async function readPublicKey(pub) {
|
|
@@ -36290,7 +36400,7 @@ async function setCommitAuthor(cwd2, machineUsername) {
|
|
|
36290
36400
|
// src/core/scaffold.ts
|
|
36291
36401
|
import { cp, mkdir as mkdir8, writeFile as writeFile8 } from "fs/promises";
|
|
36292
36402
|
import { execFile as execFile10 } from "child_process";
|
|
36293
|
-
import { dirname as dirname8, join as
|
|
36403
|
+
import { dirname as dirname8, join as join22, resolve as resolve7 } from "path";
|
|
36294
36404
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
36295
36405
|
import { promisify as promisify10 } from "util";
|
|
36296
36406
|
var run9 = promisify10(execFile10);
|
|
@@ -36319,7 +36429,7 @@ async function provisionRepos(target, repos, emit, opts = {}) {
|
|
|
36319
36429
|
}
|
|
36320
36430
|
continue;
|
|
36321
36431
|
}
|
|
36322
|
-
const dir2 =
|
|
36432
|
+
const dir2 = join22(target, subDirName(repo));
|
|
36323
36433
|
if (repo.url) {
|
|
36324
36434
|
emit("git", `Cloning sub-repo ${repo.url}\u2026`);
|
|
36325
36435
|
await run9("git", ["clone", repo.url, dir2], { timeout: 12e4 });
|
|
@@ -36339,14 +36449,14 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
|
|
|
36339
36449
|
const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
|
|
36340
36450
|
try {
|
|
36341
36451
|
const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
|
|
36342
|
-
const target =
|
|
36452
|
+
const target = join22(root, payload.projectName);
|
|
36343
36453
|
await mkdir8(target, { recursive: true });
|
|
36344
36454
|
emit("copy", "Copying the sample template\u2026");
|
|
36345
36455
|
await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
|
|
36346
36456
|
if (payload.spec) {
|
|
36347
36457
|
emit("spec", "Writing project.spec.json\u2026");
|
|
36348
36458
|
await writeFile8(
|
|
36349
|
-
|
|
36459
|
+
join22(target, "project.spec.json"),
|
|
36350
36460
|
JSON.stringify(payload.spec, null, 2),
|
|
36351
36461
|
"utf8"
|
|
36352
36462
|
);
|
|
@@ -36364,7 +36474,7 @@ async function aiInit(target, spec, emit) {
|
|
|
36364
36474
|
emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
|
|
36365
36475
|
const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
|
|
36366
36476
|
if (subagents.length > 0) {
|
|
36367
|
-
await mkdir8(
|
|
36477
|
+
await mkdir8(join22(target, ".claude", "agents"), { recursive: true });
|
|
36368
36478
|
for (const sa of subagents) {
|
|
36369
36479
|
const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
36370
36480
|
if (!name) continue;
|
|
@@ -36374,17 +36484,17 @@ name: ${name}
|
|
|
36374
36484
|
|
|
36375
36485
|
${(sa.description || "").trim()}
|
|
36376
36486
|
`;
|
|
36377
|
-
await writeFile8(
|
|
36487
|
+
await writeFile8(join22(target, ".claude", "agents", `${name}.md`), body, "utf8");
|
|
36378
36488
|
}
|
|
36379
36489
|
}
|
|
36380
36490
|
const specJson = JSON.stringify(spec);
|
|
36381
36491
|
await generateFile(
|
|
36382
|
-
|
|
36492
|
+
join22(target, "README.md"),
|
|
36383
36493
|
`Write a concise README.md (Markdown only, no preamble) for this project from its spec JSON:
|
|
36384
36494
|
${specJson}`
|
|
36385
36495
|
);
|
|
36386
36496
|
await generateFile(
|
|
36387
|
-
|
|
36497
|
+
join22(target, "CLAUDE.md"),
|
|
36388
36498
|
`Write a CLAUDE.md (Markdown only, no preamble) with guidance/conventions for AI agents working in this project, derived from its spec JSON:
|
|
36389
36499
|
${specJson}`
|
|
36390
36500
|
);
|
|
@@ -36400,7 +36510,7 @@ async function addProject(payload, profileDir2, onProgress) {
|
|
|
36400
36510
|
const emit = (step, message) => onProgress?.({ projectId: payload.projectId, step, message });
|
|
36401
36511
|
try {
|
|
36402
36512
|
const root = process.env.SCAFFOLD_ROOT ? resolve7(process.env.SCAFFOLD_ROOT) : resolve7(profileDir2);
|
|
36403
|
-
const target =
|
|
36513
|
+
const target = join22(root, payload.projectName);
|
|
36404
36514
|
await mkdir8(target, { recursive: true });
|
|
36405
36515
|
const repos = payload.repos ?? [];
|
|
36406
36516
|
if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
|
|
@@ -36412,14 +36522,14 @@ async function addProject(payload, profileDir2, onProgress) {
|
|
|
36412
36522
|
}
|
|
36413
36523
|
|
|
36414
36524
|
// src/core/config-sync.ts
|
|
36415
|
-
import { existsSync as
|
|
36416
|
-
import { join as
|
|
36525
|
+
import { existsSync as existsSync11, readFileSync as readFileSync15 } from "fs";
|
|
36526
|
+
import { join as join23 } from "path";
|
|
36417
36527
|
var SERVER_MANAGED_KEYS = ["physicPath", "sessionSwitchPct", "perPromptTokenLimit"];
|
|
36418
36528
|
function readConfigText(profileDir2) {
|
|
36419
|
-
const path =
|
|
36420
|
-
if (
|
|
36529
|
+
const path = join23(profileDir2, "config.json");
|
|
36530
|
+
if (existsSync11(path)) {
|
|
36421
36531
|
try {
|
|
36422
|
-
return
|
|
36532
|
+
return readFileSync15(path, "utf8");
|
|
36423
36533
|
} catch {
|
|
36424
36534
|
}
|
|
36425
36535
|
}
|
|
@@ -36844,7 +36954,6 @@ var WsClient = class {
|
|
|
36844
36954
|
});
|
|
36845
36955
|
this.outboundReviewEnabled = token.outboundReview?.enabled === true;
|
|
36846
36956
|
this.restrictToFolder = token.aiRestrictToFolder === true;
|
|
36847
|
-
writeEgressAllowlist(this.context.profileDir, token.aiSandbox ?? null);
|
|
36848
36957
|
applyGitAuth(token.gitAuth ?? null);
|
|
36849
36958
|
this.machineUsername = token.machineUsername ?? "";
|
|
36850
36959
|
if (token.scope && token.scope !== this.credential.scope) {
|
|
@@ -36890,6 +36999,7 @@ var WsClient = class {
|
|
|
36890
36999
|
socket.on("close", (code) => {
|
|
36891
37000
|
this.clearHeartbeat();
|
|
36892
37001
|
this.sessionKey = null;
|
|
37002
|
+
setToolHealthSink(null);
|
|
36893
37003
|
logger.debug("ws.close", { code });
|
|
36894
37004
|
if (code === CLOSE_DRAINING) {
|
|
36895
37005
|
this.bus.log("Server draining \u2014 will reconnect (backoff + jitter).");
|
|
@@ -36931,6 +37041,7 @@ var WsClient = class {
|
|
|
36931
37041
|
this.startUsagePolling();
|
|
36932
37042
|
this.startLogUpload();
|
|
36933
37043
|
this.startKbRefresh();
|
|
37044
|
+
setToolHealthSink((report) => this.send(WsChannels.TOOL_HEALTH, report));
|
|
36934
37045
|
this.connectWaiters.splice(0).forEach((fn) => fn());
|
|
36935
37046
|
return;
|
|
36936
37047
|
}
|
|
@@ -36992,8 +37103,8 @@ var WsClient = class {
|
|
|
36992
37103
|
const oldRoot = this.physicFolderPath(sync.oldName);
|
|
36993
37104
|
if (oldRoot) void uninstallCron(oldRoot).catch(() => void 0);
|
|
36994
37105
|
}
|
|
36995
|
-
if (sync.oldName)
|
|
36996
|
-
mkdirSync5(
|
|
37106
|
+
if (sync.oldName) rmSync4(join24(this.context.profileDir, sync.oldName), { recursive: true, force: true });
|
|
37107
|
+
mkdirSync5(join24(this.context.profileDir, sync.newName), { recursive: true });
|
|
36997
37108
|
this.physicRoot = this.physicFolderPath(sync.newName);
|
|
36998
37109
|
this.bus.setProject(sync.newName);
|
|
36999
37110
|
this.bus.log(`Physic project folder synced \u2192 ${sync.newName}`);
|
|
@@ -37004,7 +37115,7 @@ var WsClient = class {
|
|
|
37004
37115
|
if (del.name) {
|
|
37005
37116
|
const delRoot = this.physicFolderPath(del.name);
|
|
37006
37117
|
if (delRoot) void uninstallCron(delRoot).catch(() => void 0);
|
|
37007
|
-
|
|
37118
|
+
rmSync4(join24(this.context.profileDir, del.name), { recursive: true, force: true });
|
|
37008
37119
|
this.bus.log(`Physic project folder deleted (project removed) \u2192 ${del.name}`);
|
|
37009
37120
|
}
|
|
37010
37121
|
void manageSshKey("delete", this.context.profileDir).catch(() => void 0);
|
|
@@ -37103,6 +37214,7 @@ var WsClient = class {
|
|
|
37103
37214
|
this.bus.push({ source: "server", kind: "aires", text: `${supportCmd} \u203A` });
|
|
37104
37215
|
this.bus.push({ source: "server", kind: "out", text: reply.body });
|
|
37105
37216
|
}
|
|
37217
|
+
reportToolResult(supportCmd, !reply.error, reply.error);
|
|
37106
37218
|
this.send(WsChannels.SUPPORT_ANSWER, reply, message.id);
|
|
37107
37219
|
}).finally(() => this.bus.endBusy("support-answer"));
|
|
37108
37220
|
break;
|
|
@@ -37376,7 +37488,7 @@ var WsClient = class {
|
|
|
37376
37488
|
}
|
|
37377
37489
|
case WsChannels.LOG_READ: {
|
|
37378
37490
|
const limit = Math.min(Math.max(payload.limit ?? 200, 1), 2e3);
|
|
37379
|
-
const lines = readRecentLogLines(
|
|
37491
|
+
const lines = readRecentLogLines(join24(this.context.profileDir, "logs"), limit);
|
|
37380
37492
|
this.send(WsChannels.LOG_READ, { lines }, message.id);
|
|
37381
37493
|
break;
|
|
37382
37494
|
}
|
|
@@ -37962,7 +38074,7 @@ var WsClient = class {
|
|
|
37962
38074
|
/** Create the physic folder at an absolute path if missing (best-effort). */
|
|
37963
38075
|
ensurePhysicFolderPath(folder) {
|
|
37964
38076
|
try {
|
|
37965
|
-
if (!
|
|
38077
|
+
if (!existsSync12(folder)) {
|
|
37966
38078
|
mkdirSync5(folder, { recursive: true });
|
|
37967
38079
|
this.bus.log(`Created physic project folder: ${folder}`);
|
|
37968
38080
|
}
|
|
@@ -37977,7 +38089,7 @@ var WsClient = class {
|
|
|
37977
38089
|
*/
|
|
37978
38090
|
physicFolderPath(projectName) {
|
|
37979
38091
|
const safe = projectName.replace(/[/\\]/g, "_").replace(/\.\./g, "_").trim();
|
|
37980
|
-
return safe ?
|
|
38092
|
+
return safe ? join24(this.context.profileDir, safe) : null;
|
|
37981
38093
|
}
|
|
37982
38094
|
/**
|
|
37983
38095
|
* Report machine.status: version + the state of the physic project being served
|
|
@@ -37991,7 +38103,7 @@ var WsClient = class {
|
|
|
37991
38103
|
projects: [],
|
|
37992
38104
|
version: CLI_VERSION,
|
|
37993
38105
|
physicPath,
|
|
37994
|
-
physicPathExists: physicPath ?
|
|
38106
|
+
physicPathExists: physicPath ? existsSync12(physicPath) : void 0,
|
|
37995
38107
|
// Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
|
|
37996
38108
|
autonomousRunning: physicPath ? isAutonomousRunning(physicPath) : false
|
|
37997
38109
|
});
|
|
@@ -38039,6 +38151,7 @@ var WsClient = class {
|
|
|
38039
38151
|
};
|
|
38040
38152
|
snapshot.aiCli = aiCli2;
|
|
38041
38153
|
snapshot.profile = profile;
|
|
38154
|
+
snapshot.network = await probeNetwork();
|
|
38042
38155
|
this.usageSnapshot = snapshot;
|
|
38043
38156
|
this.bus.setUsage?.(snapshot);
|
|
38044
38157
|
this.send(WsChannels.MACHINE_USAGE, snapshot);
|
|
@@ -38080,7 +38193,7 @@ var WsClient = class {
|
|
|
38080
38193
|
*/
|
|
38081
38194
|
uploadLog() {
|
|
38082
38195
|
try {
|
|
38083
|
-
const upload = readLogUpload(
|
|
38196
|
+
const upload = readLogUpload(join24(this.context.profileDir, "logs"));
|
|
38084
38197
|
if (!upload) return;
|
|
38085
38198
|
const sig = `${upload.fileName}:${upload.totalBytes}`;
|
|
38086
38199
|
if (sig === this.lastLogSig) return;
|
|
@@ -38108,10 +38221,10 @@ var WsClient = class {
|
|
|
38108
38221
|
};
|
|
38109
38222
|
|
|
38110
38223
|
// src/core/instance-lock.ts
|
|
38111
|
-
import { readFileSync as
|
|
38112
|
-
import { join as
|
|
38224
|
+
import { readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
38225
|
+
import { join as join25 } from "path";
|
|
38113
38226
|
function lockPath(profileDir2) {
|
|
38114
|
-
return
|
|
38227
|
+
return join25(profileDir2, "start.lock");
|
|
38115
38228
|
}
|
|
38116
38229
|
function isAlive(pid) {
|
|
38117
38230
|
try {
|
|
@@ -38123,7 +38236,7 @@ function isAlive(pid) {
|
|
|
38123
38236
|
}
|
|
38124
38237
|
function lockHolder(profileDir2) {
|
|
38125
38238
|
try {
|
|
38126
|
-
const pid = Number.parseInt(
|
|
38239
|
+
const pid = Number.parseInt(readFileSync16(lockPath(profileDir2), "utf8").trim(), 10);
|
|
38127
38240
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && isAlive(pid)) return pid;
|
|
38128
38241
|
} catch {
|
|
38129
38242
|
}
|
|
@@ -38131,13 +38244,13 @@ function lockHolder(profileDir2) {
|
|
|
38131
38244
|
}
|
|
38132
38245
|
function acquireInstanceLock(profileDir2) {
|
|
38133
38246
|
if (lockHolder(profileDir2) !== null) return false;
|
|
38134
|
-
|
|
38247
|
+
writeFileSync7(lockPath(profileDir2), String(process.pid), "utf8");
|
|
38135
38248
|
return true;
|
|
38136
38249
|
}
|
|
38137
38250
|
function releaseInstanceLock(profileDir2) {
|
|
38138
38251
|
try {
|
|
38139
|
-
const pid = Number.parseInt(
|
|
38140
|
-
if (pid === process.pid)
|
|
38252
|
+
const pid = Number.parseInt(readFileSync16(lockPath(profileDir2), "utf8").trim(), 10);
|
|
38253
|
+
if (pid === process.pid) rmSync5(lockPath(profileDir2), { force: true });
|
|
38141
38254
|
} catch {
|
|
38142
38255
|
}
|
|
38143
38256
|
}
|
|
@@ -38398,8 +38511,8 @@ var SessionBus = class {
|
|
|
38398
38511
|
|
|
38399
38512
|
// src/core/control-server.ts
|
|
38400
38513
|
import { createServer } from "net";
|
|
38401
|
-
import { rmSync as
|
|
38402
|
-
import { join as
|
|
38514
|
+
import { rmSync as rmSync6 } from "fs";
|
|
38515
|
+
import { join as join26 } from "path";
|
|
38403
38516
|
|
|
38404
38517
|
// src/core/control-protocol.ts
|
|
38405
38518
|
var CONTROL_SOCKET_FILE = "control.sock";
|
|
@@ -38428,9 +38541,9 @@ function createFrameParser() {
|
|
|
38428
38541
|
|
|
38429
38542
|
// src/core/control-server.ts
|
|
38430
38543
|
function startControlServer(bus, profileDir2, info) {
|
|
38431
|
-
const socketPath =
|
|
38544
|
+
const socketPath = join26(profileDir2, CONTROL_SOCKET_FILE);
|
|
38432
38545
|
try {
|
|
38433
|
-
|
|
38546
|
+
rmSync6(socketPath, { force: true });
|
|
38434
38547
|
} catch {
|
|
38435
38548
|
}
|
|
38436
38549
|
const clients = /* @__PURE__ */ new Set();
|
|
@@ -38496,7 +38609,7 @@ function startControlServer(bus, profileDir2, info) {
|
|
|
38496
38609
|
clients.clear();
|
|
38497
38610
|
server.close();
|
|
38498
38611
|
try {
|
|
38499
|
-
|
|
38612
|
+
rmSync6(socketPath, { force: true });
|
|
38500
38613
|
} catch {
|
|
38501
38614
|
}
|
|
38502
38615
|
};
|
|
@@ -40476,7 +40589,7 @@ var src_default = Yoga;
|
|
|
40476
40589
|
|
|
40477
40590
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
|
|
40478
40591
|
var import_react_reconciler = __toESM(require_react_reconciler(), 1);
|
|
40479
|
-
var
|
|
40592
|
+
var import_constants7 = __toESM(require_constants2(), 1);
|
|
40480
40593
|
import process3 from "process";
|
|
40481
40594
|
|
|
40482
40595
|
// ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
@@ -41718,7 +41831,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
41718
41831
|
scheduleTimeout: setTimeout,
|
|
41719
41832
|
cancelTimeout: clearTimeout,
|
|
41720
41833
|
noTimeout: -1,
|
|
41721
|
-
getCurrentEventPriority: () =>
|
|
41834
|
+
getCurrentEventPriority: () => import_constants7.DefaultEventPriority,
|
|
41722
41835
|
beforeActiveInstanceBlur() {
|
|
41723
41836
|
},
|
|
41724
41837
|
afterActiveInstanceBlur() {
|
|
@@ -44160,17 +44273,17 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
44160
44273
|
var import_react26 = __toESM(require_react(), 1);
|
|
44161
44274
|
|
|
44162
44275
|
// src/core/input-history.ts
|
|
44163
|
-
import { existsSync as
|
|
44164
|
-
import { join as
|
|
44276
|
+
import { existsSync as existsSync14, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "fs";
|
|
44277
|
+
import { join as join27 } from "path";
|
|
44165
44278
|
var MAX_HISTORY = 200;
|
|
44166
44279
|
function historyPath(profileDir2) {
|
|
44167
|
-
return
|
|
44280
|
+
return join27(profileDir2, "input-history.json");
|
|
44168
44281
|
}
|
|
44169
44282
|
function loadInputHistory(profileDir2) {
|
|
44170
44283
|
const path = historyPath(profileDir2);
|
|
44171
|
-
if (!
|
|
44284
|
+
if (!existsSync14(path)) return [];
|
|
44172
44285
|
try {
|
|
44173
|
-
const data = JSON.parse(
|
|
44286
|
+
const data = JSON.parse(readFileSync18(path, "utf8"));
|
|
44174
44287
|
return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
|
|
44175
44288
|
} catch {
|
|
44176
44289
|
return [];
|
|
@@ -44181,7 +44294,7 @@ function appendInputHistory(profileDir2, line, current) {
|
|
|
44181
44294
|
if (!trimmed || current[current.length - 1] === trimmed) return current;
|
|
44182
44295
|
const next = [...current, trimmed].slice(-MAX_HISTORY);
|
|
44183
44296
|
try {
|
|
44184
|
-
|
|
44297
|
+
writeFileSync8(historyPath(profileDir2), JSON.stringify(next), "utf8");
|
|
44185
44298
|
} catch {
|
|
44186
44299
|
}
|
|
44187
44300
|
return next;
|
|
@@ -44430,8 +44543,8 @@ function TranscriptLine({ line }) {
|
|
|
44430
44543
|
var import_react24 = __toESM(require_react(), 1);
|
|
44431
44544
|
|
|
44432
44545
|
// src/ui/slash-commands.ts
|
|
44433
|
-
import { existsSync as
|
|
44434
|
-
import { join as
|
|
44546
|
+
import { existsSync as existsSync15 } from "fs";
|
|
44547
|
+
import { join as join28 } from "path";
|
|
44435
44548
|
var CONFIG_KEYS = [
|
|
44436
44549
|
"aiCli",
|
|
44437
44550
|
"claudeHome",
|
|
@@ -44443,7 +44556,7 @@ var CONFIG_KEYS = [
|
|
|
44443
44556
|
"aiEnv"
|
|
44444
44557
|
];
|
|
44445
44558
|
function configPath(profileDir2) {
|
|
44446
|
-
return
|
|
44559
|
+
return join28(profileDir2, "config.json");
|
|
44447
44560
|
}
|
|
44448
44561
|
function parseConfigAssignment(key, valueTokens) {
|
|
44449
44562
|
const value = valueTokens.join(" ").trim();
|
|
@@ -44493,7 +44606,7 @@ function runConfig(ctx) {
|
|
|
44493
44606
|
ctx.print(`\u2714 ${verb} default config: ${path}`);
|
|
44494
44607
|
ctx.print("add claude profiles: /config set claudeHome .claude .claude-1 (tried in order)");
|
|
44495
44608
|
};
|
|
44496
|
-
if (
|
|
44609
|
+
if (existsSync15(path)) {
|
|
44497
44610
|
ctx.confirm(
|
|
44498
44611
|
`config exists: ${path} \u2014 replace it with defaults? (y/N)`,
|
|
44499
44612
|
() => writeDefaults("replaced with")
|
|
@@ -44578,7 +44691,7 @@ function runOutput(ctx) {
|
|
|
44578
44691
|
}
|
|
44579
44692
|
function runLogs(ctx) {
|
|
44580
44693
|
const n = Math.max(1, Math.min(200, Number(ctx.args[0]) || 20));
|
|
44581
|
-
const dir2 =
|
|
44694
|
+
const dir2 = join28(ctx.info.profileDir, "logs");
|
|
44582
44695
|
const lines = readRecentLogLines(dir2, n);
|
|
44583
44696
|
if (lines.length === 0) {
|
|
44584
44697
|
ctx.print("No log lines yet.");
|
|
@@ -45099,7 +45212,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
45099
45212
|
return;
|
|
45100
45213
|
}
|
|
45101
45214
|
logger.configure({
|
|
45102
|
-
dir:
|
|
45215
|
+
dir: join29(profileDir2, "logs"),
|
|
45103
45216
|
level: resolveLogLevel(),
|
|
45104
45217
|
base: { version: CLI_VERSION, profile: profileName, scope: credential.scope }
|
|
45105
45218
|
});
|
|
@@ -45205,13 +45318,13 @@ async function runStart(profileDir2, profileName) {
|
|
|
45205
45318
|
}
|
|
45206
45319
|
|
|
45207
45320
|
// src/commands/attach.ts
|
|
45208
|
-
import { join as
|
|
45321
|
+
import { join as join30 } from "path";
|
|
45209
45322
|
|
|
45210
45323
|
// src/core/control-client.ts
|
|
45211
|
-
import { connect } from "net";
|
|
45324
|
+
import { connect as connect2 } from "net";
|
|
45212
45325
|
function connectControl(socketPath, bus) {
|
|
45213
45326
|
return new Promise((resolve8, reject) => {
|
|
45214
|
-
const socket =
|
|
45327
|
+
const socket = connect2(socketPath);
|
|
45215
45328
|
socket.setEncoding("utf8");
|
|
45216
45329
|
let ready = false;
|
|
45217
45330
|
const forwardSubmit = bus.onLocalSubmit((input) => {
|
|
@@ -45304,7 +45417,7 @@ async function runAttach(profileDir2, profileName) {
|
|
|
45304
45417
|
process.exitCode = 1;
|
|
45305
45418
|
return;
|
|
45306
45419
|
}
|
|
45307
|
-
const socketPath =
|
|
45420
|
+
const socketPath = join30(profileDir2, CONTROL_SOCKET_FILE);
|
|
45308
45421
|
const bus = new SessionBus();
|
|
45309
45422
|
let conn;
|
|
45310
45423
|
try {
|
|
@@ -45389,7 +45502,7 @@ Tip: for the credentials to survive \`docker rm\`/recreate, keep each profile pa
|
|
|
45389
45502
|
}
|
|
45390
45503
|
|
|
45391
45504
|
// src/commands/unlink.ts
|
|
45392
|
-
import { rmSync as
|
|
45505
|
+
import { rmSync as rmSync7 } from "fs";
|
|
45393
45506
|
async function runUnlink(profileDir2, profileName) {
|
|
45394
45507
|
const cred = readCredential(profileDir2, profileName);
|
|
45395
45508
|
if (!cred) {
|
|
@@ -45404,7 +45517,7 @@ async function runUnlink(profileDir2, profileName) {
|
|
|
45404
45517
|
`\u26A0 Could not reach the server to revoke \u2014 revoke it at web /machines. (${err.message})`
|
|
45405
45518
|
);
|
|
45406
45519
|
}
|
|
45407
|
-
|
|
45520
|
+
rmSync7(profileDir2, { recursive: true, force: true });
|
|
45408
45521
|
clearDefaultProfileIf(profileName);
|
|
45409
45522
|
console.log("\u2714 Deleted the profile and its physic project folder.");
|
|
45410
45523
|
}
|