nexarch 0.13.8 → 0.15.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/README.md +69 -63
- package/dist/commands/enroll.js +28 -1
- package/dist/commands/login.js +14 -13
- package/dist/commands/setup.js +14 -17
- package/dist/commands/skills-update.js +51 -0
- package/dist/commands/status.js +13 -4
- package/dist/index.js +12 -2
- package/dist/lib/credentials.js +34 -6
- package/dist/lib/skills.js +10 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,63 +1,69 @@
|
|
|
1
|
-
# nexarch
|
|
2
|
-
|
|
3
|
-
Your architecture workspace for AI delivery.
|
|
4
|
-
|
|
5
|
-
## Quick start
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
npx nexarch login
|
|
9
|
-
npx nexarch setup
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
|
22
|
-
|
|
23
|
-
| `nexarch
|
|
24
|
-
| `nexarch
|
|
25
|
-
| `nexarch
|
|
26
|
-
| `nexarch
|
|
27
|
-
| `nexarch
|
|
28
|
-
| `nexarch
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`nexarch init-agent`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
# nexarch
|
|
2
|
+
|
|
3
|
+
Your architecture workspace for AI delivery.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx nexarch login
|
|
9
|
+
npx nexarch setup
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
For browserless agent enrollment, use `npx nexarch enroll --code <code> --client <client>`.
|
|
13
|
+
Known clients receive their MCP connection configuration and Nexarch skills as part
|
|
14
|
+
of the same enrollment.
|
|
15
|
+
|
|
16
|
+
> `setup`, `mcp-config`, and `init-agent` are registry-driven and fail closed.
|
|
17
|
+
> If the published integration registry is unavailable/invalid, these commands stop until service is restored.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
| Command | Description |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `nexarch login [--company <id>]` | Authenticate via browser and store company-scoped credentials; prompts for company when multiple memberships exist |
|
|
24
|
+
| `nexarch logout` | Remove local credentials |
|
|
25
|
+
| `nexarch status` | Check connection, registry health/version, and architecture summary for the company selected at login |
|
|
26
|
+
| `nexarch setup` | Auto-configure detected MCP clients, write instructions, and refresh all managed skills |
|
|
27
|
+
| `nexarch skills update` | Refresh all Nexarch-managed skills for installed agent runtimes |
|
|
28
|
+
| `nexarch enroll --code <code> --client <client>` | Redeem a one-time enrollment, configure the known client, and install its Nexarch skills |
|
|
29
|
+
| `nexarch mcp-config [client]` | Print config block for manual setup (supported client codes are registry-managed) |
|
|
30
|
+
| `nexarch mcp-proxy` | stdio→HTTP bridge used internally by MCP clients |
|
|
31
|
+
| `nexarch init-agent [--json] [--strict] [--agent-id <id>] [--redact-hostname]` | Run onboarding handshake and mandatory `agent` entity registration in graph |
|
|
32
|
+
| `nexarch init-agent --bind-to-external-key <key> [--bind-relationship-type <code>]` | Optionally bind the agent node to an existing graph external key |
|
|
33
|
+
| `nexarch init-agent` (default behavior) | Also upserts technology component entities (host, OS, Node.js runtime) and links them to the agent |
|
|
34
|
+
| `nexarch agent identify ...` | Submit provider/model/client identity metadata to complete agent profile enrichment |
|
|
35
|
+
|
|
36
|
+
## Bootstrap flow after `init-agent`
|
|
37
|
+
|
|
38
|
+
`nexarch init-agent` writes a bootstrap file at:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
~/.nexarch/agent-bootstrap.md
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That file contains a pre-filled `npx nexarch agent identify ...` command template.
|
|
45
|
+
The current workflow is:
|
|
46
|
+
|
|
47
|
+
1. run `npx nexarch init-agent`
|
|
48
|
+
2. open `~/.nexarch/agent-bootstrap.md`
|
|
49
|
+
3. copy the generated `npx nexarch agent identify ...` template
|
|
50
|
+
4. fill in the real provider/model/client details
|
|
51
|
+
5. run the completed command
|
|
52
|
+
|
|
53
|
+
Do not assume an `npx nexarch agent prompt` command exists unless/until it is explicitly implemented and documented.
|
|
54
|
+
|
|
55
|
+
## Company context behavior
|
|
56
|
+
|
|
57
|
+
- Company is selected during `nexarch login`.
|
|
58
|
+
- If your user has one active company, login auto-selects it.
|
|
59
|
+
- If your user has multiple active companies, login requires explicit selection.
|
|
60
|
+
- To switch company later, run `nexarch login` again and pick another company.
|
|
61
|
+
|
|
62
|
+
## Requirements
|
|
63
|
+
|
|
64
|
+
- Node.js 18 or later
|
|
65
|
+
- A Nexarch workspace account
|
|
66
|
+
|
|
67
|
+
## Documentation
|
|
68
|
+
|
|
69
|
+
[nexarch.ai/docs/cli-reference](https://nexarch.ai/docs/cli-reference)
|
package/dist/commands/enroll.js
CHANGED
|
@@ -3,6 +3,8 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { expandHomePath, supportsAutoWrite, writeClientConfig } from "../lib/client-config-writers.js";
|
|
6
|
+
import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
7
|
+
import { installSkillsForRuntime } from "../lib/skills.js";
|
|
6
8
|
// Matches www.nexarch.ai — the default production host for the web app that
|
|
7
9
|
// owns /api/agent-enrollments/exchange. Not the same service as
|
|
8
10
|
// mcp.nexarch.ai (the MCP gateway); --host exists because staging and
|
|
@@ -36,6 +38,18 @@ function parseOptionValue(args, option) {
|
|
|
36
38
|
function redactedManifest(manifest) {
|
|
37
39
|
return { ...manifest, credential: { ...manifest.credential, token: "(redacted — see saved file, or pass --print-token)" } };
|
|
38
40
|
}
|
|
41
|
+
function skillRuntimeForClient(clientCode) {
|
|
42
|
+
switch (clientCode) {
|
|
43
|
+
case "claude-code":
|
|
44
|
+
return "claude-code";
|
|
45
|
+
case "codex-cli":
|
|
46
|
+
return "codex-cli";
|
|
47
|
+
case "hermes-agent":
|
|
48
|
+
return "hermes-agent";
|
|
49
|
+
default:
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
39
53
|
/**
|
|
40
54
|
* Bootstraps a headless (browserless) MCP agent by redeeming a one-time
|
|
41
55
|
* enrollment code for a long-lived credential — the CLI equivalent of the
|
|
@@ -95,9 +109,15 @@ export async function enroll(args) {
|
|
|
95
109
|
});
|
|
96
110
|
wroteClientConfig = true;
|
|
97
111
|
}
|
|
112
|
+
let skills = [];
|
|
113
|
+
const skillRuntime = skillRuntimeForClient(clientCode);
|
|
114
|
+
if (skillRuntime) {
|
|
115
|
+
const registry = await fetchAgentRegistryOrThrow();
|
|
116
|
+
skills = installSkillsForRuntime(registry, skillRuntime);
|
|
117
|
+
}
|
|
98
118
|
if (asJson) {
|
|
99
119
|
const output = printToken ? manifest : redactedManifest(manifest);
|
|
100
|
-
process.stdout.write(`${JSON.stringify({ ...output, wroteClientConfig }, null, 2)}\n`);
|
|
120
|
+
process.stdout.write(`${JSON.stringify({ ...output, wroteClientConfig, skills }, null, 2)}\n`);
|
|
101
121
|
return;
|
|
102
122
|
}
|
|
103
123
|
console.log(`✓ Enrolled agent ${manifest.agent.ref} in workspace "${manifest.workspace.name}"`);
|
|
@@ -114,6 +134,13 @@ export async function enroll(args) {
|
|
|
114
134
|
else {
|
|
115
135
|
console.log(`\nNo known auto-write target for client "${clientCode}" — connect it manually:`);
|
|
116
136
|
}
|
|
137
|
+
if (skills.length > 0) {
|
|
138
|
+
console.log(`\n${clientCode} skills:`);
|
|
139
|
+
for (const skill of skills) {
|
|
140
|
+
const verb = skill.status === "installed" ? "installed" : skill.status === "updated" ? "updated" : "already current";
|
|
141
|
+
console.log(` ${verb.padEnd(15)} ${skill.dirName}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
117
144
|
const shownToken = printToken ? manifest.credential.token : `<see ${destination}>`;
|
|
118
145
|
if (manifest.connectInstructionsTemplate) {
|
|
119
146
|
console.log(renderInstructions(manifest.connectInstructionsTemplate, manifest, shownToken, mcpEndpoint));
|
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/setup.js
CHANGED
|
@@ -3,7 +3,7 @@ import { requireCredentials } from "../lib/credentials.js";
|
|
|
3
3
|
import { detectClientsFromRegistry, writeClientConfig, nexarchServerBlockFromRegistry } from "../lib/clients.js";
|
|
4
4
|
import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
5
5
|
import { initAgent } from "./init-agent.js";
|
|
6
|
-
import { installSkillsForRuntime } from "../lib/skills.js";
|
|
6
|
+
import { installSkillsForRuntime, installedSkillRuntimes } from "../lib/skills.js";
|
|
7
7
|
import { login } from "./login.js";
|
|
8
8
|
function argValue(args, flag) {
|
|
9
9
|
const idx = args.indexOf(flag);
|
|
@@ -168,22 +168,19 @@ export async function setup(args) {
|
|
|
168
168
|
initAgentArgs.push("--instruction-runtime-targets", instructionRuntimeTargets.join(","));
|
|
169
169
|
}
|
|
170
170
|
await initAgent(initAgentArgs);
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
for (const { clientCode, runtime, label } of skillRuntimes) {
|
|
185
|
-
if (!clients.some((client) => client.code === clientCode))
|
|
186
|
-
continue;
|
|
171
|
+
// Refresh every installed skill-capable runtime, not only MCP clients
|
|
172
|
+
// detected in this setup pass. This keeps `setup` useful for existing
|
|
173
|
+
// installations and gives it the same managed-skill behavior as
|
|
174
|
+
// `nexarch skills update`.
|
|
175
|
+
const skillRuntimes = new Set(installedSkillRuntimes());
|
|
176
|
+
for (const client of clients) {
|
|
177
|
+
if (client.code === "claude-code")
|
|
178
|
+
skillRuntimes.add("claude-code");
|
|
179
|
+
if (client.code === "codex-cli")
|
|
180
|
+
skillRuntimes.add("codex-cli");
|
|
181
|
+
}
|
|
182
|
+
for (const runtime of skillRuntimes) {
|
|
183
|
+
const label = runtime === "claude-code" ? "Claude Code" : runtime === "codex-cli" ? "Codex CLI" : "Hermes Agent";
|
|
187
184
|
try {
|
|
188
185
|
const skills = installSkillsForRuntime(registry, runtime);
|
|
189
186
|
const anyChanged = skills.some((s) => s.status !== "already_current");
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
2
|
+
import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
3
|
+
import { installSkillsForRuntime, installedSkillRuntimes } from "../lib/skills.js";
|
|
4
|
+
const RUNTIME_LABELS = {
|
|
5
|
+
"claude-code": "Claude Code",
|
|
6
|
+
"codex-cli": "Codex CLI",
|
|
7
|
+
"hermes-agent": "Hermes Agent",
|
|
8
|
+
};
|
|
9
|
+
function hasFlag(args, flag) {
|
|
10
|
+
return args.includes(flag);
|
|
11
|
+
}
|
|
12
|
+
export async function skillsUpdate(args) {
|
|
13
|
+
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
14
|
+
console.log(`
|
|
15
|
+
Usage:
|
|
16
|
+
nexarch skills update [--json]
|
|
17
|
+
|
|
18
|
+
Refresh all Nexarch-managed skills for installed agent runtimes.
|
|
19
|
+
`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const asJson = hasFlag(args, "--json");
|
|
23
|
+
requireCredentials();
|
|
24
|
+
const registry = await fetchAgentRegistryOrThrow();
|
|
25
|
+
const runtimes = installedSkillRuntimes();
|
|
26
|
+
const results = [];
|
|
27
|
+
for (const runtime of runtimes) {
|
|
28
|
+
results.push({
|
|
29
|
+
runtime,
|
|
30
|
+
label: RUNTIME_LABELS[runtime],
|
|
31
|
+
skills: installSkillsForRuntime(registry, runtime),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (asJson) {
|
|
35
|
+
process.stdout.write(`${JSON.stringify({ registryVersion: registry.release.version, runtimes: results }, null, 2)}\n`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.log(`Using integration registry release v${registry.release.version}.`);
|
|
39
|
+
if (results.length === 0) {
|
|
40
|
+
console.log("No installed Nexarch skill runtimes found.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const result of results) {
|
|
44
|
+
console.log(`\n${result.label} skills:`);
|
|
45
|
+
for (const skill of result.skills) {
|
|
46
|
+
const verb = skill.status === "installed" ? "installed" : skill.status === "updated" ? "updated" : "already current";
|
|
47
|
+
console.log(` ${verb.padEnd(15)} ${skill.dirName}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
console.log("\nNexarch-managed skills refreshed.");
|
|
51
|
+
}
|
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/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { enroll } from "./commands/enroll.js";
|
|
|
4
4
|
import { logout } from "./commands/logout.js";
|
|
5
5
|
import { status } from "./commands/status.js";
|
|
6
6
|
import { setup } from "./commands/setup.js";
|
|
7
|
+
import { skillsUpdate } from "./commands/skills-update.js";
|
|
7
8
|
import { mcpConfig } from "./commands/mcp-config.js";
|
|
8
9
|
import { mcpProxy } from "./commands/mcp-proxy.js";
|
|
9
10
|
import { initAgent } from "./commands/init-agent.js";
|
|
@@ -82,6 +83,13 @@ async function main() {
|
|
|
82
83
|
return;
|
|
83
84
|
}
|
|
84
85
|
}
|
|
86
|
+
if (command === "skills") {
|
|
87
|
+
const [subcommand, ...subArgs] = args;
|
|
88
|
+
if (subcommand === "update") {
|
|
89
|
+
await skillsUpdate(subArgs);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
85
93
|
if (command === "proposals") {
|
|
86
94
|
const [subcommand, ...subArgs] = args;
|
|
87
95
|
if (subcommand === "start") {
|
|
@@ -119,8 +127,8 @@ Usage:
|
|
|
119
127
|
credential to ~/.nexarch/agent-credential.json (mode 600)
|
|
120
128
|
rather than printing it. For a client with a known config
|
|
121
129
|
format (e.g. hermes-agent), also writes the connection
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
and installs its Nexarch skills; for anything else,
|
|
131
|
+
prints instructions instead.
|
|
124
132
|
Options: --code <code> (required, starts with nxe_)
|
|
125
133
|
--client <code> (required, e.g. hermes-agent)
|
|
126
134
|
--client-version <v>
|
|
@@ -141,6 +149,8 @@ Usage:
|
|
|
141
149
|
Options: --company <id|code> target a workspace directly
|
|
142
150
|
--yes accept the stored workspace without asking
|
|
143
151
|
--no-browser log in by pasting a one-time code (see login)
|
|
152
|
+
nexarch skills update
|
|
153
|
+
Refresh all Nexarch-managed skills for installed agent runtimes
|
|
144
154
|
nexarch mcp-config Print MCP server config block for manual setup
|
|
145
155
|
Client list is registry-managed (see 'nexarch mcp-config --client <code>')
|
|
146
156
|
nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
|
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/dist/lib/skills.js
CHANGED
|
@@ -408,7 +408,16 @@ export const SKILLS = [
|
|
|
408
408
|
const RUNTIME_SKILLS_ROOT = {
|
|
409
409
|
"claude-code": [".claude", "skills"],
|
|
410
410
|
"codex-cli": [".agents", "skills"],
|
|
411
|
+
"hermes-agent": [".hermes", "skills"],
|
|
411
412
|
};
|
|
413
|
+
export function skillRootForRuntime(runtime, homeDir = homedir()) {
|
|
414
|
+
return runtime === "hermes-agent" && process.env.HERMES_HOME
|
|
415
|
+
? join(process.env.HERMES_HOME, "skills")
|
|
416
|
+
: join(homeDir, ...RUNTIME_SKILLS_ROOT[runtime]);
|
|
417
|
+
}
|
|
418
|
+
export function installedSkillRuntimes(homeDir = homedir()) {
|
|
419
|
+
return Object.keys(RUNTIME_SKILLS_ROOT).filter((runtime) => existsSync(skillRootForRuntime(runtime, homeDir)));
|
|
420
|
+
}
|
|
412
421
|
function installSkill(spec, registry, skillsRoot) {
|
|
413
422
|
const template = registry.instructionTemplates.find((t) => t.code === spec.templateCode);
|
|
414
423
|
const body = template ? template.body.trim() + "\n" : spec.fallbackBody;
|
|
@@ -428,7 +437,6 @@ function installSkill(spec, registry, skillsRoot) {
|
|
|
428
437
|
return { dirName: spec.dirName, path: skillPath, status: "installed", source };
|
|
429
438
|
}
|
|
430
439
|
export function installSkillsForRuntime(registry, runtime, options = {}) {
|
|
431
|
-
const
|
|
432
|
-
const skillsRoot = join(homeDir, ...RUNTIME_SKILLS_ROOT[runtime]);
|
|
440
|
+
const skillsRoot = skillRootForRuntime(runtime, options.homeDir ?? homedir());
|
|
433
441
|
return SKILLS.map((spec) => installSkill(spec, registry, skillsRoot));
|
|
434
442
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexarch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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 && tsx scripts/test-hermes-skills.ts"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22",
|