@giamme/forge 0.0.0-stage → 0.8.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1854 -2
  4. package/SKILL.md +122 -0
  5. package/VERSION +1 -0
  6. package/forge +74 -0
  7. package/package.json +26 -4
  8. package/references/dataset.md +329 -0
  9. package/references/decompose.md +667 -0
  10. package/references/fractal-dashboard.md +21 -0
  11. package/references/fractal.md +307 -0
  12. package/references/harnesses.md +353 -0
  13. package/references/jev.md +865 -0
  14. package/references/memory.md +228 -0
  15. package/references/planning.md +42 -0
  16. package/references/ripwire.md +47 -0
  17. package/references/runtime.md +64 -0
  18. package/references/solo.md +113 -0
  19. package/references/ui.md +112 -0
  20. package/registry.tsv +81 -0
  21. package/scripts/forge-artifact.sh +78 -0
  22. package/scripts/forge-contract.py +430 -0
  23. package/scripts/forge-dataset.py +6 -0
  24. package/scripts/forge-dispatch.sh +665 -0
  25. package/scripts/forge-fail-first.py +195 -0
  26. package/scripts/forge-fractal-dispatch.sh +4 -0
  27. package/scripts/forge-fractal-options.sh +54 -0
  28. package/scripts/forge-fractal.py +6 -0
  29. package/scripts/forge-guard.py +266 -0
  30. package/scripts/forge-install-fractal.sh +4 -0
  31. package/scripts/forge-install-ripwire.sh +52 -0
  32. package/scripts/forge-install.sh +135 -0
  33. package/scripts/forge-jev-options.sh +259 -0
  34. package/scripts/forge-jev.py +6 -0
  35. package/scripts/forge-lib-plans.sh +785 -0
  36. package/scripts/forge-lib-review.sh +494 -0
  37. package/scripts/forge-lib-task.sh +302 -0
  38. package/scripts/forge-lib-verify.sh +30 -0
  39. package/scripts/forge-memory.sh +575 -0
  40. package/scripts/forge-metrics.sh +39 -0
  41. package/scripts/forge-parallel-options.sh +76 -0
  42. package/scripts/forge-parallel.sh +1717 -0
  43. package/scripts/forge-plan-check.py +118 -0
  44. package/scripts/forge-prompt.py +45 -0
  45. package/scripts/forge-ripwire.py +136 -0
  46. package/scripts/forge-route.py +344 -0
  47. package/scripts/forge-runtime.py +533 -0
  48. package/scripts/forge-schedule.py +312 -0
  49. package/scripts/forge-shadow.py +305 -0
  50. package/scripts/forge-solo.sh +347 -0
  51. package/scripts/forge-ui-options.sh +42 -0
  52. package/scripts/forge-ui.py +435 -0
  53. package/scripts/forge-update.sh +71 -0
  54. package/scripts/forge-verify-coverage.py +956 -0
  55. package/scripts/forge-version.py +198 -0
  56. package/scripts/forge_dataset/__init__.py +439 -0
  57. package/scripts/forge_dataset/capture.py +330 -0
  58. package/scripts/forge_dataset/checks.py +109 -0
  59. package/scripts/forge_dataset/cli.py +233 -0
  60. package/scripts/forge_dataset/export.py +1009 -0
  61. package/scripts/forge_dataset/harvest.py +716 -0
  62. package/scripts/forge_dataset/importer.py +412 -0
  63. package/scripts/forge_dataset/outcomes.py +275 -0
  64. package/scripts/forge_dataset/routing.py +278 -0
  65. package/scripts/forge_fractal/__init__.py +83 -0
  66. package/scripts/forge_fractal/bridge.py +46 -0
  67. package/scripts/forge_fractal/cli.py +202 -0
  68. package/scripts/forge_fractal/dashboard.css +138 -0
  69. package/scripts/forge_fractal/dashboard.html +41 -0
  70. package/scripts/forge_fractal/dashboard.js +687 -0
  71. package/scripts/forge_fractal/decomposition.py +262 -0
  72. package/scripts/forge_fractal/execution.py +659 -0
  73. package/scripts/forge_fractal/inspection.py +261 -0
  74. package/scripts/forge_fractal/install.py +158 -0
  75. package/scripts/forge_fractal/invocation.py +94 -0
  76. package/scripts/forge_fractal/pipeline.py +124 -0
  77. package/scripts/forge_fractal/selection.py +179 -0
  78. package/scripts/forge_jev/__init__.py +376 -0
  79. package/scripts/forge_jev/backtest.py +322 -0
  80. package/scripts/forge_jev/cli.py +980 -0
  81. package/scripts/forge_jev/client.py +418 -0
  82. package/scripts/forge_jev/corpus.py +156 -0
  83. package/scripts/forge_jev/coupling.py +244 -0
  84. package/scripts/forge_jev/features.py +24 -0
  85. package/scripts/forge_jev/gates.py +100 -0
  86. package/scripts/forge_jev/memory.py +163 -0
  87. package/scripts/forge_jev/outcome.py +49 -0
  88. package/scripts/forge_jev/predict.py +204 -0
  89. package/scripts/forge_jev/questions.py +661 -0
  90. package/scripts/forge_jev/review.py +73 -0
  91. package/scripts/forge_jev/routing.py +271 -0
  92. package/scripts/forge_jev/subset.py +123 -0
  93. package/scripts/forge_jev/verify.py +453 -0
  94. package/scripts/forge_registry.py +140 -0
  95. package/ui/README.md +287 -0
  96. package/ui/THIRD_PARTY_NOTICES.md +69 -0
  97. package/ui/docs/api.md +888 -0
  98. package/ui/forge_ui/__init__.py +20 -0
  99. package/ui/forge_ui/__main__.py +135 -0
  100. package/ui/forge_ui/diffs.py +454 -0
  101. package/ui/forge_ui/executions.py +436 -0
  102. package/ui/forge_ui/export.py +204 -0
  103. package/ui/forge_ui/findings.py +132 -0
  104. package/ui/forge_ui/fractal.py +583 -0
  105. package/ui/forge_ui/models.py +216 -0
  106. package/ui/forge_ui/reader.py +1336 -0
  107. package/ui/forge_ui/server.py +303 -0
  108. package/ui/forge_ui/static/app.js +924 -0
  109. package/ui/forge_ui/static/cloud3d.js +646 -0
  110. package/ui/forge_ui/static/cloudmodel.js +375 -0
  111. package/ui/forge_ui/static/cloudui.js +394 -0
  112. package/ui/forge_ui/static/diffview.js +216 -0
  113. package/ui/forge_ui/static/favicon.svg +1 -0
  114. package/ui/forge_ui/static/files.js +776 -0
  115. package/ui/forge_ui/static/gantt.js +97 -0
  116. package/ui/forge_ui/static/graph.js +266 -0
  117. package/ui/forge_ui/static/index.html +55 -0
  118. package/ui/forge_ui/static/iso.js +765 -0
  119. package/ui/forge_ui/static/leaderboard.js +315 -0
  120. package/ui/forge_ui/static/map3d.js +45 -0
  121. package/ui/forge_ui/static/modelstats.js +249 -0
  122. package/ui/forge_ui/static/notify.js +179 -0
  123. package/ui/forge_ui/static/panel.js +526 -0
  124. package/ui/forge_ui/static/runmodel.js +651 -0
  125. package/ui/forge_ui/static/scene3d.js +996 -0
  126. package/ui/forge_ui/static/search.js +119 -0
  127. package/ui/forge_ui/static/style.css +618 -0
@@ -0,0 +1,119 @@
1
+ /* forge-ui quick jump: Ctrl/⌘-K or "/" opens one search over every run, task, project, model and command.
2
+ Enter opens the pick, Shift+Enter opens a run (or a task's run) in the cloud. Recent picks come first
3
+ when nothing is typed. All values enter the DOM as text.
4
+ window.ForgeSearch = { init(ctx) }, where ctx = { runs(), commands(), go(href), cloudFilter(filter) }. */
5
+ window.ForgeSearch = (() => {
6
+ 'use strict';
7
+ const RM = window.ForgeRunModel, CM = window.ForgeCloudModel;
8
+ const RECENT = 'forge-ui-recent', RECENT_CAP = 30;
9
+ const GROUP = { command: 'Commands', run: 'Runs', task: 'Tasks', project: 'Projects', model: 'Models' };
10
+ const PER = { run: 8, task: 8, project: 5, model: 5, command: 6 };
11
+ const STATE_ST = { live: 'running', failed: 'fail', done: 'merged', pending: 'pending' };
12
+ function el(tag, text, cls) {
13
+ const n = document.createElement(tag);
14
+ if (text !== undefined && text !== null) n.textContent = String(text);
15
+ if (cls) n.className = cls;
16
+ return n;
17
+ }
18
+ const loadRecent = () => { try { const v = JSON.parse(localStorage.getItem(RECENT) || '{}'); return v && typeof v === 'object' ? v : {}; } catch (_) { return {}; } };
19
+ function saveRecent(id) {
20
+ const r = loadRecent(); r[id] = Date.now() / 1000;
21
+ const keep = Object.entries(r).sort((a, b) => b[1] - a[1]).slice(0, RECENT_CAP);
22
+ try { localStorage.setItem(RECENT, JSON.stringify(Object.fromEntries(keep))); } catch (_) { /* not remembered */ }
23
+ }
24
+ const typing = t => t && (t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName));
25
+ const mac = /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || '');
26
+
27
+ function init(ctx) {
28
+ const dlg = el('dialog', undefined, 'jump'); dlg.setAttribute('aria-label', 'Jump to');
29
+ const input = el('input', undefined, 'jump-input');
30
+ input.type = 'search'; input.autocomplete = 'off'; input.spellcheck = false;
31
+ input.placeholder = 'Jump to a run, task, project, model or command…';
32
+ input.setAttribute('role', 'combobox'); input.setAttribute('aria-expanded', 'true'); input.setAttribute('aria-controls', 'jump-list'); input.setAttribute('aria-autocomplete', 'list');
33
+ const listEl = el('ul', undefined, 'jump-list'); listEl.id = 'jump-list'; listEl.setAttribute('role', 'listbox'); listEl.setAttribute('aria-label', 'Results');
34
+ const foot = el('p', 'Enter opens · Shift+Enter opens in the cloud · ↑ ↓ choose · Esc closes', 'jump-foot');
35
+ dlg.append(input, listEl, foot); document.body.append(dlg);
36
+ let items = [], active = 0;
37
+ const cache = { ref: null, idx: [] };
38
+
39
+ function index() {
40
+ const runs = ctx.runs();
41
+ if (runs !== cache.ref) {
42
+ cache.ref = runs;
43
+ const projects = CM ? CM.projects(runs).map(p => ({ id: 'project:' + p.id, kind: 'project', label: p.name, sub: `${p.count} run${p.count === 1 ? '' : 's'} · ${p.repo || ''}`,
44
+ ids: [], words: [p.repo], t: Number.isFinite(p.last) ? p.last : 0, href: '#/cloud/projects/' + encodeURIComponent(p.id) })) : [];
45
+ const used = new Map();
46
+ for (const r of runs) for (const a of new Set((r.models || []).map(RM.alias).filter(Boolean))) { const u = used.get(a) || { n: 0, t: 0 }; u.n++; u.t = Math.max(u.t, r.updated || 0); used.set(a, u); }
47
+ const models = [...used].map(([a, u]) => ({ id: 'model:' + a, kind: 'model', label: a, sub: `in ${u.n} run${u.n === 1 ? '' : 's'} · shows them in the cloud`, ids: [a], t: u.t,
48
+ action: () => ctx.cloudFilter({ models: { aliases: [a], role: 'any' } }) }));
49
+ cache.idx = RM.searchIndex(runs).concat(projects, models);
50
+ }
51
+ return cache.idx.concat(ctx.commands().map(c => ({ ...c, kind: 'command' })));
52
+ }
53
+ function labelWithMark(e) {
54
+ const span = el('span', undefined, 'jump-label'), s = String(e.label || '');
55
+ if (e.mark && e.mark[1] > e.mark[0]) span.append(document.createTextNode(s.slice(0, e.mark[0])), el('mark', s.slice(e.mark[0], e.mark[1])), document.createTextNode(s.slice(e.mark[1])));
56
+ else span.textContent = s;
57
+ return span;
58
+ }
59
+ function render() {
60
+ const ranked = RM.searchRank(index(), input.value, { now: Date.now() / 1000, recent: loadRecent(), limit: 300 });
61
+ const groups = new Map();
62
+ for (const e of ranked) { const g = groups.get(e.kind) || []; if (g.length < (PER[e.kind] || 5)) g.push(e); groups.set(e.kind, g); }
63
+ items = []; listEl.replaceChildren();
64
+ for (const [kind, es] of groups) {
65
+ if (!es.length) continue;
66
+ const h = el('li', GROUP[kind] || kind, 'jump-group'); h.setAttribute('role', 'presentation'); listEl.append(h);
67
+ for (const e of es) {
68
+ const i = items.length, li = el('li', undefined, 'jump-item');
69
+ li.id = 'jump-opt-' + i; li.setAttribute('role', 'option'); li.dataset.i = String(i);
70
+ const dot = el('i', undefined, 'led st-' + (e.kind === 'run' ? STATE_ST[e.state] || 'unknown' : e.kind === 'task' ? String(e.status || 'pending').toLowerCase() : 'none'));
71
+ const text = el('span', undefined, 'jump-text'); text.append(labelWithMark(e), el('span', e.sub || '', 'jump-sub'));
72
+ li.append(dot, text);
73
+ if (e.kind === 'run' || e.kind === 'task') li.title = 'Enter opens · Shift+Enter shows it in the cloud';
74
+ listEl.append(li); items.push({ e, li });
75
+ }
76
+ }
77
+ if (!items.length) { const li = el('li', input.value.trim() ? 'Nothing matches.' : 'No runs yet.', 'jump-empty'); li.setAttribute('role', 'presentation'); listEl.append(li); }
78
+ setActive(Math.min(active, Math.max(0, items.length - 1)));
79
+ }
80
+ function setActive(i) {
81
+ active = i;
82
+ items.forEach((it, k) => it.li.setAttribute('aria-selected', String(k === i)));
83
+ const cur = items[i];
84
+ if (cur) { input.setAttribute('aria-activedescendant', cur.li.id); cur.li.scrollIntoView({ block: 'nearest' }); } else input.removeAttribute('aria-activedescendant');
85
+ }
86
+ function pick(e, inCloud) {
87
+ saveRecent(e.id); close();
88
+ if (inCloud && (e.kind === 'run' || e.kind === 'task')) ctx.go('#/cloud/runs/' + encodeURIComponent(e.key));
89
+ else if (e.action) e.action();
90
+ else if (e.href) ctx.go(e.href);
91
+ }
92
+ function open() {
93
+ if (dlg.open) { input.select(); return; }
94
+ input.value = ''; active = 0; render();
95
+ dlg.showModal(); input.focus();
96
+ }
97
+ function close() { if (dlg.open) dlg.close(); }
98
+
99
+ input.addEventListener('input', () => { active = 0; render(); });
100
+ input.addEventListener('keydown', e => {
101
+ if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { e.preventDefault(); if (items.length) setActive((active + (e.key === 'ArrowDown' ? 1 : -1) + items.length) % items.length); }
102
+ else if (e.key === 'PageDown' || e.key === 'PageUp') { e.preventDefault(); if (items.length) setActive(Math.max(0, Math.min(items.length - 1, active + (e.key === 'PageDown' ? 8 : -8)))); }
103
+ else if (e.key === 'Enter') { e.preventDefault(); const cur = items[active]; if (cur) pick(cur.e, e.shiftKey); }
104
+ });
105
+ listEl.addEventListener('mousemove', e => { const li = e.target.closest('[role=option]'); if (li && Number(li.dataset.i) !== active) setActive(Number(li.dataset.i)); });
106
+ listEl.addEventListener('click', e => { const li = e.target.closest('[role=option]'); if (li) pick(items[Number(li.dataset.i)].e, e.shiftKey); });
107
+ dlg.addEventListener('click', e => { if (e.target === dlg) close(); }); // the backdrop
108
+ document.addEventListener('keydown', e => {
109
+ if ((e.key === 'k' || e.key === 'K') && (e.ctrlKey || e.metaKey) && !e.altKey) { e.preventDefault(); if (dlg.open) close(); else open(); }
110
+ else if (e.key === '/' && !e.ctrlKey && !e.metaKey && !e.altKey && !dlg.open && !typing(e.target)) { e.preventDefault(); open(); }
111
+ });
112
+ for (const b of document.querySelectorAll('[data-jump]')) {
113
+ b.addEventListener('click', open);
114
+ const k = b.querySelector('kbd'); if (k) k.textContent = mac ? '⌘K' : 'Ctrl K';
115
+ }
116
+ return { open, close, get isOpen() { return dlg.open; } };
117
+ }
118
+ return { init };
119
+ })();