lockwire 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +327 -0
- package/dist/actions.d.ts +67 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +430 -0
- package/dist/actions.js.map +1 -0
- package/dist/actor.d.ts +4 -0
- package/dist/actor.d.ts.map +1 -0
- package/dist/actor.js +14 -0
- package/dist/actor.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +192 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -0
- package/dist/extract.d.ts +16 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +349 -0
- package/dist/extract.js.map +1 -0
- package/dist/format.d.ts +5 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +65 -0
- package/dist/format.js.map +1 -0
- package/dist/grammar.d.ts +6 -0
- package/dist/grammar.d.ts.map +1 -0
- package/dist/grammar.js +45 -0
- package/dist/grammar.js.map +1 -0
- package/dist/hash.d.ts +12 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +34 -0
- package/dist/hash.js.map +1 -0
- package/dist/hook-claude.d.ts +6 -0
- package/dist/hook-claude.d.ts.map +1 -0
- package/dist/hook-claude.js +50 -0
- package/dist/hook-claude.js.map +1 -0
- package/dist/hook-codex.d.ts +8 -0
- package/dist/hook-codex.d.ts.map +1 -0
- package/dist/hook-codex.js +52 -0
- package/dist/hook-codex.js.map +1 -0
- package/dist/hook-common.d.ts +23 -0
- package/dist/hook-common.d.ts.map +1 -0
- package/dist/hook-common.js +72 -0
- package/dist/hook-common.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger.d.ts +13 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +69 -0
- package/dist/ledger.js.map +1 -0
- package/dist/lockfile.d.ts +9 -0
- package/dist/lockfile.d.ts.map +1 -0
- package/dist/lockfile.js +40 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/markers.d.ts +18 -0
- package/dist/markers.d.ts.map +1 -0
- package/dist/markers.js +89 -0
- package/dist/markers.js.map +1 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +69 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/repo.d.ts +14 -0
- package/dist/repo.d.ts.map +1 -0
- package/dist/repo.js +75 -0
- package/dist/repo.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Talha Hameed and Zaid Ul Haq
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/wordmark-dark.png">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="assets/wordmark-light.png">
|
|
5
|
+
<img alt="lockwire" src="assets/wordmark-light.png" width="420">
|
|
6
|
+
</picture>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
# lockwire
|
|
10
|
+
|
|
11
|
+
**Catch stale `CLAUDE.md`, `AGENTS.md`, and docs before your coding agent acts on them.**
|
|
12
|
+
|
|
13
|
+
The mark is literal, not a metaphor: [lockwiring](https://en.wikipedia.org/wiki/Lock_wire) is the aviation-maintenance technique of threading wire through two fasteners so neither can work loose under vibration — the same idea applied to a doc claim and the code it depends on.
|
|
14
|
+
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
[](https://code.claude.com/docs/en/plugins)
|
|
17
|
+
[](docs/agents.md)
|
|
18
|
+
[](docs/agents.md)
|
|
19
|
+
[](https://github.com/Reality-Ventures/lockwire/actions/workflows/ci.yml)
|
|
20
|
+
|
|
21
|
+
A sentence in your docs is a claim about a specific state of your code. Nothing binds the two together, so the claim rots and nobody notices — until an autonomous agent reads the stale sentence and acts on it. lockwire fingerprints the code a claim depends on, checks that fingerprint at write time inside Claude Code and Codex, and keeps a tamper-evident history of every time the claim broke.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
$ lockwire check
|
|
25
|
+
|
|
26
|
+
CLAUDE.md
|
|
27
|
+
DRIFTED src/auth/session.ts#createSession (sig)
|
|
28
|
+
ok src/auth/provider.ts#AuthConfig
|
|
29
|
+
|
|
30
|
+
1 anchor · 1 ok · 1 drifted · 0 orphaned
|
|
31
|
+
single-hash would flag 1 · lockwire flagged 1 · noise −0%
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
$ lockwire history k7q2m9xv
|
|
36
|
+
2026-09-25T10:00:11Z anchor.created
|
|
37
|
+
2026-09-25T14:12:03Z anchor.drifted sig param `ttl: number` added
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## The problem, specifically
|
|
43
|
+
|
|
44
|
+
1. **Coding agents change code faster than humans reconcile prose.** Drift that used to accumulate over quarters now accumulates over an afternoon.
|
|
45
|
+
2. **`CLAUDE.md` and `AGENTS.md` are read by an agent on every request.** A stale line doesn't just mislead a person reading it later — it silently redirects an autonomous process *right now*. Stale agent context is a correctness problem, not a hygiene problem.
|
|
46
|
+
3. **Wrong documentation is worse than no documentation.** Macke & Doyle (NAACL 2024) found that incorrect documentation "can greatly hinder" an LLM's ability to understand code, while missing documentation barely affects it at all — see [docs/research.md](docs/research.md). A confidently wrong `CLAUDE.md` is actively harmful in a way an empty one isn't.
|
|
47
|
+
|
|
48
|
+
And the tools built to fix this have a shared failure mode: **one hash per symbol.** Hash a whole function, and a one-line body tweak invalidates a doc that only ever claimed something about the *signature*. Teams get flooded with false staleness, the CI gate gets marked `continue-on-error`, and the tool gets uninstalled. This is the specific failure lockwire is built to not have.
|
|
49
|
+
|
|
50
|
+
## How it's different
|
|
51
|
+
|
|
52
|
+
lockwire fingerprints **four aspects of a symbol separately**, and a claim only binds the aspects it actually depends on:
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
SYM["Symbol<br/><b>createSession()</b>"] --> P & S & B & D
|
|
57
|
+
|
|
58
|
+
P["<b>path</b><br/>file location"]
|
|
59
|
+
S["<b>sig</b><br/>name · params · types<br/>return · modifiers"]
|
|
60
|
+
B["<b>body</b><br/>normalized AST<br/>of the implementation"]
|
|
61
|
+
D["<b>deps</b><br/>sorted set of<br/>outbound calls"]
|
|
62
|
+
|
|
63
|
+
P --> C1["<i>structural claim</i><br/>'sessions are created in<br/>src/auth/session.ts'"]
|
|
64
|
+
S --> C2["<i>contractual claim</i><br/>'takes a UserId,<br/>returns a Session'"]
|
|
65
|
+
B --> C3["<i>behavioral claim</i><br/>'retries 3x with<br/>exponential backoff'"]
|
|
66
|
+
D --> C4["<i>architectural claim</i><br/>'delegates token minting<br/>to the KMS client'"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
*A contractual claim binds only `sig` — a body refactor never touches it. This is the whole mechanism.*
|
|
70
|
+
|
|
71
|
+
A doc claiming "takes a `UserId`, returns a `Session`" binds `sig` only, and stays silent through every internal refactor of `createSession`. The [P0 test suite](test/e2e.test.ts) proves this on a real example: a body-only edit that adds a logging call produces **zero** drifted anchors and a noise line reading `single-hash would flag 1 · lockwire flagged 0 · noise −100%`.
|
|
72
|
+
|
|
73
|
+
## System view
|
|
74
|
+
|
|
75
|
+
```mermaid
|
|
76
|
+
flowchart TB
|
|
77
|
+
subgraph SRC["Inputs"]
|
|
78
|
+
direction LR
|
|
79
|
+
CODE["Source tree<br/>TS · TSX · JS · Python"]
|
|
80
|
+
DOCS["CLAUDE.md · AGENTS.md<br/>docs/**/*.md"]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
subgraph L1["Fingerprint"]
|
|
84
|
+
direction LR
|
|
85
|
+
TS["tree-sitter<br/>parse"] --> EX["Tier extractor<br/>path · sig · body · deps"] --> HASH["BLAKE3<br/>fingerprint"]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
subgraph L2["State"]
|
|
89
|
+
direction LR
|
|
90
|
+
LF[("lockwire.lock<br/>anchors")]
|
|
91
|
+
LG[("ledger.jsonl<br/>history")]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
subgraph L3["Three gates"]
|
|
95
|
+
direction LR
|
|
96
|
+
G1["write-time<br/>PreToolUse hook"]
|
|
97
|
+
G2["commit-time<br/>pre-commit"]
|
|
98
|
+
G3["merge-time<br/>GitHub Action"]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
CODE --> L1
|
|
102
|
+
DOCS -->|"<!-- lockwire ... --><br/>markers"| L2
|
|
103
|
+
L1 --> L2
|
|
104
|
+
L2 --> L3
|
|
105
|
+
|
|
106
|
+
classDef store fill:#1f2937,stroke:#60a5fa,color:#e5e7eb
|
|
107
|
+
class LF,LG store
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Anchor lifecycle
|
|
111
|
+
|
|
112
|
+
```mermaid
|
|
113
|
+
stateDiagram-v2
|
|
114
|
+
[*] --> Fresh: lockwire link<br/><i>anchor.created</i>
|
|
115
|
+
|
|
116
|
+
Fresh --> Drifted: bound tier changed<br/><i>anchor.drifted</i>
|
|
117
|
+
Fresh --> Relocated: symbol not at path,<br/>exactly one sig match<br/>elsewhere in the file<br/><i>anchor.relocated</i>
|
|
118
|
+
Fresh --> Orphaned: symbol or file gone<br/><i>anchor.orphaned</i>
|
|
119
|
+
|
|
120
|
+
Drifted --> Fresh: doc updated + link --reviewed<br/><i>anchor.resolved</i>
|
|
121
|
+
Drifted --> Waived: time-boxed waiver<br/><i>waiver.granted</i>
|
|
122
|
+
Drifted --> Superseded: claim no longer applies<br/><i>anchor.acknowledged</i>
|
|
123
|
+
|
|
124
|
+
Waived --> Drifted: waiver expires<br/><i>waiver.expired</i>
|
|
125
|
+
|
|
126
|
+
Superseded --> [*]
|
|
127
|
+
|
|
128
|
+
note right of Relocated
|
|
129
|
+
Same-file rename detection only in P0.
|
|
130
|
+
A symbol moved to a different file
|
|
131
|
+
still reports orphaned — see
|
|
132
|
+
docs/concepts.md limitations.
|
|
133
|
+
end note
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Write-time enforcement
|
|
137
|
+
|
|
138
|
+
```mermaid
|
|
139
|
+
sequenceDiagram
|
|
140
|
+
participant A as Coding agent
|
|
141
|
+
participant H as PreToolUse hook
|
|
142
|
+
participant L as lockwire core
|
|
143
|
+
participant D as Ledger
|
|
144
|
+
|
|
145
|
+
A->>H: Edit src/auth/session.ts
|
|
146
|
+
H->>L: which anchors cover this file?
|
|
147
|
+
L-->>H: 1 claim, bound to sig
|
|
148
|
+
|
|
149
|
+
alt advisory (default)
|
|
150
|
+
H-->>A: inject claim as context —<br/>no block, no prompt
|
|
151
|
+
else ask
|
|
152
|
+
H-->>A: prompt: acknowledge or proceed anyway
|
|
153
|
+
else deny
|
|
154
|
+
H-->>A: block until acknowledged
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
A->>A: edits the file
|
|
158
|
+
A->>L: PostToolUse — re-fingerprint
|
|
159
|
+
L->>D: anchor.drifted (if the bound tier moved)
|
|
160
|
+
D-->>A: additionalContext: which claim just broke
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Install
|
|
164
|
+
|
|
165
|
+
**Claude Code** — hook, MCP server, and skill in one plugin:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
/plugin marketplace add Reality-Ventures/lockwire
|
|
169
|
+
/plugin install lockwire@lockwire
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Codex, Cursor, Gemini CLI, and other agents that read `SKILL.md`** — the skill only; wire up the hook and MCP server per your agent (see [docs/agents.md](docs/agents.md)):
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npx skills add Reality-Ventures/lockwire
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**CLI and CI** — no agent required (not yet published to npm; build from source until it is):
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git clone https://github.com/Reality-Ventures/lockwire && cd lockwire
|
|
182
|
+
npm ci && npm run build
|
|
183
|
+
node dist/cli.js check
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**GitHub Action** — merge-time gate:
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
- uses: Reality-Ventures/lockwire@v0
|
|
190
|
+
with:
|
|
191
|
+
args: --changed
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**pre-commit** — commit-time gate:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
lockwire check --changed
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Quickstart
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
$ lockwire init
|
|
204
|
+
lockwire initialized: lockwire.lock, .lockwire/config.json, .gitattributes (ledger merge=union)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Add a marker above a claim in `CLAUDE.md`:
|
|
208
|
+
|
|
209
|
+
```markdown
|
|
210
|
+
<!-- lockwire src/auth/session.ts#createSession sig -->
|
|
211
|
+
`createSession` takes a `UserId` and returns a `Session` valid for 24 hours.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
$ lockwire link CLAUDE.md
|
|
216
|
+
CLAUDE.md: 1 created, 0 refreshed
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The marker is now stamped with an id:
|
|
220
|
+
|
|
221
|
+
```markdown
|
|
222
|
+
<!-- lockwire src/auth/session.ts#createSession sig id=k7q2m9xv -->
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Refactor the function's body without touching its signature, then check:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
$ lockwire check
|
|
229
|
+
CLAUDE.md
|
|
230
|
+
ok src/auth/session.ts#createSession
|
|
231
|
+
|
|
232
|
+
1 anchor · 1 ok · 0 drifted · 0 orphaned
|
|
233
|
+
single-hash would flag 1 · lockwire flagged 0 · noise −100%
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Now change the actual signature (add a parameter) and check again:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
$ lockwire check
|
|
240
|
+
CLAUDE.md
|
|
241
|
+
DRIFTED src/auth/session.ts#createSession (sig)
|
|
242
|
+
|
|
243
|
+
1 anchor · 0 ok · 1 drifted · 0 orphaned
|
|
244
|
+
single-hash would flag 1 · lockwire flagged 1 · noise −0%
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Update the doc, then re-stamp — `--reviewed` is required because this anchor is currently `drifted`:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
$ lockwire link CLAUDE.md --reviewed
|
|
251
|
+
CLAUDE.md: 0 created, 1 refreshed
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
And ask what happened, whenever, from anyone:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
$ lockwire history k7q2m9xv
|
|
258
|
+
2026-09-25T10:00:11Z anchor.created
|
|
259
|
+
2026-09-25T14:12:03Z anchor.drifted sig param `ttl: number` added
|
|
260
|
+
2026-09-25T14:15:40Z anchor.resolved
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Inside Claude Code, the hook does this automatically — before the edit, you'd see the claim injected as context; after, you'd see exactly which claim just drifted, with no `check` invocation needed. See [docs/agents.md](docs/agents.md) for the injected text.
|
|
264
|
+
|
|
265
|
+
## What lockwire does not do
|
|
266
|
+
|
|
267
|
+
Hashes cannot catch semantic drift — a doc saying "we use Redux" when the code moved to Zustand, where every file path still resolves and no signature changed. Catching that requires reasoning about meaning, not fingerprints; [ClaudeDrift](https://github.com/marky291/claude-drift) does this well as an on-demand, LLM-reasoning layer, and pairs naturally with lockwire's continuous, deterministic one — see [docs/comparison.md](docs/comparison.md). P0 supports TypeScript, TSX, JavaScript, and Python; cross-file rename detection, a resolver agent, and semantic-claim extraction are roadmap, not shipped — see [docs/concepts.md](docs/concepts.md#limitations).
|
|
268
|
+
|
|
269
|
+
## FAQ
|
|
270
|
+
|
|
271
|
+
### How is this different from fiberplane/drift?
|
|
272
|
+
|
|
273
|
+
[fiberplane/drift](https://github.com/fiberplane/drift) computes one AST hash per anchor — a body refactor invalidates a doc that only claimed something about the signature. lockwire fingerprints path, signature, body, and dependencies separately, so a claim only re-flags when the aspect it actually depends on changes. Neither fiberplane/drift nor any other tool we found keeps a history of *why* a claim broke, *who* broke it, or *how often* — lockwire's ledger does. See the full comparison in [docs/comparison.md](docs/comparison.md).
|
|
274
|
+
|
|
275
|
+
### Does it call an LLM?
|
|
276
|
+
|
|
277
|
+
No. Detection is deterministic: tree-sitter parsing, BLAKE3 hashing, set comparison. No network calls, no API keys, no per-check cost. The write-time hook and CLI both run entirely offline.
|
|
278
|
+
|
|
279
|
+
### Will it slow down Claude Code?
|
|
280
|
+
|
|
281
|
+
The hook has a 10-second timeout and only re-parses the one file that was just touched — in practice, well under a second for typical files. It fails open: if anything throws, the hook exits silently and the tool call proceeds untouched. See [docs/agents.md](docs/agents.md).
|
|
282
|
+
|
|
283
|
+
### What happens on merge conflicts in the ledger?
|
|
284
|
+
|
|
285
|
+
`.lockwire/ledger.jsonl` is append-only JSONL with `merge=union` in `.gitattributes` (written by `lockwire init`), so `git merge` unions the lines from both branches instead of conflicting. Event hashes don't chain to a previous event, deliberately — the ledger's tamper-evidence is order-independent (a BLAKE3 root over the *set* of event hashes), because ordering is already supplied by each event's timestamp and commit SHA. See [docs/ledger.md](docs/ledger.md).
|
|
286
|
+
|
|
287
|
+
### Can I use it without Claude Code?
|
|
288
|
+
|
|
289
|
+
Yes. The core is a standalone CLI (`lockwire check`, `lockwire link`, …) that runs anywhere Node runs — in a pre-commit hook, in any CI system, or by hand. Claude Code and Codex hooks are two of several ways to trigger it; the GitHub Action is a third.
|
|
290
|
+
|
|
291
|
+
### What languages are supported?
|
|
292
|
+
|
|
293
|
+
TypeScript, TSX, JavaScript, and Python in P0 (v0.1.0). More tree-sitter grammars are a small addition on top of the existing tier-extraction pipeline — see [docs/concepts.md](docs/concepts.md).
|
|
294
|
+
|
|
295
|
+
### Why not just use an LLM to check everything?
|
|
296
|
+
|
|
297
|
+
Because then every `check` costs money and time, becomes non-deterministic, and can't run inside a 10-second write-time hook. lockwire's deterministic core handles the mechanical 80% (does this claim's bound aspect still match); an LLM-reasoning layer for the harder semantic 20% is a natural P2 addition, not a P0 requirement — see [docs/research.md](docs/research.md) for why teams abandon LLM-only or hash-flood-prone tools.
|
|
298
|
+
|
|
299
|
+
## Comparison
|
|
300
|
+
|
|
301
|
+
| | lockwire | [fiberplane/drift](https://github.com/fiberplane/drift) | [ClaudeDrift](https://github.com/marky291/claude-drift) | [pallaprolus/drift](https://github.com/pallaprolus/drift) |
|
|
302
|
+
|---|---|---|---|---|
|
|
303
|
+
| Fingerprint granularity | 4 tiers per symbol | 1 hash per anchor | none (LLM judgment) | 1 score per doc-code pair |
|
|
304
|
+
| Write-time agent hook | ✅ Claude Code + Codex | ❌ | ❌ (on-demand) | ❌ |
|
|
305
|
+
| History / ledger | ✅ append-only, tamper-evident | ❌ | ❌ | ❌ |
|
|
306
|
+
| Semantic drift (meaning changed, refs still resolve) | ❌ (roadmap) | ❌ | ✅ | ✅ (opt-in, on-demand) |
|
|
307
|
+
| Runs with no LLM | ✅ | ✅ | ❌ | ✅ (core checks) |
|
|
308
|
+
| Languages (P0) | TS, TSX, JS, Python | TS, Python, Rust, Go, Zig, Java | any (LLM-read) | TS/JS, Python, Go, Rust, Java |
|
|
309
|
+
|
|
310
|
+
Full detail, including two smaller entrants and where each tool actually stops, in [docs/comparison.md](docs/comparison.md).
|
|
311
|
+
|
|
312
|
+
## Documentation
|
|
313
|
+
|
|
314
|
+
- [docs/concepts.md](docs/concepts.md) — tiers, anchors, claims, drift, and the current limitations
|
|
315
|
+
- [docs/cli.md](docs/cli.md) — full command reference
|
|
316
|
+
- [docs/agents.md](docs/agents.md) — Claude Code plugin, Codex, MCP tools, hook payloads, other agents via skills
|
|
317
|
+
- [docs/ledger.md](docs/ledger.md) — the append-only ledger, union merge, Agent Trace actors, verification
|
|
318
|
+
- [docs/comparison.md](docs/comparison.md) — the full competitive comparison
|
|
319
|
+
- [docs/research.md](docs/research.md) — the evidence base this design is built on
|
|
320
|
+
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Security issues: see [SECURITY.md](SECURITY.md), not a public issue.
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Actor, Anchor, FileSymbols, Fingerprints, LockwireConfig, Tier } from "./types.js";
|
|
2
|
+
export interface TargetResolution {
|
|
3
|
+
found: boolean;
|
|
4
|
+
fingerprints: Fingerprints;
|
|
5
|
+
symbols?: FileSymbols;
|
|
6
|
+
}
|
|
7
|
+
/** Recomputes all four tier fingerprints for a target, or reports it unresolved (file/symbol not found). */
|
|
8
|
+
export declare function resolveTarget(repoRoot: string, target: {
|
|
9
|
+
path: string;
|
|
10
|
+
symbol?: string;
|
|
11
|
+
}, config: LockwireConfig): Promise<TargetResolution | null>;
|
|
12
|
+
/** Same-file rename detection: if a symbol vanished but exactly one other symbol in the file shares its `sig` fingerprint, relink to it. Cross-file relocation (the symbol moved to a different file) is not attempted in P0 — see docs/concepts.md limitations. */
|
|
13
|
+
export declare function findRelocationCandidate(symbols: FileSymbols, missingSigFp: string): string | null;
|
|
14
|
+
export interface LinkResult {
|
|
15
|
+
created: number;
|
|
16
|
+
refreshed: number;
|
|
17
|
+
skipped: {
|
|
18
|
+
reason: string;
|
|
19
|
+
target: string;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
/** Scans a markdown doc for `<!-- lockwire ... -->` markers and creates/refreshes their anchors. */
|
|
23
|
+
export declare function linkDoc(repoRoot: string, docPath: string, config: LockwireConfig, actor: Actor, opts?: {
|
|
24
|
+
reviewed?: boolean;
|
|
25
|
+
commit?: string | null;
|
|
26
|
+
}): Promise<LinkResult>;
|
|
27
|
+
/** `lockwire link <doc> <target>` — a lockfile-only anchor with no inline marker, for whole-doc-to-file bindings. */
|
|
28
|
+
export declare function linkLockfileOnly(repoRoot: string, docPath: string, target: {
|
|
29
|
+
path: string;
|
|
30
|
+
symbol?: string;
|
|
31
|
+
}, tiers: Tier[], config: LockwireConfig, actor: Actor): Promise<Anchor>;
|
|
32
|
+
export interface AnchorCheckResult {
|
|
33
|
+
anchor: Anchor;
|
|
34
|
+
status: Anchor["status"];
|
|
35
|
+
driftedTiers: Tier[];
|
|
36
|
+
singleHashWouldFlag: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface CheckSummary {
|
|
39
|
+
anchors: number;
|
|
40
|
+
fresh: number;
|
|
41
|
+
drifted: number;
|
|
42
|
+
relocated: number;
|
|
43
|
+
orphaned: number;
|
|
44
|
+
waived: number;
|
|
45
|
+
superseded: number;
|
|
46
|
+
noise: {
|
|
47
|
+
singleHashWouldFlag: number;
|
|
48
|
+
tieredFlagged: number;
|
|
49
|
+
reductionPercent: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface CheckResult {
|
|
53
|
+
summary: CheckSummary;
|
|
54
|
+
results: AnchorCheckResult[];
|
|
55
|
+
}
|
|
56
|
+
export declare function check(repoRoot: string, config: LockwireConfig, onlyPaths?: readonly string[]): Promise<CheckResult>;
|
|
57
|
+
export declare function discoverDocs(repoRoot: string, config: LockwireConfig): Promise<string[]>;
|
|
58
|
+
export declare function ack(repoRoot: string, anchorId: string, resolution: "updated" | "superseded" | "false-positive", note: string | undefined, actor: Actor, config: LockwireConfig): Promise<Anchor>;
|
|
59
|
+
export declare function waive(repoRoot: string, anchorId: string, reason: string, expires: string, actor: Actor): Promise<Anchor>;
|
|
60
|
+
export declare function unlink(repoRoot: string, anchorId: string): Promise<void>;
|
|
61
|
+
export declare function refs(repoRoot: string, path: string, symbol?: string): Promise<Anchor[]>;
|
|
62
|
+
export declare function status(repoRoot: string, scope?: string): Promise<Anchor[]>;
|
|
63
|
+
export declare function history(repoRoot: string, ref: string): Promise<{
|
|
64
|
+
anchors: Anchor[];
|
|
65
|
+
events: import("./types.js").LedgerRecord[];
|
|
66
|
+
}>;
|
|
67
|
+
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
|