@llodev/pm-tasks-asana 0.0.0-pr-22-9002a06
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/CHANGELOG.md +282 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/SKILL.md +198 -0
- package/anti-patterns/asana.md +62 -0
- package/dist/adapter.d.ts +19 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +18 -0
- package/dist/adapter.js.map +1 -0
- package/dist/bin/init.d.ts +3 -0
- package/dist/bin/init.d.ts.map +1 -0
- package/dist/bin/init.js +280 -0
- package/dist/bin/init.js.map +1 -0
- package/dist/doctor-cli.d.ts +6 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +166 -0
- package/dist/doctor-cli.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/transport-asana.d.ts +44 -0
- package/dist/transport-asana.d.ts.map +1 -0
- package/dist/transport-asana.js +254 -0
- package/dist/transport-asana.js.map +1 -0
- package/docs/i18n/README.es-ES.md +100 -0
- package/docs/i18n/README.pt-BR.md +100 -0
- package/i18n/en-US.json +24 -0
- package/i18n/es-ES.json +24 -0
- package/i18n/pt-BR.json +24 -0
- package/manifest.json +12 -0
- package/package.json +67 -0
- package/references/operations.md +62 -0
- package/schemas/config.json +173 -0
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@llodev/pm-tasks-asana",
|
|
3
|
+
"version": "0.0.0-pr-22-9002a06",
|
|
4
|
+
"description": "Asana adapter for the @llodev/pm-tasks-* family. Use when the user mentions Asana (create Asana task, publish to Asana, post to Asana, add comment in Asana, --publish-asana, close task, check subtask) or wants to publish a plan as Asana tasks with subtasks. Modes: paste-ready (no MCP needed), MCP publish (via claude.ai Asana MCP), autonomous (sentinel [autonomous] / --auto). Implements 6 CRUD verbs from @llodev/pm-tasks-core/references/contract.md mapped to Asana (parent task + subtasks, custom fields, sections, multi-assignee). REQUIRES: @llodev/pm-tasks-core installed (skillpm / Claude Code marketplace cascade auto; Vercel CLI users install manually).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/llodev/skills/tree/main/pm-tasks/pm-tasks-asana",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/llodev/skills.git",
|
|
10
|
+
"directory": "pm-tasks/pm-tasks-asana"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/bin/init.js",
|
|
13
|
+
"types": "./dist/bin/init.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"SKILL.md",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"CHANGELOG.md",
|
|
19
|
+
"docs",
|
|
20
|
+
"anti-patterns",
|
|
21
|
+
"references",
|
|
22
|
+
"i18n",
|
|
23
|
+
"schemas",
|
|
24
|
+
"manifest.json",
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"agent-skill",
|
|
29
|
+
"asana",
|
|
30
|
+
"plan-to-tasks",
|
|
31
|
+
"pm-tools",
|
|
32
|
+
"asana-mcp"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/bin/init.d.ts",
|
|
38
|
+
"import": "./dist/bin/init.js"
|
|
39
|
+
},
|
|
40
|
+
"./adapter": {
|
|
41
|
+
"types": "./dist/adapter.d.ts",
|
|
42
|
+
"import": "./dist/adapter.js"
|
|
43
|
+
},
|
|
44
|
+
"./i18n/*.json": "./i18n/*.json",
|
|
45
|
+
"./schemas/*.json": "./schemas/*.json",
|
|
46
|
+
"./manifest.json": "./manifest.json"
|
|
47
|
+
},
|
|
48
|
+
"bin": {
|
|
49
|
+
"pm-tasks-asana": "./dist/bin/init.js"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"ajv": "^8.17.1",
|
|
53
|
+
"ajv-formats": "^3.0.1",
|
|
54
|
+
"@llodev/pm-tasks-core": "^0.0.0-pr-22-9002a06"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/bin/init.js",
|
|
64
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
65
|
+
"test": "pnpm build && vitest run --passWithNoTests"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Asana CRUD operations (v1)
|
|
2
|
+
|
|
3
|
+
Verb → MCP tool mapping for `@llodev/pm-tasks-asana`. All verbs return the core result envelope; see [`../../pm-tasks-core/references/contract.md`](../../pm-tasks-core/references/contract.md) § Result envelope.
|
|
4
|
+
|
|
5
|
+
## Verb → MCP tool
|
|
6
|
+
|
|
7
|
+
| Core verb | Asana MCP tool (`mcp__claude_ai_Asana__*`) | Notes |
|
|
8
|
+
| ------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| `task.create` | `create_tasks` | parent + subtasks; `memberships: [{ project, section }]` places card in the correct section at creation time. |
|
|
10
|
+
| `task.move` | `update_tasks` | `memberships: [{ project: <projectGid>, section: <resolvedGid> }]`. See § `task.move` below for resolution rules. Idempotency: check current section before calling. |
|
|
11
|
+
| `checklist.check` | `update_tasks` | `{ task: <subtaskGid>, completed: true }`. Subtask model emulates checklist items. |
|
|
12
|
+
| `task.close` | `update_tasks` | `{ task: <parentGid>, completed: true }`. Visual section move is handled separately by `task.move(cardId, "done")` before calling `task.close`. |
|
|
13
|
+
| `task.due-date.set` | `update_tasks` | `{ task: <gid>, due_on: "YYYY-MM-DD" }`. Pass `null` to clear. |
|
|
14
|
+
| `task.assignee.add` | `update_tasks` + `update_tasks` (add_followers) | Primary assignee via `assignee` field; additional users become followers via `add_followers: [<gid>]`. |
|
|
15
|
+
| `task.comment.add` | `add_comment` | Creates a comment story on the task. Apply attribution prefix per `config.locale` if `config.attribution` is enabled. |
|
|
16
|
+
|
|
17
|
+
## `task.move` — resolution rules
|
|
18
|
+
|
|
19
|
+
Schema: `{ cardId: string, targetList: "open" | "wip" | "done" | string }`
|
|
20
|
+
|
|
21
|
+
Resolution order for `targetList`:
|
|
22
|
+
|
|
23
|
+
1. If `targetList` is `"wip"` → look up `defaults.wipSectionAlias` in `.asana.json`, find the matching entry in `sections[]` by alias, use its `id` as the section GID.
|
|
24
|
+
2. If `targetList` is `"done"` → look up `defaults.doneSectionAlias` in `.asana.json`.
|
|
25
|
+
3. If `targetList` is `"open"` → look up `defaults.openSectionAlias` in `.asana.json`.
|
|
26
|
+
4. Otherwise → treat `targetList` as a raw Asana section GID and pass through directly.
|
|
27
|
+
|
|
28
|
+
The resolved section GID MUST be in `autonomous.scope.sections` — otherwise the verb returns `{ ok: false, code: "OUT_OF_SCOPE" }`.
|
|
29
|
+
|
|
30
|
+
Idempotency: fetch current task memberships before calling `update_tasks`. If the task is already in the target section, return `{ ok: true }` without an MCP write.
|
|
31
|
+
|
|
32
|
+
## `<task-ref>` resolution for Asana
|
|
33
|
+
|
|
34
|
+
Accept, in order:
|
|
35
|
+
|
|
36
|
+
1. Full Asana permalink (`https://app.asana.com/0/<project>/<task>`).
|
|
37
|
+
2. Bare GID (numeric string).
|
|
38
|
+
3. Alias from `.asana.json` `taskAliases[]`.
|
|
39
|
+
4. `clientToken` match in audit log (most recent).
|
|
40
|
+
5. Name partial match in audit log scoped to `autonomous.scope`.
|
|
41
|
+
6. Otherwise → `{ ok: false, code: "REF_NOT_RESOLVED", candidates: [...] }`.
|
|
42
|
+
|
|
43
|
+
## Idempotency
|
|
44
|
+
|
|
45
|
+
| Verb | Idempotency rule |
|
|
46
|
+
| ------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `task.create` | Before creating, search scope for task with matching `clientToken`. If found, return existing ref. |
|
|
48
|
+
| `task.move` | Check current section before `update_tasks`. No-op if already in target. |
|
|
49
|
+
| `task.close` | Natural — `completed: true` is a no-op if already completed. |
|
|
50
|
+
| others | Natural or `clientToken`-based; see [`crud-vocabulary.md`](../../pm-tasks-core/references/crud-vocabulary.md). |
|
|
51
|
+
|
|
52
|
+
## Result envelope — Asana-specific `details`
|
|
53
|
+
|
|
54
|
+
| Verb | `details` fields |
|
|
55
|
+
| ------------------- | ------------------------------------------------------------------------ |
|
|
56
|
+
| `task.create` | `{ parentGid, subtaskGids[], projectGid, sectionGid?, customFields[]? }` |
|
|
57
|
+
| `task.move` | `{ taskGid, sectionGid, targetList }` |
|
|
58
|
+
| `checklist.check` | `{ subtaskGid, completed: true }` |
|
|
59
|
+
| `task.close` | `{ parentGid, completed: true }` |
|
|
60
|
+
| `task.due-date.set` | `{ taskGid, due_on }` |
|
|
61
|
+
| `task.assignee.add` | `{ taskGid, assignee, followers[]? }` |
|
|
62
|
+
| `task.comment.add` | `{ taskGid, storyGid }` |
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://llodev.github.io/skills/schemas/pm-tasks-asana.json",
|
|
4
|
+
"title": "pm-tasks-asana config",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["version", "projects", "sections"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "type": "string" },
|
|
10
|
+
"version": { "const": "1" },
|
|
11
|
+
"locale": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["en-US", "pt-BR", "es-ES"]
|
|
14
|
+
},
|
|
15
|
+
"workspace": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"properties": {
|
|
19
|
+
"id": { "type": "string", "minLength": 4 },
|
|
20
|
+
"name": { "type": "string" }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"projects": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"minItems": 1,
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"required": ["id", "alias"],
|
|
29
|
+
"additionalProperties": false,
|
|
30
|
+
"properties": {
|
|
31
|
+
"id": { "type": "string", "minLength": 4 },
|
|
32
|
+
"name": { "type": "string" },
|
|
33
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" },
|
|
34
|
+
"url": { "type": "string", "format": "uri" }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"sections": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["projectAlias", "id", "alias"],
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"properties": {
|
|
45
|
+
"projectAlias": { "type": "string" },
|
|
46
|
+
"id": { "type": "string", "minLength": 4 },
|
|
47
|
+
"name": { "type": "string" },
|
|
48
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"customFields": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"required": ["projectAlias", "id", "name", "type", "alias"],
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"properties": {
|
|
59
|
+
"projectAlias": { "type": "string" },
|
|
60
|
+
"id": { "type": "string", "minLength": 4 },
|
|
61
|
+
"name": { "type": "string" },
|
|
62
|
+
"type": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"enum": ["text", "number", "enum", "multi_enum", "date", "people"]
|
|
65
|
+
},
|
|
66
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" },
|
|
67
|
+
"options": {
|
|
68
|
+
"type": "array",
|
|
69
|
+
"items": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"required": ["id", "name"],
|
|
72
|
+
"additionalProperties": false,
|
|
73
|
+
"properties": {
|
|
74
|
+
"id": { "type": "string", "minLength": 4 },
|
|
75
|
+
"name": { "type": "string" },
|
|
76
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"subtaskDefaults": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"additionalProperties": false,
|
|
86
|
+
"properties": {
|
|
87
|
+
"inheritParentFields": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"items": { "type": "string", "minLength": 4 },
|
|
90
|
+
"description": "Custom field IDs whose values flow from parent to subtask at create time."
|
|
91
|
+
},
|
|
92
|
+
"inheritAssignee": { "type": "boolean" }
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"members": {
|
|
96
|
+
"type": "array",
|
|
97
|
+
"items": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"required": ["id", "alias"],
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"properties": {
|
|
102
|
+
"id": { "type": "string", "minLength": 4 },
|
|
103
|
+
"name": { "type": "string" },
|
|
104
|
+
"email": { "type": "string", "format": "email" },
|
|
105
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"defaults": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"additionalProperties": false,
|
|
112
|
+
"properties": {
|
|
113
|
+
"projectAlias": { "type": "string" },
|
|
114
|
+
"sectionAlias": { "type": "string" },
|
|
115
|
+
"closeSectionAlias": { "type": "string" },
|
|
116
|
+
"assigneeAlias": { "type": "string" },
|
|
117
|
+
"escalateToAlias": { "type": "string" }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"taskAliases": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"required": ["alias", "id"],
|
|
125
|
+
"additionalProperties": false,
|
|
126
|
+
"properties": {
|
|
127
|
+
"alias": { "type": "string", "pattern": "^[a-z0-9-]+$" },
|
|
128
|
+
"id": { "type": "string" },
|
|
129
|
+
"url": { "type": "string", "format": "uri" }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"attribution": { "$ref": "https://llodev.com/pm-tasks/attribution.schema.json" },
|
|
134
|
+
"autonomous": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"properties": {
|
|
138
|
+
"enabled": { "type": "boolean" },
|
|
139
|
+
"allow": {
|
|
140
|
+
"type": "array",
|
|
141
|
+
"items": {
|
|
142
|
+
"enum": [
|
|
143
|
+
"task.create",
|
|
144
|
+
"task.move",
|
|
145
|
+
"checklist.check",
|
|
146
|
+
"task.close",
|
|
147
|
+
"task.due-date.set",
|
|
148
|
+
"task.assignee.add",
|
|
149
|
+
"task.comment.add"
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"scope": {
|
|
154
|
+
"type": "object",
|
|
155
|
+
"additionalProperties": false,
|
|
156
|
+
"properties": {
|
|
157
|
+
"projects": { "type": "array", "items": { "type": "string" } },
|
|
158
|
+
"sections": { "type": "array", "items": { "type": "string" } }
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"rateLimit": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": false,
|
|
164
|
+
"properties": {
|
|
165
|
+
"writesPerMinute": { "type": "integer", "minimum": 1, "maximum": 600 },
|
|
166
|
+
"commentsPerMinute": { "type": "integer", "minimum": 1, "maximum": 600 }
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"auditLog": { "type": "string" }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|