@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 +2 -1
- package/package.json +1 -1
- package/src/commands/doctor.js +134 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.0.
|
|
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
package/src/commands/doctor.js
CHANGED
|
@@ -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
|
|
616
|
-
fix: '
|
|
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();
|