pi-anchor 0.1.0
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/LICENSE +21 -0
- package/README.md +273 -0
- package/README_zh.md +272 -0
- package/bin/anchor.js +163 -0
- package/dist/chunk-NNYUD5O7.js +1295 -0
- package/dist/extension.cjs +1560 -0
- package/dist/extension.d.cts +5 -0
- package/dist/extension.d.ts +5 -0
- package/dist/extension.js +312 -0
- package/dist/index.cjs +1433 -0
- package/dist/index.d.cts +448 -0
- package/dist/index.d.ts +448 -0
- package/dist/index.js +144 -0
- package/package.json +64 -0
- package/src/context_injector.ts +157 -0
- package/src/decay.ts +123 -0
- package/src/extension.ts +363 -0
- package/src/index.ts +9 -0
- package/src/matcher.ts +130 -0
- package/src/observer.ts +141 -0
- package/src/pi-types.d.ts +42 -0
- package/src/protocol.ts +95 -0
- package/src/settlement.ts +72 -0
- package/src/store.ts +682 -0
- package/src/tui.ts +386 -0
- package/src/types.ts +104 -0
package/bin/anchor.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Anchor CLI - Minimalist task protocol for AI coding workflows
|
|
5
|
+
* Production-ready executable with dual-timeline & 4-quadrant cognitive grouping
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
AnchorStore,
|
|
10
|
+
classifyAnchor,
|
|
11
|
+
formatOrigin,
|
|
12
|
+
formatTargetDate,
|
|
13
|
+
formatCreationTime,
|
|
14
|
+
groupAnchorsByQuadrant,
|
|
15
|
+
padToWidth
|
|
16
|
+
} from '../dist/index.js';
|
|
17
|
+
|
|
18
|
+
const store = new AnchorStore();
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
|
|
21
|
+
// 1. View pending tasks: `anchor` or `anchor list`
|
|
22
|
+
if (args.length === 0 || args[0] === 'list' || args[0] === 'ls') {
|
|
23
|
+
const active = store.list({ status: 'active', cwd: process.cwd() });
|
|
24
|
+
|
|
25
|
+
if (active.length === 0) {
|
|
26
|
+
console.log('\n⌖ No active anchors. Use `anchor <task>` to record.\n');
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`\n⌖ Anchors (${active.length} active):\n`);
|
|
31
|
+
|
|
32
|
+
const groups = groupAnchorsByQuadrant(active);
|
|
33
|
+
const sections = [
|
|
34
|
+
{ title: 'Today · 今日聚焦', list: groups.today },
|
|
35
|
+
{ title: 'Upcoming · 近期排期', list: groups.upcoming },
|
|
36
|
+
{ title: 'Habits · 每日循环', list: groups.habits },
|
|
37
|
+
{ title: 'Backlog · 长期愿景', list: groups.backlog },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
let seqNum = 1;
|
|
41
|
+
|
|
42
|
+
for (const sec of sections) {
|
|
43
|
+
if (sec.list.length === 0) continue;
|
|
44
|
+
console.log(` [${sec.title}]`);
|
|
45
|
+
sec.list.forEach((a) => {
|
|
46
|
+
const num = seqNum.toString().padStart(2, '0');
|
|
47
|
+
seqNum++;
|
|
48
|
+
|
|
49
|
+
const category = padToWidth(`[${classifyAnchor(a)}]`, 12);
|
|
50
|
+
const origin = formatOrigin(a);
|
|
51
|
+
const target = formatTargetDate(a);
|
|
52
|
+
const created = formatCreationTime(a.createdAt);
|
|
53
|
+
|
|
54
|
+
const titleWithFiles = (a.files && a.files.length > 0)
|
|
55
|
+
? `${a.title} [${a.files.slice(0, 1).join(', ')}]`
|
|
56
|
+
: a.title;
|
|
57
|
+
|
|
58
|
+
const colNum = ` ${num} `;
|
|
59
|
+
const colTitle = padToWidth(titleWithFiles, 28);
|
|
60
|
+
const colOrigin = padToWidth(origin, 10);
|
|
61
|
+
const colTarget = padToWidth(target, 12);
|
|
62
|
+
const colCreated = created;
|
|
63
|
+
|
|
64
|
+
console.log(`${colNum}${category}${colTitle} ${colOrigin} ${colTarget} ${colCreated}`);
|
|
65
|
+
});
|
|
66
|
+
console.log('');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log(' Use `anchor done <id>` to complete.\n');
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2. Undo settlement: `anchor undo`
|
|
74
|
+
if (args[0] === 'undo') {
|
|
75
|
+
try {
|
|
76
|
+
const restored = store.undoSettle();
|
|
77
|
+
console.log(`⌖ Restored #${restored.id}: "${restored.title}"`);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(`Error: ${err.message}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 3. Help: `anchor --help` or `anchor -h`
|
|
86
|
+
if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
|
|
87
|
+
console.log(`
|
|
88
|
+
⌖ Anchor CLI - Cross-session task protocol for AI coding agents
|
|
89
|
+
|
|
90
|
+
Usage:
|
|
91
|
+
anchor List active anchors
|
|
92
|
+
anchor <task> Pin a new task across sessions
|
|
93
|
+
anchor done <id> Settle and evict a task (e.g. anchor done 1)
|
|
94
|
+
anchor undo Restore the last settled task
|
|
95
|
+
|
|
96
|
+
Options:
|
|
97
|
+
-h, --help Show this help message
|
|
98
|
+
-v, --version Show version
|
|
99
|
+
-d, --due <date> Specify expected completion date (e.g. tomorrow, friday, 2026-09-28)
|
|
100
|
+
`);
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 4. Close task: `anchor done <id>` or `anchor rm <id>`
|
|
105
|
+
if (args[0] === 'done' || args[0] === 'rm' || args[0] === 'close') {
|
|
106
|
+
const idInput = args[1];
|
|
107
|
+
if (!idInput) {
|
|
108
|
+
console.error('Usage: anchor done <id>');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
// 1. Check if idInput is a 1-based sequential display number (e.g. '1', '01')
|
|
113
|
+
const active = store.list({ status: 'active', cwd: process.cwd() });
|
|
114
|
+
const groups = groupAnchorsByQuadrant(active);
|
|
115
|
+
const sortedActive = [
|
|
116
|
+
...groups.today,
|
|
117
|
+
...groups.upcoming,
|
|
118
|
+
...groups.habits,
|
|
119
|
+
...groups.backlog
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
let targetId = idInput;
|
|
123
|
+
const numMatch = idInput.match(/^\d+$/);
|
|
124
|
+
if (numMatch) {
|
|
125
|
+
const seqIndex = parseInt(idInput, 10);
|
|
126
|
+
if (seqIndex >= 1 && seqIndex <= sortedActive.length) {
|
|
127
|
+
targetId = sortedActive[seqIndex - 1].id;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const settled = store.settle(targetId, { settledBy: 'manual-command' });
|
|
132
|
+
const successMsg = settled.recurrence === 'daily'
|
|
133
|
+
? `⌖ Completed for today: "${settled.title}" (resets tomorrow)`
|
|
134
|
+
: `⌖ Settled: "${settled.title}"`;
|
|
135
|
+
console.log(successMsg);
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error(`Error: ${err.message}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 5. Pin new task: `anchor <task description> [--due <date>]`
|
|
144
|
+
let targetDateFlag;
|
|
145
|
+
const dueIdx = args.findIndex(a => a === '--due' || a === '-d');
|
|
146
|
+
if (dueIdx !== -1 && args[dueIdx + 1]) {
|
|
147
|
+
targetDateFlag = args[dueIdx + 1];
|
|
148
|
+
args.splice(dueIdx, 2);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const title = args.join(' ').trim();
|
|
152
|
+
if (!title) {
|
|
153
|
+
console.error('Error: task description cannot be empty.');
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const anc = store.create({
|
|
158
|
+
title,
|
|
159
|
+
targetDate: targetDateFlag,
|
|
160
|
+
cwd: process.cwd()
|
|
161
|
+
});
|
|
162
|
+
const targetBadge = anc.targetDate ? ` · ${formatTargetDate(anc)}` : '';
|
|
163
|
+
console.log(`⌖ Pinned #${anc.id}: "${anc.title}" [${anc.project}]${targetBadge}`);
|