create-pmos 0.251.0 → 0.253.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/package.json +1 -1
- package/payload/KIT-VERSION +2 -2
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/workflow-state.js +6 -1
- package/payload/state/discoveries.md +1 -1
- package/payload/state/log.md +1 -1
- package/workspace/briefing-premium-board-test.js +275 -0
- package/workspace/briefing-premium-initiative-test.js +304 -0
- package/workspace/briefing-premium-test.js +438 -0
- package/workspace/briefing-premium-work-test.js +281 -0
- package/workspace/fixtures/board-premium-facts.js +38 -0
- package/workspace/fixtures/briefing-premium-facts.js +32 -0
- package/workspace/fixtures/initiative-premium-facts.js +42 -0
- package/workspace/fixtures/my-work-premium-facts.js +31 -0
- package/workspace/guide/briefing-premium.md +137 -0
- package/workspace/guide/index.md +1 -0
- package/workspace/lib/board-premium.js +133 -0
- package/workspace/lib/briefing-premium-agent.js +134 -0
- package/workspace/lib/briefing-premium-writes.js +138 -0
- package/workspace/lib/briefing-premium.js +514 -0
- package/workspace/lib/engine/workflow-state.js +6 -1
- package/workspace/lib/headless.js +1 -1
- package/workspace/lib/initiative-premium.js +147 -0
- package/workspace/lib/my-work-premium.js +151 -0
- package/workspace/lib/route-modules.js +4 -0
- package/workspace/lib/routes-board-premium.js +61 -0
- package/workspace/lib/routes-briefing-premium.js +83 -0
- package/workspace/lib/routes-initiative-premium.js +68 -0
- package/workspace/lib/routes-my-work-premium.js +31 -0
- package/workspace/lib/vendor/scripts/workflow-state.js +6 -1
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/premium-board.js +180 -0
- package/workspace/public/pm/premium-initiative.js +336 -0
- package/workspace/public/pm/premium-shell.js +184 -0
- package/workspace/public/pm/premium-work.js +198 -0
- package/workspace/public/pm/premium.css +1198 -0
- package/workspace/public/pm/premium.js +228 -0
- package/workspace/public/premium-board.html +73 -0
- package/workspace/public/premium-initiative.html +46 -0
- package/workspace/public/premium-work.html +84 -0
- package/workspace/public/premium.html +68 -0
- package/workspace/public/vendor/geist-mono-var.woff2 +0 -0
- package/workspace/public/vendor/geist-var.woff2 +0 -0
- package/workspace/server.js +49 -10
- package/workspace/test-files.json +12 -0
- package/workspace/test-lists/briefing-premium.json +17 -0
- package/workspace/test-lists/workspace-session-restore.json +5 -0
- package/workspace/third-party/README.md +12 -0
- package/workspace/third-party/geist-OFL.LICENSE +93 -0
- package/workspace/third-party/geist-mono-OFL.LICENSE +93 -0
package/workspace/server.js
CHANGED
|
@@ -2838,7 +2838,7 @@ function stripLegacyClientScreen(buf) {
|
|
|
2838
2838
|
return buf.replace(TMUX_CLIENT_SMCUP, '').replace(TMUX_CLIENT_RMCUP, '');
|
|
2839
2839
|
}
|
|
2840
2840
|
|
|
2841
|
-
function restorePersisted() {
|
|
2841
|
+
function restorePersisted(opts = {}) {
|
|
2842
2842
|
// On server start, load prior sessions' metadata + scrollback. A tmux-backed session whose
|
|
2843
2843
|
// process is STILL ALIVE (it outlived this server via the tmux daemon) is RE-ATTACHED live —
|
|
2844
2844
|
// the PM's `claude` keeps its in-flight state across `pmos stop`/relaunch, no respawn (R7).
|
|
@@ -2853,10 +2853,13 @@ function restorePersisted() {
|
|
|
2853
2853
|
const n = Number(f.replace(/\.json$/, '').split('-')[1]);
|
|
2854
2854
|
if (Number.isFinite(n) && n >= seq) seq = n + 1;
|
|
2855
2855
|
}
|
|
2856
|
-
for (
|
|
2856
|
+
// One lookup for every live pane, not three per session (has-session, pane_id, pane_pid): with many sessions that was seconds
|
|
2857
|
+
// of blocking subprocesses before the server could answer.
|
|
2858
|
+
const live = tmuxLivePanes();
|
|
2859
|
+
const restoreOne = (f) => {
|
|
2857
2860
|
try {
|
|
2858
2861
|
const meta = JSON.parse(fs.readFileSync(path.join(SESS_DIR, f), 'utf8'));
|
|
2859
|
-
if (!meta.id || sessions.has(meta.id))
|
|
2862
|
+
if (!meta.id || sessions.has(meta.id)) return;
|
|
2860
2863
|
let buf = '';
|
|
2861
2864
|
try { buf = stripLegacyClientScreen(fs.readFileSync(path.join(SESS_DIR, meta.id + '.scrollback'), 'utf8')); } catch {}
|
|
2862
2865
|
// re-home the session: its workspace must exist for it to be reachable in the UI
|
|
@@ -2868,8 +2871,10 @@ function restorePersisted() {
|
|
|
2868
2871
|
lastOutputAt: Date.now(), // a restored session's idle clock starts at boot, never from a missing value
|
|
2869
2872
|
};
|
|
2870
2873
|
sessions.set(meta.id, s);
|
|
2871
|
-
if (TMUX && meta.tmux &&
|
|
2874
|
+
if (TMUX && meta.tmux && live.has(meta.tmux)) {
|
|
2872
2875
|
s.state = 'working'; s.note = '';
|
|
2876
|
+
s.paneId = live.get(meta.tmux).paneId; // stable for the life of the tmux session; saves the pane_id lookup on attach
|
|
2877
|
+
if (live.get(meta.tmux).pid > 0) s.agentPid = live.get(meta.tmux).pid;
|
|
2873
2878
|
// seed: this server was DOWN, so output produced in the gap never reached our ring buffer.
|
|
2874
2879
|
// Control mode replays no history, so take tmux's — it is the superset (R7 + scrollback).
|
|
2875
2880
|
attachPty(s, { seed: true }); // the process is alive — reconnect to it, live
|
|
@@ -2889,8 +2894,23 @@ function restorePersisted() {
|
|
|
2889
2894
|
}
|
|
2890
2895
|
const n = Number(String(meta.id).split('-')[1]); if (Number.isFinite(n) && n >= seq) seq = n + 1;
|
|
2891
2896
|
} catch {}
|
|
2897
|
+
};
|
|
2898
|
+
if (!opts.progressive) {
|
|
2899
|
+
for (const f of files) restoreOne(f);
|
|
2900
|
+
adoptOrphanTmuxSessions();
|
|
2901
|
+
return;
|
|
2892
2902
|
}
|
|
2893
|
-
|
|
2903
|
+
// The running server restores in short slices AFTER it is listening, so the page is reachable at once and the sessions
|
|
2904
|
+
// appear as they come back. Every id was floored above, so a session spawned meanwhile cannot take a restored id.
|
|
2905
|
+
const queue = files.slice();
|
|
2906
|
+
const slice = () => {
|
|
2907
|
+
const t0 = Date.now();
|
|
2908
|
+
while (queue.length && Date.now() - t0 < 15) restoreOne(queue.shift());
|
|
2909
|
+
if (queue.length) { setImmediate(slice); return; }
|
|
2910
|
+
try { adoptOrphanTmuxSessions(); } catch {}
|
|
2911
|
+
try { pushSessions(); } catch {}
|
|
2912
|
+
};
|
|
2913
|
+
setImmediate(slice);
|
|
2894
2914
|
}
|
|
2895
2915
|
|
|
2896
2916
|
// The registered workspace a directory belongs to — the LONGEST matching root, so a repo opened
|
|
@@ -2926,7 +2946,7 @@ function adoptOrphanTmuxSessions() {
|
|
|
2926
2946
|
if (!TMUX) return 0;
|
|
2927
2947
|
const claimed = new Set([...sessions.values()].map((s) => s.tmux).filter(Boolean));
|
|
2928
2948
|
let adopted = 0;
|
|
2929
|
-
for (const t of tmuxList().sort((a, b) => a.created - b.created)) {
|
|
2949
|
+
for (const t of tmuxList(claimed).sort((a, b) => a.created - b.created)) {
|
|
2930
2950
|
if (!t.name.startsWith('pmos-') || claimed.has(t.name)) continue;
|
|
2931
2951
|
const dir = t.dir && isDir(t.dir) ? path.resolve(t.dir) : null;
|
|
2932
2952
|
const start = t.start && isDir(t.start) ? path.resolve(t.start) : null;
|
|
@@ -3415,11 +3435,14 @@ function tmuxField(name, fmt) {
|
|
|
3415
3435
|
const r = tmuxCtl(['display-message', '-p', '-t', name, fmt]);
|
|
3416
3436
|
return r && r.status === 0 ? String(r.stdout || '').trim() : '';
|
|
3417
3437
|
}
|
|
3418
|
-
|
|
3438
|
+
// `skip` names sessions the caller already owns: they are not described, so a restart with many live sessions does not
|
|
3439
|
+
// start five blocking tmux calls for each one of them just to throw the answer away.
|
|
3440
|
+
function tmuxList(skip) {
|
|
3419
3441
|
if (!TMUX) return [];
|
|
3420
3442
|
const r = tmuxCtl(['list-sessions', '-F', '#{session_name}']);
|
|
3421
3443
|
if (!r || r.status !== 0) return [];
|
|
3422
3444
|
return String(r.stdout || '').split('\n').map((line) => line.trim()).filter(Boolean)
|
|
3445
|
+
.filter((name) => !(skip && skip.has(name)))
|
|
3423
3446
|
.map((name) => ({
|
|
3424
3447
|
name,
|
|
3425
3448
|
dir: tmuxField(name, '#{pane_current_path}'),
|
|
@@ -3431,6 +3454,20 @@ function tmuxList() {
|
|
|
3431
3454
|
cmd: tmuxField(name, '#{pane_start_command}'),
|
|
3432
3455
|
}));
|
|
3433
3456
|
}
|
|
3457
|
+
// Every live session's active pane in ONE call: name -> { paneId, pid }. The restore asks it instead of running has-session,
|
|
3458
|
+
// pane_id and pane_pid per session. A pipe separates the fields: tmux rewrites a tab inside a format string (see tmuxField).
|
|
3459
|
+
function tmuxLivePanes() {
|
|
3460
|
+
const out = new Map();
|
|
3461
|
+
if (!TMUX) return out;
|
|
3462
|
+
const r = tmuxCtl(['list-panes', '-a', '-F', '#{session_name}|#{window_active}|#{pane_active}|#{pane_id}|#{pane_pid}']);
|
|
3463
|
+
if (!r || r.status !== 0) return out;
|
|
3464
|
+
for (const line of String(r.stdout || '').split('\n')) {
|
|
3465
|
+
const [name, win, pane, paneId, pid] = line.trim().split('|');
|
|
3466
|
+
if (!name || win !== '1' || pane !== '1' || !/^%\d+$/.test(paneId || '')) continue;
|
|
3467
|
+
if (!out.has(name)) out.set(name, { paneId, pid: Number(pid) });
|
|
3468
|
+
}
|
|
3469
|
+
return out;
|
|
3470
|
+
}
|
|
3434
3471
|
// The pane id (%0, %1, …) the control client must address for input. One cheap lookup per attach;
|
|
3435
3472
|
// cached on the session because a pane id is stable for the life of the tmux session.
|
|
3436
3473
|
function tmuxPaneId(s, name) {
|
|
@@ -6056,12 +6093,12 @@ async function handleRequest(req, res) {
|
|
|
6056
6093
|
|
|
6057
6094
|
// console3 (public/c3.html) is the default page: '/' and '/index.html' serve it, and '/c3.html' stays an alias so old links
|
|
6058
6095
|
// keep working. The older shell (public/index.html) moved to '/classic.html' (c3-default-page), reachable and easy to return to.
|
|
6059
|
-
if (p === '/' || p === '/index.html' || p === '/c3.html' || p === '/classic' || p === '/classic.html' || p === '/welcome' || p === '/welcome.html') {
|
|
6096
|
+
if (p === '/' || p === '/index.html' || p === '/c3.html' || p === '/classic' || p === '/classic.html' || p === '/welcome' || p === '/welcome.html' || p === '/premium' || p === '/premium.html' || p === '/premium-work' || p === '/premium-work.html' || p === '/premium-board' || p === '/premium-board.html' || p === '/premium-initiative' || p === '/premium-initiative.html') {
|
|
6060
6097
|
// pm-os-absorb Run 2 (R25, X11): the per-launch nonce goes into the base meta line, nowhere else. no-store, so a
|
|
6061
6098
|
// restarted server never answers a press from a page that holds the previous launch's value. The page code is
|
|
6062
6099
|
// referenced under this launch's build prefix.
|
|
6063
6100
|
const n = pmGuard.launchNonce();
|
|
6064
|
-
return fs.readFile(path.join(PUB, (p === '/classic' || p === '/classic.html') ? 'index.html' : (p === '/welcome' || p === '/welcome.html') ? 'welcome.html' : 'c3.html'), 'utf8', (err, html) => {
|
|
6101
|
+
return fs.readFile(path.join(PUB, (p === '/classic' || p === '/classic.html') ? 'index.html' : (p === '/welcome' || p === '/welcome.html') ? 'welcome.html' : (p === '/premium' || p === '/premium.html') ? 'premium.html' : (p === '/premium-work' || p === '/premium-work.html') ? 'premium-work.html' : (p === '/premium-board' || p === '/premium-board.html') ? 'premium-board.html' : (p === '/premium-initiative' || p === '/premium-initiative.html') ? 'premium-initiative.html' : 'c3.html'), 'utf8', (err, html) => {
|
|
6065
6102
|
if (err) { res.writeHead(404); res.end('not found'); return; }
|
|
6066
6103
|
let out = withBuild(html);
|
|
6067
6104
|
if (n) out = out.replace('<meta name="' + pmGuard.NONCE_META + '" content="" />', '<meta name="' + pmGuard.NONCE_META + '" content="' + n + '" />');
|
|
@@ -6147,6 +6184,8 @@ async function handleRequest(req, res) {
|
|
|
6147
6184
|
// companion app that has to render correctly with no network at all. Plex Mono ships 400 + 700
|
|
6148
6185
|
// because the terminal renders bold — with only the regular face the browser synthesises it.
|
|
6149
6186
|
if (p === '/vendor/space-grotesk-var.woff2') return serveFile(res, path.join(PUB, 'vendor', 'space-grotesk-var.woff2'));
|
|
6187
|
+
if (p === '/vendor/geist-var.woff2') return serveFile(res, path.join(PUB, 'vendor', 'geist-var.woff2'));
|
|
6188
|
+
if (p === '/vendor/geist-mono-var.woff2') return serveFile(res, path.join(PUB, 'vendor', 'geist-mono-var.woff2'));
|
|
6150
6189
|
if (p === '/vendor/ibm-plex-mono-400.woff2') return serveFile(res, path.join(PUB, 'vendor', 'ibm-plex-mono-400.woff2'));
|
|
6151
6190
|
// 500 joined 400/700 with the four-panel design, whose section labels and pills are medium-weight
|
|
6152
6191
|
// mono. Without the face the browser synthesises it, and a synthesised weight is exactly the kind
|
|
@@ -9656,7 +9695,7 @@ wss.on('connection', (ws) => {
|
|
|
9656
9695
|
loadWorkspaces();
|
|
9657
9696
|
if (HOME_ENABLED) registerWorkspace(SELF_ROOT); // the home workspace is hosted (PMOS-self, or the repo the launcher named)
|
|
9658
9697
|
writeTmuxConf(); // must exist before restore may reattach or spawn creates
|
|
9659
|
-
restorePersisted();
|
|
9698
|
+
restorePersisted({ progressive: !REQUIRED_AS_LIBRARY });
|
|
9660
9699
|
|
|
9661
9700
|
// A first shell so the workspace is never empty on first run (honest real PTY). Only when there
|
|
9662
9701
|
// is a repo to open it IN: an installed copy with no home and no registered repo yet must wait
|
|
@@ -35,6 +35,12 @@
|
|
|
35
35
|
"c3-brief-summary.test.js",
|
|
36
36
|
"work-assigned.test.js",
|
|
37
37
|
"briefing-real-data.test.js",
|
|
38
|
+
"briefing-premium.test.js",
|
|
39
|
+
"briefing-premium-writes.test.js",
|
|
40
|
+
"briefing-premium-agent.test.js",
|
|
41
|
+
"briefing-premium-work.test.js",
|
|
42
|
+
"briefing-premium-board.test.js",
|
|
43
|
+
"briefing-premium-initiative.test.js",
|
|
38
44
|
"calendar-events.test.js",
|
|
39
45
|
"calendar-supersede.test.js",
|
|
40
46
|
"tracker-read.test.js",
|
|
@@ -188,6 +194,12 @@
|
|
|
188
194
|
"c3-brief-summary.test.js": 1,
|
|
189
195
|
"work-assigned.test.js": 1,
|
|
190
196
|
"briefing-real-data.test.js": 1,
|
|
197
|
+
"briefing-premium.test.js": 1,
|
|
198
|
+
"briefing-premium-writes.test.js": 1,
|
|
199
|
+
"briefing-premium-agent.test.js": 1,
|
|
200
|
+
"briefing-premium-work.test.js": 1,
|
|
201
|
+
"briefing-premium-board.test.js": 1,
|
|
202
|
+
"briefing-premium-initiative.test.js": 1,
|
|
191
203
|
"calendar-events.test.js": 1,
|
|
192
204
|
"calendar-supersede.test.js": 1,
|
|
193
205
|
"tracker-read.test.js": 1,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Initiative briefing-premium: the premium Briefing page, served from a fixture model, checked against the mockup; and its reply box against the real server with a stub claude.",
|
|
3
|
+
"panels": [
|
|
4
|
+
"briefing-premium-test.js",
|
|
5
|
+
"briefing-premium-work-test.js",
|
|
6
|
+
"briefing-premium-board-test.js",
|
|
7
|
+
"briefing-premium-initiative-test.js",
|
|
8
|
+
"briefing-premium-agent-server.test.js"
|
|
9
|
+
],
|
|
10
|
+
"seconds": {
|
|
11
|
+
"briefing-premium-test.js": 60,
|
|
12
|
+
"briefing-premium-work-test.js": 80,
|
|
13
|
+
"briefing-premium-board-test.js": 120,
|
|
14
|
+
"briefing-premium-initiative-test.js": 120,
|
|
15
|
+
"briefing-premium-agent-server.test.js": 40
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "workspace-event-loop-lag: a restart with many live sessions asks tmux once for every live pane and restores in slices after the server is listening (session-restore).",
|
|
3
|
+
"modules": ["session-restore.test.js"],
|
|
4
|
+
"seconds": { "session-restore.test.js": 12 }
|
|
5
|
+
}
|
|
@@ -42,3 +42,15 @@ sha256sum workspace/public/vendor/Sortable.min.js workspace/public/vendor/lucide
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Compare each tarball hash with the table before you copy a file. When a hash changes, update the table in the same commit. To add an icon, add its name to `ICONS` in `build-lucide-sprite.js`, regenerate the sprite and record its new hash.
|
|
45
|
+
|
|
46
|
+
## Geist fonts (the premium Briefing, initiative briefing-premium)
|
|
47
|
+
|
|
48
|
+
Two binary font faces are vendored under `public/vendor/` for `public/premium.html`. The browser loads them with `@font-face`. They hold no parseable text, so `no-network.test.js` accounts for them by name.
|
|
49
|
+
|
|
50
|
+
| Font | Licence | Shipped file | sha256 |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| Geist (variable) | SIL Open Font License 1.1 | `public/vendor/geist-var.woff2` | `19f9c92546aa300c312235e3125af1b81394d8db9a4bc4a425cd5b641d2d54e1` |
|
|
53
|
+
| Geist Mono (variable) | SIL Open Font License 1.1 | `public/vendor/geist-mono-var.woff2` | `684ad5b531f81d43c1e8c7038262d5db7cdc1f68006e04d6c7769efa8d33c8cc` |
|
|
54
|
+
|
|
55
|
+
The licences are in this folder: [geist-OFL.LICENSE](geist-OFL.LICENSE) and [geist-mono-OFL.LICENSE](geist-mono-OFL.LICENSE). The files are the ones in `prototype/premium-ux-concept/fonts/`.
|
|
56
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) Geist-Italic[wght].ttf: Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font.git) GeistMono-Italic[wght].ttf: Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font.git)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|