@desplega.ai/agent-swarm 1.85.0 → 1.86.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.
- package/README.md +1 -0
- package/openapi.json +1 -1
- package/package.json +8 -6
- package/src/be/db.ts +44 -0
- package/src/be/migrations/078_backfill_gpt_5_5_pricing.sql +15 -0
- package/src/be/modelsdev-cache.json +152028 -0
- package/src/be/modelsdev-cache.ts +46 -0
- package/src/be/seed-pricing.ts +7 -44
- package/src/cli.tsx +12 -2
- package/src/commands/codex-session-runner.ts +132 -0
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/provider-credentials.ts +10 -5
- package/src/commands/runner.ts +3 -3
- package/src/prompts/base-prompt.ts +49 -3
- package/src/providers/claude-adapter.ts +83 -2
- package/src/providers/claude-managed-models.ts +18 -2
- package/src/providers/codex-adapter.ts +417 -97
- package/src/providers/codex-models.ts +9 -2
- package/src/providers/index.ts +28 -19
- package/src/providers/pricing-sources.md +7 -4
- package/src/providers/swarm-events-shared.ts +14 -0
- package/src/slack/HEURISTICS.md +5 -1
- package/src/slack/handlers.test.ts +35 -0
- package/src/slack/handlers.ts +79 -2
- package/src/tests/base-prompt.test.ts +46 -8
- package/src/tests/claude-managed-adapter.test.ts +4 -4
- package/src/tests/codex-adapter-otel.test.ts +4 -4
- package/src/tests/codex-adapter.test.ts +20 -7
- package/src/tests/codex-swarm-events.test.ts +35 -0
- package/src/tests/context-window.test.ts +1 -0
- package/src/tests/credential-check.test.ts +48 -29
- package/src/tests/entrypoint-config-env-export.test.ts +81 -0
- package/src/tests/follow-up-redelivery-guard.test.ts +165 -0
- package/src/tests/migration-046-budgets.test.ts +6 -5
- package/src/tests/pricing-routes.test.ts +6 -5
- package/src/tests/provider-adapter.test.ts +10 -10
- package/src/tests/provider-command-format.test.ts +4 -4
- package/src/tests/session-costs-codex-recompute.test.ts +25 -0
- package/src/tools/send-task.ts +30 -9
- package/src/utils/context-window.ts +1 -0
- package/templates/schedules/daily-blocker-digest/config.json +13 -0
- package/templates/schedules/daily-blocker-digest/content.md +150 -0
- package/templates/schedules/daily-compounding-reflection/config.json +21 -0
- package/templates/schedules/daily-compounding-reflection/content.md +210 -0
- package/templates/schedules/daily-hn-briefing/config.json +13 -0
- package/templates/schedules/daily-hn-briefing/content.md +97 -0
- package/templates/schedules/daily-workflow-health-audit/config.json +13 -0
- package/templates/schedules/daily-workflow-health-audit/content.md +189 -0
- package/templates/schedules/gtm-weekly-review/config.json +13 -0
- package/templates/schedules/gtm-weekly-review/content.md +58 -0
- package/templates/schedules/weekly-dependabot-triage/config.json +13 -0
- package/templates/schedules/weekly-dependabot-triage/content.md +45 -0
- package/templates/schema.ts +26 -0
- package/templates/skills/agentmail-sending/config.json +13 -0
- package/templates/skills/agentmail-sending/content.md +48 -0
- package/templates/skills/artifacts/config.json +13 -0
- package/templates/skills/artifacts/content.md +87 -0
- package/templates/skills/browser-use-cloud/config.json +13 -0
- package/templates/skills/browser-use-cloud/content.md +155 -0
- package/templates/skills/desloppify/config.json +13 -0
- package/templates/skills/desloppify/content.md +201 -0
- package/templates/skills/exa-search/config.json +13 -0
- package/templates/skills/exa-search/content.md +106 -0
- package/templates/skills/jira-interaction/config.json +13 -0
- package/templates/skills/jira-interaction/content.md +252 -0
- package/templates/skills/kapso-whatsapp/config.json +13 -0
- package/templates/skills/kapso-whatsapp/content.md +369 -0
- package/templates/skills/kv-storage/config.json +13 -0
- package/templates/skills/kv-storage/content.md +111 -0
- package/templates/skills/linear-interaction/config.json +20 -0
- package/templates/skills/linear-interaction/content.md +230 -0
- package/templates/skills/pages/config.json +18 -0
- package/templates/skills/pages/content.md +85 -0
- package/templates/skills/profile-corruption-escalation/config.json +13 -0
- package/templates/skills/profile-corruption-escalation/content.md +105 -0
- package/templates/skills/scheduled-task-resilience/config.json +13 -0
- package/templates/skills/scheduled-task-resilience/content.md +95 -0
- package/templates/skills/sprite-cli/config.json +13 -0
- package/templates/skills/sprite-cli/content.md +133 -0
- package/templates/skills/turso-interaction/config.json +13 -0
- package/templates/skills/turso-interaction/content.md +192 -0
- package/templates/skills/workflow-iterate/config.json +18 -0
- package/templates/skills/workflow-iterate/content.md +399 -0
- package/templates/skills/workflow-structured-output/config.json +13 -0
- package/templates/skills/workflow-structured-output/content.md +101 -0
- package/templates/skills/x-api-interactions/config.json +13 -0
- package/templates/skills/x-api-interactions/content.md +109 -0
- package/templates/workflows/autopilot/config.json +13 -0
- package/templates/workflows/autopilot/content.md +58 -0
- package/templates/workflows/linear-drain-loop/config.json +21 -0
- package/templates/workflows/linear-drain-loop/content.md +72 -0
- package/templates/workflows/ralph-loop/config.json +13 -0
- package/templates/workflows/ralph-loop/content.md +75 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Exa Search
|
|
2
|
+
|
|
3
|
+
Exa (https://exa.ai) is a neural/semantic search API. It returns web results ranked by embedding similarity rather than keyword match — much better than Google for "find me companies that sound like X" or "what papers explore the shape of Y."
|
|
4
|
+
|
|
5
|
+
## When to use Exa vs. WebSearch
|
|
6
|
+
|
|
7
|
+
| Query shape | Use |
|
|
8
|
+
|---|---|
|
|
9
|
+
| "What is the official Bun docs URL?" | WebSearch (concrete lookup) |
|
|
10
|
+
| "Latest CVE for Next.js" | WebSearch (recent, factual) |
|
|
11
|
+
| "Companies building post-hierarchy AI org platforms" | **Exa** (conceptual / discovery) |
|
|
12
|
+
| "Papers on Bayesian memory rating for agents" | **Exa** (topic-shape) |
|
|
13
|
+
| "Blogs that argue knowledge ≠ data in agent systems" | **Exa** (argument-shape) |
|
|
14
|
+
| "Funding rounds for company X in 2026" | WebSearch (named entity + date) |
|
|
15
|
+
|
|
16
|
+
Rule of thumb: if you're tempted to run 5+ WebSearch calls rephrasing the same idea, use Exa instead — one neural query usually surfaces the cluster.
|
|
17
|
+
|
|
18
|
+
## Step 1 — Get the API key
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Via MCP tool (preferred — handles secret resolution)
|
|
22
|
+
mcp__agent-swarm__get-config(key="EXA_API_KEY", includeSecrets=true)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The value comes back at `configs[0].value`. Export to env or pass inline.
|
|
26
|
+
|
|
27
|
+
## Step 2 — Call the search endpoint
|
|
28
|
+
|
|
29
|
+
Endpoint: `POST https://api.exa.ai/search` — full reference at https://exa.ai/docs/reference/search
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
curl -X POST 'https://api.exa.ai/search' \
|
|
33
|
+
-H "x-api-key: $EXA_API_KEY" \
|
|
34
|
+
-H 'Content-Type: application/json' \
|
|
35
|
+
-d '{
|
|
36
|
+
"query": "companies building agent coordination layers for enterprises",
|
|
37
|
+
"type": "neural",
|
|
38
|
+
"numResults": 10,
|
|
39
|
+
"useAutoprompt": true
|
|
40
|
+
}'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Key request fields:
|
|
44
|
+
- `query` (required): the natural-language description, NOT keywords
|
|
45
|
+
- `type`: `"neural"` (semantic, default for discovery) or `"keyword"` (legacy) or `"auto"` (let Exa choose)
|
|
46
|
+
- `numResults`: 1–25, default 10
|
|
47
|
+
- `useAutoprompt`: true → Exa rewrites your query for better embedding match (recommended for short/colloquial queries)
|
|
48
|
+
- `includeDomains` / `excludeDomains`: arrays for filtering
|
|
49
|
+
- `startPublishedDate` / `endPublishedDate`: ISO dates for time-bounding
|
|
50
|
+
- `category`: e.g. `"company"`, `"research paper"`, `"news"`, `"github"`, `"tweet"`, `"pdf"` — narrows the result type
|
|
51
|
+
|
|
52
|
+
Response shape (trimmed):
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"results": [
|
|
56
|
+
{ "title": "...", "url": "...", "publishedDate": "...", "author": "...", "score": 0.42, "id": "..." }
|
|
57
|
+
],
|
|
58
|
+
"autopromptString": "the rewritten query Exa actually used"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Step 3 — (Optional) Get full content
|
|
63
|
+
|
|
64
|
+
The `/search` endpoint returns metadata only. To pull article bodies:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl -X POST 'https://api.exa.ai/contents' \
|
|
68
|
+
-H "x-api-key: $EXA_API_KEY" \
|
|
69
|
+
-H 'Content-Type: application/json' \
|
|
70
|
+
-d '{
|
|
71
|
+
"ids": ["result-id-from-search"],
|
|
72
|
+
"text": true
|
|
73
|
+
}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Or use the one-shot `/search` variant with `"contents": { "text": true }` baked into the search request to get content in a single round-trip.
|
|
77
|
+
|
|
78
|
+
## Step 4 — Pair with WebFetch for verification
|
|
79
|
+
|
|
80
|
+
Exa surfaces candidates fast but its content snippets can be stale or truncated. For any claim you'll cite (funding amount, headcount, product description), follow up with WebFetch on the canonical company URL. Treat Exa as a discovery layer, WebFetch as the source of truth.
|
|
81
|
+
|
|
82
|
+
## Discipline — no fabrication
|
|
83
|
+
|
|
84
|
+
If a query returns no relevant results, **say "not surfaced"** in your output rather than inventing plausible-sounding companies/papers/links. The most common Exa failure mode is over-promising a comprehensive landscape when the embedding space had thin coverage of your topic. Marking gaps explicitly is what makes the research trustworthy.
|
|
85
|
+
|
|
86
|
+
## Real-world example queries (from 2026-05-04 swarm competitive analysis)
|
|
87
|
+
|
|
88
|
+
These are the exact queries the Researcher used to map the agent-coordination landscape:
|
|
89
|
+
|
|
90
|
+
- `"multi-agent platform for enterprises"`
|
|
91
|
+
- `"AI org operating system post-hierarchy intelligence"`
|
|
92
|
+
- `"AI employee platform digital workers"`
|
|
93
|
+
- `"derived knowledge layer for AI agents"`
|
|
94
|
+
- `"agent coordination layer routes work specialist"`
|
|
95
|
+
- `"humans at the edge AI org structure"`
|
|
96
|
+
- `"agent capability gap registry knowledge graph"`
|
|
97
|
+
|
|
98
|
+
Each surfaced 8–12 results; combined with WebFetch on company sites and WebSearch for funding numbers, the Researcher mapped 5 staked competitive slots + 1 open quadrant in ~30 min. See `agent-fs --org 648a5f3c-35c8-4f11-8673-b89de52cd6bd cat thoughts/d454d1a5-4df9-49bd-8a89-e58d6a657dc3/research/2026-05-04-swarm-competitive-analysis.md` for the full output.
|
|
99
|
+
|
|
100
|
+
## Quick gotchas
|
|
101
|
+
|
|
102
|
+
- The header is `x-api-key`, **not** `Authorization: Bearer`.
|
|
103
|
+
- Free-tier rate limits are tight — batch your queries, don't fire dozens.
|
|
104
|
+
- Neural search is non-deterministic across calls; same query can shuffle top-5 results.
|
|
105
|
+
- `useAutoprompt: true` is almost always right; only disable if you've already hand-tuned the query.
|
|
106
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "skill",
|
|
3
|
+
"name": "jira-interaction",
|
|
4
|
+
"displayName": "Jira Interaction",
|
|
5
|
+
"slug": "jira-interaction",
|
|
6
|
+
"title": "Jira Interaction",
|
|
7
|
+
"description": "Generic Jira update discipline for issue comments, transitions, and triage.",
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"category": "skills",
|
|
10
|
+
"placeholders": ["JIRA_PROJECT_KEY"],
|
|
11
|
+
"runAllSeedersCandidate": false,
|
|
12
|
+
"tags": ["jira", "tracker", "project-management"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Jira Interaction (Read + Outbound Push)
|
|
2
|
+
|
|
3
|
+
The swarm has Jira OAuth connected but **no inbound sync** (unlike Linear). Every read or write is a direct API call against the Atlassian REST API v3.
|
|
4
|
+
|
|
5
|
+
## TL;DR — minimum knowledge
|
|
6
|
+
|
|
7
|
+
1. Pull the access token from `oauth_tokens` (provider = `jira`).
|
|
8
|
+
2. Hit `https://api.atlassian.com/ex/jira/<CLOUD_ID>/rest/api/3/...` — *not* `desplega.atlassian.net` directly. 3LO bearer tokens only work via the `api.atlassian.com` proxy.
|
|
9
|
+
3. Bodies for descriptions/comments must be in **ADF** (Atlassian Document Format), not plain text or markdown.
|
|
10
|
+
|
|
11
|
+
## Known constants (Desplega tenant)
|
|
12
|
+
|
|
13
|
+
- Site: `desplega.atlassian.net`
|
|
14
|
+
- Cloud ID: `0054e739-8d39-4f01-8d6a-431619cae8fc`
|
|
15
|
+
- Default project: `KAN` ("Swarm")
|
|
16
|
+
- Scopes on the stored token: `manage:jira-webhook offline_access read:jira-work read:me write:jira-work`
|
|
17
|
+
|
|
18
|
+
If the cloudId ever changes, rediscover it:
|
|
19
|
+
```bash
|
|
20
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
21
|
+
https://api.atlassian.com/oauth/token/accessible-resources | jq '.'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Authentication
|
|
25
|
+
|
|
26
|
+
The OAuth token is in the swarm DB (`oauth_tokens`, provider = `jira`).
|
|
27
|
+
|
|
28
|
+
```sql
|
|
29
|
+
-- via the db-query MCP tool
|
|
30
|
+
SELECT accessToken, expiresAt, scope FROM oauth_tokens WHERE provider = 'jira';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Always check `expiresAt` first.** Atlassian access tokens are short-lived (~1h). If expired, do NOT keep retrying — report it. Re-auth path:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
https://api.desplega.agent-swarm.dev/api/trackers/jira/authorize
|
|
37
|
+
```
|
|
38
|
+
(User may need to remove the app and re-auth.)
|
|
39
|
+
|
|
40
|
+
## Calling pattern
|
|
41
|
+
|
|
42
|
+
Every endpoint below is relative to:
|
|
43
|
+
```
|
|
44
|
+
https://api.atlassian.com/ex/jira/<CLOUD_ID>/rest/api/3
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Standard header set:
|
|
48
|
+
```bash
|
|
49
|
+
-H "Authorization: Bearer $TOKEN"
|
|
50
|
+
-H "Accept: application/json"
|
|
51
|
+
-H "Content-Type: application/json" # only on POST/PUT
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Common operations
|
|
55
|
+
|
|
56
|
+
### 1. List projects
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
60
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/project/search" \
|
|
61
|
+
| jq '.values[] | {key, name, id, projectTypeKey}'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Get a project (with issue types + lead)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
68
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/project/KAN" \
|
|
69
|
+
| jq '{key, name, lead: .lead.displayName, issueTypes: [.issueTypes[] | {id, name, subtask}]}'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Search issues with JQL
|
|
73
|
+
|
|
74
|
+
Use the **`/search/jql`** endpoint (the older `/search` is deprecated for cloud).
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
curl -s -G \
|
|
78
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
79
|
+
--data-urlencode 'jql=project = KAN AND statusCategory != Done' \
|
|
80
|
+
--data-urlencode 'fields=summary,status,assignee,priority' \
|
|
81
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/search/jql" \
|
|
82
|
+
| jq '[.issues[] | {key, summary: .fields.summary, status: .fields.status.name, assignee: .fields.assignee.displayName}]'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 4. Create an issue
|
|
86
|
+
|
|
87
|
+
Description must be ADF. Minimal valid ADF:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
curl -s -X POST \
|
|
91
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
92
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue" \
|
|
93
|
+
-d '{
|
|
94
|
+
"fields": {
|
|
95
|
+
"project": { "key": "KAN" },
|
|
96
|
+
"summary": "Short title",
|
|
97
|
+
"issuetype": { "name": "Task" },
|
|
98
|
+
"description": {
|
|
99
|
+
"type": "doc",
|
|
100
|
+
"version": 1,
|
|
101
|
+
"content": [
|
|
102
|
+
{ "type": "paragraph", "content": [ { "type": "text", "text": "Body goes here." } ] }
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}'
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Returns `{ id, key, self }` on success (HTTP 201). The `key` (e.g. `KAN-7`) is what humans use; URL is `https://desplega.atlassian.net/browse/<KEY>`.
|
|
110
|
+
|
|
111
|
+
Available issue types in `KAN` (verify per-project): `Epic, Subtask, Task, Story, Feature, Request, Bug`.
|
|
112
|
+
|
|
113
|
+
### 5. Transition issue status (e.g. → Done)
|
|
114
|
+
|
|
115
|
+
Transitions are project- and workflow-specific. Always discover them first:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
119
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/<KEY>/transitions" \
|
|
120
|
+
| jq '.transitions[] | {id, name, to: .to.name}'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
For project `KAN` (verified 2026-04-27), the workflow exposes ALL transitions from any state — you do not need to walk through intermediate states:
|
|
124
|
+
|
|
125
|
+
| Transition ID | Target state |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `11` | To Do |
|
|
128
|
+
| `21` | In Progress |
|
|
129
|
+
| `31` | In Review |
|
|
130
|
+
| `41` | Backlog |
|
|
131
|
+
| `51` | **Done** |
|
|
132
|
+
|
|
133
|
+
Transition (returns HTTP 204 on success, no body):
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
curl -s -X POST \
|
|
137
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
138
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/KAN-3/transitions" \
|
|
139
|
+
-d '{"transition":{"id":"51"}}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 6. Comment on an issue
|
|
143
|
+
|
|
144
|
+
ADF body again:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
curl -s -X POST \
|
|
148
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
149
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/KAN-3/comment" \
|
|
150
|
+
-d '{
|
|
151
|
+
"body": {
|
|
152
|
+
"type": "doc", "version": 1,
|
|
153
|
+
"content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Update from the swarm." } ] } ]
|
|
154
|
+
}
|
|
155
|
+
}'
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 7. Assign an issue
|
|
159
|
+
|
|
160
|
+
Atlassian Cloud uses **accountId**, not username. Find one via:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
curl -s -G -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
164
|
+
--data-urlencode 'query=taras' \
|
|
165
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/user/search" \
|
|
166
|
+
| jq '.[] | {accountId, displayName, emailAddress}'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Assign:
|
|
170
|
+
```bash
|
|
171
|
+
curl -s -X PUT \
|
|
172
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
173
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/KAN-3/assignee" \
|
|
174
|
+
-d '{"accountId":"<ACCOUNT_ID>"}'
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
To unassign: `{"accountId": null}`.
|
|
178
|
+
|
|
179
|
+
### 8. Edit fields on an existing issue
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
curl -s -X PUT \
|
|
183
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
184
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/KAN-3" \
|
|
185
|
+
-d '{ "fields": { "summary": "New summary", "labels": ["swarm","auto"] } }'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Returns HTTP 204.
|
|
189
|
+
|
|
190
|
+
## ADF cheat-sheet
|
|
191
|
+
|
|
192
|
+
ADF = JSON tree. Always wrap content in `{ "type": "doc", "version": 1, "content": [...] }`.
|
|
193
|
+
|
|
194
|
+
Common nodes:
|
|
195
|
+
- Paragraph: `{ "type": "paragraph", "content": [ { "type": "text", "text": "hi" } ] }`
|
|
196
|
+
- Bold: `{ "type": "text", "text": "x", "marks": [{ "type": "strong" }] }`
|
|
197
|
+
- Code inline: `{ "type": "text", "text": "x", "marks": [{ "type": "code" }] }`
|
|
198
|
+
- Code block: `{ "type": "codeBlock", "attrs": { "language": "bash" }, "content": [ { "type": "text", "text": "echo hi" } ] }`
|
|
199
|
+
- Bullet list: `{ "type": "bulletList", "content": [ { "type": "listItem", "content": [ { "type": "paragraph", "content": [...] } ] } ] }`
|
|
200
|
+
- Link: `{ "type": "text", "text": "click", "marks": [{ "type": "link", "attrs": { "href": "https://..." } }] }`
|
|
201
|
+
|
|
202
|
+
If you need rich content, build it in a script — don't try to write deep ADF inline in shell.
|
|
203
|
+
|
|
204
|
+
## Operational rules
|
|
205
|
+
|
|
206
|
+
- **Token-expiry first.** Always check `expiresAt`. Don't loop on 401s.
|
|
207
|
+
- **Use the proxy.** All authenticated calls go through `api.atlassian.com/ex/jira/<cloudId>/...`. Hitting `desplega.atlassian.net/rest/api/3/...` with a 3LO bearer token will fail.
|
|
208
|
+
- **Discover transitions per issue** before transitioning — different projects/workflows have different IDs.
|
|
209
|
+
- **Use `/search/jql`**, not the legacy `/search` (which is deprecated and may be removed).
|
|
210
|
+
- **ADF is mandatory** for `description`, `comment`, and rich text fields. Plain strings will be rejected.
|
|
211
|
+
- **Account IDs, not usernames** for assignment, mentions, and filters.
|
|
212
|
+
- **Rate limits:** Atlassian rate-limits per app and per user. For bulk transitions/comments, sleep ~200–500 ms between calls.
|
|
213
|
+
- **Don't leak tokens.** Never echo the access token to logs or Slack. Read it into an env var only.
|
|
214
|
+
|
|
215
|
+
## Error handling
|
|
216
|
+
|
|
217
|
+
| Status | Likely cause | Action |
|
|
218
|
+
|---|---|---|
|
|
219
|
+
| 401 | Token expired/invalid | Check `expiresAt`. Notify user to re-auth. Don't retry. |
|
|
220
|
+
| 403 | Missing scope, or restricted issue | Check the `scope` column. For `write:jira-work` operations, confirm scope is present. |
|
|
221
|
+
| 404 | Wrong key, wrong cloudId, wrong project | Re-verify with a project list call. |
|
|
222
|
+
| 400 | Body shape wrong (often ADF or required field) | Inspect `errorMessages` / `errors` in the response JSON. |
|
|
223
|
+
| 429 | Rate-limited | Back off, retry after `Retry-After` seconds. |
|
|
224
|
+
|
|
225
|
+
## Complete worked example: clean a project
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
TOKEN=$(db-query "SELECT accessToken FROM oauth_tokens WHERE provider='jira'")
|
|
229
|
+
CLOUD_ID="0054e739-8d39-4f01-8d6a-431619cae8fc"
|
|
230
|
+
|
|
231
|
+
# 1. List open issues in KAN
|
|
232
|
+
curl -s -G -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
|
|
233
|
+
--data-urlencode 'jql=project = KAN AND statusCategory != Done' \
|
|
234
|
+
--data-urlencode 'fields=summary,status' \
|
|
235
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/search/jql" \
|
|
236
|
+
| jq -r '.issues[].key' > /tmp/keys.txt
|
|
237
|
+
|
|
238
|
+
# 2. Transition each to Done (id 51 in KAN)
|
|
239
|
+
for KEY in $(cat /tmp/keys.txt); do
|
|
240
|
+
curl -s -X POST \
|
|
241
|
+
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
242
|
+
"https://api.atlassian.com/ex/jira/$CLOUD_ID/rest/api/3/issue/$KEY/transitions" \
|
|
243
|
+
-d '{"transition":{"id":"51"}}'
|
|
244
|
+
sleep 0.3
|
|
245
|
+
done
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Notes for swarm sync (future)
|
|
249
|
+
|
|
250
|
+
- The MCP tracker tools (`tracker-link-task`, `tracker-sync-status`, etc.) are designed for two-way sync mappings. Jira tracker support exists at the schema level but is not currently wired up to inbound webhooks. Until it is, all Jira interaction must go through this skill.
|
|
251
|
+
- If/when inbound Jira webhooks land, this skill should add a "When to transition" section mirroring the Linear one.
|
|
252
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "skill",
|
|
3
|
+
"name": "kapso-whatsapp",
|
|
4
|
+
"displayName": "WhatsApp Messaging",
|
|
5
|
+
"slug": "kapso-whatsapp",
|
|
6
|
+
"title": "WhatsApp Messaging",
|
|
7
|
+
"description": "Generic WhatsApp messaging guardrails for approved business messaging providers.",
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"category": "skills",
|
|
10
|
+
"placeholders": ["WHATSAPP_PROVIDER_API_KEY", "WHATSAPP_SENDER_ID"],
|
|
11
|
+
"runAllSeedersCandidate": false,
|
|
12
|
+
"tags": ["whatsapp", "messaging", "communications"]
|
|
13
|
+
}
|