zam-core 0.4.1 → 0.4.2
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/cli/index.js +298 -74
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { readFileSync as readFileSync14 } from "fs";
|
|
5
|
-
import { dirname as dirname10, join as
|
|
5
|
+
import { dirname as dirname10, join as join23 } from "path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7
7
|
import { Command as Command24 } from "commander";
|
|
8
8
|
|
|
@@ -4932,10 +4932,10 @@ var agentCommand = new Command("agent").description("Provision and inspect the a
|
|
|
4932
4932
|
|
|
4933
4933
|
// src/cli/commands/bridge.ts
|
|
4934
4934
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
4935
|
-
import { randomBytes } from "crypto";
|
|
4935
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
4936
4936
|
import { readdirSync as readdirSync2, readFileSync as readFileSync10, rmSync as rmSync2 } from "fs";
|
|
4937
|
-
import { homedir as homedir8, tmpdir } from "os";
|
|
4938
|
-
import { join as
|
|
4937
|
+
import { homedir as homedir8, tmpdir as tmpdir2 } from "os";
|
|
4938
|
+
import { join as join13 } from "path";
|
|
4939
4939
|
import { Command as Command2 } from "commander";
|
|
4940
4940
|
|
|
4941
4941
|
// src/cli/llm/client.ts
|
|
@@ -5498,7 +5498,9 @@ async function ensureHighQualityQuestion(db, token) {
|
|
|
5498
5498
|
|
|
5499
5499
|
// src/cli/llm/vision.ts
|
|
5500
5500
|
import { readFileSync as readFileSync9 } from "fs";
|
|
5501
|
-
import {
|
|
5501
|
+
import { randomBytes } from "crypto";
|
|
5502
|
+
import { tmpdir } from "os";
|
|
5503
|
+
import { basename as basename2, join as join12 } from "path";
|
|
5502
5504
|
var LANGUAGE_NAMES2 = {
|
|
5503
5505
|
en: "English",
|
|
5504
5506
|
de: "German",
|
|
@@ -5531,15 +5533,61 @@ async function observeUiSnapshotViaLLM(db, input8) {
|
|
|
5531
5533
|
"Vision observation is disabled in settings (llm.vision.enabled)"
|
|
5532
5534
|
);
|
|
5533
5535
|
}
|
|
5534
|
-
const
|
|
5535
|
-
const
|
|
5536
|
+
const imageUrls = [];
|
|
5537
|
+
const isVideo = /\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(input8.imagePath);
|
|
5538
|
+
if (isVideo) {
|
|
5539
|
+
const { mkdirSync: mkdirSync12, readdirSync: readdirSync3, rmSync: rmSync3 } = await import("fs");
|
|
5540
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
5541
|
+
const tempDir = join12(tmpdir(), `zam-frames-${randomBytes(4).toString("hex")}`);
|
|
5542
|
+
mkdirSync12(tempDir, { recursive: true });
|
|
5543
|
+
try {
|
|
5544
|
+
execSync7(
|
|
5545
|
+
`ffmpeg -i "${input8.imagePath}" -vf "fps=1/3,scale=1280:-1" -vsync vfr "${tempDir}/frame_%03d.png"`,
|
|
5546
|
+
{ stdio: "ignore" }
|
|
5547
|
+
);
|
|
5548
|
+
let files = readdirSync3(tempDir).filter((f) => f.endsWith(".png")).sort();
|
|
5549
|
+
if (files.length === 0) {
|
|
5550
|
+
execSync7(
|
|
5551
|
+
`ffmpeg -i "${input8.imagePath}" -vframes 1 "${tempDir}/frame_001.png"`,
|
|
5552
|
+
{ stdio: "ignore" }
|
|
5553
|
+
);
|
|
5554
|
+
files = readdirSync3(tempDir).filter((f) => f.endsWith(".png")).sort();
|
|
5555
|
+
}
|
|
5556
|
+
let sampledFiles = files;
|
|
5557
|
+
if (files.length > 12) {
|
|
5558
|
+
const step = (files.length - 1) / 11;
|
|
5559
|
+
sampledFiles = [];
|
|
5560
|
+
for (let i = 0; i < 12; i++) {
|
|
5561
|
+
const index = Math.round(i * step);
|
|
5562
|
+
sampledFiles.push(files[index]);
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
for (const file of sampledFiles) {
|
|
5566
|
+
const bytes = readFileSync9(join12(tempDir, file));
|
|
5567
|
+
imageUrls.push(`data:image/png;base64,${bytes.toString("base64")}`);
|
|
5568
|
+
}
|
|
5569
|
+
} finally {
|
|
5570
|
+
try {
|
|
5571
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
5572
|
+
} catch {
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5575
|
+
} else {
|
|
5576
|
+
const imageBytes = readFileSync9(input8.imagePath);
|
|
5577
|
+
const ext = input8.imagePath.split(".").pop()?.toLowerCase();
|
|
5578
|
+
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
|
|
5579
|
+
imageUrls.push(`data:${mime};base64,${imageBytes.toString("base64")}`);
|
|
5580
|
+
}
|
|
5581
|
+
if (imageUrls.length === 0) {
|
|
5582
|
+
throw new Error("No image data available for vision analysis");
|
|
5583
|
+
}
|
|
5536
5584
|
const model = input8.model ?? cfg.model;
|
|
5537
5585
|
const content = await requestVisionDraft({
|
|
5538
5586
|
url: cfg.url,
|
|
5539
5587
|
apiKey: cfg.apiKey || DEFAULT_LLM_API_KEY,
|
|
5540
5588
|
model,
|
|
5541
5589
|
locale: cfg.locale,
|
|
5542
|
-
|
|
5590
|
+
imageUrls,
|
|
5543
5591
|
input: input8
|
|
5544
5592
|
});
|
|
5545
5593
|
let draft;
|
|
@@ -5589,17 +5637,22 @@ async function requestVisionDraft(args) {
|
|
|
5589
5637
|
content: [
|
|
5590
5638
|
{
|
|
5591
5639
|
type: "text",
|
|
5592
|
-
text: `Observe this Windows application
|
|
5640
|
+
text: args.imageUrls.length > 1 ? `Observe this sequence of Windows/macOS application snapshots showing a task performed over time.
|
|
5641
|
+
Application process: ${args.input.application.processName}
|
|
5642
|
+
Window title: ${args.input.application.windowTitle ?? "(unknown)"}
|
|
5643
|
+
|
|
5644
|
+
Return this JSON draft only:
|
|
5645
|
+
${schema}` : `Observe this Windows/macOS application snapshot for a learning session.
|
|
5593
5646
|
Application process: ${args.input.application.processName}
|
|
5594
5647
|
Window title: ${args.input.application.windowTitle ?? "(unknown)"}
|
|
5595
5648
|
|
|
5596
5649
|
Return this JSON draft only:
|
|
5597
5650
|
${schema}`
|
|
5598
5651
|
},
|
|
5599
|
-
{
|
|
5652
|
+
...args.imageUrls.map((url) => ({
|
|
5600
5653
|
type: "image_url",
|
|
5601
|
-
image_url: { url
|
|
5602
|
-
}
|
|
5654
|
+
image_url: { url }
|
|
5655
|
+
}))
|
|
5603
5656
|
]
|
|
5604
5657
|
}
|
|
5605
5658
|
],
|
|
@@ -6239,7 +6292,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
6239
6292
|
"20"
|
|
6240
6293
|
).action(async (opts) => {
|
|
6241
6294
|
try {
|
|
6242
|
-
const monitorDir =
|
|
6295
|
+
const monitorDir = join13(homedir8(), ".zam", "monitor");
|
|
6243
6296
|
let files;
|
|
6244
6297
|
try {
|
|
6245
6298
|
files = readdirSync2(monitorDir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -6252,7 +6305,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
6252
6305
|
return;
|
|
6253
6306
|
}
|
|
6254
6307
|
const limit = Number(opts.limit);
|
|
6255
|
-
const sorted = files.map((f) => ({ name: f, path:
|
|
6308
|
+
const sorted = files.map((f) => ({ name: f, path: join13(monitorDir, f) })).sort((a, b) => b.name.localeCompare(a.name)).slice(0, limit);
|
|
6256
6309
|
const sessionCommands = /* @__PURE__ */ new Map();
|
|
6257
6310
|
for (const file of sorted) {
|
|
6258
6311
|
const sessionId = file.name.replace(".jsonl", "");
|
|
@@ -6332,8 +6385,8 @@ bridgeCommand.command("get-observations").description("Read UI observer reports
|
|
|
6332
6385
|
}
|
|
6333
6386
|
});
|
|
6334
6387
|
bridgeCommand.command("observe-ui-snapshot").description(
|
|
6335
|
-
"Analyze a captured UI snapshot with the configured vision LLM (JSON)"
|
|
6336
|
-
).requiredOption("--session <id>", "Observer session ID").requiredOption("--sequence <n>", "Monotonic observation sequence number").requiredOption("--image <path>", "PNG snapshot path").requiredOption("--observed-from <iso>", "Observation window start time").requiredOption("--observed-to <iso>", "Observation window end time").requiredOption("--process-name <name>", "Observed application process name").option("--process-id <n>", "Observed application process ID").option("--window-title <title>", "Observed window title").option("--evidence-ref <ref>", "Evidence reference to put in the report").option("--model <model>", "Override configured LLM model for this request").option("--max-tokens <n>", "Model response token budget").option("--timeout <ms>", "Hard request timeout in milliseconds").option("--redacted", "Mark the snapshot evidence as redacted").option("--write-log", "Append the generated report to the session JSONL").action(async (opts) => {
|
|
6388
|
+
"Analyze a captured UI snapshot or video recording with the configured vision LLM (JSON)"
|
|
6389
|
+
).requiredOption("--session <id>", "Observer session ID").requiredOption("--sequence <n>", "Monotonic observation sequence number").requiredOption("--image <path>", "PNG snapshot or video recording path").requiredOption("--observed-from <iso>", "Observation window start time").requiredOption("--observed-to <iso>", "Observation window end time").requiredOption("--process-name <name>", "Observed application process name").option("--process-id <n>", "Observed application process ID").option("--window-title <title>", "Observed window title").option("--evidence-ref <ref>", "Evidence reference to put in the report").option("--model <model>", "Override configured LLM model for this request").option("--max-tokens <n>", "Model response token budget").option("--timeout <ms>", "Hard request timeout in milliseconds").option("--redacted", "Mark the snapshot evidence as redacted").option("--write-log", "Append the generated report to the session JSONL").action(async (opts) => {
|
|
6337
6390
|
const sequence = parseNonNegativeIntegerOption("sequence", opts.sequence);
|
|
6338
6391
|
const processId = opts.processId === void 0 ? void 0 : parseNonNegativeIntegerOption("process-id", opts.processId);
|
|
6339
6392
|
const maxTokens = opts.maxTokens === void 0 ? void 0 : parseNonNegativeIntegerOption("max-tokens", opts.maxTokens);
|
|
@@ -6754,7 +6807,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
6754
6807
|
return;
|
|
6755
6808
|
}
|
|
6756
6809
|
}
|
|
6757
|
-
const outputPath = opts.image ?? opts.output ??
|
|
6810
|
+
const outputPath = opts.image ?? opts.output ?? join13(tmpdir2(), `zam-capture-${randomBytes2(4).toString("hex")}.png`);
|
|
6758
6811
|
const captureResult = isProvided ? { method: "provided", target: null } : captureScreenshot(outputPath, opts.hwnd, opts.processName);
|
|
6759
6812
|
if (!isProvided) {
|
|
6760
6813
|
const post = decidePostCapture(policy, {
|
|
@@ -6798,6 +6851,177 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
6798
6851
|
});
|
|
6799
6852
|
});
|
|
6800
6853
|
});
|
|
6854
|
+
bridgeCommand.command("start-recording").description("Start screen recording in the background (macOS only) (JSON)").requiredOption("--session <id>", "ZAM session ID").option("--output <path>", "Video output path").action(async (opts) => {
|
|
6855
|
+
const platform = process.platform;
|
|
6856
|
+
if (platform !== "darwin") {
|
|
6857
|
+
jsonOut2({
|
|
6858
|
+
sessionId: opts.session,
|
|
6859
|
+
started: false,
|
|
6860
|
+
error: "Screen recording is only supported on macOS (darwin)"
|
|
6861
|
+
});
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
const sessionId = opts.session;
|
|
6865
|
+
const statePath = join13(tmpdir2(), `zam-recording-${sessionId}.json`);
|
|
6866
|
+
const outputPath = opts.output ?? join13(tmpdir2(), `zam-recording-${sessionId}.mov`);
|
|
6867
|
+
const { existsSync: existsSync22, writeFileSync: writeFileSync12, openSync, closeSync } = await import("fs");
|
|
6868
|
+
if (existsSync22(statePath)) {
|
|
6869
|
+
jsonOut2({
|
|
6870
|
+
sessionId,
|
|
6871
|
+
started: false,
|
|
6872
|
+
error: `Recording is already active for session ${sessionId}`
|
|
6873
|
+
});
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
const logPath = join13(tmpdir2(), `zam-recording-${sessionId}.log`);
|
|
6877
|
+
let logFd;
|
|
6878
|
+
try {
|
|
6879
|
+
logFd = openSync(logPath, "w");
|
|
6880
|
+
} catch (e) {
|
|
6881
|
+
jsonOut2({
|
|
6882
|
+
sessionId,
|
|
6883
|
+
started: false,
|
|
6884
|
+
error: `Failed to open log file at ${logPath}: ${e.message}`
|
|
6885
|
+
});
|
|
6886
|
+
return;
|
|
6887
|
+
}
|
|
6888
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
6889
|
+
const child = spawn3(
|
|
6890
|
+
"ffmpeg",
|
|
6891
|
+
[
|
|
6892
|
+
"-y",
|
|
6893
|
+
"-f",
|
|
6894
|
+
"avfoundation",
|
|
6895
|
+
"-r",
|
|
6896
|
+
"5",
|
|
6897
|
+
"-i",
|
|
6898
|
+
"0",
|
|
6899
|
+
"-pix_fmt",
|
|
6900
|
+
"yuv420p",
|
|
6901
|
+
outputPath
|
|
6902
|
+
],
|
|
6903
|
+
{
|
|
6904
|
+
detached: true,
|
|
6905
|
+
stdio: ["pipe", logFd, logFd]
|
|
6906
|
+
}
|
|
6907
|
+
);
|
|
6908
|
+
try {
|
|
6909
|
+
closeSync(logFd);
|
|
6910
|
+
} catch {
|
|
6911
|
+
}
|
|
6912
|
+
child.unref();
|
|
6913
|
+
if (child.pid) {
|
|
6914
|
+
writeFileSync12(
|
|
6915
|
+
statePath,
|
|
6916
|
+
JSON.stringify({
|
|
6917
|
+
pid: child.pid,
|
|
6918
|
+
outputPath,
|
|
6919
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6920
|
+
}),
|
|
6921
|
+
"utf8"
|
|
6922
|
+
);
|
|
6923
|
+
jsonOut2({
|
|
6924
|
+
sessionId,
|
|
6925
|
+
started: true,
|
|
6926
|
+
outputPath,
|
|
6927
|
+
pid: child.pid
|
|
6928
|
+
});
|
|
6929
|
+
} else {
|
|
6930
|
+
jsonOut2({
|
|
6931
|
+
sessionId,
|
|
6932
|
+
started: false,
|
|
6933
|
+
error: "Failed to spawn ffmpeg process"
|
|
6934
|
+
});
|
|
6935
|
+
}
|
|
6936
|
+
});
|
|
6937
|
+
bridgeCommand.command("stop-recording").description(
|
|
6938
|
+
"Stop active screen recording and apply idle-frame compression (macOS only) (JSON)"
|
|
6939
|
+
).requiredOption("--session <id>", "ZAM session ID").action(async (opts) => {
|
|
6940
|
+
const platform = process.platform;
|
|
6941
|
+
if (platform !== "darwin") {
|
|
6942
|
+
jsonOut2({
|
|
6943
|
+
sessionId: opts.session,
|
|
6944
|
+
stopped: false,
|
|
6945
|
+
error: "Screen recording is only supported on macOS (darwin)"
|
|
6946
|
+
});
|
|
6947
|
+
return;
|
|
6948
|
+
}
|
|
6949
|
+
const sessionId = opts.session;
|
|
6950
|
+
const statePath = join13(tmpdir2(), `zam-recording-${sessionId}.json`);
|
|
6951
|
+
const { existsSync: existsSync22, readFileSync: readFileSync15, rmSync: rmSync3 } = await import("fs");
|
|
6952
|
+
if (!existsSync22(statePath)) {
|
|
6953
|
+
jsonOut2({
|
|
6954
|
+
sessionId,
|
|
6955
|
+
stopped: false,
|
|
6956
|
+
error: `No active recording found for session ${sessionId}`
|
|
6957
|
+
});
|
|
6958
|
+
return;
|
|
6959
|
+
}
|
|
6960
|
+
const state = JSON.parse(readFileSync15(statePath, "utf8"));
|
|
6961
|
+
const { pid, outputPath } = state;
|
|
6962
|
+
try {
|
|
6963
|
+
process.kill(pid, "SIGINT");
|
|
6964
|
+
} catch (e) {
|
|
6965
|
+
}
|
|
6966
|
+
const isProcessRunning = (pId) => {
|
|
6967
|
+
try {
|
|
6968
|
+
process.kill(pId, 0);
|
|
6969
|
+
return true;
|
|
6970
|
+
} catch (e) {
|
|
6971
|
+
return false;
|
|
6972
|
+
}
|
|
6973
|
+
};
|
|
6974
|
+
let attempts = 0;
|
|
6975
|
+
while (isProcessRunning(pid) && attempts < 20) {
|
|
6976
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
6977
|
+
attempts++;
|
|
6978
|
+
}
|
|
6979
|
+
if (isProcessRunning(pid)) {
|
|
6980
|
+
try {
|
|
6981
|
+
process.kill(pid, "SIGKILL");
|
|
6982
|
+
} catch (e) {
|
|
6983
|
+
}
|
|
6984
|
+
}
|
|
6985
|
+
try {
|
|
6986
|
+
rmSync3(statePath, { force: true });
|
|
6987
|
+
} catch {
|
|
6988
|
+
}
|
|
6989
|
+
if (!existsSync22(outputPath)) {
|
|
6990
|
+
jsonOut2({
|
|
6991
|
+
sessionId,
|
|
6992
|
+
stopped: false,
|
|
6993
|
+
error: `Recording file not found at ${outputPath}`
|
|
6994
|
+
});
|
|
6995
|
+
return;
|
|
6996
|
+
}
|
|
6997
|
+
const decimatedPath = outputPath.replace(/\.[^.]+$/, "-decimated.mp4");
|
|
6998
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
6999
|
+
try {
|
|
7000
|
+
execSync7(
|
|
7001
|
+
`ffmpeg -y -i "${outputPath}" -vf "mpdecimate,setpts=N/FRAME_RATE/TB" -an -pix_fmt yuv420p "${decimatedPath}"`,
|
|
7002
|
+
{ stdio: "ignore" }
|
|
7003
|
+
);
|
|
7004
|
+
} catch (ffmpegErr) {
|
|
7005
|
+
jsonOut2({
|
|
7006
|
+
sessionId,
|
|
7007
|
+
stopped: true,
|
|
7008
|
+
videoPath: outputPath,
|
|
7009
|
+
decimated: false,
|
|
7010
|
+
warning: `mpdecimate post-processing failed: ${ffmpegErr.message}`
|
|
7011
|
+
});
|
|
7012
|
+
return;
|
|
7013
|
+
}
|
|
7014
|
+
try {
|
|
7015
|
+
rmSync3(outputPath, { force: true });
|
|
7016
|
+
} catch {
|
|
7017
|
+
}
|
|
7018
|
+
jsonOut2({
|
|
7019
|
+
sessionId,
|
|
7020
|
+
stopped: true,
|
|
7021
|
+
videoPath: decimatedPath,
|
|
7022
|
+
decimated: true
|
|
7023
|
+
});
|
|
7024
|
+
});
|
|
6801
7025
|
bridgeCommand.command("get-observer-policy").description(
|
|
6802
7026
|
"Report the resolved observer policy so an agent can check before capturing (JSON)"
|
|
6803
7027
|
).action(async () => {
|
|
@@ -7506,18 +7730,18 @@ async function setupTurso(urlArg, tokenArg, mode) {
|
|
|
7506
7730
|
// src/cli/commands/git-sync.ts
|
|
7507
7731
|
import { execSync as execSync4 } from "child_process";
|
|
7508
7732
|
import { chmodSync as chmodSync2, existsSync as existsSync13, writeFileSync as writeFileSync6 } from "fs";
|
|
7509
|
-
import { join as
|
|
7733
|
+
import { join as join14 } from "path";
|
|
7510
7734
|
import { Command as Command5 } from "commander";
|
|
7511
7735
|
function installHook2() {
|
|
7512
|
-
const gitDir =
|
|
7736
|
+
const gitDir = join14(process.cwd(), ".git");
|
|
7513
7737
|
if (!existsSync13(gitDir)) {
|
|
7514
7738
|
console.error(
|
|
7515
7739
|
"Error: Current directory is not the root of a Git repository."
|
|
7516
7740
|
);
|
|
7517
7741
|
process.exit(1);
|
|
7518
7742
|
}
|
|
7519
|
-
const hooksDir =
|
|
7520
|
-
const hookPath =
|
|
7743
|
+
const hooksDir = join14(gitDir, "hooks");
|
|
7744
|
+
const hookPath = join14(hooksDir, "post-commit");
|
|
7521
7745
|
const hookContent = `#!/bin/sh
|
|
7522
7746
|
# ZAM Spaced Repetition Auto-Stale Hook
|
|
7523
7747
|
# Triggered automatically on git commits to decay modified concept cards.
|
|
@@ -7813,7 +8037,7 @@ goalCommand.command("status <slug> <status>").description("Update a goal's statu
|
|
|
7813
8037
|
// src/cli/commands/init.ts
|
|
7814
8038
|
import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
7815
8039
|
import { homedir as homedir9 } from "os";
|
|
7816
|
-
import { join as
|
|
8040
|
+
import { join as join15 } from "path";
|
|
7817
8041
|
import { confirm, input as input3 } from "@inquirer/prompts";
|
|
7818
8042
|
import { Command as Command7 } from "commander";
|
|
7819
8043
|
var HOME2 = homedir9();
|
|
@@ -7821,10 +8045,10 @@ function printLine(char = "\u2550", len = 60, color = "\x1B[36m") {
|
|
|
7821
8045
|
console.log(`${color}${char.repeat(len)}\x1B[0m`);
|
|
7822
8046
|
}
|
|
7823
8047
|
function bootstrapSandboxWorkspace(workspaceDir) {
|
|
7824
|
-
mkdirSync9(
|
|
7825
|
-
mkdirSync9(
|
|
7826
|
-
mkdirSync9(
|
|
7827
|
-
const worldviewFile =
|
|
8048
|
+
mkdirSync9(join15(workspaceDir, "beliefs"), { recursive: true });
|
|
8049
|
+
mkdirSync9(join15(workspaceDir, "goals"), { recursive: true });
|
|
8050
|
+
mkdirSync9(join15(workspaceDir, "skills"), { recursive: true });
|
|
8051
|
+
const worldviewFile = join15(workspaceDir, "beliefs", "worldview.md");
|
|
7828
8052
|
if (!existsSync15(worldviewFile)) {
|
|
7829
8053
|
writeFileSync7(
|
|
7830
8054
|
worldviewFile,
|
|
@@ -7838,7 +8062,7 @@ Here, I declare the core concepts and principles I want to master.
|
|
|
7838
8062
|
"utf8"
|
|
7839
8063
|
);
|
|
7840
8064
|
}
|
|
7841
|
-
const goalsFile =
|
|
8065
|
+
const goalsFile = join15(workspaceDir, "goals", "goals.md");
|
|
7842
8066
|
if (!existsSync15(goalsFile)) {
|
|
7843
8067
|
writeFileSync7(
|
|
7844
8068
|
goalsFile,
|
|
@@ -7862,7 +8086,7 @@ var initCommand = new Command7("init").description("Launch the guided interactiv
|
|
|
7862
8086
|
);
|
|
7863
8087
|
printLine();
|
|
7864
8088
|
console.log("\n\x1B[1m[1/5] Setting up Local Workspace Sandbox\x1B[0m");
|
|
7865
|
-
const defaultWorkspace =
|
|
8089
|
+
const defaultWorkspace = join15(HOME2, "Documents", "zam");
|
|
7866
8090
|
const workspacePath = await input3({
|
|
7867
8091
|
message: "Choose your ZAM workspace directory:",
|
|
7868
8092
|
default: defaultWorkspace
|
|
@@ -8561,8 +8785,8 @@ ${"\u2550".repeat(50)}`);
|
|
|
8561
8785
|
// src/cli/commands/monitor.ts
|
|
8562
8786
|
import { execFileSync as execFileSync3, execSync as execSync5 } from "child_process";
|
|
8563
8787
|
import { unlinkSync, writeFileSync as writeFileSync8 } from "fs";
|
|
8564
|
-
import { tmpdir as
|
|
8565
|
-
import { basename as basename3, join as
|
|
8788
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
8789
|
+
import { basename as basename3, join as join16 } from "path";
|
|
8566
8790
|
import { Command as Command9 } from "commander";
|
|
8567
8791
|
function isPowerShellShell(shell) {
|
|
8568
8792
|
return shell === "pwsh" || shell === "powershell";
|
|
@@ -8739,8 +8963,8 @@ function resolveZamInvocation(shell) {
|
|
|
8739
8963
|
if (installed) {
|
|
8740
8964
|
return isPowerShellShell(shell) ? `& ${psSingleQuoted2(installed)}` : installed;
|
|
8741
8965
|
}
|
|
8742
|
-
const projectRoot =
|
|
8743
|
-
const cliSource =
|
|
8966
|
+
const projectRoot = join16(import.meta.dirname, "..", "..", "..");
|
|
8967
|
+
const cliSource = join16(projectRoot, "src/cli/index.ts");
|
|
8744
8968
|
if (isPowerShellShell(shell)) {
|
|
8745
8969
|
return `& npx --prefix ${psSingleQuoted2(projectRoot)} tsx ${psSingleQuoted2(cliSource)}`;
|
|
8746
8970
|
}
|
|
@@ -8830,7 +9054,7 @@ end tell` : `tell application "Terminal"
|
|
|
8830
9054
|
activate
|
|
8831
9055
|
do script "${escaped}"
|
|
8832
9056
|
end tell`;
|
|
8833
|
-
const tmpFile =
|
|
9057
|
+
const tmpFile = join16(tmpdir3(), `zam-monitor-${sessionId}.scpt`);
|
|
8834
9058
|
try {
|
|
8835
9059
|
writeFileSync8(tmpFile, appleScript);
|
|
8836
9060
|
execSync5(`osascript ${JSON.stringify(tmpFile)}`, { stdio: "ignore" });
|
|
@@ -8946,7 +9170,7 @@ observerCommand.command("revoke <process>").description("Remove a process from o
|
|
|
8946
9170
|
|
|
8947
9171
|
// src/cli/commands/profile.ts
|
|
8948
9172
|
import { homedir as homedir10 } from "os";
|
|
8949
|
-
import { dirname as dirname5, join as
|
|
9173
|
+
import { dirname as dirname5, join as join17, resolve as resolve4 } from "path";
|
|
8950
9174
|
import { Command as Command11 } from "commander";
|
|
8951
9175
|
var C2 = {
|
|
8952
9176
|
reset: "\x1B[0m",
|
|
@@ -8956,7 +9180,7 @@ var C2 = {
|
|
|
8956
9180
|
green: "\x1B[32m"
|
|
8957
9181
|
};
|
|
8958
9182
|
function defaultPersonalDir() {
|
|
8959
|
-
return
|
|
9183
|
+
return join17(homedir10(), "Documents", "zam");
|
|
8960
9184
|
}
|
|
8961
9185
|
function render(profile) {
|
|
8962
9186
|
const sync = profile.syncProvider ? `${C2.green}${profile.syncProvider}${C2.reset} ${C2.dim}(good for cross-device snapshots)${C2.reset}` : `${C2.dim}local folder (use a synced folder or snapshots to move between machines)${C2.reset}`;
|
|
@@ -9677,31 +9901,31 @@ settingsCommand.command("repos").description("Show or set Personal, Team, and Or
|
|
|
9677
9901
|
|
|
9678
9902
|
// src/cli/commands/setup.ts
|
|
9679
9903
|
import { copyFileSync as copyFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
9680
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
9904
|
+
import { basename as basename4, dirname as dirname6, join as join18 } from "path";
|
|
9681
9905
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9682
9906
|
import { Command as Command15 } from "commander";
|
|
9683
9907
|
var packageRoot = [
|
|
9684
9908
|
fileURLToPath2(new URL("../..", import.meta.url)),
|
|
9685
9909
|
fileURLToPath2(new URL("../../..", import.meta.url))
|
|
9686
|
-
].find((candidate) => existsSync17(
|
|
9910
|
+
].find((candidate) => existsSync17(join18(candidate, "package.json"))) ?? fileURLToPath2(new URL("../..", import.meta.url));
|
|
9687
9911
|
var SKILL_PAIRS = [
|
|
9688
9912
|
{
|
|
9689
|
-
from:
|
|
9690
|
-
to:
|
|
9913
|
+
from: join18(packageRoot, ".claude", "skills", "zam", "SKILL.md"),
|
|
9914
|
+
to: join18(".claude", "skills", "zam", "SKILL.md")
|
|
9691
9915
|
},
|
|
9692
9916
|
{
|
|
9693
|
-
from:
|
|
9694
|
-
to:
|
|
9917
|
+
from: join18(packageRoot, ".agent", "skills", "zam", "SKILL.md"),
|
|
9918
|
+
to: join18(".agent", "skills", "zam", "SKILL.md")
|
|
9695
9919
|
},
|
|
9696
9920
|
{
|
|
9697
|
-
from:
|
|
9698
|
-
to:
|
|
9921
|
+
from: join18(packageRoot, ".agents", "skills", "zam", "SKILL.md"),
|
|
9922
|
+
to: join18(".agents", "skills", "zam", "SKILL.md")
|
|
9699
9923
|
}
|
|
9700
9924
|
];
|
|
9701
9925
|
function copySkills(force, cwd = process.cwd()) {
|
|
9702
9926
|
let anyAction = false;
|
|
9703
9927
|
for (const { from, to } of SKILL_PAIRS) {
|
|
9704
|
-
const dest =
|
|
9928
|
+
const dest = join18(cwd, to);
|
|
9705
9929
|
if (!existsSync17(from)) {
|
|
9706
9930
|
console.warn(` warn source not found, skipping: ${from}`);
|
|
9707
9931
|
continue;
|
|
@@ -9751,7 +9975,7 @@ async function initDatabase(skipInit) {
|
|
|
9751
9975
|
}
|
|
9752
9976
|
function writeClaudeMd(skipClaudeMd, cwd = process.cwd()) {
|
|
9753
9977
|
if (skipClaudeMd) return;
|
|
9754
|
-
const dest =
|
|
9978
|
+
const dest = join18(cwd, "CLAUDE.md");
|
|
9755
9979
|
if (existsSync17(dest)) {
|
|
9756
9980
|
console.log(` skip CLAUDE.md (already present)`);
|
|
9757
9981
|
return;
|
|
@@ -9785,7 +10009,7 @@ Use \`zam connector setup turso\` to store cloud credentials in
|
|
|
9785
10009
|
}
|
|
9786
10010
|
function writeAgentsMd(skipAgentsMd, cwd = process.cwd()) {
|
|
9787
10011
|
if (skipAgentsMd) return;
|
|
9788
|
-
const dest =
|
|
10012
|
+
const dest = join18(cwd, "AGENTS.md");
|
|
9789
10013
|
if (existsSync17(dest)) {
|
|
9790
10014
|
console.log(` skip AGENTS.md (already present)`);
|
|
9791
10015
|
return;
|
|
@@ -9933,7 +10157,7 @@ skillCommand.command("add").description("Register a new agent skill").requiredOp
|
|
|
9933
10157
|
// src/cli/commands/snapshot.ts
|
|
9934
10158
|
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
9935
10159
|
import { homedir as homedir11 } from "os";
|
|
9936
|
-
import { dirname as dirname7, join as
|
|
10160
|
+
import { dirname as dirname7, join as join19 } from "path";
|
|
9937
10161
|
import { Command as Command17 } from "commander";
|
|
9938
10162
|
function defaultOutName() {
|
|
9939
10163
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
|
|
@@ -9953,7 +10177,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
|
|
|
9953
10177
|
try {
|
|
9954
10178
|
db = await openDatabaseWithSync({ initialize: true });
|
|
9955
10179
|
const snapshot = await exportSnapshot(db);
|
|
9956
|
-
const personalDir = await getSetting(db, "personal.workspace_dir") ||
|
|
10180
|
+
const personalDir = await getSetting(db, "personal.workspace_dir") || join19(homedir11(), "Documents", "zam");
|
|
9957
10181
|
await db.close();
|
|
9958
10182
|
db = void 0;
|
|
9959
10183
|
const manifest = verifySnapshot(snapshot);
|
|
@@ -9962,7 +10186,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
|
|
|
9962
10186
|
process.stdout.write(snapshot);
|
|
9963
10187
|
return;
|
|
9964
10188
|
}
|
|
9965
|
-
const out = opts.out ??
|
|
10189
|
+
const out = opts.out ?? join19(personalDir, "snapshots", defaultOutName());
|
|
9966
10190
|
const dir = dirname7(out);
|
|
9967
10191
|
if (dir && dir !== "." && !existsSync18(dir)) {
|
|
9968
10192
|
mkdirSync11(dir, { recursive: true });
|
|
@@ -10349,7 +10573,7 @@ tokenCommand.command("status").description("Show full status of a token for a us
|
|
|
10349
10573
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
10350
10574
|
import { existsSync as existsSync19 } from "fs";
|
|
10351
10575
|
import { homedir as homedir12 } from "os";
|
|
10352
|
-
import { dirname as dirname8, join as
|
|
10576
|
+
import { dirname as dirname8, join as join20 } from "path";
|
|
10353
10577
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10354
10578
|
import { Command as Command20 } from "commander";
|
|
10355
10579
|
var C3 = {
|
|
@@ -10365,8 +10589,8 @@ function findDesktopDir() {
|
|
|
10365
10589
|
for (const start of starts) {
|
|
10366
10590
|
let dir = start;
|
|
10367
10591
|
for (let i = 0; i < 10; i++) {
|
|
10368
|
-
if (existsSync19(
|
|
10369
|
-
return
|
|
10592
|
+
if (existsSync19(join20(dir, "desktop", "src-tauri", "tauri.conf.json"))) {
|
|
10593
|
+
return join20(dir, "desktop");
|
|
10370
10594
|
}
|
|
10371
10595
|
const parent = dirname8(dir);
|
|
10372
10596
|
if (parent === dir) break;
|
|
@@ -10376,18 +10600,18 @@ function findDesktopDir() {
|
|
|
10376
10600
|
return null;
|
|
10377
10601
|
}
|
|
10378
10602
|
function findBuiltApp(desktopDir) {
|
|
10379
|
-
const releaseDir =
|
|
10603
|
+
const releaseDir = join20(desktopDir, "src-tauri", "target", "release");
|
|
10380
10604
|
if (process.platform === "win32") {
|
|
10381
10605
|
for (const name of ["ZAM.exe", "zam.exe", "zam-desktop.exe"]) {
|
|
10382
|
-
const p =
|
|
10606
|
+
const p = join20(releaseDir, name);
|
|
10383
10607
|
if (existsSync19(p)) return p;
|
|
10384
10608
|
}
|
|
10385
10609
|
} else if (process.platform === "darwin") {
|
|
10386
|
-
const app =
|
|
10610
|
+
const app = join20(releaseDir, "bundle", "macos", "ZAM.app");
|
|
10387
10611
|
if (existsSync19(app)) return app;
|
|
10388
10612
|
} else {
|
|
10389
10613
|
for (const name of ["zam", "ZAM", "zam-desktop"]) {
|
|
10390
|
-
const p =
|
|
10614
|
+
const p = join20(releaseDir, name);
|
|
10391
10615
|
if (existsSync19(p)) return p;
|
|
10392
10616
|
}
|
|
10393
10617
|
}
|
|
@@ -10395,10 +10619,10 @@ function findBuiltApp(desktopDir) {
|
|
|
10395
10619
|
}
|
|
10396
10620
|
function findInstalledApp() {
|
|
10397
10621
|
const candidates = process.platform === "win32" ? [
|
|
10398
|
-
process.env.LOCALAPPDATA &&
|
|
10399
|
-
process.env.ProgramFiles &&
|
|
10400
|
-
process.env["ProgramFiles(x86)"] &&
|
|
10401
|
-
] : process.platform === "darwin" ? ["/Applications/ZAM.app",
|
|
10622
|
+
process.env.LOCALAPPDATA && join20(process.env.LOCALAPPDATA, "Programs", "ZAM", "ZAM.exe"),
|
|
10623
|
+
process.env.ProgramFiles && join20(process.env.ProgramFiles, "ZAM", "ZAM.exe"),
|
|
10624
|
+
process.env["ProgramFiles(x86)"] && join20(process.env["ProgramFiles(x86)"], "ZAM", "ZAM.exe")
|
|
10625
|
+
] : process.platform === "darwin" ? ["/Applications/ZAM.app", join20(homedir12(), "Applications", "ZAM.app")] : ["/opt/ZAM/zam", "/usr/bin/zam-desktop"];
|
|
10402
10626
|
return candidates.find((candidate) => candidate && existsSync19(candidate)) || null;
|
|
10403
10627
|
}
|
|
10404
10628
|
function runNpm(args, opts) {
|
|
@@ -10410,7 +10634,7 @@ function runNpm(args, opts) {
|
|
|
10410
10634
|
return res.status ?? 1;
|
|
10411
10635
|
}
|
|
10412
10636
|
function ensureDesktopDeps(desktopDir) {
|
|
10413
|
-
if (existsSync19(
|
|
10637
|
+
if (existsSync19(join20(desktopDir, "node_modules"))) return true;
|
|
10414
10638
|
console.log(
|
|
10415
10639
|
`${C3.cyan}Installing desktop dependencies (one-time)...${C3.reset}`
|
|
10416
10640
|
);
|
|
@@ -10436,7 +10660,7 @@ function requireRust() {
|
|
|
10436
10660
|
function hasMsvcBuildTools() {
|
|
10437
10661
|
if (process.platform !== "win32") return true;
|
|
10438
10662
|
const pf86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
|
|
10439
|
-
const vswhere =
|
|
10663
|
+
const vswhere = join20(
|
|
10440
10664
|
pf86,
|
|
10441
10665
|
"Microsoft Visual Studio",
|
|
10442
10666
|
"Installer",
|
|
@@ -10474,7 +10698,7 @@ function requireMsvcOnWindows() {
|
|
|
10474
10698
|
return false;
|
|
10475
10699
|
}
|
|
10476
10700
|
function warnIfCliMissing(repoRoot) {
|
|
10477
|
-
if (!existsSync19(
|
|
10701
|
+
if (!existsSync19(join20(repoRoot, "dist", "cli", "index.js"))) {
|
|
10478
10702
|
console.warn(
|
|
10479
10703
|
`${C3.yellow}\u26A0 CLI build not found (dist/cli/index.js). The GUI bridge needs it \u2014 run 'npm run build' at the repo root.${C3.reset}`
|
|
10480
10704
|
);
|
|
@@ -10558,7 +10782,7 @@ var uiCommand = new Command20("ui").description("Launch the ZAM Desktop GUI (Act
|
|
|
10558
10782
|
);
|
|
10559
10783
|
const code = runNpm(["run", "tauri", "build"], { cwd: desktopDir });
|
|
10560
10784
|
if (code === 0) {
|
|
10561
|
-
const bundle =
|
|
10785
|
+
const bundle = join20(
|
|
10562
10786
|
desktopDir,
|
|
10563
10787
|
"src-tauri",
|
|
10564
10788
|
"target",
|
|
@@ -10636,7 +10860,7 @@ ${C3.dim}After that, 'zam ui' launches it directly.${C3.reset}`
|
|
|
10636
10860
|
// src/cli/commands/update.ts
|
|
10637
10861
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10638
10862
|
import { existsSync as existsSync20, readFileSync as readFileSync13, realpathSync } from "fs";
|
|
10639
|
-
import { dirname as dirname9, join as
|
|
10863
|
+
import { dirname as dirname9, join as join21 } from "path";
|
|
10640
10864
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10641
10865
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
10642
10866
|
import { Command as Command21 } from "commander";
|
|
@@ -10661,7 +10885,7 @@ function currentVersion() {
|
|
|
10661
10885
|
for (const up of ["..", "../..", "../../.."]) {
|
|
10662
10886
|
try {
|
|
10663
10887
|
const pkg2 = JSON.parse(
|
|
10664
|
-
readFileSync13(
|
|
10888
|
+
readFileSync13(join21(here, up, "package.json"), "utf-8")
|
|
10665
10889
|
);
|
|
10666
10890
|
if (pkg2.version) return pkg2.version;
|
|
10667
10891
|
} catch {
|
|
@@ -10672,7 +10896,7 @@ function currentVersion() {
|
|
|
10672
10896
|
function versionAt(dir) {
|
|
10673
10897
|
try {
|
|
10674
10898
|
const pkg2 = JSON.parse(
|
|
10675
|
-
readFileSync13(
|
|
10899
|
+
readFileSync13(join21(dir, "package.json"), "utf-8")
|
|
10676
10900
|
);
|
|
10677
10901
|
return pkg2.version ?? "unknown";
|
|
10678
10902
|
} catch {
|
|
@@ -10752,11 +10976,11 @@ function findSourceRepo() {
|
|
|
10752
10976
|
let dir = realpathSync(dirname9(fileURLToPath4(import.meta.url)));
|
|
10753
10977
|
let parent = dirname9(dir);
|
|
10754
10978
|
while (parent !== dir) {
|
|
10755
|
-
if (existsSync20(
|
|
10979
|
+
if (existsSync20(join21(dir, ".git"))) return dir;
|
|
10756
10980
|
dir = parent;
|
|
10757
10981
|
parent = dirname9(dir);
|
|
10758
10982
|
}
|
|
10759
|
-
return existsSync20(
|
|
10983
|
+
return existsSync20(join21(dir, ".git")) ? dir : null;
|
|
10760
10984
|
}
|
|
10761
10985
|
function runGit(cwd, args, capture) {
|
|
10762
10986
|
const res = spawnSync2("git", args, {
|
|
@@ -10821,7 +11045,7 @@ Commit or stash them, or re-run with ${C4.cyan}--force${C4.reset}.`
|
|
|
10821
11045
|
console.log(`${C4.dim}\u2192 zam setup --force${C4.reset}`);
|
|
10822
11046
|
const setup = spawnSync2(
|
|
10823
11047
|
process.execPath,
|
|
10824
|
-
[
|
|
11048
|
+
[join21(src, "dist", "cli", "index.js"), "setup", "--force"],
|
|
10825
11049
|
{ cwd: process.cwd(), stdio: "inherit" }
|
|
10826
11050
|
);
|
|
10827
11051
|
if (setup.status !== 0) {
|
|
@@ -10933,7 +11157,7 @@ var whoamiCommand = new Command22("whoami").description("Show or set the default
|
|
|
10933
11157
|
// src/cli/commands/workspace.ts
|
|
10934
11158
|
import { execSync as execSync6 } from "child_process";
|
|
10935
11159
|
import { existsSync as existsSync21, writeFileSync as writeFileSync11 } from "fs";
|
|
10936
|
-
import { join as
|
|
11160
|
+
import { join as join22 } from "path";
|
|
10937
11161
|
import { confirm as confirm4, input as input7 } from "@inquirer/prompts";
|
|
10938
11162
|
import { Command as Command23 } from "commander";
|
|
10939
11163
|
function runGit2(cwd, args) {
|
|
@@ -10980,7 +11204,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
10980
11204
|
);
|
|
10981
11205
|
process.exit(1);
|
|
10982
11206
|
}
|
|
10983
|
-
const gitignorePath =
|
|
11207
|
+
const gitignorePath = join22(workspaceDir, ".gitignore");
|
|
10984
11208
|
if (!existsSync21(gitignorePath)) {
|
|
10985
11209
|
writeFileSync11(
|
|
10986
11210
|
gitignorePath,
|
|
@@ -10988,7 +11212,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
10988
11212
|
"utf8"
|
|
10989
11213
|
);
|
|
10990
11214
|
}
|
|
10991
|
-
const hasGitRepo = existsSync21(
|
|
11215
|
+
const hasGitRepo = existsSync21(join22(workspaceDir, ".git"));
|
|
10992
11216
|
if (!hasGitRepo) {
|
|
10993
11217
|
console.log("Initializing local Git repository...");
|
|
10994
11218
|
runGit2(workspaceDir, "init -b main");
|
|
@@ -11084,7 +11308,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
11084
11308
|
// src/cli/index.ts
|
|
11085
11309
|
var __dirname = dirname10(fileURLToPath5(import.meta.url));
|
|
11086
11310
|
var pkg = JSON.parse(
|
|
11087
|
-
readFileSync14(
|
|
11311
|
+
readFileSync14(join23(__dirname, "..", "..", "package.json"), "utf-8")
|
|
11088
11312
|
);
|
|
11089
11313
|
var program = new Command24();
|
|
11090
11314
|
program.name("zam").description(
|