feat(settings): add interactive setup wizard for initial configuration#204
feat(settings): add interactive setup wizard for initial configuration#204
Conversation
Adds a step-by-step setup wizard to the settings page that replaces the CLI setup flow. The wizard walks through channels, provider/model, workspace, and agents configuration — then writes settings.json and creates all directories via a new POST /api/setup endpoint. https://claude.ai/code/session_01JANJmrpc35awJqJvQCS3z2
Greptile SummaryThis PR introduces a guided 5-step setup wizard ( Key observations:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User as User Browser
participant Settings as /settings page
participant Setup as /setup page
participant API as Server API
participant FS as Filesystem
User->>Settings: Load settings page
Settings->>API: GET /api/settings
API-->>Settings: Settings (empty / error)
Settings-->>User: "Setup Required" — link to /setup
User->>Setup: Navigate to /setup
Setup-->>User: Step 0 — Select Channels + tokens
User->>Setup: Next (validates tokens)
Setup-->>User: Step 1 — Provider, Model, Heartbeat
User->>Setup: Next
Setup-->>User: Step 2 — Workspace name/path
User->>Setup: Next
Setup-->>User: Step 3 — Agents (id, name, provider, model)
User->>Setup: Next (validates unique IDs)
Setup-->>User: Step 4 — Review (buildSettings() preview)
User->>Setup: Click "Finish Setup"
Setup->>Setup: buildSettings() → Settings object
Setup->>API: POST /api/setup (Settings JSON)
API->>API: expandHomePath(workspace.path)
API->>API: expandHomePath(agent.working_directory) for each agent
API->>FS: Write settings.json
API->>FS: mkdirSync(TINYCLAW_HOME/logs)
API->>FS: mkdirSync(TINYCLAW_HOME/files)
API->>FS: Copy .claude, heartbeat.md, AGENTS.md templates
API->>FS: mkdirSync(workspace.path)
API->>FS: ensureAgentDirectory(agent.working_directory) × N
API-->>Setup: { ok: true, settings }
Setup->>User: router.push("/")
|
| const templateItems = ['.claude', 'heartbeat.md', 'AGENTS.md']; | ||
| for (const item of templateItems) { | ||
| const srcPath = path.join(SCRIPT_DIR, item); | ||
| const destPath = path.join(TINYCLAW_HOME, item); | ||
| if (fs.existsSync(srcPath)) { | ||
| if (fs.statSync(srcPath).isDirectory()) { | ||
| copyDirSync(srcPath, destPath); | ||
| } else { | ||
| fs.copyFileSync(srcPath, destPath); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Template files unconditionally overwritten on re-run
The "Run Setup" button on the settings page can trigger this endpoint again on an already-configured system. Since there's no existence check on destPath, files like .claude (which often holds custom Claude configuration) and AGENTS.md will be silently overwritten with the bundled templates, discarding any user modifications.
Consider guarding the copy with an !fs.existsSync(destPath) check, or at least documenting this destructive behaviour:
if (fs.existsSync(srcPath) && !fs.existsSync(destPath)) {
if (fs.statSync(srcPath).isDirectory()) {
copyDirSync(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}|
@greptileai review |
| app.post('/api/setup', async (c) => { | ||
| const settings = (await c.req.json()) as Settings; | ||
|
|
||
| if (settings.workspace?.path) { | ||
| settings.workspace.path = expandHomePath(settings.workspace.path); | ||
| } | ||
| if (settings.agents) { | ||
| for (const agent of Object.values(settings.agents)) { | ||
| if (agent.working_directory) { | ||
| agent.working_directory = expandHomePath(agent.working_directory) || agent.working_directory; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Write settings.json | ||
| fs.mkdirSync(path.dirname(SETTINGS_FILE), { recursive: true }); | ||
| fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\n'); | ||
| log('INFO', '[API] Setup: settings.json written'); | ||
|
|
||
| // Create TINYCLAW_HOME directories | ||
| fs.mkdirSync(path.join(TINYCLAW_HOME, 'logs'), { recursive: true }); | ||
| fs.mkdirSync(path.join(TINYCLAW_HOME, 'files'), { recursive: true }); | ||
|
|
||
| // Copy template files into TINYCLAW_HOME | ||
| const templateItems = ['.claude', 'heartbeat.md', 'AGENTS.md']; | ||
| for (const item of templateItems) { | ||
| const srcPath = path.join(SCRIPT_DIR, item); | ||
| const destPath = path.join(TINYCLAW_HOME, item); | ||
| if (fs.existsSync(srcPath)) { | ||
| if (fs.statSync(srcPath).isDirectory()) { | ||
| copyDirSync(srcPath, destPath); | ||
| } else { | ||
| fs.copyFileSync(srcPath, destPath); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Create workspace directory | ||
| const workspacePath = settings.workspace?.path; | ||
| if (workspacePath) { | ||
| fs.mkdirSync(workspacePath, { recursive: true }); | ||
| } | ||
|
|
||
| // Create agent directories | ||
| if (settings.agents) { | ||
| for (const agent of Object.values(settings.agents)) { | ||
| ensureAgentDirectory(agent.working_directory); | ||
| } | ||
| } | ||
|
|
||
| log('INFO', '[API] Setup complete'); | ||
| return c.json({ ok: true, settings }); | ||
| }); |
There was a problem hiding this comment.
Filesystem errors surface as unhandled exceptions
The POST /api/setup handler performs several fs.* operations (mkdirSync, copyFileSync, etc.) with no surrounding try-catch. If any of these fail — due to permission denied, disk full, or a missing parent directory — Hono will propagate the exception as an unhandled 500, and the client's apiFetch will only see "Internal Server Error" rather than a descriptive message.
Wrapping the side-effectful block in a try-catch lets you return a structured error that the UI can display to the user:
try {
// ... all fs.mkdirSync / copyFileSync / ensureAgentDirectory calls ...
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
log('ERROR', `[API] Setup failed: ${msg}`);
return c.json({ ok: false, error: msg }, 500);
}
Description
Add an interactive setup wizard to guide users through initial TinyClaw configuration. When settings are empty or missing, users are presented with a multi-step wizard instead of a blank configuration page. The wizard collects channel preferences, AI provider/model selection, workspace configuration, and agent definitions, then persists everything via a new
/api/setupendpoint.This improves the onboarding experience by replacing manual JSON editing with a guided form-based flow.
Changes
Settings page (
tinyoffice/src/app/settings/page.tsx):SetupWizardcomponent with 5-step flow: Channels → Provider → Workspace → Agents → ReviewSettings API (
packages/server/src/routes/settings.ts):POST /api/setupendpoint to atomically write settings and initialize directoriesAPI client (
tinyoffice/src/lib/api.ts):runSetup()function andAgentConfigtype for wizard integrationTesting
/api/setupChecklist
https://claude.ai/code/session_01JANJmrpc35awJqJvQCS3z2