cowork-os 0.3.21 → 0.3.25
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/README.md +372 -10
- package/connectors/README.md +20 -0
- package/connectors/asana-mcp/README.md +24 -0
- package/connectors/asana-mcp/dist/index.js +427 -0
- package/connectors/asana-mcp/package.json +15 -0
- package/connectors/asana-mcp/src/index.ts +553 -0
- package/connectors/asana-mcp/tsconfig.json +13 -0
- package/connectors/hubspot-mcp/README.md +35 -0
- package/connectors/hubspot-mcp/dist/index.js +454 -0
- package/connectors/hubspot-mcp/package.json +15 -0
- package/connectors/hubspot-mcp/src/index.ts +562 -0
- package/connectors/hubspot-mcp/tsconfig.json +13 -0
- package/connectors/jira-mcp/README.md +49 -0
- package/connectors/jira-mcp/dist/index.js +588 -0
- package/connectors/jira-mcp/package.json +15 -0
- package/connectors/jira-mcp/src/index.ts +711 -0
- package/connectors/jira-mcp/tsconfig.json +13 -0
- package/connectors/linear-mcp/README.md +22 -0
- package/connectors/linear-mcp/dist/index.js +402 -0
- package/connectors/linear-mcp/package.json +15 -0
- package/connectors/linear-mcp/src/index.ts +522 -0
- package/connectors/linear-mcp/tsconfig.json +13 -0
- package/connectors/okta-mcp/README.md +24 -0
- package/connectors/okta-mcp/dist/index.js +411 -0
- package/connectors/okta-mcp/package.json +15 -0
- package/connectors/okta-mcp/src/index.ts +520 -0
- package/connectors/okta-mcp/tsconfig.json +13 -0
- package/connectors/salesforce-mcp/README.md +47 -0
- package/connectors/salesforce-mcp/dist/index.js +584 -0
- package/connectors/salesforce-mcp/package.json +15 -0
- package/connectors/salesforce-mcp/src/index.ts +722 -0
- package/connectors/salesforce-mcp/tsconfig.json +13 -0
- package/connectors/servicenow-mcp/README.md +26 -0
- package/connectors/servicenow-mcp/dist/index.js +400 -0
- package/connectors/servicenow-mcp/package.json +15 -0
- package/connectors/servicenow-mcp/src/index.ts +500 -0
- package/connectors/servicenow-mcp/tsconfig.json +13 -0
- package/connectors/templates/mcp-connector/README.md +31 -0
- package/connectors/templates/mcp-connector/package.json +15 -0
- package/connectors/templates/mcp-connector/src/index.ts +330 -0
- package/connectors/templates/mcp-connector/tsconfig.json +13 -0
- package/connectors/zendesk-mcp/README.md +40 -0
- package/connectors/zendesk-mcp/dist/index.js +431 -0
- package/connectors/zendesk-mcp/package.json +15 -0
- package/connectors/zendesk-mcp/src/index.ts +543 -0
- package/connectors/zendesk-mcp/tsconfig.json +13 -0
- package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
- package/dist/electron/electron/agent/daemon.js +189 -13
- package/dist/electron/electron/agent/executor.js +895 -78
- package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
- package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
- package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
- package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
- package/dist/electron/electron/agent/llm/index.js +13 -1
- package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
- package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
- package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
- package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
- package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
- package/dist/electron/electron/agent/llm/types.js +66 -1
- package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
- package/dist/electron/electron/agent/search/provider-factory.js +38 -2
- package/dist/electron/electron/agent/tools/box-tools.js +231 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
- package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
- package/dist/electron/electron/agent/tools/file-tools.js +66 -3
- package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
- package/dist/electron/electron/agent/tools/image-tools.js +11 -1
- package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
- package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
- package/dist/electron/electron/agent/tools/registry.js +548 -10
- package/dist/electron/electron/agent/tools/search-tools.js +28 -10
- package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
- package/dist/electron/electron/agent/tools/x-tools.js +1 -1
- package/dist/electron/electron/agents/agent-dispatch.js +63 -0
- package/dist/electron/electron/database/repositories.js +19 -5
- package/dist/electron/electron/database/schema.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
- package/dist/electron/electron/gateway/index.js +75 -1
- package/dist/electron/electron/gateway/router.js +209 -154
- package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
- package/dist/electron/electron/ipc/handlers.js +763 -267
- package/dist/electron/electron/main.js +63 -0
- package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
- package/dist/electron/electron/memory/MemoryService.js +2 -1
- package/dist/electron/electron/preload.js +78 -1
- package/dist/electron/electron/settings/appearance-manager.js +18 -1
- package/dist/electron/electron/settings/box-manager.js +54 -0
- package/dist/electron/electron/settings/dropbox-manager.js +54 -0
- package/dist/electron/electron/settings/google-drive-manager.js +54 -0
- package/dist/electron/electron/settings/notion-manager.js +56 -0
- package/dist/electron/electron/settings/onedrive-manager.js +54 -0
- package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
- package/dist/electron/electron/utils/box-api.js +153 -0
- package/dist/electron/electron/utils/dropbox-api.js +144 -0
- package/dist/electron/electron/utils/env-migration.js +19 -0
- package/dist/electron/electron/utils/google-drive-api.js +152 -0
- package/dist/electron/electron/utils/notion-api.js +103 -0
- package/dist/electron/electron/utils/onedrive-api.js +113 -0
- package/dist/electron/electron/utils/sharepoint-api.js +109 -0
- package/dist/electron/electron/utils/validation.js +98 -3
- package/dist/electron/electron/utils/x-cli.js +1 -1
- package/dist/electron/shared/channelMessages.js +284 -3
- package/dist/electron/shared/llm-provider-catalog.js +198 -0
- package/dist/electron/shared/types.js +90 -1
- package/package.json +14 -3
- package/resources/skills/nano-banana-pro.json +4 -4
- package/resources/skills/openai-image-gen.json +3 -3
- package/resources/skills/scripts/gen.py +163 -0
- package/resources/skills/scripts/generate_image.py +91 -0
- package/src/electron/agent/custom-skill-loader.ts +34 -1
- package/src/electron/agent/daemon.ts +210 -14
- package/src/electron/agent/executor.ts +1124 -85
- package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
- package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
- package/src/electron/agent/llm/bedrock-provider.ts +62 -9
- package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
- package/src/electron/agent/llm/groq-provider.ts +39 -0
- package/src/electron/agent/llm/index.ts +6 -0
- package/src/electron/agent/llm/kimi-provider.ts +39 -0
- package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
- package/src/electron/agent/llm/openai-compatible.ts +133 -0
- package/src/electron/agent/llm/openai-oauth.ts +2 -1
- package/src/electron/agent/llm/openrouter-provider.ts +2 -1
- package/src/electron/agent/llm/provider-factory.ts +459 -6
- package/src/electron/agent/llm/types.ts +95 -1
- package/src/electron/agent/llm/xai-provider.ts +39 -0
- package/src/electron/agent/search/provider-factory.ts +43 -2
- package/src/electron/agent/tools/box-tools.ts +239 -0
- package/src/electron/agent/tools/builtin-settings.ts +36 -0
- package/src/electron/agent/tools/dropbox-tools.ts +237 -0
- package/src/electron/agent/tools/file-tools.ts +66 -3
- package/src/electron/agent/tools/gmail-tools.ts +240 -0
- package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
- package/src/electron/agent/tools/google-drive-tools.ts +228 -0
- package/src/electron/agent/tools/grep-tools.ts +97 -12
- package/src/electron/agent/tools/image-tools.ts +11 -1
- package/src/electron/agent/tools/notion-tools.ts +330 -0
- package/src/electron/agent/tools/onedrive-tools.ts +217 -0
- package/src/electron/agent/tools/registry.ts +794 -10
- package/src/electron/agent/tools/search-tools.ts +29 -11
- package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
- package/src/electron/agent/tools/shell-tools.ts +11 -3
- package/src/electron/agent/tools/x-tools.ts +1 -1
- package/src/electron/agents/agent-dispatch.ts +79 -0
- package/src/electron/database/SecureSettingsRepository.ts +7 -1
- package/src/electron/database/repositories.ts +58 -6
- package/src/electron/database/schema.ts +8 -0
- package/src/electron/gateway/channels/discord.ts +4 -0
- package/src/electron/gateway/channels/google-chat.ts +3 -0
- package/src/electron/gateway/channels/line.ts +3 -0
- package/src/electron/gateway/channels/matrix-client.ts +15 -0
- package/src/electron/gateway/channels/matrix.ts +31 -0
- package/src/electron/gateway/channels/mattermost.ts +3 -0
- package/src/electron/gateway/channels/signal.ts +3 -0
- package/src/electron/gateway/channels/slack.ts +9 -4
- package/src/electron/gateway/channels/teams.ts +4 -0
- package/src/electron/gateway/channels/telegram.ts +2 -0
- package/src/electron/gateway/channels/twitch.ts +2 -0
- package/src/electron/gateway/channels/types.ts +8 -0
- package/src/electron/gateway/channels/whatsapp.ts +66 -0
- package/src/electron/gateway/index.ts +95 -2
- package/src/electron/gateway/router.ts +231 -161
- package/src/electron/gateway/security.ts +21 -9
- package/src/electron/ipc/canvas-handlers.ts +10 -0
- package/src/electron/ipc/handlers.ts +848 -292
- package/src/electron/main.ts +35 -0
- package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
- package/src/electron/memory/MemoryService.ts +7 -1
- package/src/electron/preload.ts +200 -5
- package/src/electron/settings/appearance-manager.ts +20 -2
- package/src/electron/settings/box-manager.ts +58 -0
- package/src/electron/settings/dropbox-manager.ts +58 -0
- package/src/electron/settings/google-workspace-manager.ts +59 -0
- package/src/electron/settings/notion-manager.ts +60 -0
- package/src/electron/settings/onedrive-manager.ts +58 -0
- package/src/electron/settings/sharepoint-manager.ts +58 -0
- package/src/electron/utils/box-api.ts +184 -0
- package/src/electron/utils/dropbox-api.ts +171 -0
- package/src/electron/utils/env-migration.ts +22 -0
- package/src/electron/utils/gmail-api.ts +121 -0
- package/src/electron/utils/google-calendar-api.ts +115 -0
- package/src/electron/utils/google-workspace-api.ts +228 -0
- package/src/electron/utils/google-workspace-auth.ts +109 -0
- package/src/electron/utils/google-workspace-oauth.ts +232 -0
- package/src/electron/utils/notion-api.ts +126 -0
- package/src/electron/utils/onedrive-api.ts +137 -0
- package/src/electron/utils/sharepoint-api.ts +132 -0
- package/src/electron/utils/validation.ts +128 -1
- package/src/electron/utils/x-cli.ts +1 -1
- package/src/renderer/App.tsx +119 -8
- package/src/renderer/components/ActivityFeedItem.tsx +34 -17
- package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
- package/src/renderer/components/AppearanceSettings.tsx +37 -2
- package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
- package/src/renderer/components/BoxSettings.tsx +203 -0
- package/src/renderer/components/BrowserView.tsx +101 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
- package/src/renderer/components/CanvasPreview.tsx +68 -1
- package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
- package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
- package/src/renderer/components/ConnectorsSettings.tsx +397 -0
- package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
- package/src/renderer/components/DiscordSettings.tsx +18 -7
- package/src/renderer/components/DropboxSettings.tsx +202 -0
- package/src/renderer/components/EmailSettings.tsx +18 -7
- package/src/renderer/components/FileViewer.tsx +21 -13
- package/src/renderer/components/GoogleChatSettings.tsx +17 -7
- package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
- package/src/renderer/components/ImessageSettings.tsx +22 -11
- package/src/renderer/components/LineIcons.tsx +376 -0
- package/src/renderer/components/LineSettings.tsx +18 -7
- package/src/renderer/components/MCPSettings.tsx +56 -0
- package/src/renderer/components/MainContent.tsx +740 -76
- package/src/renderer/components/MatrixSettings.tsx +18 -7
- package/src/renderer/components/MattermostSettings.tsx +18 -7
- package/src/renderer/components/NodesSettings.tsx +58 -99
- package/src/renderer/components/NotificationPanel.tsx +25 -11
- package/src/renderer/components/NotionSettings.tsx +231 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
- package/src/renderer/components/OnboardingModal.tsx +70 -1
- package/src/renderer/components/OneDriveSettings.tsx +212 -0
- package/src/renderer/components/RightPanel.tsx +141 -28
- package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
- package/src/renderer/components/SearchSettings.tsx +118 -114
- package/src/renderer/components/Settings.tsx +1425 -651
- package/src/renderer/components/SharePointSettings.tsx +224 -0
- package/src/renderer/components/Sidebar.tsx +94 -19
- package/src/renderer/components/SignalSettings.tsx +18 -7
- package/src/renderer/components/SkillHubBrowser.tsx +144 -185
- package/src/renderer/components/SlackSettings.tsx +18 -7
- package/src/renderer/components/TaskQuickActions.tsx +11 -6
- package/src/renderer/components/TaskTimeline.tsx +58 -26
- package/src/renderer/components/TeamsSettings.tsx +18 -7
- package/src/renderer/components/TelegramSettings.tsx +18 -7
- package/src/renderer/components/ThemeIcon.tsx +16 -0
- package/src/renderer/components/TwitchSettings.tsx +18 -7
- package/src/renderer/components/VoiceSettings.tsx +30 -74
- package/src/renderer/components/WhatsAppSettings.tsx +48 -37
- package/src/renderer/components/WorkingStateHistory.tsx +7 -5
- package/src/renderer/components/WorkspaceSelector.tsx +42 -13
- package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
- package/src/renderer/styles/index.css +2333 -209
- package/src/shared/channelMessages.ts +367 -4
- package/src/shared/llm-provider-catalog.ts +217 -0
- package/src/shared/types.ts +251 -2
|
@@ -136,102 +136,88 @@ export function SkillHubBrowser({ onSkillInstalled, onClose }: SkillHubBrowserPr
|
|
|
136
136
|
|
|
137
137
|
const getStatusBadge = (entry: SkillStatusEntry) => {
|
|
138
138
|
if (entry.eligible) {
|
|
139
|
-
return <span className="badge badge
|
|
139
|
+
return <span className="settings-badge settings-badge--success">Ready</span>;
|
|
140
140
|
}
|
|
141
141
|
if (entry.disabled) {
|
|
142
|
-
return <span className="badge badge
|
|
142
|
+
return <span className="settings-badge settings-badge--warning">Disabled</span>;
|
|
143
143
|
}
|
|
144
144
|
if (entry.blockedByAllowlist) {
|
|
145
|
-
return <span className="badge badge
|
|
145
|
+
return <span className="settings-badge settings-badge--error">Blocked</span>;
|
|
146
146
|
}
|
|
147
|
-
return <span className="badge badge
|
|
147
|
+
return <span className="settings-badge settings-badge--neutral">Missing Requirements</span>;
|
|
148
148
|
};
|
|
149
149
|
|
|
150
150
|
const renderBrowseTab = () => (
|
|
151
|
-
<div className="
|
|
152
|
-
|
|
153
|
-
<div className="flex gap-2">
|
|
151
|
+
<div className="skillhub-tab">
|
|
152
|
+
<div className="input-with-button">
|
|
154
153
|
<input
|
|
155
154
|
type="text"
|
|
156
155
|
placeholder="Search skills..."
|
|
157
|
-
className="input
|
|
156
|
+
className="settings-input"
|
|
158
157
|
value={searchQuery}
|
|
159
158
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
160
159
|
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
|
|
161
160
|
/>
|
|
162
161
|
<button
|
|
163
|
-
className="
|
|
162
|
+
className="button-secondary button-small"
|
|
164
163
|
onClick={handleSearch}
|
|
165
164
|
disabled={isSearching}
|
|
166
165
|
>
|
|
167
|
-
{isSearching ?
|
|
168
|
-
<span className="loading loading-spinner loading-sm" />
|
|
169
|
-
) : (
|
|
170
|
-
'Search'
|
|
171
|
-
)}
|
|
166
|
+
{isSearching ? 'Searching...' : 'Search'}
|
|
172
167
|
</button>
|
|
173
168
|
</div>
|
|
174
169
|
|
|
175
|
-
{/* Search Results */}
|
|
176
170
|
{searchResults.length > 0 ? (
|
|
177
|
-
<div className="
|
|
171
|
+
<div className="skillhub-list">
|
|
178
172
|
{searchResults.map((skill) => (
|
|
179
173
|
<div
|
|
180
174
|
key={skill.id}
|
|
181
|
-
className={`card
|
|
182
|
-
selectedSkill?.id === skill.id ? 'ring-2 ring-primary' : ''
|
|
183
|
-
}`}
|
|
175
|
+
className={`settings-card skillhub-card ${selectedSkill?.id === skill.id ? 'is-selected' : ''}`}
|
|
184
176
|
onClick={() => setSelectedSkill(skill)}
|
|
185
177
|
>
|
|
186
|
-
<div className="card-
|
|
187
|
-
<div className="
|
|
188
|
-
<
|
|
189
|
-
<span className="text-2xl">{skill.icon || '📦'}</span>
|
|
178
|
+
<div className="skillhub-card-header">
|
|
179
|
+
<div className="skillhub-card-info">
|
|
180
|
+
<span className="skillhub-icon">{skill.icon || '📦'}</span>
|
|
190
181
|
<div>
|
|
191
|
-
<
|
|
192
|
-
|
|
182
|
+
<div className="skillhub-title-row">
|
|
183
|
+
<h4 className="skillhub-title">{skill.name}</h4>
|
|
184
|
+
</div>
|
|
185
|
+
<p className="settings-description skillhub-description">{skill.description}</p>
|
|
193
186
|
</div>
|
|
194
|
-
</div>
|
|
195
|
-
<div className="flex items-center gap-2">
|
|
196
|
-
{installedSkills.has(skill.id) ? (
|
|
197
|
-
<span className="badge badge-success">Installed</span>
|
|
198
|
-
) : (
|
|
199
|
-
<button
|
|
200
|
-
className="btn btn-primary btn-sm"
|
|
201
|
-
onClick={(e) => {
|
|
202
|
-
e.stopPropagation();
|
|
203
|
-
handleInstall(skill.id);
|
|
204
|
-
}}
|
|
205
|
-
disabled={installing === skill.id}
|
|
206
|
-
>
|
|
207
|
-
{installing === skill.id ? (
|
|
208
|
-
<span className="loading loading-spinner loading-xs" />
|
|
209
|
-
) : (
|
|
210
|
-
'Install'
|
|
211
|
-
)}
|
|
212
|
-
</button>
|
|
213
|
-
)}
|
|
214
|
-
</div>
|
|
215
187
|
</div>
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
188
|
+
<div className="skillhub-card-actions">
|
|
189
|
+
{installedSkills.has(skill.id) ? (
|
|
190
|
+
<span className="settings-badge settings-badge--success">Installed</span>
|
|
191
|
+
) : (
|
|
192
|
+
<button
|
|
193
|
+
className="button-primary button-small"
|
|
194
|
+
onClick={(e) => {
|
|
195
|
+
e.stopPropagation();
|
|
196
|
+
handleInstall(skill.id);
|
|
197
|
+
}}
|
|
198
|
+
disabled={installing === skill.id}
|
|
199
|
+
>
|
|
200
|
+
{installing === skill.id ? 'Installing...' : 'Install'}
|
|
201
|
+
</button>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
225
204
|
</div>
|
|
205
|
+
{skill.tags && skill.tags.length > 0 && (
|
|
206
|
+
<div className="skillhub-tags">
|
|
207
|
+
{skill.tags.map((tag) => (
|
|
208
|
+
<span key={tag} className="settings-badge settings-badge--outline">
|
|
209
|
+
{tag}
|
|
210
|
+
</span>
|
|
211
|
+
))}
|
|
212
|
+
</div>
|
|
213
|
+
)}
|
|
226
214
|
</div>
|
|
227
215
|
))}
|
|
228
216
|
</div>
|
|
229
217
|
) : searchQuery && !isSearching ? (
|
|
230
|
-
<div className="
|
|
231
|
-
No skills found. Try a different search term.
|
|
232
|
-
</div>
|
|
218
|
+
<div className="settings-empty">No skills found. Try a different search term.</div>
|
|
233
219
|
) : (
|
|
234
|
-
<div className="
|
|
220
|
+
<div className="settings-empty">
|
|
235
221
|
Search the SkillHub registry to discover and install new skills.
|
|
236
222
|
</div>
|
|
237
223
|
)}
|
|
@@ -242,67 +228,58 @@ export function SkillHubBrowser({ onSkillInstalled, onClose }: SkillHubBrowserPr
|
|
|
242
228
|
const managedSkills = skillStatus?.skills.filter(s => s.source === 'managed') || [];
|
|
243
229
|
|
|
244
230
|
return (
|
|
245
|
-
<div className="
|
|
246
|
-
<div className="
|
|
247
|
-
<h3
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
231
|
+
<div className="skillhub-tab">
|
|
232
|
+
<div className="settings-section-header">
|
|
233
|
+
<h3>Installed from Registry</h3>
|
|
234
|
+
<div className="settings-section-actions">
|
|
235
|
+
<button className="button-secondary button-small" onClick={handleOpenFolder}>
|
|
236
|
+
Open Folder
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
251
239
|
</div>
|
|
252
240
|
|
|
253
241
|
{managedSkills.length > 0 ? (
|
|
254
|
-
<div className="
|
|
242
|
+
<div className="skillhub-list">
|
|
255
243
|
{managedSkills.map((skill) => (
|
|
256
|
-
<div key={skill.id} className="card
|
|
257
|
-
<div className="card-
|
|
258
|
-
<div className="
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
<div>
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
{getStatusBadge(skill)}
|
|
265
|
-
</div>
|
|
266
|
-
<p className="text-sm text-base-content/70">{skill.description}</p>
|
|
267
|
-
{skill.metadata?.version && (
|
|
268
|
-
<p className="text-xs text-base-content/50">v{skill.metadata.version}</p>
|
|
269
|
-
)}
|
|
244
|
+
<div key={skill.id} className="settings-card skillhub-card">
|
|
245
|
+
<div className="skillhub-card-header">
|
|
246
|
+
<div className="skillhub-card-info">
|
|
247
|
+
<span className="skillhub-icon">{skill.icon || '📦'}</span>
|
|
248
|
+
<div>
|
|
249
|
+
<div className="skillhub-title-row">
|
|
250
|
+
<h4 className="skillhub-title">{skill.name}</h4>
|
|
251
|
+
{getStatusBadge(skill)}
|
|
270
252
|
</div>
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
onClick={() => handleUninstall(skill.id)}
|
|
275
|
-
disabled={installing === skill.id}
|
|
276
|
-
>
|
|
277
|
-
{installing === skill.id ? (
|
|
278
|
-
<span className="loading loading-spinner loading-xs" />
|
|
279
|
-
) : (
|
|
280
|
-
'Uninstall'
|
|
281
|
-
)}
|
|
282
|
-
</button>
|
|
283
|
-
</div>
|
|
284
|
-
|
|
285
|
-
{/* Missing requirements */}
|
|
286
|
-
{!skill.eligible && (
|
|
287
|
-
<div className="mt-2 text-sm">
|
|
288
|
-
{skill.missing.bins.length > 0 && (
|
|
289
|
-
<p className="text-warning">
|
|
290
|
-
Missing binaries: {skill.missing.bins.join(', ')}
|
|
291
|
-
</p>
|
|
292
|
-
)}
|
|
293
|
-
{skill.missing.env.length > 0 && (
|
|
294
|
-
<p className="text-warning">
|
|
295
|
-
Missing env vars: {skill.missing.env.join(', ')}
|
|
296
|
-
</p>
|
|
253
|
+
<p className="settings-description skillhub-description">{skill.description}</p>
|
|
254
|
+
{skill.metadata?.version && (
|
|
255
|
+
<p className="skillhub-meta">v{skill.metadata.version}</p>
|
|
297
256
|
)}
|
|
298
257
|
</div>
|
|
299
|
-
|
|
258
|
+
</div>
|
|
259
|
+
<button
|
|
260
|
+
className="button-danger button-small"
|
|
261
|
+
onClick={() => handleUninstall(skill.id)}
|
|
262
|
+
disabled={installing === skill.id}
|
|
263
|
+
>
|
|
264
|
+
{installing === skill.id ? 'Uninstalling...' : 'Uninstall'}
|
|
265
|
+
</button>
|
|
300
266
|
</div>
|
|
267
|
+
|
|
268
|
+
{!skill.eligible && (
|
|
269
|
+
<div className="skillhub-warnings">
|
|
270
|
+
{skill.missing.bins.length > 0 && (
|
|
271
|
+
<p>Missing binaries: {skill.missing.bins.join(', ')}</p>
|
|
272
|
+
)}
|
|
273
|
+
{skill.missing.env.length > 0 && (
|
|
274
|
+
<p>Missing env vars: {skill.missing.env.join(', ')}</p>
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
)}
|
|
301
278
|
</div>
|
|
302
279
|
))}
|
|
303
280
|
</div>
|
|
304
281
|
) : (
|
|
305
|
-
<div className="
|
|
282
|
+
<div className="settings-empty">
|
|
306
283
|
No skills installed from registry yet.
|
|
307
284
|
<br />
|
|
308
285
|
Browse the registry to discover and install skills.
|
|
@@ -315,59 +292,53 @@ export function SkillHubBrowser({ onSkillInstalled, onClose }: SkillHubBrowserPr
|
|
|
315
292
|
const renderStatusTab = () => {
|
|
316
293
|
if (!skillStatus) {
|
|
317
294
|
return (
|
|
318
|
-
<div className="
|
|
319
|
-
<span className="loading loading-spinner" />
|
|
320
|
-
</div>
|
|
295
|
+
<div className="settings-empty">Loading skill status...</div>
|
|
321
296
|
);
|
|
322
297
|
}
|
|
323
298
|
|
|
324
299
|
return (
|
|
325
|
-
<div className="
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
<div className="stat-title">Total Skills</div>
|
|
300
|
+
<div className="skillhub-tab">
|
|
301
|
+
<div className="stats-grid">
|
|
302
|
+
<div className="stat-card">
|
|
303
|
+
<div className="stat-label">Total Skills</div>
|
|
330
304
|
<div className="stat-value">{skillStatus.summary.total}</div>
|
|
331
305
|
</div>
|
|
332
|
-
<div className="stat">
|
|
333
|
-
<div className="stat-
|
|
334
|
-
<div className="stat-value
|
|
306
|
+
<div className="stat-card">
|
|
307
|
+
<div className="stat-label">Ready</div>
|
|
308
|
+
<div className="stat-value stat-value--success">{skillStatus.summary.eligible}</div>
|
|
335
309
|
</div>
|
|
336
|
-
<div className="stat">
|
|
337
|
-
<div className="stat-
|
|
338
|
-
<div className="stat-value
|
|
310
|
+
<div className="stat-card">
|
|
311
|
+
<div className="stat-label">Disabled</div>
|
|
312
|
+
<div className="stat-value stat-value--warning">{skillStatus.summary.disabled}</div>
|
|
339
313
|
</div>
|
|
340
|
-
<div className="stat">
|
|
341
|
-
<div className="stat-
|
|
342
|
-
<div className="stat-value
|
|
314
|
+
<div className="stat-card">
|
|
315
|
+
<div className="stat-label">Missing Deps</div>
|
|
316
|
+
<div className="stat-value stat-value--error">{skillStatus.summary.missingRequirements}</div>
|
|
343
317
|
</div>
|
|
344
318
|
</div>
|
|
345
319
|
|
|
346
|
-
{/* All Skills by Source */}
|
|
347
320
|
{['bundled', 'managed', 'workspace'].map((source) => {
|
|
348
321
|
const skills = skillStatus.skills.filter(s => s.source === source);
|
|
349
322
|
if (skills.length === 0) return null;
|
|
350
323
|
|
|
351
324
|
return (
|
|
352
|
-
<
|
|
353
|
-
<
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
</
|
|
357
|
-
<div className="
|
|
358
|
-
|
|
359
|
-
{
|
|
360
|
-
<div
|
|
361
|
-
<
|
|
362
|
-
|
|
363
|
-
<span className="font-medium">{skill.name}</span>
|
|
364
|
-
</div>
|
|
365
|
-
{getStatusBadge(skill)}
|
|
325
|
+
<details key={source} className="skillhub-group" open={source !== 'bundled'}>
|
|
326
|
+
<summary>
|
|
327
|
+
<span className="skillhub-group-title">{source} Skills</span>
|
|
328
|
+
<span className="settings-badge settings-badge--neutral">{skills.length}</span>
|
|
329
|
+
</summary>
|
|
330
|
+
<div className="skillhub-group-content">
|
|
331
|
+
{skills.map((skill) => (
|
|
332
|
+
<div key={skill.id} className="skillhub-group-item">
|
|
333
|
+
<div className="skillhub-group-info">
|
|
334
|
+
<span>{skill.icon || '📦'}</span>
|
|
335
|
+
<span>{skill.name}</span>
|
|
366
336
|
</div>
|
|
367
|
-
|
|
368
|
-
|
|
337
|
+
{getStatusBadge(skill)}
|
|
338
|
+
</div>
|
|
339
|
+
))}
|
|
369
340
|
</div>
|
|
370
|
-
</
|
|
341
|
+
</details>
|
|
371
342
|
);
|
|
372
343
|
})}
|
|
373
344
|
</div>
|
|
@@ -376,79 +347,67 @@ export function SkillHubBrowser({ onSkillInstalled, onClose }: SkillHubBrowserPr
|
|
|
376
347
|
|
|
377
348
|
// Show initial loading state
|
|
378
349
|
if (isLoadingStatus) {
|
|
379
|
-
return
|
|
380
|
-
<div className="flex flex-col h-full items-center justify-center">
|
|
381
|
-
<span className="loading loading-spinner loading-lg" />
|
|
382
|
-
<p className="mt-4 text-base-content/70">Loading skills...</p>
|
|
383
|
-
</div>
|
|
384
|
-
);
|
|
350
|
+
return <div className="settings-loading">Loading skills...</div>;
|
|
385
351
|
}
|
|
386
352
|
|
|
387
353
|
return (
|
|
388
|
-
<div className="
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
{isRefreshing ? (
|
|
405
|
-
<span className="loading loading-spinner loading-xs" />
|
|
406
|
-
) : (
|
|
407
|
-
'↻'
|
|
408
|
-
)}
|
|
409
|
-
</button>
|
|
410
|
-
{onClose && (
|
|
411
|
-
<button className="btn btn-ghost btn-sm" onClick={onClose}>
|
|
412
|
-
Close
|
|
354
|
+
<div className="skillhub-settings">
|
|
355
|
+
<div className="settings-section">
|
|
356
|
+
<div className="settings-section-header">
|
|
357
|
+
<div>
|
|
358
|
+
<h3>SkillHub</h3>
|
|
359
|
+
<p className="settings-description">
|
|
360
|
+
Search the SkillHub registry to discover and install new skills.
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
363
|
+
<div className="settings-section-actions">
|
|
364
|
+
<button
|
|
365
|
+
className="button-secondary button-small"
|
|
366
|
+
onClick={handleRefresh}
|
|
367
|
+
disabled={isRefreshing}
|
|
368
|
+
>
|
|
369
|
+
{isRefreshing ? 'Refreshing...' : 'Refresh'}
|
|
413
370
|
</button>
|
|
414
|
-
|
|
371
|
+
{onClose && (
|
|
372
|
+
<button className="button-secondary button-small" onClick={onClose}>
|
|
373
|
+
Close
|
|
374
|
+
</button>
|
|
375
|
+
)}
|
|
376
|
+
</div>
|
|
415
377
|
</div>
|
|
416
378
|
</div>
|
|
417
379
|
|
|
418
|
-
{/* Error Alert */}
|
|
419
380
|
{error && (
|
|
420
|
-
<div className="alert alert-error
|
|
381
|
+
<div className="settings-alert settings-alert-error">
|
|
421
382
|
<span>{error}</span>
|
|
422
|
-
<button className="
|
|
383
|
+
<button className="button-secondary button-small" onClick={() => setError(null)}>
|
|
423
384
|
Dismiss
|
|
424
385
|
</button>
|
|
425
386
|
</div>
|
|
426
387
|
)}
|
|
427
388
|
|
|
428
|
-
|
|
429
|
-
<div className="tabs tabs-boxed mb-4">
|
|
389
|
+
<div className="settings-tabs">
|
|
430
390
|
<button
|
|
431
|
-
className={`tab ${activeTab === 'installed' ? '
|
|
391
|
+
className={`settings-tab ${activeTab === 'installed' ? 'active' : ''}`}
|
|
432
392
|
onClick={() => setActiveTab('installed')}
|
|
433
393
|
>
|
|
434
394
|
Installed
|
|
435
395
|
</button>
|
|
436
396
|
<button
|
|
437
|
-
className={`tab ${activeTab === 'browse' ? '
|
|
397
|
+
className={`settings-tab ${activeTab === 'browse' ? 'active' : ''}`}
|
|
438
398
|
onClick={() => setActiveTab('browse')}
|
|
439
399
|
>
|
|
440
400
|
Browse Registry
|
|
441
401
|
</button>
|
|
442
402
|
<button
|
|
443
|
-
className={`tab ${activeTab === 'status' ? '
|
|
403
|
+
className={`settings-tab ${activeTab === 'status' ? 'active' : ''}`}
|
|
444
404
|
onClick={() => setActiveTab('status')}
|
|
445
405
|
>
|
|
446
406
|
Status
|
|
447
407
|
</button>
|
|
448
408
|
</div>
|
|
449
409
|
|
|
450
|
-
|
|
451
|
-
<div className="flex-1 overflow-y-auto">
|
|
410
|
+
<div className="skillhub-tab-content">
|
|
452
411
|
{activeTab === 'browse' && renderBrowseTab()}
|
|
453
412
|
{activeTab === 'installed' && renderInstalledTab()}
|
|
454
413
|
{activeTab === 'status' && renderStatusTab()}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { ChannelData, ChannelUserData, SecurityMode } from '../../shared/types';
|
|
3
3
|
|
|
4
4
|
interface SlackSettingsProps {
|
|
@@ -23,11 +23,7 @@ export function SlackSettings({ onStatusChange }: SlackSettingsProps) {
|
|
|
23
23
|
// Pairing code state
|
|
24
24
|
const [pairingCode, setPairingCode] = useState<string | null>(null);
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
loadChannel();
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
const loadChannel = async () => {
|
|
26
|
+
const loadChannel = useCallback(async () => {
|
|
31
27
|
try {
|
|
32
28
|
setLoading(true);
|
|
33
29
|
const channels = await window.electronAPI.getGatewayChannels();
|
|
@@ -48,7 +44,22 @@ export function SlackSettings({ onStatusChange }: SlackSettingsProps) {
|
|
|
48
44
|
} finally {
|
|
49
45
|
setLoading(false);
|
|
50
46
|
}
|
|
51
|
-
};
|
|
47
|
+
}, [onStatusChange]);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
loadChannel();
|
|
51
|
+
}, [loadChannel]);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const unsubscribe = window.electronAPI?.onGatewayUsersUpdated?.((data) => {
|
|
55
|
+
if (data?.channelType !== 'slack') return;
|
|
56
|
+
if (channel && data?.channelId && data.channelId !== channel.id) return;
|
|
57
|
+
loadChannel();
|
|
58
|
+
});
|
|
59
|
+
return () => {
|
|
60
|
+
if (unsubscribe) unsubscribe();
|
|
61
|
+
};
|
|
62
|
+
}, [channel?.id, loadChannel]);
|
|
52
63
|
|
|
53
64
|
const handleAddChannel = async () => {
|
|
54
65
|
if (!botToken.trim() || !appToken.trim()) return;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
+
import { ThemeIcon } from './ThemeIcon';
|
|
3
|
+
import { BotIcon, CalendarIcon, ClockIcon, ColumnsIcon, FlagIcon, TagIcon } from './LineIcons';
|
|
2
4
|
import {
|
|
3
5
|
TaskBoardColumn,
|
|
4
6
|
TaskLabelData,
|
|
@@ -107,7 +109,7 @@ export function TaskQuickActions({
|
|
|
107
109
|
className={`action-btn ${activePanel === 'column' ? 'active' : ''}`}
|
|
108
110
|
onClick={() => setActivePanel(activePanel === 'column' ? null : 'column')}
|
|
109
111
|
>
|
|
110
|
-
<
|
|
112
|
+
<ThemeIcon className="action-icon" emoji="📋" icon={<ColumnsIcon size={16} />} />
|
|
111
113
|
Move to Column
|
|
112
114
|
</button>
|
|
113
115
|
|
|
@@ -115,7 +117,7 @@ export function TaskQuickActions({
|
|
|
115
117
|
className={`action-btn ${activePanel === 'priority' ? 'active' : ''}`}
|
|
116
118
|
onClick={() => setActivePanel(activePanel === 'priority' ? null : 'priority')}
|
|
117
119
|
>
|
|
118
|
-
<
|
|
120
|
+
<ThemeIcon className="action-icon" emoji="!" icon={<FlagIcon size={16} />} />
|
|
119
121
|
Set Priority
|
|
120
122
|
</button>
|
|
121
123
|
|
|
@@ -123,7 +125,7 @@ export function TaskQuickActions({
|
|
|
123
125
|
className={`action-btn ${activePanel === 'labels' ? 'active' : ''}`}
|
|
124
126
|
onClick={() => setActivePanel(activePanel === 'labels' ? null : 'labels')}
|
|
125
127
|
>
|
|
126
|
-
<
|
|
128
|
+
<ThemeIcon className="action-icon" emoji="🏷️" icon={<TagIcon size={16} />} />
|
|
127
129
|
Labels
|
|
128
130
|
</button>
|
|
129
131
|
|
|
@@ -131,7 +133,7 @@ export function TaskQuickActions({
|
|
|
131
133
|
className={`action-btn ${activePanel === 'agent' ? 'active' : ''}`}
|
|
132
134
|
onClick={() => setActivePanel(activePanel === 'agent' ? null : 'agent')}
|
|
133
135
|
>
|
|
134
|
-
<
|
|
136
|
+
<ThemeIcon className="action-icon" emoji="🤖" icon={<BotIcon size={16} />} />
|
|
135
137
|
Assign Agent
|
|
136
138
|
</button>
|
|
137
139
|
|
|
@@ -139,7 +141,7 @@ export function TaskQuickActions({
|
|
|
139
141
|
className={`action-btn ${activePanel === 'due' ? 'active' : ''}`}
|
|
140
142
|
onClick={() => setActivePanel(activePanel === 'due' ? null : 'due')}
|
|
141
143
|
>
|
|
142
|
-
<
|
|
144
|
+
<ThemeIcon className="action-icon" emoji="📅" icon={<CalendarIcon size={16} />} />
|
|
143
145
|
Due Date
|
|
144
146
|
</button>
|
|
145
147
|
|
|
@@ -147,7 +149,7 @@ export function TaskQuickActions({
|
|
|
147
149
|
className={`action-btn ${activePanel === 'estimate' ? 'active' : ''}`}
|
|
148
150
|
onClick={() => setActivePanel(activePanel === 'estimate' ? null : 'estimate')}
|
|
149
151
|
>
|
|
150
|
-
<
|
|
152
|
+
<ThemeIcon className="action-icon" emoji="⏱️" icon={<ClockIcon size={16} />} />
|
|
151
153
|
Estimate
|
|
152
154
|
</button>
|
|
153
155
|
</div>
|
|
@@ -383,6 +385,9 @@ export function TaskQuickActions({
|
|
|
383
385
|
font-size: 14px;
|
|
384
386
|
width: 20px;
|
|
385
387
|
text-align: center;
|
|
388
|
+
display: inline-flex;
|
|
389
|
+
align-items: center;
|
|
390
|
+
justify-content: center;
|
|
386
391
|
}
|
|
387
392
|
|
|
388
393
|
.action-panel {
|