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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # ⌖ Anchor
2
2
 
3
- > **A digital sticky note for Pi Coding Agent — with three clever touches.**
4
- > Stick a quick note across sessions (`/pin`), get a 1-line comment whisper when the AI touches that file, and watch the note tear itself off when you `git commit`. Zero `TODO.md` clutter in your repo.
3
+ > **A digital sticky note docked below your Pi editor — 0ms instant stick, micro progress bars `[■■□□ 2/4]`, 1-click session teleport (`↪`), and automatic teardown on `git commit`.**
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: 9 Passed](https://img.shields.io/badge/Tests-9%20Passed-22c55e.svg)](tests/store.test.ts)
8
+ [![Tests: 10 Passed](https://img.shields.io/badge/Tests-10%20Passed-22c55e.svg)](tests/store.test.ts)
9
+ [![Startup: < 45ms](https://img.shields.io/badge/Startup-%3C%2045ms-success.svg)](package.json)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-f97316.svg)](LICENSE)
11
11
 
12
12
  **English** | [简体中文](./README_zh.md)
@@ -16,57 +16,104 @@ pi install npm:pi-anchor
16
16
  ```
17
17
 
18
18
  <p align="center">
19
- <img src="assets/hero-en.svg" alt="Anchor Sticky Notes" width="820">
19
+ <img src="assets/hero-en.svg" alt="Anchor Below-Editor Sticky Strip" width="820">
20
20
  </p>
21
21
 
22
22
  ```text
23
- ⌖ Notes (3):
23
+ ┌─ [aboveEditor stays 100% free for pi-lingual and other HUD widgets] ────────────┐
24
+ ╭─┴─ Pi Editor ────────────────────────────────────────────────────────────────────╮
25
+ │ ❯ pin: Refactor auth flow: 1. Extract interface 2. HttpOnly cookie 3. Unit tests │
26
+ ╰─┬────────────────────────────────────────────────────────────────────────────────╯
27
+ └─► ⌖ #1 [■■□□ 2/4] Refactor auth flow ▸ Unit tests (app · auth.ts ↪)
28
+ ```
24
29
 
25
- 01 Switch session token to HttpOnly cookie app · auth.ts 25m ago
26
- 02 Double-check rate limit fallback on timeout app · gateway.ts 3h ago
27
- 03 Read external architecture notes first College/优化 · notes.md 8d ago · quiet
30
+ ---
28
31
 
29
- Run `anchor done <num>` to tear off, or `anchor undo` to put back.
30
- ```
32
+ ## Core Value
33
+
34
+ Late at night, mid-way through fixing a bug, you spot a second issue in `src/auth.ts` or need to pause a multi-step refactor until tomorrow. Standard ways of recording that note create immediate friction:
35
+
36
+ 1. **Terminal Exit Wipes Working Memory**: Closing the terminal or running `/new` clears the agent's context. Yesterday's unfinished steps and the conversation history behind them vanish.
37
+ 2. **`TODO.md` Pollutes Git & Burns Context Tokens**: Tracking personal reminders inside repository markdown files dirties `git status` and re-injects stale checklists into the system prompt on every turn.
38
+ 3. **Splash Banners Vanish When You Start Typing**: Traditional startup widgets disappear on the first message. For the rest of a two-hour session, your notes are hidden unless you manually run a slash command.
39
+
40
+ **Anchor acts like a physical sticky note stuck to the bottom bezel of your Pi editor**:
41
+ - **Persistent Below-Editor Strip (`belowEditor`)**: Docks a single-line note strip directly beneath your input box. It stays in view while you code, leaves `aboveEditor` untouched for extensions like `pi-lingual`, and collapses to 0 lines when empty.
42
+ - **0ms Human-First Capture (`pin: ...`)**: Type `pin: Check token expiry` (or `/pin ...`) straight into the editor. An input hook intercepts the text in `0.00ms` without calling the language model or spending tokens.
43
+ - **Micro Progress Bar (`[■■□□ 2/4]`)**: Write `[2/4]` or numbered steps (`1. Extract interface 2. HttpOnly cookie 3. Unit tests`) in your note to get an inline 4-cell progress bar with next-step hints.
44
+ - **Session Teleport (`↪ Jump to session`)**: Every note bookmarks the exact `.jsonl` session file where it was created or last touched. Select `↪ Jump to session` in `/anchor` to switch Pi straight back to that conversation.
31
45
 
32
46
  ---
33
47
 
34
- ## Why a Sticky Note Instead of `TODO.md`?
48
+ ## How It Works
35
49
 
36
- When you're deep in a coding session at 11 PM and realize *"I still need to fix the token expiry in `src/auth.ts` tomorrow"*, you don't want a heavy task manager:
37
- - Putting a `TODO.md` inside your repo pollutes `git status` and forces the AI to re-read stale checklists on every single turn.
38
- - Closing the terminal wipes the agent's working memory clean.
50
+ | Mode / Action | What You Input | What the Engine Does | What You See | Best For |
51
+ | :--- | :--- | :--- | :--- | :--- |
52
+ | **Stick a Note (0ms)** | Type `pin: Fix auth in src/auth.ts` or `/pin ...` | Intercepts via input hook in `0ms`, extracts file paths, and links current `sessionFile` | 1-line strip appears below editor: `⌖ #1 Fix auth (app · auth.ts ↪)` | Capturing a tangent without derailing the current prompt |
53
+ | **Track Multi-Step Work** | Type `/pin Refactor: 1. API 2. Cookie 3. Tests` then `/step 1` | Parses step list and increments `done / total` counter in `~/.anchor/state.json` | Strip updates in place: `⌖ #1 [■■□□ 2/3] Refactor ▸ Tests` | Multi-session features and long-running study goals |
54
+ | **Resume Context (`↪`)** | Run `/anchor` ➔ select `↪ Jump to session` (or `/anchor jump 1`) | Invokes Pi's native `ctx.switchSession(note.sessionFile)` | Terminal switches directly back to the original conversation transcript | Picking up a complex task days later with full history |
55
+ | **Auto-Tear on Commit** | Commit code (`git commit -m "feat: fix auth"`) or run `/done 1` | Matches commit message against active notes (filtering generic stop-words) | Note archives to `archive.jsonl`; strip clears (`⌖ Auto-torn off #1`) | Keeping the sticky strip clean without manual bookkeeping |
39
56
 
40
- **Anchor is just a physical sticky note stuck to the bezel of your terminal** — stored outside your repo in `~/.anchor/state.json` (<10 KB, zero external dependencies, 4 source files), with three small, thoughtful touches:
57
+ ---
41
58
 
42
- ### 1. Stick It & Forget It (Smart Path Spotting)
43
- Write a note in plain language:
44
- ```text
45
- /pin Switch session token to HttpOnly cookie in src/auth.ts
46
- ```
47
- Anchor spots `src/auth.ts` (or any project path like `D:/College/...`) directly from your sentence — no forms or tags to fill out. Next time you open Pi in that project, a quiet card sits above your editor (`⌖ 1 note`) and disappears the moment you start typing.
59
+ ## Features & Engineering Answers
48
60
 
49
- ### 2. A Gentle Whisper When Touching the File (0 Idle Tokens)
50
- Anchor briefs the AI once on Turn 1 of a session, then drops to **0 tokens** from Turn 2 onwards.
51
- When the AI reads or edits `src/auth.ts`, Anchor slips a single syntax-safe comment onto the end of that file read (`// ⌖ Note #1: Switch session token to HttpOnly cookie`), while strictly skipping `.json`, `.env`, and lockfiles.
61
+ ### 1. Will the sticky strip collide with `pi-lingual` or overflow narrow split panes?
62
+ Anchor mounts its widget with `{ placement: "belowEditor" }`. Extensions that render translation cards or diagnostics above the input box (`aboveEditor`) never overlap with Anchor.
63
+ On narrow terminal splits (such as 50-column tmux panes), the strip measures visual column widths using Unicode East Asian Width rules (CJK/emoji = 2 cells, ASCII = 1 cell) and dynamically folds multiple notes into `⌖ 3: #1 [■■□□ 2/4] Refactor… +2` while stripping unclosed brackets before ellipses.
52
64
 
53
- *(Notes untouched for more than 7 days automatically enter `quiet` mode so they don't spend Turn-1 tokens in unrelated workspaces, while staying 100% visible in `/anchor` and waking up as soon as you open their project.)*
65
+ ### 2. Does keeping sticky notes cost tokens on every turn?
66
+ **Turn 2+ consumes 0 system prompt tokens.**
67
+ Anchor injects a compact summary of active notes only on Turn 1 of a cold session. From Turn 2 onwards, the system prompt hook returns nothing. When the agent reads or edits a file that matches a note's path or glob (`src/auth/*.ts`), Anchor appends a single syntax-safe comment line (`// ⌖ Note #1: ...`) to that tool result, while returning `null` for `.json`, `.env`, lockfiles, and binaries.
54
68
 
55
- ### 3. Auto-Tears Off on `git commit`
56
- When you or the AI commits the fix (`git commit -m "feat: switch session token to HttpOnly cookie"`), Anchor matches the commit message against your sticky notes and tears the note off in real time (`⌖ Auto-torn off #1`).
57
- Tore one off by mistake? Run `/anchor undo` to stick it right back.
69
+ ### 3. What happens to old notes or accidental `git commit` matches?
70
+ - **7-Day Quiet Mode (Zero Silent Deletion)**: Notes untouched for more than 7 days transition to `sleeping` (`quiet`). They stop appearing in Turn-1 prompts for unrelated workspaces, remain 100% visible in `/anchor`, and wake up automatically when you open their target project.
71
+ - **Stop-Word Filtered Commit Matching & 1-Tap Undo**: Commit matching strips generic words (`fix`, `feat`, `chore`, `bug`, `update`) so a commit like `fix: typo in bug template` never tears off a note titled `fix bug in login`. If you ever tear off a note by mistake, `/anchor undo` pops the last entry from `archive.jsonl` right back onto your strip.
72
+ - **Bracketed Ratio Parsing**: Progress ratios require explicit brackets (`[2/4]` or `(5/30)`), ensuring calendar dates in note titles (like `Before 10/12 release`) are never mistaken for progress bars.
73
+
74
+ ### 4. Storage Topology & Cross-Process Lock Safety
75
+ All state lives in `~/.anchor/` outside your git repository:
76
+ ```text
77
+ ~/.anchor/
78
+ ├── state.json # Active and quiet sticky notes (< 2KB, atomic temp-file + rename)
79
+ ├── state.lock # Cross-process exclusive lock (fs.openSync 'wx' + dead-PID reclamation)
80
+ └── archive.jsonl # Append-only history of torn-off notes (powers /anchor undo)
81
+ ```
58
82
 
59
83
  ---
60
84
 
61
85
  ## Commands
62
86
 
63
- | Where | Command | What It Does |
87
+ | Where | Input / Command | Description |
64
88
  | :--- | :--- | :--- |
65
- | **Inside Pi** | `/pin <note>` | Stick a new note (or just tell the AI *"Remember to..."*) |
66
- | **Inside Pi** | `/anchor` | Open the interactive sticky note list (press Enter to tear off or read) |
67
- | **Inside Pi** | `/done 1` | Tear off note `#01` directly |
68
- | **Inside Pi** | `/anchor undo` | Put back the last torn-off note |
69
- | **Terminal CLI** | `anchor` / `anchor "<note>"` / `anchor done 1` | Manage the exact same sticky notes outside Pi |
89
+ | **Pi Editor** | `pin: <note>` or `便签: <note>` | Stick a note in **0ms** without calling the LLM |
90
+ | **Pi Slash** | `/pin <note>` | Stick a note (supports `[1/4]` or `1. A 2. B 3. C` steps) |
91
+ | **Pi Slash** | `/anchor` | Open interactive sticky note board (tear off, `+1` step, `↪` jump to session, or read details) |
92
+ | **Pi Slash** | `/step 1` | Advance progress bar on note `#1` by `+1` |
93
+ | **Pi Slash** | `/anchor jump 1` | Switch Pi back to the conversation session linked to note `#1` |
94
+ | **Pi Slash** | `/done 1` / `/anchor 1` | Tear off note `#1` and archive it |
95
+ | **Pi Slash** | `/anchor undo` | Put back the most recently torn-off note |
96
+ | **Terminal CLI** | `anchor` / `anchor "<note>"` | View or stick notes from any shell outside Pi |
97
+ | **Terminal CLI** | `anchor step 1` / `anchor done 1` / `anchor undo` | Advance progress, tear off, or restore notes from the command line |
98
+
99
+ ---
100
+
101
+ ## Author's Note
102
+
103
+ Anchor started because I hated watching `TODO.md` files rot inside my git repositories, yet closing my terminal at night always meant losing track of what I still needed to fix the next morning.
104
+
105
+ In its early versions, I over-engineered the solution. By `v0.3`, Anchor had grown into a 10-file miniature project manager with four cognitive quadrants (`Today`, `Upcoming`, `Habits`, `Backlog`), `[P0]` priority tags, daily recurring habit trackers, pre-flight shell test runners on startup, and a graveyard eviction state machine. Ironically, the more features it gained, the less I wanted to use it. Worse, its startup banner disappeared the moment I typed my first message, hiding my notes for the rest of the coding session.
106
+
107
+ In `v0.4` and `v0.5`, I threw away 60% of the codebase and rebuilt Anchor around four files (`types.ts`, `store.ts`, `tui.ts`, `extension.ts`) as a simple digital sticky note:
108
+ 1. Dock the 1-line note strip **below** the editor (`belowEditor`) so it stays in sight while coding and never fights with `pi-lingual` above the editor.
109
+ 2. Let human hands stick a note in `0ms` by typing `pin: ...` without waiting on a model call.
110
+ 3. Add a 4-cell progress bar (`[■■□□ 2/4]`) for multi-step refactors and bookmark the session file (`↪`) so clicking a note teleports you back to the exact conversation where the work started.
111
+
112
+ ```bash
113
+ npm run typecheck # Strict tsc --noEmit check (0 errors)
114
+ npm test # Native Node test runner (10/10 passing)
115
+ npm run build # Dual ESM/CJS compilation via tsup + declaration emit
116
+ ```
70
117
 
71
118
  ---
72
119
 
package/README_zh.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # ⌖ Anchor
2
2
 
3
- > **贴在 Pi 终端边框上的电子便签 —— 带一点刚刚好的小巧思。**
4
- > 随手贴一张跨会话备忘(`/pin`),AI 读改关联文件时顺手递上一行注释提醒,`git commit` 提交代码时自动撕掉便签。不在代码仓库里留任何 `TODO.md` 垃圾。
3
+ > **贴在 Pi 输入框正下方的电子便签 —— `便签: ...` 0ms 瞬贴上屏、长线任务迷你进度条 `[■■□□ 2/4]`、一键切回原对话上下文 (`↪`),`git commit` 提交代码自动撕便签。**
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: 9 Passed](https://img.shields.io/badge/Tests-9%20通过-22c55e.svg)](tests/store.test.ts)
8
+ [![Tests: 10 Passed](https://img.shields.io/badge/Tests-10%20通过-22c55e.svg)](tests/store.test.ts)
9
+ [![启动耗时: < 45ms](https://img.shields.io/badge/启动耗时-%3C%2045ms-success.svg)](package.json)
10
10
  [![开源协议: MIT](https://img.shields.io/badge/开源协议-MIT-f97316.svg)](LICENSE)
11
11
 
12
12
  [English](./README.md) | **简体中文**
@@ -16,60 +16,107 @@ pi install npm:pi-anchor
16
16
  ```
17
17
 
18
18
  <p align="center">
19
- <img src="assets/hero-zh.svg" alt="Anchor 电子便签预览" width="820">
19
+ <img src="assets/hero-zh.svg" alt="Anchor 输入框下方常驻便签条预览" width="820">
20
20
  </p>
21
21
 
22
22
  ```text
23
- ⌖ Notes (3):
23
+ ┌─ [输入框上方 aboveEditor 完全留给 pi-lingual 等插件,上下零冲突] ─────────────┐
24
+ ╭─┴─ Pi 输入框 ────────────────────────────────────────────────────────────────────╮
25
+ │ ❯ 便签: 重构登录鉴权流: 1. 抽出接口 2. 替换Cookie 3. 补单测 4. 压测 │
26
+ ╰─┬────────────────────────────────────────────────────────────────────────────────╯
27
+ └─► ⌖ #1 [■■□□ 2/4] 重构登录鉴权流 ▸ 补单测 (app · auth.ts ↪)
28
+ ```
24
29
 
25
- 01 把登录 Token 改用 HttpOnly Cookie 存储 app · auth.ts 25m ago
26
- 02 检查网关超时后的降级重试边界 app · gateway.ts 3h ago
27
- 03 College 重构前置查阅外部架构参考库 College/优化 · notes.md 8d ago · quiet
30
+ ---
28
31
 
29
- Run `anchor done <num>` to tear off, or `anchor undo` to put back.
30
- ```
32
+ ## Core Value
33
+
34
+ 深夜写代码查问题时,你经常顺眼看到另一个文件里的隐患,或者手头的长线重构今天只做了一半。传统的记录方式总有三处具体的别扭:
35
+
36
+ 1. **关掉终端或开新会话即失忆**:按下 `Ctrl+C` 或敲 `/new` 开启新会话,昨晚改到哪一步、当时那场对话聊了什么上下文,瞬间断线。
37
+ 2. **`TODO.md` 弄脏 Git 且每轮白烧 Token**:在项目根目录维护待办文件,既制造杂乱的 Git 修改记录,又在每一轮对话里反复把旧清单塞进系统提示词。
38
+ 3. **开局闪现横幅一打字就消失**:普通插件只在打开终端时闪一下提示,你发完第一句话它就自我隐藏。接下来两个小时写代码,除非专门敲命令查询,否则根本看不见自己记了什么。
39
+
40
+ **Anchor 的定位很单纯:贴在 Pi 输入框下边框的一张电子便签**:
41
+ - **输入框正下方常驻 1 行 (`belowEditor`)**:便签条固定在输入框下沿,写代码时抬眼可见;输入框上方空间完全留给 `pi-lingual` 等插件;没有便签时自动收起为 0 行。
42
+ - **自己随手敲,0ms 瞬贴 (`便签: ...`)**:直接在输入框敲 `便签: 检查网关超时重试`(或 `pin: ...`、`/pin ...`),输入钩子在 `0.00ms` 内直接拦截上屏,不调用大模型、不耗费 1 个 Token,并自动关联当前刚修改过的代码文件。
43
+ - **长线任务迷你进度条 (`[■■□□ 2/4]`)**:在便签里写 `[2/4]` 或分步序号 `1. 抽出接口 2. 替换Cookie 3. 补单测`,便签条自动显示 4 格进度条与下一步提示。
44
+ - **原对话一键穿越 (`↪ Jump to session`)**:每张便签自动记录创建或施工时的会话文件路径(`sessionFile`)。在 `/anchor` 面板中点击 `↪ Jump to session`,直接切回当时那场对话。
45
+
46
+ ---
47
+
48
+ ## How It Works
49
+
50
+ | 操作场景 | 你的输入 | 后台执行逻辑 | 界面即时反馈 | 适用时刻 |
51
+ | :--- | :--- | :--- | :--- | :--- |
52
+ | **0ms 随手贴便签** | 输入框敲 `便签: 把 src/auth.ts 改用 Cookie` | `input` 钩子 0ms 拦截,提取文件路径并记录当前 `sessionFile` | 输入框下方立即浮现:`⌖ #1 把 src/auth.ts 改用 Cookie (app · auth.ts ↪)` | 改代码中途冒出支线念头,不想打断当前对话 |
53
+ | **分步推进长任务** | 敲 `/pin 重构: 1. 接口 2. Cookie 3. 单测` 后敲 `/step 1` | 解析分步列表并在 `~/.anchor/state.json` 推进完成步数 | 下方便签条实时变为:`⌖ #1 [■■□□ 2/3] 重构 ▸ 单测` | 跨天重构、分步排障或刷课程章节 |
54
+ | **切回原对话 (`↪`)** | 敲 `/anchor` 选中便签点 `↪ Jump to session`(或 `/anchor jump 1`) | 调用 Pi 原生 `ctx.switchSession(note.sessionFile)` | 终端直接切回贴这张便签时的完整历史对话上下文 | 隔了几天回来继续施工,需要找回当时的讨论细节 |
55
+ | **提交代码自动撕** | 执行 `git commit -m "feat: 登录改用 Cookie"` 或敲 `/done 1` | 过滤通用停用词后比对提交信息与便签关键词 | 便签自动归档至 `archive.jsonl`,下方便签条同步消失 | 写完代码顺手提交,免去手动打勾销账 |
31
56
 
32
57
  ---
33
58
 
34
- ## 为什么是一张电子便签,而不是 `TODO.md`?
59
+ ## Features & Engineering Answers
35
60
 
36
- 深夜写代码准备关机时,你突然想到 *“明天得把 `src/auth.ts` 里的 Token 改成 Cookie”*。这时候你不需要一套沉重的项目管理系统:
37
- - 往仓库里塞 `TODO.md` 会弄脏 `git status`,而且每一轮对话都在白白消耗上下文 Token;
38
- - 直接关掉终端,AI 的内存记忆瞬间清空。
61
+ ### 1. 下方常驻便签条会和 `pi-lingual` 冲突,或者在窄分屏下撑爆换行吗?
62
+ Anchor 显式指定 `{ placement: "belowEditor" }` 挂载在输入框下方,与挂载在输入框上方(`aboveEditor`)的 `pi-lingual` 物理隔离,上下各司其职。
63
+ 面对 50 列宽度的窄分屏终端,排版函数按 Unicode 东亚字符宽度标准(中文/Emoji 计 2 列,ASCII 计 1 列)动态计算剩余预算:窄屏下自动折叠为 `⌖ 3: #1 [■■□□ 2/4] 重构登录… +2`,并在省略号截断前自动清理未闭合的左括号。
39
64
 
40
- **Anchor 就是贴在终端显示器边框上的一张电子便签** —— 独立保存在全局 `~/.anchor/state.json`(全工程仅 4 个核心源码文件、0 外部依赖、20KB 体积),只做三件有小巧思的事:
65
+ ### 2. 便签常驻显示,会不会每一轮对话都偷偷消耗上下文 Token?
66
+ **第 2 轮起系统提示词消耗为 0 Token。**
67
+ 界面上的便签条是纯本地终端 TUI 渲染组件。仅在会话第 1 轮冷启动时,Anchor 向系统提示词注入一次简短摘要;从第 2 轮起完全静默。只有当 AI 读取或编辑了便签关联的代码文件时,Anchor 才在该文件工具返回结果末尾追加 1 行对应语言的注释(`// ⌖ Note #1: ...`),遇到 `.json`、`.env`、锁文件与二进制文件则严格返回 `null` 跳过。
41
68
 
42
- ### 1. 随手一贴,自动认路(无需填表打标签)
43
- 直接用大白话敲一句:
69
+ ### 3. 很久没碰的旧便签会丢吗?普通的 `git commit -m "fix bug"` 会不会误撕便签?
70
+ - **7 天转静默,永不自动删数据**:超过 7 天未触碰的便签自动标记为 `quiet`(不在无关工程的首轮提示词里刷存在感),但在 `/anchor` 列表中始终保留,一旦进入对应工程目录即自动唤醒。
71
+ - **停用词过滤与一键反悔**:Git 提交匹配会自动剔除 `fix`、`feat`、`bug`、`修复`、`优化` 等高频泛化词,杜绝无关提交误删便签。万一手动撕错了,敲 `/anchor undo` 即可从 `archive.jsonl` 原样贴回。
72
+ - **进度比防误判守卫**:比例进度条严格要求带括号(如 `[2/4]` 或 `(5/30)`),日常写 `10/12 前发布接口` 等日期数字绝不会被误判为进度条。
73
+
74
+ ### 4. 全局存储拓扑与多窗口并发锁
75
+ 所有便签数据独立存放在用户主目录 `~/.anchor/`,项目仓库保持 100% 干净:
44
76
  ```text
45
- /pin 把 src/auth.ts 的登录改用 HttpOnly Cookie
77
+ ~/.anchor/
78
+ ├── state.json # 当前便签状态表 (< 2KB,临时文件写入 + 原子 rename)
79
+ ├── state.lock # 跨进程排他文件锁 (fs.openSync 'wx' + 死进程 PID 自动回收)
80
+ └── archive.jsonl # 已撕下便签的追加式历史记录 (支撑 /anchor undo 秒级恢复)
46
81
  ```
47
- Anchor 会自动从这句话里认出文件名 `src/auth.ts`(或诸如 `D:/College/...` 的目录路径),自动绑定到对应工程。下次打开终端时,输入框上方安静浮现小便签(`⌖ 1 note`),你一开始打字它就自动收起,绝不挡视线。
48
82
 
49
- ### 2. 碰文件时顺手递纸条(平时 0 Token)
50
- 会话第 1 轮冷启动时向 AI 交代一眼当前便签,从第 2 轮起 **0 Token 损耗**。
51
- 只有当 AI 真正读取或修改 `src/auth.ts` 时,Anchor 才会在文件内容末尾顺手附上 1 行合法注释(`// ⌖ Note #1: 把 src/auth.ts 的登录改用 HttpOnly Cookie`),遇到 `.json`、`.env` 等文件则严格跳过。
83
+ ---
52
84
 
53
- *(超过 7 天没动过的旧便签会自动加上 `· quiet` 静默省流标记,不在无关工程首轮刷存在感,但在 `/anchor` 列表里永远都在,绝不莫名消失;一旦你进入对应工程目录就会自动唤醒。)*
85
+ ## Commands
54
86
 
55
- ### 3. 提交代码自动撕便签(支持一键反悔)
56
- 当你或 AI 执行 `git commit -m "feat: 登录改用 HttpOnly Cookie"` 时,Anchor 发现提交说明与便签吻合,当场自动帮你把这张便签撕掉归档(`⌖ Auto-torn off #1`)。
57
- 撕错了?敲一下 `/anchor undo` 就能原封不动贴回来。
87
+ | 位置 | 输入 / 命令 | 作用说明 |
88
+ | :--- | :--- | :--- |
89
+ | **Pi 输入框直敲** | `便签: <内容>` 或 `pin: <内容>` | **0ms 直接贴便签**(不触发大模型请求,自动绑定当前改过的文件与 Session) |
90
+ | **Pi 斜杠命令** | `/pin <内容>` | 贴一张新便签(支持写 `[1/4]` 或 `1. A 2. B 3. C` 自动生成进度条) |
91
+ | **Pi 斜杠命令** | `/anchor` | 打开交互面板(回车可撕便签、推进度 `+1`、`↪` 切回原对话 Session、看详情) |
92
+ | **Pi 斜杠命令** | `/step 1` | 将 `#1` 便签的进度条往前推进 `+1` 步 |
93
+ | **Pi 斜杠命令** | `/anchor jump 1` | 直接切换回 `#1` 便签绑定的那场历史对话 (`switchSession`) |
94
+ | **Pi 斜杠命令** | `/done 1` / `/anchor 1` | 按编号 `#1` 直接撕下便签并归档 |
95
+ | **Pi 斜杠命令** | `/anchor undo` | 把刚刚撕下的便签重新贴回原位 |
96
+ | **系统命令行** | `anchor` / `anchor "<内容>"` | 不进 Pi 也能在外部终端查看或贴便签 |
97
+ | **系统命令行** | `anchor step 1` / `anchor done 1` / `anchor undo` | 在外部终端推进进度、撕便签或撤销 |
58
98
 
59
99
  ---
60
100
 
61
- ## 常用命令
101
+ ## Author's Note
62
102
 
63
- | 场景 | 命令 | 作用 |
64
- | :--- | :--- | :--- |
65
- | **Pi 终端内** | `/pin <内容>` | 随手贴一张新便签(也可以直接对 AI 说 *“记一下明天…”*) |
66
- | **Pi 终端内** | `/anchor` | 打开便签列表,回车即可撕掉(Done)或查看详情 |
67
- | **Pi 终端内** | `/done 1` | 直接按编号撕掉第 1 张便签 |
68
- | **Pi 终端内** | `/anchor undo` | 把刚撕掉的便签重新贴回来 |
69
- | **系统命令行** | `anchor` / `anchor "<内容>"` / `anchor done 1` | 不开 Pi 也能随时在终端查看或贴便签 |
103
+ 做 Anchor 的初衷很简单:我讨厌项目仓库里的 `TODO.md` 弄脏 Git 提交历史,但每天深夜关掉终端时,又需要有个地方随手记一句“明天接着改哪儿”。
104
+
105
+ 早期版本里,我犯了典型的过度设计病。到 `v0.3` 时,Anchor 膨胀成了 10 个源码文件的小型任务管理系统:塞进了四象限分类(`Today`、`Upcoming`、`Habits`、`Backlog`)、`[P0]` 优先级标签、每日习惯打卡、启动时同步阻塞跑测试脚本,甚至还有一套自动把过期任务移入坟场的淘汰机制。结果功能越堆越多,我自己反而越用越别扭——尤其荒诞的是,开局弹出的便签提示在我发出第一句话后就自动隐藏了,真正写代码的几个小时里根本看不见它。
106
+
107
+ 在 `v0.4` 和 `v0.5` 中,我删掉了 60% 的代码,只留 4 个核心文件(`types.ts`、`store.ts`、`tui.ts`、`extension.ts`),让它老老实实回归一张贴在输入框下沿的电子便签:
108
+ 1. 用 `belowEditor` 把单行便签条固定在输入框正下方,写代码时一眼能瞥见,同时把输入框上方的位置让给 `pi-lingual`。
109
+ 2. 便签本来就是给人自己随手写的,敲一句 `便签: ...` 在 0ms 内直接上屏,不必等大模型转圈。
110
+ 3. 针对跨天的大活,顺手加上 4 格迷你进度条(`[■■□□ 2/4]`)和原对话书签(`↪`),点一下就能切回当时的对话上下文接着干。
111
+
112
+ ```bash
113
+ npm run typecheck # TypeScript 严格类型检查 (0 错误)
114
+ npm test # 原生 Node 测试运行器 (10/10 全绿通过)
115
+ npm run build # tsup 双格式打包与类型声明生成
116
+ ```
70
117
 
71
118
  ---
72
119
 
73
- ## 开源协议
120
+ ## License
74
121
 
75
122
  MIT © [Jason Song](https://github.com/3ZEROS12)
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 390" width="840" height="390">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 410" width="840" height="410">
2
2
  <defs>
3
3
  <filter id="shadow" x="-5%" y="-5%" width="110%" height="115%" filterUnits="userSpaceOnUse">
4
4
  <feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#000000" flood-opacity="0.45" />
@@ -10,62 +10,79 @@
10
10
  </defs>
11
11
 
12
12
  <g filter="url(#shadow)">
13
- <rect x="20" y="15" width="800" height="350" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
13
+ <rect x="20" y="15" width="800" height="370" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
14
14
  <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" />
15
15
  <line x1="20" y1="52" x2="820" y2="52" stroke="#2d353b" stroke-width="1" />
16
16
  <circle cx="42" cy="33.5" r="5.5" fill="#e67e80" />
17
17
  <circle cx="60" cy="33.5" r="5.5" fill="#dbbc7f" />
18
18
  <circle cx="78" cy="33.5" r="5.5" fill="#a7c080" />
19
19
  <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">
20
- ⌖ anchor · A Digital Sticky Note for Your Terminal
20
+ ⌖ anchor (v0.5.0) · Below-Editor Sticky Strip · Progress Bar · Session Teleport
21
21
  </text>
22
22
  </g>
23
23
 
24
24
  <g font-family="'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace" font-size="13" xml:space="preserve">
25
- <text x="45" y="86">
26
- <tspan fill="#a7c080" font-weight="bold">~/Workspace/app</tspan>
27
- <tspan fill="#7fbbb3"> ❯ </tspan>
28
- <tspan fill="#d3c6aa" font-weight="bold">anchor</tspan>
29
- </text>
30
-
31
- <text x="45" y="120">
25
+ <text x="45" y="84">
32
26
  <tspan fill="#7fbbb3" font-weight="bold">⌖ Notes (3):</tspan>
33
27
  </text>
34
28
 
35
- <text x="45" y="154">
29
+ <text x="45" y="116">
36
30
  <tspan fill="#859289"> 01 </tspan>
37
- <tspan fill="#d3c6aa">Switch session token to HttpOnly cookie </tspan>
38
- <tspan fill="#7fbbb3">app · auth.ts </tspan>
31
+ <tspan fill="#a7c080" font-weight="bold">[■■□□ 2/4] </tspan>
32
+ <tspan fill="#d3c6aa">Refactor auth flow </tspan>
33
+ <tspan fill="#7fbbb3">app · auth.ts ↪ </tspan>
39
34
  <tspan fill="#7a8478">25m ago</tspan>
40
35
  </text>
41
36
 
42
- <text x="45" y="182">
37
+ <text x="45" y="144">
43
38
  <tspan fill="#859289"> 02 </tspan>
44
- <tspan fill="#d3c6aa">Double-check rate limit fallback on timeout </tspan>
45
- <tspan fill="#7fbbb3">app · gateway.ts </tspan>
39
+ <tspan fill="#d3c6aa">Double-check rate limit fallback on timeout </tspan>
40
+ <tspan fill="#7fbbb3">app · gateway.ts ↪ </tspan>
46
41
  <tspan fill="#7a8478">3h ago</tspan>
47
42
  </text>
48
43
 
49
- <text x="45" y="210">
44
+ <text x="45" y="172">
50
45
  <tspan fill="#859289"> 03 </tspan>
51
- <tspan fill="#859289">Read external architecture notes first </tspan>
46
+ <tspan fill="#859289">Read external architecture notes first </tspan>
52
47
  <tspan fill="#7a8478">College/优化 · notes.md </tspan>
53
48
  <tspan fill="#56635f">8d ago · quiet</tspan>
54
49
  </text>
55
50
 
56
- <rect x="45" y="242" width="750" height="58" rx="6" fill="#232a2e" stroke="#3a464c" stroke-width="1" />
57
- <text x="62" y="266" fill="#dbbc7f">1. Stick a note: /pin Switch session token to HttpOnly cookie in src/auth.ts</text>
58
- <text x="62" y="287" fill="#a7c080">2. Auto-tear off: git commit -m "feat: switch session token to HttpOnly cookie" ➔ ⌖ Torn off #1</text>
51
+ <!-- Simulated Pi Input Box + Below-Editor Persistent Sticky Strip -->
52
+ <rect x="45" y="204" width="750" height="44" rx="6" fill="#232a2e" stroke="#4f5b58" stroke-width="1.2" />
53
+ <text x="62" y="231">
54
+ <tspan fill="#a7c080" font-weight="bold">❯ </tspan>
55
+ <tspan fill="#d3c6aa">pin: Refactor auth flow: 1. Extract interface 2. HttpOnly cookie 3. Unit tests</tspan>
56
+ </text>
57
+
58
+ <!-- Below-Editor Sticky Strip -->
59
+ <rect x="45" y="256" width="750" height="36" rx="6" fill="#292b28" stroke="#a7c080" stroke-width="1" stroke-dasharray="4,3" />
60
+ <text x="62" y="279">
61
+ <tspan fill="#a7c080" font-weight="bold">⌖ </tspan>
62
+ <tspan fill="#859289">#1 </tspan>
63
+ <tspan fill="#dbbc7f" font-weight="bold">[■■□□ 2/4] </tspan>
64
+ <tspan fill="#d3c6aa">Refactor auth flow </tspan>
65
+ <tspan fill="#7fbbb3">▸ HttpOnly cookie </tspan>
66
+ <tspan fill="#859289">(app · auth.ts ↪)</tspan>
67
+ </text>
59
68
 
60
- <text x="45" y="334" fill="#7a8478">
61
- <tspan> Commands: </tspan>
62
- <tspan fill="#7fbbb3" font-weight="bold">`/pin &lt;note&gt;`</tspan>
63
- <tspan> · </tspan>
64
- <tspan fill="#7fbbb3" font-weight="bold">`/anchor`</tspan>
65
- <tspan> · </tspan>
66
- <tspan fill="#7fbbb3" font-weight="bold">`/done 1`</tspan>
67
- <tspan> · </tspan>
68
- <tspan fill="#7fbbb3" font-weight="bold">`/anchor undo`</tspan>
69
+ <text x="45" y="324" fill="#859289">
70
+ <tspan> • </tspan>
71
+ <tspan fill="#d3c6aa" font-weight="bold">0ms Instant Stick</tspan>
72
+ <tspan>: Type </tspan>
73
+ <tspan fill="#7fbbb3">`pin: &lt;note&gt;`</tspan>
74
+ <tspan> (or </tspan>
75
+ <tspan fill="#7fbbb3">`/pin`</tspan>
76
+ <tspan>) — docked below editor, never collides with aboveEditor HUDs.</tspan>
77
+ </text>
78
+ <text x="45" y="348" fill="#859289">
79
+ <tspan> • </tspan>
80
+ <tspan fill="#d3c6aa" font-weight="bold">Session Teleport (↪)</tspan>
81
+ <tspan>: Select any note in </tspan>
82
+ <tspan fill="#7fbbb3">`/anchor`</tspan>
83
+ <tspan> or run </tspan>
84
+ <tspan fill="#7fbbb3">`/anchor jump 1`</tspan>
85
+ <tspan> to resume its conversation.</tspan>
69
86
  </text>
70
87
  </g>
71
88
  </svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 390" width="840" height="390">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 410" width="840" height="410">
2
2
  <defs>
3
3
  <filter id="shadow" x="-5%" y="-5%" width="110%" height="115%" filterUnits="userSpaceOnUse">
4
4
  <feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#000000" flood-opacity="0.45" />
@@ -10,62 +10,79 @@
10
10
  </defs>
11
11
 
12
12
  <g filter="url(#shadow)">
13
- <rect x="20" y="15" width="800" height="350" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
13
+ <rect x="20" y="15" width="800" height="370" rx="12" fill="#1e2326" stroke="#343f44" stroke-width="1.2" />
14
14
  <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" />
15
15
  <line x1="20" y1="52" x2="820" y2="52" stroke="#2d353b" stroke-width="1" />
16
16
  <circle cx="42" cy="33.5" r="5.5" fill="#e67e80" />
17
17
  <circle cx="60" cy="33.5" r="5.5" fill="#dbbc7f" />
18
18
  <circle cx="78" cy="33.5" r="5.5" fill="#a7c080" />
19
19
  <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">
20
- ⌖ anchor · 贴在终端边框上的电子便签
20
+ ⌖ anchor (v0.5.0) · 输入框下方常驻便签条 · 迷你进度条 · 原对话一键穿越
21
21
  </text>
22
22
  </g>
23
23
 
24
24
  <g font-family="'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace" font-size="13" xml:space="preserve">
25
- <text x="45" y="86">
26
- <tspan fill="#a7c080" font-weight="bold">~/Workspace/app</tspan>
27
- <tspan fill="#7fbbb3"> ❯ </tspan>
28
- <tspan fill="#d3c6aa" font-weight="bold">anchor</tspan>
29
- </text>
30
-
31
- <text x="45" y="120">
25
+ <text x="45" y="84">
32
26
  <tspan fill="#7fbbb3" font-weight="bold">⌖ Notes (3):</tspan>
33
27
  </text>
34
28
 
35
- <text x="45" y="154">
29
+ <text x="45" y="116">
36
30
  <tspan fill="#859289"> 01 </tspan>
37
- <tspan fill="#d3c6aa">把登录 Token 改用 HttpOnly Cookie 存储 </tspan>
38
- <tspan fill="#7fbbb3">app · auth.ts </tspan>
31
+ <tspan fill="#a7c080" font-weight="bold">[■■□□ 2/4] </tspan>
32
+ <tspan fill="#d3c6aa">重构登录鉴权流 </tspan>
33
+ <tspan fill="#7fbbb3">app · auth.ts ↪ </tspan>
39
34
  <tspan fill="#7a8478">25m ago</tspan>
40
35
  </text>
41
36
 
42
- <text x="45" y="182">
37
+ <text x="45" y="144">
43
38
  <tspan fill="#859289"> 02 </tspan>
44
39
  <tspan fill="#d3c6aa">检查网关超时后的降级重试边界 </tspan>
45
- <tspan fill="#7fbbb3">app · gateway.ts </tspan>
40
+ <tspan fill="#7fbbb3">app · gateway.ts ↪ </tspan>
46
41
  <tspan fill="#7a8478">3h ago</tspan>
47
42
  </text>
48
43
 
49
- <text x="45" y="210">
44
+ <text x="45" y="172">
50
45
  <tspan fill="#859289"> 03 </tspan>
51
46
  <tspan fill="#859289">College 重构前置查阅外部架构参考库 </tspan>
52
47
  <tspan fill="#7a8478">College/优化 · notes.md </tspan>
53
48
  <tspan fill="#56635f">8d ago · quiet</tspan>
54
49
  </text>
55
50
 
56
- <rect x="45" y="242" width="750" height="58" rx="6" fill="#232a2e" stroke="#3a464c" stroke-width="1" />
57
- <text x="62" y="266" fill="#dbbc7f">1. 随手贴一张: /pin 把 src/auth.ts 的登录改用 HttpOnly Cookie</text>
58
- <text x="62" y="287" fill="#a7c080">2. 提交自动撕: git commit -m "feat: 登录改用 HttpOnly Cookie" ➔ ⌖ Torn off #1</text>
51
+ <!-- Simulated Pi Input Box + Below-Editor Persistent Sticky Strip -->
52
+ <rect x="45" y="204" width="750" height="44" rx="6" fill="#232a2e" stroke="#4f5b58" stroke-width="1.2" />
53
+ <text x="62" y="231">
54
+ <tspan fill="#a7c080" font-weight="bold">❯ </tspan>
55
+ <tspan fill="#d3c6aa">便签: 重构登录鉴权流: 1. 抽出接口 2. 替换Cookie 3. 补单测 4. 压测</tspan>
56
+ </text>
57
+
58
+ <!-- Below-Editor Sticky Strip -->
59
+ <rect x="45" y="256" width="750" height="36" rx="6" fill="#292b28" stroke="#a7c080" stroke-width="1" stroke-dasharray="4,3" />
60
+ <text x="62" y="279">
61
+ <tspan fill="#a7c080" font-weight="bold">⌖ </tspan>
62
+ <tspan fill="#859289">#1 </tspan>
63
+ <tspan fill="#dbbc7f" font-weight="bold">[■■□□ 2/4] </tspan>
64
+ <tspan fill="#d3c6aa">重构登录鉴权流 </tspan>
65
+ <tspan fill="#7fbbb3">▸ 补单测 </tspan>
66
+ <tspan fill="#859289">(app · auth.ts ↪)</tspan>
67
+ </text>
59
68
 
60
- <text x="45" y="334" fill="#7a8478">
61
- <tspan> 常用命令: </tspan>
62
- <tspan fill="#7fbbb3" font-weight="bold">`/pin &lt;便签&gt;`</tspan>
63
- <tspan> · </tspan>
64
- <tspan fill="#7fbbb3" font-weight="bold">`/anchor`</tspan>
65
- <tspan> · </tspan>
66
- <tspan fill="#7fbbb3" font-weight="bold">`/done 1`</tspan>
67
- <tspan> · </tspan>
68
- <tspan fill="#7fbbb3" font-weight="bold">`/anchor undo`</tspan>
69
+ <text x="45" y="324" fill="#859289">
70
+ <tspan> • </tspan>
71
+ <tspan fill="#d3c6aa" font-weight="bold">输入框下方常驻 1 行便签条</tspan>
72
+ <tspan>:采用 </tspan>
73
+ <tspan fill="#7fbbb3">belowEditor</tspan>
74
+ <tspan> 挂载,与上方 </tspan>
75
+ <tspan fill="#7fbbb3">pi-lingual</tspan>
76
+ <tspan> 零冲突;敲 </tspan>
77
+ <tspan fill="#7fbbb3">便签: ...</tspan>
78
+ <tspan> 0ms 瞬贴。</tspan>
79
+ </text>
80
+ <text x="45" y="348" fill="#859289">
81
+ <tspan> • </tspan>
82
+ <tspan fill="#d3c6aa" font-weight="bold">原对话一键穿越 (↪)</tspan>
83
+ <tspan>:自动记录贴便签时的 Session,在 </tspan>
84
+ <tspan fill="#7fbbb3">/anchor</tspan>
85
+ <tspan> 中点击即可直接切回当时的对话上下文。</tspan>
69
86
  </text>
70
87
  </g>
71
88
  </svg>