/** * Hub onboarding wizard: state + step definitions (hosted vs self-hosted). * UI binding lives in hub.js; this module stays testable without a browser DOM. */ export const ONBOARDING_LS_KEY = 'knowtation_onboarding_v1'; /** Repo docs on GitHub main (Hub is often opened without a local clone). */ export const DOCS_BASE = 'https://github.com/aaronrene/knowtation/blob/main/docs'; export const AGENT_INTEGRATION_ANCHOR_PROPOSALS = `${DOCS_BASE}/AGENT-INTEGRATION.md#4-proposals-review-before-commit`; export const IMPORT_SOURCES_URL = `${DOCS_BASE}/IMPORT-SOURCES.md`; /** * Copyable text: user pastes into ChatGPT / Claude / etc. to get export steps for their stack. * Grounded in IMPORT-SOURCES.md (chatgpt-export, claude-export, openclaw). */ export const LLM_SELF_HELP_EXPORT_PROMPT = [ 'I am importing chats and memory into Knowtation (Markdown vault notes with frontmatter).', '', 'Please give concise, accurate export instructions for my situation:', '- OpenAI / ChatGPT: account data export (ZIP or folder with conversations.json) suitable for a `chatgpt-export` style import.', '- Anthropic / Claude: privacy export (chats and/or memory) suitable for a `claude-export` style import.', '- OpenClaw: any supported export path or files that map to Knowtation `openclaw` import.', '- Hermes Agent: export from `~/.hermes/memories/` or `hermes memory export`; import via `markdown` or copy MEMORY.md / USER.md.', '', '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.', '', 'I will upload the result via Knowtation Hub Import or run `knowtation import …` from the CLI after export.', ].join('\n'); /** @typedef {'hosted'|'selfhosted'} HostingPath */ /** @typedef {'in_progress'|'dismissed'|'completed'} OnboardingStatus */ /** * @typedef {Object} OnboardingStateV1 * @property {1} v * @property {string} userKey * @property {HostingPath} hostingPath * @property {number} stepIndex * @property {OnboardingStatus} status * @property {number | null} [dismissedAt] * @property {number | null} [completedAt] */ /** * @param {unknown} raw * @returns {OnboardingStateV1 | null} */ export function parseOnboardingState(raw) { if (raw == null || typeof raw !== 'string') return null; try { const o = JSON.parse(raw); if (!o || o.v !== 1 || typeof o.userKey !== 'string') return null; if (o.hostingPath !== 'hosted' && o.hostingPath !== 'selfhosted') return null; const status = o.status; if (status !== 'in_progress' && status !== 'dismissed' && status !== 'completed') return null; const stepIndex = Math.max(0, Math.floor(Number(o.stepIndex) || 0)); return { v: 1, userKey: o.userKey, hostingPath: o.hostingPath, stepIndex, status, dismissedAt: typeof o.dismissedAt === 'number' ? o.dismissedAt : null, completedAt: typeof o.completedAt === 'number' ? o.completedAt : null, }; } catch { return null; } } /** @param {OnboardingStateV1} s */ export function serializeOnboardingState(s) { return JSON.stringify(s); } /** * @param {string} userKey * @param {HostingPath} hostingPath * @returns {OnboardingStateV1} */ export function createFreshState(userKey, hostingPath) { return { v: 1, userKey, hostingPath, stepIndex: 0, status: 'in_progress', dismissedAt: null, completedAt: null, }; } /** * @param {boolean} isHosted * @returns {number} */ export function getStepCount(isHosted) { return isHosted ? 9 : 5; } /** * Whether to open the wizard automatically after login/settings. * @param {OnboardingStateV1 | null} state * @param {string} currentUserKey * @param {HostingPath} currentHostingPath * @returns {boolean} */ export function shouldAutoOpenWizard(state, currentUserKey, currentHostingPath) { if (!currentUserKey) return false; if (!state) return true; if (state.userKey !== currentUserKey) return true; if (state.hostingPath !== currentHostingPath) return true; if (state.status === 'dismissed' || state.status === 'completed') return false; return state.status === 'in_progress'; } /** * @param {boolean} isHosted * @param {number} index * @returns {{ id: string, title: string, bodyHtml: string } | null} */ export function getStepContent(isHosted, index) { if (isHosted) { const steps = [ { id: 'h0', title: 'Your memory home', bodyHtml: '

Knowtation Hub holds your team’s indexed notes — Markdown you own, fast search, and one simple rule for AI: suggested edits wait for your approval before they become real notes.

' + '
' + 'More detail — “token savings” (two layers, plain English)' + '
' + '

Vault & search: Assistants pull short snippets instead of giant paste-ins — that saves context in any tool.

' + '

Terminal chatter: Shrinking raw shell logs on your laptop is separate optional tooling; it is not what this hosted vault product runs for you.

' + '

Same framing as Token savings (retrieval & cost discipline).

' + '
' + '
', }, { id: 'h1', title: 'What do you want to do first?', bodyHtml: '

For hosted Knowtation (what you signed into here), almost everyone starts one of two ways — pick one; you can do the other anytime.

' + '
' + '
' + '

Bring in chats & files

' + '

Upload exports or files with Import (header). Use this when you already have a ChatGPT / Claude / OpenClaw export or documents on your computer.

' + '
' + '
' + '

Connect your assistant

' + '

Open Settings → Integrations and paste the copied block into Cursor, Claude Desktop, or another MCP-capable tool so it can search your vault and queue suggested edits.

' + '
' + '
' + '
' + 'Self-hosted only — I run Knowtation on my own computer' + '
' + '

If you cloned this repo and run the Hub locally, the ideas are the same (import vs connect tools), but you also manage disk paths, OAuth apps, and config files. Follow How to use → Setup → Self-hosted setup and the repo Quick start (self-hosted).

' + '
' + '
' + '

Next: Integrations, imports by platform, then Suggested (where edits wait for approval).

', }, { id: 'h2', title: 'Integrations (MCP + API)', bodyHtml: '

While signed in, open Settings → Integrations → Hub API.

' + '

Copy Hub URL, token & vault — your private “key card” for tools outside the browser (paste into env vars or MCP config).

' + '

Copy MCP — a ready-made snippet for common clients.

' + '

Copy prime — a small non-secret JSON reminder (which Hub and vault). Not your password; use it with the key card after your tool connects.

' + '
' + 'Technical details (headers, env names, prime URI)' + '
' + '

Requests use Authorization: Bearer … and X-Vault-Id on POST …/mcp, /api/v1/search, and related routes. The copy button names variables such as KNOWTATION_HUB_URL, KNOWTATION_HUB_TOKEN, and KNOWTATION_HUB_VAULT_ID.

' + '

Copy prime JSON points at MCP readResource URI knowtation://hosted/prime plus gateway base URL and vault id — no JWT inside. After connect, reading that resource can return session context and prompt names for your role.

' + '
' + '
' + '

Deep reference: Agent integration (CLI, MCP, Hub API).

', }, { id: 'h-imports', title: 'Imports by platform', bodyHtml: '

Use Import in the header to upload exports. Most people start with one of these:

' + '' + '
' + 'CLI & API source names' + '
' + '

The Hub and CLI label these as chatgpt-export, claude-export, openclaw, and more. Full list and flags: Import sources.

' + '
' + '
' + '

Full matrix: IMPORT-SOURCES.md.

' + '

LLM self-help: paste the text below into any assistant and name your product; ask it for exact export menu paths and file shapes.

' + '' + '

', }, { id: 'h4', title: 'Proposals and the Suggested queue', bodyHtml: '

Agents suggest; humans approve. Proposed edits stay out of the canonical vault until someone approves them — same speed as direct writes, with a paper trail and roles.

' + '

In the Hub, open the Suggested tab (next to Notes and Activity) to review proposals. Activity is the timeline; Discarded keeps rejected items for reference. You can also start a proposal from a note (Propose change) or New proposal.

' + '

Contract and API details: Agent integration — §4 Proposals.

', }, { id: 'h5', title: 'Your notes live here', bodyHtml: '

After you sign in, your vault is your private space in Knowtation. The list may look empty until you add something — that is normal.

' + '

On hosted Knowtation, a project is a label on notes to group them (not a disk folder path).

', }, { id: 'h6', title: 'Add your first note or file', bodyHtml: '

Use + New note to write something small (for example a shopping list or a link you want to remember).

' + '

Or use Import to bring in a file from your computer.

' + '

Want more detail? Open How to use → Knowledge & agents anytime.

', }, { id: 'h7', title: 'Keep a copy (optional)', bodyHtml: '

Your notes are already stored on Knowtation. If you also want a copy on GitHub (your account, your repo), use Settings → Backup and connect GitHub when you are ready.

' + '

You can skip this until later.

', }, { id: 'h8', title: 'Power tools for agents', bodyHtml: '

On hosted Knowtation, MCP exposes vault operations your role allows — search and read notes, propose changes (with humans approving in Suggested), imports, indexing, memory tools where enabled, and more.

' + '

MCP prompts are composition templates registered for your session. After you connect, your client can list them (e.g. via prompts/list) — that list is authoritative for this deployment.

' + '
' + 'Technical inventory (prompt names & prime)' + '
' + '

Example prompt names you may see include daily-brief, search-and-synthesize, project-summary, temporal-summary, content-plan, meeting-notes, knowledge-gap, causal-chain, extract-entities, write-from-capture (editor+), memory-context, memory-informed-search, resume-session — plus tools such as search, get_note, list_notes, propose, import, index. Copy prime JSON references knowtation://hosted/prime and echoes allowed prompt names for your current session.

' + '
' + '
' + '

One page for tools, REST, CLI, and proposal semantics: AGENT-INTEGRATION.md.

' + '

That is the whole hosted loop: notes and imports in the vault, integrations for assistants, proposals for safe writes, optional GitHub backup.

', }, ]; return steps[index] || null; } const steps = [ { id: 's1', title: 'Where your notes live', bodyHtml: '

In this browser Hub, your note list, Import, and search work without you setting a folder path — that is managed for you.

' + '
' + 'Self-hosted only — folder on your machine' + '
' + '

If you run Knowtation from a clone on your computer, notes live in a real folder. Match that path in config/local.yaml, KNOWTATION_VAULT_PATH in .env, and Settings → Backup so the CLI and Hub agree.

' + '

Quick start (self-hosted) has the exact commands.

' + '
' + '
', }, { id: 's2', title: 'Search and indexing', bodyHtml: '

Browsing and listing notes works right away. After you import a lot or change search-related settings, use Re-index in the toolbar so “meaning” search stays in sync.

' + '
' + 'Self-hosted only — CLI from the repo' + '
' + '

From the project root run npm run index, or use Re-index here after embedding or vector config changes. Plain-language steps: How to use → Setup (embeddings / sqlite-vec).

' + '
' + '
' + '

Open How to use → Setup anytime for the full checklist.

', }, { id: 's3', title: 'Signing in', bodyHtml: '

You sign in with Google or GitHub so this Hub knows which account and vault are yours.

' + '
' + 'Self-hosted only — your own OAuth app (.env)' + '
' + '

Operators register a Google/GitHub OAuth app and put client ID and secret in .env, then restart the Hub. If you see OAuth is not configured, follow How to use → Setup → Step 3 or ask whoever runs your server.

' + '
' + '
', }, { id: 's4', title: 'Import, agents, and backup', bodyHtml: '

Import brings files from other tools. Settings → Integrations shows how to connect agents (MCP). Settings → Backup walks through GitHub backup when you want version history off-machine.

' + '

Proposals: agents use the same APIs as humans; review queued changes under the Hub Suggested tab before they merge into the vault. See Agent integration — §4 Proposals.

' + '

The seven steps under How to use → Setup stay the full reference — this wizard is the short path.

', }, { id: 's5', title: 'You are set', bodyHtml: '

Use the tree and search to browse notes, + New note to capture, and Settings anytime for backup and integrations.

' + '

Come back to How to use whenever you need deeper explanations.

', }, ]; return steps[index] || null; } /** * Secondary actions for wizard footer (handled in hub.js). * @typedef {{ id: string, label: string }} OnboardingAction * @param {boolean} isHosted * @param {number} index * @returns {OnboardingAction[]} */ export function getStepSecondaryActions(isHosted, index) { if (isHosted) { if (index === 0) return [{ id: 'openWhyTokenDoc', label: 'Why Knowtation (tokens)' }]; if (index === 1) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openSettingsIntegrations', label: 'Settings → Integrations' }]; if (index === 2) return [{ id: 'openSettingsIntegrations', label: 'Open Settings → Integrations' }]; if (index === 3) return [{ id: 'openImportModal', label: 'Open Import' }, { id: 'openImportSourcesDoc', label: 'Import sources (docs)' }]; if (index === 4) return [{ id: 'focusSuggestedTab', label: 'Open Suggested tab' }, { id: 'openAgentDocProposals', label: 'Read §4 Proposals (docs)' }]; if (index === 5) return [{ id: 'projectsHelp', label: 'How projects work' }]; if (index === 6) return [{ id: 'howToKnowledge', label: 'How to use: Knowledge & agents' }]; if (index === 7) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }]; if (index === 8) return [{ id: 'openAgentIntegrationDoc', label: 'Open AGENT-INTEGRATION.md' }]; return []; } if (index === 0) return [{ id: 'openSettingsBackup', label: 'Open Settings → Backup' }]; if (index === 1) return [{ id: 'howToSetup4', label: 'How to use: Setup (search)' }]; if (index === 2) return [{ id: 'howToSetup3', label: 'How to use: Setup (sign in)' }]; if (index === 3) { return [ { id: 'openSettingsIntegrations', label: 'Settings → Integrations' }, { id: 'openSettingsBackup', label: 'Settings → Backup' }, { id: 'openAgentDocProposals', label: '§4 Proposals (docs)' }, ]; } return []; }