onboarding-wizard.mjs
354 lines 20.3 KB
Raw
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 12 days 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 // Never auto-popup. Wizard is opened only from How to use / Setup guide.
113 return false;
114 }
115
116 /**
117 * @param {boolean} isHosted
118 * @param {number} index
119 * @returns {{ id: string, title: string, bodyHtml: string } | null}
120 */
121 export function getStepContent(isHosted, index) {
122 if (isHosted) {
123 const steps = [
124 {
125 id: 'h0',
126 title: 'Your memory home',
127 bodyHtml:
128 '<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>' +
129 '<details class="how-to-details">' +
130 '<summary>More detail — “token savings” (two layers, plain English)</summary>' +
131 '<div class="how-to-details-body">' +
132 '<p><strong>Vault &amp; search:</strong> Assistants pull short snippets instead of giant paste-ins — that saves context in any tool.</p>' +
133 '<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>' +
134 '<p class="onboarding-tip">Same framing as <a href="' +
135 DOCS_BASE +
136 '/TOKEN-SAVINGS.md" target="_blank" rel="noopener">Token savings (retrieval &amp; cost discipline)</a>.</p>' +
137 '</div>' +
138 '</details>',
139 },
140 {
141 id: 'h1',
142 title: 'What do you want to do first?',
143 bodyHtml:
144 '<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>' +
145 '<div class="onboarding-path-grid" role="group" aria-label="Hosted getting started">' +
146 '<div class="onboarding-path-card">' +
147 '<h3 class="onboarding-path-card-title">Bring in chats &amp; files</h3>' +
148 '<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>' +
149 '</div>' +
150 '<div class="onboarding-path-card">' +
151 '<h3 class="onboarding-path-card-title">Connect your assistant</h3>' +
152 '<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>' +
153 '</div>' +
154 '</div>' +
155 '<details class="how-to-details">' +
156 '<summary>Self-hosted only — I run Knowtation on my own computer</summary>' +
157 '<div class="how-to-details-body">' +
158 '<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="' +
159 DOCS_BASE +
160 '/TWO-PATHS-HOSTED-AND-SELF-HOSTED.md#quick-start-self-hosted" target="_blank" rel="noopener">Quick start (self-hosted)</a>.</p>' +
161 '</div>' +
162 '</details>' +
163 '<p class="onboarding-tip">Next: <strong>Integrations</strong>, imports by platform, then <strong>Review</strong> (where edits wait for approval).</p>',
164 },
165 {
166 id: 'h2',
167 title: 'Integrations (MCP + API)',
168 bodyHtml:
169 '<p>While signed in, open <strong>Settings → Integrations → Hub API</strong>.</p>' +
170 '<p><strong>Copy session access token (expires)</strong> plus Hub URL and vault — for short scripts and smoke tests, not always-on cloud agents (use <strong>Connect cloud agent</strong> below for those).</p>' +
171 '<p><strong>Copy MCP</strong> — a ready-made snippet for common clients.</p>' +
172 '<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>' +
173 '<details class="how-to-details">' +
174 '<summary>Technical details (headers, env names, prime URI)</summary>' +
175 '<div class="how-to-details-body">' +
176 '<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>' +
177 '<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>' +
178 '</div>' +
179 '</details>' +
180 '<p class="onboarding-tip">Deep reference: <a href="' +
181 DOCS_BASE +
182 '/AGENT-INTEGRATION.md" target="_blank" rel="noopener">Agent integration</a> (CLI, MCP, Hub API).</p>',
183 },
184 {
185 id: 'h-imports',
186 title: 'Imports by platform',
187 bodyHtml:
188 '<p>Use <strong>Import</strong> in the header to upload exports. Most people start with one of these:</p>' +
189 '<ul class="onboarding-import-cards" role="list">' +
190 '<li><strong>OpenAI / ChatGPT</strong> — account data export (ZIP or folder; often includes <code>conversations.json</code>).</li>' +
191 '<li><strong>Anthropic / Claude</strong> — privacy / data export (chats and/or memory).</li>' +
192 '<li><strong>OpenClaw</strong> — supported agent exports per our import matrix.</li>' +
193 '</ul>' +
194 '<details class="how-to-details">' +
195 '<summary>CLI &amp; API source names</summary>' +
196 '<div class="how-to-details-body">' +
197 '<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="' +
198 IMPORT_SOURCES_URL +
199 '" target="_blank" rel="noopener">Import sources</a>.</p>' +
200 '</div>' +
201 '</details>' +
202 '<p class="onboarding-tip">Full matrix: <a href="' +
203 IMPORT_SOURCES_URL +
204 '" target="_blank" rel="noopener">IMPORT-SOURCES.md</a>.</p>' +
205 '<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>' +
206 '<textarea class="onboarding-llm-prompt" data-onboarding-llm-prompt readonly rows="9" aria-label="Copyable prompt for export instructions"></textarea>' +
207 '<p class="onboarding-copy-row"><button type="button" class="btn-secondary onboarding-copy-llm-btn">Copy export helper prompt</button></p>',
208 },
209 {
210 id: 'h4',
211 title: 'Proposals and the Review queue',
212 bodyHtml:
213 '<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>' +
214 '<p>In the Hub, open <strong>Review</strong> in the left rail (or the mobile bottom nav) to triage proposals. <strong>History</strong> holds <strong>Activity</strong> (timeline) and <strong>Discarded</strong> (rejected items). You can also start a proposal from a note (<strong>Propose change</strong>) or <strong>New proposal</strong>.</p>' +
215 '<p class="onboarding-tip">Contract and API details: <a href="' +
216 AGENT_INTEGRATION_ANCHOR_PROPOSALS +
217 '" target="_blank" rel="noopener">Agent integration — §4 Proposals</a>.</p>',
218 },
219 {
220 id: 'h5',
221 title: 'Your notes live here',
222 bodyHtml:
223 '<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>' +
224 '<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>',
225 },
226 {
227 id: 'h6',
228 title: 'Add your first note or file',
229 bodyHtml:
230 '<p>Use <strong>+ New note</strong> to write something small (for example a shopping list or a link you want to remember).</p>' +
231 '<p>Or use <strong>Import</strong> to bring in a file from your computer.</p>' +
232 '<p class="onboarding-tip">Want more detail? Open <strong>How to use</strong> → Knowledge &amp; agents anytime.</p>',
233 },
234 {
235 id: 'h7',
236 title: 'Keep a copy (optional)',
237 bodyHtml:
238 '<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>' +
239 '<p class="onboarding-tip">You can skip this until later.</p>',
240 },
241 {
242 id: 'h8',
243 title: 'Power tools for agents',
244 bodyHtml:
245 '<p>On hosted Knowtation, MCP exposes vault operations your role allows — search and read notes, propose changes (with humans approving in <strong>Review</strong>), imports, indexing, memory tools where enabled, and more.</p>' +
246 '<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>' +
247 '<details class="how-to-details">' +
248 '<summary>Technical inventory (prompt names &amp; prime)</summary>' +
249 '<div class="how-to-details-body">' +
250 '<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>' +
251 '</div>' +
252 '</details>' +
253 '<p class="onboarding-tip">One page for tools, REST, CLI, and proposal semantics: <a href="' +
254 DOCS_BASE +
255 '/AGENT-INTEGRATION.md" target="_blank" rel="noopener">AGENT-INTEGRATION.md</a>.</p>' +
256 '<p>That is the whole hosted loop: notes and imports in the vault, integrations for assistants, proposals for safe writes, optional GitHub backup.</p>',
257 },
258 ];
259 return steps[index] || null;
260 }
261 const steps = [
262 {
263 id: 's1',
264 title: 'Where your notes live',
265 bodyHtml:
266 '<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>' +
267 '<details class="how-to-details">' +
268 '<summary>Self-hosted only — folder on your machine</summary>' +
269 '<div class="how-to-details-body">' +
270 '<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>' +
271 '<p class="onboarding-tip"><a href="' +
272 DOCS_BASE +
273 '/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>' +
274 '</div>' +
275 '</details>',
276 },
277 {
278 id: 's2',
279 title: 'Search and indexing',
280 bodyHtml:
281 '<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>' +
282 '<details class="how-to-details">' +
283 '<summary>Self-hosted only — CLI from the repo</summary>' +
284 '<div class="how-to-details-body">' +
285 '<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>' +
286 '</div>' +
287 '</details>' +
288 '<p class="onboarding-tip">Open <strong>How to use → Setup</strong> anytime for the full checklist.</p>',
289 },
290 {
291 id: 's3',
292 title: 'Signing in',
293 bodyHtml:
294 '<p>You sign in with <strong>Google or GitHub</strong> so this Hub knows which account and vault are yours.</p>' +
295 '<details class="how-to-details">' +
296 '<summary>Self-hosted only — your own OAuth app (.env)</summary>' +
297 '<div class="how-to-details-body">' +
298 '<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>' +
299 '</div>' +
300 '</details>',
301 },
302 {
303 id: 's4',
304 title: 'Import, agents, and backup',
305 bodyHtml:
306 '<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>' +
307 '<p><strong>Proposals:</strong> agents use the same APIs as humans; review queued changes under Hub <strong>Review</strong> before they merge into the vault. See <a href="' +
308 AGENT_INTEGRATION_ANCHOR_PROPOSALS +
309 '" target="_blank" rel="noopener">Agent integration — §4 Proposals</a>.</p>' +
310 '<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>',
311 },
312 {
313 id: 's5',
314 title: 'You are set',
315 bodyHtml:
316 '<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>' +
317 '<p class="onboarding-tip">Come back to <strong>How to use</strong> whenever you need deeper explanations.</p>',
318 },
319 ];
320 return steps[index] || null;
321 }
322
323 /**
324 * Secondary actions for wizard footer (handled in hub.js).
325 * @typedef {{ id: string, label: string }} OnboardingAction
326 * @param {boolean} isHosted
327 * @param {number} index
328 * @returns {OnboardingAction[]}
329 */
330 export function getStepSecondaryActions(isHosted, index) {
331 if (isHosted) {
332 if (index === 0) return [{ id: 'openWhyTokenDoc', label: 'Why Knowtation (tokens)' }];
333 if (index === 1) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openSettingsIntegrations', label: 'Settings → Integrations' }];
334 if (index === 2) return [{ id: 'openSettingsIntegrations', label: 'Open Settings → Integrations' }];
335 if (index === 3) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openImportSourcesDoc', label: 'Import sources (docs)' }];
336 if (index === 4) return [{ id: 'focusSuggestedTab', label: 'Open Review' }, { id: 'openAgentDocProposals', label: 'Read §4 Proposals (docs)' }];
337 if (index === 5) return [{ id: 'projectsHelp', label: 'How projects work' }];
338 if (index === 6) return [{ id: 'howToKnowledge', label: 'How to use: Knowledge & agents' }];
339 if (index === 7) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }];
340 if (index === 8) return [{ id: 'openAgentIntegrationDoc', label: 'Open AGENT-INTEGRATION.md' }];
341 return [];
342 }
343 if (index === 0) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }];
344 if (index === 1) return [{ id: 'howToSetup4', label: 'How to use: Setup (search)' }];
345 if (index === 2) return [{ id: 'howToSetup3', label: 'How to use: Setup (sign in)' }];
346 if (index === 3) {
347 return [
348 { id: 'openSettingsIntegrations', label: 'Settings → Integrations' },
349 { id: 'openSettingsBackup', label: 'Settings → Backup' },
350 { id: 'openAgentDocProposals', label: '§4 Proposals (docs)' },
351 ];
352 }
353 return [];
354 }
File History 1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 12 days ago