@hasna/machines 0.0.18 → 0.0.20
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 +56 -8
- package/dist/cli/index.js +307 -20
- package/dist/commands/backup.d.ts +17 -2
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/compatibility.d.ts.map +1 -1
- package/dist/consumer.d.ts +2 -2
- package/dist/consumer.d.ts.map +1 -1
- package/dist/consumer.js +252 -13
- package/dist/index.js +343 -17
- package/dist/manifests.d.ts +8 -0
- package/dist/manifests.d.ts.map +1 -1
- package/dist/mcp/index.js +311 -21
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/topology.d.ts +65 -0
- package/dist/topology.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/consumer.js
CHANGED
|
@@ -4212,6 +4212,7 @@ var machineSchema = exports_external.object({
|
|
|
4212
4212
|
workspacePath: exports_external.string(),
|
|
4213
4213
|
bunPath: exports_external.string().optional(),
|
|
4214
4214
|
tags: exports_external.array(exports_external.string()).optional(),
|
|
4215
|
+
metadata: exports_external.record(exports_external.unknown()).optional(),
|
|
4215
4216
|
packages: exports_external.array(packageSchema).optional(),
|
|
4216
4217
|
apps: exports_external.array(appSchema).optional(),
|
|
4217
4218
|
files: exports_external.array(fileSchema).optional()
|
|
@@ -4310,6 +4311,40 @@ function getPackageVersion() {
|
|
|
4310
4311
|
// src/topology.ts
|
|
4311
4312
|
var MACHINES_CONSUMER_CONTRACT_VERSION = 1;
|
|
4312
4313
|
var MACHINES_PACKAGE_NAME = "@hasna/machines";
|
|
4314
|
+
var MACHINES_CONSUMER_ENTRYPOINT = "@hasna/machines/consumer";
|
|
4315
|
+
var MACHINES_CONSUMER_CAPABILITIES = {
|
|
4316
|
+
topology: true,
|
|
4317
|
+
compatibility: true,
|
|
4318
|
+
route_resolution: true,
|
|
4319
|
+
cli_json_fallback: true,
|
|
4320
|
+
workspace_path_mapping: true
|
|
4321
|
+
};
|
|
4322
|
+
var MACHINES_CONSUMER_CONTRACT = {
|
|
4323
|
+
schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
|
|
4324
|
+
package_name: MACHINES_PACKAGE_NAME,
|
|
4325
|
+
entrypoint: MACHINES_CONSUMER_ENTRYPOINT,
|
|
4326
|
+
capabilities: MACHINES_CONSUMER_CAPABILITIES,
|
|
4327
|
+
envelopes: ["topology", "route", "workspace", "compatibility"],
|
|
4328
|
+
stable_exports: [
|
|
4329
|
+
"MACHINES_CONSUMER_CONTRACT",
|
|
4330
|
+
"MACHINES_CONSUMER_CONTRACT_VERSION",
|
|
4331
|
+
"MACHINES_CONSUMER_CAPABILITIES",
|
|
4332
|
+
"MACHINES_PACKAGE_NAME",
|
|
4333
|
+
"discoverMachineTopology",
|
|
4334
|
+
"getLocalMachineTopology",
|
|
4335
|
+
"resolveMachineRoute",
|
|
4336
|
+
"resolveMachineWorkspace",
|
|
4337
|
+
"checkMachineCompatibility",
|
|
4338
|
+
"resolveMachineCommand",
|
|
4339
|
+
"runMachineCommand",
|
|
4340
|
+
"buildSshCommand",
|
|
4341
|
+
"resolveSshTarget",
|
|
4342
|
+
"getPackageVersion"
|
|
4343
|
+
]
|
|
4344
|
+
};
|
|
4345
|
+
function getMachinesConsumerCapabilities() {
|
|
4346
|
+
return { ...MACHINES_CONSUMER_CAPABILITIES };
|
|
4347
|
+
}
|
|
4313
4348
|
function normalizePlatform2(value = platform2()) {
|
|
4314
4349
|
const normalized = value.toLowerCase();
|
|
4315
4350
|
if (normalized === "darwin" || normalized === "macos")
|
|
@@ -4510,12 +4545,7 @@ function discoverMachineTopology(options = {}) {
|
|
|
4510
4545
|
name: MACHINES_PACKAGE_NAME,
|
|
4511
4546
|
version: getPackageVersion()
|
|
4512
4547
|
},
|
|
4513
|
-
capabilities:
|
|
4514
|
-
topology: true,
|
|
4515
|
-
compatibility: true,
|
|
4516
|
-
route_resolution: true,
|
|
4517
|
-
cli_json_fallback: true
|
|
4518
|
-
},
|
|
4548
|
+
capabilities: getMachinesConsumerCapabilities(),
|
|
4519
4549
|
generated_at: now.toISOString(),
|
|
4520
4550
|
local_machine_id: localMachineId,
|
|
4521
4551
|
local_hostname: hostname3(),
|
|
@@ -4639,6 +4669,215 @@ function resolveMachineRoute(machineId, options = {}) {
|
|
|
4639
4669
|
warnings
|
|
4640
4670
|
};
|
|
4641
4671
|
}
|
|
4672
|
+
function isRecord(value) {
|
|
4673
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4674
|
+
}
|
|
4675
|
+
function metadataString(metadata, keys) {
|
|
4676
|
+
for (const key of keys) {
|
|
4677
|
+
const value = metadata[key];
|
|
4678
|
+
if (typeof value === "string" && value.trim())
|
|
4679
|
+
return value.trim();
|
|
4680
|
+
}
|
|
4681
|
+
return null;
|
|
4682
|
+
}
|
|
4683
|
+
function metadataBoolean(metadata, keys) {
|
|
4684
|
+
for (const key of keys) {
|
|
4685
|
+
const value = metadata[key];
|
|
4686
|
+
if (typeof value === "boolean")
|
|
4687
|
+
return value;
|
|
4688
|
+
}
|
|
4689
|
+
return null;
|
|
4690
|
+
}
|
|
4691
|
+
function metadataStringArray(metadata, keys) {
|
|
4692
|
+
for (const key of keys) {
|
|
4693
|
+
const value = metadata[key];
|
|
4694
|
+
if (Array.isArray(value))
|
|
4695
|
+
return value.filter((entry) => typeof entry === "string");
|
|
4696
|
+
}
|
|
4697
|
+
return [];
|
|
4698
|
+
}
|
|
4699
|
+
function readMappedPath(input) {
|
|
4700
|
+
for (const containerName of input.containers) {
|
|
4701
|
+
const container = input.metadata[containerName];
|
|
4702
|
+
if (!isRecord(container))
|
|
4703
|
+
continue;
|
|
4704
|
+
for (const key of input.keys) {
|
|
4705
|
+
const value = container[key];
|
|
4706
|
+
if (typeof value === "string" && value.trim())
|
|
4707
|
+
return value.trim();
|
|
4708
|
+
if (isRecord(value)) {
|
|
4709
|
+
const path = metadataString(value, ["path", "root", "workspacePath", "workspace_path"]);
|
|
4710
|
+
if (path)
|
|
4711
|
+
return path;
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4715
|
+
return null;
|
|
4716
|
+
}
|
|
4717
|
+
function trimTrailingSlash(value) {
|
|
4718
|
+
return value.replace(/\/+$/, "");
|
|
4719
|
+
}
|
|
4720
|
+
function joinPath(left, right) {
|
|
4721
|
+
return `${trimTrailingSlash(left)}/${right.replace(/^\/+/, "")}`;
|
|
4722
|
+
}
|
|
4723
|
+
function inferRepoRoot(workspaceRoot, repoName) {
|
|
4724
|
+
if (!workspaceRoot || !repoName)
|
|
4725
|
+
return null;
|
|
4726
|
+
const root = trimTrailingSlash(workspaceRoot);
|
|
4727
|
+
if (root.endsWith(`/${repoName}`) || root === repoName)
|
|
4728
|
+
return root;
|
|
4729
|
+
if (root.endsWith("/workspace") || root.endsWith("/Workspace")) {
|
|
4730
|
+
return joinPath(root, `hasna/opensource/${repoName}`);
|
|
4731
|
+
}
|
|
4732
|
+
return joinPath(root, repoName);
|
|
4733
|
+
}
|
|
4734
|
+
function projectPathFromMetadata(metadata, projectId, repoName) {
|
|
4735
|
+
const keys = [projectId, repoName].filter((value) => Boolean(value));
|
|
4736
|
+
return readMappedPath({
|
|
4737
|
+
metadata,
|
|
4738
|
+
containers: ["workspace_paths", "workspacePaths", "repo_paths", "repoPaths", "project_paths", "projectPaths", "projects"],
|
|
4739
|
+
keys
|
|
4740
|
+
});
|
|
4741
|
+
}
|
|
4742
|
+
function openFilesPathFromMetadata(metadata, projectId, repoName) {
|
|
4743
|
+
const direct = metadataString(metadata, ["open_files_root", "openFilesRoot", "open_files_path", "openFilesPath"]);
|
|
4744
|
+
if (direct)
|
|
4745
|
+
return direct;
|
|
4746
|
+
const keys = [projectId, repoName, "open-files", "open_files", "default"].filter((value) => Boolean(value));
|
|
4747
|
+
return readMappedPath({
|
|
4748
|
+
metadata,
|
|
4749
|
+
containers: ["open_files_roots", "openFilesRoots", "open_files_paths", "openFilesPaths"],
|
|
4750
|
+
keys
|
|
4751
|
+
});
|
|
4752
|
+
}
|
|
4753
|
+
function trustStatus(machine) {
|
|
4754
|
+
if (!machine)
|
|
4755
|
+
return "unknown";
|
|
4756
|
+
const explicit = metadataString(machine.metadata, ["trust_status", "trustStatus"]);
|
|
4757
|
+
if (explicit === "trusted" || explicit === "untrusted" || explicit === "unknown")
|
|
4758
|
+
return explicit;
|
|
4759
|
+
const trusted = metadataBoolean(machine.metadata, ["trusted", "syncTrusted", "sync_trusted"]);
|
|
4760
|
+
if (trusted === true)
|
|
4761
|
+
return "trusted";
|
|
4762
|
+
if (trusted === false)
|
|
4763
|
+
return "untrusted";
|
|
4764
|
+
if (machine.route_hints.some((hint) => hint.kind === "local"))
|
|
4765
|
+
return "trusted";
|
|
4766
|
+
if (machine.tags.includes("trusted"))
|
|
4767
|
+
return "trusted";
|
|
4768
|
+
return "unknown";
|
|
4769
|
+
}
|
|
4770
|
+
function authStatus(machine) {
|
|
4771
|
+
if (!machine)
|
|
4772
|
+
return "unknown";
|
|
4773
|
+
const explicit = metadataString(machine.metadata, ["auth_status", "authStatus"]);
|
|
4774
|
+
if (explicit === "authenticated" || explicit === "unauthenticated" || explicit === "unknown")
|
|
4775
|
+
return explicit;
|
|
4776
|
+
const authenticated = metadataBoolean(machine.metadata, ["authenticated", "sshAuthorized", "ssh_authorized"]);
|
|
4777
|
+
if (authenticated === true)
|
|
4778
|
+
return "authenticated";
|
|
4779
|
+
if (authenticated === false)
|
|
4780
|
+
return "unauthenticated";
|
|
4781
|
+
if (machine.route_hints.some((hint) => hint.kind === "local"))
|
|
4782
|
+
return "authenticated";
|
|
4783
|
+
return "unknown";
|
|
4784
|
+
}
|
|
4785
|
+
function primaryMachine(machine, projectId, primaryMachineId) {
|
|
4786
|
+
if (!machine)
|
|
4787
|
+
return false;
|
|
4788
|
+
if (primaryMachineId)
|
|
4789
|
+
return machine.machine_id === primaryMachineId;
|
|
4790
|
+
if (metadataBoolean(machine.metadata, ["primary", "primary_machine", "primaryMachine"]) === true)
|
|
4791
|
+
return true;
|
|
4792
|
+
const primaryProjects = metadataStringArray(machine.metadata, ["primary_projects", "primaryProjects"]);
|
|
4793
|
+
if (primaryProjects.includes(projectId))
|
|
4794
|
+
return true;
|
|
4795
|
+
return machine.tags.includes("primary");
|
|
4796
|
+
}
|
|
4797
|
+
function metadataKeysForDiagnostics(metadata) {
|
|
4798
|
+
return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
|
|
4799
|
+
}
|
|
4800
|
+
function resolveMachineWorkspace(options) {
|
|
4801
|
+
const topology = options.topology ?? discoverMachineTopology(options);
|
|
4802
|
+
const warnings = [...topology.warnings];
|
|
4803
|
+
const { machine, matchedBy } = findRouteMachine(topology, options.machineId);
|
|
4804
|
+
const generatedAt = (options.now ?? new Date).toISOString();
|
|
4805
|
+
const repoName = options.repoName ?? options.projectId;
|
|
4806
|
+
const openFilesRepoName = options.openFilesRepoName ?? "open-files";
|
|
4807
|
+
if (!machine) {
|
|
4808
|
+
warnings.push(`machine_not_found:${options.machineId}`);
|
|
4809
|
+
return {
|
|
4810
|
+
schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
|
|
4811
|
+
package: topology.package,
|
|
4812
|
+
ok: false,
|
|
4813
|
+
requested_machine_id: options.machineId,
|
|
4814
|
+
machine_id: null,
|
|
4815
|
+
generated_at: generatedAt,
|
|
4816
|
+
project: { project_id: options.projectId, repo_name: repoName, canonical: Boolean(options.projectId) },
|
|
4817
|
+
machine: { current: false, primary: false, trust_status: "unknown", auth_status: "unknown" },
|
|
4818
|
+
paths: {
|
|
4819
|
+
workspace_root: { path: null, source: "unresolved" },
|
|
4820
|
+
project_root: { path: null, source: "unresolved" },
|
|
4821
|
+
open_files_root: { path: null, source: "unresolved" }
|
|
4822
|
+
},
|
|
4823
|
+
evidence: {
|
|
4824
|
+
topology: true,
|
|
4825
|
+
matched_by: matchedBy,
|
|
4826
|
+
manifest_declared: null,
|
|
4827
|
+
metadata_keys: []
|
|
4828
|
+
},
|
|
4829
|
+
warnings
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
const metadata = machine.metadata;
|
|
4833
|
+
const workspaceRootPath = options.workspaceRoot ?? machine.workspace_path;
|
|
4834
|
+
const workspaceRootSource = options.workspaceRoot ? "argument" : machine.workspace_path ? "manifest" : "unresolved";
|
|
4835
|
+
const metadataProjectRoot = projectPathFromMetadata(metadata, options.projectId, repoName);
|
|
4836
|
+
const inferredProjectRoot = inferRepoRoot(workspaceRootPath, repoName);
|
|
4837
|
+
const projectRootPath = options.projectRoot ?? metadataProjectRoot ?? inferredProjectRoot;
|
|
4838
|
+
const projectRootSource = options.projectRoot ? "argument" : metadataProjectRoot ? "manifest_metadata" : inferredProjectRoot ? "inferred" : "unresolved";
|
|
4839
|
+
const metadataOpenFilesRoot = openFilesPathFromMetadata(metadata, options.projectId, openFilesRepoName);
|
|
4840
|
+
const inferredOpenFilesRoot = inferRepoRoot(workspaceRootPath, openFilesRepoName);
|
|
4841
|
+
const openFilesRootPath = options.openFilesRoot ?? metadataOpenFilesRoot ?? inferredOpenFilesRoot;
|
|
4842
|
+
const openFilesRootSource = options.openFilesRoot ? "argument" : metadataOpenFilesRoot ? "manifest_metadata" : inferredOpenFilesRoot ? "inferred" : "unresolved";
|
|
4843
|
+
if (projectRootSource === "inferred")
|
|
4844
|
+
warnings.push(`project_root_inferred:${options.projectId}`);
|
|
4845
|
+
if (openFilesRootSource === "inferred")
|
|
4846
|
+
warnings.push(`open_files_root_inferred:${options.projectId}`);
|
|
4847
|
+
if (!projectRootPath)
|
|
4848
|
+
warnings.push(`project_root_unresolved:${options.projectId}`);
|
|
4849
|
+
return {
|
|
4850
|
+
schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
|
|
4851
|
+
package: topology.package,
|
|
4852
|
+
ok: Boolean(projectRootPath),
|
|
4853
|
+
requested_machine_id: options.machineId,
|
|
4854
|
+
machine_id: machine.machine_id,
|
|
4855
|
+
generated_at: generatedAt,
|
|
4856
|
+
project: {
|
|
4857
|
+
project_id: options.projectId,
|
|
4858
|
+
repo_name: repoName,
|
|
4859
|
+
canonical: Boolean(options.projectId && repoName)
|
|
4860
|
+
},
|
|
4861
|
+
machine: {
|
|
4862
|
+
current: machine.machine_id === topology.local_machine_id,
|
|
4863
|
+
primary: primaryMachine(machine, options.projectId, options.primaryMachineId),
|
|
4864
|
+
trust_status: trustStatus(machine),
|
|
4865
|
+
auth_status: authStatus(machine)
|
|
4866
|
+
},
|
|
4867
|
+
paths: {
|
|
4868
|
+
workspace_root: { path: workspaceRootPath, source: workspaceRootSource },
|
|
4869
|
+
project_root: { path: projectRootPath, source: projectRootSource },
|
|
4870
|
+
open_files_root: { path: openFilesRootPath, source: openFilesRootSource }
|
|
4871
|
+
},
|
|
4872
|
+
evidence: {
|
|
4873
|
+
topology: true,
|
|
4874
|
+
matched_by: matchedBy,
|
|
4875
|
+
manifest_declared: machine.manifest_declared,
|
|
4876
|
+
metadata_keys: metadataKeysForDiagnostics(metadata)
|
|
4877
|
+
},
|
|
4878
|
+
warnings
|
|
4879
|
+
};
|
|
4880
|
+
}
|
|
4642
4881
|
function getLocalMachineTopology(options = {}) {
|
|
4643
4882
|
const topology = discoverMachineTopology(options);
|
|
4644
4883
|
return topology.machines.find((machine) => machine.machine_id === topology.local_machine_id) ?? {
|
|
@@ -4957,12 +5196,7 @@ function checkMachineCompatibility(options = {}) {
|
|
|
4957
5196
|
name: MACHINES_PACKAGE_NAME,
|
|
4958
5197
|
version: getPackageVersion()
|
|
4959
5198
|
},
|
|
4960
|
-
capabilities:
|
|
4961
|
-
topology: true,
|
|
4962
|
-
compatibility: true,
|
|
4963
|
-
route_resolution: true,
|
|
4964
|
-
cli_json_fallback: true
|
|
4965
|
-
},
|
|
5199
|
+
capabilities: getMachinesConsumerCapabilities(),
|
|
4966
5200
|
ok: summary.fail === 0,
|
|
4967
5201
|
machine_id: machineId,
|
|
4968
5202
|
source: checks[0]?.source ?? "local",
|
|
@@ -4974,13 +5208,18 @@ function checkMachineCompatibility(options = {}) {
|
|
|
4974
5208
|
export {
|
|
4975
5209
|
runMachineCommand,
|
|
4976
5210
|
resolveSshTarget,
|
|
5211
|
+
resolveMachineWorkspace,
|
|
4977
5212
|
resolveMachineRoute,
|
|
4978
5213
|
resolveMachineCommand,
|
|
4979
5214
|
getPackageVersion,
|
|
5215
|
+
getMachinesConsumerCapabilities,
|
|
4980
5216
|
getLocalMachineTopology,
|
|
4981
5217
|
discoverMachineTopology,
|
|
4982
5218
|
checkMachineCompatibility,
|
|
4983
5219
|
buildSshCommand,
|
|
4984
5220
|
MACHINES_PACKAGE_NAME,
|
|
4985
|
-
|
|
5221
|
+
MACHINES_CONSUMER_ENTRYPOINT,
|
|
5222
|
+
MACHINES_CONSUMER_CONTRACT_VERSION,
|
|
5223
|
+
MACHINES_CONSUMER_CONTRACT,
|
|
5224
|
+
MACHINES_CONSUMER_CAPABILITIES
|
|
4986
5225
|
};
|