mu-agent 0.1.10 → 0.1.13
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/CHANGELOG.md +94 -0
- package/README.md +6 -6
- package/dist/bundle/chunks/{chunk-O7IPTASE.js → chunk-3J3HSHLX.js} +22 -21
- package/dist/bundle/chunks/{chunk-DNNHZBQR.js → chunk-6Z2347ML.js} +1 -1
- package/dist/bundle/chunks/{chunk-X234222Q.js → chunk-DYTENXHX.js} +2 -2
- package/dist/bundle/chunks/{chunk-RAQ6TU76.js → chunk-FLHKNMLQ.js} +1 -1
- package/dist/bundle/chunks/chunk-LHRPMXVI.js +2 -0
- package/dist/bundle/chunks/{chunk-HZNN636Z.js → chunk-LT2C56HV.js} +1 -1
- package/dist/bundle/chunks/{chunk-SGOTYFMT.js → chunk-MF3VB62R.js} +1 -1
- package/dist/bundle/chunks/{chunk-QOEEJKS4.js → chunk-URBBMV3M.js} +1 -1
- package/dist/bundle/chunks/{chunk-VJLOQZKR.js → chunk-WCJNJQO5.js} +1 -1
- package/dist/bundle/chunks/{chunk-FN6OEZYR.js → chunk-WDURT4ZM.js} +1 -1
- package/dist/bundle/chunks/{cli-722OL3K5.js → cli-M4YBZZ6Q.js} +1 -1
- package/dist/bundle/chunks/{easter-egg-3d-6H34EDGX.js → easter-egg-3d-VFY3YRQR.js} +1 -1
- package/dist/bundle/chunks/{execute-KVSEIDWL.js → execute-FKI7Y4XR.js} +1 -1
- package/dist/bundle/chunks/{runtime-O3ELDOM7.js → runtime-IKE5OQIW.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-IKEARUOZ.js → virtual-modules-TJPHLTRT.js} +1 -1
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/docs/settings.md +1 -1
- package/judge/dist/auth.js +51 -26
- package/judge/dist/chrome.js +2 -2
- package/judge/dist/import.js +833 -161
- package/judge/dist/setup.js +129 -46
- package/judge/manifest.json +1935 -349
- package/judge/mu/chunk-3NQ5BIBI.js +4773 -0
- package/judge/mu/chunk-SKGYWHW6.js +51 -0
- package/judge/mu/chunk-WQM4MV6L.js +58 -0
- package/judge/mu/cloud-code-V7FOGB4J.js +22802 -0
- package/judge/mu/dist-75PS4OC4.js +1283 -0
- package/judge/mu/index.js +4509 -32801
- package/judge/mu/multipart-parser-ZDXVIOOP.js +372 -0
- package/judge/mu/src-TVVA5ZK2.js +1409 -0
- package/kyrn/bin/kyrn-doctor +28 -3
- package/kyrn/bin/kyrn-judge-local +42 -13
- package/kyrn/bin/kyrn-ledger +16 -1
- package/kyrn/bin/mu.mjs +77 -23
- package/kyrn/local-judge/server.py +26 -14
- package/package.json +6 -3
- package/dist/bundle/chunks/chunk-BSS6T6KQ.js +0 -2
package/kyrn/bin/kyrn-doctor
CHANGED
|
@@ -330,12 +330,37 @@ row(
|
|
|
330
330
|
"browse",
|
|
331
331
|
[browseTiers].flat().some(canRelate)
|
|
332
332
|
? `driven by ${[browseTiers].flat().join(" > ")}`
|
|
333
|
-
: 'needs a judge that can match a goal to a page. In mu.json: "routes": { "browser.step": ["llm:openai
|
|
333
|
+
: 'needs a judge that can match a goal to a page. In mu.json: "routes": { "browser.step": ["llm:openai/gpt-5.6-luna"] }',
|
|
334
334
|
);
|
|
335
335
|
|
|
336
336
|
const marks = { ok: "\x1b[32m ok\x1b[0m", fix: "\x1b[33mfix\x1b[0m", "--": "\x1b[2m ·\x1b[0m" };
|
|
337
337
|
const plain = !process.stdout.isTTY;
|
|
338
|
+
/** Where a row's text starts: the mark, two spaces, the name's column. */
|
|
339
|
+
const TEXT_COLUMN = 18;
|
|
340
|
+
/** `text` broken between words into lines at most `size` wide; without a terminal, one line. */
|
|
341
|
+
function wrap(text, size) {
|
|
342
|
+
if (!size || size < 20) return [text];
|
|
343
|
+
const lines = [];
|
|
344
|
+
let line = "";
|
|
345
|
+
for (const word of text.split(" ")) {
|
|
346
|
+
if (line && line.length + 1 + word.length > size) {
|
|
347
|
+
lines.push(line);
|
|
348
|
+
line = word;
|
|
349
|
+
} else line = line ? `${line} ${word}` : word;
|
|
350
|
+
}
|
|
351
|
+
return [...lines, line];
|
|
352
|
+
}
|
|
353
|
+
// In a terminal, what needs doing comes first, as in /doctor inside mu; piped, every line is a row.
|
|
354
|
+
const fixes = rows.filter(([state]) => state === "fix").length;
|
|
355
|
+
if (!plain) {
|
|
356
|
+
console.log(
|
|
357
|
+
fixes > 0 ? `mu doctor found ${fixes} ${fixes === 1 ? "thing" : "things"} to fix` : "mu doctor: everything is set up",
|
|
358
|
+
);
|
|
359
|
+
}
|
|
338
360
|
for (const [state, name, text] of rows) {
|
|
339
|
-
|
|
361
|
+
// In a terminal, a long row continues under its own text rather than at the left edge.
|
|
362
|
+
const [first, ...rest] = wrap(text, plain ? undefined : process.stdout.columns - TEXT_COLUMN - 1);
|
|
363
|
+
console.log(`${plain ? state.padStart(3) : marks[state]} ${name.padEnd(13)}${first}`);
|
|
364
|
+
for (const line of rest) console.log(`${" ".repeat(TEXT_COLUMN)}${line}`);
|
|
340
365
|
}
|
|
341
|
-
process.exit(
|
|
366
|
+
process.exit(fixes > 0 ? 1 : 0);
|
|
@@ -34,17 +34,17 @@ is_up() { [[ "$(health)" == *'"status"'* ]]; }
|
|
|
34
34
|
|
|
35
35
|
require_setup() {
|
|
36
36
|
if [[ ! -x "$PYTHON" || ! -f "$MODEL_DIR/coreml_config.json" ]]; then
|
|
37
|
-
echo "The local judge
|
|
37
|
+
echo "The local judge isn't installed yet. Run: mu judge setup" >&2
|
|
38
38
|
exit 1
|
|
39
39
|
fi
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
cmd_setup() {
|
|
43
43
|
if [[ "$(uname -s)-$(uname -m)" != "Darwin-arm64" ]]; then
|
|
44
|
-
echo "
|
|
44
|
+
echo "The local judge needs a Mac with Apple silicon and macOS 15 or later." >&2
|
|
45
45
|
exit 1
|
|
46
46
|
fi
|
|
47
|
-
command -v uv >/dev/null || { echo "
|
|
47
|
+
command -v uv >/dev/null || { echo "mu judge setup needs uv: https://docs.astral.sh/uv/" >&2; exit 1; }
|
|
48
48
|
mkdir -p "$STATE_DIR"
|
|
49
49
|
[[ -x "$PYTHON" ]] || uv venv --python 3.12 "$STATE_DIR/.venv"
|
|
50
50
|
# The official index on purpose: mirrors lag behind new releases.
|
|
@@ -72,7 +72,7 @@ from laya_coreml.artifacts import verify_files
|
|
|
72
72
|
directory = Path(sys.argv[1])
|
|
73
73
|
manifest = json.loads((directory / "coreml_config.json").read_text())
|
|
74
74
|
verify_files(directory, manifest["files"])
|
|
75
|
-
print(f"
|
|
75
|
+
print(f"Weights checked against the bundle's manifest ({len(manifest['files'])} files).")
|
|
76
76
|
PY
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -84,7 +84,7 @@ cmd_run() {
|
|
|
84
84
|
cmd_start() {
|
|
85
85
|
require_setup
|
|
86
86
|
if is_up; then
|
|
87
|
-
echo "local judge already running at $URL"
|
|
87
|
+
echo "The local judge is already running at $URL."
|
|
88
88
|
return 0
|
|
89
89
|
fi
|
|
90
90
|
mkdir -p "$RUN_DIR"
|
|
@@ -92,25 +92,25 @@ cmd_start() {
|
|
|
92
92
|
echo $! >"$PID_FILE"
|
|
93
93
|
for _ in $(seq 1 120); do
|
|
94
94
|
if is_ready; then
|
|
95
|
-
echo "local judge ready at $URL (pid $(cat "$PID_FILE"), log $LOG_FILE)"
|
|
95
|
+
echo "The local judge is ready at $URL (pid $(cat "$PID_FILE"), log $LOG_FILE)."
|
|
96
96
|
return 0
|
|
97
97
|
fi
|
|
98
98
|
if ! kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
|
|
99
|
-
echo "local judge
|
|
99
|
+
echo "The local judge stopped while starting; see $LOG_FILE" >&2
|
|
100
100
|
tail -5 "$LOG_FILE" >&2 || true
|
|
101
101
|
return 1
|
|
102
102
|
fi
|
|
103
103
|
sleep 0.5
|
|
104
104
|
done
|
|
105
|
-
echo "local judge is still warming up; see $LOG_FILE" >&2
|
|
105
|
+
echo "The local judge is still warming up; see $LOG_FILE" >&2
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
cmd_stop() {
|
|
109
109
|
if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
|
|
110
110
|
kill "$(cat "$PID_FILE")"
|
|
111
|
-
echo "
|
|
111
|
+
echo "Stopped the local judge (pid $(cat "$PID_FILE"))."
|
|
112
112
|
else
|
|
113
|
-
echo "local judge
|
|
113
|
+
echo "The local judge isn't running."
|
|
114
114
|
fi
|
|
115
115
|
rm -f "$PID_FILE"
|
|
116
116
|
}
|
|
@@ -118,7 +118,35 @@ cmd_stop() {
|
|
|
118
118
|
cmd_status() {
|
|
119
119
|
local body
|
|
120
120
|
body="$(health)"
|
|
121
|
-
if [[ -
|
|
121
|
+
if [[ -z "$body" ]]; then echo "The local judge isn't running at $URL."; return 1; fi
|
|
122
|
+
# --json: the server's own answer, for scripts.
|
|
123
|
+
if [[ "${1:-}" == "--json" ]]; then echo "$body"; return 0; fi
|
|
124
|
+
URL="$URL" node -e '
|
|
125
|
+
let text = "";
|
|
126
|
+
process.stdin.on("data", (chunk) => (text += chunk)).on("end", () => {
|
|
127
|
+
let health;
|
|
128
|
+
try { health = JSON.parse(text); } catch { console.log(text.trim()); return; }
|
|
129
|
+
const up = Math.round((health.uptimeSeconds ?? 0) / 60);
|
|
130
|
+
const uptime = up < 60 ? `${up} min` : `${Math.floor(up / 60)} h ${up % 60} min`;
|
|
131
|
+
const state = health.status === "ok" ? "running" : `starting (${health.status})`;
|
|
132
|
+
const model = String(health.model ?? "").split("/").pop();
|
|
133
|
+
console.log(`The local judge is ${state} at ${process.env.URL}: ${model} on ${health.computeUnits}, pid ${health.pid}, up ${uptime}, ${health.requests} requests.`);
|
|
134
|
+
});' <<<"$body"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
usage() {
|
|
138
|
+
cat <<'USAGE'
|
|
139
|
+
mu judge: the local judge, Laya, on Core ML (macOS on Apple silicon).
|
|
140
|
+
|
|
141
|
+
mu judge setup install it: a Python environment and the weights (about 680 MB)
|
|
142
|
+
mu judge start start it in the background, unless it's already running
|
|
143
|
+
mu judge stop stop it
|
|
144
|
+
mu judge status [--json] whether it's running, and what it serves
|
|
145
|
+
mu judge run run it in the foreground
|
|
146
|
+
|
|
147
|
+
One local judge serves every mu session on this machine. To have mu ask it, add "laya" to "tiers" in
|
|
148
|
+
mu.json, or start mu with MU_JUDGE=laya.
|
|
149
|
+
USAGE
|
|
122
150
|
}
|
|
123
151
|
|
|
124
152
|
case "${1:-status}" in
|
|
@@ -126,6 +154,7 @@ case "${1:-status}" in
|
|
|
126
154
|
run) shift; cmd_run "$@" ;;
|
|
127
155
|
start) cmd_start ;;
|
|
128
156
|
stop) cmd_stop ;;
|
|
129
|
-
status) cmd_status ;;
|
|
130
|
-
|
|
157
|
+
status) shift; cmd_status "$@" ;;
|
|
158
|
+
help | -h | --help) usage ;;
|
|
159
|
+
*) usage >&2; exit 2 ;;
|
|
131
160
|
esac
|
package/kyrn/bin/kyrn-ledger
CHANGED
|
@@ -12,6 +12,20 @@ import { homedir } from "node:os";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
14
|
const args = process.argv.slice(2);
|
|
15
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
16
|
+
console.log(
|
|
17
|
+
[
|
|
18
|
+
"mu ledger: the judge's verdicts from your recent sessions, each with the message it judged.",
|
|
19
|
+
"",
|
|
20
|
+
" mu ledger verdicts from the 5 most recent sessions",
|
|
21
|
+
" mu ledger <n> from the n most recent",
|
|
22
|
+
" mu ledger --json one JSON object per verdict, for scripts",
|
|
23
|
+
"",
|
|
24
|
+
"It reads the session files mu keeps on this machine; nothing is sent anywhere.",
|
|
25
|
+
].join("\n"),
|
|
26
|
+
);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
15
29
|
const asJson = args.includes("--json");
|
|
16
30
|
const limit = Number(args.find((arg) => /^\d+$/.test(arg)) ?? 5);
|
|
17
31
|
/** `MU_<name>`, or the `KYRN_<name>` spelling from before the rename. */
|
|
@@ -87,4 +101,5 @@ for (const file of files) {
|
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
|
|
90
|
-
|
|
104
|
+
const tilde = (path) => (path.startsWith(homedir()) ? `~${path.slice(homedir().length)}` : path);
|
|
105
|
+
if (!asJson) console.log(count === 0 ? `No verdicts found under ${tilde(sessionsDir)}` : `\n${count} ${count === 1 ? "verdict" : "verdicts"} from ${files.length} ${files.length === 1 ? "session" : "sessions"}`);
|
package/kyrn/bin/mu.mjs
CHANGED
|
@@ -104,7 +104,7 @@ export function usage(platform) {
|
|
|
104
104
|
" (see mu setup --help for scripting, reading a key from stdin and the supported services)",
|
|
105
105
|
" mu judge <cmd> manage the local judge, Laya (macOS on Apple silicon): setup | start | stop | status | run",
|
|
106
106
|
" mu ledger [n] [--json] print the judge's verdicts from the last n sessions",
|
|
107
|
-
" mu import
|
|
107
|
+
" mu import <file>... import Claude Code, Codex and ZCode conversations; --list shows them (mu import --help)",
|
|
108
108
|
" mu doctor check the installation, the judges and the connections",
|
|
109
109
|
" mu auth <cmd> sign-in helper for the desktop app (JSON lines):",
|
|
110
110
|
" status | login <provider> | logout <provider>",
|
|
@@ -431,7 +431,7 @@ export function localJudgeSupport({ platform, env, wsl = false }) {
|
|
|
431
431
|
url,
|
|
432
432
|
message: [
|
|
433
433
|
`The local judge (Laya) is a Core ML sidecar that runs only on macOS on Apple silicon, not on ${where}.`,
|
|
434
|
-
"mu works without it: Jev answers
|
|
434
|
+
"mu works without it: Jev, the default hosted judge, answers instead (free on OpenCode Zen, or with your own key via mu setup); you can also set an LLM judge in mu.json.",
|
|
435
435
|
"A local judge for the desktop app is in progress. Without a judge, decision points use their fallbacks.",
|
|
436
436
|
"To use a server that implements the same API (GET /health, POST /evaluate), set:",
|
|
437
437
|
" MU_LOCAL_JUDGE_URL=http://host:port",
|
|
@@ -451,12 +451,14 @@ export function launchStrategy({ platform, env, canExec }) {
|
|
|
451
451
|
* The judgment layer never runs for them, so its extension stays out of their way. */
|
|
452
452
|
function judgeArgs({ argv, layout, root, platform, agentDir, readFile }) {
|
|
453
453
|
if (PI_COMMANDS.has(argv[0])) return [];
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
return
|
|
454
|
+
return ["-e", judgeExtension({ layout, root, platform }), ...themeArgs({ argv, layout, root, platform, agentDir, readFile })];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** The judgment layer's extension file: the package's build, or a checkout's source. */
|
|
458
|
+
function judgeExtension({ layout, root, platform }) {
|
|
459
|
+
return layout === "package"
|
|
460
|
+
? packageEntries({ root, platform }).extension
|
|
461
|
+
: pathFor(platform).join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts");
|
|
460
462
|
}
|
|
461
463
|
|
|
462
464
|
/** mu's own terminal themes, beside the judgment layer's files. */
|
|
@@ -538,6 +540,8 @@ export function planLaunch({
|
|
|
538
540
|
if (typeof value === "string") childEnv[key] = value;
|
|
539
541
|
}
|
|
540
542
|
childEnv.PI_PACKAGE_DIR = appDir;
|
|
543
|
+
// The judgment layer is part of mu, not an extension loaded for this run: pi shows its commands without [t].
|
|
544
|
+
childEnv.PI_APP_EXTENSIONS = judgeExtension({ layout, root, platform });
|
|
541
545
|
childEnv.MU_CODING_AGENT_DIR = agentDir;
|
|
542
546
|
childEnv.KYRN_CODING_AGENT_DIR = agentDir;
|
|
543
547
|
childEnv.PI_CODING_AGENT_DIR = agentDir;
|
|
@@ -553,7 +557,7 @@ export function planLaunch({
|
|
|
553
557
|
if (support.runs) startJudge = true;
|
|
554
558
|
else if (!support.url) {
|
|
555
559
|
notes.push(
|
|
556
|
-
`mu: the configuration asks for the local judge (Laya), which runs on macOS only; on ${platformName({ platform, wsl })}
|
|
560
|
+
`mu: the configuration asks for the local judge (Laya), which runs on macOS only; on ${platformName({ platform, wsl })}, the decision points it would answer use the next judge or their fallbacks (mu judge status)`,
|
|
557
561
|
);
|
|
558
562
|
}
|
|
559
563
|
}
|
|
@@ -579,6 +583,9 @@ export function planLaunch({
|
|
|
579
583
|
* Node flags that process starts with, pi's arguments (the judgment layer, then `argv`) and its whole environment.
|
|
580
584
|
* The app's pi and the command line's are then one: the same files, settings, sign-ins and keys.
|
|
581
585
|
*
|
|
586
|
+
* `cli` is the script the command line runs pi with. pi starts its sub-agents (swarm, hive, delegate) by running
|
|
587
|
+
* `process.argv[1]` again, which inside the host is the host's own file: the host hands pi this script there instead.
|
|
588
|
+
*
|
|
582
589
|
* A checkout runs there as it runs on the command line (sourceRuntime). Returns { error } when pi cannot run.
|
|
583
590
|
*/
|
|
584
591
|
export function planHost({ platform, env, argv, root, home, fs, wsl = false, stripsTypes = true }) {
|
|
@@ -598,6 +605,7 @@ export function planHost({ platform, env, argv, root, home, fs, wsl = false, str
|
|
|
598
605
|
return {
|
|
599
606
|
...common,
|
|
600
607
|
module: path.join(root, "dist", "bundle", "index.js"),
|
|
608
|
+
cli: packageEntries({ root, platform }).cli,
|
|
601
609
|
execArgv: [],
|
|
602
610
|
args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
|
|
603
611
|
};
|
|
@@ -607,6 +615,7 @@ export function planHost({ platform, env, argv, root, home, fs, wsl = false, str
|
|
|
607
615
|
return {
|
|
608
616
|
...common,
|
|
609
617
|
module: path.join(root, "packages", "coding-agent", "src", "index.ts"),
|
|
618
|
+
cli: path.join(root, "packages", "coding-agent", "src", "cli.ts"),
|
|
610
619
|
execArgv: runtime.args,
|
|
611
620
|
args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
|
|
612
621
|
};
|
|
@@ -668,6 +677,29 @@ export async function prepareLaunchAsync({ plan, platform, root, bin, err }) {
|
|
|
668
677
|
/** What `mu auth` answers itself. Every other `auth` command (check, print-api-key, ...) is pi's own. */
|
|
669
678
|
export const AUTH_COMMANDS = ["status", "login", "logout"];
|
|
670
679
|
|
|
680
|
+
/** `mu link --help` and `mu unlink --help`. */
|
|
681
|
+
export const LINK_USAGE = [
|
|
682
|
+
"mu link: put this mu on your PATH, as a link in ~/.local/bin (on Windows, a small mu.cmd there). MU_LINK_DIR",
|
|
683
|
+
"names another folder.",
|
|
684
|
+
"",
|
|
685
|
+
" mu link link this mu, unless another mu is already on your PATH",
|
|
686
|
+
" mu link --force link it anyway (it comes first only if its folder comes first on your PATH)",
|
|
687
|
+
" mu unlink remove the link mu link made",
|
|
688
|
+
"",
|
|
689
|
+
"A mu installed with npm is already on your PATH and needs neither.",
|
|
690
|
+
].join("\n");
|
|
691
|
+
|
|
692
|
+
/** What `mu auth --help` (or a bare `mu auth`) says before pi's own auth commands. */
|
|
693
|
+
export const AUTH_USAGE = [
|
|
694
|
+
"mu's sign-in, which the desktop app runs (JSON lines on stdout):",
|
|
695
|
+
" mu auth status",
|
|
696
|
+
" mu auth login <provider>",
|
|
697
|
+
" mu auth logout <provider>",
|
|
698
|
+
"In a terminal, /login inside mu signs in the same way.",
|
|
699
|
+
"",
|
|
700
|
+
"pi's auth commands:",
|
|
701
|
+
].join("\n");
|
|
702
|
+
|
|
671
703
|
/**
|
|
672
704
|
* `mu auth status | login <provider> | logout <provider>`: the sign-in the desktop app runs, with pi's own OAuth
|
|
673
705
|
* flows and credential store (packages/kyrn-judge/src/auth). It is pi's code, so it runs the way pi does here:
|
|
@@ -715,7 +747,7 @@ export function planJudge({ platform, env, argv, bin, wsl = false }) {
|
|
|
715
747
|
// ---------------------------------------------------------------------------------------------------------
|
|
716
748
|
|
|
717
749
|
/**
|
|
718
|
-
* `mu import`: Claude Code and
|
|
750
|
+
* `mu import`: Claude Code, Codex and ZCode conversations into mu's sessions (packages/kyrn-judge/src/import). The importer
|
|
719
751
|
* needs nothing but Node: the npm package runs its build, judge/dist/import.js, and a checkout its TypeScript with
|
|
720
752
|
* Node's own type stripping (on by default from 22.18).
|
|
721
753
|
*/
|
|
@@ -753,6 +785,17 @@ export const SETUP_DECLINED_FILE = "setup-declined";
|
|
|
753
785
|
/** How `mu setup` says: set up, and start a session now. */
|
|
754
786
|
export const SETUP_EXIT_START = 3;
|
|
755
787
|
|
|
788
|
+
/** How `mu setup` says: a subscription was chosen, so start a session that opens on /login. */
|
|
789
|
+
export const SETUP_EXIT_SIGN_IN = 4;
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* What the session is started with after the wizard ended with `code`: /login after a subscription was chosen, unless
|
|
793
|
+
* the command line already says what to do.
|
|
794
|
+
*/
|
|
795
|
+
export function afterSetup(code, argv) {
|
|
796
|
+
return code === SETUP_EXIT_SIGN_IN && argv.length === 0 ? ["/login"] : argv;
|
|
797
|
+
}
|
|
798
|
+
|
|
756
799
|
/** How `mu setup` says it was cancelled (ctrl+c): a first start then goes no further. */
|
|
757
800
|
export const SETUP_EXIT_CANCELLED = 130;
|
|
758
801
|
|
|
@@ -1073,12 +1116,12 @@ export function planUnlink({ platform, env, home, fs }) {
|
|
|
1073
1116
|
text = fs.readFile(link);
|
|
1074
1117
|
} catch {}
|
|
1075
1118
|
return text?.includes(SHIM_MARK)
|
|
1076
|
-
? { remove: link, message: `
|
|
1077
|
-
: { message: `${link} is not a shim written by mu link; nothing removed
|
|
1119
|
+
? { remove: link, message: `Removed ${link}.` }
|
|
1120
|
+
: { message: `${link} is not a shim written by mu link; nothing removed.` };
|
|
1078
1121
|
}
|
|
1079
1122
|
return fs.isLink(link)
|
|
1080
|
-
? { remove: link, message: `
|
|
1081
|
-
: { message: `${link} is not a link; nothing removed
|
|
1123
|
+
? { remove: link, message: `Removed ${link}.` }
|
|
1124
|
+
: { message: `${link} is not a link; nothing removed.` };
|
|
1082
1125
|
}
|
|
1083
1126
|
|
|
1084
1127
|
/** What `mu doctor` says about the command. */
|
|
@@ -1249,7 +1292,7 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
|
|
|
1249
1292
|
}
|
|
1250
1293
|
if (found.browser.length > 0) busy.push(` the mu browser (pid ${list(found.browser)}). Close it.`);
|
|
1251
1294
|
if (found.desktop.length > 0) {
|
|
1252
|
-
busy.push(` the desktop app's
|
|
1295
|
+
busy.push(` the desktop app's local service (pid ${list(found.desktop)}). Quit the desktop app.`);
|
|
1253
1296
|
}
|
|
1254
1297
|
if (busy.length > 0) {
|
|
1255
1298
|
err(`Nothing was moved, because these are still using ${old}:`);
|
|
@@ -1390,6 +1433,8 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1390
1433
|
out(usage(platform));
|
|
1391
1434
|
return 0;
|
|
1392
1435
|
}
|
|
1436
|
+
// mu's own auth commands first; pi prints its own after them.
|
|
1437
|
+
if (command === "auth" && (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h")) out(AUTH_USAGE);
|
|
1393
1438
|
if (command === "auth" && AUTH_COMMANDS.includes(rest[0])) {
|
|
1394
1439
|
const plan = planAuth({
|
|
1395
1440
|
platform,
|
|
@@ -1498,8 +1543,8 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1498
1543
|
if (plan.keyGiven) process.title = "mu setup";
|
|
1499
1544
|
mkdirSync(plan.agentDir, { recursive: true });
|
|
1500
1545
|
const code = await handOver(plan);
|
|
1501
|
-
if (code !== SETUP_EXIT_START) return code;
|
|
1502
|
-
sessionArgv = [];
|
|
1546
|
+
if (code !== SETUP_EXIT_START && code !== SETUP_EXIT_SIGN_IN) return code;
|
|
1547
|
+
sessionArgv = afterSetup(code, []);
|
|
1503
1548
|
}
|
|
1504
1549
|
if (command === "doctor") {
|
|
1505
1550
|
const link = linkPath({ platform, env, home });
|
|
@@ -1510,8 +1555,12 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1510
1555
|
strategy,
|
|
1511
1556
|
});
|
|
1512
1557
|
}
|
|
1558
|
+
if ((command === "link" || command === "unlink") && (rest[0] === "--help" || rest[0] === "-h")) {
|
|
1559
|
+
out(LINK_USAGE);
|
|
1560
|
+
return 0;
|
|
1561
|
+
}
|
|
1513
1562
|
if ((command === "link" || command === "unlink") && layout === "package") {
|
|
1514
|
-
out("This mu was installed with npm, which already put `mu` on your PATH (npm i -g mu-agent); nothing to
|
|
1563
|
+
out("This mu was installed with npm, which already put `mu` on your PATH (npm i -g mu-agent); nothing to do.");
|
|
1515
1564
|
return 0;
|
|
1516
1565
|
}
|
|
1517
1566
|
if (command === "link") {
|
|
@@ -1544,9 +1593,10 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1544
1593
|
return 0;
|
|
1545
1594
|
}
|
|
1546
1595
|
|
|
1547
|
-
|
|
1596
|
+
// --version is the bare number, in the npm package as in a checkout (below).
|
|
1597
|
+
if (layout === "package" && (command === "version" || command === "--version" || command === "-v")) {
|
|
1548
1598
|
const pkg = JSON.parse(readText(path.join(root, "package.json")));
|
|
1549
|
-
out(`mu ${pkg.version} (pi ${pkg.muBuild?.pi ?? "?"}, npm package ${pkg.name})`);
|
|
1599
|
+
out(command === "version" ? `mu ${pkg.version} (pi ${pkg.muBuild?.pi ?? "?"}, npm package ${pkg.name})` : pkg.version);
|
|
1550
1600
|
return 0;
|
|
1551
1601
|
}
|
|
1552
1602
|
// Asked before `version` too, as it always was: a checkout without its dependencies says so at the first command.
|
|
@@ -1554,10 +1604,12 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1554
1604
|
err(installHint({ root, platform }));
|
|
1555
1605
|
return 1;
|
|
1556
1606
|
}
|
|
1557
|
-
if (command === "version") {
|
|
1607
|
+
if (command === "version" || command === "--version" || command === "-v") {
|
|
1558
1608
|
// mu's version is the one this tree is released as; the judgment layer's own package.json is never released.
|
|
1559
1609
|
const version = (file) => JSON.parse(readText(path.join(root, ...file.split("/")))).version;
|
|
1560
|
-
|
|
1610
|
+
const mu = version("kyrn/npm/package.template.json");
|
|
1611
|
+
// --version is the bare number, as the npm package's pi bundle prints it; pi's own here would be pi's version.
|
|
1612
|
+
out(command === "version" ? `mu ${mu} (pi ${version("packages/coding-agent/package.json")})` : mu);
|
|
1561
1613
|
return 0;
|
|
1562
1614
|
}
|
|
1563
1615
|
|
|
@@ -1591,7 +1643,9 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1591
1643
|
if (!setup.error) {
|
|
1592
1644
|
mkdirSync(setup.agentDir, { recursive: true });
|
|
1593
1645
|
// Whatever the wizard ends with, the session follows (pi says itself when there is no model), unless it was cancelled.
|
|
1594
|
-
|
|
1646
|
+
const code = await handOver(setup);
|
|
1647
|
+
if (code === SETUP_EXIT_CANCELLED) return SETUP_EXIT_CANCELLED;
|
|
1648
|
+
sessionArgv = afterSetup(code, sessionArgv);
|
|
1595
1649
|
}
|
|
1596
1650
|
}
|
|
1597
1651
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Serves a Laya Core ML checkpoint (https://github.com/mizorewww/laya-coreml) over
|
|
5
5
|
the same wire contract as the AI Gateway `evaluation-model` endpoint, so the
|
|
6
|
-
mu kernel can swap
|
|
6
|
+
mu kernel can swap the hosted judge model for a local one without translating anything:
|
|
7
7
|
|
|
8
8
|
POST /evaluate {"state": ..., "questions": {id: {type, instructions, criteria?}}}
|
|
9
9
|
-> {"answers": {...}, "usage": {...}, "warnings": [...], "providerMetadata": {"laya": {...}}}
|
|
@@ -27,9 +27,16 @@ from pathlib import Path
|
|
|
27
27
|
DEFAULT_HOST = "127.0.0.1"
|
|
28
28
|
DEFAULT_PORT = 47823
|
|
29
29
|
MAX_BODY_BYTES = 1024 * 1024
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
|
|
30
|
+
# Every request is padded to at least this many tokens; by default (None) to the checkpoint's whole window, so that
|
|
31
|
+
# after warm-up the input length never changes. A change of length is what crashed the sidecar: Core ML re-specializes
|
|
32
|
+
# the GPU program from its compiled copy of the model in ~/Library/Caches/<process>/com.apple.e5rt.e5bundlecache,
|
|
33
|
+
# which it marks APFS-purgeable, and macOS deletes those files whenever the disk runs low. The next change of length
|
|
34
|
+
# then recompiles the model (3-36 s, 644 MB written again) or, when the purge lands mid-load, aborts the process with
|
|
35
|
+
# "MPSGraphTensorData.mm: failed assertion `shape.count = 0 != strides.count = 2'". Measured on an M6 under load:
|
|
36
|
+
# 1024 tokens cost ~34 ms a question at a steady length against ~23-32 ms for 384-768, while a change of length
|
|
37
|
+
# cost 0.4-1.1 s at p50 and up to 18 s at p90. A lower floor (MU_LOCAL_JUDGE_MIN_LENGTH=256) is faster for short
|
|
38
|
+
# requests and brings the changes of length back.
|
|
39
|
+
DEFAULT_MIN_LENGTH = None
|
|
33
40
|
DEFAULT_MODEL_DIR = Path(__file__).resolve().parent / "models" / "laya-multilingual-coreml"
|
|
34
41
|
|
|
35
42
|
|
|
@@ -88,11 +95,10 @@ def from_laya_answer(answer):
|
|
|
88
95
|
|
|
89
96
|
|
|
90
97
|
class LocalJudge:
|
|
91
|
-
def __init__(self, model_dir, compute_units=None, min_length=
|
|
98
|
+
def __init__(self, model_dir, compute_units=None, min_length=DEFAULT_MIN_LENGTH):
|
|
92
99
|
import laya_coreml as laya
|
|
93
100
|
|
|
94
101
|
self.model_dir = Path(model_dir)
|
|
95
|
-
self.min_length = min_length
|
|
96
102
|
started = time.perf_counter()
|
|
97
103
|
self.agent = laya.load(str(self.model_dir), local_files_only=True, compute_units=compute_units)
|
|
98
104
|
self.load_seconds = time.perf_counter() - started
|
|
@@ -103,15 +109,19 @@ class LocalJudge:
|
|
|
103
109
|
manifest = getattr(self.agent, "manifest", {})
|
|
104
110
|
self.model_id = "laya:" + str(manifest.get("repository") or self.model_dir.name)
|
|
105
111
|
self.shape = getattr(self.agent, "shape", {})
|
|
112
|
+
if min_length is None:
|
|
113
|
+
min_length = getattr(self.agent, "cfg", {}).get("max_len") or self.shape.get("max_length") or 0
|
|
114
|
+
self.min_length = int(min_length)
|
|
106
115
|
|
|
107
116
|
def uniform_shape(self, state, laya_questions):
|
|
108
117
|
"""Pad every question of a request to one input length.
|
|
109
118
|
|
|
110
119
|
Core ML re-specializes the GPU program whenever the enumerated length
|
|
111
|
-
changes (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
changes (0.3-1 s, against ~30 ms for a steady shape), reading the
|
|
121
|
+
compiled model back from a cache macOS may have purged (see
|
|
122
|
+
DEFAULT_MIN_LENGTH). The questions of one request differ in length
|
|
123
|
+
because their options do, so one bucket per request removes the
|
|
124
|
+
changes within it; the floor keeps every request in the same bucket.
|
|
115
125
|
"""
|
|
116
126
|
lengths = self.agent.shape.get("lengths")
|
|
117
127
|
if not lengths:
|
|
@@ -199,9 +209,10 @@ class LocalJudge:
|
|
|
199
209
|
def warm_up(self):
|
|
200
210
|
"""Core ML compiles each enumerated input length on first use (seconds). Pay that before real traffic."""
|
|
201
211
|
lengths = list(self.shape.get("lengths") or [self.shape.get("default_length", 128)])
|
|
202
|
-
#
|
|
212
|
+
# Requests are padded to at least the floor's bucket, so no request uses a shorter one: warm only the lengths
|
|
213
|
+
# traffic can reach, and finish on the floor's bucket, so the first request does not pay a shape switch.
|
|
203
214
|
resting = next((n for n in lengths if n >= self.min_length), lengths[-1])
|
|
204
|
-
lengths = [n for n in lengths if n
|
|
215
|
+
lengths = [n for n in lengths if n > resting] + [resting]
|
|
205
216
|
question = {"warm": {"type": "noul", "instructions": "Is this a warm-up request?"}}
|
|
206
217
|
started = time.perf_counter()
|
|
207
218
|
for length in lengths:
|
|
@@ -299,8 +310,9 @@ def main():
|
|
|
299
310
|
parser.add_argument(
|
|
300
311
|
"--min-length",
|
|
301
312
|
type=int,
|
|
302
|
-
default=
|
|
303
|
-
help="Smallest input length to pad to.
|
|
313
|
+
default=setting("LOCAL_JUDGE_MIN_LENGTH", DEFAULT_MIN_LENGTH),
|
|
314
|
+
help="Smallest input length to pad to. Default: the checkpoint's window, so the length never changes after "
|
|
315
|
+
"warm-up; a change of length is slow and, when macOS has purged Core ML's cache, can crash the sidecar.",
|
|
304
316
|
)
|
|
305
317
|
args = parser.parse_args()
|
|
306
318
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "mu: a coding agent that hands its routine decisions to a small, fast judge model, so the main model can keep its attention on the work. Built on pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,13 +12,16 @@
|
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
14
|
"coding-agent",
|
|
15
|
+
"pi-coding-agent",
|
|
15
16
|
"ai",
|
|
16
17
|
"llm",
|
|
17
18
|
"cli",
|
|
18
19
|
"terminal",
|
|
19
20
|
"agent",
|
|
20
21
|
"judge",
|
|
21
|
-
"pi"
|
|
22
|
+
"pi",
|
|
23
|
+
"mcp",
|
|
24
|
+
"prompt-injection"
|
|
22
25
|
],
|
|
23
26
|
"homepage": "https://github.com/qybaihe/mu",
|
|
24
27
|
"repository": {
|
|
@@ -39,6 +42,6 @@
|
|
|
39
42
|
"muBuild": {
|
|
40
43
|
"pi": "1.3.0",
|
|
41
44
|
"judge": "0.1.0",
|
|
42
|
-
"commit": "
|
|
45
|
+
"commit": "47bdfac19"
|
|
43
46
|
}
|
|
44
47
|
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
-
import{__commonJS,__require,__toESM}from"./chunk-JXWJOIH4.js";var require_windows=__commonJS({"node_modules/isexe/windows.js"(exports,module){module.exports=isexe;isexe.sync=sync;var fs=__require("fs");function checkPathExt(path,options){var pathext=options.pathExt!==void 0?options.pathExt:process.env.PATHEXT;if(!pathext||(pathext=pathext.split(";"),pathext.indexOf("")!==-1))return!0;for(var i=0;i<pathext.length;i++){var p=pathext[i].toLowerCase();if(p&&path.substr(-p.length).toLowerCase()===p)return!0}return!1}function checkStat(stat,path,options){return!stat.isSymbolicLink()&&!stat.isFile()?!1:checkPathExt(path,options)}function isexe(path,options,cb){fs.stat(path,function(er,stat){cb(er,er?!1:checkStat(stat,path,options))})}function sync(path,options){return checkStat(fs.statSync(path),path,options)}}});var require_mode=__commonJS({"node_modules/isexe/mode.js"(exports,module){module.exports=isexe;isexe.sync=sync;var fs=__require("fs");function isexe(path,options,cb){fs.stat(path,function(er,stat){cb(er,er?!1:checkStat(stat,options))})}function sync(path,options){return checkStat(fs.statSync(path),options)}function checkStat(stat,options){return stat.isFile()&&checkMode(stat,options)}function checkMode(stat,options){var mod=stat.mode,uid=stat.uid,gid=stat.gid,myUid=options.uid!==void 0?options.uid:process.getuid&&process.getuid(),myGid=options.gid!==void 0?options.gid:process.getgid&&process.getgid(),u=parseInt("100",8),g=parseInt("010",8),o=parseInt("001",8),ug=u|g,ret=mod&o||mod&g&&gid===myGid||mod&u&&uid===myUid||mod&ug&&myUid===0;return ret}}});var require_isexe=__commonJS({"node_modules/isexe/index.js"(exports,module){var fs=__require("fs"),core;process.platform==="win32"||global.TESTING_WINDOWS?core=require_windows():core=require_mode();module.exports=isexe;isexe.sync=sync;function isexe(path,options,cb){if(typeof options=="function"&&(cb=options,options={}),!cb){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(resolve2,reject){isexe(path,options||{},function(er,is){er?reject(er):resolve2(is)})})}core(path,options||{},function(er,is){er&&(er.code==="EACCES"||options&&options.ignoreErrors)&&(er=null,is=!1),cb(er,is)})}function sync(path,options){try{return core.sync(path,options||{})}catch(er){if(options&&options.ignoreErrors||er.code==="EACCES")return!1;throw er}}}});var require_which=__commonJS({"node_modules/which/which.js"(exports,module){var isWindows=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",path=__require("path"),COLON=isWindows?";":":",isexe=require_isexe(),getNotFoundError=cmd=>Object.assign(new Error(`not found: ${cmd}`),{code:"ENOENT"}),getPathInfo=(cmd,opt)=>{let colon=opt.colon||COLON,pathEnv=cmd.match(/\//)||isWindows&&cmd.match(/\\/)?[""]:[...isWindows?[process.cwd()]:[],...(opt.path||process.env.PATH||"").split(colon)],pathExtExe=isWindows?opt.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",pathExt=isWindows?pathExtExe.split(colon):[""];return isWindows&&cmd.indexOf(".")!==-1&&pathExt[0]!==""&&pathExt.unshift(""),{pathEnv,pathExt,pathExtExe}},which=(cmd,opt,cb)=>{typeof opt=="function"&&(cb=opt,opt={}),opt||(opt={});let{pathEnv,pathExt,pathExtExe}=getPathInfo(cmd,opt),found=[],step=i=>new Promise((resolve2,reject)=>{if(i===pathEnv.length)return opt.all&&found.length?resolve2(found):reject(getNotFoundError(cmd));let ppRaw=pathEnv[i],pathPart=/^".*"$/.test(ppRaw)?ppRaw.slice(1,-1):ppRaw,pCmd=path.join(pathPart,cmd),p=!pathPart&&/^\.[\\\/]/.test(cmd)?cmd.slice(0,2)+pCmd:pCmd;resolve2(subStep(p,i,0))}),subStep=(p,i,ii)=>new Promise((resolve2,reject)=>{if(ii===pathExt.length)return resolve2(step(i+1));let ext=pathExt[ii];isexe(p+ext,{pathExt:pathExtExe},(er,is)=>{if(!er&&is)if(opt.all)found.push(p+ext);else return resolve2(p+ext);return resolve2(subStep(p,i,ii+1))})});return cb?step(0).then(res=>cb(null,res),cb):step(0)},whichSync=(cmd,opt)=>{opt=opt||{};let{pathEnv,pathExt,pathExtExe}=getPathInfo(cmd,opt),found=[];for(let i=0;i<pathEnv.length;i++){let ppRaw=pathEnv[i],pathPart=/^".*"$/.test(ppRaw)?ppRaw.slice(1,-1):ppRaw,pCmd=path.join(pathPart,cmd),p=!pathPart&&/^\.[\\\/]/.test(cmd)?cmd.slice(0,2)+pCmd:pCmd;for(let j=0;j<pathExt.length;j++){let cur=p+pathExt[j];try{if(isexe.sync(cur,{pathExt:pathExtExe}))if(opt.all)found.push(cur);else return cur}catch{}}}if(opt.all&&found.length)return found;if(opt.nothrow)return null;throw getNotFoundError(cmd)};module.exports=which;which.sync=whichSync}});var require_path_key=__commonJS({"node_modules/path-key/index.js"(exports,module){"use strict";var pathKey=(options={})=>{let environment=options.env||process.env;return(options.platform||process.platform)!=="win32"?"PATH":Object.keys(environment).reverse().find(key=>key.toUpperCase()==="PATH")||"Path"};module.exports=pathKey;module.exports.default=pathKey}});var require_resolveCommand=__commonJS({"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports,module){"use strict";var path=__require("path"),which=require_which(),getPathKey=require_path_key();function resolveCommandAttempt(parsed,withoutPathExt){let env=parsed.options.env||process.env,cwd=process.cwd(),hasCustomCwd=parsed.options.cwd!=null,shouldSwitchCwd=hasCustomCwd&&process.chdir!==void 0&&!process.chdir.disabled;if(shouldSwitchCwd)try{process.chdir(parsed.options.cwd)}catch{}let resolved;try{resolved=which.sync(parsed.command,{path:env[getPathKey({env})],pathExt:withoutPathExt?path.delimiter:void 0})}catch{}finally{shouldSwitchCwd&&process.chdir(cwd)}return resolved&&(resolved=path.resolve(hasCustomCwd?parsed.options.cwd:"",resolved)),resolved}function resolveCommand(parsed){return resolveCommandAttempt(parsed)||resolveCommandAttempt(parsed,!0)}module.exports=resolveCommand}});var require_escape=__commonJS({"node_modules/cross-spawn/lib/util/escape.js"(exports,module){"use strict";var metaCharsRegExp=/([()\][%!^"`<>&|;, *?])/g;function escapeCommand(arg){return arg=arg.replace(metaCharsRegExp,"^$1"),arg}function escapeArgument(arg,doubleEscapeMetaChars){return arg=`${arg}`,arg=arg.replace(/(?=(\\+?)?)\1"/g,'$1$1\\"'),arg=arg.replace(/(?=(\\+?)?)\1$/,"$1$1"),arg=`"${arg}"`,arg=arg.replace(metaCharsRegExp,"^$1"),doubleEscapeMetaChars&&(arg=arg.replace(metaCharsRegExp,"^$1")),arg}module.exports.command=escapeCommand;module.exports.argument=escapeArgument}});var require_shebang_regex=__commonJS({"node_modules/shebang-regex/index.js"(exports,module){"use strict";module.exports=/^#!(.*)/}});var require_shebang_command=__commonJS({"node_modules/shebang-command/index.js"(exports,module){"use strict";var shebangRegex=require_shebang_regex();module.exports=(string="")=>{let match=string.match(shebangRegex);if(!match)return null;let[path,argument]=match[0].replace(/#! ?/,"").split(" "),binary=path.split("/").pop();return binary==="env"?argument:argument?`${binary} ${argument}`:binary}}});var require_readShebang=__commonJS({"node_modules/cross-spawn/lib/util/readShebang.js"(exports,module){"use strict";var fs=__require("fs"),shebangCommand=require_shebang_command();function readShebang(command){let buffer=Buffer.alloc(150),fd;try{fd=fs.openSync(command,"r"),fs.readSync(fd,buffer,0,150,0),fs.closeSync(fd)}catch{}return shebangCommand(buffer.toString())}module.exports=readShebang}});var require_parse=__commonJS({"node_modules/cross-spawn/lib/parse.js"(exports,module){"use strict";var path=__require("path"),resolveCommand=require_resolveCommand(),escape=require_escape(),readShebang=require_readShebang(),isWin=process.platform==="win32",isExecutableRegExp=/\.(?:com|exe)$/i,isCmdShimRegExp=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function detectShebang(parsed){parsed.file=resolveCommand(parsed);let shebang=parsed.file&&readShebang(parsed.file);return shebang?(parsed.args.unshift(parsed.file),parsed.command=shebang,resolveCommand(parsed)):parsed.file}function parseNonShell(parsed){if(!isWin)return parsed;let commandFile=detectShebang(parsed),needsShell=!isExecutableRegExp.test(commandFile);if(parsed.options.forceShell||needsShell){let needsDoubleEscapeMetaChars=isCmdShimRegExp.test(commandFile);parsed.command=path.normalize(parsed.command),parsed.command=escape.command(parsed.command),parsed.args=parsed.args.map(arg=>escape.argument(arg,needsDoubleEscapeMetaChars));let shellCommand=[parsed.command].concat(parsed.args).join(" ");parsed.args=["/d","/s","/c",`"${shellCommand}"`],parsed.command=process.env.comspec||"cmd.exe",parsed.options.windowsVerbatimArguments=!0}return parsed}function parse(command,args,options){args&&!Array.isArray(args)&&(options=args,args=null),args=args?args.slice(0):[],options=Object.assign({},options);let parsed={command,args,options,file:void 0,original:{command,args}};return options.shell?parsed:parseNonShell(parsed)}module.exports=parse}});var require_enoent=__commonJS({"node_modules/cross-spawn/lib/enoent.js"(exports,module){"use strict";var isWin=process.platform==="win32";function notFoundError(original,syscall){return Object.assign(new Error(`${syscall} ${original.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${syscall} ${original.command}`,path:original.command,spawnargs:original.args})}function hookChildProcess(cp,parsed){if(!isWin)return;let originalEmit=cp.emit;cp.emit=function(name,arg1){if(name==="exit"){let err=verifyENOENT(arg1,parsed);if(err)return originalEmit.call(cp,"error",err)}return originalEmit.apply(cp,arguments)}}function verifyENOENT(status,parsed){return isWin&&status===1&&!parsed.file?notFoundError(parsed.original,"spawn"):null}function verifyENOENTSync(status,parsed){return isWin&&status===1&&!parsed.file?notFoundError(parsed.original,"spawnSync"):null}module.exports={hookChildProcess,verifyENOENT,verifyENOENTSync,notFoundError}}});var require_cross_spawn=__commonJS({"node_modules/cross-spawn/index.js"(exports,module){"use strict";var cp=__require("child_process"),parse=require_parse(),enoent=require_enoent();function spawn(command,args,options){let parsed=parse(command,args,options),spawned=cp.spawn(parsed.command,parsed.args,parsed.options);return enoent.hookChildProcess(spawned,parsed),spawned}function spawnSync(command,args,options){let parsed=parse(command,args,options),result=cp.spawnSync(parsed.command,parsed.args,parsed.options);return result.error=result.error||enoent.verifyENOENTSync(result.status,parsed),result}module.exports=spawn;module.exports.spawn=spawn;module.exports.sync=spawnSync;module.exports._parse=parse;module.exports._enoent=enoent}});import{accessSync,constants,existsSync,readFileSync,realpathSync as realpathSync2}from"fs";import{createRequire}from"module";import{homedir as homedir2}from"os";import{basename,dirname,join as join2,resolve,sep as sep2,win32}from"path";import{fileURLToPath as fileURLToPath2}from"url";var import_cross_spawn=__toESM(require_cross_spawn(),1);import{spawn as nodeSpawn,spawnSync as nodeSpawnSync}from"node:child_process";var EXIT_STDIO_GRACE_MS=100;function spawnProcess(command,args,options){return process.platform==="win32"?(0,import_cross_spawn.default)(command,args,options):nodeSpawn(command,args,options)}function spawnProcessSync(command,args,options){return process.platform==="win32"?import_cross_spawn.default.sync(command,args,options):nodeSpawnSync(command,args,options)}function waitForChildProcess(child){return new Promise((resolve2,reject)=>{let settled=!1,exited=!1,exitCode=null,postExitTimer,stdoutEnded=child.stdout===null,stderrEnded=child.stderr===null,cleanup=()=>{postExitTimer&&(clearTimeout(postExitTimer),postExitTimer=void 0),child.removeListener("error",onError),child.removeListener("exit",onExit),child.removeListener("close",onClose),child.stdout?.removeListener("end",onStdoutEnd),child.stderr?.removeListener("end",onStderrEnd),child.stdout?.removeListener("data",onData),child.stderr?.removeListener("data",onData)},finalize=code=>{settled||(settled=!0,cleanup(),child.stdout?.destroy(),child.stderr?.destroy(),resolve2(code))},maybeFinalizeAfterExit=()=>{!exited||settled||stdoutEnded&&stderrEnded&&finalize(exitCode)},armIdleTimer=()=>{postExitTimer&&clearTimeout(postExitTimer),postExitTimer=setTimeout(()=>finalize(exitCode),EXIT_STDIO_GRACE_MS)},onData=()=>{exited&&!settled&&armIdleTimer()},onStdoutEnd=()=>{stdoutEnded=!0,maybeFinalizeAfterExit()},onStderrEnd=()=>{stderrEnded=!0,maybeFinalizeAfterExit()},onError=err=>{settled||(settled=!0,cleanup(),reject(err))},onExit=code=>{exited=!0,exitCode=code,maybeFinalizeAfterExit(),settled||armIdleTimer()},onClose=code=>{finalize(code)};child.stdout?.once("end",onStdoutEnd),child.stderr?.once("end",onStderrEnd),child.stdout?.on("data",onData),child.stderr?.on("data",onData),child.once("error",onError),child.once("exit",onExit),child.once("close",onClose)})}import{realpathSync,statSync}from"node:fs";import{homedir}from"node:os";import{isAbsolute,join,resolve as nodeResolvePath,relative,sep}from"node:path";import{fileURLToPath}from"node:url";var UNICODE_SPACES=/[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;function canonicalizePath(path){try{return realpathSync(path)}catch{return path}}function getFileRevision(path){try{let stats=statSync(path,{bigint:!0});return`${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeNs}:${stats.ctimeNs}`}catch{return}}function isLocalPath(value){let trimmed=value.trim();return!(trimmed.startsWith("npm:")||trimmed.startsWith("git:")||trimmed.startsWith("github:")||trimmed.startsWith("http:")||trimmed.startsWith("https:")||trimmed.startsWith("ssh:")||trimmed.startsWith("builtin:"))}function normalizeWindowsShellPath(filePath){if(!filePath.startsWith("/")||filePath.startsWith("//")||filePath.includes("\\"))return filePath;let match=filePath.match(/^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/i);if(!match)return filePath;let suffix=match[2]?.replaceAll("/","\\");return`${match[1].toUpperCase()}:\\${suffix??""}`}function normalizePath(input,options={}){let normalized=options.trim?input.trim():input;if(options.normalizeUnicodeSpaces&&(normalized=normalized.replace(UNICODE_SPACES," ")),options.stripAtPrefix&&normalized.startsWith("@")&&(normalized=normalized.slice(1)),process.platform==="win32"&&(normalized=normalizeWindowsShellPath(normalized)),options.expandTilde??!0){let home=options.homeDir??homedir();if(normalized==="~")return home;if(normalized.startsWith("~/")||process.platform==="win32"&&normalized.startsWith("~\\"))return join(home,normalized.slice(2))}return/^file:\/\//.test(normalized)?fileURLToPath(normalized):normalized}function resolvePath(input,baseDir=process.cwd(),options={}){let normalized=normalizePath(input,options),normalizedBaseDir=normalizePath(baseDir);return isAbsolute(normalized)?nodeResolvePath(normalized):nodeResolvePath(normalizedBaseDir,normalized)}function getCwdRelativePath(filePath,cwd){let resolvedCwd=resolvePath(cwd),resolvedPath=resolvePath(filePath,resolvedCwd),relativePath=relative(resolvedCwd,resolvedPath);return relativePath===""||relativePath!==".."&&!relativePath.startsWith(`..${sep}`)&&!isAbsolute(relativePath)?relativePath||".":void 0}function formatPathRelativeToCwdOrAbsolute(filePath,cwd){let absolutePath=resolvePath(filePath,cwd);return(getCwdRelativePath(absolutePath,cwd)??absolutePath).split(sep).join("/")}function markPathIgnoredByCloudSync(path){let attrs=process.platform==="darwin"?["com.dropbox.ignored","com.apple.fileprovider.ignore#P"]:process.platform==="linux"?["user.com.dropbox.ignored"]:[];for(let attr of attrs)process.platform==="darwin"?spawnProcessSync("xattr",["-w",attr,"1",path],{encoding:"utf-8",stdio:"ignore"}):spawnProcessSync("setfattr",["-n",attr,"-v","1",path],{encoding:"utf-8",stdio:"ignore"})}function splitBom(content){return content.startsWith("\uFEFF")?{bom:"\uFEFF",text:content.slice(1)}:{bom:"",text:content}}function stripBom(content){return splitBom(content).text}var __filename=fileURLToPath2(import.meta.url),__dirname=dirname(__filename),isBunBinary=import.meta.url.includes("$bunfs")||import.meta.url.includes("~BUN")||import.meta.url.includes("%7EBUN"),isBunRuntime=!!process.versions.bun,isBundledNode=!0;function normalizeSelfUpdatePackageTarget(target){return typeof target=="string"?{packageName:target,installSpec:target}:{packageName:target.packageName,installSpec:target.installSpec??target.packageName}}function makeSelfUpdateCommand(installStep,uninstallStep){return uninstallStep?{...installStep,display:`${uninstallStep.display} && ${installStep.display}`,steps:[uninstallStep,installStep]}:installStep}function makeSelfUpdateCommandStep(command,args){return{command,args,display:[command,...args].map(arg=>/\s/.test(arg)?`"${arg}"`:arg).join(" ")}}function detectInstallMethod(){if(isBunBinary)return"bun-binary";let resolvedPath=`${__dirname}\0${process.execPath||""}`.toLowerCase().replace(/\\/g,"/");return resolvedPath.includes("/pnpm/")||resolvedPath.includes("/.pnpm/")?"pnpm":resolvedPath.includes("/yarn/")||resolvedPath.includes("/.yarn/")?"yarn":isBunRuntime||resolvedPath.includes("/install/global/node_modules/")?"bun":resolvedPath.includes("/npm/")||resolvedPath.includes("/node_modules/")?"npm":"unknown"}function getInferredNpmInstall(){let packageDir=getPackageDir(),path=process.platform==="win32"||packageDir.includes("\\")?win32:{basename,dirname},parent=path.dirname(packageDir),root;if(path.basename(parent).startsWith("@")&&path.basename(path.dirname(parent))==="node_modules"?root=path.dirname(parent):path.basename(parent)==="node_modules"&&(root=parent),!root)return;let rootParent=path.dirname(root);if(path.basename(rootParent)==="lib")return{root,prefix:path.dirname(rootParent)}}function getSelfUpdateCommandForMethod(method,installedPackageName,updatePackageTarget=installedPackageName,npmCommand){let target=normalizeSelfUpdatePackageTarget(updatePackageTarget);switch(method){case"bun-binary":return;case"pnpm":{let match=readCommandOutput("pnpm",["root","-g"])?void 0:/^(.*[\\/]global[\\/][^\\/]+)[\\/]\.pnpm[\\/]/.exec(getPackageDir()),binDirArgs=match?[`--config.global-bin-dir=${process.env.PNPM_HOME||dirname(dirname(match[1]))}`]:[];return makeSelfUpdateCommand(makeSelfUpdateCommandStep("pnpm",["install","-g","--ignore-scripts","--config.minimumReleaseAge=0",...binDirArgs,target.installSpec]),target.packageName===installedPackageName?void 0:makeSelfUpdateCommandStep("pnpm",["remove","-g",...binDirArgs,installedPackageName]))}case"yarn":return makeSelfUpdateCommand(makeSelfUpdateCommandStep("yarn",["global","add","--ignore-scripts",target.installSpec]),target.packageName===installedPackageName?void 0:makeSelfUpdateCommandStep("yarn",["global","remove",installedPackageName]));case"bun":return makeSelfUpdateCommand(makeSelfUpdateCommandStep("bun",["install","-g","--ignore-scripts","--minimum-release-age=0",target.installSpec]),target.packageName===installedPackageName?void 0:makeSelfUpdateCommandStep("bun",["uninstall","-g",installedPackageName]));case"npm":{let[command="npm",...npmArgs]=npmCommand??[],inferred=npmCommand?.length?void 0:getInferredNpmInstall(),prefixArgs=[...npmArgs,...inferred?["--prefix",inferred.prefix]:[]],installStep=makeSelfUpdateCommandStep(command,[...prefixArgs,"install","-g","--ignore-scripts","--min-release-age=0",target.installSpec]),uninstallStep=target.packageName===installedPackageName?void 0:makeSelfUpdateCommandStep(command,[...prefixArgs,"uninstall","-g",installedPackageName]);return makeSelfUpdateCommand(installStep,uninstallStep)}case"unknown":return}}function readCommandOutput(command,args,options={}){let result=spawnProcessSync(command,args,{encoding:"utf-8",stdio:["ignore","pipe","pipe"]});if(result.status===0)return result.stdout.trim()||void 0;if(options.requireSuccess){let reason=result.error?.message||result.stderr.trim()||`exit code ${result.status??"unknown"}`;throw new Error(`Failed to run ${[command,...args].join(" ")}: ${reason}`)}}function getGlobalPackageRoots(method,_packageName,npmCommand){switch(method){case"npm":{let configured=!!npmCommand?.length,[command="npm",...npmArgs]=npmCommand??[];if(configured&&command==="bun"){let bunBin=readCommandOutput(command,[...npmArgs,"pm","bin","-g"],{requireSuccess:!0}),roots=[join2(homedir2(),".bun","install","global","node_modules")];return bunBin&&roots.push(join2(dirname(bunBin),"install","global","node_modules")),roots}let root=readCommandOutput(command,[...npmArgs,"root","-g"],{requireSuccess:configured}),inferred=configured?void 0:getInferredNpmInstall();return[root,inferred?.root].filter(x=>!!x)}case"pnpm":{let root=readCommandOutput("pnpm",["root","-g"]);if(root)return[root,dirname(root)];let match=/^(.*[\\/]global[\\/][^\\/]+)[\\/]\.pnpm[\\/]/.exec(getPackageDir());return match?[match[1]]:[]}case"yarn":{let dir=readCommandOutput("yarn",["global","dir"]);return dir?[dir,join2(dir,"node_modules")]:[]}case"bun":{let bunBin=readCommandOutput("bun",["pm","bin","-g"]),roots=[join2(homedir2(),".bun","install","global","node_modules")];return bunBin&&roots.push(join2(dirname(bunBin),"install","global","node_modules")),roots}case"bun-binary":case"unknown":return[]}}function normalizeExistingPathForComparison(path,resolveSymlinks){let resolvedPath=resolve(path);if(!existsSync(resolvedPath))return;let normalizedPath=resolvedPath;if(resolveSymlinks)try{normalizedPath=realpathSync2(resolvedPath)}catch{return}return process.platform==="win32"&&(normalizedPath=normalizedPath.toLowerCase()),normalizedPath}function getPathComparisonCandidates(path){return Array.from(new Set([normalizeExistingPathForComparison(path,!1),normalizeExistingPathForComparison(path,!0)].filter(candidate=>!!candidate)))}function getEntrypointPackageDir(){let entrypoint=process.argv[1];if(!entrypoint)return;let dir=dirname(entrypoint);for(;dir!==dirname(dir);){if(existsSync(join2(dir,"package.json")))return dir;dir=dirname(dir)}}function isSelfUpdatePathWritable(){let packageDir=getPackageDir();try{return accessSync(packageDir,constants.W_OK),accessSync(dirname(packageDir),constants.W_OK),!0}catch{return!1}}function isManagedByGlobalPackageManager(method,packageName,npmCommand){let packageDirCandidates=[getPackageDir(),getEntrypointPackageDir()].filter(dir=>!!dir).flatMap(dir=>getPathComparisonCandidates(dir));return getGlobalPackageRoots(method,packageName,npmCommand).some(root=>getPathComparisonCandidates(root).some(normalizedRoot=>{let rootPrefix=normalizedRoot.endsWith(sep2)?normalizedRoot:`${normalizedRoot}${sep2}`;return packageDirCandidates.some(packageDir=>packageDir.startsWith(rootPrefix))}))}function getSelfUpdateCommand(packageName,npmCommand,updatePackageTarget=packageName){let method=detectInstallMethod(),command=getSelfUpdateCommandForMethod(method,packageName,updatePackageTarget,npmCommand);if(!(!command||!isManagedByGlobalPackageManager(method,packageName,npmCommand)||!isSelfUpdatePathWritable()))return command}function getSelfUpdateUnavailableInstruction(packageName,npmCommand,updatePackageTarget=packageName){let method=detectInstallMethod(),target=normalizeSelfUpdatePackageTarget(updatePackageTarget);if(method==="bun-binary")return"Download from: https://github.com/earendil-works/pi/releases/latest";let command=getSelfUpdateCommandForMethod(method,packageName,target,npmCommand);return command?isManagedByGlobalPackageManager(method,packageName,npmCommand)&&!isSelfUpdatePathWritable()?`This installation is managed by a global ${method} install, but the install path is not writable. Update it yourself with: ${command.display}`:`This installation is not managed by a global ${method} install. Update it with the package manager, wrapper, or source checkout that provides it.`:`Update ${target.installSpec} using the package manager, wrapper, or source checkout that provides this installation.`}function findNodePackageDir(startDir){let dir=startDir;for(;dir!==dirname(dir);){if(existsSync(join2(dir,"package.json"))){let parent=dirname(dir);return basename(dir)==="dist"&&existsSync(join2(parent,"package.json"))?parent:dir}dir=dirname(dir)}return startDir}function getPackageDir(){let envDir=process.env.PI_PACKAGE_DIR;return envDir?normalizePath(envDir):isBunBinary?dirname(process.execPath):findNodePackageDir(__dirname)}function getThemesDir(){if(isBunBinary)return join2(getPackageDir(),"theme");let packageDir=getPackageDir(),srcOrDist=existsSync(join2(packageDir,"src"))?"src":"dist";return join2(packageDir,srcOrDist,"modes","interactive","theme")}function getExportTemplateDir(){if(isBunBinary)return join2(getPackageDir(),"export-html");let packageDir=getPackageDir(),srcOrDist=existsSync(join2(packageDir,"src"))?"src":"dist";return join2(packageDir,srcOrDist,"core","export-html")}function getPackageJsonPath(){return join2(getPackageDir(),"package.json")}function getReadmePath(){return resolve(join2(getPackageDir(),"README.md"))}function getDocsPath(){return resolve(join2(getPackageDir(),"docs"))}function getExamplesPath(){return resolve(join2(getPackageDir(),"examples"))}function getChangelogPath(){return resolve(join2(getPackageDir(),"CHANGELOG.md"))}function getInteractiveAssetsDir(){if(isBunBinary)return join2(getPackageDir(),"assets");let packageDir=getPackageDir(),srcOrDist=existsSync(join2(packageDir,"src"))?"src":"dist";return join2(packageDir,srcOrDist,"modes","interactive","assets")}function getBundledInteractiveAssetPath(name){return join2(getInteractiveAssetsDir(),name)}var quickJSWasmPath;function getQuickJSWasmPath(){return quickJSWasmPath??=createRequire(import.meta.url).resolve("quickjs-wasi/quickjs.wasm"),quickJSWasmPath}function resolveCodemodeWorkerSpecifier(runtime,moduleUrl){if(runtime==="bun-binary")return"./src/extensions/codemode/worker.ts";if(runtime==="bundled-node")return new URL("./codemode-worker.js",moduleUrl)}var codemodeWorkerDataUrl;function getCodemodeWorkerSpecifier(){let runtime=isBunBinary?"bun-binary":isBundledNode?"bundled-node":"unbundled",specifier=resolveCodemodeWorkerSpecifier(runtime,import.meta.url);return runtime!=="bundled-node"||!(specifier instanceof URL)?specifier:(codemodeWorkerDataUrl??=new URL(`data:text/javascript;base64,${readFileSync(specifier).toString("base64")}`),codemodeWorkerDataUrl)}function detectInstallChange(packageJsonPath=startupPackageJsonPath){if(isBunBinary||!packageJsonPath)return;let installed;try{installed=JSON.parse(stripBom(readFileSync(packageJsonPath,"utf-8")))}catch(error){return error.code==="ENOENT"?{kind:"removed"}:void 0}return installed.version&&installed.version!==VERSION?{kind:"updated",version:installed.version}:void 0}var pkg={},startupPackageJsonPath;try{let packageJsonPath=getPackageJsonPath();pkg=JSON.parse(stripBom(readFileSync(packageJsonPath,"utf-8"))),startupPackageJsonPath=packageJsonPath}catch(e){if(e.code!=="ENOENT")throw e}var piConfigName=pkg.piConfig?.name,PACKAGE_NAME=pkg.name||"@earendil-works/pi-coding-agent",APP_NAME=piConfigName||"pi",APP_TITLE=piConfigName?APP_NAME:"\u03C0",CONFIG_DIR_NAME=pkg.piConfig?.configDir||".pi",VERSION=pkg.version||"0.0.0",ENV_AGENT_DIR=`${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`,ENV_SESSION_DIR=`${APP_NAME.toUpperCase()}_CODING_AGENT_SESSION_DIR`;function expandTildePath(path){return normalizePath(path)}var DEFAULT_SHARE_VIEWER_URL="https://pi.dev/session/";function getShareViewerUrl(gistId){return`${process.env.PI_SHARE_VIEWER_URL||DEFAULT_SHARE_VIEWER_URL}#${gistId}`}function getAgentDir(){let envDir=process.env[ENV_AGENT_DIR];return envDir?expandTildePath(envDir):join2(homedir2(),CONFIG_DIR_NAME,"agent")}function getCustomThemesDir(){return join2(getAgentDir(),"themes")}function getAuthPath(){return join2(getAgentDir(),"auth.json")}function getSettingsPath(){return join2(getAgentDir(),"settings.json")}function getBinDir(){return join2(getAgentDir(),"bin")}function getSessionsDir(){return join2(getAgentDir(),"sessions")}function getDebugLogPath(){return join2(getAgentDir(),`${APP_NAME}-debug.log`)}export{require_cross_spawn,spawnProcess,spawnProcessSync,waitForChildProcess,canonicalizePath,getFileRevision,isLocalPath,normalizePath,resolvePath,getCwdRelativePath,formatPathRelativeToCwdOrAbsolute,markPathIgnoredByCloudSync,splitBom,stripBom,isBunBinary,isBundledNode,detectInstallMethod,getSelfUpdateCommand,getSelfUpdateUnavailableInstruction,getPackageDir,getThemesDir,getExportTemplateDir,getReadmePath,getDocsPath,getExamplesPath,getChangelogPath,getBundledInteractiveAssetPath,getQuickJSWasmPath,getCodemodeWorkerSpecifier,detectInstallChange,PACKAGE_NAME,APP_NAME,APP_TITLE,CONFIG_DIR_NAME,VERSION,ENV_AGENT_DIR,ENV_SESSION_DIR,expandTildePath,getShareViewerUrl,getAgentDir,getCustomThemesDir,getAuthPath,getSettingsPath,getBinDir,getSessionsDir,getDebugLogPath};
|