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