@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/README.md +23 -5
- package/dist/cli/index.js +115 -11
- package/dist/consumer-schema.d.ts +21 -0
- package/dist/consumer-schema.d.ts.map +1 -0
- package/dist/consumer.d.ts +4 -2
- package/dist/consumer.d.ts.map +1 -1
- package/dist/consumer.js +498 -13
- package/dist/index.js +263 -12
- package/dist/mcp/index.js +115 -11
- package/dist/topology.d.ts +117 -1
- package/dist/topology.d.ts.map +1 -1
- package/package.json +2 -1
- package/schemas/machines-consumer.schema.json +47 -0
- package/scripts/consumer-conformance.mjs +27 -2
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
};
|