@4pm/cli 1.5.17 → 1.5.25
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 +384 -170
- package/dist/project-sample/.claude/commands/auto-cycle.md +4 -4
- package/dist/project-sample/.claude/templates/AI_DONE.empty.md +11 -3
- package/dist/project-sample/.claude/templates/AI_DONE.sample.md +8 -2
- package/dist/project-sample/AI_DONE.md +11 -3
- package/package.json +1 -1
- package/dist/project-sample/.4pm +0 -0
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(resolve9, 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, resolve9, reject);
|
|
5722
5722
|
} else {
|
|
5723
|
-
|
|
5723
|
+
resolve9(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(resolve9, reject) {
|
|
5754
5754
|
if (ReactCurrentActQueue.current === null) {
|
|
5755
5755
|
ReactCurrentActQueue.current = [];
|
|
5756
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
5756
|
+
recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
|
|
5757
5757
|
} else {
|
|
5758
|
-
|
|
5758
|
+
resolve9(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(resolve9, reject) {
|
|
5766
|
+
resolve9(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, resolve9, 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
|
+
resolve9(returnValue);
|
|
5792
5792
|
} else {
|
|
5793
|
-
recursivelyFlushAsyncActWork(returnValue,
|
|
5793
|
+
recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
|
|
5794
5794
|
}
|
|
5795
5795
|
});
|
|
5796
5796
|
} catch (error2) {
|
|
5797
5797
|
reject(error2);
|
|
5798
5798
|
}
|
|
5799
5799
|
} else {
|
|
5800
|
-
|
|
5800
|
+
resolve9(returnValue);
|
|
5801
5801
|
}
|
|
5802
5802
|
}
|
|
5803
5803
|
}
|
|
@@ -28775,7 +28775,7 @@ async function checkAndUpdate(serverUrl, autoUpdate) {
|
|
|
28775
28775
|
// src/core/ws-client.ts
|
|
28776
28776
|
init_wrapper();
|
|
28777
28777
|
import { randomUUID } from "crypto";
|
|
28778
|
-
import { basename as
|
|
28778
|
+
import { basename as basename5, join as join26 } from "path";
|
|
28779
28779
|
|
|
28780
28780
|
// vendor/@4pm/utils/helpers.ts
|
|
28781
28781
|
function backoffJitterMs(attempt, baseMs = 500, maxMs = 1e4) {
|
|
@@ -28807,6 +28807,24 @@ function prettyResult(text) {
|
|
|
28807
28807
|
return trimmed;
|
|
28808
28808
|
}
|
|
28809
28809
|
|
|
28810
|
+
// vendor/@4pm/constants/project-template.ts
|
|
28811
|
+
var PROJECT_TEMPLATE = {
|
|
28812
|
+
version: "1.0.0",
|
|
28813
|
+
changelog: [
|
|
28814
|
+
{
|
|
28815
|
+
version: "1.0.0",
|
|
28816
|
+
date: "2026-09-12",
|
|
28817
|
+
summary: "Baseline scaffold template with version tracking.",
|
|
28818
|
+
notes: [
|
|
28819
|
+
"Initial CLAUDE.md, .claude config (settings, hooks, skills, agents, autonomous).",
|
|
28820
|
+
"Standard docs/tests/reports/src layout and placeholder files.",
|
|
28821
|
+
"Introduces .4pm/.4pm.json template-version tracking."
|
|
28822
|
+
],
|
|
28823
|
+
files: []
|
|
28824
|
+
}
|
|
28825
|
+
]
|
|
28826
|
+
};
|
|
28827
|
+
|
|
28810
28828
|
// vendor/@4pm/constants/quota.ts
|
|
28811
28829
|
var UsageMetric = {
|
|
28812
28830
|
AI_TOKENS: "ai_tokens",
|
|
@@ -32939,6 +32957,14 @@ var commandImageRefSchema = external_exports.object({
|
|
|
32939
32957
|
name: external_exports.string().max(255),
|
|
32940
32958
|
mime: external_exports.enum(COMMAND_IMAGE_MIME_TYPES)
|
|
32941
32959
|
});
|
|
32960
|
+
var aiRunConfigSchema = external_exports.object({
|
|
32961
|
+
/** `--model` override for this run (must match the resolved provider's model id). */
|
|
32962
|
+
model: external_exports.string().trim().max(120).optional(),
|
|
32963
|
+
/** Coarse reasoning-budget level, mapped to the provider's own mechanism. */
|
|
32964
|
+
thinking: external_exports.enum(["off", "low", "medium", "high"]).optional(),
|
|
32965
|
+
/** Sampling temperature 0..1 (best-effort per provider). */
|
|
32966
|
+
temperature: external_exports.number().min(0).max(1).optional()
|
|
32967
|
+
});
|
|
32942
32968
|
var dispatchCommandRequestSchema = external_exports.object({
|
|
32943
32969
|
projectId: external_exports.string().uuid(),
|
|
32944
32970
|
// Target cli. Required unless `pick` is set — with `pick:"idle"` the server chooses the
|
|
@@ -32986,7 +33012,22 @@ var dispatchCommandRequestSchema = external_exports.object({
|
|
|
32986
33012
|
* the repo / edit files / loop forever. Only meaningful with `ai:true`; absent ⇒ a full
|
|
32987
33013
|
* agent run (the Console tab + Git merge, which legitimately use tools).
|
|
32988
33014
|
*/
|
|
32989
|
-
aiOneShot: external_exports.boolean().optional()
|
|
33015
|
+
aiOneShot: external_exports.boolean().optional(),
|
|
33016
|
+
/**
|
|
33017
|
+
* Read-only agent AI mode (ADR-0265): the prompt is a task that must **read + inspect the repo
|
|
33018
|
+
* but write nothing** (the project-template "Analyze impact"). Unlike `aiOneShot` it keeps the
|
|
33019
|
+
* read/search tools (`Read`/`Glob`/`Grep`/`Bash`) and runs multi-turn, but the cli blocks the
|
|
33020
|
+
* write/orchestration tools and runs claude under `--permission-mode plan` (codex `--sandbox
|
|
33021
|
+
* read-only`) so it can diff files without editing them. Only meaningful with `ai:true`;
|
|
33022
|
+
* **mutually exclusive with `aiOneShot`** (a run is one-shot | read-only | full-agent).
|
|
33023
|
+
*/
|
|
33024
|
+
aiReadOnly: external_exports.boolean().optional(),
|
|
33025
|
+
/**
|
|
33026
|
+
* Per-run AI execution overrides (ADR-0261): model/thinking/temperature chosen in the web
|
|
33027
|
+
* "AI settings" modal (per-user localStorage), layered over the profile default by the cli.
|
|
33028
|
+
* Only meaningful with `ai:true`.
|
|
33029
|
+
*/
|
|
33030
|
+
aiConfig: aiRunConfigSchema.optional()
|
|
32990
33031
|
}).superRefine((v, ctx) => {
|
|
32991
33032
|
if (v.machineLinkId == null === (v.pick == null)) {
|
|
32992
33033
|
ctx.addIssue({
|
|
@@ -32995,6 +33036,13 @@ var dispatchCommandRequestSchema = external_exports.object({
|
|
|
32995
33036
|
message: "Provide exactly one of machineLinkId or pick."
|
|
32996
33037
|
});
|
|
32997
33038
|
}
|
|
33039
|
+
if (v.aiOneShot && v.aiReadOnly) {
|
|
33040
|
+
ctx.addIssue({
|
|
33041
|
+
code: external_exports.ZodIssueCode.custom,
|
|
33042
|
+
path: ["aiReadOnly"],
|
|
33043
|
+
message: "aiOneShot and aiReadOnly are mutually exclusive."
|
|
33044
|
+
});
|
|
33045
|
+
}
|
|
32998
33046
|
if (!v.ai && v.command.length > COMMAND_MAX_LEN) {
|
|
32999
33047
|
ctx.addIssue({
|
|
33000
33048
|
code: external_exports.ZodIssueCode.too_big,
|
|
@@ -33129,6 +33177,17 @@ var fsWriteRequestSchema = external_exports.object({
|
|
|
33129
33177
|
/** Full new UTF-8 content (replaces the file wholesale). */
|
|
33130
33178
|
content: external_exports.string().max(FILE_WRITE_MAX_BYTES)
|
|
33131
33179
|
});
|
|
33180
|
+
var fsMutateRequestSchema = external_exports.object({
|
|
33181
|
+
op: external_exports.enum(["mkdir", "create", "move", "delete"]),
|
|
33182
|
+
path: external_exports.string().max(1024).optional(),
|
|
33183
|
+
content: external_exports.string().max(FILE_WRITE_MAX_BYTES).optional(),
|
|
33184
|
+
from: external_exports.string().max(1024).optional(),
|
|
33185
|
+
to: external_exports.string().max(1024).optional()
|
|
33186
|
+
});
|
|
33187
|
+
var taskApproveRequestSchema = external_exports.object({
|
|
33188
|
+
taskId: external_exports.string().min(1).max(64),
|
|
33189
|
+
approved: external_exports.boolean()
|
|
33190
|
+
});
|
|
33132
33191
|
var autonomousWriteRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
33133
33192
|
external_exports.object({ kind: external_exports.literal("settings"), settings: external_exports.string().max(64 * 1024) }),
|
|
33134
33193
|
external_exports.object({ kind: external_exports.literal("approvals"), taskId: external_exports.string().min(1).max(64), approved: external_exports.boolean() }),
|
|
@@ -33275,16 +33334,6 @@ var MEMO_MAX_LENGTH = 65536;
|
|
|
33275
33334
|
var putMemoRequestSchema = external_exports.object({
|
|
33276
33335
|
content: external_exports.string().max(MEMO_MAX_LENGTH)
|
|
33277
33336
|
});
|
|
33278
|
-
var MEMO_ITEM_MAX_LENGTH = 2e3;
|
|
33279
|
-
var createMemoItemSchema = external_exports.object({
|
|
33280
|
-
content: external_exports.string().trim().min(1).max(MEMO_ITEM_MAX_LENGTH)
|
|
33281
|
-
});
|
|
33282
|
-
var updateMemoItemSchema = external_exports.object({
|
|
33283
|
-
content: external_exports.string().trim().min(1).max(MEMO_ITEM_MAX_LENGTH).optional(),
|
|
33284
|
-
done: external_exports.boolean().optional()
|
|
33285
|
-
}).refine((v) => v.content !== void 0 || v.done !== void 0, {
|
|
33286
|
-
message: "content or done required"
|
|
33287
|
-
});
|
|
33288
33337
|
var HTTP_JSON_BODY_LIMIT_BYTES = 2 * 1048576;
|
|
33289
33338
|
var putSpecDraftRequestSchema = external_exports.object({
|
|
33290
33339
|
spec: external_exports.record(external_exports.unknown()),
|
|
@@ -33710,6 +33759,9 @@ var WsChannels = {
|
|
|
33710
33759
|
// ADR-0151) — the Git tab's manual conflict resolution (`project.git_write`); the only
|
|
33711
33760
|
// git-tab write not carried by a git command over command dispatch.
|
|
33712
33761
|
FS_WRITE: "fs.write",
|
|
33762
|
+
// server → cli (reply): create/rename/move/delete a file or folder in the project tree,
|
|
33763
|
+
// each op path-clamped to the physic root (machine-0059, ADR-0260, `project.files_write`).
|
|
33764
|
+
FS_MUTATE: "fs.mutate",
|
|
33713
33765
|
GIT_DIFF: "git.diff",
|
|
33714
33766
|
GIT_ENV: "git.env",
|
|
33715
33767
|
// server → cli (reply): read/write the paired profile's config.json (machine-0025/0026,
|
|
@@ -34026,8 +34078,8 @@ function resolveInstallTimeoutMs(sec) {
|
|
|
34026
34078
|
return sec && sec > 0 ? sec * 1e3 : TOOL_INSTALL_TIMEOUT_DEFAULT_MS;
|
|
34027
34079
|
}
|
|
34028
34080
|
function sleep(ms) {
|
|
34029
|
-
return new Promise((
|
|
34030
|
-
const t = setTimeout(
|
|
34081
|
+
return new Promise((resolve9) => {
|
|
34082
|
+
const t = setTimeout(resolve9, ms);
|
|
34031
34083
|
t.unref?.();
|
|
34032
34084
|
});
|
|
34033
34085
|
}
|
|
@@ -34049,14 +34101,14 @@ function classifyToolFailure(code, out) {
|
|
|
34049
34101
|
return { reason: "other", retryable: false };
|
|
34050
34102
|
}
|
|
34051
34103
|
function run(cmd, args, onLine, timeoutMs = 18e4) {
|
|
34052
|
-
return new Promise((
|
|
34104
|
+
return new Promise((resolve9) => {
|
|
34053
34105
|
let out = "";
|
|
34054
34106
|
let buf = "";
|
|
34055
34107
|
let child = null;
|
|
34056
34108
|
const done = (code) => {
|
|
34057
34109
|
clearTimeout(timer);
|
|
34058
34110
|
if (onLine && buf.trim()) onLine(buf.trim());
|
|
34059
|
-
|
|
34111
|
+
resolve9({ code, out });
|
|
34060
34112
|
};
|
|
34061
34113
|
const timer = setTimeout(() => {
|
|
34062
34114
|
child?.kill();
|
|
@@ -34437,7 +34489,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
34437
34489
|
});
|
|
34438
34490
|
child.stdout?.on("data", (data) => batcher.push(data.toString("utf8")));
|
|
34439
34491
|
child.stderr?.on("data", (data) => batcher.push(data.toString("utf8")));
|
|
34440
|
-
await new Promise((
|
|
34492
|
+
await new Promise((resolve9) => {
|
|
34441
34493
|
child.on("close", (exitCode) => {
|
|
34442
34494
|
clearTimers();
|
|
34443
34495
|
batcher.flush();
|
|
@@ -34450,7 +34502,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
34450
34502
|
// server settles the command as failed and the web surfaces the note instead of spinning.
|
|
34451
34503
|
exitCode: timedOut ? 124 : exitCode ?? -1
|
|
34452
34504
|
});
|
|
34453
|
-
|
|
34505
|
+
resolve9();
|
|
34454
34506
|
});
|
|
34455
34507
|
child.on("error", (err) => {
|
|
34456
34508
|
clearTimers();
|
|
@@ -34462,7 +34514,7 @@ async function runCommand(dispatch, emit, opts) {
|
|
|
34462
34514
|
done: true,
|
|
34463
34515
|
exitCode: -1
|
|
34464
34516
|
});
|
|
34465
|
-
|
|
34517
|
+
resolve9();
|
|
34466
34518
|
});
|
|
34467
34519
|
});
|
|
34468
34520
|
}
|
|
@@ -34599,15 +34651,15 @@ function isOutOfCredits(text) {
|
|
|
34599
34651
|
);
|
|
34600
34652
|
}
|
|
34601
34653
|
function runAttempt(commandId, cmd, args, stdin, cwd2, env3, onChunk, timeoutMs) {
|
|
34602
|
-
return new Promise((
|
|
34654
|
+
return new Promise((resolve9) => {
|
|
34603
34655
|
runCommand(
|
|
34604
34656
|
{ commandId, cmd, args, path: cwd2, env: env3 },
|
|
34605
34657
|
(out) => {
|
|
34606
34658
|
if (out.chunk) onChunk(out.chunk);
|
|
34607
|
-
if (out.done)
|
|
34659
|
+
if (out.done) resolve9(out.exitCode ?? -1);
|
|
34608
34660
|
},
|
|
34609
34661
|
{ stdin, ...timeoutMs > 0 ? { timeoutMs } : {} }
|
|
34610
|
-
).catch(() =>
|
|
34662
|
+
).catch(() => resolve9(-1));
|
|
34611
34663
|
});
|
|
34612
34664
|
}
|
|
34613
34665
|
async function runAiFailover(plan, commandId, cwd2, handlers, timeoutMs = 0) {
|
|
@@ -34797,6 +34849,48 @@ function oneShotArgs(cmd) {
|
|
|
34797
34849
|
if (!cmd.includes("claude")) return [];
|
|
34798
34850
|
return ["--max-turns=1", "--disallowedTools", ONE_SHOT_DISALLOWED_CLAUDE_TOOLS, "--permission-mode", "default"];
|
|
34799
34851
|
}
|
|
34852
|
+
var READ_ONLY_DISALLOWED_CLAUDE_TOOLS = [
|
|
34853
|
+
"Edit",
|
|
34854
|
+
"Write",
|
|
34855
|
+
"NotebookEdit",
|
|
34856
|
+
"Task",
|
|
34857
|
+
"SlashCommand",
|
|
34858
|
+
"Skill",
|
|
34859
|
+
"WebSearch",
|
|
34860
|
+
"WebFetch",
|
|
34861
|
+
"TaskCreate",
|
|
34862
|
+
"TaskGet",
|
|
34863
|
+
"TaskList",
|
|
34864
|
+
"TaskOutput",
|
|
34865
|
+
"TaskStop",
|
|
34866
|
+
"TaskUpdate",
|
|
34867
|
+
"Monitor",
|
|
34868
|
+
"DesignSync",
|
|
34869
|
+
"CronCreate",
|
|
34870
|
+
"CronDelete",
|
|
34871
|
+
"CronList",
|
|
34872
|
+
"EnterWorktree",
|
|
34873
|
+
"ExitWorktree",
|
|
34874
|
+
"RemoteTrigger",
|
|
34875
|
+
"ScheduleWakeup",
|
|
34876
|
+
"SendMessage",
|
|
34877
|
+
"PushNotification"
|
|
34878
|
+
].join(",");
|
|
34879
|
+
var READ_ONLY_MAX_TURNS = 40;
|
|
34880
|
+
function readOnlyArgs(cmd, profileMaxTurns) {
|
|
34881
|
+
if (cmd.includes("claude")) {
|
|
34882
|
+
const turns = typeof profileMaxTurns === "number" && profileMaxTurns > 0 ? Math.floor(profileMaxTurns) : READ_ONLY_MAX_TURNS;
|
|
34883
|
+
return [
|
|
34884
|
+
`--max-turns=${turns}`,
|
|
34885
|
+
"--disallowedTools",
|
|
34886
|
+
READ_ONLY_DISALLOWED_CLAUDE_TOOLS,
|
|
34887
|
+
"--permission-mode",
|
|
34888
|
+
"plan"
|
|
34889
|
+
];
|
|
34890
|
+
}
|
|
34891
|
+
if (cmd.includes("codex")) return ["--sandbox", "read-only"];
|
|
34892
|
+
return [];
|
|
34893
|
+
}
|
|
34800
34894
|
function requiredArgs(cmd) {
|
|
34801
34895
|
if (cmd.includes("claude")) return REQUIRED_AI_ARGS.claude;
|
|
34802
34896
|
if (cmd.includes("codex")) return REQUIRED_AI_ARGS.codex;
|
|
@@ -34856,15 +34950,36 @@ function folderScopeGuard(folder, prompt) {
|
|
|
34856
34950
|
prompt
|
|
34857
34951
|
].join("\n");
|
|
34858
34952
|
}
|
|
34859
|
-
|
|
34953
|
+
var THINKING_TOKENS = { low: 4e3, medium: 1e4, high: 31999 };
|
|
34954
|
+
function overrideArgs(cmd, o) {
|
|
34955
|
+
if (!o || !cmd.includes("codex")) return [];
|
|
34956
|
+
const args = [];
|
|
34957
|
+
if (o.thinking && o.thinking !== "off") args.push("-c", `model_reasoning_effort="${o.thinking}"`);
|
|
34958
|
+
if (typeof o.temperature === "number") args.push("-c", `model_temperature=${o.temperature}`);
|
|
34959
|
+
return args;
|
|
34960
|
+
}
|
|
34961
|
+
function overrideEnv(cmd, o) {
|
|
34962
|
+
if (!o || !cmd.includes("claude")) return {};
|
|
34963
|
+
if (!o.thinking || o.thinking === "off") return {};
|
|
34964
|
+
const budget = THINKING_TOKENS[o.thinking];
|
|
34965
|
+
return budget ? { MAX_THINKING_TOKENS: String(budget) } : {};
|
|
34966
|
+
}
|
|
34967
|
+
function buildRunArgs(profile, cmd, resumeId, oneShot = false, override, readOnly = false) {
|
|
34860
34968
|
const extras = profile.args ?? [];
|
|
34861
|
-
const model = profile.model?.trim();
|
|
34969
|
+
const model = override?.model?.trim() || profile.model?.trim();
|
|
34862
34970
|
const modelArgs = model ? ["--model", model] : [];
|
|
34863
34971
|
const resumeArgs = resumeId && cmd.includes("claude") ? ["--resume", resumeId] : [];
|
|
34864
34972
|
const turns = profile.maxTurns;
|
|
34865
|
-
const perProfileTurns = !oneShot && cmd.includes("claude") && typeof turns === "number" && turns > 0 ? [`--max-turns=${Math.floor(turns)}`] : [];
|
|
34866
|
-
const
|
|
34867
|
-
return [
|
|
34973
|
+
const perProfileTurns = !oneShot && !readOnly && cmd.includes("claude") && typeof turns === "number" && turns > 0 ? [`--max-turns=${Math.floor(turns)}`] : [];
|
|
34974
|
+
const modeExtra = oneShot ? oneShotArgs(cmd) : readOnly ? readOnlyArgs(cmd, turns) : perProfileTurns;
|
|
34975
|
+
return [
|
|
34976
|
+
...requiredArgs(cmd),
|
|
34977
|
+
...resumeArgs,
|
|
34978
|
+
...extras,
|
|
34979
|
+
...modelArgs,
|
|
34980
|
+
...overrideArgs(cmd, override),
|
|
34981
|
+
...modeExtra
|
|
34982
|
+
];
|
|
34868
34983
|
}
|
|
34869
34984
|
function claudeHomeDirs(config) {
|
|
34870
34985
|
const dirs = profileDirs(claudeProfilesOf(config));
|
|
@@ -34903,10 +35018,10 @@ function resolveClaudeProfiles(config, workingDir) {
|
|
|
34903
35018
|
if (idx > 0) profiles.unshift(profiles.splice(idx, 1)[0]);
|
|
34904
35019
|
return profiles;
|
|
34905
35020
|
}
|
|
34906
|
-
function planAiRun(prompt, config, hint = {}, resume = /* @__PURE__ */ new Map(), oneShot = false) {
|
|
34907
|
-
return isUnifiedConfig(config) ? planUnifiedRun(prompt, config, hint.credential ?? null, resume, oneShot) : planLegacyRun(prompt, config, hint.dir ?? null, resume, oneShot);
|
|
35021
|
+
function planAiRun(prompt, config, hint = {}, resume = /* @__PURE__ */ new Map(), oneShot = false, override, readOnly = false) {
|
|
35022
|
+
return isUnifiedConfig(config) ? planUnifiedRun(prompt, config, hint.credential ?? null, resume, oneShot, override, readOnly) : planLegacyRun(prompt, config, hint.dir ?? null, resume, oneShot, override, readOnly);
|
|
34908
35023
|
}
|
|
34909
|
-
function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
|
|
35024
|
+
function planUnifiedRun(prompt, config, workingCredential, resume, oneShot, override, readOnly = false) {
|
|
34910
35025
|
const baseEnv = config.aiEnv ?? {};
|
|
34911
35026
|
const active = activeProvider(config);
|
|
34912
35027
|
const usable = config.aiProfiles.filter(isUsableCredential);
|
|
@@ -34915,7 +35030,7 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
|
|
|
34915
35030
|
return {
|
|
34916
35031
|
cmd: active,
|
|
34917
35032
|
attempts: [
|
|
34918
|
-
{ cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
|
|
35033
|
+
{ cmd: active, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, active, void 0, oneShot, override, readOnly), stdin: prompt, env: { ...baseEnv, ...overrideEnv(active, override) } }
|
|
34919
35034
|
]
|
|
34920
35035
|
};
|
|
34921
35036
|
}
|
|
@@ -34933,20 +35048,20 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot) {
|
|
|
34933
35048
|
label: cred.label?.trim() || profileDisplayLabel(dir2),
|
|
34934
35049
|
dir: dir2,
|
|
34935
35050
|
key,
|
|
34936
|
-
args: buildRunArgs(cred, cmd, resume.get(key), oneShot),
|
|
35051
|
+
args: buildRunArgs(cred, cmd, resume.get(key), oneShot, override, readOnly),
|
|
34937
35052
|
stdin: prompt,
|
|
34938
|
-
env: envVar ? { ...baseEnv, [envVar]: dir2 } : { ...baseEnv }
|
|
35053
|
+
env: envVar ? { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) } : { ...baseEnv, ...overrideEnv(cmd, override) }
|
|
34939
35054
|
}));
|
|
34940
35055
|
return { cmd: attempts[0]?.cmd ?? DEFAULT_AI_CLI, attempts };
|
|
34941
35056
|
}
|
|
34942
|
-
function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
|
|
35057
|
+
function planLegacyRun(prompt, config, workingDir, resume, oneShot, override, readOnly = false) {
|
|
34943
35058
|
const cmd = config.aiCli || DEFAULT_AI_CLI;
|
|
34944
35059
|
const baseEnv = config.aiEnv ?? {};
|
|
34945
35060
|
const envVar = profileEnvVar(cmd);
|
|
34946
35061
|
const defaultPlan = {
|
|
34947
35062
|
cmd,
|
|
34948
35063
|
attempts: [
|
|
34949
|
-
{ cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot), stdin: prompt, env: { ...baseEnv } }
|
|
35064
|
+
{ cmd, label: "default", dir: null, key: null, args: buildRunArgs({ profile: "" }, cmd, void 0, oneShot, override, readOnly), stdin: prompt, env: { ...baseEnv, ...overrideEnv(cmd, override) } }
|
|
34950
35065
|
]
|
|
34951
35066
|
};
|
|
34952
35067
|
if (!envVar) return defaultPlan;
|
|
@@ -34963,9 +35078,9 @@ function planLegacyRun(prompt, config, workingDir, resume, oneShot) {
|
|
|
34963
35078
|
label: profileDisplayLabel(dir2),
|
|
34964
35079
|
dir: dir2,
|
|
34965
35080
|
key,
|
|
34966
|
-
args: buildRunArgs(profile, cmd, resume.get(key), oneShot),
|
|
35081
|
+
args: buildRunArgs(profile, cmd, resume.get(key), oneShot, override, readOnly),
|
|
34967
35082
|
stdin: prompt,
|
|
34968
|
-
env: { ...baseEnv, [envVar]: dir2 }
|
|
35083
|
+
env: { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) }
|
|
34969
35084
|
};
|
|
34970
35085
|
});
|
|
34971
35086
|
return { cmd, attempts };
|
|
@@ -35006,16 +35121,16 @@ async function fetchUsage(token) {
|
|
|
35006
35121
|
}
|
|
35007
35122
|
}
|
|
35008
35123
|
function runUsageCli(dir2, aiCli2) {
|
|
35009
|
-
return new Promise((
|
|
35124
|
+
return new Promise((resolve9) => {
|
|
35010
35125
|
let out = "";
|
|
35011
35126
|
let child = null;
|
|
35012
35127
|
const finish = () => {
|
|
35013
35128
|
clearTimeout(timer);
|
|
35014
|
-
|
|
35129
|
+
resolve9(out);
|
|
35015
35130
|
};
|
|
35016
35131
|
const timer = setTimeout(() => {
|
|
35017
35132
|
child?.kill();
|
|
35018
|
-
|
|
35133
|
+
resolve9(out);
|
|
35019
35134
|
}, 3e4);
|
|
35020
35135
|
timer.unref?.();
|
|
35021
35136
|
try {
|
|
@@ -35537,6 +35652,80 @@ async function writeWorkerFile(root, relPath, content) {
|
|
|
35537
35652
|
}
|
|
35538
35653
|
}
|
|
35539
35654
|
|
|
35655
|
+
// src/core/fs-mutate.ts
|
|
35656
|
+
import { mkdir as mkdir3, writeFile as writeFile2, rename, rm, stat } from "fs/promises";
|
|
35657
|
+
import { basename as basename2, dirname as dirname4, resolve as resolve4, sep as sep4 } from "path";
|
|
35658
|
+
var MAX_BYTES3 = 2 * 1024 * 1024;
|
|
35659
|
+
function resolveInRoot2(root, rel) {
|
|
35660
|
+
const base = resolve4(root);
|
|
35661
|
+
const target = resolve4(base, rel || ".");
|
|
35662
|
+
return target === base || target.startsWith(base + sep4) ? target : null;
|
|
35663
|
+
}
|
|
35664
|
+
async function isDir(p) {
|
|
35665
|
+
try {
|
|
35666
|
+
return (await stat(p)).isDirectory();
|
|
35667
|
+
} catch {
|
|
35668
|
+
return false;
|
|
35669
|
+
}
|
|
35670
|
+
}
|
|
35671
|
+
async function exists(p) {
|
|
35672
|
+
try {
|
|
35673
|
+
await stat(p);
|
|
35674
|
+
return true;
|
|
35675
|
+
} catch {
|
|
35676
|
+
return false;
|
|
35677
|
+
}
|
|
35678
|
+
}
|
|
35679
|
+
async function mutateFs(root, req) {
|
|
35680
|
+
if (!root) return { ok: false, path: req.path ?? req.from ?? "", error: "no project served" };
|
|
35681
|
+
const escaped = (p) => ({ ok: false, path: p, error: "path escapes the project root" });
|
|
35682
|
+
try {
|
|
35683
|
+
switch (req.op) {
|
|
35684
|
+
case "mkdir": {
|
|
35685
|
+
const target = resolveInRoot2(root, req.path ?? "");
|
|
35686
|
+
if (!target || target === resolve4(root)) return escaped(req.path ?? "");
|
|
35687
|
+
await mkdir3(target, { recursive: true });
|
|
35688
|
+
return { ok: true, path: target };
|
|
35689
|
+
}
|
|
35690
|
+
case "create": {
|
|
35691
|
+
const target = resolveInRoot2(root, req.path ?? "");
|
|
35692
|
+
if (!target || target === resolve4(root)) return escaped(req.path ?? "");
|
|
35693
|
+
if (await exists(target)) return { ok: false, path: target, error: "already exists" };
|
|
35694
|
+
const content = req.content ?? "";
|
|
35695
|
+
if (Buffer.byteLength(content, "utf8") > MAX_BYTES3) {
|
|
35696
|
+
return { ok: false, path: target, error: `content too large (max ${MAX_BYTES3} bytes)` };
|
|
35697
|
+
}
|
|
35698
|
+
await mkdir3(dirname4(target), { recursive: true });
|
|
35699
|
+
await writeFile2(target, content, "utf8");
|
|
35700
|
+
return { ok: true, path: target };
|
|
35701
|
+
}
|
|
35702
|
+
case "move": {
|
|
35703
|
+
const from = resolveInRoot2(root, req.from ?? "");
|
|
35704
|
+
let to = resolveInRoot2(root, req.to ?? "");
|
|
35705
|
+
if (!from || !to) return escaped(req.from ?? req.to ?? "");
|
|
35706
|
+
if (from === resolve4(root)) return { ok: false, path: from, error: "cannot move the project root" };
|
|
35707
|
+
if (await isDir(to)) to = resolve4(to, basename2(from));
|
|
35708
|
+
if (to !== resolve4(root) && !to.startsWith(resolve4(root) + sep4)) return escaped(req.to ?? "");
|
|
35709
|
+
if (await exists(to)) return { ok: false, path: to, error: "destination already exists" };
|
|
35710
|
+
await mkdir3(dirname4(to), { recursive: true });
|
|
35711
|
+
await rename(from, to);
|
|
35712
|
+
return { ok: true, path: to };
|
|
35713
|
+
}
|
|
35714
|
+
case "delete": {
|
|
35715
|
+
const target = resolveInRoot2(root, req.path ?? "");
|
|
35716
|
+
if (!target) return escaped(req.path ?? "");
|
|
35717
|
+
if (target === resolve4(root)) return { ok: false, path: target, error: "cannot delete the project root" };
|
|
35718
|
+
await rm(target, { recursive: true, force: true });
|
|
35719
|
+
return { ok: true, path: target };
|
|
35720
|
+
}
|
|
35721
|
+
default:
|
|
35722
|
+
return { ok: false, path: "", error: "unknown op" };
|
|
35723
|
+
}
|
|
35724
|
+
} catch (err) {
|
|
35725
|
+
return { ok: false, path: req.path ?? req.from ?? "", error: err instanceof Error ? err.message : String(err) };
|
|
35726
|
+
}
|
|
35727
|
+
}
|
|
35728
|
+
|
|
35540
35729
|
// src/core/support-answer.ts
|
|
35541
35730
|
import { spawn as spawn5 } from "child_process";
|
|
35542
35731
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -35661,7 +35850,7 @@ function parseModeratedAnswer(text) {
|
|
|
35661
35850
|
return { body: text.trim() };
|
|
35662
35851
|
}
|
|
35663
35852
|
function runClaudeOnce(cmd, profile, prompt, extraEnv) {
|
|
35664
|
-
return new Promise((
|
|
35853
|
+
return new Promise((resolve9, reject) => {
|
|
35665
35854
|
const isClaude = cmd.includes("claude");
|
|
35666
35855
|
const args = [
|
|
35667
35856
|
"-p",
|
|
@@ -35691,7 +35880,7 @@ function runClaudeOnce(cmd, profile, prompt, extraEnv) {
|
|
|
35691
35880
|
child.on("close", (code) => {
|
|
35692
35881
|
clearTimeout(timer);
|
|
35693
35882
|
out += parser.flush();
|
|
35694
|
-
|
|
35883
|
+
resolve9({ code: code ?? -1, out, err, usage: parser.usage() });
|
|
35695
35884
|
});
|
|
35696
35885
|
child.stdin.write(prompt);
|
|
35697
35886
|
child.stdin.end();
|
|
@@ -35762,7 +35951,7 @@ Extra focus from the author: ${req.prompt}` : "";
|
|
|
35762
35951
|
].join("\n");
|
|
35763
35952
|
}
|
|
35764
35953
|
function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
|
|
35765
|
-
return new Promise((
|
|
35954
|
+
return new Promise((resolve9, reject) => {
|
|
35766
35955
|
const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
|
|
35767
35956
|
const env3 = {
|
|
35768
35957
|
...process.env,
|
|
@@ -35785,7 +35974,7 @@ function runOnce(cmd, profile, prompt, cwd2, extraEnv) {
|
|
|
35785
35974
|
});
|
|
35786
35975
|
child.on("close", (code) => {
|
|
35787
35976
|
clearTimeout(timer);
|
|
35788
|
-
|
|
35977
|
+
resolve9({ code: code ?? -1, out, err });
|
|
35789
35978
|
});
|
|
35790
35979
|
child.stdin.write(prompt);
|
|
35791
35980
|
child.stdin.end();
|
|
@@ -35815,7 +36004,7 @@ async function runKnowledgeCompose(req, ai, physicRoot) {
|
|
|
35815
36004
|
}
|
|
35816
36005
|
|
|
35817
36006
|
// src/core/autonomous.ts
|
|
35818
|
-
import { readFile as readFile3, writeFile as
|
|
36007
|
+
import { readFile as readFile3, writeFile as writeFile3, chmod } from "fs/promises";
|
|
35819
36008
|
import { readFileSync as readFileSync13 } from "fs";
|
|
35820
36009
|
import { execFile as execFile3, spawn as spawn7 } from "child_process";
|
|
35821
36010
|
import { join as join14 } from "path";
|
|
@@ -35861,10 +36050,10 @@ async function crontabList() {
|
|
|
35861
36050
|
}
|
|
35862
36051
|
}
|
|
35863
36052
|
async function crontabSet(content) {
|
|
35864
|
-
return new Promise((
|
|
36053
|
+
return new Promise((resolve9) => {
|
|
35865
36054
|
const child = spawn7("crontab", ["-"], { stdio: ["pipe", "ignore", "ignore"] });
|
|
35866
|
-
child.on("error", () =>
|
|
35867
|
-
child.on("close", (code) =>
|
|
36055
|
+
child.on("error", () => resolve9(false));
|
|
36056
|
+
child.on("close", (code) => resolve9(code === 0));
|
|
35868
36057
|
child.stdin.end(content.endsWith("\n") ? content : content + "\n");
|
|
35869
36058
|
});
|
|
35870
36059
|
}
|
|
@@ -35940,14 +36129,14 @@ async function writeAutonomous(root, req, by) {
|
|
|
35940
36129
|
switch (req.kind) {
|
|
35941
36130
|
case "settings": {
|
|
35942
36131
|
if (!parseJson(req.settings)) return { ok: false, error: "settings is not valid JSON" };
|
|
35943
|
-
await
|
|
36132
|
+
await writeFile3(join14(root, SETTINGS_REL), req.settings, "utf8");
|
|
35944
36133
|
break;
|
|
35945
36134
|
}
|
|
35946
36135
|
case "approvals": {
|
|
35947
36136
|
const map = parseJson(await readText(join14(root, APPROVALS_REL), "{}")) ?? {};
|
|
35948
36137
|
if (req.approved) map[req.taskId] = { approved: true, by, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
35949
36138
|
else delete map[req.taskId];
|
|
35950
|
-
await
|
|
36139
|
+
await writeFile3(join14(root, APPROVALS_REL), JSON.stringify(map, null, 2) + "\n", "utf8");
|
|
35951
36140
|
break;
|
|
35952
36141
|
}
|
|
35953
36142
|
case "userTodo": {
|
|
@@ -35957,7 +36146,7 @@ async function writeAutonomous(root, req, by) {
|
|
|
35957
36146
|
> posted by ${by} at ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
35958
36147
|
${req.content.trim()}
|
|
35959
36148
|
`;
|
|
35960
|
-
await
|
|
36149
|
+
await writeFile3(join14(root, BOOK_FILES.userTodo), cur.trimEnd() + block, "utf8");
|
|
35961
36150
|
break;
|
|
35962
36151
|
}
|
|
35963
36152
|
case "cron": {
|
|
@@ -35973,7 +36162,7 @@ ${req.content.trim()}
|
|
|
35973
36162
|
}
|
|
35974
36163
|
|
|
35975
36164
|
// src/core/agents.ts
|
|
35976
|
-
import { readFile as readFile4, writeFile as
|
|
36165
|
+
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir as readdir3, rm as rm2 } from "fs/promises";
|
|
35977
36166
|
import { join as join15 } from "path";
|
|
35978
36167
|
var AGENTS_REL = ".claude/agents";
|
|
35979
36168
|
var SKILLS_REL = ".claude/skills";
|
|
@@ -36036,14 +36225,14 @@ async function writeAgent(root, req) {
|
|
|
36036
36225
|
if (!n) return { ok: false, error: "invalid name" };
|
|
36037
36226
|
try {
|
|
36038
36227
|
if (req.action === "delete") {
|
|
36039
|
-
if (req.kind === "subagent") await
|
|
36040
|
-
else await
|
|
36228
|
+
if (req.kind === "subagent") await rm2(itemPath(root, "subagent", n), { force: true });
|
|
36229
|
+
else await rm2(join15(root, SKILLS_REL, n), { recursive: true, force: true });
|
|
36041
36230
|
return { ok: true };
|
|
36042
36231
|
}
|
|
36043
36232
|
if (req.content === void 0) return { ok: false, error: "content is required" };
|
|
36044
36233
|
const path = itemPath(root, req.kind, n);
|
|
36045
|
-
await
|
|
36046
|
-
await
|
|
36234
|
+
await mkdir4(join15(path, ".."), { recursive: true });
|
|
36235
|
+
await writeFile4(path, req.content, "utf8");
|
|
36047
36236
|
return { ok: true };
|
|
36048
36237
|
} catch (err) {
|
|
36049
36238
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -36052,8 +36241,8 @@ async function writeAgent(root, req) {
|
|
|
36052
36241
|
|
|
36053
36242
|
// src/core/packages.ts
|
|
36054
36243
|
import { createHash as createHash4 } from "crypto";
|
|
36055
|
-
import { readFile as readFile5, writeFile as
|
|
36056
|
-
import { dirname as
|
|
36244
|
+
import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir4, rm as rm3, stat as stat2 } from "fs/promises";
|
|
36245
|
+
import { dirname as dirname5, join as join16, relative } from "path";
|
|
36057
36246
|
var AGENTS_REL2 = ".claude/agents";
|
|
36058
36247
|
var SKILLS_REL2 = ".claude/skills";
|
|
36059
36248
|
var MANIFEST_REL = ".claude/.4pm-packages.json";
|
|
@@ -36117,7 +36306,7 @@ async function artifactSha256(root, kind, slug) {
|
|
|
36117
36306
|
async function artifactExists(root, kind, slug) {
|
|
36118
36307
|
const target = kind === "subagent" ? join16(root, AGENTS_REL2, `${slug}.md`) : join16(root, SKILLS_REL2, slug);
|
|
36119
36308
|
try {
|
|
36120
|
-
await
|
|
36309
|
+
await stat2(target);
|
|
36121
36310
|
return true;
|
|
36122
36311
|
} catch {
|
|
36123
36312
|
return false;
|
|
@@ -36134,34 +36323,34 @@ async function readManifest(root) {
|
|
|
36134
36323
|
}
|
|
36135
36324
|
async function writeManifest(root, manifest) {
|
|
36136
36325
|
const path = join16(root, MANIFEST_REL);
|
|
36137
|
-
await
|
|
36138
|
-
await
|
|
36326
|
+
await mkdir5(dirname5(path), { recursive: true });
|
|
36327
|
+
await writeFile5(path, JSON.stringify(manifest, null, 2), "utf8");
|
|
36139
36328
|
}
|
|
36140
36329
|
async function writeArtifactFiles(root, kind, slug, files) {
|
|
36141
36330
|
const byPath = new Map(files.map((f) => [f.path, Buffer.from(f.contentBase64, "base64")]));
|
|
36142
36331
|
if (kind === "subagent") {
|
|
36143
36332
|
const agent = byPath.get("agent.md");
|
|
36144
36333
|
if (agent) {
|
|
36145
|
-
await
|
|
36146
|
-
await
|
|
36334
|
+
await mkdir5(join16(root, AGENTS_REL2), { recursive: true });
|
|
36335
|
+
await writeFile5(join16(root, AGENTS_REL2, `${slug}.md`), agent);
|
|
36147
36336
|
}
|
|
36148
36337
|
const short = byPath.get("short-memory.md");
|
|
36149
36338
|
if (short) {
|
|
36150
|
-
await
|
|
36151
|
-
await
|
|
36339
|
+
await mkdir5(join16(root, AGENTS_REL2, "short-memory"), { recursive: true });
|
|
36340
|
+
await writeFile5(join16(root, AGENTS_REL2, "short-memory", `${slug}.md`), short);
|
|
36152
36341
|
}
|
|
36153
36342
|
const long = byPath.get("long-memory.md");
|
|
36154
36343
|
if (long) {
|
|
36155
|
-
await
|
|
36156
|
-
await
|
|
36344
|
+
await mkdir5(join16(root, AGENTS_REL2, "long-memory"), { recursive: true });
|
|
36345
|
+
await writeFile5(join16(root, AGENTS_REL2, "long-memory", `${slug}.md`), long);
|
|
36157
36346
|
}
|
|
36158
36347
|
} else {
|
|
36159
36348
|
const base = join16(root, SKILLS_REL2, slug);
|
|
36160
36349
|
for (const [rel, buf] of byPath) {
|
|
36161
36350
|
if (rel.includes("..") || rel.startsWith("/")) continue;
|
|
36162
36351
|
const dest = join16(base, rel);
|
|
36163
|
-
await
|
|
36164
|
-
await
|
|
36352
|
+
await mkdir5(dirname5(dest), { recursive: true });
|
|
36353
|
+
await writeFile5(dest, buf);
|
|
36165
36354
|
}
|
|
36166
36355
|
}
|
|
36167
36356
|
}
|
|
@@ -36225,11 +36414,11 @@ async function removePackage(root, slug) {
|
|
|
36225
36414
|
const entry = manifest[n];
|
|
36226
36415
|
if (!entry) return { ok: false, error: "not installed" };
|
|
36227
36416
|
if (entry.kind === "subagent") {
|
|
36228
|
-
await
|
|
36229
|
-
await
|
|
36230
|
-
await
|
|
36417
|
+
await rm3(join16(root, AGENTS_REL2, `${n}.md`), { force: true });
|
|
36418
|
+
await rm3(join16(root, AGENTS_REL2, "short-memory", `${n}.md`), { force: true });
|
|
36419
|
+
await rm3(join16(root, AGENTS_REL2, "long-memory", `${n}.md`), { force: true });
|
|
36231
36420
|
} else {
|
|
36232
|
-
await
|
|
36421
|
+
await rm3(join16(root, SKILLS_REL2, n), { recursive: true, force: true });
|
|
36233
36422
|
}
|
|
36234
36423
|
delete manifest[n];
|
|
36235
36424
|
await writeManifest(root, manifest);
|
|
@@ -36257,14 +36446,14 @@ function detectContainerized() {
|
|
|
36257
36446
|
}
|
|
36258
36447
|
}
|
|
36259
36448
|
function canReach(host, port) {
|
|
36260
|
-
return new Promise((
|
|
36449
|
+
return new Promise((resolve9) => {
|
|
36261
36450
|
const socket = connect({ host, port });
|
|
36262
36451
|
let done = false;
|
|
36263
36452
|
const finish = (ok) => {
|
|
36264
36453
|
if (done) return;
|
|
36265
36454
|
done = true;
|
|
36266
36455
|
socket.destroy();
|
|
36267
|
-
|
|
36456
|
+
resolve9(ok);
|
|
36268
36457
|
};
|
|
36269
36458
|
socket.setTimeout(PROBE_TIMEOUT_MS);
|
|
36270
36459
|
socket.once("connect", () => finish(true));
|
|
@@ -36345,7 +36534,7 @@ function applyGitAuth(method) {
|
|
|
36345
36534
|
}
|
|
36346
36535
|
|
|
36347
36536
|
// src/core/secrets.ts
|
|
36348
|
-
import { readFile as readFile6, writeFile as
|
|
36537
|
+
import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
36349
36538
|
import { join as join18 } from "path";
|
|
36350
36539
|
var SECURITY_REL = "AI_SECURITY.md";
|
|
36351
36540
|
var PLACEHOLDER_REL = "AI_PLACEHOLDER.md";
|
|
@@ -36392,14 +36581,14 @@ async function readSecrets(root) {
|
|
|
36392
36581
|
async function writeSecrets(root, req) {
|
|
36393
36582
|
try {
|
|
36394
36583
|
if (req.kind === "security") {
|
|
36395
|
-
await
|
|
36584
|
+
await writeFile6(join18(root, SECURITY_REL), req.content, "utf8");
|
|
36396
36585
|
} else if (req.kind === "placeholder") {
|
|
36397
|
-
await
|
|
36586
|
+
await writeFile6(join18(root, PLACEHOLDER_REL), req.content, "utf8");
|
|
36398
36587
|
} else {
|
|
36399
36588
|
const secrets = await readSecretsObject(root);
|
|
36400
36589
|
if (req.kind === "secret") secrets[req.key] = req.value;
|
|
36401
36590
|
else delete secrets[req.key];
|
|
36402
|
-
await
|
|
36591
|
+
await writeFile6(join18(root, SECRETS_REL), JSON.stringify(secrets, null, 2) + "\n", "utf8");
|
|
36403
36592
|
}
|
|
36404
36593
|
return { ok: true };
|
|
36405
36594
|
} catch (err) {
|
|
@@ -36408,8 +36597,8 @@ async function writeSecrets(root, req) {
|
|
|
36408
36597
|
}
|
|
36409
36598
|
|
|
36410
36599
|
// src/core/agent-tools.ts
|
|
36411
|
-
import { readFile as readFile7, writeFile as
|
|
36412
|
-
import { dirname as
|
|
36600
|
+
import { readFile as readFile7, writeFile as writeFile7, mkdir as mkdir6 } from "fs/promises";
|
|
36601
|
+
import { dirname as dirname6, join as join19 } from "path";
|
|
36413
36602
|
var SHARED_REL = ".claude/settings.json";
|
|
36414
36603
|
var LOCAL_REL = ".claude/settings.local.json";
|
|
36415
36604
|
var SECRETS_DENY = "Read(./project.secrets.json)";
|
|
@@ -36442,8 +36631,8 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
36442
36631
|
const next = normalizePermissions(permissions);
|
|
36443
36632
|
if (scope === "shared" && !next.deny.includes(SECRETS_DENY)) next.deny = [...next.deny, SECRETS_DENY];
|
|
36444
36633
|
obj.permissions = next;
|
|
36445
|
-
await
|
|
36446
|
-
await
|
|
36634
|
+
await mkdir6(dirname6(path), { recursive: true });
|
|
36635
|
+
await writeFile7(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
|
|
36447
36636
|
return { ok: true };
|
|
36448
36637
|
} catch (err) {
|
|
36449
36638
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -36452,7 +36641,7 @@ async function writeAgentTools(root, scope, permissions) {
|
|
|
36452
36641
|
|
|
36453
36642
|
// src/core/graph.ts
|
|
36454
36643
|
import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
|
|
36455
|
-
import { join as join20, relative as relative2, dirname as
|
|
36644
|
+
import { join as join20, relative as relative2, dirname as dirname7, resolve as resolve5, extname, basename as basename3 } from "path";
|
|
36456
36645
|
var MAX_FILES = 2e3;
|
|
36457
36646
|
var MAX_NODES = 3e3;
|
|
36458
36647
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "out", "coverage", ".turbo"]);
|
|
@@ -36492,7 +36681,7 @@ async function buildDocs(root) {
|
|
|
36492
36681
|
const ids = new Set(files.map((f) => relative2(root, f).split("\\").join("/")));
|
|
36493
36682
|
const nodes = files.map((f) => {
|
|
36494
36683
|
const rel = relative2(root, f).split("\\").join("/");
|
|
36495
|
-
return { id: rel, label:
|
|
36684
|
+
return { id: rel, label: basename3(rel), kind: "doc", file: rel };
|
|
36496
36685
|
});
|
|
36497
36686
|
const edges = [];
|
|
36498
36687
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -36507,7 +36696,7 @@ async function buildDocs(root) {
|
|
|
36507
36696
|
for (const m of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
|
|
36508
36697
|
const href = (m[1] ?? "").split("#")[0].trim();
|
|
36509
36698
|
if (!href || !href.endsWith(".md") || href.startsWith("http")) continue;
|
|
36510
|
-
const target = relative2(root,
|
|
36699
|
+
const target = relative2(root, resolve5(dirname7(f), href)).split("\\").join("/");
|
|
36511
36700
|
if (ids.has(target) && target !== rel) {
|
|
36512
36701
|
const key = `${rel}->${target}`;
|
|
36513
36702
|
if (!seen.has(key)) {
|
|
@@ -36591,7 +36780,7 @@ async function buildGraph(root, mode) {
|
|
|
36591
36780
|
}
|
|
36592
36781
|
|
|
36593
36782
|
// src/core/rag.ts
|
|
36594
|
-
import { readFile as readFile9, writeFile as
|
|
36783
|
+
import { readFile as readFile9, writeFile as writeFile8, statfs as statfs2, mkdir as mkdir7 } from "fs/promises";
|
|
36595
36784
|
import { existsSync as existsSync11 } from "fs";
|
|
36596
36785
|
import { execFile as execFile4, spawn as spawn8 } from "child_process";
|
|
36597
36786
|
import { totalmem as totalmem2, cpus as cpus2 } from "os";
|
|
@@ -36765,8 +36954,8 @@ if __name__ == "__main__":
|
|
|
36765
36954
|
elif cmd == "query": query(sys.argv[2], int(sys.argv[3]) if len(sys.argv) > 3 else 8)
|
|
36766
36955
|
`;
|
|
36767
36956
|
async function ensureEngine(root) {
|
|
36768
|
-
await
|
|
36769
|
-
await
|
|
36957
|
+
await mkdir7(join21(root, RAG_REL), { recursive: true }).catch(() => void 0);
|
|
36958
|
+
await writeFile8(join21(root, RAG_REL, "rag_engine.py"), RAG_ENGINE_PY, "utf8");
|
|
36770
36959
|
}
|
|
36771
36960
|
async function ragReindex(root) {
|
|
36772
36961
|
const py = await detectPython();
|
|
@@ -36814,7 +37003,7 @@ async function ragInstall(root, model) {
|
|
|
36814
37003
|
if (!py.found) return { ok: false, started: false, error: "python3 not found on the worker" };
|
|
36815
37004
|
if (existsSync11(join21(root, RAG_REL, ".installing"))) return { ok: true, started: true };
|
|
36816
37005
|
try {
|
|
36817
|
-
await
|
|
37006
|
+
await mkdir7(join21(root, RAG_REL), { recursive: true });
|
|
36818
37007
|
} catch {
|
|
36819
37008
|
}
|
|
36820
37009
|
const script = `
|
|
@@ -36843,13 +37032,13 @@ rm -f "${RAG_REL}/.installing"
|
|
|
36843
37032
|
// src/core/git-diff.ts
|
|
36844
37033
|
import { readFile as readFile10 } from "fs/promises";
|
|
36845
37034
|
import { execFile as execFile5 } from "child_process";
|
|
36846
|
-
import { basename as
|
|
37035
|
+
import { basename as basename4, dirname as dirname8, resolve as resolve6 } from "path";
|
|
36847
37036
|
import { promisify as promisify5 } from "util";
|
|
36848
37037
|
var run5 = promisify5(execFile5);
|
|
36849
37038
|
async function gitDiff(path) {
|
|
36850
|
-
const target =
|
|
36851
|
-
const dir2 =
|
|
36852
|
-
const base =
|
|
37039
|
+
const target = resolve6(path);
|
|
37040
|
+
const dir2 = dirname8(target);
|
|
37041
|
+
const base = basename4(target);
|
|
36853
37042
|
let newContent = "";
|
|
36854
37043
|
try {
|
|
36855
37044
|
newContent = await readFile10(target, "utf8");
|
|
@@ -36901,7 +37090,7 @@ ${stderr}`;
|
|
|
36901
37090
|
|
|
36902
37091
|
// src/core/git-ssh-key.ts
|
|
36903
37092
|
import { execFile as execFile7 } from "child_process";
|
|
36904
|
-
import { readFile as readFile11, rm as
|
|
37093
|
+
import { readFile as readFile11, rm as rm4, mkdir as mkdir8 } from "fs/promises";
|
|
36905
37094
|
import { join as join22 } from "path";
|
|
36906
37095
|
import { promisify as promisify7 } from "util";
|
|
36907
37096
|
var run7 = promisify7(execFile7);
|
|
@@ -36934,9 +37123,9 @@ async function configureGit(key) {
|
|
|
36934
37123
|
}
|
|
36935
37124
|
async function generate(profileDir2) {
|
|
36936
37125
|
const { dir: dir2, key, pub } = keyPaths(profileDir2);
|
|
36937
|
-
await
|
|
36938
|
-
await
|
|
36939
|
-
await
|
|
37126
|
+
await mkdir8(dir2, { recursive: true });
|
|
37127
|
+
await rm4(key, { force: true });
|
|
37128
|
+
await rm4(pub, { force: true });
|
|
36940
37129
|
await run7("ssh-keygen", ["-t", "ed25519", "-f", key, "-N", "", "-C", "4pm-deploy-key"], {
|
|
36941
37130
|
timeout: 15e3
|
|
36942
37131
|
});
|
|
@@ -36945,8 +37134,8 @@ async function generate(profileDir2) {
|
|
|
36945
37134
|
}
|
|
36946
37135
|
async function remove(profileDir2) {
|
|
36947
37136
|
const { key, pub } = keyPaths(profileDir2);
|
|
36948
|
-
await
|
|
36949
|
-
await
|
|
37137
|
+
await rm4(key, { force: true });
|
|
37138
|
+
await rm4(pub, { force: true });
|
|
36950
37139
|
await run7("git", ["config", "--global", "--unset", "core.sshCommand"], { timeout: 5e3 }).catch(
|
|
36951
37140
|
() => void 0
|
|
36952
37141
|
);
|
|
@@ -36970,16 +37159,16 @@ async function manageSshKey(op, profileDir2) {
|
|
|
36970
37159
|
// src/core/git-history.ts
|
|
36971
37160
|
import { readdir as readdir6 } from "fs/promises";
|
|
36972
37161
|
import { execFile as execFile8 } from "child_process";
|
|
36973
|
-
import { resolve as
|
|
37162
|
+
import { resolve as resolve7, sep as sep5 } from "path";
|
|
36974
37163
|
import { promisify as promisify8 } from "util";
|
|
36975
37164
|
var run8 = promisify8(execFile8);
|
|
36976
37165
|
var FS = "";
|
|
36977
37166
|
var RS = "";
|
|
36978
37167
|
function resolveRepo(root, repo) {
|
|
36979
37168
|
if (!root) return null;
|
|
36980
|
-
const base =
|
|
36981
|
-
const requested =
|
|
36982
|
-
return requested === base || requested.startsWith(base +
|
|
37169
|
+
const base = resolve7(root);
|
|
37170
|
+
const requested = resolve7(base, repo && repo.trim() ? repo : ".");
|
|
37171
|
+
return requested === base || requested.startsWith(base + sep5) ? requested : base;
|
|
36983
37172
|
}
|
|
36984
37173
|
async function git(cwd2, args) {
|
|
36985
37174
|
try {
|
|
@@ -36995,13 +37184,13 @@ async function git(cwd2, args) {
|
|
|
36995
37184
|
}
|
|
36996
37185
|
async function gitRepos(root) {
|
|
36997
37186
|
if (!root) return { repos: [] };
|
|
36998
|
-
const base =
|
|
37187
|
+
const base = resolve7(root);
|
|
36999
37188
|
const found = /* @__PURE__ */ new Set();
|
|
37000
37189
|
const repos = [];
|
|
37001
37190
|
const add = async (dir2) => {
|
|
37002
37191
|
const inside = await git(dir2, ["rev-parse", "--show-toplevel"]);
|
|
37003
37192
|
const top = inside.trim();
|
|
37004
|
-
if (!top || found.has(top) || !(top === base || top.startsWith(base +
|
|
37193
|
+
if (!top || found.has(top) || !(top === base || top.startsWith(base + sep5))) return;
|
|
37005
37194
|
found.add(top);
|
|
37006
37195
|
const subdir = top === base ? "" : top.slice(base.length + 1);
|
|
37007
37196
|
const remote = (await git(top, ["remote", "get-url", "origin"])).trim();
|
|
@@ -37012,13 +37201,13 @@ async function gitRepos(root) {
|
|
|
37012
37201
|
const lvl1 = await readdir6(base, { withFileTypes: true });
|
|
37013
37202
|
for (const d of lvl1) {
|
|
37014
37203
|
if (!d.isDirectory() || d.name === ".git" || d.name === "node_modules") continue;
|
|
37015
|
-
const p1 =
|
|
37204
|
+
const p1 = resolve7(base, d.name);
|
|
37016
37205
|
await add(p1);
|
|
37017
37206
|
try {
|
|
37018
37207
|
const lvl2 = await readdir6(p1, { withFileTypes: true });
|
|
37019
37208
|
for (const d2 of lvl2) {
|
|
37020
37209
|
if (!d2.isDirectory() || d2.name === ".git" || d2.name === "node_modules") continue;
|
|
37021
|
-
await add(
|
|
37210
|
+
await add(resolve7(p1, d2.name));
|
|
37022
37211
|
}
|
|
37023
37212
|
} catch {
|
|
37024
37213
|
}
|
|
@@ -37097,10 +37286,10 @@ async function setCommitAuthor(cwd2, machineUsername) {
|
|
|
37097
37286
|
}
|
|
37098
37287
|
|
|
37099
37288
|
// src/core/scaffold.ts
|
|
37100
|
-
import { cp, mkdir as
|
|
37289
|
+
import { cp, mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
|
|
37101
37290
|
import { existsSync as existsSync12 } from "fs";
|
|
37102
37291
|
import { execFile as execFile10 } from "child_process";
|
|
37103
|
-
import { dirname as
|
|
37292
|
+
import { dirname as dirname9, join as join23, resolve as resolve8 } from "path";
|
|
37104
37293
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
37105
37294
|
import { promisify as promisify10 } from "util";
|
|
37106
37295
|
var run10 = promisify10(execFile10);
|
|
@@ -37135,31 +37324,35 @@ async function provisionRepos(target, repos, emit, opts = {}) {
|
|
|
37135
37324
|
await run10("git", ["clone", repo.url, dir2], { timeout: 12e4 });
|
|
37136
37325
|
} else {
|
|
37137
37326
|
emit("git", `Initializing sub-repo ${subDirName(repo)}\u2026`);
|
|
37138
|
-
await
|
|
37327
|
+
await mkdir9(dir2, { recursive: true });
|
|
37139
37328
|
await run10("git", ["init"], { cwd: dir2, timeout: 2e4 });
|
|
37140
37329
|
}
|
|
37141
37330
|
}
|
|
37142
37331
|
}
|
|
37143
37332
|
function sampleDir() {
|
|
37144
37333
|
if (process.env.SCAFFOLD_SAMPLE_DIR) return process.env.SCAFFOLD_SAMPLE_DIR;
|
|
37145
|
-
const here =
|
|
37146
|
-
const bundled =
|
|
37147
|
-
for (const candidate of [bundled,
|
|
37334
|
+
const here = dirname9(fileURLToPath3(import.meta.url));
|
|
37335
|
+
const bundled = resolve8(here, "project-sample");
|
|
37336
|
+
for (const candidate of [bundled, resolve8(here, "../project-sample"), resolve8(here, "../../project-sample")]) {
|
|
37148
37337
|
if (existsSync12(candidate)) return candidate;
|
|
37149
37338
|
}
|
|
37150
37339
|
return bundled;
|
|
37151
37340
|
}
|
|
37152
37341
|
async function scaffoldProject(payload, profileDir2, onProgress) {
|
|
37153
|
-
|
|
37342
|
+
let lastStep = "start";
|
|
37343
|
+
const emit = (step, message) => {
|
|
37344
|
+
lastStep = step;
|
|
37345
|
+
onProgress?.({ projectId: payload.projectId, step, message });
|
|
37346
|
+
};
|
|
37154
37347
|
try {
|
|
37155
|
-
const root = process.env.SCAFFOLD_ROOT ?
|
|
37348
|
+
const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
|
|
37156
37349
|
const target = join23(root, payload.projectName);
|
|
37157
|
-
await
|
|
37350
|
+
await mkdir9(target, { recursive: true });
|
|
37158
37351
|
emit("copy", "Copying the sample template\u2026");
|
|
37159
37352
|
await cp(sampleDir(), target, { recursive: true, force: false, errorOnExist: false });
|
|
37160
37353
|
if (payload.spec) {
|
|
37161
37354
|
emit("spec", "Writing project.spec.json\u2026");
|
|
37162
|
-
await
|
|
37355
|
+
await writeFile9(
|
|
37163
37356
|
join23(target, "project.spec.json"),
|
|
37164
37357
|
JSON.stringify(payload.spec, null, 2),
|
|
37165
37358
|
"utf8"
|
|
@@ -37168,17 +37361,25 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
|
|
|
37168
37361
|
const repos = reposOf(payload.spec);
|
|
37169
37362
|
if (repos.length > 0) await provisionRepos(target, repos, emit);
|
|
37170
37363
|
if (payload.spec) await aiInit(target, payload.spec, emit);
|
|
37364
|
+
emit("version", "Writing .4pm/.4pm.json\u2026");
|
|
37365
|
+
await writeTemplateMarker(target);
|
|
37171
37366
|
onProgress?.({ projectId: payload.projectId, step: "done", message: "Scaffold complete.", done: true });
|
|
37172
37367
|
return { ok: true, path: target };
|
|
37173
37368
|
} catch (err) {
|
|
37174
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
37369
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
|
|
37175
37370
|
}
|
|
37176
37371
|
}
|
|
37372
|
+
async function writeTemplateMarker(target) {
|
|
37373
|
+
const dir2 = join23(target, ".4pm");
|
|
37374
|
+
await mkdir9(dir2, { recursive: true });
|
|
37375
|
+
const marker = { templateVersion: PROJECT_TEMPLATE.version, scaffoldedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
37376
|
+
await writeFile9(join23(dir2, ".4pm.json"), JSON.stringify(marker, null, 2) + "\n", "utf8");
|
|
37377
|
+
}
|
|
37177
37378
|
async function aiInit(target, spec, emit) {
|
|
37178
37379
|
emit("ai-init", "AI init: subagents, README, CLAUDE.md\u2026");
|
|
37179
37380
|
const subagents = Array.isArray(spec.subagents) ? spec.subagents : [];
|
|
37180
37381
|
if (subagents.length > 0) {
|
|
37181
|
-
await
|
|
37382
|
+
await mkdir9(join23(target, ".claude", "agents"), { recursive: true });
|
|
37182
37383
|
for (const sa of subagents) {
|
|
37183
37384
|
const name = (sa.name || "").trim().replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
37184
37385
|
if (!name) continue;
|
|
@@ -37188,7 +37389,7 @@ name: ${name}
|
|
|
37188
37389
|
|
|
37189
37390
|
${(sa.description || "").trim()}
|
|
37190
37391
|
`;
|
|
37191
|
-
await
|
|
37392
|
+
await writeFile9(join23(target, ".claude", "agents", `${name}.md`), body, "utf8");
|
|
37192
37393
|
}
|
|
37193
37394
|
}
|
|
37194
37395
|
const specJson = JSON.stringify(spec);
|
|
@@ -37206,22 +37407,26 @@ ${specJson}`
|
|
|
37206
37407
|
async function generateFile(path, prompt) {
|
|
37207
37408
|
try {
|
|
37208
37409
|
const text = await aiGenerate(prompt);
|
|
37209
|
-
if (text.trim()) await
|
|
37410
|
+
if (text.trim()) await writeFile9(path, text.trim() + "\n", "utf8");
|
|
37210
37411
|
} catch {
|
|
37211
37412
|
}
|
|
37212
37413
|
}
|
|
37213
37414
|
async function addProject(payload, profileDir2, onProgress) {
|
|
37214
|
-
|
|
37415
|
+
let lastStep = "start";
|
|
37416
|
+
const emit = (step, message) => {
|
|
37417
|
+
lastStep = step;
|
|
37418
|
+
onProgress?.({ projectId: payload.projectId, step, message });
|
|
37419
|
+
};
|
|
37215
37420
|
try {
|
|
37216
|
-
const root = process.env.SCAFFOLD_ROOT ?
|
|
37421
|
+
const root = process.env.SCAFFOLD_ROOT ? resolve8(process.env.SCAFFOLD_ROOT) : resolve8(profileDir2);
|
|
37217
37422
|
const target = join23(root, payload.projectName);
|
|
37218
|
-
await
|
|
37423
|
+
await mkdir9(target, { recursive: true });
|
|
37219
37424
|
const repos = payload.repos ?? [];
|
|
37220
37425
|
if (repos.length > 0) await provisionRepos(target, repos, emit, { clonePrimary: true });
|
|
37221
37426
|
onProgress?.({ projectId: payload.projectId, step: "done", message: "Project added.", done: true });
|
|
37222
37427
|
return { ok: true, path: target };
|
|
37223
37428
|
} catch (err) {
|
|
37224
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
37429
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
|
|
37225
37430
|
}
|
|
37226
37431
|
}
|
|
37227
37432
|
|
|
@@ -37639,7 +37844,7 @@ function buildPrompt3(input) {
|
|
|
37639
37844
|
].join("\n");
|
|
37640
37845
|
}
|
|
37641
37846
|
function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
|
|
37642
|
-
return new Promise((
|
|
37847
|
+
return new Promise((resolve9, reject) => {
|
|
37643
37848
|
const args = ["-p", ...profile?.model ? ["--model", profile.model] : []];
|
|
37644
37849
|
const env3 = {
|
|
37645
37850
|
...process.env,
|
|
@@ -37662,7 +37867,7 @@ function runOnce2(cmd, profile, prompt, cwd2, extraEnv) {
|
|
|
37662
37867
|
});
|
|
37663
37868
|
child.on("close", (code) => {
|
|
37664
37869
|
clearTimeout(timer);
|
|
37665
|
-
|
|
37870
|
+
resolve9({ code: code ?? -1, out, err });
|
|
37666
37871
|
});
|
|
37667
37872
|
child.stdin.write(prompt);
|
|
37668
37873
|
child.stdin.end();
|
|
@@ -37937,14 +38142,14 @@ var WsClient = class {
|
|
|
37937
38142
|
*/
|
|
37938
38143
|
awaitConnected(timeoutMs) {
|
|
37939
38144
|
if (this.sessionKey && this.bus.status === "connected") return Promise.resolve(true);
|
|
37940
|
-
return new Promise((
|
|
38145
|
+
return new Promise((resolve9) => {
|
|
37941
38146
|
const waiter = () => {
|
|
37942
38147
|
clearTimeout(timer);
|
|
37943
|
-
|
|
38148
|
+
resolve9(true);
|
|
37944
38149
|
};
|
|
37945
38150
|
const timer = setTimeout(() => {
|
|
37946
38151
|
this.connectWaiters = this.connectWaiters.filter((w) => w !== waiter);
|
|
37947
|
-
|
|
38152
|
+
resolve9(false);
|
|
37948
38153
|
}, timeoutMs);
|
|
37949
38154
|
this.connectWaiters.push(waiter);
|
|
37950
38155
|
});
|
|
@@ -37971,16 +38176,16 @@ var WsClient = class {
|
|
|
37971
38176
|
this.forceReconnect = false;
|
|
37972
38177
|
return Promise.resolve();
|
|
37973
38178
|
}
|
|
37974
|
-
return new Promise((
|
|
38179
|
+
return new Promise((resolve9) => {
|
|
37975
38180
|
const timer = setTimeout(() => {
|
|
37976
38181
|
this.wakeReconnect = null;
|
|
37977
|
-
|
|
38182
|
+
resolve9();
|
|
37978
38183
|
}, ms);
|
|
37979
38184
|
this.wakeReconnect = () => {
|
|
37980
38185
|
clearTimeout(timer);
|
|
37981
38186
|
this.wakeReconnect = null;
|
|
37982
38187
|
this.forceReconnect = false;
|
|
37983
|
-
|
|
38188
|
+
resolve9();
|
|
37984
38189
|
};
|
|
37985
38190
|
});
|
|
37986
38191
|
}
|
|
@@ -38034,7 +38239,7 @@ var WsClient = class {
|
|
|
38034
38239
|
* One WS session: token → connect → handshake → handle messages until close.
|
|
38035
38240
|
*/
|
|
38036
38241
|
connectOnce() {
|
|
38037
|
-
return new Promise((
|
|
38242
|
+
return new Promise((resolve9, reject) => {
|
|
38038
38243
|
void (async () => {
|
|
38039
38244
|
this.sessionEstablished = false;
|
|
38040
38245
|
this.bus.setStatus("connecting");
|
|
@@ -38128,7 +38333,7 @@ var WsClient = class {
|
|
|
38128
38333
|
if (code === CLOSE_DRAINING) {
|
|
38129
38334
|
this.bus.log("Server draining \u2014 will reconnect (backoff + jitter).");
|
|
38130
38335
|
}
|
|
38131
|
-
|
|
38336
|
+
resolve9();
|
|
38132
38337
|
});
|
|
38133
38338
|
socket.on("error", (err) => {
|
|
38134
38339
|
this.clearHeartbeat();
|
|
@@ -38285,7 +38490,9 @@ var WsClient = class {
|
|
|
38285
38490
|
dispatch.commandId,
|
|
38286
38491
|
"server",
|
|
38287
38492
|
dispatch.aiOneShot ?? false,
|
|
38288
|
-
dispatch.images
|
|
38493
|
+
dispatch.images,
|
|
38494
|
+
dispatch.aiConfig,
|
|
38495
|
+
dispatch.aiReadOnly ?? false
|
|
38289
38496
|
);
|
|
38290
38497
|
}
|
|
38291
38498
|
break;
|
|
@@ -38341,6 +38548,13 @@ var WsClient = class {
|
|
|
38341
38548
|
);
|
|
38342
38549
|
break;
|
|
38343
38550
|
}
|
|
38551
|
+
case WsChannels.FS_MUTATE: {
|
|
38552
|
+
const req = payload;
|
|
38553
|
+
void mutateFs(this.physicRoot, req).then(
|
|
38554
|
+
(reply) => this.send(WsChannels.FS_MUTATE, reply, message.id)
|
|
38555
|
+
);
|
|
38556
|
+
break;
|
|
38557
|
+
}
|
|
38344
38558
|
case WsChannels.SUPPORT_ANSWER: {
|
|
38345
38559
|
const req = payload;
|
|
38346
38560
|
const supportConfig = readProfileConfig(this.context.profileDir);
|
|
@@ -38775,7 +38989,7 @@ var WsClient = class {
|
|
|
38775
38989
|
* exactly like typing the prompt in the cli (tries profiles, meters real tokens) instead
|
|
38776
38990
|
* of spawning the text as a raw command. Streams output to the transcript AND the server.
|
|
38777
38991
|
*/
|
|
38778
|
-
async runAiPrompt(prompt, commandId, origin, oneShot = false, images) {
|
|
38992
|
+
async runAiPrompt(prompt, commandId, origin, oneShot = false, images, aiConfig, readOnly = false) {
|
|
38779
38993
|
const config = readProfileConfig(this.context.profileDir);
|
|
38780
38994
|
const projectTimeoutSec = config.projectAiRunTimeoutSec ?? 0;
|
|
38781
38995
|
const machineTimeoutSec = config.aiRunTimeoutSec ?? 0;
|
|
@@ -38847,7 +39061,7 @@ var WsClient = class {
|
|
|
38847
39061
|
const guardedPrompt = this.restrictToFolder && this.physicRoot ? folderScopeGuard(this.physicRoot, aiBodyPrompt) : aiBodyPrompt;
|
|
38848
39062
|
const hint = unified ? { credential: startCred ?? workingCred } : { dir: startDir ?? workingDir };
|
|
38849
39063
|
const memCfg = resolveMemoryConfig(config);
|
|
38850
|
-
const firstAttempt = planAiRun(guardedPrompt, config, hint).attempts[0];
|
|
39064
|
+
const firstAttempt = planAiRun(guardedPrompt, config, hint, /* @__PURE__ */ new Map(), oneShot, aiConfig, readOnly).attempts[0];
|
|
38851
39065
|
const resumeId = memCfg.enabled && firstAttempt?.key && firstAttempt.cmd === "claude" ? this.sessionIdByKey.get(firstAttempt.key) : void 0;
|
|
38852
39066
|
let effectivePrompt = guardedPrompt;
|
|
38853
39067
|
let resume = /* @__PURE__ */ new Map();
|
|
@@ -38859,7 +39073,7 @@ ${this.aiMemory}
|
|
|
38859
39073
|
|
|
38860
39074
|
${guardedPrompt}`;
|
|
38861
39075
|
}
|
|
38862
|
-
const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot);
|
|
39076
|
+
const plan = planAiRun(effectivePrompt, config, hint, resume, oneShot, aiConfig, readOnly);
|
|
38863
39077
|
const markerArgs = plan.attempts[0]?.args ?? [];
|
|
38864
39078
|
const startStamp = formatTimestampInZone(/* @__PURE__ */ new Date(), this.orgTimezone);
|
|
38865
39079
|
this.bus.push({ source: origin, kind: "aireq", text: `${startStamp} ${plan.cmd} \u2039 ${prompt}` });
|
|
@@ -39068,7 +39282,7 @@ ${guardedPrompt}`;
|
|
|
39068
39282
|
const info = {
|
|
39069
39283
|
version: CLI_VERSION,
|
|
39070
39284
|
scope: this.bus.scope ?? "project",
|
|
39071
|
-
profile:
|
|
39285
|
+
profile: basename5(this.context.profileDir),
|
|
39072
39286
|
profileDir: this.context.profileDir,
|
|
39073
39287
|
serverUrl: this.context.credential.serverUrl,
|
|
39074
39288
|
physicPath: this.physicRoot ?? config.physicPath ?? null,
|
|
@@ -39398,7 +39612,7 @@ ${guardedPrompt}`;
|
|
|
39398
39612
|
* Used for quota.check before spawning an AI cli (ADR-0020).
|
|
39399
39613
|
*/
|
|
39400
39614
|
request(channel, data) {
|
|
39401
|
-
return new Promise((
|
|
39615
|
+
return new Promise((resolve9, reject) => {
|
|
39402
39616
|
if (!this.socket || !this.sessionKey) {
|
|
39403
39617
|
reject(new Error("Not connected to the server."));
|
|
39404
39618
|
return;
|
|
@@ -39418,7 +39632,7 @@ ${guardedPrompt}`;
|
|
|
39418
39632
|
}, 15e3);
|
|
39419
39633
|
timer.unref?.();
|
|
39420
39634
|
this.pending.set(envelope.id, {
|
|
39421
|
-
resolve: (value) =>
|
|
39635
|
+
resolve: (value) => resolve9(value),
|
|
39422
39636
|
timer
|
|
39423
39637
|
});
|
|
39424
39638
|
this.socket.send(JSON.stringify(envelope));
|
|
@@ -39544,7 +39758,7 @@ ${guardedPrompt}`;
|
|
|
39544
39758
|
const working = getWorkingProfile(this.context.profileDir, aiCli2);
|
|
39545
39759
|
const configured = claudeHomeDirs(config);
|
|
39546
39760
|
const dirs = working ? [working, ...configured.filter((d) => d !== working)] : configured;
|
|
39547
|
-
const profile = working ?
|
|
39761
|
+
const profile = working ? basename5(working) : dirs[0] ? basename5(dirs[0]) : "default";
|
|
39548
39762
|
const api = await checkClaudeUsage(dirs, aiCli2);
|
|
39549
39763
|
const snapshot = api ?? {
|
|
39550
39764
|
plan: "?",
|
|
@@ -42003,7 +42217,7 @@ var src_default = Yoga;
|
|
|
42003
42217
|
|
|
42004
42218
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/reconciler.js
|
|
42005
42219
|
var import_react_reconciler = __toESM(require_react_reconciler(), 1);
|
|
42006
|
-
var
|
|
42220
|
+
var import_constants8 = __toESM(require_constants2(), 1);
|
|
42007
42221
|
import process3 from "process";
|
|
42008
42222
|
|
|
42009
42223
|
// ../../node_modules/.pnpm/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
@@ -43245,7 +43459,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
43245
43459
|
scheduleTimeout: setTimeout,
|
|
43246
43460
|
cancelTimeout: clearTimeout,
|
|
43247
43461
|
noTimeout: -1,
|
|
43248
|
-
getCurrentEventPriority: () =>
|
|
43462
|
+
getCurrentEventPriority: () => import_constants8.DefaultEventPriority,
|
|
43249
43463
|
beforeActiveInstanceBlur() {
|
|
43250
43464
|
},
|
|
43251
43465
|
afterActiveInstanceBlur() {
|
|
@@ -45319,8 +45533,8 @@ var Ink = class {
|
|
|
45319
45533
|
}
|
|
45320
45534
|
}
|
|
45321
45535
|
async waitUntilExit() {
|
|
45322
|
-
this.exitPromise ||= new Promise((
|
|
45323
|
-
this.resolveExitPromise =
|
|
45536
|
+
this.exitPromise ||= new Promise((resolve9, reject) => {
|
|
45537
|
+
this.resolveExitPromise = resolve9;
|
|
45324
45538
|
this.rejectExitPromise = reject;
|
|
45325
45539
|
});
|
|
45326
45540
|
return this.exitPromise;
|
|
@@ -46381,7 +46595,7 @@ async function runStart(profileDir2, profileName) {
|
|
|
46381
46595
|
logger.error("ws.run.crash", { message: e.message, stack: e.stack });
|
|
46382
46596
|
if (client.isStopped) return;
|
|
46383
46597
|
bus.log(`Recovered from an internal error \u2014 reconnecting: ${e.message}`, "error");
|
|
46384
|
-
await new Promise((
|
|
46598
|
+
await new Promise((resolve9) => setTimeout(resolve9, 1e3));
|
|
46385
46599
|
}
|
|
46386
46600
|
}
|
|
46387
46601
|
};
|
|
@@ -46427,7 +46641,7 @@ import { join as join31 } from "path";
|
|
|
46427
46641
|
// src/core/control-client.ts
|
|
46428
46642
|
import { connect as connect2 } from "net";
|
|
46429
46643
|
function connectControl(socketPath, bus) {
|
|
46430
|
-
return new Promise((
|
|
46644
|
+
return new Promise((resolve9, reject) => {
|
|
46431
46645
|
const socket = connect2(socketPath);
|
|
46432
46646
|
socket.setEncoding("utf8");
|
|
46433
46647
|
let ready = false;
|
|
@@ -46474,7 +46688,7 @@ function connectControl(socketPath, bus) {
|
|
|
46474
46688
|
bus.setTokens(frame.tokens);
|
|
46475
46689
|
for (const entry of frame.transcript) bus.pushEntry(entry);
|
|
46476
46690
|
ready = true;
|
|
46477
|
-
|
|
46691
|
+
resolve9({ info: frame.info, close });
|
|
46478
46692
|
break;
|
|
46479
46693
|
case "transcript":
|
|
46480
46694
|
bus.pushEntry(frame.entry);
|
|
@@ -46555,18 +46769,18 @@ async function runAttach(profileDir2, profileName) {
|
|
|
46555
46769
|
// src/commands/ai-login.ts
|
|
46556
46770
|
import { spawn as spawn11 } from "child_process";
|
|
46557
46771
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
46558
|
-
import { basename as
|
|
46772
|
+
import { basename as basename6 } from "path";
|
|
46559
46773
|
function runProviderLogin(cmd, envVar, dir2) {
|
|
46560
|
-
return new Promise((
|
|
46774
|
+
return new Promise((resolve9) => {
|
|
46561
46775
|
const child = spawn11(cmd, [], {
|
|
46562
46776
|
stdio: "inherit",
|
|
46563
46777
|
env: { ...process.env, [envVar]: dir2 }
|
|
46564
46778
|
});
|
|
46565
46779
|
child.on("error", (err) => {
|
|
46566
46780
|
console.error(` \u2716 Could not launch \`${cmd}\` \u2014 is it installed? (${err.message})`);
|
|
46567
|
-
|
|
46781
|
+
resolve9(1);
|
|
46568
46782
|
});
|
|
46569
|
-
child.on("exit", (code) =>
|
|
46783
|
+
child.on("exit", (code) => resolve9(code ?? 0));
|
|
46570
46784
|
});
|
|
46571
46785
|
}
|
|
46572
46786
|
async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
@@ -46579,7 +46793,7 @@ async function runAiLogin(profileDir2, profileName, aiFilter) {
|
|
|
46579
46793
|
return;
|
|
46580
46794
|
}
|
|
46581
46795
|
const selected = aiFilter ? credentials.filter(
|
|
46582
|
-
(c, i) => c.profile === aiFilter ||
|
|
46796
|
+
(c, i) => c.profile === aiFilter || basename6(resolveHomePath(c.profile)) === aiFilter || String(i + 1) === aiFilter
|
|
46583
46797
|
) : credentials;
|
|
46584
46798
|
if (selected.length === 0) {
|
|
46585
46799
|
console.log(`No AI profile matches --ai "${aiFilter}". Available: ${credentials.map((c) => c.profile).join(", ")}`);
|
|
@@ -46712,10 +46926,10 @@ function Picker({
|
|
|
46712
46926
|
] });
|
|
46713
46927
|
}
|
|
46714
46928
|
function selectFromList(items, title) {
|
|
46715
|
-
return new Promise((
|
|
46929
|
+
return new Promise((resolve9) => {
|
|
46716
46930
|
let chosen = null;
|
|
46717
46931
|
const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Picker, { items, title, onDone: (v) => chosen = v }));
|
|
46718
|
-
void app.waitUntilExit().then(() =>
|
|
46932
|
+
void app.waitUntilExit().then(() => resolve9(chosen));
|
|
46719
46933
|
});
|
|
46720
46934
|
}
|
|
46721
46935
|
|