@hasna/machines 0.0.23 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11060,6 +11060,7 @@ function writeManifest(manifest, path = getManifestPath()) {
11060
11060
  generatedAt: new Date().toISOString(),
11061
11061
  machines: normalizeMachines(manifest.machines)
11062
11062
  };
11063
+ fleetSchema.parse(payload);
11063
11064
  writeFileSync(path, `${JSON.stringify(payload, null, 2)}
11064
11065
  `, "utf8");
11065
11066
  return path;
@@ -11112,29 +11113,78 @@ function getPackageVersion() {
11112
11113
  var MACHINES_CONSUMER_CONTRACT_VERSION = 1;
11113
11114
  var MACHINES_PACKAGE_NAME = "@hasna/machines";
11114
11115
  var MACHINES_CONSUMER_ENTRYPOINT = "@hasna/machines/consumer";
11116
+ var MACHINES_CONSUMER_SCHEMA_URI = "https://schemas.hasna.xyz/machines/consumer/v1/machines-consumer.schema.json";
11117
+ var MACHINES_CONSUMER_SCHEMA_ARTIFACT = "schemas/machines-consumer.schema.json";
11118
+ var DEFAULT_MACHINE_RESOLVER_TTL_MS = 24 * 60 * 60 * 1000;
11115
11119
  var MACHINES_CONSUMER_CAPABILITIES = {
11116
11120
  topology: true,
11117
11121
  compatibility: true,
11118
11122
  route_resolution: true,
11119
11123
  cli_json_fallback: true,
11120
11124
  workspace_path_mapping: true,
11121
- workspace_diagnostics: true
11125
+ workspace_diagnostics: true,
11126
+ schema_artifacts: true,
11127
+ cacheability_metadata: true,
11128
+ resolver_snapshots: true,
11129
+ field_capability_descriptors: true
11130
+ };
11131
+ var MACHINES_CONSUMER_FIELD_CAPABILITIES = {
11132
+ topology: {
11133
+ machine_identity: true,
11134
+ route_hints: true,
11135
+ tailscale_status: true,
11136
+ manifest_metadata: true
11137
+ },
11138
+ route: {
11139
+ cacheability: true,
11140
+ confidence: true,
11141
+ resolver_evidence: true
11142
+ },
11143
+ workspace: {
11144
+ cacheability: true,
11145
+ path_mapping: true,
11146
+ diagnostics: true,
11147
+ repair_hints: true,
11148
+ trust_auth: true
11149
+ },
11150
+ compatibility: {
11151
+ commands: true,
11152
+ packages: true,
11153
+ workspaces: true
11154
+ },
11155
+ resolver_snapshot: {
11156
+ cacheability: true,
11157
+ redacted_provenance: true
11158
+ }
11122
11159
  };
11123
11160
  var MACHINES_CONSUMER_CONTRACT = {
11124
11161
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11125
11162
  package_name: MACHINES_PACKAGE_NAME,
11126
11163
  entrypoint: MACHINES_CONSUMER_ENTRYPOINT,
11164
+ schema_uri: MACHINES_CONSUMER_SCHEMA_URI,
11165
+ schema_artifact: MACHINES_CONSUMER_SCHEMA_ARTIFACT,
11127
11166
  capabilities: MACHINES_CONSUMER_CAPABILITIES,
11128
- envelopes: ["topology", "route", "workspace", "compatibility"],
11167
+ field_capabilities: MACHINES_CONSUMER_FIELD_CAPABILITIES,
11168
+ cacheability: {
11169
+ default_ttl_ms: DEFAULT_MACHINE_RESOLVER_TTL_MS,
11170
+ stale_requires_refresh: true
11171
+ },
11172
+ envelopes: ["topology", "route", "workspace", "compatibility", "resolver_snapshot"],
11129
11173
  stable_exports: [
11130
11174
  "MACHINES_CONSUMER_CONTRACT",
11131
11175
  "MACHINES_CONSUMER_CONTRACT_VERSION",
11132
11176
  "MACHINES_CONSUMER_CAPABILITIES",
11177
+ "MACHINES_CONSUMER_FIELD_CAPABILITIES",
11178
+ "MACHINES_CONSUMER_SCHEMA_BUNDLE",
11179
+ "MACHINES_CONSUMER_SCHEMA_URI",
11133
11180
  "MACHINES_PACKAGE_NAME",
11134
11181
  "discoverMachineTopology",
11135
11182
  "getLocalMachineTopology",
11136
11183
  "resolveMachineRoute",
11137
11184
  "resolveMachineWorkspace",
11185
+ "createMachineResolverSnapshot",
11186
+ "getMachinesConsumerSchemaBundle",
11187
+ "validateMachinesConsumerEnvelope",
11138
11188
  "checkMachineCompatibility",
11139
11189
  "resolveMachineCommand",
11140
11190
  "runMachineCommand",
@@ -11412,11 +11462,100 @@ function routeConfidence(input) {
11412
11462
  return "low";
11413
11463
  return "none";
11414
11464
  }
11465
+ function addMilliseconds(date, milliseconds) {
11466
+ return new Date(date.getTime() + milliseconds).toISOString();
11467
+ }
11468
+ function routeAuthority(input) {
11469
+ if (!input.machine)
11470
+ return "unresolved";
11471
+ if (input.matchedBy === "fallback")
11472
+ return "fallback";
11473
+ if (input.selectedHint?.kind === "local")
11474
+ return "live_topology";
11475
+ if (input.selectedHint?.kind === "tailscale" || input.machine.tailscale.online !== null)
11476
+ return "live_topology";
11477
+ if (input.machine.manifest_declared)
11478
+ return "manifest";
11479
+ return "open-machines";
11480
+ }
11481
+ function workspaceAuthority(paths) {
11482
+ const sources = [paths.workspace_root.source, paths.project_root.source, paths.open_files_root.source];
11483
+ if (sources.some((source) => source === "argument"))
11484
+ return "argument";
11485
+ if (sources.some((source) => source === "manifest_metadata"))
11486
+ return "manifest_metadata";
11487
+ if (sources.some((source) => source === "manifest"))
11488
+ return "manifest";
11489
+ if (sources.some((source) => source === "inferred"))
11490
+ return "inferred";
11491
+ if (sources.every((source) => source === "unresolved"))
11492
+ return "unresolved";
11493
+ return "open-machines";
11494
+ }
11495
+ function cacheability(input) {
11496
+ const ttlMs = input.ttlMs === undefined ? DEFAULT_MACHINE_RESOLVER_TTL_MS : input.ttlMs;
11497
+ const expiresAt = typeof ttlMs === "number" && ttlMs > 0 ? addMilliseconds(input.observedAt, ttlMs) : null;
11498
+ const stale = expiresAt ? input.now.getTime() > new Date(expiresAt).getTime() : false;
11499
+ const confidenceCacheable = input.confidence !== "none" && input.confidence !== "low";
11500
+ const cacheable = input.ok && confidenceCacheable && !stale && input.authority !== "unresolved";
11501
+ const reasons = [...input.reasons];
11502
+ if (!input.ok)
11503
+ reasons.push("resolver_not_ok");
11504
+ if (!confidenceCacheable)
11505
+ reasons.push(`low_confidence:${input.confidence}`);
11506
+ if (stale)
11507
+ reasons.push("stale");
11508
+ if (input.authority === "unresolved")
11509
+ reasons.push("unresolved_authority");
11510
+ return {
11511
+ observed_at: input.observedAt.toISOString(),
11512
+ verified_at: input.ok ? input.now.toISOString() : null,
11513
+ expires_at: expiresAt,
11514
+ ttl_ms: typeof ttlMs === "number" && ttlMs > 0 ? ttlMs : null,
11515
+ source_authority: input.authority,
11516
+ confidence: input.confidence,
11517
+ cacheable,
11518
+ stale,
11519
+ reasons: [...new Set(reasons)].sort()
11520
+ };
11521
+ }
11522
+ function worstConfidence(values) {
11523
+ const rank = {
11524
+ exact: 0,
11525
+ high: 1,
11526
+ medium: 2,
11527
+ low: 3,
11528
+ none: 4
11529
+ };
11530
+ return [...values].sort((left, right) => rank[right] - rank[left])[0] ?? "none";
11531
+ }
11532
+ function mergeAuthorities(values) {
11533
+ const filtered = values.filter((value) => value !== "unknown");
11534
+ if (filtered.length === 0)
11535
+ return "unknown";
11536
+ const first = filtered[0];
11537
+ return filtered.every((value) => value === first) ? first : "mixed";
11538
+ }
11539
+ function mergeCacheability(input) {
11540
+ const confidence = worstConfidence(input.cacheabilities.map((entry) => entry.confidence));
11541
+ const reasons = input.cacheabilities.flatMap((entry) => entry.reasons);
11542
+ const ok = input.cacheabilities.every((entry) => entry.cacheable);
11543
+ return cacheability({
11544
+ ok,
11545
+ observedAt: input.observedAt,
11546
+ now: input.now,
11547
+ ttlMs: input.ttlMs,
11548
+ authority: mergeAuthorities(input.authorities),
11549
+ confidence,
11550
+ reasons
11551
+ });
11552
+ }
11415
11553
  function resolveMachineRoute(machineId, options = {}) {
11554
+ const now = options.now ?? new Date;
11416
11555
  const topology = options.topology ?? discoverMachineTopology(options);
11417
11556
  const warnings = [...topology.warnings];
11418
11557
  const { machine, matchedBy } = findRouteMachine(topology, machineId);
11419
- const generatedAt = (options.now ?? new Date).toISOString();
11558
+ const generatedAt = now.toISOString();
11420
11559
  if (!machine) {
11421
11560
  warnings.push(`machine_not_found:${machineId}`);
11422
11561
  return {
@@ -11440,16 +11579,27 @@ function resolveMachineRoute(machineId, options = {}) {
11440
11579
  tailscale_online: null,
11441
11580
  selected_hint: null
11442
11581
  },
11582
+ cacheability: cacheability({
11583
+ ok: false,
11584
+ observedAt: now,
11585
+ now,
11586
+ ttlMs: options.resolverTtlMs,
11587
+ authority: "unresolved",
11588
+ confidence: "none",
11589
+ reasons: [`machine_not_found:${machineId}`]
11590
+ }),
11443
11591
  warnings
11444
11592
  };
11445
11593
  }
11446
11594
  const selectedHint = selectRouteHint(machine.route_hints);
11447
11595
  const route = selectedHint?.kind ?? machine.ssh.route ?? "unknown";
11448
11596
  const local = route === "local" || machine.machine_id === topology.local_machine_id;
11597
+ const confidence = routeConfidence({ machine, hint: selectedHint, matchedBy });
11598
+ const ok = Boolean(selectedHint?.target);
11449
11599
  return {
11450
11600
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11451
11601
  package: topology.package,
11452
- ok: Boolean(selectedHint?.target),
11602
+ ok,
11453
11603
  machine_id: machine.machine_id,
11454
11604
  requested_machine_id: machineId,
11455
11605
  generated_at: generatedAt,
@@ -11457,7 +11607,7 @@ function resolveMachineRoute(machineId, options = {}) {
11457
11607
  source: route,
11458
11608
  target: selectedHint?.target ?? null,
11459
11609
  command_target: selectedHint?.target ?? null,
11460
- confidence: routeConfidence({ machine, hint: selectedHint, matchedBy }),
11610
+ confidence,
11461
11611
  local,
11462
11612
  evidence: {
11463
11613
  topology: true,
@@ -11467,6 +11617,15 @@ function resolveMachineRoute(machineId, options = {}) {
11467
11617
  tailscale_online: machine.tailscale.online,
11468
11618
  selected_hint: selectedHint
11469
11619
  },
11620
+ cacheability: cacheability({
11621
+ ok,
11622
+ observedAt: now,
11623
+ now,
11624
+ ttlMs: options.resolverTtlMs,
11625
+ authority: routeAuthority({ machine, selectedHint, matchedBy }),
11626
+ confidence,
11627
+ reasons: selectedHint ? [] : ["route_target_unresolved"]
11628
+ }),
11470
11629
  warnings
11471
11630
  };
11472
11631
  }
@@ -11763,10 +11922,11 @@ function metadataKeysForDiagnostics(metadata) {
11763
11922
  return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
11764
11923
  }
11765
11924
  function resolveMachineWorkspace(options) {
11925
+ const now = options.now ?? new Date;
11766
11926
  const topology = options.topology ?? discoverMachineTopology(options);
11767
11927
  const warnings = [...topology.warnings];
11768
11928
  const { machine, matchedBy } = findRouteMachine(topology, options.machineId);
11769
- const generatedAt = (options.now ?? new Date).toISOString();
11929
+ const generatedAt = now.toISOString();
11770
11930
  const repoName = options.repoName ?? options.projectId;
11771
11931
  const openFilesRepoName = options.openFilesRepoName ?? "open-files";
11772
11932
  if (!machine) {
@@ -11793,6 +11953,15 @@ function resolveMachineWorkspace(options) {
11793
11953
  manifest_declared: null,
11794
11954
  metadata_keys: []
11795
11955
  },
11956
+ cacheability: cacheability({
11957
+ ok: false,
11958
+ observedAt: now,
11959
+ now,
11960
+ ttlMs: options.resolverTtlMs,
11961
+ authority: "unresolved",
11962
+ confidence: "none",
11963
+ reasons: [`machine_not_found:${options.machineId}`]
11964
+ }),
11796
11965
  warnings
11797
11966
  };
11798
11967
  const diagnostics2 = workspaceDiagnostics({
@@ -11824,10 +11993,16 @@ function resolveMachineWorkspace(options) {
11824
11993
  warnings.push(`open_files_root_inferred:${options.projectId}`);
11825
11994
  if (!projectRootPath)
11826
11995
  warnings.push(`project_root_unresolved:${options.projectId}`);
11996
+ const workspacePaths = {
11997
+ workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
11998
+ project_root: { path: projectRootPath, source: projectRootSource },
11999
+ open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
12000
+ };
12001
+ const workspaceOk = Boolean(projectRootPath);
11827
12002
  const resolution = {
11828
12003
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11829
12004
  package: topology.package,
11830
- ok: Boolean(projectRootPath),
12005
+ ok: workspaceOk,
11831
12006
  requested_machine_id: options.machineId,
11832
12007
  machine_id: machine.machine_id,
11833
12008
  generated_at: generatedAt,
@@ -11842,11 +12017,7 @@ function resolveMachineWorkspace(options) {
11842
12017
  trust_status: trustStatus(machine),
11843
12018
  auth_status: authStatus(machine)
11844
12019
  },
11845
- paths: {
11846
- workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
11847
- project_root: { path: projectRootPath, source: projectRootSource },
11848
- open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
11849
- },
12020
+ paths: workspacePaths,
11850
12021
  diagnostics: [],
11851
12022
  repair_hints: [],
11852
12023
  evidence: {
@@ -11855,6 +12026,15 @@ function resolveMachineWorkspace(options) {
11855
12026
  manifest_declared: machine.manifest_declared,
11856
12027
  metadata_keys: metadataKeysForDiagnostics(metadata)
11857
12028
  },
12029
+ cacheability: cacheability({
12030
+ ok: workspaceOk,
12031
+ observedAt: now,
12032
+ now,
12033
+ ttlMs: options.resolverTtlMs,
12034
+ authority: workspaceAuthority(workspacePaths),
12035
+ confidence: workspaceOk ? "medium" : "none",
12036
+ reasons: projectRootPath ? [] : [`project_root_unresolved:${options.projectId}`]
12037
+ }),
11858
12038
  warnings
11859
12039
  };
11860
12040
  const diagnostics = workspaceDiagnostics({
@@ -11869,6 +12049,73 @@ function resolveMachineWorkspace(options) {
11869
12049
  repair_hints: diagnostics.repairHints
11870
12050
  };
11871
12051
  }
12052
+ function createMachineResolverSnapshot(options) {
12053
+ const now = options.now ?? new Date;
12054
+ const routeObservedAt = new Date(options.route.generated_at);
12055
+ const workspaceObservedAt = options.workspace ? new Date(options.workspace.generated_at) : null;
12056
+ const observedAt = new Date(Math.max(Number.isNaN(routeObservedAt.getTime()) ? 0 : routeObservedAt.getTime(), workspaceObservedAt && !Number.isNaN(workspaceObservedAt.getTime()) ? workspaceObservedAt.getTime() : 0));
12057
+ const cacheabilities = [options.route.cacheability, options.workspace?.cacheability].filter((entry) => Boolean(entry));
12058
+ const authorities = cacheabilities.map((entry) => entry.source_authority);
12059
+ const warnings = [...new Set([
12060
+ ...options.route.warnings,
12061
+ ...options.workspace?.warnings ?? [],
12062
+ ...cacheabilities.flatMap((entry) => entry.reasons)
12063
+ ])].sort();
12064
+ return {
12065
+ schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
12066
+ package: options.route.package,
12067
+ generated_at: now.toISOString(),
12068
+ requested_machine_id: options.route.requested_machine_id,
12069
+ machine_id: options.route.machine_id ?? options.workspace?.machine_id ?? null,
12070
+ route: {
12071
+ ok: options.route.ok,
12072
+ source: options.route.source,
12073
+ route: options.route.route,
12074
+ target: options.route.target,
12075
+ command_target: options.route.command_target,
12076
+ confidence: options.route.confidence,
12077
+ local: options.route.local,
12078
+ cacheability: options.route.cacheability
12079
+ },
12080
+ workspace: options.workspace ? {
12081
+ ok: options.workspace.ok,
12082
+ project: options.workspace.project,
12083
+ machine: options.workspace.machine,
12084
+ paths: options.workspace.paths,
12085
+ diagnostics: options.workspace.diagnostics,
12086
+ repair_hints: options.workspace.repair_hints,
12087
+ cacheability: options.workspace.cacheability
12088
+ } : null,
12089
+ cacheability: mergeCacheability({
12090
+ observedAt: observedAt.getTime() > 0 ? observedAt : now,
12091
+ now,
12092
+ ttlMs: options.resolverTtlMs,
12093
+ authorities,
12094
+ cacheabilities
12095
+ }),
12096
+ warnings,
12097
+ provenance: {
12098
+ route: {
12099
+ schema_version: options.route.schema_version,
12100
+ generated_at: options.route.generated_at,
12101
+ evidence: {
12102
+ matched_by: options.route.evidence.matched_by,
12103
+ manifest_declared: options.route.evidence.manifest_declared,
12104
+ heartbeat_status: options.route.evidence.heartbeat_status,
12105
+ tailscale_online: options.route.evidence.tailscale_online,
12106
+ selected_hint_kind: options.route.evidence.selected_hint?.kind ?? null
12107
+ }
12108
+ },
12109
+ workspace: options.workspace ? {
12110
+ schema_version: options.workspace.schema_version,
12111
+ generated_at: options.workspace.generated_at,
12112
+ metadata_keys: options.workspace.evidence.metadata_keys,
12113
+ matched_by: options.workspace.evidence.matched_by,
12114
+ manifest_declared: options.workspace.evidence.manifest_declared
12115
+ } : null
12116
+ }
12117
+ };
12118
+ }
11872
12119
  function getLocalMachineTopology(options = {}) {
11873
12120
  const topology = discoverMachineTopology(options);
11874
12121
  return topology.machines.find((machine) => machine.machine_id === topology.local_machine_id) ?? {
@@ -12219,7 +12466,7 @@ function getAgentStatus(machineId = getLocalMachineId()) {
12219
12466
  }));
12220
12467
  }
12221
12468
  // src/commands/backup.ts
12222
- import { homedir as homedir2 } from "os";
12469
+ import { homedir as homedir2, hostname as hostname5 } from "os";
12223
12470
  import { join as join3 } from "path";
12224
12471
  var MACHINES_BACKUP_BUCKET_ENV = "HASNA_MACHINES_S3_BUCKET";
12225
12472
  var MACHINES_BACKUP_BUCKET_FALLBACK_ENV = "MACHINES_S3_BUCKET";
@@ -12289,7 +12536,7 @@ function buildBackupPlan(bucket, prefix) {
12289
12536
  {
12290
12537
  id: "backup-upload",
12291
12538
  title: "Upload archive to S3",
12292
- command: `aws s3 cp ${quote(archivePath)} s3://${target.bucket}/${target.prefix}/$(hostname)-backup.tgz`,
12539
+ command: `aws s3 cp ${quote(archivePath)} ${quote(`s3://${target.bucket}/${target.prefix}/${hostname5()}-backup.tgz`)}`,
12293
12540
  manager: "custom"
12294
12541
  }
12295
12542
  ];
@@ -12344,20 +12591,21 @@ function shellQuote5(value) {
12344
12591
  }
12345
12592
  function buildAppCommand(machine, app) {
12346
12593
  const packageName = getPackageName(app);
12594
+ const quotedPackageName = shellQuote5(packageName);
12347
12595
  const manager = getAppManager(machine, app);
12348
12596
  if (manager === "custom") {
12349
12597
  return packageName;
12350
12598
  }
12351
12599
  if (machine.platform === "macos") {
12352
12600
  if (manager === "cask") {
12353
- return `brew install --cask ${packageName}`;
12601
+ return `brew install --cask ${quotedPackageName}`;
12354
12602
  }
12355
- return `brew install ${packageName}`;
12603
+ return `brew install ${quotedPackageName}`;
12356
12604
  }
12357
12605
  if (machine.platform === "windows") {
12358
- return `winget install ${packageName}`;
12606
+ return `winget install ${quotedPackageName}`;
12359
12607
  }
12360
- return `sudo apt-get install -y ${packageName}`;
12608
+ return `sudo apt-get install -y ${quotedPackageName}`;
12361
12609
  }
12362
12610
  function buildAppProbeCommand(machine, app) {
12363
12611
  const packageName = shellQuote5(getPackageName(app));
@@ -12643,9 +12891,10 @@ function manifestList() {
12643
12891
  return readManifest();
12644
12892
  }
12645
12893
  function manifestAdd(machine) {
12894
+ const validatedMachine = machineSchema.parse(machine);
12646
12895
  const manifest = readManifest();
12647
- const nextMachines = manifest.machines.filter((entry) => entry.id !== machine.id);
12648
- nextMachines.push(machine);
12896
+ const nextMachines = manifest.machines.filter((entry) => entry.id !== validatedMachine.id);
12897
+ nextMachines.push(validatedMachine);
12649
12898
  const nextManifest = { ...manifest, machines: nextMachines };
12650
12899
  writeManifest(nextManifest);
12651
12900
  return nextManifest;
@@ -13495,6 +13744,7 @@ function runSelfTest() {
13495
13744
  };
13496
13745
  }
13497
13746
  // src/commands/setup.ts
13747
+ import { homedir as homedir4 } from "os";
13498
13748
  function quote3(value) {
13499
13749
  return `'${value.replace(/'/g, `'\\''`)}'`;
13500
13750
  }
@@ -13542,11 +13792,11 @@ function buildPackageSteps(machine) {
13542
13792
  const manager = pkg.manager || (machine.platform === "macos" ? "brew" : "apt");
13543
13793
  let command = pkg.name;
13544
13794
  if (manager === "bun") {
13545
- command = `bun install -g ${pkg.name}`;
13795
+ command = `bun install -g ${quote3(pkg.name)}`;
13546
13796
  } else if (manager === "brew") {
13547
- command = `brew install ${pkg.name}`;
13797
+ command = `brew install ${quote3(pkg.name)}`;
13548
13798
  } else if (manager === "apt") {
13549
- command = `sudo apt-get install -y ${pkg.name}`;
13799
+ command = `sudo apt-get install -y ${quote3(pkg.name)}`;
13550
13800
  }
13551
13801
  return {
13552
13802
  id: `package-${index + 1}`,
@@ -13564,7 +13814,7 @@ function buildSetupPlan(machineId) {
13564
13814
  const target = selected || {
13565
13815
  id: currentMachineId,
13566
13816
  platform: "linux",
13567
- workspacePath: "~/workspace"
13817
+ workspacePath: `${homedir4()}/workspace`
13568
13818
  };
13569
13819
  const steps = [...buildBaseSteps(target), ...buildPackageSteps(target)];
13570
13820
  return {
@@ -13608,8 +13858,58 @@ function runSetup(machineId, options = {}) {
13608
13858
  recordSetupRun(plan.machineId, "completed", summary);
13609
13859
  return summary;
13610
13860
  }
13861
+ // src/commands/screen.ts
13862
+ function shellQuote7(value) {
13863
+ return `'${value.replace(/'/g, "'\\''")}'`;
13864
+ }
13865
+ function splitTarget(target) {
13866
+ const at = target.indexOf("@");
13867
+ if (at === -1)
13868
+ return [null, target];
13869
+ return [target.slice(0, at), target.slice(at + 1)];
13870
+ }
13871
+ function resolveScreenTarget(machineId, options = {}) {
13872
+ const resolved = resolveMachineRoute(machineId, options);
13873
+ if (!resolved.ok || !resolved.target) {
13874
+ throw new Error(`Machine route not found: ${machineId}`);
13875
+ }
13876
+ if (resolved.route === "unknown") {
13877
+ throw new Error(`Machine route is not reachable for screen sharing: ${machineId}`);
13878
+ }
13879
+ let [user, host] = splitTarget(resolved.target);
13880
+ if (!user) {
13881
+ const topology = options.topology ?? discoverMachineTopology(options);
13882
+ const entry = topology.machines.find((m) => m.machine_id === (resolved.machine_id ?? machineId));
13883
+ user = entry?.user ?? null;
13884
+ }
13885
+ const url = user ? `vnc://${user}@${host}` : `vnc://${host}`;
13886
+ return {
13887
+ machineId: resolved.machine_id ?? machineId,
13888
+ user,
13889
+ host,
13890
+ url,
13891
+ route: resolved.route,
13892
+ confidence: resolved.confidence,
13893
+ warnings: resolved.warnings
13894
+ };
13895
+ }
13896
+ function buildScreenCommand(machineId, options = {}) {
13897
+ const resolved = resolveScreenTarget(machineId, options);
13898
+ return `open ${resolved.url}`;
13899
+ }
13900
+ function buildScreenEnableRemoteCommand(user, vncPassword) {
13901
+ const kickstart = "/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart";
13902
+ const lines = [
13903
+ `dseditgroup -o edit -a ${shellQuote7(user)} -t user com.apple.access_screensharing 2>/dev/null || true`,
13904
+ "defaults write /Library/Preferences/com.apple.RemoteManagement AllowSRPForNetworkNodes -bool true",
13905
+ `${kickstart} -configure -clientopts -setvnclegacy -vnclegacy yes -setvncpw -vncpw ${shellQuote7(vncPassword)}`,
13906
+ `${kickstart} -activate -configure -access -on -users ${shellQuote7(user)} -privs -all -restart -agent -menu`
13907
+ ];
13908
+ return lines.join(" && ");
13909
+ }
13611
13910
  // src/commands/sync.ts
13612
13911
  import { existsSync as existsSync7, lstatSync, readFileSync as readFileSync5, symlinkSync, copyFileSync } from "fs";
13912
+ import { homedir as homedir5 } from "os";
13613
13913
  function quote4(value) {
13614
13914
  return `'${value.replace(/'/g, `'\\''`)}'`;
13615
13915
  }
@@ -13627,13 +13927,13 @@ function packageCheckCommand(machine, packageName, manager = machine.platform ==
13627
13927
  }
13628
13928
  function packageInstallCommand(machine, packageName, manager = machine.platform === "macos" ? "brew" : "apt") {
13629
13929
  if (manager === "bun") {
13630
- return `bun install -g ${packageName}`;
13930
+ return `bun install -g ${quote4(packageName)}`;
13631
13931
  }
13632
13932
  if (manager === "brew") {
13633
- return `brew install ${packageName}`;
13933
+ return `brew install ${quote4(packageName)}`;
13634
13934
  }
13635
13935
  if (manager === "apt") {
13636
- return `sudo apt-get install -y ${packageName}`;
13936
+ return `sudo apt-get install -y ${quote4(packageName)}`;
13637
13937
  }
13638
13938
  return packageName;
13639
13939
  }
@@ -13686,7 +13986,7 @@ function buildSyncPlan(machineId) {
13686
13986
  const target = selected || {
13687
13987
  id: currentMachineId,
13688
13988
  platform: "linux",
13689
- workspacePath: "~/workspace"
13989
+ workspacePath: `${homedir5()}/workspace`
13690
13990
  };
13691
13991
  const actions = [
13692
13992
  ...detectPackageActions(target),
@@ -14631,7 +14931,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
14631
14931
  var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
14632
14932
  var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
14633
14933
  var base64url = /^[A-Za-z0-9_-]*$/;
14634
- var hostname5 = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/;
14934
+ var hostname6 = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/;
14635
14935
  var e164 = /^\+(?:[0-9]){6,14}[0-9]$/;
14636
14936
  var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
14637
14937
  var date = /* @__PURE__ */ new RegExp(`^${dateSource}$`);
@@ -15243,7 +15543,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
15243
15543
  code: "invalid_format",
15244
15544
  format: "url",
15245
15545
  note: "Invalid hostname",
15246
- pattern: hostname5.source,
15546
+ pattern: hostname6.source,
15247
15547
  input: payload.value,
15248
15548
  inst,
15249
15549
  continue: !def.abort
@@ -17232,7 +17532,7 @@ class JSONSchemaGenerator {
17232
17532
  if (val === undefined) {
17233
17533
  if (this.unrepresentable === "throw") {
17234
17534
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
17235
- } else {}
17535
+ }
17236
17536
  } else if (typeof val === "bigint") {
17237
17537
  if (this.unrepresentable === "throw") {
17238
17538
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -23061,6 +23361,7 @@ export {
23061
23361
  runAppsInstall,
23062
23362
  resolveTables,
23063
23363
  resolveSshTarget,
23364
+ resolveScreenTarget,
23064
23365
  resolveMachineWorkspace,
23065
23366
  resolveMachineRoute,
23066
23367
  resolveBackupTarget,
@@ -23125,6 +23426,7 @@ export {
23125
23426
  diffApps,
23126
23427
  detectCurrentMachineManifest,
23127
23428
  createMcpServer,
23429
+ createMachineResolverSnapshot,
23128
23430
  countRuns,
23129
23431
  closeDb,
23130
23432
  checkMachineCompatibility,
@@ -23133,6 +23435,8 @@ export {
23133
23435
  buildSshCommand,
23134
23436
  buildSetupPlan,
23135
23437
  buildServer,
23438
+ buildScreenEnableRemoteCommand,
23439
+ buildScreenCommand,
23136
23440
  buildClaudeInstallPlan,
23137
23441
  buildCertPlan,
23138
23442
  buildBackupPlan,
@@ -23150,6 +23454,9 @@ export {
23150
23454
  MACHINES_STORAGE_FALLBACK_ENV,
23151
23455
  MACHINES_STORAGE_ENV,
23152
23456
  MACHINES_PACKAGE_NAME,
23457
+ MACHINES_CONSUMER_SCHEMA_URI,
23458
+ MACHINES_CONSUMER_SCHEMA_ARTIFACT,
23459
+ MACHINES_CONSUMER_FIELD_CAPABILITIES,
23153
23460
  MACHINES_CONSUMER_ENTRYPOINT,
23154
23461
  MACHINES_CONSUMER_CONTRACT_VERSION,
23155
23462
  MACHINES_CONSUMER_CONTRACT,
@@ -23158,6 +23465,7 @@ export {
23158
23465
  MACHINES_BACKUP_PREFIX_ENV,
23159
23466
  MACHINES_BACKUP_BUCKET_FALLBACK_ENV,
23160
23467
  MACHINES_BACKUP_BUCKET_ENV,
23468
+ DEFAULT_MACHINE_RESOLVER_TTL_MS,
23161
23469
  DEFAULT_BACKUP_PREFIX,
23162
23470
  CROSSREFS_KEY
23163
23471
  };
@@ -1 +1 @@
1
- {"version":3,"file":"manifests.d.ts","sourceRoot":"","sources":["../src/manifests.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoBjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAItB,CAAC;AAoBH,wBAAgB,kBAAkB,IAAI,aAAa,CAMlD;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAoB,GAAG,aAAa,CAMpE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAoB,GAAG,aAAa,CAExE;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,SAAoB,GAAG,MAAM,CAUvF;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,eAAe,GAAG,IAAI,CAEtG;AAED,wBAAgB,4BAA4B,IAAI,eAAe,CAiB9D"}
1
+ {"version":3,"file":"manifests.d.ts","sourceRoot":"","sources":["../src/manifests.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoBjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAItB,CAAC;AAoBH,wBAAgB,kBAAkB,IAAI,aAAa,CAMlD;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAoB,GAAG,aAAa,CAMpE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAoB,GAAG,aAAa,CAExE;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,SAAoB,GAAG,MAAM,CAWvF;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,eAAe,GAAG,IAAI,CAEtG;AAED,wBAAgB,4BAA4B,IAAI,eAAe,CAiB9D"}