nexarch 0.6.3 → 0.6.5

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.
@@ -1,5 +1,5 @@
1
1
  import process from "process";
2
- import { existsSync, readFileSync, readdirSync, statSync } from "fs";
2
+ import { existsSync, readFileSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { homedir } from "os";
5
5
  import { requireCredentials } from "../lib/credentials.js";
@@ -23,136 +23,65 @@ function parseToolText(result) {
23
23
  function loadIdentity() {
24
24
  const identityPath = join(homedir(), ".nexarch", "identity.json");
25
25
  if (!existsSync(identityPath))
26
- return { agentKey: null, projectKeys: [] };
26
+ return { agentKey: null, companyId: null };
27
27
  try {
28
28
  const data = JSON.parse(readFileSync(identityPath, "utf8"));
29
- return {
30
- agentKey: data.agentKey ?? null,
31
- projectKeys: Array.isArray(data.projectKeys) ? data.projectKeys : [],
32
- };
29
+ return { agentKey: data.agentKey ?? null, companyId: data.companyId ?? null };
33
30
  }
34
31
  catch {
35
- return { agentKey: null, projectKeys: [] };
32
+ return { agentKey: null, companyId: null };
36
33
  }
37
34
  }
38
- function safeReadText(path, maxChars = 6000) {
39
- if (!existsSync(path))
40
- return null;
41
- try {
42
- return readFileSync(path, "utf8").slice(0, maxChars);
43
- }
44
- catch {
45
- return null;
46
- }
47
- }
48
- function collectEvidenceFromRepo() {
49
- const cwd = process.cwd();
50
- const readme = safeReadText(join(cwd, "README.md"), 8000)
51
- ?? safeReadText(join(cwd, "readme.md"), 8000)
52
- ?? undefined;
53
- const packageJson = safeReadText(join(cwd, "package.json"), 5000);
54
- const notes = [];
55
- if (packageJson)
56
- notes.push("package.json detected");
57
- const files = [];
58
- if (packageJson)
59
- files.push({ path: "package.json", content: packageJson });
60
- const srcDir = join(cwd, "src");
61
- if (existsSync(srcDir)) {
62
- try {
63
- const entries = readdirSync(srcDir)
64
- .filter((name) => /\.(ts|tsx|js|jsx)$/i.test(name))
65
- .slice(0, 8);
66
- for (const name of entries) {
67
- const full = join(srcDir, name);
68
- try {
69
- if (!statSync(full).isFile())
70
- continue;
71
- const content = safeReadText(full, 4000);
72
- if (content)
73
- files.push({ path: `src/${name}`, content });
74
- }
75
- catch {
76
- // ignore per-file failures
77
- }
78
- }
79
- if (entries.length > 0)
80
- notes.push(`included ${entries.length} source file snippet(s)`);
81
- }
82
- catch {
83
- // ignore directory read issues
84
- }
85
- }
86
- const summary = [
87
- `cwd=${cwd}`,
88
- readme ? "README included" : "README missing",
89
- files.length > 0 ? `evidence files=${files.length}` : "no evidence files collected",
90
- ].join("; ");
91
- return {
92
- summary,
93
- ...(readme ? { readme } : {}),
94
- ...(notes.length ? { notes: notes.join("; ") } : {}),
95
- ...(files.length ? { files } : {}),
96
- };
97
- }
98
35
  export async function checkIn(args) {
99
36
  const asJson = parseFlag(args, "--json");
100
37
  const agentKeyArg = parseOptionValue(args, "--agent-key");
101
- const projectKey = parseOptionValue(args, "--project");
102
38
  const creds = requireCredentials();
103
39
  const identity = loadIdentity();
104
40
  const agentKey = agentKeyArg ?? identity.agentKey;
105
- // Use --project flag as a single override, otherwise send all stored keys
106
- const resolvedProjectKeys = projectKey ? [projectKey] : identity.projectKeys;
107
41
  if (!agentKey) {
108
42
  if (asJson) {
109
- process.stdout.write(JSON.stringify({ command: null, reason: "no-agent-key" }) + "\n");
43
+ process.stdout.write(JSON.stringify({ commands: [], reason: "no-agent-key" }) + "\n");
110
44
  }
111
45
  else {
112
46
  console.log("No agent key found. Pass --agent-key or run nexarch init-agent first.");
113
47
  }
114
48
  return;
115
49
  }
116
- const mcpOpts = { companyId: creds.companyId };
117
- const evidence = collectEvidenceFromRepo();
118
50
  const raw = await callMcpTool("nexarch_claim_command", {
119
51
  agentKey,
120
- ...(resolvedProjectKeys.length > 0 ? { projectKeys: resolvedProjectKeys } : {}),
121
- evidence,
122
52
  companyId: creds.companyId,
123
- }, mcpOpts);
53
+ }, { companyId: creds.companyId });
124
54
  const result = parseToolText(raw);
125
55
  if (asJson) {
126
56
  process.stdout.write(JSON.stringify(result) + "\n");
127
57
  return;
128
58
  }
129
- if (!result.command) {
130
- console.log("No pending commands. Nothing to do.");
59
+ const commands = result.commands ?? [];
60
+ if (commands.length === 0) {
61
+ console.log("No pending application-target commands found.");
131
62
  return;
132
63
  }
133
- const cmd = result.command;
134
- console.log(`\n╔══════════════════════════════════════════════════════════════════╗`);
135
- console.log(`║ COMMAND QUEUED action required ║`);
136
- console.log(`╚══════════════════════════════════════════════════════════════════╝`);
137
- console.log(`\nCommand ID : ${cmd.id}`);
138
- console.log(`Type : ${cmd.command_type}`);
139
- console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
140
- console.log(`Priority : ${cmd.priority}`);
141
- if (cmd.resolved_runtime_handler)
142
- console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
143
- if (cmd.command_type_version != null)
144
- console.log(`Type ver : ${cmd.command_type_version}`);
145
- if (Object.keys(cmd.command_params).length > 0) {
146
- console.log(`Params : ${JSON.stringify(cmd.command_params)}`);
147
- }
148
- if (cmd.resolved_playbook_text?.trim()) {
149
- console.log(`\nPlaybook:\n${cmd.resolved_playbook_text}`);
64
+ console.log("\nPending application-target commands (preview only; nothing claimed):");
65
+ console.log(`Company scope is resolved server-side from companyId=${creds.companyId}.`);
66
+ if (identity.companyId && identity.companyId !== creds.companyId) {
67
+ console.log(`Note: local identity companyId ${identity.companyId} differs from current credentials companyId ${creds.companyId}.`);
150
68
  }
151
- if (cmd.instructions) {
152
- console.log(`\nInstructions:\n${cmd.instructions}`);
69
+ for (const cmd of commands) {
70
+ const claimable = cmd.claimable ? "yes" : "no";
71
+ const reason = cmd.claimReason ?? (cmd.claimable ? "application_access_confirmed" : "application_not_found_for_company");
72
+ console.log(`\n- ID : ${cmd.id}`);
73
+ console.log(` Type : ${cmd.command_type}`);
74
+ console.log(` Target : ${cmd.target_entity_key ?? "(none)"}`);
75
+ console.log(` Priority : ${cmd.priority}`);
76
+ console.log(` Claimable : ${claimable} (${reason})`);
77
+ if (cmd.command_type_version != null)
78
+ console.log(` Type ver : ${cmd.command_type_version}`);
79
+ if (cmd.resolved_runtime_handler)
80
+ console.log(` Runtime : ${cmd.resolved_runtime_handler}`);
81
+ if (cmd.claimable) {
82
+ console.log(` Claim cmd : npx nexarch command-claim --id "${cmd.id}"`);
83
+ }
153
84
  }
154
- console.log(`\nWhen done, run:`);
155
- console.log(` npx nexarch command-done --id "${cmd.id}" --summary "..."`);
156
- console.log(`\nIf it fails, run:`);
157
- console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
85
+ console.log("\nTo validate an application target is accessible in Nexarch before claiming:");
86
+ console.log(" npx nexarch policy-controls --entity <application:key> --json");
158
87
  }
@@ -0,0 +1,91 @@
1
+ import process from "process";
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { requireCredentials } from "../lib/credentials.js";
6
+ import { callMcpTool } from "../lib/mcp.js";
7
+ function parseFlag(args, flag) {
8
+ return args.includes(flag);
9
+ }
10
+ function parseOptionValue(args, option) {
11
+ const idx = args.indexOf(option);
12
+ if (idx === -1)
13
+ return null;
14
+ const v = args[idx + 1];
15
+ if (!v || v.startsWith("--"))
16
+ return null;
17
+ return v;
18
+ }
19
+ function parseToolText(result) {
20
+ const text = result.content?.[0]?.text ?? "{}";
21
+ return JSON.parse(text);
22
+ }
23
+ function loadIdentity() {
24
+ const identityPath = join(homedir(), ".nexarch", "identity.json");
25
+ if (!existsSync(identityPath))
26
+ return { agentKey: null };
27
+ try {
28
+ const data = JSON.parse(readFileSync(identityPath, "utf8"));
29
+ return { agentKey: data.agentKey ?? null };
30
+ }
31
+ catch {
32
+ return { agentKey: null };
33
+ }
34
+ }
35
+ export async function commandClaim(args) {
36
+ const asJson = parseFlag(args, "--json");
37
+ const id = parseOptionValue(args, "--id");
38
+ const agentKeyArg = parseOptionValue(args, "--agent-key");
39
+ if (!id) {
40
+ console.error("error: --id <commandId> is required");
41
+ process.exit(1);
42
+ }
43
+ const creds = requireCredentials();
44
+ const identity = loadIdentity();
45
+ const agentKey = agentKeyArg ?? identity.agentKey;
46
+ if (!agentKey) {
47
+ console.error("error: no agent key found. Pass --agent-key or run nexarch init-agent first.");
48
+ process.exit(1);
49
+ }
50
+ const raw = await callMcpTool("nexarch_claim_command_by_id", {
51
+ commandId: id,
52
+ agentKey,
53
+ companyId: creds.companyId,
54
+ }, { companyId: creds.companyId });
55
+ const result = parseToolText(raw);
56
+ if (asJson) {
57
+ process.stdout.write(JSON.stringify(result) + "\n");
58
+ return;
59
+ }
60
+ if (!result.command) {
61
+ console.log(`Command ${id} was not claimed.`);
62
+ if (result.reason)
63
+ console.log(`Reason: ${result.reason}`);
64
+ return;
65
+ }
66
+ const cmd = result.command;
67
+ console.log(`\n╔══════════════════════════════════════════════════════════════════╗`);
68
+ console.log(`║ COMMAND CLAIMED — action required ║`);
69
+ console.log(`╚══════════════════════════════════════════════════════════════════╝`);
70
+ console.log(`\nCommand ID : ${cmd.id}`);
71
+ console.log(`Type : ${cmd.command_type}`);
72
+ console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
73
+ console.log(`Priority : ${cmd.priority}`);
74
+ if (cmd.resolved_runtime_handler)
75
+ console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
76
+ if (cmd.command_type_version != null)
77
+ console.log(`Type ver : ${cmd.command_type_version}`);
78
+ if (Object.keys(cmd.command_params).length > 0) {
79
+ console.log(`Params : ${JSON.stringify(cmd.command_params)}`);
80
+ }
81
+ if (cmd.resolved_playbook_text?.trim()) {
82
+ console.log(`\nPlaybook:\n${cmd.resolved_playbook_text}`);
83
+ }
84
+ if (cmd.instructions) {
85
+ console.log(`\nInstructions:\n${cmd.instructions}`);
86
+ }
87
+ console.log(`\nWhen done, run:`);
88
+ console.log(` npx nexarch command-done --id "${cmd.id}" --summary "..."`);
89
+ console.log(`\nIf it fails, run:`);
90
+ console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
91
+ }
@@ -756,7 +756,7 @@ export async function initAgent(args) {
756
756
  // Save identity so check-in can find the agent key
757
757
  const identityDir = join(homedir(), ".nexarch");
758
758
  mkdirSync(identityDir, { recursive: true });
759
- writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey: `agent:${agentId}` }, null, 2), { mode: 0o600 });
759
+ writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey: `agent:${agentId}`, companyId: creds.companyId }, null, 2), { mode: 0o600 });
760
760
  }
761
761
  catch {
762
762
  // non-fatal
@@ -1,8 +1,7 @@
1
1
  import process from "process";
2
2
  import { execFileSync } from "node:child_process";
3
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
4
  import { basename, join, relative, resolve as resolvePath } from "node:path";
5
- import { homedir } from "node:os";
6
5
  import { requireCredentials } from "../lib/credentials.js";
7
6
  import { callMcpTool } from "../lib/mcp.js";
8
7
  import { buildVersionAttributes } from "../lib/version-normalization.js";
@@ -1234,30 +1233,6 @@ ${subPkgSection}${gapCheckSection}`;
1234
1233
  relationshipErrors: relsResult?.errors ?? [],
1235
1234
  enrichmentTask,
1236
1235
  };
1237
- // Persist all application entity keys to ~/.nexarch/identity.json so nexarch check-in
1238
- // can automatically claim commands targeted at any application in this project.
1239
- if (output.ok) {
1240
- try {
1241
- const allAppKeys = [
1242
- projectExternalKey,
1243
- ...subPackages
1244
- .filter((sp) => sp.entityType === "application" && sp.externalKey)
1245
- .map((sp) => sp.externalKey),
1246
- ];
1247
- const identityDir = join(homedir(), ".nexarch");
1248
- mkdirSync(identityDir, { recursive: true });
1249
- const identityPath = join(identityDir, "identity.json");
1250
- const existing = existsSync(identityPath)
1251
- ? JSON.parse(readFileSync(identityPath, "utf8"))
1252
- : {};
1253
- const stored = Array.isArray(existing.projectKeys) ? existing.projectKeys : [];
1254
- const merged = Array.from(new Set([...allAppKeys, ...stored]));
1255
- writeFileSync(identityPath, JSON.stringify({ ...existing, projectKeys: merged }, null, 2), { mode: 0o600 });
1256
- }
1257
- catch {
1258
- // non-fatal
1259
- }
1260
- }
1261
1236
  if (asJson) {
1262
1237
  process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
1263
1238
  if (!output.ok)
@@ -3,6 +3,9 @@ import { createServer as createNetServer } from "net";
3
3
  import { randomBytes } from "crypto";
4
4
  import { execFile } from "child_process";
5
5
  import { saveCredentials } from "../lib/credentials.js";
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
6
9
  const NEXARCH_URL = "https://nexarch.ai";
7
10
  const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
8
11
  function printLoginBanner() {
@@ -152,6 +155,20 @@ export async function login(args) {
152
155
  companyId,
153
156
  expiresAt: expiresAt.toISOString(),
154
157
  });
158
+ try {
159
+ const identityDir = join(homedir(), ".nexarch");
160
+ mkdirSync(identityDir, { recursive: true });
161
+ const identityPath = join(identityDir, "identity.json");
162
+ const existing = existsSync(identityPath)
163
+ ? JSON.parse(readFileSync(identityPath, "utf8"))
164
+ : {};
165
+ const next = { ...existing, companyId };
166
+ delete next.projectKeys;
167
+ writeFileSync(identityPath, JSON.stringify(next, null, 2), { mode: 0o600 });
168
+ }
169
+ catch {
170
+ // non-fatal
171
+ }
155
172
  console.log("✓ Logged in successfully");
156
173
  console.log("\nRun `nexarch status` to verify your connection.");
157
174
  }
@@ -1,4 +1,7 @@
1
1
  import { loadCredentials, removeCredentials } from "../lib/credentials.js";
2
+ import { existsSync, rmSync } from "fs";
3
+ import { homedir } from "os";
4
+ import { join } from "path";
2
5
  export async function logout(_args) {
3
6
  const creds = loadCredentials();
4
7
  if (!creds) {
@@ -6,7 +9,11 @@ export async function logout(_args) {
6
9
  return;
7
10
  }
8
11
  removeCredentials();
12
+ const identityPath = join(homedir(), ".nexarch", "identity.json");
13
+ if (existsSync(identityPath))
14
+ rmSync(identityPath);
9
15
  console.log("✓ Logged out. Credentials removed from ~/.nexarch/credentials.json");
16
+ console.log("✓ Local identity removed from ~/.nexarch/identity.json");
10
17
  console.log("\nNote: the token still exists in your Nexarch workspace until revoked.");
11
18
  console.log("To revoke it, visit Workspace → Agents → Manage tokens.");
12
19
  }
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ import { resolveNames } from "./commands/resolve-names.js";
15
15
  import { checkIn } from "./commands/check-in.js";
16
16
  import { commandDone } from "./commands/command-done.js";
17
17
  import { commandFail } from "./commands/command-fail.js";
18
+ import { commandClaim } from "./commands/command-claim.js";
18
19
  import { policyControls } from "./commands/policy-controls.js";
19
20
  import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
20
21
  const [, , command, ...args] = process.argv;
@@ -35,6 +36,7 @@ const commands = {
35
36
  "check-in": checkIn,
36
37
  "command-done": commandDone,
37
38
  "command-fail": commandFail,
39
+ "command-claim": commandClaim,
38
40
  "policy-controls": policyControls,
39
41
  "policy-audit-submit": policyAuditSubmit,
40
42
  };
@@ -117,11 +119,14 @@ Usage:
117
119
  results before calling add-relationship.
118
120
  Options: --names <csv> (required, e.g. "vercel,neon")
119
121
  --json
120
- nexarch check-in Poll the command queue and claim the next pending command
121
- for this agent. Reads agent key from ~/.nexarch/identity.json
122
- (written by init-agent) or via --agent-key.
122
+ nexarch check-in Preview pending application-target commands (no auto-claim).
123
+ Scope is resolved server-side from active company context.
123
124
  Options: --agent-key <key> override stored agent key
124
- --project <key> application entity key
125
+ --json
126
+ nexarch command-claim
127
+ Explicitly claim a pending command by ID.
128
+ Options: --id <commandId> (required)
129
+ --agent-key <key> override stored agent key
125
130
  --json
126
131
  nexarch command-done
127
132
  Mark a claimed command as completed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",