pi-anchor 0.4.0 → 0.5.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.
package/bin/anchor.js CHANGED
@@ -7,6 +7,7 @@
7
7
  import {
8
8
  AnchorStore,
9
9
  formatOrigin,
10
+ formatProgressBar,
10
11
  formatRelativeAge,
11
12
  sortAnchorsForDisplay,
12
13
  padToWidth
@@ -29,21 +30,22 @@ if (args.length === 0 || args[0] === 'list' || args[0] === 'ls') {
29
30
  const sorted = sortAnchorsForDisplay(allNotes, process.cwd());
30
31
  console.log(`\n⌖ Notes (${sorted.length}):\n`);
31
32
 
32
- sorted.forEach((a, idx) => {
33
- const num = String(idx + 1).padStart(2, '0');
34
- const origin = formatOrigin(a);
33
+ sorted.forEach((a) => {
34
+ const num = a.id.replace(/^anc-/, '').padStart(2, '0');
35
+ const bar = a.progress ? `${formatProgressBar(a.progress)} ` : '';
36
+ const origin = formatOrigin(a) + (a.sessionFile ? ' ↪' : '');
35
37
  const age = a.status === 'sleeping'
36
38
  ? `${formatRelativeAge(a.createdAt)} · quiet`
37
39
  : formatRelativeAge(a.createdAt);
38
40
 
39
41
  const colNum = ` ${num} `;
40
- const colTitle = padToWidth(a.title, 42);
42
+ const colTitle = padToWidth(`${bar}${a.title}`, 42);
41
43
  const colOrigin = padToWidth(origin, 22);
42
44
 
43
45
  console.log(`${colNum}${colTitle} ${colOrigin} ${age}`);
44
46
  });
45
47
 
46
- console.log('\n Run `anchor done <num>` to tear off, or `anchor undo` to put back.\n');
48
+ console.log('\n Run `anchor step <num>` (+1 step), `anchor done <num>` (tear off), or `anchor undo`.\n');
47
49
  process.exit(0);
48
50
  }
49
51
 
@@ -59,21 +61,49 @@ if (args[0] === 'undo') {
59
61
  process.exit(0);
60
62
  }
61
63
 
62
- // 3. Help: `anchor --help`
64
+ // 3. Advance progress bar: `anchor step <num>`
65
+ if (args[0] === 'step' || args[0] === '+') {
66
+ const idInput = args[1] || '1';
67
+ const delta = args[2] ? parseInt(args[2], 10) : 1;
68
+ try {
69
+ const direct = store.get(idInput);
70
+ let targetId = direct ? direct.id : idInput;
71
+ if (!direct && /^\d+$/.test(idInput)) {
72
+ const allNotes = store
73
+ .list({ cwd: process.cwd(), all: true })
74
+ .filter(a => a.status === 'active' || a.status === 'sleeping');
75
+ const sorted = sortAnchorsForDisplay(allNotes, process.cwd());
76
+ const seqIndex = parseInt(idInput, 10);
77
+ if (seqIndex >= 1 && seqIndex <= sorted.length) {
78
+ targetId = sorted[seqIndex - 1].id;
79
+ }
80
+ }
81
+
82
+ const { anchor: updated } = store.step(targetId, isNaN(delta) ? 1 : delta);
83
+ console.log(`⌖ Advanced #${updated.id.replace(/^anc-/, '')} to ${formatProgressBar(updated.progress)}: "${updated.title}"`);
84
+ } catch (err) {
85
+ console.error(`Error: ${err.message}`);
86
+ process.exit(1);
87
+ }
88
+ process.exit(0);
89
+ }
90
+
91
+ // 4. Help: `anchor --help`
63
92
  if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
64
93
  console.log(`
65
94
  ⌖ Anchor — Digital sticky notes for AI coding sessions
66
95
 
67
96
  Usage:
68
97
  anchor View all sticky notes
69
- anchor "<note>" Stick a new note
98
+ anchor "<note>" Stick a new note (supports [1/4] or 1. A 2. B progress steps)
99
+ anchor step <num> Advance progress bar on a note (e.g. anchor step 1)
70
100
  anchor done <num> Tear off a completed note (e.g. anchor done 1)
71
101
  anchor undo Put back the last torn-off note
72
102
  `);
73
103
  process.exit(0);
74
104
  }
75
105
 
76
- // 4. Tear off note: `anchor done <num>`
106
+ // 5. Tear off note: `anchor done <num>`
77
107
  if (args[0] === 'done' || args[0] === 'rm' || args[0] === 'close') {
78
108
  const idInput = args[1];
79
109
  if (!idInput) {
@@ -81,13 +111,13 @@ if (args[0] === 'done' || args[0] === 'rm' || args[0] === 'close') {
81
111
  process.exit(1);
82
112
  }
83
113
  try {
84
- const allNotes = store
85
- .list({ cwd: process.cwd(), all: true })
86
- .filter(a => a.status === 'active' || a.status === 'sleeping');
87
- const sorted = sortAnchorsForDisplay(allNotes, process.cwd());
88
-
89
- let targetId = idInput;
90
- if (/^\d+$/.test(idInput)) {
114
+ const direct = store.get(idInput);
115
+ let targetId = direct ? direct.id : idInput;
116
+ if (!direct && /^\d+$/.test(idInput)) {
117
+ const allNotes = store
118
+ .list({ cwd: process.cwd(), all: true })
119
+ .filter(a => a.status === 'active' || a.status === 'sleeping');
120
+ const sorted = sortAnchorsForDisplay(allNotes, process.cwd());
91
121
  const seqIndex = parseInt(idInput, 10);
92
122
  if (seqIndex >= 1 && seqIndex <= sorted.length) {
93
123
  targetId = sorted[seqIndex - 1].id;
@@ -103,7 +133,7 @@ if (args[0] === 'done' || args[0] === 'rm' || args[0] === 'close') {
103
133
  process.exit(0);
104
134
  }
105
135
 
106
- // 5. Stick a new note: `anchor <note text>`
136
+ // 6. Stick a new note: `anchor <note text>`
107
137
  const title = args.join(' ').trim();
108
138
  if (!title) {
109
139
  console.error('Error: Note text cannot be empty');
@@ -114,4 +144,5 @@ const created = store.create({
114
144
  title,
115
145
  cwd: process.cwd()
116
146
  });
117
- console.log(`⌖ Pinned #${created.id.replace(/^anc-/, '')}: "${created.title}"`);
147
+ const bar = created.progress ? ` ${formatProgressBar(created.progress)}` : '';
148
+ console.log(`⌖ Pinned #${created.id.replace(/^anc-/, '')}${bar}: "${created.title}"`);