visualproof 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -33
- package/dist/assets/tips/phone-fingers.light.mp4 +0 -0
- package/dist/assets/tips/phone-fingers.light.webp +0 -0
- package/dist/assets/tips/tour-agent.webp +0 -0
- package/dist/assets/tips/tour-arrange.webp +0 -0
- package/dist/assets/tips/tour-artwork.webp +0 -0
- package/dist/assets/tips/tour-checks.webp +0 -0
- package/dist/assets/tips/tour-export.webp +0 -0
- package/dist/assets/tips/tour-keys.webp +0 -0
- package/dist/assets/tips/tour-library.webp +0 -0
- package/dist/assets/tips/tour-project.webp +0 -0
- package/dist/assets/tips/tour-review.webp +0 -0
- package/dist/assets/tips/tour-share.webp +0 -0
- package/dist/assets/tips/tour-source.webp +0 -0
- package/dist/assets/tips/tour-target.webp +0 -0
- package/dist/assets/tips/tour-view.webp +0 -0
- package/dist/assets/tips/tour.json +289 -0
- package/dist/assets/tips/tour.webp +0 -0
- package/dist/assets/webfonts/LICENSE-Noto.txt +95 -0
- package/dist/assets/webfonts/metrics.json +1 -0
- package/dist/assets/webfonts/ttf/jost-400-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/jost-500-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/noto-sans-math.ttf +0 -0
- package/dist/assets/webfonts/ttf/noto-sans.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-400-italic.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-400-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-500-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-600-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-700-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-serif-4-400-italic.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-serif-4-600-italic.ttf +0 -0
- package/dist/mcp/visualproof-mcp.mjs +3 -1
- package/dist/server/agent.js +94 -91
- package/dist/server/agentdocs.js +1 -1
- package/dist/server/artcmd.js +335 -0
- package/dist/server/children.js +85 -0
- package/dist/server/doctor.js +105 -42
- package/dist/server/events.js +10 -0
- package/dist/server/export.js +11 -4
- package/dist/server/extract.js +3 -2
- package/dist/server/figures.js +3 -2
- package/dist/server/film.js +380 -0
- package/dist/server/history.js +11 -1
- package/dist/server/hover.js +8 -5
- package/dist/server/live.js +72 -9
- package/dist/server/main.js +352 -23
- package/dist/server/mcptools.js +4 -1
- package/dist/server/media.js +114 -0
- package/dist/server/pipeline.js +21 -10
- package/dist/server/poppler.js +3 -2
- package/dist/server/readonlygate.js +4 -4
- package/dist/server/review.js +4 -1
- package/dist/server/reviewapi.js +35 -1
- package/dist/server/snapshot.js +10 -1
- package/dist/server/sourcestore.js +3 -2
- package/dist/server/status.js +3 -2
- package/dist/server/supervise.js +219 -0
- package/dist/server/updates.js +951 -0
- package/dist/server/usage.js +3 -1
- package/dist/server/version.js +183 -0
- package/dist/server/view.js +0 -7
- package/dist/server/views.js +24 -0
- package/dist/shared/artfonts.js +81 -0
- package/dist/shared/artrecipe.js +316 -0
- package/dist/shared/collab.js +7 -2
- package/dist/shared/declfind.js +95 -0
- package/dist/shared/lostfound.js +1 -0
- package/dist/shared/pastgraph.js +6 -6
- package/dist/shared/review.js +62 -5
- package/dist/shared/timeline.js +5 -0
- package/dist/web/bundle/app.js +3006 -413
- package/dist/web/bundle/edges.js +1 -1
- package/dist/web/index.html +13 -1
- package/dist/web/src/agentmark.js +14 -0
- package/dist/web/src/artwork.js +1000 -0
- package/dist/web/src/bundles.js +151 -0
- package/dist/web/src/canvas.js +3716 -0
- package/dist/web/src/drag.js +61 -0
- package/dist/web/src/edgequeue.js +204 -0
- package/dist/web/src/gl/gl.js +123 -0
- package/dist/web/src/gl/renderer.js +451 -0
- package/dist/web/src/halo.js +95 -0
- package/dist/web/src/highlight.js +108 -0
- package/dist/web/src/overview.js +393 -0
- package/dist/web/src/reviewqueue.js +250 -0
- package/dist/web/src/selection.js +272 -0
- package/dist/web/src/status.js +80 -0
- package/dist/web/src/visitors.js +318 -0
- package/dist/web/src/visits.js +174 -0
- package/dist/web/style.css +196 -1
- package/docs/agent-api/README.md +1 -1
- package/docs/agent-api/export.md +41 -2
- package/docs/agent-api/history.md +5 -3
- package/docs/agent-api/mcp.md +1 -1
- package/docs/agent-api/reading.md +2 -1
- package/package.json +5 -1
package/dist/server/live.js
CHANGED
|
@@ -39,6 +39,8 @@ import { join } from "node:path";
|
|
|
39
39
|
import { PROJECT, viewTitle } from "../shared/views.js";
|
|
40
40
|
import { boardSet } from "../shared/board.js";
|
|
41
41
|
import { derivesOn, existsIn } from "../shared/noteplace.js";
|
|
42
|
+
import { packageVersion } from "./version.js";
|
|
43
|
+
import { withoutReasons } from "../shared/timeline.js";
|
|
42
44
|
const TICK = 1000;
|
|
43
45
|
/** outputs quiet this long, and no compile running: the build is over */
|
|
44
46
|
const SETTLE = 2500;
|
|
@@ -58,8 +60,6 @@ export const MAX_BUFFERED = 4 << 20;
|
|
|
58
60
|
const PRESENCE_EVERY = 500;
|
|
59
61
|
/** The graph's modules and their files (meta.modules), per graph read (agentviews.ts, graphOf). */
|
|
60
62
|
const moduleFiles = new WeakMap();
|
|
61
|
-
/** What a stream's page alone is told of it (`hello`). */
|
|
62
|
-
const helloOf = (st) => ({ id: st.id, token: st.token, ...(st.private ? { private: true } : {}) });
|
|
63
63
|
export class Live {
|
|
64
64
|
project;
|
|
65
65
|
/** the site directory and the project's caches (server/dirs.ts) */
|
|
@@ -85,6 +85,15 @@ export class Live {
|
|
|
85
85
|
/** review changes not yet sent: those made in one turn of the event loop go out as one */
|
|
86
86
|
reviewPending = [];
|
|
87
87
|
version = 0;
|
|
88
|
+
/** this server's process, as its pages know it (UpdateSpec decision 8): the graph's versions are
|
|
89
|
+
* counted again by another */
|
|
90
|
+
instance = randomBytes(6).toString("base64url");
|
|
91
|
+
/** the VisualProof version this server runs, read as it started */
|
|
92
|
+
toolVersion = packageVersion();
|
|
93
|
+
/** what a page is told of VisualProof's releases (server/updates.ts): everything, or the version
|
|
94
|
+
* alone (`full` false: a read-only reader, an agent); null where nobody follows them (a test's
|
|
95
|
+
* server) */
|
|
96
|
+
updateStatus = null;
|
|
88
97
|
/** the review's logs (ReviewSpec.md, server/review.ts) */
|
|
89
98
|
review;
|
|
90
99
|
/** who has a page open (CollabSpec.md) */
|
|
@@ -140,7 +149,7 @@ export class Live {
|
|
|
140
149
|
this.editor = editor;
|
|
141
150
|
this.usage = new UsagePass(project, dirs, saved ? 0 : jobs, (l) => this.say(l));
|
|
142
151
|
this.tracker = new BuildTracker(project);
|
|
143
|
-
this.timeline = new Timeline(dirs.site, (e) => this.
|
|
152
|
+
this.timeline = new Timeline(dirs.site, (e) => this.sendActivity(e));
|
|
144
153
|
this.tokens = new AgentTokens(dirs.site);
|
|
145
154
|
this.invites = new Invites(dirs.site);
|
|
146
155
|
// every page knows the names the people invited by a link go by, so that what each did shows
|
|
@@ -304,7 +313,7 @@ export class Live {
|
|
|
304
313
|
// a private reader cannot be followed: what they asked is withdrawn
|
|
305
314
|
if (priv)
|
|
306
315
|
this.asks.withdraw(s.token);
|
|
307
|
-
this.write(s.res, "hello", helloOf(s));
|
|
316
|
+
this.write(s.res, "hello", this.helloOf(s));
|
|
308
317
|
if (s.session) {
|
|
309
318
|
if (priv)
|
|
310
319
|
this.views.hold(s.session, was ? [...(was.view ? [was.view] : []), ...was.tabs] : []);
|
|
@@ -660,7 +669,7 @@ export class Live {
|
|
|
660
669
|
written = found.written;
|
|
661
670
|
return found;
|
|
662
671
|
};
|
|
663
|
-
const r = this.history.record(ex.graph, { at: buildTime(this.project), fingerprint: ex.fingerprint, commit, toolchain: this.project.toolchain, missing, sources });
|
|
672
|
+
const r = this.history.record(ex.graph, { at: buildTime(this.project), fingerprint: ex.fingerprint, commit, toolchain: this.project.toolchain, missing, sources, tool: this.toolVersion });
|
|
664
673
|
if (!r.written)
|
|
665
674
|
return renamed;
|
|
666
675
|
const s = r.info;
|
|
@@ -913,6 +922,12 @@ export class Live {
|
|
|
913
922
|
}
|
|
914
923
|
return made;
|
|
915
924
|
}
|
|
925
|
+
/** The holder of a personal link in force who goes by `name` (CollabSpec decision 9): whom an
|
|
926
|
+
* opinion recorded for that name is for (ReviewSpec decision 8). */
|
|
927
|
+
invited(name) {
|
|
928
|
+
const r = this.invites.holder(name);
|
|
929
|
+
return r ? { id: r.id, name: r.name } : undefined;
|
|
930
|
+
}
|
|
916
931
|
/** The usage pass's contexts of a module (shared/context.ts), when the graph on show has them. */
|
|
917
932
|
contextsOf(module) {
|
|
918
933
|
return this.graph?.prep.usage?.contexts[module] ?? null;
|
|
@@ -950,7 +965,53 @@ export class Live {
|
|
|
950
965
|
if (!this.graph)
|
|
951
966
|
return null;
|
|
952
967
|
const { prep: _, ...info } = this.graph;
|
|
953
|
-
return info;
|
|
968
|
+
return { ...info, instance: this.instance };
|
|
969
|
+
}
|
|
970
|
+
/** What a stream's page alone is told of it (`hello`), and which server it is (UpdateSpec
|
|
971
|
+
* decision 8): its version, and its process. */
|
|
972
|
+
helloOf(st) {
|
|
973
|
+
return { id: st.id, token: st.token, ...(st.private ? { private: true } : {}), server: { version: this.toolVersion, instance: this.instance } };
|
|
974
|
+
}
|
|
975
|
+
/** How many pages are open on the server (their event streams), read-only readers' too. */
|
|
976
|
+
get pages() {
|
|
977
|
+
return this.streams.size;
|
|
978
|
+
}
|
|
979
|
+
/** Whether the server is working on the build (an extraction, a re-layout, the usage pass):
|
|
980
|
+
* no moment to restart in (UpdateSpec decision 6). */
|
|
981
|
+
get busy() {
|
|
982
|
+
return this.extracting || this.usage.status.state === "running";
|
|
983
|
+
}
|
|
984
|
+
/** What happened, to every page: a version set aside, without why, to those not told all
|
|
985
|
+
* (UpdateSpec decision 11). */
|
|
986
|
+
sendActivity(e) {
|
|
987
|
+
if (e.kind !== "tool" || !e.setAside)
|
|
988
|
+
return this.send("activity", e);
|
|
989
|
+
const full = `event: activity\ndata: ${JSON.stringify(e)}\n\n`;
|
|
990
|
+
const slim = `event: activity\ndata: ${JSON.stringify(withoutReasons(e))}\n\n`;
|
|
991
|
+
for (const st of [...this.streams.values()])
|
|
992
|
+
this.push(st, st.toldAll ? full : slim);
|
|
993
|
+
}
|
|
994
|
+
/** What is known of VisualProof's releases changed: each page is told what it may know of it
|
|
995
|
+
* (`toldAll`, as GET /api/updates says it). */
|
|
996
|
+
updatesChanged() {
|
|
997
|
+
const status = this.updateStatus;
|
|
998
|
+
if (!status)
|
|
999
|
+
return;
|
|
1000
|
+
const full = `event: updates\ndata: ${JSON.stringify(status(true))}\n\n`;
|
|
1001
|
+
const slim = `event: updates\ndata: ${JSON.stringify(status(false))}\n\n`;
|
|
1002
|
+
for (const st of [...this.streams.values()])
|
|
1003
|
+
this.push(st, st.toldAll ? full : slim);
|
|
1004
|
+
}
|
|
1005
|
+
/** The server stops (UpdateSpec decision 9): every page is told why — a restart into another
|
|
1006
|
+
* version (`update`), or a stop (`bye`) — and its stream ended, so that it comes back to the
|
|
1007
|
+
* server that answers next. */
|
|
1008
|
+
end(why) {
|
|
1009
|
+
const text = "update" in why ? `event: update\ndata: ${JSON.stringify(why.update)}\n\n` : `event: bye\ndata: ${JSON.stringify({ why: "stopped" })}\n\n`;
|
|
1010
|
+
for (const st of [...this.streams.values()]) {
|
|
1011
|
+
this.streams.delete(st.res);
|
|
1012
|
+
this.byToken.delete(st.token);
|
|
1013
|
+
st.res.end(text);
|
|
1014
|
+
}
|
|
954
1015
|
}
|
|
955
1016
|
/** What /api/status says: enough for the loader and for a page that just connected. */
|
|
956
1017
|
status() {
|
|
@@ -975,7 +1036,7 @@ export class Live {
|
|
|
975
1036
|
* it), `person` the personal link it came by. The stream is named by the server: the page is
|
|
976
1037
|
* told its id, which everyone sees, and a secret for its heartbeats (`hello`); it is gone from
|
|
977
1038
|
* presence when its stream closes. */
|
|
978
|
-
subscribe(res, session = null, person = null, readOnly = null) {
|
|
1039
|
+
subscribe(res, session = null, person = null, readOnly = null, toldAll = readOnly === null) {
|
|
979
1040
|
if (session) {
|
|
980
1041
|
// a page that opens one more than a page needs (a reload whose old stream lingers) loses
|
|
981
1042
|
// its oldest
|
|
@@ -995,12 +1056,14 @@ export class Live {
|
|
|
995
1056
|
connection: "keep-alive",
|
|
996
1057
|
});
|
|
997
1058
|
res.write("retry: 2000\n\n");
|
|
998
|
-
const st = { res, id: randomBytes(9).toString("base64url"), token: randomBytes(24).toString("base64url"), session, private: false, person, readOnly };
|
|
1059
|
+
const st = { res, id: randomBytes(9).toString("base64url"), token: randomBytes(24).toString("base64url"), session, private: false, person, readOnly, toldAll };
|
|
999
1060
|
this.streams.set(res, st);
|
|
1000
1061
|
this.byToken.set(st.token, st);
|
|
1001
1062
|
this.presence.open(st.id);
|
|
1002
1063
|
res.on("close", () => this.close(st));
|
|
1003
|
-
this.write(res, "hello", helloOf(st));
|
|
1064
|
+
this.write(res, "hello", this.helloOf(st));
|
|
1065
|
+
if (this.updateStatus)
|
|
1066
|
+
this.write(res, "updates", this.updateStatus(st.toldAll));
|
|
1004
1067
|
this.write(res, "presence", this.presence.list());
|
|
1005
1068
|
this.write(res, "private", { count: this.presence.privateCount() });
|
|
1006
1069
|
this.write(res, "people", this.invites.people());
|