@hasna/machines 0.0.30 → 0.0.32

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.
@@ -1,13 +1,14 @@
1
+ import { type MachineCommandRunner } from "../remote.js";
1
2
  import type { AppsDiffResult, AppsStatusResult, ManifestAppSpec, SetupResult } from "../types.js";
2
3
  export declare function listApps(machineId?: string): {
3
4
  machineId: string;
4
5
  apps: ManifestAppSpec[];
5
6
  };
6
7
  export declare function buildAppsPlan(machineId?: string): SetupResult;
7
- export declare function getAppsStatus(machineId?: string): AppsStatusResult;
8
- export declare function diffApps(machineId?: string): AppsDiffResult;
8
+ export declare function getAppsStatus(machineId?: string, runner?: MachineCommandRunner): AppsStatusResult;
9
+ export declare function diffApps(machineId?: string, runner?: MachineCommandRunner): AppsDiffResult;
9
10
  export declare function runAppsInstall(machineId?: string, options?: {
10
11
  apply?: boolean;
11
12
  yes?: boolean;
12
- }): SetupResult;
13
+ }, runner?: MachineCommandRunner): SetupResult;
13
14
  //# sourceMappingURL=apps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAGhB,eAAe,EACf,WAAW,EAEZ,MAAM,aAAa,CAAC;AA+FrB,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,EAAE,CAAA;CAAE,CAM3F;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAQ7D;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAWlE;AAED,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAO3D;AAED,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,CA0BhH"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AACA,OAAO,EAAmD,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAGhB,eAAe,EACf,WAAW,EAEZ,MAAM,aAAa,CAAC;AAqGrB,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,EAAE,CAAA;CAAE,CAM3F;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAQ7D;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,oBAAwC,GAAG,gBAAgB,CAYpH;AAED,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,oBAAwC,GAAG,cAAc,CAO7G;AAED,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,EAChD,MAAM,GAAE,oBAAwC,GAC/C,WAAW,CAmBb"}
@@ -1,3 +1,4 @@
1
+ import { type MachineCommandRunner } from "../remote.js";
1
2
  import type { ClaudeCliDiffResult, ClaudeCliStatusResult, SetupResult } from "../types.js";
2
3
  declare const AI_CLI_PACKAGES: {
3
4
  readonly claude: "@anthropic-ai/claude-code";
@@ -6,11 +7,11 @@ declare const AI_CLI_PACKAGES: {
6
7
  };
7
8
  export type AiCliTool = keyof typeof AI_CLI_PACKAGES;
8
9
  export declare function buildClaudeInstallPlan(machineId?: string, tools?: string[]): SetupResult;
9
- export declare function getClaudeCliStatus(machineId?: string, tools?: string[]): ClaudeCliStatusResult;
10
- export declare function diffClaudeCli(machineId?: string, tools?: string[]): ClaudeCliDiffResult;
10
+ export declare function getClaudeCliStatus(machineId?: string, tools?: string[], runner?: MachineCommandRunner): ClaudeCliStatusResult;
11
+ export declare function diffClaudeCli(machineId?: string, tools?: string[], runner?: MachineCommandRunner): ClaudeCliDiffResult;
11
12
  export declare function runClaudeInstall(machineId?: string, tools?: string[], options?: {
12
13
  apply?: boolean;
13
14
  yes?: boolean;
14
- }): SetupResult;
15
+ }, runner?: MachineCommandRunner): SetupResult;
15
16
  export {};
16
17
  //# sourceMappingURL=install-claude.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install-claude.d.ts","sourceRoot":"","sources":["../../src/commands/install-claude.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAkC,WAAW,EAAa,MAAM,aAAa,CAAC;AAEtI,QAAA,MAAM,eAAe;;;;CAIX,CAAC;AAQX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,eAAe,CAAC;AA6CrD,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,CAQxF;AAED,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAS9F;AAED,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAOvF;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/C,WAAW,CA0Bb"}
1
+ {"version":3,"file":"install-claude.d.ts","sourceRoot":"","sources":["../../src/commands/install-claude.ts"],"names":[],"mappings":"AACA,OAAO,EAAmD,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAkC,WAAW,EAAa,MAAM,aAAa,CAAC;AAEtI,QAAA,MAAM,eAAe;;;;CAIX,CAAC;AAQX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,eAAe,CAAC;AAkDrD,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,CAQxF;AAED,wBAAgB,kBAAkB,CAChC,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,MAAM,GAAE,oBAAwC,GAC/C,qBAAqB,CAYvB;AAED,wBAAgB,aAAa,CAC3B,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,MAAM,GAAE,oBAAwC,GAC/C,mBAAmB,CAOrB;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,EAChD,MAAM,GAAE,oBAAwC,GAC/C,WAAW,CAmBb"}
@@ -1,7 +1,8 @@
1
+ import { type MachineCommandRunner } from "../remote.js";
1
2
  import type { SetupResult } from "../types.js";
2
3
  export declare function buildTailscaleInstallPlan(machineId?: string): SetupResult;
3
4
  export declare function runTailscaleInstall(machineId?: string, options?: {
4
5
  apply?: boolean;
5
6
  yes?: boolean;
6
- }): SetupResult;
7
+ }, runner?: MachineCommandRunner): SetupResult;
7
8
  //# sourceMappingURL=install-tailscale.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install-tailscale.d.ts","sourceRoot":"","sources":["../../src/commands/install-tailscale.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,WAAW,EAAa,MAAM,aAAa,CAAC;AAoC3E,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAQzE;AAED,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,CA0BrH"}
1
+ {"version":3,"file":"install-tailscale.d.ts","sourceRoot":"","sources":["../../src/commands/install-tailscale.ts"],"names":[],"mappings":"AACA,OAAO,EAAmD,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,KAAK,EAAmB,WAAW,EAAa,MAAM,aAAa,CAAC;AAoC3E,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAWzE;AAED,wBAAgB,mBAAmB,CACjC,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,EAChD,MAAM,GAAE,oBAAwC,GAC/C,WAAW,CAmBb"}
@@ -1,7 +1,8 @@
1
+ import { type MachineCommandRunner } from "../remote.js";
1
2
  import type { SetupResult } from "../types.js";
2
3
  export declare function buildSetupPlan(machineId?: string): SetupResult;
3
4
  export declare function runSetup(machineId?: string, options?: {
4
5
  apply?: boolean;
5
6
  yes?: boolean;
6
- }): SetupResult;
7
+ }, runner?: MachineCommandRunner): SetupResult;
7
8
  //# sourceMappingURL=setup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmB,WAAW,EAAa,MAAM,aAAa,CAAC;AAsE3E,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAqB9D;AAED,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,CAoC1G"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoD,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,KAAK,EAAmB,WAAW,EAAa,MAAM,aAAa,CAAC;AAsE3E,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAyB9D;AAED,wBAAgB,QAAQ,CACtB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,EAChD,MAAM,GAAE,oBAAwC,GAC/C,WAAW,CAmCb"}
@@ -1,7 +1,8 @@
1
+ import { type MachineCommandRunner } from "../remote.js";
1
2
  import type { SyncResult } from "../types.js";
2
- export declare function buildSyncPlan(machineId?: string): SyncResult;
3
+ export declare function buildSyncPlan(machineId?: string, runner?: MachineCommandRunner): SyncResult;
3
4
  export declare function runSync(machineId?: string, options?: {
4
5
  apply?: boolean;
5
6
  yes?: boolean;
6
- }): SyncResult;
7
+ }, runner?: MachineCommandRunner): SyncResult;
7
8
  //# sourceMappingURL=sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA+B,UAAU,EAAE,MAAM,aAAa,CAAC;AAiF3E,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAwB5D;AAwBD,wBAAgB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,UAAU,CAyCxG"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2E,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAClI,OAAO,KAAK,EAA+B,UAAU,EAAE,MAAM,aAAa,CAAC;AAqF3E,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,oBAAwC,GAAG,UAAU,CA4B9G;AAwBD,wBAAgB,OAAO,CACrB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,EAChD,MAAM,GAAE,oBAAwC,GAC/C,UAAU,CAwCZ"}
package/dist/consumer.js CHANGED
@@ -5633,6 +5633,17 @@ function runMachineCommand(machineId, command) {
5633
5633
  exitCode: result.status ?? 1
5634
5634
  };
5635
5635
  }
5636
+ function describeMachineCommandFailure(operation, result) {
5637
+ const detail = (result.stderr || result.stdout || "").trim();
5638
+ const suffix = detail ? `: ${detail}` : "";
5639
+ return `${operation} failed on ${result.machineId} via ${result.source} (exit ${result.exitCode})${suffix}`;
5640
+ }
5641
+ function requireMachineCommandSuccess(operation, result) {
5642
+ if (result.exitCode !== 0) {
5643
+ throw new Error(describeMachineCommandFailure(operation, result));
5644
+ }
5645
+ return result;
5646
+ }
5636
5647
 
5637
5648
  // src/compatibility.ts
5638
5649
  var DEFAULT_COMMANDS = [
package/dist/index.js CHANGED
@@ -12202,6 +12202,17 @@ function runMachineCommand(machineId, command) {
12202
12202
  exitCode: result.status ?? 1
12203
12203
  };
12204
12204
  }
12205
+ function describeMachineCommandFailure(operation, result) {
12206
+ const detail = (result.stderr || result.stdout || "").trim();
12207
+ const suffix = detail ? `: ${detail}` : "";
12208
+ return `${operation} failed on ${result.machineId} via ${result.source} (exit ${result.exitCode})${suffix}`;
12209
+ }
12210
+ function requireMachineCommandSuccess(operation, result) {
12211
+ if (result.exitCode !== 0) {
12212
+ throw new Error(describeMachineCommandFailure(operation, result));
12213
+ }
12214
+ return result;
12215
+ }
12205
12216
 
12206
12217
  // src/compatibility.ts
12207
12218
  var DEFAULT_COMMANDS = [
@@ -12634,7 +12645,14 @@ function buildAppSteps(machine) {
12634
12645
  }));
12635
12646
  }
12636
12647
  function resolveMachine(machineId) {
12637
- return (machineId ? getManifestMachine(machineId) : null) || detectCurrentMachineManifest();
12648
+ if (!machineId)
12649
+ return detectCurrentMachineManifest();
12650
+ return getManifestMachine(machineId) || {
12651
+ id: machineId,
12652
+ platform: "linux",
12653
+ workspacePath: "",
12654
+ apps: []
12655
+ };
12638
12656
  }
12639
12657
  function parseProbeOutput(app, machine, stdout) {
12640
12658
  const lines = stdout.trim().split(`
@@ -12665,27 +12683,28 @@ function buildAppsPlan(machineId) {
12665
12683
  executed: 0
12666
12684
  };
12667
12685
  }
12668
- function getAppsStatus(machineId) {
12686
+ function getAppsStatus(machineId, runner = runMachineCommand) {
12669
12687
  const machine = resolveMachine(machineId);
12688
+ const readiness = requireMachineCommandSuccess("Apps status readiness check", runner(machine.id, "true"));
12670
12689
  const apps = (machine.apps || []).map((app) => {
12671
- const probe = runMachineCommand(machine.id, buildAppProbeCommand(machine, app));
12690
+ const probe = requireMachineCommandSuccess(`App probe ${app.name}`, runner(machine.id, buildAppProbeCommand(machine, app)));
12672
12691
  return parseProbeOutput(app, machine, probe.stdout);
12673
12692
  });
12674
12693
  return {
12675
12694
  machineId: machine.id,
12676
- source: apps.length > 0 ? runMachineCommand(machine.id, "true").source : machine.id === detectCurrentMachineManifest().id ? "local" : runMachineCommand(machine.id, "true").source,
12695
+ source: readiness.source,
12677
12696
  apps
12678
12697
  };
12679
12698
  }
12680
- function diffApps(machineId) {
12681
- const status = getAppsStatus(machineId);
12699
+ function diffApps(machineId, runner = runMachineCommand) {
12700
+ const status = getAppsStatus(machineId, runner);
12682
12701
  return {
12683
12702
  ...status,
12684
12703
  missing: status.apps.filter((app) => !app.installed).map((app) => app.name),
12685
12704
  installed: status.apps.filter((app) => app.installed).map((app) => app.name)
12686
12705
  };
12687
12706
  }
12688
- function runAppsInstall(machineId, options = {}) {
12707
+ function runAppsInstall(machineId, options = {}, runner = runMachineCommand) {
12689
12708
  const plan = buildAppsPlan(machineId);
12690
12709
  if (!options.apply)
12691
12710
  return plan;
@@ -12694,14 +12713,7 @@ function runAppsInstall(machineId, options = {}) {
12694
12713
  }
12695
12714
  let executed = 0;
12696
12715
  for (const step of plan.steps) {
12697
- const result = Bun.spawnSync(["bash", "-lc", step.command], {
12698
- stdout: "pipe",
12699
- stderr: "pipe",
12700
- env: process.env
12701
- });
12702
- if (result.exitCode !== 0) {
12703
- throw new Error(`App install failed (${step.id}): ${result.stderr.toString().trim()}`);
12704
- }
12716
+ requireMachineCommandSuccess(`App install ${step.id}`, runner(plan.machineId, step.command));
12705
12717
  executed += 1;
12706
12718
  }
12707
12719
  return {
@@ -12990,7 +13002,13 @@ function buildInstallSteps(machine, tools) {
12990
13002
  }));
12991
13003
  }
12992
13004
  function resolveMachine2(machineId) {
12993
- return (machineId ? getManifestMachine(machineId) : null) || detectCurrentMachineManifest();
13005
+ if (!machineId)
13006
+ return detectCurrentMachineManifest();
13007
+ return getManifestMachine(machineId) || {
13008
+ id: machineId,
13009
+ platform: "linux",
13010
+ workspacePath: ""
13011
+ };
12994
13012
  }
12995
13013
  function buildProbeCommand(tool) {
12996
13014
  const binary = getToolBinary(tool);
@@ -13017,25 +13035,28 @@ function buildClaudeInstallPlan(machineId, tools) {
13017
13035
  executed: 0
13018
13036
  };
13019
13037
  }
13020
- function getClaudeCliStatus(machineId, tools) {
13038
+ function getClaudeCliStatus(machineId, tools, runner = runMachineCommand) {
13021
13039
  const machine = resolveMachine2(machineId);
13022
13040
  const normalizedTools = normalizeTools(tools);
13023
- const route = runMachineCommand(machine.id, "true").source;
13041
+ const route = requireMachineCommandSuccess("AI CLI status readiness check", runner(machine.id, "true")).source;
13024
13042
  return {
13025
13043
  machineId: machine.id,
13026
13044
  source: route,
13027
- tools: normalizedTools.map((tool) => parseProbe(tool, runMachineCommand(machine.id, buildProbeCommand(tool)).stdout))
13045
+ tools: normalizedTools.map((tool) => {
13046
+ const result = requireMachineCommandSuccess(`AI CLI probe ${tool}`, runner(machine.id, buildProbeCommand(tool)));
13047
+ return parseProbe(tool, result.stdout);
13048
+ })
13028
13049
  };
13029
13050
  }
13030
- function diffClaudeCli(machineId, tools) {
13031
- const status = getClaudeCliStatus(machineId, tools);
13051
+ function diffClaudeCli(machineId, tools, runner = runMachineCommand) {
13052
+ const status = getClaudeCliStatus(machineId, tools, runner);
13032
13053
  return {
13033
13054
  ...status,
13034
13055
  missing: status.tools.filter((tool) => !tool.installed).map((tool) => tool.tool),
13035
13056
  installed: status.tools.filter((tool) => tool.installed).map((tool) => tool.tool)
13036
13057
  };
13037
13058
  }
13038
- function runClaudeInstall(machineId, tools, options = {}) {
13059
+ function runClaudeInstall(machineId, tools, options = {}, runner = runMachineCommand) {
13039
13060
  const plan = buildClaudeInstallPlan(machineId, tools);
13040
13061
  if (!options.apply)
13041
13062
  return plan;
@@ -13044,14 +13065,7 @@ function runClaudeInstall(machineId, tools, options = {}) {
13044
13065
  }
13045
13066
  let executed = 0;
13046
13067
  for (const step of plan.steps) {
13047
- const result = Bun.spawnSync(["bash", "-lc", step.command], {
13048
- stdout: "pipe",
13049
- stderr: "pipe",
13050
- env: process.env
13051
- });
13052
- if (result.exitCode !== 0) {
13053
- throw new Error(`AI CLI install failed (${step.id}): ${result.stderr.toString().trim()}`);
13054
- }
13068
+ requireMachineCommandSuccess(`AI CLI install ${step.id}`, runner(plan.machineId, step.command));
13055
13069
  executed += 1;
13056
13070
  }
13057
13071
  return {
@@ -13094,7 +13108,10 @@ function buildInstallSteps2(machine) {
13094
13108
  ];
13095
13109
  }
13096
13110
  function buildTailscaleInstallPlan(machineId) {
13097
- const machine = (machineId ? getManifestMachine(machineId) : null) || detectCurrentMachineManifest();
13111
+ const machine = machineId ? getManifestMachine(machineId) : detectCurrentMachineManifest();
13112
+ if (!machine) {
13113
+ throw new Error(`Machine not found in manifest: ${machineId}`);
13114
+ }
13098
13115
  return {
13099
13116
  machineId: machine.id,
13100
13117
  mode: "plan",
@@ -13102,7 +13119,7 @@ function buildTailscaleInstallPlan(machineId) {
13102
13119
  executed: 0
13103
13120
  };
13104
13121
  }
13105
- function runTailscaleInstall(machineId, options = {}) {
13122
+ function runTailscaleInstall(machineId, options = {}, runner = runMachineCommand) {
13106
13123
  const plan = buildTailscaleInstallPlan(machineId);
13107
13124
  if (!options.apply)
13108
13125
  return plan;
@@ -13111,14 +13128,7 @@ function runTailscaleInstall(machineId, options = {}) {
13111
13128
  }
13112
13129
  let executed = 0;
13113
13130
  for (const step of plan.steps) {
13114
- const result = Bun.spawnSync(["bash", "-lc", step.command], {
13115
- stdout: "pipe",
13116
- stderr: "pipe",
13117
- env: process.env
13118
- });
13119
- if (result.exitCode !== 0) {
13120
- throw new Error(`Tailscale install failed (${step.id}): ${result.stderr.toString().trim()}`);
13121
- }
13131
+ requireMachineCommandSuccess(`Tailscale install ${step.id}`, runner(plan.machineId, step.command));
13122
13132
  executed += 1;
13123
13133
  }
13124
13134
  return {
@@ -14482,6 +14492,9 @@ function buildSetupPlan(machineId) {
14482
14492
  const manifest = readManifest();
14483
14493
  const currentMachineId = getLocalMachineId();
14484
14494
  const selected = machineId ? manifest.machines.find((machine) => machine.id === machineId) : manifest.machines.find((machine) => machine.id === currentMachineId);
14495
+ if (machineId && !selected) {
14496
+ throw new Error(`Machine not found in manifest: ${machineId}`);
14497
+ }
14485
14498
  const target = selected || {
14486
14499
  id: currentMachineId,
14487
14500
  platform: "linux",
@@ -14495,7 +14508,7 @@ function buildSetupPlan(machineId) {
14495
14508
  executed: 0
14496
14509
  };
14497
14510
  }
14498
- function runSetup(machineId, options = {}) {
14511
+ function runSetup(machineId, options = {}, runner = runMachineCommand) {
14499
14512
  const plan = buildSetupPlan(machineId);
14500
14513
  if (!options.apply) {
14501
14514
  return plan;
@@ -14505,18 +14518,17 @@ function runSetup(machineId, options = {}) {
14505
14518
  }
14506
14519
  let executed = 0;
14507
14520
  for (const step of plan.steps) {
14508
- const result = Bun.spawnSync(["bash", "-lc", step.command], {
14509
- stdout: "pipe",
14510
- stderr: "pipe",
14511
- env: process.env
14512
- });
14521
+ const result = runner(plan.machineId, step.command);
14513
14522
  if (result.exitCode !== 0) {
14514
14523
  recordSetupRun(plan.machineId, "failed", {
14515
14524
  executed,
14516
14525
  failedStep: step,
14517
- stderr: result.stderr.toString()
14526
+ stderr: result.stderr,
14527
+ stdout: result.stdout,
14528
+ exitCode: result.exitCode,
14529
+ source: result.source
14518
14530
  });
14519
- throw new Error(`Setup step failed (${step.id}): ${result.stderr.toString().trim()}`);
14531
+ throw new Error(describeMachineCommandFailure(`Setup step ${step.id}`, result));
14520
14532
  }
14521
14533
  executed += 1;
14522
14534
  }
@@ -14657,16 +14669,17 @@ function quote4(value) {
14657
14669
  return `'${value.replace(/'/g, `'\\''`)}'`;
14658
14670
  }
14659
14671
  function packageCheckCommand(machine, packageName, manager = machine.platform === "macos" ? "brew" : "apt") {
14672
+ const quotedPackageName = quote4(packageName);
14660
14673
  if (manager === "bun") {
14661
- return `bun pm ls -g --all | grep -F ${quote4(packageName)}`;
14674
+ return `if bun pm ls -g --all 2>/dev/null | grep -F ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14662
14675
  }
14663
14676
  if (manager === "brew") {
14664
- return `brew list --versions ${quote4(packageName)}`;
14677
+ return `if brew list --versions ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14665
14678
  }
14666
14679
  if (manager === "apt") {
14667
- return `dpkg -s ${quote4(packageName)} >/dev/null 2>&1`;
14680
+ return `if dpkg -s ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14668
14681
  }
14669
- return `command -v ${quote4(packageName)} >/dev/null 2>&1`;
14682
+ return `if command -v ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14670
14683
  }
14671
14684
  function packageInstallCommand(machine, packageName, manager = machine.platform === "macos" ? "brew" : "apt") {
14672
14685
  if (manager === "bun") {
@@ -14680,15 +14693,15 @@ function packageInstallCommand(machine, packageName, manager = machine.platform
14680
14693
  }
14681
14694
  return packageName;
14682
14695
  }
14683
- function detectPackageActions(machine) {
14696
+ function detectPackageActions(machine, runner) {
14684
14697
  return (machine.packages || []).map((pkg, index) => {
14685
14698
  const manager = pkg.manager || (machine.platform === "macos" ? "brew" : "apt");
14686
- const check2 = Bun.spawnSync(["bash", "-lc", packageCheckCommand(machine, pkg.name, manager)], {
14687
- stdout: "ignore",
14688
- stderr: "ignore",
14689
- env: process.env
14690
- });
14691
- const installed = check2.exitCode === 0;
14699
+ const check2 = runner(machine.id, packageCheckCommand(machine, pkg.name, manager));
14700
+ if (check2.exitCode !== 0) {
14701
+ throw new Error(describeMachineCommandFailure(`Sync package probe ${pkg.name}`, check2));
14702
+ }
14703
+ const installed = check2.stdout.split(`
14704
+ `).some((line) => line.trim() === "installed=1");
14692
14705
  return {
14693
14706
  id: `package-${index + 1}`,
14694
14707
  title: `${installed ? "Package present" : "Install package"} ${pkg.name}`,
@@ -14699,6 +14712,9 @@ function detectPackageActions(machine) {
14699
14712
  });
14700
14713
  }
14701
14714
  function detectFileActions(machine) {
14715
+ if ((machine.files || []).length > 0 && resolveMachineCommand(machine.id, "true").source !== "local") {
14716
+ throw new Error(`Remote file sync planning is not supported for ${machine.id}; refusing to inspect or apply local paths as remote state.`);
14717
+ }
14702
14718
  return (machine.files || []).map((file, index) => {
14703
14719
  const sourceExists = existsSync8(file.source);
14704
14720
  const targetExists = existsSync8(file.target);
@@ -14722,17 +14738,20 @@ function detectFileActions(machine) {
14722
14738
  };
14723
14739
  });
14724
14740
  }
14725
- function buildSyncPlan(machineId) {
14741
+ function buildSyncPlan(machineId, runner = runMachineCommand) {
14726
14742
  const manifest = readManifest();
14727
14743
  const currentMachineId = getLocalMachineId();
14728
14744
  const selected = machineId ? manifest.machines.find((machine) => machine.id === machineId) : manifest.machines.find((machine) => machine.id === currentMachineId);
14745
+ if (machineId && !selected) {
14746
+ throw new Error(`Machine not found in manifest: ${machineId}`);
14747
+ }
14729
14748
  const target = selected || {
14730
14749
  id: currentMachineId,
14731
14750
  platform: "linux",
14732
14751
  workspacePath: `${homedir6()}/workspace`
14733
14752
  };
14734
14753
  const actions = [
14735
- ...detectPackageActions(target),
14754
+ ...detectPackageActions(target, runner),
14736
14755
  ...detectFileActions(target)
14737
14756
  ];
14738
14757
  return {
@@ -14762,8 +14781,8 @@ function applyFileAction(command) {
14762
14781
  symlinkSync(sourcePath, targetPath);
14763
14782
  }
14764
14783
  }
14765
- function runSync(machineId, options = {}) {
14766
- const plan = buildSyncPlan(machineId);
14784
+ function runSync(machineId, options = {}, runner = runMachineCommand) {
14785
+ const plan = buildSyncPlan(machineId, runner);
14767
14786
  if (!options.apply) {
14768
14787
  return plan;
14769
14788
  }
@@ -14777,18 +14796,17 @@ function runSync(machineId, options = {}) {
14777
14796
  if (action.kind === "file") {
14778
14797
  applyFileAction(action.command);
14779
14798
  } else {
14780
- const result = Bun.spawnSync(["bash", "-lc", action.command], {
14781
- stdout: "pipe",
14782
- stderr: "pipe",
14783
- env: process.env
14784
- });
14799
+ const result = runner(plan.machineId, action.command);
14785
14800
  if (result.exitCode !== 0) {
14786
14801
  recordSyncRun(plan.machineId, "failed", {
14787
14802
  executed,
14788
14803
  failedAction: action,
14789
- stderr: result.stderr.toString()
14804
+ stderr: result.stderr,
14805
+ stdout: result.stdout,
14806
+ exitCode: result.exitCode,
14807
+ source: result.source
14790
14808
  });
14791
- throw new Error(`Sync action failed (${action.id}): ${result.stderr.toString().trim()}`);
14809
+ throw new Error(describeMachineCommandFailure(`Sync action ${action.id}`, result));
14792
14810
  }
14793
14811
  }
14794
14812
  executed += 1;