nexarch 0.13.8 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/login.js +14 -13
- package/dist/commands/status.js +13 -4
- package/dist/lib/credentials.js +34 -6
- package/package.json +2 -2
package/dist/commands/login.js
CHANGED
|
@@ -24,15 +24,15 @@ async function promptCapabilityProfile() {
|
|
|
24
24
|
return selectFromList("Select a capability profile for this credential:", PROFILE_CHOICES, "worker");
|
|
25
25
|
}
|
|
26
26
|
function printLoginBanner() {
|
|
27
|
-
const logo = String.raw `
|
|
28
|
-
###### ######
|
|
29
|
-
####### ######
|
|
30
|
-
######### ###### ##
|
|
31
|
-
################## #####
|
|
32
|
-
##### ########## ######
|
|
33
|
-
###### ####### ######
|
|
34
|
-
##### #### #############
|
|
35
|
-
###### ## ###############
|
|
27
|
+
const logo = String.raw `
|
|
28
|
+
###### ######
|
|
29
|
+
####### ######
|
|
30
|
+
######### ###### ##
|
|
31
|
+
################## #####
|
|
32
|
+
##### ########## ######
|
|
33
|
+
###### ####### ######
|
|
34
|
+
##### #### #############
|
|
35
|
+
###### ## ###############
|
|
36
36
|
`;
|
|
37
37
|
console.log(logo);
|
|
38
38
|
console.log("NEXARCH CLI login\n");
|
|
@@ -95,10 +95,10 @@ function waitForCallback(port, expectedState) {
|
|
|
95
95
|
const companyName = url.searchParams.get("companyName") ?? undefined;
|
|
96
96
|
const companyCode = url.searchParams.get("companyCode") ?? undefined;
|
|
97
97
|
const error = url.searchParams.get("error");
|
|
98
|
-
const html = (message) => `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Nexarch CLI</title>
|
|
99
|
-
<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f8fafc}
|
|
100
|
-
.card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:2rem;max-width:400px;text-align:center}
|
|
101
|
-
h1{font-size:1.25rem;margin:0 0 .5rem;color:#0f172a}p{color:#64748b;font-size:.9rem;margin:.5rem 0}</style></head>
|
|
98
|
+
const html = (message) => `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Nexarch CLI</title>
|
|
99
|
+
<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f8fafc}
|
|
100
|
+
.card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:2rem;max-width:400px;text-align:center}
|
|
101
|
+
h1{font-size:1.25rem;margin:0 0 .5rem;color:#0f172a}p{color:#64748b;font-size:.9rem;margin:.5rem 0}</style></head>
|
|
102
102
|
<body><div class="card"><h1>Nexarch CLI</h1><p>${message}</p></div></body></html>`;
|
|
103
103
|
if (state !== expectedState) {
|
|
104
104
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
@@ -247,6 +247,7 @@ export async function login(args) {
|
|
|
247
247
|
companyCode: companyCode ?? undefined,
|
|
248
248
|
companyId,
|
|
249
249
|
expiresAt: expiresAt.toISOString(),
|
|
250
|
+
source: "interactive",
|
|
250
251
|
});
|
|
251
252
|
try {
|
|
252
253
|
const identityDir = join(homedir(), ".nexarch");
|
package/dist/commands/status.js
CHANGED
|
@@ -5,8 +5,8 @@ import { callMcpTool } from "../lib/mcp.js";
|
|
|
5
5
|
export async function status(_args) {
|
|
6
6
|
const creds = requireCredentials();
|
|
7
7
|
const selectedCompanyId = creds.companyId;
|
|
8
|
-
const expiresAt = new Date(creds.expiresAt);
|
|
9
|
-
const daysLeft = Math.ceil((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
|
8
|
+
const expiresAt = creds.expiresAt ? new Date(creds.expiresAt) : null;
|
|
9
|
+
const daysLeft = expiresAt ? Math.ceil((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
10
10
|
const lease = loadCheckInLease();
|
|
11
11
|
const leaseState = lease && lease.companyId === selectedCompanyId ? getCheckInLeaseState(lease) : { status: "missing", expiresInSeconds: null };
|
|
12
12
|
process.stdout.write("Connecting to mcp.nexarch.ai… ");
|
|
@@ -28,6 +28,15 @@ export async function status(_args) {
|
|
|
28
28
|
if (creds.email) {
|
|
29
29
|
console.log(` Signed in as: ${creds.email}`);
|
|
30
30
|
}
|
|
31
|
+
else if (creds.source === "agent") {
|
|
32
|
+
console.log(" Authentication: Hermes agent enrollment");
|
|
33
|
+
if (creds.agentRef) {
|
|
34
|
+
console.log(` Agent: ${creds.agentRef}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (creds.source === "service") {
|
|
38
|
+
console.log(" Authentication: service credential");
|
|
39
|
+
}
|
|
31
40
|
if (creds.company) {
|
|
32
41
|
console.log(` Workspace: ${creds.company}`);
|
|
33
42
|
}
|
|
@@ -53,7 +62,7 @@ export async function status(_args) {
|
|
|
53
62
|
else {
|
|
54
63
|
console.log(` Latest snapshot: none published yet`);
|
|
55
64
|
}
|
|
56
|
-
console.log(`\n Token expires: ${expiresAt.toLocaleDateString()} (${daysLeft} days)`);
|
|
65
|
+
console.log(`\n Token expires: ${expiresAt ? `${expiresAt.toLocaleDateString()} (${daysLeft} days)` : "not reported"}`);
|
|
57
66
|
if (leaseState.status === "valid" && lease) {
|
|
58
67
|
console.log(` Check-in lease: ${new Date(lease.leaseExpiresAt).toLocaleString()} (${Math.ceil((leaseState.expiresInSeconds ?? 0) / 3600)}h left)`);
|
|
59
68
|
}
|
|
@@ -63,7 +72,7 @@ export async function status(_args) {
|
|
|
63
72
|
else {
|
|
64
73
|
console.log(" Check-in lease: none stored");
|
|
65
74
|
}
|
|
66
|
-
if (daysLeft <= 14) {
|
|
75
|
+
if (daysLeft !== null && daysLeft <= 14) {
|
|
67
76
|
console.log(`\n ⚠ Your token expires soon. Run \`nexarch login\` to renew.`);
|
|
68
77
|
}
|
|
69
78
|
if (leaseState.status !== "valid") {
|
package/dist/lib/credentials.js
CHANGED
|
@@ -4,6 +4,9 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync } from "fs";
|
|
|
4
4
|
function credentialsPath() {
|
|
5
5
|
return join(homedir(), ".nexarch", "credentials.json");
|
|
6
6
|
}
|
|
7
|
+
function agentCredentialPath() {
|
|
8
|
+
return join(homedir(), ".nexarch", "agent-credential.json");
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
11
|
* Credentials supplied by the environment, for CI.
|
|
9
12
|
*
|
|
@@ -27,24 +30,49 @@ function credentialsFromEnvironment() {
|
|
|
27
30
|
company: "",
|
|
28
31
|
companyId: process.env.NEXARCH_COMPANY_ID?.trim() ?? "",
|
|
29
32
|
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
|
33
|
+
source: "service",
|
|
30
34
|
};
|
|
31
35
|
}
|
|
36
|
+
function credentialsFromAgentManifest() {
|
|
37
|
+
const path = agentCredentialPath();
|
|
38
|
+
if (!existsSync(path))
|
|
39
|
+
return null;
|
|
40
|
+
try {
|
|
41
|
+
const manifest = JSON.parse(readFileSync(path, "utf-8"));
|
|
42
|
+
const token = typeof manifest.credential?.token === "string" ? manifest.credential.token.trim() : "";
|
|
43
|
+
const companyId = typeof manifest.workspace?.id === "string" ? manifest.workspace.id : "";
|
|
44
|
+
if (!token || !companyId)
|
|
45
|
+
return null;
|
|
46
|
+
return {
|
|
47
|
+
token,
|
|
48
|
+
email: "",
|
|
49
|
+
company: typeof manifest.workspace?.name === "string" ? manifest.workspace.name : "",
|
|
50
|
+
companyId,
|
|
51
|
+
expiresAt: typeof manifest.credential?.expiresAt === "string" ? manifest.credential.expiresAt : null,
|
|
52
|
+
source: "agent",
|
|
53
|
+
agentRef: typeof manifest.agent?.ref === "string" ? manifest.agent.ref : undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
32
60
|
export function loadCredentials() {
|
|
33
61
|
const fromEnv = credentialsFromEnvironment();
|
|
34
62
|
if (fromEnv)
|
|
35
63
|
return fromEnv;
|
|
36
64
|
const path = credentialsPath();
|
|
37
65
|
if (!existsSync(path))
|
|
38
|
-
return
|
|
66
|
+
return credentialsFromAgentManifest();
|
|
39
67
|
try {
|
|
40
68
|
const raw = readFileSync(path, "utf-8");
|
|
41
69
|
const creds = JSON.parse(raw);
|
|
42
70
|
if (!creds.token)
|
|
43
|
-
return
|
|
44
|
-
return creds;
|
|
71
|
+
return credentialsFromAgentManifest();
|
|
72
|
+
return { ...creds, source: "interactive" };
|
|
45
73
|
}
|
|
46
74
|
catch {
|
|
47
|
-
return
|
|
75
|
+
return credentialsFromAgentManifest();
|
|
48
76
|
}
|
|
49
77
|
}
|
|
50
78
|
export function saveCredentials(creds) {
|
|
@@ -63,13 +91,13 @@ export function removeCredentials() {
|
|
|
63
91
|
export function requireCredentials() {
|
|
64
92
|
const creds = loadCredentials();
|
|
65
93
|
if (!creds) {
|
|
66
|
-
throw new Error("
|
|
94
|
+
throw new Error("No Nexarch credential found. Run `nexarch login` for interactive CLI access, or `nexarch enroll` for headless agent access.");
|
|
67
95
|
}
|
|
68
96
|
// Environment-supplied service credentials are validated by the gateway, not
|
|
69
97
|
// by this process; only the stored interactive session carries a local expiry.
|
|
70
98
|
if (process.env.NEXARCH_TOKEN?.trim())
|
|
71
99
|
return creds;
|
|
72
|
-
if (new Date(creds.expiresAt) < new Date()) {
|
|
100
|
+
if (creds.expiresAt && new Date(creds.expiresAt) < new Date()) {
|
|
73
101
|
throw new Error("Your session has expired. Run `nexarch login` to re-authenticate.");
|
|
74
102
|
}
|
|
75
103
|
return creds;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexarch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Your architecture workspace for AI delivery.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nexarch",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"prepublishOnly": "tsc",
|
|
27
27
|
"dev": "tsx src/index.ts",
|
|
28
28
|
"typecheck": "tsc --noEmit",
|
|
29
|
-
"test": "tsx scripts/test-mcp-proxy-response.ts && tsx scripts/test-trust-reattest.ts && tsx scripts/test-similar-applications.ts && tsx scripts/test-iac-tool.ts && tsx scripts/test-ansible.ts && tsx scripts/test-reference-sightings.ts && tsx scripts/test-search-icons.ts && tsx scripts/test-paste-login.ts"
|
|
29
|
+
"test": "tsx scripts/test-mcp-proxy-response.ts && tsx scripts/test-trust-reattest.ts && tsx scripts/test-similar-applications.ts && tsx scripts/test-iac-tool.ts && tsx scripts/test-ansible.ts && tsx scripts/test-reference-sightings.ts && tsx scripts/test-search-icons.ts && tsx scripts/test-paste-login.ts && tsx scripts/test-credentials-resolution.ts"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22",
|