pi-anchor 0.2.3 → 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 +16 -5
- package/README_zh.md +16 -5
- package/assets/hero-en.svg +108 -0
- package/assets/hero-zh.svg +108 -0
- package/assets/hero.svg +108 -0
- package/bin/anchor.js +4 -4
- package/dist/extension.cjs +114 -19
- package/dist/extension.d.cts +16 -1
- package/dist/extension.d.ts +16 -1
- package/dist/extension.js +111 -19
- package/dist/index.d.cts +3 -209
- package/dist/index.d.ts +3 -209
- package/dist/store-BNKjzhS_.d.cts +209 -0
- package/dist/store-BNKjzhS_.d.ts +209 -0
- package/package.json +21 -5
- package/src/extension.ts +137 -24
package/README.md
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
# ⌖ Anchor
|
|
2
2
|
|
|
3
|
-
> **
|
|
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
|
[](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml)
|
|
7
6
|
[](package.json)
|
|
8
7
|
[](tsconfig.json)
|
|
9
|
-
[](tests/store.test.ts)
|
|
10
9
|
[](package.json)
|
|
11
10
|
[](#1-zero-repository-contamination--storage-topology)
|
|
12
11
|
[](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
|
|
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 (
|
|
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
|
-
>
|
|
4
|
-
> 告别发霉的 TODO.md。零 Git 历史污染,0 闲置 Token 损耗,代码提交自动核销结算。
|
|
3
|
+
> **关掉终端也不丢待办 —— 一句话钉住跨会话任务(`/pin`),触碰关联代码时自动提醒 AI,提交代码(`git commit`)自动销账,0 `TODO.md` 污染。**
|
|
5
4
|
|
|
6
5
|
[](https://github.com/3ZEROS12/anchor/actions/workflows/ci.yml)
|
|
7
6
|
[](package.json)
|
|
8
7
|
[](tsconfig.json)
|
|
9
|
-
[](tests/store.test.ts)
|
|
10
9
|
[](package.json)
|
|
11
10
|
[](#1-绝对零仓库污染与跨进程文件锁)
|
|
12
11
|
[](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 # 全套自动化单元测试 (
|
|
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 & 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 & 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 <id>`</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 <id>`</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/assets/hero.svg
ADDED
|
@@ -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 <id>`</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:
|
|
35
|
-
{ title: 'Upcoming ·
|
|
36
|
-
{ title: 'Habits ·
|
|
37
|
-
{ title: '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;
|
package/dist/extension.cjs
CHANGED
|
@@ -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(
|
|
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(`\
|
|
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
|
|
1823
|
+
description: "Inspect, pin, or settle active anchors (e.g. /anchor, /anchor done 1, /anchor undo)",
|
|
1773
1824
|
handler: async (args, ctx) => {
|
|
1774
|
-
const
|
|
1775
|
-
if (
|
|
1825
|
+
const parsed = parseAnchorCommandInput(args);
|
|
1826
|
+
if (parsed.mode === "dashboard") {
|
|
1776
1827
|
await openAnchorDashboard(ctx, store);
|
|
1777
1828
|
return;
|
|
1778
1829
|
}
|
|
1779
|
-
if (
|
|
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
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
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
|
|
1798
|
-
|
|
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: "
|
|
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
|
|
1806
|
-
if (!
|
|
1890
|
+
const target = (args || "").trim();
|
|
1891
|
+
if (!target) {
|
|
1807
1892
|
await openAnchorDashboard(ctx, store);
|
|
1808
1893
|
return;
|
|
1809
1894
|
}
|
|
1810
|
-
const
|
|
1811
|
-
|
|
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
|
+
});
|