@4pm/cli 1.19.9 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +276 -109
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29519,8 +29519,8 @@ async function runLink(serverUrl, explicitProfile, token = null) {
|
|
|
29519
29519
|
}
|
|
29520
29520
|
|
|
29521
29521
|
// src/commands/start.ts
|
|
29522
|
-
import { spawn as
|
|
29523
|
-
import { join as
|
|
29522
|
+
import { spawn as spawn11 } from "child_process";
|
|
29523
|
+
import { join as join37 } from "path";
|
|
29524
29524
|
|
|
29525
29525
|
// src/core/update.ts
|
|
29526
29526
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -32732,9 +32732,9 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
|
|
|
32732
32732
|
|
|
32733
32733
|
// src/core/ws-client.ts
|
|
32734
32734
|
init_wrapper();
|
|
32735
|
-
import { randomUUID as
|
|
32736
|
-
import { basename as basename7, join as
|
|
32737
|
-
import { existsSync as
|
|
32735
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
32736
|
+
import { basename as basename7, join as join32 } from "path";
|
|
32737
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8 } from "fs";
|
|
32738
32738
|
|
|
32739
32739
|
// vendor/@4pm/utils/helpers.ts
|
|
32740
32740
|
function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
|
|
@@ -38389,6 +38389,12 @@ var WsChannels = {
|
|
|
38389
38389
|
// AI knowledge distill (ADR-0190): server → project cli request–reply. The worker runs the AI CLI
|
|
38390
38390
|
// in the project's working dir with a distillation prompt and replies with the composed markdown.
|
|
38391
38391
|
KNOWLEDGE_COMPOSE: "knowledge.compose",
|
|
38392
|
+
// Ticket → FAQ synthesis (ADR-0333): server (platform-pool dispatcher) → platform-pool cli
|
|
38393
|
+
// request–reply. The dispatcher sends the selected support tickets + the 4pm-faq repo with a
|
|
38394
|
+
// short-lived WRITE token; the worker runs an agent-write that distils the tickets into FAQ
|
|
38395
|
+
// entries, commits, pushes a branch, opens a PR, then wipes the token/clone, and replies with the
|
|
38396
|
+
// PR URL. The write token never persists on the worker (leak-safety on release/reassign).
|
|
38397
|
+
FAQ_COMPOSE: "faq.compose",
|
|
38392
38398
|
// Shared AI memory (ADR-0245): cli → server one-way write-back of the compacted rolling memory for
|
|
38393
38399
|
// the project it serves (persisted per project × machine-user link). The read direction rides
|
|
38394
38400
|
// `ws_token` (seeds the cli cache on connect); this channel only carries updates.
|
|
@@ -42799,6 +42805,145 @@ async function runKnowledgeCompose(req, ai2, physicRoot) {
|
|
|
42799
42805
|
return { bodyMarkdown: "", error: lastReason };
|
|
42800
42806
|
}
|
|
42801
42807
|
|
|
42808
|
+
// src/core/faq-compose.ts
|
|
42809
|
+
import { spawn as spawn9, execFile as execFile10 } from "child_process";
|
|
42810
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, rmSync as rmSync7 } from "fs";
|
|
42811
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
42812
|
+
import { join as join24 } from "path";
|
|
42813
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
42814
|
+
import { promisify as promisify10 } from "util";
|
|
42815
|
+
var execFileAsync2 = promisify10(execFile10);
|
|
42816
|
+
var NO_USAGE2 = { tokens: 0, input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
|
|
42817
|
+
var COMPOSE_TIMEOUT_MS2 = 10 * 60 * 1e3;
|
|
42818
|
+
function authedUrl2(url, token) {
|
|
42819
|
+
if (url.startsWith("https://")) return url.replace("https://", `https://x-access-token:${token}@`);
|
|
42820
|
+
return url;
|
|
42821
|
+
}
|
|
42822
|
+
function buildPrompt4(tickets) {
|
|
42823
|
+
const transcript = tickets.map((t2) => {
|
|
42824
|
+
const thread = t2.messages.map((m2) => ` [${m2.author}] ${m2.body}`).join("\n");
|
|
42825
|
+
return `### Ticket ${t2.id} \u2014 ${t2.subject} (${t2.category})
|
|
42826
|
+
${thread}`;
|
|
42827
|
+
}).join("\n\n");
|
|
42828
|
+
return [
|
|
42829
|
+
"You are maintaining the 4PM product FAQ, stored as markdown in THIS git repository (your CWD).",
|
|
42830
|
+
"From the resolved support tickets below, distil reusable, product-general FAQ entries and add or",
|
|
42831
|
+
"update the appropriate markdown file(s) in this repo (e.g. an FAQ.md, or the closest existing",
|
|
42832
|
+
"topic file \u2014 inspect the repo first and match its structure/style).",
|
|
42833
|
+
"",
|
|
42834
|
+
"Rules:",
|
|
42835
|
+
"- Write generalized Q&A, NOT ticket-specific replies; never include customer names, emails, ids,",
|
|
42836
|
+
" org names or any personal data from the tickets.",
|
|
42837
|
+
"- Merge with existing entries instead of duplicating; keep the existing formatting and headings.",
|
|
42838
|
+
"- If a ticket yields no reusable FAQ value, skip it. If nothing is worth adding, make NO changes.",
|
|
42839
|
+
"- Only edit markdown documentation files; do not touch code, CI, or unrelated files.",
|
|
42840
|
+
"- Do NOT run git commit/push or open a PR yourself \u2014 just leave the edited files in the working",
|
|
42841
|
+
" tree; the surrounding tooling handles commit + PR.",
|
|
42842
|
+
"",
|
|
42843
|
+
"===== RESOLVED TICKETS =====",
|
|
42844
|
+
transcript
|
|
42845
|
+
].join("\n");
|
|
42846
|
+
}
|
|
42847
|
+
function runClaudeOnce2(cmd, profile, prompt, cwd2, extraEnv) {
|
|
42848
|
+
return new Promise((resolve10, reject) => {
|
|
42849
|
+
const isClaude = cmd.includes("claude");
|
|
42850
|
+
const args = [
|
|
42851
|
+
"-p",
|
|
42852
|
+
...profile?.model ? ["--model", profile.model] : [],
|
|
42853
|
+
...isClaude ? ["--output-format", "stream-json", "--verbose"] : [],
|
|
42854
|
+
// Write-capable headless agent (ADR-0271): auto-approve tools so it never stalls on a prompt.
|
|
42855
|
+
...isClaude ? ["--permission-mode", "bypassPermissions"] : [],
|
|
42856
|
+
...cmd.includes("codex") ? ["--dangerously-bypass-approvals-and-sandbox"] : []
|
|
42857
|
+
];
|
|
42858
|
+
const env3 = {
|
|
42859
|
+
...process.env,
|
|
42860
|
+
...extraEnv,
|
|
42861
|
+
...profile ? { CLAUDE_CONFIG_DIR: profile.dir } : {}
|
|
42862
|
+
};
|
|
42863
|
+
const child = spawn9(cmd, args, { stdio: ["pipe", "pipe", "pipe"], cwd: cwd2, env: env3 });
|
|
42864
|
+
const parser = createAiStreamParser(cmd);
|
|
42865
|
+
let out = "";
|
|
42866
|
+
let err = "";
|
|
42867
|
+
const timer = setTimeout(() => {
|
|
42868
|
+
child.kill("SIGKILL");
|
|
42869
|
+
reject(new Error("faq-compose agent timed out"));
|
|
42870
|
+
}, COMPOSE_TIMEOUT_MS2);
|
|
42871
|
+
timer.unref();
|
|
42872
|
+
child.stdout.on("data", (d) => out += parser.push(d.toString()));
|
|
42873
|
+
child.stderr.on("data", (d) => err += d.toString());
|
|
42874
|
+
child.on("error", (e) => {
|
|
42875
|
+
clearTimeout(timer);
|
|
42876
|
+
reject(e);
|
|
42877
|
+
});
|
|
42878
|
+
child.on("close", (code) => {
|
|
42879
|
+
clearTimeout(timer);
|
|
42880
|
+
out += parser.flush();
|
|
42881
|
+
resolve10({ code: code ?? -1, out, err, usage: parser.usage() });
|
|
42882
|
+
});
|
|
42883
|
+
child.stdin.write(prompt);
|
|
42884
|
+
child.stdin.end();
|
|
42885
|
+
});
|
|
42886
|
+
}
|
|
42887
|
+
async function runClaudeWithFailover2(prompt, cwd2, ai2) {
|
|
42888
|
+
const attempts = ai2.profiles.length > 0 ? ai2.profiles : [null];
|
|
42889
|
+
let lastReason = "no attempt";
|
|
42890
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
42891
|
+
const { code, out, err, usage } = await runClaudeOnce2(ai2.cmd, attempts[i], prompt, cwd2, ai2.env);
|
|
42892
|
+
if (code === 0) return usage;
|
|
42893
|
+
lastReason = `exited ${code}: ${(err || out).slice(0, 500)}`;
|
|
42894
|
+
if (i === attempts.length - 1) break;
|
|
42895
|
+
}
|
|
42896
|
+
throw new Error(`claude ${lastReason}`);
|
|
42897
|
+
}
|
|
42898
|
+
async function runFaqCompose(req, ai2) {
|
|
42899
|
+
if (!req.repo.token) return { prUrl: "", error: "no write token" };
|
|
42900
|
+
const workDir = join24(tmpdir3(), "4pm-faq-sync", randomUUID3());
|
|
42901
|
+
const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
|
|
42902
|
+
const authed = authedUrl2(req.repo.url, req.repo.token);
|
|
42903
|
+
try {
|
|
42904
|
+
mkdirSync7(workDir, { recursive: true });
|
|
42905
|
+
await execFileAsync2("git", ["clone", "--depth", "1", "--branch", req.repo.branch, authed, workDir], { env: gitEnv });
|
|
42906
|
+
await execFileAsync2("git", ["-C", workDir, "config", "user.name", "4PM FAQ Bot"], { env: gitEnv });
|
|
42907
|
+
await execFileAsync2("git", ["-C", workDir, "config", "user.email", "faq-bot@4pm.app"], { env: gitEnv });
|
|
42908
|
+
await execFileAsync2("git", ["-C", workDir, "checkout", "-b", req.headBranch], { env: gitEnv });
|
|
42909
|
+
const usage = await runClaudeWithFailover2(buildPrompt4(req.tickets), workDir, ai2);
|
|
42910
|
+
await execFileAsync2("git", ["-C", workDir, "add", "-A"], { env: gitEnv });
|
|
42911
|
+
const staged = await execFileAsync2("git", ["-C", workDir, "diff", "--cached", "--name-only"], { env: gitEnv });
|
|
42912
|
+
if (!staged.stdout.trim()) return { prUrl: "", tokens: usage.tokens || estimateTokens2(""), finishedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
42913
|
+
await execFileAsync2("git", ["-C", workDir, "commit", "-m", "docs(faq): synthesize from support tickets (4PM)"], { env: gitEnv });
|
|
42914
|
+
await execFileAsync2("git", ["-C", workDir, "push", "-u", "origin", req.headBranch], { env: gitEnv });
|
|
42915
|
+
let prUrl = "";
|
|
42916
|
+
try {
|
|
42917
|
+
const pr2 = await execFileAsync2(
|
|
42918
|
+
"gh",
|
|
42919
|
+
["pr", "create", "--fill", "--head", req.headBranch, "--base", req.repo.branch],
|
|
42920
|
+
{ cwd: workDir, env: { ...gitEnv, GH_TOKEN: req.repo.token } }
|
|
42921
|
+
);
|
|
42922
|
+
prUrl = pr2.stdout.trim().split("\n").pop() ?? "";
|
|
42923
|
+
} catch (err) {
|
|
42924
|
+
logger.warn("faq.compose.pr.failed", { error: String(err) });
|
|
42925
|
+
}
|
|
42926
|
+
const u2 = usage.tokens > 0 ? usage : { ...NO_USAGE2 };
|
|
42927
|
+
return {
|
|
42928
|
+
prUrl,
|
|
42929
|
+
branch: req.headBranch,
|
|
42930
|
+
tokens: u2.tokens,
|
|
42931
|
+
...usage.tokens > 0 ? { tokensBreakdown: { input: usage.input, output: usage.output, cacheRead: usage.cacheRead, cacheCreation: usage.cacheCreation } } : {},
|
|
42932
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
42933
|
+
};
|
|
42934
|
+
} catch (err) {
|
|
42935
|
+
logger.warn("faq.compose.failed", { error: String(err) });
|
|
42936
|
+
return { prUrl: "", error: String(err) };
|
|
42937
|
+
} finally {
|
|
42938
|
+
if (existsSync14(workDir)) {
|
|
42939
|
+
try {
|
|
42940
|
+
rmSync7(workDir, { recursive: true, force: true });
|
|
42941
|
+
} catch {
|
|
42942
|
+
}
|
|
42943
|
+
}
|
|
42944
|
+
}
|
|
42945
|
+
}
|
|
42946
|
+
|
|
42802
42947
|
// src/core/ws-client/handlers/support.ts
|
|
42803
42948
|
function handleSupportChannels(ctx, message, payload) {
|
|
42804
42949
|
switch (message.channel) {
|
|
@@ -42855,6 +43000,28 @@ function handleSupportChannels(ctx, message, payload) {
|
|
|
42855
43000
|
}).finally(() => ctx.bus.endBusy("knowledge-compose"));
|
|
42856
43001
|
return true;
|
|
42857
43002
|
}
|
|
43003
|
+
case WsChannels.FAQ_COMPOSE: {
|
|
43004
|
+
const freq = payload;
|
|
43005
|
+
const fcfg = readProfileConfig(ctx.profileDir);
|
|
43006
|
+
const fcmd = fcfg.aiCli || "claude";
|
|
43007
|
+
const fai = {
|
|
43008
|
+
cmd: fcmd,
|
|
43009
|
+
profiles: resolveClaudeProfiles(fcfg, getWorkingProfile(ctx.profileDir, fcmd)),
|
|
43010
|
+
env: fcfg.aiEnv
|
|
43011
|
+
};
|
|
43012
|
+
ctx.bus.push({ source: "server", kind: "aireq", text: `${fcmd} \u2039 synthesize FAQ (${freq.tickets.length} tickets)` });
|
|
43013
|
+
ctx.bus.startBusy("faq-compose");
|
|
43014
|
+
void runFaqCompose(freq, fai).then((reply) => {
|
|
43015
|
+
if (reply.error) {
|
|
43016
|
+
ctx.bus.push({ source: "server", kind: "log", text: `faq-compose failed: ${reply.error}`, level: "warn" });
|
|
43017
|
+
} else {
|
|
43018
|
+
ctx.bus.push({ source: "server", kind: "aires", text: `${fcmd} \u203A ${reply.prUrl || "no changes"}` });
|
|
43019
|
+
}
|
|
43020
|
+
reportToolResult(fcmd, !reply.error, reply.error);
|
|
43021
|
+
ctx.send(WsChannels.FAQ_COMPOSE, reply, message.id);
|
|
43022
|
+
}).finally(() => ctx.bus.endBusy("faq-compose"));
|
|
43023
|
+
return true;
|
|
43024
|
+
}
|
|
42858
43025
|
default:
|
|
42859
43026
|
return false;
|
|
42860
43027
|
}
|
|
@@ -42953,7 +43120,7 @@ function handleToolsChannels(ctx, message, payload) {
|
|
|
42953
43120
|
|
|
42954
43121
|
// src/core/agents.ts
|
|
42955
43122
|
import { readFile as readFile10, writeFile as writeFile8, mkdir as mkdir8, readdir as readdir4, rm as rm5 } from "fs/promises";
|
|
42956
|
-
import { join as
|
|
43123
|
+
import { join as join25 } from "path";
|
|
42957
43124
|
var AGENTS_REL = ".claude/agents";
|
|
42958
43125
|
var SKILLS_REL = ".claude/skills";
|
|
42959
43126
|
var MEMORY_DIRS = /* @__PURE__ */ new Set(["short-memory", "long-memory"]);
|
|
@@ -42977,17 +43144,17 @@ async function listAgents(root) {
|
|
|
42977
43144
|
const subagents = [];
|
|
42978
43145
|
const skills = [];
|
|
42979
43146
|
try {
|
|
42980
|
-
for (const e of await readdir4(
|
|
43147
|
+
for (const e of await readdir4(join25(root, AGENTS_REL), { withFileTypes: true })) {
|
|
42981
43148
|
if (!e.isFile() || !e.name.endsWith(".md") || MEMORY_DIRS.has(e.name)) continue;
|
|
42982
|
-
const fm = frontmatter(await readText2(
|
|
43149
|
+
const fm = frontmatter(await readText2(join25(root, AGENTS_REL, e.name)));
|
|
42983
43150
|
subagents.push({ name: e.name.replace(/\.md$/, ""), description: fm.description });
|
|
42984
43151
|
}
|
|
42985
43152
|
} catch {
|
|
42986
43153
|
}
|
|
42987
43154
|
try {
|
|
42988
|
-
for (const e of await readdir4(
|
|
43155
|
+
for (const e of await readdir4(join25(root, SKILLS_REL), { withFileTypes: true })) {
|
|
42989
43156
|
if (!e.isDirectory()) continue;
|
|
42990
|
-
const fm = frontmatter(await readText2(
|
|
43157
|
+
const fm = frontmatter(await readText2(join25(root, SKILLS_REL, e.name, "SKILL.md")));
|
|
42991
43158
|
skills.push({ name: e.name, description: fm.description });
|
|
42992
43159
|
}
|
|
42993
43160
|
} catch {
|
|
@@ -42998,15 +43165,15 @@ async function listAgents(root) {
|
|
|
42998
43165
|
}
|
|
42999
43166
|
function itemPath(root, kind, name) {
|
|
43000
43167
|
const n = safeName(name);
|
|
43001
|
-
return kind === "subagent" ?
|
|
43168
|
+
return kind === "subagent" ? join25(root, AGENTS_REL, `${n}.md`) : join25(root, SKILLS_REL, n, "SKILL.md");
|
|
43002
43169
|
}
|
|
43003
43170
|
async function readAgent(root, kind, name) {
|
|
43004
43171
|
const content = await readText2(itemPath(root, kind, name));
|
|
43005
43172
|
if (kind !== "subagent") return { content };
|
|
43006
43173
|
const n = safeName(name);
|
|
43007
43174
|
const [short, long] = await Promise.all([
|
|
43008
|
-
readText2(
|
|
43009
|
-
readText2(
|
|
43175
|
+
readText2(join25(root, AGENTS_REL, "short-memory", `${n}.md`)),
|
|
43176
|
+
readText2(join25(root, AGENTS_REL, "long-memory", `${n}.md`))
|
|
43010
43177
|
]);
|
|
43011
43178
|
return { content, memory: { short, long } };
|
|
43012
43179
|
}
|
|
@@ -43016,12 +43183,12 @@ async function writeAgent(root, req) {
|
|
|
43016
43183
|
try {
|
|
43017
43184
|
if (req.action === "delete") {
|
|
43018
43185
|
if (req.kind === "subagent") await rm5(itemPath(root, "subagent", n), { force: true });
|
|
43019
|
-
else await rm5(
|
|
43186
|
+
else await rm5(join25(root, SKILLS_REL, n), { recursive: true, force: true });
|
|
43020
43187
|
return { ok: true };
|
|
43021
43188
|
}
|
|
43022
43189
|
if (req.content === void 0) return { ok: false, error: "content is required" };
|
|
43023
43190
|
const path = itemPath(root, req.kind, n);
|
|
43024
|
-
await mkdir8(
|
|
43191
|
+
await mkdir8(join25(path, ".."), { recursive: true });
|
|
43025
43192
|
await writeFile8(path, req.content, "utf8");
|
|
43026
43193
|
return { ok: true };
|
|
43027
43194
|
} catch (err) {
|
|
@@ -43031,7 +43198,7 @@ async function writeAgent(root, req) {
|
|
|
43031
43198
|
|
|
43032
43199
|
// src/core/secrets.ts
|
|
43033
43200
|
import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
43034
|
-
import { join as
|
|
43201
|
+
import { join as join26 } from "path";
|
|
43035
43202
|
var SECURITY_REL = "AI_SECURITY.md";
|
|
43036
43203
|
var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
|
|
43037
43204
|
var SECRETS_REL = "project.secrets.json";
|
|
@@ -43044,7 +43211,7 @@ async function readText3(path, fallback = "") {
|
|
|
43044
43211
|
}
|
|
43045
43212
|
async function readSecretsObject(root) {
|
|
43046
43213
|
try {
|
|
43047
|
-
const v2 = JSON.parse(await readFile11(
|
|
43214
|
+
const v2 = JSON.parse(await readFile11(join26(root, SECRETS_REL), "utf8"));
|
|
43048
43215
|
return v2 && typeof v2 === "object" ? v2 : {};
|
|
43049
43216
|
} catch {
|
|
43050
43217
|
return {};
|
|
@@ -43063,8 +43230,8 @@ function placeholderKeys(text) {
|
|
|
43063
43230
|
}
|
|
43064
43231
|
async function readSecrets(root) {
|
|
43065
43232
|
const [security, placeholder, secrets] = await Promise.all([
|
|
43066
|
-
readText3(
|
|
43067
|
-
readText3(
|
|
43233
|
+
readText3(join26(root, SECURITY_REL)),
|
|
43234
|
+
readText3(join26(root, PLACEHOLDER_REL)),
|
|
43068
43235
|
readSecretsObject(root)
|
|
43069
43236
|
]);
|
|
43070
43237
|
const names = /* @__PURE__ */ new Set([...placeholderKeys(placeholder), ...Object.keys(secrets)]);
|
|
@@ -43077,14 +43244,14 @@ async function readSecrets(root) {
|
|
|
43077
43244
|
async function writeSecrets(root, req) {
|
|
43078
43245
|
try {
|
|
43079
43246
|
if (req.kind === "security") {
|
|
43080
|
-
await writeFile9(
|
|
43247
|
+
await writeFile9(join26(root, SECURITY_REL), req.content, "utf8");
|
|
43081
43248
|
} else if (req.kind === "placeholder") {
|
|
43082
|
-
await writeFile9(
|
|
43249
|
+
await writeFile9(join26(root, PLACEHOLDER_REL), req.content, "utf8");
|
|
43083
43250
|
} else {
|
|
43084
43251
|
const secrets = await readSecretsObject(root);
|
|
43085
43252
|
if (req.kind === "secret") secrets[req.key] = req.value;
|
|
43086
43253
|
else delete secrets[req.key];
|
|
43087
|
-
await writeFile9(
|
|
43254
|
+
await writeFile9(join26(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
|
|
43088
43255
|
}
|
|
43089
43256
|
return { ok: true };
|
|
43090
43257
|
} catch (err) {
|
|
@@ -43094,12 +43261,12 @@ async function writeSecrets(root, req) {
|
|
|
43094
43261
|
|
|
43095
43262
|
// src/core/agent-tools.ts
|
|
43096
43263
|
import { readFile as readFile12, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
|
|
43097
|
-
import { dirname as dirname8, join as
|
|
43264
|
+
import { dirname as dirname8, join as join27 } from "path";
|
|
43098
43265
|
var SHARED_REL = ".claude/settings.json";
|
|
43099
43266
|
var LOCAL_REL = ".claude/settings.local.json";
|
|
43100
43267
|
var SECRETS_DENY = "Read(./project.secrets.json)";
|
|
43101
43268
|
function fileFor(root, scope) {
|
|
43102
|
-
return
|
|
43269
|
+
return join27(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
|
|
43103
43270
|
}
|
|
43104
43271
|
async function readSettingsObject(path) {
|
|
43105
43272
|
try {
|
|
@@ -43136,7 +43303,7 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
43136
43303
|
// src/core/packages.ts
|
|
43137
43304
|
import { createHash as createHash4 } from "crypto";
|
|
43138
43305
|
import { readFile as readFile13, writeFile as writeFile11, mkdir as mkdir10, readdir as readdir5, rm as rm6, stat as stat4 } from "fs/promises";
|
|
43139
|
-
import { dirname as dirname9, join as
|
|
43306
|
+
import { dirname as dirname9, join as join28, relative } from "path";
|
|
43140
43307
|
var AGENTS_REL2 = ".claude/agents";
|
|
43141
43308
|
var SKILLS_REL2 = ".claude/skills";
|
|
43142
43309
|
var MANIFEST_REL = ".claude/.4pm-packages.json";
|
|
@@ -43160,7 +43327,7 @@ async function listFilesRel(dir2) {
|
|
|
43160
43327
|
return;
|
|
43161
43328
|
}
|
|
43162
43329
|
for (const e of entries2) {
|
|
43163
|
-
const full =
|
|
43330
|
+
const full = join28(d, e.name);
|
|
43164
43331
|
if (e.isDirectory()) await walk2(full);
|
|
43165
43332
|
else if (e.isFile()) out.push(relative(dir2, full));
|
|
43166
43333
|
}
|
|
@@ -43171,16 +43338,16 @@ async function listFilesRel(dir2) {
|
|
|
43171
43338
|
async function readArtifactFiles(root, kind, slug) {
|
|
43172
43339
|
const files = [];
|
|
43173
43340
|
if (kind === "subagent") {
|
|
43174
|
-
const agent = await readMaybe(
|
|
43341
|
+
const agent = await readMaybe(join28(root, AGENTS_REL2, `${slug}.md`));
|
|
43175
43342
|
if (agent) files.push({ path: "agent.md", contentBase64: agent.toString("base64") });
|
|
43176
|
-
const short = await readMaybe(
|
|
43343
|
+
const short = await readMaybe(join28(root, AGENTS_REL2, "short-memory", `${slug}.md`));
|
|
43177
43344
|
if (short) files.push({ path: "short-memory.md", contentBase64: short.toString("base64") });
|
|
43178
|
-
const long = await readMaybe(
|
|
43345
|
+
const long = await readMaybe(join28(root, AGENTS_REL2, "long-memory", `${slug}.md`));
|
|
43179
43346
|
if (long) files.push({ path: "long-memory.md", contentBase64: long.toString("base64") });
|
|
43180
43347
|
} else {
|
|
43181
|
-
const base =
|
|
43348
|
+
const base = join28(root, SKILLS_REL2, slug);
|
|
43182
43349
|
for (const rel of await listFilesRel(base)) {
|
|
43183
|
-
const buf = await readMaybe(
|
|
43350
|
+
const buf = await readMaybe(join28(base, rel));
|
|
43184
43351
|
if (buf) files.push({ path: rel.split("\\").join("/"), contentBase64: buf.toString("base64") });
|
|
43185
43352
|
}
|
|
43186
43353
|
}
|
|
@@ -43198,7 +43365,7 @@ async function artifactSha256(root, kind, slug) {
|
|
|
43198
43365
|
return h.digest("hex");
|
|
43199
43366
|
}
|
|
43200
43367
|
async function artifactExists(root, kind, slug) {
|
|
43201
|
-
const target = kind === "subagent" ?
|
|
43368
|
+
const target = kind === "subagent" ? join28(root, AGENTS_REL2, `${slug}.md`) : join28(root, SKILLS_REL2, slug);
|
|
43202
43369
|
try {
|
|
43203
43370
|
await stat4(target);
|
|
43204
43371
|
return true;
|
|
@@ -43207,7 +43374,7 @@ async function artifactExists(root, kind, slug) {
|
|
|
43207
43374
|
}
|
|
43208
43375
|
}
|
|
43209
43376
|
async function readManifest(root) {
|
|
43210
|
-
const buf = await readMaybe(
|
|
43377
|
+
const buf = await readMaybe(join28(root, MANIFEST_REL));
|
|
43211
43378
|
if (!buf) return {};
|
|
43212
43379
|
try {
|
|
43213
43380
|
return JSON.parse(buf.toString("utf8"));
|
|
@@ -43216,7 +43383,7 @@ async function readManifest(root) {
|
|
|
43216
43383
|
}
|
|
43217
43384
|
}
|
|
43218
43385
|
async function writeManifest(root, manifest) {
|
|
43219
|
-
const path =
|
|
43386
|
+
const path = join28(root, MANIFEST_REL);
|
|
43220
43387
|
await mkdir10(dirname9(path), { recursive: true });
|
|
43221
43388
|
await writeFile11(path, JSON.stringify(manifest, null, 2), "utf8");
|
|
43222
43389
|
}
|
|
@@ -43225,24 +43392,24 @@ async function writeArtifactFiles(root, kind, slug, files) {
|
|
|
43225
43392
|
if (kind === "subagent") {
|
|
43226
43393
|
const agent = byPath.get("agent.md");
|
|
43227
43394
|
if (agent) {
|
|
43228
|
-
await mkdir10(
|
|
43229
|
-
await writeFile11(
|
|
43395
|
+
await mkdir10(join28(root, AGENTS_REL2), { recursive: true });
|
|
43396
|
+
await writeFile11(join28(root, AGENTS_REL2, `${slug}.md`), agent);
|
|
43230
43397
|
}
|
|
43231
43398
|
const short = byPath.get("short-memory.md");
|
|
43232
43399
|
if (short) {
|
|
43233
|
-
await mkdir10(
|
|
43234
|
-
await writeFile11(
|
|
43400
|
+
await mkdir10(join28(root, AGENTS_REL2, "short-memory"), { recursive: true });
|
|
43401
|
+
await writeFile11(join28(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
|
|
43235
43402
|
}
|
|
43236
43403
|
const long = byPath.get("long-memory.md");
|
|
43237
43404
|
if (long) {
|
|
43238
|
-
await mkdir10(
|
|
43239
|
-
await writeFile11(
|
|
43405
|
+
await mkdir10(join28(root, AGENTS_REL2, "long-memory"), { recursive: true });
|
|
43406
|
+
await writeFile11(join28(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
|
|
43240
43407
|
}
|
|
43241
43408
|
} else {
|
|
43242
|
-
const base =
|
|
43409
|
+
const base = join28(root, SKILLS_REL2, slug);
|
|
43243
43410
|
for (const [rel, buf] of byPath) {
|
|
43244
43411
|
if (rel.includes("..") || rel.startsWith("/")) continue;
|
|
43245
|
-
const dest =
|
|
43412
|
+
const dest = join28(base, rel);
|
|
43246
43413
|
await mkdir10(dirname9(dest), { recursive: true });
|
|
43247
43414
|
await writeFile11(dest, buf);
|
|
43248
43415
|
}
|
|
@@ -43308,11 +43475,11 @@ async function removePackage(root, slug) {
|
|
|
43308
43475
|
const entry = manifest[n];
|
|
43309
43476
|
if (!entry) return { ok: false, error: "not installed" };
|
|
43310
43477
|
if (entry.kind === "subagent") {
|
|
43311
|
-
await rm6(
|
|
43312
|
-
await rm6(
|
|
43313
|
-
await rm6(
|
|
43478
|
+
await rm6(join28(root, AGENTS_REL2, `${n}.md`), { force: true });
|
|
43479
|
+
await rm6(join28(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
|
|
43480
|
+
await rm6(join28(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
|
|
43314
43481
|
} else {
|
|
43315
|
-
await rm6(
|
|
43482
|
+
await rm6(join28(root, SKILLS_REL2, n), { recursive: true, force: true });
|
|
43316
43483
|
}
|
|
43317
43484
|
delete manifest[n];
|
|
43318
43485
|
await writeManifest(root, manifest);
|
|
@@ -43324,7 +43491,7 @@ async function removePackage(root, slug) {
|
|
|
43324
43491
|
|
|
43325
43492
|
// src/core/graph.ts
|
|
43326
43493
|
import { readFile as readFile14, readdir as readdir6 } from "fs/promises";
|
|
43327
|
-
import { join as
|
|
43494
|
+
import { join as join29, relative as relative2, dirname as dirname10, resolve as resolve9, extname as extname2, basename as basename6 } from "path";
|
|
43328
43495
|
var MAX_FILES = 2e3;
|
|
43329
43496
|
var MAX_NODES = 3e3;
|
|
43330
43497
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
|
|
@@ -43344,7 +43511,7 @@ async function walk(root, accept) {
|
|
|
43344
43511
|
if (e.name.startsWith(".") && e.name !== ".claude") {
|
|
43345
43512
|
if (e.isDirectory()) continue;
|
|
43346
43513
|
}
|
|
43347
|
-
const full =
|
|
43514
|
+
const full = join29(dir2, e.name);
|
|
43348
43515
|
if (e.isDirectory()) {
|
|
43349
43516
|
if (!SKIP_DIRS.has(e.name)) stack.push(full);
|
|
43350
43517
|
} else if (accept(full)) {
|
|
@@ -43464,12 +43631,12 @@ async function buildGraph(root, mode) {
|
|
|
43464
43631
|
|
|
43465
43632
|
// src/core/rag.ts
|
|
43466
43633
|
import { readFile as readFile15, writeFile as writeFile12, statfs as statfs2, mkdir as mkdir11 } from "fs/promises";
|
|
43467
|
-
import { existsSync as
|
|
43468
|
-
import { execFile as
|
|
43634
|
+
import { existsSync as existsSync15 } from "fs";
|
|
43635
|
+
import { execFile as execFile11, spawn as spawn10 } from "child_process";
|
|
43469
43636
|
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
43470
|
-
import { join as
|
|
43471
|
-
import { promisify as
|
|
43472
|
-
var run10 =
|
|
43637
|
+
import { join as join30 } from "path";
|
|
43638
|
+
import { promisify as promisify11 } from "util";
|
|
43639
|
+
var run10 = promisify11(execFile11);
|
|
43473
43640
|
var RAG_REL = ".claude/rag";
|
|
43474
43641
|
async function tryRun(cmd, args) {
|
|
43475
43642
|
try {
|
|
@@ -43488,7 +43655,7 @@ async function detectPython() {
|
|
|
43488
43655
|
}
|
|
43489
43656
|
async function installLog(root) {
|
|
43490
43657
|
try {
|
|
43491
|
-
const text = await readFile15(
|
|
43658
|
+
const text = await readFile15(join30(root, RAG_REL, "install.log"), "utf8");
|
|
43492
43659
|
return text.split("\n").filter((l) => l.length > 0).slice(-200);
|
|
43493
43660
|
} catch {
|
|
43494
43661
|
return [];
|
|
@@ -43550,14 +43717,14 @@ async function ragStatus(root) {
|
|
|
43550
43717
|
};
|
|
43551
43718
|
let modelName = "";
|
|
43552
43719
|
try {
|
|
43553
|
-
modelName = (await readFile15(
|
|
43720
|
+
modelName = (await readFile15(join30(root, RAG_REL, ".installed"), "utf8")).trim();
|
|
43554
43721
|
} catch {
|
|
43555
43722
|
modelName = "";
|
|
43556
43723
|
}
|
|
43557
43724
|
const modelPresent = modelName.length > 0;
|
|
43558
43725
|
return {
|
|
43559
43726
|
installed: fastembed && sqliteVec && modelPresent,
|
|
43560
|
-
installing:
|
|
43727
|
+
installing: existsSync15(join30(root, RAG_REL, ".installing")),
|
|
43561
43728
|
python: { found: py.found, version: py.version },
|
|
43562
43729
|
deps: { pip, fastembed, sqliteVec },
|
|
43563
43730
|
model: { present: modelPresent, name: modelName },
|
|
@@ -43568,9 +43735,9 @@ async function ragStatus(root) {
|
|
|
43568
43735
|
};
|
|
43569
43736
|
}
|
|
43570
43737
|
async function readIndexMeta(root) {
|
|
43571
|
-
const indexing =
|
|
43738
|
+
const indexing = existsSync15(join30(root, RAG_REL, ".indexing"));
|
|
43572
43739
|
try {
|
|
43573
|
-
const m2 = JSON.parse(await readFile15(
|
|
43740
|
+
const m2 = JSON.parse(await readFile15(join30(root, RAG_REL, ".index.json"), "utf8"));
|
|
43574
43741
|
return {
|
|
43575
43742
|
present: true,
|
|
43576
43743
|
indexing,
|
|
@@ -43637,14 +43804,14 @@ if __name__ == "__main__":
|
|
|
43637
43804
|
elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
|
|
43638
43805
|
`;
|
|
43639
43806
|
async function ensureEngine(root) {
|
|
43640
|
-
await mkdir11(
|
|
43641
|
-
await writeFile12(
|
|
43807
|
+
await mkdir11(join30(root, RAG_REL), { recursive: true }).catch(() => void 0);
|
|
43808
|
+
await writeFile12(join30(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
|
|
43642
43809
|
}
|
|
43643
43810
|
async function ragReindex(root) {
|
|
43644
43811
|
const py = await detectPython();
|
|
43645
43812
|
if (!py.found) return { ok: false, started: false, error: "python3 not found" };
|
|
43646
|
-
if (!
|
|
43647
|
-
if (
|
|
43813
|
+
if (!existsSync15(join30(root, RAG_REL, ".installed"))) return { ok: false, started: false, error: "RAG is not installed" };
|
|
43814
|
+
if (existsSync15(join30(root, RAG_REL, ".indexing"))) return { ok: true, started: true };
|
|
43648
43815
|
await ensureEngine(root);
|
|
43649
43816
|
const script = `
|
|
43650
43817
|
set +e
|
|
@@ -43652,7 +43819,7 @@ touch "${RAG_REL}/.indexing"
|
|
|
43652
43819
|
{ echo "[reindex] $(date)"; "$RAG_PY" "${RAG_REL}/rag_engine.py" reindex 2>&1; } >> "${RAG_REL}/index.log" 2>&1
|
|
43653
43820
|
rm -f "${RAG_REL}/.indexing"
|
|
43654
43821
|
`;
|
|
43655
|
-
const child =
|
|
43822
|
+
const child = spawn10("bash", ["-c", script], {
|
|
43656
43823
|
cwd: root,
|
|
43657
43824
|
env: { ...process.env, RAG_PY: py.bin },
|
|
43658
43825
|
detached: true,
|
|
@@ -43664,12 +43831,12 @@ rm -f "${RAG_REL}/.indexing"
|
|
|
43664
43831
|
async function ragQuery(root, queryText, k2 = 8) {
|
|
43665
43832
|
const py = await detectPython();
|
|
43666
43833
|
if (!py.found) return { results: [], error: "python3 not found" };
|
|
43667
|
-
if (!
|
|
43834
|
+
if (!existsSync15(join30(root, RAG_REL, "index.db"))) return { results: [], error: "no index \u2014 reindex first" };
|
|
43668
43835
|
await ensureEngine(root);
|
|
43669
43836
|
try {
|
|
43670
43837
|
const { stdout } = await run10(
|
|
43671
43838
|
py.bin,
|
|
43672
|
-
[
|
|
43839
|
+
[join30(RAG_REL, "rag_engine.py"), "query", queryText, String(Math.min(Math.max(k2, 1), 20))],
|
|
43673
43840
|
{ cwd: root, timeout: 3e4, maxBuffer: 4 * 1024 * 1024 }
|
|
43674
43841
|
);
|
|
43675
43842
|
const parsed = JSON.parse(stdout.trim() || '{"results":[]}');
|
|
@@ -43684,9 +43851,9 @@ async function ragInstall(root, model) {
|
|
|
43684
43851
|
}
|
|
43685
43852
|
const py = await detectPython();
|
|
43686
43853
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
43687
|
-
if (
|
|
43854
|
+
if (existsSync15(join30(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
43688
43855
|
try {
|
|
43689
|
-
await mkdir11(
|
|
43856
|
+
await mkdir11(join30(root, RAG_REL), { recursive: true });
|
|
43690
43857
|
} catch {
|
|
43691
43858
|
}
|
|
43692
43859
|
const script = `
|
|
@@ -43702,7 +43869,7 @@ rm -f "${RAG_REL}/.installed"
|
|
|
43702
43869
|
} >> "${RAG_REL}/install.log" 2>&1
|
|
43703
43870
|
rm -f "${RAG_REL}/.installing"
|
|
43704
43871
|
`;
|
|
43705
|
-
const child =
|
|
43872
|
+
const child = spawn10("bash", ["-c", script], {
|
|
43706
43873
|
cwd: root,
|
|
43707
43874
|
env: { ...process.env, RAG_PY: py.bin, RAG_MODEL: model },
|
|
43708
43875
|
detached: true,
|
|
@@ -43713,8 +43880,8 @@ rm -f "${RAG_REL}/.installing"
|
|
|
43713
43880
|
}
|
|
43714
43881
|
|
|
43715
43882
|
// src/core/config-sync.ts
|
|
43716
|
-
import { existsSync as
|
|
43717
|
-
import { join as
|
|
43883
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
|
|
43884
|
+
import { join as join31 } from "path";
|
|
43718
43885
|
var SERVER_MANAGED_KEYS = [
|
|
43719
43886
|
"physicPath",
|
|
43720
43887
|
"sessionSwitchPct",
|
|
@@ -43731,8 +43898,8 @@ var SERVER_MANAGED_KEYS = [
|
|
|
43731
43898
|
"projectAiMemoryBudgetChars"
|
|
43732
43899
|
];
|
|
43733
43900
|
function readConfigText(profileDir2) {
|
|
43734
|
-
const path =
|
|
43735
|
-
if (
|
|
43901
|
+
const path = join31(profileDir2, "config.json");
|
|
43902
|
+
if (existsSync16(path)) {
|
|
43736
43903
|
try {
|
|
43737
43904
|
return readFileSync16(path, "utf8");
|
|
43738
43905
|
} catch {
|
|
@@ -44521,7 +44688,7 @@ var WsClient = class {
|
|
|
44521
44688
|
}
|
|
44522
44689
|
const { payload, nonce } = encryptPayload(this.sessionKey, data);
|
|
44523
44690
|
const envelope = {
|
|
44524
|
-
id:
|
|
44691
|
+
id: randomUUID4(),
|
|
44525
44692
|
replyTo,
|
|
44526
44693
|
channel,
|
|
44527
44694
|
wsToken: this.wsToken,
|
|
@@ -44542,7 +44709,7 @@ var WsClient = class {
|
|
|
44542
44709
|
}
|
|
44543
44710
|
const { payload, nonce } = encryptPayload(this.sessionKey, data);
|
|
44544
44711
|
const envelope = {
|
|
44545
|
-
id:
|
|
44712
|
+
id: randomUUID4(),
|
|
44546
44713
|
replyTo: null,
|
|
44547
44714
|
channel,
|
|
44548
44715
|
wsToken: this.wsToken,
|
|
@@ -44609,8 +44776,8 @@ var WsClient = class {
|
|
|
44609
44776
|
/** Create the physic folder at an absolute path if missing (best-effort). */
|
|
44610
44777
|
ensurePhysicFolderPath(folder) {
|
|
44611
44778
|
try {
|
|
44612
|
-
if (!
|
|
44613
|
-
|
|
44779
|
+
if (!existsSync17(folder)) {
|
|
44780
|
+
mkdirSync8(folder, { recursive: true });
|
|
44614
44781
|
this.bus.log(t("project.createdFolder", { folder }));
|
|
44615
44782
|
}
|
|
44616
44783
|
} catch (err) {
|
|
@@ -44624,7 +44791,7 @@ var WsClient = class {
|
|
|
44624
44791
|
*/
|
|
44625
44792
|
physicFolderPath(projectName) {
|
|
44626
44793
|
const safe = projectName.replace(/[/\\]/g, "_").replace(/\.\./g, "_").trim();
|
|
44627
|
-
return safe ?
|
|
44794
|
+
return safe ? join32(this.context.profileDir, safe) : null;
|
|
44628
44795
|
}
|
|
44629
44796
|
/**
|
|
44630
44797
|
* Report machine.status: version + the state of the physic project being served
|
|
@@ -44639,7 +44806,7 @@ var WsClient = class {
|
|
|
44639
44806
|
projects: [],
|
|
44640
44807
|
version: CLI_VERSION,
|
|
44641
44808
|
physicPath,
|
|
44642
|
-
physicPathExists: physicPath ?
|
|
44809
|
+
physicPathExists: physicPath ? existsSync17(physicPath) : void 0,
|
|
44643
44810
|
// Real coarse state (ADR-0152): !paused and a recent tick (was hard-coded false).
|
|
44644
44811
|
autonomousRunning: physicPath ? isAutonomousRunning(physicPath, this.context.profileDir) : false,
|
|
44645
44812
|
// The machine-user AI-run limit (0 = unlimited) + profile count so a dispatch can resolve the
|
|
@@ -44733,7 +44900,7 @@ var WsClient = class {
|
|
|
44733
44900
|
*/
|
|
44734
44901
|
uploadLog() {
|
|
44735
44902
|
try {
|
|
44736
|
-
const upload = readLogUpload(
|
|
44903
|
+
const upload = readLogUpload(join32(this.context.profileDir, "logs"));
|
|
44737
44904
|
if (!upload) return;
|
|
44738
44905
|
const sig = `${upload.fileName}:${upload.totalBytes}`;
|
|
44739
44906
|
if (sig === this.lastLogSig) return;
|
|
@@ -44895,10 +45062,10 @@ var WsClient = class {
|
|
|
44895
45062
|
};
|
|
44896
45063
|
|
|
44897
45064
|
// src/core/instance-lock.ts
|
|
44898
|
-
import { readFileSync as readFileSync17, rmSync as
|
|
44899
|
-
import { join as
|
|
45065
|
+
import { readFileSync as readFileSync17, rmSync as rmSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
45066
|
+
import { join as join33 } from "path";
|
|
44900
45067
|
function lockPath(profileDir2) {
|
|
44901
|
-
return
|
|
45068
|
+
return join33(profileDir2, "start.lock");
|
|
44902
45069
|
}
|
|
44903
45070
|
function isAlive(pid) {
|
|
44904
45071
|
try {
|
|
@@ -44924,14 +45091,14 @@ function acquireInstanceLock(profileDir2) {
|
|
|
44924
45091
|
function releaseInstanceLock(profileDir2) {
|
|
44925
45092
|
try {
|
|
44926
45093
|
const pid = Number.parseInt(readFileSync17(lockPath(profileDir2), "utf8").trim(), 10);
|
|
44927
|
-
if (pid === process.pid)
|
|
45094
|
+
if (pid === process.pid) rmSync8(lockPath(profileDir2), { force: true });
|
|
44928
45095
|
} catch {
|
|
44929
45096
|
}
|
|
44930
45097
|
}
|
|
44931
45098
|
|
|
44932
45099
|
// src/core/session-bus.ts
|
|
44933
45100
|
import { EventEmitter } from "events";
|
|
44934
|
-
import { randomUUID as
|
|
45101
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
44935
45102
|
var REPLAY_CAP = 500;
|
|
44936
45103
|
var SessionBus = class {
|
|
44937
45104
|
emitter = new EventEmitter();
|
|
@@ -44962,7 +45129,7 @@ var SessionBus = class {
|
|
|
44962
45129
|
/** Producer → consumers: push one transcript entry. Returns its id (for `updateEntry`). */
|
|
44963
45130
|
push(input) {
|
|
44964
45131
|
const entry = {
|
|
44965
|
-
id:
|
|
45132
|
+
id: randomUUID5(),
|
|
44966
45133
|
level: "info",
|
|
44967
45134
|
...input,
|
|
44968
45135
|
ts: Date.now()
|
|
@@ -45219,8 +45386,8 @@ var SessionBus = class {
|
|
|
45219
45386
|
|
|
45220
45387
|
// src/core/control-server.ts
|
|
45221
45388
|
import { createServer } from "net";
|
|
45222
|
-
import { chmodSync as chmodSync4, rmSync as
|
|
45223
|
-
import { join as
|
|
45389
|
+
import { chmodSync as chmodSync4, rmSync as rmSync9 } from "fs";
|
|
45390
|
+
import { join as join35 } from "path";
|
|
45224
45391
|
|
|
45225
45392
|
// src/core/control-protocol.ts
|
|
45226
45393
|
var CONTROL_SOCKET_FILE = "control.sock";
|
|
@@ -45251,9 +45418,9 @@ function createFrameParser() {
|
|
|
45251
45418
|
// src/core/control-token.ts
|
|
45252
45419
|
import { chmodSync as chmodSync3, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
|
|
45253
45420
|
import { randomBytes as randomBytes3, timingSafeEqual } from "crypto";
|
|
45254
|
-
import { join as
|
|
45421
|
+
import { join as join34 } from "path";
|
|
45255
45422
|
function controlTokenPath(profileDir2) {
|
|
45256
|
-
return
|
|
45423
|
+
return join34(profileDir2, CONTROL_TOKEN_FILE);
|
|
45257
45424
|
}
|
|
45258
45425
|
function writeControlToken(profileDir2) {
|
|
45259
45426
|
const token = randomBytes3(32).toString("hex");
|
|
@@ -45282,9 +45449,9 @@ function tokenMatches(expected, given) {
|
|
|
45282
45449
|
|
|
45283
45450
|
// src/core/control-server.ts
|
|
45284
45451
|
function startControlServer(bus, profileDir2, info) {
|
|
45285
|
-
const socketPath =
|
|
45452
|
+
const socketPath = join35(profileDir2, CONTROL_SOCKET_FILE);
|
|
45286
45453
|
try {
|
|
45287
|
-
|
|
45454
|
+
rmSync9(socketPath, { force: true });
|
|
45288
45455
|
} catch {
|
|
45289
45456
|
}
|
|
45290
45457
|
const clients = /* @__PURE__ */ new Set();
|
|
@@ -45370,8 +45537,8 @@ function startControlServer(bus, profileDir2, info) {
|
|
|
45370
45537
|
clients.clear();
|
|
45371
45538
|
server.close();
|
|
45372
45539
|
try {
|
|
45373
|
-
|
|
45374
|
-
|
|
45540
|
+
rmSync9(socketPath, { force: true });
|
|
45541
|
+
rmSync9(controlTokenPath(profileDir2), { force: true });
|
|
45375
45542
|
} catch {
|
|
45376
45543
|
}
|
|
45377
45544
|
};
|
|
@@ -51034,15 +51201,15 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
51034
51201
|
var import_react26 = __toESM(require_react(), 1);
|
|
51035
51202
|
|
|
51036
51203
|
// src/core/input-history.ts
|
|
51037
|
-
import { existsSync as
|
|
51038
|
-
import { join as
|
|
51204
|
+
import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
|
|
51205
|
+
import { join as join36 } from "path";
|
|
51039
51206
|
var MAX_HISTORY = 200;
|
|
51040
51207
|
function historyPath(profileDir2) {
|
|
51041
|
-
return
|
|
51208
|
+
return join36(profileDir2, "input-history.json");
|
|
51042
51209
|
}
|
|
51043
51210
|
function loadInputHistory(profileDir2) {
|
|
51044
51211
|
const path = historyPath(profileDir2);
|
|
51045
|
-
if (!
|
|
51212
|
+
if (!existsSync19(path)) return [];
|
|
51046
51213
|
try {
|
|
51047
51214
|
const data = JSON.parse(readFileSync20(path, "utf8"));
|
|
51048
51215
|
return Array.isArray(data) ? data.filter((x) => typeof x === "string") : [];
|
|
@@ -51652,7 +51819,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
51652
51819
|
return;
|
|
51653
51820
|
}
|
|
51654
51821
|
logger.configure({
|
|
51655
|
-
dir:
|
|
51822
|
+
dir: join37(profileDir2, "logs"),
|
|
51656
51823
|
level: resolveLogLevel(),
|
|
51657
51824
|
base: { version: CLI_VERSION, profile: profileName, scope: credential.scope }
|
|
51658
51825
|
});
|
|
@@ -51672,7 +51839,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
51672
51839
|
if (result.action === "updated") {
|
|
51673
51840
|
logger.info("update.updated", { version: result.version });
|
|
51674
51841
|
console.log(t("start.restarting"));
|
|
51675
|
-
const child =
|
|
51842
|
+
const child = spawn11(process.execPath, process.argv.slice(1), {
|
|
51676
51843
|
stdio: "inherit",
|
|
51677
51844
|
env: { ...process.env, FOURPM_NO_UPDATE: "1" }
|
|
51678
51845
|
});
|
|
@@ -51761,7 +51928,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
51761
51928
|
}
|
|
51762
51929
|
|
|
51763
51930
|
// src/commands/attach.ts
|
|
51764
|
-
import { join as
|
|
51931
|
+
import { join as join38 } from "path";
|
|
51765
51932
|
|
|
51766
51933
|
// src/core/control-client.ts
|
|
51767
51934
|
import { connect as connect2 } from "net";
|
|
@@ -51870,7 +52037,7 @@ async function runAttach(profileDir2, profileName) {
|
|
|
51870
52037
|
process.exitCode = 1;
|
|
51871
52038
|
return;
|
|
51872
52039
|
}
|
|
51873
|
-
const socketPath =
|
|
52040
|
+
const socketPath = join38(profileDir2, CONTROL_SOCKET_FILE);
|
|
51874
52041
|
const bus = new SessionBus();
|
|
51875
52042
|
let conn;
|
|
51876
52043
|
try {
|
|
@@ -51901,11 +52068,11 @@ async function runAttach(profileDir2, profileName) {
|
|
|
51901
52068
|
|
|
51902
52069
|
// src/commands/auto-run.ts
|
|
51903
52070
|
import { connect as connect3 } from "net";
|
|
51904
|
-
import { join as
|
|
52071
|
+
import { join as join39 } from "path";
|
|
51905
52072
|
var AUTO_RUN_TIMEOUT_MS = 3 * 60 * 60 * 1e3;
|
|
51906
52073
|
async function runAutoRun(profileDir2, profileName) {
|
|
51907
52074
|
initI18n(readProfileConfig(profileDir2).locale);
|
|
51908
|
-
const socketPath =
|
|
52075
|
+
const socketPath = join39(profileDir2, CONTROL_SOCKET_FILE);
|
|
51909
52076
|
const token = readControlToken(profileDir2);
|
|
51910
52077
|
const code = await new Promise((resolve10) => {
|
|
51911
52078
|
let settled = false;
|
|
@@ -51961,12 +52128,12 @@ async function runAutoRun(profileDir2, profileName) {
|
|
|
51961
52128
|
}
|
|
51962
52129
|
|
|
51963
52130
|
// src/commands/ai-login.ts
|
|
51964
|
-
import { spawn as
|
|
51965
|
-
import { mkdirSync as
|
|
52131
|
+
import { spawn as spawn12 } from "child_process";
|
|
52132
|
+
import { mkdirSync as mkdirSync9 } from "fs";
|
|
51966
52133
|
import { basename as basename8 } from "path";
|
|
51967
52134
|
function runProviderLogin(cmd, envVar, dir2) {
|
|
51968
52135
|
return new Promise((resolve10) => {
|
|
51969
|
-
const child =
|
|
52136
|
+
const child = spawn12(cmd, [], {
|
|
51970
52137
|
stdio: "inherit",
|
|
51971
52138
|
env: { ...process.env, [envVar]: dir2 }
|
|
51972
52139
|
});
|
|
@@ -51999,7 +52166,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
|
51999
52166
|
continue;
|
|
52000
52167
|
}
|
|
52001
52168
|
const dir2 = resolveHomePath(cred.profile);
|
|
52002
|
-
|
|
52169
|
+
mkdirSync9(dir2, { recursive: true });
|
|
52003
52170
|
console.log(t("aiLogin.loggingIn", { provider: cred.provider, profile: cred.profile, envVar, dir: dir2 }));
|
|
52004
52171
|
console.log(t("aiLogin.completeSignIn"));
|
|
52005
52172
|
const code = await runProviderLogin(cred.provider, envVar, dir2);
|
|
@@ -52011,7 +52178,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
|
52011
52178
|
}
|
|
52012
52179
|
|
|
52013
52180
|
// src/commands/unlink.ts
|
|
52014
|
-
import { rmSync as
|
|
52181
|
+
import { rmSync as rmSync10 } from "fs";
|
|
52015
52182
|
async function runUnlink(profileDir2, profileName) {
|
|
52016
52183
|
initI18n(readProfileConfig(profileDir2).locale);
|
|
52017
52184
|
const cred = readCredential(profileDir2, profileName);
|
|
@@ -52025,7 +52192,7 @@ async function runUnlink(profileDir2, profileName) {
|
|
|
52025
52192
|
} catch (err) {
|
|
52026
52193
|
console.log(t("unlink.revokeFailed", { message: err.message }));
|
|
52027
52194
|
}
|
|
52028
|
-
|
|
52195
|
+
rmSync10(profileDir2, { recursive: true, force: true });
|
|
52029
52196
|
clearDefaultProfileIf(profileName);
|
|
52030
52197
|
console.log(t("unlink.deleted"));
|
|
52031
52198
|
}
|