pi-weave 0.1.7 → 0.1.9
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 +123 -37
- package/package.json +17 -5
- package/skills/weave-notepad/SKILL.md +13 -4
- package/src/core/cache/workspace.ts +466 -0
- package/src/core/concurrency.ts +36 -0
- package/src/core/frontmatter.ts +270 -23
- package/src/core/git.ts +19 -0
- package/src/core/graph/build.ts +97 -5
- package/src/core/graph/current.ts +41 -28
- package/src/core/graph/mentions.ts +170 -0
- package/src/core/graph/model.ts +39 -0
- package/src/core/graph/wikilinks.ts +5 -1
- package/src/core/index.ts +14 -0
- package/src/core/openInEditor.ts +69 -0
- package/src/core/paths.ts +7 -0
- package/src/core/sessions.ts +929 -0
- package/src/core/summaries.ts +1 -19
- package/src/core/types.ts +40 -0
- package/src/core/vault.ts +739 -57
- package/src/core/view/cluster.ts +262 -0
- package/src/core/view/detail.ts +118 -0
- package/src/core/view/focus.ts +109 -0
- package/src/core/view/health.ts +156 -0
- package/src/core/view/index.ts +15 -0
- package/src/core/view/links.ts +105 -0
- package/src/core/view/time.ts +47 -0
- package/src/core/view/tree.ts +269 -0
- package/src/core/view/types.ts +39 -0
- package/src/core/workspace.ts +3 -3
- package/src/pi/index.ts +248 -48
- package/src/pi/sessionScan.ts +104 -0
- package/src/pi/summarize.ts +24 -4
- package/src/pi/tools/noteTool.ts +13 -4
- package/src/pi/viewer/tui/branding.ts +8 -7
- package/src/pi/viewer/tui/explorer.ts +5 -3
- package/src/pi/viewer/tui/model.ts +46 -667
- package/src/pi/viewer/tui/openNote.ts +7 -56
- package/src/pi/viewer/tui/surface/explore.ts +4 -2
- package/src/pi/viewer/web/run.ts +331 -0
- package/src/web/client/api.dom.ts +40 -0
- package/src/web/client/api.ts +472 -0
- package/src/web/client/bootstrap.ts +58 -0
- package/src/web/client/context/context.model.ts +313 -0
- package/src/web/client/dist/app.js +764 -0
- package/src/web/client/graph/Graph.tsx +209 -0
- package/src/web/client/graph/column.model.ts +372 -0
- package/src/web/client/graph/dynamics.ts +176 -0
- package/src/web/client/graph/graph.model.ts +546 -0
- package/src/web/client/graph/positions.ts +380 -0
- package/src/web/client/graph/project.ts +153 -0
- package/src/web/client/graph/renderer.dom.ts +52 -0
- package/src/web/client/graph/renderer.ts +339 -0
- package/src/web/client/graph/scheme.ts +44 -0
- package/src/web/client/live.model.ts +275 -0
- package/src/web/client/live.ts +151 -0
- package/src/web/client/main.tsx +27 -0
- package/src/web/client/note/Editor.tsx +102 -0
- package/src/web/client/note/Note.tsx +113 -0
- package/src/web/client/note/editor.controller.ts +151 -0
- package/src/web/client/note/editor.model.ts +636 -0
- package/src/web/client/note/note.model.ts +738 -0
- package/src/web/client/search/SearchPalette.tsx +105 -0
- package/src/web/client/search/search.model.ts +588 -0
- package/src/web/client/search/search.ts +107 -0
- package/src/web/client/selection.storage.ts +69 -0
- package/src/web/client/shell/Columns.tsx +161 -0
- package/src/web/client/shell/ContextRail.tsx +87 -0
- package/src/web/client/shell/Divider.tsx +44 -0
- package/src/web/client/shell/FocusTrap.tsx +56 -0
- package/src/web/client/shell/Header.tsx +64 -0
- package/src/web/client/shell/HelpOverlay.tsx +70 -0
- package/src/web/client/shell/Shell.tsx +210 -0
- package/src/web/client/shell/StatusBar.tsx +28 -0
- package/src/web/client/shell/cssvars.ts +70 -0
- package/src/web/client/shell/drag.model.ts +170 -0
- package/src/web/client/shell/focus.model.ts +100 -0
- package/src/web/client/shell/keys.model.ts +453 -0
- package/src/web/client/shell/keys.ts +59 -0
- package/src/web/client/shell/layout.model.ts +526 -0
- package/src/web/client/shell/shell.model.ts +333 -0
- package/src/web/client/shell/theme.ts +490 -0
- package/src/web/client/shell/viewport.ts +29 -0
- package/src/web/client/state.ts +89 -0
- package/src/web/client/tree/Tree.tsx +141 -0
- package/src/web/client/tree/tree.model.ts +674 -0
- package/src/web/client/workspace.ts +278 -0
- package/src/web/server/page.ts +258 -0
- package/src/web/server/routes.ts +987 -0
- package/src/web/server/security.ts +361 -0
- package/src/web/server/server.ts +275 -0
- package/src/web/server/sse.ts +321 -0
- package/src/web/server/watcher.ts +507 -0
- package/src/web/shared/graph.ts +213 -0
- package/src/web/shared/layout.ts +314 -0
- package/src/web/shared/logo.ts +11 -0
- package/src/web/shared/metrics.ts +136 -0
- package/src/web/shared/view.ts +200 -0
- package/src/web/shared/wire.ts +358 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live force dynamics for the graph's current shape — the Obsidian-style
|
|
3
|
+
* "the graph is alive" feel while the user drags.
|
|
4
|
+
*
|
|
5
|
+
* ## One physics, two drivers
|
|
6
|
+
*
|
|
7
|
+
* The static layout (`shared/layout.ts`) and this module now share ONE force
|
|
8
|
+
* configuration: {@link createForceSimulation}. They used to be two
|
|
9
|
+
* independent physics — the static path ring-sized its link distances per
|
|
10
|
+
* fan-out and anchored every node to its seed; this one pulled at a flat 90
|
|
11
|
+
* units toward its own equilibrium. Every graph therefore *visibly re-laid
|
|
12
|
+
* itself* after mount (a 215-node repo graph migrated from a ~1200-unit ring
|
|
13
|
+
* to the bespoke sim's ~300-unit cloud over about thirty seconds), and the
|
|
14
|
+
* constant-alpha loop ticked at 60 fps forever, because a bespoke integrator
|
|
15
|
+
* has no alpha to decay. Sharing the factory fixes both by construction: the
|
|
16
|
+
* warm start is already at the shared equilibrium, so there is nothing to
|
|
17
|
+
* migrate to, and d3's alpha decay is what says "settled".
|
|
18
|
+
*
|
|
19
|
+
* ## The lifecycle
|
|
20
|
+
*
|
|
21
|
+
* A new engine starts at {@link SETTLE_ALPHA} (an expand/collapse lands new
|
|
22
|
+
* nodes already laid out; the brief settle is the "alive" response, not a
|
|
23
|
+
* re-layout) and decays to d3's alpha floor, at which point {@link awake}
|
|
24
|
+
* turns false and the component's clock puts itself to sleep — no frames are
|
|
25
|
+
* spent on a graph that is holding still. `pin` re-heats to
|
|
26
|
+
* {@link DRAG_ALPHA_TARGET} (d3's own drag pattern), so neighbours make room
|
|
27
|
+
* while the user drags; `release` clears the pin AND retargets the node's
|
|
28
|
+
* anchor to its drop point, so a dragged node stays where it was dropped
|
|
29
|
+
* instead of springing back to its seed.
|
|
30
|
+
*
|
|
31
|
+
* ## The §7.2 vertical-line freeze
|
|
32
|
+
*
|
|
33
|
+
* Inherited from d3 itself: `manyBody`, `collide` and `link` all inject a
|
|
34
|
+
* seeded `jiggle` into a zero axis component, so coincident or collinear
|
|
35
|
+
* nodes always acquire a direction. The seeded LCG (`seed: 1`) keeps the
|
|
36
|
+
* whole thing deterministic — the same graph, the same gestures, byte-identical
|
|
37
|
+
* positions — which is what the test gate asserts.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import type { Point } from "../../shared/layout";
|
|
41
|
+
import { createForceSimulation, isContainment } from "../../shared/layout";
|
|
42
|
+
import type { WireEdgeKind } from "../../shared/graph";
|
|
43
|
+
import type { RenderGraph } from "./graph.model";
|
|
44
|
+
|
|
45
|
+
interface SimNode {
|
|
46
|
+
id: string;
|
|
47
|
+
x?: number;
|
|
48
|
+
y?: number;
|
|
49
|
+
vx?: number;
|
|
50
|
+
vy?: number;
|
|
51
|
+
index?: number;
|
|
52
|
+
fx?: number | null;
|
|
53
|
+
fy?: number | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface SimLink {
|
|
57
|
+
source: string | SimNode;
|
|
58
|
+
target: string | SimNode;
|
|
59
|
+
kind: WireEdgeKind;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface GraphSimulation {
|
|
63
|
+
tick(): void;
|
|
64
|
+
positions(): Map<string, Point>;
|
|
65
|
+
pin(id: string, at: Point): void;
|
|
66
|
+
release(id: string): void;
|
|
67
|
+
/** `false` once the alpha floor is reached — the graph is holding still, and the clock can sleep. */
|
|
68
|
+
awake(): boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Re-heat on creation (mount, expand, collapse): brief and local, never a re-layout. */
|
|
72
|
+
const SETTLE_ALPHA = 0.06;
|
|
73
|
+
/**
|
|
74
|
+
* The drag alpha target. The balance the user feels: too low and the
|
|
75
|
+
* neighbours read as stiff and lazy while the node moves; too high and the
|
|
76
|
+
* whole tree thrashes (measured: the hub drag peaks at ~950px/s of per-node
|
|
77
|
+
* ripple at 0.3 with rigid links, ~174px/s at 0.2 with the soft springs —
|
|
78
|
+
* lively, and an order of magnitude inside the crazy regime).
|
|
79
|
+
*/
|
|
80
|
+
const DRAG_ALPHA_TARGET = 0.2;
|
|
81
|
+
/** d3-force's alpha floor. */
|
|
82
|
+
const ALPHA_MIN = 0.001;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build a live simulation over a {@link RenderGraph}.
|
|
86
|
+
*
|
|
87
|
+
* `initial`, when given, is the warm start: existing ids keep their current
|
|
88
|
+
* positions (so a drag or an expand does not make the graph jump), and ids it
|
|
89
|
+
* does not name fall back to the graph's own laid-out positions. Those warm
|
|
90
|
+
* positions are also the anchor targets, so the graph rests exactly where the
|
|
91
|
+
* layout left it.
|
|
92
|
+
*
|
|
93
|
+
* Returns `null` for an empty graph — there is nothing to simulate, and an
|
|
94
|
+
* empty `Map` every frame is work for nothing.
|
|
95
|
+
*/
|
|
96
|
+
export function createGraphSimulation(graph: RenderGraph, initial?: ReadonlyMap<string, Point>): GraphSimulation | null {
|
|
97
|
+
if (graph.nodes.length === 0) return null;
|
|
98
|
+
|
|
99
|
+
const nodes: SimNode[] = graph.nodes.map((node) => {
|
|
100
|
+
const at = initial?.get(node.id);
|
|
101
|
+
return {
|
|
102
|
+
id: node.id,
|
|
103
|
+
x: at !== undefined && Number.isFinite(at.x) ? at.x : node.x,
|
|
104
|
+
y: at !== undefined && Number.isFinite(at.y) ? at.y : node.y,
|
|
105
|
+
vx: 0,
|
|
106
|
+
vy: 0,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
110
|
+
|
|
111
|
+
// Dangling endpoints and self-edges are a degenerate *input*; forceLink
|
|
112
|
+
// would throw on them, so they are dropped here and the layout's own
|
|
113
|
+
// `pathologicalGraph` fixture remains the gate for degenerate *outputs*.
|
|
114
|
+
const seen = new Set<string>();
|
|
115
|
+
const links: SimLink[] = [];
|
|
116
|
+
for (const edge of graph.edges) {
|
|
117
|
+
if (edge.source === edge.target) continue;
|
|
118
|
+
if (!byId.has(edge.source) || !byId.has(edge.target)) continue;
|
|
119
|
+
const key = `${edge.source}\u0000${edge.target}\u0000${edge.kind}`;
|
|
120
|
+
if (seen.has(key)) continue;
|
|
121
|
+
seen.add(key);
|
|
122
|
+
links.push({ source: edge.source, target: edge.target, kind: edge.kind });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// No invented seeding; centre gravity lives in the factory (`forceX()`/
|
|
126
|
+
// `forceY()`). `anchors` starts empty — every node targets the origin — and
|
|
127
|
+
// grows on release: a dropped node's anchor is retargeted to its drop point,
|
|
128
|
+
// so placement sticks (the anchor is five times stronger than the leaf
|
|
129
|
+
// spring, so the node rests where the user left it).
|
|
130
|
+
const anchors = new Map<string, Point>();
|
|
131
|
+
const sim = createForceSimulation({ nodes, links, anchors, seed: 1 })
|
|
132
|
+
.alpha(SETTLE_ALPHA)
|
|
133
|
+
.alphaMin(ALPHA_MIN);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
tick() {
|
|
137
|
+
sim.tick();
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
awake() {
|
|
141
|
+
// A held alpha target is motion about to happen — the clock must stay
|
|
142
|
+
// armed even while alpha itself is still converging up to the target.
|
|
143
|
+
return sim.alphaTarget() > ALPHA_MIN || sim.alpha() > ALPHA_MIN;
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
positions() {
|
|
147
|
+
return new Map(nodes.map((node) => [node.id, { x: node.x ?? 0, y: node.y ?? 0 }]));
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
pin(id, at) {
|
|
151
|
+
const node = byId.get(id);
|
|
152
|
+
if (!node) return;
|
|
153
|
+
// d3's canonical drag, from the force-directed graph example: fix the
|
|
154
|
+
// subject at the pointer and hold the alpha target up so the neighbours
|
|
155
|
+
// make room, then cool on release. A pinned node is immune to every
|
|
156
|
+
// force — the drag must not fight the sim, or the node would shudder
|
|
157
|
+
// under its own neighbours.
|
|
158
|
+
node.fx = at.x;
|
|
159
|
+
node.fy = at.y;
|
|
160
|
+
sim.alphaTarget(DRAG_ALPHA_TARGET);
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
release(id) {
|
|
164
|
+
const node = byId.get(id);
|
|
165
|
+
if (!node) return;
|
|
166
|
+
// Unfix, like d3's `dragended` — and retarget the node's centre-gravity
|
|
167
|
+
// anchor to the drop point, so the graph reads the drop as a placement:
|
|
168
|
+
// the node rests where the user left it instead of gliding back into
|
|
169
|
+
// the tree.
|
|
170
|
+
anchors.set(id, { x: node.x ?? 0, y: node.y ?? 0 });
|
|
171
|
+
node.fx = null;
|
|
172
|
+
node.fy = null;
|
|
173
|
+
sim.alphaTarget(0);
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|