onboarding-wizard.mjs
358 lines 20.4 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Hub onboarding wizard: state + step definitions (hosted vs self-hosted).
3 * UI binding lives in hub.js; this module stays testable without a browser DOM.
4 */
5
6 export const ONBOARDING_LS_KEY = 'knowtation_onboarding_v1';
7
8 /** Repo docs on GitHub main (Hub is often opened without a local clone). */
9 export const DOCS_BASE = 'https://github.com/aaronrene/knowtation/blob/main/docs';
10
11 export const AGENT_INTEGRATION_ANCHOR_PROPOSALS = `${DOCS_BASE}/AGENT-INTEGRATION.md#4-proposals-review-before-commit`;
12
13 export const IMPORT_SOURCES_URL = `${DOCS_BASE}/IMPORT-SOURCES.md`;
14
15 /**
16 * Copyable text: user pastes into ChatGPT / Claude / etc. to get export steps for their stack.
17 * Grounded in IMPORT-SOURCES.md (chatgpt-export, claude-export, openclaw).
18 */
19 export const LLM_SELF_HELP_EXPORT_PROMPT = [
20 'I am importing chats and memory into Knowtation (Markdown vault notes with frontmatter).',
21 '',
22 'Please give concise, accurate export instructions for my situation:',
23 '- OpenAI / ChatGPT: account data export (ZIP or folder with conversations.json) suitable for a `chatgpt-export` style import.',
24 '- Anthropic / Claude: privacy export (chats and/or memory) suitable for a `claude-export` style import.',
25 '- OpenClaw: any supported export path or files that map to Knowtation `openclaw` import.',
26 '- Hermes Agent: export from `~/.hermes/memories/` or `hermes memory export`; import via `markdown` or copy MEMORY.md / USER.md.',
27 '',
28 'For each product I name, list the exact menu path (as of my stated app version if I add one), the file types I will get (ZIP, JSON, folder layout), and any size or rate limits I should watch for.',
29 '',
30 'I will upload the result via Knowtation Hub Import or run `knowtation import <source-type> …` from the CLI after export.',
31 ].join('\n');
32
33 /** @typedef {'hosted'|'selfhosted'} HostingPath */
34 /** @typedef {'in_progress'|'dismissed'|'completed'} OnboardingStatus */
35
36 /**
37 * @typedef {Object} OnboardingStateV1
38 * @property {1} v
39 * @property {string} userKey
40 * @property {HostingPath} hostingPath
41 * @property {number} stepIndex
42 * @property {OnboardingStatus} status
43 * @property {number | null} [dismissedAt]
44 * @property {number | null} [completedAt]
45 */
46
47 /**
48 * @param {unknown} raw
49 * @returns {OnboardingStateV1 | null}
50 */
51 export function parseOnboardingState(raw) {
52 if (raw == null || typeof raw !== 'string') return null;
53 try {
54 const o = JSON.parse(raw);
55 if (!o || o.v !== 1 || typeof o.userKey !== 'string') return null;
56 if (o.hostingPath !== 'hosted' && o.hostingPath !== 'selfhosted') return null;
57 const status = o.status;
58 if (status !== 'in_progress' && status !== 'dismissed' && status !== 'completed') return null;
59 const stepIndex = Math.max(0, Math.floor(Number(o.stepIndex) || 0));
60 return {
61 v: 1,
62 userKey: o.userKey,
63 hostingPath: o.hostingPath,
64 stepIndex,
65 status,
66 dismissedAt: typeof o.dismissedAt === 'number' ? o.dismissedAt : null,
67 completedAt: typeof o.completedAt === 'number' ? o.completedAt : null,
68 };
69 } catch {
70 return null;
71 }
72 }
73
74 /** @param {OnboardingStateV1} s */
75 export function serializeOnboardingState(s) {
76 return JSON.stringify(s);
77 }
78
79 /**
80 * @param {string} userKey
81 * @param {HostingPath} hostingPath
82 * @returns {OnboardingStateV1}
83 */
84 export function createFreshState(userKey, hostingPath) {
85 return {
86 v: 1,
87 userKey,
88 hostingPath,
89 stepIndex: 0,
90 status: 'in_progress',
91 dismissedAt: null,
92 completedAt: null,
93 };
94 }
95
96 /**
97 * @param {boolean} isHosted
98 * @returns {number}
99 */
100 export function getStepCount(isHosted) {
101 return isHosted ? 9 : 5;
102 }
103
104 /**
105 * Whether to open the wizard automatically after login/settings.
106 * @param {OnboardingStateV1 | null} state
107 * @param {string} currentUserKey
108 * @param {HostingPath} currentHostingPath
109 * @returns {boolean}
110 */
111 export function shouldAutoOpenWizard(state, currentUserKey, currentHostingPath) {
112 if (!currentUserKey) return false;
113 if (!state) return true;
114 if (state.userKey !== currentUserKey) return true;
115 if (state.hostingPath !== currentHostingPath) return true;
116 if (state.status === 'dismissed' || state.status === 'completed') return false;
117 return state.status === 'in_progress';
118 }
119
120 /**
121 * @param {boolean} isHosted
122 * @param {number} index
123 * @returns {{ id: string, title: string, bodyHtml: string } | null}
124 */
125 export function getStepContent(isHosted, index) {
126 if (isHosted) {
127 const steps = [
128 {
129 id: 'h0',
130 title: 'Your memory home',
131 bodyHtml:
132 '<p><strong>Knowtation Hub</strong> holds your team’s indexed notes — Markdown you own, fast search, and one simple rule for AI: <strong>suggested edits wait for your approval</strong> before they become real notes.</p>' +
133 '<details class="how-to-details">' +
134 '<summary>More detail — “token savings” (two layers, plain English)</summary>' +
135 '<div class="how-to-details-body">' +
136 '<p><strong>Vault &amp; search:</strong> Assistants pull short snippets instead of giant paste-ins — that saves context in any tool.</p>' +
137 '<p><strong>Terminal chatter:</strong> Shrinking raw shell logs on your laptop is separate optional tooling; it is not what this hosted vault product runs for you.</p>' +
138 '<p class="onboarding-tip">Same framing as <a href="' +
139 DOCS_BASE +
140 '/TOKEN-SAVINGS.md" target="_blank" rel="noopener">Token savings (retrieval &amp; cost discipline)</a>.</p>' +
141 '</div>' +
142 '</details>',
143 },
144 {
145 id: 'h1',
146 title: 'What do you want to do first?',
147 bodyHtml:
148 '<p>For <strong>hosted</strong> Knowtation (what you signed into here), almost everyone starts one of two ways — pick one; you can do the other anytime.</p>' +
149 '<div class="onboarding-path-grid" role="group" aria-label="Hosted getting started">' +
150 '<div class="onboarding-path-card">' +
151 '<h3 class="onboarding-path-card-title">Bring in chats &amp; files</h3>' +
152 '<p class="onboarding-path-card-body">Upload exports or files with <strong>Import</strong> (header). Use this when you already have a ChatGPT / Claude / OpenClaw export or documents on your computer.</p>' +
153 '</div>' +
154 '<div class="onboarding-path-card">' +
155 '<h3 class="onboarding-path-card-title">Connect your assistant</h3>' +
156 '<p class="onboarding-path-card-body">Open <strong>Settings → Integrations</strong> and paste the copied block into Cursor, Claude Desktop, or another MCP-capable tool so it can search your vault and queue suggested edits.</p>' +
157 '</div>' +
158 '</div>' +
159 '<details class="how-to-details">' +
160 '<summary>Self-hosted only — I run Knowtation on my own computer</summary>' +
161 '<div class="how-to-details-body">' +
162 '<p>If you cloned this repo and run the Hub locally, the <em>ideas</em> are the same (import vs connect tools), but you also manage disk paths, OAuth apps, and config files. Follow <strong>How to use → Setup → Self-hosted setup</strong> and the repo <a href="' +
163 DOCS_BASE +
164 '/TWO-PATHS-HOSTED-AND-SELF-HOSTED.md#quick-start-self-hosted" target="_blank" rel="noopener">Quick start (self-hosted)</a>.</p>' +
165 '</div>' +
166 '</details>' +
167 '<p class="onboarding-tip">Next: <strong>Integrations</strong>, imports by platform, then <strong>Suggested</strong> (where edits wait for approval).</p>',
168 },
169 {
170 id: 'h2',
171 title: 'Integrations (MCP + API)',
172 bodyHtml:
173 '<p>While signed in, open <strong>Settings → Integrations → Hub API</strong>.</p>' +
174 '<p><strong>Copy Hub URL, token &amp; vault</strong> — your private “key card” for tools outside the browser (paste into env vars or MCP config).</p>' +
175 '<p><strong>Copy MCP</strong> — a ready-made snippet for common clients.</p>' +
176 '<p><strong>Copy prime</strong> — a small <strong>non-secret</strong> JSON reminder (which Hub and vault). Not your password; use it with the key card after your tool connects.</p>' +
177 '<details class="how-to-details">' +
178 '<summary>Technical details (headers, env names, prime URI)</summary>' +
179 '<div class="how-to-details-body">' +
180 '<p>Requests use <code>Authorization: Bearer …</code> and <code>X-Vault-Id</code> on <code>POST …/mcp</code>, <code>/api/v1/search</code>, and related routes. The copy button names variables such as <code>KNOWTATION_HUB_URL</code>, <code>KNOWTATION_HUB_TOKEN</code>, and <code>KNOWTATION_HUB_VAULT_ID</code>.</p>' +
181 '<p><strong>Copy prime</strong> JSON points at MCP <code>readResource</code> URI <code>knowtation://hosted/prime</code> plus gateway base URL and vault id — <strong>no JWT inside</strong>. After connect, reading that resource can return session context and prompt names for your role.</p>' +
182 '</div>' +
183 '</details>' +
184 '<p class="onboarding-tip">Deep reference: <a href="' +
185 DOCS_BASE +
186 '/AGENT-INTEGRATION.md" target="_blank" rel="noopener">Agent integration</a> (CLI, MCP, Hub API).</p>',
187 },
188 {
189 id: 'h-imports',
190 title: 'Imports by platform',
191 bodyHtml:
192 '<p>Use <strong>Import</strong> in the header to upload exports. Most people start with one of these:</p>' +
193 '<ul class="onboarding-import-cards" role="list">' +
194 '<li><strong>OpenAI / ChatGPT</strong> — account data export (ZIP or folder; often includes <code>conversations.json</code>).</li>' +
195 '<li><strong>Anthropic / Claude</strong> — privacy / data export (chats and/or memory).</li>' +
196 '<li><strong>OpenClaw</strong> — supported agent exports per our import matrix.</li>' +
197 '</ul>' +
198 '<details class="how-to-details">' +
199 '<summary>CLI &amp; API source names</summary>' +
200 '<div class="how-to-details-body">' +
201 '<p>The Hub and CLI label these as <code>chatgpt-export</code>, <code>claude-export</code>, <code>openclaw</code>, and more. Full list and flags: <a href="' +
202 IMPORT_SOURCES_URL +
203 '" target="_blank" rel="noopener">Import sources</a>.</p>' +
204 '</div>' +
205 '</details>' +
206 '<p class="onboarding-tip">Full matrix: <a href="' +
207 IMPORT_SOURCES_URL +
208 '" target="_blank" rel="noopener">IMPORT-SOURCES.md</a>.</p>' +
209 '<p><strong>LLM self-help:</strong> paste the text below into any assistant and name your product; ask it for exact export menu paths and file shapes.</p>' +
210 '<textarea class="onboarding-llm-prompt" data-onboarding-llm-prompt readonly rows="9" aria-label="Copyable prompt for export instructions"></textarea>' +
211 '<p class="onboarding-copy-row"><button type="button" class="btn-secondary onboarding-copy-llm-btn">Copy export helper prompt</button></p>',
212 },
213 {
214 id: 'h4',
215 title: 'Proposals and the Suggested queue',
216 bodyHtml:
217 '<p><strong>Agents suggest; humans approve.</strong> Proposed edits stay out of the canonical vault until someone approves them — same speed as direct writes, with a paper trail and roles.</p>' +
218 '<p>In the Hub, open the <strong>Suggested</strong> tab (next to Notes and Activity) to review proposals. <strong>Activity</strong> is the timeline; <strong>Discarded</strong> keeps rejected items for reference. You can also start a proposal from a note (<strong>Propose change</strong>) or <strong>New proposal</strong>.</p>' +
219 '<p class="onboarding-tip">Contract and API details: <a href="' +
220 AGENT_INTEGRATION_ANCHOR_PROPOSALS +
221 '" target="_blank" rel="noopener">Agent integration — §4 Proposals</a>.</p>',
222 },
223 {
224 id: 'h5',
225 title: 'Your notes live here',
226 bodyHtml:
227 '<p>After you sign in, your vault is <strong>your private space</strong> in Knowtation. The list may look empty until you add something — that is normal.</p>' +
228 '<p class="onboarding-tip">On hosted Knowtation, a <strong>project</strong> is a label on notes to group them (not a disk folder path).</p>',
229 },
230 {
231 id: 'h6',
232 title: 'Add your first note or file',
233 bodyHtml:
234 '<p>Use <strong>+ New note</strong> to write something small (for example a shopping list or a link you want to remember).</p>' +
235 '<p>Or use <strong>Import</strong> to bring in a file from your computer.</p>' +
236 '<p class="onboarding-tip">Want more detail? Open <strong>How to use</strong> → Knowledge &amp; agents anytime.</p>',
237 },
238 {
239 id: 'h7',
240 title: 'Keep a copy (optional)',
241 bodyHtml:
242 '<p>Your notes are already stored on Knowtation. If you also want a <strong>copy on GitHub</strong> (your account, your repo), use <strong>Settings → Backup</strong> and connect GitHub when you are ready.</p>' +
243 '<p class="onboarding-tip">You can skip this until later.</p>',
244 },
245 {
246 id: 'h8',
247 title: 'Power tools for agents',
248 bodyHtml:
249 '<p>On hosted Knowtation, MCP exposes vault operations your role allows — search and read notes, propose changes (with humans approving in <strong>Suggested</strong>), imports, indexing, memory tools where enabled, and more.</p>' +
250 '<p><strong>MCP prompts</strong> are composition templates registered for your session. After you connect, your client can list them (e.g. via <code>prompts/list</code>) — that list is authoritative for this deployment.</p>' +
251 '<details class="how-to-details">' +
252 '<summary>Technical inventory (prompt names &amp; prime)</summary>' +
253 '<div class="how-to-details-body">' +
254 '<p>Example prompt names you may see include <strong>daily-brief</strong>, <strong>search-and-synthesize</strong>, <strong>project-summary</strong>, <strong>temporal-summary</strong>, <strong>content-plan</strong>, <strong>meeting-notes</strong>, <strong>knowledge-gap</strong>, <strong>causal-chain</strong>, <strong>extract-entities</strong>, <strong>write-from-capture</strong> (editor+), <strong>memory-context</strong>, <strong>memory-informed-search</strong>, <strong>resume-session</strong> — plus tools such as <strong>search</strong>, <strong>get_note</strong>, <strong>list_notes</strong>, <strong>propose</strong>, <strong>import</strong>, <strong>index</strong>. <strong>Copy prime</strong> JSON references <code>knowtation://hosted/prime</code> and echoes allowed prompt names for your current session.</p>' +
255 '</div>' +
256 '</details>' +
257 '<p class="onboarding-tip">One page for tools, REST, CLI, and proposal semantics: <a href="' +
258 DOCS_BASE +
259 '/AGENT-INTEGRATION.md" target="_blank" rel="noopener">AGENT-INTEGRATION.md</a>.</p>' +
260 '<p>That is the whole hosted loop: notes and imports in the vault, integrations for assistants, proposals for safe writes, optional GitHub backup.</p>',
261 },
262 ];
263 return steps[index] || null;
264 }
265 const steps = [
266 {
267 id: 's1',
268 title: 'Where your notes live',
269 bodyHtml:
270 '<p>In this <strong>browser Hub</strong>, your note list, Import, and search work without you setting a folder path — that is managed for you.</p>' +
271 '<details class="how-to-details">' +
272 '<summary>Self-hosted only — folder on your machine</summary>' +
273 '<div class="how-to-details-body">' +
274 '<p>If you run Knowtation from a clone on your computer, notes live in a real <strong>folder</strong>. Match that path in <code>config/local.yaml</code>, <code>KNOWTATION_VAULT_PATH</code> in <code>.env</code>, and <strong>Settings → Backup</strong> so the CLI and Hub agree.</p>' +
275 '<p class="onboarding-tip"><a href="' +
276 DOCS_BASE +
277 '/TWO-PATHS-HOSTED-AND-SELF-HOSTED.md#quick-start-self-hosted" target="_blank" rel="noopener">Quick start (self-hosted)</a> has the exact commands.</p>' +
278 '</div>' +
279 '</details>',
280 },
281 {
282 id: 's2',
283 title: 'Search and indexing',
284 bodyHtml:
285 '<p><strong>Browsing and listing notes</strong> works right away. After you import a lot or change search-related settings, use <strong>Re-index</strong> in the toolbar so “meaning” search stays in sync.</p>' +
286 '<details class="how-to-details">' +
287 '<summary>Self-hosted only — CLI from the repo</summary>' +
288 '<div class="how-to-details-body">' +
289 '<p>From the project root run <code>npm run index</code>, or use <strong>Re-index</strong> here after embedding or vector config changes. Plain-language steps: <strong>How to use → Setup</strong> (embeddings / sqlite-vec).</p>' +
290 '</div>' +
291 '</details>' +
292 '<p class="onboarding-tip">Open <strong>How to use → Setup</strong> anytime for the full checklist.</p>',
293 },
294 {
295 id: 's3',
296 title: 'Signing in',
297 bodyHtml:
298 '<p>You sign in with <strong>Google or GitHub</strong> so this Hub knows which account and vault are yours.</p>' +
299 '<details class="how-to-details">' +
300 '<summary>Self-hosted only — your own OAuth app (.env)</summary>' +
301 '<div class="how-to-details-body">' +
302 '<p>Operators register a Google/GitHub OAuth app and put client ID and secret in <code>.env</code>, then restart the Hub. If you see <strong>OAuth is not configured</strong>, follow <strong>How to use → Setup → Step 3</strong> or ask whoever runs your server.</p>' +
303 '</div>' +
304 '</details>',
305 },
306 {
307 id: 's4',
308 title: 'Import, agents, and backup',
309 bodyHtml:
310 '<p><strong>Import</strong> brings files from other tools. <strong>Settings → Integrations</strong> shows how to connect agents (MCP). <strong>Settings → Backup</strong> walks through GitHub backup when you want version history off-machine.</p>' +
311 '<p><strong>Proposals:</strong> agents use the same APIs as humans; review queued changes under the Hub <strong>Suggested</strong> tab before they merge into the vault. See <a href="' +
312 AGENT_INTEGRATION_ANCHOR_PROPOSALS +
313 '" target="_blank" rel="noopener">Agent integration — §4 Proposals</a>.</p>' +
314 '<p class="onboarding-tip">The seven steps under <strong>How to use → Setup</strong> stay the full reference — this wizard is the short path.</p>',
315 },
316 {
317 id: 's5',
318 title: 'You are set',
319 bodyHtml:
320 '<p>Use the tree and search to browse notes, <strong>+ New note</strong> to capture, and <strong>Settings</strong> anytime for backup and integrations.</p>' +
321 '<p class="onboarding-tip">Come back to <strong>How to use</strong> whenever you need deeper explanations.</p>',
322 },
323 ];
324 return steps[index] || null;
325 }
326
327 /**
328 * Secondary actions for wizard footer (handled in hub.js).
329 * @typedef {{ id: string, label: string }} OnboardingAction
330 * @param {boolean} isHosted
331 * @param {number} index
332 * @returns {OnboardingAction[]}
333 */
334 export function getStepSecondaryActions(isHosted, index) {
335 if (isHosted) {
336 if (index === 0) return [{ id: 'openWhyTokenDoc', label: 'Why Knowtation (tokens)' }];
337 if (index === 1) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openSettingsIntegrations', label: 'Settings → Integrations' }];
338 if (index === 2) return [{ id: 'openSettingsIntegrations', label: 'Open Settings → Integrations' }];
339 if (index === 3) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openImportSourcesDoc', label: 'Import sources (docs)' }];
340 if (index === 4) return [{ id: 'focusSuggestedTab', label: 'Open Suggested tab' }, { id: 'openAgentDocProposals', label: 'Read §4 Proposals (docs)' }];
341 if (index === 5) return [{ id: 'projectsHelp', label: 'How projects work' }];
342 if (index === 6) return [{ id: 'howToKnowledge', label: 'How to use: Knowledge & agents' }];
343 if (index === 7) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }];
344 if (index === 8) return [{ id: 'openAgentIntegrationDoc', label: 'Open AGENT-INTEGRATION.md' }];
345 return [];
346 }
347 if (index === 0) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }];
348 if (index === 1) return [{ id: 'howToSetup4', label: 'How to use: Setup (search)' }];
349 if (index === 2) return [{ id: 'howToSetup3', label: 'How to use: Setup (sign in)' }];
350 if (index === 3) {
351 return [
352 { id: 'openSettingsIntegrations', label: 'Settings → Integrations' },
353 { id: 'openSettingsBackup', label: 'Settings → Backup' },
354 { id: 'openAgentDocProposals', label: '§4 Proposals (docs)' },
355 ];
356 }
357 return [];
358 }
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago