@bibobonking/opensol 0.0.0-stage → 3.0.1

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.
Files changed (114) hide show
  1. package/.github/workflows/build.yml +25 -0
  2. package/README.md +74 -2
  3. package/dist/assets/index-BmN7pBji.css +1 -0
  4. package/dist/assets/index-DgNDjkOz.js +301 -0
  5. package/dist/favicon.svg +15 -0
  6. package/dist/index.html +55 -0
  7. package/dist/preview-host.html +33 -0
  8. package/index.html +54 -0
  9. package/package.json +43 -4
  10. package/postcss.config.js +6 -0
  11. package/public/favicon.svg +15 -0
  12. package/public/preview-host.html +33 -0
  13. package/shared/plugin-builder.test.mjs +43 -0
  14. package/shared/plugin-package.d.mts +34 -0
  15. package/shared/plugin-package.mjs +197 -0
  16. package/shared/plugin-package.test.mjs +94 -0
  17. package/src/App.tsx +152 -0
  18. package/src/agent/adapters/anthropic.ts +233 -0
  19. package/src/agent/adapters/gemini.ts +225 -0
  20. package/src/agent/adapters/openai-responses.ts +215 -0
  21. package/src/agent/adapters/openai.ts +200 -0
  22. package/src/agent/adapters/shared.ts +96 -0
  23. package/src/agent/approval.ts +20 -0
  24. package/src/agent/compact.ts +234 -0
  25. package/src/agent/index.ts +36 -0
  26. package/src/agent/model.ts +20 -0
  27. package/src/agent/prompt.ts +107 -0
  28. package/src/agent/queue.test.mjs +111 -0
  29. package/src/agent/queue.ts +84 -0
  30. package/src/agent/subagent.ts +109 -0
  31. package/src/agent/tools.ts +541 -0
  32. package/src/components/ChatView.tsx +403 -0
  33. package/src/components/CommandPalette.tsx +416 -0
  34. package/src/components/Composer.tsx +678 -0
  35. package/src/components/ContextBar.tsx +58 -0
  36. package/src/components/DeployModal.tsx +512 -0
  37. package/src/components/ErrorBoundary.tsx +75 -0
  38. package/src/components/HomeDashboard.tsx +189 -0
  39. package/src/components/Logo.tsx +41 -0
  40. package/src/components/Markdown.tsx +232 -0
  41. package/src/components/MessageItem.tsx +655 -0
  42. package/src/components/ModelPicker.tsx +487 -0
  43. package/src/components/PixleSol.tsx +243 -0
  44. package/src/components/PluginBuilder.tsx +285 -0
  45. package/src/components/PluginManager.tsx +341 -0
  46. package/src/components/PreviewPane.tsx +166 -0
  47. package/src/components/SettingsModal.tsx +2052 -0
  48. package/src/components/Sidebar.tsx +504 -0
  49. package/src/components/Splash.tsx +104 -0
  50. package/src/components/ToolCallCard.tsx +177 -0
  51. package/src/components/TopBar.tsx +182 -0
  52. package/src/components/TrajectoryView.tsx +178 -0
  53. package/src/components/WorkspacePanel.tsx +710 -0
  54. package/src/components/ui.tsx +311 -0
  55. package/src/core/kernel.ts +45 -0
  56. package/src/core/plugins/tools/fs.ts +219 -0
  57. package/src/core/plugins/tools/git.ts +83 -0
  58. package/src/core/plugins/tools/grep.ts +98 -0
  59. package/src/core/plugins/tools/shell.ts +88 -0
  60. package/src/core/plugins/tools/subagent.ts +36 -0
  61. package/src/core/plugins/tools/web.ts +97 -0
  62. package/src/core/services/agent-loop.ts +417 -0
  63. package/src/core/services/approval.ts +66 -0
  64. package/src/core/services/compaction.ts +45 -0
  65. package/src/core/services/llm.ts +32 -0
  66. package/src/core/services/sessions.ts +47 -0
  67. package/src/core/services/subagents.ts +15 -0
  68. package/src/core/services/system-prompt.ts +177 -0
  69. package/src/core/services/tools.ts +135 -0
  70. package/src/core/services/ui.ts +109 -0
  71. package/src/core/types.ts +139 -0
  72. package/src/data/providers.ts +125 -0
  73. package/src/data/skills.ts +68 -0
  74. package/src/index.css +776 -0
  75. package/src/lib/boot.ts +94 -0
  76. package/src/lib/context.ts +75 -0
  77. package/src/lib/conversation.test.mjs +64 -0
  78. package/src/lib/conversation.ts +59 -0
  79. package/src/lib/daemon.ts +475 -0
  80. package/src/lib/hooks.ts +33 -0
  81. package/src/lib/permissions.ts +60 -0
  82. package/src/lib/pixlesol.test.mjs +51 -0
  83. package/src/lib/pixlesol.ts +55 -0
  84. package/src/lib/plugin-folder.test.mjs +145 -0
  85. package/src/lib/plugin-folder.ts +96 -0
  86. package/src/lib/reasoning.ts +87 -0
  87. package/src/lib/sse.ts +75 -0
  88. package/src/lib/themes.test.mjs +72 -0
  89. package/src/lib/themes.ts +52 -0
  90. package/src/lib/usage.test.mjs +72 -0
  91. package/src/lib/usage.ts +155 -0
  92. package/src/lib/utils.ts +73 -0
  93. package/src/main.tsx +16 -0
  94. package/src/plugins/api.test.mjs +77 -0
  95. package/src/plugins/api.ts +113 -0
  96. package/src/plugins/bridge.d.mts +1 -0
  97. package/src/plugins/bridge.mjs +26 -0
  98. package/src/plugins/bridge.test.mjs +17 -0
  99. package/src/plugins/index.ts +52 -0
  100. package/src/plugins/preview.test.mjs +18 -0
  101. package/src/plugins/preview.ts +34 -0
  102. package/src/plugins/runtime.ts +194 -0
  103. package/src/plugins/types.ts +40 -0
  104. package/src/store/chats.ts +278 -0
  105. package/src/store/models.ts +120 -0
  106. package/src/store/settings.ts +445 -0
  107. package/src/store/ui.ts +132 -0
  108. package/src/store/workspace.ts +299 -0
  109. package/src/types.ts +337 -0
  110. package/src/vite-env.d.ts +1 -0
  111. package/tailwind.config.js +83 -0
  112. package/tsconfig.json +22 -0
  113. package/tsconfig.tsbuildinfo +1 -0
  114. package/vite.config.ts +19 -0
@@ -0,0 +1,299 @@
1
+ import { create } from 'zustand'
2
+ import type { WorkspaceEntry, WorkspaceFile, WorkspaceInfo } from '../types'
3
+ import {
4
+ addWorkspace as addWorkspaceToDaemon,
5
+ createWorkspaceEntry,
6
+ deleteWorkspaceEntry,
7
+ forgetWorkspace as forgetWorkspaceInDaemon,
8
+ getProjectInstructions,
9
+ getWorkspaceTree,
10
+ gitSummary as fetchGitSummary,
11
+ readWorkspaceFile,
12
+ renameWorkspaceEntry,
13
+ writeWorkspaceFile,
14
+ } from '../lib/daemon'
15
+ import { useUi } from './ui'
16
+
17
+ export interface GitState {
18
+ available: boolean
19
+ root: string
20
+ branch: string
21
+ entries: Array<{ status: string; path: string }>
22
+ error: string
23
+ }
24
+
25
+ const EMPTY_INFO: WorkspaceInfo = {
26
+ root: '',
27
+ name: '',
28
+ available: false,
29
+ error: '',
30
+ workspaces: [],
31
+ }
32
+
33
+ const EMPTY_GIT: GitState = {
34
+ available: false,
35
+ root: '',
36
+ branch: '',
37
+ entries: [],
38
+ error: '',
39
+ }
40
+
41
+ interface WorkspaceStore {
42
+ info: WorkspaceInfo
43
+ root: string
44
+ entries: WorkspaceEntry[]
45
+ truncated: boolean
46
+ loadingTree: boolean
47
+ treeError: string
48
+ activeFile: string | null
49
+ file: WorkspaceFile | null
50
+ content: string
51
+ dirty: boolean
52
+ saving: boolean
53
+ openingFile: boolean
54
+ git: GitState
55
+ gitLoading: boolean
56
+ /** The project instruction file (MAXCODE.md, AGENTS.md, CLAUDE.md) the agent reads each turn. */
57
+ instructions: { file: string; content: string; truncated: boolean }
58
+ hydrate: (info: WorkspaceInfo) => Promise<void>
59
+ loadTree: () => Promise<void>
60
+ refresh: (options?: { treeOnly?: boolean }) => Promise<void>
61
+ openFile: (path: string, options?: { force?: boolean }) => Promise<void>
62
+ loadInstructions: () => Promise<void>
63
+ closeFile: () => void
64
+ setContent: (content: string) => void
65
+ saveFile: () => Promise<boolean>
66
+ createEntry: (path: string, type: 'file' | 'dir') => Promise<void>
67
+ renameEntry: (from: string, to: string) => Promise<void>
68
+ deleteEntry: (path: string) => Promise<void>
69
+ addWorkspace: (path: string) => Promise<void>
70
+ forgetWorkspace: () => Promise<void>
71
+ loadGit: () => Promise<void>
72
+ setActiveFile: (path: string | null) => void
73
+ }
74
+
75
+ function isRemoved(activeFile: string | null, path: string) {
76
+ return Boolean(activeFile && (activeFile === path || activeFile.startsWith(`${path}/`)))
77
+ }
78
+
79
+ export const useWorkspace = create<WorkspaceStore>()((set, get) => ({
80
+ info: EMPTY_INFO,
81
+ root: '',
82
+ entries: [],
83
+ truncated: false,
84
+ loadingTree: false,
85
+ treeError: '',
86
+ activeFile: null,
87
+ file: null,
88
+ content: '',
89
+ dirty: false,
90
+ saving: false,
91
+ openingFile: false,
92
+ git: EMPTY_GIT,
93
+ gitLoading: false,
94
+ instructions: { file: '', content: '', truncated: false },
95
+
96
+ hydrate: async (info) => {
97
+ set({
98
+ info,
99
+ root: info.root,
100
+ treeError: info.available ? '' : info.error,
101
+ entries: info.available ? get().entries : [],
102
+ activeFile: info.available ? get().activeFile : null,
103
+ file: info.available ? get().file : null,
104
+ content: info.available ? get().content : '',
105
+ dirty: false,
106
+ git: info.available ? get().git : EMPTY_GIT,
107
+ })
108
+ if (info.available) {
109
+ await get().loadTree()
110
+ void get().loadGit()
111
+ void get().loadInstructions()
112
+ } else {
113
+ set({ instructions: { file: '', content: '', truncated: false } })
114
+ }
115
+ },
116
+
117
+ loadInstructions: async () => {
118
+ if (!get().info.available) return
119
+ try {
120
+ set({ instructions: await getProjectInstructions() })
121
+ } catch {
122
+ set({ instructions: { file: '', content: '', truncated: false } })
123
+ }
124
+ },
125
+
126
+ loadTree: async () => {
127
+ const info = get().info
128
+ if (!info.available || !info.root) {
129
+ set({ entries: [], loadingTree: false, treeError: info.error })
130
+ return
131
+ }
132
+ set({ loadingTree: true, treeError: '' })
133
+ try {
134
+ const result = await getWorkspaceTree('', 7)
135
+ set({
136
+ entries: result.entries,
137
+ truncated: result.truncated,
138
+ loadingTree: false,
139
+ root: result.root,
140
+ info: result.workspace,
141
+ })
142
+ void get().loadInstructions()
143
+ } catch (error) {
144
+ set({
145
+ loadingTree: false,
146
+ treeError: error instanceof Error ? error.message : 'Could not read the workspace.',
147
+ })
148
+ }
149
+ },
150
+
151
+ refresh: async ({ treeOnly = false } = {}) => {
152
+ await get().loadTree()
153
+ if (treeOnly) return
154
+ const active = get().activeFile
155
+ if (!active || get().dirty) return
156
+ const stillThere = get().entries.some((entry) => entry.path === active && entry.type === 'file')
157
+ if (!stillThere) {
158
+ set({ activeFile: null, file: null, content: '', dirty: false })
159
+ return
160
+ }
161
+ try {
162
+ await get().openFile(active, { force: true })
163
+ } catch {
164
+ // A tree refresh is still useful if the file disappeared mid-read.
165
+ }
166
+ },
167
+
168
+ openFile: async (path, { force = false } = {}) => {
169
+ if (!path || get().openingFile) return
170
+ if (!force && get().activeFile === path && get().file) return
171
+ if (get().dirty) {
172
+ const saved = await get().saveFile()
173
+ if (!saved) return
174
+ }
175
+ set({ openingFile: true, treeError: '' })
176
+ try {
177
+ const file = await readWorkspaceFile(path)
178
+ set({
179
+ activeFile: path,
180
+ file,
181
+ content: file.content,
182
+ dirty: false,
183
+ openingFile: false,
184
+ })
185
+ } catch (error) {
186
+ set({
187
+ openingFile: false,
188
+ treeError: error instanceof Error ? error.message : 'Could not open that file.',
189
+ })
190
+ useUi.getState().notify(error instanceof Error ? error.message : 'Could not open that file.', 'error')
191
+ }
192
+ },
193
+
194
+ closeFile: () => set({ activeFile: null, file: null, content: '', dirty: false }),
195
+
196
+ setContent: (content) => {
197
+ if (get().file?.binary) return
198
+ if (content === get().content) return
199
+ set({ content, dirty: true })
200
+ },
201
+
202
+ saveFile: async () => {
203
+ const { activeFile, content, dirty, file, saving } = get()
204
+ if (!activeFile || !dirty || saving || file?.binary) return true
205
+ set({ saving: true })
206
+ try {
207
+ const result = await writeWorkspaceFile(activeFile, content)
208
+ set({
209
+ saving: false,
210
+ dirty: false,
211
+ file: file
212
+ ? { ...file, size: result.size, mtime: result.mtime, hash: result.hash, truncated: false }
213
+ : file,
214
+ })
215
+ useUi.getState().notify(`Saved ${activeFile}`, 'success')
216
+ return true
217
+ } catch (error) {
218
+ set({ saving: false })
219
+ useUi.getState().notify(error instanceof Error ? error.message : 'Could not save that file.', 'error')
220
+ return false
221
+ }
222
+ },
223
+
224
+ createEntry: async (path, type) => {
225
+ await createWorkspaceEntry(path, type)
226
+ await get().loadTree()
227
+ if (type === 'file') await get().openFile(path)
228
+ useUi.getState().notify(`${type === 'dir' ? 'Folder' : 'File'} created: ${path}`, 'success')
229
+ },
230
+
231
+ renameEntry: async (from, to) => {
232
+ await renameWorkspaceEntry(from, to)
233
+ await get().loadTree()
234
+ if (isRemoved(get().activeFile, from)) {
235
+ const moved = get().activeFile === from ? to : `${to}${get().activeFile?.slice(from.length) ?? ''}`
236
+ set({ activeFile: null, file: null, content: '', dirty: false })
237
+ await get().openFile(moved)
238
+ }
239
+ useUi.getState().notify(`Renamed to ${to}`, 'success')
240
+ },
241
+
242
+ deleteEntry: async (path) => {
243
+ await deleteWorkspaceEntry(path)
244
+ if (isRemoved(get().activeFile, path)) {
245
+ set({ activeFile: null, file: null, content: '', dirty: false })
246
+ }
247
+ await get().loadTree()
248
+ useUi.getState().notify(`Deleted ${path}`, 'success')
249
+ },
250
+
251
+ addWorkspace: async (path) => {
252
+ const result = await addWorkspaceToDaemon(path)
253
+ set({ activeFile: null, file: null, content: '', dirty: false, entries: [] })
254
+ await get().hydrate(result.workspace)
255
+ useUi.getState().notify(`Workspace set to ${result.entry.name}`, 'success')
256
+ },
257
+
258
+ forgetWorkspace: async () => {
259
+ if (get().dirty) {
260
+ const saved = await get().saveFile()
261
+ if (!saved) return
262
+ }
263
+ const info = await forgetWorkspaceInDaemon()
264
+ set({
265
+ info,
266
+ root: '',
267
+ entries: [],
268
+ activeFile: null,
269
+ file: null,
270
+ content: '',
271
+ dirty: false,
272
+ git: EMPTY_GIT,
273
+ instructions: { file: '', content: '', truncated: false },
274
+ })
275
+ },
276
+
277
+ loadGit: async () => {
278
+ if (!get().info.available) return
279
+ set({ gitLoading: true })
280
+ try {
281
+ const git = await fetchGitSummary()
282
+ set({ git: { ...git }, gitLoading: false })
283
+ } catch (error) {
284
+ set({
285
+ git: { ...EMPTY_GIT, error: error instanceof Error ? error.message : 'Git status failed.' },
286
+ gitLoading: false,
287
+ })
288
+ }
289
+ },
290
+
291
+ setActiveFile: (path) => {
292
+ if (!path) get().closeFile()
293
+ else void get().openFile(path)
294
+ },
295
+ }))
296
+
297
+ export function workspaceFileCount(state: WorkspaceStore) {
298
+ return state.entries.filter((entry) => entry.type === 'file').length
299
+ }
package/src/types.ts ADDED
@@ -0,0 +1,337 @@
1
+ import type { ThemeId } from './lib/themes'
2
+
3
+ export type ApiFormat = 'openai' | 'anthropic' | 'gemini'
4
+
5
+ export type ApiKind = 'openai-chat' | 'openai-responses' | 'anthropic' | 'gemini'
6
+
7
+ export type ProviderId =
8
+ | 'openai'
9
+ | 'anthropic'
10
+ | 'google'
11
+ | 'deepseek'
12
+ | 'openrouter'
13
+ | 'opencode'
14
+ | 'groq'
15
+ | 'mistral'
16
+ | 'xai'
17
+ | 'together'
18
+ | 'ollama'
19
+ | 'custom'
20
+
21
+ export type Effort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'
22
+
23
+ export type ReasoningOption =
24
+ | { type: 'effort'; values: Effort[] }
25
+ | { type: 'toggle' }
26
+ | { type: 'budget_tokens'; min?: number; max?: number }
27
+
28
+ export interface ModelInfo {
29
+ id: string
30
+ name: string
31
+ context?: number
32
+ maxOutput?: number
33
+ vision?: boolean
34
+ reasoningOptions: ReasoningOption[]
35
+ toolCall: boolean
36
+ temperature: boolean
37
+ family?: string
38
+ apiKind: ApiKind
39
+ free?: boolean
40
+ canonicalId?: string
41
+ note?: string
42
+ }
43
+
44
+ export interface ProviderDef {
45
+ id: ProviderId
46
+ name: string
47
+ format: ApiFormat
48
+ baseUrl: string
49
+ keyless?: boolean
50
+ keyHint: string
51
+ note?: string
52
+ }
53
+
54
+ export interface ProviderCredentials {
55
+ baseUrl?: string
56
+ }
57
+
58
+ export interface ProviderStatus {
59
+ id: ProviderId
60
+ name: string
61
+ format: 'openai' | 'anthropic' | 'gemini' | 'opencode'
62
+ baseUrl: string
63
+ keyless: boolean
64
+ configured: boolean
65
+ hint: string
66
+ }
67
+
68
+ export interface SecretEntry {
69
+ configured: boolean
70
+ hint: string
71
+ }
72
+
73
+ export interface DeploySecretEntry extends SecretEntry {
74
+ fields: Record<string, string>
75
+ }
76
+
77
+ export interface SecretsSummary {
78
+ providers: Record<string, SecretEntry>
79
+ search: SecretEntry
80
+ deploy: {
81
+ cloudflare: DeploySecretEntry
82
+ netlify: DeploySecretEntry
83
+ vercel: DeploySecretEntry
84
+ }
85
+ encryption: string
86
+ }
87
+
88
+ export type AgentMode = 'build' | 'plan'
89
+
90
+ export type ToolName =
91
+ | 'shell'
92
+ | 'read_file'
93
+ | 'list_files'
94
+ | 'write_file'
95
+ | 'edit_file'
96
+ | 'rewrite_file'
97
+ | 'grep'
98
+ | 'web_search'
99
+ | 'read_url'
100
+ | 'git'
101
+ | 'subagent'
102
+
103
+ export interface ToolSetting {
104
+ enabled: boolean
105
+ approval: 'auto' | 'ask'
106
+ }
107
+
108
+ export type SearchProvider = 'duckduckgo' | 'tavily' | 'brave' | 'serper'
109
+
110
+ export interface Skill {
111
+ id: string
112
+ name: string
113
+ description: string
114
+ instructions: string
115
+ enabled: boolean
116
+ builtIn?: boolean
117
+ }
118
+
119
+ export interface AppSettings {
120
+ provider: ProviderId
121
+ model: string
122
+ effort: Effort
123
+ webSearchEnabled: boolean
124
+ temperature: number
125
+ maxTokens: number
126
+ systemPrompt: string
127
+ providers: Record<string, ProviderCredentials>
128
+ searchProvider: SearchProvider
129
+ tools: Record<ToolName, ToolSetting>
130
+ skills: Skill[]
131
+ theme: ThemeId
132
+ showTokenEstimate: boolean
133
+ mode: AgentMode
134
+ chatFontSize: number
135
+ workDetail: 'concise' | 'detailed'
136
+ autoCollapseWork: boolean
137
+ }
138
+
139
+ export interface Attachment {
140
+ id: string
141
+ name: string
142
+ kind: 'image' | 'text'
143
+ mime: string
144
+ dataUrl?: string
145
+ text?: string
146
+ size: number
147
+ }
148
+
149
+ export interface ToolCall {
150
+ id: string
151
+ name: ToolName
152
+ args: Record<string, unknown>
153
+ /** Gemini thought signature that must be replayed with the tool call. */
154
+ thoughtSignature?: string
155
+ }
156
+
157
+ export type MessagePart =
158
+ | { type: 'text'; text: string }
159
+ | { type: 'reasoning'; text: string }
160
+ | { type: 'tool'; call: ToolCall; status: ToolRunStatus; result?: string; durationMs?: number }
161
+
162
+ export type ToolRunStatus = 'running' | 'done' | 'error' | 'denied' | 'awaiting'
163
+
164
+ export interface UserMessage {
165
+ id: string
166
+ role: 'user'
167
+ content: string
168
+ attachments?: Attachment[]
169
+ createdAt: number
170
+ }
171
+
172
+ export interface AssistantMessage {
173
+ id: string
174
+ role: 'assistant'
175
+ content: string
176
+ reasoning: string
177
+ thinkingBlocks?: Array<{ text: string; signature?: string }>
178
+ toolCalls: ToolCall[]
179
+ model?: string
180
+ provider?: ProviderId
181
+ usage?: { input?: number; output?: number }
182
+ error?: string
183
+ stopped?: boolean
184
+ durationMs?: number
185
+ createdAt: number
186
+ /** Tool calls in this round already have follow-up tool messages. */
187
+ round: number
188
+ }
189
+
190
+ export interface ToolMessage {
191
+ id: string
192
+ role: 'tool'
193
+ call: ToolCall
194
+ status: ToolRunStatus
195
+ result?: string
196
+ durationMs?: number
197
+ createdAt: number
198
+ round: number
199
+ }
200
+
201
+ export type Message = UserMessage | AssistantMessage | ToolMessage
202
+
203
+ export interface ChatSession {
204
+ id: string
205
+ title: string
206
+ createdAt: number
207
+ updatedAt: number
208
+ messages: Message[]
209
+ provider?: ProviderId
210
+ model?: string
211
+ mode?: AgentMode
212
+ }
213
+
214
+ export interface Usage {
215
+ input?: number
216
+ output?: number
217
+ }
218
+
219
+ export interface StreamHandlers {
220
+ onText: (delta: string) => void
221
+ onReasoning: (delta: string) => void
222
+ onToolCalls: (calls: ToolCall[]) => void
223
+ onUsage: (usage: Usage) => void
224
+ }
225
+
226
+ export interface ToolEvent {
227
+ id: string
228
+ name: ToolName
229
+ args: Record<string, unknown>
230
+ status: ToolRunStatus
231
+ result?: string
232
+ durationMs?: number
233
+ }
234
+
235
+ export interface SearchResult {
236
+ title: string
237
+ url: string
238
+ snippet: string
239
+ }
240
+
241
+ export interface ShellResult {
242
+ stdout: string
243
+ stderr: string
244
+ code: number
245
+ }
246
+
247
+ export interface WorkspaceRecord {
248
+ path: string
249
+ name: string
250
+ lastOpened: number
251
+ }
252
+
253
+ export interface WorkspaceInfo {
254
+ root: string
255
+ name: string
256
+ available: boolean
257
+ error: string
258
+ workspaces: WorkspaceRecord[]
259
+ }
260
+
261
+ export interface WorkspaceEntry {
262
+ name: string
263
+ path: string
264
+ type: 'file' | 'dir' | 'link'
265
+ size: number
266
+ mtime: number
267
+ }
268
+
269
+ export interface WorkspaceFile {
270
+ path: string
271
+ size: number
272
+ mtime: number
273
+ binary: boolean
274
+ truncated: boolean
275
+ content: string
276
+ base64: string
277
+ hash: string
278
+ }
279
+
280
+ export interface DaemonInfo {
281
+ version: string
282
+ dataDir: string
283
+ home: string
284
+ platform: string
285
+ node: string
286
+ }
287
+
288
+ export type DeployProviderId = 'cloudflare' | 'netlify' | 'vercel'
289
+
290
+ export interface DeployToolInfo {
291
+ bin: string
292
+ pkg: string
293
+ label: string
294
+ installed: boolean
295
+ version: string
296
+ }
297
+
298
+ export interface DeployRequest {
299
+ provider: DeployProviderId
300
+ path: string
301
+ outputDir?: string
302
+ buildCommand?: string
303
+ projectName?: string
304
+ siteId?: string
305
+ mode?: AgentMode
306
+ }
307
+
308
+ export interface DeployResult {
309
+ provider: DeployProviderId
310
+ url: string
311
+ siteId?: string
312
+ project?: string
313
+ }
314
+
315
+ export type DeployEvent =
316
+ | { type: 'start'; provider: DeployProviderId; path?: string }
317
+ | { type: 'log'; stream: 'stdout' | 'stderr' | 'meta'; text: string }
318
+ | { type: 'done'; result: DeployResult }
319
+ | { type: 'error'; message: string; code?: string }
320
+
321
+ export interface DaemonSnapshot {
322
+ version: string
323
+ dataDir: string
324
+ home: string
325
+ platform: string
326
+ node: string
327
+ settings: Partial<AppSettings>
328
+ chats: { sessions: ChatSession[]; activeId: string | null }
329
+ workspace: WorkspaceInfo
330
+ secrets: SecretsSummary
331
+ secretsError: string
332
+ providers: ProviderStatus[]
333
+ deployTools: Record<DeployProviderId, DeployToolInfo>
334
+ deploySecrets: SecretsSummary['deploy']
335
+ migration: { migratedAt: string | null }
336
+ modelCatalog: { providers: string[] }
337
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />