@inkobytes/nexus 1.0.0 → 1.0.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.
@@ -0,0 +1,124 @@
1
+ /**
2
+ * nexus completion zsh
3
+ * Print shell completion scripts.
4
+ */
5
+
6
+ export default function completion(args) {
7
+ const shell = args[0] || 'zsh';
8
+
9
+ switch (shell) {
10
+ case 'zsh':
11
+ console.log(buildZshCompletion());
12
+ return;
13
+ case '--help':
14
+ case '-h':
15
+ case 'help':
16
+ printHelp();
17
+ return;
18
+ default:
19
+ throw new Error(`Unsupported completion shell: ${shell}`);
20
+ }
21
+ }
22
+
23
+ function printHelp() {
24
+ console.log(`Usage: nexus completion zsh
25
+
26
+ Print a shell completion script for Nexus.
27
+
28
+ Example:
29
+ source <(nexus completion zsh)
30
+ `);
31
+ }
32
+
33
+ function buildZshCompletion() {
34
+ return `#compdef nexus
35
+
36
+ local -a commands
37
+ commands=(
38
+ 'init:Scaffold Nexus files into current repo'
39
+ 'doctor:Check or repair agent protocol files'
40
+ 'completion:Print a shell completion script'
41
+ 'checkin:Signal agent presence'
42
+ 'checkout:Signal session end or cleanup'
43
+ 'claim:Lock a file or directory'
44
+ 'release:Unlock, auto-commit, and log'
45
+ 'standup:Append a validated standup line'
46
+ 'status:Show current blackboard state'
47
+ 'clean:Prune locks'
48
+ 'next:Suggest next safe task from queue'
49
+ 'start:Orient an agent entering this repo'
50
+ 'dashboard:Serve the local dashboard'
51
+ 'metrics:Summarize commits, releases, and queue cost'
52
+ 'ledger:Show or backfill completed task ledger'
53
+ 'chmod:Show or set promptCHMOD permissions'
54
+ 'db:Database backup and recovery'
55
+ 'drill:Inspect or run protocol drills'
56
+ 'soul:Manage local soul overlay in agent files'
57
+ 'help:Show command help'
58
+ )
59
+
60
+ local -a drill_actions db_actions
61
+ drill_actions=(list show run report help)
62
+ db_actions=(backup list restore schedule)
63
+
64
+ case $CURRENT in
65
+ 2)
66
+ _describe 'nexus command' commands
67
+ return
68
+ ;;
69
+ esac
70
+
71
+ case $words[2] in
72
+ checkin|checkout|next)
73
+ _arguments '1:agent:(@agy @claude @codex @gemini)'
74
+ ;;
75
+ claim)
76
+ _arguments \\
77
+ '1:path:_files' \\
78
+ '2:agent:(@agy @claude @codex @gemini)' \\
79
+ '3:intent:_message' \\
80
+ '--agent[Agent handle]:agent:(@agy @claude @codex @gemini)' \\
81
+ '--intent[Claim intent]:intent:_message'
82
+ ;;
83
+ release)
84
+ _arguments '1:path:_files' '2:commit message:_message'
85
+ ;;
86
+ standup)
87
+ _arguments '1:standup message:_message'
88
+ ;;
89
+ doctor)
90
+ _arguments '--fix[Repair known protocol drift]' '--json[Print JSON report]'
91
+ ;;
92
+ completion)
93
+ _arguments '1:shell:(zsh)'
94
+ ;;
95
+ clean)
96
+ _arguments '1:target or flag:(--stale)'
97
+ ;;
98
+ dashboard)
99
+ _arguments '--serve[Start the dashboard server]' '--port[Dashboard port]:port number:'
100
+ ;;
101
+ metrics)
102
+ _arguments '--json[Print JSON]'
103
+ ;;
104
+ ledger)
105
+ _arguments '1:mode:(backfill --json)'
106
+ ;;
107
+ chmod)
108
+ _arguments '--list[List current permissions]' '--init[Initialize promptCHMOD permissions]'
109
+ ;;
110
+ db)
111
+ _arguments '1:db action:(\${db_actions[*]})'
112
+ ;;
113
+ drill)
114
+ _arguments '1:drill action:(\${drill_actions[*]})'
115
+ ;;
116
+ soul)
117
+ _arguments '--file[Overlay file path]:path:_files' '--status[Show status]' '--remove[Remove overlay]'
118
+ ;;
119
+ start)
120
+ _arguments '--agent[Agent handle]:agent:(@agy @claude @codex @gemini)'
121
+ ;;
122
+ esac
123
+ `;
124
+ }
@@ -54,6 +54,7 @@ export function buildSnapshot() {
54
54
  const queueText = readText(config.queue);
55
55
  const standupText = readText(config.standup);
56
56
  const reportText = readText(config.report);
57
+ const parsedReport = parseReportBlocks(reportText);
57
58
  const git = getGitStatus(config.root);
58
59
 
59
60
  return {
@@ -69,6 +70,8 @@ export function buildSnapshot() {
69
70
  ledger: readLedgerEntries().reverse(),
70
71
  standup: parseStandupEntries(standupText).filter(entry => entry.type.startsWith('@')).slice(-8).reverse(),
71
72
  releases: parseReleaseEntries(reportText).slice(-16).reverse(),
73
+ reportIntro: parsedReport.intro,
74
+ reportBlocks: parsedReport.blocks,
72
75
  report: sortReportBlocksLatestFirst(reportText),
73
76
  };
74
77
  }
@@ -364,6 +367,70 @@ function hasReleaseDetailValue(detail) {
364
367
  return detail.slice(colon + 1).trim().length > 0;
365
368
  }
366
369
 
370
+ function parseReportBlocks(content) {
371
+ const trimmed = content.trim();
372
+ if (!trimmed) return { intro: '', blocks: [] };
373
+
374
+ const firstBlock = trimmed.search(/^## \[/m);
375
+ if (firstBlock === -1) return { intro: trimmed, blocks: [] };
376
+
377
+ const intro = trimmed.slice(0, firstBlock).trimEnd();
378
+ const blocks = trimmed
379
+ .slice(firstBlock)
380
+ .split(/\n(?=## \[)/)
381
+ .map((block) => block.trimEnd())
382
+ .filter(Boolean)
383
+ .reverse()
384
+ .map((block, index) => {
385
+ const lines = block.split('\n');
386
+ const heading = lines[0]?.match(/^## \[([^\]]+)\]\s*(.*)$/);
387
+ const timestamp = heading?.[1]?.trim() || '';
388
+ const target = heading?.[2]?.trim() || lines[0]?.replace(/^##\s*/, '') || '';
389
+ const details = lines.slice(1).join('\n').trim();
390
+ const parsed = parseReportTimestamp(timestamp);
391
+ const monthKey = parsed
392
+ ? `${parsed.getFullYear()}-${String(parsed.getMonth() + 1).padStart(2, '0')}`
393
+ : '';
394
+
395
+ return {
396
+ id: `report-${index}`,
397
+ timestamp,
398
+ target,
399
+ details,
400
+ raw: block,
401
+ monthKey,
402
+ monthLabel: parsed ? formatReportMonth(parsed) : 'Undated',
403
+ };
404
+ });
405
+
406
+ return { intro, blocks };
407
+ }
408
+
409
+ function parseReportTimestamp(value) {
410
+ const match = String(value || '').match(
411
+ /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{1,2}):(\d{2})(?::(\d{2}))?(?:\s?(AM|PM|am|pm))?)?$/
412
+ );
413
+ if (!match) return null;
414
+
415
+ const year = Number.parseInt(match[1], 10);
416
+ const month = Number.parseInt(match[2], 10) - 1;
417
+ const day = Number.parseInt(match[3], 10);
418
+ let hour = Number.parseInt(match[4] || '0', 10);
419
+ const minute = Number.parseInt(match[5] || '0', 10);
420
+ const second = Number.parseInt(match[6] || '0', 10);
421
+ const meridiem = (match[7] || '').toUpperCase();
422
+
423
+ if (meridiem === 'PM' && hour < 12) hour += 12;
424
+ if (meridiem === 'AM' && hour === 12) hour = 0;
425
+
426
+ const date = new Date(year, month, day, hour, minute, second);
427
+ return Number.isNaN(date.getTime()) ? null : date;
428
+ }
429
+
430
+ function formatReportMonth(date) {
431
+ return date.toLocaleString('en-US', { month: 'long', year: 'numeric' });
432
+ }
433
+
367
434
  function sortReportBlocksLatestFirst(content) {
368
435
  const trimmed = content.trim();
369
436
  if (!trimmed) return content;