@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/README.md +35 -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 +4 -1
- package/schemas/machines-consumer.schema.json +47 -0
- package/scripts/consumer-conformance.mjs +430 -0
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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({
|