@hasna/machines 0.0.42 → 0.0.44

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/README.md CHANGED
@@ -144,6 +144,7 @@ CLI and MCP expose the same topology view:
144
144
  machines topology --json
145
145
  machines topology --no-tailscale --json
146
146
  machines route --machine linux-dev-01 --json
147
+ machines ssh --machine linux-dev-01 --private-metadata
147
148
  ```
148
149
 
149
150
  ## Screen sharing
@@ -322,6 +323,11 @@ set `HASNA_MACHINES_ALLOW_PRIVATE_OUTPUT=1` and pass the explicit
322
323
  `privateMetadata=true` query parameter or MCP `private_metadata` argument. The
323
324
  caller flag alone is ignored.
324
325
 
326
+ Default status and SSH-resolution output is public-safe: local paths, machine
327
+ identifiers, route targets, and generated SSH commands are redacted unless
328
+ private output is explicitly requested. CLI commands that print raw SSH targets
329
+ require `--private-metadata`.
330
+
325
331
  Doctor summaries are also opt-in with `--doctor-summary` or
326
332
  `HASNA_MACHINES_AGENT_DOCTOR_SUMMARY=1`. The daemon records a compact
327
333
  ok/warn/fail count plus redacted blockers and avoids optional private adapters
package/dist/cli/index.js CHANGED
@@ -9972,7 +9972,8 @@ function parseJsonObject(value) {
9972
9972
  return null;
9973
9973
  }
9974
9974
  }
9975
- function getStatus() {
9975
+ function getStatus(options = {}) {
9976
+ const privateMetadata = options.privateMetadata === true;
9976
9977
  const manifest = readManifest();
9977
9978
  const heartbeats = listHeartbeats();
9978
9979
  const heartbeatByMachine = latestHeartbeatByMachine(heartbeats);
@@ -9981,17 +9982,17 @@ function getStatus() {
9981
9982
  ...heartbeats.map((heartbeat) => heartbeat.machine_id)
9982
9983
  ]);
9983
9984
  return {
9984
- machineId: getLocalMachineId(),
9985
- manifestPath: getManifestPath(),
9986
- dbPath: getDbPath(),
9987
- notificationsPath: getNotificationsPath(),
9985
+ machineId: privateMetadata ? getLocalMachineId() : REDACTED_VALUE,
9986
+ manifestPath: privateMetadata ? getManifestPath() : REDACTED_VALUE,
9987
+ dbPath: privateMetadata ? getDbPath() : REDACTED_VALUE,
9988
+ notificationsPath: privateMetadata ? getNotificationsPath() : REDACTED_VALUE,
9988
9989
  manifestMachineCount: manifest.machines.length,
9989
9990
  heartbeatCount: heartbeats.length,
9990
9991
  machines: [...machineIds].sort().map((machineId) => {
9991
9992
  const declared = manifest.machines.find((machine) => machine.id === machineId);
9992
9993
  const heartbeat = heartbeatByMachine.get(machineId);
9993
9994
  return {
9994
- machineId,
9995
+ machineId: privateMetadata ? machineId : REDACTED_VALUE,
9995
9996
  platform: declared?.platform,
9996
9997
  manifestDeclared: Boolean(declared),
9997
9998
  heartbeatStatus: heartbeat?.status || "unknown",
@@ -9999,7 +10000,7 @@ function getStatus() {
9999
10000
  daemonVersion: heartbeat?.daemon_version ?? null,
10000
10001
  agentMode: heartbeat?.agent_mode ?? null,
10001
10002
  storageSyncStatus: heartbeat?.storage_sync_status ?? null,
10002
- doctorSummary: parseJsonObject(heartbeat?.doctor_summary_json),
10003
+ doctorSummary: privateMetadata ? parseJsonObject(heartbeat?.doctor_summary_json) : null,
10003
10004
  privateMetadata: Boolean(heartbeat?.private_metadata)
10004
10005
  };
10005
10006
  }),
@@ -10588,7 +10589,7 @@ function runDoctor(machineId, options = {}) {
10588
10589
 
10589
10590
  // src/commands/daemon.ts
10590
10591
  import { execFileSync } from "child_process";
10591
- import { chmodSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
10592
+ import { chmodSync, existsSync as existsSync8, readFileSync as readFileSync6, statSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
10592
10593
  import { dirname as dirname4 } from "path";
10593
10594
  import { platform as osPlatform } from "os";
10594
10595
  var DEFAULT_SERVICE_NAME = "machines-agent";
@@ -10929,6 +10930,8 @@ function escapeSystemdEnvironmentValue(value) {
10929
10930
  function launchdPlist(options) {
10930
10931
  const env2 = Object.entries(options.env).map(([name, value]) => ` <key>${xmlEscape(name)}</key>
10931
10932
  <string>${xmlEscape(value)}</string>`).join(`
10933
+ `);
10934
+ const programArguments = daemonProgramArguments(options).map((value) => ` <string>${xmlEscape(value)}</string>`).join(`
10932
10935
  `);
10933
10936
  return `<?xml version="1.0" encoding="UTF-8"?>
10934
10937
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -10938,9 +10941,7 @@ function launchdPlist(options) {
10938
10941
  <string>${xmlEscape(options.serviceId)}</string>
10939
10942
  <key>ProgramArguments</key>
10940
10943
  <array>
10941
- <string>${xmlEscape(options.executable)}</string>
10942
- <string>--interval-ms</string>
10943
- <string>${options.intervalMs}</string>
10944
+ ${programArguments}
10944
10945
  </array>
10945
10946
  <key>EnvironmentVariables</key>
10946
10947
  <dict>
@@ -10961,6 +10962,7 @@ ${env2}
10961
10962
  function systemdUnit(options) {
10962
10963
  const env2 = Object.entries(options.env).map(([name, value]) => `Environment=${quoteSystemdEnvironment(name, value)}`).join(`
10963
10964
  `);
10965
+ const execStart = daemonProgramArguments(options).map(quoteSystemdExecArg).join(" ");
10964
10966
  return `[Unit]
10965
10967
  Description=Hasna machines agent
10966
10968
  After=network-online.target
@@ -10968,7 +10970,7 @@ Wants=network-online.target
10968
10970
 
10969
10971
  [Service]
10970
10972
  Type=simple
10971
- ExecStart=${quoteSystemdExecArg(options.executable)} --interval-ms ${options.intervalMs}
10973
+ ExecStart=${execStart}
10972
10974
  Restart=always
10973
10975
  RestartSec=10
10974
10976
  ${env2}
@@ -10977,6 +10979,36 @@ ${env2}
10977
10979
  WantedBy=${options.mode === "system" ? "multi-user.target" : "default.target"}
10978
10980
  `;
10979
10981
  }
10982
+ function daemonProgramArguments(options) {
10983
+ const bunRuntime = siblingBunRuntime(options.executable);
10984
+ const base = bunRuntime ? [bunRuntime, options.executable] : [options.executable];
10985
+ return [...base, "--interval-ms", String(options.intervalMs)];
10986
+ }
10987
+ function siblingBunRuntime(executable) {
10988
+ if (!isBunShebangScript(executable))
10989
+ return null;
10990
+ const candidate = `${dirname4(executable)}/bun`;
10991
+ return isExecutableFile(candidate) ? candidate : null;
10992
+ }
10993
+ function isBunShebangScript(executable) {
10994
+ try {
10995
+ const content = readFileSync6(executable, "utf8").slice(0, 256);
10996
+ const firstLine2 = content.split(/\r?\n/, 1)[0] ?? "";
10997
+ return /^#!.*\bbun\b/.test(firstLine2);
10998
+ } catch {
10999
+ return false;
11000
+ }
11001
+ }
11002
+ function isExecutableFile(path) {
11003
+ if (!existsSync8(path))
11004
+ return false;
11005
+ try {
11006
+ const stats = statSync(path);
11007
+ return stats.isFile() && (stats.mode & 73) !== 0;
11008
+ } catch {
11009
+ return false;
11010
+ }
11011
+ }
10980
11012
  function launchdDomain(options) {
10981
11013
  return options.mode === "system" ? "system" : "gui/$UID";
10982
11014
  }
@@ -11333,7 +11365,7 @@ function startDashboardServer(options = {}) {
11333
11365
  return Response.json({ ok: true, ...getServeInfo(options) });
11334
11366
  }
11335
11367
  if (url.pathname === "/api/status") {
11336
- return Response.json(getStatus());
11368
+ return Response.json(appendWarnings(getStatus({ privateMetadata }), privateWarnings));
11337
11369
  }
11338
11370
  if (url.pathname === "/api/topology") {
11339
11371
  const topology = discoverMachineTopology({ includeTailscale: url.searchParams.get("tailscale") !== "false" });
@@ -11471,15 +11503,16 @@ function check(id, status, summary, detail) {
11471
11503
  function runSelfTest() {
11472
11504
  const version = getPackageVersion();
11473
11505
  const status = getStatus();
11506
+ const machineId = getLocalMachineId();
11474
11507
  const doctor = runDoctor();
11475
11508
  const serveInfo = getServeInfo();
11476
11509
  const html = renderDashboardHtml();
11477
11510
  const notifications = listNotificationChannels();
11478
- const apps = listApps(status.machineId);
11479
- const appsDiff = diffApps(status.machineId);
11480
- const cliPlan = buildClaudeInstallPlan(status.machineId);
11511
+ const apps = listApps(machineId);
11512
+ const appsDiff = diffApps(machineId);
11513
+ const cliPlan = buildClaudeInstallPlan(machineId);
11481
11514
  return {
11482
- machineId: getLocalMachineId(),
11515
+ machineId,
11483
11516
  checks: [
11484
11517
  check("package-version", version === "0.0.0" ? "fail" : "ok", "Package version resolves", version),
11485
11518
  check("status", "ok", "Status loads", JSON.stringify({ machines: status.manifestMachineCount, heartbeats: status.heartbeatCount })),
@@ -11497,7 +11530,7 @@ function runSelfTest() {
11497
11530
  // src/commands/clipboard.ts
11498
11531
  init_paths();
11499
11532
  import { createHash } from "crypto";
11500
- import { existsSync as existsSync8, readFileSync as readFileSync6, rmSync, writeFileSync as writeFileSync5 } from "fs";
11533
+ import { existsSync as existsSync9, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync5 } from "fs";
11501
11534
  import { join as join6 } from "path";
11502
11535
  var DEFAULT_CONFIG = {
11503
11536
  version: 1,
@@ -11528,10 +11561,10 @@ function getDefaultConfig() {
11528
11561
  }
11529
11562
  function readConfig(configPath) {
11530
11563
  const path = resolveConfigPath(configPath);
11531
- if (!existsSync8(path)) {
11564
+ if (!existsSync9(path)) {
11532
11565
  return getDefaultConfig();
11533
11566
  }
11534
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
11567
+ const parsed = JSON.parse(readFileSync7(path, "utf8"));
11535
11568
  return { ...getDefaultConfig(), ...parsed };
11536
11569
  }
11537
11570
  function writeConfig(config, configPath) {
@@ -11542,11 +11575,11 @@ function writeConfig(config, configPath) {
11542
11575
  }
11543
11576
  function readHistory(historyPath) {
11544
11577
  const path = resolveHistoryPath(historyPath);
11545
- if (!existsSync8(path)) {
11578
+ if (!existsSync9(path)) {
11546
11579
  return [];
11547
11580
  }
11548
11581
  try {
11549
- return JSON.parse(readFileSync6(path, "utf8"));
11582
+ return JSON.parse(readFileSync7(path, "utf8"));
11550
11583
  } catch {
11551
11584
  return [];
11552
11585
  }
@@ -11575,8 +11608,8 @@ function sanitizeClipboardForRead(content, maxSizeBytes, skipPatterns) {
11575
11608
  }
11576
11609
  function getOrCreateClipboardKey() {
11577
11610
  const keyPath = getClipboardKeyPath();
11578
- if (existsSync8(keyPath)) {
11579
- return readFileSync6(keyPath, "utf8").trim();
11611
+ if (existsSync9(keyPath)) {
11612
+ return readFileSync7(keyPath, "utf8").trim();
11580
11613
  }
11581
11614
  const key = createHash("sha256").update(crypto.randomUUID()).digest("hex").slice(0, 32);
11582
11615
  ensureParentDir(keyPath);
@@ -11615,7 +11648,7 @@ function addClipboardEntry(entry, historyPath) {
11615
11648
  }
11616
11649
  function clearClipboardHistory(historyPath) {
11617
11650
  const path = resolveHistoryPath(historyPath);
11618
- if (existsSync8(path)) {
11651
+ if (existsSync9(path)) {
11619
11652
  rmSync(path);
11620
11653
  }
11621
11654
  }
@@ -11631,7 +11664,7 @@ function getClipboardStatus(historyPath) {
11631
11664
 
11632
11665
  // src/commands/clipboard-daemon.ts
11633
11666
  init_paths();
11634
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
11667
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
11635
11668
  import { join as join7 } from "path";
11636
11669
  import { createHash as createHash3 } from "crypto";
11637
11670
 
@@ -11639,7 +11672,7 @@ import { createHash as createHash3 } from "crypto";
11639
11672
  init_paths();
11640
11673
  import { createServer } from "http";
11641
11674
  import { createHash as createHash2 } from "crypto";
11642
- import { readFileSync as readFileSync7 } from "fs";
11675
+ import { readFileSync as readFileSync8 } from "fs";
11643
11676
  function readLocalClipboardSync() {
11644
11677
  const platform5 = process.platform;
11645
11678
  if (platform5 === "darwin") {
@@ -11685,7 +11718,7 @@ function hasCommand3(binary) {
11685
11718
  function loadSharedSecret() {
11686
11719
  const keyPath = getClipboardKeyPath();
11687
11720
  try {
11688
- return readFileSync7(keyPath, "utf8").trim();
11721
+ return readFileSync8(keyPath, "utf8").trim();
11689
11722
  } catch {
11690
11723
  return "";
11691
11724
  }
@@ -11852,7 +11885,7 @@ function computeHash2(content) {
11852
11885
  }
11853
11886
  function loadSharedSecret2() {
11854
11887
  try {
11855
- return readFileSync8(getClipboardKeyPath(), "utf8").trim();
11888
+ return readFileSync9(getClipboardKeyPath(), "utf8").trim();
11856
11889
  } catch {
11857
11890
  return "";
11858
11891
  }
@@ -11863,7 +11896,7 @@ function writePid(pid) {
11863
11896
  }
11864
11897
  function readPid() {
11865
11898
  try {
11866
- const pid = Number.parseInt(readFileSync8(DAEMON_PID_PATH, "utf8").trim());
11899
+ const pid = Number.parseInt(readFileSync9(DAEMON_PID_PATH, "utf8").trim());
11867
11900
  return Number.isFinite(pid) ? pid : null;
11868
11901
  } catch {
11869
11902
  return null;
@@ -11964,7 +11997,7 @@ async function discoverPeers() {
11964
11997
 
11965
11998
  // src/commands/heal.ts
11966
11999
  init_paths();
11967
- import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
12000
+ import { existsSync as existsSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
11968
12001
  import { join as join8 } from "path";
11969
12002
  var DEFAULT_THRESHOLDS = {
11970
12003
  reconnect: 3,
@@ -12016,9 +12049,9 @@ function getHealStatePath() {
12016
12049
  }
12017
12050
  function readHealConfig(path) {
12018
12051
  const p = path || getHealConfigPath();
12019
- if (!existsSync9(p))
12052
+ if (!existsSync10(p))
12020
12053
  return { ...DEFAULT_HEAL_CONFIG, thresholds: { ...DEFAULT_THRESHOLDS } };
12021
- const parsed = JSON.parse(readFileSync9(p, "utf8"));
12054
+ const parsed = JSON.parse(readFileSync10(p, "utf8"));
12022
12055
  return {
12023
12056
  ...DEFAULT_HEAL_CONFIG,
12024
12057
  ...parsed,
@@ -12034,10 +12067,10 @@ function writeHealConfig(config, path) {
12034
12067
  }
12035
12068
  function readHealState(path) {
12036
12069
  const p = path || getHealStatePath();
12037
- if (!existsSync9(p))
12070
+ if (!existsSync10(p))
12038
12071
  return defaultHealState();
12039
12072
  try {
12040
- return { ...defaultHealState(), ...JSON.parse(readFileSync9(p, "utf8")) };
12073
+ return { ...defaultHealState(), ...JSON.parse(readFileSync10(p, "utf8")) };
12041
12074
  } catch {
12042
12075
  return defaultHealState();
12043
12076
  }
@@ -12164,7 +12197,7 @@ function sh(cmd, timeoutMs = 8000) {
12164
12197
  }
12165
12198
  function getCurrentBootId() {
12166
12199
  try {
12167
- return readFileSync9("/proc/sys/kernel/random/boot_id", "utf8").trim();
12200
+ return readFileSync10("/proc/sys/kernel/random/boot_id", "utf8").trim();
12168
12201
  } catch {
12169
12202
  return "";
12170
12203
  }
@@ -12250,7 +12283,7 @@ function executeAction(action, config) {
12250
12283
 
12251
12284
  // src/commands/heal-daemon.ts
12252
12285
  init_paths();
12253
- import { existsSync as existsSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
12286
+ import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
12254
12287
  import { join as join9 } from "path";
12255
12288
  var DAEMON_PID_PATH2 = join9(getDataDir(), "heal-daemon.pid");
12256
12289
  var SERVICE_PATH = "/etc/systemd/system/machines-heal.service";
@@ -12298,7 +12331,7 @@ function writePid2(pid) {
12298
12331
  }
12299
12332
  function readPid2() {
12300
12333
  try {
12301
- const pid = Number.parseInt(readFileSync10(DAEMON_PID_PATH2, "utf8").trim());
12334
+ const pid = Number.parseInt(readFileSync11(DAEMON_PID_PATH2, "utf8").trim());
12302
12335
  return Number.isFinite(pid) ? pid : null;
12303
12336
  } catch {
12304
12337
  return null;
@@ -12370,9 +12403,9 @@ function applyDeterminism(config) {
12370
12403
  }
12371
12404
  function enableHardwareWatchdog() {
12372
12405
  const log2 = [];
12373
- if (!existsSync10(SYSTEM_CONF))
12406
+ if (!existsSync11(SYSTEM_CONF))
12374
12407
  return ["/etc/systemd/system.conf not found; skipping hardware watchdog"];
12375
- let conf = readFileSync10(SYSTEM_CONF, "utf8");
12408
+ let conf = readFileSync11(SYSTEM_CONF, "utf8");
12376
12409
  const set = (key, value) => {
12377
12410
  const re = new RegExp(`^#?\\s*${key}=.*$`, "m");
12378
12411
  if (re.test(conf))
@@ -12402,7 +12435,7 @@ function binPath() {
12402
12435
  candidates.push(`${home}/.bun/bin/machines`);
12403
12436
  candidates.push("/root/.bun/bin/machines", "/usr/local/bin/machines");
12404
12437
  for (const c of candidates) {
12405
- if (c && existsSync10(c))
12438
+ if (c && existsSync11(c))
12406
12439
  return c;
12407
12440
  }
12408
12441
  return "machines";
@@ -12438,7 +12471,7 @@ WantedBy=multi-user.target
12438
12471
  function uninstallHealService() {
12439
12472
  const log2 = [];
12440
12473
  sh2("systemctl disable --now machines-heal.service 2>/dev/null || true");
12441
- if (existsSync10(SERVICE_PATH)) {
12474
+ if (existsSync11(SERVICE_PATH)) {
12442
12475
  sh2(`rm -f ${SERVICE_PATH}`);
12443
12476
  sh2("systemctl daemon-reload");
12444
12477
  log2.push(`removed ${SERVICE_PATH}`);
@@ -12449,7 +12482,7 @@ function uninstallHealService() {
12449
12482
  }
12450
12483
  function healServiceStatus() {
12451
12484
  return {
12452
- installed: existsSync10(SERVICE_PATH),
12485
+ installed: existsSync11(SERVICE_PATH),
12453
12486
  active: sh2("systemctl is-active machines-heal.service").out === "active",
12454
12487
  enabled: sh2("systemctl is-enabled machines-heal.service 2>/dev/null").out === "enabled"
12455
12488
  };
@@ -12489,7 +12522,7 @@ ${items.map((item) => `- ${item}`).join(`
12489
12522
 
12490
12523
  // src/cli/index.ts
12491
12524
  import { rmSync as rmSync2 } from "fs";
12492
- import { readFileSync as readFileSync11 } from "fs";
12525
+ import { readFileSync as readFileSync12 } from "fs";
12493
12526
  var program2 = new Command;
12494
12527
  function printJsonOrText(data, text, json = false) {
12495
12528
  if (json || program2.opts().quiet) {
@@ -12821,7 +12854,7 @@ manifestCommand.command("add").description("Add or replace a machine in the flee
12821
12854
  console.error("error: --from-stdin requires piped input");
12822
12855
  process.exit(1);
12823
12856
  }
12824
- const input = readFileSync11(0, "utf8");
12857
+ const input = readFileSync12(0, "utf8");
12825
12858
  const machine2 = JSON.parse(input);
12826
12859
  console.log(JSON.stringify(manifestAdd(machine2), null, 2));
12827
12860
  return;
@@ -13150,13 +13183,25 @@ program2.command("route").description("Resolve the best route for a machine").re
13150
13183
  }
13151
13184
  console.log(options.privateMetadata ? command2 ?? `${resolved.route}:${resolved.target}` : `${publicResolved.route}:${publicResolved.target ?? "unresolved"}`);
13152
13185
  });
13153
- program2.command("ssh").description("Choose the best SSH route for a machine").requiredOption("--machine <id>", "Machine identifier").option("--cmd <command>", "Remote command to run").option("-j, --json", "Print JSON output", false).action((options) => {
13186
+ program2.command("ssh").description("Choose the best SSH route for a machine").requiredOption("--machine <id>", "Machine identifier").option("--cmd <command>", "Remote command to run").option("--private-metadata", "Print private SSH target and command", false).option("-j, --json", "Print JSON output", false).action((options) => {
13187
+ const resolved = resolveMachineRoute(options.machine);
13188
+ const publicResolved = redactRouteForOutput(resolved, { privateMetadata: options.privateMetadata });
13189
+ const command2 = resolved.ok && options.privateMetadata ? buildSshCommand(options.machine, options.cmd) : resolved.ok ? REDACTED_VALUE : null;
13154
13190
  if (options.json) {
13155
- const resolved = resolveMachineRoute(options.machine);
13156
- console.log(JSON.stringify({ resolved, command: resolved.ok ? buildSshCommand(options.machine, options.cmd) : null }, null, 2));
13191
+ console.log(JSON.stringify({ resolved: publicResolved, command: command2 }, null, 2));
13192
+ return;
13193
+ }
13194
+ if (!resolved.ok) {
13195
+ console.error(source_default.red(resolved.warnings.join("; ") || `No route found for ${options.machine}`));
13196
+ process.exitCode = 1;
13157
13197
  return;
13158
13198
  }
13159
- console.log(buildSshCommand(options.machine, options.cmd));
13199
+ if (!options.privateMetadata) {
13200
+ console.error(source_default.red("Refusing to print private SSH target; rerun with --private-metadata."));
13201
+ process.exitCode = 1;
13202
+ return;
13203
+ }
13204
+ console.log(command2);
13160
13205
  });
13161
13206
  program2.command("screen").description("Open Screen Sharing (VNC) to a machine using its best live route").argument("[machine]", "Machine identifier").option("--machine <id>", "Machine identifier (alternative to positional arg)").option("--all", "Open every reachable machine", false).option("--print", "Print the vnc:// URL instead of opening it", false).option("-j, --json", "Print JSON output", false).action((machineArg, options) => {
13162
13207
  if (options.all) {
@@ -13304,8 +13349,8 @@ storageCommand.command("sync").description("Bidirectional storage sync: pull the
13304
13349
  printStorageError(error);
13305
13350
  }
13306
13351
  });
13307
- program2.command("status").description("Print local machine and storage status").option("-j, --json", "Print JSON output", false).action((options) => {
13308
- const status = getStatus();
13352
+ program2.command("status").description("Print local machine and storage status").option("--private-metadata", "Print private local paths and machine identifiers", false).option("-j, --json", "Print JSON output", false).action((options) => {
13353
+ const status = getStatus({ privateMetadata: options.privateMetadata });
13309
13354
  printJsonOrText(status, renderFleetStatus(status), options.json);
13310
13355
  });
13311
13356
  program2.command("doctor").description("Run machine preflight checks").option("--machine <id>", "Machine identifier").option("-j, --json", "Print JSON output", false).action((options) => {
@@ -1 +1 @@
1
- {"version":3,"file":"self-test.d.ts","sourceRoot":"","sources":["../../src/commands/self-test.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,aAAa,CAAC;AAMjE,wBAAgB,WAAW,IAAI,cAAc,CAkD5C"}
1
+ {"version":3,"file":"self-test.d.ts","sourceRoot":"","sources":["../../src/commands/self-test.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,aAAa,CAAC;AAMjE,wBAAgB,WAAW,IAAI,cAAc,CAmD5C"}
@@ -1,3 +1,6 @@
1
1
  import type { FleetStatus } from "../types.js";
2
- export declare function getStatus(): FleetStatus;
2
+ export interface FleetStatusOptions {
3
+ privateMetadata?: boolean;
4
+ }
5
+ export declare function getStatus(options?: FleetStatusOptions): FleetStatus;
3
6
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAY/C,wBAAgB,SAAS,IAAI,WAAW,CAmCvC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAY/C,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAoCvE"}
package/dist/index.js CHANGED
@@ -13728,7 +13728,7 @@ function renderDomainMapping(domain) {
13728
13728
  }
13729
13729
  // src/commands/daemon.ts
13730
13730
  import { execFileSync as execFileSync2 } from "child_process";
13731
- import { chmodSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
13731
+ import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync4, statSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
13732
13732
  import { dirname as dirname4 } from "path";
13733
13733
  import { platform as osPlatform } from "os";
13734
13734
  var DEFAULT_SERVICE_NAME = "machines-agent";
@@ -14092,6 +14092,8 @@ function escapeSystemdEnvironmentValue(value) {
14092
14092
  function launchdPlist(options) {
14093
14093
  const env = Object.entries(options.env).map(([name, value]) => ` <key>${xmlEscape(name)}</key>
14094
14094
  <string>${xmlEscape(value)}</string>`).join(`
14095
+ `);
14096
+ const programArguments = daemonProgramArguments(options).map((value) => ` <string>${xmlEscape(value)}</string>`).join(`
14095
14097
  `);
14096
14098
  return `<?xml version="1.0" encoding="UTF-8"?>
14097
14099
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -14101,9 +14103,7 @@ function launchdPlist(options) {
14101
14103
  <string>${xmlEscape(options.serviceId)}</string>
14102
14104
  <key>ProgramArguments</key>
14103
14105
  <array>
14104
- <string>${xmlEscape(options.executable)}</string>
14105
- <string>--interval-ms</string>
14106
- <string>${options.intervalMs}</string>
14106
+ ${programArguments}
14107
14107
  </array>
14108
14108
  <key>EnvironmentVariables</key>
14109
14109
  <dict>
@@ -14124,6 +14124,7 @@ ${env}
14124
14124
  function systemdUnit(options) {
14125
14125
  const env = Object.entries(options.env).map(([name, value]) => `Environment=${quoteSystemdEnvironment(name, value)}`).join(`
14126
14126
  `);
14127
+ const execStart = daemonProgramArguments(options).map(quoteSystemdExecArg).join(" ");
14127
14128
  return `[Unit]
14128
14129
  Description=Hasna machines agent
14129
14130
  After=network-online.target
@@ -14131,7 +14132,7 @@ Wants=network-online.target
14131
14132
 
14132
14133
  [Service]
14133
14134
  Type=simple
14134
- ExecStart=${quoteSystemdExecArg(options.executable)} --interval-ms ${options.intervalMs}
14135
+ ExecStart=${execStart}
14135
14136
  Restart=always
14136
14137
  RestartSec=10
14137
14138
  ${env}
@@ -14140,6 +14141,36 @@ ${env}
14140
14141
  WantedBy=${options.mode === "system" ? "multi-user.target" : "default.target"}
14141
14142
  `;
14142
14143
  }
14144
+ function daemonProgramArguments(options) {
14145
+ const bunRuntime = siblingBunRuntime(options.executable);
14146
+ const base = bunRuntime ? [bunRuntime, options.executable] : [options.executable];
14147
+ return [...base, "--interval-ms", String(options.intervalMs)];
14148
+ }
14149
+ function siblingBunRuntime(executable) {
14150
+ if (!isBunShebangScript(executable))
14151
+ return null;
14152
+ const candidate = `${dirname4(executable)}/bun`;
14153
+ return isExecutableFile(candidate) ? candidate : null;
14154
+ }
14155
+ function isBunShebangScript(executable) {
14156
+ try {
14157
+ const content = readFileSync4(executable, "utf8").slice(0, 256);
14158
+ const firstLine2 = content.split(/\r?\n/, 1)[0] ?? "";
14159
+ return /^#!.*\bbun\b/.test(firstLine2);
14160
+ } catch {
14161
+ return false;
14162
+ }
14163
+ }
14164
+ function isExecutableFile(path) {
14165
+ if (!existsSync6(path))
14166
+ return false;
14167
+ try {
14168
+ const stats = statSync(path);
14169
+ return stats.isFile() && (stats.mode & 73) !== 0;
14170
+ } catch {
14171
+ return false;
14172
+ }
14173
+ }
14143
14174
  function launchdDomain(options) {
14144
14175
  return options.mode === "system" ? "system" : "gui/$UID";
14145
14176
  }
@@ -14420,7 +14451,7 @@ function runTailscaleInstall(machineId, options = {}, runner = runMachineCommand
14420
14451
  };
14421
14452
  }
14422
14453
  // src/commands/notifications.ts
14423
- import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
14454
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
14424
14455
  var notificationChannelSchema = exports_external.object({
14425
14456
  id: exports_external.string(),
14426
14457
  type: exports_external.enum(["email", "webhook", "command"]),
@@ -14576,10 +14607,10 @@ function getDefaultNotificationConfig() {
14576
14607
  };
14577
14608
  }
14578
14609
  function readNotificationConfig(path = getNotificationsPath()) {
14579
- if (!existsSync6(path)) {
14610
+ if (!existsSync7(path)) {
14580
14611
  return getDefaultNotificationConfig();
14581
14612
  }
14582
- return notificationConfigSchema.parse(JSON.parse(readFileSync4(path, "utf8")));
14613
+ return notificationConfigSchema.parse(JSON.parse(readFileSync5(path, "utf8")));
14583
14614
  }
14584
14615
  function writeNotificationConfig(config, path = getNotificationsPath()) {
14585
14616
  ensureParentDir(path);
@@ -14820,7 +14851,8 @@ function parseJsonObject2(value) {
14820
14851
  return null;
14821
14852
  }
14822
14853
  }
14823
- function getStatus() {
14854
+ function getStatus(options = {}) {
14855
+ const privateMetadata = options.privateMetadata === true;
14824
14856
  const manifest = readManifest();
14825
14857
  const heartbeats = listHeartbeats();
14826
14858
  const heartbeatByMachine = latestHeartbeatByMachine(heartbeats);
@@ -14829,17 +14861,17 @@ function getStatus() {
14829
14861
  ...heartbeats.map((heartbeat) => heartbeat.machine_id)
14830
14862
  ]);
14831
14863
  return {
14832
- machineId: getLocalMachineId(),
14833
- manifestPath: getManifestPath(),
14834
- dbPath: getDbPath(),
14835
- notificationsPath: getNotificationsPath(),
14864
+ machineId: privateMetadata ? getLocalMachineId() : REDACTED_VALUE,
14865
+ manifestPath: privateMetadata ? getManifestPath() : REDACTED_VALUE,
14866
+ dbPath: privateMetadata ? getDbPath() : REDACTED_VALUE,
14867
+ notificationsPath: privateMetadata ? getNotificationsPath() : REDACTED_VALUE,
14836
14868
  manifestMachineCount: manifest.machines.length,
14837
14869
  heartbeatCount: heartbeats.length,
14838
14870
  machines: [...machineIds].sort().map((machineId) => {
14839
14871
  const declared = manifest.machines.find((machine) => machine.id === machineId);
14840
14872
  const heartbeat = heartbeatByMachine.get(machineId);
14841
14873
  return {
14842
- machineId,
14874
+ machineId: privateMetadata ? machineId : REDACTED_VALUE,
14843
14875
  platform: declared?.platform,
14844
14876
  manifestDeclared: Boolean(declared),
14845
14877
  heartbeatStatus: heartbeat?.status || "unknown",
@@ -14847,7 +14879,7 @@ function getStatus() {
14847
14879
  daemonVersion: heartbeat?.daemon_version ?? null,
14848
14880
  agentMode: heartbeat?.agent_mode ?? null,
14849
14881
  storageSyncStatus: heartbeat?.storage_sync_status ?? null,
14850
- doctorSummary: parseJsonObject2(heartbeat?.doctor_summary_json),
14882
+ doctorSummary: privateMetadata ? parseJsonObject2(heartbeat?.doctor_summary_json) : null,
14851
14883
  privateMetadata: Boolean(heartbeat?.private_metadata)
14852
14884
  };
14853
14885
  }),
@@ -15089,7 +15121,7 @@ function startDashboardServer(options = {}) {
15089
15121
  return Response.json({ ok: true, ...getServeInfo(options) });
15090
15122
  }
15091
15123
  if (url.pathname === "/api/status") {
15092
- return Response.json(getStatus());
15124
+ return Response.json(appendWarnings(getStatus({ privateMetadata }), privateWarnings));
15093
15125
  }
15094
15126
  if (url.pathname === "/api/topology") {
15095
15127
  const topology = discoverMachineTopology({ includeTailscale: url.searchParams.get("tailscale") !== "false" });
@@ -15227,15 +15259,16 @@ function check(id, status, summary, detail) {
15227
15259
  function runSelfTest() {
15228
15260
  const version = getPackageVersion();
15229
15261
  const status = getStatus();
15262
+ const machineId = getLocalMachineId();
15230
15263
  const doctor = runDoctor();
15231
15264
  const serveInfo = getServeInfo();
15232
15265
  const html = renderDashboardHtml();
15233
15266
  const notifications = listNotificationChannels();
15234
- const apps = listApps(status.machineId);
15235
- const appsDiff = diffApps(status.machineId);
15236
- const cliPlan = buildClaudeInstallPlan(status.machineId);
15267
+ const apps = listApps(machineId);
15268
+ const appsDiff = diffApps(machineId);
15269
+ const cliPlan = buildClaudeInstallPlan(machineId);
15237
15270
  return {
15238
- machineId: getLocalMachineId(),
15271
+ machineId,
15239
15272
  checks: [
15240
15273
  check("package-version", version === "0.0.0" ? "fail" : "ok", "Package version resolves", version),
15241
15274
  check("status", "ok", "Status loads", JSON.stringify({ machines: status.manifestMachineCount, heartbeats: status.heartbeatCount })),
@@ -15516,7 +15549,7 @@ function buildScreenEnableCommand(machineId, options = {}) {
15516
15549
  };
15517
15550
  }
15518
15551
  // src/commands/sync.ts
15519
- import { existsSync as existsSync7, lstatSync, readFileSync as readFileSync5, symlinkSync, copyFileSync } from "fs";
15552
+ import { existsSync as existsSync8, lstatSync, readFileSync as readFileSync6, symlinkSync, copyFileSync } from "fs";
15520
15553
  import { homedir as homedir5 } from "os";
15521
15554
  function quote4(value) {
15522
15555
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -15569,15 +15602,15 @@ function detectFileActions(machine) {
15569
15602
  throw new Error(`Remote file sync planning is not supported for ${machine.id}; refusing to inspect or apply local paths as remote state.`);
15570
15603
  }
15571
15604
  return (machine.files || []).map((file, index) => {
15572
- const sourceExists = existsSync7(file.source);
15573
- const targetExists = existsSync7(file.target);
15605
+ const sourceExists = existsSync8(file.source);
15606
+ const targetExists = existsSync8(file.target);
15574
15607
  let status = "missing";
15575
15608
  if (sourceExists && targetExists) {
15576
15609
  if (file.mode === "symlink") {
15577
15610
  status = lstatSync(file.target).isSymbolicLink() ? "ok" : "drifted";
15578
15611
  } else {
15579
- const source = readFileSync5(file.source, "utf8");
15580
- const target = readFileSync5(file.target, "utf8");
15612
+ const source = readFileSync6(file.source, "utf8");
15613
+ const target = readFileSync6(file.target, "utf8");
15581
15614
  status = source === target ? "ok" : "drifted";
15582
15615
  }
15583
15616
  }
@@ -24805,14 +24838,17 @@ function privateOutputWarnings2(requested, allowed) {
24805
24838
  function appendWarnings2(payload, warnings) {
24806
24839
  if (warnings.length === 0)
24807
24840
  return payload;
24808
- return { ...payload, warnings: [...payload.warnings ?? [], ...warnings] };
24841
+ const currentWarnings = typeof payload === "object" && payload && "warnings" in payload && Array.isArray(payload.warnings) ? payload.warnings : [];
24842
+ return { ...payload, warnings: [...currentWarnings, ...warnings] };
24809
24843
  }
24810
24844
  function createMcpServer(version2) {
24811
24845
  const server = new McpServer({ name: "machines", version: version2 });
24812
24846
  const events = new EventsClient3;
24813
- server.tool("machines_status", "Return local machine fleet status paths and machine identity.", {}, async () => ({
24814
- content: [{ type: "text", text: JSON.stringify(getStatus(), null, 2) }]
24815
- }));
24847
+ server.tool("machines_status", "Return local machine fleet status paths and machine identity.", { private_metadata: exports_external.boolean().optional().describe("Include private local paths and machine identifiers") }, async ({ private_metadata }) => {
24848
+ const privateMetadata = privateMetadataAllowed(private_metadata);
24849
+ const warnings = privateOutputWarnings2(private_metadata, privateMetadata);
24850
+ return { content: [{ type: "text", text: JSON.stringify(appendWarnings2(getStatus({ privateMetadata }), warnings), null, 2) }] };
24851
+ });
24816
24852
  server.tool("machines_doctor", "Run machine preflight checks.", { machine_id: exports_external.string().optional().describe("Machine identifier") }, async ({ machine_id }) => ({ content: [{ type: "text", text: JSON.stringify(runDoctor(machine_id), null, 2) }] }));
24817
24853
  server.tool("machines_self_test", "Run local package smoke checks.", {}, async () => ({
24818
24854
  content: [{ type: "text", text: JSON.stringify(runSelfTest(), null, 2) }]
@@ -24993,9 +25029,23 @@ function createMcpServer(version2) {
24993
25029
  }), null, 2)
24994
25030
  }]
24995
25031
  }));
24996
- server.tool("machines_ssh_resolve", "Resolve the best SSH route for a machine.", { machine_id: exports_external.string().describe("Machine identifier"), remote_command: exports_external.string().optional().describe("Optional remote command") }, async ({ machine_id, remote_command }) => ({
24997
- content: [{ type: "text", text: JSON.stringify({ resolved: resolveMachineRoute(machine_id), command: buildSshCommand(machine_id, remote_command) }, null, 2) }]
24998
- }));
25032
+ server.tool("machines_ssh_resolve", "Resolve the best SSH route for a machine.", {
25033
+ machine_id: exports_external.string().describe("Machine identifier"),
25034
+ remote_command: exports_external.string().optional().describe("Optional remote command"),
25035
+ private_metadata: exports_external.boolean().optional().describe("Include private SSH target and command")
25036
+ }, async ({ machine_id, remote_command, private_metadata }) => {
25037
+ const privateMetadata = privateMetadataAllowed(private_metadata);
25038
+ const warnings = privateOutputWarnings2(private_metadata, privateMetadata);
25039
+ const resolved = resolveMachineRoute(machine_id);
25040
+ const publicResolved = redactRouteForOutput(resolved, { privateMetadata });
25041
+ const command2 = resolved.ok && privateMetadata ? buildSshCommand(machine_id, remote_command) : resolved.ok ? "[redacted]" : null;
25042
+ return {
25043
+ content: [{
25044
+ type: "text",
25045
+ text: JSON.stringify(appendWarnings2({ resolved: publicResolved, command: command2 }, warnings), null, 2)
25046
+ }]
25047
+ };
25048
+ });
24999
25049
  server.tool("machines_ports", "List listening ports on a machine.", { machine_id: exports_external.string().optional().describe("Machine identifier") }, async ({ machine_id }) => ({
25000
25050
  content: [{ type: "text", text: JSON.stringify(listPorts(machine_id), null, 2) }]
25001
25051
  }));
package/dist/mcp/index.js CHANGED
@@ -5954,6 +5954,7 @@ function diffMachines(leftMachineId, rightMachineId) {
5954
5954
  }
5955
5955
 
5956
5956
  // src/commands/daemon.ts
5957
+ import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync4, statSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
5957
5958
  import { dirname as dirname4 } from "path";
5958
5959
  import { platform as osPlatform } from "os";
5959
5960
  var DEFAULT_SERVICE_NAME = "machines-agent";
@@ -6168,6 +6169,8 @@ function command(id, description, program, args, sudo, mutates, allowFailure = f
6168
6169
  function launchdPlist(options) {
6169
6170
  const env = Object.entries(options.env).map(([name, value]) => ` <key>${xmlEscape(name)}</key>
6170
6171
  <string>${xmlEscape(value)}</string>`).join(`
6172
+ `);
6173
+ const programArguments = daemonProgramArguments(options).map((value) => ` <string>${xmlEscape(value)}</string>`).join(`
6171
6174
  `);
6172
6175
  return `<?xml version="1.0" encoding="UTF-8"?>
6173
6176
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -6177,9 +6180,7 @@ function launchdPlist(options) {
6177
6180
  <string>${xmlEscape(options.serviceId)}</string>
6178
6181
  <key>ProgramArguments</key>
6179
6182
  <array>
6180
- <string>${xmlEscape(options.executable)}</string>
6181
- <string>--interval-ms</string>
6182
- <string>${options.intervalMs}</string>
6183
+ ${programArguments}
6183
6184
  </array>
6184
6185
  <key>EnvironmentVariables</key>
6185
6186
  <dict>
@@ -6200,6 +6201,7 @@ ${env}
6200
6201
  function systemdUnit(options) {
6201
6202
  const env = Object.entries(options.env).map(([name, value]) => `Environment=${quoteSystemdEnvironment(name, value)}`).join(`
6202
6203
  `);
6204
+ const execStart = daemonProgramArguments(options).map(quoteSystemdExecArg).join(" ");
6203
6205
  return `[Unit]
6204
6206
  Description=Hasna machines agent
6205
6207
  After=network-online.target
@@ -6207,7 +6209,7 @@ Wants=network-online.target
6207
6209
 
6208
6210
  [Service]
6209
6211
  Type=simple
6210
- ExecStart=${quoteSystemdExecArg(options.executable)} --interval-ms ${options.intervalMs}
6212
+ ExecStart=${execStart}
6211
6213
  Restart=always
6212
6214
  RestartSec=10
6213
6215
  ${env}
@@ -6216,6 +6218,36 @@ ${env}
6216
6218
  WantedBy=${options.mode === "system" ? "multi-user.target" : "default.target"}
6217
6219
  `;
6218
6220
  }
6221
+ function daemonProgramArguments(options) {
6222
+ const bunRuntime = siblingBunRuntime(options.executable);
6223
+ const base = bunRuntime ? [bunRuntime, options.executable] : [options.executable];
6224
+ return [...base, "--interval-ms", String(options.intervalMs)];
6225
+ }
6226
+ function siblingBunRuntime(executable) {
6227
+ if (!isBunShebangScript(executable))
6228
+ return null;
6229
+ const candidate = `${dirname4(executable)}/bun`;
6230
+ return isExecutableFile(candidate) ? candidate : null;
6231
+ }
6232
+ function isBunShebangScript(executable) {
6233
+ try {
6234
+ const content = readFileSync4(executable, "utf8").slice(0, 256);
6235
+ const firstLine = content.split(/\r?\n/, 1)[0] ?? "";
6236
+ return /^#!.*\bbun\b/.test(firstLine);
6237
+ } catch {
6238
+ return false;
6239
+ }
6240
+ }
6241
+ function isExecutableFile(path) {
6242
+ if (!existsSync6(path))
6243
+ return false;
6244
+ try {
6245
+ const stats = statSync(path);
6246
+ return stats.isFile() && (stats.mode & 73) !== 0;
6247
+ } catch {
6248
+ return false;
6249
+ }
6250
+ }
6219
6251
  function launchdDomain(options) {
6220
6252
  return options.mode === "system" ? "system" : "gui/$UID";
6221
6253
  }
@@ -6610,7 +6642,7 @@ function runTailscaleInstall(machineId, options = {}, runner = runMachineCommand
6610
6642
  }
6611
6643
 
6612
6644
  // src/commands/notifications.ts
6613
- import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
6645
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
6614
6646
  var notificationChannelSchema = exports_external.object({
6615
6647
  id: exports_external.string(),
6616
6648
  type: exports_external.enum(["email", "webhook", "command"]),
@@ -6766,10 +6798,10 @@ function getDefaultNotificationConfig() {
6766
6798
  };
6767
6799
  }
6768
6800
  function readNotificationConfig(path = getNotificationsPath()) {
6769
- if (!existsSync6(path)) {
6801
+ if (!existsSync7(path)) {
6770
6802
  return getDefaultNotificationConfig();
6771
6803
  }
6772
- return notificationConfigSchema.parse(JSON.parse(readFileSync4(path, "utf8")));
6804
+ return notificationConfigSchema.parse(JSON.parse(readFileSync5(path, "utf8")));
6773
6805
  }
6774
6806
  function writeNotificationConfig(config, path = getNotificationsPath()) {
6775
6807
  ensureParentDir(path);
@@ -6778,7 +6810,7 @@ function writeNotificationConfig(config, path = getNotificationsPath()) {
6778
6810
  updatedAt: new Date().toISOString(),
6779
6811
  channels: sortChannels(config.channels)
6780
6812
  };
6781
- writeFileSync3(path, `${JSON.stringify(nextConfig, null, 2)}
6813
+ writeFileSync4(path, `${JSON.stringify(nextConfig, null, 2)}
6782
6814
  `, "utf8");
6783
6815
  return nextConfig;
6784
6816
  }
@@ -7397,7 +7429,8 @@ function parseJsonObject2(value) {
7397
7429
  return null;
7398
7430
  }
7399
7431
  }
7400
- function getStatus() {
7432
+ function getStatus(options = {}) {
7433
+ const privateMetadata = options.privateMetadata === true;
7401
7434
  const manifest = readManifest();
7402
7435
  const heartbeats = listHeartbeats();
7403
7436
  const heartbeatByMachine = latestHeartbeatByMachine(heartbeats);
@@ -7406,17 +7439,17 @@ function getStatus() {
7406
7439
  ...heartbeats.map((heartbeat) => heartbeat.machine_id)
7407
7440
  ]);
7408
7441
  return {
7409
- machineId: getLocalMachineId(),
7410
- manifestPath: getManifestPath(),
7411
- dbPath: getDbPath(),
7412
- notificationsPath: getNotificationsPath(),
7442
+ machineId: privateMetadata ? getLocalMachineId() : REDACTED_VALUE,
7443
+ manifestPath: privateMetadata ? getManifestPath() : REDACTED_VALUE,
7444
+ dbPath: privateMetadata ? getDbPath() : REDACTED_VALUE,
7445
+ notificationsPath: privateMetadata ? getNotificationsPath() : REDACTED_VALUE,
7413
7446
  manifestMachineCount: manifest.machines.length,
7414
7447
  heartbeatCount: heartbeats.length,
7415
7448
  machines: [...machineIds].sort().map((machineId) => {
7416
7449
  const declared = manifest.machines.find((machine) => machine.id === machineId);
7417
7450
  const heartbeat = heartbeatByMachine.get(machineId);
7418
7451
  return {
7419
- machineId,
7452
+ machineId: privateMetadata ? machineId : REDACTED_VALUE,
7420
7453
  platform: declared?.platform,
7421
7454
  manifestDeclared: Boolean(declared),
7422
7455
  heartbeatStatus: heartbeat?.status || "unknown",
@@ -7424,7 +7457,7 @@ function getStatus() {
7424
7457
  daemonVersion: heartbeat?.daemon_version ?? null,
7425
7458
  agentMode: heartbeat?.agent_mode ?? null,
7426
7459
  storageSyncStatus: heartbeat?.storage_sync_status ?? null,
7427
- doctorSummary: parseJsonObject2(heartbeat?.doctor_summary_json),
7460
+ doctorSummary: privateMetadata ? parseJsonObject2(heartbeat?.doctor_summary_json) : null,
7428
7461
  privateMetadata: Boolean(heartbeat?.private_metadata)
7429
7462
  };
7430
7463
  }),
@@ -7440,15 +7473,16 @@ function check(id, status, summary, detail) {
7440
7473
  function runSelfTest() {
7441
7474
  const version = getPackageVersion();
7442
7475
  const status = getStatus();
7476
+ const machineId = getLocalMachineId();
7443
7477
  const doctor = runDoctor();
7444
7478
  const serveInfo = getServeInfo();
7445
7479
  const html = renderDashboardHtml();
7446
7480
  const notifications = listNotificationChannels();
7447
- const apps = listApps(status.machineId);
7448
- const appsDiff = diffApps(status.machineId);
7449
- const cliPlan = buildClaudeInstallPlan(status.machineId);
7481
+ const apps = listApps(machineId);
7482
+ const appsDiff = diffApps(machineId);
7483
+ const cliPlan = buildClaudeInstallPlan(machineId);
7450
7484
  return {
7451
- machineId: getLocalMachineId(),
7485
+ machineId,
7452
7486
  checks: [
7453
7487
  check("package-version", version === "0.0.0" ? "fail" : "ok", "Package version resolves", version),
7454
7488
  check("status", "ok", "Status loads", JSON.stringify({ machines: status.manifestMachineCount, heartbeats: status.heartbeatCount })),
@@ -7807,7 +7841,7 @@ function runSetup(machineId, options = {}, runner = runMachineCommand) {
7807
7841
  }
7808
7842
 
7809
7843
  // src/commands/sync.ts
7810
- import { existsSync as existsSync7, lstatSync, readFileSync as readFileSync5, symlinkSync, copyFileSync } from "fs";
7844
+ import { existsSync as existsSync8, lstatSync, readFileSync as readFileSync6, symlinkSync, copyFileSync } from "fs";
7811
7845
  import { homedir as homedir5 } from "os";
7812
7846
  function quote4(value) {
7813
7847
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -7860,15 +7894,15 @@ function detectFileActions(machine) {
7860
7894
  throw new Error(`Remote file sync planning is not supported for ${machine.id}; refusing to inspect or apply local paths as remote state.`);
7861
7895
  }
7862
7896
  return (machine.files || []).map((file, index) => {
7863
- const sourceExists = existsSync7(file.source);
7864
- const targetExists = existsSync7(file.target);
7897
+ const sourceExists = existsSync8(file.source);
7898
+ const targetExists = existsSync8(file.target);
7865
7899
  let status = "missing";
7866
7900
  if (sourceExists && targetExists) {
7867
7901
  if (file.mode === "symlink") {
7868
7902
  status = lstatSync(file.target).isSymbolicLink() ? "ok" : "drifted";
7869
7903
  } else {
7870
- const source = readFileSync5(file.source, "utf8");
7871
- const target = readFileSync5(file.target, "utf8");
7904
+ const source = readFileSync6(file.source, "utf8");
7905
+ const target = readFileSync6(file.target, "utf8");
7872
7906
  status = source === target ? "ok" : "drifted";
7873
7907
  }
7874
7908
  }
@@ -8218,14 +8252,17 @@ function privateOutputWarnings(requested, allowed) {
8218
8252
  function appendWarnings(payload, warnings) {
8219
8253
  if (warnings.length === 0)
8220
8254
  return payload;
8221
- return { ...payload, warnings: [...payload.warnings ?? [], ...warnings] };
8255
+ const currentWarnings = typeof payload === "object" && payload && "warnings" in payload && Array.isArray(payload.warnings) ? payload.warnings : [];
8256
+ return { ...payload, warnings: [...currentWarnings, ...warnings] };
8222
8257
  }
8223
8258
  function createMcpServer(version) {
8224
8259
  const server = new McpServer({ name: "machines", version });
8225
8260
  const events = new EventsClient2;
8226
- server.tool("machines_status", "Return local machine fleet status paths and machine identity.", {}, async () => ({
8227
- content: [{ type: "text", text: JSON.stringify(getStatus(), null, 2) }]
8228
- }));
8261
+ server.tool("machines_status", "Return local machine fleet status paths and machine identity.", { private_metadata: exports_external.boolean().optional().describe("Include private local paths and machine identifiers") }, async ({ private_metadata }) => {
8262
+ const privateMetadata = privateMetadataAllowed(private_metadata);
8263
+ const warnings = privateOutputWarnings(private_metadata, privateMetadata);
8264
+ return { content: [{ type: "text", text: JSON.stringify(appendWarnings(getStatus({ privateMetadata }), warnings), null, 2) }] };
8265
+ });
8229
8266
  server.tool("machines_doctor", "Run machine preflight checks.", { machine_id: exports_external.string().optional().describe("Machine identifier") }, async ({ machine_id }) => ({ content: [{ type: "text", text: JSON.stringify(runDoctor(machine_id), null, 2) }] }));
8230
8267
  server.tool("machines_self_test", "Run local package smoke checks.", {}, async () => ({
8231
8268
  content: [{ type: "text", text: JSON.stringify(runSelfTest(), null, 2) }]
@@ -8406,9 +8443,23 @@ function createMcpServer(version) {
8406
8443
  }), null, 2)
8407
8444
  }]
8408
8445
  }));
8409
- server.tool("machines_ssh_resolve", "Resolve the best SSH route for a machine.", { machine_id: exports_external.string().describe("Machine identifier"), remote_command: exports_external.string().optional().describe("Optional remote command") }, async ({ machine_id, remote_command }) => ({
8410
- content: [{ type: "text", text: JSON.stringify({ resolved: resolveMachineRoute(machine_id), command: buildSshCommand(machine_id, remote_command) }, null, 2) }]
8411
- }));
8446
+ server.tool("machines_ssh_resolve", "Resolve the best SSH route for a machine.", {
8447
+ machine_id: exports_external.string().describe("Machine identifier"),
8448
+ remote_command: exports_external.string().optional().describe("Optional remote command"),
8449
+ private_metadata: exports_external.boolean().optional().describe("Include private SSH target and command")
8450
+ }, async ({ machine_id, remote_command, private_metadata }) => {
8451
+ const privateMetadata = privateMetadataAllowed(private_metadata);
8452
+ const warnings = privateOutputWarnings(private_metadata, privateMetadata);
8453
+ const resolved = resolveMachineRoute(machine_id);
8454
+ const publicResolved = redactRouteForOutput(resolved, { privateMetadata });
8455
+ const command2 = resolved.ok && privateMetadata ? buildSshCommand(machine_id, remote_command) : resolved.ok ? "[redacted]" : null;
8456
+ return {
8457
+ content: [{
8458
+ type: "text",
8459
+ text: JSON.stringify(appendWarnings({ resolved: publicResolved, command: command2 }, warnings), null, 2)
8460
+ }]
8461
+ };
8462
+ });
8412
8463
  server.tool("machines_ports", "List listening ports on a machine.", { machine_id: exports_external.string().optional().describe("Machine identifier") }, async ({ machine_id }) => ({
8413
8464
  content: [{ type: "text", text: JSON.stringify(listPorts(machine_id), null, 2) }]
8414
8465
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE,eAAO,MAAM,sBAAsB,k9CA2DzB,CAAC;AAEX,wBAAgB,WAAW,CAAC,OAAO,GAAE,MAA4B,GAAG,SAAS,CAE5E;AAeD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAojB1D"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE,eAAO,MAAM,sBAAsB,k9CA2DzB,CAAC;AAEX,wBAAgB,WAAW,CAAC,OAAO,GAAE,MAA4B,GAAG,SAAS,CAE5E;AAkBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAykB1D"}
package/dist/types.d.ts CHANGED
@@ -116,6 +116,7 @@ export interface FleetStatus {
116
116
  machines: FleetStatusMachine[];
117
117
  recentSetupRuns: number;
118
118
  recentSyncRuns: number;
119
+ warnings?: string[];
119
120
  }
120
121
  export type NotificationChannelType = "email" | "webhook" | "command";
121
122
  export interface NotificationChannel {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,KAAK,GAAG,WAAW,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,aAAa,CAAC;AAExD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,kBAAkB,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,kBAAkB,GAAG,SAAS,GAAG,UAAU,CAAC;IACxD,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,SAAS,CAAC;IACrC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE;QACf,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,YAAY,EAAE;QACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/C,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;IAC9C,IAAI,EAAE,kBAAkB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;IAC9C,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,0BAA0B,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;IAC9C,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/machines",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "Machine fleet management CLI + MCP for developers",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",