@nextsparkjs/ai-workflow 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: asana-integration
|
|
3
|
+
description: |
|
|
4
|
+
Asana integration patterns for work management.
|
|
5
|
+
Covers Personal Access Tokens, webhooks, and task management.
|
|
6
|
+
Use this skill when implementing Asana features or syncing sessions with tasks.
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Asana Integration Skill
|
|
12
|
+
|
|
13
|
+
Integration patterns for syncing development sessions with Asana tasks.
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ ASANA INTEGRATION │
|
|
20
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
21
|
+
│ │
|
|
22
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
23
|
+
│ │ Claude │────►│ REST API │────►│ Asana │ │
|
|
24
|
+
│ │ Session │◄────│ Client │◄────│ Cloud │ │
|
|
25
|
+
│ └─────────────┘ └──────────────┘ └──────────────┘ │
|
|
26
|
+
│ │ │ │
|
|
27
|
+
│ ▼ ▼ │
|
|
28
|
+
│ ┌─────────────┐ ┌──────────────┐ │
|
|
29
|
+
│ │ Session │ │ Webhooks │ │
|
|
30
|
+
│ │ Files │ │ │ │
|
|
31
|
+
│ └─────────────┘ └──────────────┘ │
|
|
32
|
+
│ │
|
|
33
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## When to Use This Skill
|
|
39
|
+
|
|
40
|
+
- Setting up Asana integration for the first time
|
|
41
|
+
- Syncing development sessions with Asana tasks
|
|
42
|
+
- Creating tasks from Claude sessions
|
|
43
|
+
- Updating task completion status
|
|
44
|
+
- Managing projects and sections
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
### .claude/config/workspace.json
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"taskManager": {
|
|
55
|
+
"enabled": true,
|
|
56
|
+
"provider": "asana",
|
|
57
|
+
"syncWithSession": true,
|
|
58
|
+
"autoUpdateStatus": true,
|
|
59
|
+
"config": {
|
|
60
|
+
"accessToken": "${ASANA_ACCESS_TOKEN}",
|
|
61
|
+
"defaultWorkspace": "your-workspace-gid",
|
|
62
|
+
"defaultProject": "your-project-gid"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Environment Variables
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# .env.local
|
|
72
|
+
ASANA_ACCESS_TOKEN=1/12345678901234:abcdefghijklmnop...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Authentication
|
|
78
|
+
|
|
79
|
+
### Personal Access Token (PAT)
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Bearer token authentication
|
|
83
|
+
const headers = {
|
|
84
|
+
'Authorization': `Bearer ${process.env.ASANA_ACCESS_TOKEN}`,
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
'Accept': 'application/json'
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Base URL
|
|
90
|
+
const BASE_URL = 'https://app.asana.com/api/1.0';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### OAuth 2.0
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// For OAuth apps
|
|
97
|
+
const authUrl = 'https://app.asana.com/-/oauth_authorize';
|
|
98
|
+
const tokenUrl = 'https://app.asana.com/-/oauth_token';
|
|
99
|
+
|
|
100
|
+
// Exchange code for token
|
|
101
|
+
const response = await fetch(tokenUrl, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
104
|
+
body: new URLSearchParams({
|
|
105
|
+
grant_type: 'authorization_code',
|
|
106
|
+
client_id: process.env.ASANA_CLIENT_ID,
|
|
107
|
+
client_secret: process.env.ASANA_CLIENT_SECRET,
|
|
108
|
+
redirect_uri: 'https://your-app.com/callback',
|
|
109
|
+
code: authorizationCode
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## API Patterns
|
|
117
|
+
|
|
118
|
+
### Common Endpoints
|
|
119
|
+
|
|
120
|
+
| Endpoint | Method | Description |
|
|
121
|
+
|----------|--------|-------------|
|
|
122
|
+
| `/users/me` | GET | Get current user |
|
|
123
|
+
| `/workspaces` | GET | List workspaces |
|
|
124
|
+
| `/projects` | GET | List projects |
|
|
125
|
+
| `/projects/{gid}` | GET | Get project details |
|
|
126
|
+
| `/projects/{gid}/tasks` | GET | List tasks in project |
|
|
127
|
+
| `/tasks` | POST | Create task |
|
|
128
|
+
| `/tasks/{gid}` | GET/PUT/DELETE | Task operations |
|
|
129
|
+
| `/tasks/{gid}/stories` | GET/POST | Task comments/activity |
|
|
130
|
+
| `/sections` | GET | List sections |
|
|
131
|
+
|
|
132
|
+
### Task Structure
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface AsanaTask {
|
|
136
|
+
gid: string;
|
|
137
|
+
name: string;
|
|
138
|
+
notes: string; // Plain text description
|
|
139
|
+
html_notes: string; // HTML description
|
|
140
|
+
completed: boolean;
|
|
141
|
+
completed_at: string | null;
|
|
142
|
+
due_on: string | null; // YYYY-MM-DD
|
|
143
|
+
due_at: string | null; // ISO datetime
|
|
144
|
+
start_on: string | null;
|
|
145
|
+
assignee: {
|
|
146
|
+
gid: string;
|
|
147
|
+
name: string;
|
|
148
|
+
email: string;
|
|
149
|
+
} | null;
|
|
150
|
+
projects: Array<{
|
|
151
|
+
gid: string;
|
|
152
|
+
name: string;
|
|
153
|
+
}>;
|
|
154
|
+
memberships: Array<{
|
|
155
|
+
project: { gid: string; name: string };
|
|
156
|
+
section: { gid: string; name: string };
|
|
157
|
+
}>;
|
|
158
|
+
tags: Array<{
|
|
159
|
+
gid: string;
|
|
160
|
+
name: string;
|
|
161
|
+
color: string;
|
|
162
|
+
}>;
|
|
163
|
+
custom_fields: Array<{
|
|
164
|
+
gid: string;
|
|
165
|
+
name: string;
|
|
166
|
+
type: string;
|
|
167
|
+
enum_value?: { gid: string; name: string };
|
|
168
|
+
number_value?: number;
|
|
169
|
+
text_value?: string;
|
|
170
|
+
}>;
|
|
171
|
+
permalink_url: string;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Session Sync Patterns
|
|
178
|
+
|
|
179
|
+
### Linking Session to Task
|
|
180
|
+
|
|
181
|
+
```markdown
|
|
182
|
+
# In requirements.md
|
|
183
|
+
|
|
184
|
+
## Asana Task
|
|
185
|
+
- **Task GID:** 1234567890123456
|
|
186
|
+
- **URL:** https://app.asana.com/0/project-gid/1234567890123456
|
|
187
|
+
- **Status:** In Progress (via section)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Task Management
|
|
191
|
+
|
|
192
|
+
Asana uses sections for status (unlike status fields):
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Move task to section (change status)
|
|
196
|
+
await fetch(`${BASE_URL}/sections/${sectionGid}/addTask`, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers,
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
data: { task: taskGid }
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Mark task complete
|
|
205
|
+
await fetch(`${BASE_URL}/tasks/${taskGid}`, {
|
|
206
|
+
method: 'PUT',
|
|
207
|
+
headers,
|
|
208
|
+
body: JSON.stringify({
|
|
209
|
+
data: { completed: true }
|
|
210
|
+
})
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Section Mapping
|
|
215
|
+
|
|
216
|
+
| Session Event | Asana Action |
|
|
217
|
+
|---------------|--------------|
|
|
218
|
+
| Session created | Move to "In Progress" section |
|
|
219
|
+
| Blocked | Move to "Blocked" section |
|
|
220
|
+
| Session closed (success) | Mark completed |
|
|
221
|
+
| Session closed (partial) | Move to "Review" section |
|
|
222
|
+
|
|
223
|
+
### Adding Stories (Comments)
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Add comment to task
|
|
227
|
+
await fetch(`${BASE_URL}/tasks/${taskGid}/stories`, {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
headers,
|
|
230
|
+
body: JSON.stringify({
|
|
231
|
+
data: {
|
|
232
|
+
text: `
|
|
233
|
+
## Session Progress Update
|
|
234
|
+
|
|
235
|
+
**Phase:** Backend Development
|
|
236
|
+
**Progress:** 60%
|
|
237
|
+
|
|
238
|
+
### Completed
|
|
239
|
+
- API endpoints created
|
|
240
|
+
- Tests written
|
|
241
|
+
|
|
242
|
+
### In Progress
|
|
243
|
+
- Frontend components
|
|
244
|
+
`.trim()
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Webhook Configuration
|
|
253
|
+
|
|
254
|
+
### Creating Webhooks
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// Create webhook
|
|
258
|
+
const webhook = await fetch(`${BASE_URL}/webhooks`, {
|
|
259
|
+
method: 'POST',
|
|
260
|
+
headers,
|
|
261
|
+
body: JSON.stringify({
|
|
262
|
+
data: {
|
|
263
|
+
resource: projectGid, // What to watch
|
|
264
|
+
target: 'https://your-app.com/api/webhooks/asana',
|
|
265
|
+
filters: [
|
|
266
|
+
{ resource_type: 'task', action: 'changed' },
|
|
267
|
+
{ resource_type: 'task', action: 'added' },
|
|
268
|
+
{ resource_type: 'story', action: 'added' }
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Webhook Handshake
|
|
276
|
+
|
|
277
|
+
Asana requires a handshake to verify webhook endpoint:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
// app/api/webhooks/asana/route.ts
|
|
281
|
+
export async function POST(request: Request) {
|
|
282
|
+
// Handle handshake
|
|
283
|
+
const hookSecret = request.headers.get('X-Hook-Secret');
|
|
284
|
+
if (hookSecret) {
|
|
285
|
+
return new Response(null, {
|
|
286
|
+
status: 200,
|
|
287
|
+
headers: { 'X-Hook-Secret': hookSecret }
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Verify signature
|
|
292
|
+
const signature = request.headers.get('X-Hook-Signature');
|
|
293
|
+
const body = await request.text();
|
|
294
|
+
// Verify HMAC-SHA256 signature...
|
|
295
|
+
|
|
296
|
+
const payload = JSON.parse(body);
|
|
297
|
+
|
|
298
|
+
for (const event of payload.events) {
|
|
299
|
+
switch (event.action) {
|
|
300
|
+
case 'changed':
|
|
301
|
+
// Handle task update
|
|
302
|
+
break;
|
|
303
|
+
case 'added':
|
|
304
|
+
// Handle new task/comment
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return Response.json({ received: true });
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Event Types
|
|
314
|
+
|
|
315
|
+
| Resource | Action | Trigger |
|
|
316
|
+
|----------|--------|---------|
|
|
317
|
+
| task | added | Task created |
|
|
318
|
+
| task | changed | Task updated |
|
|
319
|
+
| task | removed | Task deleted |
|
|
320
|
+
| task | undeleted | Task restored |
|
|
321
|
+
| story | added | Comment/activity added |
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Custom Fields
|
|
326
|
+
|
|
327
|
+
### Reading Custom Fields
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// Get task with custom fields
|
|
331
|
+
const response = await fetch(
|
|
332
|
+
`${BASE_URL}/tasks/${taskGid}?opt_fields=custom_fields,custom_fields.name,custom_fields.enum_value`,
|
|
333
|
+
{ headers }
|
|
334
|
+
);
|
|
335
|
+
const { data: task } = await response.json();
|
|
336
|
+
|
|
337
|
+
// Find specific field
|
|
338
|
+
const statusField = task.custom_fields.find(f => f.name === 'Status');
|
|
339
|
+
console.log(statusField.enum_value?.name); // "In Progress"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Updating Custom Fields
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// Update custom field value
|
|
346
|
+
await fetch(`${BASE_URL}/tasks/${taskGid}`, {
|
|
347
|
+
method: 'PUT',
|
|
348
|
+
headers,
|
|
349
|
+
body: JSON.stringify({
|
|
350
|
+
data: {
|
|
351
|
+
custom_fields: {
|
|
352
|
+
[customFieldGid]: enumOptionGid // For enum fields
|
|
353
|
+
// or
|
|
354
|
+
[customFieldGid]: 42 // For number fields
|
|
355
|
+
// or
|
|
356
|
+
[customFieldGid]: "text value" // For text fields
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Rate Limiting
|
|
366
|
+
|
|
367
|
+
### Limits
|
|
368
|
+
|
|
369
|
+
| Type | Limit |
|
|
370
|
+
|------|-------|
|
|
371
|
+
| Standard | 1500 requests/minute |
|
|
372
|
+
| Free tier | 150 requests/minute |
|
|
373
|
+
| Per-user | Based on plan |
|
|
374
|
+
|
|
375
|
+
### Headers
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
// Asana uses retry-after for rate limits
|
|
379
|
+
const retryAfter = response.headers.get('Retry-After');
|
|
380
|
+
if (response.status === 429) {
|
|
381
|
+
await sleep(parseInt(retryAfter) * 1000);
|
|
382
|
+
// Retry request
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Error Handling
|
|
389
|
+
|
|
390
|
+
### Common Error Codes
|
|
391
|
+
|
|
392
|
+
| Code | Description | Resolution |
|
|
393
|
+
|------|-------------|------------|
|
|
394
|
+
| 400 | Bad request | Check request body |
|
|
395
|
+
| 401 | Unauthorized | Check token |
|
|
396
|
+
| 403 | Forbidden | Check permissions |
|
|
397
|
+
| 404 | Not found | Verify GID |
|
|
398
|
+
| 429 | Rate limited | Wait and retry |
|
|
399
|
+
| 500 | Server error | Retry with backoff |
|
|
400
|
+
|
|
401
|
+
### Error Response Format
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"errors": [
|
|
406
|
+
{
|
|
407
|
+
"message": "task: Unknown object: 1234567890",
|
|
408
|
+
"help": "For more information on API status codes..."
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Testing Patterns
|
|
417
|
+
|
|
418
|
+
### Mock API Responses
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// __mocks__/asana.ts
|
|
422
|
+
export const mockTask = {
|
|
423
|
+
gid: "1234567890123456",
|
|
424
|
+
name: "Test Task",
|
|
425
|
+
completed: false,
|
|
426
|
+
assignee: { gid: "user-gid", name: "Test User" }
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
export const mockGetTask = jest.fn().mockResolvedValue({ data: mockTask });
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Integration Tests
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
describe('Asana Integration', () => {
|
|
436
|
+
it('should fetch task details', async () => {
|
|
437
|
+
const task = await asana.getTask('1234567890123456');
|
|
438
|
+
expect(task.name).toBeDefined();
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it('should complete task', async () => {
|
|
442
|
+
await asana.completeTask('1234567890123456');
|
|
443
|
+
const task = await asana.getTask('1234567890123456');
|
|
444
|
+
expect(task.completed).toBe(true);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Anti-Patterns
|
|
452
|
+
|
|
453
|
+
### DON'T: Forget opt_fields
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// BAD - Returns minimal data
|
|
457
|
+
const task = await fetch(`${BASE_URL}/tasks/${gid}`);
|
|
458
|
+
|
|
459
|
+
// GOOD - Request needed fields
|
|
460
|
+
const task = await fetch(
|
|
461
|
+
`${BASE_URL}/tasks/${gid}?opt_fields=name,notes,assignee,completed,custom_fields`
|
|
462
|
+
);
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### DON'T: Poll for Changes
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
// BAD - Polling wastes resources
|
|
469
|
+
setInterval(async () => {
|
|
470
|
+
const tasks = await getTasks();
|
|
471
|
+
// Check for changes...
|
|
472
|
+
}, 5000);
|
|
473
|
+
|
|
474
|
+
// GOOD - Use webhooks
|
|
475
|
+
await createWebhook(projectGid, callbackUrl);
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Checklist
|
|
481
|
+
|
|
482
|
+
Before using Asana integration:
|
|
483
|
+
|
|
484
|
+
- [ ] Personal Access Token generated
|
|
485
|
+
- [ ] Workspace GID configured
|
|
486
|
+
- [ ] Default project set
|
|
487
|
+
- [ ] Section GIDs mapped for status workflow
|
|
488
|
+
- [ ] Custom field GIDs identified (if used)
|
|
489
|
+
- [ ] Webhook endpoint set up (if needed)
|
|
490
|
+
- [ ] Webhook handshake implemented
|
|
491
|
+
- [ ] opt_fields used in all requests
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## Related Skills
|
|
496
|
+
|
|
497
|
+
- `session-management` - Session lifecycle
|
|
498
|
+
- `scheduled-actions` - Background task processing
|
|
499
|
+
- `service-layer` - API implementation patterns
|