pi-anchor 0.2.2 → 0.2.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/README.md CHANGED
@@ -1,22 +1,31 @@
1
1
  # ⌖ Anchor
2
2
 
3
- > **Zero-pollution, 0-idle-token cross-session task memory for AI coding agents**
4
- > Maintain cross-session intent with zero idle tokens, syntax-safe JIT touch wakeups, and zero git repository pollution.
3
+ > **Never lose unfinished tasks when closing Pi — pin reminders across sessions, wake them when touching matching files, and auto-complete on `git commit` with zero `TODO.md` clutter.**
5
4
 
6
5
  [![CI Status](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml/badge.svg)](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml)
7
6
  [![Node v20+](https://img.shields.io/badge/Node-v20+-22c55e.svg)](package.json)
8
7
  [![TypeScript Strict](https://img.shields.io/badge/TypeScript-Strict-3b82f6.svg)](tsconfig.json)
9
- [![Tests: 29 Passed](https://img.shields.io/badge/Tests-29%20Passed-22c55e.svg)](tests/store.test.ts)
8
+ [![Tests: 31 Passed](https://img.shields.io/badge/Tests-31%20Passed-22c55e.svg)](tests/store.test.ts)
10
9
  [![Startup: < 90ms](https://img.shields.io/badge/Startup-%3C%2090ms-success.svg)](package.json)
11
10
  [![Zero Repo Pollution](https://img.shields.io/badge/Storage-Zero%20Repo%20Pollution-success.svg)](#1-zero-repository-contamination--storage-topology)
12
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-f97316.svg)](LICENSE)
13
12
 
14
13
  **English** | [简体中文](./README_zh.md)
15
14
 
15
+ ```bash
16
+ pi install npm:pi-anchor
17
+ ```
18
+
16
19
  <p align="center">
17
20
  <img src="assets/hero-en.svg" alt="Anchor Terminal Dashboard" width="820">
18
21
  </p>
19
22
 
23
+ ### How It Works in 3 Steps
24
+
25
+ 1. **Pin in 1 second**: Tell the AI *"Remember to migrate auth tomorrow"* or type `/pin Migrate auth to HttpOnly cookies --due tomorrow`. Stored in `~/.anchor/state.json` (zero `TODO.md` files in your git repo).
26
+ 2. **Wake up next session (0 idle tokens)**: Next time you open Pi, Anchor shows a 3-line summary above your editor and briefs the AI on Turn 1. From Turn 2 onwards, it consumes **0 tokens** — waking up only with a 1-line comment when the AI reads or edits matching files.
27
+ 3. **Auto-complete on commit or test pass**: Commit related code (`git commit`), pass a `verifyCommand`, or run `/done 1` — Anchor archives the task automatically.
28
+
20
29
  ```text
21
30
  ⌖ Anchors (4 active):
22
31
 
@@ -143,8 +152,10 @@ anchor undo # Restore last archived task
143
152
  ### Pi Coding Agent Commands
144
153
  | Command | Description |
145
154
  | :--- | :--- |
146
- | `/pin "task description"` | Pin an anchor task for the current workspace |
155
+ | `/pin <task> [--due tomorrow]` | Pin a task across sessions with optional due date |
147
156
  | `/anchor` | Open interactive terminal task dashboard |
157
+ | `/done <id>` or `/anchor done <id>` | Complete task by row number (`1`) or ID (`anc-1`) |
158
+ | `/anchor undo` | Restore the last settled task |
148
159
  | Status bar `⌖ N` | Displays active task count in status row; 100% hidden when 0 tasks exist |
149
160
 
150
161
  ---
@@ -186,7 +197,7 @@ Engineered with strict TypeScript and 100% standard library test coverage using
186
197
 
187
198
  ```bash
188
199
  npm run typecheck # Strict tsc --noEmit check (0 errors)
189
- npm test # Native Node test runner (29/29 passing)
200
+ npm test # Native Node test runner (31/31 passing)
190
201
  npm run build # Dual ESM/CJS compilation via tsup + declaration emit
191
202
  ```
192
203
 
package/README_zh.md CHANGED
@@ -1,22 +1,31 @@
1
1
  # ⌖ Anchor
2
2
 
3
- > **面向 AI 编程智能体的零污染、0 闲置 Token 跨会话任务记忆系统**
4
- > 告别发霉的 TODO.md。零 Git 历史污染,0 闲置 Token 损耗,代码提交自动核销结算。
3
+ > **关掉终端也不丢待办 —— 一句话钉住跨会话任务(`/pin`),触碰关联代码时自动提醒 AI,提交代码(`git commit`)自动销账,0 `TODO.md` 污染。**
5
4
 
6
5
  [![CI 状态](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml/badge.svg)](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml)
7
6
  [![Node v20+](https://img.shields.io/badge/Node-v20+-22c55e.svg)](package.json)
8
7
  [![TypeScript Strict](https://img.shields.io/badge/TypeScript-Strict-3b82f6.svg)](tsconfig.json)
9
- [![Tests: 29 Passed](https://img.shields.io/badge/Tests-29%20通过-22c55e.svg)](tests/store.test.ts)
8
+ [![Tests: 31 Passed](https://img.shields.io/badge/Tests-31%20通过-22c55e.svg)](tests/store.test.ts)
10
9
  [![启动耗时: < 90ms](https://img.shields.io/badge/启动耗时-%3C%2090ms-success.svg)](package.json)
11
10
  [![零仓库污染](https://img.shields.io/badge/存储-零仓库污染-success.svg)](#1-绝对零仓库污染与跨进程文件锁)
12
11
  [![开源协议: MIT](https://img.shields.io/badge/开源协议-MIT-f97316.svg)](LICENSE)
13
12
 
14
13
  [English](./README.md) | **简体中文**
15
14
 
15
+ ```bash
16
+ pi install npm:pi-anchor
17
+ ```
18
+
16
19
  <p align="center">
17
20
  <img src="assets/hero-zh.svg" alt="Anchor 终端仪表盘实录" width="820">
18
21
  </p>
19
22
 
23
+ ### 3 步看懂它怎么工作
24
+
25
+ 1. **随手钉住待办**:直接对 AI 说 *“记一下明天把鉴权改成 HttpOnly Cookie”*,或敲 `/pin 重构鉴权模块 --due tomorrow`。保存在全局 `~/.anchor/state.json`,不在项目里留任何 `TODO.md` 垃圾文件。
26
+ 2. **下次开终端自动唤醒(平时 0 Token)**:重新打开 Pi 时,编辑器上方展示 3 行今日聚焦清单,并在第 1 轮自动提醒 AI;从第 2 轮起 **0 Token 损耗**,只有当 AI 读/改关联代码文件时才附带 1 行注释精准提醒。
27
+ 3. **提交代码自动销账**:`git commit` 提交关联代码、单测命令通过、或敲 `/done 1`,任务自动归档结案。
28
+
20
29
  ```text
21
30
  ⌖ Anchors (4 active):
22
31
 
@@ -146,8 +155,10 @@ anchor undo # 撤销上一次完成归档
146
155
  ### Pi 扩展内交互命令
147
156
  | 命令 | 说明 |
148
157
  | :--- | :--- |
149
- | `/pin "任务描述"` | 快速立项当前工程的跨会话任务 |
158
+ | `/pin <任务描述> [--due tomorrow]` | 快速立项当前工程的跨会话任务(支持指定到期日) |
150
159
  | `/anchor` | 在终端内弹出全景交互式任务仪表盘 |
160
+ | `/done <编号>` 或 `/anchor done <编号>` | 按列表行号(`1`)或 ID(`anc-1`)直接完成核销 |
161
+ | `/anchor undo` | 撤销上一次归档的任务 |
151
162
  | 状态栏 `⌖ N` | 底部常驻微标签,有活跃任务时显示数量,无任务时 100% 静默隐形 |
152
163
 
153
164
  ---
@@ -193,7 +204,7 @@ Anchor 选择了一条极度克制的工程路径:把状态移出代码仓库
193
204
 
194
205
  ```bash
195
206
  npm run typecheck # TypeScript 严格类型检查 (0 错误)
196
- npm test # 全套自动化单元测试 (29/29 全绿通过)
207
+ npm test # 全套自动化单元测试 (31/31 全绿通过)
197
208
  npm run build # tsup 双格式打包 (ESM/CJS) 与 .d.ts 类型生成
198
209
  ```
199
210
 
@@ -0,0 +1,108 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 430" width="840" height="430">
2
+ <defs>
3
+ <filter id="shadow" x="-5%" y="-5%" width="110%" height="115%" filterUnits="userSpaceOnUse">
4
+ <feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#000000" flood-opacity="0.45" />
5
+ </filter>
6
+ <linearGradient id="headerGrad" x1="0%" y1="0%" x2="0%" y2="100%">
7
+ <stop offset="0%" stop-color="#2b3339" />
8
+ <stop offset="100%" stop-color="#232a2e" />
9
+ </linearGradient>
10
+ </defs>
11
+
12
+ <!-- Window Container with Shadow -->
13
+ <g filter="url(#shadow)">
14
+ <rect x="20" y="15" width="800" height="390" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
15
+
16
+ <!-- Titlebar -->
17
+ <path d="M 20,27 A 12,12 0 0,1 32,15 L 808,15 A 12,12 0 0,1 820,27 L 820,52 L 20,52 Z" fill="url(#headerGrad)" stroke="#343f44" stroke-width="1" />
18
+ <line x1="20" y1="52" x2="820" y2="52" stroke="#2d353b" stroke-width="1" />
19
+
20
+ <!-- Window Controls (macOS Dots) -->
21
+ <circle cx="42" cy="33.5" r="5.5" fill="#e67e80" />
22
+ <circle cx="60" cy="33.5" r="5.5" fill="#dbbc7f" />
23
+ <circle cx="78" cy="33.5" r="5.5" fill="#a7c080" />
24
+
25
+ <!-- Window Title -->
26
+ <text x="420" y="38" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="12" font-weight="500" fill="#859289" letter-spacing="0.3">
27
+ Jason@laptop ~ ⌖ anchor (v0.2.1)
28
+ </text>
29
+ </g>
30
+
31
+ <!-- Terminal Text Content -->
32
+ <g font-family="'JetBrains Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace" font-size="13" xml:space="preserve">
33
+ <!-- Prompt Command Line -->
34
+ <text x="45" y="85">
35
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
36
+ <tspan fill="#7fbbb3"> ❯ </tspan>
37
+ <tspan fill="#d3c6aa" font-weight="bold">anchor</tspan>
38
+ </text>
39
+
40
+ <!-- Header Line -->
41
+ <text x="45" y="118">
42
+ <tspan fill="#7fbbb3" font-weight="bold">⌖ Anchors </tspan>
43
+ <tspan fill="#859289">(4 active):</tspan>
44
+ </text>
45
+
46
+ <!-- Today Section Header -->
47
+ <text x="45" y="152" fill="#e67e80" font-weight="bold"> [Today · Today's Focus]</text>
48
+
49
+ <!-- Today Item -->
50
+ <text x="45" y="178">
51
+ <tspan fill="#859289"> 01 </tspan>
52
+ <tspan fill="#e67e80" font-weight="bold">[Today] </tspan>
53
+ <tspan fill="#d3c6aa">Optimize token truncation &amp; JIT safety </tspan>
54
+ <tspan fill="#859289">Desktop </tspan>
55
+ <tspan fill="#e67e80" font-weight="bold">Today </tspan>
56
+ <tspan fill="#7a8478">Today 10:02</tspan>
57
+ </text>
58
+
59
+ <!-- Upcoming Section Header -->
60
+ <text x="45" y="218" fill="#dbbc7f" font-weight="bold"> [Upcoming · Scheduled]</text>
61
+
62
+ <!-- Upcoming Items -->
63
+ <text x="45" y="244">
64
+ <tspan fill="#859289"> 02 </tspan>
65
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
66
+ <tspan fill="#d3c6aa">Add concurrent file lock unit tests </tspan>
67
+ <tspan fill="#859289">Desktop </tspan>
68
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
69
+ <tspan fill="#7a8478">Yesterday 21:34</tspan>
70
+ </text>
71
+
72
+ <text x="45" y="270">
73
+ <tspan fill="#859289"> 03 </tspan>
74
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
75
+ <tspan fill="#d3c6aa">Migrate auth module to HttpOnly cookies</tspan>
76
+ <tspan fill="#859289">Desktop </tspan>
77
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
78
+ <tspan fill="#7a8478">Today 10:02</tspan>
79
+ </text>
80
+
81
+ <text x="45" y="296">
82
+ <tspan fill="#859289"> 04 </tspan>
83
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
84
+ <tspan fill="#d3c6aa">Polish CLI interactive dashboard &amp; TUI </tspan>
85
+ <tspan fill="#859289">Desktop </tspan>
86
+ <tspan fill="#dbbc7f">In 2d </tspan>
87
+ <tspan fill="#7a8478">Today 10:02</tspan>
88
+ </text>
89
+
90
+ <!-- Footer Action -->
91
+ <text x="45" y="340" fill="#7a8478">
92
+ <tspan> Use </tspan>
93
+ <tspan fill="#7fbbb3" font-weight="bold">`anchor done &lt;id&gt;`</tspan>
94
+ <tspan> to complete.</tspan>
95
+ </text>
96
+
97
+ <!-- Active Input Cursor -->
98
+ <text x="45" y="378">
99
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
100
+ <tspan fill="#7fbbb3"> ❯ </tspan>
101
+ <tspan fill="#7fbbb3">⌖</tspan>
102
+ <tspan fill="#d3c6aa"> </tspan>
103
+ <rect x="175" y="364" width="8" height="16" fill="#a7c080" opacity="0.8">
104
+ <animate attributeName="opacity" values="0.8;0.1;0.8" dur="1.1s" repeatCount="indefinite" />
105
+ </rect>
106
+ </text>
107
+ </g>
108
+ </svg>
@@ -0,0 +1,108 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 430" width="840" height="430">
2
+ <defs>
3
+ <filter id="shadow" x="-5%" y="-5%" width="110%" height="115%" filterUnits="userSpaceOnUse">
4
+ <feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#000000" flood-opacity="0.45" />
5
+ </filter>
6
+ <linearGradient id="headerGrad" x1="0%" y1="0%" x2="0%" y2="100%">
7
+ <stop offset="0%" stop-color="#2b3339" />
8
+ <stop offset="100%" stop-color="#232a2e" />
9
+ </linearGradient>
10
+ </defs>
11
+
12
+ <!-- Window Container with Shadow -->
13
+ <g filter="url(#shadow)">
14
+ <rect x="20" y="15" width="800" height="390" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
15
+
16
+ <!-- Titlebar -->
17
+ <path d="M 20,27 A 12,12 0 0,1 32,15 L 808,15 A 12,12 0 0,1 820,27 L 820,52 L 20,52 Z" fill="url(#headerGrad)" stroke="#343f44" stroke-width="1" />
18
+ <line x1="20" y1="52" x2="820" y2="52" stroke="#2d353b" stroke-width="1" />
19
+
20
+ <!-- Window Controls (macOS Dots) -->
21
+ <circle cx="42" cy="33.5" r="5.5" fill="#e67e80" />
22
+ <circle cx="60" cy="33.5" r="5.5" fill="#dbbc7f" />
23
+ <circle cx="78" cy="33.5" r="5.5" fill="#a7c080" />
24
+
25
+ <!-- Window Title -->
26
+ <text x="420" y="38" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="12" font-weight="500" fill="#859289" letter-spacing="0.3">
27
+ Jason@laptop ~ ⌖ anchor (v0.2.1)
28
+ </text>
29
+ </g>
30
+
31
+ <!-- Terminal Text Content -->
32
+ <g font-family="'JetBrains Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace" font-size="13" xml:space="preserve">
33
+ <!-- Prompt Command Line -->
34
+ <text x="45" y="85">
35
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
36
+ <tspan fill="#7fbbb3"> ❯ </tspan>
37
+ <tspan fill="#d3c6aa" font-weight="bold">anchor</tspan>
38
+ </text>
39
+
40
+ <!-- Header Line -->
41
+ <text x="45" y="118">
42
+ <tspan fill="#7fbbb3" font-weight="bold">⌖ Anchors </tspan>
43
+ <tspan fill="#859289">(4 active):</tspan>
44
+ </text>
45
+
46
+ <!-- Today Section Header -->
47
+ <text x="45" y="152" fill="#e67e80" font-weight="bold"> [Today · 今日聚焦]</text>
48
+
49
+ <!-- Today Item -->
50
+ <text x="45" y="178">
51
+ <tspan fill="#859289"> 01 </tspan>
52
+ <tspan fill="#e67e80" font-weight="bold">[Today] </tspan>
53
+ <tspan fill="#d3c6aa">今天完成anchor项目后端优化 </tspan>
54
+ <tspan fill="#859289"> Desktop </tspan>
55
+ <tspan fill="#e67e80" font-weight="bold">Today </tspan>
56
+ <tspan fill="#7a8478">Today 10:02</tspan>
57
+ </text>
58
+
59
+ <!-- Upcoming Section Header -->
60
+ <text x="45" y="218" fill="#dbbc7f" font-weight="bold"> [Upcoming · 近期排期]</text>
61
+
62
+ <!-- Upcoming Items -->
63
+ <text x="45" y="244">
64
+ <tspan fill="#859289"> 02 </tspan>
65
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
66
+ <tspan fill="#d3c6aa">明天优化并发文件锁单元测试 </tspan>
67
+ <tspan fill="#859289"> Desktop </tspan>
68
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
69
+ <tspan fill="#7a8478">Yesterday 21:34</tspan>
70
+ </text>
71
+
72
+ <text x="45" y="270">
73
+ <tspan fill="#859289"> 03 </tspan>
74
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
75
+ <tspan fill="#d3c6aa">重构鉴权模块为HttpOnly Cookie </tspan>
76
+ <tspan fill="#859289"> Desktop </tspan>
77
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
78
+ <tspan fill="#7a8478">Today 10:02</tspan>
79
+ </text>
80
+
81
+ <text x="45" y="296">
82
+ <tspan fill="#859289"> 04 </tspan>
83
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
84
+ <tspan fill="#d3c6aa">完善CLI交互式仪表盘与TUI组件 </tspan>
85
+ <tspan fill="#859289"> Desktop </tspan>
86
+ <tspan fill="#dbbc7f">In 2d </tspan>
87
+ <tspan fill="#7a8478">Today 10:02</tspan>
88
+ </text>
89
+
90
+ <!-- Footer Action -->
91
+ <text x="45" y="340" fill="#7a8478">
92
+ <tspan> Use </tspan>
93
+ <tspan fill="#7fbbb3" font-weight="bold">`anchor done &lt;id&gt;`</tspan>
94
+ <tspan> to complete.</tspan>
95
+ </text>
96
+
97
+ <!-- Active Input Cursor -->
98
+ <text x="45" y="378">
99
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
100
+ <tspan fill="#7fbbb3"> ❯ </tspan>
101
+ <tspan fill="#7fbbb3">⌖</tspan>
102
+ <tspan fill="#d3c6aa"> </tspan>
103
+ <rect x="175" y="364" width="8" height="16" fill="#a7c080" opacity="0.8">
104
+ <animate attributeName="opacity" values="0.8;0.1;0.8" dur="1.1s" repeatCount="indefinite" />
105
+ </rect>
106
+ </text>
107
+ </g>
108
+ </svg>
@@ -0,0 +1,108 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 430" width="840" height="430">
2
+ <defs>
3
+ <filter id="shadow" x="-5%" y="-5%" width="110%" height="115%" filterUnits="userSpaceOnUse">
4
+ <feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#000000" flood-opacity="0.45" />
5
+ </filter>
6
+ <linearGradient id="headerGrad" x1="0%" y1="0%" x2="0%" y2="100%">
7
+ <stop offset="0%" stop-color="#2b3339" />
8
+ <stop offset="100%" stop-color="#232a2e" />
9
+ </linearGradient>
10
+ </defs>
11
+
12
+ <!-- Window Container with Shadow -->
13
+ <g filter="url(#shadow)">
14
+ <rect x="20" y="15" width="800" height="390" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
15
+
16
+ <!-- Titlebar -->
17
+ <path d="M 20,27 A 12,12 0 0,1 32,15 L 808,15 A 12,12 0 0,1 820,27 L 820,52 L 20,52 Z" fill="url(#headerGrad)" stroke="#343f44" stroke-width="1" />
18
+ <line x1="20" y1="52" x2="820" y2="52" stroke="#2d353b" stroke-width="1" />
19
+
20
+ <!-- Window Controls (macOS Dots) -->
21
+ <circle cx="42" cy="33.5" r="5.5" fill="#e67e80" />
22
+ <circle cx="60" cy="33.5" r="5.5" fill="#dbbc7f" />
23
+ <circle cx="78" cy="33.5" r="5.5" fill="#a7c080" />
24
+
25
+ <!-- Window Title -->
26
+ <text x="420" y="38" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="12" font-weight="500" fill="#859289" letter-spacing="0.3">
27
+ Jason@laptop ~ ⌖ anchor (v0.2.1)
28
+ </text>
29
+ </g>
30
+
31
+ <!-- Terminal Text Content -->
32
+ <g font-family="'JetBrains Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace" font-size="13" xml:space="preserve">
33
+ <!-- Prompt Command Line -->
34
+ <text x="45" y="85">
35
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
36
+ <tspan fill="#7fbbb3"> ❯ </tspan>
37
+ <tspan fill="#d3c6aa" font-weight="bold">anchor</tspan>
38
+ </text>
39
+
40
+ <!-- Header Line -->
41
+ <text x="45" y="118">
42
+ <tspan fill="#7fbbb3" font-weight="bold">⌖ Anchors </tspan>
43
+ <tspan fill="#859289">(4 active):</tspan>
44
+ </text>
45
+
46
+ <!-- Today Section Header -->
47
+ <text x="45" y="152" fill="#e67e80" font-weight="bold"> [Today · 今日聚焦]</text>
48
+
49
+ <!-- Today Item -->
50
+ <text x="45" y="178">
51
+ <tspan fill="#859289"> 01 </tspan>
52
+ <tspan fill="#e67e80" font-weight="bold">[Today] </tspan>
53
+ <tspan fill="#d3c6aa">今天完成anchor项目后端优化 </tspan>
54
+ <tspan fill="#859289"> Desktop </tspan>
55
+ <tspan fill="#e67e80" font-weight="bold">Today </tspan>
56
+ <tspan fill="#7a8478">Today 10:02</tspan>
57
+ </text>
58
+
59
+ <!-- Upcoming Section Header -->
60
+ <text x="45" y="218" fill="#dbbc7f" font-weight="bold"> [Upcoming · 近期排期]</text>
61
+
62
+ <!-- Upcoming Items -->
63
+ <text x="45" y="244">
64
+ <tspan fill="#859289"> 02 </tspan>
65
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
66
+ <tspan fill="#d3c6aa">明天优化并发文件锁单元测试 </tspan>
67
+ <tspan fill="#859289"> Desktop </tspan>
68
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
69
+ <tspan fill="#7a8478">Yesterday 21:34</tspan>
70
+ </text>
71
+
72
+ <text x="45" y="270">
73
+ <tspan fill="#859289"> 03 </tspan>
74
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
75
+ <tspan fill="#d3c6aa">重构鉴权模块为HttpOnly Cookie </tspan>
76
+ <tspan fill="#859289"> Desktop </tspan>
77
+ <tspan fill="#dbbc7f">Tomorrow </tspan>
78
+ <tspan fill="#7a8478">Today 10:02</tspan>
79
+ </text>
80
+
81
+ <text x="45" y="296">
82
+ <tspan fill="#859289"> 04 </tspan>
83
+ <tspan fill="#dbbc7f">[Upcoming] </tspan>
84
+ <tspan fill="#d3c6aa">完善CLI交互式仪表盘与TUI组件 </tspan>
85
+ <tspan fill="#859289"> Desktop </tspan>
86
+ <tspan fill="#dbbc7f">In 2d </tspan>
87
+ <tspan fill="#7a8478">Today 10:02</tspan>
88
+ </text>
89
+
90
+ <!-- Footer Action -->
91
+ <text x="45" y="340" fill="#7a8478">
92
+ <tspan> Use </tspan>
93
+ <tspan fill="#7fbbb3" font-weight="bold">`anchor done &lt;id&gt;`</tspan>
94
+ <tspan> to complete.</tspan>
95
+ </text>
96
+
97
+ <!-- Active Input Cursor -->
98
+ <text x="45" y="378">
99
+ <tspan fill="#a7c080" font-weight="bold">~/Workspace</tspan>
100
+ <tspan fill="#7fbbb3"> ❯ </tspan>
101
+ <tspan fill="#7fbbb3">⌖</tspan>
102
+ <tspan fill="#d3c6aa"> </tspan>
103
+ <rect x="175" y="364" width="8" height="16" fill="#a7c080" opacity="0.8">
104
+ <animate attributeName="opacity" values="0.8;0.1;0.8" dur="1.1s" repeatCount="indefinite" />
105
+ </rect>
106
+ </text>
107
+ </g>
108
+ </svg>
package/bin/anchor.js CHANGED
@@ -31,10 +31,10 @@ if (args.length === 0 || args[0] === 'list' || args[0] === 'ls') {
31
31
 
32
32
  const groups = groupAnchorsByQuadrant(active);
33
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 },
34
+ { title: "Today · Today's Focus", list: groups.today },
35
+ { title: 'Upcoming · Scheduled', list: groups.upcoming },
36
+ { title: 'Habits · Daily Loop', list: groups.habits },
37
+ { title: 'Backlog · Someday', list: groups.backlog },
38
38
  ];
39
39
 
40
40
  let seqNum = 1;
@@ -30,7 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/extension.ts
31
31
  var extension_exports = {};
32
32
  __export(extension_exports, {
33
- default: () => extension_default
33
+ default: () => extension_default,
34
+ parseAnchorCommandInput: () => parseAnchorCommandInput,
35
+ resolveAnchorTarget: () => resolveAnchorTarget
34
36
  });
35
37
  module.exports = __toCommonJS(extension_exports);
36
38
  var import_typebox = require("@sinclair/typebox");
@@ -1414,6 +1416,55 @@ var import_node_child_process2 = require("child_process");
1414
1416
  var import_node_fs3 = __toESM(require("fs"), 1);
1415
1417
  var import_node_path5 = __toESM(require("path"), 1);
1416
1418
  var MUTATION_TOOLS2 = /* @__PURE__ */ new Set(["edit", "write", "patch", "apply_diff", "create_file", "modify"]);
1419
+ function parseAnchorCommandInput(raw, now = Date.now()) {
1420
+ const trimmed = (raw || "").trim();
1421
+ if (!trimmed || trimmed === "list" || trimmed === "ls") {
1422
+ return { mode: "dashboard" };
1423
+ }
1424
+ if (trimmed === "undo") {
1425
+ return { mode: "undo" };
1426
+ }
1427
+ const settleMatch = trimmed.match(/^(?:done|rm|close|settle)\s+(.+)$/i);
1428
+ if (settleMatch) {
1429
+ return {
1430
+ mode: "settle",
1431
+ targetId: settleMatch[1].trim().replace(/^#/, "")
1432
+ };
1433
+ }
1434
+ let targetDate;
1435
+ const tokens = trimmed.split(/\s+/);
1436
+ const dueIdx = tokens.findIndex((t) => t === "--due" || t === "-d");
1437
+ if (dueIdx !== -1 && tokens[dueIdx + 1]) {
1438
+ const rawDue = tokens[dueIdx + 1];
1439
+ targetDate = detectTargetDate(rawDue, now) || rawDue;
1440
+ tokens.splice(dueIdx, 2);
1441
+ }
1442
+ const cleanTitle = tokens.join(" ").trim();
1443
+ return {
1444
+ mode: "pin",
1445
+ title: cleanTitle || trimmed,
1446
+ targetDate
1447
+ };
1448
+ }
1449
+ function resolveAnchorTarget(store, idOrIndex, cwd) {
1450
+ const clean = idOrIndex.trim().replace(/^#/, "");
1451
+ if (/^\d+$/.test(clean)) {
1452
+ const seqIndex = parseInt(clean, 10);
1453
+ const active = store.list({ status: "active", cwd });
1454
+ const groups = groupAnchorsByQuadrant(active);
1455
+ const sortedActive = [
1456
+ ...groups.today,
1457
+ ...groups.upcoming,
1458
+ ...groups.habits,
1459
+ ...groups.backlog
1460
+ ];
1461
+ if (seqIndex >= 1 && seqIndex <= sortedActive.length) {
1462
+ return sortedActive[seqIndex - 1].id;
1463
+ }
1464
+ }
1465
+ const direct = store.get(clean);
1466
+ return direct?.id;
1467
+ }
1417
1468
  function extension_default(pi) {
1418
1469
  const store = new AnchorStore();
1419
1470
  const observer = new SessionTouchObserver();
@@ -1425,7 +1476,7 @@ function extension_default(pi) {
1425
1476
  preflightFailures.clear();
1426
1477
  const sweep = sweepStore(store);
1427
1478
  if (sweep.transitionedToSleeping.length > 0) {
1428
- ctx.ui.notify(`Anchor: ${sweep.transitionedToSleeping.length} \u4E2A\u975E\u6D3B\u8DC3\u4EFB\u52A1\u5DF2\u8FDB\u5165\u4F11\u7720`, "info");
1479
+ ctx.ui.notify(`\u2316 Anchor: ${sweep.transitionedToSleeping.length} inactive tasks transitioned to sleep`, "info");
1429
1480
  }
1430
1481
  const activeAnchors = store.list({ cwd: ctx.cwd }).filter((a) => a.status === "active");
1431
1482
  for (const a of activeAnchors) {
@@ -1437,7 +1488,7 @@ function extension_default(pi) {
1437
1488
  settledBy: "verification-test",
1438
1489
  summary: `Physical pre-flight test passed: ${a.verifyCommand}`
1439
1490
  });
1440
- ctx.ui.notify(`\u2693 \u7269\u7406\u9A8C\u8BC1\u901A\u8FC7\uFF01\u951A\u70B9 #${a.id} ("${a.title}") \u5DF2\u81EA\u52A8\u7ED3\u6848\u5F52\u6863\u3002`, "info");
1491
+ ctx.ui.notify(`\u2316 Verification passed! Auto-settled #${a.id}: "${a.title}"`, "info");
1441
1492
  } else {
1442
1493
  preflightFailures.set(a.id, res.output.slice(-250));
1443
1494
  }
@@ -1769,14 +1820,14 @@ Mark as completed and archive?`
1769
1820
  }
1770
1821
  });
1771
1822
  pi.registerCommand("anchor", {
1772
- description: "Inspect and settle active anchors",
1823
+ description: "Inspect, pin, or settle active anchors (e.g. /anchor, /anchor done 1, /anchor undo)",
1773
1824
  handler: async (args, ctx) => {
1774
- const input = (args || "").trim();
1775
- if (!input || input === "list" || input === "ls") {
1825
+ const parsed = parseAnchorCommandInput(args);
1826
+ if (parsed.mode === "dashboard") {
1776
1827
  await openAnchorDashboard(ctx, store);
1777
1828
  return;
1778
1829
  }
1779
- if (input === "undo") {
1830
+ if (parsed.mode === "undo") {
1780
1831
  try {
1781
1832
  const restored = store.undoSettle();
1782
1833
  ctx.ui.notify(`\u2316 Restored #${restored.id}: "${restored.title}"`, "info");
@@ -1786,29 +1837,68 @@ Mark as completed and archive?`
1786
1837
  }
1787
1838
  return;
1788
1839
  }
1789
- const targetId = input.startsWith("#") ? input.slice(1) : input;
1790
- const item = store.get(targetId);
1791
- if (item) {
1792
- store.settle(targetId, { settledBy: "manual-command" });
1793
- ctx.ui.notify(`\u2316 Settled: "${item.title}"`, "info");
1840
+ if (parsed.mode === "settle" && parsed.targetId) {
1841
+ const resolvedId = resolveAnchorTarget(store, parsed.targetId, ctx.cwd);
1842
+ if (!resolvedId) {
1843
+ ctx.ui.notify(`\u2316 Anchor not found: ${parsed.targetId}`, "error");
1844
+ return;
1845
+ }
1846
+ const settled = store.settle(resolvedId, { settledBy: "manual-command" });
1847
+ ctx.ui.notify(`\u2316 Settled #${settled.id}: "${settled.title}" (/anchor undo to revert)`, "info");
1794
1848
  updateAnchorStatusBar(ctx, store);
1795
1849
  return;
1796
1850
  }
1797
- const anc = store.create({ title: input, cwd: ctx.cwd });
1798
- ctx.ui.notify(`\u2316 Pinned #${anc.id}: "${anc.title}"`, "info");
1851
+ const rawTrimmed = (args || "").trim();
1852
+ if (/^(?:#?anc-\d+|#\d+)$/i.test(rawTrimmed)) {
1853
+ const resolvedId = resolveAnchorTarget(store, rawTrimmed, ctx.cwd);
1854
+ if (resolvedId) {
1855
+ const settled = store.settle(resolvedId, { settledBy: "manual-command" });
1856
+ ctx.ui.notify(`\u2316 Settled #${settled.id}: "${settled.title}" (/anchor undo to revert)`, "info");
1857
+ updateAnchorStatusBar(ctx, store);
1858
+ return;
1859
+ }
1860
+ }
1861
+ const anc = store.create({
1862
+ title: parsed.title || rawTrimmed,
1863
+ targetDate: parsed.targetDate,
1864
+ cwd: ctx.cwd
1865
+ });
1866
+ ctx.ui.notify(`\u2316 Pinned #${anc.id}: "${anc.title}"${anc.targetDate ? ` (due ${anc.targetDate})` : ""}`, "info");
1799
1867
  updateAnchorStatusBar(ctx, store);
1800
1868
  }
1801
1869
  });
1802
1870
  pi.registerCommand("pin", {
1803
- description: "Quickly pin a task across sessions",
1871
+ description: "Pin a task across sessions (e.g. /pin Refactor auth --due tomorrow)",
1872
+ handler: async (args, ctx) => {
1873
+ const parsed = parseAnchorCommandInput(args);
1874
+ if (parsed.mode === "dashboard" || !parsed.title) {
1875
+ await openAnchorDashboard(ctx, store);
1876
+ return;
1877
+ }
1878
+ const anc = store.create({
1879
+ title: parsed.title,
1880
+ targetDate: parsed.targetDate,
1881
+ cwd: ctx.cwd
1882
+ });
1883
+ ctx.ui.notify(`\u2316 Pinned #${anc.id}: "${anc.title}"${anc.targetDate ? ` (due ${anc.targetDate})` : ""}`, "info");
1884
+ updateAnchorStatusBar(ctx, store);
1885
+ }
1886
+ });
1887
+ pi.registerCommand("done", {
1888
+ description: "Complete an active anchor by row number or ID (e.g. /done 1)",
1804
1889
  handler: async (args, ctx) => {
1805
- const title = (args || "").trim();
1806
- if (!title) {
1890
+ const target = (args || "").trim();
1891
+ if (!target) {
1807
1892
  await openAnchorDashboard(ctx, store);
1808
1893
  return;
1809
1894
  }
1810
- const anc = store.create({ title, cwd: ctx.cwd });
1811
- ctx.ui.notify(`\u2316 Pinned #${anc.id}: "${anc.title}"`, "info");
1895
+ const resolvedId = resolveAnchorTarget(store, target, ctx.cwd);
1896
+ if (!resolvedId) {
1897
+ ctx.ui.notify(`\u2316 Anchor not found: ${target}`, "error");
1898
+ return;
1899
+ }
1900
+ const settled = store.settle(resolvedId, { settledBy: "manual-command" });
1901
+ ctx.ui.notify(`\u2316 Settled #${settled.id}: "${settled.title}" (/anchor undo to revert)`, "info");
1812
1902
  updateAnchorStatusBar(ctx, store);
1813
1903
  }
1814
1904
  });
@@ -1819,3 +1909,8 @@ Mark as completed and archive?`
1819
1909
  }
1820
1910
  });
1821
1911
  }
1912
+ // Annotate the CommonJS export names for ESM import in node:
1913
+ 0 && (module.exports = {
1914
+ parseAnchorCommandInput,
1915
+ resolveAnchorTarget
1916
+ });