synabun 1.3.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/CHANGELOG.md +665 -0
- package/LICENSE +191 -0
- package/README.md +853 -0
- package/hooks/claude-code/post-plan.mjs +391 -0
- package/hooks/claude-code/post-remember.mjs +239 -0
- package/hooks/claude-code/pre-compact.mjs +241 -0
- package/hooks/claude-code/pre-websearch.mjs +90 -0
- package/hooks/claude-code/prompt-submit.mjs +861 -0
- package/hooks/claude-code/session-start.mjs +494 -0
- package/hooks/claude-code/shared.mjs +368 -0
- package/hooks/claude-code/stop.mjs +646 -0
- package/hooks/claude-code/test-user-learning.mjs +531 -0
- package/mcp-server/package.json +38 -0
- package/mcp-server/run.mjs +10 -0
- package/mcp-server/src/config.ts +70 -0
- package/mcp-server/src/http.ts +93 -0
- package/mcp-server/src/index.ts +203 -0
- package/mcp-server/src/preload-http.ts +25 -0
- package/mcp-server/src/preload.ts +29 -0
- package/mcp-server/src/scripts/migrate-qdrant-to-sqlite.ts +506 -0
- package/mcp-server/src/services/categories.ts +429 -0
- package/mcp-server/src/services/discord.ts +702 -0
- package/mcp-server/src/services/file-checksums.ts +33 -0
- package/mcp-server/src/services/local-embeddings.ts +77 -0
- package/mcp-server/src/services/neural-interface.ts +344 -0
- package/mcp-server/src/services/sqlite.ts +823 -0
- package/mcp-server/src/tools/browser-advanced.ts +123 -0
- package/mcp-server/src/tools/browser-interact.ts +255 -0
- package/mcp-server/src/tools/browser-navigate.ts +77 -0
- package/mcp-server/src/tools/browser-observe.ts +1330 -0
- package/mcp-server/src/tools/browser.ts +107 -0
- package/mcp-server/src/tools/card-tools.ts +193 -0
- package/mcp-server/src/tools/card.ts +22 -0
- package/mcp-server/src/tools/category.ts +379 -0
- package/mcp-server/src/tools/discord-channel.ts +274 -0
- package/mcp-server/src/tools/discord-guild.ts +188 -0
- package/mcp-server/src/tools/discord-member.ts +158 -0
- package/mcp-server/src/tools/discord-message.ts +231 -0
- package/mcp-server/src/tools/discord-onboarding.ts +228 -0
- package/mcp-server/src/tools/discord-role.ts +209 -0
- package/mcp-server/src/tools/discord-thread.ts +110 -0
- package/mcp-server/src/tools/discord-webhook.ts +176 -0
- package/mcp-server/src/tools/discord.ts +40 -0
- package/mcp-server/src/tools/forget.ts +38 -0
- package/mcp-server/src/tools/git-tools.ts +141 -0
- package/mcp-server/src/tools/git.ts +13 -0
- package/mcp-server/src/tools/image-tools.ts +98 -0
- package/mcp-server/src/tools/image.ts +17 -0
- package/mcp-server/src/tools/leonardo-browser-tools.ts +281 -0
- package/mcp-server/src/tools/leonardo.ts +28 -0
- package/mcp-server/src/tools/loop.ts +348 -0
- package/mcp-server/src/tools/memories.ts +118 -0
- package/mcp-server/src/tools/recall.ts +323 -0
- package/mcp-server/src/tools/reflect.ts +145 -0
- package/mcp-server/src/tools/remember.ts +115 -0
- package/mcp-server/src/tools/response.ts +26 -0
- package/mcp-server/src/tools/restore.ts +34 -0
- package/mcp-server/src/tools/sync.ts +114 -0
- package/mcp-server/src/tools/tictactoe-tools.ts +98 -0
- package/mcp-server/src/tools/tictactoe.ts +13 -0
- package/mcp-server/src/tools/utils.ts +25 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +260 -0
- package/mcp-server/src/tools/whiteboard.ts +22 -0
- package/mcp-server/src/tui.ts +940 -0
- package/mcp-server/src/types.ts +85 -0
- package/mcp-server/tsconfig.json +19 -0
- package/neural-interface/package.json +27 -0
- package/neural-interface/public/apple-touch-icon.png +0 -0
- package/neural-interface/public/category-logos/claude.svg +1 -0
- package/neural-interface/public/category-logos/gemini-color.svg +1 -0
- package/neural-interface/public/category-logos/openai.svg +1 -0
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude-chat.css +878 -0
- package/neural-interface/public/claude-chat.html +92 -0
- package/neural-interface/public/claude-chat.js +1168 -0
- package/neural-interface/public/favicon-16x16.png +0 -0
- package/neural-interface/public/favicon-32x32.png +0 -0
- package/neural-interface/public/gallery.svg +6 -0
- package/neural-interface/public/icon-192.png +0 -0
- package/neural-interface/public/icon-512.png +0 -0
- package/neural-interface/public/index-legacy.html +14677 -0
- package/neural-interface/public/index.html +212 -0
- package/neural-interface/public/index2d-legacy.html +8193 -0
- package/neural-interface/public/index2d.html +127 -0
- package/neural-interface/public/invite.html +351 -0
- package/neural-interface/public/leonardoai.svg +1 -0
- package/neural-interface/public/logo-synabun.png +0 -0
- package/neural-interface/public/logoHD.png +0 -0
- package/neural-interface/public/manifest.json +14 -0
- package/neural-interface/public/offline.html +299 -0
- package/neural-interface/public/onboarding.html +2335 -0
- package/neural-interface/public/openclaw-logo-text.png +0 -0
- package/neural-interface/public/pin-svgrepo-com.svg +25 -0
- package/neural-interface/public/sessionicon.svg +8 -0
- package/neural-interface/public/shared/ansi-parser.js +305 -0
- package/neural-interface/public/shared/api.js +1043 -0
- package/neural-interface/public/shared/colors.js +153 -0
- package/neural-interface/public/shared/constants.js +141 -0
- package/neural-interface/public/shared/html-shell.js +777 -0
- package/neural-interface/public/shared/html-term-renderer.js +1022 -0
- package/neural-interface/public/shared/i18n.js +147 -0
- package/neural-interface/public/shared/registry.js +82 -0
- package/neural-interface/public/shared/state.js +86 -0
- package/neural-interface/public/shared/storage.js +150 -0
- package/neural-interface/public/shared/styles.css +21212 -0
- package/neural-interface/public/shared/ui-automation-studio.js +3573 -0
- package/neural-interface/public/shared/ui-bookmarks.js +231 -0
- package/neural-interface/public/shared/ui-claude-panel.js +6333 -0
- package/neural-interface/public/shared/ui-command-runner.js +534 -0
- package/neural-interface/public/shared/ui-cost-widget.js +602 -0
- package/neural-interface/public/shared/ui-detail.js +1454 -0
- package/neural-interface/public/shared/ui-explorer.js +1356 -0
- package/neural-interface/public/shared/ui-file-explorer.js +2750 -0
- package/neural-interface/public/shared/ui-games.js +411 -0
- package/neural-interface/public/shared/ui-help.js +107 -0
- package/neural-interface/public/shared/ui-image-gallery.js +461 -0
- package/neural-interface/public/shared/ui-invite.js +519 -0
- package/neural-interface/public/shared/ui-keybinds.js +452 -0
- package/neural-interface/public/shared/ui-layouts.js +297 -0
- package/neural-interface/public/shared/ui-link.js +731 -0
- package/neural-interface/public/shared/ui-loading.js +255 -0
- package/neural-interface/public/shared/ui-menubar.js +499 -0
- package/neural-interface/public/shared/ui-multiselect.js +93 -0
- package/neural-interface/public/shared/ui-navbar.js +222 -0
- package/neural-interface/public/shared/ui-notifications.js +287 -0
- package/neural-interface/public/shared/ui-panels.js +309 -0
- package/neural-interface/public/shared/ui-resume.js +653 -0
- package/neural-interface/public/shared/ui-search.js +145 -0
- package/neural-interface/public/shared/ui-sessions.js +531 -0
- package/neural-interface/public/shared/ui-settings.js +5987 -0
- package/neural-interface/public/shared/ui-sidebar.js +1905 -0
- package/neural-interface/public/shared/ui-skills.js +2805 -0
- package/neural-interface/public/shared/ui-stats.js +38 -0
- package/neural-interface/public/shared/ui-sync.js +201 -0
- package/neural-interface/public/shared/ui-terminal.js +6385 -0
- package/neural-interface/public/shared/ui-tooltip.js +123 -0
- package/neural-interface/public/shared/ui-trash.js +439 -0
- package/neural-interface/public/shared/ui-tutorial-draw.js +875 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +2276 -0
- package/neural-interface/public/shared/ui-tutorial.js +1117 -0
- package/neural-interface/public/shared/ui-update.js +244 -0
- package/neural-interface/public/shared/ui-whiteboard.js +3262 -0
- package/neural-interface/public/shared/ui-workspaces.js +722 -0
- package/neural-interface/public/shared/utils.js +360 -0
- package/neural-interface/public/shared/vterm-buffer.js +1102 -0
- package/neural-interface/public/sw.js +52 -0
- package/neural-interface/public/synabun.png +0 -0
- package/neural-interface/public/toolbar-album.svg +8 -0
- package/neural-interface/public/toolbar-question.svg +6 -0
- package/neural-interface/public/toolbar-sessions.svg +6 -0
- package/neural-interface/public/variant/2d/background.js +113 -0
- package/neural-interface/public/variant/2d/context-menu.js +133 -0
- package/neural-interface/public/variant/2d/gfx.js +45 -0
- package/neural-interface/public/variant/2d/graph.js +1635 -0
- package/neural-interface/public/variant/2d/hulls.js +207 -0
- package/neural-interface/public/variant/2d/lasso.js +135 -0
- package/neural-interface/public/variant/2d/layout.js +594 -0
- package/neural-interface/public/variant/2d/main.js +521 -0
- package/neural-interface/public/variant/2d/minimap.js +312 -0
- package/neural-interface/public/variant/2d/settings-gfx.js +98 -0
- package/neural-interface/public/variant/3d/background.js +884 -0
- package/neural-interface/public/variant/3d/camera.js +661 -0
- package/neural-interface/public/variant/3d/gfx.js +116 -0
- package/neural-interface/public/variant/3d/graph.js +2399 -0
- package/neural-interface/public/variant/3d/main.js +500 -0
- package/neural-interface/public/variant/3d/settings-gfx.js +228 -0
- package/neural-interface/scripts/rebuild-pty.js +100 -0
- package/neural-interface/server.js +15000 -0
- package/neural-interface/templates/CLAUDE-template.md +211 -0
- package/package.json +53 -0
- package/postinstall.js +135 -0
- package/setup.js +260 -0
- package/skills/leonardo/SKILL.md +159 -0
- package/skills/leonardo/icon.svg +1 -0
- package/skills/leonardo/modules/browser-guide.md +378 -0
- package/skills/leonardo/modules/image-prompter.md +277 -0
- package/skills/leonardo/modules/model-advisor.md +100 -0
- package/skills/leonardo/modules/prompt-library.md +110 -0
- package/skills/leonardo/modules/style-guide.md +186 -0
- package/skills/leonardo/modules/video-prompter.md +311 -0
- package/skills/synabun/SKILL.md +185 -0
- package/skills/synabun/icon.png +0 -0
- package/skills/synabun/modules/audit.md +374 -0
- package/skills/synabun/modules/changelog.md +194 -0
- package/skills/synabun/modules/idea.md +144 -0
- package/skills/synabun/modules/memorize.md +188 -0
- package/skills/synabun/synabunicon.png +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# SynaBun — Persistent Vector Memory for AI Coding Tools
|
|
2
|
+
|
|
3
|
+
Persistent vector memory via SQLite + local Transformers.js embeddings. Memories survive across sessions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Memory Ruleset
|
|
8
|
+
|
|
9
|
+
> Portable ruleset — copy into any project's `CLAUDE.md`. Copy button in Neural Interface: Settings > Connections > Claude Code > Copy Ruleset.
|
|
10
|
+
|
|
11
|
+
### Tools
|
|
12
|
+
|
|
13
|
+
| Tool | Purpose |
|
|
14
|
+
|------|---------|
|
|
15
|
+
| `remember` | Store memory (content, category, project, tags, importance, related_files) |
|
|
16
|
+
| `recall` | Semantic search across memories |
|
|
17
|
+
| `forget` / `restore` | Trash / restore a memory by ID |
|
|
18
|
+
| `reflect` | Update existing memory (importance, tags, content, category) |
|
|
19
|
+
| `memories` | List recent or stats (recent, by-category, by-project) |
|
|
20
|
+
| `sync` | Detect stale memories (file content changed) |
|
|
21
|
+
| `category_create/update/delete/list` | Manage category hierarchy |
|
|
22
|
+
|
|
23
|
+
### Auto-Recall
|
|
24
|
+
|
|
25
|
+
- Session start: `recall` current project context
|
|
26
|
+
- Topic mentioned: `recall` what you know
|
|
27
|
+
- Before decisions: `recall` past decisions
|
|
28
|
+
- Debugging: `recall` similar bugs
|
|
29
|
+
|
|
30
|
+
### Auto-Remember (MANDATORY)
|
|
31
|
+
|
|
32
|
+
After ANY task (bug fix, feature, refactor, config change, investigation, architecture decision), MUST `remember` BEFORE responding.
|
|
33
|
+
|
|
34
|
+
**Steps:**
|
|
35
|
+
1. `remember` — what + why + how, appropriate category, set project, related_files, importance (5=routine, 6-7=significant, 8+=critical), and 3-5 tags
|
|
36
|
+
|
|
37
|
+
`remember` now returns the full UUID and accepts all fields (tags, importance) directly. No need to recall+reflect afterward.
|
|
38
|
+
|
|
39
|
+
**NOT triggered by:** Simple Q&A, file reads with no findings, trivial typos.
|
|
40
|
+
|
|
41
|
+
**Importance:** 1-2=trivial, 3-4=low, 5=normal, 6-7=significant, 8-9=critical, 10=foundational. User says "remember this" → 8+. Architecture decisions → 8+. API quirks → 6+.
|
|
42
|
+
|
|
43
|
+
### Response Ordering (IMPORTANT)
|
|
44
|
+
|
|
45
|
+
When finishing a task, structure your response as:
|
|
46
|
+
1. Call `remember` (and any other memory tools) **FIRST**
|
|
47
|
+
2. Write your completion summary / final message **LAST**
|
|
48
|
+
|
|
49
|
+
Tool call results appear above text within a single response, so the summary naturally ends up at the bottom where the user sees it. This prevents memory tool calls from burying your completion message under noise.
|
|
50
|
+
|
|
51
|
+
**Never** write your summary first and then call memory tools — the stop hook will block you, forcing a new response of memory tool calls that pushes your summary off-screen.
|
|
52
|
+
|
|
53
|
+
### Category Selection
|
|
54
|
+
|
|
55
|
+
1. Match existing child → use it
|
|
56
|
+
2. Parent fits but no child → `category_create` child → use it
|
|
57
|
+
3. Nothing fits → `category_create` parent + child → use it
|
|
58
|
+
|
|
59
|
+
Never store directly in parent categories.
|
|
60
|
+
|
|
61
|
+
### Tool Quirks
|
|
62
|
+
|
|
63
|
+
- `remember` returns the full UUID and accepts tags + importance directly.
|
|
64
|
+
- `reflect` requires FULL UUID — use the one returned by `remember`, or `recall` to find existing memories.
|
|
65
|
+
- Sequential MCP calls only — never parallel.
|
|
66
|
+
|
|
67
|
+
### Plan Mode (MANDATORY)
|
|
68
|
+
|
|
69
|
+
When in plan mode and you need clarification or have questions:
|
|
70
|
+
- **ALWAYS** use `AskUserQuestion` to present options — never write questions as plain text
|
|
71
|
+
- Load the tool via `ToolSearch` first if its schema is not yet available
|
|
72
|
+
- Structure as distinct choices (2-4 options per question, max 4 questions)
|
|
73
|
+
- Use for approach clarification BEFORE finalizing the plan
|
|
74
|
+
- Use `ExitPlanMode` (not AskUserQuestion) for final plan approval
|
|
75
|
+
|
|
76
|
+
### Multi-Select Questions
|
|
77
|
+
|
|
78
|
+
When using `AskUserQuestion`, set `multiSelect: true` when options are NOT mutually exclusive — i.e., the user could reasonably want more than one. Examples: selecting multiple features, tags, effects, or follow-up actions. Keep single-select (default) for inherently exclusive choices (one model, one style, one dimension).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Coexistence with Other Tools
|
|
83
|
+
|
|
84
|
+
When running SynaBun alongside other memory or code intelligence tools (CogniLayer, mem0, etc.):
|
|
85
|
+
|
|
86
|
+
**SynaBun owns ALL memory operations:**
|
|
87
|
+
- Storing information: `remember`
|
|
88
|
+
- Searching past context: `recall`
|
|
89
|
+
- Updating memories: `reflect`
|
|
90
|
+
- Deleting/restoring: `forget` / `restore`
|
|
91
|
+
- Browsing: `memories`
|
|
92
|
+
- Stale detection: `sync`
|
|
93
|
+
- Categories: `category` (create/update/delete/list)
|
|
94
|
+
|
|
95
|
+
**Other tools** should be restricted to their non-memory capabilities only (e.g., AST-based code search, code impact analysis).
|
|
96
|
+
|
|
97
|
+
**Enforcement rule for CLAUDE.md / project instructions:**
|
|
98
|
+
```
|
|
99
|
+
For ALL memory operations (store, search, recall, update, delete), use SynaBun tools exclusively.
|
|
100
|
+
[OtherTool] is restricted to [specific use case, e.g., code_search, code_context, code_impact].
|
|
101
|
+
Never use [OtherTool] for remembering, recalling, or reflecting on past work.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If you notice the AI defaulting to another tool's memory features, add the enforcement rule above to your project's `CLAUDE.md`.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Condensed Rulesets
|
|
109
|
+
|
|
110
|
+
### Cursor
|
|
111
|
+
```
|
|
112
|
+
# Memory: SynaBun MCP (SQLite + local embeddings)
|
|
113
|
+
## Tools: remember, recall, forget, restore, reflect, memories, sync, category_create/update/delete/list
|
|
114
|
+
## Rules
|
|
115
|
+
- Session start: recall project context
|
|
116
|
+
- After any task: remember what+why+how with tags + importance (MANDATORY)
|
|
117
|
+
- Response ordering: call remember FIRST, then write your summary LAST. Never summary-then-tools.
|
|
118
|
+
- Bug fixes: importance 7+. Architecture: 8+. User says "remember this": 8+
|
|
119
|
+
- remember returns full UUID. Use reflect only to update existing memories.
|
|
120
|
+
- Sequential MCP calls only
|
|
121
|
+
- Scale: 1-2=trivial, 5=normal, 7=significant, 9=critical, 10=foundational
|
|
122
|
+
- Plan mode: ALWAYS use AskUserQuestion for questions — never plain text. Use ExitPlanMode for plan approval.
|
|
123
|
+
- AskUserQuestion: use multiSelect: true when options aren't mutually exclusive (multiple tags, features, effects, actions).
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Generic
|
|
127
|
+
```
|
|
128
|
+
## Memory: SynaBun MCP
|
|
129
|
+
Tools: remember, recall, forget, restore, reflect, memories, sync, category_*
|
|
130
|
+
- Recall at session start. Remember after every task with tags + importance (MANDATORY).
|
|
131
|
+
- Response ordering: call remember FIRST, then write your summary LAST. Never summary-then-tools.
|
|
132
|
+
- remember returns full UUID. reflect is for updating existing memories.
|
|
133
|
+
- Sequential calls only. Scale: 1-2=trivial, 5=normal, 7=significant, 9=critical
|
|
134
|
+
- Plan mode: ALWAYS use AskUserQuestion for questions — never plain text. Use ExitPlanMode for plan approval.
|
|
135
|
+
- AskUserQuestion: use multiSelect: true when options aren't mutually exclusive (multiple tags, features, effects, actions).
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Gemini
|
|
139
|
+
```
|
|
140
|
+
## Memory: SynaBun MCP
|
|
141
|
+
Tools: remember, recall, forget, restore, reflect, memories, sync, category_*
|
|
142
|
+
- Recall at session start. Remember after every task with tags + importance (MANDATORY).
|
|
143
|
+
- Response ordering: call remember FIRST, then write your summary LAST. Never summary-then-tools.
|
|
144
|
+
- remember returns full UUID. reflect is for updating existing memories.
|
|
145
|
+
- Sequential calls only. Scale: 1-2=trivial, 5=normal, 7=significant, 9=critical
|
|
146
|
+
- Plan mode: ALWAYS use AskUserQuestion for questions — never plain text. Use ExitPlanMode for plan approval.
|
|
147
|
+
- AskUserQuestion: use multiSelect: true when options aren't mutually exclusive (multiple tags, features, effects, actions).
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Codex
|
|
151
|
+
```
|
|
152
|
+
## Memory: SynaBun MCP
|
|
153
|
+
Tools: remember, recall, forget, restore, reflect, memories, sync, category_*
|
|
154
|
+
- Recall at session start. Remember after every task with tags + importance (MANDATORY).
|
|
155
|
+
- Response ordering: call remember FIRST, then write your summary LAST. Never summary-then-tools.
|
|
156
|
+
- remember returns full UUID. reflect is for updating existing memories.
|
|
157
|
+
- Sequential calls only. Scale: 1-2=trivial, 5=normal, 7=significant, 9=critical
|
|
158
|
+
- Plan mode: ALWAYS use AskUserQuestion for questions — never plain text. Use ExitPlanMode for plan approval.
|
|
159
|
+
- AskUserQuestion: use multiSelect: true when options aren't mutually exclusive (multiple tags, features, effects, actions).
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Hook System
|
|
165
|
+
|
|
166
|
+
7 Claude Code hooks in `hooks/claude-code/`, registered in `~/.claude/settings.json`.
|
|
167
|
+
|
|
168
|
+
| Hook | Script | Purpose |
|
|
169
|
+
|------|--------|---------|
|
|
170
|
+
| SessionStart | `session-start.mjs` | Greeting, boot sequence, compaction recovery, loop detection, session registration. |
|
|
171
|
+
| UserPromptSubmit | `prompt-submit.mjs` | Tiered recall nudges, loop iteration injection, category tree on first threshold. |
|
|
172
|
+
| PreCompact | `pre-compact.mjs` | Caches session data, sets pending-compact flag. |
|
|
173
|
+
| Stop | `stop.mjs` | Combined obligations: compaction, loops, task memory, user learning, conversation turns, auto-store, unstored plans. |
|
|
174
|
+
| PreToolUse | `pre-websearch.mjs` | Blocks WebSearch/WebFetch during active browser sessions. |
|
|
175
|
+
| PostToolUse | `post-remember.mjs` | Tracks edits. Clears flags on remember. User learning flag management. |
|
|
176
|
+
| PostToolUse | `post-plan.mjs` | Auto-stores plans in memory when exiting plan mode. |
|
|
177
|
+
|
|
178
|
+
**Compaction chain:** PreCompact → flag → SessionStart injects → Claude remembers(conversations) → PostToolUse clears → Stop allows.
|
|
179
|
+
**Task chain:** PostToolUse tracks edits → Stop blocks at 3+ → Claude remembers → cleared.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Category System
|
|
184
|
+
|
|
185
|
+
Stored in `mcp-server/data/custom-categories-{connId}.json`. Managed via MCP tools or Neural Interface UI.
|
|
186
|
+
|
|
187
|
+
Descriptions are routing instructions: `"ONLY for deal/pricing memories"` not `"Pricing and stores"`.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Development
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
synabun/
|
|
195
|
+
├── mcp-server/ # TS MCP server → dist/ (npm run build)
|
|
196
|
+
├── hooks/claude-code/ # 7 hook scripts (.mjs, ESM)
|
|
197
|
+
├── neural-interface/ # Express server + public/ + templates/
|
|
198
|
+
│ ├── public/ # index.html, onboarding.html, shared/ (modular JS/CSS)
|
|
199
|
+
│ └── templates/ # CLAUDE-template.md (source of truth for rulesets)
|
|
200
|
+
├── skills/ # Claude Code skill definitions
|
|
201
|
+
├── data/ # Runtime flags, features, API keys
|
|
202
|
+
└── .env # All config (optional overrides)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
node neural-interface/server.js # UI on :3344
|
|
207
|
+
cd mcp-server && npm run build # Build MCP
|
|
208
|
+
claude mcp add SynaBun -s user -- node ".../mcp-server/run.mjs"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Architecture:** SQLite database (data/memory.db), local Transformers.js embeddings (384 dims), per-connection categories, ESM hooks, modular Neural Interface (vanilla JS + Three.js, shared/ modules), paths from `resolve(__dirname, '..')`.
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "synabun",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Persistent vector memory for AI assistants",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "The SynaBun Authors",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/danilokhury/Synabun.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://synabun.ai",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"synabun": "setup.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"setup.js",
|
|
18
|
+
"postinstall.js",
|
|
19
|
+
"mcp-server/package.json",
|
|
20
|
+
"mcp-server/tsconfig.json",
|
|
21
|
+
"mcp-server/src/",
|
|
22
|
+
"mcp-server/run.mjs",
|
|
23
|
+
"mcp-server/data/.gitkeep",
|
|
24
|
+
"neural-interface/package.json",
|
|
25
|
+
"neural-interface/server.js",
|
|
26
|
+
"neural-interface/public/",
|
|
27
|
+
"neural-interface/templates/",
|
|
28
|
+
"neural-interface/scripts/",
|
|
29
|
+
"hooks/",
|
|
30
|
+
"skills/",
|
|
31
|
+
"data/.gitkeep",
|
|
32
|
+
"CLAUDE.md",
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"start": "node setup.js",
|
|
38
|
+
"postinstall": "node postinstall.js"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"claude",
|
|
42
|
+
"memory",
|
|
43
|
+
"mcp",
|
|
44
|
+
"vector",
|
|
45
|
+
"embeddings",
|
|
46
|
+
"ai",
|
|
47
|
+
"persistent-memory",
|
|
48
|
+
"claude-code"
|
|
49
|
+
],
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=22.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SynaBun — NPM postinstall script
|
|
5
|
+
*
|
|
6
|
+
* Runs automatically after `npm install -g synabun`.
|
|
7
|
+
* Installs subdependencies and builds the MCP server.
|
|
8
|
+
* Does NOT start the server — that's setup.js / `synabun` command.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execSync } from 'node:child_process';
|
|
12
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
13
|
+
import { resolve, dirname } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
|
|
18
|
+
// ── ANSI color helpers ──
|
|
19
|
+
|
|
20
|
+
const c = {
|
|
21
|
+
reset: '\x1b[0m',
|
|
22
|
+
dim: '\x1b[2m',
|
|
23
|
+
cyan: '\x1b[36m',
|
|
24
|
+
green: '\x1b[32m',
|
|
25
|
+
yellow: '\x1b[33m',
|
|
26
|
+
red: '\x1b[31m',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function ok(msg) { console.log(` ${c.green}\u2713${c.reset} ${msg}`); }
|
|
30
|
+
function warn(msg) { console.log(` ${c.yellow}!${c.reset} ${msg}`); }
|
|
31
|
+
function fail(msg) { console.log(` ${c.red}\u2717${c.reset} ${msg}`); }
|
|
32
|
+
function info(msg) { console.log(` ${c.cyan}\u2192${c.reset} ${msg}`); }
|
|
33
|
+
|
|
34
|
+
// ── Ensure data directories exist ──
|
|
35
|
+
|
|
36
|
+
function ensureDirectories() {
|
|
37
|
+
const dirs = [
|
|
38
|
+
resolve(__dirname, 'data'),
|
|
39
|
+
resolve(__dirname, 'mcp-server', 'data'),
|
|
40
|
+
];
|
|
41
|
+
for (const dir of dirs) {
|
|
42
|
+
if (!existsSync(dir)) {
|
|
43
|
+
mkdirSync(dir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Dependency installation ──
|
|
49
|
+
|
|
50
|
+
function needsInstall(dir) {
|
|
51
|
+
return !existsSync(resolve(dir, 'node_modules', '.package-lock.json'));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function installDeps(name, dir) {
|
|
55
|
+
if (!needsInstall(dir)) {
|
|
56
|
+
ok(`${name} dependencies already installed`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
info(`Installing ${name} dependencies...`);
|
|
61
|
+
try {
|
|
62
|
+
execSync('npm install', {
|
|
63
|
+
cwd: dir,
|
|
64
|
+
stdio: 'inherit',
|
|
65
|
+
timeout: 300_000,
|
|
66
|
+
});
|
|
67
|
+
ok(`${name} dependencies installed`);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
fail(`Failed to install ${name} dependencies`);
|
|
70
|
+
console.error(err.stderr?.toString() || err.message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── node-pty native rebuild ──
|
|
76
|
+
|
|
77
|
+
function rebuildPty() {
|
|
78
|
+
const rebuildScript = resolve(__dirname, 'neural-interface', 'scripts', 'rebuild-pty.js');
|
|
79
|
+
if (!existsSync(rebuildScript)) {
|
|
80
|
+
warn('rebuild-pty.js not found, skipping native rebuild');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
info('Rebuilding node-pty native addon...');
|
|
85
|
+
try {
|
|
86
|
+
execSync(`node "${rebuildScript}"`, {
|
|
87
|
+
cwd: resolve(__dirname, 'neural-interface'),
|
|
88
|
+
stdio: 'inherit',
|
|
89
|
+
timeout: 120_000,
|
|
90
|
+
});
|
|
91
|
+
ok('node-pty rebuilt');
|
|
92
|
+
} catch (err) {
|
|
93
|
+
warn('node-pty rebuild failed (terminal features may not work)');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── MCP server build ──
|
|
98
|
+
|
|
99
|
+
function buildMcpServer() {
|
|
100
|
+
const distIndex = resolve(__dirname, 'mcp-server', 'dist', 'index.js');
|
|
101
|
+
if (existsSync(distIndex)) {
|
|
102
|
+
ok('MCP server already built');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
info('Building MCP server...');
|
|
107
|
+
try {
|
|
108
|
+
execSync('npm run build', {
|
|
109
|
+
cwd: resolve(__dirname, 'mcp-server'),
|
|
110
|
+
stdio: 'pipe',
|
|
111
|
+
timeout: 60_000,
|
|
112
|
+
});
|
|
113
|
+
ok('MCP server built');
|
|
114
|
+
} catch (err) {
|
|
115
|
+
fail('MCP server build failed');
|
|
116
|
+
console.error(err.stderr?.toString() || err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Main ──
|
|
122
|
+
|
|
123
|
+
function main() {
|
|
124
|
+
console.log(`\n ${c.cyan}SynaBun${c.reset} ${c.dim}postinstall${c.reset}\n`);
|
|
125
|
+
|
|
126
|
+
ensureDirectories();
|
|
127
|
+
installDeps('Neural Interface', resolve(__dirname, 'neural-interface'));
|
|
128
|
+
installDeps('MCP Server', resolve(__dirname, 'mcp-server'));
|
|
129
|
+
rebuildPty();
|
|
130
|
+
buildMcpServer();
|
|
131
|
+
|
|
132
|
+
console.log(`\n ${c.green}\u2713${c.reset} Setup complete. Run ${c.cyan}synabun${c.reset} to start.\n`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
main();
|
package/setup.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SynaBun — Single-command setup & launch
|
|
5
|
+
*
|
|
6
|
+
* Usage: node setup.js (or: npm start)
|
|
7
|
+
*
|
|
8
|
+
* 1. Checks Node.js version (>=22)
|
|
9
|
+
* 2. Installs npm deps for neural-interface/ and mcp-server/
|
|
10
|
+
* 3. Builds the MCP server TypeScript (if dist/ is missing or stale)
|
|
11
|
+
* 4. Starts the Neural Interface Express server
|
|
12
|
+
* 5. Auto-opens browser to onboarding wizard (or main page if setup complete)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { execSync, spawn, exec } from 'node:child_process';
|
|
16
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
17
|
+
import { resolve, dirname } from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { platform } from 'node:os';
|
|
20
|
+
|
|
21
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
|
|
23
|
+
// ── ANSI color helpers ──
|
|
24
|
+
|
|
25
|
+
const c = {
|
|
26
|
+
reset: '\x1b[0m',
|
|
27
|
+
bold: '\x1b[1m',
|
|
28
|
+
dim: '\x1b[2m',
|
|
29
|
+
cyan: '\x1b[36m',
|
|
30
|
+
green: '\x1b[32m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
red: '\x1b[31m',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function ok(msg) { console.log(` ${c.green}\u2713${c.reset} ${msg}`); }
|
|
36
|
+
function warn(msg) { console.log(` ${c.yellow}!${c.reset} ${msg}`); }
|
|
37
|
+
function fail(msg) { console.log(` ${c.red}\u2717${c.reset} ${msg}`); }
|
|
38
|
+
function info(msg) { console.log(` ${c.cyan}\u2192${c.reset} ${msg}`); }
|
|
39
|
+
|
|
40
|
+
// ── Phase 1: Prerequisite checks ──
|
|
41
|
+
|
|
42
|
+
function checkNodeVersion() {
|
|
43
|
+
const [major] = process.versions.node.split('.').map(Number);
|
|
44
|
+
if (major < 22) {
|
|
45
|
+
fail(`Node.js 22+ required, found v${process.versions.node}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
ok(`Node.js v${process.versions.node}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Phase 2: Dependency installation ──
|
|
52
|
+
|
|
53
|
+
function needsInstall(dir) {
|
|
54
|
+
// Check for .package-lock.json which npm creates after a successful install
|
|
55
|
+
// A bare node_modules/ directory (e.g. from a failed npx or partial install) is not enough
|
|
56
|
+
return !existsSync(resolve(dir, 'node_modules', '.package-lock.json'));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function installDeps(name, dir) {
|
|
60
|
+
if (!needsInstall(dir)) {
|
|
61
|
+
ok(`${name} dependencies already installed`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
info(`Installing ${name} dependencies...`);
|
|
66
|
+
try {
|
|
67
|
+
execSync('npm install', {
|
|
68
|
+
cwd: dir,
|
|
69
|
+
stdio: 'inherit',
|
|
70
|
+
timeout: 300_000,
|
|
71
|
+
});
|
|
72
|
+
ok(`${name} dependencies installed`);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
fail(`Failed to install ${name} dependencies`);
|
|
75
|
+
console.error(err.stderr?.toString() || err.message);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Phase 3: Playwright Chromium (for browser automation) ──
|
|
81
|
+
|
|
82
|
+
function installPlaywrightChromium() {
|
|
83
|
+
const niDir = resolve(__dirname, 'neural-interface');
|
|
84
|
+
// Check if already installed by resolving the executable path
|
|
85
|
+
try {
|
|
86
|
+
const result = execSync('node -e "const pw=require(\'playwright\');const p=pw.chromium.executablePath();process.stdout.write(p)"', {
|
|
87
|
+
cwd: niDir, encoding: 'utf8', timeout: 10_000,
|
|
88
|
+
});
|
|
89
|
+
if (existsSync(result)) {
|
|
90
|
+
ok('Playwright Chromium already installed');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
} catch { /* not installed */ }
|
|
94
|
+
|
|
95
|
+
info('Installing Playwright Chromium (for browser automation)...');
|
|
96
|
+
try {
|
|
97
|
+
execSync('npx playwright install chromium', {
|
|
98
|
+
cwd: niDir,
|
|
99
|
+
stdio: 'inherit',
|
|
100
|
+
timeout: 120_000,
|
|
101
|
+
});
|
|
102
|
+
ok('Playwright Chromium installed');
|
|
103
|
+
} catch (err) {
|
|
104
|
+
// Non-fatal — system Chrome will be used as fallback
|
|
105
|
+
console.log(' (optional) Playwright Chromium install failed — system Chrome will be used');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── Phase 4: MCP server build ──
|
|
110
|
+
|
|
111
|
+
function needsBuild() {
|
|
112
|
+
const distIndex = resolve(__dirname, 'mcp-server', 'dist', 'index.js');
|
|
113
|
+
if (!existsSync(distIndex)) return true;
|
|
114
|
+
|
|
115
|
+
const srcIndex = resolve(__dirname, 'mcp-server', 'src', 'index.ts');
|
|
116
|
+
try {
|
|
117
|
+
return statSync(srcIndex).mtimeMs > statSync(distIndex).mtimeMs;
|
|
118
|
+
} catch {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function buildMcpServer() {
|
|
124
|
+
if (!needsBuild()) {
|
|
125
|
+
ok('MCP server already built');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
info('Building MCP server...');
|
|
130
|
+
try {
|
|
131
|
+
execSync('npm run build', {
|
|
132
|
+
cwd: resolve(__dirname, 'mcp-server'),
|
|
133
|
+
stdio: 'pipe',
|
|
134
|
+
timeout: 60_000,
|
|
135
|
+
});
|
|
136
|
+
ok('MCP server built');
|
|
137
|
+
} catch (err) {
|
|
138
|
+
fail('MCP server build failed');
|
|
139
|
+
console.error(err.stderr?.toString() || err.message);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Phase 4: Setup state detection ──
|
|
145
|
+
|
|
146
|
+
function isSetupComplete() {
|
|
147
|
+
const envPath = resolve(__dirname, '.env');
|
|
148
|
+
try {
|
|
149
|
+
const content = readFileSync(envPath, 'utf-8');
|
|
150
|
+
for (const line of content.split('\n')) {
|
|
151
|
+
const trimmed = line.trim();
|
|
152
|
+
if (trimmed.startsWith('SETUP_COMPLETE=')) {
|
|
153
|
+
return trimmed.split('=')[1] === 'true';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} catch {}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── Phase 5: Server launch + browser open ──
|
|
161
|
+
|
|
162
|
+
function openBrowser(url) {
|
|
163
|
+
const plat = platform();
|
|
164
|
+
const fallback = () => { warn('Could not open browser automatically'); info(`Open manually: ${url}`); };
|
|
165
|
+
|
|
166
|
+
if (plat === 'win32') {
|
|
167
|
+
exec(`start "" "${url}"`, (err) => { if (err) fallback(); });
|
|
168
|
+
} else if (plat === 'darwin') {
|
|
169
|
+
exec(`open "${url}"`, (err) => { if (err) fallback(); });
|
|
170
|
+
} else {
|
|
171
|
+
exec(`xdg-open "${url}"`, (err) => { if (err) fallback(); });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function startServer() {
|
|
176
|
+
const serverPath = resolve(__dirname, 'neural-interface', 'server.js');
|
|
177
|
+
|
|
178
|
+
info('Starting Neural Interface server...');
|
|
179
|
+
console.log('');
|
|
180
|
+
|
|
181
|
+
const child = spawn('node', [serverPath], {
|
|
182
|
+
cwd: resolve(__dirname, 'neural-interface'),
|
|
183
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
let opened = false;
|
|
187
|
+
const setupComplete = isSetupComplete();
|
|
188
|
+
|
|
189
|
+
child.stdout.on('data', (data) => {
|
|
190
|
+
process.stdout.write(data.toString());
|
|
191
|
+
|
|
192
|
+
if (!opened && data.toString().includes('Server:')) {
|
|
193
|
+
opened = true;
|
|
194
|
+
const port = data.toString().match(/Server:\s+http:\/\/localhost:(\d+)/)?.[1] || '3344';
|
|
195
|
+
const url = `http://localhost:${port}${setupComplete ? '/' : '/onboarding.html'}`;
|
|
196
|
+
|
|
197
|
+
if (!setupComplete) setTimeout(() => openBrowser(url), 1500);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
child.stderr.on('data', (data) => {
|
|
202
|
+
process.stderr.write(data.toString());
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
child.on('exit', (code) => {
|
|
206
|
+
if (code !== 0 && code !== null) {
|
|
207
|
+
fail(`Server exited with code ${code}`);
|
|
208
|
+
process.exit(code);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Clean shutdown on Ctrl+C
|
|
213
|
+
process.on('SIGINT', () => { child.kill('SIGINT'); process.exit(0); });
|
|
214
|
+
process.on('SIGTERM', () => { child.kill('SIGTERM'); process.exit(0); });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── Main ──
|
|
218
|
+
|
|
219
|
+
function main() {
|
|
220
|
+
console.log('');
|
|
221
|
+
console.log(` ${c.cyan}╔═══════════════════════════════════╗${c.reset}`);
|
|
222
|
+
console.log(` ${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
|
|
223
|
+
console.log(` ${c.cyan}║${c.reset} ${c.bold}${c.cyan}[██] [██]${c.reset} ${c.bold}${c.cyan}SynaBun${c.reset} ${c.cyan}║${c.reset}`);
|
|
224
|
+
console.log(` ${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
|
|
225
|
+
console.log(` ${c.cyan}║${c.reset} ${c.dim}Persistent Vector Memory${c.reset} ${c.cyan}║${c.reset}`);
|
|
226
|
+
console.log(` ${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
|
|
227
|
+
console.log(` ${c.cyan}╚═══════════════════════════════════╝${c.reset}`);
|
|
228
|
+
console.log(` ${c.dim}synabun.ai${c.reset}`);
|
|
229
|
+
console.log('');
|
|
230
|
+
|
|
231
|
+
// Prerequisites
|
|
232
|
+
checkNodeVersion();
|
|
233
|
+
console.log('');
|
|
234
|
+
|
|
235
|
+
// Dependencies
|
|
236
|
+
installDeps('Neural Interface', resolve(__dirname, 'neural-interface'));
|
|
237
|
+
installDeps('MCP Server', resolve(__dirname, 'mcp-server'));
|
|
238
|
+
console.log('');
|
|
239
|
+
|
|
240
|
+
// Playwright browser
|
|
241
|
+
installPlaywrightChromium();
|
|
242
|
+
console.log('');
|
|
243
|
+
|
|
244
|
+
// Build
|
|
245
|
+
buildMcpServer();
|
|
246
|
+
console.log('');
|
|
247
|
+
|
|
248
|
+
// State
|
|
249
|
+
if (isSetupComplete()) {
|
|
250
|
+
ok('Setup already complete');
|
|
251
|
+
} else {
|
|
252
|
+
info('First-time setup \u2014 opening onboarding wizard');
|
|
253
|
+
}
|
|
254
|
+
console.log('');
|
|
255
|
+
|
|
256
|
+
// Launch
|
|
257
|
+
startServer();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
main();
|