graphlin 0.1.2 → 0.2.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.
Files changed (102) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +12 -3
  4. package/docs/decision-service.md +393 -0
  5. package/docs/extension-authoring.md +553 -0
  6. package/docs/model-api.md +293 -0
  7. package/docs/usage.md +465 -0
  8. package/docs/visualizer-views.md +199 -0
  9. package/node_modules/@vscode/tree-sitter-wasm/LICENSE +21 -0
  10. package/node_modules/@vscode/tree-sitter-wasm/README.md +36 -0
  11. package/node_modules/@vscode/tree-sitter-wasm/SECURITY.md +41 -0
  12. package/node_modules/@vscode/tree-sitter-wasm/cgmanifest.json +16 -0
  13. package/node_modules/@vscode/tree-sitter-wasm/package.json +42 -0
  14. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-bash.wasm +0 -0
  15. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-c-sharp.wasm +0 -0
  16. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-cpp.wasm +0 -0
  17. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-css.wasm +0 -0
  18. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-go.wasm +0 -0
  19. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-ini.wasm +0 -0
  20. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-java.wasm +0 -0
  21. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-javascript.wasm +0 -0
  22. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-php.wasm +0 -0
  23. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-powershell.wasm +0 -0
  24. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-python.wasm +0 -0
  25. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-regex.wasm +0 -0
  26. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-ruby.wasm +0 -0
  27. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-rust.wasm +0 -0
  28. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-tsx.wasm +0 -0
  29. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-typescript.wasm +0 -0
  30. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter.js +4075 -0
  31. package/node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter.wasm +0 -0
  32. package/node_modules/@vscode/tree-sitter-wasm/wasm/web-tree-sitter.d.ts +1027 -0
  33. package/package.json +74 -9
  34. package/plugin.json +4 -2
  35. package/runtime/core/evidence.mjs +43 -9
  36. package/runtime/core/graph.mjs +11 -6
  37. package/runtime/core/privacy.mjs +1 -0
  38. package/runtime/daemon/auth.mjs +7 -3
  39. package/runtime/daemon/diagnostics.mjs +1 -1
  40. package/runtime/daemon/extension-api.mjs +203 -0
  41. package/runtime/daemon/lineage.mjs +70 -0
  42. package/runtime/daemon/manager.mjs +9 -6
  43. package/runtime/daemon/model-api.mjs +728 -0
  44. package/runtime/daemon/model-persistence.mjs +220 -0
  45. package/runtime/daemon/server.mjs +70 -12
  46. package/runtime/daemon/settings.mjs +11 -3
  47. package/runtime/decisions/broker.mjs +349 -0
  48. package/runtime/decisions/contracts.mjs +179 -0
  49. package/runtime/decisions/evaluation.mjs +305 -0
  50. package/runtime/decisions/faults.mjs +32 -0
  51. package/runtime/decisions/index.mjs +818 -0
  52. package/runtime/decisions/profiles.mjs +93 -0
  53. package/runtime/decisions/questions.mjs +268 -0
  54. package/runtime/discovery/index.mjs +2 -0
  55. package/runtime/discovery/inventory.mjs +160 -0
  56. package/runtime/discovery/parser.mjs +40 -0
  57. package/runtime/discovery/structure.mjs +232 -0
  58. package/runtime/extensions/contracts.mjs +59 -0
  59. package/runtime/extensions/frame.mjs +64 -0
  60. package/runtime/extensions/index.mjs +9 -0
  61. package/runtime/extensions/manifest.mjs +95 -0
  62. package/runtime/extensions/packages.mjs +222 -0
  63. package/runtime/extensions/profiles.mjs +36 -0
  64. package/runtime/extensions/projection.mjs +130 -0
  65. package/runtime/extensions/registry.mjs +285 -0
  66. package/runtime/extensions/scene.mjs +105 -0
  67. package/runtime/extensions/sdk.d.ts +205 -0
  68. package/runtime/extensions/sdk.mjs +88 -0
  69. package/runtime/jev/index.mjs +13 -777
  70. package/runtime/jev/provider.mjs +101 -0
  71. package/runtime/jev/questions.mjs +16 -258
  72. package/runtime/jev/wire.mjs +17 -25
  73. package/runtime/model/changes.mjs +42 -0
  74. package/runtime/model/history.mjs +124 -0
  75. package/runtime/model/index.mjs +2 -0
  76. package/runtime/model/project-model.mjs +889 -0
  77. package/runtime/model/records.mjs +239 -0
  78. package/runtime/pipeline.mjs +127 -48
  79. package/runtime/platform.mjs +254 -0
  80. package/runtime/visualizers/blocks.mjs +5 -0
  81. package/runtime/visualizers/c4.mjs +52 -0
  82. package/runtime/visualizers/changes.mjs +24 -0
  83. package/runtime/visualizers/code.mjs +5 -0
  84. package/runtime/visualizers/index.mjs +23 -0
  85. package/runtime/visualizers/structure.mjs +120 -0
  86. package/runtime/visualizers/timeline.mjs +66 -0
  87. package/runtime/web/app.js +369 -86
  88. package/runtime/web/extension-frame.js +128 -0
  89. package/runtime/web/index.html +123 -80
  90. package/runtime/web/model-client.js +162 -0
  91. package/runtime/web/platform.js +337 -0
  92. package/runtime/web/scene.js +111 -0
  93. package/runtime/web/style.css +152 -142
  94. package/schemas/graph.schema.json +4 -1
  95. package/scripts/arguments.mjs +5 -1
  96. package/scripts/build-packages.mjs +6 -2
  97. package/scripts/control.mjs +1 -1
  98. package/scripts/daemon.mjs +2 -1
  99. package/scripts/extensions.mjs +44 -0
  100. package/scripts/graphlin.mjs +23 -3
  101. package/scripts/onboarding.mjs +10 -3
  102. package/scripts/validate-packages.mjs +54 -8
package/docs/usage.md ADDED
@@ -0,0 +1,465 @@
1
+ # Graphlin user guide
2
+
3
+ For your first run, follow the [two-step quick start](../README.md#get-started).
4
+
5
+ A local plugin for live architecture and activity diagrams while a coding agent works.
6
+
7
+ ![Graphlin's Sketchbook diagram showing function calls, a cache write, and a browser-to-service connection](images/graphlin-preview.png)
8
+
9
+ *A close-up from the offline demo. [See the full diagram](images/graphlin-overview.png).*
10
+
11
+ **Development preview.** Install from npm with the command below, or use a
12
+ checkout. Releases pass the full CI matrix; see [releasing](releasing.md) for
13
+ the publishing workflow.
14
+
15
+ ## Guided setup
16
+
17
+ In your project's terminal:
18
+
19
+ ```sh
20
+ npx --yes graphlin@latest
21
+ ```
22
+
23
+ The first run detects host CLIs. If only one is available it selects that host;
24
+ otherwise choose **claude**, **codex**, or **both**. Choose **source** to permit locally filtered source excerpts, user
25
+ prompts, and public agent messages to reach TypeSafe. Choose **local** to parse
26
+ supported source entirely on your machine, or **metadata** to inventory paths
27
+ without opening source files. Local and metadata modes need no API key. Source mode offers a masked key
28
+ prompt when no key is available. Keys never belong in command arguments or chat.
29
+
30
+ Graphlin registers its local marketplaces and installs through the native host
31
+ CLIs for your user account. It preserves unrelated host configuration. Versioned
32
+ packages live under `~/.local/state/graphlin/plugins/graphlin/<version>`, outside
33
+ the npm cache. The viewer opens automatically and stays in the foreground;
34
+ **Ctrl+C** stops it. `--no-open` suppresses browser opening.
35
+
36
+ In a second terminal in the same project, run `claude` or `codex`. Accept the
37
+ project trust prompt. Confirm Graphlin is enabled using Claude's `/plugin`;
38
+ in Codex, use `/hooks` to review and trust Graphlin's hooks. Start a new host
39
+ session after installation. If using a custom data directory, copy the printed
40
+ agent command so the hooks inherit the same `GRAPHLIN_DATA_DIR`.
41
+
42
+ On subsequent runs, the bare command reuses saved setup. To configure without
43
+ starting a viewer, append `init`. A checkout can use
44
+ `node scripts/graphlin.mjs init`. Explicit `start` opens the viewer without
45
+ installing host plugins; omitted policy flags reuse current or saved consent.
46
+ `--no-source` explicitly opts out. A new project without consent is metadata only.
47
+ `--local-source` enables local parsing without remote classification.
48
+
49
+ ## Explore the project
50
+
51
+ The viewer inventories the project before an agent connects. With source
52
+ permission it progressively parses JavaScript, TypeScript, TSX, and Python.
53
+ Other languages retain file-level scopes and show their unsupported coverage.
54
+ The drawing limit does not limit the project model.
55
+
56
+ Choose Code, Blocks, C4, Changes, or Activity timeline. Blocks shows actual
57
+ containment; C4 requires supported architectural interpretations and keeps
58
+ ambiguous responsibilities unknown. Use **Set baseline now** to compare a
59
+ task's changes; discovery of existing code is not automatically creation.
60
+ Search with `/`, clear with Escape, and turn off **Follow agent** to explore
61
+ without camera movement.
62
+
63
+ [View controls and limitations](visualizer-views.md) ·
64
+ [Install or author a visualizer](extension-authoring.md) ·
65
+ [Local read API](model-api.md) · [Replace the decision provider](decision-service.md)
66
+
67
+ ## Consent and keys
68
+
69
+ Consent belongs to the canonical project. The key and installed host list are
70
+ shared within the data directory. The key is kept in a private user settings
71
+ file (0600) in a private directory (0700), separate from evidence and exports.
72
+ Source-enabled `init` also saves an environment-provided key for later launches.
73
+ `TYPESAFE_API_KEY` overrides the saved key; an explicitly empty value disables
74
+ the saved key, so unset it to use the saved credential.
75
+
76
+ To replace an expired or incorrect saved key, run the npm command
77
+ with `init --replace-key`, or `node scripts/graphlin.mjs init --replace-key`
78
+ from a checkout. Replacement uses the masked terminal prompt; no command-line
79
+ key value is accepted. Restart the viewer to load the new key. Use `doctor`
80
+ to inspect setup and classifier state; it does not make a paid key-validation call.
81
+
82
+ Non-interactive commands never wait for Graphlin prompts. Specify a host and
83
+ source choice explicitly, for example:
84
+
85
+ ```sh
86
+ npx --yes graphlin@latest init --host codex --no-source
87
+ ```
88
+
89
+ A pending installation can resume from the bare command using already saved
90
+ project consent, including without a terminal. New projects still require an
91
+ explicit consent choice.
92
+
93
+ With `--allow-source`, a key must already be saved or supplied securely through
94
+ the environment. Use the interactive prompt to save a key. Missing CLIs,
95
+ cancelled setup, and failed host commands produce errors; each completed host
96
+ installation is recorded separately so a partial failure is visible. Installing
97
+ a plugin does not prove its hooks are active or its classifier key is valid.
98
+ Graphlin makes no key-validation request during setup.
99
+
100
+ Setup checks existing marketplace registrations before retrying. A name collision
101
+ with an unrelated `graphlin-local` marketplace is reported without replacing it.
102
+ Version upgrades update every recorded host, even when only one is selected,
103
+ so the shared version stays consistent. A failed upgrade retains the old version
104
+ until all hosts finish. If Codex's marketplace rebind fails after its old
105
+ registration was removed, it is recorded as pending rather than installed.
106
+ The next bare Graphlin run resumes unfinished hosts, including a partially
107
+ completed first installation. Existing keys and Graphlin history remain.
108
+
109
+ To reopen the viewer with a fresh one-use browser URL, use `graphlin open`
110
+ (or append `open` to the npm command). It starts a detached viewer
111
+ if needed. Use `graphlin stop` to stop it.
112
+
113
+ ## Uninstall
114
+
115
+ ```sh
116
+ npx --yes graphlin@latest uninstall
117
+ ```
118
+
119
+ This removes Graphlin from the recorded hosts **for all projects**. Use
120
+ `--host claude`, `--host codex`, or `--host both` to choose explicitly, including
121
+ a manually installed Graphlin plugin. The native host CLIs remove only
122
+ `graphlin@graphlin-local`; unrelated plugins and settings remain intact.
123
+ Claude receives `--keep-data`. Keys, Graphlin history, generated packages, and
124
+ marketplace registrations remain for recovery or reinstall.
125
+
126
+ Uninstall resets source and evidence-persistence consent for the current
127
+ project. It does not change an already running viewer's active policy; stop it
128
+ with `graphlin stop`. Other projects retain their consent. A failed host removal
129
+ is reported and remains in the installation record.
130
+
131
+ The design uses Jev at two principal stages: **intelligent intake** (semantic normalization, contextual redaction, and candidate extraction) and **architecture decisions**. Focused code snippets go directly to Noul questions such as “does this function implement a database write?”, with optional Score evidence-strength diagnostics. Parsers help select context and resolve references; a library-specific semantic analyzer is not required for every relationship. A shared decision service can also support bounded alignment, grouping, enrichment, and contradiction checks. Local code owns privacy enforcement, evidence validity, precise drawing operations, and rendering.
132
+
133
+ ## Try it
134
+
135
+ Requires Node.js 22.14+ on macOS or Linux. There are no package dependencies or
136
+ required build steps.
137
+
138
+ ```sh
139
+ npm run demo
140
+ ```
141
+
142
+ Open the local URL printed by the command. The demo uses synthetic source files
143
+ and recorded classifier answers; it makes no network API requests. It runs the
144
+ actual event normalization, evidence, decision, graph, and viewer components.
145
+ The command stays in your terminal. Press **Ctrl+C** to stop the service.
146
+ `start` behaves the same way; use `--background` only when you want it detached.
147
+
148
+ Starting again for the same canonical project and data directory reuses the
149
+ running service and port. A fresh one-use browser token does not mean a new
150
+ server. A foreground start can join an existing service; Ctrl+C stops that
151
+ joined service too. Separate projects or data directories have separate
152
+ services.
153
+
154
+ For your own project, explicitly start with metadata only:
155
+
156
+ ```sh
157
+ node scripts/graphlin.mjs start --project /path/to/your/app --no-source
158
+ ```
159
+
160
+ Source classification requires a TypeSafe key and explicit permission to
161
+ transmit sanitized excerpts:
162
+
163
+ ```sh
164
+ node scripts/graphlin.mjs init --project /path/to/your/app
165
+ node scripts/graphlin.mjs start --project /path/to/your/app
166
+ ```
167
+
168
+ Choose source mode and enter the key at the masked prompt. The key is read by
169
+ the daemon and never sent to the browser or inherited by installer/browser
170
+ subprocesses. Existing secure `TYPESAFE_API_KEY` environments are also supported.
171
+
172
+ Local filtering excludes credential/environment files, configured exclusions,
173
+ binary/oversized files, and obvious secret values before Jev sees anything.
174
+ Jev adds contextual filtering. Approved evidence is displayed by default;
175
+ use `--no-display-evidence` to hide it. Evidence persistence is a separate
176
+ opt-in, `--persist-evidence`. A policy change requires stopping and restarting
177
+ the daemon.
178
+
179
+ ```sh
180
+ node scripts/graphlin.mjs doctor --project /path/to/your/app
181
+ node scripts/graphlin.mjs status --project /path/to/your/app
182
+ node scripts/graphlin.mjs export --project /path/to/your/app
183
+ node scripts/graphlin.mjs stop --project /path/to/your/app
184
+ ```
185
+
186
+ State lives under `~/.local/state/graphlin` by default. Set
187
+ `GRAPHLIN_DATA_DIR` or use `--data-dir` to choose another location.
188
+ Source excerpts are ephemeral unless persistence is enabled. Retention and
189
+ payload sizes are bounded.
190
+
191
+ ## Investigate a missing shape
192
+
193
+ Select **Classification log** in the viewer and search for a file, such as
194
+ `src/cache.ts`, or an entity name. The log connects file capture and candidate
195
+ selection to Jev's intake scores, role/relation decisions, and the final diagram
196
+ changes. It also explains work that never reaches Jev: duplicate events,
197
+ pre-tool intentions, withheld source, empty candidates, and capacity limits.
198
+
199
+ From another terminal:
200
+
201
+ ```sh
202
+ node scripts/graphlin.mjs logs --project /path/to/your/app
203
+ node scripts/graphlin.mjs logs --project /path/to/your/app --file src/cache.ts
204
+ ```
205
+
206
+ Logging is automatic. After updating Graphlin, stop the existing service with
207
+ **Ctrl+C** and run the same `start` command again. A running process cannot load
208
+ the new logger, and old classifier scores cannot be reconstructed.
209
+
210
+ Each classification records the effective thresholds, both request durations,
211
+ model/rubric versions, validated scores, and fixed rejection reasons. A successful
212
+ classification can still result in no change because source changed while it
213
+ was running, an entity is already current, or a drawing limit was reached.
214
+ The log distinguishes those outcomes from an API failure or timeout.
215
+
216
+ Logs contain no source bodies, prompts, credentials, launch tokens, or raw API
217
+ errors. Live file names and candidate labels follow the evidence-display setting;
218
+ persisted logs omit them unless `--persist-evidence` is enabled. The `--file`
219
+ filter also matches stable artifact IDs, including after a file is deleted.
220
+ The service prints its log location. Retention is bounded to a recent in-memory
221
+ window and two private JSONL files; logs remain separate from diagram exports.
222
+
223
+ ## Plugin packages
224
+
225
+ Guided setup builds and installs these packages automatically. For development
226
+ or manual recovery:
227
+
228
+ ```sh
229
+ npm run build
230
+ claude --plugin-dir ./dist/claude/graphlin
231
+ ```
232
+
233
+ The build creates a `graphlin/` plugin inside `dist/portable`, `dist/claude`,
234
+ and `dist/codex`. Start
235
+ Graphlin for the project before working with the agent; passive hooks quietly
236
+ hand off events to the running service. A bundled MCP server also exposes
237
+ start, stop, status, and doctor controls.
238
+
239
+ The portable package uses Agent Plugins 1.0. Claude has its native manifest;
240
+ Codex has its portable extension and compatibility manifest. Kiro currently
241
+ has an experimental adapter profile. See [adapter coverage](../adapters/README.md).
242
+ Building a package does not install it into your host configuration.
243
+
244
+ The first implementation is Claude-first. Configuration and payload fixtures
245
+ are tested separately from real host activation. It does not claim universal
246
+ hook coverage or access to private reasoning.
247
+
248
+ ## Connect an agent
249
+
250
+ In the live viewer, select **How to connect**. The guide shows copyable commands
251
+ using that service's project, data directory, and available plugin packages.
252
+ Its build step puts versioned plugins under the service's data directory, so
253
+ setup also works when Graphlin's installation folder is read-only.
254
+ Keep Graphlin running in its terminal and run the agent in another terminal.
255
+ The Jev key stays with the service; the agent commands do not include it.
256
+
257
+ After guided installation, simply start `claude` in the project. The manual
258
+ recovery guide can use `claude --plugin-dir` to load the built Claude profile.
259
+ The guide also shows how to resume a session with that profile.
260
+
261
+ The build includes a local Codex marketplace under `dist/codex`. From this
262
+ checkout, the setup commands are:
263
+
264
+ ```sh
265
+ npm run build
266
+ codex plugin marketplace add "$PWD/dist/codex"
267
+ codex plugin add graphlin@graphlin-local
268
+ codex -C /path/to/your/app
269
+ ```
270
+
271
+ Inside Codex, use `/hooks` to review and trust Graphlin's hooks. Start a new
272
+ session after installation. Building the marketplace only creates files;
273
+ the commands above register and install it when you run them.
274
+ If the service uses a custom data directory, use the guide's command so the
275
+ agent inherits the matching `GRAPHLIN_DATA_DIR`.
276
+
277
+ The command forms were checked against the installed CLIs and the official
278
+ [plugin packaging](https://developers.openai.com/plugins/build/plugins) and
279
+ [Codex hooks](https://developers.openai.com/codex/hooks) documentation.
280
+ Installation and hook trust still depend on your host configuration.
281
+
282
+ ## Discover an existing project
283
+
284
+ Start Graphlin with `--allow-source`, connect Claude with the built plugin,
285
+ and ask it to **“orient yourself in this project”** or **“explore the architecture.”**
286
+ Completed reads, searches, and file listings can populate the diagram without
287
+ editing any files. There is no special prompt keyword or extra agent tool.
288
+
289
+ The existing `PostToolUse` hook supplies both the tool arguments and its result.
290
+ Graphlin recognizes returned file paths from Read, Glob, structured Grep results,
291
+ and common `find`, `rg --files`, and simple `ls` listings. It treats those paths as
292
+ hints and captures the current files from disk through the normal project and
293
+ privacy checks. Arbitrary shell output and an agent's summary do not become
294
+ confirmed source evidence. The hook never modifies Claude's tool result.
295
+
296
+ Classification runs asynchronously with two active workflows. Each receives its
297
+ own five-second deadline when it starts, so time waiting behind other file reads
298
+ does not consume that deadline. Queued source is checked again before
299
+ classification and before a result reaches the diagram. Work is deduplicated
300
+ within each session; another session can discover the same unchanged project.
301
+ The classification log records queue wait time and why work was skipped.
302
+
303
+ Discovery is bounded: the fallback directory scan visits at most 100 directories,
304
+ five levels deep, and selects up to 64 source files; explicit tool results can
305
+ identify additional files. The queue holds up to 64 waiting workflows for at most
306
+ two minutes. Excluded, unavailable, oversized, or sensitive files remain subject
307
+ to the existing evidence policy. A shape means code was observed; it does not
308
+ mean a database connection or other runtime operation succeeded.
309
+
310
+ Run `npm run eval:discovery` to replay a burst of orientation reads against real
311
+ Jev using a temporary, synthetic seven-file project. It reports per-file diagram
312
+ coverage, queue timing, and missing files. The probe uses `TYPESAFE_API_KEY` or
313
+ the local `.env.local`; it never reads your application or Claude transcript.
314
+
315
+ ## Follow live work
316
+
317
+ A new Claude session automatically becomes the selected diagram when its
318
+ `SessionStart` hook arrives. Ordinary hooks, delayed classifications, and
319
+ background compaction from another session do not take the selection away.
320
+ You can still choose an older session manually.
321
+
322
+ Expand **Hooks received** in the sidebar to see individual hook receipts from
323
+ all sessions in this project, newest first. Pre-tool, post-tool, and repeated
324
+ deliveries remain separate. The feed holds up to 200 receipts in memory and
325
+ contains event metadata, not tool bodies, prompts, or credentials.
326
+
327
+ **Diagram changes** stacks miniature added, removed, and changed shapes, with
328
+ the latest revision at the top. Select a current shape to inspect its evidence,
329
+ or a removed shape to replay the preceding retained revision. History is bounded;
330
+ gaps and unavailable older revisions are identified. Theme, zoom, and layout
331
+ changes do not create architecture history.
332
+
333
+ Restart an older Graphlin service and reload the viewer to enable the detailed
334
+ hook feed. Receipts from before that restart cannot be reconstructed.
335
+
336
+ ## Arrange the diagram
337
+
338
+ The diagram fills the workspace. Layout, theme, search, and type filters sit
339
+ above it. **Details**, **History**, and **Activity** open panels that are hidden
340
+ by default. Selecting a shape opens its evidence inspector.
341
+
342
+ The dashboard shows the active Git branch, full project path, and running
343
+ Graphlin version. Branch information refreshes every 30 seconds. The update
344
+ check asks npm only for Graphlin's public release metadata and caches the result
345
+ for 30 minutes. If a newer release is available, **How to update** provides a
346
+ copyable command that preserves this project's data directory. Stop the viewer
347
+ with **Ctrl+C**, run that command, and start a new agent session after setup.
348
+
349
+ Choose **Hierarchy**, **Dependency flow**, **Group by type**, **Circular**,
350
+ **Grid**, or **Original**. Auto-arrange responds to changes in the diagram;
351
+ turn it off to keep existing shapes in place, then use **Arrange** when ready.
352
+ Hierarchy follows the arrows and handles cycles; it does not imply ownership.
353
+
354
+ Scroll up over the diagram to zoom in around the pointer; scroll down to zoom
355
+ out. Drag the background to pan. **Fit**, layout switches, and **Arrange** show
356
+ the whole diagram, including below 50% for large hierarchies.
357
+
358
+ When a new shape arrives, the camera centers on it before its balloon animation.
359
+ A view below 50% zoom moves to 50%; a closer view keeps its zoom. If several
360
+ shapes arrive together, the last added shape gets the focus. Initial loads and
361
+ session switches show the whole diagram. Ordinary hook and status updates
362
+ preserve manual zoom and pan.
363
+
364
+ Type in the search box above the diagram, or press **/** to focus it. Search
365
+ matches any part of a node name, ignoring case, and shows only matching nodes
366
+ and connections between them. Each change rearranges the visible nodes and fits
367
+ them into the canvas, including clearing the search with **Esc**.
368
+
369
+ Type buttons show the component kinds present in the current diagram. Toggle
370
+ them individually, choose **All types**, or **Clear all** to start a new
371
+ selection. Search and type filters work together; Esc clears the search while
372
+ keeping the selected types. Filtering changes the view without deleting nodes
373
+ or changing exports.
374
+
375
+ Twelve component kinds map to distinct shapes, including functions, classes,
376
+ interfaces, events, configuration, packages, queues, and datastores.
377
+ Select a component to choose among 15 shapes in the inspector. Long names
378
+ wrap to two lines; the inspector retains the full name.
379
+
380
+ Shapes and arrows use **Tidy sketch** lines: gentle bends, close double strokes,
381
+ and slightly imperfect corners. The **Theme** selector offers
382
+ Sketchbook, Ocean, Forest, Sunset, Berry, Sepia, Blueprint dark, and Midnight
383
+ dark. Component kinds have coordinated fill colors; evidence labels and line
384
+ patterns remain distinct in every theme. Themes apply to the diagram and its
385
+ controls, leaving the evidence inspector readable in the surrounding interface.
386
+
387
+ New components inflate with a small bounce. Removed components pop into
388
+ particles. Replay, initial loading, reconnection, and stale evidence do not
389
+ trigger these effects. Reduced-motion preferences are respected.
390
+
391
+ Layouts and shape overrides affect the view only. They do not change evidence,
392
+ classification, recorded coordinates, or exported graphs. View preferences
393
+ are kept in memory per project/session/replay view and reset on page refresh.
394
+
395
+ ## Test
396
+
397
+ The following development and evaluation commands require a source checkout.
398
+ They are not part of the installed runtime package.
399
+
400
+ ```sh
401
+ npm test
402
+ ```
403
+
404
+ The automated suite uses local fixtures and injected transports. It checks
405
+ privacy, the A-to-B boundary, HTTP response validation, deadlines, event
406
+ correlation, source-version invalidation, graph integrity, replay, local
407
+ authentication, packaging, and viewer behavior.
408
+
409
+ An explicit live evaluation calls Jev with synthetic code cases:
410
+
411
+ ```sh
412
+ npm run eval:jev
413
+ node scripts/evaluate-jev.mjs --repeat 3
414
+ ```
415
+
416
+ This command reads `TYPESAFE_API_KEY`, optionally from `.env.local`, and saves
417
+ a numeric report in the ignored `.graphlin/` directory. It never sends your
418
+ project source. It reports missing candidates/questions and timeouts as
419
+ inconclusive. The default request cap is 128; explicit repeats keep their
420
+ earlier failures in the report. These examples are a smoke evaluation, not a
421
+ calibrated benchmark. See [live findings](jev-integration-findings.md).
422
+
423
+ The implementation uses JavaScript ES modules on Node.js, with HTML, CSS,
424
+ and JavaScript in the viewer. TypeSafe provides an official JavaScript/TypeScript
425
+ SDK, `@typesafe-ai/sdk`. This first slice uses the documented HTTP API through
426
+ Node's built-in `fetch`, keeping installation dependency-free while controlling
427
+ the complete request deadline, response bounds, and retry policy.
428
+
429
+ ## Evidence and limits
430
+
431
+ - Jev interprets focused snippets. A classified write path does not prove a
432
+ live database connection or a successful write.
433
+ - Pre-tool events show pending activity; they cannot confirm future changes.
434
+ - File observations have their own versions and unknown authorship. Changes
435
+ invalidate dependent claims across sessions even when Jev is unavailable.
436
+ - Restored claims start stale until fresh authorized observations support them.
437
+ - Streaming message assembly, semantic alias merging, broad static analysis,
438
+ account-wide budgets, and Windows transport are outside this first slice.
439
+ - Request budgets are per daemon. Classification can pause while metadata and
440
+ evidence invalidation continue.
441
+
442
+ ## Design and review
443
+
444
+ - [Proposed design](graphlin-design.md): architecture, plugin packaging, host coverage, Jev requests, state, drawing language, failure behavior, and delivery plan.
445
+ - [Interactive walkthrough](graphlin-design.html): replay a build, failed check, later verification, component removal, and Jev outage; inspect the two-stage pipeline.
446
+ - [Independent review](graphlin-review.md): prioritized findings and follow-up status.
447
+ - [Research coverage](research-coverage.md): primary documentation and design decisions.
448
+ - [Implementation plan](implementation-plan.md) and [module contracts](module-contracts.md).
449
+ - [Preimplementation review](implementation-review.md).
450
+ - [Implementation validation](implementation-validation.md): code review,
451
+ automated tests, browser checks, and remaining scope.
452
+ - [Jev patterns](jev-patterns.md): intent routing, speculative fan-out,
453
+ confidence gates, and evaluation before enabling domain routing.
454
+
455
+ Open the HTML file directly in a browser, or serve `docs/` with a local static web server. The walkthrough is self-contained and makes no network API calls.
456
+
457
+ The design walkthrough remains illustrative. The live viewer is served by the
458
+ runtime started through the commands above.
459
+
460
+ ## Contributing and license
461
+
462
+ See [CONTRIBUTING.md](../CONTRIBUTING.md) for development and review guidance,
463
+ [SECURITY.md](../SECURITY.md) for vulnerability reporting, and
464
+ [the release guide](releasing.md) for npm publishing.
465
+ Graphlin is available under the [MIT license](../LICENSE).
@@ -0,0 +1,199 @@
1
+ # Viewer views
2
+
3
+ Graphlin keeps a source model separate from the drawing. The compact view picker
4
+ selects **Code**, **Blocks**, **C4**, **Changes**, **Activity timeline**, or an
5
+ installed visualizer. Details, History, and the legacy Activity panel remain
6
+ hidden until opened. The existing sketch renderer and eight palettes remain
7
+ available.
8
+
9
+ ## Reference views
10
+
11
+ | View | What it shows |
12
+ | --- | --- |
13
+ | Code | Canonical declarations and supported relationships, using the existing sketch shapes and layouts |
14
+ | Blocks | Filesystem scopes and parsed containment, with expandable parent frames |
15
+ | C4 | Context, applications/datastores, components, and code; supported current interpretations determine architectural boundaries |
16
+ | Changes | Discoveries, creations, modifications, removals, and invalidations against an explicitly selected checkpoint |
17
+ | Activity timeline | Ordered tool/agent observations, attributed lanes, terminal outcomes, and attempts whose outcome is unresolved |
18
+
19
+ Folders do not establish applications, processes, or deployment boundaries.
20
+ Without a supported interpretation at the selected C4 level, source scopes
21
+ remain usable and the view reports that their responsibilities are unknown.
22
+ Missing interpretation does not trigger a classifier call from the browser.
23
+ The Blocks view does not invent responsibility labels.
24
+
25
+ **Set baseline now** creates a named checkpoint through the authenticated host
26
+ API, including the selected session. It is disabled during replay. Selecting a
27
+ retained checkpoint uses the core comparison implementation.
28
+ First observation is discovery unless the core records supported creation or a
29
+ compatible complete enumeration proves prior absence. Missing retained records
30
+ are not treated as deleted. Source edits do not establish runtime success.
31
+
32
+ The timeline works with zero entities and zero relations. Correlation uses
33
+ recorded tool/agent identifiers; an unpaired attempt stays unresolved. Selecting
34
+ an observation inspects its linked entity, or explains that no source entity is
35
+ linked. It never claims private reasoning capture.
36
+
37
+ ## Navigation
38
+
39
+ Search and source-kind filters apply together. Matching declarations keep their
40
+ ancestor frames, and searches expand the path to a match. Escape clears the
41
+ search while retaining type choices. Filtering arranges and fits the result.
42
+ The inspector's **Open source scope** action and the breadcrumb buttons request
43
+ a bounded source scope. C4 interpretation groups can expand to their supported
44
+ source members.
45
+
46
+ Collapsed connections aggregate by source scope, target scope, relation type,
47
+ and validity. Calls and writes remain separate. Internal connections do not
48
+ become self-arrows. Each aggregate retains its relation IDs and count for the
49
+ host evidence inspector. Scene limits affect presentation, never discovery.
50
+ The coverage line reports truncation and available inventory/inspection counts.
51
+
52
+ Selection maps to canonical entities. Switching views preserves that entity
53
+ when represented, otherwise its nearest represented ancestor/group. Each view
54
+ retains its camera, layout, shape overrides, and theme. **Follow agent** reveals
55
+ newly arriving or newly active entities through containment; turning it off
56
+ keeps the camera in place. Fit and Arrange remain explicit user actions.
57
+
58
+ **Position** selects Live or a retained model checkpoint. Model replay uses
59
+ recorded snapshots and makes no inference calls. The older History scrubber
60
+ remains available when using the legacy API; model views use Position instead.
61
+ Custom views disable graph layout/zoom controls that they do not implement.
62
+
63
+ ## Browser modules and lifecycle
64
+
65
+ `runtime/visualizers/` contains pure source-to-scene projectors, a common
66
+ containment/aggregation projector, and the first-party custom timeline.
67
+ `createBuiltin()` and `createExtensionFrame()` expose `update(input)` and
68
+ `dispose()` to the viewer host. Updates return a validated scene or bounded
69
+ custom status. The timeline mounts DOM through this same lifecycle and has no
70
+ dependency on the graph renderer.
71
+
72
+ `runtime/web/model-client.js` owns authenticated model snapshot/stream access.
73
+ `runtime/web/platform.js` owns view choice, per-view settings, checkpoints,
74
+ grants, cancellation, and scope. `runtime/web/scene.js` supplies containment
75
+ geometry, filtering, and canonical mappings. `runtime/web/app.js` retains
76
+ authentication, evidence inspection, diagnostics, sketch rendering, and the
77
+ legacy fallback.
78
+ Legacy source references accept both `jev_interpretation` and
79
+ `decision_interpretation`; alternate providers use the generic Decision
80
+ interpretation label while existing Jev labels remain compatible.
81
+
82
+ Browser-safe scene and message validation is imported from the SDK contract
83
+ modules rather than reimplemented by each built-in. Shared scenes contain
84
+ finite primitives, never extension-supplied HTML or SVG. Nested frames use a
85
+ title band, padded containment, and separated sibling rectangles.
86
+
87
+ ## API integration
88
+
89
+ All requests use the existing host session cookie and same-origin credentials.
90
+ No launch token is forwarded to a visualizer.
91
+
92
+ | Route | Use |
93
+ | --- | --- |
94
+ | `GET /api/model/v1/snapshot` | Paged schema 2 model; optional `scope`, `session`, `checkpoint` |
95
+ | `GET /api/model/v1/entities`, `/relations`, `/interpretations`, `/activity`, `/sessions`, `/history` | Revision-bound cursor pages; history supplies checkpoints |
96
+ | `GET /api/model/v1/events` | Snapshot envelopes with the same pages/cursors; optional scope/session |
97
+ | `POST /api/model/v1/checkpoints` | Explicit host action with `label` and optional `sessionId` |
98
+ | `GET /api/extensions` | Catalog with manifest, digest, current grant, and declared profile descriptors |
99
+ | `POST /api/extensions/grant` | `{id, digest, fields, history, approved, profiles}` |
100
+ | `POST /api/extensions/analysis` | Explicit Run analysis action with `{id, digest, profileId, entityIds, revision}` |
101
+ | `GET /api/extensions/data/<id>` | Daemon policy/grant-projected model, with the same scope/session/checkpoint options |
102
+ | `GET /api/extensions/frame/<id>?nonce=...` | Daemon-generated document with response-level sandbox/CSP |
103
+
104
+ The client hydrates pages at one project/revision/model sequence and transport
105
+ epoch. It restarts stale cursors rather than mixing revisions. Transport sequence
106
+ and epoch govern SSE ordering independently of the model's observation sequence;
107
+ coalesced snapshots may skip transport positions. Scope/replay changes cancel
108
+ obsolete work. Selecting a checkpoint closes the live model subscription.
109
+
110
+ Hydration retains at most 2,048 entities, 4,096 relations, 512 interpretations,
111
+ 2,048 activities, 100 sessions, and 100 checkpoints, within a 6 MiB budget.
112
+ The API's individual response limit remains 512 KiB. Coverage records retained
113
+ and total counts when these bounds truncate a scope. Opening a narrower source
114
+ scope requests that scope from the daemon; the browser does not need an
115
+ unbounded full-project model.
116
+
117
+ An absent model endpoint leaves the legacy `/api/state` and `/api/events` code
118
+ map usable. Capture/status, diagnostics, exports, and authentication keep their
119
+ existing routes. The model endpoint never replaces the host evidence policy.
120
+
121
+ ## Installed visualizers
122
+
123
+ Installation alone does not grant data. The host shows explicit field and
124
+ history choices, and approval is bound to the project and installed digest.
125
+ Before approval, no projected-data request or model delivery is made.
126
+ Raw source, excerpts, prompts, transcripts, credentials, and unrestricted source
127
+ retrieval are not offered as grant fields.
128
+
129
+ An approved extension receives **only** the response from its daemon-projected
130
+ data endpoint. The host never forwards its own raw model as a fallback.
131
+ Catalog/grants are rechecked before each delivery, including history.
132
+ An independent two-second poll checks the mounted extension's grant and digest
133
+ even during replay. Unmounting cancels that poll.
134
+ Revocation, denied access, digest replacement, or frame navigation clears the
135
+ controlled view and disposes its port/frame. It cannot recall data already
136
+ copied by third-party code.
137
+
138
+ The iframe uses `sandbox="allow-scripts"` with no same-origin permission.
139
+ Both the host response policy and the HTML meta policy permit same-origin
140
+ frames. The browser check caught and fixed the missing HTML `frame-src 'self'`
141
+ directive; frame mounting now passes in the actual headless browser.
142
+ One bootstrap is sent to its exact window with a fresh nonce and a dedicated
143
+ MessageChannel. Readiness must echo that nonce before data is sent. The opaque
144
+ origin requires `*` for the bootstrap target origin; the exact frame window,
145
+ one-use nonce, and port supply the binding.
146
+
147
+ Typed project/result messages carry instance, project, revision, view epoch,
148
+ request ID, and API version. Late responses are ignored; scene mappings are
149
+ checked against the delivered projection. Payload size, message rate, readiness,
150
+ and update deadlines are bounded. Invalid output or navigation disposes the
151
+ frame; the host falls back to Code after extension failure. First-party projector failure keeps the
152
+ last accepted drawing. Policy/grant failures always clear affected content.
153
+ Selection and inspection requests require a declared request capability, an
154
+ active matching grant, and access to the mapped data field.
155
+
156
+ Declared analysis profiles have separate approval checkboxes. **Run analysis**
157
+ uses the selected canonical entity, or at most 256 entities in the current scope,
158
+ at the current revision. Mount, layout, theme, filtering, and replay do not call
159
+ analysis. Replay disables the action. The approval text explains that a profile
160
+ may send locally filtered evidence to the configured service and requires the
161
+ project's existing source-transmission consent; visualizer approval does not
162
+ enable that consent. The daemon rechecks the grant, profile, revision, candidates,
163
+ and source policy.
164
+
165
+ The first-party timeline is trusted bundled code using the custom lifecycle.
166
+ Third-party custom renderers use the opaque frame and bounded custom status;
167
+ they do not receive first-party inspector privileges. Iframes are not a promise
168
+ of hard CPU isolation or universal prevention of disclosure.
169
+
170
+ ## Verification
171
+
172
+ `node --test tests/web/*.test.mjs` exercises both the existing viewer and model
173
+ views, including source-kind filters, group bounds, aggregation, C4 abstention,
174
+ checkpoint comparisons, custom activity, follow behavior, obsolete responses,
175
+ readiness, invalid scenes, and navigation teardown.
176
+ Focused tests also exercise actual model API paging beyond 200 records, bounded
177
+ hydration, transport epochs, and session-filtered checkpoint creation/replay.
178
+
179
+ `node tests/web/platform-browser-fixture.mjs` starts a disposable loopback-only
180
+ fixture for browser review. It supplies generated models and an installed
181
+ fixture visualizer; it does not run capture, inspect a user's project, read a
182
+ key, or persist user state. Its API is a test fixture, not an authentication
183
+ test or a replacement for the daemon's integration/isolation tests.
184
+
185
+ `node tests/web/platform-daemon-fixture.mjs` starts the actual daemon against a
186
+ generated source project and installed custom extension under a disposable
187
+ temporary directory. It uses a random loopback port and disables source
188
+ transmission. Its `change` and `revoke` input commands support manual browser
189
+ checks; stopping it removes its own fixture state.
190
+
191
+ `node tests/web/platform-browser-check.mjs` runs the actual fixture in a separate
192
+ headless Playwright browser with a temporary profile. Set
193
+ `GRAPHLIN_BROWSER_DEPENDENCIES` to a directory whose `node_modules` includes
194
+ Playwright, optionally `GRAPHLIN_BROWSER_EXECUTABLE` to a Chrome executable, and
195
+ `GRAPHLIN_BROWSER_ARTIFACTS` for screenshots and the verification report.
196
+ This explicit check covers the reference views, narrow-screen keyboard use,
197
+ real sandbox frame mounting, profile approval/run, selection, and grant
198
+ revocation during replay. It does not access existing user browser profiles,
199
+ projects, or daemon instances, and is not a privacy certification.