@hasna/machines 0.0.23 → 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/index.js CHANGED
@@ -11112,29 +11112,78 @@ function getPackageVersion() {
11112
11112
  var MACHINES_CONSUMER_CONTRACT_VERSION = 1;
11113
11113
  var MACHINES_PACKAGE_NAME = "@hasna/machines";
11114
11114
  var MACHINES_CONSUMER_ENTRYPOINT = "@hasna/machines/consumer";
11115
+ var MACHINES_CONSUMER_SCHEMA_URI = "https://schemas.hasna.xyz/machines/consumer/v1/machines-consumer.schema.json";
11116
+ var MACHINES_CONSUMER_SCHEMA_ARTIFACT = "schemas/machines-consumer.schema.json";
11117
+ var DEFAULT_MACHINE_RESOLVER_TTL_MS = 24 * 60 * 60 * 1000;
11115
11118
  var MACHINES_CONSUMER_CAPABILITIES = {
11116
11119
  topology: true,
11117
11120
  compatibility: true,
11118
11121
  route_resolution: true,
11119
11122
  cli_json_fallback: true,
11120
11123
  workspace_path_mapping: true,
11121
- workspace_diagnostics: true
11124
+ workspace_diagnostics: true,
11125
+ schema_artifacts: true,
11126
+ cacheability_metadata: true,
11127
+ resolver_snapshots: true,
11128
+ field_capability_descriptors: true
11129
+ };
11130
+ var MACHINES_CONSUMER_FIELD_CAPABILITIES = {
11131
+ topology: {
11132
+ machine_identity: true,
11133
+ route_hints: true,
11134
+ tailscale_status: true,
11135
+ manifest_metadata: true
11136
+ },
11137
+ route: {
11138
+ cacheability: true,
11139
+ confidence: true,
11140
+ resolver_evidence: true
11141
+ },
11142
+ workspace: {
11143
+ cacheability: true,
11144
+ path_mapping: true,
11145
+ diagnostics: true,
11146
+ repair_hints: true,
11147
+ trust_auth: true
11148
+ },
11149
+ compatibility: {
11150
+ commands: true,
11151
+ packages: true,
11152
+ workspaces: true
11153
+ },
11154
+ resolver_snapshot: {
11155
+ cacheability: true,
11156
+ redacted_provenance: true
11157
+ }
11122
11158
  };
11123
11159
  var MACHINES_CONSUMER_CONTRACT = {
11124
11160
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11125
11161
  package_name: MACHINES_PACKAGE_NAME,
11126
11162
  entrypoint: MACHINES_CONSUMER_ENTRYPOINT,
11163
+ schema_uri: MACHINES_CONSUMER_SCHEMA_URI,
11164
+ schema_artifact: MACHINES_CONSUMER_SCHEMA_ARTIFACT,
11127
11165
  capabilities: MACHINES_CONSUMER_CAPABILITIES,
11128
- envelopes: ["topology", "route", "workspace", "compatibility"],
11166
+ field_capabilities: MACHINES_CONSUMER_FIELD_CAPABILITIES,
11167
+ cacheability: {
11168
+ default_ttl_ms: DEFAULT_MACHINE_RESOLVER_TTL_MS,
11169
+ stale_requires_refresh: true
11170
+ },
11171
+ envelopes: ["topology", "route", "workspace", "compatibility", "resolver_snapshot"],
11129
11172
  stable_exports: [
11130
11173
  "MACHINES_CONSUMER_CONTRACT",
11131
11174
  "MACHINES_CONSUMER_CONTRACT_VERSION",
11132
11175
  "MACHINES_CONSUMER_CAPABILITIES",
11176
+ "MACHINES_CONSUMER_FIELD_CAPABILITIES",
11177
+ "MACHINES_CONSUMER_SCHEMA_BUNDLE",
11178
+ "MACHINES_CONSUMER_SCHEMA_URI",
11133
11179
  "MACHINES_PACKAGE_NAME",
11134
11180
  "discoverMachineTopology",
11135
11181
  "getLocalMachineTopology",
11136
11182
  "resolveMachineRoute",
11137
11183
  "resolveMachineWorkspace",
11184
+ "createMachineResolverSnapshot",
11185
+ "getMachinesConsumerSchemaBundle",
11186
+ "validateMachinesConsumerEnvelope",
11138
11187
  "checkMachineCompatibility",
11139
11188
  "resolveMachineCommand",
11140
11189
  "runMachineCommand",
@@ -11412,11 +11461,100 @@ function routeConfidence(input) {
11412
11461
  return "low";
11413
11462
  return "none";
11414
11463
  }
11464
+ function addMilliseconds(date, milliseconds) {
11465
+ return new Date(date.getTime() + milliseconds).toISOString();
11466
+ }
11467
+ function routeAuthority(input) {
11468
+ if (!input.machine)
11469
+ return "unresolved";
11470
+ if (input.matchedBy === "fallback")
11471
+ return "fallback";
11472
+ if (input.selectedHint?.kind === "local")
11473
+ return "live_topology";
11474
+ if (input.selectedHint?.kind === "tailscale" || input.machine.tailscale.online !== null)
11475
+ return "live_topology";
11476
+ if (input.machine.manifest_declared)
11477
+ return "manifest";
11478
+ return "open-machines";
11479
+ }
11480
+ function workspaceAuthority(paths) {
11481
+ const sources = [paths.workspace_root.source, paths.project_root.source, paths.open_files_root.source];
11482
+ if (sources.some((source) => source === "argument"))
11483
+ return "argument";
11484
+ if (sources.some((source) => source === "manifest_metadata"))
11485
+ return "manifest_metadata";
11486
+ if (sources.some((source) => source === "manifest"))
11487
+ return "manifest";
11488
+ if (sources.some((source) => source === "inferred"))
11489
+ return "inferred";
11490
+ if (sources.every((source) => source === "unresolved"))
11491
+ return "unresolved";
11492
+ return "open-machines";
11493
+ }
11494
+ function cacheability(input) {
11495
+ const ttlMs = input.ttlMs === undefined ? DEFAULT_MACHINE_RESOLVER_TTL_MS : input.ttlMs;
11496
+ const expiresAt = typeof ttlMs === "number" && ttlMs > 0 ? addMilliseconds(input.observedAt, ttlMs) : null;
11497
+ const stale = expiresAt ? input.now.getTime() > new Date(expiresAt).getTime() : false;
11498
+ const confidenceCacheable = input.confidence !== "none" && input.confidence !== "low";
11499
+ const cacheable = input.ok && confidenceCacheable && !stale && input.authority !== "unresolved";
11500
+ const reasons = [...input.reasons];
11501
+ if (!input.ok)
11502
+ reasons.push("resolver_not_ok");
11503
+ if (!confidenceCacheable)
11504
+ reasons.push(`low_confidence:${input.confidence}`);
11505
+ if (stale)
11506
+ reasons.push("stale");
11507
+ if (input.authority === "unresolved")
11508
+ reasons.push("unresolved_authority");
11509
+ return {
11510
+ observed_at: input.observedAt.toISOString(),
11511
+ verified_at: input.ok ? input.now.toISOString() : null,
11512
+ expires_at: expiresAt,
11513
+ ttl_ms: typeof ttlMs === "number" && ttlMs > 0 ? ttlMs : null,
11514
+ source_authority: input.authority,
11515
+ confidence: input.confidence,
11516
+ cacheable,
11517
+ stale,
11518
+ reasons: [...new Set(reasons)].sort()
11519
+ };
11520
+ }
11521
+ function worstConfidence(values) {
11522
+ const rank = {
11523
+ exact: 0,
11524
+ high: 1,
11525
+ medium: 2,
11526
+ low: 3,
11527
+ none: 4
11528
+ };
11529
+ return [...values].sort((left, right) => rank[right] - rank[left])[0] ?? "none";
11530
+ }
11531
+ function mergeAuthorities(values) {
11532
+ const filtered = values.filter((value) => value !== "unknown");
11533
+ if (filtered.length === 0)
11534
+ return "unknown";
11535
+ const first = filtered[0];
11536
+ return filtered.every((value) => value === first) ? first : "mixed";
11537
+ }
11538
+ function mergeCacheability(input) {
11539
+ const confidence = worstConfidence(input.cacheabilities.map((entry) => entry.confidence));
11540
+ const reasons = input.cacheabilities.flatMap((entry) => entry.reasons);
11541
+ const ok = input.cacheabilities.every((entry) => entry.cacheable);
11542
+ return cacheability({
11543
+ ok,
11544
+ observedAt: input.observedAt,
11545
+ now: input.now,
11546
+ ttlMs: input.ttlMs,
11547
+ authority: mergeAuthorities(input.authorities),
11548
+ confidence,
11549
+ reasons
11550
+ });
11551
+ }
11415
11552
  function resolveMachineRoute(machineId, options = {}) {
11553
+ const now = options.now ?? new Date;
11416
11554
  const topology = options.topology ?? discoverMachineTopology(options);
11417
11555
  const warnings = [...topology.warnings];
11418
11556
  const { machine, matchedBy } = findRouteMachine(topology, machineId);
11419
- const generatedAt = (options.now ?? new Date).toISOString();
11557
+ const generatedAt = now.toISOString();
11420
11558
  if (!machine) {
11421
11559
  warnings.push(`machine_not_found:${machineId}`);
11422
11560
  return {
@@ -11440,16 +11578,27 @@ function resolveMachineRoute(machineId, options = {}) {
11440
11578
  tailscale_online: null,
11441
11579
  selected_hint: null
11442
11580
  },
11581
+ cacheability: cacheability({
11582
+ ok: false,
11583
+ observedAt: now,
11584
+ now,
11585
+ ttlMs: options.resolverTtlMs,
11586
+ authority: "unresolved",
11587
+ confidence: "none",
11588
+ reasons: [`machine_not_found:${machineId}`]
11589
+ }),
11443
11590
  warnings
11444
11591
  };
11445
11592
  }
11446
11593
  const selectedHint = selectRouteHint(machine.route_hints);
11447
11594
  const route = selectedHint?.kind ?? machine.ssh.route ?? "unknown";
11448
11595
  const local = route === "local" || machine.machine_id === topology.local_machine_id;
11596
+ const confidence = routeConfidence({ machine, hint: selectedHint, matchedBy });
11597
+ const ok = Boolean(selectedHint?.target);
11449
11598
  return {
11450
11599
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11451
11600
  package: topology.package,
11452
- ok: Boolean(selectedHint?.target),
11601
+ ok,
11453
11602
  machine_id: machine.machine_id,
11454
11603
  requested_machine_id: machineId,
11455
11604
  generated_at: generatedAt,
@@ -11457,7 +11606,7 @@ function resolveMachineRoute(machineId, options = {}) {
11457
11606
  source: route,
11458
11607
  target: selectedHint?.target ?? null,
11459
11608
  command_target: selectedHint?.target ?? null,
11460
- confidence: routeConfidence({ machine, hint: selectedHint, matchedBy }),
11609
+ confidence,
11461
11610
  local,
11462
11611
  evidence: {
11463
11612
  topology: true,
@@ -11467,6 +11616,15 @@ function resolveMachineRoute(machineId, options = {}) {
11467
11616
  tailscale_online: machine.tailscale.online,
11468
11617
  selected_hint: selectedHint
11469
11618
  },
11619
+ cacheability: cacheability({
11620
+ ok,
11621
+ observedAt: now,
11622
+ now,
11623
+ ttlMs: options.resolverTtlMs,
11624
+ authority: routeAuthority({ machine, selectedHint, matchedBy }),
11625
+ confidence,
11626
+ reasons: selectedHint ? [] : ["route_target_unresolved"]
11627
+ }),
11470
11628
  warnings
11471
11629
  };
11472
11630
  }
@@ -11763,10 +11921,11 @@ function metadataKeysForDiagnostics(metadata) {
11763
11921
  return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
11764
11922
  }
11765
11923
  function resolveMachineWorkspace(options) {
11924
+ const now = options.now ?? new Date;
11766
11925
  const topology = options.topology ?? discoverMachineTopology(options);
11767
11926
  const warnings = [...topology.warnings];
11768
11927
  const { machine, matchedBy } = findRouteMachine(topology, options.machineId);
11769
- const generatedAt = (options.now ?? new Date).toISOString();
11928
+ const generatedAt = now.toISOString();
11770
11929
  const repoName = options.repoName ?? options.projectId;
11771
11930
  const openFilesRepoName = options.openFilesRepoName ?? "open-files";
11772
11931
  if (!machine) {
@@ -11793,6 +11952,15 @@ function resolveMachineWorkspace(options) {
11793
11952
  manifest_declared: null,
11794
11953
  metadata_keys: []
11795
11954
  },
11955
+ cacheability: cacheability({
11956
+ ok: false,
11957
+ observedAt: now,
11958
+ now,
11959
+ ttlMs: options.resolverTtlMs,
11960
+ authority: "unresolved",
11961
+ confidence: "none",
11962
+ reasons: [`machine_not_found:${options.machineId}`]
11963
+ }),
11796
11964
  warnings
11797
11965
  };
11798
11966
  const diagnostics2 = workspaceDiagnostics({
@@ -11824,10 +11992,16 @@ function resolveMachineWorkspace(options) {
11824
11992
  warnings.push(`open_files_root_inferred:${options.projectId}`);
11825
11993
  if (!projectRootPath)
11826
11994
  warnings.push(`project_root_unresolved:${options.projectId}`);
11995
+ const workspacePaths = {
11996
+ workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
11997
+ project_root: { path: projectRootPath, source: projectRootSource },
11998
+ open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
11999
+ };
12000
+ const workspaceOk = Boolean(projectRootPath);
11827
12001
  const resolution = {
11828
12002
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
11829
12003
  package: topology.package,
11830
- ok: Boolean(projectRootPath),
12004
+ ok: workspaceOk,
11831
12005
  requested_machine_id: options.machineId,
11832
12006
  machine_id: machine.machine_id,
11833
12007
  generated_at: generatedAt,
@@ -11842,11 +12016,7 @@ function resolveMachineWorkspace(options) {
11842
12016
  trust_status: trustStatus(machine),
11843
12017
  auth_status: authStatus(machine)
11844
12018
  },
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
- },
12019
+ paths: workspacePaths,
11850
12020
  diagnostics: [],
11851
12021
  repair_hints: [],
11852
12022
  evidence: {
@@ -11855,6 +12025,15 @@ function resolveMachineWorkspace(options) {
11855
12025
  manifest_declared: machine.manifest_declared,
11856
12026
  metadata_keys: metadataKeysForDiagnostics(metadata)
11857
12027
  },
12028
+ cacheability: cacheability({
12029
+ ok: workspaceOk,
12030
+ observedAt: now,
12031
+ now,
12032
+ ttlMs: options.resolverTtlMs,
12033
+ authority: workspaceAuthority(workspacePaths),
12034
+ confidence: workspaceOk ? "medium" : "none",
12035
+ reasons: projectRootPath ? [] : [`project_root_unresolved:${options.projectId}`]
12036
+ }),
11858
12037
  warnings
11859
12038
  };
11860
12039
  const diagnostics = workspaceDiagnostics({
@@ -11869,6 +12048,73 @@ function resolveMachineWorkspace(options) {
11869
12048
  repair_hints: diagnostics.repairHints
11870
12049
  };
11871
12050
  }
12051
+ function createMachineResolverSnapshot(options) {
12052
+ const now = options.now ?? new Date;
12053
+ const routeObservedAt = new Date(options.route.generated_at);
12054
+ const workspaceObservedAt = options.workspace ? new Date(options.workspace.generated_at) : null;
12055
+ const observedAt = new Date(Math.max(Number.isNaN(routeObservedAt.getTime()) ? 0 : routeObservedAt.getTime(), workspaceObservedAt && !Number.isNaN(workspaceObservedAt.getTime()) ? workspaceObservedAt.getTime() : 0));
12056
+ const cacheabilities = [options.route.cacheability, options.workspace?.cacheability].filter((entry) => Boolean(entry));
12057
+ const authorities = cacheabilities.map((entry) => entry.source_authority);
12058
+ const warnings = [...new Set([
12059
+ ...options.route.warnings,
12060
+ ...options.workspace?.warnings ?? [],
12061
+ ...cacheabilities.flatMap((entry) => entry.reasons)
12062
+ ])].sort();
12063
+ return {
12064
+ schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
12065
+ package: options.route.package,
12066
+ generated_at: now.toISOString(),
12067
+ requested_machine_id: options.route.requested_machine_id,
12068
+ machine_id: options.route.machine_id ?? options.workspace?.machine_id ?? null,
12069
+ route: {
12070
+ ok: options.route.ok,
12071
+ source: options.route.source,
12072
+ route: options.route.route,
12073
+ target: options.route.target,
12074
+ command_target: options.route.command_target,
12075
+ confidence: options.route.confidence,
12076
+ local: options.route.local,
12077
+ cacheability: options.route.cacheability
12078
+ },
12079
+ workspace: options.workspace ? {
12080
+ ok: options.workspace.ok,
12081
+ project: options.workspace.project,
12082
+ machine: options.workspace.machine,
12083
+ paths: options.workspace.paths,
12084
+ diagnostics: options.workspace.diagnostics,
12085
+ repair_hints: options.workspace.repair_hints,
12086
+ cacheability: options.workspace.cacheability
12087
+ } : null,
12088
+ cacheability: mergeCacheability({
12089
+ observedAt: observedAt.getTime() > 0 ? observedAt : now,
12090
+ now,
12091
+ ttlMs: options.resolverTtlMs,
12092
+ authorities,
12093
+ cacheabilities
12094
+ }),
12095
+ warnings,
12096
+ provenance: {
12097
+ route: {
12098
+ schema_version: options.route.schema_version,
12099
+ generated_at: options.route.generated_at,
12100
+ evidence: {
12101
+ matched_by: options.route.evidence.matched_by,
12102
+ manifest_declared: options.route.evidence.manifest_declared,
12103
+ heartbeat_status: options.route.evidence.heartbeat_status,
12104
+ tailscale_online: options.route.evidence.tailscale_online,
12105
+ selected_hint_kind: options.route.evidence.selected_hint?.kind ?? null
12106
+ }
12107
+ },
12108
+ workspace: options.workspace ? {
12109
+ schema_version: options.workspace.schema_version,
12110
+ generated_at: options.workspace.generated_at,
12111
+ metadata_keys: options.workspace.evidence.metadata_keys,
12112
+ matched_by: options.workspace.evidence.matched_by,
12113
+ manifest_declared: options.workspace.evidence.manifest_declared
12114
+ } : null
12115
+ }
12116
+ };
12117
+ }
11872
12118
  function getLocalMachineTopology(options = {}) {
11873
12119
  const topology = discoverMachineTopology(options);
11874
12120
  return topology.machines.find((machine) => machine.machine_id === topology.local_machine_id) ?? {
@@ -23125,6 +23371,7 @@ export {
23125
23371
  diffApps,
23126
23372
  detectCurrentMachineManifest,
23127
23373
  createMcpServer,
23374
+ createMachineResolverSnapshot,
23128
23375
  countRuns,
23129
23376
  closeDb,
23130
23377
  checkMachineCompatibility,
@@ -23150,6 +23397,9 @@ export {
23150
23397
  MACHINES_STORAGE_FALLBACK_ENV,
23151
23398
  MACHINES_STORAGE_ENV,
23152
23399
  MACHINES_PACKAGE_NAME,
23400
+ MACHINES_CONSUMER_SCHEMA_URI,
23401
+ MACHINES_CONSUMER_SCHEMA_ARTIFACT,
23402
+ MACHINES_CONSUMER_FIELD_CAPABILITIES,
23153
23403
  MACHINES_CONSUMER_ENTRYPOINT,
23154
23404
  MACHINES_CONSUMER_CONTRACT_VERSION,
23155
23405
  MACHINES_CONSUMER_CONTRACT,
@@ -23158,6 +23408,7 @@ export {
23158
23408
  MACHINES_BACKUP_PREFIX_ENV,
23159
23409
  MACHINES_BACKUP_BUCKET_FALLBACK_ENV,
23160
23410
  MACHINES_BACKUP_BUCKET_ENV,
23411
+ DEFAULT_MACHINE_RESOLVER_TTL_MS,
23161
23412
  DEFAULT_BACKUP_PREFIX,
23162
23413
  CROSSREFS_KEY
23163
23414
  };
package/dist/mcp/index.js CHANGED
@@ -4370,13 +4370,18 @@ import { arch as arch2, hostname as hostname3, platform as platform2, userInfo a
4370
4370
  import { spawnSync } from "child_process";
4371
4371
  var MACHINES_CONSUMER_CONTRACT_VERSION = 1;
4372
4372
  var MACHINES_PACKAGE_NAME = "@hasna/machines";
4373
+ var DEFAULT_MACHINE_RESOLVER_TTL_MS = 24 * 60 * 60 * 1000;
4373
4374
  var MACHINES_CONSUMER_CAPABILITIES = {
4374
4375
  topology: true,
4375
4376
  compatibility: true,
4376
4377
  route_resolution: true,
4377
4378
  cli_json_fallback: true,
4378
4379
  workspace_path_mapping: true,
4379
- workspace_diagnostics: true
4380
+ workspace_diagnostics: true,
4381
+ schema_artifacts: true,
4382
+ cacheability_metadata: true,
4383
+ resolver_snapshots: true,
4384
+ field_capability_descriptors: true
4380
4385
  };
4381
4386
  function getMachinesConsumerCapabilities() {
4382
4387
  return { ...MACHINES_CONSUMER_CAPABILITIES };
@@ -4647,11 +4652,69 @@ function routeConfidence(input) {
4647
4652
  return "low";
4648
4653
  return "none";
4649
4654
  }
4655
+ function addMilliseconds(date, milliseconds) {
4656
+ return new Date(date.getTime() + milliseconds).toISOString();
4657
+ }
4658
+ function routeAuthority(input) {
4659
+ if (!input.machine)
4660
+ return "unresolved";
4661
+ if (input.matchedBy === "fallback")
4662
+ return "fallback";
4663
+ if (input.selectedHint?.kind === "local")
4664
+ return "live_topology";
4665
+ if (input.selectedHint?.kind === "tailscale" || input.machine.tailscale.online !== null)
4666
+ return "live_topology";
4667
+ if (input.machine.manifest_declared)
4668
+ return "manifest";
4669
+ return "open-machines";
4670
+ }
4671
+ function workspaceAuthority(paths) {
4672
+ const sources = [paths.workspace_root.source, paths.project_root.source, paths.open_files_root.source];
4673
+ if (sources.some((source) => source === "argument"))
4674
+ return "argument";
4675
+ if (sources.some((source) => source === "manifest_metadata"))
4676
+ return "manifest_metadata";
4677
+ if (sources.some((source) => source === "manifest"))
4678
+ return "manifest";
4679
+ if (sources.some((source) => source === "inferred"))
4680
+ return "inferred";
4681
+ if (sources.every((source) => source === "unresolved"))
4682
+ return "unresolved";
4683
+ return "open-machines";
4684
+ }
4685
+ function cacheability(input) {
4686
+ const ttlMs = input.ttlMs === undefined ? DEFAULT_MACHINE_RESOLVER_TTL_MS : input.ttlMs;
4687
+ const expiresAt = typeof ttlMs === "number" && ttlMs > 0 ? addMilliseconds(input.observedAt, ttlMs) : null;
4688
+ const stale = expiresAt ? input.now.getTime() > new Date(expiresAt).getTime() : false;
4689
+ const confidenceCacheable = input.confidence !== "none" && input.confidence !== "low";
4690
+ const cacheable = input.ok && confidenceCacheable && !stale && input.authority !== "unresolved";
4691
+ const reasons = [...input.reasons];
4692
+ if (!input.ok)
4693
+ reasons.push("resolver_not_ok");
4694
+ if (!confidenceCacheable)
4695
+ reasons.push(`low_confidence:${input.confidence}`);
4696
+ if (stale)
4697
+ reasons.push("stale");
4698
+ if (input.authority === "unresolved")
4699
+ reasons.push("unresolved_authority");
4700
+ return {
4701
+ observed_at: input.observedAt.toISOString(),
4702
+ verified_at: input.ok ? input.now.toISOString() : null,
4703
+ expires_at: expiresAt,
4704
+ ttl_ms: typeof ttlMs === "number" && ttlMs > 0 ? ttlMs : null,
4705
+ source_authority: input.authority,
4706
+ confidence: input.confidence,
4707
+ cacheable,
4708
+ stale,
4709
+ reasons: [...new Set(reasons)].sort()
4710
+ };
4711
+ }
4650
4712
  function resolveMachineRoute(machineId, options = {}) {
4713
+ const now = options.now ?? new Date;
4651
4714
  const topology = options.topology ?? discoverMachineTopology(options);
4652
4715
  const warnings = [...topology.warnings];
4653
4716
  const { machine, matchedBy } = findRouteMachine(topology, machineId);
4654
- const generatedAt = (options.now ?? new Date).toISOString();
4717
+ const generatedAt = now.toISOString();
4655
4718
  if (!machine) {
4656
4719
  warnings.push(`machine_not_found:${machineId}`);
4657
4720
  return {
@@ -4675,16 +4738,27 @@ function resolveMachineRoute(machineId, options = {}) {
4675
4738
  tailscale_online: null,
4676
4739
  selected_hint: null
4677
4740
  },
4741
+ cacheability: cacheability({
4742
+ ok: false,
4743
+ observedAt: now,
4744
+ now,
4745
+ ttlMs: options.resolverTtlMs,
4746
+ authority: "unresolved",
4747
+ confidence: "none",
4748
+ reasons: [`machine_not_found:${machineId}`]
4749
+ }),
4678
4750
  warnings
4679
4751
  };
4680
4752
  }
4681
4753
  const selectedHint = selectRouteHint(machine.route_hints);
4682
4754
  const route = selectedHint?.kind ?? machine.ssh.route ?? "unknown";
4683
4755
  const local = route === "local" || machine.machine_id === topology.local_machine_id;
4756
+ const confidence = routeConfidence({ machine, hint: selectedHint, matchedBy });
4757
+ const ok = Boolean(selectedHint?.target);
4684
4758
  return {
4685
4759
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
4686
4760
  package: topology.package,
4687
- ok: Boolean(selectedHint?.target),
4761
+ ok,
4688
4762
  machine_id: machine.machine_id,
4689
4763
  requested_machine_id: machineId,
4690
4764
  generated_at: generatedAt,
@@ -4692,7 +4766,7 @@ function resolveMachineRoute(machineId, options = {}) {
4692
4766
  source: route,
4693
4767
  target: selectedHint?.target ?? null,
4694
4768
  command_target: selectedHint?.target ?? null,
4695
- confidence: routeConfidence({ machine, hint: selectedHint, matchedBy }),
4769
+ confidence,
4696
4770
  local,
4697
4771
  evidence: {
4698
4772
  topology: true,
@@ -4702,6 +4776,15 @@ function resolveMachineRoute(machineId, options = {}) {
4702
4776
  tailscale_online: machine.tailscale.online,
4703
4777
  selected_hint: selectedHint
4704
4778
  },
4779
+ cacheability: cacheability({
4780
+ ok,
4781
+ observedAt: now,
4782
+ now,
4783
+ ttlMs: options.resolverTtlMs,
4784
+ authority: routeAuthority({ machine, selectedHint, matchedBy }),
4785
+ confidence,
4786
+ reasons: selectedHint ? [] : ["route_target_unresolved"]
4787
+ }),
4705
4788
  warnings
4706
4789
  };
4707
4790
  }
@@ -4998,10 +5081,11 @@ function metadataKeysForDiagnostics(metadata) {
4998
5081
  return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
4999
5082
  }
5000
5083
  function resolveMachineWorkspace(options) {
5084
+ const now = options.now ?? new Date;
5001
5085
  const topology = options.topology ?? discoverMachineTopology(options);
5002
5086
  const warnings = [...topology.warnings];
5003
5087
  const { machine, matchedBy } = findRouteMachine(topology, options.machineId);
5004
- const generatedAt = (options.now ?? new Date).toISOString();
5088
+ const generatedAt = now.toISOString();
5005
5089
  const repoName = options.repoName ?? options.projectId;
5006
5090
  const openFilesRepoName = options.openFilesRepoName ?? "open-files";
5007
5091
  if (!machine) {
@@ -5028,6 +5112,15 @@ function resolveMachineWorkspace(options) {
5028
5112
  manifest_declared: null,
5029
5113
  metadata_keys: []
5030
5114
  },
5115
+ cacheability: cacheability({
5116
+ ok: false,
5117
+ observedAt: now,
5118
+ now,
5119
+ ttlMs: options.resolverTtlMs,
5120
+ authority: "unresolved",
5121
+ confidence: "none",
5122
+ reasons: [`machine_not_found:${options.machineId}`]
5123
+ }),
5031
5124
  warnings
5032
5125
  };
5033
5126
  const diagnostics2 = workspaceDiagnostics({
@@ -5059,10 +5152,16 @@ function resolveMachineWorkspace(options) {
5059
5152
  warnings.push(`open_files_root_inferred:${options.projectId}`);
5060
5153
  if (!projectRootPath)
5061
5154
  warnings.push(`project_root_unresolved:${options.projectId}`);
5155
+ const workspacePaths = {
5156
+ workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
5157
+ project_root: { path: projectRootPath, source: projectRootSource },
5158
+ open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
5159
+ };
5160
+ const workspaceOk = Boolean(projectRootPath);
5062
5161
  const resolution = {
5063
5162
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
5064
5163
  package: topology.package,
5065
- ok: Boolean(projectRootPath),
5164
+ ok: workspaceOk,
5066
5165
  requested_machine_id: options.machineId,
5067
5166
  machine_id: machine.machine_id,
5068
5167
  generated_at: generatedAt,
@@ -5077,11 +5176,7 @@ function resolveMachineWorkspace(options) {
5077
5176
  trust_status: trustStatus(machine),
5078
5177
  auth_status: authStatus(machine)
5079
5178
  },
5080
- paths: {
5081
- workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
5082
- project_root: { path: projectRootPath, source: projectRootSource },
5083
- open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
5084
- },
5179
+ paths: workspacePaths,
5085
5180
  diagnostics: [],
5086
5181
  repair_hints: [],
5087
5182
  evidence: {
@@ -5090,6 +5185,15 @@ function resolveMachineWorkspace(options) {
5090
5185
  manifest_declared: machine.manifest_declared,
5091
5186
  metadata_keys: metadataKeysForDiagnostics(metadata)
5092
5187
  },
5188
+ cacheability: cacheability({
5189
+ ok: workspaceOk,
5190
+ observedAt: now,
5191
+ now,
5192
+ ttlMs: options.resolverTtlMs,
5193
+ authority: workspaceAuthority(workspacePaths),
5194
+ confidence: workspaceOk ? "medium" : "none",
5195
+ reasons: projectRootPath ? [] : [`project_root_unresolved:${options.projectId}`]
5196
+ }),
5093
5197
  warnings
5094
5198
  };
5095
5199
  const diagnostics = workspaceDiagnostics({