@giamme/forge 0.0.0-stage → 0.9.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/CHANGELOG.md +205 -0
- package/LICENSE +21 -0
- package/README.md +194 -2
- package/SKILL.md +123 -0
- package/VERSION +1 -0
- package/docs/README.md +26 -0
- package/docs/add-ons.md +33 -0
- package/docs/artifacts.md +69 -0
- package/docs/commands.md +315 -0
- package/docs/dataset.md +20 -0
- package/docs/decomposed-runs.md +268 -0
- package/docs/development.md +95 -0
- package/docs/forge-ui.md +92 -0
- package/docs/fractal.md +181 -0
- package/docs/install.md +160 -0
- package/docs/memory.md +156 -0
- package/docs/models.md +118 -0
- package/docs/reviews.md +231 -0
- package/docs/safety.md +55 -0
- package/docs/troubleshooting.md +54 -0
- package/forge +79 -0
- package/package.json +27 -4
- package/references/dataset.md +329 -0
- package/references/decompose.md +667 -0
- package/references/fractal-dashboard.md +21 -0
- package/references/fractal.md +307 -0
- package/references/harnesses.md +365 -0
- package/references/jev.md +865 -0
- package/references/memory.md +228 -0
- package/references/planning.md +42 -0
- package/references/ripwire.md +47 -0
- package/references/runtime.md +64 -0
- package/references/solo.md +113 -0
- package/references/ui.md +112 -0
- package/registry.tsv +81 -0
- package/scripts/forge-artifact.sh +78 -0
- package/scripts/forge-contract.py +430 -0
- package/scripts/forge-dataset.py +6 -0
- package/scripts/forge-dispatch.sh +671 -0
- package/scripts/forge-fail-first.py +195 -0
- package/scripts/forge-fractal-dispatch.sh +4 -0
- package/scripts/forge-fractal-options.sh +54 -0
- package/scripts/forge-fractal.py +6 -0
- package/scripts/forge-guard.py +266 -0
- package/scripts/forge-install-fractal.sh +4 -0
- package/scripts/forge-install-ripwire.sh +52 -0
- package/scripts/forge-install.sh +135 -0
- package/scripts/forge-jev-options.sh +259 -0
- package/scripts/forge-jev.py +6 -0
- package/scripts/forge-lib-plans.sh +785 -0
- package/scripts/forge-lib-review.sh +494 -0
- package/scripts/forge-lib-task.sh +302 -0
- package/scripts/forge-lib-verify.sh +30 -0
- package/scripts/forge-memory.sh +575 -0
- package/scripts/forge-metrics.sh +39 -0
- package/scripts/forge-parallel-options.sh +76 -0
- package/scripts/forge-parallel.sh +1717 -0
- package/scripts/forge-plan-check.py +118 -0
- package/scripts/forge-prompt.py +45 -0
- package/scripts/forge-ripwire.py +136 -0
- package/scripts/forge-route.py +344 -0
- package/scripts/forge-runs.py +121 -0
- package/scripts/forge-runtime.py +586 -0
- package/scripts/forge-schedule.py +312 -0
- package/scripts/forge-shadow.py +305 -0
- package/scripts/forge-solo.sh +347 -0
- package/scripts/forge-ui-options.sh +42 -0
- package/scripts/forge-ui.py +435 -0
- package/scripts/forge-update.sh +71 -0
- package/scripts/forge-verify-coverage.py +956 -0
- package/scripts/forge-version.py +240 -0
- package/scripts/forge_dataset/__init__.py +439 -0
- package/scripts/forge_dataset/capture.py +330 -0
- package/scripts/forge_dataset/checks.py +109 -0
- package/scripts/forge_dataset/cli.py +233 -0
- package/scripts/forge_dataset/export.py +1009 -0
- package/scripts/forge_dataset/harvest.py +716 -0
- package/scripts/forge_dataset/importer.py +412 -0
- package/scripts/forge_dataset/outcomes.py +275 -0
- package/scripts/forge_dataset/routing.py +278 -0
- package/scripts/forge_fractal/__init__.py +84 -0
- package/scripts/forge_fractal/bridge.py +46 -0
- package/scripts/forge_fractal/cli.py +202 -0
- package/scripts/forge_fractal/dashboard.css +138 -0
- package/scripts/forge_fractal/dashboard.html +41 -0
- package/scripts/forge_fractal/dashboard.js +687 -0
- package/scripts/forge_fractal/decomposition.py +262 -0
- package/scripts/forge_fractal/execution.py +659 -0
- package/scripts/forge_fractal/inspection.py +261 -0
- package/scripts/forge_fractal/install.py +158 -0
- package/scripts/forge_fractal/invocation.py +94 -0
- package/scripts/forge_fractal/pipeline.py +124 -0
- package/scripts/forge_fractal/selection.py +179 -0
- package/scripts/forge_jev/__init__.py +376 -0
- package/scripts/forge_jev/backtest.py +322 -0
- package/scripts/forge_jev/cli.py +980 -0
- package/scripts/forge_jev/client.py +418 -0
- package/scripts/forge_jev/corpus.py +156 -0
- package/scripts/forge_jev/coupling.py +244 -0
- package/scripts/forge_jev/features.py +24 -0
- package/scripts/forge_jev/gates.py +100 -0
- package/scripts/forge_jev/memory.py +163 -0
- package/scripts/forge_jev/outcome.py +49 -0
- package/scripts/forge_jev/predict.py +204 -0
- package/scripts/forge_jev/questions.py +661 -0
- package/scripts/forge_jev/review.py +73 -0
- package/scripts/forge_jev/routing.py +271 -0
- package/scripts/forge_jev/subset.py +123 -0
- package/scripts/forge_jev/verify.py +453 -0
- package/scripts/forge_registry.py +140 -0
- package/ui/README.md +347 -0
- package/ui/THIRD_PARTY_NOTICES.md +177 -0
- package/ui/docs/api.md +970 -0
- package/ui/forge_ui/__init__.py +20 -0
- package/ui/forge_ui/__main__.py +135 -0
- package/ui/forge_ui/diffs.py +454 -0
- package/ui/forge_ui/executions.py +436 -0
- package/ui/forge_ui/export.py +214 -0
- package/ui/forge_ui/findings.py +132 -0
- package/ui/forge_ui/fractal.py +582 -0
- package/ui/forge_ui/models.py +216 -0
- package/ui/forge_ui/reader.py +1424 -0
- package/ui/forge_ui/server.py +312 -0
- package/ui/forge_ui/static/D-DINCondensed-Bold.woff2 +0 -0
- package/ui/forge_ui/static/app.js +1079 -0
- package/ui/forge_ui/static/cloud3d.js +647 -0
- package/ui/forge_ui/static/cloudmodel.js +375 -0
- package/ui/forge_ui/static/cloudui.js +397 -0
- package/ui/forge_ui/static/convo.js +295 -0
- package/ui/forge_ui/static/datatable.js +232 -0
- package/ui/forge_ui/static/diffview.js +235 -0
- package/ui/forge_ui/static/favicon.svg +1 -0
- package/ui/forge_ui/static/files.js +776 -0
- package/ui/forge_ui/static/findings3d.js +134 -0
- package/ui/forge_ui/static/gantt.js +97 -0
- package/ui/forge_ui/static/graph.js +266 -0
- package/ui/forge_ui/static/icons.js +94 -0
- package/ui/forge_ui/static/index.html +67 -0
- package/ui/forge_ui/static/iso.js +816 -0
- package/ui/forge_ui/static/leaderboard.js +311 -0
- package/ui/forge_ui/static/map3d.js +45 -0
- package/ui/forge_ui/static/modelstats.js +249 -0
- package/ui/forge_ui/static/notify.js +179 -0
- package/ui/forge_ui/static/panel.js +562 -0
- package/ui/forge_ui/static/runmodel.js +667 -0
- package/ui/forge_ui/static/scene3d.js +1471 -0
- package/ui/forge_ui/static/search.js +120 -0
- package/ui/forge_ui/static/shell.js +137 -0
- package/ui/forge_ui/static/stagectl.js +150 -0
- package/ui/forge_ui/static/style.css +1073 -0
- package/ui/forge_ui/static/theme.js +25 -0
- package/ui/forge_ui/transcripts.py +608 -0
package/ui/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# forge-ui
|
|
2
|
+
|
|
3
|
+
forge-ui is a small, read-only local web UI for forge runs. It draws them the way
|
|
4
|
+
[archivision](https://github.com/Giamme/archivision) draws a codebase: a 3D isometric map of
|
|
5
|
+
blocks on a plate, with cables between them and lamps that light up as things happen.
|
|
6
|
+
|
|
7
|
+
- **A map of every run**, one district per repo and one block per run, with a lamp per task.
|
|
8
|
+
Filter it by state, repo, kind, model, age or review verdict; what does not match fades
|
|
9
|
+
instead of disappearing.
|
|
10
|
+
- **A run, as planned and as it ran.** *Plan* puts each task in its planned wave, with
|
|
11
|
+
dependency cables, and ends in a *finish* line of three nodes: integration, verification
|
|
12
|
+
and the whole-run **final review**. *Execution* lays the same work out on wall-clock time:
|
|
13
|
+
one block per attempt, in the lane it really ran in, with its dwarf and review inside, the
|
|
14
|
+
attempts that have not started projected by forge-schedule's own rules, and a strip of how
|
|
15
|
+
many slots were busy against `--max-parallel`. Switching between the two moves each task
|
|
16
|
+
from its wave to where it ran.
|
|
17
|
+
- **Click to open.** A task opens to show its attempts, each with its dwarf, its reviewer and
|
|
18
|
+
any shadow reviews, linked; an escalation is a labelled cable between attempts. The
|
|
19
|
+
inspector beside the stage shows what launched each step and what came of it: the exact
|
|
20
|
+
prompt, the model (alias, harness, model, effort, clamping), the timings by phase, tokens,
|
|
21
|
+
the verdict, and every **P0–P3 finding** of every review, the final review included.
|
|
22
|
+
- **Live.** Statuses change in place while a run works (every 2 s while something runs, 5 s
|
|
23
|
+
otherwise); running nodes pulse and show their current phase.
|
|
24
|
+
- **Extras:** replay a run from its recorded times, light its critical path, set block height
|
|
25
|
+
and colour by duration, tokens, attempts or model, and mark shadow reviews that disagreed
|
|
26
|
+
with the primary and how sure Clef was that each task would pass.
|
|
27
|
+
- **Beyond one run:** a full-screen **run cloud** of every run, grouped by project, in five
|
|
28
|
+
layouts with filters and runs you can drag anywhere; **diffs** with each finding under the
|
|
29
|
+
line it names; each dwarf's and reviewer's **conversation**, read from its CLI's log; a
|
|
30
|
+
**model leaderboard**; a **files heatmap**; **Fractal** child-task trees;
|
|
31
|
+
**quick jump** and **notifications**; and **export** of a run as one HTML file. See
|
|
32
|
+
[What you see](#what-you-see).
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="docs/media/hero.webp" width="860" alt="A decomposed run on its 3D plate: eight tasks in their planned waves with a mark for each review finding, then the same run on wall-clock time, where two first attempts that failed review show in red beside the retries that passed.">
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
The 3D view loads three.js from a CDN the first time it is used (see [Privacy](#privacy)).
|
|
39
|
+
Without it (offline, an old browser, no WebGL) the same page shows the 2D dependency graph,
|
|
40
|
+
an execution chart and the same inspector. The server is Python's standard library; there
|
|
41
|
+
is no install or build step.
|
|
42
|
+
|
|
43
|
+
It lives inside forge, in `ui/`, and is forge's companion: runs open it with `--ui`.
|
|
44
|
+
|
|
45
|
+
## Run it
|
|
46
|
+
|
|
47
|
+
Normally forge launches it. `forge ui open [DIR]` (from the forge checkout) starts or
|
|
48
|
+
reuses one shared detached server and prints the link to a run dir, `forge ui status`
|
|
49
|
+
shows it and `forge ui stop` ends it; see [references/ui.md](../references/ui.md). A run
|
|
50
|
+
starts it itself with `forge-solo.sh --ui` or `forge-parallel.sh plan --ui`.
|
|
51
|
+
|
|
52
|
+
To run the server directly, from `ui/`:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
python3 -m forge_ui
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Open the printed URL (default `http://127.0.0.1:8765/`). Stop with Ctrl-C.
|
|
59
|
+
|
|
60
|
+
- `--plan DIR`: add one plan directory; repeatable, default none.
|
|
61
|
+
- `--root DIR`: scan for plan directories at depth 0–2; repeatable, default none.
|
|
62
|
+
- `--no-registry`: disable the registry, which is read by default.
|
|
63
|
+
- `--registry-dir DIR`: override the registry directory described below.
|
|
64
|
+
- `--port N`: use port N, default `8765`; `0` selects a free port.
|
|
65
|
+
- `--quiet`: suppress request logging; off by default (errors can still be logged).
|
|
66
|
+
- `--open`: open the browser after startup; off by default.
|
|
67
|
+
- `--idle-exit SECONDS`: exit after that many idle seconds; default `0` (never). `forge ui` sets it from `FORGE_UI_IDLE_S`.
|
|
68
|
+
- `--version`: print the version and exit.
|
|
69
|
+
- `-h`, `--help`: print usage and exit.
|
|
70
|
+
|
|
71
|
+
Three examples (replace the example paths with your own):
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
# Registry only
|
|
75
|
+
python3 -m forge_ui
|
|
76
|
+
# One plan directory only
|
|
77
|
+
python3 -m forge_ui --no-registry --plan /path/to/plan
|
|
78
|
+
# A root containing many runs, without registry entries
|
|
79
|
+
python3 -m forge_ui --no-registry --root /path/to/runs
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
No runs yet? `tools/demo_runs.py` writes made-up ones, the same that fill the pictures here: a
|
|
83
|
+
live run and a few weeks of history across five projects.
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
python3 tools/demo_runs.py /tmp/forge-demo
|
|
87
|
+
python3 -m forge_ui --no-registry --root /tmp/forge-demo --open
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Where runs come from
|
|
91
|
+
|
|
92
|
+
Sources are checked in this order:
|
|
93
|
+
|
|
94
|
+
1. Explicit `--plan DIR` directories.
|
|
95
|
+
2. `--root DIR` itself, its children and grandchildren. Scanning stops when a plan
|
|
96
|
+
directory is found; hidden children and symlinked child directories are skipped.
|
|
97
|
+
3. Forge's registry: `*.txt` files in `$XDG_CONFIG_HOME/forge/runs/`, defaulting
|
|
98
|
+
to `~/.config/forge/runs/` when XDG_CONFIG_HOME is unset or empty. Each file
|
|
99
|
+
supplies absolute paths, one per line; blank lines and `#` comments are ignored.
|
|
100
|
+
`--registry-dir` replaces this location; `--no-registry` disables it.
|
|
101
|
+
|
|
102
|
+
Plan directories (containing a `tasks.tsv` file) and solo run directories (a `prompt.md`
|
|
103
|
+
and a `repo` file) appear through `--plan` and the registry; `--root` finds plan directories
|
|
104
|
+
only. Stale or invalid paths are skipped. Duplicate real paths appear once,
|
|
105
|
+
with the first source winning. Discovery and disk reads repeat on each API request.
|
|
106
|
+
|
|
107
|
+
## What you see
|
|
108
|
+
|
|
109
|
+
forge-ui looks like a signal box's route-setting desk: the run is drawn on a panel, every heading
|
|
110
|
+
is an engraved plate, every switch is a push button whose lamp lights when it is on, and lamps
|
|
111
|
+
keep one meaning everywhere (amber running, green merged or passed, red failed, unlit pending).
|
|
112
|
+
|
|
113
|
+
- **Layout:** the *Runs*, *Inspector* and *Tasks* modules sit around the stage. *Immersive* (the
|
|
114
|
+
default) floats them over a stage that fills the window; *Workbench* docks them beside it, and
|
|
115
|
+
the runs list folds to a rail of lamps. Switch with the two layout keys in the header; the
|
|
116
|
+
module keys beside them, or `1`, `2` and `3`, fold and open the runs, the inspector and the
|
|
117
|
+
tasks. On your first visit the inspector and the tasks start folded, so a run opens on its plate. Drag a module's inner edge, or focus it and use the arrow keys, to resize it. The header
|
|
118
|
+
also switches the theme (system, light or dark). All of this is remembered in this browser.
|
|
119
|
+
- **Map (`#/`):** every discovered run, newest first, grouped by repo. By default the last
|
|
120
|
+
60 runs from the past 14 days; *older runs too* shows the rest. The runs list follows the same
|
|
121
|
+
filter, and sorts by latest activity, state or repo.
|
|
122
|
+
|
|
123
|
+
<img src="docs/media/map.png" width="760" alt="The map: one block per run, in a district per repo, green when done, amber while running, red with failures.">
|
|
124
|
+
- **Run cloud (`#/cloud`):** every run at once, full screen, floating in 3D and grouped by project
|
|
125
|
+
(repo). Pick a layout: *Helix* (one spiral per project, oldest at the bottom), *Sphere*,
|
|
126
|
+
*Galaxy* (a disc per project, newest at the centre), *Timeline* (left to right by start time,
|
|
127
|
+
one lane per project) or *Constellation* (pulled together by project and shared models, with
|
|
128
|
+
lines joining each project's nearest runs). Runs are *Blocks* (a lamp per task on the roof) or
|
|
129
|
+
*Orbs* (a ring of task segments); size is the number of tasks, colour the run's state. The
|
|
130
|
+
filter panel narrows the cloud to exactly the runs wanted: projects, state, kind, difficulty
|
|
131
|
+
(has a task of, or mostly), tasks per run, models (any role, implementer or reviewer), recent
|
|
132
|
+
activity, final review, verification, decompose level and text (goals, ids, task titles).
|
|
133
|
+
Orbit, pan and zoom anywhere; drag a run to put it where you want (Shift: nearer or further,
|
|
134
|
+
Alt: up or down). Dropped positions are kept in this browser per layout; *Positions* resets them
|
|
135
|
+
(with undo) or exports and imports them as a JSON file. Click a run for its card, double-click
|
|
136
|
+
to open it; `#/cloud/runs/<key>` and `#/cloud/projects/<id>` link to a selection. Keys:
|
|
137
|
+
arrows orbit, + − zoom, F frames, P steps through projects, [ ] through runs, L changes the
|
|
138
|
+
layout, B the shape, 0 resets the view, Esc steps back. With *2D*, the cloud lists the same
|
|
139
|
+
filtered runs and offers *Load 3D*.
|
|
140
|
+
|
|
141
|
+
<img src="docs/media/cloud.webp" width="760" alt="The run cloud orbited, then laid out as galaxies and as a timeline with one lane per project.">
|
|
142
|
+
- **Run (`#/runs/<key>`):** a header with the goal, the repo, a describer (each state's count,
|
|
143
|
+
the wall time, how long since anything moved), a bank of push buttons (*Plan* /
|
|
144
|
+
*Execution* / *Files*, *3D* / *2D*, and *View*: height and colour overlays, the *Layers* that
|
|
145
|
+
switch each part of the 3D drawing on or off, and the *Marks*: *Critical path*, *Review marks*,
|
|
146
|
+
*Projected*) and the replay's time base; then the stage, the inspector and the
|
|
147
|
+
task table. The stage frames the run in the part of the window the modules leave free. The
|
|
148
|
+
inspector opens when you choose a task, an attempt or a finish node; with
|
|
149
|
+
nothing chosen it shows the run's timeline, finish and record (*Run details* in the header:
|
|
150
|
+
settings, request, waves, verification output).
|
|
151
|
+
- **Stage (3D):** each review finding stands over its task's block as a mark shaped by its
|
|
152
|
+
severity (P0 spike, P1 diamond, P2 cone, P3 pin, a ring when it has none; a plausible one smaller
|
|
153
|
+
and paler); on an opened task it moves onto the review that raised it, and the final review's sit
|
|
154
|
+
on *Final review*. Hover one for its location and summary; click it to open the diff that
|
|
155
|
+
review read at that finding. Choosing a task keeps its route lit, what it waits on and what
|
|
156
|
+
waits on it (`I` switches this off). Hovering a task shows its card: status, attempts, busy
|
|
157
|
+
time, tokens, models, its worst finding and what waits on it. A block whose roof text is too
|
|
158
|
+
small to read gets its name on a tag that faces you. A merge sends a pulse to *Integration*, a
|
|
159
|
+
failed attempt a red ring across the plate, an escalation a hop with the two models, a final
|
|
160
|
+
review a ring in its verdict's colour, live and during a replay (with reduced motion the block
|
|
161
|
+
lights instead). The keys at the stage's edge fit what is shown (`F`), zoom (`+` `−`), change
|
|
162
|
+
the projection (`V`: perspective, true isometric, top-down), reset the view (`0`), open the
|
|
163
|
+
legend of what the stage draws now (`L`), go full screen, and list every key (`?`). The layers,
|
|
164
|
+
the projection and the route are remembered.
|
|
165
|
+
- **Lamps:** green merged or passed, amber running, red failed, unlit pending. A hollow lamp is
|
|
166
|
+
that family's other case: passed or accepted without a merge (green), interrupted (amber), an
|
|
167
|
+
infrastructure failure, a timeout or blocked behind a failure (red). Review findings are never
|
|
168
|
+
a lamp: their severity is a shape (P0 spike, P1 diamond, P2 cone, P3 pin).
|
|
169
|
+
- **Tables:** the task table and the leaderboard's tables sort by any column (click its header:
|
|
170
|
+
ascending, descending, off), reorder by dragging a header (or Alt+← → on it), and show or hide
|
|
171
|
+
columns from *Columns*, which also resets them. Each table remembers its columns.
|
|
172
|
+
|
|
173
|
+
<img src="docs/media/run.png" width="49%" alt="Planned waves: a run's tasks on a 3D plate with dependency cables, finding marks and the finish nodes, between the runs list and the run's inspector."> <img src="docs/media/execution.png" width="49%" alt="Execution: one block per attempt on wall-clock time, failed attempts in red, with the timeline and critical path in the inspector.">
|
|
174
|
+
- **Inspector:** for the run, its timeline, critical path, peak concurrency and finish line;
|
|
175
|
+
for a task, its models and routing, escalations, timings (busy, model time, overhead,
|
|
176
|
+
queue wait after its dependencies merged), attempts and their executions, review findings
|
|
177
|
+
with the gate decision, Clef predictions against outcomes, and its prompts; for one
|
|
178
|
+
execution, its model, phases, tokens, exact prompt and final message; for the final
|
|
179
|
+
review, its verdict, findings, report, prompt and history.
|
|
180
|
+
- **Files (the run toolbar's third mode):** a heatmap of files (grouped and collapsible by
|
|
181
|
+
directory) against tasks (grouped by wave): planned files outlined, touched files filled by how
|
|
182
|
+
many attempts changed them, drift hatched, merge conflicts ringed, and a dot where another task
|
|
183
|
+
of the same wave planned or touched the file too. Filter by path, sort by path, most touched or
|
|
184
|
+
most tasks, and hide any kind of mark; a cell selects its task and offers that file's diff.
|
|
185
|
+
Below: overlaps, drift, merge conflicts and deferrals as lists.
|
|
186
|
+
|
|
187
|
+
<img src="docs/media/files.png" width="760" alt="The files heatmap: files by directory against tasks by wave, with planned, touched, drift and same-wave overlap marks.">
|
|
188
|
+
- **Models (`#/models`):** a leaderboard of the models forge used. Implementers: tasks, first-attempt
|
|
189
|
+
pass rate with its 95% Wilson interval, censored attempts, retries, escalations away from the
|
|
190
|
+
model, timeouts, gate and human accepts, median model time and tokens. Reviewers: primary,
|
|
191
|
+
shadow and final reviews, the PASS/FAIL split, findings per review by severity, and how often a
|
|
192
|
+
shadow review agreed with the primary. Filter by project, difficulty, kind and period, or keep
|
|
193
|
+
only exploratory picks; open a difficulty for its own table. Routing is not random, so the
|
|
194
|
+
numbers compare what happened, not what would have: the page says so. A model's name opens the
|
|
195
|
+
run cloud filtered to its runs.
|
|
196
|
+
|
|
197
|
+
<img src="docs/media/models.png" width="760" alt="The implementers table: tasks, first-attempt pass rate with its 95% interval, retries, escalations, timeouts, accepts, median model time and tokens per model.">
|
|
198
|
+
- **Diffs (`…/tasks/<id>/diff[/<source>][/file/<path> | /finding/<id>]`, `…/final-review/<name>/diff[/finding/<id>]`):** a task's
|
|
199
|
+
`changes.diff`, its previous or committed diff, or exactly the diff one reviewer read (the last
|
|
200
|
+
diff in that review's prompt), picked from a row of sources with each review's verdict; a final
|
|
201
|
+
review's combined diff. Files are listed with their +/− counts and how many findings point
|
|
202
|
+
into them; each finding is shown under the line it names, those on a line outside the changed
|
|
203
|
+
hunks at the top of their file, and those whose file is not in the diff (or that name no
|
|
204
|
+
location) in a section of their own. n and p move between findings, j and k between files.
|
|
205
|
+
Open it from a task, an attempt's review, an execution or the final review in the inspector, or
|
|
206
|
+
from a finding's mark on the stage (`/finding/<id>` scrolls to that finding and focuses it).
|
|
207
|
+
|
|
208
|
+
<img src="docs/media/diff.png" width="760" alt="The diff a reviewer read, with a P1 finding under the line that compares token digests and a P2 finding under the revoke function.">
|
|
209
|
+
- **Conversations (`…/tasks/<id>/executions/<dwarf-or-qa>/conversation`, `…/executions/<id>/conversation`):**
|
|
210
|
+
what one dwarf or reviewer said and did, read from its agent CLI's `<role>.log`, in the diff's
|
|
211
|
+
place: its messages, its thinking folded, each command with its exit and output, each edit with
|
|
212
|
+
its patch and a link to the file in the diff its review read, other tool calls, and the final
|
|
213
|
+
answer with the tokens and cost. Search it (`/`), keep only what it said, ran or changed, and
|
|
214
|
+
step through its errors (`E`). While the agent works the log is read again every few seconds and
|
|
215
|
+
*Follow* keeps the newest event in view. codex, grok, claude, openclaude and opencode logs are
|
|
216
|
+
read event by event; when a claude run logged only its final answer, the conversation comes from
|
|
217
|
+
Claude's own session file for that run, if it is still on this machine; any other log is shown
|
|
218
|
+
as it is. Open it from an attempt's dwarf or reviewer in the inspector.
|
|
219
|
+
|
|
220
|
+
<img src="docs/media/conversation.png" width="760" alt="A dwarf's conversation: its thinking, the files it wrote, a test run that failed with exit 1 and the run that passed after the fix.">
|
|
221
|
+
- **Fractal child tasks:** when a run used Fractal, a task's inspector shows the tree it was split
|
|
222
|
+
into (status, difficulty, model, phase, cost, the split decision), and the opened task in 3D
|
|
223
|
+
carries the same tree floating above it. A node (`…/tasks/<id>/fractal/<node>`) shows its goal,
|
|
224
|
+
paths, timings, cost and tokens, its decomposition and the children it admitted, its last
|
|
225
|
+
messages, and its candidate diff. Fractal's state is read under `$XDG_STATE_HOME/forge/fractal`
|
|
226
|
+
(default `~/.local/state`), read-only, without following symlinks.
|
|
227
|
+
- **Export:** *Export…* in a run's header downloads the run as one HTML file that opens in any
|
|
228
|
+
browser without forge-ui, offline included (in 2D; in 3D when cdn.jsdelivr.net is reachable).
|
|
229
|
+
It asks each time: by default prompts, reviewer reports, logs, finding details and diffs are
|
|
230
|
+
left out (each finding's headline stays) and local paths are reduced to their last component.
|
|
231
|
+
The file states what it left out, and fetches nothing but three.js: its own policy allows only
|
|
232
|
+
its inline scripts, by hash.
|
|
233
|
+
- **Quick jump:** Ctrl K (⌘K on a Mac), `/` or *Search* opens one search over every run (goal,
|
|
234
|
+
run id, repo, models), task (id and title), project, model and command. Enter opens the pick;
|
|
235
|
+
Shift+Enter shows a run in the cloud; a model shows its runs in the cloud. With nothing typed,
|
|
236
|
+
recent picks and running runs come first.
|
|
237
|
+
- **Notifications:** the bell lists what changed while the page was open: a run that finished or
|
|
238
|
+
ended with failures, a task that failed (FAIL, ERROR, CONFLICT, TIMEOUT, INVALIDATED,
|
|
239
|
+
INTERRUPTED or BLOCKED; INFRA retries are not failures) and a final review's verdict, each
|
|
240
|
+
linked to it. Unread ones show as a count in the tab title and a dot on its icon. *Enable
|
|
241
|
+
browser notifications* asks the browser once; then changes also show as system notifications
|
|
242
|
+
while the tab is in the background, and a hidden tab checks the run list every 30 seconds
|
|
243
|
+
(browsers may check less often after a while). Open tabs share one log and notify once. Runs
|
|
244
|
+
that have not changed for two hours never notify.
|
|
245
|
+
- **Keys on the stage:** with the stage focused, ← → move between tasks (on the map, between
|
|
246
|
+
runs; ↑ ↓ between repos, Enter opens the run), Esc closes, `e` switches plan and execution.
|
|
247
|
+
Anywhere on the page while the stage shows: `F`, `+` `−`, `V`, `0`, `L`, `I`, Shift+F (full
|
|
248
|
+
screen) and `?`. Drag to orbit, right-drag to pan, scroll to zoom once the stage is clicked.
|
|
249
|
+
|
|
250
|
+
URLs such as `http://127.0.0.1:8765/#/runs/<key>/tasks/<id>` are shareable within the
|
|
251
|
+
machine while this server is running and discovering that run dir. *Live refresh* pauses
|
|
252
|
+
polling; a hidden tab polls only the run list, every 30 seconds, and only with browser
|
|
253
|
+
notifications on. Failed requests keep the last good data and show a banner.
|
|
254
|
+
|
|
255
|
+
## Layout of the code
|
|
256
|
+
|
|
257
|
+
- `forge_ui/reader.py`: discover runs, parse their files and produce summaries and details.
|
|
258
|
+
- `forge_ui/executions.py`: the per-dispatch records (`attempts/<role>-<uuid>/`), nested and
|
|
259
|
+
matched to attempts, through a cache keyed by each file's identity and mtime.
|
|
260
|
+
- `forge_ui/findings.py`: P0–P3 findings and the gate, parsed by forge's own `scripts/forge-contract.py`.
|
|
261
|
+
- `forge_ui/server.py`: serve the JSON API and static assets, with GET/HEAD only.
|
|
262
|
+
- `forge_ui/__main__.py`: CLI options, local startup and optional browser opening.
|
|
263
|
+
- `forge_ui/__init__.py`: package version and the build id `forge ui` compares to find a stale server.
|
|
264
|
+
- `forge_ui/static/index.html`, `style.css`, `app.js`: the page shell, styles, routes, views and polling.
|
|
265
|
+
- `forge_ui/static/theme.js`, `shell.js`, `icons.js`, `datatable.js`: the theme switch, the Immersive and
|
|
266
|
+
Workbench layouts with their modules, keys and splitters, the icon set, and the sortable tables
|
|
267
|
+
(their pure parts are node-tested). `D-DINCondensed-Bold.woff2` is the engraved labels' face.
|
|
268
|
+
- `forge_ui/static/runmodel.js`: the pure run model (layouts, schedule projection, critical path, replay).
|
|
269
|
+
- `forge_ui/static/panel.js`, `gantt.js`, `graph.js`: the inspector, the execution chart and strip, the 2D graph.
|
|
270
|
+
- `forge_ui/static/map3d.js`, `scene3d.js`, `iso.js`: the 3D loader, scenes and engine (ported from archivision);
|
|
271
|
+
`findings3d.js` the findings' marks, `stagectl.js` the stage's keys, legend and keys sheet.
|
|
272
|
+
- `forge_ui/static/cloudmodel.js`, `cloud3d.js`, `cloudui.js`: the run cloud's pure model (projects,
|
|
273
|
+
filters, layouts, layout files), its scene on the shared stage, and its controls.
|
|
274
|
+
- `forge_ui/static/diffview.js`: the diff viewer, with findings pinned to their lines.
|
|
275
|
+
- `forge_ui/static/convo.js`, `forge_ui/transcripts.py`: an execution's conversation, and the
|
|
276
|
+
reader of each agent CLI's log format behind it.
|
|
277
|
+
- `forge_ui/static/files.js`: the files heatmap (`matrix()` is pure and node-tested).
|
|
278
|
+
- `forge_ui/export.py`: a run as one HTML file (the page's scripts and styles inlined, the API
|
|
279
|
+
responses it reads, the 3D stage's modules as one module text, a hash-based policy).
|
|
280
|
+
- `forge_ui/static/modelstats.js`, `leaderboard.js`: the leaderboard's aggregation (outcomes as
|
|
281
|
+
`scripts/forge_dataset/export.py` labels them, the interval of its `routing.py`) and its page.
|
|
282
|
+
- `forge_ui/diffs.py`, `fractal.py`, `models.py`: diff parsing and finding pins, the Fractal state
|
|
283
|
+
reader, and the facts behind the model leaderboard.
|
|
284
|
+
- `forge_ui/static/search.js`, `notify.js`, `favicon.svg`: the quick jump and the notifications
|
|
285
|
+
(ranking and change detection are in `runmodel.js`).
|
|
286
|
+
- `tests/`: reader, executions, endpoints, server, static-script and browser checks; `run_fixture.py`
|
|
287
|
+
builds realistic runs in a temp dir (`python3 tests/run_fixture.py DIR` writes two you can open),
|
|
288
|
+
and `many_fixture.py` many small ones across repos for the cloud (`python3 tests/many_fixture.py DIR 300`).
|
|
289
|
+
- `tools/demo_runs.py`, `tools/readme_media.py`: made-up runs to look around with (one live run
|
|
290
|
+
and five projects of history), and the script that turns them into the READMEs' pictures in
|
|
291
|
+
`docs/media/`.
|
|
292
|
+
- [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md): the licences of the ported and loaded code;
|
|
293
|
+
forge-ui itself is under forge's [MIT License](../LICENSE).
|
|
294
|
+
|
|
295
|
+
[docs/api.md](docs/api.md) is the data contract between the reader, server and page.
|
|
296
|
+
|
|
297
|
+
### Known differences from docs/api.md
|
|
298
|
+
|
|
299
|
+
- Root discovery stops at a discovered plan and skips symlinked child directories;
|
|
300
|
+
it does not visit every nested plan within depth 2.
|
|
301
|
+
- The reader accepts wave numbers only from 1 to 10,000 and warns about other values.
|
|
302
|
+
- List `updated` timestamps cover the directory and summary inputs; detail timestamps
|
|
303
|
+
additionally cover files read for the task panels and other run details.
|
|
304
|
+
- The server rejects Host headers other than `127.0.0.1` or `localhost` (optional
|
|
305
|
+
port) with `403`; an absent Host is accepted. This also precedes method rejection.
|
|
306
|
+
- Static filenames must contain only letters, digits, `_`, `-` and `.` and must
|
|
307
|
+
not contain `..`; resolved files must be directly inside the static directory.
|
|
308
|
+
|
|
309
|
+
## Develop
|
|
310
|
+
|
|
311
|
+
Use Python 3.9+ to run the server and tests. Node.js 18+ runs the JavaScript checks; use a
|
|
312
|
+
modern browser for the page (import maps: Chrome 89, Firefox 108, Safari 16.4). No Python or
|
|
313
|
+
Node packages need installing.
|
|
314
|
+
|
|
315
|
+
Run these from `ui/`:
|
|
316
|
+
|
|
317
|
+
```sh
|
|
318
|
+
python3 -m unittest discover -s tests # includes the syntax checks and node --test
|
|
319
|
+
node --test tests/js/*.test.js # the run and cloud models alone
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`tests/test_browser.py` drives the page in Chromium when Python Playwright is installed, and
|
|
323
|
+
skips otherwise. Its 3D tests need three.js: the CDN, or a local copy of the npm package
|
|
324
|
+
(`npm pack three@0.160.0`, unpacked) named by `FORGE_UI_TEST_THREE=<dir>/package`.
|
|
325
|
+
|
|
326
|
+
The pictures in this README and forge's come from `tools/readme_media.py`. After a change you
|
|
327
|
+
can see, run it again: it builds the demo runs, serves them, and captures each view in
|
|
328
|
+
Chromium with Playwright (three.js as for the browser tests; libwebp's `img2webp` and ImageMagick
|
|
329
|
+
to encode the animations and PNGs). `--only cloud diff` retakes some of them.
|
|
330
|
+
|
|
331
|
+
```sh
|
|
332
|
+
python3 tools/readme_media.py # writes docs/media/
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Privacy
|
|
336
|
+
|
|
337
|
+
Run dirs can contain prompts, diffs and review text from private repos. The server binds
|
|
338
|
+
only `127.0.0.1`, makes no network requests, and writes nothing to run dirs, repositories or
|
|
339
|
+
forge's config. Outside the runs it reads one kind of file: for a claude execution whose log
|
|
340
|
+
holds only its final answer, that run's session file, `<session id>.jsonl` under
|
|
341
|
+
`~/.claude/projects/` (or `$CLAUDE_CONFIG_DIR/projects/`). Anyone with access to the local server can read the runs it discovers, and
|
|
342
|
+
forge now registers every run, so that is every run on the machine.
|
|
343
|
+
|
|
344
|
+
The 3D view loads three.js 0.160.0 from `cdn.jsdelivr.net` the first time it is shown in a
|
|
345
|
+
tab: the browser asks the CDN for those script files and sends nothing about your runs
|
|
346
|
+
(`Referrer-Policy: no-referrer`, and the page's CSP allows only that one package). Choose
|
|
347
|
+
**2D** in the toolbar and the browser remembers it and never contacts the CDN.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
forge-ui's 3D view is ported from archivision and draws in the iso-glow style. The served
|
|
4
|
+
copies of that code (`forge_ui/static/iso.js`, `scene3d.js` and `runmodel.js`) carry these
|
|
5
|
+
notices in their head comments; this file keeps them with the source.
|
|
6
|
+
|
|
7
|
+
## archivision
|
|
8
|
+
|
|
9
|
+
`forge_ui/static/iso.js` and `scene3d.js` port `assets/shell-3d.html` and `assets/figure.js`;
|
|
10
|
+
`forge_ui/static/runmodel.js` ports `lib/layout.js` (https://github.com/Giamme/archivision).
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
MIT License
|
|
14
|
+
|
|
15
|
+
Copyright (c) 2026 Giamme
|
|
16
|
+
|
|
17
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
in the Software without restriction, including without limitation the rights
|
|
20
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
furnished to do so, subject to the following conditions:
|
|
23
|
+
|
|
24
|
+
The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
copies or substantial portions of the Software.
|
|
26
|
+
|
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
SOFTWARE.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## iso-glow and iso-figure
|
|
37
|
+
|
|
38
|
+
archivision's shell and the drawing style of its figures come from iso-glow, which is based
|
|
39
|
+
on iso-figure. The same code is in `forge_ui/static/iso.js` and `scene3d.js`.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
MIT License
|
|
43
|
+
|
|
44
|
+
Copyright (c) 2026 April Zhu (iso-glow: lighting, palettes, gallery shell, examples)
|
|
45
|
+
Copyright (c) 2026 Tolga Cohce (iso-figure, on which iso-glow is based)
|
|
46
|
+
|
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
48
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
49
|
+
in the Software without restriction, including without limitation the rights
|
|
50
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
51
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
52
|
+
furnished to do so, subject to the following conditions:
|
|
53
|
+
|
|
54
|
+
The above copyright notice and this permission notice shall be included in all
|
|
55
|
+
copies or substantial portions of the Software.
|
|
56
|
+
|
|
57
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
58
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
59
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
60
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
61
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
62
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
63
|
+
SOFTWARE.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## three.js
|
|
67
|
+
|
|
68
|
+
three.js 0.160.0 (MIT, Copyright © 2010-2023 three.js authors) is not part of forge. The page
|
|
69
|
+
loads it, with its `examples/jsm` add-ons, from `cdn.jsdelivr.net` when the 3D view is used.
|
|
70
|
+
|
|
71
|
+
## D-DIN Condensed (font)
|
|
72
|
+
|
|
73
|
+
`forge_ui/static/D-DINCondensed-Bold.woff2`, unmodified, is the D-DIN Condensed Bold face by Datto Inc.
|
|
74
|
+
(https://www.datto.com/fonts/d-din), used for forge-ui's engraved labels. It is licensed under the SIL Open
|
|
75
|
+
Font License 1.1; "D-DIN" and "D-DIN Condensed" are Reserved Font Names.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Copyright (C) 2017 Datto Inc. https://www.datto.com/fonts/d-din,
|
|
79
|
+
with Reserved Font Names "D-DIN".
|
|
80
|
+
|
|
81
|
+
Copyright (C) 2017 Datto Inc. https://www.datto.com/fonts/d-din,
|
|
82
|
+
with Reserved Font Names "D-DIN Condensed".
|
|
83
|
+
|
|
84
|
+
Copyright (C) 2017 Datto Inc. https://www.datto.com/fonts/d-din,
|
|
85
|
+
with Reserved Font Names "D-DIN Expanded".
|
|
86
|
+
|
|
87
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
88
|
+
This license is copied below, and is also available with a FAQ at:
|
|
89
|
+
http://scripts.sil.org/OFL
|
|
90
|
+
|
|
91
|
+
-----------------------------------------------------------
|
|
92
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
93
|
+
-----------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
PREAMBLE
|
|
96
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
97
|
+
development of collaborative font projects, to support the font creation
|
|
98
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
99
|
+
open framework in which fonts may be shared and improved in partnership
|
|
100
|
+
with others.
|
|
101
|
+
|
|
102
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
103
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
104
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
105
|
+
redistributed and/or sold with any software provided that any reserved
|
|
106
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
107
|
+
however, cannot be released under any other type of license. The
|
|
108
|
+
requirement for fonts to remain under this license does not apply
|
|
109
|
+
to any document created using the fonts or their derivatives.
|
|
110
|
+
|
|
111
|
+
DEFINITIONS
|
|
112
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
113
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
114
|
+
include source files, build scripts and documentation.
|
|
115
|
+
|
|
116
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
117
|
+
copyright statement(s).
|
|
118
|
+
|
|
119
|
+
"Original Version" refers to the collection of Font Software components as
|
|
120
|
+
distributed by the Copyright Holder(s).
|
|
121
|
+
|
|
122
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
123
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
124
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
125
|
+
new environment.
|
|
126
|
+
|
|
127
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
128
|
+
writer or other person who contributed to the Font Software.
|
|
129
|
+
|
|
130
|
+
PERMISSION & CONDITIONS
|
|
131
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
132
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
133
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
134
|
+
Software, subject to the following conditions:
|
|
135
|
+
|
|
136
|
+
1) Neither the Font Software nor any of its individual components,
|
|
137
|
+
in Original or Modified Versions, may be sold by itself.
|
|
138
|
+
|
|
139
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
140
|
+
redistributed and/or sold with any software, provided that each copy
|
|
141
|
+
contains the above copyright notice and this license. These can be
|
|
142
|
+
included either as stand-alone text files, human-readable headers or
|
|
143
|
+
in the appropriate machine-readable metadata fields within text or
|
|
144
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
145
|
+
|
|
146
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
147
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
148
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
149
|
+
presented to the users.
|
|
150
|
+
|
|
151
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
152
|
+
Software shall not be used to promote, endorse or advertise any
|
|
153
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
154
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
155
|
+
permission.
|
|
156
|
+
|
|
157
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
158
|
+
must be distributed entirely under this license, and must not be
|
|
159
|
+
distributed under any other license. The requirement for fonts to
|
|
160
|
+
remain under this license does not apply to any document created
|
|
161
|
+
using the Font Software.
|
|
162
|
+
|
|
163
|
+
TERMINATION
|
|
164
|
+
This license becomes null and void if any of the above conditions are
|
|
165
|
+
not met.
|
|
166
|
+
|
|
167
|
+
DISCLAIMER
|
|
168
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
169
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
170
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
171
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
172
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
173
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
174
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
175
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
176
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
177
|
+
```
|