@inkobytes/nexus 1.0.3 → 1.0.4

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/CHANGELOG.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # Changelog
2
2
 
3
- ## 1.0.3 - 2026-06-03
3
+ ## 1.0.4 - 2026-06-03
4
4
 
5
5
  - Collapsed large `nexus doctor` Git Privacy floods into grouped per-root summaries with sample paths.
6
6
  - Prioritized `CONTINUITY.md` and `memories/` samples first so agent-local issues stay visible.
7
7
  - Collapsed shared agent roots like `.claude/`, `.codex/`, and `.gemini/` into one concise Git Privacy note for repos that intentionally track them.
8
8
  - Colorized `nexus doctor` output and grouped findings under clearer action buckets like `Fix the following` and `Review / informational`.
9
9
  - Added `.nexus/config.json` support for `doctor.allowTrackedAgentTrees` so intentionally tracked shared agent trees can be treated as informational.
10
+ - Reformatted lock and queue findings into compact field-style output like `file`, `by`, `needs`, `impact`, and shorter `fix` lines.
10
11
 
11
12
  ## 1.0.1 - 2026-06-02
12
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkobytes/nexus",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Multi-agent coordination CLI for coding agents sharing a local repository",
5
5
  "type": "module",
6
6
  "bin": {
@@ -521,6 +521,13 @@ export default function doctor(args) {
521
521
  sections.Locks.push({
522
522
  issue: `Stale lock on ${lock.target} (${lock.age}s old)`,
523
523
  fix: 'Run `nexus clean --stale`.',
524
+ displayGroup: lock.target,
525
+ lockInfo: {
526
+ target: lock.target,
527
+ agent: lock.agent || '',
528
+ kind: 'stale',
529
+ age: `${lock.age}s old`,
530
+ },
524
531
  });
525
532
  }
526
533
  }
@@ -532,18 +539,38 @@ export default function doctor(args) {
532
539
  issue: `Active lock on ${lock.target} (${age})`,
533
540
  fix: 'No action if the agent is still working. Use `nexus status` to inspect.',
534
541
  ok: true,
542
+ displayGroup: lock.target,
543
+ lockInfo: {
544
+ target: lock.target,
545
+ agent: lock.agent || '',
546
+ kind: 'active',
547
+ age,
548
+ },
535
549
  });
536
550
  if (!lock.model) {
537
551
  sections.Locks.push({
538
552
  issue: `Active lock on ${lock.target} has no --model metadata`,
539
553
  fix: 'Use `nexus claim ... --model <name>` for future claims; only the human operator can declare the real model.',
540
554
  ok: true,
555
+ displayGroup: lock.target,
556
+ lockInfo: {
557
+ target: lock.target,
558
+ agent: lock.agent || '',
559
+ kind: 'missing_model',
560
+ },
541
561
  });
542
562
  }
543
563
  if (!lock.verified) {
544
564
  sections.Locks.push({
545
565
  issue: `Unverified claim on ${lock.target} by ${lock.agent} (trust: ${lock.trustSource}) — no CLAUDECODE or NEXUS_AGENT env detected at claim time`,
546
566
  fix: 'If this is a local/unverified model, set NEXUS_AGENT=@handle before claiming. If unexpected, inspect the lock.',
567
+ displayGroup: lock.target,
568
+ lockInfo: {
569
+ target: lock.target,
570
+ agent: lock.agent || '',
571
+ kind: 'unverified',
572
+ trustSource: lock.trustSource,
573
+ },
547
574
  });
548
575
  }
549
576
  }
@@ -612,8 +639,15 @@ export default function doctor(args) {
612
639
  if (unapproved.length) {
613
640
  for (const id of unapproved) {
614
641
  sections['Queue Authorship'].push({
615
- issue: `Task "${id}" is auto-flow: yes in Ready Queue but missing Review: approved — nexus next will skip it`,
616
- fix: 'Add "- Review: approved" and "- Approved by: human" to the task, or move it to ## Proposed Queue.',
642
+ issue: `Task "${id}" is missing Review: approved`,
643
+ fix: 'add `Review: approved` and `Approved by: human`, or move it to `## Proposed Queue`',
644
+ displayGroup: id,
645
+ queueInfo: {
646
+ taskId: id,
647
+ state: 'auto-flow: yes in Ready Queue',
648
+ needs: 'Review: approved',
649
+ impact: 'nexus next will skip it',
650
+ },
617
651
  });
618
652
  }
619
653
  } else {
@@ -693,6 +727,14 @@ export default function doctor(args) {
693
727
 
694
728
  function renderEntryBucket(label, entries, headingColor, markerColor, sectionTitle, colors) {
695
729
  console.log(` ${headingColor(label)}`);
730
+ if (sectionTitle === 'Locks') {
731
+ renderLockEntries(entries, markerColor, colors);
732
+ return;
733
+ }
734
+ if (sectionTitle === 'Queue Authorship') {
735
+ renderQueueEntries(entries, markerColor, colors);
736
+ return;
737
+ }
696
738
  const groups = groupEntriesForDisplay(entries, sectionTitle);
697
739
  for (const group of groups) {
698
740
  if (group.label) {
@@ -715,6 +757,96 @@ function renderEntryBucket(label, entries, headingColor, markerColor, sectionTit
715
757
  }
716
758
  }
717
759
 
760
+ function renderLockEntries(entries, markerColor, colors) {
761
+ const groups = new Map();
762
+
763
+ for (const entry of entries) {
764
+ const target = entry.lockInfo?.target || entry.displayGroup || entry.issue;
765
+ if (!groups.has(target)) groups.set(target, []);
766
+ groups.get(target).push(entry);
767
+ }
768
+
769
+ for (const [target, lockEntries] of groups) {
770
+ const agent = lockEntries.find((entry) => entry.lockInfo?.agent)?.lockInfo?.agent || '';
771
+ console.log(` ${colors.bold(`file: ${target}`)}`);
772
+ console.log(` ${colors.dim(`by: ${agent || 'unknown'}`)}`);
773
+ for (const entry of lockEntries) {
774
+ const prefix = entry.ok ? '-' : '!';
775
+ const state = formatLockState(entry);
776
+ console.log(` ${markerColor(prefix)} ${state}`);
777
+ if (entry.fix) {
778
+ console.log(` ${colors.bold('fix:')} ${colors.dim(compactLockFix(entry))}`);
779
+ }
780
+ }
781
+ }
782
+ }
783
+
784
+ function renderQueueEntries(entries, markerColor, colors) {
785
+ const groups = new Map();
786
+
787
+ for (const entry of entries) {
788
+ const taskId = entry.queueInfo?.taskId || entry.displayGroup || entry.issue;
789
+ if (!groups.has(taskId)) groups.set(taskId, []);
790
+ groups.get(taskId).push(entry);
791
+ }
792
+
793
+ for (const [taskId, taskEntries] of groups) {
794
+ console.log(` ${colors.bold(`task: ${taskId}`)}`);
795
+ for (const entry of taskEntries) {
796
+ const prefix = entry.ok ? '-' : '!';
797
+ const state = entry.queueInfo?.state || entry.issue;
798
+ const needs = entry.queueInfo?.needs;
799
+ const impact = entry.queueInfo?.impact;
800
+ console.log(` ${markerColor(prefix)} ${state}`);
801
+ if (needs) {
802
+ console.log(` ${colors.dim(`needs: ${needs}`)}`);
803
+ }
804
+ if (impact) {
805
+ console.log(` ${colors.dim(`impact: ${impact}`)}`);
806
+ }
807
+ if (entry.fix) {
808
+ console.log(` ${colors.bold('fix:')} ${colors.dim(entry.fix)}`);
809
+ }
810
+ }
811
+ }
812
+ }
813
+
814
+ function formatLockState(entry) {
815
+ const info = entry.lockInfo;
816
+ if (!info) return entry.issue;
817
+
818
+ switch (info.kind) {
819
+ case 'stale':
820
+ return `stale lock (${info.age})`;
821
+ case 'active':
822
+ return `active lock (${info.age})`;
823
+ case 'missing_model':
824
+ return 'missing --model metadata';
825
+ case 'unverified':
826
+ return `unverified claim (trust: ${info.trustSource || 'unknown'})`;
827
+ default:
828
+ return entry.issue;
829
+ }
830
+ }
831
+
832
+ function compactLockFix(entry) {
833
+ const info = entry.lockInfo;
834
+ if (!info) return entry.fix;
835
+
836
+ switch (info.kind) {
837
+ case 'stale':
838
+ return 'run `nexus clean --stale`';
839
+ case 'active':
840
+ return 'leave it if someone is working, or inspect with `nexus status`';
841
+ case 'missing_model':
842
+ return 'use `nexus claim ... --model <name>` on future claims';
843
+ case 'unverified':
844
+ return 'set `NEXUS_AGENT=@handle` for local claims, or inspect the lock';
845
+ default:
846
+ return entry.fix;
847
+ }
848
+ }
849
+
718
850
  function groupEntriesForDisplay(entries, sectionTitle) {
719
851
  const groups = [];
720
852
  const grouped = new Map();