thurview 0.15.0 → 0.17.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 +118 -89
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/document/compile.js +81 -2
- package/dist/document/compile.js.map +1 -1
- package/dist/document/parse.js +37 -13
- package/dist/document/parse.js.map +1 -1
- package/dist/document/schema.js +36 -0
- package/dist/document/schema.js.map +1 -1
- package/dist/queue.js +123 -0
- package/dist/queue.js.map +1 -0
- package/dist/server/server.js +3 -9
- package/dist/server/server.js.map +1 -1
- package/dist/store.js +10 -0
- package/dist/store.js.map +1 -1
- package/dist/ui/app.css +80 -0
- package/dist/ui/app.js +213 -12
- package/dist/ui/app.js.map +3 -3
- package/package.json +1 -1
- package/skills/thurview/references/components.md +47 -0
- package/skills/thurview/references/document-authoring.md +5 -2
- package/skills/thurview/references/lifecycle.md +21 -0
package/README.md
CHANGED
|
@@ -1,82 +1,123 @@
|
|
|
1
1
|
# thurview
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
**Your coding agent writes the review; you read it in the browser, anchored to
|
|
4
|
+
the code, and approve it or send it back.**
|
|
5
|
+
|
|
6
|
+
[](https://github.com/Thurbeen/thurview/actions/workflows/ci.yml)
|
|
7
|
+
[](https://www.npmjs.com/package/thurview)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+

|
|
12
|
+
|
|
13
|
+
_The reader's half of it; the agent is working off camera._
|
|
14
|
+
|
|
15
|
+
- **Every claim is anchored to code.** The prose links to an exact file and
|
|
16
|
+
line range at a pinned commit, and the reader opens that code beside the
|
|
17
|
+
text — no hunting for what a sentence is about.
|
|
18
|
+
- **You read it in your browser, not in a comment thread.** An argument in the
|
|
19
|
+
order somebody chose to make it, with the code, the diff between the pinned
|
|
20
|
+
commits and the system around it one click away — instead of forty remarks
|
|
21
|
+
in the order they happened to be written.
|
|
22
|
+
- **You ask, and the agent answers in the document.** A question goes to the
|
|
23
|
+
agent — at once if one is listening, queued if not — and the answer lands
|
|
24
|
+
in the same thread; a comment waits for your decision. Then you approve the
|
|
25
|
+
change or send it back with the comments attached.
|
|
26
|
+
- **A code graph answers what the diff cannot.** Who calls the symbol that
|
|
27
|
+
moved, which tests reach it, where the change landed in the system and what
|
|
28
|
+
sits next to it. thurview builds the graph itself with tree-sitter from the
|
|
29
|
+
pinned commits, for TypeScript, JavaScript, Python, Go, Rust, Java and Elixir.
|
|
30
|
+
- **The evidence is checked, not taken on trust.** An anchor whose lines
|
|
31
|
+
do not exist at the pinned commit, a call stack frame asserting a call the
|
|
32
|
+
diff does not show, an interface annotation for a symbol the change never
|
|
33
|
+
moved, a trust boundary crossing that resolves to nothing — publishing
|
|
34
|
+
rejects each one rather than rendering it.
|
|
8
35
|
|
|
9
36
|
## Install
|
|
10
37
|
|
|
11
|
-
|
|
12
|
-
CLI - it works with Claude
|
|
13
|
-
reads the Agent Skills
|
|
38
|
+
One command gives your agent every skill this repository ships, through the
|
|
39
|
+
[skills](https://github.com/vercel-labs/skills) CLI - it works with Claude
|
|
40
|
+
Code, Codex, Cursor, OpenCode and every agent that reads the Agent Skills
|
|
41
|
+
format:
|
|
14
42
|
|
|
15
43
|
```sh
|
|
16
44
|
npx skills@latest add https://github.com/Thurbeen/thurview \
|
|
17
|
-
--skill
|
|
45
|
+
--skill '*' --agent universal claude-code --global --yes
|
|
18
46
|
```
|
|
19
47
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
48
|
+
`--skill '*'` takes all four; quote the star so your shell does not expand it
|
|
49
|
+
against the current directory. The skills reach the `thurview` command through
|
|
50
|
+
`npx`, so the requirements are Node 22 or later and git (`gh` for pull
|
|
51
|
+
requests, `glab` for merge requests). Then, in any repository, ask your agent:
|
|
23
52
|
|
|
24
53
|
```text
|
|
25
54
|
Use the thurview skill to review my current branch against up-to-date main
|
|
26
55
|
and open it.
|
|
27
56
|
```
|
|
28
57
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
range
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
## The four skills
|
|
59
|
+
|
|
60
|
+
Three kinds of document, and one companion that writes none:
|
|
61
|
+
|
|
62
|
+
- **`thurview`** - a change that is already written: a branch, a pull request,
|
|
63
|
+
a commit range. The document carries the diff, the commits and the interface
|
|
64
|
+
delta, and the reader approves it or sends it back.
|
|
65
|
+
- **`thurview-explain`** - a codebase, or one subsystem of it, at a single
|
|
66
|
+
pinned commit. No diff and nothing to approve: it surfaces the architecture
|
|
67
|
+
well enough for the reader to spot design problems, and states what it did
|
|
68
|
+
not examine.
|
|
69
|
+
- **`thurview-design`** - a change that is not written yet: a design, an
|
|
70
|
+
architecture proposal, an implementation plan. It anchors on the code as it
|
|
71
|
+
stands and declares what it would build as proposals, each attached to the
|
|
72
|
+
code it lands in today.
|
|
73
|
+
- **`thurview-fix`** - no browser and no reader. It reviews, fixes what it is
|
|
74
|
+
sure of behind the repository's own tests and lint, and reports the rest -
|
|
75
|
+
optionally as inline comments on the change request.
|
|
37
76
|
|
|
38
77
|
<details>
|
|
39
|
-
<summary><b>Other ways to install</b> -
|
|
40
|
-
command from npm, run from a checkout, session hooks,
|
|
41
|
-
|
|
78
|
+
<summary><b>Other ways to install</b> - one skill at a time, pin to a release,
|
|
79
|
+
install the command from npm, run from a checkout, session hooks, and coming
|
|
80
|
+
from an older install</summary>
|
|
42
81
|
|
|
43
82
|
`--global` installs for your user, so one install covers every repository.
|
|
44
|
-
`universal` puts the one real copy
|
|
45
|
-
no single agent owns, and every other agent you name gets a
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
skill
|
|
54
|
-
|
|
83
|
+
`universal` puts the one real copy of each skill under `~/.agents/skills/`,
|
|
84
|
+
the directory no single agent owns, and every other agent you name gets a
|
|
85
|
+
symlink to it - `~/.claude/skills/thurview` →
|
|
86
|
+
`../../.agents/skills/thurview`, and the same for the other three - so an
|
|
87
|
+
update lands everywhere at once. Swap `claude-code` for any agent the skills
|
|
88
|
+
CLI supports, but keep `universal` and at least one more: with `--yes` and a
|
|
89
|
+
single target, the CLI copies instead of linking.
|
|
90
|
+
|
|
91
|
+
`--skill` also takes names, one or several, when you do not want all four:
|
|
92
|
+
`--skill thurview`, or `--skill thurview thurview-fix`.
|
|
93
|
+
|
|
94
|
+
The untagged URL above tracks this repository's default branch:
|
|
95
|
+
`skills update` takes whatever `main` holds, which can be ahead of the
|
|
96
|
+
released command. To pin the skills to a release instead, install from the
|
|
97
|
+
tag, which the skill lock records and later updates keep:
|
|
55
98
|
|
|
56
99
|
```sh
|
|
57
|
-
npx skills@latest add https://github.com/Thurbeen/thurview/tree/v0.
|
|
58
|
-
--agent universal claude-code --global --yes
|
|
100
|
+
npx skills@latest add https://github.com/Thurbeen/thurview/tree/v0.15.0 \
|
|
101
|
+
--skill '*' --agent universal claude-code --global --yes
|
|
59
102
|
```
|
|
60
103
|
|
|
61
104
|
Releases tag without committing, so nothing moves the tag above: swap in the
|
|
62
105
|
[latest release](https://github.com/Thurbeen/thurview/releases/latest).
|
|
63
106
|
|
|
64
|
-
The npm package ships the same
|
|
65
|
-
that
|
|
66
|
-
move together.
|
|
107
|
+
The npm package ships the same skills, so `thurview setup skill` links the
|
|
108
|
+
copies that match the command you have installed. Use that when you want the
|
|
109
|
+
two to move together.
|
|
67
110
|
|
|
68
|
-
Install the command itself, rather than leaving the
|
|
111
|
+
Install the command itself, rather than leaving the skills to reach it through
|
|
69
112
|
`npx` on every run:
|
|
70
113
|
|
|
71
114
|
```sh
|
|
72
115
|
npm install -g thurview # or: pnpm add -g thurview
|
|
73
116
|
```
|
|
74
117
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
symbol, what tests cover it and how files cluster, for TypeScript,
|
|
79
|
-
JavaScript, Python, Go, Rust, Java and Elixir.
|
|
118
|
+
Nothing else needs installing: the code graph is built from the pinned commits
|
|
119
|
+
with tree-sitter. `thurview graph` answers which interfaces the change moved,
|
|
120
|
+
what it reaches, who calls a symbol, what tests cover it and how files cluster.
|
|
80
121
|
|
|
81
122
|
To run from a checkout instead:
|
|
82
123
|
|
|
@@ -89,43 +130,27 @@ npm link # puts `thurview` on PATH
|
|
|
89
130
|
Optional, for ambient context: `thurview setup hooks` installs a
|
|
90
131
|
SessionStart hook for Claude Code, Codex and OpenCode, so every session opens
|
|
91
132
|
with the reviews of its working directory. `thurview setup skill` links the
|
|
92
|
-
|
|
133
|
+
skills from this checkout instead of the `skills` CLI copies; use one or the
|
|
93
134
|
other.
|
|
94
135
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
[below](#review-and-fix).
|
|
136
|
+
**Coming from an older install.** A skill name is an address, so nothing
|
|
137
|
+
renames or splits one in place - the command above adds what is missing, and
|
|
138
|
+
what is stale has to go.
|
|
99
139
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```
|
|
140
|
+
`thurview-explain` used to be a second kind inside the `thurview` skill, so an
|
|
141
|
+
install made before the split does not have it. Under the `skills` CLI,
|
|
142
|
+
updating `thurview` adds no second skill; run the install command above, which
|
|
143
|
+
takes all four. Under `thurview setup skill`, update the command first -
|
|
144
|
+
`thurview update`, or pull and rebuild the checkout you linked from - and run
|
|
145
|
+
`thurview setup skill` again: it links every skill the installed command
|
|
146
|
+
carries, so it picks the new one up on its own.
|
|
108
147
|
|
|
109
|
-
`thurview-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
avoid. Under the `skills` CLI a skill is installed by name and updating
|
|
113
|
-
`thurview` adds no second one, so run the first command above. Under
|
|
114
|
-
`thurview setup skill`, update the command first - `thurview update`, or pull
|
|
115
|
-
and rebuild the checkout you linked from - and run `thurview setup skill`
|
|
116
|
-
again: it links every skill the installed command carries, so it picks the new
|
|
117
|
-
one up on its own.
|
|
118
|
-
|
|
119
|
-
`thurview-fix` was called `review-fix`. A skill name is an address, so nothing
|
|
120
|
-
updates the old one in place: an install made before the rename keeps answering
|
|
121
|
-
to `/review-fix` from a copy that will never change again, and one made with
|
|
122
|
-
`thurview setup skill` leaves a symlink pointing at a directory this repository
|
|
123
|
-
no longer ships. Remove it and add the skill under its new name:
|
|
148
|
+
`thurview-fix` was called `review-fix`, and an install made before the rename
|
|
149
|
+
keeps answering to `/review-fix` from a copy that will never change again.
|
|
150
|
+
Remove it:
|
|
124
151
|
|
|
125
152
|
```sh
|
|
126
153
|
npx skills@latest remove --global review-fix
|
|
127
|
-
npx skills@latest add https://github.com/Thurbeen/thurview \
|
|
128
|
-
--skill thurview-fix --agent universal claude-code --global --yes
|
|
129
154
|
```
|
|
130
155
|
|
|
131
156
|
For a `thurview setup skill` install, delete the stale link -
|
|
@@ -141,20 +166,14 @@ and serves it in your browser: the walkthrough, live code peeks, the diff,
|
|
|
141
166
|
commits, and a software map. You ask questions, leave anchored comments, and
|
|
142
167
|
approve or request changes. The agent answers and republishes.
|
|
143
168
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
An explainer and a design run the same loop over a different unit. An
|
|
170
|
+
explainer pins one commit instead of a range, so it has no diff and nothing to
|
|
171
|
+
approve. A design pins the commit it argues from: its anchors land on the code
|
|
172
|
+
as it stands, never on code that does not exist yet, and what it would build
|
|
173
|
+
rides beside them as proposals.
|
|
149
174
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
code as it stands, and what it would build declared as proposals, each attached
|
|
153
|
-
to the code it lands in today. An anchor never points at code that does not
|
|
154
|
-
exist; the reader approves the design or sends it back.
|
|
155
|
-
|
|
156
|
-
It does not review the code for you. It helps you understand it fast enough
|
|
157
|
-
to review it yourself.
|
|
175
|
+
The document does not review the code for you. It helps you understand the
|
|
176
|
+
code fast enough to judge it yourself.
|
|
158
177
|
|
|
159
178
|
```mermaid
|
|
160
179
|
flowchart LR
|
|
@@ -168,6 +187,16 @@ flowchart LR
|
|
|
168
187
|
|
|
169
188
|
## What the reader sees
|
|
170
189
|
|
|
190
|
+
The home page is a queue: every review, explainer and design, grouped by
|
|
191
|
+
repository and ordered by whose turn it is - a decision not yet posted to its
|
|
192
|
+
change request first, then documents waiting for your reading, then ones whose
|
|
193
|
+
change request moved past the pin, then ones waiting for the agent, then ones
|
|
194
|
+
not published yet. A row bound to a change request also says whether the pin is
|
|
195
|
+
still the head, what you decided and whether it reached the forge, and whether
|
|
196
|
+
CI is a real gate there, as of the last `forge` command and with that age on
|
|
197
|
+
screen. The browser never calls the forge; explainers and designs carry those
|
|
198
|
+
columns empty.
|
|
199
|
+
|
|
171
200
|
Prose with every claim anchored to code, opened beside the text:
|
|
172
201
|
|
|
173
202
|
` links prose to code. Fenced
|
|
329
|
-
blocks `peek`, `sequence`, `callstack` and `database` add components.
|
|
358
|
+
blocks `peek`, `sequence`, `flow`, `callstack` and `database` add components.
|
|
330
359
|
`## Heading {collapsed}` folds a section by default.
|
|
331
360
|
- `data.yaml`: typed inputs: `actors`, `anchors` (file, from, to, graph),
|
|
332
361
|
`stores`, `interfaces` (a capability line per derived entry, plus the
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { startServer } from "./server/server.js";
|
|
|
21
21
|
import { parseFlags, helpFor, str, bool } from "./flags.js";
|
|
22
22
|
import { forgeFor, repoOf, summariseCi, } from "./forge/index.js";
|
|
23
23
|
import { parseSubmission, longComments, buildPass } from "./forge/submission.js";
|
|
24
|
+
import { recordForgeFacts, ciFacts } from "./queue.js";
|
|
24
25
|
import { VERSION } from "./version.js";
|
|
25
26
|
const execFileP = promisify(execFile);
|
|
26
27
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
@@ -756,6 +757,7 @@ const commands = {
|
|
|
756
757
|
let base;
|
|
757
758
|
let head;
|
|
758
759
|
let title = str(p, "title") ?? "";
|
|
760
|
+
let pinned = null;
|
|
759
761
|
const b = existing?.binding;
|
|
760
762
|
const pr = str(p, "pr");
|
|
761
763
|
if (pr || b?.kind === "pr") {
|
|
@@ -779,6 +781,7 @@ const commands = {
|
|
|
779
781
|
base = await g.mergeBase(worktree, baseRef, head);
|
|
780
782
|
binding = { kind: "pr", name: cr.number, url: cr.url, forge: forge.id };
|
|
781
783
|
title ||= cr.title;
|
|
784
|
+
pinned = { repo, cr };
|
|
782
785
|
}
|
|
783
786
|
else if (str(p, "base") || str(p, "head") || b?.kind === "range") {
|
|
784
787
|
const [bb, hh] = b?.kind === "range" && !str(p, "base") && !str(p, "head")
|
|
@@ -857,6 +860,8 @@ const commands = {
|
|
|
857
860
|
await writeReview(review);
|
|
858
861
|
}
|
|
859
862
|
}
|
|
863
|
+
if (pinned)
|
|
864
|
+
await recordForgeFacts(review, pinned.repo, pinned.cr);
|
|
860
865
|
const stat = await g.shortStat(worktree, base, head);
|
|
861
866
|
const dir = reviewDir(review.id);
|
|
862
867
|
return {
|
|
@@ -1648,6 +1653,7 @@ const commands = {
|
|
|
1648
1653
|
const checks = await ctx.forge.checks(ctx.repo, ctx.cr);
|
|
1649
1654
|
const baseline = await ctx.forge.baseline(ctx.repo, ctx.cr.baseBranch).catch(() => null);
|
|
1650
1655
|
const ci = summariseCi(checks, baseline, ctx.cr.baseBranch);
|
|
1656
|
+
await recordForgeFacts(ctx.review, ctx.repo, ctx.cr, { ci: ciFacts(ci) });
|
|
1651
1657
|
const shown = bool(p, "full") ? checks : checks.filter((c) => c.state !== "passed");
|
|
1652
1658
|
const hidden = checks.length - shown.length;
|
|
1653
1659
|
const help = [
|
|
@@ -1869,6 +1875,9 @@ const commands = {
|
|
|
1869
1875
|
],
|
|
1870
1876
|
};
|
|
1871
1877
|
const posted = await ctx.forge.submit(ctx.repo, ctx.cr, submission);
|
|
1878
|
+
await recordForgeFacts(ctx.review, ctx.repo, ctx.cr, {
|
|
1879
|
+
posted: { at: now(), verdict: posted.verdict, head: ctx.cr.head },
|
|
1880
|
+
});
|
|
1872
1881
|
return {
|
|
1873
1882
|
submitted: {
|
|
1874
1883
|
forge: ctx.forge.id,
|