@hasna/machines 0.0.28 → 0.0.29

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.
@@ -0,0 +1,32 @@
1
+ import { EventsClient, type EmitResult } from "@hasna/events";
2
+ export interface TmuxPaneProbeResult {
3
+ target: string;
4
+ exists: boolean;
5
+ paneId?: string;
6
+ checkedAt: string;
7
+ exitCode?: number | null;
8
+ error?: string;
9
+ stderr?: string;
10
+ }
11
+ export interface TmuxWatchOptions {
12
+ target: string;
13
+ intervalMs?: number;
14
+ maxChecks?: number;
15
+ emitInitialMissing?: boolean;
16
+ deliver?: boolean;
17
+ tmuxCommand?: string;
18
+ client?: Pick<EventsClient, "emit">;
19
+ probe?: (target: string) => TmuxPaneProbeResult | Promise<TmuxPaneProbeResult>;
20
+ sleep?: (ms: number) => Promise<void>;
21
+ onProbe?: (probe: TmuxPaneProbeResult) => void;
22
+ }
23
+ export interface TmuxWatchResult {
24
+ target: string;
25
+ checks: number;
26
+ status: "present" | "missing" | "died" | "stopped";
27
+ lastProbe: TmuxPaneProbeResult;
28
+ emitted?: EmitResult;
29
+ }
30
+ export declare function probeTmuxPane(target: string, tmuxCommand?: string): TmuxPaneProbeResult;
31
+ export declare function watchTmuxPane(options: TmuxWatchOptions): Promise<TmuxWatchResult>;
32
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/commands/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAmB,MAAM,eAAe,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/E,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACnD,SAAS,EAAE,mBAAmB,CAAC;IAC/B,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,SAAmD,GAAG,mBAAmB,CAmBjI;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA6CvF"}
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export * from "./commands/install-claude.js";
17
17
  export * from "./commands/install-tailscale.js";
18
18
  export * from "./commands/notifications.js";
19
19
  export * from "./commands/ports.js";
20
+ export * from "./commands/runtime.js";
20
21
  export * from "./commands/self-test.js";
21
22
  export * from "./commands/serve.js";
22
23
  export * from "./commands/setup.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,EACzB,kCAAkC,EAClC,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtH,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,EACzB,kCAAkC,EAClC,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtH,cAAc,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -13427,6 +13427,10 @@ function listPorts(machineId) {
13427
13427
  listeners: parsePortOutput(result.stdout, format)
13428
13428
  };
13429
13429
  }
13430
+ // src/commands/runtime.ts
13431
+ import { spawnSync as spawnSync4 } from "child_process";
13432
+ import { setTimeout as sleep } from "timers/promises";
13433
+
13430
13434
  // node_modules/@hasna/events/dist/index.js
13431
13435
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
13432
13436
  import { existsSync as existsSync7 } from "fs";
@@ -13947,6 +13951,91 @@ function normalizeRetryPolicy(policy) {
13947
13951
  };
13948
13952
  }
13949
13953
 
13954
+ // src/commands/runtime.ts
13955
+ function probeTmuxPane(target, tmuxCommand = process.env["HASNA_MACHINES_TMUX_BIN"] || "tmux") {
13956
+ const checkedAt = new Date().toISOString();
13957
+ const result = spawnSync4(tmuxCommand, ["display-message", "-p", "-t", target, "#{pane_id}"], {
13958
+ encoding: "utf8",
13959
+ timeout: 5000
13960
+ });
13961
+ const stdout = result.stdout?.trim();
13962
+ const stderr = result.stderr?.trim();
13963
+ const exists = result.status === 0 && Boolean(stdout);
13964
+ return {
13965
+ target,
13966
+ exists,
13967
+ paneId: exists ? stdout : undefined,
13968
+ checkedAt,
13969
+ exitCode: result.status,
13970
+ error: result.error?.message,
13971
+ stderr: stderr || undefined
13972
+ };
13973
+ }
13974
+ async function watchTmuxPane(options) {
13975
+ const target = options.target.trim();
13976
+ if (!target)
13977
+ throw new Error("tmux pane target is required");
13978
+ const intervalMs = Math.max(0, options.intervalMs ?? 5000);
13979
+ const maxChecks = options.maxChecks ?? Number.POSITIVE_INFINITY;
13980
+ const client = options.client ?? new EventsClient;
13981
+ const probe = options.probe ?? ((paneTarget) => probeTmuxPane(paneTarget, options.tmuxCommand));
13982
+ const wait = options.sleep ?? sleep;
13983
+ let lastPresent;
13984
+ let lastProbe;
13985
+ for (let checks = 1;checks <= maxChecks; checks += 1) {
13986
+ const current = await probe(target);
13987
+ lastProbe = current;
13988
+ options.onProbe?.(current);
13989
+ if (current.exists) {
13990
+ lastPresent = current;
13991
+ } else if (lastPresent) {
13992
+ const emitted = await emitTmuxEvent(client, "machines.tmux.pane_died", current, lastPresent, options.deliver !== false);
13993
+ return { target, checks, status: "died", lastProbe: current, emitted };
13994
+ } else if (options.emitInitialMissing) {
13995
+ const emitted = await emitTmuxEvent(client, "machines.tmux.pane_missing", current, undefined, options.deliver !== false);
13996
+ return { target, checks, status: "missing", lastProbe: current, emitted };
13997
+ }
13998
+ if (checks < maxChecks)
13999
+ await wait(intervalMs);
14000
+ }
14001
+ if (!lastProbe) {
14002
+ lastProbe = {
14003
+ target,
14004
+ exists: false,
14005
+ checkedAt: new Date().toISOString(),
14006
+ error: "No probe executed"
14007
+ };
14008
+ }
14009
+ return {
14010
+ target,
14011
+ checks: Number.isFinite(maxChecks) ? maxChecks : 0,
14012
+ status: lastProbe.exists ? "present" : "stopped",
14013
+ lastProbe
14014
+ };
14015
+ }
14016
+ async function emitTmuxEvent(client, type, probe, lastPresent, deliver) {
14017
+ const input = {
14018
+ source: "machines",
14019
+ type,
14020
+ subject: `tmux:${probe.target}`,
14021
+ severity: type === "machines.tmux.pane_died" ? "warning" : "notice",
14022
+ message: type === "machines.tmux.pane_died" ? `tmux pane disappeared: ${probe.target}` : `tmux pane is missing: ${probe.target}`,
14023
+ data: {
14024
+ target: probe.target,
14025
+ paneId: lastPresent?.paneId,
14026
+ lastSeenAt: lastPresent?.checkedAt,
14027
+ checkedAt: probe.checkedAt,
14028
+ exitCode: probe.exitCode,
14029
+ error: probe.error,
14030
+ stderr: probe.stderr
14031
+ },
14032
+ metadata: {
14033
+ monitor: "tmux-pane",
14034
+ runtime: "machines"
14035
+ }
14036
+ };
14037
+ return client.emit(input, { deliver });
14038
+ }
13950
14039
  // src/commands/status.ts
13951
14040
  function getStatus() {
13952
14041
  const manifest = readManifest();
@@ -24057,6 +24146,7 @@ export {
24057
24146
  writeNotificationConfig,
24058
24147
  writeManifest,
24059
24148
  writeHeartbeat,
24149
+ watchTmuxPane,
24060
24150
  validateManifest,
24061
24151
  upsertHeartbeat,
24062
24152
  testNotificationChannel,
@@ -24090,6 +24180,7 @@ export {
24090
24180
  recordSetupRun,
24091
24181
  readNotificationConfig,
24092
24182
  readManifest,
24183
+ probeTmuxPane,
24093
24184
  parseStorageTables,
24094
24185
  parsePortOutput,
24095
24186
  markOffline,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/machines",
3
- "version": "0.0.28",
3
+ "version": "0.0.29",
4
4
  "description": "Machine fleet management CLI + MCP for developers",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",