create-egregore 0.19.32 → 0.20.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/assets/egregore-launcher.js +118 -13
- package/bin/cli.js +48 -3
- package/lib/connect-runtime.js +4 -2
- package/lib/local.js +15 -1
- package/lib/prime-runtime.js +208 -0
- package/lib/setup.js +45 -3
- package/package.json +5 -4
- package/runtime/codex/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/spec-manifest.json +3 -3
- package/runtime/codex/AGENTS.md +11 -4
- package/runtime/codex/bin/activity-data.sh +4 -8
- package/runtime/codex/bin/attendant.sh +13 -0
- package/runtime/codex/bin/autosave.sh +27 -1
- package/runtime/codex/bin/codex-render-spec.mjs +6 -0
- package/runtime/codex/bin/codex-session-start.sh +8 -1
- package/runtime/codex/bin/connect-refresh.sh +33 -0
- package/runtime/codex/bin/graph-batch.sh +25 -6
- package/runtime/codex/bin/graph-op.sh +5 -4
- package/runtime/codex/bin/graph.sh +31 -5
- package/runtime/codex/bin/ingest.py +81 -5
- package/runtime/codex/bin/lib/context.sh +26 -1
- package/runtime/codex/bin/lib/greeting.sh +4 -1
- package/runtime/codex/bin/lib/worktree-links.sh +25 -0
- package/runtime/codex/manifest.json +8 -1
- package/runtime/pi/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/spec-manifest.json +3 -3
- package/runtime/pi/.pi/APPEND_SYSTEM.md +3 -2
- package/runtime/pi/.pi/extensions/egregore.ts +17 -6
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +11 -4
- package/runtime/pi/bin/activity-data.sh +4 -8
- package/runtime/pi/bin/attendant.sh +13 -0
- package/runtime/pi/bin/autosave.sh +27 -1
- package/runtime/pi/bin/codex-render-spec.mjs +6 -0
- package/runtime/pi/bin/codex-session-start.sh +8 -1
- package/runtime/pi/bin/connect-refresh.sh +33 -0
- package/runtime/pi/bin/graph-batch.sh +25 -6
- package/runtime/pi/bin/graph-op.sh +5 -4
- package/runtime/pi/bin/graph.sh +31 -5
- package/runtime/pi/bin/ingest.py +81 -5
- package/runtime/pi/bin/lib/context.sh +26 -1
- package/runtime/pi/bin/lib/greeting.sh +4 -1
- package/runtime/pi/bin/lib/worktree-links.sh +25 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +138 -1
- package/runtime/pi/bin/pi-product-workflows.mjs +35 -7
- package/runtime/pi/manifest.json +8 -1
- package/runtime/prime/.claude/context/notification-consent.md +66 -0
- package/runtime/prime/.codex/config.toml +17 -0
- package/runtime/prime/.codex/hooks/branch-guard.js +461 -0
- package/runtime/prime/.codex/hooks/search-hint.js +67 -0
- package/runtime/prime/.codex/hooks.json +30 -0
- package/runtime/prime/.codex/skills/activity/SKILL.md +82 -0
- package/runtime/prime/.codex/skills/announce/SKILL.md +67 -0
- package/runtime/prime/.codex/skills/archive/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/branch/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/checkup/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/commit/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/contribute/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/create-skill/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dark-mode/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/prime/.codex/skills/deep-reflect/SKILL.md +109 -0
- package/runtime/prime/.codex/skills/delete-user/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/emissary/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/handoff/SKILL.md +166 -0
- package/runtime/prime/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
- package/runtime/prime/.codex/skills/harvest/SKILL.md +131 -0
- package/runtime/prime/.codex/skills/ingest/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/invite/SKILL.md +44 -0
- package/runtime/prime/.codex/skills/issue/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/me/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/meeting/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/note/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/onboarding/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/pr/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/pull/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/push/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/quest/SKILL.md +80 -0
- package/runtime/prime/.codex/skills/reflect/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/review-pr/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/save/SKILL.md +125 -0
- package/runtime/prime/.codex/skills/slack-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/summon/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/sync-repos/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telegram-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telemetry/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/test/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/prime/.codex/skills/tui-design/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/tutorial/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/update/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/view/SKILL.md +156 -0
- package/runtime/prime/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/prime/.codex/skills/visual-explain/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/wrap/SKILL.md +58 -0
- package/runtime/prime/.codex/spec-manifest.json +132 -0
- package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +393 -0
- package/runtime/prime/.prime/agent/extensions/egregore.ts +460 -0
- package/runtime/prime/.prime/agent/settings.json +4 -0
- package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +34 -0
- package/runtime/prime/.prime/agent/skills/egregore/pyproject.toml +13 -0
- package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +156 -0
- package/runtime/prime/.prime/agent/spec-manifest.json +12 -0
- package/runtime/prime/AGENTS.md +489 -0
- package/runtime/prime/bin/activity-data.sh +238 -0
- package/runtime/prime/bin/agent.sh +775 -0
- package/runtime/prime/bin/attendant.sh +707 -0
- package/runtime/prime/bin/autosave.sh +112 -0
- package/runtime/prime/bin/capture-reconcile.sh +69 -0
- package/runtime/prime/bin/capture-run.sh +341 -0
- package/runtime/prime/bin/codex-install-skills.sh +78 -0
- package/runtime/prime/bin/codex-render-spec.mjs +440 -0
- package/runtime/prime/bin/codex-session-start.sh +265 -0
- package/runtime/prime/bin/codex-skill-render.mjs +347 -0
- package/runtime/prime/bin/codex-sync-skills.sh +232 -0
- package/runtime/prime/bin/connect-refresh.sh +33 -0
- package/runtime/prime/bin/dashboard-data.sh +178 -0
- package/runtime/prime/bin/graph-batch.sh +79 -0
- package/runtime/prime/bin/graph-op.sh +1102 -0
- package/runtime/prime/bin/graph-wal.sh +229 -0
- package/runtime/prime/bin/graph.sh +223 -0
- package/runtime/prime/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/prime/bin/handoff-run.sh +671 -0
- package/runtime/prime/bin/handoff-save-egregore.sh +212 -0
- package/runtime/prime/bin/index-handoff.sh +322 -0
- package/runtime/prime/bin/ingest-graph.sh +80 -0
- package/runtime/prime/bin/ingest-surface.html +495 -0
- package/runtime/prime/bin/ingest.py +756 -0
- package/runtime/prime/bin/ingest.sh +279 -0
- package/runtime/prime/bin/ingest_graph.py +856 -0
- package/runtime/prime/bin/ingest_surface.py +544 -0
- package/runtime/prime/bin/lib/artifact-id.sh +46 -0
- package/runtime/prime/bin/lib/config.sh +116 -0
- package/runtime/prime/bin/lib/context.sh +621 -0
- package/runtime/prime/bin/lib/dashboard-artifact.sh +242 -0
- package/runtime/prime/bin/lib/ensure-develop.sh +183 -0
- package/runtime/prime/bin/lib/git-sync.sh +406 -0
- package/runtime/prime/bin/lib/greeting.sh +519 -0
- package/runtime/prime/bin/lib/hash.sh +13 -0
- package/runtime/prime/bin/lib/identity.sh +213 -0
- package/runtime/prime/bin/lib/metrics.sh +374 -0
- package/runtime/prime/bin/lib/noncode.sh +31 -0
- package/runtime/prime/bin/lib/permissions.sh +106 -0
- package/runtime/prime/bin/lib/time.sh +56 -0
- package/runtime/prime/bin/lib/worktree-links.sh +79 -0
- package/runtime/prime/bin/notify.sh +636 -0
- package/runtime/prime/bin/person.py +630 -0
- package/runtime/prime/bin/person.sh +448 -0
- package/runtime/prime/bin/pi-branch-policy.mjs +312 -0
- package/runtime/prime/bin/pi-product-workflows.mjs +394 -0
- package/runtime/prime/bin/prime-render-spec.mjs +123 -0
- package/runtime/prime/bin/prime-session-start.sh +24 -0
- package/runtime/prime/bin/publish-artifact.sh +271 -0
- package/runtime/prime/bin/publish-references.sh +144 -0
- package/runtime/prime/bin/repo-state.sh +96 -0
- package/runtime/prime/bin/search.sh +240 -0
- package/runtime/prime/bin/session-autosave.sh +209 -0
- package/runtime/prime/bin/session-log.sh +199 -0
- package/runtime/prime/bin/settings.sh +304 -0
- package/runtime/prime/bin/telemetry.sh +391 -0
- package/runtime/prime/bin/worktree-create.sh +128 -0
- package/runtime/prime/bin/worktree-remove.sh +50 -0
- package/runtime/prime/bin/worktree.sh +198 -0
- package/runtime/prime/manifest.json +178 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="ledger" data-theme-pair="sovereign" data-theme-mode="auto">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>Ingest into Egregore</title>
|
|
7
|
+
<script type="application/json" id="egregore-design-manifest">{"system":"egregore-design-convention","version":"0.3.0","lineage":"meridian","pair":"sovereign","mode":"auto","resolvedTheme":"ledger","target":"browser","surfaceId":"ingest-picker"}</script>
|
|
8
|
+
<script>
|
|
9
|
+
(function () {
|
|
10
|
+
var pairs = {
|
|
11
|
+
meridian: {light: 'vellum', dark: 'nocturne'},
|
|
12
|
+
agronomic: {light: 'loam', dark: 'soil'},
|
|
13
|
+
sovereign: {light: 'ledger', dark: 'bedrock'}
|
|
14
|
+
};
|
|
15
|
+
var modes = ['light', 'auto', 'dark'];
|
|
16
|
+
function resolveAuto() {
|
|
17
|
+
if (matchMedia('(prefers-color-scheme: dark)').matches) return 'dark';
|
|
18
|
+
if (matchMedia('(prefers-color-scheme: light)').matches) return 'light';
|
|
19
|
+
var hour = new Date().getHours();
|
|
20
|
+
return hour >= 19 || hour < 7 ? 'dark' : 'light';
|
|
21
|
+
}
|
|
22
|
+
function apply(pair, mode) {
|
|
23
|
+
var resolvedMode = mode === 'auto' ? resolveAuto() : mode;
|
|
24
|
+
var resolvedTheme = pairs[pair][resolvedMode];
|
|
25
|
+
document.documentElement.dataset.theme = resolvedTheme;
|
|
26
|
+
document.documentElement.dataset.themePair = pair;
|
|
27
|
+
document.documentElement.dataset.themeMode = mode;
|
|
28
|
+
var manifest = document.getElementById('egregore-design-manifest');
|
|
29
|
+
if (manifest) {
|
|
30
|
+
var value = JSON.parse(manifest.textContent);
|
|
31
|
+
value.pair = pair; value.mode = mode; value.resolvedTheme = resolvedTheme;
|
|
32
|
+
manifest.textContent = JSON.stringify(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var serverPreference = __EGREGORE_PREFERENCES_JSON__;
|
|
36
|
+
var savedPair = serverPreference.pair || localStorage.getItem('eg-theme-pair');
|
|
37
|
+
if (!pairs[savedPair]) savedPair = 'sovereign';
|
|
38
|
+
var savedMode = serverPreference.mode || localStorage.getItem('eg-theme-mode') || 'auto';
|
|
39
|
+
localStorage.setItem('eg-theme-pair', savedPair);
|
|
40
|
+
localStorage.setItem('eg-theme-mode', savedMode);
|
|
41
|
+
apply(savedPair, savedMode);
|
|
42
|
+
matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function () {
|
|
43
|
+
if ((localStorage.getItem('eg-theme-mode') || 'auto') === 'auto') {
|
|
44
|
+
apply(localStorage.getItem('eg-theme-pair') || 'sovereign', 'auto');
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
window.__egTheme = {
|
|
48
|
+
setPair: function (pair) {
|
|
49
|
+
if (!pairs[pair]) return;
|
|
50
|
+
localStorage.setItem('eg-theme-pair', pair);
|
|
51
|
+
apply(pair, localStorage.getItem('eg-theme-mode') || 'auto');
|
|
52
|
+
this.paint();
|
|
53
|
+
if (window.__saveEgTheme) window.__saveEgTheme();
|
|
54
|
+
},
|
|
55
|
+
cycle: function () {
|
|
56
|
+
var current = localStorage.getItem('eg-theme-mode') || 'auto';
|
|
57
|
+
var next = modes[(modes.indexOf(current) + 1) % modes.length];
|
|
58
|
+
localStorage.setItem('eg-theme-mode', next);
|
|
59
|
+
var pair = localStorage.getItem('eg-theme-pair') || 'sovereign';
|
|
60
|
+
apply(pair, next);
|
|
61
|
+
this.paint();
|
|
62
|
+
if (window.__saveEgTheme) window.__saveEgTheme();
|
|
63
|
+
},
|
|
64
|
+
paint: function () {
|
|
65
|
+
var mode = localStorage.getItem('eg-theme-mode') || 'auto';
|
|
66
|
+
var pair = localStorage.getItem('eg-theme-pair') || 'sovereign';
|
|
67
|
+
document.querySelectorAll('.theme-label').forEach(function (label) { label.textContent = mode; });
|
|
68
|
+
document.querySelectorAll('[data-pair]').forEach(function (button) {
|
|
69
|
+
button.classList.toggle('active', button.dataset.pair === pair);
|
|
70
|
+
button.setAttribute('aria-pressed', button.dataset.pair === pair ? 'true' : 'false');
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}());
|
|
75
|
+
</script>
|
|
76
|
+
<style>
|
|
77
|
+
__EGREGORE_DESIGN_CSS__
|
|
78
|
+
</style>
|
|
79
|
+
<style>
|
|
80
|
+
:root {
|
|
81
|
+
--cream: var(--paper);
|
|
82
|
+
--black: var(--ink);
|
|
83
|
+
--dark: var(--ink-soft);
|
|
84
|
+
--muted: var(--ink-faint);
|
|
85
|
+
--warm-gray: var(--line);
|
|
86
|
+
--border: var(--line);
|
|
87
|
+
--hairline: var(--line-soft);
|
|
88
|
+
--card-bg: var(--card);
|
|
89
|
+
--elevated-bg: var(--paper-2);
|
|
90
|
+
--terracotta: var(--t1);
|
|
91
|
+
--terracotta-soft: var(--t1-bg);
|
|
92
|
+
--blue-muted: var(--t2);
|
|
93
|
+
--success: var(--t2);
|
|
94
|
+
--danger: var(--t3);
|
|
95
|
+
--font-serif: var(--serif);
|
|
96
|
+
--font-sans: var(--sans);
|
|
97
|
+
--font-mono: var(--mono);
|
|
98
|
+
}
|
|
99
|
+
* { box-sizing: border-box; }
|
|
100
|
+
body { margin: 0; background: var(--cream); color: var(--dark); font-family: var(--font-sans); min-height: 100vh; }
|
|
101
|
+
button, input, textarea { font: inherit; }
|
|
102
|
+
button { cursor: pointer; }
|
|
103
|
+
::selection { background: var(--terracotta); color: var(--cream); }
|
|
104
|
+
.shell { width: min(980px, calc(100% - 40px)); margin: 0 auto; padding: 64px 0 80px; }
|
|
105
|
+
header { display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: start; border-bottom: 1px solid var(--border); padding-bottom: 32px; }
|
|
106
|
+
.eyebrow { color: var(--terracotta); font-family: var(--font-mono); font-size: 11px; letter-spacing: .13em; text-transform: uppercase; }
|
|
107
|
+
h1 { color: var(--black); font-family: var(--font-serif); font-size: clamp(38px, 6vw, 68px); font-weight: 400; letter-spacing: -.035em; line-height: .98; margin: 12px 0; }
|
|
108
|
+
.lede { color: var(--muted); font-size: 15px; line-height: 1.6; margin: 0; max-width: 620px; }
|
|
109
|
+
.theme-controls { display: grid; justify-items: end; gap: 9px; }
|
|
110
|
+
.pair-switcher { display: flex; gap: 4px; padding: 4px; border: 1px solid var(--border); border-radius: 99px; background: var(--card-bg); }
|
|
111
|
+
.pair { border: 0; border-radius: 99px; background: transparent; color: var(--muted); padding: 7px 10px; font-family: var(--font-mono); font-size: 9px; text-transform: uppercase; letter-spacing: .07em; transition: color .15s, background .15s; }
|
|
112
|
+
.pair:hover { color: var(--black); }
|
|
113
|
+
.pair.active { background: var(--terracotta-soft); color: var(--terracotta); }
|
|
114
|
+
.theme { border: 1px solid var(--border); border-radius: 99px; background: var(--card-bg); color: var(--muted); padding: 8px 12px; font-family: var(--font-mono); font-size: 9px; text-transform: uppercase; letter-spacing: .08em; }
|
|
115
|
+
main { display: grid; gap: 18px; padding-top: 28px; }
|
|
116
|
+
.panel { background: var(--card-bg); border: 1px solid var(--border); border-radius: 16px; padding: 24px; }
|
|
117
|
+
.panel-head { display: flex; justify-content: space-between; gap: 20px; align-items: baseline; margin-bottom: 18px; }
|
|
118
|
+
h2 { color: var(--black); font-family: var(--font-serif); font-size: 25px; font-weight: 400; margin: 0; }
|
|
119
|
+
.step { color: var(--muted); font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }
|
|
120
|
+
.pickers { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
121
|
+
.pick { display: block; border: 1px dashed var(--warm-gray); border-radius: 12px; padding: 24px; background: var(--cream); color: var(--black); text-align: left; transition: border-color .15s, background .15s; }
|
|
122
|
+
.pick:hover { border-color: var(--terracotta); }
|
|
123
|
+
.pick strong { display: block; font-family: var(--font-serif); font-size: 20px; font-weight: 400; }
|
|
124
|
+
.pick span { color: var(--muted); display: block; font-size: 12px; margin-top: 7px; }
|
|
125
|
+
input[type="file"] { position: absolute; width: 1px; height: 1px; overflow: hidden; opacity: 0; }
|
|
126
|
+
.hidden { display: none !important; }
|
|
127
|
+
.file-summary { color: var(--muted); font-family: var(--font-mono); font-size: 11px; }
|
|
128
|
+
.files { max-height: 250px; overflow: auto; border-top: 1px solid var(--border); }
|
|
129
|
+
.file { display: grid; grid-template-columns: 1fr auto auto; gap: 14px; padding: 11px 2px; border-bottom: 1px solid var(--border); align-items: center; font-size: 12px; }
|
|
130
|
+
.file-name { color: var(--black); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
131
|
+
.file-meta, .capability { color: var(--muted); font-family: var(--font-mono); font-size: 10px; }
|
|
132
|
+
.capability.attention { color: var(--terracotta); }
|
|
133
|
+
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
|
134
|
+
label.field { display: grid; gap: 7px; color: var(--muted); font-family: var(--font-mono); font-size: 10px; letter-spacing: .07em; text-transform: uppercase; }
|
|
135
|
+
label.field.full { grid-column: 1 / -1; }
|
|
136
|
+
input[type="text"], textarea { width: 100%; border: 1px solid var(--border); border-radius: 9px; background: var(--cream); color: var(--black); padding: 11px 12px; outline: none; }
|
|
137
|
+
input[type="text"]:focus, textarea:focus { border-color: var(--terracotta); }
|
|
138
|
+
textarea { min-height: 72px; resize: vertical; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; }
|
|
139
|
+
.field-help { color: var(--muted); font-family: var(--font-sans); font-size: 11px; line-height: 1.45; letter-spacing: 0; text-transform: none; }
|
|
140
|
+
.check { display: flex; gap: 10px; align-items: flex-start; color: var(--dark); font-size: 12px; line-height: 1.5; margin-top: 16px; }
|
|
141
|
+
.check input { accent-color: var(--terracotta); margin-top: 3px; }
|
|
142
|
+
.actions { display: flex; justify-content: flex-end; gap: 10px; padding-top: 4px; }
|
|
143
|
+
.button { border-radius: 99px; padding: 11px 18px; border: 1px solid var(--border); background: var(--card-bg); color: var(--dark); }
|
|
144
|
+
.button.primary { border-color: var(--terracotta); background: var(--terracotta); color: var(--paper); }
|
|
145
|
+
.button:disabled { cursor: not-allowed; color: var(--warm-gray); border-color: var(--border); background: var(--card-bg); }
|
|
146
|
+
.connectors { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
|
|
147
|
+
.connectors-head { display: flex; justify-content: space-between; align-items: baseline; }
|
|
148
|
+
.connectors-head h3 { font-size: 13px; font-weight: 600; color: var(--dark); }
|
|
149
|
+
.connector-row { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
|
|
150
|
+
.connector { display: flex; flex-direction: column; gap: 3px; text-align: left; border: 1px solid var(--border); border-radius: 12px; padding: 12px 16px; background: var(--card-bg); color: var(--dark); min-width: 180px; }
|
|
151
|
+
.connector:hover { border-color: var(--terracotta); }
|
|
152
|
+
.connector span { color: var(--muted); font-size: 12px; }
|
|
153
|
+
.connector-note { margin-top: 10px; color: var(--muted); font-size: 12px; line-height: 1.5; }
|
|
154
|
+
.status { border-left: 2px solid var(--terracotta); padding: 10px 12px; color: var(--muted); font-size: 12px; line-height: 1.5; }
|
|
155
|
+
.status.error { border-color: var(--danger); color: var(--danger); }
|
|
156
|
+
.status.done { border-color: var(--success); color: var(--success); }
|
|
157
|
+
.completion { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; overflow: hidden; background: var(--paper); color: var(--ink); }
|
|
158
|
+
.completion::before, .completion::after { content: ""; position: absolute; border: 1px solid var(--line); border-radius: 50%; pointer-events: none; }
|
|
159
|
+
.completion::before { width: min(74vw, 920px); aspect-ratio: 1; left: -18vw; top: -42vw; }
|
|
160
|
+
.completion::after { width: min(54vw, 700px); aspect-ratio: 1; right: -19vw; bottom: -33vw; border-color: var(--line-soft); }
|
|
161
|
+
.completion-card { position: relative; width: min(720px, calc(100% - 40px)); padding: clamp(36px, 7vw, 72px); background: var(--card); border: 1px solid var(--line); border-radius: 22px; box-shadow: var(--shadow); text-align: center; animation: arrive .55s var(--ease) both; }
|
|
162
|
+
.completion-mark { display: grid; place-items: center; width: 58px; height: 58px; margin: 0 auto 28px; border: 1px solid var(--t1); border-radius: 50%; background: var(--t1-bg); color: var(--t1); font-family: var(--font-mono); font-size: 21px; }
|
|
163
|
+
.completion-kicker { color: var(--t1); font-family: var(--font-mono); font-size: 10px; letter-spacing: .13em; text-transform: uppercase; }
|
|
164
|
+
.completion h2 { max-width: 520px; margin: 14px auto 18px; font-size: clamp(38px, 7vw, 64px); line-height: 1.02; letter-spacing: -.035em; }
|
|
165
|
+
.completion-copy { max-width: 470px; margin: 0 auto; color: var(--ink-soft); font-size: 15px; line-height: 1.65; }
|
|
166
|
+
.completion-receipt { display: inline-flex; flex-wrap: wrap; justify-content: center; gap: 8px 14px; margin-top: 28px; padding: 10px 14px; border-radius: 99px; background: var(--paper-2); color: var(--ink-faint); font-family: var(--font-mono); font-size: 10px; }
|
|
167
|
+
.completion-receipt strong { color: var(--ink); font-weight: 500; }
|
|
168
|
+
@keyframes arrive { from { opacity: 0; transform: translateY(18px) scale(.985); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
|
169
|
+
@media (prefers-reduced-motion: reduce) { .completion-card { animation: none; } }
|
|
170
|
+
@media (max-width: 680px) {
|
|
171
|
+
.shell { width: min(100% - 24px, 980px); padding-top: 28px; }
|
|
172
|
+
header { grid-template-columns: 1fr; }
|
|
173
|
+
.theme-controls { justify-items: start; }
|
|
174
|
+
.pair-switcher { max-width: 100%; overflow-x: auto; }
|
|
175
|
+
.pickers, .form-grid { grid-template-columns: 1fr; }
|
|
176
|
+
label.field.full { grid-column: auto; }
|
|
177
|
+
.file { grid-template-columns: 1fr auto; }
|
|
178
|
+
.capability { grid-column: 1 / -1; }
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
181
|
+
</head>
|
|
182
|
+
<body>
|
|
183
|
+
<div class="shell">
|
|
184
|
+
<header>
|
|
185
|
+
<div>
|
|
186
|
+
<div class="eyebrow">Egregore · org-scoped intake</div>
|
|
187
|
+
<h1>Bring the source,<br>keep the evidence.</h1>
|
|
188
|
+
<p class="lede">Selected files stay on this machine. Review their source identity and any retrieval boundaries before they enter unverified organizational intake.</p>
|
|
189
|
+
</div>
|
|
190
|
+
<div class="theme-controls" aria-label="Appearance">
|
|
191
|
+
<div class="pair-switcher" aria-label="Palette pair">
|
|
192
|
+
<button class="pair" type="button" data-pair="meridian" onclick="__egTheme.setPair('meridian')">Meridian</button>
|
|
193
|
+
<button class="pair" type="button" data-pair="agronomic" onclick="__egTheme.setPair('agronomic')">Agronomic</button>
|
|
194
|
+
<button class="pair" type="button" data-pair="sovereign" onclick="__egTheme.setPair('sovereign')">Sovereign</button>
|
|
195
|
+
</div>
|
|
196
|
+
<button class="theme" type="button" onclick="__egTheme.cycle()">◐ <span class="theme-label">auto</span></button>
|
|
197
|
+
</div>
|
|
198
|
+
</header>
|
|
199
|
+
|
|
200
|
+
<main>
|
|
201
|
+
<section class="panel" id="choose-panel">
|
|
202
|
+
<div class="panel-head"><h2>Select material</h2><span class="step">01 · local</span></div>
|
|
203
|
+
<div class="pickers">
|
|
204
|
+
<label class="pick" for="file-input"><strong>Choose files</strong><span>Select one or many documents.</span></label>
|
|
205
|
+
<label class="pick" for="folder-input"><strong>Choose a folder</strong><span>Preserve its visible directory structure.</span></label>
|
|
206
|
+
</div>
|
|
207
|
+
<input id="file-input" type="file" multiple>
|
|
208
|
+
<input id="folder-input" type="file" webkitdirectory multiple>
|
|
209
|
+
<div class="connectors hidden" id="connectors">
|
|
210
|
+
<div class="connectors-head"><h3>Or bring a connected source</h3><span class="step">guided setup</span></div>
|
|
211
|
+
<div class="connector-row" id="connector-row"></div>
|
|
212
|
+
<p class="connector-note">Setup continues in the terminal — the agent walks you through authorization, and your tokens stay on this machine.</p>
|
|
213
|
+
</div>
|
|
214
|
+
</section>
|
|
215
|
+
|
|
216
|
+
<section class="panel hidden" id="review-panel">
|
|
217
|
+
<div class="panel-head"><h2>Review selection</h2><span class="file-summary" id="file-summary"></span></div>
|
|
218
|
+
<div class="files" id="files"></div>
|
|
219
|
+
</section>
|
|
220
|
+
|
|
221
|
+
<section class="panel hidden" id="contract-panel">
|
|
222
|
+
<div class="panel-head"><h2>Source contract</h2><span class="step">02 · review</span></div>
|
|
223
|
+
<div class="form-grid">
|
|
224
|
+
<label class="field">Stable source ID<input id="source-id" type="text" autocomplete="off"></label>
|
|
225
|
+
<label class="field">Source name<input id="source-name" type="text" autocomplete="off"></label>
|
|
226
|
+
<label class="field full">Retrieval boundaries · optional<textarea id="boundaries" aria-describedby="boundary-help"></textarea><span class="field-help" id="boundary-help">One <code>key=value</code> per line. Add these only when retrieval must never cross a domain, jurisdiction, project, region, or customer boundary.</span></label>
|
|
227
|
+
</div>
|
|
228
|
+
<label class="check"><input id="authoritative" type="checkbox"><span>This is an authoritative full snapshot. On later runs, absent files should become tombstones.</span></label>
|
|
229
|
+
</section>
|
|
230
|
+
|
|
231
|
+
<div class="status hidden" id="status" role="status"></div>
|
|
232
|
+
<div class="actions">
|
|
233
|
+
<button class="button" id="cancel" type="button">Cancel</button>
|
|
234
|
+
<button class="button primary" id="confirm" type="button" disabled>Send to agent</button>
|
|
235
|
+
</div>
|
|
236
|
+
</main>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<section class="completion hidden" id="completion" aria-live="polite">
|
|
240
|
+
<div class="completion-card">
|
|
241
|
+
<div class="completion-mark" id="completion-mark" aria-hidden="true">···</div>
|
|
242
|
+
<div class="completion-kicker" id="completion-kicker">Egregore is processing</div>
|
|
243
|
+
<h2 id="completion-title">You can go back to the terminal now.</h2>
|
|
244
|
+
<p class="completion-copy" id="completion-copy">Your active agent is validating the files, extracting their contents, and attaching the intake to this organization. Leave this page open for the final receipt.</p>
|
|
245
|
+
<div class="completion-receipt"><strong id="completion-source">source</strong><span id="completion-files">0 files</span><span id="completion-outcome">local · unverified</span></div>
|
|
246
|
+
</div>
|
|
247
|
+
</section>
|
|
248
|
+
|
|
249
|
+
<script>
|
|
250
|
+
var token = __EGREGORE_TOKEN_JSON__;
|
|
251
|
+
var capabilities = __EGREGORE_CAPABILITIES_JSON__;
|
|
252
|
+
var selected = [];
|
|
253
|
+
var busy = false;
|
|
254
|
+
var supported = new Set(['txt','md','markdown','rst','csv','tsv','json','jsonl','yaml','yml','xml','html','htm','docx']);
|
|
255
|
+
var fileInput = document.getElementById('file-input');
|
|
256
|
+
var folderInput = document.getElementById('folder-input');
|
|
257
|
+
var statusBox = document.getElementById('status');
|
|
258
|
+
__egTheme.paint();
|
|
259
|
+
|
|
260
|
+
function formatBytes(bytes) {
|
|
261
|
+
if (bytes < 1024) return bytes + ' B';
|
|
262
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
263
|
+
return (bytes / 1024 / 1024).toFixed(1) + ' MB';
|
|
264
|
+
}
|
|
265
|
+
function slug(value) {
|
|
266
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'local-files';
|
|
267
|
+
}
|
|
268
|
+
function relativePath(file) {
|
|
269
|
+
return file.webkitRelativePath || file.name;
|
|
270
|
+
}
|
|
271
|
+
function extractionLabel(file) {
|
|
272
|
+
var ext = file.name.includes('.') ? file.name.split('.').pop().toLowerCase() : '';
|
|
273
|
+
if (supported.has(ext)) return ['local extraction', ''];
|
|
274
|
+
if (ext === 'pdf' && capabilities.pdftotext) return ['PDF text layer', ''];
|
|
275
|
+
if (ext === 'pdf') return ['agent/PDF reader needed', 'attention'];
|
|
276
|
+
return ['unsupported until an adapter is available', 'attention'];
|
|
277
|
+
}
|
|
278
|
+
function setStatus(message, kind) {
|
|
279
|
+
statusBox.textContent = message;
|
|
280
|
+
statusBox.className = 'status' + (kind ? ' ' + kind : '');
|
|
281
|
+
}
|
|
282
|
+
function showCompletion(result) {
|
|
283
|
+
document.getElementById('completion-source').textContent = result.source_id;
|
|
284
|
+
document.getElementById('completion-files').textContent = result.files + (result.files === 1 ? ' file' : ' files') + ' · ' + formatBytes(result.bytes);
|
|
285
|
+
document.querySelector('.shell').classList.add('hidden');
|
|
286
|
+
document.getElementById('completion').classList.remove('hidden');
|
|
287
|
+
document.title = 'Return to the terminal — Egregore';
|
|
288
|
+
}
|
|
289
|
+
var connectorMeta = {
|
|
290
|
+
google: { label: 'Google Workspace', detail: 'Gmail, Drive, Calendar — multiple accounts' },
|
|
291
|
+
notion: { label: 'Notion', detail: 'Pages and databases' }
|
|
292
|
+
};
|
|
293
|
+
function showConnectorCompletion(provider) {
|
|
294
|
+
var meta = connectorMeta[provider] || { label: provider };
|
|
295
|
+
var account = (capabilities.connector_accounts || {})[provider] || '';
|
|
296
|
+
document.getElementById('completion-kicker').textContent = account
|
|
297
|
+
? 'Already connected'
|
|
298
|
+
: 'Guided setup continues in the terminal';
|
|
299
|
+
document.getElementById('completion-copy').textContent = account
|
|
300
|
+
? meta.label + ' is already connected as ' + account + '. Back in the terminal, your agent can add another account or start bringing material in.'
|
|
301
|
+
: 'Your agent is waiting there to connect ' + meta.label + ' — it walks you through authorization step by step. Tokens stay on this machine.';
|
|
302
|
+
document.getElementById('completion-source').textContent = account || meta.label;
|
|
303
|
+
document.getElementById('completion-files').textContent = account ? 'connected' : 'connected source';
|
|
304
|
+
document.getElementById('completion-outcome').textContent = account ? meta.label : 'guided setup';
|
|
305
|
+
document.querySelector('.shell').classList.add('hidden');
|
|
306
|
+
document.getElementById('completion').classList.remove('hidden');
|
|
307
|
+
document.title = 'Return to the terminal — Egregore';
|
|
308
|
+
}
|
|
309
|
+
function chooseConnector(provider) {
|
|
310
|
+
if (busy) return;
|
|
311
|
+
busy = true;
|
|
312
|
+
post('/api/connector', {
|
|
313
|
+
method: 'POST',
|
|
314
|
+
headers: {'Content-Type': 'application/json'},
|
|
315
|
+
body: JSON.stringify({ provider: provider })
|
|
316
|
+
}).then(function (result) {
|
|
317
|
+
if (result.redirect) {
|
|
318
|
+
// The CLI pre-started the OAuth listener — continue this same tab
|
|
319
|
+
// straight into the sign-in page.
|
|
320
|
+
window.location.href = result.redirect;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
showConnectorCompletion(provider);
|
|
324
|
+
}).catch(function (err) {
|
|
325
|
+
busy = false;
|
|
326
|
+
setStatus(err.message, 'error');
|
|
327
|
+
statusBox.classList.remove('hidden');
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
(function renderConnectors() {
|
|
331
|
+
var list = (capabilities.connectors || []).filter(function (p) { return connectorMeta[p]; });
|
|
332
|
+
if (!list.length) return;
|
|
333
|
+
var row = document.getElementById('connector-row');
|
|
334
|
+
row.innerHTML = list.map(function (p) {
|
|
335
|
+
return '<button class="connector" type="button" data-provider="' + p + '"><strong>' + connectorMeta[p].label + '</strong><span>' + connectorMeta[p].detail + '</span></button>';
|
|
336
|
+
}).join('');
|
|
337
|
+
row.querySelectorAll('.connector').forEach(function (btn) {
|
|
338
|
+
btn.addEventListener('click', function () { chooseConnector(btn.dataset.provider); });
|
|
339
|
+
});
|
|
340
|
+
document.getElementById('connectors').classList.remove('hidden');
|
|
341
|
+
})();
|
|
342
|
+
function choose(files) {
|
|
343
|
+
var seen = new Set();
|
|
344
|
+
selected = Array.from(files).filter(function (file) {
|
|
345
|
+
var path = relativePath(file);
|
|
346
|
+
if (path.split('/').some(function (part) { return part.startsWith('.'); })) return false;
|
|
347
|
+
if (seen.has(path)) return false;
|
|
348
|
+
seen.add(path);
|
|
349
|
+
return true;
|
|
350
|
+
});
|
|
351
|
+
if (!selected.length) {
|
|
352
|
+
setStatus('No visible files were selected.', 'error');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
document.getElementById('review-panel').classList.remove('hidden');
|
|
356
|
+
document.getElementById('contract-panel').classList.remove('hidden');
|
|
357
|
+
document.getElementById('confirm').disabled = false;
|
|
358
|
+
statusBox.classList.add('hidden');
|
|
359
|
+
var total = selected.reduce(function (sum, file) { return sum + file.size; }, 0);
|
|
360
|
+
document.getElementById('file-summary').textContent = selected.length + ' files · ' + formatBytes(total);
|
|
361
|
+
document.getElementById('files').innerHTML = selected.map(function (file) {
|
|
362
|
+
var capability = extractionLabel(file);
|
|
363
|
+
return '<div class="file"><span class="file-name"></span><span class="file-meta"></span><span class="capability ' + capability[1] + '"></span></div>';
|
|
364
|
+
}).join('');
|
|
365
|
+
Array.from(document.querySelectorAll('.file')).forEach(function (row, index) {
|
|
366
|
+
var file = selected[index];
|
|
367
|
+
row.querySelector('.file-name').textContent = relativePath(file);
|
|
368
|
+
row.querySelector('.file-meta').textContent = formatBytes(file.size);
|
|
369
|
+
row.querySelector('.capability').textContent = extractionLabel(file)[0];
|
|
370
|
+
});
|
|
371
|
+
var firstPath = relativePath(selected[0]);
|
|
372
|
+
var root = firstPath.includes('/') ? firstPath.split('/')[0] : selected.length === 1 ? selected[0].name.replace(/\.[^.]+$/, '') : 'local-files';
|
|
373
|
+
document.getElementById('source-id').value = slug(root);
|
|
374
|
+
document.getElementById('source-name').value = root.replace(/[-_]+/g, ' ');
|
|
375
|
+
}
|
|
376
|
+
function boundaries() {
|
|
377
|
+
var result = {};
|
|
378
|
+
document.getElementById('boundaries').value.split('\n').forEach(function (line) {
|
|
379
|
+
line = line.trim();
|
|
380
|
+
if (!line) return;
|
|
381
|
+
var split = line.indexOf('=');
|
|
382
|
+
if (split < 1 || !line.slice(split + 1).trim()) throw new Error('Boundaries must use key=value, one per line.');
|
|
383
|
+
result[line.slice(0, split).trim()] = line.slice(split + 1).trim();
|
|
384
|
+
});
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
387
|
+
async function post(path, options) {
|
|
388
|
+
options = options || {};
|
|
389
|
+
options.headers = Object.assign({}, options.headers || {}, {'X-Egregore-Token': token});
|
|
390
|
+
var response = await fetch(path, options);
|
|
391
|
+
var value = await response.json();
|
|
392
|
+
if (!response.ok) throw new Error(value.error || 'Local ingest request failed.');
|
|
393
|
+
return value;
|
|
394
|
+
}
|
|
395
|
+
window.__saveEgTheme = function () {
|
|
396
|
+
post('/api/preferences', {
|
|
397
|
+
method: 'POST',
|
|
398
|
+
headers: {'Content-Type': 'application/json'},
|
|
399
|
+
body: JSON.stringify({pair: localStorage.getItem('eg-theme-pair') || 'sovereign', mode: localStorage.getItem('eg-theme-mode') || 'auto'})
|
|
400
|
+
}).catch(function () {});
|
|
401
|
+
};
|
|
402
|
+
function renderReceipt(result) {
|
|
403
|
+
var state = result.status || 'processing';
|
|
404
|
+
var mark = document.getElementById('completion-mark');
|
|
405
|
+
var kicker = document.getElementById('completion-kicker');
|
|
406
|
+
var title = document.getElementById('completion-title');
|
|
407
|
+
var copy = document.getElementById('completion-copy');
|
|
408
|
+
document.getElementById('completion-outcome').textContent = result.outcome || ('local · ' + state);
|
|
409
|
+
if (state === 'complete') {
|
|
410
|
+
mark.textContent = '✓'; kicker.textContent = 'Indexed into Egregore';
|
|
411
|
+
title.textContent = 'The source is ready to retrieve.';
|
|
412
|
+
copy.textContent = result.message || 'The files were validated, normalized, and added to the organization-scoped retrieval index.';
|
|
413
|
+
document.title = 'Ingest complete — Egregore';
|
|
414
|
+
} else if (state === 'attention') {
|
|
415
|
+
mark.textContent = '!'; kicker.textContent = 'Ingest needs attention';
|
|
416
|
+
title.textContent = 'Some material could not be indexed.';
|
|
417
|
+
copy.textContent = result.message || 'The successful files are available; review the terminal for files that still need extraction.';
|
|
418
|
+
document.title = 'Ingest needs attention — Egregore';
|
|
419
|
+
} else if (state === 'failed') {
|
|
420
|
+
mark.textContent = '×'; kicker.textContent = 'Indexing failed';
|
|
421
|
+
title.textContent = 'The source is not retrieval-ready yet.';
|
|
422
|
+
copy.textContent = result.message || 'The local recovery record was retained. Return to the terminal for the failure and repair command.';
|
|
423
|
+
document.title = 'Ingest failed — Egregore';
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function waitForReceipt() {
|
|
427
|
+
for (;;) {
|
|
428
|
+
try {
|
|
429
|
+
var result = await post('/api/status', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{}'});
|
|
430
|
+
renderReceipt(result);
|
|
431
|
+
if (['complete', 'attention', 'failed'].includes(result.status)) {
|
|
432
|
+
await post('/api/ack', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{}'}).catch(function () {});
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
} catch (_) {}
|
|
436
|
+
await new Promise(function (resolve) { setTimeout(resolve, 900); });
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async function confirmSelection() {
|
|
440
|
+
if (busy) return;
|
|
441
|
+
var contract;
|
|
442
|
+
try {
|
|
443
|
+
contract = {
|
|
444
|
+
source: {
|
|
445
|
+
id: document.getElementById('source-id').value,
|
|
446
|
+
name: document.getElementById('source-name').value,
|
|
447
|
+
boundaries: boundaries(),
|
|
448
|
+
authoritative_snapshot: document.getElementById('authoritative').checked
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
} catch (error) {
|
|
452
|
+
setStatus(error.message, 'error');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
busy = true;
|
|
456
|
+
document.getElementById('confirm').disabled = true;
|
|
457
|
+
fileInput.disabled = true;
|
|
458
|
+
folderInput.disabled = true;
|
|
459
|
+
try {
|
|
460
|
+
for (var index = 0; index < selected.length; index += 1) {
|
|
461
|
+
var file = selected[index];
|
|
462
|
+
setStatus('Staging ' + (index + 1) + ' of ' + selected.length + ' · ' + relativePath(file));
|
|
463
|
+
await post('/api/upload', {
|
|
464
|
+
method: 'POST',
|
|
465
|
+
headers: {'X-Egregore-Path': encodeURIComponent(relativePath(file)), 'Content-Type': file.type || 'application/octet-stream'},
|
|
466
|
+
body: file
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
setStatus('Finalizing the local selection manifest…');
|
|
470
|
+
var result = await post('/api/confirm', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(contract)});
|
|
471
|
+
showCompletion(result);
|
|
472
|
+
waitForReceipt();
|
|
473
|
+
} catch (error) {
|
|
474
|
+
busy = false;
|
|
475
|
+
document.getElementById('confirm').disabled = false;
|
|
476
|
+
fileInput.disabled = false;
|
|
477
|
+
folderInput.disabled = false;
|
|
478
|
+
setStatus(error.message, 'error');
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async function cancelSelection() {
|
|
482
|
+
if (busy) return;
|
|
483
|
+
busy = true;
|
|
484
|
+
try { await post('/api/cancel', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{}'}); } catch (_) {}
|
|
485
|
+
setStatus('Selection cancelled. This window can be closed.');
|
|
486
|
+
document.getElementById('confirm').disabled = true;
|
|
487
|
+
document.getElementById('cancel').disabled = true;
|
|
488
|
+
}
|
|
489
|
+
fileInput.addEventListener('change', function () { choose(fileInput.files); });
|
|
490
|
+
folderInput.addEventListener('change', function () { choose(folderInput.files); });
|
|
491
|
+
document.getElementById('confirm').addEventListener('click', confirmSelection);
|
|
492
|
+
document.getElementById('cancel').addEventListener('click', cancelSelection);
|
|
493
|
+
</script>
|
|
494
|
+
</body>
|
|
495
|
+
</html>
|