@bendyline/gilde 0.1.85 → 0.1.87
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/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/raw-index.json +1 -1
- package/data/craftbook-templates/ta/tailor-resume/versions/1.0.5/craftbook.json +226 -0
- package/data/craftbook-templates/ta/tailor-resume/versions/1.0.5/test.json +79 -0
- package/data/knowledge-catalogs/ca/caselaw-alaska-part-0001/manifest.json +24 -0
- package/data/knowledge-catalogs/ca/caselaw-alaska-part-0001/versions/2026.10.1/manifest.json +658 -0
- package/data/knowledge-catalogs/ca/caselaw-us-347-349/manifest.json +25 -0
- package/data/knowledge-catalogs/ca/caselaw-us-347-349/versions/2026.10.5/manifest.json +38 -0
- package/data/knowledge-catalogs/index.json +1 -1
- package/data/knowledge-catalogs/raw-index.json +1 -1
- package/data/project-types/ch/checkers/versions/1.2.1/about.md +9 -0
- package/data/project-types/ch/checkers/versions/1.2.1/game.json +77 -0
- package/data/project-types/ch/checkers/versions/1.2.1/manifest.json +168 -0
- package/data/project-types/ch/checkers/versions/1.2.1/mission.md +9 -0
- package/data/project-types/ch/checkers/versions/1.2.1/pages/board/index.html +1158 -0
- package/data/project-types/ch/chess/versions/1.0.4/about.md +9 -0
- package/data/project-types/ch/chess/versions/1.0.4/game.json +127 -0
- package/data/project-types/ch/chess/versions/1.0.4/manifest.json +182 -0
- package/data/project-types/ch/chess/versions/1.0.4/mission.md +8 -0
- package/data/project-types/ch/chess/versions/1.0.4/pages/board/index.html +851 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/about.md +6 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/manifest.json +70 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/mission.md +3 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/pages/gallery/index.html +212 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/schemes/index.json +9 -0
- package/data/project-types/de/design-scheme/versions/1.0.2/schemes/warm-dusk.json +4 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/about.md +7 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/budget.json +5 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/guests.json +10 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/manifest.json +171 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/mission.md +6 -0
- package/data/project-types/ev/event-planner/versions/1.0.2/pages/dashboard/index.html +283 -0
- package/data/project-types/fi/fitness-coach/versions/1.0.2/about.md +7 -0
- package/data/project-types/fi/fitness-coach/versions/1.0.2/manifest.json +126 -0
- package/data/project-types/fi/fitness-coach/versions/1.0.2/mission.md +7 -0
- package/data/project-types/fi/fitness-coach/versions/1.0.2/pages/dashboard/index.html +273 -0
- package/data/project-types/fi/fitness-coach/versions/1.0.2/training.json +6 -0
- package/data/project-types/fl/flashcards/versions/1.1.1/about.md +8 -0
- package/data/project-types/fl/flashcards/versions/1.1.1/deck.json +7 -0
- package/data/project-types/fl/flashcards/versions/1.1.1/manifest.json +168 -0
- package/data/project-types/fl/flashcards/versions/1.1.1/mission.md +6 -0
- package/data/project-types/fl/flashcards/versions/1.1.1/pages/review/index.html +477 -0
- package/data/project-types/fr/freelance-office/versions/1.0.2/about.md +6 -0
- package/data/project-types/fr/freelance-office/versions/1.0.2/invoices.json +9 -0
- package/data/project-types/fr/freelance-office/versions/1.0.2/manifest.json +143 -0
- package/data/project-types/fr/freelance-office/versions/1.0.2/mission.md +6 -0
- package/data/project-types/fr/freelance-office/versions/1.0.2/pages/dashboard/index.html +258 -0
- package/data/project-types/fu/fundraiser-hq/versions/1.0.2/about.md +7 -0
- package/data/project-types/fu/fundraiser-hq/versions/1.0.2/donations.json +7 -0
- package/data/project-types/fu/fundraiser-hq/versions/1.0.2/manifest.json +127 -0
- package/data/project-types/fu/fundraiser-hq/versions/1.0.2/mission.md +6 -0
- package/data/project-types/fu/fundraiser-hq/versions/1.0.2/pages/dashboard/index.html +261 -0
- package/data/project-types/go/go/versions/1.0.2/about.md +9 -0
- package/data/project-types/go/go/versions/1.0.2/game.json +103 -0
- package/data/project-types/go/go/versions/1.0.2/manifest.json +168 -0
- package/data/project-types/go/go/versions/1.0.2/mission.md +8 -0
- package/data/project-types/go/go/versions/1.0.2/pages/board/index.html +855 -0
- package/data/project-types/ho/household-budget/versions/1.0.3/about.md +6 -0
- package/data/project-types/ho/household-budget/versions/1.0.3/ledger.json +5 -0
- package/data/project-types/ho/household-budget/versions/1.0.3/manifest.json +164 -0
- package/data/project-types/ho/household-budget/versions/1.0.3/mission.md +5 -0
- package/data/project-types/ho/household-budget/versions/1.0.3/pages/dashboard/index.html +340 -0
- package/data/project-types/ho/household-manual/versions/1.0.2/about.md +7 -0
- package/data/project-types/ho/household-manual/versions/1.0.2/manifest.json +153 -0
- package/data/project-types/ho/household-manual/versions/1.0.2/mission.md +8 -0
- package/data/project-types/ho/household-manual/versions/1.0.2/pages/dashboard/index.html +258 -0
- package/data/project-types/ho/household-manual/versions/1.0.2/systems.json +8 -0
- package/data/project-types/index.json +1 -1
- package/data/project-types/jo/job-hunt/versions/1.0.2/about.md +10 -0
- package/data/project-types/jo/job-hunt/versions/1.0.2/activity.json +4 -0
- package/data/project-types/jo/job-hunt/versions/1.0.2/manifest.json +213 -0
- package/data/project-types/jo/job-hunt/versions/1.0.2/mission.md +9 -0
- package/data/project-types/jo/job-hunt/versions/1.0.2/pages/dashboard/index.html +430 -0
- package/data/project-types/jo/job-hunt/versions/1.0.2/pipeline.json +6 -0
- package/data/project-types/la/language-trainer/versions/1.0.2/about.md +6 -0
- package/data/project-types/la/language-trainer/versions/1.0.2/manifest.json +80 -0
- package/data/project-types/la/language-trainer/versions/1.0.2/mission.md +4 -0
- package/data/project-types/la/language-trainer/versions/1.0.2/pages/dashboard/index.html +268 -0
- package/data/project-types/la/language-trainer/versions/1.0.2/progress.json +7 -0
- package/data/project-types/li/life-binder/versions/1.0.3/about.md +7 -0
- package/data/project-types/li/life-binder/versions/1.0.3/documents.json +145 -0
- package/data/project-types/li/life-binder/versions/1.0.3/manifest.json +138 -0
- package/data/project-types/li/life-binder/versions/1.0.3/mission.md +6 -0
- package/data/project-types/li/life-binder/versions/1.0.3/pages/dashboard/index.html +248 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/about.md +6 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/manifest.json +160 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/menu.json +5 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/mission.md +5 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/pages/dashboard/index.html +248 -0
- package/data/project-types/me/meal-planner/versions/1.0.2/pantry.json +9 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/about.md +7 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/chapters.json +10 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/manifest.json +158 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/mission.md +7 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/pages/dashboard/index.html +264 -0
- package/data/project-types/no/novel-writing-room/versions/1.0.2/sessions.json +6 -0
- package/data/project-types/raw-index.json +1 -1
- package/data/project-types/tr/trip-planner/versions/1.0.2/about.md +7 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/journal.json +4 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/manifest.json +194 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/mission.md +4 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/packing.json +8 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/pages/dashboard/index.html +308 -0
- package/data/project-types/tr/trip-planner/versions/1.0.2/trip.json +7 -0
- package/package.json +1 -1
- package/schemas/project-type-version.schema.json +13 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="gezel-demo" content="standalone" />
|
|
7
|
+
<title>Language progress</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light dark;
|
|
11
|
+
--bg: #faf7f2;
|
|
12
|
+
--card: #fff;
|
|
13
|
+
--ink: #2b2620;
|
|
14
|
+
--muted: #7a7166;
|
|
15
|
+
--accent: #b5651d;
|
|
16
|
+
--track: #ece5da;
|
|
17
|
+
}
|
|
18
|
+
:root[data-theme='dark'] {
|
|
19
|
+
--bg: #1c1a17;
|
|
20
|
+
--card: #262320;
|
|
21
|
+
--ink: #efe9e0;
|
|
22
|
+
--muted: #a59a8c;
|
|
23
|
+
--accent: #e0894a;
|
|
24
|
+
--track: #3a352f;
|
|
25
|
+
}
|
|
26
|
+
@media (prefers-color-scheme: dark) {
|
|
27
|
+
:root:not([data-theme='light']) {
|
|
28
|
+
--bg: #1c1a17;
|
|
29
|
+
--card: #262320;
|
|
30
|
+
--ink: #efe9e0;
|
|
31
|
+
--muted: #a59a8c;
|
|
32
|
+
--accent: #e0894a;
|
|
33
|
+
--track: #3a352f;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
* { box-sizing: border-box; }
|
|
37
|
+
body {
|
|
38
|
+
margin: 0;
|
|
39
|
+
font: 16px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
40
|
+
background: var(--bg);
|
|
41
|
+
color: var(--ink);
|
|
42
|
+
padding: 2rem 1.25rem;
|
|
43
|
+
}
|
|
44
|
+
main { max-width: 640px; margin: 0 auto; }
|
|
45
|
+
h1 { font-size: 1.5rem; margin: 0 0 0.25rem; }
|
|
46
|
+
.sub { color: var(--muted); margin: 0 0 1.5rem; }
|
|
47
|
+
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-bottom: 1.5rem; }
|
|
48
|
+
.tile {
|
|
49
|
+
background: var(--card);
|
|
50
|
+
border: 1px solid var(--track);
|
|
51
|
+
border-radius: 12px;
|
|
52
|
+
padding: 1rem;
|
|
53
|
+
text-align: center;
|
|
54
|
+
}
|
|
55
|
+
.tile .n { font-size: 2rem; font-weight: 700; color: var(--accent); }
|
|
56
|
+
.tile .l { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
|
57
|
+
.bar { background: var(--track); border-radius: 999px; height: 10px; overflow: hidden; margin: 0.5rem 0 1.5rem; }
|
|
58
|
+
.bar > span { display: block; height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.4s ease; }
|
|
59
|
+
.notes { background: var(--card); border: 1px solid var(--track); border-radius: 12px; padding: 1rem 1.25rem; }
|
|
60
|
+
.notes h2 { font-size: 0.95rem; margin: 0 0 0.5rem; }
|
|
61
|
+
.notes ul { margin: 0; padding-left: 1.1rem; color: var(--muted); }
|
|
62
|
+
.notes li { margin: 0.2rem 0; }
|
|
63
|
+
.empty { color: var(--muted); font-style: italic; }
|
|
64
|
+
.demo-banner {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: space-between;
|
|
68
|
+
gap: 0.75rem;
|
|
69
|
+
margin: 0 0 0.85rem;
|
|
70
|
+
padding: 0.5rem 0.65rem;
|
|
71
|
+
border: 1px solid var(--accent);
|
|
72
|
+
border-radius: 6px;
|
|
73
|
+
background: color-mix(in srgb, var(--card) 88%, var(--accent));
|
|
74
|
+
color: var(--ink);
|
|
75
|
+
font-size: 0.8rem;
|
|
76
|
+
}
|
|
77
|
+
.demo-banner[hidden] { display: none; }
|
|
78
|
+
.demo-banner strong { font-weight: 700; }
|
|
79
|
+
.demo-reset {
|
|
80
|
+
flex: none;
|
|
81
|
+
padding: 0.25rem 0.5rem;
|
|
82
|
+
border: 1px solid var(--accent);
|
|
83
|
+
border-radius: 6px;
|
|
84
|
+
background: var(--card);
|
|
85
|
+
color: var(--ink);
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
font: inherit;
|
|
88
|
+
}
|
|
89
|
+
.demo-reset:hover { border-color: var(--ink); }
|
|
90
|
+
</style>
|
|
91
|
+
</head>
|
|
92
|
+
<body>
|
|
93
|
+
<main>
|
|
94
|
+
<div class="demo-banner" data-gezel-demo-banner hidden>
|
|
95
|
+
<span><strong>Demo mode</strong> — sample data stays in this page.</span>
|
|
96
|
+
<button type="button" class="demo-reset" onclick="location.reload()">Reset demo</button>
|
|
97
|
+
</div>
|
|
98
|
+
<h1 id="title">Your language journey</h1>
|
|
99
|
+
<p class="sub" id="sub">Loading your progress…</p>
|
|
100
|
+
<div class="tiles">
|
|
101
|
+
<div class="tile"><div class="n" id="level">—</div><div class="l">Level</div></div>
|
|
102
|
+
<div class="tile"><div class="n" id="sessions">—</div><div class="l">Sessions</div></div>
|
|
103
|
+
<div class="tile"><div class="n" id="streak">—</div><div class="l">Day streak</div></div>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="bar"><span id="levelbar" style="width: 0%"></span></div>
|
|
106
|
+
<div class="notes">
|
|
107
|
+
<h2>Recent notes</h2>
|
|
108
|
+
<ul id="notes"><li class="empty">No notes yet — start a conversation with your tutor.</li></ul>
|
|
109
|
+
</div>
|
|
110
|
+
</main>
|
|
111
|
+
<script>
|
|
112
|
+
/* gezel-page-demo-stub v1 */
|
|
113
|
+
/*
|
|
114
|
+
* The canonical demo stub for Gezel type pages. MIT License.
|
|
115
|
+
*
|
|
116
|
+
* Paste this file's bytes verbatim into a <script> block ahead of the
|
|
117
|
+
* page's own code, then call makeDemoGezel({ page, tools, data }) with the
|
|
118
|
+
* page's demo handlers. Served by Gezel, the real window.gezel is already
|
|
119
|
+
* injected and the stub steps aside; opened as a raw file (the live demos
|
|
120
|
+
* on gezelgilde.com), it installs a window.gezel whose tools and data are
|
|
121
|
+
* the page-supplied handler maps — one code path in every mode. `tools`
|
|
122
|
+
* and `data` map a tool name / declared read path to a function; data
|
|
123
|
+
* handlers back read() and list(), and url() returns the handler's value
|
|
124
|
+
* or passes a data: URI through. See docs/page-authoring.md.
|
|
125
|
+
*/
|
|
126
|
+
(function () {
|
|
127
|
+
'use strict';
|
|
128
|
+
window.makeDemoGezel = function (opts) {
|
|
129
|
+
if (window.gezel) return window.gezel;
|
|
130
|
+
var page = (opts && opts.page) || {};
|
|
131
|
+
var tools = (opts && opts.tools) || {};
|
|
132
|
+
var data = (opts && opts.data) || {};
|
|
133
|
+
var themeListeners = [];
|
|
134
|
+
var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
135
|
+
var ui = {
|
|
136
|
+
theme: { mode: media && media.matches ? 'dark' : 'light' },
|
|
137
|
+
onTheme: function (cb) {
|
|
138
|
+
themeListeners.push(cb);
|
|
139
|
+
return function () {
|
|
140
|
+
var at = themeListeners.indexOf(cb);
|
|
141
|
+
if (at >= 0) themeListeners.splice(at, 1);
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
if (media && media.addEventListener) {
|
|
146
|
+
media.addEventListener('change', function (ev) {
|
|
147
|
+
ui.theme = { mode: ev.matches ? 'dark' : 'light' };
|
|
148
|
+
themeListeners.slice().forEach(function (cb) { cb(ui.theme); });
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function fail(code, message) {
|
|
152
|
+
var err = new Error(message);
|
|
153
|
+
err.code = code;
|
|
154
|
+
return Promise.reject(err);
|
|
155
|
+
}
|
|
156
|
+
function run(map, key, arg) {
|
|
157
|
+
if (!Object.prototype.hasOwnProperty.call(map, key)) return null;
|
|
158
|
+
return Promise.resolve().then(function () { return map[key](arg); });
|
|
159
|
+
}
|
|
160
|
+
window.gezel = {
|
|
161
|
+
page: {
|
|
162
|
+
api: 1,
|
|
163
|
+
projectId: 'demo',
|
|
164
|
+
source: 'type',
|
|
165
|
+
entry: page.entry || 'index.html',
|
|
166
|
+
typeName: page.typeName || 'demo',
|
|
167
|
+
params: page.params || {},
|
|
168
|
+
mode: 'demo',
|
|
169
|
+
},
|
|
170
|
+
tools: {
|
|
171
|
+
list: function () { return Promise.resolve(Object.keys(tools)); },
|
|
172
|
+
invoke: function (name, input) {
|
|
173
|
+
var call = run(tools, name, input || {});
|
|
174
|
+
if (!call) return fail('not-allowed', "The demo does not handle the tool '" + name + "'.");
|
|
175
|
+
return call.then(function (output) { return { output: output }; });
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
data: {
|
|
179
|
+
read: function (path, o) {
|
|
180
|
+
return run(data, path, o || {}) || fail('not-allowed', "The demo has no data for '" + path + "'.");
|
|
181
|
+
},
|
|
182
|
+
list: function (path, o) {
|
|
183
|
+
return run(data, path, o || {}) || Promise.resolve([]);
|
|
184
|
+
},
|
|
185
|
+
watch: function () { return function () {}; },
|
|
186
|
+
url: function (path) {
|
|
187
|
+
if (Object.prototype.hasOwnProperty.call(data, path)) return String(data[path]({}));
|
|
188
|
+
return typeof path === 'string' && path.indexOf('data:') === 0 ? path : '';
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
ui: ui,
|
|
192
|
+
refresh: function () {},
|
|
193
|
+
};
|
|
194
|
+
return window.gezel;
|
|
195
|
+
};
|
|
196
|
+
})();
|
|
197
|
+
</script>
|
|
198
|
+
<script>
|
|
199
|
+
// Reads the student's progress through window.gezel (progress.json is
|
|
200
|
+
// declared in the manifest's pages.reads).
|
|
201
|
+
(function () {
|
|
202
|
+
'use strict';
|
|
203
|
+
|
|
204
|
+
// ── demo progress (used only when the page opens as a raw file) ──
|
|
205
|
+
var demoProgress = {
|
|
206
|
+
language: 'Dutch',
|
|
207
|
+
level: 7,
|
|
208
|
+
sessions: 18,
|
|
209
|
+
streak: 5,
|
|
210
|
+
notes: [
|
|
211
|
+
'Word order is settling in after omdat clauses.',
|
|
212
|
+
'Practice separable verbs in everyday errands.',
|
|
213
|
+
'Listening: caught the main idea without subtitles.',
|
|
214
|
+
'Next session: ordering at a café.',
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
makeDemoGezel({
|
|
219
|
+
page: { entry: 'dashboard/index.html', typeName: 'Language Trainer', params: { language: 'Spanish' } },
|
|
220
|
+
data: {
|
|
221
|
+
'progress.json': function () { return demoProgress; },
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// ── one code path from here: window.gezel exists in every mode ──
|
|
226
|
+
var demoMode = gezel.page.mode === 'demo';
|
|
227
|
+
|
|
228
|
+
function applyTheme(mode) {
|
|
229
|
+
document.documentElement.setAttribute('data-theme', mode === 'dark' ? 'dark' : 'light');
|
|
230
|
+
}
|
|
231
|
+
applyTheme(gezel.ui.theme.mode);
|
|
232
|
+
gezel.ui.onTheme(function (theme) { applyTheme(theme.mode); });
|
|
233
|
+
|
|
234
|
+
if (demoMode) document.querySelector('[data-gezel-demo-banner]').hidden = false;
|
|
235
|
+
|
|
236
|
+
function esc(s) { return String(s).replace(/[&<>]/g, function (c) { return { '&': '&', '<': '<', '>': '>' }[c]; }); }
|
|
237
|
+
function render(p) {
|
|
238
|
+
document.getElementById('sub').textContent = 'Learning ' + (p.language || 'a new language');
|
|
239
|
+
document.getElementById('level').textContent = p.level ?? 1;
|
|
240
|
+
document.getElementById('sessions').textContent = p.sessions ?? 0;
|
|
241
|
+
document.getElementById('streak').textContent = p.streak ?? 0;
|
|
242
|
+
var lvl = Math.max(1, p.level ?? 1);
|
|
243
|
+
document.getElementById('levelbar').style.width = Math.min(100, ((lvl - 1) % 10) * 10 + 5) + '%';
|
|
244
|
+
var notes = Array.isArray(p.notes) ? p.notes.slice(-6).reverse() : [];
|
|
245
|
+
var ul = document.getElementById('notes');
|
|
246
|
+
if (notes.length) {
|
|
247
|
+
ul.innerHTML = notes.map(function (n) { return '<li>' + esc(n) + '</li>'; }).join('');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function loadProgress() {
|
|
252
|
+
return gezel.data
|
|
253
|
+
.read('progress.json')
|
|
254
|
+
.then(function (p) {
|
|
255
|
+
if (!p) throw new Error('no progress yet');
|
|
256
|
+
render(p);
|
|
257
|
+
})
|
|
258
|
+
.catch(function () {
|
|
259
|
+
document.getElementById('sub').textContent = 'No sessions recorded yet — say hello to your tutor to begin.';
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
loadProgress();
|
|
264
|
+
gezel.data.watch('progress.json', function () { loadProgress(); });
|
|
265
|
+
})();
|
|
266
|
+
</script>
|
|
267
|
+
</body>
|
|
268
|
+
</html>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
The binder {{household}} hopes never to need — complete, current, and findable.
|
|
2
|
+
Your Archivaris keeps the checklist: which documents exist, where the originals
|
|
3
|
+
live, which are missing, which are due a review. Contents are never stored;
|
|
4
|
+
locations are.
|
|
5
|
+
|
|
6
|
+
The **Output** tab shows the completeness picture at a glance. Start anywhere:
|
|
7
|
+
tell your Archivaris about one document you know exists.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"stages": [
|
|
4
|
+
"missing",
|
|
5
|
+
"present"
|
|
6
|
+
],
|
|
7
|
+
"records": [
|
|
8
|
+
{
|
|
9
|
+
"id": "doc-1",
|
|
10
|
+
"status": "missing",
|
|
11
|
+
"fields": {
|
|
12
|
+
"name": "Will",
|
|
13
|
+
"note": "The signed original, and who holds copies."
|
|
14
|
+
},
|
|
15
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
17
|
+
"history": [
|
|
18
|
+
{
|
|
19
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
20
|
+
"from": null,
|
|
21
|
+
"to": "missing"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "doc-2",
|
|
27
|
+
"status": "missing",
|
|
28
|
+
"fields": {
|
|
29
|
+
"name": "Medical directives",
|
|
30
|
+
"note": "Living will / healthcare proxy."
|
|
31
|
+
},
|
|
32
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
33
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
34
|
+
"history": [
|
|
35
|
+
{
|
|
36
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
37
|
+
"from": null,
|
|
38
|
+
"to": "missing"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "doc-3",
|
|
44
|
+
"status": "missing",
|
|
45
|
+
"fields": {
|
|
46
|
+
"name": "Life insurance policy",
|
|
47
|
+
"note": "Provider, policy number, where the paperwork lives."
|
|
48
|
+
},
|
|
49
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
50
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
51
|
+
"history": [
|
|
52
|
+
{
|
|
53
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
54
|
+
"from": null,
|
|
55
|
+
"to": "missing"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "doc-4",
|
|
61
|
+
"status": "missing",
|
|
62
|
+
"fields": {
|
|
63
|
+
"name": "Home or renters insurance",
|
|
64
|
+
"note": "Provider and policy number."
|
|
65
|
+
},
|
|
66
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
67
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
68
|
+
"history": [
|
|
69
|
+
{
|
|
70
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
71
|
+
"from": null,
|
|
72
|
+
"to": "missing"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "doc-5",
|
|
78
|
+
"status": "missing",
|
|
79
|
+
"fields": {
|
|
80
|
+
"name": "Accounts list",
|
|
81
|
+
"note": "Banks, retirement, investments — institutions only, no credentials."
|
|
82
|
+
},
|
|
83
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
84
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
85
|
+
"history": [
|
|
86
|
+
{
|
|
87
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
88
|
+
"from": null,
|
|
89
|
+
"to": "missing"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "doc-6",
|
|
95
|
+
"status": "missing",
|
|
96
|
+
"fields": {
|
|
97
|
+
"name": "Passwords location",
|
|
98
|
+
"note": "Where the password manager or list lives, not the passwords."
|
|
99
|
+
},
|
|
100
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
101
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
102
|
+
"history": [
|
|
103
|
+
{
|
|
104
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
105
|
+
"from": null,
|
|
106
|
+
"to": "missing"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "doc-7",
|
|
112
|
+
"status": "missing",
|
|
113
|
+
"fields": {
|
|
114
|
+
"name": "Emergency contacts",
|
|
115
|
+
"note": "Who to call first: family, lawyer, doctor."
|
|
116
|
+
},
|
|
117
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
118
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
119
|
+
"history": [
|
|
120
|
+
{
|
|
121
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
122
|
+
"from": null,
|
|
123
|
+
"to": "missing"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "doc-8",
|
|
129
|
+
"status": "missing",
|
|
130
|
+
"fields": {
|
|
131
|
+
"name": "Deeds and titles",
|
|
132
|
+
"note": "House, vehicles — where the originals live."
|
|
133
|
+
},
|
|
134
|
+
"createdAt": "2026-07-18T00:00:00.000Z",
|
|
135
|
+
"updatedAt": "2026-07-18T00:00:00.000Z",
|
|
136
|
+
"history": [
|
|
137
|
+
{
|
|
138
|
+
"at": "2026-07-18T00:00:00.000Z",
|
|
139
|
+
"from": null,
|
|
140
|
+
"to": "missing"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"releasedAt": "2026-10-06T00:00:00Z",
|
|
5
|
+
"meesterManaged": false,
|
|
6
|
+
"params": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"household": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"title": "Who is this binder for?",
|
|
12
|
+
"description": "e.g. 'our family', 'Mom', 'me'.",
|
|
13
|
+
"default": "our family"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"required": [
|
|
17
|
+
"household"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"nameTemplate": "Life Binder",
|
|
21
|
+
"aboutTemplate": "about.md",
|
|
22
|
+
"missionTemplate": "mission.md",
|
|
23
|
+
"gezels": [
|
|
24
|
+
{
|
|
25
|
+
"templateId": "archivaris",
|
|
26
|
+
"voorman": true
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"tools": [
|
|
30
|
+
{
|
|
31
|
+
"name": "record_document",
|
|
32
|
+
"description": "Record that a document exists and where the original lives.",
|
|
33
|
+
"script": "binder-store",
|
|
34
|
+
"inputs": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"properties": {
|
|
37
|
+
"name": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
"location": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"note": {
|
|
44
|
+
"type": "string"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"required": [
|
|
48
|
+
"name"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"bind": {
|
|
52
|
+
"action": "record_document"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "mark_missing",
|
|
57
|
+
"description": "Mark a checklist item as a known gap.",
|
|
58
|
+
"script": "binder-store",
|
|
59
|
+
"inputs": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": {
|
|
63
|
+
"type": "string"
|
|
64
|
+
},
|
|
65
|
+
"name": {
|
|
66
|
+
"type": "string"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"bind": {
|
|
71
|
+
"action": "mark_missing"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "mark_reviewed",
|
|
76
|
+
"description": "Confirm a document was just reviewed and is current.",
|
|
77
|
+
"script": "binder-store",
|
|
78
|
+
"inputs": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"id": {
|
|
82
|
+
"type": "string"
|
|
83
|
+
},
|
|
84
|
+
"name": {
|
|
85
|
+
"type": "string"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"bind": {
|
|
90
|
+
"action": "mark_reviewed"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "binder_status",
|
|
95
|
+
"description": "The completeness picture: what's in place, missing, or due a review.",
|
|
96
|
+
"script": "binder-store",
|
|
97
|
+
"inputs": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": {}
|
|
100
|
+
},
|
|
101
|
+
"bind": {
|
|
102
|
+
"action": "status"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "checklist",
|
|
107
|
+
"description": "Read the whole checklist with locations.",
|
|
108
|
+
"script": "binder-store",
|
|
109
|
+
"inputs": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"properties": {}
|
|
112
|
+
},
|
|
113
|
+
"bind": {
|
|
114
|
+
"action": "checklist"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"craftbooks": [
|
|
119
|
+
"annual-document-review"
|
|
120
|
+
],
|
|
121
|
+
"schedules": [],
|
|
122
|
+
"pages": {
|
|
123
|
+
"entry": "dashboard/index.html",
|
|
124
|
+
"api": 1,
|
|
125
|
+
"reads": [
|
|
126
|
+
{
|
|
127
|
+
"source": "workspace",
|
|
128
|
+
"path": "documents.json"
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"workspaceSeed": [
|
|
133
|
+
"documents.json"
|
|
134
|
+
],
|
|
135
|
+
"scripts": {
|
|
136
|
+
"binder-store": "import { type InferredInput, defineScript, gezel } from '@bendyline/gezel-sdk';\nimport { rosterStore } from '@bendyline/gezel-sdk/stores';\n\nexport const meta = defineScript({\n name: 'binder-store',\n description:\n \"Read and update the life binder (documents.json). Call action:'status' for the completeness picture; 'record_document' when a document exists (name + where the original lives); 'mark_missing' / 'mark_reviewed' as reality changes; 'checklist' to read everything.\",\n inputs: {\n action: {\n type: 'string',\n description:\n \"One of 'status', 'record_document', 'mark_missing', 'mark_reviewed', or 'checklist'.\",\n required: true,\n },\n name: { type: 'string', description: \"Document name, e.g. 'Will', 'Home insurance policy'.\" },\n location: { type: 'string', description: 'Where the original lives (drawer, safe, provider).' },\n note: { type: 'string', description: 'Anything a trusted person should know about it.' },\n id: { type: 'string', description: \"Document id, e.g. 'doc-2'.\" },\n },\n outputs: {\n total: { type: 'number', description: 'Documents on the checklist.' },\n present: { type: 'number', description: 'Recorded as existing.' },\n missing: { type: 'number', description: 'Known gaps.' },\n stale: { type: 'number', description: 'Present but unreviewed for over a year.' },\n summary: { type: 'string', description: 'The completeness picture.' },\n },\n requires: ['workspace.read', 'workspace.write'],\n} as const);\n\nconst input = gezel.input as InferredInput<typeof meta>;\n\n// ── binder-rules-start ──\n// Pure derivations over rosterStore-shaped document records: statuses are\n// missing -> present; staleness is derived (present + unreviewed > 365d).\n\nvar YEAR_MS = 365 * 24 * 60 * 60 * 1000;\n\nfunction isStale(record, nowMs) {\n if (record.status !== 'present') return false;\n var reviewed = record.fields && typeof record.fields.reviewedAt === 'string'\n ? Date.parse(record.fields.reviewedAt)\n : Date.parse(record.updatedAt);\n return isFinite(reviewed) && nowMs - reviewed > YEAR_MS;\n}\n\nfunction binderShape(records, nowMs) {\n var present = 0;\n var missing = [];\n var stale = [];\n records.forEach(function (r) {\n if (r.status === 'present') {\n present += 1;\n if (isStale(r, nowMs)) stale.push(r);\n } else {\n missing.push(r);\n }\n });\n return { present: present, missing: missing, stale: stale };\n}\n\nfunction binderLine(records, nowMs) {\n var shape = binderShape(records, nowMs);\n var gaps = shape.missing\n .map(function (r) {\n return r.fields && r.fields.name ? r.fields.name : r.id;\n })\n .join(', ');\n var staleNames = shape.stale\n .map(function (r) {\n return r.fields && r.fields.name ? r.fields.name : r.id;\n })\n .join(', ');\n return (\n shape.present +\n ' of ' +\n records.length +\n ' in place' +\n (gaps ? '. Missing: ' + gaps : '. Nothing missing') +\n (staleNames ? '. Due a review: ' + staleNames + '.' : '.')\n );\n}\n// ── binder-rules-end ──\n\nconst binder = rosterStore(gezel.fs, 'documents.json', {\n stages: ['missing', 'present'],\n idPrefix: 'doc',\n});\n\nasync function resolveDoc(): Promise<string> {\n if (input.id) return input.id;\n if (input.name) {\n const wanted = input.name.toLowerCase();\n const matches = (await binder.list()).filter(\n (r) => String(r.fields.name ?? '').toLowerCase() === wanted,\n );\n if (matches.length === 1) return matches[0]!.id;\n }\n throw new Error(\"Pass 'id' (e.g. 'doc-2') or an exact document 'name'.\");\n}\n\nif (input.action === 'record_document') {\n if (!input.name) throw new Error(\"record_document needs 'name'.\");\n const existing = (await binder.list()).find(\n (r) => String(r.fields.name ?? '').toLowerCase() === input.name!.toLowerCase(),\n );\n if (existing) {\n await binder.update(existing.id, {\n fields: {\n ...(input.location ? { location: input.location } : {}),\n ...(input.note ? { note: input.note } : {}),\n reviewedAt: new Date().toISOString(),\n },\n });\n await binder.transition(existing.id, 'present');\n } else {\n await binder.add({\n status: 'present',\n fields: {\n name: input.name,\n ...(input.location ? { location: input.location } : {}),\n ...(input.note ? { note: input.note } : {}),\n reviewedAt: new Date().toISOString(),\n },\n });\n }\n} else if (input.action === 'mark_missing') {\n await binder.transition(await resolveDoc(), 'missing');\n} else if (input.action === 'mark_reviewed') {\n const id = await resolveDoc();\n await binder.update(id, { fields: { reviewedAt: new Date().toISOString() } });\n await binder.transition(id, 'present');\n} else if (input.action !== 'status' && input.action !== 'checklist') {\n throw new Error(\n `Unknown action '${input.action}'. Use status, record_document, mark_missing, mark_reviewed, or checklist.`,\n );\n}\n\nconst records = await binder.list();\nconst shape = binderShape(records, Date.now());\nconst listing =\n input.action === 'checklist'\n ? records\n .map(\n (r) =>\n `${r.id} [${r.status}${isStale(r, Date.now()) ? ', stale' : ''}] ${String(r.fields.name ?? '?')}${r.fields.location ? ` — ${String(r.fields.location)}` : ''}`,\n )\n .join('\\n') || 'The checklist is empty.'\n : '';\n\ngezel.output({\n total: records.length,\n present: shape.present,\n missing: shape.missing.length,\n stale: shape.stale.length,\n summary: listing || binderLine(records, Date.now()),\n});\n"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
- Every checklist item is either recorded (with where the original lives) or a
|
|
2
|
+
known, owned gap — nothing ambiguous.
|
|
3
|
+
- The one-page test holds: a trusted person could find what they need in five
|
|
4
|
+
minutes from what's recorded here.
|
|
5
|
+
- Anything unreviewed for a year gets flagged and re-confirmed.
|
|
6
|
+
- Document contents are never stored; locations and instructions are.
|