nexarch 0.12.1 → 0.12.3

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.
@@ -337,29 +337,28 @@ function canonicalTargetKey(filePath) {
337
337
  const abs = resolve(filePath);
338
338
  return process.platform === "win32" || process.platform === "darwin" ? abs.toLowerCase() : abs;
339
339
  }
340
- function injectAgentConfigs(registry) {
340
+ function injectAgentConfigs(registry, runtimeCode) {
341
341
  const templateByCode = new Map(registry.instructionTemplates.map((t) => [t.code, t]));
342
- const targets = [...registry.instructionTargets].sort((a, b) => a.sortOrder - b.sortOrder || a.filePathPattern.localeCompare(b.filePathPattern));
343
- const results = [];
344
- const seenTargets = new Set();
345
- for (const target of targets) {
346
- if (target.matchMode !== "exact")
347
- continue;
342
+ const sortedTargets = [...registry.instructionTargets]
343
+ .filter((target) => target.matchMode === "exact")
344
+ .sort((a, b) => a.sortOrder - b.sortOrder || a.filePathPattern.localeCompare(b.filePathPattern));
345
+ const candidateTargets = runtimeCode
346
+ ? sortedTargets.filter((target) => target.runtimeCode === runtimeCode)
347
+ : sortedTargets;
348
+ const applyToTarget = (target) => {
348
349
  const template = templateByCode.get(target.templateCode);
349
350
  if (!template)
350
- continue;
351
+ return null;
351
352
  const filePath = join(process.cwd(), target.filePathPattern);
352
- const targetKey = canonicalTargetKey(filePath);
353
- if (seenTargets.has(targetKey))
354
- continue;
355
- seenTargets.add(targetKey);
356
- if (!existsSync(filePath))
357
- continue;
358
- const existing = readFileSync(filePath, "utf8");
359
353
  const sectionBody = template.body.trim();
360
354
  const sectionHeading = target.sectionHeading ?? "## Nexarch Agent Registration";
361
355
  const sectionMarker = target.sectionMarker ?? sectionHeading;
362
356
  const managedBody = wrapManagedSection("agent-registration", sectionBody);
357
+ if (!existsSync(filePath)) {
358
+ writeFileSync(filePath, `${managedBody}\n`, "utf8");
359
+ return { path: filePath, status: "injected" };
360
+ }
361
+ const existing = readFileSync(filePath, "utf8");
363
362
  if (target.insertionMode === "replace_section") {
364
363
  let replaced = replaceManagedSection(existing, "agent-registration", sectionBody);
365
364
  if (replaced === existing) {
@@ -372,29 +371,46 @@ function injectAgentConfigs(registry) {
372
371
  }
373
372
  if (replaced !== existing) {
374
373
  writeFileSync(filePath, replaced, "utf8");
375
- results.push({ path: filePath, status: "updated" });
374
+ return { path: filePath, status: "updated" };
376
375
  }
377
- else if (existing.includes(managedBody) || existing.includes(sectionBody)) {
378
- results.push({ path: filePath, status: "already_present" });
379
- }
380
- else {
381
- const separator = existing.endsWith("\n") ? "" : "\n";
382
- writeFileSync(filePath, existing + separator + managedBody + "\n", "utf8");
383
- results.push({ path: filePath, status: "injected" });
376
+ if (existing.includes(managedBody) || existing.includes(sectionBody)) {
377
+ return { path: filePath, status: "already_present" };
384
378
  }
385
- continue;
379
+ const separator = existing.endsWith("\n") ? "" : "\n";
380
+ writeFileSync(filePath, existing + separator + managedBody + "\n", "utf8");
381
+ return { path: filePath, status: "injected" };
386
382
  }
387
383
  if (existing.includes(managedBody) || existing.includes(sectionBody)) {
388
- results.push({ path: filePath, status: "already_present" });
389
- }
390
- else {
391
- const separator = existing.endsWith("\n") ? "" : "\n";
392
- const next = existing + separator + managedBody + "\n";
393
- writeFileSync(filePath, next, "utf8");
394
- results.push({ path: filePath, status: "injected" });
384
+ return { path: filePath, status: "already_present" };
395
385
  }
386
+ const separator = existing.endsWith("\n") ? "" : "\n";
387
+ const next = existing + separator + managedBody + "\n";
388
+ writeFileSync(filePath, next, "utf8");
389
+ return { path: filePath, status: "injected" };
390
+ };
391
+ const seenTargets = new Set();
392
+ const existingMatches = [];
393
+ for (const target of candidateTargets) {
394
+ const filePath = join(process.cwd(), target.filePathPattern);
395
+ const targetKey = canonicalTargetKey(filePath);
396
+ if (seenTargets.has(targetKey))
397
+ continue;
398
+ seenTargets.add(targetKey);
399
+ if (existsSync(filePath))
400
+ existingMatches.push(target);
401
+ }
402
+ if (existingMatches.length > 0) {
403
+ const results = existingMatches
404
+ .map((target) => applyToTarget(target))
405
+ .filter((result) => Boolean(result));
406
+ if (results.length > 0)
407
+ return results;
408
+ }
409
+ if (runtimeCode && candidateTargets.length > 0) {
410
+ const created = applyToTarget(candidateTargets[0]);
411
+ return created ? [created] : [];
396
412
  }
397
- return results;
413
+ return [];
398
414
  }
399
415
  function injectTrustAttestationBlock(path, attestation) {
400
416
  if (!attestation.token || !attestation.payload)
@@ -1017,6 +1033,7 @@ export async function initAgent(args) {
1017
1033
  detail: "skipped",
1018
1034
  missingRequired: [],
1019
1035
  };
1036
+ let selectedClient = clientArg ?? null;
1020
1037
  if (registration.ok) {
1021
1038
  let provider = providerArg;
1022
1039
  let model = modelArg;
@@ -1026,6 +1043,7 @@ export async function initAgent(args) {
1026
1043
  model = model ?? await promptForValue("Model id (e.g. claude-sonnet-4-6): ", true);
1027
1044
  client = client ?? await promptForValue("Client (e.g. claude-code/cursor/codex-cli): ", true);
1028
1045
  }
1046
+ selectedClient = client ?? null;
1029
1047
  const missingRequired = [
1030
1048
  !provider ? "provider" : null,
1031
1049
  !model ? "model" : null,
@@ -1110,7 +1128,7 @@ export async function initAgent(args) {
1110
1128
  catch {
1111
1129
  // non-fatal
1112
1130
  }
1113
- let existingInstructionTargets = injectAgentConfigs(registry);
1131
+ let existingInstructionTargets = injectAgentConfigs(registry, selectedClient);
1114
1132
  if (existingInstructionTargets.length === 0) {
1115
1133
  existingInstructionTargets = injectGenericAgentConfig(registry);
1116
1134
  }
@@ -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 and ask your agent to register its runtime with Nexarch. Check-in is a separate step when you want to preview work.`);
70
+ console.log(`\nSetup complete. Open a new ${listed} session your Nexarch registration is already in place. If you want the agent to look for pending work, ask it to check in.`);
71
71
  }
72
72
  else {
73
- console.log("\nSetup complete. Once you have configured an MCP client (see above), open a new session and ask your agent to register its runtime with Nexarch. Check-in is a separate step when you want to preview work.");
73
+ console.log("\nSetup complete. Once you have configured an MCP client (see above), open a new session your Nexarch registration is already in place. If you want the agent to look for pending work, ask it to check in.");
74
74
  }
75
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",