@hasna/machines 0.0.29 → 0.0.31

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;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,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;AA6CrD,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,CAQzE;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,CAqB9D;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,CAwB9G;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 = [
@@ -12665,27 +12676,28 @@ function buildAppsPlan(machineId) {
12665
12676
  executed: 0
12666
12677
  };
12667
12678
  }
12668
- function getAppsStatus(machineId) {
12679
+ function getAppsStatus(machineId, runner = runMachineCommand) {
12669
12680
  const machine = resolveMachine(machineId);
12681
+ const readiness = requireMachineCommandSuccess("Apps status readiness check", runner(machine.id, "true"));
12670
12682
  const apps = (machine.apps || []).map((app) => {
12671
- const probe = runMachineCommand(machine.id, buildAppProbeCommand(machine, app));
12683
+ const probe = requireMachineCommandSuccess(`App probe ${app.name}`, runner(machine.id, buildAppProbeCommand(machine, app)));
12672
12684
  return parseProbeOutput(app, machine, probe.stdout);
12673
12685
  });
12674
12686
  return {
12675
12687
  machineId: machine.id,
12676
- source: apps.length > 0 ? runMachineCommand(machine.id, "true").source : machine.id === detectCurrentMachineManifest().id ? "local" : runMachineCommand(machine.id, "true").source,
12688
+ source: readiness.source,
12677
12689
  apps
12678
12690
  };
12679
12691
  }
12680
- function diffApps(machineId) {
12681
- const status = getAppsStatus(machineId);
12692
+ function diffApps(machineId, runner = runMachineCommand) {
12693
+ const status = getAppsStatus(machineId, runner);
12682
12694
  return {
12683
12695
  ...status,
12684
12696
  missing: status.apps.filter((app) => !app.installed).map((app) => app.name),
12685
12697
  installed: status.apps.filter((app) => app.installed).map((app) => app.name)
12686
12698
  };
12687
12699
  }
12688
- function runAppsInstall(machineId, options = {}) {
12700
+ function runAppsInstall(machineId, options = {}, runner = runMachineCommand) {
12689
12701
  const plan = buildAppsPlan(machineId);
12690
12702
  if (!options.apply)
12691
12703
  return plan;
@@ -12694,14 +12706,7 @@ function runAppsInstall(machineId, options = {}) {
12694
12706
  }
12695
12707
  let executed = 0;
12696
12708
  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
- }
12709
+ requireMachineCommandSuccess(`App install ${step.id}`, runner(plan.machineId, step.command));
12705
12710
  executed += 1;
12706
12711
  }
12707
12712
  return {
@@ -13017,25 +13022,28 @@ function buildClaudeInstallPlan(machineId, tools) {
13017
13022
  executed: 0
13018
13023
  };
13019
13024
  }
13020
- function getClaudeCliStatus(machineId, tools) {
13025
+ function getClaudeCliStatus(machineId, tools, runner = runMachineCommand) {
13021
13026
  const machine = resolveMachine2(machineId);
13022
13027
  const normalizedTools = normalizeTools(tools);
13023
- const route = runMachineCommand(machine.id, "true").source;
13028
+ const route = requireMachineCommandSuccess("AI CLI status readiness check", runner(machine.id, "true")).source;
13024
13029
  return {
13025
13030
  machineId: machine.id,
13026
13031
  source: route,
13027
- tools: normalizedTools.map((tool) => parseProbe(tool, runMachineCommand(machine.id, buildProbeCommand(tool)).stdout))
13032
+ tools: normalizedTools.map((tool) => {
13033
+ const result = requireMachineCommandSuccess(`AI CLI probe ${tool}`, runner(machine.id, buildProbeCommand(tool)));
13034
+ return parseProbe(tool, result.stdout);
13035
+ })
13028
13036
  };
13029
13037
  }
13030
- function diffClaudeCli(machineId, tools) {
13031
- const status = getClaudeCliStatus(machineId, tools);
13038
+ function diffClaudeCli(machineId, tools, runner = runMachineCommand) {
13039
+ const status = getClaudeCliStatus(machineId, tools, runner);
13032
13040
  return {
13033
13041
  ...status,
13034
13042
  missing: status.tools.filter((tool) => !tool.installed).map((tool) => tool.tool),
13035
13043
  installed: status.tools.filter((tool) => tool.installed).map((tool) => tool.tool)
13036
13044
  };
13037
13045
  }
13038
- function runClaudeInstall(machineId, tools, options = {}) {
13046
+ function runClaudeInstall(machineId, tools, options = {}, runner = runMachineCommand) {
13039
13047
  const plan = buildClaudeInstallPlan(machineId, tools);
13040
13048
  if (!options.apply)
13041
13049
  return plan;
@@ -13044,14 +13052,7 @@ function runClaudeInstall(machineId, tools, options = {}) {
13044
13052
  }
13045
13053
  let executed = 0;
13046
13054
  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
- }
13055
+ requireMachineCommandSuccess(`AI CLI install ${step.id}`, runner(plan.machineId, step.command));
13055
13056
  executed += 1;
13056
13057
  }
13057
13058
  return {
@@ -13102,7 +13103,7 @@ function buildTailscaleInstallPlan(machineId) {
13102
13103
  executed: 0
13103
13104
  };
13104
13105
  }
13105
- function runTailscaleInstall(machineId, options = {}) {
13106
+ function runTailscaleInstall(machineId, options = {}, runner = runMachineCommand) {
13106
13107
  const plan = buildTailscaleInstallPlan(machineId);
13107
13108
  if (!options.apply)
13108
13109
  return plan;
@@ -13111,14 +13112,7 @@ function runTailscaleInstall(machineId, options = {}) {
13111
13112
  }
13112
13113
  let executed = 0;
13113
13114
  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
- }
13115
+ requireMachineCommandSuccess(`Tailscale install ${step.id}`, runner(plan.machineId, step.command));
13122
13116
  executed += 1;
13123
13117
  }
13124
13118
  return {
@@ -14495,7 +14489,7 @@ function buildSetupPlan(machineId) {
14495
14489
  executed: 0
14496
14490
  };
14497
14491
  }
14498
- function runSetup(machineId, options = {}) {
14492
+ function runSetup(machineId, options = {}, runner = runMachineCommand) {
14499
14493
  const plan = buildSetupPlan(machineId);
14500
14494
  if (!options.apply) {
14501
14495
  return plan;
@@ -14505,18 +14499,17 @@ function runSetup(machineId, options = {}) {
14505
14499
  }
14506
14500
  let executed = 0;
14507
14501
  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
- });
14502
+ const result = runner(plan.machineId, step.command);
14513
14503
  if (result.exitCode !== 0) {
14514
14504
  recordSetupRun(plan.machineId, "failed", {
14515
14505
  executed,
14516
14506
  failedStep: step,
14517
- stderr: result.stderr.toString()
14507
+ stderr: result.stderr,
14508
+ stdout: result.stdout,
14509
+ exitCode: result.exitCode,
14510
+ source: result.source
14518
14511
  });
14519
- throw new Error(`Setup step failed (${step.id}): ${result.stderr.toString().trim()}`);
14512
+ throw new Error(describeMachineCommandFailure(`Setup step ${step.id}`, result));
14520
14513
  }
14521
14514
  executed += 1;
14522
14515
  }
@@ -14657,16 +14650,17 @@ function quote4(value) {
14657
14650
  return `'${value.replace(/'/g, `'\\''`)}'`;
14658
14651
  }
14659
14652
  function packageCheckCommand(machine, packageName, manager = machine.platform === "macos" ? "brew" : "apt") {
14653
+ const quotedPackageName = quote4(packageName);
14660
14654
  if (manager === "bun") {
14661
- return `bun pm ls -g --all | grep -F ${quote4(packageName)}`;
14655
+ 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
14656
  }
14663
14657
  if (manager === "brew") {
14664
- return `brew list --versions ${quote4(packageName)}`;
14658
+ return `if brew list --versions ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14665
14659
  }
14666
14660
  if (manager === "apt") {
14667
- return `dpkg -s ${quote4(packageName)} >/dev/null 2>&1`;
14661
+ return `if dpkg -s ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14668
14662
  }
14669
- return `command -v ${quote4(packageName)} >/dev/null 2>&1`;
14663
+ return `if command -v ${quotedPackageName} >/dev/null 2>&1; then printf 'installed=1\\n'; else printf 'installed=0\\n'; fi`;
14670
14664
  }
14671
14665
  function packageInstallCommand(machine, packageName, manager = machine.platform === "macos" ? "brew" : "apt") {
14672
14666
  if (manager === "bun") {
@@ -14680,15 +14674,15 @@ function packageInstallCommand(machine, packageName, manager = machine.platform
14680
14674
  }
14681
14675
  return packageName;
14682
14676
  }
14683
- function detectPackageActions(machine) {
14677
+ function detectPackageActions(machine, runner) {
14684
14678
  return (machine.packages || []).map((pkg, index) => {
14685
14679
  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;
14680
+ const check2 = runner(machine.id, packageCheckCommand(machine, pkg.name, manager));
14681
+ if (check2.exitCode !== 0) {
14682
+ throw new Error(describeMachineCommandFailure(`Sync package probe ${pkg.name}`, check2));
14683
+ }
14684
+ const installed = check2.stdout.split(`
14685
+ `).some((line) => line.trim() === "installed=1");
14692
14686
  return {
14693
14687
  id: `package-${index + 1}`,
14694
14688
  title: `${installed ? "Package present" : "Install package"} ${pkg.name}`,
@@ -14699,6 +14693,9 @@ function detectPackageActions(machine) {
14699
14693
  });
14700
14694
  }
14701
14695
  function detectFileActions(machine) {
14696
+ if ((machine.files || []).length > 0 && resolveMachineCommand(machine.id, "true").source !== "local") {
14697
+ throw new Error(`Remote file sync planning is not supported for ${machine.id}; refusing to inspect or apply local paths as remote state.`);
14698
+ }
14702
14699
  return (machine.files || []).map((file, index) => {
14703
14700
  const sourceExists = existsSync8(file.source);
14704
14701
  const targetExists = existsSync8(file.target);
@@ -14722,7 +14719,7 @@ function detectFileActions(machine) {
14722
14719
  };
14723
14720
  });
14724
14721
  }
14725
- function buildSyncPlan(machineId) {
14722
+ function buildSyncPlan(machineId, runner = runMachineCommand) {
14726
14723
  const manifest = readManifest();
14727
14724
  const currentMachineId = getLocalMachineId();
14728
14725
  const selected = machineId ? manifest.machines.find((machine) => machine.id === machineId) : manifest.machines.find((machine) => machine.id === currentMachineId);
@@ -14732,7 +14729,7 @@ function buildSyncPlan(machineId) {
14732
14729
  workspacePath: `${homedir6()}/workspace`
14733
14730
  };
14734
14731
  const actions = [
14735
- ...detectPackageActions(target),
14732
+ ...detectPackageActions(target, runner),
14736
14733
  ...detectFileActions(target)
14737
14734
  ];
14738
14735
  return {
@@ -14762,8 +14759,8 @@ function applyFileAction(command) {
14762
14759
  symlinkSync(sourcePath, targetPath);
14763
14760
  }
14764
14761
  }
14765
- function runSync(machineId, options = {}) {
14766
- const plan = buildSyncPlan(machineId);
14762
+ function runSync(machineId, options = {}, runner = runMachineCommand) {
14763
+ const plan = buildSyncPlan(machineId, runner);
14767
14764
  if (!options.apply) {
14768
14765
  return plan;
14769
14766
  }
@@ -14777,18 +14774,17 @@ function runSync(machineId, options = {}) {
14777
14774
  if (action.kind === "file") {
14778
14775
  applyFileAction(action.command);
14779
14776
  } else {
14780
- const result = Bun.spawnSync(["bash", "-lc", action.command], {
14781
- stdout: "pipe",
14782
- stderr: "pipe",
14783
- env: process.env
14784
- });
14777
+ const result = runner(plan.machineId, action.command);
14785
14778
  if (result.exitCode !== 0) {
14786
14779
  recordSyncRun(plan.machineId, "failed", {
14787
14780
  executed,
14788
14781
  failedAction: action,
14789
- stderr: result.stderr.toString()
14782
+ stderr: result.stderr,
14783
+ stdout: result.stdout,
14784
+ exitCode: result.exitCode,
14785
+ source: result.source
14790
14786
  });
14791
- throw new Error(`Sync action failed (${action.id}): ${result.stderr.toString().trim()}`);
14787
+ throw new Error(describeMachineCommandFailure(`Sync action ${action.id}`, result));
14792
14788
  }
14793
14789
  }
14794
14790
  executed += 1;