jivamai 0.1.4-dev.edce8f4 → 0.2.0-dev.08fad0b

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.
@@ -1,162 +0,0 @@
1
- # IPC Contract
2
-
3
- All communication between the renderer and the main process uses Electron's `ipcRenderer.invoke` / `ipcMain.handle` (request-response) or `ipcRenderer.on` / `webContents.send` (push events).
4
-
5
- The preload script (`electron/preload.ts`) exposes these as typed methods on `window.electron`. The full TypeScript interface is in `src/types/electron.d.ts`.
6
-
7
- ---
8
-
9
- ## Setup
10
-
11
- | Channel | Direction | Description |
12
- |---------|-----------|-------------|
13
- | `setup:check` | invoke | Pre-flight check: Node.js, jiva-core, config |
14
-
15
- **`setup:check` return:**
16
- ```typescript
17
- {
18
- nodejs: { ok: boolean; version?: string }
19
- jivaCore: { ok: boolean; version?: string }
20
- config: { ok: boolean; path: string }
21
- platform: string // 'win32' | 'darwin' | 'linux'
22
- }
23
- ```
24
-
25
- ---
26
-
27
- ## Jiva Server Lifecycle
28
-
29
- | Channel | Direction | Description |
30
- |---------|-----------|-------------|
31
- | `jiva:server:start` | invoke | Initialize JivaRunner (load jiva-core, start DualAgent) |
32
- | `jiva:server:stop` | invoke | Cleanup agent and MCP servers |
33
- | `jiva:server:restart` | invoke | Stop then start |
34
- | `jiva:server:status` | invoke | Returns `{ status: ServerStatus; port: number }` |
35
- | `jiva:server:status-changed` | push | Renderer receives status updates from runner |
36
- | `jiva:phase-update` | push | Agent phase updates during inference (`thinking`, `calling-tool`, etc.) |
37
-
38
- **`ServerStatus`:** `'stopped' | 'starting' | 'running' | 'error'`
39
-
40
- ---
41
-
42
- ## Chat / Messaging
43
-
44
- | Channel | Direction | Description |
45
- |---------|-----------|-------------|
46
- | `jiva:send-message` | invoke | Send a prompt; returns full result when complete |
47
- | `jiva:reset-conversation` | invoke | Start a new conversation (clears agent memory) |
48
- | `jiva:load-conversation` | invoke | Load a saved conversation by ID into the agent |
49
-
50
- **`jiva:send-message` payload:** `(prompt: string, persona?: string)`
51
- **`jiva:send-message` return:** `{ success: boolean; result?: AgentResult; conversationId?: string; error?: string }`
52
-
53
- ---
54
-
55
- ## Conversations
56
-
57
- | Channel | Direction | Description |
58
- |---------|-----------|-------------|
59
- | `conversations:list` | invoke | List saved conversations from `~/.jiva/conversations/` |
60
- | `conversations:load` | invoke | Read a conversation JSON by ID |
61
-
62
- **`conversations:list` return:**
63
- ```typescript
64
- Array<{
65
- id: string
66
- summary: string // title from metadata, or first user message (truncated to 60 chars)
67
- messageCount: number
68
- lastModified: number // ms timestamp
69
- }>
70
- ```
71
-
72
- ---
73
-
74
- ## Personas
75
-
76
- | Channel | Direction | Description |
77
- |---------|-----------|-------------|
78
- | `personas:list` | invoke | List all persona directories from `~/.jiva/personas/` |
79
- | `personas:activate` | invoke | Activate a persona and switch the agent's context |
80
- | `personas:active` | invoke | Get the currently active persona name |
81
-
82
- **`personas:list` return:** `PersonaInfo[]` (see `electron/persona-manager.ts`)
83
-
84
- ---
85
-
86
- ## Configuration
87
-
88
- | Channel | Direction | Description |
89
- |---------|-----------|-------------|
90
- | `config:read` | invoke | Read `JivaConfig` from the platform-specific path |
91
- | `config:write` | invoke | Write `JivaConfig` to the platform-specific path |
92
-
93
- Config is read from / written to `getJivaConfigPath()` — see `electron/config-manager.ts`.
94
-
95
- ---
96
-
97
- ## MCP Server Management
98
-
99
- | Channel | Direction | Description |
100
- |---------|-----------|-------------|
101
- | `mcp:list-status` | invoke | List all MCP servers with runtime connection status |
102
- | `mcp:get-tools` | invoke | Get all tools exposed by connected MCP servers |
103
- | `mcp:add-server` | invoke | Add a new MCP server (stdio or HTTP) to config and runtime |
104
- | `mcp:remove-server` | invoke | Remove an MCP server from config and runtime |
105
- | `mcp:toggle-server` | invoke | Enable or disable an MCP server |
106
- | `mcp:reconnect-server` | invoke | Reconnect a specific MCP server |
107
-
108
- **`mcp:list-status` return item:**
109
- ```typescript
110
- {
111
- name: string
112
- enabled: boolean
113
- connected: boolean
114
- toolCount: number
115
- command: string // stdio servers
116
- args: string[]
117
- env: Record<string, string>
118
- url?: string // HTTP servers
119
- type: 'stdio' | 'http'
120
- error?: string
121
- }
122
- ```
123
-
124
- ---
125
-
126
- ## Workspace / File Browser
127
-
128
- | Channel | Direction | Description |
129
- |---------|-----------|-------------|
130
- | `workspace:get-dir` | invoke | Get the configured workspace directory |
131
- | `workspace:set-dir` | invoke | Set the workspace directory (persisted to config) |
132
- | `workspace:pick-dir` | invoke | Open native folder picker dialog |
133
- | `workspace:list-files` | invoke | List files in a directory (restricted to `$HOME`) |
134
- | `workspace:read-file` | invoke | Read a file's text content (max 500 KB) |
135
- | `workspace:open-external` | invoke | Reveal a file in the native file manager |
136
-
137
- ---
138
-
139
- ## Window Controls
140
-
141
- | Channel | Direction | Description |
142
- |---------|-----------|-------------|
143
- | `window:minimize` | invoke | Minimize the window |
144
- | `window:maximize` | invoke | Toggle maximize/restore |
145
- | `window:close` | invoke | Close the window |
146
- | `window:isMaximized` | invoke | Returns `boolean` |
147
-
148
- ---
149
-
150
- ## System / Native Events
151
-
152
- | Channel | Direction | Description |
153
- |---------|-----------|-------------|
154
- | `native-theme-changed` | push | System light/dark mode changed; payload: `isDark: boolean` |
155
-
156
- ---
157
-
158
- ## Notes
159
-
160
- - All invoke handlers return `{ success: boolean; error?: string }` on failure unless otherwise specified.
161
- - Push events use `ipcRenderer.on` in the preload and are exposed as `onXxx(callback)` methods on `window.electron`.
162
- - The `persona` parameter on `jiva:send-message` is accepted but intentionally ignored to avoid destroying conversation history mid-chat. Use `personas:activate` for explicit persona switches.
@@ -1,147 +0,0 @@
1
- # jiva-core Integration
2
-
3
- Jivam does not bundle jiva-core. It dynamically loads the globally installed npm package at runtime. This means:
4
-
5
- - Users must have `npm install -g jiva-core` before Jivam can start
6
- - Updating jiva-core globally is sufficient — no Jivam rebuild needed
7
- - The integration layer is entirely in `electron/jiva-runner.ts`
8
-
9
- ---
10
-
11
- ## Runtime Resolution
12
-
13
- ### `augmentPath()`
14
-
15
- In a packaged Electron app, the OS launches the process with a minimal PATH that often excludes npm's global bin directory. `augmentPath()` fixes this by spawning the user's login shell:
16
-
17
- ```typescript
18
- const loginPath = execSync(`${shell} -l -c 'echo $PATH'`).toString().trim()
19
- process.env.PATH = loginPath
20
- ```
21
-
22
- This runs before any `execSync` or `import()` calls that depend on npm being on PATH.
23
-
24
- ### `resolveJivaCoreEntryPath()`
25
-
26
- Finds the jiva-core ESM entry point:
27
-
28
- 1. `npm root -g` → e.g. `/usr/local/lib/node_modules` → checks for `jiva-core/package.json`
29
- 2. Fallback: `~/.npm-global/lib/node_modules/jiva-core/package.json` (common Linux setup)
30
- 3. Fallback: `./node_modules/jiva-core/package.json` (development / local install)
31
-
32
- Reads `package.json` → follows the `"exports"` or `"main"` field to get the entry file path.
33
-
34
- ### Dynamic ESM Import
35
-
36
- ```typescript
37
- const { DualAgent, ConversationManager, MCPServerManager } = await import(entryPath)
38
- ```
39
-
40
- This is a true ESM dynamic import — no CommonJS `require()`. jiva-core is an ESM-only package.
41
-
42
- ---
43
-
44
- ## Configuration
45
-
46
- Config is read via `readConfig()` in `electron/config-manager.ts`, which reads from `getJivaConfigPath()` — the platform-specific location where jiva-core stores its `config.json`.
47
-
48
- The config shape relevant to jiva-core:
49
-
50
- ```typescript
51
- {
52
- models: {
53
- reasoning: {
54
- provider?: string // e.g. 'anthropic', 'openai'
55
- apiKey?: string
56
- endpoint?: string
57
- model?: string
58
- useHarmonyFormat?: boolean
59
- }
60
- }
61
- mcpServers?: Record<string, MCPServerConfig>
62
- workspaceDir?: string
63
- }
64
- ```
65
-
66
- ---
67
-
68
- ## DualAgent
69
-
70
- `DualAgent` is jiva-core's primary agent class. JivaRunner wraps it:
71
-
72
- | JivaRunner method | DualAgent call | Notes |
73
- |-------------------|----------------|-------|
74
- | `initialize()` | `new DualAgent(config)` | Constructs with model config, persona, directive |
75
- | `chat(prompt, onPhase)` | `agent.chat(prompt)` | Streams phase events via callback |
76
- | `resetConversation()` | `agent.resetConversation()` | Clears in-memory conversation state |
77
- | `loadConversation(id)` | `agent.loadConversation(id)` | Loads from `~/.jiva/conversations/<id>.json` |
78
- | `saveConversation()` | `agent.saveConversation()` | Saves to `~/.jiva/conversations/` |
79
- | `switchPersona(name)` | `agent.cleanup()` + `new DualAgent(...)` | Full re-init with new persona dir |
80
- | `cleanup()` | `agent.cleanup()` | Closes MCP connections, frees resources |
81
-
82
- ---
83
-
84
- ## Directive Injection
85
-
86
- Before each agent initialization, `electron/directive-manager.ts` writes a directive file to `~/.jiva/jiva-directive.md`. This file contains:
87
-
88
- - Today's date (so the agent always knows the current date)
89
- - Any custom user instructions configured for the active persona
90
-
91
- jiva-core reads this file as a system-level context injection, so the directive takes effect on every conversation without needing to be in the message history.
92
-
93
- ---
94
-
95
- ## Persona System
96
-
97
- Personas live in `~/.jiva/personas/<name>/`. Each persona directory may contain:
98
-
99
- - `.jiva-plugin/plugin.json` — manifest with `name`, `description`, `tags`
100
- - `CLAUDE.md` or `SKILL.md` — persona instructions read by jiva-core
101
- - Custom tools, skills, or resource files
102
-
103
- `electron/persona-manager.ts` handles:
104
- - `listPersonas()` — scans `~/.jiva/personas/`, reads manifests, returns `PersonaInfo[]`
105
- - `activatePersona(name)` — writes `~/.jiva/active-persona.txt` (fallback if CLI unavailable)
106
- - `getActivePersona()` — reads from config's `activePersona` field, falls back to `active-persona.txt`
107
-
108
- ---
109
-
110
- ## MCP Server Management
111
-
112
- MCP (Model Context Protocol) servers extend the agent with external tools. They are configured in `config.mcpServers`:
113
-
114
- **Stdio server** (local process):
115
- ```json
116
- {
117
- "myServer": {
118
- "command": "node",
119
- "args": ["/path/to/server.js"],
120
- "env": { "API_KEY": "..." },
121
- "enabled": true
122
- }
123
- }
124
- ```
125
-
126
- **HTTP server** (remote):
127
- ```json
128
- {
129
- "remoteServer": {
130
- "url": "http://localhost:8080/mcp",
131
- "enabled": true
132
- }
133
- }
134
- ```
135
-
136
- `MCPServerManager` (jiva-core) manages connections. JivaRunner exposes these live operations:
137
-
138
- | Method | Description |
139
- |--------|-------------|
140
- | `getMCPServerStatus()` | Current connection state + tool count for each server |
141
- | `getMCPTools()` | All tools grouped by server name |
142
- | `addMCPServer(name, config)` | Add and connect a new server at runtime |
143
- | `removeMCPServer(name)` | Disconnect and remove a server at runtime |
144
- | `toggleMCPServer(name, enabled)` | Enable/disable without removing |
145
- | `reconnectMCPServer(name)` | Force reconnect a failed server |
146
-
147
- Config changes are written to disk immediately via `writeConfig()` so they persist across restarts.
@@ -1,87 +0,0 @@
1
- # Architecture Overview
2
-
3
- ## Three-Process Model
4
-
5
- Electron enforces strict process separation. Jivam uses all three Electron processes:
6
-
7
- ```
8
- ┌─────────────────────────────────────────────────────────────┐
9
- │ Main Process (Node.js) │
10
- │ electron/main.ts │
11
- │ · Creates BrowserWindow │
12
- │ · Loads jiva-core via dynamic import │
13
- │ · Registers IPC handlers (ipc-handlers.ts) │
14
- │ · Manages JivaRunner lifecycle │
15
- └──────────────────────┬──────────────────────────────────────┘
16
- │ contextBridge (context isolation ON)
17
- ┌──────────────────────▼──────────────────────────────────────┐
18
- │ Preload Script (Node.js, sandboxed) │
19
- │ electron/preload.ts │
20
- │ · Exposes window.electron API to renderer │
21
- │ · Wraps ipcRenderer.invoke / ipcRenderer.on │
22
- └──────────────────────┬──────────────────────────────────────┘
23
- │ window.electron.*
24
- ┌──────────────────────▼──────────────────────────────────────┐
25
- │ Renderer Process (Chromium, no Node access) │
26
- │ src/ (React + TypeScript + Vite) │
27
- │ · All UI components and Zustand stores │
28
- │ · Calls window.electron.* for all system operations │
29
- └─────────────────────────────────────────────────────────────┘
30
- ```
31
-
32
- Context isolation is **enabled** — the renderer has no direct Node.js or Electron API access. All privileged operations go through the preload bridge.
33
-
34
- ---
35
-
36
- ## Key Directories
37
-
38
- | Directory | Process | Purpose |
39
- |-----------|---------|---------|
40
- | `electron/` | Main | IPC handlers, jiva-core runner, config, persona, directive managers |
41
- | `src/` | Renderer | React components, Zustand stores, types |
42
- | `src/components/` | Renderer | UI component tree |
43
- | `src/store/` | Renderer | Zustand state stores |
44
- | `src/types/` | Shared | TypeScript interfaces including `ElectronAPI` |
45
-
46
- ---
47
-
48
- ## Data Persistence
49
-
50
- | Data | Location | Manager |
51
- |------|----------|---------|
52
- | AI model config / API keys | Platform-specific (see below) | `electron/config-manager.ts` |
53
- | Conversations | `~/.jiva/conversations/*.json` | jiva-core's ConversationManager |
54
- | Personas | `~/.jiva/personas/<name>/` | `electron/persona-manager.ts` |
55
- | Active persona | `~/.jiva/active-persona.txt` | `electron/persona-manager.ts` |
56
- | Directive | `~/.jiva/jiva-directive.md` | `electron/directive-manager.ts` |
57
- | Workspace dir preference | Inside config.json | `electron/config-manager.ts` |
58
- | UI preferences (theme) | `localStorage` | `src/store/settings.store.ts` |
59
-
60
- ### Platform-Specific Config Paths
61
-
62
- jiva-core stores `config.json` at OS-appropriate locations, **not** `~/.jiva/config.json`. `getJivaConfigPath()` in `electron/config-manager.ts` returns the correct path:
63
-
64
- | Platform | Path |
65
- |----------|------|
66
- | Windows | `%APPDATA%\jiva-nodejs\Config\config.json` |
67
- | macOS | `~/Library/Preferences/jiva-nodejs/config.json` |
68
- | Linux | `$XDG_CONFIG_HOME/jiva-nodejs/config.json` (default: `~/.config/jiva-nodejs/config.json`) |
69
-
70
- ---
71
-
72
- ## Build System
73
-
74
- | Tool | Role |
75
- |------|------|
76
- | `vite` | Bundles the renderer (React app) |
77
- | `vite-plugin-electron` | Co-builds main + preload alongside renderer |
78
- | `electron-builder` | Packages the app for distribution |
79
- | `build.sh` | Wrapper script: cleans, builds, packages all platforms |
80
-
81
- **Packaging targets:**
82
-
83
- | Platform | Formats |
84
- |----------|---------|
85
- | macOS | DMG (installer) + ZIP (portable) |
86
- | Windows | NSIS installer + portable EXE |
87
- | Linux | AppImage + `.deb` |
@@ -1,108 +0,0 @@
1
- # Startup Flow
2
-
3
- This document traces the full boot sequence from process launch to a fully interactive UI.
4
-
5
- ---
6
-
7
- ## Phase 1 — Electron Main Process Starts
8
-
9
- **File:** `electron/main.ts`
10
-
11
- 1. Electron creates the `BrowserWindow` with `contextIsolation: true` and `nodeIntegration: false`.
12
- 2. The preload script (`electron/preload.ts`) is loaded into the window context.
13
- 3. The window loads the renderer: dev server URL in development, `dist/index.html` in production.
14
- 4. `setupIpcHandlers(jivaRunner, getWindow)` is called, registering all `ipcMain.handle()` listeners.
15
- 5. `JivaRunner` instance is created but **not yet initialized** — it waits for the renderer to request it.
16
-
17
- ---
18
-
19
- ## Phase 2 — Renderer Mounts, Pre-flight Check
20
-
21
- **File:** `src/App.tsx`
22
-
23
- 1. React mounts. `setupDone` state is initialized to `null` (pre-flight in progress).
24
- 2. `window.electron.setup.check()` is invoked — this calls `setup:check` IPC.
25
-
26
- **Main process handles `setup:check`** (`electron/ipc-handlers.ts`):
27
-
28
- - Runs `npm --version` (ok flag) + `node --version` (display version)
29
- - Checks `npm root -g` for `jiva-core/package.json`
30
- - Checks `getJivaConfigPath()` for a config file with a non-empty `apiKey`
31
- - Returns `{ nodejs, jivaCore, config, platform }`
32
-
33
- 3. If all three checks pass → `setupDone = true` → proceed to Phase 3.
34
- 4. If any fail → `setupDone = false` → `<SetupScreen>` renders with the check results.
35
- - SetupScreen auto-polls every 3 seconds until all checks pass.
36
- - User can configure the AI model in-app via the Settings overlay.
37
- - Once all pass, user clicks "Continue" → `setupDone = true`.
38
-
39
- ---
40
-
41
- ## Phase 3 — Jiva Agent Initialization
42
-
43
- **File:** `src/store/jiva.store.ts` → `startServer()` → `window.electron.jiva.server.start()`
44
-
45
- **Main process handles `jiva:server:start`** (`electron/ipc-handlers.ts`):
46
-
47
- 1. Calls `jivaRunner.initialize()`.
48
-
49
- **`JivaRunner.initialize()`** (`electron/jiva-runner.ts`):
50
-
51
- 1. `augmentPath()` — spawns `$SHELL -l -c 'echo $PATH'` to capture the login shell's PATH (needed in packaged apps where the process PATH is minimal).
52
- 2. `resolveJivaCoreEntryPath()` — runs `npm root -g` to locate the global `jiva-core` install. Falls back to `~/.npm-global` and local `node_modules`.
53
- 3. Dynamic ESM import: `const { DualAgent, ConversationManager, MCPServerManager } = await import(entryPath)`
54
- 4. Reads config via `readConfig()` → `getJivaConfigPath()`.
55
- 5. `directive-manager.ts` writes a date-aware `~/.jiva/jiva-directive.md` (injected as system context).
56
- 6. `persona-manager.ts` resolves the active persona directory.
57
- 7. `DualAgent` is constructed with the config, persona, directive, and MCP server config.
58
- 8. MCP servers from `config.mcpServers` are started via `MCPServerManager`.
59
- 9. Runner emits `status-changed: 'ready'`.
60
-
61
- ---
62
-
63
- ## Phase 4 — Status Events and UI Ready
64
-
65
- **File:** `electron/ipc-handlers.ts`
66
-
67
- The runner's `status-changed` event is forwarded to the renderer via `win.webContents.send('jiva:server:status-changed', ...)`.
68
-
69
- **File:** `src/store/jiva.store.ts`
70
-
71
- `initPhaseListener()` registers `window.electron.jiva.onStatusChange()` and `window.electron.jiva.onPhaseUpdate()`. Status updates flow:
72
-
73
- ```
74
- JivaRunner emits 'status-changed'
75
- → ipcMain forwards to renderer
76
- → jiva.store sets serverStatus
77
- → App.tsx reacts: setShowSplash(false)
78
- → AppShell renders
79
- ```
80
-
81
- ---
82
-
83
- ## Phase 5 — App Shell Renders
84
-
85
- **File:** `src/components/layout/AppShell.tsx`
86
-
87
- - `loadPersonas()` is called from `App.tsx` once `showSplash` clears.
88
- - `AppShell` renders the sidebar, topbar, and active tab panel.
89
- - The user can now chat, switch personas, browse conversations, manage MCP servers, and browse files.
90
-
91
- ---
92
-
93
- ## Sequence Summary
94
-
95
- ```
96
- main.ts → BrowserWindow, setupIpcHandlers
97
- preload.ts → window.electron exposed
98
- App.tsx mounts → setup:check IPC
99
- [SetupScreen if needed]
100
- setupDone = true
101
- jiva:server:start → JivaRunner.initialize()
102
- augmentPath → resolveJivaCoreEntryPath → import(jiva-core)
103
- DualAgent created, MCP servers started
104
- status-changed: 'ready'
105
- showSplash = false
106
- AppShell renders
107
- loadPersonas()
108
- ```
@@ -1,153 +0,0 @@
1
- # State Management
2
-
3
- Jivam uses [Zustand](https://github.com/pmndrs/zustand) for all renderer-side state. There are six stores, each with a single responsibility.
4
-
5
- ---
6
-
7
- ## Data Flow Pattern
8
-
9
- ```
10
- User action
11
- → Component calls store action
12
- → Store action calls window.electron.* (IPC invoke)
13
- → Main process handler executes
14
- → Returns result
15
- → Store updates state
16
- → Component re-renders
17
- ```
18
-
19
- Push events (server status, phase updates) follow the reverse path: main process sends via `webContents.send` → preload forwards via `ipcRenderer.on` → store listener updates state.
20
-
21
- ---
22
-
23
- ## Stores
24
-
25
- ### `useJivaStore` — `src/store/jiva.store.ts`
26
-
27
- Manages the jiva-core agent lifecycle and runtime state.
28
-
29
- | State | Type | Description |
30
- |-------|------|-------------|
31
- | `serverStatus` | `'stopped' \| 'starting' \| 'running' \| 'error'` | Current agent status |
32
- | `currentPhase` | `string \| null` | Agent's current reasoning phase |
33
- | `isInitializing` | `boolean` | True while `startServer()` is in progress |
34
-
35
- | Action | Description |
36
- |--------|-------------|
37
- | `startServer()` | Invokes `jiva:server:start`, transitions status through `starting → running` |
38
- | `stopServer()` | Invokes `jiva:server:stop` |
39
- | `restartServer()` | Invokes `jiva:server:restart` |
40
- | `setServerStatus(status)` | Direct status setter (used by push event listener) |
41
- | `initPhaseListener()` | Registers listeners for `jiva:server:status-changed` and `jiva:phase-update` push events |
42
-
43
- ---
44
-
45
- ### `useChatStore` — `src/store/chat.store.ts`
46
-
47
- Manages the chat message history and streaming state for the active session.
48
-
49
- | State | Type | Description |
50
- |-------|------|-------------|
51
- | `messages` | `ChatMessage[]` | Array of user and assistant messages |
52
- | `isStreaming` | `boolean` | True while awaiting agent response |
53
- | `streamError` | `string \| null` | Error from the last failed send |
54
-
55
- | Action | Description |
56
- |--------|-------------|
57
- | `sendMessage(prompt, persona?)` | Appends user message, invokes `jiva:send-message`, appends assistant response |
58
- | `clearMessages()` | Clears the message array (used when starting a new conversation) |
59
- | `setMessages(messages)` | Bulk-replaces messages (used when loading a saved conversation) |
60
-
61
- **`ChatMessage` shape:**
62
- ```typescript
63
- {
64
- id: string
65
- role: 'user' | 'assistant'
66
- content: string
67
- timestamp: number
68
- phase?: string // reasoning phase tag, shown on assistant messages
69
- }
70
- ```
71
-
72
- ---
73
-
74
- ### `useConversationStore` — `src/store/conversation.store.ts`
75
-
76
- Manages the conversation list in the sidebar and the active conversation ID.
77
-
78
- | State | Type | Description |
79
- |-------|------|-------------|
80
- | `conversations` | `ConversationSummary[]` | Sidebar list, sorted newest-first |
81
- | `activeId` | `string \| null` | ID of the currently loaded conversation |
82
- | `isLoading` | `boolean` | True while fetching the list |
83
-
84
- | Action | Description |
85
- |--------|-------------|
86
- | `loadConversations()` | Invokes `conversations:list`, populates `conversations` |
87
- | `selectConversation(id)` | Invokes `conversations:load` + `jiva:load-conversation`, sets `activeId`, loads messages into `useChatStore` |
88
- | `newConversation()` | Invokes `jiva:reset-conversation`, clears messages, sets `activeId = null` |
89
- | `refreshConversations()` | Re-fetches the list (called after a chat completes to capture new titles) |
90
-
91
- ---
92
-
93
- ### `usePersonaStore` — `src/store/persona.store.ts`
94
-
95
- Manages the persona list and active persona.
96
-
97
- | State | Type | Description |
98
- |-------|------|-------------|
99
- | `personas` | `PersonaInfo[]` | All discovered personas from `~/.jiva/personas/` |
100
- | `activePersona` | `string \| null` | Name of the currently active persona |
101
- | `isLoading` | `boolean` | True while fetching |
102
-
103
- | Action | Description |
104
- |--------|-------------|
105
- | `loadPersonas()` | Invokes `personas:list` and `personas:active`, populates state |
106
- | `activatePersona(name)` | Invokes `personas:activate`, updates `activePersona` |
107
-
108
- ---
109
-
110
- ### `useSettingsStore` — `src/store/settings.store.ts`
111
-
112
- Manages UI preferences. Persisted to `localStorage` via Zustand's `persist` middleware.
113
-
114
- | State | Type | Description |
115
- |-------|------|-------------|
116
- | `theme` | `'light' \| 'dark' \| 'system'` | Active color theme |
117
- | `modelConfig` | `ModelConfig \| null` | Cached model configuration for the Settings UI |
118
-
119
- | Action | Description |
120
- |--------|-------------|
121
- | `setTheme(theme)` | Updates theme, persisted automatically |
122
- | `loadModelConfig()` | Invokes `config:read`, populates `modelConfig` |
123
- | `saveModelConfig(config)` | Invokes `config:write` with the updated config |
124
-
125
- ---
126
-
127
- ### `useFilesStore` — `src/store/files.store.ts`
128
-
129
- Manages the workspace file browser state.
130
-
131
- | State | Type | Description |
132
- |-------|------|-------------|
133
- | `workspaceDir` | `string` | Current workspace root directory |
134
- | `entries` | `FileEntry[]` | Files and subdirectories in the current directory |
135
- | `selectedFile` | `FileEntry \| null` | File currently open in the preview panel |
136
- | `fileContent` | `string \| null` | Text content of the selected file |
137
- | `isLoading` | `boolean` | True while listing or reading |
138
-
139
- | Action | Description |
140
- |--------|-------------|
141
- | `loadWorkspaceDir()` | Invokes `workspace:get-dir`, sets `workspaceDir` |
142
- | `listFiles(dirPath)` | Invokes `workspace:list-files`, populates `entries` |
143
- | `selectFile(entry)` | Invokes `workspace:read-file`, sets `selectedFile` and `fileContent` |
144
- | `pickDirectory()` | Invokes `workspace:pick-dir` (native dialog), then `workspace:set-dir` |
145
- | `openExternal(path)` | Invokes `workspace:open-external` to reveal file in native file manager |
146
-
147
- ---
148
-
149
- ## Store Composition Rules
150
-
151
- - Stores are independent — no cross-store imports. Components compose multiple stores.
152
- - `useChatStore` and `useConversationStore` are coupled by convention: `selectConversation()` in the conversation store calls `setMessages()` on the chat store internally via the `window.electron` conversation load.
153
- - `useSettingsStore` is the only store with persistence (localStorage). All others are session-only.