runwork 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/agents/__tests__/claude-code-stats.test.d.ts +1 -0
  2. package/dist/agents/__tests__/claude-code-stats.test.js +153 -0
  3. package/dist/agents/__tests__/claude-desktop-stats.test.d.ts +1 -0
  4. package/dist/agents/__tests__/claude-desktop-stats.test.js +280 -0
  5. package/dist/agents/__tests__/codex-stats.test.d.ts +1 -0
  6. package/dist/agents/__tests__/codex-stats.test.js +262 -0
  7. package/dist/agents/__tests__/cursor-stats.test.d.ts +1 -0
  8. package/dist/agents/__tests__/cursor-stats.test.js +183 -0
  9. package/dist/agents/__tests__/graceful-degradation.test.d.ts +1 -0
  10. package/dist/agents/__tests__/graceful-degradation.test.js +123 -0
  11. package/dist/agents/__tests__/instruction-hint.test.d.ts +1 -0
  12. package/dist/agents/__tests__/instruction-hint.test.js +69 -0
  13. package/dist/agents/__tests__/intro-skill.test.d.ts +1 -0
  14. package/dist/agents/__tests__/intro-skill.test.js +135 -0
  15. package/dist/agents/__tests__/schema-validation.test.d.ts +1 -0
  16. package/dist/agents/__tests__/schema-validation.test.js +212 -0
  17. package/dist/agents/claude-code.d.ts +16 -1
  18. package/dist/agents/claude-code.js +344 -21
  19. package/dist/agents/claude-desktop.d.ts +10 -1
  20. package/dist/agents/claude-desktop.js +250 -8
  21. package/dist/agents/cline.d.ts +13 -0
  22. package/dist/agents/cline.js +88 -0
  23. package/dist/agents/codex.d.ts +7 -2
  24. package/dist/agents/codex.js +130 -18
  25. package/dist/agents/cursor.d.ts +6 -1
  26. package/dist/agents/cursor.js +164 -7
  27. package/dist/agents/detect.js +30 -7
  28. package/dist/agents/gemini.d.ts +6 -3
  29. package/dist/agents/gemini.js +57 -20
  30. package/dist/agents/generic-adapter.d.ts +23 -0
  31. package/dist/agents/generic-adapter.js +106 -0
  32. package/dist/agents/intro-skill.d.ts +36 -0
  33. package/dist/agents/intro-skill.js +358 -0
  34. package/dist/agents/registry.d.ts +53 -0
  35. package/dist/agents/registry.js +219 -0
  36. package/dist/agents/types.d.ts +44 -1
  37. package/dist/agents/types.js +11 -4
  38. package/dist/agents/utils/instruction-hint.d.ts +11 -0
  39. package/dist/agents/utils/instruction-hint.js +62 -0
  40. package/dist/agents/utils/json-config.js +3 -3
  41. package/dist/agents/windsurf.d.ts +2 -0
  42. package/dist/agents/windsurf.js +26 -9
  43. package/dist/api/client.d.ts +85 -2
  44. package/dist/api/client.js +40 -10
  45. package/dist/auth/__tests__/login-flow.test.d.ts +1 -0
  46. package/dist/auth/__tests__/login-flow.test.js +125 -0
  47. package/dist/auth/login-flow.d.ts +16 -0
  48. package/dist/auth/login-flow.js +101 -1
  49. package/dist/commands/clone.d.ts +9 -1
  50. package/dist/commands/clone.js +40 -12
  51. package/dist/commands/deploy.js +27 -4
  52. package/dist/commands/dev.js +35 -1
  53. package/dist/commands/doctor.d.ts +2 -0
  54. package/dist/commands/doctor.js +82 -0
  55. package/dist/commands/info.js +6 -2
  56. package/dist/commands/init.d.ts +10 -2
  57. package/dist/commands/init.js +58 -15
  58. package/dist/commands/integrations.js +47 -10
  59. package/dist/commands/login.js +31 -4
  60. package/dist/commands/mcp.js +143 -15
  61. package/dist/commands/setup.js +47 -122
  62. package/dist/commands/skills.js +230 -12
  63. package/dist/commands/sync.d.ts +8 -0
  64. package/dist/commands/sync.js +398 -65
  65. package/dist/commands/welcome.js +6 -3
  66. package/dist/generated/version.d.ts +1 -1
  67. package/dist/generated/version.js +1 -1
  68. package/dist/health/__tests__/checks.test.d.ts +1 -0
  69. package/dist/health/__tests__/checks.test.js +223 -0
  70. package/dist/health/checks.d.ts +20 -0
  71. package/dist/health/checks.js +392 -0
  72. package/dist/health/runner.d.ts +2 -0
  73. package/dist/health/runner.js +26 -0
  74. package/dist/health/types.d.ts +12 -0
  75. package/dist/health/types.js +1 -0
  76. package/dist/index.js +32 -0
  77. package/dist/sync/__tests__/change-detect.test.d.ts +1 -0
  78. package/dist/sync/__tests__/change-detect.test.js +123 -0
  79. package/dist/sync/__tests__/hash.test.d.ts +1 -0
  80. package/dist/sync/__tests__/hash.test.js +18 -0
  81. package/dist/sync/change-detect.d.ts +19 -0
  82. package/dist/sync/change-detect.js +136 -0
  83. package/dist/sync/conflict-ui.d.ts +5 -0
  84. package/dist/sync/conflict-ui.js +78 -0
  85. package/dist/sync/executor.d.ts +21 -0
  86. package/dist/sync/executor.js +98 -0
  87. package/dist/sync/hash.d.ts +1 -0
  88. package/dist/sync/hash.js +4 -0
  89. package/dist/sync/types.d.ts +24 -0
  90. package/dist/sync/types.js +1 -0
  91. package/dist/types.d.ts +12 -0
  92. package/dist/ui/__tests__/banner.test.js +17 -1
  93. package/dist/ui/banner.d.ts +1 -1
  94. package/dist/ui/banner.js +27 -2
  95. package/dist/utils/__tests__/resolve.test.d.ts +1 -0
  96. package/dist/utils/__tests__/resolve.test.js +95 -0
  97. package/dist/utils/__tests__/sqlite.test.d.ts +1 -0
  98. package/dist/utils/__tests__/sqlite.test.js +77 -0
  99. package/dist/utils/agent-guidance.d.ts +32 -0
  100. package/dist/utils/agent-guidance.js +106 -0
  101. package/dist/utils/fs.js +2 -2
  102. package/dist/utils/help-json.d.ts +56 -0
  103. package/dist/utils/help-json.js +85 -0
  104. package/dist/utils/resolve.d.ts +12 -0
  105. package/dist/utils/resolve.js +52 -0
  106. package/dist/utils/setup-state.d.ts +3 -0
  107. package/dist/utils/setup-state.js +19 -0
  108. package/dist/utils/sqlite.d.ts +7 -0
  109. package/dist/utils/sqlite.js +24 -0
  110. package/dist/utils/which.d.ts +6 -0
  111. package/dist/utils/which.js +18 -0
  112. package/package.json +7 -3
  113. package/dist/agents/copilot-cli.d.ts +0 -10
  114. package/dist/agents/copilot-cli.js +0 -46
  115. package/dist/agents/copilot-vscode.d.ts +0 -10
  116. package/dist/agents/copilot-vscode.js +0 -37
@@ -0,0 +1,358 @@
1
+ /** Format a list of names with truncation. Shows up to `max` items, then "+ N more". */
2
+ function formatList(items, max = 8) {
3
+ if (items.length <= max)
4
+ return items.join(', ');
5
+ return `${items.slice(0, max).join(', ')} + ${items.length - max} more`;
6
+ }
7
+ function buildInventoryLine(ctx) {
8
+ const parts = [];
9
+ if (ctx.appCount > 0)
10
+ parts.push(`${ctx.appCount} app${ctx.appCount > 1 ? 's' : ''}`);
11
+ if (ctx.registries) {
12
+ const reg = ctx.registries;
13
+ if (reg.entities.length > 0) {
14
+ // Deduplicate entity names (same entity can be registered by multiple apps)
15
+ const uniqueNames = [...new Set(reg.entities.map(e => e.entityName))];
16
+ parts.push(`${uniqueNames.length} entit${uniqueNames.length > 1 ? 'ies' : 'y'} (${formatList(uniqueNames, 5)})`);
17
+ }
18
+ if (reg.fileStorages.length > 0)
19
+ parts.push(`${reg.fileStorages.length} file storage${reg.fileStorages.length > 1 ? 's' : ''}`);
20
+ if (reg.schedules.length > 0) {
21
+ const names = reg.schedules.map(s => s.name).filter(Boolean);
22
+ if (names.length > 0)
23
+ parts.push(`${reg.schedules.length} schedule${reg.schedules.length > 1 ? 's' : ''} (${formatList(names, 3)})`);
24
+ else
25
+ parts.push(`${reg.schedules.length} schedule${reg.schedules.length > 1 ? 's' : ''}`);
26
+ }
27
+ if (reg.workflows.length > 0) {
28
+ const names = reg.workflows.map(w => w.name).filter(Boolean);
29
+ if (names.length > 0)
30
+ parts.push(`${reg.workflows.length} workflow${reg.workflows.length > 1 ? 's' : ''} (${formatList(names, 3)})`);
31
+ else
32
+ parts.push(`${reg.workflows.length} workflow${reg.workflows.length > 1 ? 's' : ''}`);
33
+ }
34
+ if (reg.agents.length > 0) {
35
+ // Filter out agents with empty/missing names
36
+ const names = reg.agents.map(a => a.name).filter(Boolean);
37
+ if (names.length > 0)
38
+ parts.push(`${reg.agents.length} agent${reg.agents.length > 1 ? 's' : ''} (${formatList(names, 3)})`);
39
+ else
40
+ parts.push(`${reg.agents.length} agent${reg.agents.length > 1 ? 's' : ''}`);
41
+ }
42
+ if (reg.endpoints.length > 0)
43
+ parts.push(`${reg.endpoints.length} endpoint${reg.endpoints.length > 1 ? 's' : ''}`);
44
+ if (reg.components.length > 0)
45
+ parts.push(`${reg.components.length} component${reg.components.length > 1 ? 's' : ''}`);
46
+ }
47
+ if (ctx.connectedIntegrations.length > 0) {
48
+ parts.push(`${ctx.connectedIntegrations.length} integration${ctx.connectedIntegrations.length > 1 ? 's' : ''} (${formatList(ctx.connectedIntegrations, 5)})`);
49
+ }
50
+ if (ctx.skillCount > 0)
51
+ parts.push(`${ctx.skillCount} skill${ctx.skillCount > 1 ? 's' : ''}`);
52
+ if (ctx.mcpServerCount > 0)
53
+ parts.push(`${ctx.mcpServerCount} MCP server${ctx.mcpServerCount > 1 ? 's' : ''}`);
54
+ return parts.length > 0 ? parts.join(', ') : 'no resources deployed yet';
55
+ }
56
+ export function buildAppSkillDescription(appName, registries) {
57
+ if (!registries)
58
+ return `${appName} - Runwork workspace application`;
59
+ const parts = [];
60
+ const appEntities = registries.entities.filter(e => e.appName === appName);
61
+ const appSchedules = registries.schedules.filter(s => s.appName === appName);
62
+ const appWorkflows = registries.workflows.filter(w => w.appName === appName);
63
+ const appAgents = registries.agents.filter(a => a.appName === appName);
64
+ const appEndpoints = registries.endpoints.filter(e => e.appName === appName);
65
+ const appFileStorages = registries.fileStorages.filter(f => f.appName === appName);
66
+ const appComponents = registries.components.filter(c => c.appName === appName);
67
+ if (appEntities.length > 0)
68
+ parts.push(`entities (${appEntities.map(e => e.entityName).join(', ')})`);
69
+ if (appFileStorages.length > 0)
70
+ parts.push('file storage');
71
+ if (appSchedules.length > 0)
72
+ parts.push(`schedules (${appSchedules.map(s => s.name).join(', ')})`);
73
+ if (appWorkflows.length > 0)
74
+ parts.push(`workflows (${appWorkflows.map(w => w.name).join(', ')})`);
75
+ if (appAgents.length > 0)
76
+ parts.push(`agents (${appAgents.map(a => a.name).join(', ')})`);
77
+ if (appEndpoints.length > 0)
78
+ parts.push(`endpoints (${appEndpoints.map(e => e.path).join(', ')})`);
79
+ if (appComponents.length > 0)
80
+ parts.push(`components (${appComponents.map(c => c.componentName).join(', ')})`);
81
+ if (parts.length === 0)
82
+ return `${appName} - Runwork workspace application`;
83
+ return `${appName} - Runwork workspace app with ${parts.join(', ')}. Use this skill when you need data or capabilities from this app.`;
84
+ }
85
+ /**
86
+ * Generate the dynamic Runwork intro skill that teaches agents what Runwork is
87
+ * and what infrastructure is available in this workspace.
88
+ */
89
+ export function generateIntroSkill(ctx) {
90
+ const lines = [];
91
+ lines.push('# Runwork');
92
+ lines.push('');
93
+ lines.push(`Runwork is this team's AI workspace platform. It connects AI agents, users, and tools to shared infrastructure: data stores, workflows, scheduled jobs, API endpoints, file storage, 3,200+ third-party integrations, and custom applications, all managed centrally. Runwork gives agents the ability to build real, deployed applications with coded workflows, schedules, pages, API routes, and endpoints in a central company AI work cloud. Skills, MCP servers, and settings sync across the team's agents.`);
94
+ lines.push('');
95
+ // Ways to use Runwork section
96
+ lines.push('## Ways to Use Runwork');
97
+ lines.push('');
98
+ lines.push('Runwork is accessible through multiple channels. Use whichever fits the situation:');
99
+ lines.push('');
100
+ lines.push('| Channel | What it does | Best for |');
101
+ lines.push('|---------|-------------|----------|');
102
+ lines.push('| **MCP tools** | Query data, call integration APIs, trigger workflows, manage resources. Connected to this agent automatically. | All data operations, integration API calls, resource discovery. Works everywhere, including sandboxes. |');
103
+ lines.push('| **CLI** (`runwork`) | Full app development lifecycle: create, develop, deploy, manage. | Building new apps, local development, deployment, debugging. |');
104
+ lines.push('| **Web dashboard** | Visual management of apps, integrations, agents, logs, and team settings. | Users who prefer a UI, team onboarding, monitoring, connecting integrations. |');
105
+ lines.push('| **Desktop app** | Tray app with workspace overview, bundled CLI, auto-syncing MCP servers and skills. | Hands-free setup, background sync, quick access. |');
106
+ lines.push('| **API** | REST API at `https://runwork.ai` for programmatic access. | Custom tooling, CI/CD, automation scripts. |');
107
+ lines.push('');
108
+ // Workspace section
109
+ lines.push(`## Workspace: ${ctx.workspaceName}`);
110
+ lines.push('');
111
+ if (ctx.registries) {
112
+ const reg = ctx.registries;
113
+ // Apps (deduplicate by appName)
114
+ const appNames = new Set();
115
+ for (const e of reg.entities)
116
+ appNames.add(e.appName);
117
+ for (const w of reg.workflows)
118
+ appNames.add(w.appName);
119
+ for (const s of reg.schedules)
120
+ appNames.add(s.appName);
121
+ for (const a of reg.agents)
122
+ appNames.add(a.appName);
123
+ for (const ep of reg.endpoints)
124
+ if (ep.appName)
125
+ appNames.add(ep.appName);
126
+ if (appNames.size > 0) {
127
+ lines.push(`### Apps (${appNames.size})`);
128
+ const appList = [...appNames];
129
+ for (const name of appList.slice(0, 15)) {
130
+ lines.push(`- ${name}`);
131
+ }
132
+ if (appList.length > 15) {
133
+ lines.push(`- ... and ${appList.length - 15} more`);
134
+ }
135
+ lines.push('');
136
+ }
137
+ // Full infrastructure inventory
138
+ lines.push('### Infrastructure Inventory');
139
+ lines.push('');
140
+ if (reg.entities.length > 0) {
141
+ lines.push(`**Entities (${reg.entities.length}):** ${formatList(reg.entities.map(e => `${e.entityName} (${e.appName})`))}`);
142
+ lines.push(` MCP: \`entity_list_{Name}\`, \`entity_get_{Name}\`, \`query_entity_data\` | CLI: \`runwork entities records <name>\``);
143
+ lines.push('');
144
+ }
145
+ if (reg.workflows.length > 0) {
146
+ lines.push(`**Workflows (${reg.workflows.length}):** ${formatList(reg.workflows.map(w => `${w.name} (${w.appName})`))}`);
147
+ lines.push(` MCP: \`trigger_workflow\`, \`list_workflows\` | CLI: \`runwork workflows trigger <name>\``);
148
+ lines.push('');
149
+ }
150
+ if (reg.schedules.length > 0) {
151
+ lines.push(`**Scheduled Jobs (${reg.schedules.length}):** ${formatList(reg.schedules.map(s => `${s.name} (${s.appName})${s.schedule ? ` [${s.schedule}]` : ''}`))}`);
152
+ lines.push(` MCP: \`trigger_schedule\`, \`list_schedules\`, \`get_schedule_status\` | CLI: \`runwork schedules list\``);
153
+ lines.push('');
154
+ }
155
+ if (reg.endpoints.length > 0) {
156
+ lines.push(`**API Endpoints (${reg.endpoints.length}):** ${formatList(reg.endpoints.map(e => `${e.method} ${e.path} (${e.appName || 'unknown'})${e.description ? `: ${e.description}` : ''}`), 6)}`);
157
+ lines.push(` MCP: \`endpoint_*\` tools, \`list_endpoints\``);
158
+ lines.push('');
159
+ }
160
+ if (reg.agents.length > 0) {
161
+ lines.push(`**AI Agents (${reg.agents.length}):** ${formatList(reg.agents.map(a => `${a.name} [${a.type || 'conversational'}] (${a.appName})`))}`);
162
+ lines.push('');
163
+ }
164
+ if (reg.fileStorages.length > 0) {
165
+ lines.push(`**File Storage (${reg.fileStorages.length}):** ${formatList(reg.fileStorages.map(f => f.appName))}`);
166
+ lines.push(` MCP: \`list_bucket_files\`, \`generate_user_presigned_url\``);
167
+ lines.push('');
168
+ }
169
+ if (reg.components.length > 0) {
170
+ lines.push(`**Components (${reg.components.length}):** ${formatList(reg.components.map(c => `${c.componentName} (${c.appName})`))}`);
171
+ lines.push('');
172
+ }
173
+ }
174
+ // Integrations section
175
+ if (ctx.connectedIntegrations.length > 0) {
176
+ lines.push(`**Integrations (${ctx.connectedIntegrations.length}):** ${formatList(ctx.connectedIntegrations)}`);
177
+ lines.push(' Each connected integration has a `{id}_api` MCP tool for authenticated API calls.');
178
+ lines.push(` Example: \`hubspot_api\` with method "GET", path "/crm/v3/objects/contacts".`);
179
+ lines.push(' Use `search_available_integrations` MCP tool to discover API documentation and endpoint patterns.');
180
+ lines.push(' To connect new integrations: visit the web dashboard or `runwork integrations search <query>`.');
181
+ lines.push('');
182
+ }
183
+ else if (!ctx.registries && ctx.connectedIntegrations.length > 0) {
184
+ // Show integrations even if registries unavailable
185
+ lines.push(`**Integrations:** ${formatList(ctx.connectedIntegrations)}`);
186
+ lines.push(' Use `{id}_api` MCP tools for authenticated API calls. CLI: `runwork integrations call <id> <method> <path>`');
187
+ lines.push('');
188
+ }
189
+ // Skills
190
+ if (ctx.skillCount > 0) {
191
+ if (ctx.skillNames && ctx.skillNames.length > 0) {
192
+ lines.push(`**Skills (${ctx.skillCount}):** ${formatList(ctx.skillNames)}`);
193
+ }
194
+ else {
195
+ lines.push(`**Skills:** ${ctx.skillCount} skill${ctx.skillCount !== 1 ? 's' : ''} configured`);
196
+ }
197
+ lines.push('');
198
+ }
199
+ // MCP Servers
200
+ if (ctx.mcpServerCount > 0) {
201
+ if (ctx.mcpServerNames && ctx.mcpServerNames.length > 0) {
202
+ lines.push(`**MCP Servers (${ctx.mcpServerCount}):** ${formatList(ctx.mcpServerNames)}`);
203
+ }
204
+ else {
205
+ lines.push(`**MCP Servers:** ${ctx.mcpServerCount} server${ctx.mcpServerCount !== 1 ? 's' : ''} configured`);
206
+ }
207
+ lines.push('');
208
+ }
209
+ // MCP Tools Reference section
210
+ lines.push('## MCP Tools Reference');
211
+ lines.push('');
212
+ lines.push('The Runwork MCP server is connected to this agent. These tools work in any environment:');
213
+ lines.push('');
214
+ lines.push('| Category | Tools | Use for |');
215
+ lines.push('|----------|-------|---------|');
216
+ lines.push('| Integration APIs | `{integrationId}_api` | Authenticated API calls to connected services (HubSpot, Slack, Google, etc.). Pass method and path. |');
217
+ lines.push('| Entity Data | `entity_list_{Name}`, `entity_get_{Name}`, `entity_create_{Name}`, `query_entity_data` | CRUD operations on stored data |');
218
+ lines.push('| Endpoints | `endpoint_{method}_{path}` | Call app API endpoints |');
219
+ lines.push('| Workflows | `trigger_workflow`, `list_workflows`, `get_workflow_instance` | Trigger and monitor multi-step processes |');
220
+ lines.push('| Schedules | `trigger_schedule`, `list_schedules`, `get_schedule_status` | Trigger and monitor background jobs |');
221
+ lines.push('| File Storage | `list_bucket_files`, `generate_user_presigned_url`, `delete_bucket_object` | Manage files in storage buckets |');
222
+ lines.push('| Discovery | `search_available_integrations`, `list_integrations`, `list_entities`, `list_apps` | Find available resources and capabilities |');
223
+ lines.push('| Logs | `get_production_logs`, `get_sandbox_logs` | View app logs and debug issues |');
224
+ lines.push('');
225
+ // CLI section
226
+ lines.push('## CLI');
227
+ lines.push('');
228
+ lines.push('The `runwork` CLI is the primary tool for building and deploying Runwork apps.');
229
+ lines.push('');
230
+ lines.push('**Finding the CLI:**');
231
+ lines.push('1. Check if already installed: `which runwork` or `runwork --version`');
232
+ lines.push('2. If installed via the Runwork Desktop app, the binary may be at `~/.runwork/bin/runwork`. Try: `~/.runwork/bin/runwork --version`');
233
+ lines.push('3. To install: `curl -fsSL https://runwork.ai/install.sh | sh` or `npm install -g runwork`');
234
+ lines.push('');
235
+ lines.push('**Key commands:**');
236
+ lines.push('');
237
+ lines.push('| Command | Description |');
238
+ lines.push('|---------|-------------|');
239
+ lines.push('| `runwork info --json` | Full workspace and app context |');
240
+ lines.push('| `runwork init my-app` | Create a new app |');
241
+ lines.push('| `runwork dev` | Start local development (watches files, syncs automatically) |');
242
+ lines.push('| `runwork deploy` | Deploy to production |');
243
+ lines.push('| `runwork entities list` | Browse data across apps |');
244
+ lines.push('| `runwork entities records <name>` | Query entity records |');
245
+ lines.push('| `runwork workflows trigger <name>` | Trigger a workflow |');
246
+ lines.push('| `runwork integrations call <id> <method> <path>` | Call an integration API |');
247
+ lines.push('| `runwork integrations search <query>` | Search 3,200+ available integrations |');
248
+ lines.push('| `runwork logs` | View app logs |');
249
+ lines.push('| `runwork doctor` | Check system health |');
250
+ lines.push('| `runwork setup` | Set up workspace connection and sync to agents |');
251
+ lines.push('| `runwork sync` | Sync skills, MCP servers, and settings to local agents |');
252
+ lines.push('');
253
+ // Building Infrastructure section
254
+ lines.push('## Building Apps');
255
+ lines.push('');
256
+ lines.push('When you need persistent data, background jobs, workflows, public APIs, AI agents, or third-party integrations, create a Runwork app.');
257
+ lines.push('');
258
+ lines.push('**Options:**');
259
+ lines.push('- **With CLI:** `runwork init my-app`, then develop locally with `runwork dev` and deploy with `runwork deploy`');
260
+ lines.push('- **With web dashboard:** Go to https://runwork.ai, create an app, and use the built-in AI agent to build it conversationally');
261
+ lines.push('- **With desktop app:** The desktop app provides quick access to create and manage apps');
262
+ lines.push('');
263
+ lines.push('**CLI development workflow:**');
264
+ lines.push('1. `runwork init my-app` -- scaffold the app');
265
+ lines.push('2. `cd my-app` -- enter the app directory');
266
+ lines.push('3. `runwork dev` -- start development (watches for file changes, syncs automatically)');
267
+ lines.push('4. Edit files for your needs (see below)');
268
+ lines.push('5. `runwork deploy` -- deploy to production');
269
+ lines.push('');
270
+ lines.push('**What to edit:**');
271
+ lines.push('| Need | File |');
272
+ lines.push('|------|------|');
273
+ lines.push('| Persistent data | `worker/entities.ts` |');
274
+ lines.push('| Background cron jobs | `worker/schedules.ts` |');
275
+ lines.push('| Multi-step durable processes | `worker/workflows.ts` |');
276
+ lines.push('| Internal API endpoints | `worker/routes.ts` |');
277
+ lines.push('| Public/external APIs | `worker/endpoints.ts` |');
278
+ lines.push('| AI agents (chat or automation) | `worker/agents.ts` |');
279
+ lines.push('| Third-party integrations | `worker/integration-requirements.ts` |');
280
+ lines.push('| Shared types | `shared/types.ts` |');
281
+ lines.push('');
282
+ lines.push('**Key rules:**');
283
+ lines.push('- Read `CLAUDE.md` in the app directory first, it has complete framework docs.');
284
+ lines.push('- Do NOT install external AI SDKs. Use `@runworkai/framework/ai`.');
285
+ lines.push('- Every workflow needs a trigger (endpoint, schedule, or UI button).');
286
+ lines.push('- Use `search_available_integrations` MCP tool or `runwork integrations search <query>` before adding integrations, never guess IDs.');
287
+ lines.push('');
288
+ // Routing Preferences
289
+ lines.push('## When to Use Runwork');
290
+ lines.push('');
291
+ lines.push('| Need | Use Runwork | Don\'t use Runwork |');
292
+ lines.push('|------|------------|-------------------|');
293
+ lines.push('| Store structured data | Apps with entities | Local files, in-memory |');
294
+ lines.push('| Store files | Apps with file storage | Local filesystem |');
295
+ lines.push('| Schedule recurring tasks | Apps with scheduled jobs | Native cron, OS schedulers |');
296
+ lines.push('| Multi-step business processes | Apps with workflows | Ad-hoc scripts |');
297
+ lines.push('| Third-party service access | Connected integrations (use `{id}_api` MCP tool or CLI, no app needed) | Direct API calls without auth management |');
298
+ lines.push('| AI chat or automation | Apps with agents | Standalone AI scripts |');
299
+ lines.push('| Share AI expertise | Skills | One-off prompts |');
300
+ lines.push('| Connect AI tools | MCP servers | Manual tool configuration |');
301
+ lines.push('| Expose APIs externally | Apps with public endpoints | Standalone servers |');
302
+ lines.push('| Reuse across projects | Apps with components | Copy-paste between repos |');
303
+ lines.push('| Team collaboration | Workspace apps, shared skills | Isolated local tools |');
304
+ lines.push('');
305
+ lines.push('**When NOT to use Runwork:** Normal development in your current codebase (editing files, running tests, git operations, building features in the product you\'re working on). Runwork is for infrastructure and team tooling.');
306
+ lines.push('');
307
+ // Helping the user section
308
+ lines.push('## Helping the User');
309
+ lines.push('');
310
+ lines.push('If the user asks about Runwork setup, integrations, or getting started:');
311
+ lines.push('');
312
+ lines.push('- **Install CLI:** `curl -fsSL https://runwork.ai/install.sh | sh` (macOS/Linux) or `npm install -g runwork` (any platform)');
313
+ lines.push('- **Desktop app:** Download from https://runwork.ai (includes bundled CLI at `~/.runwork/bin/runwork`)');
314
+ lines.push('- **Connect workspace:** `runwork login` then `runwork setup`');
315
+ lines.push('- **Connect an integration:** Visit the workspace settings in the web dashboard at https://runwork.ai, or use `runwork integrations search <query>` to find services');
316
+ lines.push('- **Web dashboard:** https://runwork.ai for visual management of everything');
317
+ lines.push('- **Troubleshoot:** `runwork doctor` checks system health; `runwork logs` shows app output');
318
+ lines.push('');
319
+ // References
320
+ lines.push('### References');
321
+ lines.push('');
322
+ lines.push('- Web dashboard: https://runwork.ai');
323
+ lines.push('- Changelog: https://www.runwork.ai/changelog');
324
+ lines.push('- Agent documentation: https://www.runwork.ai/for/agents/');
325
+ return {
326
+ name: 'runwork',
327
+ filename: 'runwork',
328
+ content: lines.join('\n'),
329
+ description: 'Your team\'s shared infrastructure platform. Use for: data & file storage, scheduling, background jobs, workflows, integrations (Slack, GitHub, etc.), AI agents, skills, MCP servers, public APIs, and reusable components. Invoke BEFORE using native alternatives for these capabilities. Interact via MCP tools (always available), CLI, web dashboard, desktop app, or API.',
330
+ };
331
+ }
332
+ /**
333
+ * Generate the minimal instruction hint that goes into agent instruction files.
334
+ * Uses HTML comment delimiters so it can be found and replaced on sync.
335
+ */
336
+ export function generateInstructionHint(ctx) {
337
+ const inventory = buildInventoryLine(ctx);
338
+ const integrationToolHint = ctx.connectedIntegrations.length > 0
339
+ ? ` Connected integrations are callable via MCP tools (${ctx.connectedIntegrations.map(id => `\`${id}_api\``).join(', ')}) or CLI (\`runwork integrations call <id> <method> <path>\`).`
340
+ : '';
341
+ const dashboardUrl = ctx.workspaceSlug ? `https://${ctx.workspaceSlug}.runwork.ai` : 'https://runwork.ai';
342
+ const workspaceIdLine = `Workspace ID: \`${ctx.workspaceId}\`${ctx.workspaceSlug ? ` | Dashboard: ${dashboardUrl}` : ''}`;
343
+ return [
344
+ '<!-- runwork:start -->',
345
+ '## Runwork',
346
+ '',
347
+ `This machine is connected to the **${ctx.workspaceName}** Runwork workspace -- your team's shared platform for building and running infrastructure: apps, data & file storage, scheduled jobs, workflows, integrations, AI agents, skills, MCP servers, public APIs, and reusable components.`,
348
+ '',
349
+ workspaceIdLine,
350
+ '',
351
+ '**Routing:** For data storage, file storage, scheduling, workflows, integrations, AI agents, automation, skills, or shared team tools -- use Runwork first. Invoke the `runwork` skill before building these from scratch or using native/built-in alternatives. This does NOT apply to normal development in your current codebase -- Runwork is for infrastructure and team tooling, not for modifying the product you\'re working on.',
352
+ '',
353
+ `**Available now:** ${inventory}`,
354
+ '',
355
+ `Use Runwork MCP tools for data access, integration API calls, and resource management (always available).${integrationToolHint} Use \`runwork\` CLI to create (\`runwork init\`), develop (\`runwork dev\`), and deploy (\`runwork deploy\`) apps. Install CLI: \`curl -fsSL https://runwork.ai/install.sh | sh\`. Web dashboard: ${dashboardUrl}. Use the \`runwork\` skill for full details.`,
356
+ '<!-- runwork:end -->',
357
+ ].join('\n');
358
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared agent registry data.
3
+ *
4
+ * Source of truth: packages/runwork-desktop/src/lib/agent-registry.ts
5
+ * When adding new agents, update both files.
6
+ *
7
+ * This is a data-only file -- no platform-specific helpers.
8
+ * The CLI uses Node's process.platform for detection.
9
+ */
10
+ export type AgentCategory = 'cli' | 'ide' | 'desktop' | 'extension';
11
+ /** Platform-specific string. Plain string = same on all platforms. */
12
+ export type PlatformString = string | {
13
+ default?: string;
14
+ macos?: string;
15
+ windows?: string;
16
+ linux?: string;
17
+ };
18
+ export interface AgentDetection {
19
+ method: 'binary' | 'path';
20
+ target: PlatformString;
21
+ }
22
+ export interface AgentDefinition {
23
+ slug: string;
24
+ name: string;
25
+ aliases?: string[];
26
+ description: string;
27
+ category: AgentCategory;
28
+ detection: AgentDetection;
29
+ /** Skill file directories relative to $HOME (global) or project root (project) */
30
+ skillsPaths?: {
31
+ global?: PlatformString;
32
+ project?: PlatformString;
33
+ };
34
+ /** MCP config file path relative to $HOME */
35
+ mcpConfigPath?: PlatformString;
36
+ /** First-class agent = full Runwork support (custom adapter) */
37
+ firstClass?: boolean;
38
+ /** Instruction file path relative to $HOME (global) or project root (project) */
39
+ instructionFile?: {
40
+ global?: PlatformString;
41
+ project?: PlatformString;
42
+ };
43
+ /** MCP config JSON key where servers are stored (default: 'mcpServers') */
44
+ mcpConfigKey?: string;
45
+ /** Skill file format */
46
+ skillFormat?: 'skill-md' | 'mdc' | 'windsurf-md' | 'gemini-flat';
47
+ }
48
+ export declare function resolvePlatformString(ps: PlatformString): string | undefined;
49
+ export declare function resolveToAbsolute(ps: PlatformString, scope: 'global' | 'project'): string | undefined;
50
+ export declare function getRegistryAgent(slug: string): AgentDefinition | undefined;
51
+ export declare function getRegistryAgents(): AgentDefinition[];
52
+ export declare function getFirstClassSlugs(): string[];
53
+ export declare function getCustomAdapterSlugs(): Set<string>;
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Shared agent registry data.
3
+ *
4
+ * Source of truth: packages/runwork-desktop/src/lib/agent-registry.ts
5
+ * When adding new agents, update both files.
6
+ *
7
+ * This is a data-only file -- no platform-specific helpers.
8
+ * The CLI uses Node's process.platform for detection.
9
+ */
10
+ import { platform, homedir } from 'os';
11
+ import { join } from 'path';
12
+ function getNodePlatform() {
13
+ const p = platform();
14
+ if (p === 'darwin')
15
+ return 'macos';
16
+ if (p === 'win32')
17
+ return 'windows';
18
+ return 'linux';
19
+ }
20
+ export function resolvePlatformString(ps) {
21
+ if (typeof ps === 'string')
22
+ return ps;
23
+ const p = getNodePlatform();
24
+ return ps[p] ?? ps.default;
25
+ }
26
+ export function resolveToAbsolute(ps, scope) {
27
+ const resolved = resolvePlatformString(ps);
28
+ if (!resolved)
29
+ return undefined;
30
+ return scope === 'global'
31
+ ? join(homedir(), resolved)
32
+ : join(process.cwd(), resolved);
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // Registry
36
+ // ---------------------------------------------------------------------------
37
+ const AGENT_REGISTRY = [
38
+ // === First-class agents (have custom adapters in CLI) ===
39
+ {
40
+ slug: 'claude-code',
41
+ name: 'Claude Code',
42
+ description: "Anthropic's AI coding agent for the terminal",
43
+ category: 'cli',
44
+ detection: { method: 'binary', target: 'claude' },
45
+ skillsPaths: { global: '.claude/skills', project: '.claude/skills' },
46
+ mcpConfigPath: '.claude/settings.json',
47
+ instructionFile: { global: '.claude/CLAUDE.md', project: '.claude/CLAUDE.md' },
48
+ mcpConfigKey: 'mcpServers',
49
+ firstClass: true,
50
+ },
51
+ {
52
+ slug: 'claude-desktop',
53
+ name: 'Claude Desktop',
54
+ aliases: ['Claude Desktop (Cowork)', 'Cowork'],
55
+ description: 'Claude as a desktop application',
56
+ category: 'desktop',
57
+ detection: {
58
+ method: 'path',
59
+ target: {
60
+ macos: 'Library/Application Support/Claude/claude_desktop_config.json',
61
+ windows: 'AppData/Roaming/Claude/claude_desktop_config.json',
62
+ linux: '.config/Claude/claude_desktop_config.json',
63
+ },
64
+ },
65
+ skillsPaths: { global: '.claude/skills', project: '.claude/skills' },
66
+ mcpConfigPath: {
67
+ macos: 'Library/Application Support/Claude/claude_desktop_config.json',
68
+ windows: 'AppData/Roaming/Claude/claude_desktop_config.json',
69
+ linux: '.config/Claude/claude_desktop_config.json',
70
+ },
71
+ mcpConfigKey: 'mcpServers',
72
+ firstClass: true,
73
+ },
74
+ {
75
+ slug: 'cursor',
76
+ name: 'Cursor',
77
+ description: 'AI-powered code editor',
78
+ category: 'ide',
79
+ detection: { method: 'binary', target: 'cursor' },
80
+ skillsPaths: { global: '.cursor/skills', project: '.cursor/skills' },
81
+ mcpConfigPath: '.cursor/mcp.json',
82
+ instructionFile: { project: '.cursor/rules/runwork.mdc' },
83
+ mcpConfigKey: 'mcpServers',
84
+ skillFormat: 'mdc',
85
+ firstClass: true,
86
+ },
87
+ {
88
+ slug: 'codex',
89
+ name: 'Codex CLI',
90
+ description: "OpenAI's AI coding agent for the terminal",
91
+ category: 'cli',
92
+ detection: { method: 'binary', target: 'codex' },
93
+ skillsPaths: { global: '.codex/skills', project: '.agents/skills' },
94
+ instructionFile: { global: '.codex/instructions.md', project: 'AGENTS.md' },
95
+ firstClass: true,
96
+ },
97
+ {
98
+ slug: 'windsurf',
99
+ name: 'Windsurf',
100
+ description: 'AI-powered code editor by Codeium',
101
+ category: 'ide',
102
+ detection: { method: 'binary', target: 'windsurf' },
103
+ skillsPaths: { global: '.codeium/windsurf/skills', project: '.windsurf/skills' },
104
+ mcpConfigPath: '.codeium/windsurf/mcp_config.json',
105
+ instructionFile: { global: '.codeium/windsurf/rules/runwork.md', project: '.windsurf/rules/runwork.md' },
106
+ mcpConfigKey: 'mcpServers',
107
+ skillFormat: 'windsurf-md',
108
+ firstClass: true,
109
+ },
110
+ {
111
+ slug: 'gemini',
112
+ name: 'Gemini CLI',
113
+ description: "Google's AI coding agent for the terminal",
114
+ category: 'cli',
115
+ detection: { method: 'binary', target: 'gemini' },
116
+ skillsPaths: { global: '.gemini/skills', project: '.gemini/skills' },
117
+ mcpConfigPath: '.gemini/settings.json',
118
+ instructionFile: { global: '.gemini/GEMINI.md', project: 'GEMINI.md' },
119
+ mcpConfigKey: 'mcpServers',
120
+ firstClass: true,
121
+ },
122
+ // === Additional agents with some custom handling ===
123
+ {
124
+ slug: 'copilot-vscode',
125
+ name: 'GitHub Copilot (VS Code)',
126
+ description: "GitHub's AI pair programmer in VS Code",
127
+ category: 'extension',
128
+ detection: { method: 'binary', target: 'code' },
129
+ skillsPaths: { global: '.copilot/skills', project: '.github/skills' },
130
+ mcpConfigPath: '.vscode/mcp.json',
131
+ mcpConfigKey: 'servers',
132
+ },
133
+ {
134
+ slug: 'cline',
135
+ name: 'Cline',
136
+ description: 'Autonomous AI coding agent for VS Code',
137
+ category: 'extension',
138
+ detection: { method: 'binary', target: 'cline' },
139
+ skillsPaths: { global: '.agents/skills', project: '.agents/skills' },
140
+ },
141
+ {
142
+ slug: 'copilot-cli',
143
+ name: 'GitHub Copilot CLI',
144
+ description: 'GitHub Copilot in the terminal',
145
+ category: 'cli',
146
+ detection: { method: 'binary', target: 'gh' },
147
+ skillsPaths: { global: '.copilot/skills', project: '.github/skills' },
148
+ mcpConfigPath: '.copilot/mcp-config.json',
149
+ mcpConfigKey: 'mcpServers',
150
+ },
151
+ // === Community agents (from skillshare targets.yaml) ===
152
+ { slug: 'antigravity', name: 'Antigravity', description: "Google's Antigravity AI agent", category: 'cli', detection: { method: 'binary', target: 'antigravity' }, skillsPaths: { global: '.gemini/antigravity/skills', project: '.agent/skills' } },
153
+ { slug: 'amp', name: 'Amp', description: 'AI coding agent by Sourcegraph', category: 'cli', detection: { method: 'binary', target: 'amp' }, skillsPaths: { global: '.config/agents/skills', project: '.agents/skills' } },
154
+ { slug: 'adal', name: 'AdaL', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'adal' }, skillsPaths: { global: '.adal/skills', project: '.adal/skills' } },
155
+ { slug: 'astrbot', name: 'AstrBot', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'astrbot' }, skillsPaths: { global: '.astrbot/data/skills', project: 'data/skills' } },
156
+ { slug: 'augment', name: 'Augment', description: 'AI coding assistant', category: 'ide', detection: { method: 'binary', target: 'augment' }, skillsPaths: { global: '.augment/skills', project: '.augment/skills' } },
157
+ { slug: 'bob', name: 'Bob', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'bob' }, skillsPaths: { global: '.bob/skills', project: '.bob/skills' } },
158
+ { slug: 'codebuddy', name: 'CodeBuddy', description: 'AI coding assistant', category: 'cli', detection: { method: 'binary', target: 'codebuddy' }, skillsPaths: { global: '.codebuddy/skills', project: '.codebuddy/skills' } },
159
+ { slug: 'comate', name: 'Comate', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'comate' }, skillsPaths: { global: '.comate/skills', project: '.comate/skills' } },
160
+ { slug: 'commandcode', name: 'Command Code', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'commandcode' }, skillsPaths: { global: '.commandcode/skills', project: '.commandcode/skills' } },
161
+ { slug: 'continue', name: 'Continue', description: 'Open-source AI code assistant', category: 'extension', detection: { method: 'binary', target: 'continue' }, skillsPaths: { global: '.continue/skills', project: '.continue/skills' } },
162
+ { slug: 'cortex', name: 'Cortex', description: "Snowflake's AI coding agent", category: 'cli', detection: { method: 'binary', target: 'cortex' }, skillsPaths: { global: '.snowflake/cortex/skills', project: '.cortex/skills' } },
163
+ { slug: 'crush', name: 'Crush', description: 'AI agent by Charm', category: 'cli', detection: { method: 'binary', target: 'crush' }, skillsPaths: { global: '.config/crush/skills', project: '.crush/skills' } },
164
+ { slug: 'deepagents', name: 'Deep Agents', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'deepagents' }, skillsPaths: { global: '.deepagents/agent/skills', project: '.deepagents/skills' } },
165
+ { slug: 'droid', name: 'Droid', description: "Factory AI's coding agent", category: 'cli', detection: { method: 'binary', target: 'droid' }, skillsPaths: { global: '.factory/skills', project: '.factory/skills' } },
166
+ { slug: 'firebender', name: 'Firebender', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'firebender' }, skillsPaths: { global: '.firebender/skills', project: '.firebender/skills' } },
167
+ { slug: 'goose', name: 'Goose', description: 'AI coding agent by Block', category: 'cli', detection: { method: 'binary', target: 'goose' }, skillsPaths: { global: '.config/goose/skills', project: '.goose/skills' } },
168
+ { slug: 'hermes', name: 'Hermes', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'hermes' }, skillsPaths: { global: '.hermes/skills', project: '.hermes/skills' } },
169
+ { slug: 'iflow', name: 'iFlow CLI', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'iflow' }, skillsPaths: { global: '.iflow/skills', project: '.iflow/skills' } },
170
+ { slug: 'junie', name: 'Junie', description: 'JetBrains AI coding agent', category: 'ide', detection: { method: 'binary', target: 'junie' }, skillsPaths: { global: '.junie/skills', project: '.junie/skills' } },
171
+ { slug: 'kilocode', name: 'Kilo Code', description: 'AI coding agent', category: 'extension', detection: { method: 'binary', target: 'kilocode' }, skillsPaths: { global: '.kilocode/skills', project: '.kilocode/skills' } },
172
+ { slug: 'kimi', name: 'Kimi Code CLI', description: "Moonshot AI's coding agent", category: 'cli', detection: { method: 'binary', target: 'kimi' }, skillsPaths: { global: '.config/agents/skills', project: '.agents/skills' } },
173
+ { slug: 'kiro', name: 'Kiro', description: "AWS's AI coding agent", category: 'ide', detection: { method: 'binary', target: 'kiro' }, skillsPaths: { global: '.kiro/skills', project: '.kiro/skills' } },
174
+ { slug: 'kode', name: 'Kode', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'kode' }, skillsPaths: { global: '.kode/skills', project: '.kode/skills' } },
175
+ { slug: 'letta', name: 'Letta', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'letta' }, skillsPaths: { global: '.letta/skills', project: '.skills' } },
176
+ { slug: 'lingma', name: 'Lingma', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'lingma' }, skillsPaths: { global: '.lingma/skills', project: '.lingma/skills' } },
177
+ { slug: 'mcpjam', name: 'MCPJam', description: 'MCP-based AI agent', category: 'cli', detection: { method: 'binary', target: 'mcpjam' }, skillsPaths: { global: '.mcpjam/skills', project: '.mcpjam/skills' } },
178
+ { slug: 'mux', name: 'Mux', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'mux' }, skillsPaths: { global: '.mux/skills', project: '.mux/skills' } },
179
+ { slug: 'neovate', name: 'Neovate', description: 'AI coding agent for Neovim', category: 'extension', detection: { method: 'binary', target: 'neovate' }, skillsPaths: { global: '.neovate/skills', project: '.neovate/skills' } },
180
+ { slug: 'omp', name: 'Oh My Pi', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'omp' }, skillsPaths: { global: '.omp/agent/skills', project: '.omp/skills' } },
181
+ { slug: 'openclaw', name: 'OpenClaw', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'openclaw' }, skillsPaths: { global: '.openclaw/skills', project: 'skills' } },
182
+ { slug: 'opencode', name: 'OpenCode', description: 'Open-source AI coding agent', category: 'cli', detection: { method: 'binary', target: 'opencode' }, skillsPaths: { global: '.config/opencode/skills', project: '.opencode/skills' } },
183
+ { slug: 'openhands', name: 'OpenHands', description: 'Open-source AI coding agent', category: 'cli', detection: { method: 'binary', target: 'openhands' }, skillsPaths: { global: '.openhands/skills', project: '.openhands/skills' } },
184
+ { slug: 'pi', name: 'Pi', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'pi' }, skillsPaths: { global: '.pi/agent/skills', project: '.pi/skills' } },
185
+ { slug: 'pochi', name: 'Pochi', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'pochi' }, skillsPaths: { global: '.pochi/skills', project: '.pochi/skills' } },
186
+ { slug: 'purecode', name: 'PureCode AI', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'purecode' }, skillsPaths: { global: '.purecode/skills', project: '.agents/skills' } },
187
+ { slug: 'qoder', name: 'Qoder', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'qoder' }, skillsPaths: { global: '.qoder/skills', project: '.qoder/skills' } },
188
+ { slug: 'qwen', name: 'Qwen Code', description: "Alibaba's AI coding agent", category: 'cli', detection: { method: 'binary', target: 'qwen' }, skillsPaths: { global: '.qwen/skills', project: '.qwen/skills' } },
189
+ { slug: 'roo', name: 'Roo Code', description: 'AI coding agent', category: 'extension', detection: { method: 'binary', target: 'roo' }, skillsPaths: { global: '.roo/skills', project: '.roo/skills' } },
190
+ { slug: 'trae', name: 'Trae', description: 'ByteDance AI coding IDE', category: 'ide', detection: { method: 'binary', target: 'trae' }, skillsPaths: { global: '.trae/skills', project: '.trae/skills' } },
191
+ { slug: 'mistral-vibe', name: 'Mistral Vibe', description: "Mistral's AI coding agent", category: 'cli', detection: { method: 'binary', target: 'vibe' }, skillsPaths: { global: '.vibe/skills', project: '.vibe/skills' } },
192
+ { slug: 'verdent', name: 'Verdent', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'verdent' }, skillsPaths: { global: '.verdent/skills', project: '.verdent/skills' } },
193
+ { slug: 'warp', name: 'Warp AI', description: 'AI-powered terminal', category: 'cli', detection: { method: 'path', target: { macos: '/Applications/Warp.app', linux: '/usr/bin/warp-terminal' } }, skillsPaths: { global: '.agents/skills', project: '.agents/skills' } },
194
+ { slug: 'witsy', name: 'Witsy', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'witsy' }, skillsPaths: { global: '.agents/skills', project: '.agents/skills' } },
195
+ { slug: 'zencoder', name: 'Zencoder', description: 'AI coding agent', category: 'cli', detection: { method: 'binary', target: 'zencoder' }, skillsPaths: { global: '.zencoder/skills', project: '.zencoder/skills' } },
196
+ { slug: 'replit', name: 'Replit', description: 'AI-powered coding platform', category: 'ide', detection: { method: 'binary', target: 'replit' }, skillsPaths: { global: '.config/agents/skills', project: '.agents/skills' } },
197
+ ];
198
+ // ---------------------------------------------------------------------------
199
+ // Index (built once)
200
+ // ---------------------------------------------------------------------------
201
+ const slugIndex = new Map();
202
+ for (const agent of AGENT_REGISTRY) {
203
+ slugIndex.set(agent.slug, agent);
204
+ }
205
+ // ---------------------------------------------------------------------------
206
+ // Public API
207
+ // ---------------------------------------------------------------------------
208
+ export function getRegistryAgent(slug) {
209
+ return slugIndex.get(slug);
210
+ }
211
+ export function getRegistryAgents() {
212
+ return AGENT_REGISTRY;
213
+ }
214
+ export function getFirstClassSlugs() {
215
+ return AGENT_REGISTRY.filter(a => a.firstClass).map(a => a.slug);
216
+ }
217
+ export function getCustomAdapterSlugs() {
218
+ return new Set(['claude-code', 'claude-desktop', 'cursor', 'windsurf', 'codex', 'cline', 'gemini']);
219
+ }