nexarch 0.9.31 → 0.10.1

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.
@@ -1333,7 +1333,7 @@ export async function initAgent(args) {
1333
1333
  console.log(` Trust attestation unavailable (${trustAttestation?.reason ?? "unknown"}).`);
1334
1334
  }
1335
1335
  }
1336
- if (needsIdentityInput) {
1336
+ if (needsIdentityInput && !fromSetup) {
1337
1337
  console.log("\nℹ Additional identity details are still needed to complete agent profile enrichment.");
1338
1338
  console.log(` Missing: ${identityCapture.missingRequired.join(", ")}`);
1339
1339
  console.log(" In an interactive terminal, rerun 'npx nexarch@latest init-agent' and answer prompts.");
@@ -1490,7 +1490,8 @@ export async function initProject(args) {
1490
1490
  // Upsert entities (chunked for progressive feedback)
1491
1491
  const entityChunks = chunkArray(entities, Math.max(1, upsertBatchSize));
1492
1492
  const entitiesResult = {
1493
- summary: { requested: 0, succeeded: 0, failed: 0 },
1493
+ summary: { requested: 0, succeeded: 0, failed: 0, preserved: 0 },
1494
+ preserved: [],
1494
1495
  errors: [],
1495
1496
  };
1496
1497
  logProgress("upsert.entities.start", `count=${entities.length}, batches=${entityChunks.length}, batchSize=${Math.max(1, upsertBatchSize)}`);
@@ -1511,7 +1512,10 @@ export async function initProject(args) {
1511
1512
  }
1512
1513
  entitiesResult.summary.requested = Number(entitiesResult.summary.requested ?? 0) + Number(chunkResult.summary?.requested ?? chunk.length);
1513
1514
  entitiesResult.summary.succeeded = Number(entitiesResult.summary.succeeded ?? 0) + Number(chunkResult.summary?.succeeded ?? 0);
1515
+ entitiesResult.summary.preserved = Number(entitiesResult.summary.preserved ?? 0) + Number(chunkResult.summary?.preserved ?? 0);
1514
1516
  entitiesResult.summary.failed = Number(entitiesResult.summary.failed ?? 0) + Number(chunkResult.summary?.failed ?? 0);
1517
+ if (chunkResult.preserved?.length)
1518
+ entitiesResult.preserved.push(...chunkResult.preserved);
1515
1519
  if (chunkResult.errors?.length)
1516
1520
  entitiesResult.errors.push(...chunkResult.errors);
1517
1521
  logProgress("upsert.entities.batch.done", `${i + 1}/${entityChunks.length} succeeded=${chunkResult.summary?.succeeded ?? 0}, failed=${chunkResult.summary?.failed ?? 0}`);
@@ -1620,11 +1624,20 @@ export async function initProject(args) {
1620
1624
  addRelationship: `nexarch add-relationship --from "decision_record:${projectSlug}_<adr_slug>" --to "${projectExternalKey}" --type decides`,
1621
1625
  },
1622
1626
  });
1627
+ const preservedEntities = entitiesResult.preserved ?? [];
1623
1628
  return {
1624
1629
  status: "enrichment_required",
1625
1630
  note: refreshMode
1626
1631
  ? "Execute ALL pendingSteps. In refresh mode, compare graphState vs scanState to identify gaps — do not blindly remove relationships the scanner missed; the scanner cannot detect platforms, integrations, data assets, or application_functions."
1627
1632
  : "Execute ALL pendingSteps before reporting the project as registered. Do not pause or ask for confirmation between steps.",
1633
+ ...(refreshMode && preservedEntities.length > 0
1634
+ ? {
1635
+ preservedEntities: {
1636
+ note: "These entities already have enriched content and were NOT overwritten by the scan. Review the scan values — if anything has genuinely changed, update with nexarch update-entity.",
1637
+ entities: preservedEntities,
1638
+ },
1639
+ }
1640
+ : {}),
1628
1641
  projectEntity: {
1629
1642
  externalKey: projectExternalKey,
1630
1643
  entityType: entityTypeOverride,
@@ -1709,11 +1722,19 @@ export async function initProject(args) {
1709
1722
  // This is addressed to the *calling agent* (Claude Code, Codex, etc.) and tells it
1710
1723
  // to act inline in this same session — not to queue enrichment for later.
1711
1724
  function buildEnrichmentDirective() {
1725
+ const preservedEntities = entitiesResult.preserved ?? [];
1712
1726
  const lines = [];
1713
- lines.push("─── ENRICHMENT REQUIRED ─────────────────────────────────────────────────");
1714
- lines.push("init-project wrote a skeleton. Complete enrichment below — do not ask the");
1715
- lines.push("user for permission, do not summarise and pause, just execute the steps.");
1716
- lines.push("Do NOT report the project as registered until enrichment is done.");
1727
+ if (refreshMode) {
1728
+ lines.push("─── REFRESH REVIEW REQUIRED ──────────────────────────────────────────────");
1729
+ lines.push("update-project refreshed the scan. Review enriched entities and complete any");
1730
+ lines.push("new skeletons below do not ask the user for permission, just execute.");
1731
+ }
1732
+ else {
1733
+ lines.push("─── ENRICHMENT REQUIRED ─────────────────────────────────────────────────");
1734
+ lines.push("init-project wrote a skeleton. Complete enrichment below — do not ask the");
1735
+ lines.push("user for permission, do not summarise and pause, just execute the steps.");
1736
+ lines.push("Do NOT report the project as registered until enrichment is done.");
1737
+ }
1717
1738
  lines.push("");
1718
1739
  lines.push(`PROJECT : ${projectExternalKey}`);
1719
1740
  lines.push(`DIR : ${dir}`);
@@ -1759,6 +1780,19 @@ export async function initProject(args) {
1759
1780
  if (unresolvedItems.length > 20)
1760
1781
  lines.push(` … and ${unresolvedItems.length - 20} more`);
1761
1782
  }
1783
+ if (refreshMode && preservedEntities.length > 0) {
1784
+ lines.push("");
1785
+ lines.push(`ENRICHED (${preservedEntities.length} — already have descriptions; not overwritten by scan):`);
1786
+ lines.push(" Review each entry. If the scan detected a real change, run update-entity manually.");
1787
+ for (const p of preservedEntities) {
1788
+ lines.push(` ${p.externalKey ?? "?"}`);
1789
+ lines.push(` current : name="${p.currentValues?.name ?? ""}" subtype="${p.currentValues?.entitySubtypeCode ?? ""}"`);
1790
+ lines.push(` scan : name="${p.scanValues?.name ?? ""}" subtype="${p.scanValues?.entitySubtypeCode ?? ""}"`);
1791
+ if (p.currentValues?.name !== p.scanValues?.name || p.currentValues?.entitySubtypeCode !== p.scanValues?.entitySubtypeCode) {
1792
+ lines.push(` ⚠ values differ — review and update if the change is real`);
1793
+ }
1794
+ }
1795
+ }
1762
1796
  lines.push("");
1763
1797
  lines.push("THEN_RUN (execute these steps — do not pause or ask for confirmation):");
1764
1798
  let step = 1;
@@ -1848,7 +1882,8 @@ export async function initProject(args) {
1848
1882
  }
1849
1883
  console.log(`\nDone.`);
1850
1884
  console.log(` Mode : ${refreshMode ? "refresh (update-project)" : "init"}`);
1851
- console.log(` Entities : ${output.entities.succeeded ?? 0} written, ${output.entities.failed ?? 0} failed`);
1885
+ const preservedCount = output.entities.preserved ?? 0;
1886
+ console.log(` Entities : ${output.entities.succeeded ?? 0} written, ${preservedCount > 0 ? `${preservedCount} preserved (enriched), ` : ""}${output.entities.failed ?? 0} failed`);
1852
1887
  console.log(` Relationships: ${output.relationships.succeeded ?? 0} written`);
1853
1888
  console.log(" Status : skeleton created; enrichment pending");
1854
1889
  if (output.metrics.relationshipsSkippedAsDuplicate > 0) {
@@ -6,6 +6,10 @@ function renderConfigForProfile(profile) {
6
6
  if (profile.mergeStrategy === "continue_style") {
7
7
  return { mcpServers: [{ name: "nexarch", ...serverBlock }] };
8
8
  }
9
+ if (profile.mergeStrategy === "codex_style") {
10
+ const args = profile.serverArgs.map((a) => JSON.stringify(a)).join(", ");
11
+ return `[mcp_servers.nexarch]\ncommand = ${JSON.stringify(profile.serverCommand)}\nargs = [${args}]`;
12
+ }
9
13
  return { mcpServers: { nexarch: serverBlock } };
10
14
  }
11
15
  export async function mcpConfig(args) {
@@ -43,7 +47,7 @@ If your client requires an MCP server URL instead of command/args, use:
43
47
  const config = renderConfigForProfile(profile);
44
48
  console.log(`\nUsing integration registry release v${registry.release.version}.`);
45
49
  console.log(`\nMCP server config for ${profile.code} (${profile.name}):\n`);
46
- console.log(JSON.stringify(config, null, 2));
50
+ console.log(typeof config === "string" ? config : JSON.stringify(config, null, 2));
47
51
  const platformKey = process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "win32" : "linux";
48
52
  const locations = profile.osPaths?.[platformKey] ?? [];
49
53
  if (locations.length > 0) {
@@ -67,9 +67,9 @@ export async function setup(args) {
67
67
  if (clients.length > 0) {
68
68
  const names = clients.map((c) => c.name);
69
69
  const listed = names.length === 1 ? names[0] : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
70
- console.log(`\nSetup complete. Open a new ${listed} session Nexarch will self-register on startup.`);
70
+ console.log(`\nSetup complete. Open a new ${listed} session and ask your agent to "register with Nexarch".`);
71
71
  }
72
72
  else {
73
- console.log("\nSetup complete. Once you have configured an MCP client (see above), open a new session Nexarch will self-register on startup.");
73
+ console.log('\nSetup complete. Once you have configured an MCP client (see above), open a new session and ask your agent to "register with Nexarch".');
74
74
  }
75
75
  }
@@ -60,12 +60,25 @@ function mergeFlatStyle(existing, serverBlock) {
60
60
  config.mcpServers = servers;
61
61
  return JSON.stringify(config, null, 2);
62
62
  }
63
+ function mergeCodexStyle(existing, serverBlock) {
64
+ const sb = serverBlock;
65
+ const command = sb.command ?? "npx";
66
+ const args = (sb.args ?? []).map((a) => JSON.stringify(a)).join(", ");
67
+ const section = `[mcp_servers.nexarch]\ncommand = ${JSON.stringify(command)}\nargs = [${args}]\n`;
68
+ const sectionPattern = /\[mcp_servers\.nexarch\][\s\S]*?(?=\n\[|\n*$)/;
69
+ if (sectionPattern.test(existing)) {
70
+ return existing.replace(sectionPattern, section.trimEnd());
71
+ }
72
+ return existing + (existing.length > 0 && !existing.endsWith("\n") ? "\n" : "") + "\n" + section;
73
+ }
63
74
  function mergeForStrategy(strategy) {
64
75
  switch (strategy) {
65
76
  case "claude_style":
66
77
  return mergeClaudeStyle;
67
78
  case "continue_style":
68
79
  return mergeContinueStyle;
80
+ case "codex_style":
81
+ return mergeCodexStyle;
69
82
  case "flat_style":
70
83
  default:
71
84
  return mergeFlatStyle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.9.31",
3
+ "version": "0.10.1",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",