@onion-ai/cli 1.0.0-beta.1
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 +529 -0
- package/bin/onion.js +6 -0
- package/framework/CLAUDE.md +45 -0
- package/framework/VERSION +1 -0
- package/framework/agents/compliance/iso-22301-specialist.md +985 -0
- package/framework/agents/compliance/iso-27001-specialist.md +713 -0
- package/framework/agents/compliance/pmbok-specialist.md +739 -0
- package/framework/agents/compliance/security-information-master.md +907 -0
- package/framework/agents/compliance/soc2-specialist.md +889 -0
- package/framework/agents/deployment/docker-specialist.md +1192 -0
- package/framework/agents/development/c4-architecture-specialist.md +745 -0
- package/framework/agents/development/c4-documentation-specialist.md +695 -0
- package/framework/agents/development/clickup-specialist.md +396 -0
- package/framework/agents/development/cursor-specialist.md +277 -0
- package/framework/agents/development/docs-reverse-engineer.md +417 -0
- package/framework/agents/development/gamma-api-specialist.md +1168 -0
- package/framework/agents/development/gitflow-specialist.md +1206 -0
- package/framework/agents/development/linux-security-specialist.md +675 -0
- package/framework/agents/development/mermaid-specialist.md +515 -0
- package/framework/agents/development/nodejs-specialist.md +672 -0
- package/framework/agents/development/nx-migration-specialist.md +866 -0
- package/framework/agents/development/nx-monorepo-specialist.md +618 -0
- package/framework/agents/development/postgres-specialist.md +1123 -0
- package/framework/agents/development/react-developer.md +131 -0
- package/framework/agents/development/runflow-specialist.md +277 -0
- package/framework/agents/development/system-documentation-orchestrator.md +1387 -0
- package/framework/agents/development/task-specialist.md +677 -0
- package/framework/agents/git/branch-code-reviewer.md +225 -0
- package/framework/agents/git/branch-documentation-writer.md +161 -0
- package/framework/agents/git/branch-metaspec-checker.md +67 -0
- package/framework/agents/git/branch-test-planner.md +176 -0
- package/framework/agents/meta/agent-creator-specialist.md +1266 -0
- package/framework/agents/meta/command-creator-specialist.md +1676 -0
- package/framework/agents/meta/metaspec-gate-keeper.md +240 -0
- package/framework/agents/meta/onion.md +824 -0
- package/framework/agents/product/branding-positioning-specialist.md +1029 -0
- package/framework/agents/product/extract-meeting-specialist.md +394 -0
- package/framework/agents/product/meeting-consolidator.md +482 -0
- package/framework/agents/product/pain-price-specialist.md +508 -0
- package/framework/agents/product/presentation-orchestrator.md +1190 -0
- package/framework/agents/product/product-agent.md +201 -0
- package/framework/agents/product/story-points-framework-specialist.md +538 -0
- package/framework/agents/product/storytelling-business-specialist.md +890 -0
- package/framework/agents/research/research-agent.md +292 -0
- package/framework/agents/review/code-reviewer.md +154 -0
- package/framework/agents/review/corporate-compliance-specialist.md +370 -0
- package/framework/agents/testing/test-agent.md +424 -0
- package/framework/agents/testing/test-engineer.md +294 -0
- package/framework/agents/testing/test-planner.md +117 -0
- package/framework/commands/common/prompts/README.md +208 -0
- package/framework/commands/common/prompts/clickup-patterns.md +144 -0
- package/framework/commands/common/prompts/code-review-checklist.md +168 -0
- package/framework/commands/common/prompts/git-workflow-patterns.md +235 -0
- package/framework/commands/common/prompts/output-formats.md +240 -0
- package/framework/commands/common/prompts/technical.md +194 -0
- package/framework/commands/common/templates/abstraction-template.md +399 -0
- package/framework/commands/common/templates/agent-template.md +353 -0
- package/framework/commands/common/templates/business_context_template.md +748 -0
- package/framework/commands/common/templates/command-template.md +273 -0
- package/framework/commands/common/templates/technical_context_template.md +526 -0
- package/framework/commands/design/screen-spec.md +505 -0
- package/framework/commands/development/runflow-dev.md +465 -0
- package/framework/commands/docs/build-business-docs.md +299 -0
- package/framework/commands/docs/build-compliance-docs.md +143 -0
- package/framework/commands/docs/build-index.md +119 -0
- package/framework/commands/docs/build-tech-docs.md +221 -0
- package/framework/commands/docs/docs-health.md +141 -0
- package/framework/commands/docs/help.md +278 -0
- package/framework/commands/docs/refine-vision.md +25 -0
- package/framework/commands/docs/reverse-consolidate.md +158 -0
- package/framework/commands/docs/sync-sessions.md +354 -0
- package/framework/commands/docs/validate-docs.md +157 -0
- package/framework/commands/engineer/bump.md +29 -0
- package/framework/commands/engineer/docs.md +11 -0
- package/framework/commands/engineer/hotfix.md +183 -0
- package/framework/commands/engineer/plan.md +85 -0
- package/framework/commands/engineer/pr-update.md +219 -0
- package/framework/commands/engineer/pr.md +117 -0
- package/framework/commands/engineer/pre-pr.md +81 -0
- package/framework/commands/engineer/start.md +254 -0
- package/framework/commands/engineer/validate-phase-sync.md +134 -0
- package/framework/commands/engineer/warm-up.md +20 -0
- package/framework/commands/engineer/work.md +155 -0
- package/framework/commands/f/company-context-extractor.md +93 -0
- package/framework/commands/f/process-meetings.md +103 -0
- package/framework/commands/git/README.md +682 -0
- package/framework/commands/git/code-review.md +213 -0
- package/framework/commands/git/fast-commit.md +43 -0
- package/framework/commands/git/feature/finish.md +88 -0
- package/framework/commands/git/feature/publish.md +89 -0
- package/framework/commands/git/feature/start.md +172 -0
- package/framework/commands/git/help.md +100 -0
- package/framework/commands/git/hotfix/finish.md +96 -0
- package/framework/commands/git/hotfix/start.md +92 -0
- package/framework/commands/git/init.md +111 -0
- package/framework/commands/git/release/finish.md +96 -0
- package/framework/commands/git/release/start.md +93 -0
- package/framework/commands/git/sync.md +199 -0
- package/framework/commands/meta/all-tools.md +58 -0
- package/framework/commands/meta/analyze-complex-problem.md +186 -0
- package/framework/commands/meta/create-abstraction.md +882 -0
- package/framework/commands/meta/create-agent-express.md +98 -0
- package/framework/commands/meta/create-agent.md +210 -0
- package/framework/commands/meta/create-command.md +203 -0
- package/framework/commands/meta/create-knowledge-base.md +143 -0
- package/framework/commands/meta/create-task-structure.md +150 -0
- package/framework/commands/meta/setup-integration.md +274 -0
- package/framework/commands/onion.md +169 -0
- package/framework/commands/product/README.md +249 -0
- package/framework/commands/product/analyze-pain-price.md +694 -0
- package/framework/commands/product/branding.md +458 -0
- package/framework/commands/product/check.md +46 -0
- package/framework/commands/product/checklist-sync.md +239 -0
- package/framework/commands/product/collect.md +95 -0
- package/framework/commands/product/consolidate-meetings.md +291 -0
- package/framework/commands/product/estimate.md +511 -0
- package/framework/commands/product/extract-meeting.md +226 -0
- package/framework/commands/product/feature.md +416 -0
- package/framework/commands/product/light-arch.md +82 -0
- package/framework/commands/product/presentation.md +174 -0
- package/framework/commands/product/refine.md +161 -0
- package/framework/commands/product/spec.md +79 -0
- package/framework/commands/product/task-check.md +378 -0
- package/framework/commands/product/task.md +603 -0
- package/framework/commands/product/validate-task.md +325 -0
- package/framework/commands/product/warm-up.md +24 -0
- package/framework/commands/quick/analisys.md +17 -0
- package/framework/commands/test/e2e.md +377 -0
- package/framework/commands/test/integration.md +508 -0
- package/framework/commands/test/unit.md +381 -0
- package/framework/commands/validate/collab/pair-testing.md +657 -0
- package/framework/commands/validate/collab/three-amigos.md +534 -0
- package/framework/commands/validate/qa-points/estimate.md +660 -0
- package/framework/commands/validate/test-strategy/analyze.md +1201 -0
- package/framework/commands/validate/test-strategy/create.md +411 -0
- package/framework/commands/validate/workflow.md +370 -0
- package/framework/commands/warm-up.md +20 -0
- package/framework/docs/architecture/acoplamento-clickup-problema-analise.md +468 -0
- package/framework/docs/architecture/desacoplamento-roadmap.md +364 -0
- package/framework/docs/architecture/validacao-fase-1.md +235 -0
- package/framework/docs/c4/c4-detection-rules.md +395 -0
- package/framework/docs/c4/c4-documentation-templates.md +579 -0
- package/framework/docs/c4/c4-mermaid-patterns.md +331 -0
- package/framework/docs/c4/c4-templates.md +256 -0
- package/framework/docs/clickup/clickup-acceptance-criteria-strategy.md +329 -0
- package/framework/docs/clickup/clickup-auto-update-strategy.md +340 -0
- package/framework/docs/clickup/clickup-comment-formatter.md +239 -0
- package/framework/docs/clickup/clickup-description-fix.md +384 -0
- package/framework/docs/clickup/clickup-dual-comment-strategy.md +528 -0
- package/framework/docs/clickup/clickup-formatting.md +302 -0
- package/framework/docs/clickup/separador-tamanho-otimizado.md +258 -0
- package/framework/docs/engineer/pre-pr-acceptance-validation.md +256 -0
- package/framework/docs/onion/ESPERANTO.md +293 -0
- package/framework/docs/onion/agents-reference.md +832 -0
- package/framework/docs/onion/clickup-integration.md +780 -0
- package/framework/docs/onion/commands-guide.md +924 -0
- package/framework/docs/onion/engineering-flows.md +900 -0
- package/framework/docs/onion/getting-started.md +803 -0
- package/framework/docs/onion/maintenance-checklist.md +421 -0
- package/framework/docs/onion/naming-conventions.md +286 -0
- package/framework/docs/onion/practical-examples.md +854 -0
- package/framework/docs/product/story-points-integration.md +269 -0
- package/framework/docs/product/story-points-validation.md +237 -0
- package/framework/docs/reviews/task-manager-docs-review-2025-11-24.md +184 -0
- package/framework/docs/strategies/clickup-comment-patterns.md +766 -0
- package/framework/docs/strategies/clickup-integration-tests.md +602 -0
- package/framework/docs/strategies/clickup-mcp-wrappers-tests.md +888 -0
- package/framework/docs/strategies/clickup-regression-tests.md +587 -0
- package/framework/docs/strategies/visual-patterns.md +315 -0
- package/framework/docs/templates/README.md +649 -0
- package/framework/docs/templates/adr-template.md +226 -0
- package/framework/docs/templates/analysis-template.md +280 -0
- package/framework/docs/templates/execution-plan-template.md +430 -0
- package/framework/docs/templates/guide-template.md +367 -0
- package/framework/docs/templates/phase-execution-prompt-template.md +504 -0
- package/framework/docs/templates/reference-template.md +522 -0
- package/framework/docs/templates/solution-template.md +390 -0
- package/framework/docs/tools/README.md +356 -0
- package/framework/docs/tools/agents.md +365 -0
- package/framework/docs/tools/commands.md +669 -0
- package/framework/docs/tools/cursor.md +539 -0
- package/framework/docs/tools/mcps.md +937 -0
- package/framework/docs/tools/rules.md +461 -0
- package/framework/rules/language-and-documentation.mdc +371 -0
- package/framework/rules/nestjs-controllers.md +83 -0
- package/framework/rules/nestjs-dtos.md +255 -0
- package/framework/rules/nestjs-modules.md +141 -0
- package/framework/rules/nestjs-services.md +230 -0
- package/framework/rules/nx-rules.mdc +41 -0
- package/framework/rules/onion-patterns.mdc +197 -0
- package/framework/skills/codebase-visualizer/SKILL.md +26 -0
- package/framework/skills/codebase-visualizer/scripts/visualize.py +131 -0
- package/framework/skills/collect/SKILL.md +84 -0
- package/framework/skills/create-rule/SKILL.md +152 -0
- package/framework/skills/db-schema-visualizer/SKILL.md +49 -0
- package/framework/skills/db-schema-visualizer/scripts/visualize.py +1191 -0
- package/framework/skills/sync-meetings/SKILL.md +239 -0
- package/framework/utils/clickup-mcp-wrappers.md +744 -0
- package/framework/utils/date-time-standards.md +200 -0
- package/framework/utils/task-manager/README.md +94 -0
- package/framework/utils/task-manager/adapters/asana.md +377 -0
- package/framework/utils/task-manager/adapters/clickup.md +467 -0
- package/framework/utils/task-manager/adapters/linear.md +421 -0
- package/framework/utils/task-manager/detector.md +299 -0
- package/framework/utils/task-manager/factory.md +363 -0
- package/framework/utils/task-manager/interface.md +248 -0
- package/framework/utils/task-manager/types.md +409 -0
- package/package.json +41 -0
- package/src/cli.js +73 -0
- package/src/commands/doctor.js +191 -0
- package/src/commands/init.js +287 -0
- package/src/commands/install.js +261 -0
- package/src/commands/list.js +152 -0
- package/src/commands/uninstall.js +90 -0
- package/src/commands/update.js +26 -0
- package/src/utils/fs.js +89 -0
- package/src/utils/log.js +35 -0
- package/src/utils/paths.js +32 -0
- package/src/utils/prompt.js +76 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# 🔍 Provider Detector - Task Manager
|
|
2
|
+
|
|
3
|
+
## 🎯 Purpose
|
|
4
|
+
|
|
5
|
+
Detects and validates the configured task management provider, and identifies the origin of task IDs to ensure compatibility.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📋 Main Functions
|
|
10
|
+
|
|
11
|
+
### detectProvider()
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
/**
|
|
15
|
+
* Detects the configured provider via environment variables.
|
|
16
|
+
* @returns Active provider configuration
|
|
17
|
+
*/
|
|
18
|
+
function detectProvider(): ProviderConfig {
|
|
19
|
+
const provider = (process.env.TASK_MANAGER_PROVIDER ||
|
|
20
|
+
'none') as TaskManagerProvider;
|
|
21
|
+
|
|
22
|
+
const configs: Record<TaskManagerProvider, ProviderConfig> = {
|
|
23
|
+
clickup: {
|
|
24
|
+
provider: 'clickup',
|
|
25
|
+
isConfigured: !!process.env.CLICKUP_API_TOKEN,
|
|
26
|
+
requiredEnvVars: ['CLICKUP_API_TOKEN'],
|
|
27
|
+
optionalEnvVars: ['CLICKUP_WORKSPACE_ID', 'CLICKUP_DEFAULT_LIST_ID'],
|
|
28
|
+
errorMessage: !process.env.CLICKUP_API_TOKEN
|
|
29
|
+
? '❌ CLICKUP_API_TOKEN not configured. Run /meta/setup-integration'
|
|
30
|
+
: undefined,
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
asana: {
|
|
34
|
+
provider: 'asana',
|
|
35
|
+
isConfigured: !!process.env.ASANA_ACCESS_TOKEN,
|
|
36
|
+
requiredEnvVars: ['ASANA_ACCESS_TOKEN'],
|
|
37
|
+
optionalEnvVars: ['ASANA_WORKSPACE_ID', 'ASANA_DEFAULT_PROJECT_ID'],
|
|
38
|
+
errorMessage: !process.env.ASANA_ACCESS_TOKEN
|
|
39
|
+
? '❌ ASANA_ACCESS_TOKEN not configured. Run /meta/setup-integration'
|
|
40
|
+
: undefined,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
linear: {
|
|
44
|
+
provider: 'linear',
|
|
45
|
+
isConfigured: !!process.env.LINEAR_API_KEY,
|
|
46
|
+
requiredEnvVars: ['LINEAR_API_KEY'],
|
|
47
|
+
optionalEnvVars: ['LINEAR_TEAM_ID'],
|
|
48
|
+
errorMessage: !process.env.LINEAR_API_KEY
|
|
49
|
+
? '❌ LINEAR_API_KEY not configured. Run /meta/setup-integration'
|
|
50
|
+
: undefined,
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
none: {
|
|
54
|
+
provider: 'none',
|
|
55
|
+
isConfigured: true, // Always "configured" as it's the fallback
|
|
56
|
+
requiredEnvVars: [],
|
|
57
|
+
optionalEnvVars: [],
|
|
58
|
+
errorMessage: undefined,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return configs[provider] || configs.none;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### detectProviderFromTaskId()
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
/**
|
|
72
|
+
* Detects the source provider based on task ID format.
|
|
73
|
+
* @param taskId - Task ID to analyze
|
|
74
|
+
* @returns Detected provider or null if format is unknown
|
|
75
|
+
*/
|
|
76
|
+
function detectProviderFromTaskId(taskId: string): TaskManagerProvider | null {
|
|
77
|
+
if (!taskId || typeof taskId !== 'string') {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const trimmedId = taskId.trim();
|
|
82
|
+
|
|
83
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
84
|
+
// CLICKUP
|
|
85
|
+
// Format: alphanumeric, 9 characters (e.g., 86adfe9eb, abc123def)
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
87
|
+
if (/^[a-z0-9]{9}$/i.test(trimmedId)) {
|
|
88
|
+
return 'clickup';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
92
|
+
// ASANA
|
|
93
|
+
// Format: numeric, 16+ digits (e.g., 1234567890123456)
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
|
+
if (/^\d{15,}$/.test(trimmedId)) {
|
|
96
|
+
return 'asana';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
100
|
+
// LINEAR
|
|
101
|
+
// Formats:
|
|
102
|
+
// - Prefix + number: ABC-123, PROJ-456
|
|
103
|
+
// - UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
104
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
105
|
+
if (/^[A-Z]+-\d+$/.test(trimmedId)) {
|
|
106
|
+
return 'linear';
|
|
107
|
+
}
|
|
108
|
+
if (
|
|
109
|
+
/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(
|
|
110
|
+
trimmedId,
|
|
111
|
+
)
|
|
112
|
+
) {
|
|
113
|
+
return 'linear';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
117
|
+
// LOCAL (generated by NoProviderAdapter)
|
|
118
|
+
// Format: local-timestamp (e.g., local-1732456789012)
|
|
119
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
120
|
+
if (/^local-\d+$/.test(trimmedId)) {
|
|
121
|
+
return 'none';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Unknown format
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### validateProviderMatch()
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
/**
|
|
135
|
+
* Validates if a task ID is compatible with the configured provider.
|
|
136
|
+
* @param taskId - Task ID to validate
|
|
137
|
+
* @param currentProvider - Currently configured provider
|
|
138
|
+
* @returns Validation result with possible warning
|
|
139
|
+
*/
|
|
140
|
+
function validateProviderMatch(
|
|
141
|
+
taskId: string,
|
|
142
|
+
currentProvider: TaskManagerProvider,
|
|
143
|
+
): ValidationResult {
|
|
144
|
+
const detectedProvider = detectProviderFromTaskId(taskId);
|
|
145
|
+
|
|
146
|
+
// Unknown format - assume valid
|
|
147
|
+
if (!detectedProvider) {
|
|
148
|
+
return {
|
|
149
|
+
valid: true,
|
|
150
|
+
warning: null,
|
|
151
|
+
detectedProvider: null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 'none' provider accepts any ID (offline mode)
|
|
156
|
+
if (currentProvider === 'none') {
|
|
157
|
+
return {
|
|
158
|
+
valid: true,
|
|
159
|
+
warning:
|
|
160
|
+
`ℹ️ Task ID "${taskId}" detected as ${detectedProvider}, ` +
|
|
161
|
+
`but no provider is configured. Operating in local mode.`,
|
|
162
|
+
detectedProvider,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Different providers - incompatibility
|
|
167
|
+
if (detectedProvider !== currentProvider) {
|
|
168
|
+
return {
|
|
169
|
+
valid: false,
|
|
170
|
+
warning:
|
|
171
|
+
`⚠️ INCOMPATIBILITY DETECTED\n` +
|
|
172
|
+
`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n` +
|
|
173
|
+
`Task ID: "${taskId}"\n` +
|
|
174
|
+
`Detected provider: ${detectedProvider}\n` +
|
|
175
|
+
`Configured provider: ${currentProvider}\n\n` +
|
|
176
|
+
`💡 Suggested actions:\n` +
|
|
177
|
+
` 1. Change TASK_MANAGER_PROVIDER to '${detectedProvider}' in .env\n` +
|
|
178
|
+
` 2. Or clear the current session and create a new task\n` +
|
|
179
|
+
` 3. Run /meta/setup-integration to reconfigure`,
|
|
180
|
+
detectedProvider,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// All OK
|
|
185
|
+
return {
|
|
186
|
+
valid: true,
|
|
187
|
+
warning: null,
|
|
188
|
+
detectedProvider,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### checkProviderConfiguration()
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
/**
|
|
199
|
+
* Checks the complete provider configuration.
|
|
200
|
+
* @returns Object with status and messages
|
|
201
|
+
*/
|
|
202
|
+
function checkProviderConfiguration(): {
|
|
203
|
+
provider: TaskManagerProvider;
|
|
204
|
+
isConfigured: boolean;
|
|
205
|
+
missingVars: string[];
|
|
206
|
+
optionalVars: { name: string; set: boolean }[];
|
|
207
|
+
message: string;
|
|
208
|
+
} {
|
|
209
|
+
const config = detectProvider();
|
|
210
|
+
|
|
211
|
+
const missingVars = config.requiredEnvVars.filter(
|
|
212
|
+
(varName) => !process.env[varName],
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const optionalVars = config.optionalEnvVars.map((varName) => ({
|
|
216
|
+
name: varName,
|
|
217
|
+
set: !!process.env[varName],
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
let message: string;
|
|
221
|
+
|
|
222
|
+
if (config.provider === 'none') {
|
|
223
|
+
message =
|
|
224
|
+
`ℹ️ No task manager configured.\n` +
|
|
225
|
+
`Commands will work in offline mode.\n` +
|
|
226
|
+
`Run /meta/setup-integration to configure.`;
|
|
227
|
+
} else if (!config.isConfigured) {
|
|
228
|
+
message =
|
|
229
|
+
`❌ ${config.provider.toUpperCase()} selected but not configured.\n` +
|
|
230
|
+
`Missing variables: ${missingVars.join(', ')}\n` +
|
|
231
|
+
`Run /meta/setup-integration to configure.`;
|
|
232
|
+
} else {
|
|
233
|
+
const optionalStatus = optionalVars
|
|
234
|
+
.map((v) => ` ${v.set ? '✅' : '⚪'} ${v.name}`)
|
|
235
|
+
.join('\n');
|
|
236
|
+
|
|
237
|
+
message =
|
|
238
|
+
`✅ ${config.provider.toUpperCase()} configured correctly.\n` +
|
|
239
|
+
`Optional variables:\n${optionalStatus}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
provider: config.provider,
|
|
244
|
+
isConfigured: config.isConfigured,
|
|
245
|
+
missingVars,
|
|
246
|
+
optionalVars,
|
|
247
|
+
message,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 📊 ID Format Table
|
|
255
|
+
|
|
256
|
+
| Provider | Format | Regex | Example |
|
|
257
|
+
| ------------- | -------------------- | --------------- | ------------------ |
|
|
258
|
+
| ClickUp | 9 alphanumeric chars | `^[a-z0-9]{9}$` | `86adfe9eb` |
|
|
259
|
+
| Asana | 15+ digits | `^\d{15,}$` | `1234567890123456` |
|
|
260
|
+
| Linear (ID) | PREFIX-NUMBER | `^[A-Z]+-\d+$` | `DEV-123` |
|
|
261
|
+
| Linear (UUID) | UUID v4 | UUID regex | `a1b2c3d4-...` |
|
|
262
|
+
| Local | local-timestamp | `^local-\d+$` | `local-1732456789` |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 🧪 Usage Examples
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Detect configured provider
|
|
270
|
+
const config = detectProvider();
|
|
271
|
+
console.log(`Provider: ${config.provider}`);
|
|
272
|
+
console.log(`Configured: ${config.isConfigured}`);
|
|
273
|
+
|
|
274
|
+
// Validate task ID
|
|
275
|
+
const taskId = '86adfe9eb';
|
|
276
|
+
const currentProvider = 'asana';
|
|
277
|
+
const validation = validateProviderMatch(taskId, currentProvider);
|
|
278
|
+
|
|
279
|
+
if (!validation.valid) {
|
|
280
|
+
console.warn(validation.warning);
|
|
281
|
+
// Ask the user what to do
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Check complete configuration
|
|
285
|
+
const status = checkProviderConfiguration();
|
|
286
|
+
console.log(status.message);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 📚 References
|
|
292
|
+
|
|
293
|
+
- [Types](./types.md) - Type definitions
|
|
294
|
+
- [Factory](./factory.md) - Adapter creation
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
**Version**: 1.0.0
|
|
299
|
+
**Created**: 2025-11-24
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# 🏭 Factory - Task Manager
|
|
2
|
+
|
|
3
|
+
## 🎯 Propósito
|
|
4
|
+
|
|
5
|
+
Fornece uma factory para instanciar o adapter correto baseado na configuração do ambiente, abstraindo a criação e permitindo uso simplificado nos comandos.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📋 Função Principal
|
|
10
|
+
|
|
11
|
+
### getTaskManager()
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
/**
|
|
15
|
+
* Retorna uma instância do TaskManager configurado.
|
|
16
|
+
* Baseado em TASK_MANAGER_PROVIDER no .env
|
|
17
|
+
*
|
|
18
|
+
* @param options - Opções de configuração (opcional)
|
|
19
|
+
* @returns Instância do adapter apropriado
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const tm = getTaskManager();
|
|
23
|
+
* const task = await tm.createTask({ name: 'Nova Task' });
|
|
24
|
+
*/
|
|
25
|
+
function getTaskManager(options?: FactoryOptions): ITaskManager {
|
|
26
|
+
const config = detectProvider();
|
|
27
|
+
|
|
28
|
+
// Log de debug (se habilitado)
|
|
29
|
+
if (options?.debug) {
|
|
30
|
+
console.log(`[TaskManager] Provider: ${config.provider}`);
|
|
31
|
+
console.log(`[TaskManager] Configured: ${config.isConfigured}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Se não está configurado, decidir comportamento
|
|
35
|
+
if (!config.isConfigured) {
|
|
36
|
+
if (options?.throwOnMisconfigured) {
|
|
37
|
+
throw new Error(config.errorMessage || 'Provider not configured');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Aviso e fallback para NoProviderAdapter
|
|
41
|
+
console.warn(`⚠️ ${config.errorMessage}`);
|
|
42
|
+
console.warn(`💡 Continuando em modo offline...`);
|
|
43
|
+
return new NoProviderAdapter();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Instanciar adapter apropriado
|
|
47
|
+
switch (config.provider) {
|
|
48
|
+
case 'clickup':
|
|
49
|
+
return new ClickUpAdapter({
|
|
50
|
+
apiToken: process.env.CLICKUP_API_TOKEN!,
|
|
51
|
+
workspaceId: process.env.CLICKUP_WORKSPACE_ID,
|
|
52
|
+
defaultListId: process.env.CLICKUP_DEFAULT_LIST_ID
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
case 'asana':
|
|
56
|
+
return new AsanaAdapter({
|
|
57
|
+
accessToken: process.env.ASANA_ACCESS_TOKEN!,
|
|
58
|
+
workspaceId: process.env.ASANA_WORKSPACE_ID,
|
|
59
|
+
defaultProjectId: process.env.ASANA_DEFAULT_PROJECT_ID
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
case 'linear':
|
|
63
|
+
return new LinearAdapter({
|
|
64
|
+
apiKey: process.env.LINEAR_API_KEY!,
|
|
65
|
+
teamId: process.env.LINEAR_TEAM_ID
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
case 'none':
|
|
69
|
+
default:
|
|
70
|
+
return new NoProviderAdapter();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## ⚙️ Tipos da Factory
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
/**
|
|
81
|
+
* Opções para a factory.
|
|
82
|
+
*/
|
|
83
|
+
interface FactoryOptions {
|
|
84
|
+
/** Habilita logs de debug */
|
|
85
|
+
debug?: boolean;
|
|
86
|
+
|
|
87
|
+
/** Lança erro se provedor não configurado (ao invés de fallback) */
|
|
88
|
+
throwOnMisconfigured?: boolean;
|
|
89
|
+
|
|
90
|
+
/** Força um provedor específico (ignora .env) */
|
|
91
|
+
forceProvider?: TaskManagerProvider;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Configuração para ClickUp Adapter.
|
|
96
|
+
*/
|
|
97
|
+
interface ClickUpAdapterConfig {
|
|
98
|
+
apiToken: string;
|
|
99
|
+
workspaceId?: string;
|
|
100
|
+
defaultListId?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Configuração para Asana Adapter.
|
|
105
|
+
*/
|
|
106
|
+
interface AsanaAdapterConfig {
|
|
107
|
+
accessToken: string;
|
|
108
|
+
workspaceId?: string;
|
|
109
|
+
defaultProjectId?: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Configuração para Linear Adapter.
|
|
114
|
+
*/
|
|
115
|
+
interface LinearAdapterConfig {
|
|
116
|
+
apiKey: string;
|
|
117
|
+
teamId?: string;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 🔄 Funções Auxiliares
|
|
124
|
+
|
|
125
|
+
### getTaskManagerOrFail()
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
/**
|
|
129
|
+
* Versão da factory que lança erro se não configurado.
|
|
130
|
+
* Útil para comandos que REQUEREM um provedor.
|
|
131
|
+
*
|
|
132
|
+
* @throws Error se provedor não configurado
|
|
133
|
+
*/
|
|
134
|
+
function getTaskManagerOrFail(): ITaskManager {
|
|
135
|
+
return getTaskManager({ throwOnMisconfigured: true });
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### getTaskManagerWithWarning()
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
/**
|
|
143
|
+
* Versão da factory que mostra warning formatado.
|
|
144
|
+
* Útil para comandos que podem funcionar sem provedor.
|
|
145
|
+
*
|
|
146
|
+
* @returns Adapter + flag indicando se está em modo offline
|
|
147
|
+
*/
|
|
148
|
+
function getTaskManagerWithWarning(): {
|
|
149
|
+
taskManager: ITaskManager;
|
|
150
|
+
isOffline: boolean;
|
|
151
|
+
warning?: string;
|
|
152
|
+
} {
|
|
153
|
+
const config = detectProvider();
|
|
154
|
+
const taskManager = getTaskManager();
|
|
155
|
+
|
|
156
|
+
if (config.provider === 'none' || !config.isConfigured) {
|
|
157
|
+
return {
|
|
158
|
+
taskManager,
|
|
159
|
+
isOffline: true,
|
|
160
|
+
warning: `⚠️ MODO OFFLINE ATIVADO
|
|
161
|
+
━━━━━━━━━━━━━━━━━━━━━━━━
|
|
162
|
+
Nenhum gerenciador de tarefas configurado.
|
|
163
|
+
|
|
164
|
+
Funcionalidades disponíveis:
|
|
165
|
+
✅ Criar documentos locais
|
|
166
|
+
✅ Gerar estrutura de sessão
|
|
167
|
+
❌ Sincronizar com ClickUp/Asana/Linear
|
|
168
|
+
❌ Atualizar status de tasks
|
|
169
|
+
|
|
170
|
+
💡 Para habilitar sincronização:
|
|
171
|
+
Execute /meta/setup-integration
|
|
172
|
+
━━━━━━━━━━━━━━━━━━━━━━━━`
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
taskManager,
|
|
178
|
+
isOffline: false
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 📊 Classe Base NoProviderAdapter
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
/**
|
|
189
|
+
* Adapter de fallback quando nenhum provedor está configurado.
|
|
190
|
+
* Permite operações locais e gera IDs locais.
|
|
191
|
+
*/
|
|
192
|
+
class NoProviderAdapter implements ITaskManager {
|
|
193
|
+
readonly provider: TaskManagerProvider = 'none';
|
|
194
|
+
readonly isConfigured: boolean = false;
|
|
195
|
+
|
|
196
|
+
async createTask(input: CreateTaskInput): Promise<TaskOutput> {
|
|
197
|
+
console.warn('⚠️ Criando task LOCAL (não sincronizada)');
|
|
198
|
+
|
|
199
|
+
const localId = `local-${Date.now()}`;
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
id: localId,
|
|
203
|
+
provider: 'none',
|
|
204
|
+
name: input.name,
|
|
205
|
+
description: input.description || '',
|
|
206
|
+
status: 'todo',
|
|
207
|
+
url: '', // Sem URL pois é local
|
|
208
|
+
createdAt: new Date().toISOString(),
|
|
209
|
+
updatedAt: new Date().toISOString(),
|
|
210
|
+
assignees: [],
|
|
211
|
+
tags: input.tags || [],
|
|
212
|
+
dueDate: input.dueDate,
|
|
213
|
+
priority: input.priority
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async getTask(taskId: string): Promise<TaskOutput> {
|
|
218
|
+
console.warn(`⚠️ getTask('${taskId}') - Operando em modo offline`);
|
|
219
|
+
throw new Error('Operação não disponível em modo offline');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async updateTask(taskId: string, updates: UpdateTaskInput): Promise<TaskOutput> {
|
|
223
|
+
console.warn(`⚠️ updateTask('${taskId}') - Operando em modo offline`);
|
|
224
|
+
throw new Error('Operação não disponível em modo offline');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async deleteTask(taskId: string): Promise<boolean> {
|
|
228
|
+
console.warn(`⚠️ deleteTask('${taskId}') - Operando em modo offline`);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async createSubtask(parentId: string, input: CreateTaskInput): Promise<TaskOutput> {
|
|
233
|
+
console.warn('⚠️ Criando subtask LOCAL (não sincronizada)');
|
|
234
|
+
|
|
235
|
+
const localId = `local-${Date.now()}-sub`;
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
id: localId,
|
|
239
|
+
provider: 'none',
|
|
240
|
+
name: input.name,
|
|
241
|
+
description: input.description || '',
|
|
242
|
+
status: 'todo',
|
|
243
|
+
url: '',
|
|
244
|
+
createdAt: new Date().toISOString(),
|
|
245
|
+
updatedAt: new Date().toISOString(),
|
|
246
|
+
assignees: [],
|
|
247
|
+
tags: input.tags || [],
|
|
248
|
+
parent: parentId
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async getSubtasks(parentId: string): Promise<TaskOutput[]> {
|
|
253
|
+
console.warn(`⚠️ getSubtasks('${parentId}') - Operando em modo offline`);
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async addComment(taskId: string, comment: string): Promise<CommentOutput> {
|
|
258
|
+
console.warn(`⚠️ addComment('${taskId}') - Operando em modo offline`);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
id: `local-comment-${Date.now()}`,
|
|
262
|
+
text: comment,
|
|
263
|
+
author: { id: 'local', name: 'Local User' },
|
|
264
|
+
createdAt: new Date().toISOString()
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async getComments(taskId: string): Promise<CommentOutput[]> {
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async updateStatus(taskId: string, status: TaskStatus): Promise<TaskOutput> {
|
|
273
|
+
console.warn(`⚠️ updateStatus('${taskId}', '${status}') - Operando em modo offline`);
|
|
274
|
+
throw new Error('Operação não disponível em modo offline');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async searchTasks(query: SearchQuery): Promise<TaskOutput[]> {
|
|
278
|
+
console.warn('⚠️ searchTasks() - Operando em modo offline');
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async getProjectList(): Promise<ProjectOutput[]> {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async getProject(projectId: string): Promise<ProjectOutput> {
|
|
287
|
+
throw new Error('Operação não disponível em modo offline');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
validateTaskId(taskId: string): boolean {
|
|
291
|
+
return /^local-\d+(-sub)?$/.test(taskId);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
getProviderFromTaskId(taskId: string): TaskManagerProvider | null {
|
|
295
|
+
return detectProviderFromTaskId(taskId);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 🧪 Exemplos de Uso
|
|
303
|
+
|
|
304
|
+
### Uso Básico
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// Obter adapter configurado
|
|
308
|
+
const taskManager = getTaskManager();
|
|
309
|
+
|
|
310
|
+
// Verificar se está online
|
|
311
|
+
if (taskManager.isConfigured) {
|
|
312
|
+
const task = await taskManager.createTask({
|
|
313
|
+
name: 'Minha Task',
|
|
314
|
+
description: 'Descrição'
|
|
315
|
+
});
|
|
316
|
+
console.log(`✅ Task criada: ${task.url}`);
|
|
317
|
+
} else {
|
|
318
|
+
console.log('⚠️ Modo offline - task não será sincronizada');
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Uso com Validação
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Requer provedor configurado
|
|
326
|
+
try {
|
|
327
|
+
const taskManager = getTaskManagerOrFail();
|
|
328
|
+
await taskManager.updateStatus(taskId, 'done');
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error('❌ Provedor não configurado');
|
|
331
|
+
// Sugerir /meta/setup-integration
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Uso com Warning
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Mostrar warning se offline
|
|
339
|
+
const { taskManager, isOffline, warning } = getTaskManagerWithWarning();
|
|
340
|
+
|
|
341
|
+
if (isOffline) {
|
|
342
|
+
console.log(warning);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Continuar com funcionalidade limitada
|
|
346
|
+
const task = await taskManager.createTask({
|
|
347
|
+
name: 'Task pode ser local'
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## 📚 Referências
|
|
354
|
+
|
|
355
|
+
- [Interface ITaskManager](./interface.md)
|
|
356
|
+
- [Detector](./detector.md)
|
|
357
|
+
- [Adapters](./adapters/)
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
**Versão**: 1.0.0
|
|
362
|
+
**Criado em**: 2025-11-24
|
|
363
|
+
|