nexarch 0.12.7 → 0.12.9

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.
@@ -95,9 +95,9 @@ export async function checkIn(args) {
95
95
  }
96
96
  if (commands.length > 0) {
97
97
  console.log("\nPending application-target commands (preview only; nothing claimed):");
98
- console.log(`Company scope is resolved server-side from companyId=${creds.companyId}.`);
98
+ console.log(`Workspace scope is resolved server-side from companyId=${creds.companyId}.`);
99
99
  if (identity.companyId && identity.companyId !== creds.companyId) {
100
- console.log(`Note: local identity companyId ${identity.companyId} differs from current credentials companyId ${creds.companyId}.`);
100
+ console.log(`Note: local identity workspace ${identity.companyId} differs from the credentials in use (${creds.companyId}).`);
101
101
  }
102
102
  for (const cmd of commands) {
103
103
  const claimable = cmd.claimable ? "yes" : "no";
@@ -1,9 +1,93 @@
1
+ import { createInterface } from "readline";
1
2
  import { requireCredentials } from "../lib/credentials.js";
2
3
  import { detectClientsFromRegistry, writeClientConfig, nexarchServerBlockFromRegistry } from "../lib/clients.js";
3
4
  import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
4
5
  import { initAgent } from "./init-agent.js";
5
6
  import { installClaudeCodeSkill } from "../lib/skills.js";
6
7
  import { login } from "./login.js";
8
+ function argValue(args, flag) {
9
+ const idx = args.indexOf(flag);
10
+ if (idx === -1)
11
+ return null;
12
+ const value = args[idx + 1];
13
+ return !value || value.startsWith("--") ? null : value;
14
+ }
15
+ /** Drops a flag and the value that belongs to it, so neither is left orphaned. */
16
+ function withoutFlag(args, flag) {
17
+ const idx = args.indexOf(flag);
18
+ if (idx === -1)
19
+ return args;
20
+ const takesValue = args[idx + 1] && !args[idx + 1].startsWith("--");
21
+ return [...args.slice(0, idx), ...args.slice(idx + (takesValue ? 2 : 1))];
22
+ }
23
+ /**
24
+ * Builds the argument list for a login triggered from setup.
25
+ *
26
+ * `login` speaks only `--company`, so `--workspace` is translated rather than
27
+ * passed through to be silently dropped by the flag it does not recognise.
28
+ */
29
+ function loginArgs(args, company) {
30
+ const base = withoutFlag(withoutFlag(args, "--company"), "--workspace");
31
+ return company ? [...base, "--company", company] : base;
32
+ }
33
+ async function askYesNo(question) {
34
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
35
+ try {
36
+ const answer = await new Promise((resolve) => rl.question(`${question} [Y/n] `, resolve));
37
+ return !/^n(o)?$/i.test(answer.trim());
38
+ }
39
+ finally {
40
+ rl.close();
41
+ }
42
+ }
43
+ /**
44
+ * Settles which workspace setup is about to write to, out loud.
45
+ *
46
+ * Setup reuses a stored session when one exists, which is right — nobody wants
47
+ * to re-authenticate to reconfigure a client. But the workspace that session is
48
+ * scoped to was chosen at login, possibly weeks ago and in another repository,
49
+ * and setup never said which one it was. Running it in a new repo after
50
+ * creating a new workspace therefore succeeded loudly and wired everything to
51
+ * the old workspace: fourteen green ticks, not one of them naming the target.
52
+ *
53
+ * The browser consent screen already has a workspace picker for accounts with
54
+ * more than one membership, so switching is a matter of routing back through
55
+ * login rather than building a second picker here. The CLI deliberately does
56
+ * not enumerate workspaces itself: its token is scoped to one company, and a
57
+ * token for company A should not be able to list company B.
58
+ */
59
+ async function confirmWorkspace(args, credentials) {
60
+ const requested = argValue(args, "--company") ?? argValue(args, "--workspace");
61
+ const current = credentials.company || credentials.companyCode || credentials.companyId;
62
+ const matchesRequest = !requested ||
63
+ requested === credentials.companyId ||
64
+ requested.toLowerCase() === (credentials.companyCode ?? "").toLowerCase() ||
65
+ requested.toLowerCase() === (credentials.company ?? "").toLowerCase();
66
+ // An explicit --company that the stored session does not satisfy must never
67
+ // be quietly ignored: the caller stated a target, and setup writes files.
68
+ if (!matchesRequest) {
69
+ console.log(`Stored session is for workspace "${current}", but --company ${requested} was requested.`);
70
+ console.log("Re-authenticating to switch workspace…\n");
71
+ await login(loginArgs(args, requested));
72
+ return requireCredentials();
73
+ }
74
+ console.log(`\nWorkspace: ${current}`);
75
+ const nonInteractive = args.includes("--non-interactive") || args.includes("--yes") || !process.stdin.isTTY;
76
+ if (nonInteractive) {
77
+ console.log("Everything below is registered here. Pass --company <id> to target a different workspace.\n");
78
+ return credentials;
79
+ }
80
+ console.log("Everything below — MCP client config, agent registration, instruction files — is registered here.");
81
+ if (await askYesNo("Continue with this workspace?"))
82
+ return credentials;
83
+ // No company is forwarded: the browser consent screen lists every workspace
84
+ // the account belongs to, which is the point of coming back here.
85
+ console.log("\nSwitching workspace — choose one in the browser…\n");
86
+ await login(loginArgs(args, null));
87
+ const switched = requireCredentials();
88
+ console.log(`\nWorkspace: ${switched.company || switched.companyId}\n`);
89
+ return switched;
90
+ }
7
91
  function instructionRuntimeCodeForClient(code) {
8
92
  switch (code) {
9
93
  case "continue-dev":
@@ -27,7 +111,7 @@ export async function setup(args) {
27
111
  console.log("No active Nexarch session found. Starting login flow…\n");
28
112
  await login(args);
29
113
  }
30
- requireCredentials(); // ensure login succeeded before continuing
114
+ await confirmWorkspace(args, requireCredentials()); // ensure login succeeded, and name the target
31
115
  let registry;
32
116
  try {
33
117
  registry = await fetchAgentRegistryOrThrow();
package/dist/index.js CHANGED
@@ -84,6 +84,10 @@ Usage:
84
84
  nexarch logout Remove stored credentials
85
85
  nexarch status Check connection and show architecture summary
86
86
  nexarch setup One-step onboarding: login (if needed) + MCP config + register agent
87
+ Names the workspace it will write to and confirms it before
88
+ registering anything; answer 'n' to pick a different one.
89
+ Options: --company <id|code> target a workspace directly
90
+ --yes accept the stored workspace without asking
87
91
  nexarch mcp-config Print MCP server config block for manual setup
88
92
  Client list is registry-managed (see 'nexarch mcp-config --client <code>')
89
93
  nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.12.7",
3
+ "version": "0.12.9",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",