zam-core 0.4.0 → 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 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 join22 } from "path";
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
 
@@ -4847,6 +4847,37 @@ function decideUpdate(input8) {
4847
4847
  };
4848
4848
  }
4849
4849
  }
4850
+ function planUpdate(decision) {
4851
+ if (!decision.updateAvailable) return [];
4852
+ switch (decision.channel) {
4853
+ case "developer":
4854
+ return [
4855
+ { kind: "git-pull", label: "Pull the latest source" },
4856
+ { kind: "npm-install", label: "Install dependencies" },
4857
+ { kind: "npm-build", label: "Rebuild the CLI" },
4858
+ {
4859
+ kind: "distribute-skills",
4860
+ label: "Refresh skill files (zam setup --force)"
4861
+ }
4862
+ ];
4863
+ case "winget":
4864
+ case "homebrew":
4865
+ return [
4866
+ {
4867
+ kind: "run-command",
4868
+ label: `Update via ${decision.channel}`,
4869
+ command: decision.command
4870
+ }
4871
+ ];
4872
+ case "direct":
4873
+ return [
4874
+ {
4875
+ kind: "self-update",
4876
+ label: "Apply the signed update via the desktop app"
4877
+ }
4878
+ ];
4879
+ }
4880
+ }
4850
4881
 
4851
4882
  // src/cli/commands/agent.ts
4852
4883
  var C = {
@@ -4901,10 +4932,10 @@ var agentCommand = new Command("agent").description("Provision and inspect the a
4901
4932
 
4902
4933
  // src/cli/commands/bridge.ts
4903
4934
  import { execFileSync as execFileSync2 } from "child_process";
4904
- import { randomBytes } from "crypto";
4935
+ import { randomBytes as randomBytes2 } from "crypto";
4905
4936
  import { readdirSync as readdirSync2, readFileSync as readFileSync10, rmSync as rmSync2 } from "fs";
4906
- import { homedir as homedir8, tmpdir } from "os";
4907
- import { join as join12 } from "path";
4937
+ import { homedir as homedir8, tmpdir as tmpdir2 } from "os";
4938
+ import { join as join13 } from "path";
4908
4939
  import { Command as Command2 } from "commander";
4909
4940
 
4910
4941
  // src/cli/llm/client.ts
@@ -5267,8 +5298,8 @@ async function startLocalRunner(url, model, locale) {
5267
5298
  process.stdout.write("\n");
5268
5299
  console.log(`\x1B[33m${t(locale, "wait_warning")}\x1B[0m`);
5269
5300
  console.log(`\x1B[2m${t(locale, "wait_info")}\x1B[0m`);
5270
- const { confirm: confirm4 } = await import("@inquirer/prompts");
5271
- const keepWaiting = await confirm4({
5301
+ const { confirm: confirm5 } = await import("@inquirer/prompts");
5302
+ const keepWaiting = await confirm5({
5272
5303
  message: t(locale, "keep_waiting_llm"),
5273
5304
  default: true
5274
5305
  }).catch(() => false);
@@ -5412,8 +5443,8 @@ async function fetchWithInteractiveTimeout(url, options = {}) {
5412
5443
  }
5413
5444
  console.log(`
5414
5445
  \x1B[33m${t(locale, "local_ai_working")}\x1B[0m`);
5415
- const { confirm: confirm4 } = await import("@inquirer/prompts");
5416
- const keepWaiting = await confirm4({
5446
+ const { confirm: confirm5 } = await import("@inquirer/prompts");
5447
+ const keepWaiting = await confirm5({
5417
5448
  message: t(locale, "keep_waiting"),
5418
5449
  default: true
5419
5450
  }).catch(() => false);
@@ -5467,7 +5498,9 @@ async function ensureHighQualityQuestion(db, token) {
5467
5498
 
5468
5499
  // src/cli/llm/vision.ts
5469
5500
  import { readFileSync as readFileSync9 } from "fs";
5470
- import { basename as basename2 } from "path";
5501
+ import { randomBytes } from "crypto";
5502
+ import { tmpdir } from "os";
5503
+ import { basename as basename2, join as join12 } from "path";
5471
5504
  var LANGUAGE_NAMES2 = {
5472
5505
  en: "English",
5473
5506
  de: "German",
@@ -5500,15 +5533,61 @@ async function observeUiSnapshotViaLLM(db, input8) {
5500
5533
  "Vision observation is disabled in settings (llm.vision.enabled)"
5501
5534
  );
5502
5535
  }
5503
- const imageBytes = readFileSync9(input8.imagePath);
5504
- const imageUrl = `data:image/png;base64,${imageBytes.toString("base64")}`;
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
+ }
5505
5584
  const model = input8.model ?? cfg.model;
5506
5585
  const content = await requestVisionDraft({
5507
5586
  url: cfg.url,
5508
5587
  apiKey: cfg.apiKey || DEFAULT_LLM_API_KEY,
5509
5588
  model,
5510
5589
  locale: cfg.locale,
5511
- imageUrl,
5590
+ imageUrls,
5512
5591
  input: input8
5513
5592
  });
5514
5593
  let draft;
@@ -5558,17 +5637,22 @@ async function requestVisionDraft(args) {
5558
5637
  content: [
5559
5638
  {
5560
5639
  type: "text",
5561
- text: `Observe this Windows application snapshot for a learning session.
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.
5562
5646
  Application process: ${args.input.application.processName}
5563
5647
  Window title: ${args.input.application.windowTitle ?? "(unknown)"}
5564
5648
 
5565
5649
  Return this JSON draft only:
5566
5650
  ${schema}`
5567
5651
  },
5568
- {
5652
+ ...args.imageUrls.map((url) => ({
5569
5653
  type: "image_url",
5570
- image_url: { url: args.imageUrl }
5571
- }
5654
+ image_url: { url }
5655
+ }))
5572
5656
  ]
5573
5657
  }
5574
5658
  ],
@@ -6208,7 +6292,7 @@ bridgeCommand.command("discover-skills").description(
6208
6292
  "20"
6209
6293
  ).action(async (opts) => {
6210
6294
  try {
6211
- const monitorDir = join12(homedir8(), ".zam", "monitor");
6295
+ const monitorDir = join13(homedir8(), ".zam", "monitor");
6212
6296
  let files;
6213
6297
  try {
6214
6298
  files = readdirSync2(monitorDir).filter((f) => f.endsWith(".jsonl"));
@@ -6221,7 +6305,7 @@ bridgeCommand.command("discover-skills").description(
6221
6305
  return;
6222
6306
  }
6223
6307
  const limit = Number(opts.limit);
6224
- const sorted = files.map((f) => ({ name: f, path: join12(monitorDir, f) })).sort((a, b) => b.name.localeCompare(a.name)).slice(0, limit);
6308
+ const sorted = files.map((f) => ({ name: f, path: join13(monitorDir, f) })).sort((a, b) => b.name.localeCompare(a.name)).slice(0, limit);
6225
6309
  const sessionCommands = /* @__PURE__ */ new Map();
6226
6310
  for (const file of sorted) {
6227
6311
  const sessionId = file.name.replace(".jsonl", "");
@@ -6301,8 +6385,8 @@ bridgeCommand.command("get-observations").description("Read UI observer reports
6301
6385
  }
6302
6386
  });
6303
6387
  bridgeCommand.command("observe-ui-snapshot").description(
6304
- "Analyze a captured UI snapshot with the configured vision LLM (JSON)"
6305
- ).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) => {
6306
6390
  const sequence = parseNonNegativeIntegerOption("sequence", opts.sequence);
6307
6391
  const processId = opts.processId === void 0 ? void 0 : parseNonNegativeIntegerOption("process-id", opts.processId);
6308
6392
  const maxTokens = opts.maxTokens === void 0 ? void 0 : parseNonNegativeIntegerOption("max-tokens", opts.maxTokens);
@@ -6723,7 +6807,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
6723
6807
  return;
6724
6808
  }
6725
6809
  }
6726
- const outputPath = opts.image ?? opts.output ?? join12(tmpdir(), `zam-capture-${randomBytes(4).toString("hex")}.png`);
6810
+ const outputPath = opts.image ?? opts.output ?? join13(tmpdir2(), `zam-capture-${randomBytes2(4).toString("hex")}.png`);
6727
6811
  const captureResult = isProvided ? { method: "provided", target: null } : captureScreenshot(outputPath, opts.hwnd, opts.processName);
6728
6812
  if (!isProvided) {
6729
6813
  const post = decidePostCapture(policy, {
@@ -6767,6 +6851,177 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
6767
6851
  });
6768
6852
  });
6769
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
+ });
6770
7025
  bridgeCommand.command("get-observer-policy").description(
6771
7026
  "Report the resolved observer policy so an agent can check before capturing (JSON)"
6772
7027
  ).action(async () => {
@@ -7475,18 +7730,18 @@ async function setupTurso(urlArg, tokenArg, mode) {
7475
7730
  // src/cli/commands/git-sync.ts
7476
7731
  import { execSync as execSync4 } from "child_process";
7477
7732
  import { chmodSync as chmodSync2, existsSync as existsSync13, writeFileSync as writeFileSync6 } from "fs";
7478
- import { join as join13 } from "path";
7733
+ import { join as join14 } from "path";
7479
7734
  import { Command as Command5 } from "commander";
7480
7735
  function installHook2() {
7481
- const gitDir = join13(process.cwd(), ".git");
7736
+ const gitDir = join14(process.cwd(), ".git");
7482
7737
  if (!existsSync13(gitDir)) {
7483
7738
  console.error(
7484
7739
  "Error: Current directory is not the root of a Git repository."
7485
7740
  );
7486
7741
  process.exit(1);
7487
7742
  }
7488
- const hooksDir = join13(gitDir, "hooks");
7489
- const hookPath = join13(hooksDir, "post-commit");
7743
+ const hooksDir = join14(gitDir, "hooks");
7744
+ const hookPath = join14(hooksDir, "post-commit");
7490
7745
  const hookContent = `#!/bin/sh
7491
7746
  # ZAM Spaced Repetition Auto-Stale Hook
7492
7747
  # Triggered automatically on git commits to decay modified concept cards.
@@ -7782,7 +8037,7 @@ goalCommand.command("status <slug> <status>").description("Update a goal's statu
7782
8037
  // src/cli/commands/init.ts
7783
8038
  import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
7784
8039
  import { homedir as homedir9 } from "os";
7785
- import { join as join14 } from "path";
8040
+ import { join as join15 } from "path";
7786
8041
  import { confirm, input as input3 } from "@inquirer/prompts";
7787
8042
  import { Command as Command7 } from "commander";
7788
8043
  var HOME2 = homedir9();
@@ -7790,10 +8045,10 @@ function printLine(char = "\u2550", len = 60, color = "\x1B[36m") {
7790
8045
  console.log(`${color}${char.repeat(len)}\x1B[0m`);
7791
8046
  }
7792
8047
  function bootstrapSandboxWorkspace(workspaceDir) {
7793
- mkdirSync9(join14(workspaceDir, "beliefs"), { recursive: true });
7794
- mkdirSync9(join14(workspaceDir, "goals"), { recursive: true });
7795
- mkdirSync9(join14(workspaceDir, "skills"), { recursive: true });
7796
- const worldviewFile = join14(workspaceDir, "beliefs", "worldview.md");
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");
7797
8052
  if (!existsSync15(worldviewFile)) {
7798
8053
  writeFileSync7(
7799
8054
  worldviewFile,
@@ -7807,7 +8062,7 @@ Here, I declare the core concepts and principles I want to master.
7807
8062
  "utf8"
7808
8063
  );
7809
8064
  }
7810
- const goalsFile = join14(workspaceDir, "goals", "goals.md");
8065
+ const goalsFile = join15(workspaceDir, "goals", "goals.md");
7811
8066
  if (!existsSync15(goalsFile)) {
7812
8067
  writeFileSync7(
7813
8068
  goalsFile,
@@ -7831,7 +8086,7 @@ var initCommand = new Command7("init").description("Launch the guided interactiv
7831
8086
  );
7832
8087
  printLine();
7833
8088
  console.log("\n\x1B[1m[1/5] Setting up Local Workspace Sandbox\x1B[0m");
7834
- const defaultWorkspace = join14(HOME2, "Documents", "zam");
8089
+ const defaultWorkspace = join15(HOME2, "Documents", "zam");
7835
8090
  const workspacePath = await input3({
7836
8091
  message: "Choose your ZAM workspace directory:",
7837
8092
  default: defaultWorkspace
@@ -8530,8 +8785,8 @@ ${"\u2550".repeat(50)}`);
8530
8785
  // src/cli/commands/monitor.ts
8531
8786
  import { execFileSync as execFileSync3, execSync as execSync5 } from "child_process";
8532
8787
  import { unlinkSync, writeFileSync as writeFileSync8 } from "fs";
8533
- import { tmpdir as tmpdir2 } from "os";
8534
- import { basename as basename3, join as join15 } from "path";
8788
+ import { tmpdir as tmpdir3 } from "os";
8789
+ import { basename as basename3, join as join16 } from "path";
8535
8790
  import { Command as Command9 } from "commander";
8536
8791
  function isPowerShellShell(shell) {
8537
8792
  return shell === "pwsh" || shell === "powershell";
@@ -8708,8 +8963,8 @@ function resolveZamInvocation(shell) {
8708
8963
  if (installed) {
8709
8964
  return isPowerShellShell(shell) ? `& ${psSingleQuoted2(installed)}` : installed;
8710
8965
  }
8711
- const projectRoot = join15(import.meta.dirname, "..", "..", "..");
8712
- const cliSource = join15(projectRoot, "src/cli/index.ts");
8966
+ const projectRoot = join16(import.meta.dirname, "..", "..", "..");
8967
+ const cliSource = join16(projectRoot, "src/cli/index.ts");
8713
8968
  if (isPowerShellShell(shell)) {
8714
8969
  return `& npx --prefix ${psSingleQuoted2(projectRoot)} tsx ${psSingleQuoted2(cliSource)}`;
8715
8970
  }
@@ -8799,7 +9054,7 @@ end tell` : `tell application "Terminal"
8799
9054
  activate
8800
9055
  do script "${escaped}"
8801
9056
  end tell`;
8802
- const tmpFile = join15(tmpdir2(), `zam-monitor-${sessionId}.scpt`);
9057
+ const tmpFile = join16(tmpdir3(), `zam-monitor-${sessionId}.scpt`);
8803
9058
  try {
8804
9059
  writeFileSync8(tmpFile, appleScript);
8805
9060
  execSync5(`osascript ${JSON.stringify(tmpFile)}`, { stdio: "ignore" });
@@ -8915,7 +9170,7 @@ observerCommand.command("revoke <process>").description("Remove a process from o
8915
9170
 
8916
9171
  // src/cli/commands/profile.ts
8917
9172
  import { homedir as homedir10 } from "os";
8918
- import { dirname as dirname5, join as join16, resolve as resolve4 } from "path";
9173
+ import { dirname as dirname5, join as join17, resolve as resolve4 } from "path";
8919
9174
  import { Command as Command11 } from "commander";
8920
9175
  var C2 = {
8921
9176
  reset: "\x1B[0m",
@@ -8925,7 +9180,7 @@ var C2 = {
8925
9180
  green: "\x1B[32m"
8926
9181
  };
8927
9182
  function defaultPersonalDir() {
8928
- return join16(homedir10(), "Documents", "zam");
9183
+ return join17(homedir10(), "Documents", "zam");
8929
9184
  }
8930
9185
  function render(profile) {
8931
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}`;
@@ -9646,31 +9901,31 @@ settingsCommand.command("repos").description("Show or set Personal, Team, and Or
9646
9901
 
9647
9902
  // src/cli/commands/setup.ts
9648
9903
  import { copyFileSync as copyFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
9649
- import { basename as basename4, dirname as dirname6, join as join17 } from "path";
9904
+ import { basename as basename4, dirname as dirname6, join as join18 } from "path";
9650
9905
  import { fileURLToPath as fileURLToPath2 } from "url";
9651
9906
  import { Command as Command15 } from "commander";
9652
9907
  var packageRoot = [
9653
9908
  fileURLToPath2(new URL("../..", import.meta.url)),
9654
9909
  fileURLToPath2(new URL("../../..", import.meta.url))
9655
- ].find((candidate) => existsSync17(join17(candidate, "package.json"))) ?? fileURLToPath2(new URL("../..", import.meta.url));
9910
+ ].find((candidate) => existsSync17(join18(candidate, "package.json"))) ?? fileURLToPath2(new URL("../..", import.meta.url));
9656
9911
  var SKILL_PAIRS = [
9657
9912
  {
9658
- from: join17(packageRoot, ".claude", "skills", "zam", "SKILL.md"),
9659
- to: join17(".claude", "skills", "zam", "SKILL.md")
9913
+ from: join18(packageRoot, ".claude", "skills", "zam", "SKILL.md"),
9914
+ to: join18(".claude", "skills", "zam", "SKILL.md")
9660
9915
  },
9661
9916
  {
9662
- from: join17(packageRoot, ".agent", "skills", "zam", "SKILL.md"),
9663
- to: join17(".agent", "skills", "zam", "SKILL.md")
9917
+ from: join18(packageRoot, ".agent", "skills", "zam", "SKILL.md"),
9918
+ to: join18(".agent", "skills", "zam", "SKILL.md")
9664
9919
  },
9665
9920
  {
9666
- from: join17(packageRoot, ".agents", "skills", "zam", "SKILL.md"),
9667
- to: join17(".agents", "skills", "zam", "SKILL.md")
9921
+ from: join18(packageRoot, ".agents", "skills", "zam", "SKILL.md"),
9922
+ to: join18(".agents", "skills", "zam", "SKILL.md")
9668
9923
  }
9669
9924
  ];
9670
9925
  function copySkills(force, cwd = process.cwd()) {
9671
9926
  let anyAction = false;
9672
9927
  for (const { from, to } of SKILL_PAIRS) {
9673
- const dest = join17(cwd, to);
9928
+ const dest = join18(cwd, to);
9674
9929
  if (!existsSync17(from)) {
9675
9930
  console.warn(` warn source not found, skipping: ${from}`);
9676
9931
  continue;
@@ -9720,7 +9975,7 @@ async function initDatabase(skipInit) {
9720
9975
  }
9721
9976
  function writeClaudeMd(skipClaudeMd, cwd = process.cwd()) {
9722
9977
  if (skipClaudeMd) return;
9723
- const dest = join17(cwd, "CLAUDE.md");
9978
+ const dest = join18(cwd, "CLAUDE.md");
9724
9979
  if (existsSync17(dest)) {
9725
9980
  console.log(` skip CLAUDE.md (already present)`);
9726
9981
  return;
@@ -9754,7 +10009,7 @@ Use \`zam connector setup turso\` to store cloud credentials in
9754
10009
  }
9755
10010
  function writeAgentsMd(skipAgentsMd, cwd = process.cwd()) {
9756
10011
  if (skipAgentsMd) return;
9757
- const dest = join17(cwd, "AGENTS.md");
10012
+ const dest = join18(cwd, "AGENTS.md");
9758
10013
  if (existsSync17(dest)) {
9759
10014
  console.log(` skip AGENTS.md (already present)`);
9760
10015
  return;
@@ -9902,7 +10157,7 @@ skillCommand.command("add").description("Register a new agent skill").requiredOp
9902
10157
  // src/cli/commands/snapshot.ts
9903
10158
  import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
9904
10159
  import { homedir as homedir11 } from "os";
9905
- import { dirname as dirname7, join as join18 } from "path";
10160
+ import { dirname as dirname7, join as join19 } from "path";
9906
10161
  import { Command as Command17 } from "commander";
9907
10162
  function defaultOutName() {
9908
10163
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
@@ -9922,7 +10177,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
9922
10177
  try {
9923
10178
  db = await openDatabaseWithSync({ initialize: true });
9924
10179
  const snapshot = await exportSnapshot(db);
9925
- const personalDir = await getSetting(db, "personal.workspace_dir") || join18(homedir11(), "Documents", "zam");
10180
+ const personalDir = await getSetting(db, "personal.workspace_dir") || join19(homedir11(), "Documents", "zam");
9926
10181
  await db.close();
9927
10182
  db = void 0;
9928
10183
  const manifest = verifySnapshot(snapshot);
@@ -9931,7 +10186,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
9931
10186
  process.stdout.write(snapshot);
9932
10187
  return;
9933
10188
  }
9934
- const out = opts.out ?? join18(personalDir, "snapshots", defaultOutName());
10189
+ const out = opts.out ?? join19(personalDir, "snapshots", defaultOutName());
9935
10190
  const dir = dirname7(out);
9936
10191
  if (dir && dir !== "." && !existsSync18(dir)) {
9937
10192
  mkdirSync11(dir, { recursive: true });
@@ -10318,7 +10573,7 @@ tokenCommand.command("status").description("Show full status of a token for a us
10318
10573
  import { spawn as spawn2, spawnSync } from "child_process";
10319
10574
  import { existsSync as existsSync19 } from "fs";
10320
10575
  import { homedir as homedir12 } from "os";
10321
- import { dirname as dirname8, join as join19 } from "path";
10576
+ import { dirname as dirname8, join as join20 } from "path";
10322
10577
  import { fileURLToPath as fileURLToPath3 } from "url";
10323
10578
  import { Command as Command20 } from "commander";
10324
10579
  var C3 = {
@@ -10334,8 +10589,8 @@ function findDesktopDir() {
10334
10589
  for (const start of starts) {
10335
10590
  let dir = start;
10336
10591
  for (let i = 0; i < 10; i++) {
10337
- if (existsSync19(join19(dir, "desktop", "src-tauri", "tauri.conf.json"))) {
10338
- return join19(dir, "desktop");
10592
+ if (existsSync19(join20(dir, "desktop", "src-tauri", "tauri.conf.json"))) {
10593
+ return join20(dir, "desktop");
10339
10594
  }
10340
10595
  const parent = dirname8(dir);
10341
10596
  if (parent === dir) break;
@@ -10345,18 +10600,18 @@ function findDesktopDir() {
10345
10600
  return null;
10346
10601
  }
10347
10602
  function findBuiltApp(desktopDir) {
10348
- const releaseDir = join19(desktopDir, "src-tauri", "target", "release");
10603
+ const releaseDir = join20(desktopDir, "src-tauri", "target", "release");
10349
10604
  if (process.platform === "win32") {
10350
10605
  for (const name of ["ZAM.exe", "zam.exe", "zam-desktop.exe"]) {
10351
- const p = join19(releaseDir, name);
10606
+ const p = join20(releaseDir, name);
10352
10607
  if (existsSync19(p)) return p;
10353
10608
  }
10354
10609
  } else if (process.platform === "darwin") {
10355
- const app = join19(releaseDir, "bundle", "macos", "ZAM.app");
10610
+ const app = join20(releaseDir, "bundle", "macos", "ZAM.app");
10356
10611
  if (existsSync19(app)) return app;
10357
10612
  } else {
10358
10613
  for (const name of ["zam", "ZAM", "zam-desktop"]) {
10359
- const p = join19(releaseDir, name);
10614
+ const p = join20(releaseDir, name);
10360
10615
  if (existsSync19(p)) return p;
10361
10616
  }
10362
10617
  }
@@ -10364,10 +10619,10 @@ function findBuiltApp(desktopDir) {
10364
10619
  }
10365
10620
  function findInstalledApp() {
10366
10621
  const candidates = process.platform === "win32" ? [
10367
- process.env.LOCALAPPDATA && join19(process.env.LOCALAPPDATA, "Programs", "ZAM", "ZAM.exe"),
10368
- process.env.ProgramFiles && join19(process.env.ProgramFiles, "ZAM", "ZAM.exe"),
10369
- process.env["ProgramFiles(x86)"] && join19(process.env["ProgramFiles(x86)"], "ZAM", "ZAM.exe")
10370
- ] : process.platform === "darwin" ? ["/Applications/ZAM.app", join19(homedir12(), "Applications", "ZAM.app")] : ["/opt/ZAM/zam", "/usr/bin/zam-desktop"];
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"];
10371
10626
  return candidates.find((candidate) => candidate && existsSync19(candidate)) || null;
10372
10627
  }
10373
10628
  function runNpm(args, opts) {
@@ -10379,7 +10634,7 @@ function runNpm(args, opts) {
10379
10634
  return res.status ?? 1;
10380
10635
  }
10381
10636
  function ensureDesktopDeps(desktopDir) {
10382
- if (existsSync19(join19(desktopDir, "node_modules"))) return true;
10637
+ if (existsSync19(join20(desktopDir, "node_modules"))) return true;
10383
10638
  console.log(
10384
10639
  `${C3.cyan}Installing desktop dependencies (one-time)...${C3.reset}`
10385
10640
  );
@@ -10405,7 +10660,7 @@ function requireRust() {
10405
10660
  function hasMsvcBuildTools() {
10406
10661
  if (process.platform !== "win32") return true;
10407
10662
  const pf86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
10408
- const vswhere = join19(
10663
+ const vswhere = join20(
10409
10664
  pf86,
10410
10665
  "Microsoft Visual Studio",
10411
10666
  "Installer",
@@ -10443,7 +10698,7 @@ function requireMsvcOnWindows() {
10443
10698
  return false;
10444
10699
  }
10445
10700
  function warnIfCliMissing(repoRoot) {
10446
- if (!existsSync19(join19(repoRoot, "dist", "cli", "index.js"))) {
10701
+ if (!existsSync19(join20(repoRoot, "dist", "cli", "index.js"))) {
10447
10702
  console.warn(
10448
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}`
10449
10704
  );
@@ -10527,7 +10782,7 @@ var uiCommand = new Command20("ui").description("Launch the ZAM Desktop GUI (Act
10527
10782
  );
10528
10783
  const code = runNpm(["run", "tauri", "build"], { cwd: desktopDir });
10529
10784
  if (code === 0) {
10530
- const bundle = join19(
10785
+ const bundle = join20(
10531
10786
  desktopDir,
10532
10787
  "src-tauri",
10533
10788
  "target",
@@ -10603,9 +10858,11 @@ ${C3.dim}After that, 'zam ui' launches it directly.${C3.reset}`
10603
10858
  });
10604
10859
 
10605
10860
  // src/cli/commands/update.ts
10606
- import { readFileSync as readFileSync13 } from "fs";
10607
- import { dirname as dirname9, join as join20 } from "path";
10861
+ import { spawnSync as spawnSync2 } from "child_process";
10862
+ import { existsSync as existsSync20, readFileSync as readFileSync13, realpathSync } from "fs";
10863
+ import { dirname as dirname9, join as join21 } from "path";
10608
10864
  import { fileURLToPath as fileURLToPath4 } from "url";
10865
+ import { confirm as confirm3 } from "@inquirer/prompts";
10609
10866
  import { Command as Command21 } from "commander";
10610
10867
  var GITHUB_REPO = "zam-os/zam";
10611
10868
  var CHANNELS = [
@@ -10620,6 +10877,7 @@ var C4 = {
10620
10877
  cyan: "\x1B[36m",
10621
10878
  dim: "\x1B[2m",
10622
10879
  green: "\x1B[32m",
10880
+ red: "\x1B[31m",
10623
10881
  yellow: "\x1B[33m"
10624
10882
  };
10625
10883
  function currentVersion() {
@@ -10627,7 +10885,7 @@ function currentVersion() {
10627
10885
  for (const up of ["..", "../..", "../../.."]) {
10628
10886
  try {
10629
10887
  const pkg2 = JSON.parse(
10630
- readFileSync13(join20(here, up, "package.json"), "utf-8")
10888
+ readFileSync13(join21(here, up, "package.json"), "utf-8")
10631
10889
  );
10632
10890
  if (pkg2.version) return pkg2.version;
10633
10891
  } catch {
@@ -10635,6 +10893,16 @@ function currentVersion() {
10635
10893
  }
10636
10894
  return "0.0.0";
10637
10895
  }
10896
+ function versionAt(dir) {
10897
+ try {
10898
+ const pkg2 = JSON.parse(
10899
+ readFileSync13(join21(dir, "package.json"), "utf-8")
10900
+ );
10901
+ return pkg2.version ?? "unknown";
10902
+ } catch {
10903
+ return "unknown";
10904
+ }
10905
+ }
10638
10906
  async function fetchLatestVersion(repo) {
10639
10907
  const res = await fetch(
10640
10908
  `https://api.github.com/repos/${repo}/releases/latest`,
@@ -10704,7 +10972,150 @@ var checkCmd = new Command21("check").description("Check whether a newer ZAM has
10704
10972
  }
10705
10973
  }
10706
10974
  );
10707
- var updateCommand = new Command21("update").description("Check for ZAM updates").addCommand(checkCmd);
10975
+ function findSourceRepo() {
10976
+ let dir = realpathSync(dirname9(fileURLToPath4(import.meta.url)));
10977
+ let parent = dirname9(dir);
10978
+ while (parent !== dir) {
10979
+ if (existsSync20(join21(dir, ".git"))) return dir;
10980
+ dir = parent;
10981
+ parent = dirname9(dir);
10982
+ }
10983
+ return existsSync20(join21(dir, ".git")) ? dir : null;
10984
+ }
10985
+ function runGit(cwd, args, capture) {
10986
+ const res = spawnSync2("git", args, {
10987
+ cwd,
10988
+ stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit",
10989
+ encoding: "utf8"
10990
+ });
10991
+ return { ok: res.status === 0, out: (res.stdout ?? "").trim() };
10992
+ }
10993
+ function runNpm2(args, cwd) {
10994
+ const res = spawnSync2("npm", args, {
10995
+ cwd,
10996
+ stdio: "inherit",
10997
+ shell: process.platform === "win32"
10998
+ });
10999
+ return res.status ?? 1;
11000
+ }
11001
+ function runShell(command) {
11002
+ const res = spawnSync2(command, { stdio: "inherit", shell: true });
11003
+ return res.status === 0;
11004
+ }
11005
+ function applyDeveloperUpdate(force) {
11006
+ if (!hasCommand("git")) {
11007
+ console.error(`${C4.red}\u2717${C4.reset} git was not found on PATH.`);
11008
+ process.exit(1);
11009
+ }
11010
+ const src = findSourceRepo();
11011
+ if (!src) {
11012
+ console.error(
11013
+ `${C4.red}\u2717${C4.reset} Could not locate the ZAM source checkout to update.`
11014
+ );
11015
+ process.exit(1);
11016
+ }
11017
+ const status = runGit(src, ["status", "--porcelain"], true);
11018
+ if (status.ok && status.out && !force) {
11019
+ console.error(
11020
+ `${C4.red}\u2717${C4.reset} The source checkout has uncommitted changes:
11021
+ ${status.out}
11022
+ Commit or stash them, or re-run with ${C4.cyan}--force${C4.reset}.`
11023
+ );
11024
+ process.exit(1);
11025
+ }
11026
+ console.log(
11027
+ `${C4.dim}\u2192 git pull --ff-only${C4.reset} ${C4.dim}(${src})${C4.reset}`
11028
+ );
11029
+ if (!runGit(src, ["pull", "--ff-only"], false).ok) {
11030
+ console.error(
11031
+ `${C4.red}\u2717${C4.reset} git pull failed \u2014 the branch may have diverged or you are offline. Resolve it manually, then retry.`
11032
+ );
11033
+ process.exit(1);
11034
+ }
11035
+ console.log(`${C4.dim}\u2192 npm install${C4.reset}`);
11036
+ if (runNpm2(["install"], src) !== 0) {
11037
+ console.error(`${C4.red}\u2717${C4.reset} npm install failed.`);
11038
+ process.exit(1);
11039
+ }
11040
+ console.log(`${C4.dim}\u2192 npm run build${C4.reset}`);
11041
+ if (runNpm2(["run", "build"], src) !== 0) {
11042
+ console.error(`${C4.red}\u2717${C4.reset} Build failed.`);
11043
+ process.exit(1);
11044
+ }
11045
+ console.log(`${C4.dim}\u2192 zam setup --force${C4.reset}`);
11046
+ const setup = spawnSync2(
11047
+ process.execPath,
11048
+ [join21(src, "dist", "cli", "index.js"), "setup", "--force"],
11049
+ { cwd: process.cwd(), stdio: "inherit" }
11050
+ );
11051
+ if (setup.status !== 0) {
11052
+ console.warn(
11053
+ `${C4.yellow}\u26A0${C4.reset} Skill refresh reported a problem \u2014 run '${C4.cyan}zam setup --force${C4.reset}' here manually.`
11054
+ );
11055
+ }
11056
+ console.log(
11057
+ `
11058
+ ${C4.green}\u2713${C4.reset} Updated to ${C4.cyan}${versionAt(src)}${C4.reset}. Restart your agent client (e.g. Claude Code) to load the refreshed ${C4.cyan}/zam${C4.reset} skill.`
11059
+ );
11060
+ }
11061
+ async function applyUpdate(opts) {
11062
+ try {
11063
+ const current = currentVersion();
11064
+ const latest = await fetchLatestVersion(GITHUB_REPO);
11065
+ const channel = getInstallChannel();
11066
+ const decision = decideUpdate({
11067
+ currentVersion: current,
11068
+ latestVersion: latest,
11069
+ channel
11070
+ });
11071
+ if (!decision.updateAvailable) {
11072
+ console.log(
11073
+ `${C4.green}\u2713${C4.reset} ZAM is up to date (${C4.cyan}${current}${C4.reset}).`
11074
+ );
11075
+ return;
11076
+ }
11077
+ console.log(
11078
+ `${C4.yellow}\u2191${C4.reset} ${C4.bold}Update available${C4.reset}: ${C4.dim}${current}${C4.reset} \u2192 ${C4.cyan}${latest}${C4.reset} ${C4.dim}(${channel} install)${C4.reset}`
11079
+ );
11080
+ for (const step of planUpdate(decision)) {
11081
+ console.log(` ${C4.dim}\u2022${C4.reset} ${step.label}`);
11082
+ }
11083
+ if (channel === "direct") {
11084
+ console.log(
11085
+ `
11086
+ ${C4.dim}This install updates through the desktop app's signed updater \u2014 open ZAM Desktop to install ${latest}.${C4.reset}`
11087
+ );
11088
+ return;
11089
+ }
11090
+ if (!opts.yes) {
11091
+ const ok = await confirm3({
11092
+ message: "Apply this update?",
11093
+ default: true
11094
+ });
11095
+ if (!ok) {
11096
+ console.log("Aborted.");
11097
+ return;
11098
+ }
11099
+ }
11100
+ console.log();
11101
+ if (channel === "winget" || channel === "homebrew") {
11102
+ if (!decision.command || !runShell(decision.command)) process.exit(1);
11103
+ return;
11104
+ }
11105
+ applyDeveloperUpdate(opts.force ?? false);
11106
+ } catch (err) {
11107
+ console.error("Error:", err.message);
11108
+ process.exit(1);
11109
+ }
11110
+ }
11111
+ var updateCommand = new Command21("update").description(
11112
+ "Update ZAM to the latest release (use `update check` to only check)"
11113
+ ).option("-y, --yes", "Apply without confirmation").option(
11114
+ "--force",
11115
+ "Update even if the source checkout has uncommitted changes"
11116
+ ).action(async (opts) => {
11117
+ await applyUpdate(opts);
11118
+ }).addCommand(checkCmd);
10708
11119
 
10709
11120
  // src/cli/commands/whoami.ts
10710
11121
  import { Command as Command22 } from "commander";
@@ -10745,11 +11156,11 @@ var whoamiCommand = new Command22("whoami").description("Show or set the default
10745
11156
 
10746
11157
  // src/cli/commands/workspace.ts
10747
11158
  import { execSync as execSync6 } from "child_process";
10748
- import { existsSync as existsSync20, writeFileSync as writeFileSync11 } from "fs";
10749
- import { join as join21 } from "path";
10750
- import { confirm as confirm3, input as input7 } from "@inquirer/prompts";
11159
+ import { existsSync as existsSync21, writeFileSync as writeFileSync11 } from "fs";
11160
+ import { join as join22 } from "path";
11161
+ import { confirm as confirm4, input as input7 } from "@inquirer/prompts";
10751
11162
  import { Command as Command23 } from "commander";
10752
- function runGit(cwd, args) {
11163
+ function runGit2(cwd, args) {
10753
11164
  try {
10754
11165
  return execSync6(`git ${args}`, {
10755
11166
  cwd,
@@ -10779,7 +11190,7 @@ workspaceCommand.command("publish").description("Publish your local workspace sa
10779
11190
  );
10780
11191
  process.exit(1);
10781
11192
  }
10782
- if (!existsSync20(workspaceDir)) {
11193
+ if (!existsSync21(workspaceDir)) {
10783
11194
  console.error(
10784
11195
  `\x1B[31m\u2717 Workspace directory does not exist: ${workspaceDir}\x1B[0m`
10785
11196
  );
@@ -10793,20 +11204,20 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
10793
11204
  );
10794
11205
  process.exit(1);
10795
11206
  }
10796
- const gitignorePath = join21(workspaceDir, ".gitignore");
10797
- if (!existsSync20(gitignorePath)) {
11207
+ const gitignorePath = join22(workspaceDir, ".gitignore");
11208
+ if (!existsSync21(gitignorePath)) {
10798
11209
  writeFileSync11(
10799
11210
  gitignorePath,
10800
11211
  "node_modules/\n.agent/\n.agents/\n.claude/\n.gemini/\n.goose/\n*.log\n",
10801
11212
  "utf8"
10802
11213
  );
10803
11214
  }
10804
- const hasGitRepo = existsSync20(join21(workspaceDir, ".git"));
11215
+ const hasGitRepo = existsSync21(join22(workspaceDir, ".git"));
10805
11216
  if (!hasGitRepo) {
10806
11217
  console.log("Initializing local Git repository...");
10807
- runGit(workspaceDir, "init -b main");
10808
- runGit(workspaceDir, "add .");
10809
- runGit(
11218
+ runGit2(workspaceDir, "init -b main");
11219
+ runGit2(workspaceDir, "add .");
11220
+ runGit2(
10810
11221
  workspaceDir,
10811
11222
  'commit -m "chore: initial workspace sandbox bootstrap"'
10812
11223
  );
@@ -10818,14 +11229,14 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
10818
11229
  message: "Choose a name for your GitHub repository:",
10819
11230
  default: "zam-personal"
10820
11231
  });
10821
- const isPrivate = await confirm3({
11232
+ const isPrivate = await confirm4({
10822
11233
  message: "Should the repository be private?",
10823
11234
  default: true
10824
11235
  });
10825
11236
  const repoVisibility = isPrivate ? "--private" : "--public";
10826
11237
  if (hasCommand("gh")) {
10827
11238
  console.log("GitHub CLI detected! Automating repository creation...");
10828
- const proceedGh = await confirm3({
11239
+ const proceedGh = await confirm4({
10829
11240
  message: "Would you like ZAM to create the repository using the GitHub CLI?",
10830
11241
  default: true
10831
11242
  });
@@ -10870,16 +11281,16 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
10870
11281
  console.log("Linking remote repository and pushing...");
10871
11282
  let hasOrigin = false;
10872
11283
  try {
10873
- runGit(workspaceDir, "remote get-url origin");
11284
+ runGit2(workspaceDir, "remote get-url origin");
10874
11285
  hasOrigin = true;
10875
11286
  } catch {
10876
11287
  }
10877
11288
  if (hasOrigin) {
10878
- runGit(workspaceDir, `remote set-url origin ${githubUrl}`);
11289
+ runGit2(workspaceDir, `remote set-url origin ${githubUrl}`);
10879
11290
  } else {
10880
- runGit(workspaceDir, `remote add origin ${githubUrl}`);
11291
+ runGit2(workspaceDir, `remote add origin ${githubUrl}`);
10881
11292
  }
10882
- runGit(workspaceDir, "push -u origin main");
11293
+ runGit2(workspaceDir, "push -u origin main");
10883
11294
  console.log(
10884
11295
  "\x1B[32m\u2713 Successfully linked and pushed to GitHub!\x1B[0m"
10885
11296
  );
@@ -10897,7 +11308,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
10897
11308
  // src/cli/index.ts
10898
11309
  var __dirname = dirname10(fileURLToPath5(import.meta.url));
10899
11310
  var pkg = JSON.parse(
10900
- readFileSync14(join22(__dirname, "..", "..", "package.json"), "utf-8")
11311
+ readFileSync14(join23(__dirname, "..", "..", "package.json"), "utf-8")
10901
11312
  );
10902
11313
  var program = new Command24();
10903
11314
  program.name("zam").description(