@hasna/machines 0.0.22 → 0.0.24

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/consumer.js CHANGED
@@ -4312,29 +4312,78 @@ function getPackageVersion() {
4312
4312
  var MACHINES_CONSUMER_CONTRACT_VERSION = 1;
4313
4313
  var MACHINES_PACKAGE_NAME = "@hasna/machines";
4314
4314
  var MACHINES_CONSUMER_ENTRYPOINT = "@hasna/machines/consumer";
4315
+ var MACHINES_CONSUMER_SCHEMA_URI = "https://schemas.hasna.xyz/machines/consumer/v1/machines-consumer.schema.json";
4316
+ var MACHINES_CONSUMER_SCHEMA_ARTIFACT = "schemas/machines-consumer.schema.json";
4317
+ var DEFAULT_MACHINE_RESOLVER_TTL_MS = 24 * 60 * 60 * 1000;
4315
4318
  var MACHINES_CONSUMER_CAPABILITIES = {
4316
4319
  topology: true,
4317
4320
  compatibility: true,
4318
4321
  route_resolution: true,
4319
4322
  cli_json_fallback: true,
4320
4323
  workspace_path_mapping: true,
4321
- workspace_diagnostics: true
4324
+ workspace_diagnostics: true,
4325
+ schema_artifacts: true,
4326
+ cacheability_metadata: true,
4327
+ resolver_snapshots: true,
4328
+ field_capability_descriptors: true
4329
+ };
4330
+ var MACHINES_CONSUMER_FIELD_CAPABILITIES = {
4331
+ topology: {
4332
+ machine_identity: true,
4333
+ route_hints: true,
4334
+ tailscale_status: true,
4335
+ manifest_metadata: true
4336
+ },
4337
+ route: {
4338
+ cacheability: true,
4339
+ confidence: true,
4340
+ resolver_evidence: true
4341
+ },
4342
+ workspace: {
4343
+ cacheability: true,
4344
+ path_mapping: true,
4345
+ diagnostics: true,
4346
+ repair_hints: true,
4347
+ trust_auth: true
4348
+ },
4349
+ compatibility: {
4350
+ commands: true,
4351
+ packages: true,
4352
+ workspaces: true
4353
+ },
4354
+ resolver_snapshot: {
4355
+ cacheability: true,
4356
+ redacted_provenance: true
4357
+ }
4322
4358
  };
4323
4359
  var MACHINES_CONSUMER_CONTRACT = {
4324
4360
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
4325
4361
  package_name: MACHINES_PACKAGE_NAME,
4326
4362
  entrypoint: MACHINES_CONSUMER_ENTRYPOINT,
4363
+ schema_uri: MACHINES_CONSUMER_SCHEMA_URI,
4364
+ schema_artifact: MACHINES_CONSUMER_SCHEMA_ARTIFACT,
4327
4365
  capabilities: MACHINES_CONSUMER_CAPABILITIES,
4328
- envelopes: ["topology", "route", "workspace", "compatibility"],
4366
+ field_capabilities: MACHINES_CONSUMER_FIELD_CAPABILITIES,
4367
+ cacheability: {
4368
+ default_ttl_ms: DEFAULT_MACHINE_RESOLVER_TTL_MS,
4369
+ stale_requires_refresh: true
4370
+ },
4371
+ envelopes: ["topology", "route", "workspace", "compatibility", "resolver_snapshot"],
4329
4372
  stable_exports: [
4330
4373
  "MACHINES_CONSUMER_CONTRACT",
4331
4374
  "MACHINES_CONSUMER_CONTRACT_VERSION",
4332
4375
  "MACHINES_CONSUMER_CAPABILITIES",
4376
+ "MACHINES_CONSUMER_FIELD_CAPABILITIES",
4377
+ "MACHINES_CONSUMER_SCHEMA_BUNDLE",
4378
+ "MACHINES_CONSUMER_SCHEMA_URI",
4333
4379
  "MACHINES_PACKAGE_NAME",
4334
4380
  "discoverMachineTopology",
4335
4381
  "getLocalMachineTopology",
4336
4382
  "resolveMachineRoute",
4337
4383
  "resolveMachineWorkspace",
4384
+ "createMachineResolverSnapshot",
4385
+ "getMachinesConsumerSchemaBundle",
4386
+ "validateMachinesConsumerEnvelope",
4338
4387
  "checkMachineCompatibility",
4339
4388
  "resolveMachineCommand",
4340
4389
  "runMachineCommand",
@@ -4612,11 +4661,100 @@ function routeConfidence(input) {
4612
4661
  return "low";
4613
4662
  return "none";
4614
4663
  }
4664
+ function addMilliseconds(date, milliseconds) {
4665
+ return new Date(date.getTime() + milliseconds).toISOString();
4666
+ }
4667
+ function routeAuthority(input) {
4668
+ if (!input.machine)
4669
+ return "unresolved";
4670
+ if (input.matchedBy === "fallback")
4671
+ return "fallback";
4672
+ if (input.selectedHint?.kind === "local")
4673
+ return "live_topology";
4674
+ if (input.selectedHint?.kind === "tailscale" || input.machine.tailscale.online !== null)
4675
+ return "live_topology";
4676
+ if (input.machine.manifest_declared)
4677
+ return "manifest";
4678
+ return "open-machines";
4679
+ }
4680
+ function workspaceAuthority(paths) {
4681
+ const sources = [paths.workspace_root.source, paths.project_root.source, paths.open_files_root.source];
4682
+ if (sources.some((source) => source === "argument"))
4683
+ return "argument";
4684
+ if (sources.some((source) => source === "manifest_metadata"))
4685
+ return "manifest_metadata";
4686
+ if (sources.some((source) => source === "manifest"))
4687
+ return "manifest";
4688
+ if (sources.some((source) => source === "inferred"))
4689
+ return "inferred";
4690
+ if (sources.every((source) => source === "unresolved"))
4691
+ return "unresolved";
4692
+ return "open-machines";
4693
+ }
4694
+ function cacheability(input) {
4695
+ const ttlMs = input.ttlMs === undefined ? DEFAULT_MACHINE_RESOLVER_TTL_MS : input.ttlMs;
4696
+ const expiresAt = typeof ttlMs === "number" && ttlMs > 0 ? addMilliseconds(input.observedAt, ttlMs) : null;
4697
+ const stale = expiresAt ? input.now.getTime() > new Date(expiresAt).getTime() : false;
4698
+ const confidenceCacheable = input.confidence !== "none" && input.confidence !== "low";
4699
+ const cacheable = input.ok && confidenceCacheable && !stale && input.authority !== "unresolved";
4700
+ const reasons = [...input.reasons];
4701
+ if (!input.ok)
4702
+ reasons.push("resolver_not_ok");
4703
+ if (!confidenceCacheable)
4704
+ reasons.push(`low_confidence:${input.confidence}`);
4705
+ if (stale)
4706
+ reasons.push("stale");
4707
+ if (input.authority === "unresolved")
4708
+ reasons.push("unresolved_authority");
4709
+ return {
4710
+ observed_at: input.observedAt.toISOString(),
4711
+ verified_at: input.ok ? input.now.toISOString() : null,
4712
+ expires_at: expiresAt,
4713
+ ttl_ms: typeof ttlMs === "number" && ttlMs > 0 ? ttlMs : null,
4714
+ source_authority: input.authority,
4715
+ confidence: input.confidence,
4716
+ cacheable,
4717
+ stale,
4718
+ reasons: [...new Set(reasons)].sort()
4719
+ };
4720
+ }
4721
+ function worstConfidence(values) {
4722
+ const rank = {
4723
+ exact: 0,
4724
+ high: 1,
4725
+ medium: 2,
4726
+ low: 3,
4727
+ none: 4
4728
+ };
4729
+ return [...values].sort((left, right) => rank[right] - rank[left])[0] ?? "none";
4730
+ }
4731
+ function mergeAuthorities(values) {
4732
+ const filtered = values.filter((value) => value !== "unknown");
4733
+ if (filtered.length === 0)
4734
+ return "unknown";
4735
+ const first = filtered[0];
4736
+ return filtered.every((value) => value === first) ? first : "mixed";
4737
+ }
4738
+ function mergeCacheability(input) {
4739
+ const confidence = worstConfidence(input.cacheabilities.map((entry) => entry.confidence));
4740
+ const reasons = input.cacheabilities.flatMap((entry) => entry.reasons);
4741
+ const ok = input.cacheabilities.every((entry) => entry.cacheable);
4742
+ return cacheability({
4743
+ ok,
4744
+ observedAt: input.observedAt,
4745
+ now: input.now,
4746
+ ttlMs: input.ttlMs,
4747
+ authority: mergeAuthorities(input.authorities),
4748
+ confidence,
4749
+ reasons
4750
+ });
4751
+ }
4615
4752
  function resolveMachineRoute(machineId, options = {}) {
4753
+ const now = options.now ?? new Date;
4616
4754
  const topology = options.topology ?? discoverMachineTopology(options);
4617
4755
  const warnings = [...topology.warnings];
4618
4756
  const { machine, matchedBy } = findRouteMachine(topology, machineId);
4619
- const generatedAt = (options.now ?? new Date).toISOString();
4757
+ const generatedAt = now.toISOString();
4620
4758
  if (!machine) {
4621
4759
  warnings.push(`machine_not_found:${machineId}`);
4622
4760
  return {
@@ -4640,16 +4778,27 @@ function resolveMachineRoute(machineId, options = {}) {
4640
4778
  tailscale_online: null,
4641
4779
  selected_hint: null
4642
4780
  },
4781
+ cacheability: cacheability({
4782
+ ok: false,
4783
+ observedAt: now,
4784
+ now,
4785
+ ttlMs: options.resolverTtlMs,
4786
+ authority: "unresolved",
4787
+ confidence: "none",
4788
+ reasons: [`machine_not_found:${machineId}`]
4789
+ }),
4643
4790
  warnings
4644
4791
  };
4645
4792
  }
4646
4793
  const selectedHint = selectRouteHint(machine.route_hints);
4647
4794
  const route = selectedHint?.kind ?? machine.ssh.route ?? "unknown";
4648
4795
  const local = route === "local" || machine.machine_id === topology.local_machine_id;
4796
+ const confidence = routeConfidence({ machine, hint: selectedHint, matchedBy });
4797
+ const ok = Boolean(selectedHint?.target);
4649
4798
  return {
4650
4799
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
4651
4800
  package: topology.package,
4652
- ok: Boolean(selectedHint?.target),
4801
+ ok,
4653
4802
  machine_id: machine.machine_id,
4654
4803
  requested_machine_id: machineId,
4655
4804
  generated_at: generatedAt,
@@ -4657,7 +4806,7 @@ function resolveMachineRoute(machineId, options = {}) {
4657
4806
  source: route,
4658
4807
  target: selectedHint?.target ?? null,
4659
4808
  command_target: selectedHint?.target ?? null,
4660
- confidence: routeConfidence({ machine, hint: selectedHint, matchedBy }),
4809
+ confidence,
4661
4810
  local,
4662
4811
  evidence: {
4663
4812
  topology: true,
@@ -4667,6 +4816,15 @@ function resolveMachineRoute(machineId, options = {}) {
4667
4816
  tailscale_online: machine.tailscale.online,
4668
4817
  selected_hint: selectedHint
4669
4818
  },
4819
+ cacheability: cacheability({
4820
+ ok,
4821
+ observedAt: now,
4822
+ now,
4823
+ ttlMs: options.resolverTtlMs,
4824
+ authority: routeAuthority({ machine, selectedHint, matchedBy }),
4825
+ confidence,
4826
+ reasons: selectedHint ? [] : ["route_target_unresolved"]
4827
+ }),
4670
4828
  warnings
4671
4829
  };
4672
4830
  }
@@ -4963,10 +5121,11 @@ function metadataKeysForDiagnostics(metadata) {
4963
5121
  return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
4964
5122
  }
4965
5123
  function resolveMachineWorkspace(options) {
5124
+ const now = options.now ?? new Date;
4966
5125
  const topology = options.topology ?? discoverMachineTopology(options);
4967
5126
  const warnings = [...topology.warnings];
4968
5127
  const { machine, matchedBy } = findRouteMachine(topology, options.machineId);
4969
- const generatedAt = (options.now ?? new Date).toISOString();
5128
+ const generatedAt = now.toISOString();
4970
5129
  const repoName = options.repoName ?? options.projectId;
4971
5130
  const openFilesRepoName = options.openFilesRepoName ?? "open-files";
4972
5131
  if (!machine) {
@@ -4993,6 +5152,15 @@ function resolveMachineWorkspace(options) {
4993
5152
  manifest_declared: null,
4994
5153
  metadata_keys: []
4995
5154
  },
5155
+ cacheability: cacheability({
5156
+ ok: false,
5157
+ observedAt: now,
5158
+ now,
5159
+ ttlMs: options.resolverTtlMs,
5160
+ authority: "unresolved",
5161
+ confidence: "none",
5162
+ reasons: [`machine_not_found:${options.machineId}`]
5163
+ }),
4996
5164
  warnings
4997
5165
  };
4998
5166
  const diagnostics2 = workspaceDiagnostics({
@@ -5024,10 +5192,16 @@ function resolveMachineWorkspace(options) {
5024
5192
  warnings.push(`open_files_root_inferred:${options.projectId}`);
5025
5193
  if (!projectRootPath)
5026
5194
  warnings.push(`project_root_unresolved:${options.projectId}`);
5195
+ const workspacePaths = {
5196
+ workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
5197
+ project_root: { path: projectRootPath, source: projectRootSource },
5198
+ open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
5199
+ };
5200
+ const workspaceOk = Boolean(projectRootPath);
5027
5201
  const resolution = {
5028
5202
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
5029
5203
  package: topology.package,
5030
- ok: Boolean(projectRootPath),
5204
+ ok: workspaceOk,
5031
5205
  requested_machine_id: options.machineId,
5032
5206
  machine_id: machine.machine_id,
5033
5207
  generated_at: generatedAt,
@@ -5042,11 +5216,7 @@ function resolveMachineWorkspace(options) {
5042
5216
  trust_status: trustStatus(machine),
5043
5217
  auth_status: authStatus(machine)
5044
5218
  },
5045
- paths: {
5046
- workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
5047
- project_root: { path: projectRootPath, source: projectRootSource },
5048
- open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
5049
- },
5219
+ paths: workspacePaths,
5050
5220
  diagnostics: [],
5051
5221
  repair_hints: [],
5052
5222
  evidence: {
@@ -5055,6 +5225,15 @@ function resolveMachineWorkspace(options) {
5055
5225
  manifest_declared: machine.manifest_declared,
5056
5226
  metadata_keys: metadataKeysForDiagnostics(metadata)
5057
5227
  },
5228
+ cacheability: cacheability({
5229
+ ok: workspaceOk,
5230
+ observedAt: now,
5231
+ now,
5232
+ ttlMs: options.resolverTtlMs,
5233
+ authority: workspaceAuthority(workspacePaths),
5234
+ confidence: workspaceOk ? "medium" : "none",
5235
+ reasons: projectRootPath ? [] : [`project_root_unresolved:${options.projectId}`]
5236
+ }),
5058
5237
  warnings
5059
5238
  };
5060
5239
  const diagnostics = workspaceDiagnostics({
@@ -5069,6 +5248,73 @@ function resolveMachineWorkspace(options) {
5069
5248
  repair_hints: diagnostics.repairHints
5070
5249
  };
5071
5250
  }
5251
+ function createMachineResolverSnapshot(options) {
5252
+ const now = options.now ?? new Date;
5253
+ const routeObservedAt = new Date(options.route.generated_at);
5254
+ const workspaceObservedAt = options.workspace ? new Date(options.workspace.generated_at) : null;
5255
+ const observedAt = new Date(Math.max(Number.isNaN(routeObservedAt.getTime()) ? 0 : routeObservedAt.getTime(), workspaceObservedAt && !Number.isNaN(workspaceObservedAt.getTime()) ? workspaceObservedAt.getTime() : 0));
5256
+ const cacheabilities = [options.route.cacheability, options.workspace?.cacheability].filter((entry) => Boolean(entry));
5257
+ const authorities = cacheabilities.map((entry) => entry.source_authority);
5258
+ const warnings = [...new Set([
5259
+ ...options.route.warnings,
5260
+ ...options.workspace?.warnings ?? [],
5261
+ ...cacheabilities.flatMap((entry) => entry.reasons)
5262
+ ])].sort();
5263
+ return {
5264
+ schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
5265
+ package: options.route.package,
5266
+ generated_at: now.toISOString(),
5267
+ requested_machine_id: options.route.requested_machine_id,
5268
+ machine_id: options.route.machine_id ?? options.workspace?.machine_id ?? null,
5269
+ route: {
5270
+ ok: options.route.ok,
5271
+ source: options.route.source,
5272
+ route: options.route.route,
5273
+ target: options.route.target,
5274
+ command_target: options.route.command_target,
5275
+ confidence: options.route.confidence,
5276
+ local: options.route.local,
5277
+ cacheability: options.route.cacheability
5278
+ },
5279
+ workspace: options.workspace ? {
5280
+ ok: options.workspace.ok,
5281
+ project: options.workspace.project,
5282
+ machine: options.workspace.machine,
5283
+ paths: options.workspace.paths,
5284
+ diagnostics: options.workspace.diagnostics,
5285
+ repair_hints: options.workspace.repair_hints,
5286
+ cacheability: options.workspace.cacheability
5287
+ } : null,
5288
+ cacheability: mergeCacheability({
5289
+ observedAt: observedAt.getTime() > 0 ? observedAt : now,
5290
+ now,
5291
+ ttlMs: options.resolverTtlMs,
5292
+ authorities,
5293
+ cacheabilities
5294
+ }),
5295
+ warnings,
5296
+ provenance: {
5297
+ route: {
5298
+ schema_version: options.route.schema_version,
5299
+ generated_at: options.route.generated_at,
5300
+ evidence: {
5301
+ matched_by: options.route.evidence.matched_by,
5302
+ manifest_declared: options.route.evidence.manifest_declared,
5303
+ heartbeat_status: options.route.evidence.heartbeat_status,
5304
+ tailscale_online: options.route.evidence.tailscale_online,
5305
+ selected_hint_kind: options.route.evidence.selected_hint?.kind ?? null
5306
+ }
5307
+ },
5308
+ workspace: options.workspace ? {
5309
+ schema_version: options.workspace.schema_version,
5310
+ generated_at: options.workspace.generated_at,
5311
+ metadata_keys: options.workspace.evidence.metadata_keys,
5312
+ matched_by: options.workspace.evidence.matched_by,
5313
+ manifest_declared: options.workspace.evidence.manifest_declared
5314
+ } : null
5315
+ }
5316
+ };
5317
+ }
5072
5318
  function getLocalMachineTopology(options = {}) {
5073
5319
  const topology = discoverMachineTopology(options);
5074
5320
  return topology.machines.find((machine) => machine.machine_id === topology.local_machine_id) ?? {
@@ -5088,6 +5334,237 @@ function getLocalMachineTopology(options = {}) {
5088
5334
  metadata: {}
5089
5335
  };
5090
5336
  }
5337
+ // src/consumer-schema.ts
5338
+ var MACHINES_CONSUMER_SCHEMA_BUNDLE = {
5339
+ $schema: "https://json-schema.org/draft/2020-12/schema",
5340
+ $id: MACHINES_CONSUMER_SCHEMA_URI,
5341
+ title: "@hasna/machines consumer contract schema bundle",
5342
+ type: "object",
5343
+ $defs: {
5344
+ cacheability: {
5345
+ type: "object",
5346
+ required: ["observed_at", "verified_at", "expires_at", "ttl_ms", "source_authority", "confidence", "cacheable", "stale", "reasons"],
5347
+ properties: {
5348
+ observed_at: { type: "string", format: "date-time" },
5349
+ verified_at: { type: ["string", "null"], format: "date-time" },
5350
+ expires_at: { type: ["string", "null"], format: "date-time" },
5351
+ ttl_ms: { type: ["number", "null"] },
5352
+ source_authority: { enum: ["open-machines", "manifest", "manifest_metadata", "live_topology", "argument", "inferred", "fallback", "unresolved", "mixed", "unknown"] },
5353
+ confidence: { enum: ["exact", "high", "medium", "low", "none"] },
5354
+ cacheable: { type: "boolean" },
5355
+ stale: { type: "boolean" },
5356
+ reasons: { type: "array", items: { type: "string" } }
5357
+ }
5358
+ },
5359
+ contract: {
5360
+ type: "object",
5361
+ required: ["schema_version", "package_name", "entrypoint", "schema_uri", "schema_artifact", "capabilities", "field_capabilities", "cacheability", "envelopes", "stable_exports"],
5362
+ properties: {
5363
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5364
+ package_name: { const: "@hasna/machines" },
5365
+ entrypoint: { const: "@hasna/machines/consumer" },
5366
+ schema_uri: { const: MACHINES_CONSUMER_SCHEMA_URI },
5367
+ schema_artifact: { const: "schemas/machines-consumer.schema.json" },
5368
+ capabilities: { type: "object" },
5369
+ field_capabilities: { type: "object" },
5370
+ cacheability: { type: "object" },
5371
+ envelopes: { type: "array", items: { enum: ["topology", "route", "workspace", "compatibility", "resolver_snapshot"] } },
5372
+ stable_exports: { type: "array", items: { type: "string" } }
5373
+ }
5374
+ },
5375
+ topology: {
5376
+ type: "object",
5377
+ required: ["schema_version", "package", "capabilities", "generated_at", "local_machine_id", "machines", "warnings"],
5378
+ properties: {
5379
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5380
+ package: { type: "object" },
5381
+ capabilities: { type: "object" },
5382
+ generated_at: { type: "string", format: "date-time" },
5383
+ local_machine_id: { type: "string" },
5384
+ machines: { type: "array" },
5385
+ warnings: { type: "array", items: { type: "string" } }
5386
+ }
5387
+ },
5388
+ route: {
5389
+ type: "object",
5390
+ required: ["schema_version", "package", "ok", "machine_id", "requested_machine_id", "generated_at", "route", "source", "target", "command_target", "confidence", "local", "evidence", "cacheability", "warnings"],
5391
+ properties: {
5392
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5393
+ package: { type: "object" },
5394
+ ok: { type: "boolean" },
5395
+ machine_id: { type: ["string", "null"] },
5396
+ requested_machine_id: { type: "string" },
5397
+ generated_at: { type: "string", format: "date-time" },
5398
+ route: { enum: ["local", "lan", "tailscale", "ssh", "unknown"] },
5399
+ source: { enum: ["local", "lan", "tailscale", "ssh", "unknown"] },
5400
+ target: { type: ["string", "null"] },
5401
+ command_target: { type: ["string", "null"] },
5402
+ confidence: { enum: ["exact", "high", "medium", "low", "none"] },
5403
+ local: { type: "boolean" },
5404
+ evidence: { type: "object" },
5405
+ cacheability: { $ref: "#/$defs/cacheability" },
5406
+ warnings: { type: "array", items: { type: "string" } }
5407
+ }
5408
+ },
5409
+ workspace: {
5410
+ type: "object",
5411
+ required: ["schema_version", "package", "ok", "requested_machine_id", "machine_id", "generated_at", "project", "machine", "paths", "diagnostics", "repair_hints", "evidence", "cacheability", "warnings"],
5412
+ properties: {
5413
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5414
+ package: { type: "object" },
5415
+ ok: { type: "boolean" },
5416
+ requested_machine_id: { type: "string" },
5417
+ machine_id: { type: ["string", "null"] },
5418
+ generated_at: { type: "string", format: "date-time" },
5419
+ project: { type: "object" },
5420
+ machine: {
5421
+ type: "object",
5422
+ required: ["current", "primary", "trust_status", "auth_status"],
5423
+ properties: {
5424
+ current: { type: "boolean" },
5425
+ primary: { type: "boolean" },
5426
+ trust_status: { enum: ["trusted", "untrusted", "unknown"] },
5427
+ auth_status: { enum: ["authenticated", "unauthenticated", "unknown"] }
5428
+ }
5429
+ },
5430
+ paths: { type: "object" },
5431
+ diagnostics: { type: "array" },
5432
+ repair_hints: { type: "array" },
5433
+ evidence: { type: "object" },
5434
+ cacheability: { $ref: "#/$defs/cacheability" },
5435
+ warnings: { type: "array", items: { type: "string" } }
5436
+ }
5437
+ },
5438
+ compatibility: {
5439
+ type: "object",
5440
+ required: ["schema_version", "package", "capabilities", "ok", "machine_id", "source", "generated_at", "checks", "summary"],
5441
+ properties: {
5442
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5443
+ package: { type: "object" },
5444
+ capabilities: { type: "object" },
5445
+ ok: { type: "boolean" },
5446
+ machine_id: { type: "string" },
5447
+ source: { type: "string" },
5448
+ generated_at: { type: "string", format: "date-time" },
5449
+ checks: { type: "array" },
5450
+ summary: { type: "object" }
5451
+ }
5452
+ },
5453
+ resolver_snapshot: {
5454
+ type: "object",
5455
+ required: ["schema_version", "package", "generated_at", "requested_machine_id", "machine_id", "route", "workspace", "cacheability", "warnings", "provenance"],
5456
+ properties: {
5457
+ schema_version: { const: MACHINES_CONSUMER_CONTRACT_VERSION },
5458
+ package: { type: "object" },
5459
+ generated_at: { type: "string", format: "date-time" },
5460
+ requested_machine_id: { type: "string" },
5461
+ machine_id: { type: ["string", "null"] },
5462
+ route: { type: "object" },
5463
+ workspace: { type: ["object", "null"] },
5464
+ cacheability: { $ref: "#/$defs/cacheability" },
5465
+ warnings: { type: "array", items: { type: "string" } },
5466
+ provenance: { type: "object" }
5467
+ }
5468
+ }
5469
+ }
5470
+ };
5471
+ function isRecord2(value) {
5472
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5473
+ }
5474
+ function hasString(value, key) {
5475
+ return typeof value[key] === "string" && value[key].length > 0;
5476
+ }
5477
+ function hasObject(value, key) {
5478
+ return isRecord2(value[key]);
5479
+ }
5480
+ function hasArray(value, key) {
5481
+ return Array.isArray(value[key]);
5482
+ }
5483
+ function hasCacheability(value, key = "cacheability") {
5484
+ const cache = value[key];
5485
+ return isRecord2(cache) && hasString(cache, "observed_at") && typeof cache.cacheable === "boolean" && typeof cache.stale === "boolean" && hasArray(cache, "reasons");
5486
+ }
5487
+ function requireFields(value, fields, errors2) {
5488
+ for (const field of fields) {
5489
+ if (!(field in value))
5490
+ errors2.push(`missing:${field}`);
5491
+ }
5492
+ }
5493
+ function getMachinesConsumerSchemaBundle() {
5494
+ return JSON.parse(JSON.stringify(MACHINES_CONSUMER_SCHEMA_BUNDLE));
5495
+ }
5496
+ function validateMachinesConsumerEnvelope(envelope, value) {
5497
+ const errors2 = [];
5498
+ if (!isRecord2(value)) {
5499
+ return { ok: false, envelope, schema_id: MACHINES_CONSUMER_SCHEMA_URI, errors: ["not_object"] };
5500
+ }
5501
+ if (value.schema_version !== MACHINES_CONSUMER_CONTRACT_VERSION)
5502
+ errors2.push(`schema_version:${String(value.schema_version)}`);
5503
+ if (envelope === "contract") {
5504
+ requireFields(value, ["package_name", "entrypoint", "schema_uri", "schema_artifact", "capabilities", "field_capabilities", "cacheability", "envelopes", "stable_exports"], errors2);
5505
+ if (value.package_name !== "@hasna/machines")
5506
+ errors2.push("package_name");
5507
+ if (value.entrypoint !== "@hasna/machines/consumer")
5508
+ errors2.push("entrypoint");
5509
+ if (!hasObject(value, "capabilities"))
5510
+ errors2.push("capabilities");
5511
+ if (!hasObject(value, "field_capabilities"))
5512
+ errors2.push("field_capabilities");
5513
+ if (!hasArray(value, "envelopes"))
5514
+ errors2.push("envelopes");
5515
+ if (!hasArray(value, "stable_exports"))
5516
+ errors2.push("stable_exports");
5517
+ } else if (envelope === "topology") {
5518
+ requireFields(value, ["package", "capabilities", "generated_at", "local_machine_id", "machines", "warnings"], errors2);
5519
+ if (!hasArray(value, "machines"))
5520
+ errors2.push("machines");
5521
+ if (!hasArray(value, "warnings"))
5522
+ errors2.push("warnings");
5523
+ } else if (envelope === "route") {
5524
+ requireFields(value, ["package", "ok", "machine_id", "requested_machine_id", "generated_at", "route", "source", "target", "command_target", "confidence", "local", "evidence", "cacheability", "warnings"], errors2);
5525
+ if (typeof value.ok !== "boolean")
5526
+ errors2.push("ok");
5527
+ if (!hasObject(value, "evidence"))
5528
+ errors2.push("evidence");
5529
+ if (!hasCacheability(value))
5530
+ errors2.push("cacheability");
5531
+ if (!hasArray(value, "warnings"))
5532
+ errors2.push("warnings");
5533
+ } else if (envelope === "workspace") {
5534
+ requireFields(value, ["package", "ok", "requested_machine_id", "machine_id", "generated_at", "project", "machine", "paths", "diagnostics", "repair_hints", "evidence", "cacheability", "warnings"], errors2);
5535
+ if (typeof value.ok !== "boolean")
5536
+ errors2.push("ok");
5537
+ if (!hasObject(value, "machine"))
5538
+ errors2.push("machine");
5539
+ if (!hasObject(value, "paths"))
5540
+ errors2.push("paths");
5541
+ if (!hasArray(value, "diagnostics"))
5542
+ errors2.push("diagnostics");
5543
+ if (!hasArray(value, "repair_hints"))
5544
+ errors2.push("repair_hints");
5545
+ if (!hasCacheability(value))
5546
+ errors2.push("cacheability");
5547
+ } else if (envelope === "compatibility") {
5548
+ requireFields(value, ["package", "capabilities", "ok", "machine_id", "source", "generated_at", "checks", "summary"], errors2);
5549
+ if (typeof value.ok !== "boolean")
5550
+ errors2.push("ok");
5551
+ if (!hasArray(value, "checks"))
5552
+ errors2.push("checks");
5553
+ if (!hasObject(value, "summary"))
5554
+ errors2.push("summary");
5555
+ } else if (envelope === "resolver_snapshot") {
5556
+ requireFields(value, ["package", "generated_at", "requested_machine_id", "machine_id", "route", "workspace", "cacheability", "warnings", "provenance"], errors2);
5557
+ if (!hasObject(value, "route"))
5558
+ errors2.push("route");
5559
+ if (!hasCacheability(value))
5560
+ errors2.push("cacheability");
5561
+ if (!hasArray(value, "warnings"))
5562
+ errors2.push("warnings");
5563
+ if (!hasObject(value, "provenance"))
5564
+ errors2.push("provenance");
5565
+ }
5566
+ return { ok: errors2.length === 0, envelope, schema_id: MACHINES_CONSUMER_SCHEMA_URI, errors: errors2 };
5567
+ }
5091
5568
  // src/remote.ts
5092
5569
  import { spawnSync as spawnSync2 } from "child_process";
5093
5570
  import { hostname as hostname4 } from "os";
@@ -5397,20 +5874,28 @@ function checkMachineCompatibility(options = {}) {
5397
5874
  };
5398
5875
  }
5399
5876
  export {
5877
+ validateMachinesConsumerEnvelope,
5400
5878
  runMachineCommand,
5401
5879
  resolveSshTarget,
5402
5880
  resolveMachineWorkspace,
5403
5881
  resolveMachineRoute,
5404
5882
  resolveMachineCommand,
5405
5883
  getPackageVersion,
5884
+ getMachinesConsumerSchemaBundle,
5406
5885
  getMachinesConsumerCapabilities,
5407
5886
  getLocalMachineTopology,
5408
5887
  discoverMachineTopology,
5888
+ createMachineResolverSnapshot,
5409
5889
  checkMachineCompatibility,
5410
5890
  buildSshCommand,
5411
5891
  MACHINES_PACKAGE_NAME,
5892
+ MACHINES_CONSUMER_SCHEMA_URI,
5893
+ MACHINES_CONSUMER_SCHEMA_BUNDLE,
5894
+ MACHINES_CONSUMER_SCHEMA_ARTIFACT,
5895
+ MACHINES_CONSUMER_FIELD_CAPABILITIES,
5412
5896
  MACHINES_CONSUMER_ENTRYPOINT,
5413
5897
  MACHINES_CONSUMER_CONTRACT_VERSION,
5414
5898
  MACHINES_CONSUMER_CONTRACT,
5415
- MACHINES_CONSUMER_CAPABILITIES
5899
+ MACHINES_CONSUMER_CAPABILITIES,
5900
+ DEFAULT_MACHINE_RESOLVER_TTL_MS
5416
5901
  };