pi-anchor 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -170
- package/README_zh.md +32 -176
- package/assets/hero-en.svg +23 -39
- package/assets/hero-zh.svg +23 -39
- package/bin/anchor.js +36 -69
- package/dist/chunk-LKY6WIKH.js +1100 -0
- package/dist/extension-B1-fzCox.d.cts +167 -0
- package/dist/extension-B1-fzCox.d.ts +167 -0
- package/dist/extension.cjs +369 -1315
- package/dist/extension.d.cts +2 -20
- package/dist/extension.d.ts +2 -20
- package/dist/extension.js +4 -536
- package/dist/index.cjs +317 -1143
- package/dist/index.d.cts +17 -250
- package/dist/index.d.ts +17 -250
- package/dist/index.js +15 -103
- package/package.json +2 -2
- package/src/extension.ts +124 -362
- package/src/index.ts +1 -6
- package/src/store.ts +294 -424
- package/src/tui.ts +102 -297
- package/src/types.ts +24 -65
- package/dist/chunk-Q7IILJFA.js +0 -1563
- package/dist/store-t2_TDhJn.d.cts +0 -210
- package/dist/store-t2_TDhJn.d.ts +0 -210
- package/src/context_injector.ts +0 -166
- package/src/decay.ts +0 -125
- package/src/matcher.ts +0 -202
- package/src/observer.ts +0 -141
- package/src/protocol.ts +0 -95
- package/src/settlement.ts +0 -140
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Anchor Data Contracts & Type Definitions
|
|
3
|
-
* Single Global Source of Truth with Zero Workspace Contamination.
|
|
4
|
-
*/
|
|
5
|
-
type AnchorStatus = 'active' | 'sleeping' | 'settled' | 'graveyard';
|
|
6
|
-
type AnchorPriority = 'p0' | 'p1' | 'p2';
|
|
7
|
-
type AnchorDurability = 'ephemeral' | 'durable';
|
|
8
|
-
interface AnchorDecayPolicy {
|
|
9
|
-
/** Days before an untouched active anchor transitions to sleeping */
|
|
10
|
-
activeDays: number;
|
|
11
|
-
/** Days an anchor remains sleeping before dropping to graveyard */
|
|
12
|
-
sleepDays: number;
|
|
13
|
-
/** Total maximum days before permanent graveyard sweep (9999 = never) */
|
|
14
|
-
graveyardDays: number;
|
|
15
|
-
}
|
|
16
|
-
interface AnchorEvidence {
|
|
17
|
-
settledAt?: number;
|
|
18
|
-
settledBy?: 'one-tap-settlement' | 'manual-command' | 'verification-test';
|
|
19
|
-
commitHash?: string;
|
|
20
|
-
summary?: string;
|
|
21
|
-
touchedFiles?: string[];
|
|
22
|
-
}
|
|
23
|
-
interface Anchor {
|
|
24
|
-
/** Unique sequential identifier, e.g., 'anc-1' */
|
|
25
|
-
id: string;
|
|
26
|
-
/** Short imperative title of the task */
|
|
27
|
-
title: string;
|
|
28
|
-
/** Optional detailed context or notes */
|
|
29
|
-
description?: string;
|
|
30
|
-
/** Task priority */
|
|
31
|
-
priority: AnchorPriority;
|
|
32
|
-
/** Current lifecycle status */
|
|
33
|
-
status: AnchorStatus;
|
|
34
|
-
/** Durability tier: ephemeral (short-lived reminder, 48h TTL) or durable (long-term architecture vision) */
|
|
35
|
-
durability: AnchorDurability;
|
|
36
|
-
/** Canonical project name (e.g. 'PPT', 'X', or 'global') */
|
|
37
|
-
project: string;
|
|
38
|
-
/** Canonical root directory where the task was anchored (empty string for global tasks) */
|
|
39
|
-
cwd: string;
|
|
40
|
-
/** Creation timestamp in ms */
|
|
41
|
-
createdAt: number;
|
|
42
|
-
/** Last update timestamp in ms */
|
|
43
|
-
updatedAt: number;
|
|
44
|
-
/** Last touched timestamp in ms (resets on file touch) */
|
|
45
|
-
lastTouchedAt: number;
|
|
46
|
-
/** Associated file paths or globs, e.g. ['src/auth/*.ts'] */
|
|
47
|
-
files: string[];
|
|
48
|
-
/** Expected completion date in format 'YYYY-MM-DD' (e.g. '2026-09-24') */
|
|
49
|
-
targetDate?: string;
|
|
50
|
-
/** Optional shell command for automated physical verification (e.g. 'npm test') */
|
|
51
|
-
verifyCommand?: string;
|
|
52
|
-
/** Topic or domain tags, e.g. ['auth', 'security'] */
|
|
53
|
-
tags: string[];
|
|
54
|
-
/** Optional recurrence pattern: 'daily' for recurring daily habits */
|
|
55
|
-
recurrence?: 'daily';
|
|
56
|
-
/** Last completed date string 'YYYY-MM-DD' for recurring tasks */
|
|
57
|
-
lastCompletedDate?: string;
|
|
58
|
-
/** Decay policy overrides */
|
|
59
|
-
decay: AnchorDecayPolicy;
|
|
60
|
-
/** Settlement evidence metadata upon closure */
|
|
61
|
-
evidence?: AnchorEvidence;
|
|
62
|
-
}
|
|
63
|
-
interface AnchorStoreState {
|
|
64
|
-
version: number;
|
|
65
|
-
anchors: Anchor[];
|
|
66
|
-
lastSweepAt: number;
|
|
67
|
-
nextId?: number;
|
|
68
|
-
}
|
|
69
|
-
interface TouchMatchResult {
|
|
70
|
-
anchor: Anchor;
|
|
71
|
-
score: number;
|
|
72
|
-
matchedFiles: string[];
|
|
73
|
-
reason: 'exact-file' | 'dir-prefix' | 'tag-keyword';
|
|
74
|
-
}
|
|
75
|
-
interface SettlementProposal {
|
|
76
|
-
anchor: Anchor;
|
|
77
|
-
matchedFiles: string[];
|
|
78
|
-
reason: string;
|
|
79
|
-
recommendedAction: 'settle' | 'defer';
|
|
80
|
-
}
|
|
81
|
-
declare const EPHEMERAL_DECAY_POLICY: AnchorDecayPolicy;
|
|
82
|
-
declare const DURABLE_DECAY_POLICY: AnchorDecayPolicy;
|
|
83
|
-
declare const DEFAULT_DECAY_POLICY: AnchorDecayPolicy;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Detect whether a task is a short-term ephemeral reminder or a long-term architectural vision
|
|
87
|
-
*/
|
|
88
|
-
declare function detectDurability(title: string): AnchorDurability;
|
|
89
|
-
/**
|
|
90
|
-
* Get custom ephemeral decay policy based on temporal span.
|
|
91
|
-
* Note: graveyardDays is always 9999 so unfinished tasks are NEVER silently deleted.
|
|
92
|
-
*/
|
|
93
|
-
declare function getEphemeralDecayPolicy(title: string): AnchorDecayPolicy;
|
|
94
|
-
/**
|
|
95
|
-
* Detect expected completion date from title keywords or explicit date string, returning 'YYYY-MM-DD'
|
|
96
|
-
*/
|
|
97
|
-
declare function detectTargetDate(titleOrDate: string, now?: number): string | undefined;
|
|
98
|
-
/**
|
|
99
|
-
* Detect recurring patterns, e.g. daily habits
|
|
100
|
-
*/
|
|
101
|
-
declare function detectRecurrence(title: string): 'daily' | undefined;
|
|
102
|
-
/**
|
|
103
|
-
* Get current date string 'YYYY-MM-DD' in local timezone
|
|
104
|
-
*/
|
|
105
|
-
declare function getTodayDateString(timestamp?: number): string;
|
|
106
|
-
/**
|
|
107
|
-
* Resolve the default storage directory for Anchor (~/.anchor).
|
|
108
|
-
* Hierarchy:
|
|
109
|
-
* 1. Process environment: ANCHOR_DIR
|
|
110
|
-
* 2. Canonical user-global store: ~/.anchor/
|
|
111
|
-
* 3. Legacy Pi harness fallback: ~/.pi/agent/anchors/ (migrates automatically if present)
|
|
112
|
-
*/
|
|
113
|
-
declare function getDefaultStorageDir(): string;
|
|
114
|
-
/**
|
|
115
|
-
* Acquire exclusive lockfile using atomic 'wx' file creation (zero external dependencies).
|
|
116
|
-
* Features:
|
|
117
|
-
* - 0 async infection (100% synchronous)
|
|
118
|
-
* - Automatic stale lock eviction (>5000ms or dead PID)
|
|
119
|
-
* - Exponential backoff with jitter
|
|
120
|
-
*/
|
|
121
|
-
declare function acquireSyncLock(lockPath: string, maxWaitMs?: number, staleTimeoutMs?: number): () => void;
|
|
122
|
-
/**
|
|
123
|
-
* Windows-tolerant atomic rename with exponential spin-retry to combat NTFS EBUSY/EPERM file locks
|
|
124
|
-
*/
|
|
125
|
-
declare function atomicRenameWithRetry(tempPath: string, targetPath: string, maxAttempts?: number): void;
|
|
126
|
-
declare class AnchorStore {
|
|
127
|
-
readonly storageDir: string;
|
|
128
|
-
readonly statePath: string;
|
|
129
|
-
readonly archivePath: string;
|
|
130
|
-
readonly graveyardPath: string;
|
|
131
|
-
constructor(customStorageDir?: string);
|
|
132
|
-
get lockPath(): string;
|
|
133
|
-
/**
|
|
134
|
-
* Execute mutation within a cross-process exclusive lock
|
|
135
|
-
*/
|
|
136
|
-
withLock<T>(fn: () => T): T;
|
|
137
|
-
private ensureDirs;
|
|
138
|
-
/**
|
|
139
|
-
* Load store state. If corrupt or missing, returns safe default.
|
|
140
|
-
*/
|
|
141
|
-
loadState(): AnchorStoreState;
|
|
142
|
-
/**
|
|
143
|
-
* Atomically save store state via temp file + atomic rename with Windows NTFS spin-retry
|
|
144
|
-
*/
|
|
145
|
-
saveState(state: AnchorStoreState): void;
|
|
146
|
-
private generateId;
|
|
147
|
-
/**
|
|
148
|
-
* Create a new Anchor with automatic project and cwd tagging
|
|
149
|
-
*/
|
|
150
|
-
create(input: {
|
|
151
|
-
title: string;
|
|
152
|
-
description?: string;
|
|
153
|
-
priority?: AnchorPriority;
|
|
154
|
-
durability?: AnchorDurability;
|
|
155
|
-
recurrence?: 'daily';
|
|
156
|
-
cwd?: string;
|
|
157
|
-
project?: string;
|
|
158
|
-
targetDate?: string;
|
|
159
|
-
files?: string[];
|
|
160
|
-
tags?: string[];
|
|
161
|
-
verifyCommand?: string;
|
|
162
|
-
decay?: AnchorDecayPolicy;
|
|
163
|
-
}): Anchor;
|
|
164
|
-
private findAnchorIndex;
|
|
165
|
-
/**
|
|
166
|
-
* Get an anchor by ID (supports 'anc-1', '#anc-1', '1', '01')
|
|
167
|
-
*/
|
|
168
|
-
get(id: string): Anchor | undefined;
|
|
169
|
-
/**
|
|
170
|
-
* List anchors. By default, if cwd is provided, only returns anchors
|
|
171
|
-
* belonging to this cwd or marked as global (''). Pass all: true for global view.
|
|
172
|
-
*/
|
|
173
|
-
list(filter?: {
|
|
174
|
-
status?: AnchorStatus;
|
|
175
|
-
priority?: AnchorPriority;
|
|
176
|
-
cwd?: string;
|
|
177
|
-
all?: boolean;
|
|
178
|
-
now?: number;
|
|
179
|
-
}): Anchor[];
|
|
180
|
-
/**
|
|
181
|
-
* Update an existing anchor
|
|
182
|
-
*/
|
|
183
|
-
update(id: string, patch: Partial<Omit<Anchor, 'id' | 'createdAt'>>): Anchor;
|
|
184
|
-
/**
|
|
185
|
-
* Touch an anchor to refresh its decay window and reactivate sleeping state
|
|
186
|
-
*/
|
|
187
|
-
touch(id: string, timestamp?: number): Anchor;
|
|
188
|
-
/**
|
|
189
|
-
* Settle an anchor (recurring daily habits complete for today and wake up tomorrow)
|
|
190
|
-
*/
|
|
191
|
-
settle(id: string, evidence?: AnchorEvidence, now?: number): Anchor;
|
|
192
|
-
/**
|
|
193
|
-
* Reverse/undo the last settled anchor, popping it from archive.jsonl back into state.json
|
|
194
|
-
*/
|
|
195
|
-
undoSettle(): Anchor;
|
|
196
|
-
/**
|
|
197
|
-
* Evict anchor to graveyard.jsonl upon total decay expiry
|
|
198
|
-
*/
|
|
199
|
-
dropToGraveyard(id: string, reason: string): Anchor;
|
|
200
|
-
getArchive(filter?: {
|
|
201
|
-
cwd?: string;
|
|
202
|
-
all?: boolean;
|
|
203
|
-
}): Anchor[];
|
|
204
|
-
getGraveyard(filter?: {
|
|
205
|
-
cwd?: string;
|
|
206
|
-
all?: boolean;
|
|
207
|
-
}): Anchor[];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export { AnchorStore as A, DEFAULT_DECAY_POLICY as D, EPHEMERAL_DECAY_POLICY as E, type SettlementProposal as S, type TouchMatchResult as T, type AnchorStatus as a, type Anchor as b, type AnchorDecayPolicy as c, type AnchorDurability as d, type AnchorEvidence as e, type AnchorPriority as f, type AnchorStoreState as g, DURABLE_DECAY_POLICY as h, acquireSyncLock as i, atomicRenameWithRetry as j, detectDurability as k, detectRecurrence as l, detectTargetDate as m, getDefaultStorageDir as n, getEphemeralDecayPolicy as o, getTodayDateString as p };
|
package/dist/store-t2_TDhJn.d.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Anchor Data Contracts & Type Definitions
|
|
3
|
-
* Single Global Source of Truth with Zero Workspace Contamination.
|
|
4
|
-
*/
|
|
5
|
-
type AnchorStatus = 'active' | 'sleeping' | 'settled' | 'graveyard';
|
|
6
|
-
type AnchorPriority = 'p0' | 'p1' | 'p2';
|
|
7
|
-
type AnchorDurability = 'ephemeral' | 'durable';
|
|
8
|
-
interface AnchorDecayPolicy {
|
|
9
|
-
/** Days before an untouched active anchor transitions to sleeping */
|
|
10
|
-
activeDays: number;
|
|
11
|
-
/** Days an anchor remains sleeping before dropping to graveyard */
|
|
12
|
-
sleepDays: number;
|
|
13
|
-
/** Total maximum days before permanent graveyard sweep (9999 = never) */
|
|
14
|
-
graveyardDays: number;
|
|
15
|
-
}
|
|
16
|
-
interface AnchorEvidence {
|
|
17
|
-
settledAt?: number;
|
|
18
|
-
settledBy?: 'one-tap-settlement' | 'manual-command' | 'verification-test';
|
|
19
|
-
commitHash?: string;
|
|
20
|
-
summary?: string;
|
|
21
|
-
touchedFiles?: string[];
|
|
22
|
-
}
|
|
23
|
-
interface Anchor {
|
|
24
|
-
/** Unique sequential identifier, e.g., 'anc-1' */
|
|
25
|
-
id: string;
|
|
26
|
-
/** Short imperative title of the task */
|
|
27
|
-
title: string;
|
|
28
|
-
/** Optional detailed context or notes */
|
|
29
|
-
description?: string;
|
|
30
|
-
/** Task priority */
|
|
31
|
-
priority: AnchorPriority;
|
|
32
|
-
/** Current lifecycle status */
|
|
33
|
-
status: AnchorStatus;
|
|
34
|
-
/** Durability tier: ephemeral (short-lived reminder, 48h TTL) or durable (long-term architecture vision) */
|
|
35
|
-
durability: AnchorDurability;
|
|
36
|
-
/** Canonical project name (e.g. 'PPT', 'X', or 'global') */
|
|
37
|
-
project: string;
|
|
38
|
-
/** Canonical root directory where the task was anchored (empty string for global tasks) */
|
|
39
|
-
cwd: string;
|
|
40
|
-
/** Creation timestamp in ms */
|
|
41
|
-
createdAt: number;
|
|
42
|
-
/** Last update timestamp in ms */
|
|
43
|
-
updatedAt: number;
|
|
44
|
-
/** Last touched timestamp in ms (resets on file touch) */
|
|
45
|
-
lastTouchedAt: number;
|
|
46
|
-
/** Associated file paths or globs, e.g. ['src/auth/*.ts'] */
|
|
47
|
-
files: string[];
|
|
48
|
-
/** Expected completion date in format 'YYYY-MM-DD' (e.g. '2026-09-24') */
|
|
49
|
-
targetDate?: string;
|
|
50
|
-
/** Optional shell command for automated physical verification (e.g. 'npm test') */
|
|
51
|
-
verifyCommand?: string;
|
|
52
|
-
/** Topic or domain tags, e.g. ['auth', 'security'] */
|
|
53
|
-
tags: string[];
|
|
54
|
-
/** Optional recurrence pattern: 'daily' for recurring daily habits */
|
|
55
|
-
recurrence?: 'daily';
|
|
56
|
-
/** Last completed date string 'YYYY-MM-DD' for recurring tasks */
|
|
57
|
-
lastCompletedDate?: string;
|
|
58
|
-
/** Decay policy overrides */
|
|
59
|
-
decay: AnchorDecayPolicy;
|
|
60
|
-
/** Settlement evidence metadata upon closure */
|
|
61
|
-
evidence?: AnchorEvidence;
|
|
62
|
-
}
|
|
63
|
-
interface AnchorStoreState {
|
|
64
|
-
version: number;
|
|
65
|
-
anchors: Anchor[];
|
|
66
|
-
lastSweepAt: number;
|
|
67
|
-
nextId?: number;
|
|
68
|
-
}
|
|
69
|
-
interface TouchMatchResult {
|
|
70
|
-
anchor: Anchor;
|
|
71
|
-
score: number;
|
|
72
|
-
matchedFiles: string[];
|
|
73
|
-
reason: 'exact-file' | 'dir-prefix' | 'tag-keyword';
|
|
74
|
-
}
|
|
75
|
-
interface SettlementProposal {
|
|
76
|
-
anchor: Anchor;
|
|
77
|
-
matchedFiles: string[];
|
|
78
|
-
reason: string;
|
|
79
|
-
recommendedAction: 'settle' | 'defer';
|
|
80
|
-
}
|
|
81
|
-
declare const EPHEMERAL_DECAY_POLICY: AnchorDecayPolicy;
|
|
82
|
-
declare const DURABLE_DECAY_POLICY: AnchorDecayPolicy;
|
|
83
|
-
declare const DEFAULT_DECAY_POLICY: AnchorDecayPolicy;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Detect whether a task is a short-term ephemeral reminder or a long-term architectural vision
|
|
87
|
-
*/
|
|
88
|
-
declare function detectDurability(title: string): AnchorDurability;
|
|
89
|
-
/**
|
|
90
|
-
* Get custom ephemeral decay policy based on temporal span.
|
|
91
|
-
* Note: graveyardDays is always 9999 so unfinished tasks are NEVER silently deleted.
|
|
92
|
-
*/
|
|
93
|
-
declare function getEphemeralDecayPolicy(title: string): AnchorDecayPolicy;
|
|
94
|
-
/**
|
|
95
|
-
* Detect expected completion date from title keywords or explicit date string, returning 'YYYY-MM-DD'
|
|
96
|
-
*/
|
|
97
|
-
declare function detectTargetDate(titleOrDate: string, now?: number): string | undefined;
|
|
98
|
-
/**
|
|
99
|
-
* Detect recurring patterns, e.g. daily habits
|
|
100
|
-
*/
|
|
101
|
-
declare function detectRecurrence(title: string): 'daily' | undefined;
|
|
102
|
-
/**
|
|
103
|
-
* Get current date string 'YYYY-MM-DD' in local timezone
|
|
104
|
-
*/
|
|
105
|
-
declare function getTodayDateString(timestamp?: number): string;
|
|
106
|
-
/**
|
|
107
|
-
* Resolve the default storage directory for Anchor (~/.anchor).
|
|
108
|
-
* Hierarchy:
|
|
109
|
-
* 1. Process environment: ANCHOR_DIR
|
|
110
|
-
* 2. Canonical user-global store: ~/.anchor/
|
|
111
|
-
* 3. Legacy Pi harness fallback: ~/.pi/agent/anchors/ (migrates automatically if present)
|
|
112
|
-
*/
|
|
113
|
-
declare function getDefaultStorageDir(): string;
|
|
114
|
-
/**
|
|
115
|
-
* Acquire exclusive lockfile using atomic 'wx' file creation (zero external dependencies).
|
|
116
|
-
* Features:
|
|
117
|
-
* - 0 async infection (100% synchronous)
|
|
118
|
-
* - Automatic stale lock eviction (>5000ms or dead PID)
|
|
119
|
-
* - Exponential backoff with jitter
|
|
120
|
-
*/
|
|
121
|
-
declare function acquireSyncLock(lockPath: string, maxWaitMs?: number, staleTimeoutMs?: number): () => void;
|
|
122
|
-
/**
|
|
123
|
-
* Windows-tolerant atomic rename with exponential spin-retry to combat NTFS EBUSY/EPERM file locks
|
|
124
|
-
*/
|
|
125
|
-
declare function atomicRenameWithRetry(tempPath: string, targetPath: string, maxAttempts?: number): void;
|
|
126
|
-
declare class AnchorStore {
|
|
127
|
-
readonly storageDir: string;
|
|
128
|
-
readonly statePath: string;
|
|
129
|
-
readonly archivePath: string;
|
|
130
|
-
readonly graveyardPath: string;
|
|
131
|
-
constructor(customStorageDir?: string);
|
|
132
|
-
get lockPath(): string;
|
|
133
|
-
/**
|
|
134
|
-
* Execute mutation within a cross-process exclusive lock
|
|
135
|
-
*/
|
|
136
|
-
withLock<T>(fn: () => T): T;
|
|
137
|
-
private ensureDirs;
|
|
138
|
-
/**
|
|
139
|
-
* Load store state. If corrupt or missing, returns safe default.
|
|
140
|
-
*/
|
|
141
|
-
loadState(): AnchorStoreState;
|
|
142
|
-
/**
|
|
143
|
-
* Atomically save store state via temp file + atomic rename with Windows NTFS spin-retry
|
|
144
|
-
*/
|
|
145
|
-
saveState(state: AnchorStoreState): void;
|
|
146
|
-
private generateId;
|
|
147
|
-
/**
|
|
148
|
-
* Create a new Anchor with automatic project and cwd tagging
|
|
149
|
-
*/
|
|
150
|
-
create(input: {
|
|
151
|
-
title: string;
|
|
152
|
-
description?: string;
|
|
153
|
-
priority?: AnchorPriority;
|
|
154
|
-
durability?: AnchorDurability;
|
|
155
|
-
recurrence?: 'daily';
|
|
156
|
-
cwd?: string;
|
|
157
|
-
project?: string;
|
|
158
|
-
targetDate?: string;
|
|
159
|
-
files?: string[];
|
|
160
|
-
tags?: string[];
|
|
161
|
-
verifyCommand?: string;
|
|
162
|
-
decay?: AnchorDecayPolicy;
|
|
163
|
-
}): Anchor;
|
|
164
|
-
private findAnchorIndex;
|
|
165
|
-
/**
|
|
166
|
-
* Get an anchor by ID (supports 'anc-1', '#anc-1', '1', '01')
|
|
167
|
-
*/
|
|
168
|
-
get(id: string): Anchor | undefined;
|
|
169
|
-
/**
|
|
170
|
-
* List anchors. By default, if cwd is provided, only returns anchors
|
|
171
|
-
* belonging to this cwd or marked as global (''). Pass all: true for global view.
|
|
172
|
-
*/
|
|
173
|
-
list(filter?: {
|
|
174
|
-
status?: AnchorStatus;
|
|
175
|
-
priority?: AnchorPriority;
|
|
176
|
-
cwd?: string;
|
|
177
|
-
all?: boolean;
|
|
178
|
-
now?: number;
|
|
179
|
-
}): Anchor[];
|
|
180
|
-
/**
|
|
181
|
-
* Update an existing anchor
|
|
182
|
-
*/
|
|
183
|
-
update(id: string, patch: Partial<Omit<Anchor, 'id' | 'createdAt'>>): Anchor;
|
|
184
|
-
/**
|
|
185
|
-
* Touch an anchor to refresh its decay window and reactivate sleeping state
|
|
186
|
-
*/
|
|
187
|
-
touch(id: string, timestamp?: number): Anchor;
|
|
188
|
-
/**
|
|
189
|
-
* Settle an anchor (recurring daily habits complete for today and wake up tomorrow)
|
|
190
|
-
*/
|
|
191
|
-
settle(id: string, evidence?: AnchorEvidence, now?: number): Anchor;
|
|
192
|
-
/**
|
|
193
|
-
* Reverse/undo the last settled anchor, popping it from archive.jsonl back into state.json
|
|
194
|
-
*/
|
|
195
|
-
undoSettle(): Anchor;
|
|
196
|
-
/**
|
|
197
|
-
* Evict anchor to graveyard.jsonl upon total decay expiry
|
|
198
|
-
*/
|
|
199
|
-
dropToGraveyard(id: string, reason: string): Anchor;
|
|
200
|
-
getArchive(filter?: {
|
|
201
|
-
cwd?: string;
|
|
202
|
-
all?: boolean;
|
|
203
|
-
}): Anchor[];
|
|
204
|
-
getGraveyard(filter?: {
|
|
205
|
-
cwd?: string;
|
|
206
|
-
all?: boolean;
|
|
207
|
-
}): Anchor[];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export { AnchorStore as A, DEFAULT_DECAY_POLICY as D, EPHEMERAL_DECAY_POLICY as E, type SettlementProposal as S, type TouchMatchResult as T, type AnchorStatus as a, type Anchor as b, type AnchorDecayPolicy as c, type AnchorDurability as d, type AnchorEvidence as e, type AnchorPriority as f, type AnchorStoreState as g, DURABLE_DECAY_POLICY as h, acquireSyncLock as i, atomicRenameWithRetry as j, detectDurability as k, detectRecurrence as l, detectTargetDate as m, getDefaultStorageDir as n, getEphemeralDecayPolicy as o, getTodayDateString as p };
|
package/src/context_injector.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import type { AnchorStore } from './store.ts';
|
|
2
|
-
import type { Anchor } from './types.ts';
|
|
3
|
-
import { sweepStore } from './decay.ts';
|
|
4
|
-
import { getTodayDateString } from './store.ts';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Universal multi-language comment generator.
|
|
9
|
-
* Maps file extension to safe comment syntax.
|
|
10
|
-
* Formats that do not safely support comments (e.g. .json, .env, binary) return null.
|
|
11
|
-
*/
|
|
12
|
-
export const COMMENT_FORMATS: Record<string, (msg: string) => string> = {
|
|
13
|
-
// Double slash //
|
|
14
|
-
'.ts': m => `// ${m}`,
|
|
15
|
-
'.tsx': m => `// ${m}`,
|
|
16
|
-
'.js': m => `// ${m}`,
|
|
17
|
-
'.jsx': m => `// ${m}`,
|
|
18
|
-
'.mjs': m => `// ${m}`,
|
|
19
|
-
'.cjs': m => `// ${m}`,
|
|
20
|
-
'.java': m => `// ${m}`,
|
|
21
|
-
'.kt': m => `// ${m}`,
|
|
22
|
-
'.swift': m => `// ${m}`,
|
|
23
|
-
'.go': m => `// ${m}`,
|
|
24
|
-
'.rs': m => `// ${m}`,
|
|
25
|
-
'.c': m => `// ${m}`,
|
|
26
|
-
'.cpp': m => `// ${m}`,
|
|
27
|
-
'.h': m => `// ${m}`,
|
|
28
|
-
'.hpp': m => `// ${m}`,
|
|
29
|
-
'.cs': m => `// ${m}`,
|
|
30
|
-
'.dart': m => `// ${m}`,
|
|
31
|
-
'.scala': m => `// ${m}`,
|
|
32
|
-
'.zig': m => `// ${m}`,
|
|
33
|
-
'.proto': m => `// ${m}`,
|
|
34
|
-
|
|
35
|
-
// Hash #
|
|
36
|
-
'.py': m => `# ${m}`,
|
|
37
|
-
'.rb': m => `# ${m}`,
|
|
38
|
-
'.sh': m => `# ${m}`,
|
|
39
|
-
'.bash': m => `# ${m}`,
|
|
40
|
-
'.zsh': m => `# ${m}`,
|
|
41
|
-
'.yaml': m => `# ${m}`,
|
|
42
|
-
'.yml': m => `# ${m}`,
|
|
43
|
-
'.toml': m => `# ${m}`,
|
|
44
|
-
'.conf': m => `# ${m}`,
|
|
45
|
-
'.dockerfile': m => `# ${m}`,
|
|
46
|
-
'.ps1': m => `# ${m}`,
|
|
47
|
-
'.r': m => `# ${m}`,
|
|
48
|
-
|
|
49
|
-
// HTML / XML <!-- -->
|
|
50
|
-
'.html': m => `<!-- ${m} -->`,
|
|
51
|
-
'.xml': m => `<!-- ${m} -->`,
|
|
52
|
-
'.svg': m => `<!-- ${m} -->`,
|
|
53
|
-
'.vue': m => `<!-- ${m} -->`,
|
|
54
|
-
'.svelte': m => `<!-- ${m} -->`,
|
|
55
|
-
|
|
56
|
-
// Block comment /* */
|
|
57
|
-
'.css': m => `/* ${m} */`,
|
|
58
|
-
'.scss': m => `/* ${m} */`,
|
|
59
|
-
'.less': m => `/* ${m} */`,
|
|
60
|
-
|
|
61
|
-
// SQL / Lua / Haskell --
|
|
62
|
-
'.sql': m => `-- ${m}`,
|
|
63
|
-
'.lua': m => `-- ${m}`,
|
|
64
|
-
'.hs': m => `-- ${m}`,
|
|
65
|
-
|
|
66
|
-
// Batch REM
|
|
67
|
-
'.bat': m => `REM ${m}`,
|
|
68
|
-
'.cmd': m => `REM ${m}`,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Format safe task context comment for a specific file.
|
|
73
|
-
* Returns null for formats that do not safely support comments (e.g. .json, .env, .lock)
|
|
74
|
-
*/
|
|
75
|
-
export function makeSafeTaskAnnotation(filePath: string, anchor: Anchor): string | null {
|
|
76
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
77
|
-
const formatter = COMMENT_FORMATS[ext];
|
|
78
|
-
if (!formatter) {
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
return '\n\n' + formatter(`⌖ anchor context: #${anchor.id} ${anchor.title} (${anchor.priority.toUpperCase()})`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Render ultra-compact cold-start context block for session turn 1.
|
|
86
|
-
* Only active anchors for the current project context are injected.
|
|
87
|
-
* From turn 2 onwards, this returns empty string (0 tokens).
|
|
88
|
-
*/
|
|
89
|
-
export function renderColdStartAnchorsContext(
|
|
90
|
-
store: AnchorStore,
|
|
91
|
-
cwdOrNow?: string | number,
|
|
92
|
-
nowArg?: number,
|
|
93
|
-
preflightFailures?: Map<string, string>
|
|
94
|
-
): string {
|
|
95
|
-
let cwd: string | undefined;
|
|
96
|
-
let now = Date.now();
|
|
97
|
-
|
|
98
|
-
if (typeof cwdOrNow === 'number') {
|
|
99
|
-
now = cwdOrNow;
|
|
100
|
-
} else if (typeof cwdOrNow === 'string') {
|
|
101
|
-
cwd = cwdOrNow;
|
|
102
|
-
}
|
|
103
|
-
if (typeof nowArg === 'number') {
|
|
104
|
-
now = nowArg;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 1. Run opportunistic sweep to ensure expired anchors don't leak into context
|
|
108
|
-
sweepStore(store, now);
|
|
109
|
-
|
|
110
|
-
// 2. Fetch only 'active' anchors scoped to the current cwd
|
|
111
|
-
const activeAnchors = store.list({ status: 'active', cwd });
|
|
112
|
-
if (activeAnchors.length === 0) {
|
|
113
|
-
return '';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const lines = activeAnchors.map(a => {
|
|
117
|
-
const fileHint = a.files.length > 0 ? ` (${a.files.slice(0, 2).join(', ')})` : '';
|
|
118
|
-
const tagHint = a.tags.length > 0 ? ` [${a.tags.join(', ')}]` : '';
|
|
119
|
-
const projHint = a.cwd ? `[${a.project}]` : '[global]';
|
|
120
|
-
|
|
121
|
-
// Target cadence hint
|
|
122
|
-
let targetHint = '';
|
|
123
|
-
if (a.recurrence === 'daily') {
|
|
124
|
-
targetHint = ' [今日循环·Daily]';
|
|
125
|
-
} else if (a.targetDate) {
|
|
126
|
-
const todayStr = getTodayDateString(now);
|
|
127
|
-
if (a.targetDate === todayStr) {
|
|
128
|
-
targetHint = ' [今日聚焦·Due Today]';
|
|
129
|
-
} else if (a.targetDate < todayStr) {
|
|
130
|
-
targetHint = ' [已逾期·Overdue]';
|
|
131
|
-
} else {
|
|
132
|
-
targetHint = ` [排期:${a.targetDate}]`;
|
|
133
|
-
}
|
|
134
|
-
} else {
|
|
135
|
-
targetHint = ' [长期愿景·Someday]';
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const ageDays = Math.floor((now - a.createdAt) / (24 * 60 * 60 * 1000));
|
|
139
|
-
const ageHint = ageDays > 0 ? ` (${ageDays}d old)` : '';
|
|
140
|
-
|
|
141
|
-
const failureSnippet = preflightFailures?.get(a.id);
|
|
142
|
-
const verifyHint = failureSnippet
|
|
143
|
-
? ` [⚡ 物理验证失败: ${failureSnippet.replace(/\s+/g, ' ').slice(-100)}]`
|
|
144
|
-
: a.verifyCommand
|
|
145
|
-
? ` [verify: ${a.verifyCommand}]`
|
|
146
|
-
: '';
|
|
147
|
-
|
|
148
|
-
return `• #${a.id} ${projHint}${targetHint} [${a.priority.toUpperCase()}] ${a.title}${verifyHint}${ageHint}${tagHint}${fileHint}`;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return [
|
|
152
|
-
`<active-anchors count="${activeAnchors.length}">`,
|
|
153
|
-
`Unfinished cross-session commitments from previous sessions:`,
|
|
154
|
-
lines.join('\n'),
|
|
155
|
-
``,
|
|
156
|
-
`CONVERSATIONAL PROTOCOL (HUMAN PARTNER TONE):`,
|
|
157
|
-
`- If the user opens the session with a casual greeting or continuation ("hi", "在吗", "继续", "早上好"), naturally prioritize items tagged [今日聚焦·Due Today] in a friendly assistant tone (e.g. "嗨!今天规划的【...】现在处理还是看别的?").`,
|
|
158
|
-
`- If an anchor has [⚡ 物理验证失败], its verifyCommand failed on session start. Target the failing assertion directly.`,
|
|
159
|
-
`- If the user issues a direct, concrete new instruction (e.g. "帮我查下这个报错"), DO NOT interrupt their flow. Focus directly on their instruction.`,
|
|
160
|
-
`- When a commitment is satisfied during work, automatically call anchor(action="settle", id=...) to clear it.`,
|
|
161
|
-
`</active-anchors>`
|
|
162
|
-
].join('\n');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** Legacy alias for backwards compatibility */
|
|
166
|
-
export const renderActiveAnchorsContext = renderColdStartAnchorsContext;
|