@gracefultools/astrid-sdk 0.7.15 → 0.8.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 (115) hide show
  1. package/README.md +127 -341
  2. package/dist/channel/channel.d.ts +33 -0
  3. package/dist/channel/channel.d.ts.map +1 -0
  4. package/dist/channel/channel.js +90 -0
  5. package/dist/channel/channel.js.map +1 -0
  6. package/dist/channel/index.d.ts +13 -0
  7. package/dist/channel/index.d.ts.map +1 -0
  8. package/dist/channel/index.js +23 -0
  9. package/dist/channel/index.js.map +1 -0
  10. package/dist/channel/message-formatter.d.ts +14 -0
  11. package/dist/channel/message-formatter.d.ts.map +1 -0
  12. package/dist/channel/message-formatter.js +71 -0
  13. package/dist/channel/message-formatter.js.map +1 -0
  14. package/dist/channel/oauth-client.d.ts +15 -0
  15. package/dist/channel/oauth-client.d.ts.map +1 -0
  16. package/dist/channel/oauth-client.js +45 -0
  17. package/dist/channel/oauth-client.js.map +1 -0
  18. package/dist/channel/rest-client.d.ts +16 -0
  19. package/dist/channel/rest-client.d.ts.map +1 -0
  20. package/dist/channel/rest-client.js +66 -0
  21. package/dist/channel/rest-client.js.map +1 -0
  22. package/dist/channel/session-mapper.d.ts +14 -0
  23. package/dist/channel/session-mapper.d.ts.map +1 -0
  24. package/dist/channel/session-mapper.js +37 -0
  25. package/dist/channel/session-mapper.js.map +1 -0
  26. package/dist/channel/sse-client.d.ts +31 -0
  27. package/dist/channel/sse-client.d.ts.map +1 -0
  28. package/dist/channel/sse-client.js +171 -0
  29. package/dist/channel/sse-client.js.map +1 -0
  30. package/dist/channel/types.d.ts +65 -0
  31. package/dist/channel/types.d.ts.map +1 -0
  32. package/dist/channel/types.js +3 -0
  33. package/dist/channel/types.js.map +1 -0
  34. package/dist/config/agent-workflow.js +7 -7
  35. package/dist/index.d.ts +1 -8
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +16 -30
  38. package/dist/index.js.map +1 -1
  39. package/dist/types/index.d.ts +1 -1
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/utils/agent-config.d.ts.map +1 -1
  42. package/dist/utils/agent-config.js +14 -0
  43. package/dist/utils/agent-config.js.map +1 -1
  44. package/openclaw.plugin.json +25 -0
  45. package/package.json +66 -77
  46. package/templates/.astrid.config.json +60 -60
  47. package/templates/ASTRID.template.md +74 -74
  48. package/dist/bin/cli.d.ts +0 -14
  49. package/dist/bin/cli.d.ts.map +0 -1
  50. package/dist/bin/cli.js +0 -1610
  51. package/dist/bin/cli.js.map +0 -1
  52. package/dist/executors/claude.d.ts +0 -65
  53. package/dist/executors/claude.d.ts.map +0 -1
  54. package/dist/executors/claude.js +0 -838
  55. package/dist/executors/claude.js.map +0 -1
  56. package/dist/executors/gemini.d.ts +0 -23
  57. package/dist/executors/gemini.d.ts.map +0 -1
  58. package/dist/executors/gemini.js +0 -558
  59. package/dist/executors/gemini.js.map +0 -1
  60. package/dist/executors/openai.d.ts +0 -17
  61. package/dist/executors/openai.d.ts.map +0 -1
  62. package/dist/executors/openai.js +0 -614
  63. package/dist/executors/openai.js.map +0 -1
  64. package/dist/executors/shared/index.d.ts +0 -9
  65. package/dist/executors/shared/index.d.ts.map +0 -1
  66. package/dist/executors/shared/index.js +0 -21
  67. package/dist/executors/shared/index.js.map +0 -1
  68. package/dist/executors/shared/tool-executor.d.ts +0 -52
  69. package/dist/executors/shared/tool-executor.d.ts.map +0 -1
  70. package/dist/executors/shared/tool-executor.js +0 -262
  71. package/dist/executors/shared/tool-executor.js.map +0 -1
  72. package/dist/executors/shared/tool-schemas.d.ts +0 -61
  73. package/dist/executors/shared/tool-schemas.d.ts.map +0 -1
  74. package/dist/executors/shared/tool-schemas.js +0 -135
  75. package/dist/executors/shared/tool-schemas.js.map +0 -1
  76. package/dist/executors/terminal-base.d.ts +0 -207
  77. package/dist/executors/terminal-base.d.ts.map +0 -1
  78. package/dist/executors/terminal-base.js +0 -552
  79. package/dist/executors/terminal-base.js.map +0 -1
  80. package/dist/executors/terminal-claude.d.ts +0 -116
  81. package/dist/executors/terminal-claude.d.ts.map +0 -1
  82. package/dist/executors/terminal-claude.js +0 -700
  83. package/dist/executors/terminal-claude.js.map +0 -1
  84. package/dist/executors/terminal-executors.test.d.ts +0 -8
  85. package/dist/executors/terminal-executors.test.d.ts.map +0 -1
  86. package/dist/executors/terminal-executors.test.js +0 -469
  87. package/dist/executors/terminal-executors.test.js.map +0 -1
  88. package/dist/executors/terminal-gemini.d.ts +0 -50
  89. package/dist/executors/terminal-gemini.d.ts.map +0 -1
  90. package/dist/executors/terminal-gemini.js +0 -401
  91. package/dist/executors/terminal-gemini.js.map +0 -1
  92. package/dist/executors/terminal-openai.d.ts +0 -50
  93. package/dist/executors/terminal-openai.d.ts.map +0 -1
  94. package/dist/executors/terminal-openai.js +0 -405
  95. package/dist/executors/terminal-openai.js.map +0 -1
  96. package/dist/server/astrid-client.d.ts +0 -77
  97. package/dist/server/astrid-client.d.ts.map +0 -1
  98. package/dist/server/astrid-client.js +0 -125
  99. package/dist/server/astrid-client.js.map +0 -1
  100. package/dist/server/index.d.ts +0 -38
  101. package/dist/server/index.d.ts.map +0 -1
  102. package/dist/server/index.js +0 -408
  103. package/dist/server/index.js.map +0 -1
  104. package/dist/server/repo-manager.d.ts +0 -41
  105. package/dist/server/repo-manager.d.ts.map +0 -1
  106. package/dist/server/repo-manager.js +0 -177
  107. package/dist/server/repo-manager.js.map +0 -1
  108. package/dist/server/session-manager.d.ts +0 -93
  109. package/dist/server/session-manager.d.ts.map +0 -1
  110. package/dist/server/session-manager.js +0 -217
  111. package/dist/server/session-manager.js.map +0 -1
  112. package/dist/server/webhook-signature.d.ts +0 -23
  113. package/dist/server/webhook-signature.d.ts.map +0 -1
  114. package/dist/server/webhook-signature.js +0 -74
  115. package/dist/server/webhook-signature.js.map +0 -1
package/README.md CHANGED
@@ -1,341 +1,127 @@
1
- # @gracefultools/astrid-sdk
2
-
3
- AI agent SDK for automated coding tasks with Claude, OpenAI, and Gemini.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install -g @gracefultools/astrid-sdk
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ### Three Execution Modes
14
-
15
- | Mode | Command | Best For |
16
- |------|---------|----------|
17
- | **API** | `npx astrid-agent` | Cloud execution via Claude Agent SDK API |
18
- | **Terminal** | `npx astrid-agent --terminal` | Local Claude Code CLI (remote control) |
19
- | **Webhook** | `npx astrid-agent serve` | Always-on servers (fly.io, VPS, AWS) |
20
-
21
- ### Terminal Mode (Remote Control Your Local Claude Code)
22
-
23
- Uses your local Claude Code CLI to process tasks. Enables remote control of your local Claude Code from Astrid.
24
-
25
- ```bash
26
- # Prerequisites: Install Claude Code CLI
27
- npm install -g @anthropic-ai/claude-code
28
-
29
- # Set up environment
30
- export ANTHROPIC_API_KEY=sk-ant-...
31
- export ASTRID_OAUTH_CLIENT_ID=your_client_id
32
- export ASTRID_OAUTH_CLIENT_SECRET=your_client_secret
33
- export ASTRID_OAUTH_LIST_ID=your_list_id
34
-
35
- # Start in terminal mode
36
- cd /your/project
37
- npx astrid-agent --terminal
38
-
39
- # With options
40
- npx astrid-agent --terminal --model=sonnet --cwd=/path/to/project --max-turns=100
41
-
42
- # Or via environment variable
43
- ASTRID_TERMINAL_MODE=true npx astrid-agent
44
- ```
45
-
46
- **How it works:**
47
- 1. Agent polls Astrid for tasks assigned to AI agents
48
- 2. When a task is found, it spawns the local Claude Code CLI with `--print`
49
- 3. Claude Code executes in your project directory
50
- 4. Results are posted back to Astrid as comments
51
- 5. Session IDs are stored for resumption support
52
-
53
- ### API Mode (Default)
54
-
55
- Uses Claude Agent SDK API for cloud execution. Best for CI/CD and servers.
56
-
57
- ```bash
58
- # Set up environment
59
- export ANTHROPIC_API_KEY=sk-ant-...
60
- export ASTRID_OAUTH_CLIENT_ID=your_client_id
61
- export ASTRID_OAUTH_CLIENT_SECRET=your_client_secret
62
- export ASTRID_OAUTH_LIST_ID=your_list_id
63
-
64
- # Start polling for tasks (API mode)
65
- npx astrid-agent
66
- ```
67
-
68
- ### Webhook Mode (For Always-On Servers)
69
-
70
- Receives instant task notifications via webhook. Requires a permanent IP or domain.
71
-
72
- ```bash
73
- # Set up environment
74
- export ANTHROPIC_API_KEY=sk-ant-...
75
- export ASTRID_WEBHOOK_SECRET=your_webhook_secret
76
-
77
- # Start webhook server
78
- npx astrid-agent serve --port=3001
79
-
80
- # Optional: Install express for the server
81
- npm install express
82
- ```
83
-
84
- Then configure your webhook URL in Astrid Settings.
85
-
86
- ## Environment Variables
87
-
88
- | Variable | Mode | Description |
89
- |----------|------|-------------|
90
- | **AI Providers** | All | |
91
- | `ANTHROPIC_API_KEY` | All | Anthropic API key (for Claude) |
92
- | `OPENAI_API_KEY` | All | OpenAI API key |
93
- | `GEMINI_API_KEY` | All | Google Gemini API key |
94
- | **Polling/Terminal Mode** | Polling, Terminal | |
95
- | `ASTRID_OAUTH_CLIENT_ID` | Polling, Terminal | OAuth client ID from Astrid |
96
- | `ASTRID_OAUTH_CLIENT_SECRET` | Polling, Terminal | OAuth client secret |
97
- | `ASTRID_OAUTH_LIST_ID` | Polling, Terminal | List ID to monitor for tasks |
98
- | **Terminal Mode** | Terminal | |
99
- | `ASTRID_TERMINAL_MODE` | Terminal | Enable terminal mode (or use --terminal flag) |
100
- | `CLAUDE_MODEL` | Terminal | Model to use (default: opus) |
101
- | `CLAUDE_MAX_TURNS` | Terminal | Max turns per execution (default: 50) |
102
- | `DEFAULT_PROJECT_PATH` | Terminal | Project directory (default: current dir) |
103
- | **Webhook Mode** | Webhook | |
104
- | `ASTRID_WEBHOOK_SECRET` | Webhook | Secret from Astrid webhook settings |
105
- | `ASTRID_CALLBACK_URL` | Webhook | Optional callback URL |
106
- | **Other** | All | |
107
- | `GITHUB_TOKEN` | All | GitHub token for cloning private repos |
108
- | `POLL_INTERVAL_MS` | Polling, Terminal | Poll interval (default: 30000) |
109
- | `MAX_BUDGET_USD` | API | Max budget per task (default: 10.0) |
110
- | **Agent Workflow** | Terminal | |
111
- | `ASTRID_AGENT_CREATE_BRANCH` | Terminal | Create feature branches (default: true) |
112
- | `ASTRID_AGENT_CREATE_PR` | Terminal | Create pull requests (default: true) |
113
- | `ASTRID_AGENT_BRANCH_PREFIX` | Terminal | Branch name prefix (default: "task/") |
114
- | `ASTRID_AGENT_RUN_TESTS` | Terminal | Run tests before committing (default: true) |
115
- | `ASTRID_AGENT_TEST_COMMAND` | Terminal | Test command (default: "npm run predeploy") |
116
- | **Vercel Deployment** | Terminal | |
117
- | `ASTRID_AGENT_VERCEL_DEPLOY` | Terminal | Trigger Vercel preview deployment (default: true) |
118
- | `ASTRID_AGENT_VERCEL_USE_API` | Terminal | Use Vercel API instead of CLI (default: false) |
119
- | `ASTRID_AGENT_PREVIEW_DOMAIN` | Terminal | Domain for preview aliases (e.g., "astrid.cc") |
120
- | `ASTRID_AGENT_PREVIEW_PATTERN` | Terminal | Subdomain pattern (default: "{branch}") |
121
- | `VERCEL_TOKEN` | Terminal | Vercel API token for deployments |
122
- | `VERCEL_PROJECT_NAME` | Terminal | Vercel project name (auto-detected) |
123
- | `VERCEL_TEAM_ID` | Terminal | Vercel team ID (optional) |
124
-
125
- ## Agent Workflow Configuration
126
-
127
- Control how AI agents create branches, PRs, and preview deployments via environment variables. No package update needed to change behavior.
128
-
129
- ### Example: Full PR + Preview Workflow (Recommended)
130
-
131
- ```bash
132
- # Git workflow
133
- export ASTRID_AGENT_CREATE_BRANCH=true # Create feature branches
134
- export ASTRID_AGENT_CREATE_PR=true # Create pull requests
135
- export ASTRID_AGENT_RUN_TESTS=true # Run tests before commit
136
-
137
- # Vercel preview deployment
138
- export ASTRID_AGENT_VERCEL_DEPLOY=true # Deploy to Vercel
139
- export ASTRID_AGENT_PREVIEW_DOMAIN=astrid.cc # Custom subdomain (for passkey support)
140
- export VERCEL_TOKEN=your-vercel-token # Required for deployment
141
- export GITHUB_TOKEN=your-github-token # Required for PR creation
142
- ```
143
-
144
- ### Example: Direct to Main (No PR)
145
-
146
- ```bash
147
- export ASTRID_AGENT_CREATE_BRANCH=false
148
- export ASTRID_AGENT_CREATE_PR=false
149
- export ASTRID_AGENT_VERCEL_DEPLOY=false
150
- ```
151
-
152
- ### Preview URL Configuration
153
-
154
- When `ASTRID_AGENT_PREVIEW_DOMAIN` is set (e.g., `astrid.cc`), preview URLs are aliased to subdomains:
155
-
156
- - Branch: `task/abc12345` → Preview URL: `https://task-abc12345.astrid.cc`
157
-
158
- This is required for features that need same-origin (passkeys, Google OAuth cookies).
159
-
160
- ### Programmatic Configuration
161
-
162
- ```typescript
163
- import {
164
- getAgentWorkflowConfig,
165
- validateWorkflowConfig,
166
- logWorkflowConfig,
167
- deployToVercel,
168
- } from '@gracefultools/astrid-sdk'
169
-
170
- // Get current config (reads from env)
171
- const config = getAgentWorkflowConfig()
172
-
173
- // Validate config
174
- const { valid, errors, warnings } = validateWorkflowConfig()
175
- if (!valid) {
176
- console.error('Config errors:', errors)
177
- }
178
-
179
- // Log config for debugging
180
- logWorkflowConfig()
181
-
182
- // Deploy to Vercel manually
183
- const result = await deployToVercel('task/abc12345', '/path/to/project')
184
- console.log('Preview URL:', result.previewUrl)
185
- ```
186
-
187
- ## Supported AI Providers
188
-
189
- The SDK automatically routes tasks to the correct provider based on the assignee email:
190
-
191
- | Agent Email | Provider | Model |
192
- |-------------|----------|-------|
193
- | `claude@astrid.cc` | Claude | claude-sonnet-4 |
194
- | `openai@astrid.cc` | OpenAI | gpt-4o |
195
- | `gemini@astrid.cc` | Gemini | gemini-2.0-flash |
196
-
197
- ## Deployment Examples
198
-
199
- ### Fly.io (Webhook Mode)
200
-
201
- ```toml
202
- # fly.toml
203
- app = "astrid-agent"
204
- primary_region = "iad"
205
-
206
- [http_service]
207
- internal_port = 3001
208
-
209
- [env]
210
- PORT = "3001"
211
- ```
212
-
213
- ```bash
214
- fly secrets set ANTHROPIC_API_KEY=sk-ant-...
215
- fly secrets set ASTRID_WEBHOOK_SECRET=...
216
- fly deploy
217
- ```
218
-
219
- ### Docker (Webhook Mode)
220
-
221
- ```dockerfile
222
- FROM node:20-slim
223
- RUN npm install -g @gracefultools/astrid-sdk express
224
- WORKDIR /app
225
- EXPOSE 3001
226
- CMD ["npx", "astrid-agent", "serve", "--port=3001"]
227
- ```
228
-
229
- ### PM2 (Polling Mode)
230
-
231
- ```bash
232
- # ecosystem.config.js
233
- module.exports = {
234
- apps: [{
235
- name: 'astrid-agent',
236
- script: 'npx',
237
- args: 'astrid-agent',
238
- env: {
239
- ANTHROPIC_API_KEY: 'sk-ant-...',
240
- ASTRID_OAUTH_CLIENT_ID: '...',
241
- ASTRID_OAUTH_CLIENT_SECRET: '...',
242
- ASTRID_OAUTH_LIST_ID: '...'
243
- }
244
- }]
245
- }
246
- ```
247
-
248
- ## Programmatic Usage
249
-
250
- ```typescript
251
- import {
252
- planWithClaude,
253
- executeWithClaude,
254
- AstridOAuthClient,
255
- } from '@gracefultools/astrid-sdk'
256
-
257
- // Connect to Astrid
258
- const client = new AstridOAuthClient({
259
- clientId: process.env.ASTRID_OAUTH_CLIENT_ID,
260
- clientSecret: process.env.ASTRID_OAUTH_CLIENT_SECRET,
261
- })
262
-
263
- // Get tasks
264
- const tasks = await client.getTasks(listId)
265
-
266
- // Plan implementation
267
- const planResult = await planWithClaude(
268
- task.title,
269
- task.description,
270
- {
271
- repoPath: '/path/to/repo',
272
- apiKey: process.env.ANTHROPIC_API_KEY,
273
- maxBudgetUsd: 5.0,
274
- logger: console.log,
275
- onProgress: (msg) => console.log(msg),
276
- }
277
- )
278
-
279
- // Execute the plan
280
- if (planResult.success && planResult.plan) {
281
- const execResult = await executeWithClaude(
282
- planResult.plan,
283
- task.title,
284
- task.description,
285
- config
286
- )
287
-
288
- console.log('Files modified:', execResult.files.length)
289
- }
290
- ```
291
-
292
- ## CLI Reference
293
-
294
- ```bash
295
- # Show help
296
- npx astrid-agent --help
297
-
298
- # API mode (default - cloud execution)
299
- npx astrid-agent
300
-
301
- # Terminal mode (local Claude Code CLI)
302
- npx astrid-agent --terminal
303
- npx astrid-agent --terminal --model=sonnet --cwd=/path/to/project
304
-
305
- # Process a specific task
306
- npx astrid-agent <taskId>
307
- npx astrid-agent --terminal <taskId>
308
-
309
- # Webhook mode
310
- npx astrid-agent serve --port=3001
311
- ```
312
-
313
- ## Comparison: Terminal vs API vs Webhook
314
-
315
- | Feature | Terminal | API | Webhook |
316
- |---------|----------|-----|---------|
317
- | Execution | Local CLI | Cloud API | Cloud API |
318
- | Requires Claude Code CLI | Yes | No | No |
319
- | Permanent IP needed | No | No | Yes |
320
- | Works behind NAT | Yes | Yes | No |
321
- | Session resume | Yes | No | No |
322
- | Task notification | ~30s poll | ~30s poll | Instant |
323
- | Best for | Local dev | CI/CD, servers | Always-on servers |
324
- | Project access | Local files | Clones repo | Clones repo |
325
-
326
- ## Updating
327
-
328
- ```bash
329
- # Update to latest version
330
- npm update -g @gracefultools/astrid-sdk
331
- ```
332
-
333
- ## License
334
-
335
- MIT
336
-
337
- ## Links
338
-
339
- - [Astrid](https://astrid.cc)
340
- - [Documentation](https://astrid.cc/docs)
341
- - [GitHub](https://github.com/Graceful-Tools/astrid-res-www)
1
+ # @gracefultools/astrid-sdk
2
+
3
+ SDK for integrating AI agents with [Astrid.cc](https://www.astrid.cc) task management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @gracefultools/astrid-sdk
9
+ ```
10
+
11
+ ## What's Included
12
+
13
+ ### OAuth API Client
14
+ Full Astrid REST API client with OAuth2 client_credentials flow:
15
+
16
+ ```typescript
17
+ import { AstridOAuthClient } from '@gracefultools/astrid-sdk'
18
+
19
+ const client = new AstridOAuthClient({
20
+ clientId: 'your-client-id',
21
+ clientSecret: 'your-client-secret',
22
+ })
23
+
24
+ // Get assigned tasks
25
+ const tasks = await client.getTasks({ completed: false })
26
+
27
+ // Post a comment
28
+ await client.addComment(taskId, 'Working on this now...')
29
+
30
+ // Complete a task
31
+ await client.updateTask(taskId, { completed: true })
32
+ ```
33
+
34
+ ### OpenClaw Channel Plugin
35
+ Connect [OpenClaw](https://openclaw.ai) to Astrid as a task channel. Your agent receives tasks via SSE (outbound connection — works behind NAT/firewalls):
36
+
37
+ ```typescript
38
+ import { AstridChannel, SSEClient, RestClient, SessionMapper, taskToMessage } from '@gracefultools/astrid-sdk'
39
+ ```
40
+
41
+ #### How it works
42
+
43
+ 1. Agent connects **outbound** to `astrid.cc/api/v1/agent/events` (SSE)
44
+ 2. When a task is assigned → agent receives it in real-time
45
+ 3. **List description = agent instructions** — each list's description tells the agent how to handle tasks
46
+ 4. Agent posts results as task comments
47
+ 5. Agent marks task complete when done
48
+
49
+ #### Quick Setup
50
+
51
+ Add to your OpenClaw config:
52
+
53
+ ```json5
54
+ {
55
+ channels: {
56
+ astrid: {
57
+ enabled: true,
58
+ clientId: "your-client-id",
59
+ clientSecret: "your-client-secret"
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### Agent Protocol
66
+
67
+ The SDK uses the Astrid Agent Protocol:
68
+
69
+ | Endpoint | Method | Description |
70
+ |----------|--------|-------------|
71
+ | `/api/v1/agent/events` | GET | SSE stream (task.assigned, task.commented, etc.) |
72
+ | `/api/v1/agent/tasks` | GET | List assigned tasks |
73
+ | `/api/v1/agent/tasks/:id` | GET/PATCH | Get or update a task |
74
+ | `/api/v1/agent/tasks/:id/comments` | GET/POST | Read or post comments |
75
+
76
+ All endpoints require OAuth Bearer token with appropriate scopes.
77
+
78
+ ### List Descriptions as Agent Instructions
79
+
80
+ Each Astrid list's **description** field serves as instructions for AI agents:
81
+
82
+ ```markdown
83
+ # Example "Code Reviews" list description:
84
+ Review PRs for security issues, test coverage, and style.
85
+ Post findings as comments. Mark complete when done.
86
+ ```
87
+
88
+ When an agent receives a task from this list, the description is included as context. Different lists = different agent behaviors. No code changes needed.
89
+
90
+ ## Configuration
91
+
92
+ ### Agent Config
93
+ ```typescript
94
+ import { getAgentConfig, isRegisteredAgent } from '@gracefultools/astrid-sdk'
95
+
96
+ // Check if an email is a registered agent
97
+ isRegisteredAgent('claude@astrid.cc') // true
98
+ isRegisteredAgent('mybot.oc@astrid.cc') // true (OpenClaw pattern)
99
+
100
+ // Get agent configuration
101
+ const config = getAgentConfig('claude@astrid.cc')
102
+ ```
103
+
104
+ ### Workflow Config
105
+ ```typescript
106
+ import { getAgentWorkflowConfig, buildWorkflowInstructions } from '@gracefultools/astrid-sdk'
107
+
108
+ const config = getAgentWorkflowConfig(task, list, repository)
109
+ const instructions = buildWorkflowInstructions(config)
110
+ ```
111
+
112
+ ## Changelog
113
+
114
+ ### 0.8.0
115
+ - **Channel plugin**: OpenClaw integration via outbound SSE (no inbound gateway needed)
116
+ - **Agent protocol**: SSE events, REST client, session mapper, message formatter
117
+ - **Removed**: Built-in AI executors (Claude, OpenAI, Gemini) agents run externally now
118
+ - **Security**: Per-endpoint OAuth scope enforcement, comment rate limiting
119
+
120
+ ### 0.7.x
121
+ - OAuth API client
122
+ - Agent workflow configuration
123
+ - Vercel deployment support
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,33 @@
1
+ import type { AstridChannelConfig, InboundMessage, OutboundMessage } from './types.js';
2
+ /**
3
+ * Astrid channel plugin for OpenClaw.
4
+ */
5
+ export declare const astridChannel: {
6
+ id: "astrid";
7
+ meta: {
8
+ id: string;
9
+ label: string;
10
+ selectionLabel: string;
11
+ docsPath: string;
12
+ blurb: string;
13
+ };
14
+ capabilities: {
15
+ chatTypes: readonly ["direct"];
16
+ media: boolean;
17
+ reactions: boolean;
18
+ edit: boolean;
19
+ polls: boolean;
20
+ };
21
+ createAdapter(config: AstridChannelConfig): {
22
+ init(): Promise<void>;
23
+ connect(onMessage: (msg: InboundMessage) => void): Promise<void>;
24
+ disconnect(): Promise<void>;
25
+ send(msg: OutboundMessage): Promise<void>;
26
+ isConnected(): boolean;
27
+ getHealth(): {
28
+ connected: boolean;
29
+ activeSessions: number;
30
+ };
31
+ };
32
+ };
33
+ //# sourceMappingURL=channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channel/channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAOtF;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;0BAmBF,mBAAmB;gBAOvB,OAAO,CAAC,IAAI,CAAC;2BAaF,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;sBAyBlD,OAAO,CAAC,IAAI,CAAC;kBAIjB,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;uBAShC,OAAO;;;;;;CAY3B,CAAA"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.astridChannel = void 0;
4
+ const oauth_client_js_1 = require("./oauth-client.js");
5
+ const rest_client_js_1 = require("./rest-client.js");
6
+ const sse_client_js_1 = require("./sse-client.js");
7
+ const session_mapper_js_1 = require("./session-mapper.js");
8
+ const message_formatter_js_1 = require("./message-formatter.js");
9
+ /**
10
+ * Astrid channel plugin for OpenClaw.
11
+ */
12
+ exports.astridChannel = {
13
+ id: 'astrid',
14
+ meta: {
15
+ id: 'astrid',
16
+ label: 'Astrid',
17
+ selectionLabel: 'Astrid.cc',
18
+ docsPath: '/channels/astrid',
19
+ blurb: 'Task management',
20
+ },
21
+ capabilities: {
22
+ chatTypes: ['direct'],
23
+ media: false,
24
+ reactions: false,
25
+ edit: false,
26
+ polls: false,
27
+ },
28
+ createAdapter(config) {
29
+ const oauth = new oauth_client_js_1.OAuthClient(config);
30
+ const rest = new rest_client_js_1.RestClient(config.apiBase, oauth);
31
+ const sse = new sse_client_js_1.SSEClient(config, oauth);
32
+ const sessions = new session_mapper_js_1.SessionMapper();
33
+ return {
34
+ async init() {
35
+ if (!config.clientId || !config.clientSecret) {
36
+ throw new Error('Astrid channel: clientId and clientSecret are required');
37
+ }
38
+ await oauth.ensureToken();
39
+ // Recover existing sessions
40
+ const tasks = await rest.getAssignedTasks(false);
41
+ for (const task of tasks) {
42
+ sessions.getOrCreate(task.id);
43
+ }
44
+ },
45
+ async connect(onMessage) {
46
+ sse.on('task.assigned', (event) => {
47
+ if (!event.data.task)
48
+ return;
49
+ const msg = (0, message_formatter_js_1.taskToMessage)(event.data.task);
50
+ sessions.getOrCreate(event.data.taskId);
51
+ onMessage(msg);
52
+ });
53
+ sse.on('task.commented', (event) => {
54
+ const sessionKey = sessions.get(event.data.taskId);
55
+ if (!sessionKey || !event.data.comment)
56
+ return;
57
+ onMessage((0, message_formatter_js_1.commentToMessage)(event.data.taskId, event.data.comment));
58
+ });
59
+ sse.on('task.completed', (event) => {
60
+ sessions.end(event.data.taskId);
61
+ });
62
+ sse.on('task.deleted', (event) => {
63
+ sessions.end(event.data.taskId);
64
+ });
65
+ await sse.connect();
66
+ },
67
+ async disconnect() {
68
+ sse.disconnect();
69
+ },
70
+ async send(msg) {
71
+ const taskId = sessions.getTaskId(msg.sessionKey);
72
+ if (!taskId) {
73
+ throw new Error(`No Astrid task mapped to session ${msg.sessionKey}`);
74
+ }
75
+ const content = (0, message_formatter_js_1.responseToComment)(msg);
76
+ await rest.postComment(taskId, content);
77
+ },
78
+ isConnected() {
79
+ return sse.isConnected();
80
+ },
81
+ getHealth() {
82
+ return {
83
+ connected: sse.isConnected(),
84
+ activeSessions: sessions.activeCount(),
85
+ };
86
+ },
87
+ };
88
+ },
89
+ };
90
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Astrid Channel Plugin for OpenClaw
3
+ *
4
+ * Connect OpenClaw to Astrid.cc via outbound SSE — no inbound gateway URL needed.
5
+ */
6
+ export { astridChannel as AstridChannel } from './channel.js';
7
+ export { SSEClient } from './sse-client.js';
8
+ export { OAuthClient } from './oauth-client.js';
9
+ export { RestClient } from './rest-client.js';
10
+ export { SessionMapper } from './session-mapper.js';
11
+ export { taskToMessage, commentToMessage, responseToComment } from './message-formatter.js';
12
+ export type { AstridChannelConfig, AgentTask, AgentComment, AgentSSEEvent, InboundMessage, OutboundMessage, } from './types.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/channel/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC3F,YAAY,EACV,mBAAmB,EACnB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAA"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /**
3
+ * Astrid Channel Plugin for OpenClaw
4
+ *
5
+ * Connect OpenClaw to Astrid.cc via outbound SSE — no inbound gateway URL needed.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.responseToComment = exports.commentToMessage = exports.taskToMessage = exports.SessionMapper = exports.RestClient = exports.OAuthClient = exports.SSEClient = exports.AstridChannel = void 0;
9
+ var channel_js_1 = require("./channel.js");
10
+ Object.defineProperty(exports, "AstridChannel", { enumerable: true, get: function () { return channel_js_1.astridChannel; } });
11
+ var sse_client_js_1 = require("./sse-client.js");
12
+ Object.defineProperty(exports, "SSEClient", { enumerable: true, get: function () { return sse_client_js_1.SSEClient; } });
13
+ var oauth_client_js_1 = require("./oauth-client.js");
14
+ Object.defineProperty(exports, "OAuthClient", { enumerable: true, get: function () { return oauth_client_js_1.OAuthClient; } });
15
+ var rest_client_js_1 = require("./rest-client.js");
16
+ Object.defineProperty(exports, "RestClient", { enumerable: true, get: function () { return rest_client_js_1.RestClient; } });
17
+ var session_mapper_js_1 = require("./session-mapper.js");
18
+ Object.defineProperty(exports, "SessionMapper", { enumerable: true, get: function () { return session_mapper_js_1.SessionMapper; } });
19
+ var message_formatter_js_1 = require("./message-formatter.js");
20
+ Object.defineProperty(exports, "taskToMessage", { enumerable: true, get: function () { return message_formatter_js_1.taskToMessage; } });
21
+ Object.defineProperty(exports, "commentToMessage", { enumerable: true, get: function () { return message_formatter_js_1.commentToMessage; } });
22
+ Object.defineProperty(exports, "responseToComment", { enumerable: true, get: function () { return message_formatter_js_1.responseToComment; } });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/channel/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,2CAA6D;AAApD,2GAAA,aAAa,OAAiB;AACvC,iDAA2C;AAAlC,0GAAA,SAAS,OAAA;AAClB,qDAA+C;AAAtC,8GAAA,WAAW,OAAA;AACpB,mDAA6C;AAApC,4GAAA,UAAU,OAAA;AACnB,yDAAmD;AAA1C,kHAAA,aAAa,OAAA;AACtB,+DAA2F;AAAlF,qHAAA,aAAa,OAAA;AAAE,wHAAA,gBAAgB,OAAA;AAAE,yHAAA,iBAAiB,OAAA"}
@@ -0,0 +1,14 @@
1
+ import type { AgentTask, AgentComment, InboundMessage, OutboundMessage } from './types.js';
2
+ /**
3
+ * Format an Astrid task as an OpenClaw inbound message.
4
+ */
5
+ export declare function taskToMessage(task: AgentTask): InboundMessage;
6
+ /**
7
+ * Format a human comment as a follow-up inbound message.
8
+ */
9
+ export declare function commentToMessage(taskId: string, comment: AgentComment): InboundMessage;
10
+ /**
11
+ * Strip agent response for posting as an Astrid comment.
12
+ */
13
+ export declare function responseToComment(msg: OutboundMessage): string;
14
+ //# sourceMappingURL=message-formatter.d.ts.map