@nanonets/graft 0.10.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -11
- package/dist/ai/crux.d.ts.map +1 -1
- package/dist/ai/crux.js +7 -6
- package/dist/ai/crux.js.map +1 -1
- package/dist/ai/failure.d.ts +49 -0
- package/dist/ai/failure.d.ts.map +1 -0
- package/dist/ai/failure.js +74 -0
- package/dist/ai/failure.js.map +1 -0
- package/dist/ai/llm/anthropic.d.ts.map +1 -1
- package/dist/ai/llm/anthropic.js +4 -1
- package/dist/ai/llm/anthropic.js.map +1 -1
- package/dist/ai/llm/claude-cli.d.ts +60 -0
- package/dist/ai/llm/claude-cli.d.ts.map +1 -0
- package/dist/ai/llm/claude-cli.js +417 -0
- package/dist/ai/llm/claude-cli.js.map +1 -0
- package/dist/ai/llm/openai.d.ts.map +1 -1
- package/dist/ai/llm/openai.js +2 -0
- package/dist/ai/llm/openai.js.map +1 -1
- package/dist/ai/llm/types.d.ts +9 -0
- package/dist/ai/llm/types.d.ts.map +1 -1
- package/dist/ai/llm/types.js +12 -1
- package/dist/ai/llm/types.js.map +1 -1
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +39 -45
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/fuse.d.ts +83 -46
- package/dist/ask/fuse.d.ts.map +1 -1
- package/dist/ask/fuse.js +165 -67
- package/dist/ask/fuse.js.map +1 -1
- package/dist/blast/blast-cli.d.ts +30 -0
- package/dist/blast/blast-cli.d.ts.map +1 -0
- package/dist/blast/blast-cli.js +163 -0
- package/dist/blast/blast-cli.js.map +1 -0
- package/dist/blast/blast.d.ts +119 -0
- package/dist/blast/blast.d.ts.map +1 -0
- package/dist/blast/blast.js +383 -0
- package/dist/blast/blast.js.map +1 -0
- package/dist/blast/diff.d.ts +53 -0
- package/dist/blast/diff.d.ts.map +1 -0
- package/dist/blast/diff.js +193 -0
- package/dist/blast/diff.js.map +1 -0
- package/dist/blast/modules.d.ts +33 -0
- package/dist/blast/modules.d.ts.map +1 -0
- package/dist/blast/modules.js +83 -0
- package/dist/blast/modules.js.map +1 -0
- package/dist/blast/name.d.ts +61 -0
- package/dist/blast/name.d.ts.map +1 -0
- package/dist/blast/name.js +233 -0
- package/dist/blast/name.js.map +1 -0
- package/dist/blast/render.d.ts +37 -0
- package/dist/blast/render.d.ts.map +1 -0
- package/dist/blast/render.js +300 -0
- package/dist/blast/render.js.map +1 -0
- package/dist/blast/viz.d.ts +17 -0
- package/dist/blast/viz.d.ts.map +1 -0
- package/dist/blast/viz.js +324 -0
- package/dist/blast/viz.js.map +1 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +18 -2
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +45 -15
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/state.d.ts +5 -0
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-picker.d.ts +44 -5
- package/dist/cli-picker.d.ts.map +1 -1
- package/dist/cli-picker.js +73 -26
- package/dist/cli-picker.js.map +1 -1
- package/dist/cli.js +270 -14
- package/dist/cli.js.map +1 -1
- package/dist/context/build.d.ts +8 -0
- package/dist/context/build.d.ts.map +1 -1
- package/dist/context/build.js +57 -9
- package/dist/context/build.js.map +1 -1
- package/dist/context/check.d.ts.map +1 -1
- package/dist/context/check.js +7 -6
- package/dist/context/check.js.map +1 -1
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +9 -2
- package/dist/context/node-file.js.map +1 -1
- package/dist/graph/bindings.d.ts.map +1 -1
- package/dist/graph/bindings.js +171 -8
- package/dist/graph/bindings.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +36 -16
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/check.d.ts +4 -0
- package/dist/graph/check.d.ts.map +1 -1
- package/dist/graph/check.js +8 -1
- package/dist/graph/check.js.map +1 -1
- package/dist/graph/container.d.ts +63 -0
- package/dist/graph/container.d.ts.map +1 -0
- package/dist/graph/container.js +185 -0
- package/dist/graph/container.js.map +1 -0
- package/dist/graph/enrich.d.ts +18 -0
- package/dist/graph/enrich.d.ts.map +1 -1
- package/dist/graph/enrich.js +55 -2
- package/dist/graph/enrich.js.map +1 -1
- package/dist/graph/extract.d.ts +3 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +215 -8
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/generic.d.ts +34 -1
- package/dist/graph/generic.d.ts.map +1 -1
- package/dist/graph/generic.js +152 -3
- package/dist/graph/generic.js.map +1 -1
- package/dist/graph/queries/clojure.scm +58 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +132 -2
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/scopes.d.ts +2 -2
- package/dist/graph/scopes.d.ts.map +1 -1
- package/dist/graph/scopes.js +8 -6
- package/dist/graph/scopes.js.map +1 -1
- package/dist/graph/source-files.d.ts +13 -4
- package/dist/graph/source-files.d.ts.map +1 -1
- package/dist/graph/source-files.js +35 -12
- package/dist/graph/source-files.js.map +1 -1
- package/dist/graph/types.d.ts +1 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/graph/workspace-cli.d.ts +2 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -1
- package/dist/graph/workspace-cli.js +10 -4
- package/dist/graph/workspace-cli.js.map +1 -1
- package/dist/graph/workspace.d.ts +11 -6
- package/dist/graph/workspace.d.ts.map +1 -1
- package/dist/graph/workspace.js +24 -13
- package/dist/graph/workspace.js.map +1 -1
- package/dist/graph/write.d.ts.map +1 -1
- package/dist/graph/write.js +25 -2
- package/dist/graph/write.js.map +1 -1
- package/dist/hosts/antigravity.d.ts +7 -0
- package/dist/hosts/antigravity.d.ts.map +1 -0
- package/dist/hosts/antigravity.js +42 -0
- package/dist/hosts/antigravity.js.map +1 -0
- package/dist/hosts/init.d.ts.map +1 -1
- package/dist/hosts/init.js +6 -1
- package/dist/hosts/init.js.map +1 -1
- package/dist/hosts/mcp-config.d.ts.map +1 -1
- package/dist/hosts/mcp-config.js +7 -0
- package/dist/hosts/mcp-config.js.map +1 -1
- package/dist/hosts/plan.d.ts +1 -1
- package/dist/hosts/plan.d.ts.map +1 -1
- package/dist/hosts/plan.js +2 -0
- package/dist/hosts/plan.js.map +1 -1
- package/dist/hosts/registry.d.ts.map +1 -1
- package/dist/hosts/registry.js +13 -0
- package/dist/hosts/registry.js.map +1 -1
- package/dist/ingest/fs.d.ts +9 -2
- package/dist/ingest/fs.d.ts.map +1 -1
- package/dist/ingest/fs.js +100 -16
- package/dist/ingest/fs.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/telemetry/contract.d.ts +90 -0
- package/dist/telemetry/contract.d.ts.map +1 -0
- package/dist/telemetry/contract.js +203 -0
- package/dist/telemetry/contract.js.map +1 -0
- package/dist/telemetry/flush.d.ts +21 -0
- package/dist/telemetry/flush.d.ts.map +1 -0
- package/dist/telemetry/flush.js +84 -0
- package/dist/telemetry/flush.js.map +1 -0
- package/dist/telemetry/gate.d.ts +16 -0
- package/dist/telemetry/gate.d.ts.map +1 -0
- package/dist/telemetry/gate.js +64 -0
- package/dist/telemetry/gate.js.map +1 -0
- package/dist/telemetry/identity.d.ts +33 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/telemetry/identity.js +80 -0
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/index.d.ts +18 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +16 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/key.d.ts +21 -0
- package/dist/telemetry/key.d.ts.map +1 -0
- package/dist/telemetry/key.js +49 -0
- package/dist/telemetry/key.js.map +1 -0
- package/dist/telemetry/notice.d.ts +19 -0
- package/dist/telemetry/notice.d.ts.map +1 -0
- package/dist/telemetry/notice.js +90 -0
- package/dist/telemetry/notice.js.map +1 -0
- package/dist/telemetry/queue.d.ts +35 -0
- package/dist/telemetry/queue.d.ts.map +1 -0
- package/dist/telemetry/queue.js +162 -0
- package/dist/telemetry/queue.js.map +1 -0
- package/dist/telemetry/send.d.ts +19 -0
- package/dist/telemetry/send.d.ts.map +1 -0
- package/dist/telemetry/send.js +84 -0
- package/dist/telemetry/send.js.map +1 -0
- package/dist/telemetry/sessions.d.ts +8 -0
- package/dist/telemetry/sessions.d.ts.map +1 -0
- package/dist/telemetry/sessions.js +81 -0
- package/dist/telemetry/sessions.js.map +1 -0
- package/dist/telemetry/track.d.ts +43 -0
- package/dist/telemetry/track.d.ts.map +1 -0
- package/dist/telemetry/track.js +108 -0
- package/dist/telemetry/track.js.map +1 -0
- package/dist/upkeep-run.d.ts +15 -0
- package/dist/upkeep-run.d.ts.map +1 -0
- package/dist/upkeep-run.js +60 -0
- package/dist/upkeep-run.js.map +1 -0
- package/dist/upkeep.d.ts +114 -0
- package/dist/upkeep.d.ts.map +1 -0
- package/dist/upkeep.js +232 -0
- package/dist/upkeep.js.map +1 -0
- package/dist/util/num.d.ts +3 -0
- package/dist/util/num.d.ts.map +1 -0
- package/dist/util/num.js +20 -0
- package/dist/util/num.js.map +1 -0
- package/dist/util/state.d.ts +11 -4
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +9 -0
- package/dist/util/state.js.map +1 -1
- package/dist/viewer/app.js +1 -1
- package/dist/viewer/index.html +1 -0
- package/dist/viewer/style.css +23 -2
- package/dist/viz/assemble.d.ts +33 -0
- package/dist/viz/assemble.d.ts.map +1 -1
- package/dist/viz/assemble.js.map +1 -1
- package/dist/viz/export.d.ts +39 -0
- package/dist/viz/export.d.ts.map +1 -0
- package/dist/viz/export.js +98 -0
- package/dist/viz/export.js.map +1 -0
- package/package.json +6 -5
- package/scripts/stamp-telemetry-key.mjs +53 -0
package/dist/upkeep.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-maintenance: keeping an installed graft, and the wiring it wrote, current.
|
|
3
|
+
*
|
|
4
|
+
* Two independent kinds of staleness, both invisible to the user today:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Binary staleness** — they installed once and never upgraded. `graft
|
|
7
|
+
* version` would tell them, but nobody runs it. So we keep a cached,
|
|
8
|
+
* machine-global registry answer and let every entry point surface a
|
|
9
|
+
* one-line nudge from it.
|
|
10
|
+
*
|
|
11
|
+
* 2. **Wiring staleness** — `graft init` copies hooks, shims, skill text and
|
|
12
|
+
* rule files INTO the repo. `npm i -g` replaces the binary but touches none
|
|
13
|
+
* of them, so a repo wired by 0.7 keeps 0.7's prompts and 0.7's hook
|
|
14
|
+
* timeouts forever (see the comment on `promptAskTimeout`, which exists
|
|
15
|
+
* only to work around exactly this). A version stamp written next to the
|
|
16
|
+
* graph lets any entry point notice the skew and re-run the writes.
|
|
17
|
+
*
|
|
18
|
+
* Everything here is fail-soft by construction: it runs inside hooks and inside
|
|
19
|
+
* the MCP server's boot path, where a throw is a broken session, and it must
|
|
20
|
+
* never block on the network — the registry is only ever read from cache, and
|
|
21
|
+
* the refresh happens in a detached child.
|
|
22
|
+
*
|
|
23
|
+
* Called from all three hosts' entry points so no editor is left out:
|
|
24
|
+
* • Claude Code — `session-start` hook (src/claude/hooks.ts)
|
|
25
|
+
* • Cursor/Codex — MCP server boot (src/mcp/server.ts), and any CLI command
|
|
26
|
+
*/
|
|
27
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
28
|
+
import { spawn } from 'node:child_process';
|
|
29
|
+
import { join } from 'node:path';
|
|
30
|
+
import { homedir } from 'node:os';
|
|
31
|
+
import { readJson, writeJsonAtomic, cacheDir } from './util/state.js';
|
|
32
|
+
import { HOSTS } from './hosts/registry.js';
|
|
33
|
+
import { START } from './hosts/sections.js';
|
|
34
|
+
import { getNpmViewVersion, readCurrentVersion } from './cli-meta.js';
|
|
35
|
+
import { graftCliPath } from './claude/paths.js';
|
|
36
|
+
/**
|
|
37
|
+
* The version of the graft package this code was loaded from.
|
|
38
|
+
*
|
|
39
|
+
* Resolved from *this* module rather than the caller's: `readCurrentVersion`
|
|
40
|
+
* looks one level up from the module URL it's given, which lands on the package
|
|
41
|
+
* root for `dist/upkeep.js` but misses entirely for `dist/claude/hooks.js` and
|
|
42
|
+
* `dist/mcp/server.js`. Every caller asking here instead of passing its own
|
|
43
|
+
* `import.meta.url` is what keeps the hook and the MCP server from reading
|
|
44
|
+
* `0.0.0` and re-initing on every single session.
|
|
45
|
+
*/
|
|
46
|
+
export function runningVersion() {
|
|
47
|
+
try {
|
|
48
|
+
return readCurrentVersion(import.meta.url);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return '0.0.0';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** How long a registry answer is considered current. A day: graft ships far less
|
|
55
|
+
* often than that, and this is a nudge, not a security update. */
|
|
56
|
+
export const UPDATE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
57
|
+
/* -------------------------------------------------------------------------- */
|
|
58
|
+
/* version comparison */
|
|
59
|
+
/* -------------------------------------------------------------------------- */
|
|
60
|
+
/** Numeric-dotted compare of the release part only (`1.2.3-beta.1` → `1.2.3`).
|
|
61
|
+
* Prerelease ordering doesn't matter here: the only question either caller asks
|
|
62
|
+
* is "is the thing on npm ahead of what's on disk", and a prerelease that
|
|
63
|
+
* compares equal simply produces no nudge. */
|
|
64
|
+
export function compareVersions(a, b) {
|
|
65
|
+
const parts = (v) => String(v).split('-')[0].split('.').map((n) => Number(n) || 0);
|
|
66
|
+
const pa = parts(a);
|
|
67
|
+
const pb = parts(b);
|
|
68
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
69
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
70
|
+
if (d !== 0)
|
|
71
|
+
return d < 0 ? -1 : 1;
|
|
72
|
+
}
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
export function isNewer(candidate, current) {
|
|
76
|
+
if (!candidate)
|
|
77
|
+
return false;
|
|
78
|
+
return compareVersions(candidate, current) > 0;
|
|
79
|
+
}
|
|
80
|
+
/** Machine-global, not per-repo: "what's the latest graft" is one fact, and a
|
|
81
|
+
* dev with twelve repos should cost the registry one request a day, not twelve. */
|
|
82
|
+
export function updateCachePath(home = homedir()) {
|
|
83
|
+
return join(home, '.graft', 'update-check.json');
|
|
84
|
+
}
|
|
85
|
+
export function readUpdateCache(home) {
|
|
86
|
+
return readJson(updateCachePath(home));
|
|
87
|
+
}
|
|
88
|
+
function writeUpdateCache(cache, home) {
|
|
89
|
+
try {
|
|
90
|
+
writeJsonAtomic(updateCachePath(home), cache);
|
|
91
|
+
}
|
|
92
|
+
catch { /* unwritable home — skip */ }
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The `graft _update-check` command body: hit the registry, store the answer.
|
|
96
|
+
* Runs in a detached child so nothing user-facing ever waits on the network.
|
|
97
|
+
*/
|
|
98
|
+
export function refreshUpdateCache(home, now = Date.now()) {
|
|
99
|
+
const res = getNpmViewVersion();
|
|
100
|
+
const cache = { latest: res.ok ? (res.version ?? null) : null, checkedAt: now };
|
|
101
|
+
writeUpdateCache(cache, home);
|
|
102
|
+
return cache;
|
|
103
|
+
}
|
|
104
|
+
/** True when the cached answer is missing or older than the TTL. */
|
|
105
|
+
export function needsRefresh(cache, now = Date.now()) {
|
|
106
|
+
return !cache || typeof cache.checkedAt !== 'number' || now - cache.checkedAt >= UPDATE_TTL_MS;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Kick off a background registry check if the cache has gone stale. Touches
|
|
110
|
+
* `checkedAt` first so concurrent callers (and a child that dies) don't spawn a
|
|
111
|
+
* fetch per invocation. Never waits, never throws.
|
|
112
|
+
*
|
|
113
|
+
* Only called from long-lived or already-slow contexts (a CLI command, MCP
|
|
114
|
+
* boot) — never from a hook, which reads the cache and nothing else.
|
|
115
|
+
*/
|
|
116
|
+
export function maybeRefreshInBackground(home, now = Date.now()) {
|
|
117
|
+
const cache = readUpdateCache(home);
|
|
118
|
+
if (!needsRefresh(cache, now))
|
|
119
|
+
return false;
|
|
120
|
+
writeUpdateCache({ latest: cache?.latest ?? null, checkedAt: now }, home);
|
|
121
|
+
try {
|
|
122
|
+
const child = spawn(process.execPath, [graftCliPath(), '_update-check'], {
|
|
123
|
+
detached: true,
|
|
124
|
+
stdio: 'ignore',
|
|
125
|
+
});
|
|
126
|
+
child.unref();
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false; // no spawn (sandbox, ENOMEM) — the nudge just uses the old cache
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** One line, or nothing. Nothing is the common case — don't spend context on
|
|
134
|
+
* "you're up to date". */
|
|
135
|
+
export function formatUpdateNudge(current, latest) {
|
|
136
|
+
if (!isNewer(latest, current))
|
|
137
|
+
return null;
|
|
138
|
+
return `⬆ graft ${current} → ${latest} available: run \`npm i -g @nanonets/graft@latest\` (restart your agent after).`;
|
|
139
|
+
}
|
|
140
|
+
export const DEFAULT_WIRING_OPTS = { global: true, mcp: true, hooks: true };
|
|
141
|
+
/** An older stamp has no `opts`; a plain `graft init` wired everything. */
|
|
142
|
+
export function wiringOpts(stamp) {
|
|
143
|
+
return { ...DEFAULT_WIRING_OPTS, ...(stamp?.opts ?? {}) };
|
|
144
|
+
}
|
|
145
|
+
/** Under `graft/.cache/`, beside the other derived state: git-ignored, per-clone,
|
|
146
|
+
* and cheap to lose — a missing stamp just means one idempotent refresh. */
|
|
147
|
+
export function stampPath(repo) {
|
|
148
|
+
return join(cacheDir(repo), 'wiring-stamp.json');
|
|
149
|
+
}
|
|
150
|
+
export function readStamp(repo) {
|
|
151
|
+
return readJson(stampPath(repo));
|
|
152
|
+
}
|
|
153
|
+
export function writeStamp(repo, version, hosts, opts = {}, at = new Date().toISOString()) {
|
|
154
|
+
try {
|
|
155
|
+
writeJsonAtomic(stampPath(repo), {
|
|
156
|
+
version,
|
|
157
|
+
hosts: [...hosts].sort(),
|
|
158
|
+
opts: { ...DEFAULT_WIRING_OPTS, ...opts },
|
|
159
|
+
at,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch { /* unwritable graft/ — a refresh will just be retried next session */ }
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Which agents this repo is *already* wired for, read off disk rather than
|
|
166
|
+
* re-detected. Detection answers "which editors does this machine have"; for a
|
|
167
|
+
* refresh we need "which files did a previous init actually write" — otherwise
|
|
168
|
+
* installing Windsurf once would silently add graft rules to every repo.
|
|
169
|
+
*/
|
|
170
|
+
export function wiredHostIds(repo) {
|
|
171
|
+
const ids = [];
|
|
172
|
+
if (existsSync(join(repo, '.claude', 'helpers', 'graft-hooks.cjs')))
|
|
173
|
+
ids.push('claude');
|
|
174
|
+
for (const host of HOSTS) {
|
|
175
|
+
const path = join(repo, host.relPath);
|
|
176
|
+
if (!existsSync(path))
|
|
177
|
+
continue;
|
|
178
|
+
// A shared file (AGENTS.md, GEMINI.md) counts only if graft's fenced section
|
|
179
|
+
// is in it — the user may own the file for entirely unrelated reasons.
|
|
180
|
+
if (host.kind === 'section') {
|
|
181
|
+
try {
|
|
182
|
+
if (!readFileSync(path, 'utf8').includes(START))
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
ids.push(host.id);
|
|
190
|
+
}
|
|
191
|
+
return ids;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Re-run init's writes when the stamp and the running binary disagree.
|
|
195
|
+
*
|
|
196
|
+
* Deliberately narrow: it refreshes the hosts already wired, replays the flags
|
|
197
|
+
* that init was given, never builds the graph (this runs at session start — a
|
|
198
|
+
* rebuild there would stall the agent's first turn), and no-ops when the repo has
|
|
199
|
+
* no graft wiring at all.
|
|
200
|
+
*/
|
|
201
|
+
export function reconcileWiring(repo, current, deps) {
|
|
202
|
+
try {
|
|
203
|
+
const stamp = readStamp(repo);
|
|
204
|
+
if (stamp && stamp.version === current)
|
|
205
|
+
return null;
|
|
206
|
+
// The stamp is the record of *intent* (what the picker chose); disk is the
|
|
207
|
+
// fallback for repos wired before stamps existed. Union, not just disk:
|
|
208
|
+
// otherwise a host whose rule file went missing — deleted by hand, lost to a
|
|
209
|
+
// merge, or clobbered by another tool — is silently dropped from every future
|
|
210
|
+
// refresh, and that file is precisely what a refresh exists to restore.
|
|
211
|
+
const onDisk = (deps.wired ?? wiredHostIds)(repo);
|
|
212
|
+
const hosts = [...new Set([...(stamp?.hosts ?? []), ...onDisk])].sort();
|
|
213
|
+
if (hosts.length === 0)
|
|
214
|
+
return null; // never wired here — not our business
|
|
215
|
+
const opts = wiringOpts(stamp);
|
|
216
|
+
deps.rewrite(repo, hosts, opts);
|
|
217
|
+
writeStamp(repo, current, hosts, opts);
|
|
218
|
+
return { from: stamp?.version ?? 'unwired', to: current, hosts, global: opts.global };
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return null; // a refresh is an optimization; never fail the caller over it
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export function formatWiringRefresh(r) {
|
|
225
|
+
if (!r)
|
|
226
|
+
return null;
|
|
227
|
+
// Name the out-of-repo writes explicitly: those are machine-wide and shared by
|
|
228
|
+
// every repo, so a user seeing this line should not have to guess what moved.
|
|
229
|
+
const scope = r.global && r.hosts.includes('agents') ? " (including this machine's ~/.codex config)" : '';
|
|
230
|
+
return `· graft refreshed this repo's agent wiring${scope} (written by ${r.from}, now ${r.to}): ${r.hosts.join(', ')}.`;
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=upkeep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upkeep.js","sourceRoot":"","sources":["../src/upkeep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"num.d.ts","sourceRoot":"","sources":["../../src/util/num.ts"],"names":[],"mappings":"AAgBA,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C"}
|
package/dist/util/num.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Number formatting for text graft emits.
|
|
3
|
+
*
|
|
4
|
+
* `toLocaleString()` with no locale follows the MACHINE's locale, which is the
|
|
5
|
+
* wrong authority for two of graft's outputs. The savings lines are read by an
|
|
6
|
+
* LLM and explicitly ask it to sum them across calls; on a pt-BR/de-DE box the
|
|
7
|
+
* bare call renders 1990 as "1.990", which an agent reads as 1.99 — so the
|
|
8
|
+
* headline "tokens saved this turn" total comes out ~1000× low. The graph's own
|
|
9
|
+
* stats are compared across machines and CI, where a separator that moves with
|
|
10
|
+
* the host makes two identical runs look different.
|
|
11
|
+
*
|
|
12
|
+
* One pinned locale for both: the output is a data interchange format that
|
|
13
|
+
* happens to be human-readable, not localized UI.
|
|
14
|
+
*/
|
|
15
|
+
const FORMATTER = new Intl.NumberFormat("en-US");
|
|
16
|
+
/** Thousands-separated integer, identical on every machine. */
|
|
17
|
+
export function formatCount(n) {
|
|
18
|
+
return FORMATTER.format(Math.round(n));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=num.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"num.js","sourceRoot":"","sources":["../../src/util/num.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;AAEjD,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
package/dist/util/state.d.ts
CHANGED
|
@@ -32,16 +32,18 @@ export declare function writeJsonAtomic(p: string, value: unknown, compact?: boo
|
|
|
32
32
|
export declare function readStats(d: string): Stats | null;
|
|
33
33
|
export declare function writeStats(d: string, s: Stats): void;
|
|
34
34
|
/**
|
|
35
|
-
* Persisted per-repo build configuration
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* skipped), so a repo that never used the flag is entirely unaffected.
|
|
35
|
+
* Persisted per-repo build configuration. Explicit CLI choices live here so
|
|
36
|
+
* later no-flag builds and automatic refreshes enumerate the same file set.
|
|
37
|
+
* Missing fields always retain backwards-compatible defaults.
|
|
39
38
|
*/
|
|
40
39
|
export interface BuildConfig {
|
|
41
40
|
/** SKIP_DIRS names to include in this repo's walks, persisted so a LATER
|
|
42
41
|
* no-flag build — and the fingerprint/refresh path, which never sees CLI
|
|
43
42
|
* flags at all — behave identically to the invocation that set it. */
|
|
44
43
|
includeDirs?: string[];
|
|
44
|
+
/** Whether initialized Git submodules are folded into this repo's graph.
|
|
45
|
+
* Absent/false keeps the historical boundary at the superproject. */
|
|
46
|
+
followSubmodules?: boolean;
|
|
45
47
|
}
|
|
46
48
|
/** Local, Git-ignored repository configuration. Kept outside generated
|
|
47
49
|
* `graft/` output so deleting/replacing that cache, workspace federation, and
|
|
@@ -50,12 +52,17 @@ export declare const BUILD_CONFIG_DIR = ".graft";
|
|
|
50
52
|
export declare function buildConfigPath(d: string): string;
|
|
51
53
|
export declare function readBuildConfig(d: string): BuildConfig | null;
|
|
52
54
|
export declare function writeBuildConfig(d: string, c: BuildConfig): void;
|
|
55
|
+
/** Merge explicit CLI choices into the existing local config, so updating one
|
|
56
|
+
* persisted build option cannot erase another. */
|
|
57
|
+
export declare function patchBuildConfig(d: string, patch: BuildConfig): void;
|
|
53
58
|
/** The persisted `--include-dir` override for repo `d`, as a Set — `undefined`
|
|
54
59
|
* when nothing was ever persisted (or the persisted list is empty), which every
|
|
55
60
|
* `shouldSkipDir`/`walkDir` caller treats as "today's default behavior". Shared
|
|
56
61
|
* by every walkDir-driven entry point (source-files.ts, scopes.ts) so a build,
|
|
57
62
|
* a later no-flag rebuild, and the hooks/refresh path all agree. */
|
|
58
63
|
export declare function readIncludeDirs(d: string): Set<string> | undefined;
|
|
64
|
+
/** Missing and explicit false both retain the backwards-compatible default. */
|
|
65
|
+
export declare function readFollowSubmodules(d: string): boolean;
|
|
59
66
|
export declare function patchStats(d: string, patch: Partial<Stats>): Stats;
|
|
60
67
|
export declare function acquireLock(d: string): boolean;
|
|
61
68
|
export declare function releaseLock(d: string): void;
|
package/dist/util/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/util/state.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClD;AAED,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,wBAAgB,UAAU,IAAI,KAAK,CAGlC;AAID,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAgD;AAGpG,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAE/C;AACD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,UAAQ,GAAG,IAAI,CAUhF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAA0C;AAC5F,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAG,IAAI,CAAsC;AAE3F
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/util/state.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClD;AAED,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,wBAAgB,UAAU,IAAI,KAAK,CAGlC;AAID,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAgD;AAGpG,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAE/C;AACD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,UAAQ,GAAG,IAAI,CAUhF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAA0C;AAC5F,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAG,IAAI,CAAsC;AAE3F;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;0EAEsE;IACtE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;yEACqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;0EAE0E;AAC1E,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAqD;AAkBvG,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAsD;AACpH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,GAAG,IAAI,CAGhE;AAED;kDACkD;AAClD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAEpE;AAED;;;;oEAIoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAGlE;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEvD;AAGD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAIlE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE9C;AACD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgBpD;AACD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEjD"}
|
package/dist/util/state.js
CHANGED
|
@@ -90,6 +90,11 @@ export function writeBuildConfig(d, c) {
|
|
|
90
90
|
ensureBuildConfigIgnored(d);
|
|
91
91
|
writeJsonAtomic(buildConfigPath(d), c);
|
|
92
92
|
}
|
|
93
|
+
/** Merge explicit CLI choices into the existing local config, so updating one
|
|
94
|
+
* persisted build option cannot erase another. */
|
|
95
|
+
export function patchBuildConfig(d, patch) {
|
|
96
|
+
writeBuildConfig(d, { ...(readBuildConfig(d) ?? {}), ...patch });
|
|
97
|
+
}
|
|
93
98
|
/** The persisted `--include-dir` override for repo `d`, as a Set — `undefined`
|
|
94
99
|
* when nothing was ever persisted (or the persisted list is empty), which every
|
|
95
100
|
* `shouldSkipDir`/`walkDir` caller treats as "today's default behavior". Shared
|
|
@@ -99,6 +104,10 @@ export function readIncludeDirs(d) {
|
|
|
99
104
|
const dirs = readBuildConfig(d)?.includeDirs;
|
|
100
105
|
return dirs && dirs.length ? new Set(dirs) : undefined;
|
|
101
106
|
}
|
|
107
|
+
/** Missing and explicit false both retain the backwards-compatible default. */
|
|
108
|
+
export function readFollowSubmodules(d) {
|
|
109
|
+
return readBuildConfig(d)?.followSubmodules === true;
|
|
110
|
+
}
|
|
102
111
|
// Best-effort read-modify-write; not atomic across concurrent processes, but acceptable
|
|
103
112
|
// for episodic hook writes (worst case is a lost update, not corruption).
|
|
104
113
|
export function patchStats(d, patch) {
|
package/dist/util/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/util/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/F,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAS1C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;QAC9E,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClF,CAAC;AAED,MAAM,SAAS,GAAG,YAAY,CAAC;AAE/B,MAAM,UAAU,QAAQ,CAAC,UAAkB,IAAY,OAAO,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpG,SAAS,SAAS,CAAC,CAAS,IAAY,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AAEjF,MAAM,UAAU,QAAQ,CAAI,CAAS;IACnC,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAM,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AACjF,CAAC;AACD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,KAAc,EAAE,OAAO,GAAG,KAAK;IACxE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,CAAC;QACH,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACrF,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC;YAAC,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,4BAA4B,CAAC,CAAC;QAC5E,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,IAAkB,OAAO,QAAQ,CAAQ,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5F,MAAM,UAAU,UAAU,CAAC,CAAS,EAAE,CAAQ,IAAU,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/util/state.ts"],"names":[],"mappings":"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"}
|
package/dist/viewer/app.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var se={part_of:"structure",contains:"structure",uses:"dependency",depends_on:"dependency",calls:"dependency",imports:"dependency",produces:"dependency",configures:"dependency",validates:"dependency",extends:"contract",implements:"contract",references:"association"};function Y(t){return se[t]??"association"}var kt={structure:85,dependency:145,contract:150,association:185};function J(t){return Y(t)==="structure"?"part of":t==="calls"||t==="uses"||t==="depends_on"||t==="imports"?"uses":t.replace(/_/g," ")}var bt={"part of":"where does this live? (contains, part of)",uses:"what breaks if the target changes? (calls, uses, depends on, imports)",produces:"where does this output come from?",configures:"what changes its behavior without a code change?",validates:"what checks or judges this? (tests, drift checks, scoring)",extends:"what contract must this honor? (inheritance)",implements:"what contract must this honor? (interface)",references:"mentioned but never called \u2014 possible dead coupling"},ae={system:"--sys",concept:"--con",file:"--fil",api:"--api"},le={file:"--k-file",class:"--k-class",function:"--k-fn",method:"--k-method",interface:"--k-iface",type:"--k-type",enum:"--k-enum"};function D(t,e){return(t==="code"?le:ae)[e]??"--edge"}function M(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}async function _t(){return await(await fetch("/api/context-graph")).json()}async function Et(){let t=await fetch("/api/code-graph");if(!t.ok)return null;let e=await t.json(),n=e.nodes.map(o=>({id:o.id,name:o.name,type:o.kind,summary:o.summary??o.signature??"",sources:[`${o.path} \xB7 ${o.span}`]})),i=new Set(n.map(o=>o.id)),r=e.edges.filter(o=>i.has(o.source)&&i.has(o.target)).map(o=>({source:o.source,target:o.target,relation:o.relation,confidence:o.confidence}));return{meta:{nodeCount:n.length,edgeCount:r.length},nodes:n,edges:r}}function Mt(t){let e=new EventSource("/events");e.onmessage=n=>{n.data==="change"&&t()}}function ot(t,e){var n,i=1;t==null&&(t=0),e==null&&(e=0);function r(){var o,a=n.length,p,l=0,s=0;for(o=0;o<a;++o)p=n[o],l+=p.x,s+=p.y;for(l=(l/a-t)*i,s=(s/a-e)*i,o=0;o<a;++o)p=n[o],p.x-=l,p.y-=s}return r.initialize=function(o){n=o},r.x=function(o){return arguments.length?(t=+o,r):t},r.y=function(o){return arguments.length?(e=+o,r):e},r.strength=function(o){return arguments.length?(i=+o,r):i},r}function Ct(t){let e=+this._x.call(null,t),n=+this._y.call(null,t);return Nt(this.cover(e,n),e,n,t)}function Nt(t,e,n,i){if(isNaN(e)||isNaN(n))return t;var r,o=t._root,a={data:i},p=t._x0,l=t._y0,s=t._x1,c=t._y1,m,u,f,v,h,d,g,y;if(!o)return t._root=a,t;for(;o.length;)if((h=e>=(m=(p+s)/2))?p=m:s=m,(d=n>=(u=(l+c)/2))?l=u:c=u,r=o,!(o=o[g=d<<1|h]))return r[g]=a,t;if(f=+t._x.call(null,o.data),v=+t._y.call(null,o.data),e===f&&n===v)return a.next=o,r?r[g]=a:t._root=a,t;do r=r?r[g]=new Array(4):t._root=new Array(4),(h=e>=(m=(p+s)/2))?p=m:s=m,(d=n>=(u=(l+c)/2))?l=u:c=u;while((g=d<<1|h)===(y=(v>=u)<<1|f>=m));return r[y]=o,r[g]=a,t}function St(t){var e,n,i=t.length,r,o,a=new Array(i),p=new Array(i),l=1/0,s=1/0,c=-1/0,m=-1/0;for(n=0;n<i;++n)isNaN(r=+this._x.call(null,e=t[n]))||isNaN(o=+this._y.call(null,e))||(a[n]=r,p[n]=o,r<l&&(l=r),r>c&&(c=r),o<s&&(s=o),o>m&&(m=o));if(l>c||s>m)return this;for(this.cover(l,s).cover(c,m),n=0;n<i;++n)Nt(this,a[n],p[n],t[n]);return this}function Lt(t,e){if(isNaN(t=+t)||isNaN(e=+e))return this;var n=this._x0,i=this._y0,r=this._x1,o=this._y1;if(isNaN(n))r=(n=Math.floor(t))+1,o=(i=Math.floor(e))+1;else{for(var a=r-n||1,p=this._root,l,s;n>t||t>=r||i>e||e>=o;)switch(s=(e<i)<<1|t<n,l=new Array(4),l[s]=p,p=l,a*=2,s){case 0:r=n+a,o=i+a;break;case 1:n=r-a,o=i+a;break;case 2:r=n+a,i=o-a;break;case 3:n=r-a,i=o-a;break}this._root&&this._root.length&&(this._root=p)}return this._x0=n,this._y0=i,this._x1=r,this._y1=o,this}function Tt(){var t=[];return this.visit(function(e){if(!e.length)do t.push(e.data);while(e=e.next)}),t}function At(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]}function S(t,e,n,i,r){this.node=t,this.x0=e,this.y0=n,this.x1=i,this.y1=r}function Vt(t,e,n){var i,r=this._x0,o=this._y0,a,p,l,s,c=this._x1,m=this._y1,u=[],f=this._root,v,h;for(f&&u.push(new S(f,r,o,c,m)),n==null?n=1/0:(r=t-n,o=e-n,c=t+n,m=e+n,n*=n);v=u.pop();)if(!(!(f=v.node)||(a=v.x0)>c||(p=v.y0)>m||(l=v.x1)<r||(s=v.y1)<o))if(f.length){var d=(a+l)/2,g=(p+s)/2;u.push(new S(f[3],d,g,l,s),new S(f[2],a,g,d,s),new S(f[1],d,p,l,g),new S(f[0],a,p,d,g)),(h=(e>=g)<<1|t>=d)&&(v=u[u.length-1],u[u.length-1]=u[u.length-1-h],u[u.length-1-h]=v)}else{var y=t-+this._x.call(null,f.data),w=e-+this._y.call(null,f.data),x=y*y+w*w;if(x<n){var _=Math.sqrt(n=x);r=t-_,o=e-_,c=t+_,m=e+_,i=f.data}}return i}function $t(t){if(isNaN(c=+this._x.call(null,t))||isNaN(m=+this._y.call(null,t)))return this;var e,n=this._root,i,r,o,a=this._x0,p=this._y0,l=this._x1,s=this._y1,c,m,u,f,v,h,d,g;if(!n)return this;if(n.length)for(;;){if((v=c>=(u=(a+l)/2))?a=u:l=u,(h=m>=(f=(p+s)/2))?p=f:s=f,e=n,!(n=n[d=h<<1|v]))return this;if(!n.length)break;(e[d+1&3]||e[d+2&3]||e[d+3&3])&&(i=e,g=d)}for(;n.data!==t;)if(r=n,!(n=n.next))return this;return(o=n.next)&&delete n.next,r?(o?r.next=o:delete r.next,this):e?(o?e[d]=o:delete e[d],(n=e[0]||e[1]||e[2]||e[3])&&n===(e[3]||e[2]||e[1]||e[0])&&!n.length&&(i?i[g]=n:this._root=n),this):(this._root=o,this)}function zt(t){for(var e=0,n=t.length;e<n;++e)this.remove(t[e]);return this}function Gt(){return this._root}function Ht(){var t=0;return this.visit(function(e){if(!e.length)do++t;while(e=e.next)}),t}function It(t){var e=[],n,i=this._root,r,o,a,p,l;for(i&&e.push(new S(i,this._x0,this._y0,this._x1,this._y1));n=e.pop();)if(!t(i=n.node,o=n.x0,a=n.y0,p=n.x1,l=n.y1)&&i.length){var s=(o+p)/2,c=(a+l)/2;(r=i[3])&&e.push(new S(r,s,c,p,l)),(r=i[2])&&e.push(new S(r,o,c,s,l)),(r=i[1])&&e.push(new S(r,s,a,p,c)),(r=i[0])&&e.push(new S(r,o,a,s,c))}return this}function Rt(t){var e=[],n=[],i;for(this._root&&e.push(new S(this._root,this._x0,this._y0,this._x1,this._y1));i=e.pop();){var r=i.node;if(r.length){var o,a=i.x0,p=i.y0,l=i.x1,s=i.y1,c=(a+l)/2,m=(p+s)/2;(o=r[0])&&e.push(new S(o,a,p,c,m)),(o=r[1])&&e.push(new S(o,c,p,l,m)),(o=r[2])&&e.push(new S(o,a,m,c,s)),(o=r[3])&&e.push(new S(o,c,m,l,s))}n.push(i)}for(;i=n.pop();)t(i.node,i.x0,i.y0,i.x1,i.y1);return this}function Dt(t){return t[0]}function Ot(t){return arguments.length?(this._x=t,this):this._x}function Bt(t){return t[1]}function jt(t){return arguments.length?(this._y=t,this):this._y}function B(t,e,n){var i=new st(e??Dt,n??Bt,NaN,NaN,NaN,NaN);return t==null?i:i.addAll(t)}function st(t,e,n,i,r,o){this._x=t,this._y=e,this._x0=n,this._y0=i,this._x1=r,this._y1=o,this._root=void 0}function Pt(t){for(var e={data:t.data},n=e;t=t.next;)n=n.next={data:t.data};return e}var A=B.prototype=st.prototype;A.copy=function(){var t=new st(this._x,this._y,this._x0,this._y0,this._x1,this._y1),e=this._root,n,i;if(!e)return t;if(!e.length)return t._root=Pt(e),t;for(n=[{source:e,target:t._root=new Array(4)}];e=n.pop();)for(var r=0;r<4;++r)(i=e.source[r])&&(i.length?n.push({source:i,target:e.target[r]=new Array(4)}):e.target[r]=Pt(i));return t};A.add=Ct;A.addAll=St;A.cover=Lt;A.data=Tt;A.extent=At;A.find=Vt;A.remove=$t;A.removeAll=zt;A.root=Gt;A.size=Ht;A.visit=It;A.visitAfter=Rt;A.x=Ot;A.y=jt;function G(t){return function(){return t}}function z(t){return(t()-.5)*1e-6}function ce(t){return t.x+t.vx}function ue(t){return t.y+t.vy}function at(t){var e,n,i,r=1,o=1;typeof t!="function"&&(t=G(t==null?1:+t));function a(){for(var s,c=e.length,m,u,f,v,h,d,g=0;g<o;++g)for(m=B(e,ce,ue).visitAfter(p),s=0;s<c;++s)u=e[s],h=n[u.index],d=h*h,f=u.x+u.vx,v=u.y+u.vy,m.visit(y);function y(w,x,_,T,V){var C=w.data,$=w.r,N=h+$;if(C){if(C.index>u.index){var I=f-C.x-C.vx,R=v-C.y-C.vy,H=I*I+R*R;H<N*N&&(I===0&&(I=z(i),H+=I*I),R===0&&(R=z(i),H+=R*R),H=(N-(H=Math.sqrt(H)))/H*r,u.vx+=(I*=H)*(N=($*=$)/(d+$)),u.vy+=(R*=H)*N,C.vx-=I*(N=1-N),C.vy-=R*N)}return}return x>f+N||T<f-N||_>v+N||V<v-N}}function p(s){if(s.data)return s.r=n[s.data.index];for(var c=s.r=0;c<4;++c)s[c]&&s[c].r>s.r&&(s.r=s[c].r)}function l(){if(e){var s,c=e.length,m;for(n=new Array(c),s=0;s<c;++s)m=e[s],n[m.index]=+t(m,s,e)}}return a.initialize=function(s,c){e=s,i=c,l()},a.iterations=function(s){return arguments.length?(o=+s,a):o},a.strength=function(s){return arguments.length?(r=+s,a):r},a.radius=function(s){return arguments.length?(t=typeof s=="function"?s:G(+s),l(),a):t},a}function de(t){return t.index}function Yt(t,e){var n=t.get(e);if(!n)throw new Error("node not found: "+e);return n}function lt(t){var e=de,n=m,i,r=G(30),o,a,p,l,s,c=1;t==null&&(t=[]);function m(d){return 1/Math.min(p[d.source.index],p[d.target.index])}function u(d){for(var g=0,y=t.length;g<c;++g)for(var w=0,x,_,T,V,C,$,N;w<y;++w)x=t[w],_=x.source,T=x.target,V=T.x+T.vx-_.x-_.vx||z(s),C=T.y+T.vy-_.y-_.vy||z(s),$=Math.sqrt(V*V+C*C),$=($-o[w])/$*d*i[w],V*=$,C*=$,T.vx-=V*(N=l[w]),T.vy-=C*N,_.vx+=V*(N=1-N),_.vy+=C*N}function f(){if(a){var d,g=a.length,y=t.length,w=new Map(a.map((_,T)=>[e(_,T,a),_])),x;for(d=0,p=new Array(g);d<y;++d)x=t[d],x.index=d,typeof x.source!="object"&&(x.source=Yt(w,x.source)),typeof x.target!="object"&&(x.target=Yt(w,x.target)),p[x.source.index]=(p[x.source.index]||0)+1,p[x.target.index]=(p[x.target.index]||0)+1;for(d=0,l=new Array(y);d<y;++d)x=t[d],l[d]=p[x.source.index]/(p[x.source.index]+p[x.target.index]);i=new Array(y),v(),o=new Array(y),h()}}function v(){if(a)for(var d=0,g=t.length;d<g;++d)i[d]=+n(t[d],d,t)}function h(){if(a)for(var d=0,g=t.length;d<g;++d)o[d]=+r(t[d],d,t)}return u.initialize=function(d,g){a=d,s=g,f()},u.links=function(d){return arguments.length?(t=d,f(),u):t},u.id=function(d){return arguments.length?(e=d,u):e},u.iterations=function(d){return arguments.length?(c=+d,u):c},u.strength=function(d){return arguments.length?(n=typeof d=="function"?d:G(+d),v(),u):n},u.distance=function(d){return arguments.length?(r=typeof d=="function"?d:G(+d),h(),u):r},u}var fe={value:()=>{}};function qt(){for(var t=0,e=arguments.length,n={},i;t<e;++t){if(!(i=arguments[t]+"")||i in n||/[\s.]/.test(i))throw new Error("illegal type: "+i);n[i]=[]}return new U(n)}function U(t){this._=t}function he(t,e){return t.trim().split(/^|\s+/).map(function(n){var i="",r=n.indexOf(".");if(r>=0&&(i=n.slice(r+1),n=n.slice(0,r)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:i}})}U.prototype=qt.prototype={constructor:U,on:function(t,e){var n=this._,i=he(t+"",n),r,o=-1,a=i.length;if(arguments.length<2){for(;++o<a;)if((r=(t=i[o]).type)&&(r=pe(n[r],t.name)))return r;return}if(e!=null&&typeof e!="function")throw new Error("invalid callback: "+e);for(;++o<a;)if(r=(t=i[o]).type)n[r]=Ft(n[r],t.name,e);else if(e==null)for(r in n)n[r]=Ft(n[r],t.name,null);return this},copy:function(){var t={},e=this._;for(var n in e)t[n]=e[n].slice();return new U(t)},call:function(t,e){if((r=arguments.length-2)>0)for(var n=new Array(r),i=0,r,o;i<r;++i)n[i]=arguments[i+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=this._[t],i=0,r=o.length;i<r;++i)o[i].value.apply(e,n)},apply:function(t,e,n){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var i=this._[t],r=0,o=i.length;r<o;++r)i[r].value.apply(e,n)}};function pe(t,e){for(var n=0,i=t.length,r;n<i;++n)if((r=t[n]).name===e)return r.value}function Ft(t,e,n){for(var i=0,r=t.length;i<r;++i)if(t[i].name===e){t[i]=fe,t=t.slice(0,i).concat(t.slice(i+1));break}return n!=null&&t.push({name:e,value:n}),t}var ct=qt;var F=0,X=0,W=0,Xt=1e3,tt,K,et=0,j=0,nt=0,Q=typeof performance=="object"&&performance.now?performance:Date,Kt=typeof window=="object"&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function ft(){return j||(Kt(ge),j=Q.now()+nt)}function ge(){j=0}function ut(){this._call=this._time=this._next=null}ut.prototype=rt.prototype={constructor:ut,restart:function(t,e,n){if(typeof t!="function")throw new TypeError("callback is not a function");n=(n==null?ft():+n)+(e==null?0:+e),!this._next&&K!==this&&(K?K._next=this:tt=this,K=this),this._call=t,this._time=n,dt()},stop:function(){this._call&&(this._call=null,this._time=1/0,dt())}};function rt(t,e,n){var i=new ut;return i.restart(t,e,n),i}function Qt(){ft(),++F;for(var t=tt,e;t;)(e=j-t._time)>=0&&t._call.call(void 0,e),t=t._next;--F}function Wt(){j=(et=Q.now())+nt,F=X=0;try{Qt()}finally{F=0,ve(),j=0}}function me(){var t=Q.now(),e=t-et;e>Xt&&(nt-=e,et=t)}function ve(){for(var t,e=tt,n,i=1/0;e;)e._call?(i>e._time&&(i=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:tt=n);K=t,dt(i)}function dt(t){if(!F){X&&(X=clearTimeout(X));var e=t-j;e>24?(t<1/0&&(X=setTimeout(Wt,t-Q.now()-nt)),W&&(W=clearInterval(W))):(W||(et=Q.now(),W=setInterval(me,Xt)),F=1,Kt(Wt))}}function Zt(){let t=1;return()=>(t=(1664525*t+1013904223)%4294967296)/4294967296}function Jt(t){return t.x}function Ut(t){return t.y}var ye=10,xe=Math.PI*(3-Math.sqrt(5));function ht(t){var e,n=1,i=.001,r=1-Math.pow(i,1/300),o=0,a=.6,p=new Map,l=rt(m),s=ct("tick","end"),c=Zt();t==null&&(t=[]);function m(){u(),s.call("tick",e),n<i&&(l.stop(),s.call("end",e))}function u(h){var d,g=t.length,y;h===void 0&&(h=1);for(var w=0;w<h;++w)for(n+=(o-n)*r,p.forEach(function(x){x(n)}),d=0;d<g;++d)y=t[d],y.fx==null?y.x+=y.vx*=a:(y.x=y.fx,y.vx=0),y.fy==null?y.y+=y.vy*=a:(y.y=y.fy,y.vy=0);return e}function f(){for(var h=0,d=t.length,g;h<d;++h){if(g=t[h],g.index=h,g.fx!=null&&(g.x=g.fx),g.fy!=null&&(g.y=g.fy),isNaN(g.x)||isNaN(g.y)){var y=ye*Math.sqrt(.5+h),w=h*xe;g.x=y*Math.cos(w),g.y=y*Math.sin(w)}(isNaN(g.vx)||isNaN(g.vy))&&(g.vx=g.vy=0)}}function v(h){return h.initialize&&h.initialize(t,c),h}return f(),e={tick:u,restart:function(){return l.restart(m),e},stop:function(){return l.stop(),e},nodes:function(h){return arguments.length?(t=h,f(),p.forEach(v),e):t},alpha:function(h){return arguments.length?(n=+h,e):n},alphaMin:function(h){return arguments.length?(i=+h,e):i},alphaDecay:function(h){return arguments.length?(r=+h,e):+r},alphaTarget:function(h){return arguments.length?(o=+h,e):o},velocityDecay:function(h){return arguments.length?(a=1-h,e):1-a},randomSource:function(h){return arguments.length?(c=h,p.forEach(v),e):c},force:function(h,d){return arguments.length>1?(d==null?p.delete(h):p.set(h,v(d)),e):p.get(h)},find:function(h,d,g){var y=0,w=t.length,x,_,T,V,C;for(g==null?g=1/0:g*=g,y=0;y<w;++y)V=t[y],x=h-V.x,_=d-V.y,T=x*x+_*_,T<g&&(C=V,g=T);return C},on:function(h,d){return arguments.length>1?(s.on(h,d),e):s.on(h)}}}function pt(){var t,e,n,i,r=G(-30),o,a=1,p=1/0,l=.81;function s(f){var v,h=t.length,d=B(t,Jt,Ut).visitAfter(m);for(i=f,v=0;v<h;++v)e=t[v],d.visit(u)}function c(){if(t){var f,v=t.length,h;for(o=new Array(v),f=0;f<v;++f)h=t[f],o[h.index]=+r(h,f,t)}}function m(f){var v=0,h,d,g=0,y,w,x;if(f.length){for(y=w=x=0;x<4;++x)(h=f[x])&&(d=Math.abs(h.value))&&(v+=h.value,g+=d,y+=d*h.x,w+=d*h.y);f.x=y/g,f.y=w/g}else{h=f,h.x=h.data.x,h.y=h.data.y;do v+=o[h.data.index];while(h=h.next)}f.value=v}function u(f,v,h,d){if(!f.value)return!0;var g=f.x-e.x,y=f.y-e.y,w=d-v,x=g*g+y*y;if(w*w/l<x)return x<p&&(g===0&&(g=z(n),x+=g*g),y===0&&(y=z(n),x+=y*y),x<a&&(x=Math.sqrt(a*x)),e.vx+=g*f.value*i/x,e.vy+=y*f.value*i/x),!0;if(f.length||x>=p)return;(f.data!==e||f.next)&&(g===0&&(g=z(n),x+=g*g),y===0&&(y=z(n),x+=y*y),x<a&&(x=Math.sqrt(a*x)));do f.data!==e&&(w=o[f.data.index]*i/x,e.vx+=g*w,e.vy+=y*w);while(f=f.next)}return s.initialize=function(f,v){t=f,n=v,c()},s.strength=function(f){return arguments.length?(r=typeof f=="function"?f:G(+f),c(),s):r},s.distanceMin=function(f){return arguments.length?(a=f*f,s):Math.sqrt(a)},s.distanceMax=function(f){return arguments.length?(p=f*f,s):Math.sqrt(p)},s.theta=function(f){return arguments.length?(l=f*f,s):Math.sqrt(l)},s}var we="http://www.w3.org/2000/svg";function L(t,e){let n=document.createElementNS(we,t);for(let[i,r]of Object.entries(e))n.setAttribute(i,String(r));return n}var it=class{svg;defs;viewport;sim=null;nodes=[];edges=[];edgeEls=[];nodeEls=[];view={x:0,y:0,k:1};tab="context";selected=null;query="";hiddenRels={};hiddenTypes={};onSelect=()=>{};constructor(e){this.svg=e,this.buildChrome(),this.bindPanZoom()}buildChrome(){this.svg.textContent="",this.defs=L("defs",{}),this.svg.appendChild(this.defs),this.viewport=L("g",{}),this.svg.appendChild(this.viewport),this.svg.addEventListener("click",()=>this.select(null))}ensureMarkers(){this.defs.textContent="";let e=L("marker",{id:"arr",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:4.5,markerHeight:4.5,orient:"auto-start-reverse"});e.appendChild(L("path",{d:"M2,1.5L8.5,5L2,8.5",fill:"none",stroke:M("--edge"),"stroke-width":1.8,"stroke-linecap":"round","stroke-linejoin":"round",opacity:.75}));let n=L("marker",{id:"arrH",viewBox:"0 0 12 12",refX:10,refY:6,markerWidth:6.5,markerHeight:6.5,orient:"auto-start-reverse"});n.appendChild(L("path",{d:"M1.5,1.5L10.5,6L1.5,10.5z",fill:M("--canvas"),stroke:M("--edge"),"stroke-width":1.4}));let i=L("marker",{id:"arrOut",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:5,markerHeight:5,orient:"auto-start-reverse"});i.appendChild(L("path",{d:"M1,1L9,5L1,9z",fill:M("--fil")}));let r=L("marker",{id:"arrIn",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:5,markerHeight:5,orient:"auto-start-reverse"});r.appendChild(L("path",{d:"M1,1L9,5L1,9z",fill:M("--accent")}));for(let o of[e,n,i,r])this.defs.appendChild(o)}setData(e,n){this.tab=n;let i=new Map(this.nodes.map(l=>[l.id,l])),r={};for(let l of e.edges)r[l.source]=(r[l.source]??0)+1,r[l.target]=(r[l.target]??0)+1;let o=this.svg.clientWidth||800,a=this.svg.clientHeight||600;this.nodes=e.nodes.map((l,s)=>{let c=i.get(l.id),m=s/Math.max(1,e.nodes.length)*Math.PI*2,u=r[l.id]??0;return{id:l.id,name:l.name,type:l.type,deg:u,r:11+Math.min(13,u*2.6),x:c?.x??o/2+Math.cos(m)*Math.min(o,a)/4,y:c?.y??a/2+Math.sin(m)*Math.min(o,a)/4,vx:c?.vx??0,vy:c?.vy??0}});let p=new Map(this.nodes.map(l=>[l.id,l]));this.edges=e.edges.map(l=>({source:p.get(l.source),target:p.get(l.target),relation:l.relation,description:l.description,confidence:l.confidence})).filter(l=>l.source&&l.target),this.sim?.stop(),this.sim=ht(this.nodes).force("charge",pt().strength(-220)).force("link",lt(this.edges).distance(l=>kt[Y(l.relation)]).strength(.5)).force("center",ot(o/2,a/2)).force("collide",at().radius(l=>l.r+6)).on("tick",()=>this.tick()),this.buildElements(),this.restyle()}buildElements(){this.ensureMarkers(),this.viewport.textContent="",this.edgeEls=this.edges.map(e=>{let n=L("path",{fill:"none","stroke-linecap":"round"}),i=L("title",{});i.textContent=e.relation.replace(/_/g," ")+(e.description?` \u2014 ${e.description}`:""),n.appendChild(i);let r=L("text",{"text-anchor":"middle","font-size":9.5,"font-weight":700,"stroke-width":3,"paint-order":"stroke",display:"none"});return r.textContent=e.relation.replace(/_/g," "),this.viewport.appendChild(n),this.viewport.appendChild(r),{path:n,label:r,edge:e}}),this.nodeEls=this.nodes.map(e=>{let n=L("g",{cursor:"pointer"}),i=L("circle",{fill:"none","stroke-width":1.6,opacity:0,r:e.r+5}),r=L("circle",{r:e.r,opacity:.92}),o=L("text",{y:e.r+15,"text-anchor":"middle","font-size":11.5,"font-weight":600});return o.textContent=e.name,n.append(i,r,o),n.addEventListener("click",a=>{a.stopPropagation(),this.select(e.id)}),this.bindDrag(n,e),this.viewport.appendChild(n),{group:n,circle:r,ring:i,label:o,node:e}})}tick(){for(let{path:e,label:n,edge:i}of this.edgeEls){let r=i.source,o=i.target,a=(o.x??0)-(r.x??0),p=(o.y??0)-(r.y??0),l=Math.sqrt(a*a+p*p)||1,s=a/l,c=p/l,m=(r.x??0)+s*(r.r+2),u=(r.y??0)+c*(r.r+2),f=(o.x??0)-s*(o.r+6),v=(o.y??0)-c*(o.r+6),h=(m+f)/2-c*10,d=(u+v)/2+s*10;e.setAttribute("d",`M${m},${u} Q${h},${d} ${f},${v}`),n.setAttribute("x",String((m+f)/2-c*14)),n.setAttribute("y",String((u+v)/2+s*14))}for(let{group:e,node:n}of this.nodeEls)e.setAttribute("transform",`translate(${n.x??0},${n.y??0})`)}restyle(){this.ensureMarkers();let e=new Set;if(this.selected)for(let r of this.edges)r.source.id===this.selected&&e.add(r.target.id),r.target.id===this.selected&&e.add(r.source.id);let n=this.query.toLowerCase(),i=r=>!this.hiddenTypes[r.type];for(let{path:r,label:o,edge:a}of this.edgeEls){let p=i(a.source)&&i(a.target)&&!this.hiddenRels[J(a.relation)];if(r.style.display=p?"":"none",o.setAttribute("display","none"),!p)continue;let l=Y(a.relation),s=M("--edge"),c=1.3,m="none",u=.5,f="url(#arr)";l==="structure"?(c=2.4,u=.32,f="none"):l==="dependency"?(c=1.5,u=.55):l==="contract"?(u=.55,f="url(#arrH)"):(m="2 5",c=1.2,u=.28,f="none"),a.confidence==="inferred"&&(m="5 4"),n&&(u=.12);let v=this.selected?a.source.id===this.selected?"out":a.target.id===this.selected?"in":"far":"none";v==="out"?(s=M("--fil"),u=.95,c+=.7,f="url(#arrOut)"):v==="in"?(s=M("--accent"),u=.95,c+=.7,f="url(#arrIn)"):v==="far"&&(u=.06),r.setAttribute("stroke",s),r.setAttribute("stroke-width",String(c)),r.setAttribute("stroke-dasharray",m),r.setAttribute("opacity",String(u)),f==="none"?r.removeAttribute("marker-end"):r.setAttribute("marker-end",f),(v==="out"||v==="in")&&(o.removeAttribute("display"),o.setAttribute("fill",s),o.setAttribute("stroke",M("--canvas")))}for(let{group:r,circle:o,ring:a,label:p,node:l}of this.nodeEls){let s=i(l);if(r.style.display=s?"":"none",!s)continue;let m=!n||l.name.toLowerCase().includes(n)?1:.22;this.selected&&l.id!==this.selected&&!e.has(l.id)&&(m=Math.min(m,.2)),r.setAttribute("opacity",String(m));let u=M(D(this.tab,l.type));o.setAttribute("fill",u),a.setAttribute("stroke",u),a.setAttribute("opacity",l.id===this.selected?"0.55":"0"),p.setAttribute("fill",M("--ink"))}}select(e){this.selected=e,this.restyle(),this.onSelect(e)}focus(e){let n=this.nodes.find(o=>o.id===e);if(!n)return;let i=this.svg.clientWidth,r=this.svg.clientHeight;this.view.k=Math.max(this.view.k,1.4),this.view.x=i/2-(n.x??0)*this.view.k,this.view.y=r/2-(n.y??0)*this.view.k,this.applyView(),this.select(e)}firstMatch(){let e=this.query.toLowerCase();return this.nodes.find(n=>!this.hiddenTypes[n.type]&&n.name.toLowerCase().includes(e))}applyView(){this.viewport.setAttribute("transform",`translate(${this.view.x},${this.view.y}) scale(${this.view.k})`)}zoomBy(e){let n=this.svg.clientWidth/2,i=this.svg.clientHeight/2,r=Math.max(.35,Math.min(3,this.view.k*e));this.view.x=n-(n-this.view.x)*(r/this.view.k),this.view.y=i-(i-this.view.y)*(r/this.view.k),this.view.k=r,this.applyView()}resetView(){this.view={x:0,y:0,k:1},this.applyView()}reheat(){this.sim?.alpha(.6).restart()}bindDrag(e,n){e.addEventListener("pointerdown",i=>{i.stopPropagation(),e.setPointerCapture(i.pointerId);let r=a=>{let p=this.svg.getBoundingClientRect();n.fx=(a.clientX-p.left-this.view.x)/this.view.k,n.fy=(a.clientY-p.top-this.view.y)/this.view.k,this.sim?.alphaTarget(.25).restart()},o=()=>{n.fx=null,n.fy=null,this.sim?.alphaTarget(0),e.removeEventListener("pointermove",r),e.removeEventListener("pointerup",o)};e.addEventListener("pointermove",r),e.addEventListener("pointerup",o)})}bindPanZoom(){let e=null;this.svg.addEventListener("pointerdown",n=>{e={x:n.clientX-this.view.x,y:n.clientY-this.view.y}}),this.svg.addEventListener("pointermove",n=>{e&&(this.view.x=n.clientX-e.x,this.view.y=n.clientY-e.y,this.applyView())}),window.addEventListener("pointerup",()=>{e=null}),this.svg.addEventListener("wheel",n=>{n.preventDefault();let i=this.svg.getBoundingClientRect(),r=n.clientX-i.left,o=n.clientY-i.top,a=Math.max(.35,Math.min(3,this.view.k*Math.exp(-n.deltaY*.0016)));this.view.x=r-(r-this.view.x)*(a/this.view.k),this.view.y=o-(o-this.view.y)*(a/this.view.k),this.view.k=a,this.applyView()},{passive:!1})}};function O(t){return t.replace(/&/g,"&").replace(/</g,"<")}function te(t,e,n,i,r){if(!i||!e){t.innerHTML='<div class="empty">Select a node to view details</div>';return}let o=e.nodes.find(u=>u.id===i);if(!o){t.innerHTML='<div class="empty">Select a node to view details</div>';return}let a=M(D(n,o.type)),p=u=>e.nodes.find(f=>f.id===u)?.name??u,l=e.edges.filter(u=>u.source===i),s=e.edges.filter(u=>u.target===i),c=`<span class="d-type"><span class="sw" style="background:${a}"></span>${O(o.type)}</span>`;if(c+=`<h3>${O(o.name)}</h3>`,o.summary&&(c+=`<p class="summary">${O(o.summary)}</p>`),o.sources.length){c+=`<div class="d-label">Sources \xB7 ${o.sources.length}</div>`;for(let u of o.sources)c+=`<div class="src mono">${O(u)}</div>`}let m=(u,f,v,h)=>{if(u.length){c+=`<div class="d-label"><span class="dot" style="background:${f}"></span>${v} \xB7 ${u.length}</div>`;for(let d of u)c+=`<button class="lnk" data-go="${O(h(d))}"><span class="rel">${O(d.relation.replace(/_/g," "))}</span> <span class="to">${O(p(h(d)))}</span>`+(d.description?`<div class="desc">${O(d.description)}</div>`:"")+"</button>"}};m(l,M("--fil"),"Depends on",u=>u.target),m(s,M("--accent"),"Depended on by",u=>u.source),t.innerHTML=c,t.querySelectorAll("[data-go]").forEach(u=>{u.addEventListener("click",()=>r(u.dataset.go))})}function gt(t){return t.replace(/&/g,"&").replace(/</g,"<")}function q(t,e,n,i,r){let o=s=>e.edges.filter(c=>c.relation==="contains"&&c.source===s).map(c=>e.nodes.find(m=>m.id===c.target)).filter(c=>!!c),a=s=>{let c=o(s);return c.length+c.reduce((m,u)=>m+a(u.id),0)},p=e.nodes.filter(s=>s.type==="file"),l=s=>{let c=o(s.id),m=i[s.id]!==!1,u=`<button class="tree-row${m?" open":""}${n===s.id?" sel":""}" data-id="${gt(s.id)}" data-haskids="${c.length?1:0}"><span class="chev">${c.length?"\u25B6":""}</span><span class="k" style="background:${M(D("code",s.type))}"></span><span class="t${s.type==="file"?" mono":""}">${gt(s.name)}</span><span class="badge">${c.length?a(s.id)+" sym":gt(s.type)}</span></button>`;return c.length&&m&&(u+=`<div class="tree-kids">${c.map(l).join("")}</div>`),u};t.innerHTML='<div class="tree-tools"><button data-tool="expand">Expand all</button><button data-tool="collapse">Collapse all</button></div>'+p.map(l).join(""),t.querySelectorAll(".tree-row").forEach(s=>{s.addEventListener("click",()=>{let c=s.dataset.id;s.dataset.haskids==="1"&&(i[c]=i[c]===!1,q(t,e,c,i,r)),r(c)})}),t.querySelector('[data-tool="expand"]')?.addEventListener("click",()=>{for(let s of Object.keys(i))delete i[s];q(t,e,n,i,r)}),t.querySelector('[data-tool="collapse"]')?.addEventListener("click",()=>{for(let s of e.nodes)i[s.id]=!1;q(t,e,n,i,r)})}var E=t=>document.getElementById(t),b={tab:"context",context:null,code:null,outlineOpen:{}},k=new it(E("graphSvg"));function Z(){return b.tab==="context"?b.context:b.code}function vt(){return b.tab==="code"||b.tab==="outline"?"code":"context"}function yt(){let t=E("edgeChips");t.innerHTML='<span class="cap">Edges</span>';let e=Z();if(!e)return;let n=new Map;for(let r of e.edges){let o=J(r.relation);n.set(o,(n.get(o)??0)+1)}let i=[...n.keys()].sort((r,o)=>{let a=p=>p==="part of"?0:p==="uses"?1:2;return a(r)-a(o)||r.localeCompare(o)});for(let r of i){let o=document.createElement("button");o.type="button",o.className="echip"+(k.hiddenRels[r]?"":" on"),o.innerHTML=`${ke(r)} ${r} <span style="opacity:.55">${n.get(r)}</span>`,o.title=(bt[r]??`"${r}" edges`)+" \u2014 click to "+(k.hiddenRels[r]?"show":"hide"),o.addEventListener("click",()=>{k.hiddenRels[r]=!k.hiddenRels[r],yt(),k.restyle(),wt()}),t.appendChild(o)}}function ke(t){let e=t==="part of"?"structure":t==="uses"?"dependency":Y(t.replace(/ /g,"_"));return{structure:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="19" y2="4" stroke="currentColor" stroke-width="3" opacity=".5"/></svg>',dependency:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="14" y2="4" stroke="currentColor" stroke-width="1.6"/><path d="M14,1 L19,4 L14,7 z" fill="currentColor"/></svg>',contract:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="13" y2="4" stroke="currentColor" stroke-width="1.4"/><path d="M13,1 L19,4 L13,7 z" fill="none" stroke="currentColor" stroke-width="1.2"/></svg>',association:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="19" y2="4" stroke="currentColor" stroke-width="1.4" stroke-dasharray="2 4" opacity=".7"/></svg>'}[e]}function xt(){let t=E("legend");t.innerHTML="";let e=Z();if(!e)return;let n=new Map;for(let i of e.nodes)n.set(i.type,(n.get(i.type)??0)+1);for(let[i,r]of n){let o=document.createElement("button");o.type="button",o.className="lchip"+(k.hiddenTypes[i]?" off":""),o.innerHTML=`<span class="sw" style="background:${M(D(vt(),i))}"></span>${i} <span style="color:var(--muted);font-weight:500">${r}</span>`,o.addEventListener("click",()=>{k.hiddenTypes[i]=!k.hiddenTypes[i],xt(),k.restyle(),wt()}),t.appendChild(o)}}function wt(){let t=Z();if(!t){E("lcount").textContent="";return}let e=t.nodes.filter(n=>!k.hiddenTypes[n.type]).length;E("lcount").textContent=`${e} / ${t.nodes.length} nodes shown`}function be(){let t=E("counts");if(b.tab==="outline"&&b.code){let e=b.code.nodes.filter(n=>n.type==="file").length;t.textContent=`${e} files \xB7 ${b.code.nodes.length} symbols`}else{let e=Z();t.textContent=e?`${e.meta.nodeCount} nodes \xB7 ${e.meta.edgeCount} links`:""}}function P(t){te(E("detail"),b.tab==="context"?b.context:b.code,vt(),t,e=>{b.tab==="outline"?(P(e),q(E("tree"),b.code,e,b.outlineOpen,P)):k.focus(e)})}k.onSelect=t=>P(t);function re(t){b.tab=t,document.querySelectorAll(".tab").forEach(i=>{i.setAttribute("aria-selected",i.dataset.tab===t?"true":"false")});let e=t==="outline";E("canvasWrap").hidden=e,E("outlineView").hidden=!e,k.hiddenRels={},k.hiddenTypes={},k.selected=null,P(null);let n=E("graphEmpty");if(t==="outline")b.code?q(E("tree"),b.code,null,b.outlineOpen,P):(E("outlineView").hidden=!0,E("canvasWrap").hidden=!1,ee('No code graph yet \u2014 run <code>graft graph</code> to generate <span class="mono">graph.json</span>.'));else{let i=Z();i?(n.hidden=!0,k.resetView(),k.setData(i,vt()),k.reheat()):ee(t==="code"?'No code graph yet \u2014 run <code>graft graph</code> to generate <span class="mono">graph.json</span>.':"No context graph \u2014 run <code>graft init</code> first.")}yt(),xt(),wt(),be()}function ee(t){let e=E("graphEmpty");e.innerHTML=t,e.hidden=!1}document.querySelectorAll(".tab").forEach(t=>{t.addEventListener("click",()=>re(t.dataset.tab))});var mt=E("search");mt.addEventListener("input",()=>{k.query=mt.value.trim(),k.restyle()});mt.addEventListener("keydown",t=>{if(t.key==="Enter"&&k.query){let e=k.firstMatch();e&&k.focus(e.id)}});E("zin").addEventListener("click",()=>k.zoomBy(1.25));E("zout").addEventListener("click",()=>k.zoomBy(1/1.25));E("zreset").addEventListener("click",()=>k.resetView());var ie="graft-viz-theme",ne=localStorage.getItem(ie);ne&&document.documentElement.setAttribute("data-theme",ne);E("themeBtn").addEventListener("click",()=>{let t=document.documentElement,e=t.getAttribute("data-theme"),n=window.matchMedia("(prefers-color-scheme: dark)").matches,r=(e?e==="dark":n)?"light":"dark";t.setAttribute("data-theme",r),localStorage.setItem(ie,r),k.restyle(),yt(),xt(),P(k.selected)});async function oe(){let[t,e]=await Promise.all([_t(),Et()]);b.context=t,b.code=e,E("repoName").textContent=t.meta.repoName??"",document.title=`graft viz \u2014 ${t.meta.repoName??""}`,re(b.tab)}Mt(()=>{let t=k.selected;oe().then(()=>{t&&(k.selected=t,k.restyle(),P(t))})});oe();
|
|
1
|
+
var pe={part_of:"structure",contains:"structure",uses:"dependency",depends_on:"dependency",calls:"dependency",imports:"dependency",produces:"dependency",configures:"dependency",validates:"dependency",extends:"contract",implements:"contract",references:"association"};function Y(t){return pe[t]??"association"}var Lt={structure:85,dependency:145,contract:150,association:185};function tt(t){return Y(t)==="structure"?"part of":t==="calls"||t==="uses"||t==="depends_on"||t==="imports"?"uses":t.replace(/_/g," ")}var Nt={"part of":"where does this live? (contains, part of)",uses:"what breaks if the target changes? (calls, uses, depends on, imports)",produces:"where does this output come from?",configures:"what changes its behavior without a code change?",validates:"what checks or judges this? (tests, drift checks, scoring)",extends:"what contract must this honor? (inheritance)",implements:"what contract must this honor? (interface)",references:"mentioned but never called \u2014 possible dead coupling"},ge={system:"--sys",concept:"--con",file:"--fil",api:"--api",changed:"--fil",affected:"--sys"},me={file:"--k-file",class:"--k-class",function:"--k-fn",method:"--k-method",interface:"--k-iface",type:"--k-type",enum:"--k-enum"};function P(t,e){return(t==="code"?me:ge)[e]??"--edge"}function M(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}var F=globalThis.__GRAFT_DATA__;async function Tt(){return F?.contextGraph?F.contextGraph:await(await fetch("/api/context-graph")).json()}async function At(){let t;if(F){if(!F.codeGraph)return null;t=F.codeGraph}else{let i=await fetch("/api/code-graph");if(!i.ok)return null;t=await i.json()}let e=t.nodes.map(i=>({id:i.id,name:i.name,type:i.kind,summary:i.summary??i.signature??"",sources:[`${i.path} \xB7 ${i.span}`]})),n=new Set(e.map(i=>i.id)),r=t.edges.filter(i=>n.has(i.source)&&n.has(i.target)).map(i=>({source:i.source,target:i.target,relation:i.relation,confidence:i.confidence}));return{meta:{nodeCount:e.length,edgeCount:r.length},nodes:e,edges:r}}function St(t){if(F)return;let e=new EventSource("/events");e.onmessage=n=>{n.data==="change"&&t()}}function lt(t,e){var n,r=1;t==null&&(t=0),e==null&&(e=0);function i(){var o,a=n.length,p,d=0,s=0;for(o=0;o<a;++o)p=n[o],d+=p.x,s+=p.y;for(d=(d/a-t)*r,s=(s/a-e)*r,o=0;o<a;++o)p=n[o],p.x-=d,p.y-=s}return i.initialize=function(o){n=o},i.x=function(o){return arguments.length?(t=+o,i):t},i.y=function(o){return arguments.length?(e=+o,i):e},i.strength=function(o){return arguments.length?(r=+o,i):r},i}function $t(t){let e=+this._x.call(null,t),n=+this._y.call(null,t);return Vt(this.cover(e,n),e,n,t)}function Vt(t,e,n,r){if(isNaN(e)||isNaN(n))return t;var i,o=t._root,a={data:r},p=t._x0,d=t._y0,s=t._x1,l=t._y1,m,c,f,v,h,u,g,y;if(!o)return t._root=a,t;for(;o.length;)if((h=e>=(m=(p+s)/2))?p=m:s=m,(u=n>=(c=(d+l)/2))?d=c:l=c,i=o,!(o=o[g=u<<1|h]))return i[g]=a,t;if(f=+t._x.call(null,o.data),v=+t._y.call(null,o.data),e===f&&n===v)return a.next=o,i?i[g]=a:t._root=a,t;do i=i?i[g]=new Array(4):t._root=new Array(4),(h=e>=(m=(p+s)/2))?p=m:s=m,(u=n>=(c=(d+l)/2))?d=c:l=c;while((g=u<<1|h)===(y=(v>=c)<<1|f>=m));return i[y]=o,i[g]=a,t}function zt(t){var e,n,r=t.length,i,o,a=new Array(r),p=new Array(r),d=1/0,s=1/0,l=-1/0,m=-1/0;for(n=0;n<r;++n)isNaN(i=+this._x.call(null,e=t[n]))||isNaN(o=+this._y.call(null,e))||(a[n]=i,p[n]=o,i<d&&(d=i),i>l&&(l=i),o<s&&(s=o),o>m&&(m=o));if(d>l||s>m)return this;for(this.cover(d,s).cover(l,m),n=0;n<r;++n)Vt(this,a[n],p[n],t[n]);return this}function Gt(t,e){if(isNaN(t=+t)||isNaN(e=+e))return this;var n=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(n))i=(n=Math.floor(t))+1,o=(r=Math.floor(e))+1;else{for(var a=i-n||1,p=this._root,d,s;n>t||t>=i||r>e||e>=o;)switch(s=(e<r)<<1|t<n,d=new Array(4),d[s]=p,p=d,a*=2,s){case 0:i=n+a,o=r+a;break;case 1:n=i-a,o=r+a;break;case 2:i=n+a,r=o-a;break;case 3:n=i-a,r=o-a;break}this._root&&this._root.length&&(this._root=p)}return this._x0=n,this._y0=r,this._x1=i,this._y1=o,this}function Dt(){var t=[];return this.visit(function(e){if(!e.length)do t.push(e.data);while(e=e.next)}),t}function Ht(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]}function N(t,e,n,r,i){this.node=t,this.x0=e,this.y0=n,this.x1=r,this.y1=i}function It(t,e,n){var r,i=this._x0,o=this._y0,a,p,d,s,l=this._x1,m=this._y1,c=[],f=this._root,v,h;for(f&&c.push(new N(f,i,o,l,m)),n==null?n=1/0:(i=t-n,o=e-n,l=t+n,m=e+n,n*=n);v=c.pop();)if(!(!(f=v.node)||(a=v.x0)>l||(p=v.y0)>m||(d=v.x1)<i||(s=v.y1)<o))if(f.length){var u=(a+d)/2,g=(p+s)/2;c.push(new N(f[3],u,g,d,s),new N(f[2],a,g,u,s),new N(f[1],u,p,d,g),new N(f[0],a,p,u,g)),(h=(e>=g)<<1|t>=u)&&(v=c[c.length-1],c[c.length-1]=c[c.length-1-h],c[c.length-1-h]=v)}else{var y=t-+this._x.call(null,f.data),w=e-+this._y.call(null,f.data),x=y*y+w*w;if(x<n){var E=Math.sqrt(n=x);i=t-E,o=e-E,l=t+E,m=e+E,r=f.data}}return r}function Rt(t){if(isNaN(l=+this._x.call(null,t))||isNaN(m=+this._y.call(null,t)))return this;var e,n=this._root,r,i,o,a=this._x0,p=this._y0,d=this._x1,s=this._y1,l,m,c,f,v,h,u,g;if(!n)return this;if(n.length)for(;;){if((v=l>=(c=(a+d)/2))?a=c:d=c,(h=m>=(f=(p+s)/2))?p=f:s=f,e=n,!(n=n[u=h<<1|v]))return this;if(!n.length)break;(e[u+1&3]||e[u+2&3]||e[u+3&3])&&(r=e,g=u)}for(;n.data!==t;)if(i=n,!(n=n.next))return this;return(o=n.next)&&delete n.next,i?(o?i.next=o:delete i.next,this):e?(o?e[u]=o:delete e[u],(n=e[0]||e[1]||e[2]||e[3])&&n===(e[3]||e[2]||e[1]||e[0])&&!n.length&&(r?r[g]=n:this._root=n),this):(this._root=o,this)}function Pt(t){for(var e=0,n=t.length;e<n;++e)this.remove(t[e]);return this}function Bt(){return this._root}function Ot(){var t=0;return this.visit(function(e){if(!e.length)do++t;while(e=e.next)}),t}function jt(t){var e=[],n,r=this._root,i,o,a,p,d;for(r&&e.push(new N(r,this._x0,this._y0,this._x1,this._y1));n=e.pop();)if(!t(r=n.node,o=n.x0,a=n.y0,p=n.x1,d=n.y1)&&r.length){var s=(o+p)/2,l=(a+d)/2;(i=r[3])&&e.push(new N(i,s,l,p,d)),(i=r[2])&&e.push(new N(i,o,l,s,d)),(i=r[1])&&e.push(new N(i,s,a,p,l)),(i=r[0])&&e.push(new N(i,o,a,s,l))}return this}function Wt(t){var e=[],n=[],r;for(this._root&&e.push(new N(this._root,this._x0,this._y0,this._x1,this._y1));r=e.pop();){var i=r.node;if(i.length){var o,a=r.x0,p=r.y0,d=r.x1,s=r.y1,l=(a+d)/2,m=(p+s)/2;(o=i[0])&&e.push(new N(o,a,p,l,m)),(o=i[1])&&e.push(new N(o,l,p,d,m)),(o=i[2])&&e.push(new N(o,a,m,l,s)),(o=i[3])&&e.push(new N(o,l,m,d,s))}n.push(r)}for(;r=n.pop();)t(r.node,r.x0,r.y0,r.x1,r.y1);return this}function Ft(t){return t[0]}function Yt(t){return arguments.length?(this._x=t,this):this._x}function qt(t){return t[1]}function Xt(t){return arguments.length?(this._y=t,this):this._y}function B(t,e,n){var r=new ct(e??Ft,n??qt,NaN,NaN,NaN,NaN);return t==null?r:r.addAll(t)}function ct(t,e,n,r,i,o){this._x=t,this._y=e,this._x0=n,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Kt(t){for(var e={data:t.data},n=e;t=t.next;)n=n.next={data:t.data};return e}var S=B.prototype=ct.prototype;S.copy=function(){var t=new ct(this._x,this._y,this._x0,this._y0,this._x1,this._y1),e=this._root,n,r;if(!e)return t;if(!e.length)return t._root=Kt(e),t;for(n=[{source:e,target:t._root=new Array(4)}];e=n.pop();)for(var i=0;i<4;++i)(r=e.source[i])&&(r.length?n.push({source:r,target:e.target[i]=new Array(4)}):e.target[i]=Kt(r));return t};S.add=$t;S.addAll=zt;S.cover=Gt;S.data=Dt;S.extent=Ht;S.find=It;S.remove=Rt;S.removeAll=Pt;S.root=Bt;S.size=Ot;S.visit=jt;S.visitAfter=Wt;S.x=Yt;S.y=Xt;function D(t){return function(){return t}}function z(t){return(t()-.5)*1e-6}function ve(t){return t.x+t.vx}function ye(t){return t.y+t.vy}function dt(t){var e,n,r,i=1,o=1;typeof t!="function"&&(t=D(t==null?1:+t));function a(){for(var s,l=e.length,m,c,f,v,h,u,g=0;g<o;++g)for(m=B(e,ve,ye).visitAfter(p),s=0;s<l;++s)c=e[s],h=n[c.index],u=h*h,f=c.x+c.vx,v=c.y+c.vy,m.visit(y);function y(w,x,E,A,$){var C=w.data,V=w.r,L=h+V;if(C){if(C.index>c.index){var I=f-C.x-C.vx,R=v-C.y-C.vy,H=I*I+R*R;H<L*L&&(I===0&&(I=z(r),H+=I*I),R===0&&(R=z(r),H+=R*R),H=(L-(H=Math.sqrt(H)))/H*i,c.vx+=(I*=H)*(L=(V*=V)/(u+V)),c.vy+=(R*=H)*L,C.vx-=I*(L=1-L),C.vy-=R*L)}return}return x>f+L||A<f-L||E>v+L||$<v-L}}function p(s){if(s.data)return s.r=n[s.data.index];for(var l=s.r=0;l<4;++l)s[l]&&s[l].r>s.r&&(s.r=s[l].r)}function d(){if(e){var s,l=e.length,m;for(n=new Array(l),s=0;s<l;++s)m=e[s],n[m.index]=+t(m,s,e)}}return a.initialize=function(s,l){e=s,r=l,d()},a.iterations=function(s){return arguments.length?(o=+s,a):o},a.strength=function(s){return arguments.length?(i=+s,a):i},a.radius=function(s){return arguments.length?(t=typeof s=="function"?s:D(+s),d(),a):t},a}function xe(t){return t.index}function Qt(t,e){var n=t.get(e);if(!n)throw new Error("node not found: "+e);return n}function ut(t){var e=xe,n=m,r,i=D(30),o,a,p,d,s,l=1;t==null&&(t=[]);function m(u){return 1/Math.min(p[u.source.index],p[u.target.index])}function c(u){for(var g=0,y=t.length;g<l;++g)for(var w=0,x,E,A,$,C,V,L;w<y;++w)x=t[w],E=x.source,A=x.target,$=A.x+A.vx-E.x-E.vx||z(s),C=A.y+A.vy-E.y-E.vy||z(s),V=Math.sqrt($*$+C*C),V=(V-o[w])/V*u*r[w],$*=V,C*=V,A.vx-=$*(L=d[w]),A.vy-=C*L,E.vx+=$*(L=1-L),E.vy+=C*L}function f(){if(a){var u,g=a.length,y=t.length,w=new Map(a.map((E,A)=>[e(E,A,a),E])),x;for(u=0,p=new Array(g);u<y;++u)x=t[u],x.index=u,typeof x.source!="object"&&(x.source=Qt(w,x.source)),typeof x.target!="object"&&(x.target=Qt(w,x.target)),p[x.source.index]=(p[x.source.index]||0)+1,p[x.target.index]=(p[x.target.index]||0)+1;for(u=0,d=new Array(y);u<y;++u)x=t[u],d[u]=p[x.source.index]/(p[x.source.index]+p[x.target.index]);r=new Array(y),v(),o=new Array(y),h()}}function v(){if(a)for(var u=0,g=t.length;u<g;++u)r[u]=+n(t[u],u,t)}function h(){if(a)for(var u=0,g=t.length;u<g;++u)o[u]=+i(t[u],u,t)}return c.initialize=function(u,g){a=u,s=g,f()},c.links=function(u){return arguments.length?(t=u,f(),c):t},c.id=function(u){return arguments.length?(e=u,c):e},c.iterations=function(u){return arguments.length?(l=+u,c):l},c.strength=function(u){return arguments.length?(n=typeof u=="function"?u:D(+u),v(),c):n},c.distance=function(u){return arguments.length?(i=typeof u=="function"?u:D(+u),h(),c):i},c}var we={value:()=>{}};function Jt(){for(var t=0,e=arguments.length,n={},r;t<e;++t){if(!(r=arguments[t]+"")||r in n||/[\s.]/.test(r))throw new Error("illegal type: "+r);n[r]=[]}return new et(n)}function et(t){this._=t}function be(t,e){return t.trim().split(/^|\s+/).map(function(n){var r="",i=n.indexOf(".");if(i>=0&&(r=n.slice(i+1),n=n.slice(0,i)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:r}})}et.prototype=Jt.prototype={constructor:et,on:function(t,e){var n=this._,r=be(t+"",n),i,o=-1,a=r.length;if(arguments.length<2){for(;++o<a;)if((i=(t=r[o]).type)&&(i=ke(n[i],t.name)))return i;return}if(e!=null&&typeof e!="function")throw new Error("invalid callback: "+e);for(;++o<a;)if(i=(t=r[o]).type)n[i]=Zt(n[i],t.name,e);else if(e==null)for(i in n)n[i]=Zt(n[i],t.name,null);return this},copy:function(){var t={},e=this._;for(var n in e)t[n]=e[n].slice();return new et(t)},call:function(t,e){if((i=arguments.length-2)>0)for(var n=new Array(i),r=0,i,o;r<i;++r)n[r]=arguments[r+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=this._[t],r=0,i=o.length;r<i;++r)o[r].value.apply(e,n)},apply:function(t,e,n){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(e,n)}};function ke(t,e){for(var n=0,r=t.length,i;n<r;++n)if((i=t[n]).name===e)return i.value}function Zt(t,e,n){for(var r=0,i=t.length;r<i;++r)if(t[r].name===e){t[r]=we,t=t.slice(0,r).concat(t.slice(r+1));break}return n!=null&&t.push({name:e,value:n}),t}var ft=Jt;var q=0,Q=0,K=0,te=1e3,nt,Z,it=0,O=0,rt=0,J=typeof performance=="object"&&performance.now?performance:Date,ee=typeof window=="object"&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function gt(){return O||(ee(_e),O=J.now()+rt)}function _e(){O=0}function ht(){this._call=this._time=this._next=null}ht.prototype=ot.prototype={constructor:ht,restart:function(t,e,n){if(typeof t!="function")throw new TypeError("callback is not a function");n=(n==null?gt():+n)+(e==null?0:+e),!this._next&&Z!==this&&(Z?Z._next=this:nt=this,Z=this),this._call=t,this._time=n,pt()},stop:function(){this._call&&(this._call=null,this._time=1/0,pt())}};function ot(t,e,n){var r=new ht;return r.restart(t,e,n),r}function ne(){gt(),++q;for(var t=nt,e;t;)(e=O-t._time)>=0&&t._call.call(void 0,e),t=t._next;--q}function Ut(){O=(it=J.now())+rt,q=Q=0;try{ne()}finally{q=0,Me(),O=0}}function Ee(){var t=J.now(),e=t-it;e>te&&(rt-=e,it=t)}function Me(){for(var t,e=nt,n,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:nt=n);Z=t,pt(r)}function pt(t){if(!q){Q&&(Q=clearTimeout(Q));var e=t-O;e>24?(t<1/0&&(Q=setTimeout(Ut,t-J.now()-rt)),K&&(K=clearInterval(K))):(K||(it=J.now(),K=setInterval(Ee,te)),q=1,ee(Ut))}}function ie(){let t=1;return()=>(t=(1664525*t+1013904223)%4294967296)/4294967296}function re(t){return t.x}function oe(t){return t.y}var Ce=10,Le=Math.PI*(3-Math.sqrt(5));function mt(t){var e,n=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,p=new Map,d=ot(m),s=ft("tick","end"),l=ie();t==null&&(t=[]);function m(){c(),s.call("tick",e),n<r&&(d.stop(),s.call("end",e))}function c(h){var u,g=t.length,y;h===void 0&&(h=1);for(var w=0;w<h;++w)for(n+=(o-n)*i,p.forEach(function(x){x(n)}),u=0;u<g;++u)y=t[u],y.fx==null?y.x+=y.vx*=a:(y.x=y.fx,y.vx=0),y.fy==null?y.y+=y.vy*=a:(y.y=y.fy,y.vy=0);return e}function f(){for(var h=0,u=t.length,g;h<u;++h){if(g=t[h],g.index=h,g.fx!=null&&(g.x=g.fx),g.fy!=null&&(g.y=g.fy),isNaN(g.x)||isNaN(g.y)){var y=Ce*Math.sqrt(.5+h),w=h*Le;g.x=y*Math.cos(w),g.y=y*Math.sin(w)}(isNaN(g.vx)||isNaN(g.vy))&&(g.vx=g.vy=0)}}function v(h){return h.initialize&&h.initialize(t,l),h}return f(),e={tick:c,restart:function(){return d.restart(m),e},stop:function(){return d.stop(),e},nodes:function(h){return arguments.length?(t=h,f(),p.forEach(v),e):t},alpha:function(h){return arguments.length?(n=+h,e):n},alphaMin:function(h){return arguments.length?(r=+h,e):r},alphaDecay:function(h){return arguments.length?(i=+h,e):+i},alphaTarget:function(h){return arguments.length?(o=+h,e):o},velocityDecay:function(h){return arguments.length?(a=1-h,e):1-a},randomSource:function(h){return arguments.length?(l=h,p.forEach(v),e):l},force:function(h,u){return arguments.length>1?(u==null?p.delete(h):p.set(h,v(u)),e):p.get(h)},find:function(h,u,g){var y=0,w=t.length,x,E,A,$,C;for(g==null?g=1/0:g*=g,y=0;y<w;++y)$=t[y],x=h-$.x,E=u-$.y,A=x*x+E*E,A<g&&(C=$,g=A);return C},on:function(h,u){return arguments.length>1?(s.on(h,u),e):s.on(h)}}}function vt(){var t,e,n,r,i=D(-30),o,a=1,p=1/0,d=.81;function s(f){var v,h=t.length,u=B(t,re,oe).visitAfter(m);for(r=f,v=0;v<h;++v)e=t[v],u.visit(c)}function l(){if(t){var f,v=t.length,h;for(o=new Array(v),f=0;f<v;++f)h=t[f],o[h.index]=+i(h,f,t)}}function m(f){var v=0,h,u,g=0,y,w,x;if(f.length){for(y=w=x=0;x<4;++x)(h=f[x])&&(u=Math.abs(h.value))&&(v+=h.value,g+=u,y+=u*h.x,w+=u*h.y);f.x=y/g,f.y=w/g}else{h=f,h.x=h.data.x,h.y=h.data.y;do v+=o[h.data.index];while(h=h.next)}f.value=v}function c(f,v,h,u){if(!f.value)return!0;var g=f.x-e.x,y=f.y-e.y,w=u-v,x=g*g+y*y;if(w*w/d<x)return x<p&&(g===0&&(g=z(n),x+=g*g),y===0&&(y=z(n),x+=y*y),x<a&&(x=Math.sqrt(a*x)),e.vx+=g*f.value*r/x,e.vy+=y*f.value*r/x),!0;if(f.length||x>=p)return;(f.data!==e||f.next)&&(g===0&&(g=z(n),x+=g*g),y===0&&(y=z(n),x+=y*y),x<a&&(x=Math.sqrt(a*x)));do f.data!==e&&(w=o[f.data.index]*r/x,e.vx+=g*w,e.vy+=y*w);while(f=f.next)}return s.initialize=function(f,v){t=f,n=v,l()},s.strength=function(f){return arguments.length?(i=typeof f=="function"?f:D(+f),l(),s):i},s.distanceMin=function(f){return arguments.length?(a=f*f,s):Math.sqrt(a)},s.distanceMax=function(f){return arguments.length?(p=f*f,s):Math.sqrt(p)},s.theta=function(f){return arguments.length?(d=f*f,s):Math.sqrt(d)},s}var Ne="http://www.w3.org/2000/svg";function T(t,e){let n=document.createElementNS(Ne,t);for(let[r,i]of Object.entries(e))n.setAttribute(r,String(i));return n}var st=class{svg;defs;viewport;sim=null;nodes=[];edges=[];edgeEls=[];nodeEls=[];view={x:0,y:0,k:1};tab="context";selected=null;query="";hiddenRels={};hiddenTypes={};onSelect=()=>{};constructor(e){this.svg=e,this.buildChrome(),this.bindPanZoom()}buildChrome(){this.svg.textContent="",this.defs=T("defs",{}),this.svg.appendChild(this.defs),this.viewport=T("g",{}),this.svg.appendChild(this.viewport),this.svg.addEventListener("click",()=>this.select(null))}ensureMarkers(){this.defs.textContent="";let e=T("marker",{id:"arr",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:4.5,markerHeight:4.5,orient:"auto-start-reverse"});e.appendChild(T("path",{d:"M2,1.5L8.5,5L2,8.5",fill:"none",stroke:M("--edge"),"stroke-width":1.8,"stroke-linecap":"round","stroke-linejoin":"round",opacity:.75}));let n=T("marker",{id:"arrH",viewBox:"0 0 12 12",refX:10,refY:6,markerWidth:6.5,markerHeight:6.5,orient:"auto-start-reverse"});n.appendChild(T("path",{d:"M1.5,1.5L10.5,6L1.5,10.5z",fill:M("--canvas"),stroke:M("--edge"),"stroke-width":1.4}));let r=T("marker",{id:"arrOut",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:5,markerHeight:5,orient:"auto-start-reverse"});r.appendChild(T("path",{d:"M1,1L9,5L1,9z",fill:M("--fil")}));let i=T("marker",{id:"arrIn",viewBox:"0 0 10 10",refX:8,refY:5,markerWidth:5,markerHeight:5,orient:"auto-start-reverse"});i.appendChild(T("path",{d:"M1,1L9,5L1,9z",fill:M("--accent")}));for(let o of[e,n,r,i])this.defs.appendChild(o)}setData(e,n){this.tab=n;let r=new Map(this.nodes.map(d=>[d.id,d])),i={};for(let d of e.edges)i[d.source]=(i[d.source]??0)+1,i[d.target]=(i[d.target]??0)+1;let o=this.svg.clientWidth||800,a=this.svg.clientHeight||600;this.nodes=e.nodes.map((d,s)=>{let l=r.get(d.id),m=s/Math.max(1,e.nodes.length)*Math.PI*2,c=i[d.id]??0;return{id:d.id,name:d.name,type:d.type,deg:c,r:11+Math.min(13,c*2.6),x:l?.x??o/2+Math.cos(m)*Math.min(o,a)/4,y:l?.y??a/2+Math.sin(m)*Math.min(o,a)/4,vx:l?.vx??0,vy:l?.vy??0}});let p=new Map(this.nodes.map(d=>[d.id,d]));this.edges=e.edges.map(d=>({source:p.get(d.source),target:p.get(d.target),relation:d.relation,description:d.description,confidence:d.confidence})).filter(d=>d.source&&d.target),this.sim?.stop(),this.sim=mt(this.nodes).force("charge",vt().strength(-220)).force("link",ut(this.edges).distance(d=>Lt[Y(d.relation)]).strength(.5)).force("center",lt(o/2,a/2)).force("collide",dt().radius(d=>d.r+6)).on("tick",()=>this.tick()),this.buildElements(),this.restyle()}buildElements(){this.ensureMarkers(),this.viewport.textContent="",this.edgeEls=this.edges.map(e=>{let n=T("path",{fill:"none","stroke-linecap":"round"}),r=T("title",{});r.textContent=e.relation.replace(/_/g," ")+(e.description?` \u2014 ${e.description}`:""),n.appendChild(r);let i=T("text",{"text-anchor":"middle","font-size":9.5,"font-weight":700,"stroke-width":3,"paint-order":"stroke",display:"none"});return i.textContent=e.relation.replace(/_/g," "),this.viewport.appendChild(n),this.viewport.appendChild(i),{path:n,label:i,edge:e}}),this.nodeEls=this.nodes.map(e=>{let n=T("g",{cursor:"pointer"}),r=T("circle",{fill:"none","stroke-width":1.6,opacity:0,r:e.r+5}),i=T("circle",{r:e.r,opacity:.92}),o=T("text",{y:e.r+15,"text-anchor":"middle","font-size":11.5,"font-weight":600});return o.textContent=e.name,n.append(r,i,o),n.addEventListener("click",a=>{a.stopPropagation(),this.select(e.id)}),this.bindDrag(n,e),this.viewport.appendChild(n),{group:n,circle:i,ring:r,label:o,node:e}})}tick(){for(let{path:e,label:n,edge:r}of this.edgeEls){let i=r.source,o=r.target,a=(o.x??0)-(i.x??0),p=(o.y??0)-(i.y??0),d=Math.sqrt(a*a+p*p)||1,s=a/d,l=p/d,m=(i.x??0)+s*(i.r+2),c=(i.y??0)+l*(i.r+2),f=(o.x??0)-s*(o.r+6),v=(o.y??0)-l*(o.r+6),h=(m+f)/2-l*10,u=(c+v)/2+s*10;e.setAttribute("d",`M${m},${c} Q${h},${u} ${f},${v}`),n.setAttribute("x",String((m+f)/2-l*14)),n.setAttribute("y",String((c+v)/2+s*14))}for(let{group:e,node:n}of this.nodeEls)e.setAttribute("transform",`translate(${n.x??0},${n.y??0})`)}restyle(){this.ensureMarkers();let e=new Set;if(this.selected)for(let i of this.edges)i.source.id===this.selected&&e.add(i.target.id),i.target.id===this.selected&&e.add(i.source.id);let n=this.query.toLowerCase(),r=i=>!this.hiddenTypes[i.type];for(let{path:i,label:o,edge:a}of this.edgeEls){let p=r(a.source)&&r(a.target)&&!this.hiddenRels[tt(a.relation)];if(i.style.display=p?"":"none",o.setAttribute("display","none"),!p)continue;let d=Y(a.relation),s=M("--edge"),l=1.3,m="none",c=.5,f="url(#arr)";d==="structure"?(l=2.4,c=.32,f="none"):d==="dependency"?(l=1.5,c=.55):d==="contract"?(c=.55,f="url(#arrH)"):(m="2 5",l=1.2,c=.28,f="none"),a.confidence==="inferred"&&(m="5 4"),n&&(c=.12);let v=this.selected?a.source.id===this.selected?"out":a.target.id===this.selected?"in":"far":"none";v==="out"?(s=M("--fil"),c=.95,l+=.7,f="url(#arrOut)"):v==="in"?(s=M("--accent"),c=.95,l+=.7,f="url(#arrIn)"):v==="far"&&(c=.06),i.setAttribute("stroke",s),i.setAttribute("stroke-width",String(l)),i.setAttribute("stroke-dasharray",m),i.setAttribute("opacity",String(c)),f==="none"?i.removeAttribute("marker-end"):i.setAttribute("marker-end",f),(v==="out"||v==="in")&&(o.removeAttribute("display"),o.setAttribute("fill",s),o.setAttribute("stroke",M("--canvas")))}for(let{group:i,circle:o,ring:a,label:p,node:d}of this.nodeEls){let s=r(d);if(i.style.display=s?"":"none",!s)continue;let m=!n||d.name.toLowerCase().includes(n)?1:.22;this.selected&&d.id!==this.selected&&!e.has(d.id)&&(m=Math.min(m,.2)),i.setAttribute("opacity",String(m));let c=M(P(this.tab,d.type));o.setAttribute("fill",c),a.setAttribute("stroke",c),a.setAttribute("opacity",d.id===this.selected?"0.55":"0"),p.setAttribute("fill",M("--ink"))}}select(e){this.selected=e,this.restyle(),this.onSelect(e)}focus(e){let n=this.nodes.find(o=>o.id===e);if(!n)return;let r=this.svg.clientWidth,i=this.svg.clientHeight;this.view.k=Math.max(this.view.k,1.4),this.view.x=r/2-(n.x??0)*this.view.k,this.view.y=i/2-(n.y??0)*this.view.k,this.applyView(),this.select(e)}firstMatch(){let e=this.query.toLowerCase();return this.nodes.find(n=>!this.hiddenTypes[n.type]&&n.name.toLowerCase().includes(e))}applyView(){this.viewport.setAttribute("transform",`translate(${this.view.x},${this.view.y}) scale(${this.view.k})`)}zoomBy(e){let n=this.svg.clientWidth/2,r=this.svg.clientHeight/2,i=Math.max(.35,Math.min(3,this.view.k*e));this.view.x=n-(n-this.view.x)*(i/this.view.k),this.view.y=r-(r-this.view.y)*(i/this.view.k),this.view.k=i,this.applyView()}resetView(){this.view={x:0,y:0,k:1},this.applyView()}reheat(){this.sim?.alpha(.6).restart()}bindDrag(e,n){e.addEventListener("pointerdown",r=>{r.stopPropagation(),e.setPointerCapture(r.pointerId);let i=a=>{let p=this.svg.getBoundingClientRect();n.fx=(a.clientX-p.left-this.view.x)/this.view.k,n.fy=(a.clientY-p.top-this.view.y)/this.view.k,this.sim?.alphaTarget(.25).restart()},o=()=>{n.fx=null,n.fy=null,this.sim?.alphaTarget(0),e.removeEventListener("pointermove",i),e.removeEventListener("pointerup",o)};e.addEventListener("pointermove",i),e.addEventListener("pointerup",o)})}bindPanZoom(){let e=null;this.svg.addEventListener("pointerdown",n=>{e={x:n.clientX-this.view.x,y:n.clientY-this.view.y}}),this.svg.addEventListener("pointermove",n=>{e&&(this.view.x=n.clientX-e.x,this.view.y=n.clientY-e.y,this.applyView())}),window.addEventListener("pointerup",()=>{e=null}),this.svg.addEventListener("wheel",n=>{n.preventDefault();let r=this.svg.getBoundingClientRect(),i=n.clientX-r.left,o=n.clientY-r.top,a=Math.max(.35,Math.min(3,this.view.k*Math.exp(-n.deltaY*.0016)));this.view.x=i-(i-this.view.x)*(a/this.view.k),this.view.y=o-(o-this.view.y)*(a/this.view.k),this.view.k=a,this.applyView()},{passive:!1})}};function G(t){return t.replace(/&/g,"&").replace(/</g,"<")}function Te(t){let e=t.lines.map(n=>`<div class="ev-l ${n.sign==="+"?"add":n.sign==="-"?"del":"ctx"}"><span class="ev-n">${n.n??""}</span><span class="ev-s">${n.sign===" "?"":n.sign}</span><span class="ev-t">${G(n.text)}</span></div>`).join("");return`<div class="ev"><div class="ev-h mono">${G(t.label)}${t.note?` <span class="ev-note">${G(t.note)}</span>`:""}</div><div class="ev-b mono">${e}</div>`+(t.more?`<div class="ev-more">+ ${t.more} more lines</div>`:"")+"</div>"}function se(t,e,n,r,i){if(!r||!e){t.innerHTML='<div class="empty">Select a node to view details</div>';return}let o=e.nodes.find(c=>c.id===r);if(!o){t.innerHTML='<div class="empty">Select a node to view details</div>';return}let a=M(P(n,o.type)),p=c=>e.nodes.find(f=>f.id===c)?.name??c,d=e.edges.filter(c=>c.source===r),s=e.edges.filter(c=>c.target===r),l=`<span class="d-type"><span class="sw" style="background:${a}"></span>${G(o.type)}</span>`;if(l+=`<h3>${G(o.name)}</h3>`,o.summary&&(l+=`<p class="summary">${G(o.summary)}</p>`),o.evidence?.length){l+=`<div class="d-label">Code \xB7 ${o.evidence.length}</div>`;for(let f of o.evidence)l+=Te(f);let c=o.sources.length-o.evidence.length;c>0&&(l+=`<div class="src mono">+ ${c} more, not shown</div>`)}else if(o.sources.length){l+=`<div class="d-label">Sources \xB7 ${o.sources.length}</div>`;for(let c of o.sources)l+=`<div class="src mono">${G(c)}</div>`}let m=(c,f,v,h)=>{if(c.length){l+=`<div class="d-label"><span class="dot" style="background:${f}"></span>${v} \xB7 ${c.length}</div>`;for(let u of c)l+=`<button class="lnk" data-go="${G(h(u))}"><span class="rel">${G(u.relation.replace(/_/g," "))}</span> <span class="to">${G(p(h(u)))}</span>`+(u.description?`<div class="desc">${G(u.description)}</div>`:"")+"</button>"}};m(d,M("--fil"),"Depends on",c=>c.target),m(s,M("--accent"),"Depended on by",c=>c.source),t.innerHTML=l,t.querySelectorAll("[data-go]").forEach(c=>{c.addEventListener("click",()=>i(c.dataset.go))})}function yt(t){return t.replace(/&/g,"&").replace(/</g,"<")}function X(t,e,n,r,i){let o=s=>e.edges.filter(l=>l.relation==="contains"&&l.source===s).map(l=>e.nodes.find(m=>m.id===l.target)).filter(l=>!!l),a=s=>{let l=o(s);return l.length+l.reduce((m,c)=>m+a(c.id),0)},p=e.nodes.filter(s=>s.type==="file"),d=s=>{let l=o(s.id),m=r[s.id]!==!1,c=`<button class="tree-row${m?" open":""}${n===s.id?" sel":""}" data-id="${yt(s.id)}" data-haskids="${l.length?1:0}"><span class="chev">${l.length?"\u25B6":""}</span><span class="k" style="background:${M(P("code",s.type))}"></span><span class="t${s.type==="file"?" mono":""}">${yt(s.name)}</span><span class="badge">${l.length?a(s.id)+" sym":yt(s.type)}</span></button>`;return l.length&&m&&(c+=`<div class="tree-kids">${l.map(d).join("")}</div>`),c};t.innerHTML='<div class="tree-tools"><button data-tool="expand">Expand all</button><button data-tool="collapse">Collapse all</button></div>'+p.map(d).join(""),t.querySelectorAll(".tree-row").forEach(s=>{s.addEventListener("click",()=>{let l=s.dataset.id;s.dataset.haskids==="1"&&(r[l]=r[l]===!1,X(t,e,l,r,i)),i(l)})}),t.querySelector('[data-tool="expand"]')?.addEventListener("click",()=>{for(let s of Object.keys(r))delete r[s];X(t,e,n,r,i)}),t.querySelector('[data-tool="collapse"]')?.addEventListener("click",()=>{for(let s of e.nodes)r[s.id]=!1;X(t,e,n,r,i)})}var k=t=>document.getElementById(t),_={tab:"context",context:null,code:null,outlineOpen:{}},b=new st(k("graphSvg"));function U(){return _.tab==="context"?_.context:_.code}function kt(){return _.tab==="code"||_.tab==="outline"?"code":"context"}function _t(){let t=k("edgeChips");t.innerHTML='<span class="cap">Edges</span>';let e=U();if(!e)return;let n=new Map;for(let i of e.edges){let o=tt(i.relation);n.set(o,(n.get(o)??0)+1)}let r=[...n.keys()].sort((i,o)=>{let a=p=>p==="part of"?0:p==="uses"?1:2;return a(i)-a(o)||i.localeCompare(o)});for(let i of r){let o=document.createElement("button");o.type="button",o.className="echip"+(b.hiddenRels[i]?"":" on"),o.innerHTML=`${Ae(i)} ${i} <span style="opacity:.55">${n.get(i)}</span>`,o.title=(Nt[i]??`"${i}" edges`)+" \u2014 click to "+(b.hiddenRels[i]?"show":"hide"),o.addEventListener("click",()=>{b.hiddenRels[i]=!b.hiddenRels[i],_t(),b.restyle(),Mt()}),t.appendChild(o)}}function Ae(t){let e=t==="part of"?"structure":t==="uses"?"dependency":Y(t.replace(/ /g,"_"));return{structure:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="19" y2="4" stroke="currentColor" stroke-width="3" opacity=".5"/></svg>',dependency:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="14" y2="4" stroke="currentColor" stroke-width="1.6"/><path d="M14,1 L19,4 L14,7 z" fill="currentColor"/></svg>',contract:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="13" y2="4" stroke="currentColor" stroke-width="1.4"/><path d="M13,1 L19,4 L13,7 z" fill="none" stroke="currentColor" stroke-width="1.2"/></svg>',association:'<svg width="20" height="8" aria-hidden="true"><line x1="1" y1="4" x2="19" y2="4" stroke="currentColor" stroke-width="1.4" stroke-dasharray="2 4" opacity=".7"/></svg>'}[e]}function Et(){let t=k("legend");t.innerHTML="";let e=U();if(!e)return;let n=new Map;for(let r of e.nodes)n.set(r.type,(n.get(r.type)??0)+1);for(let[r,i]of n){let o=document.createElement("button");o.type="button",o.className="lchip"+(b.hiddenTypes[r]?" off":""),o.innerHTML=`<span class="sw" style="background:${M(P(kt(),r))}"></span>${r} <span style="color:var(--muted);font-weight:500">${i}</span>`,o.addEventListener("click",()=>{b.hiddenTypes[r]=!b.hiddenTypes[r],Et(),b.restyle(),Mt()}),t.appendChild(o)}}function Mt(){let t=U();if(!t){k("lcount").textContent="";return}let e=t.nodes.filter(n=>!b.hiddenTypes[n.type]).length;k("lcount").textContent=`${e} / ${t.nodes.length} nodes shown`}function Se(){let t=k("counts");if(_.tab==="outline"&&_.code){let e=_.code.nodes.filter(n=>n.type==="file").length;t.textContent=`${e} files \xB7 ${_.code.nodes.length} symbols`}else{let e=U();t.textContent=e?`${e.meta.nodeCount} nodes \xB7 ${e.meta.edgeCount} links`:""}}function j(t){se(k("detail"),_.tab==="context"?_.context:_.code,kt(),t,e=>{_.tab==="outline"?(j(e),X(k("tree"),_.code,e,_.outlineOpen,j)):b.focus(e)})}b.onSelect=t=>j(t);function ce(t){_.tab=t,document.querySelectorAll(".tab").forEach(r=>{r.setAttribute("aria-selected",r.dataset.tab===t?"true":"false")});let e=t==="outline";k("canvasWrap").hidden=e,k("outlineView").hidden=!e,b.hiddenRels={},b.hiddenTypes={},b.selected=null,j(null);let n=k("graphEmpty");if(t==="outline")_.code?X(k("tree"),_.code,null,_.outlineOpen,j):(k("outlineView").hidden=!0,k("canvasWrap").hidden=!1,ae('No code graph yet \u2014 run <code>graft graph</code> to generate <span class="mono">graph.json</span>.'));else{let r=U();!r||r.nodes.length===0?ae(r?.meta.emptyNote?$e(r.meta.emptyNote):t==="code"?'No code graph yet \u2014 run <code>graft graph</code> to generate <span class="mono">graph.json</span>.':"No context graph \u2014 run <code>graft init</code> first."):(n.hidden=!0,b.resetView(),b.setData(r,kt()),b.reheat())}_t(),Et(),Mt(),Se()}function $e(t){return t.replace(/&/g,"&").replace(/</g,"<")}function ae(t){let e=k("graphEmpty");e.innerHTML=t,e.hidden=!1}document.querySelectorAll(".tab").forEach(t=>{t.addEventListener("click",()=>ce(t.dataset.tab))});var wt=k("search");wt.addEventListener("input",()=>{b.query=wt.value.trim(),b.restyle()});wt.addEventListener("keydown",t=>{if(t.key==="Enter"&&b.query){let e=b.firstMatch();e&&b.focus(e.id)}});k("zin").addEventListener("click",()=>b.zoomBy(1.25));k("zout").addEventListener("click",()=>b.zoomBy(1/1.25));k("zreset").addEventListener("click",()=>b.resetView());var de="graft-viz-theme",le=localStorage.getItem(de);le&&document.documentElement.setAttribute("data-theme",le);k("themeBtn").addEventListener("click",()=>{let t=document.documentElement,e=t.getAttribute("data-theme"),n=window.matchMedia("(prefers-color-scheme: dark)").matches,i=(e?e==="dark":n)?"light":"dark";t.setAttribute("data-theme",i),localStorage.setItem(de,i),b.restyle(),_t(),Et(),j(b.selected)});var ue="graft-viz-detail-w",bt=220,Ve=document.documentElement,ze=t=>Math.min(Math.max(bt,Math.round(window.innerWidth*.6)),Math.max(bt,Math.round(t)));function Ct(t,e=!0){let n=ze(t);Ve.style.setProperty("--detail-w",`${n}px`),e&&localStorage.setItem(ue,String(n))}var xt=Number(localStorage.getItem(ue));Number.isFinite(xt)&&xt>=bt&&Ct(xt,!1);var W=k("detailResizer"),at=!1;W.addEventListener("pointerdown",t=>{let e=t;at=!0,W.setPointerCapture(e.pointerId),document.body.style.cursor="col-resize",t.preventDefault()});W.addEventListener("pointermove",t=>{at&&Ct(window.innerWidth-t.clientX)});var fe=t=>{if(at){at=!1,document.body.style.cursor="";try{W.releasePointerCapture(t.pointerId)}catch{}b.reheat()}};W.addEventListener("pointerup",fe);W.addEventListener("pointercancel",fe);W.addEventListener("keydown",t=>{let e=t;if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;let n=e.shiftKey?40:16,r=k("detail").getBoundingClientRect().width;Ct(r+(e.key==="ArrowLeft"?n:-n)),b.reheat(),t.preventDefault()});async function he(){let[t,e]=await Promise.all([Tt(),At()]);_.context=t,_.code=e;let n=[t.meta.repoName,t.meta.subtitle].filter(Boolean).join(" \xB7 ");k("repoName").textContent=n,document.title=`graft viz \u2014 ${n}`;let r=t.meta.tabs;r&&document.querySelectorAll(".tab").forEach(o=>{o.hidden=!r.includes(o.dataset.tab)});let i=t.meta.defaultTab;ce(i&&i!==_.tab?i:_.tab)}St(()=>{let t=b.selected;he().then(()=>{t&&(b.selected=t,b.restyle(),j(t))})});he();
|
package/dist/viewer/index.html
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
<div class="outline" id="outlineView" hidden>
|
|
41
41
|
<div class="tree" id="tree"></div>
|
|
42
42
|
</div>
|
|
43
|
+
<div class="resizer" id="detailResizer" role="separator" aria-orientation="vertical" aria-label="Resize details panel" tabindex="0" title="Drag to resize"></div>
|
|
43
44
|
<aside class="detail" id="detail"><div class="empty">Select a node to view details</div></aside>
|
|
44
45
|
</main>
|
|
45
46
|
|
package/dist/viewer/style.css
CHANGED
|
@@ -83,7 +83,11 @@ svg.graph:active{cursor:grabbing}
|
|
|
83
83
|
.zoomctl{position:absolute;right:14px;bottom:14px;display:flex;flex-direction:column;gap:6px}
|
|
84
84
|
.zoomctl .iconbtn{background:var(--panel)}
|
|
85
85
|
|
|
86
|
-
.
|
|
86
|
+
.resizer{flex:none;width:9px;margin:0 -4px;z-index:6;cursor:col-resize;position:relative;touch-action:none}
|
|
87
|
+
.resizer::before{content:"";position:absolute;top:0;bottom:0;left:4px;width:1px;background:var(--border)}
|
|
88
|
+
.resizer:hover::before,.resizer:focus-visible::before{left:3px;width:3px;background:var(--accent)}
|
|
89
|
+
.resizer:focus-visible{outline:none}
|
|
90
|
+
.detail{width:var(--detail-w,300px);flex:none;border-left:1px solid var(--border);background:var(--panel);overflow-y:auto;padding:18px 18px 24px}
|
|
87
91
|
.detail .empty{color:var(--muted);font-size:13.5px;text-align:center;margin-top:200px}
|
|
88
92
|
.d-type{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;padding:3px 10px;border-radius:20px;background:var(--chip)}
|
|
89
93
|
.d-type .sw{width:8px;height:8px;border-radius:50%}
|
|
@@ -116,4 +120,21 @@ svg.graph:active{cursor:grabbing}
|
|
|
116
120
|
.emptytab code{background:var(--chip);padding:2px 8px;border-radius:6px;font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace;font-size:.9em}
|
|
117
121
|
|
|
118
122
|
@media (prefers-reduced-motion:reduce){ .tree-row .chev{transition:none} }
|
|
119
|
-
@media (max-width:760px){ .detail{display:none} .searchbox input{width:120px} .counts{display:none} }
|
|
123
|
+
@media (max-width:760px){ .detail,.resizer{display:none} .searchbox input{width:120px} .counts{display:none} }
|
|
124
|
+
/* Evidence blocks: a snippet under a node, so a panel shows the change rather
|
|
125
|
+
than a line number the reader has to go and look up. */
|
|
126
|
+
.ev{margin:7px 0 11px;border:1px solid var(--line);border-radius:7px;overflow:hidden}
|
|
127
|
+
.ev-h{font-size:11px;padding:5px 8px;background:var(--chip);color:var(--fg);border-bottom:1px solid var(--line);overflow-wrap:anywhere}
|
|
128
|
+
.ev-note{color:var(--muted);font-style:italic}
|
|
129
|
+
.ev-b{font-size:11.5px;padding:4px 0;overflow-x:auto}
|
|
130
|
+
.ev-l{display:flex;gap:8px;padding:1px 8px}
|
|
131
|
+
.ev-n{color:var(--muted);opacity:.65;min-width:2.6em;text-align:right;user-select:none;flex:none}
|
|
132
|
+
.ev-s{width:.7em;user-select:none;flex:none}
|
|
133
|
+
/* Wrapped, not scrolled: the panel is ~280px and a diff line is longer than
|
|
134
|
+
that, so a horizontal scrollbar per hunk would hide the half that matters. */
|
|
135
|
+
.ev-t{flex:1;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
136
|
+
.ev-l.add{background:color-mix(in srgb,var(--ok,#2E9E6B) 11%,transparent)}
|
|
137
|
+
.ev-l.del{background:color-mix(in srgb,var(--warn,#D9534F) 10%,transparent)}
|
|
138
|
+
.ev-l.add .ev-s{color:var(--ok,#2E9E6B)}
|
|
139
|
+
.ev-l.del .ev-s{color:var(--warn,#D9534F)}
|
|
140
|
+
.ev-more{font-size:11px;color:var(--muted);padding:3px 9px 5px}
|