amazingteam 3.0.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/.ai-team/agents/architect.md +144 -0
- package/.ai-team/agents/ci-analyst.md +188 -0
- package/.ai-team/agents/developer.md +176 -0
- package/.ai-team/agents/planner.md +355 -0
- package/.ai-team/agents/qa.md +189 -0
- package/.ai-team/agents/reviewer.md +211 -0
- package/.ai-team/agents/triage.md +146 -0
- package/.ai-team/commands/ci-analyze.md +116 -0
- package/.ai-team/commands/design.md +100 -0
- package/.ai-team/commands/implement.md +108 -0
- package/.ai-team/commands/release-check.md +142 -0
- package/.ai-team/commands/review.md +142 -0
- package/.ai-team/commands/test.md +115 -0
- package/.ai-team/commands/triage.md +138 -0
- package/.ai-team/memory/architect/architecture_notes.md +67 -0
- package/.ai-team/memory/architect/design_rationale.md +113 -0
- package/.ai-team/memory/architect/module_map.md +84 -0
- package/.ai-team/memory/ci-analyst/failure_patterns.md +102 -0
- package/.ai-team/memory/ci-analyst/runbook_references.md +87 -0
- package/.ai-team/memory/developer/bug_investigation.md +102 -0
- package/.ai-team/memory/developer/build_issues.md +115 -0
- package/.ai-team/memory/developer/implementation_notes.md +83 -0
- package/.ai-team/memory/failures/failure_library.md +103 -0
- package/.ai-team/memory/planner/decomposition_notes.md +82 -0
- package/.ai-team/memory/planner/flow_rules.md +86 -0
- package/.ai-team/memory/planner/github_issue_patterns.md +229 -0
- package/.ai-team/memory/qa/regression_cases.md +101 -0
- package/.ai-team/memory/qa/test_strategy.md +138 -0
- package/.ai-team/memory/qa/validation_notes.md +110 -0
- package/.ai-team/memory/reviewer/quality_rules.md +105 -0
- package/.ai-team/memory/reviewer/recurring_risks.md +109 -0
- package/.ai-team/memory/reviewer/review_notes.md +124 -0
- package/.ai-team/memory/triage/classification_heuristics.md +82 -0
- package/.ai-team/memory/triage/debug_notes.md +87 -0
- package/.ai-team/opencode.template.jsonc +216 -0
- package/.ai-team/skills/bugfix-playbook/skill.md +174 -0
- package/.ai-team/skills/ci-failure-analysis/skill.md +176 -0
- package/.ai-team/skills/issue-triage/skill.md +163 -0
- package/.ai-team/skills/regression-checklist/skill.md +176 -0
- package/.ai-team/skills/release-readiness-check/skill.md +216 -0
- package/.ai-team/skills/repo-architecture-reader/skill.md +139 -0
- package/.ai-team/skills/safe-refactor-checklist/skill.md +215 -0
- package/.ai-team/skills/task-breakdown-and-dispatch/skill.md +151 -0
- package/.ai-team/skills/test-first-feature-dev/skill.md +205 -0
- package/.ai-team/workflows/ci.yml +81 -0
- package/.ai-team/workflows/nightly-ai-maintenance.yml +129 -0
- package/.ai-team/workflows/opencode.yml +33 -0
- package/.ai-team/workflows/pr-check.yml +41 -0
- package/.foundation/foundation.lock +38 -0
- package/.foundation/local-overrides.md +97 -0
- package/.foundation/upgrade-history.md +38 -0
- package/.opencode/agents/architect.md +38 -0
- package/.opencode/agents/ci-analyst.md +38 -0
- package/.opencode/agents/developer.md +43 -0
- package/.opencode/agents/planner.md +47 -0
- package/.opencode/agents/qa.md +34 -0
- package/.opencode/agents/reviewer.md +38 -0
- package/.opencode/agents/triage.md +37 -0
- package/.opencode/commands/auto.md +264 -0
- package/.opencode/commands/breakdown-issue.md +94 -0
- package/.opencode/commands/ci-analyze.md +15 -0
- package/.opencode/commands/close-parent-task.md +122 -0
- package/.opencode/commands/design.md +15 -0
- package/.opencode/commands/dispatch-next.md +102 -0
- package/.opencode/commands/implement.md +16 -0
- package/.opencode/commands/release-check.md +16 -0
- package/.opencode/commands/resume.md +88 -0
- package/.opencode/commands/review.md +15 -0
- package/.opencode/commands/show-blockers.md +97 -0
- package/.opencode/commands/summarize-parent.md +121 -0
- package/.opencode/commands/test.md +15 -0
- package/.opencode/commands/triage.md +109 -0
- package/.opencode/skills/bugfix-playbook/SKILL.md +81 -0
- package/.opencode/skills/ci-failure-analysis/SKILL.md +94 -0
- package/.opencode/skills/issue-triage/SKILL.md +80 -0
- package/.opencode/skills/regression-checklist/SKILL.md +81 -0
- package/.opencode/skills/release-readiness-check/SKILL.md +81 -0
- package/.opencode/skills/repo-architecture-reader/SKILL.md +65 -0
- package/.opencode/skills/safe-refactor-checklist/SKILL.md +76 -0
- package/.opencode/skills/task-breakdown-and-dispatch/SKILL.md +255 -0
- package/.opencode/skills/test-first-feature-dev/SKILL.md +78 -0
- package/AGENTS.md +879 -0
- package/CHANGELOG.md +261 -0
- package/LICENSE +21 -0
- package/README.md +1215 -0
- package/VERSION +1 -0
- package/action/__tests__/downloader.test.js +251 -0
- package/action/__tests__/merger.test.js +156 -0
- package/action/__tests__/path-resolver.test.js +199 -0
- package/action/__tests__/validator.test.js +310 -0
- package/action/action.yml +61 -0
- package/action/index.js +223 -0
- package/action/lib/downloader.js +344 -0
- package/action/lib/merger.js +170 -0
- package/action/lib/path-resolver.js +176 -0
- package/action/lib/setup.js +286 -0
- package/action/lib/validator.js +324 -0
- package/cli/__tests__/cli.test.js +270 -0
- package/cli/amazingteam.cjs +225 -0
- package/cli/commands/check-update.cjs +159 -0
- package/cli/commands/init.cjs +412 -0
- package/cli/commands/local.cjs +264 -0
- package/cli/commands/migrate.cjs +316 -0
- package/cli/commands/status.cjs +241 -0
- package/cli/commands/upgrade.cjs +213 -0
- package/cli/commands/validate.cjs +259 -0
- package/cli/commands/version.cjs +59 -0
- package/cli/sync.cjs +237 -0
- package/dist/index.js +35 -0
- package/docs/architecture/overview.md +138 -0
- package/docs/blocker_resolution_design.md +372 -0
- package/docs/bootstrap-model.md +356 -0
- package/docs/config-reference.md +458 -0
- package/docs/how-to-use.md +178 -0
- package/docs/migration-to-v3.md +355 -0
- package/docs/overlay-guide.md +156 -0
- package/docs/patterns/README.md +67 -0
- package/docs/quick-start-v3.md +330 -0
- package/docs/releases/README.md +64 -0
- package/docs/runbooks/ci/README.md +62 -0
- package/docs/runbooks/ci/build-debug.md +120 -0
- package/docs/runbooks/ci/flaky-tests.md +127 -0
- package/docs/runbooks/getting-started.md +81 -0
- package/docs/upgrade-policy.md +188 -0
- package/docs/versioning.md +199 -0
- package/overlays/README.md +30 -0
- package/overlays/ai-agent-product/.ai-team/skills/llm-integration/skill.md +99 -0
- package/overlays/ai-agent-product/docs/ai-agent-architecture.md +68 -0
- package/overlays/ai-agent-product/overlay.yaml +26 -0
- package/overlays/cpp-qt-desktop/.ai-team/skills/qt-signals-slots/skill.md +60 -0
- package/overlays/cpp-qt-desktop/docs/qt-conventions.md +64 -0
- package/overlays/cpp-qt-desktop/overlay.yaml +22 -0
- package/overlays/python-backend/.ai-team/skills/python-testing/skill.md +90 -0
- package/overlays/python-backend/docs/python-style.md +78 -0
- package/overlays/python-backend/overlay.yaml +22 -0
- package/overlays/web-fullstack/.ai-team/skills/frontend-testing/skill.md +70 -0
- package/overlays/web-fullstack/docs/frontend-conventions.md +68 -0
- package/overlays/web-fullstack/overlay.yaml +26 -0
- package/package.json +84 -0
- package/presets/default.yaml +161 -0
- package/presets/go.yaml +43 -0
- package/presets/python.yaml +43 -0
- package/presets/typescript.yaml +40 -0
- package/schemas/config.schema.json +239 -0
- package/scripts/diff_foundation_vs_project.sh +134 -0
- package/scripts/generate_docs.sh +200 -0
- package/scripts/init_project.sh +455 -0
- package/scripts/plan_upgrade.sh +268 -0
- package/scripts/upgrade_foundation.sh +365 -0
- package/scripts/validate-foundation.cjs +278 -0
- package/scripts/validate_foundation.sh +192 -0
- package/scripts/validate_project_setup.sh +171 -0
- package/tasks/README.md +94 -0
- package/tasks/_template/analysis.md +76 -0
- package/tasks/_template/design.md +121 -0
- package/tasks/_template/implementation.md +121 -0
- package/tasks/_template/release.md +119 -0
- package/tasks/_template/review.md +131 -0
- package/tasks/_template/subtasks/task.yaml +24 -0
- package/tasks/_template/task.yaml +75 -0
- package/tasks/_template/validation.md +128 -0
- package/templates/amazingteam.yml +81 -0
- package/templates/gitignore +14 -0
- package/templates/opencode.jsonc +216 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command
|
|
3
|
+
* Initialize AmazingTeam in a project
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const readline = require('readline');
|
|
9
|
+
|
|
10
|
+
const VERSION = require('../../package.json').version;
|
|
11
|
+
|
|
12
|
+
const COLORS = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
blue: '\x1b[34m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
cyan: '\x1b[36m'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function log(message, color = 'reset') {
|
|
22
|
+
console.log(`${COLORS[color] || ''}${message}${COLORS.reset}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createRL() {
|
|
26
|
+
return readline.createInterface({
|
|
27
|
+
input: process.stdin,
|
|
28
|
+
output: process.stdout
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function question(rl, prompt, defaultValue = null) {
|
|
33
|
+
return new Promise(resolve => {
|
|
34
|
+
const displayPrompt = defaultValue
|
|
35
|
+
? `${prompt} (${defaultValue}): `
|
|
36
|
+
: `${prompt}: `;
|
|
37
|
+
rl.question(displayPrompt, answer => {
|
|
38
|
+
resolve(answer || defaultValue);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function fileExists(filePath) {
|
|
44
|
+
return fs.existsSync(filePath);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getTemplate(name) {
|
|
48
|
+
const templates = {
|
|
49
|
+
'amazingteam.config.yaml': `# AmazingTeam Project Configuration
|
|
50
|
+
# Generated by amazingteam init
|
|
51
|
+
|
|
52
|
+
version: "1.0"
|
|
53
|
+
|
|
54
|
+
project:
|
|
55
|
+
name: "{{PROJECT_NAME}}"
|
|
56
|
+
description: "{{PROJECT_DESCRIPTION}}"
|
|
57
|
+
language: "{{LANGUAGE}}"
|
|
58
|
+
framework: "{{FRAMEWORK}}"
|
|
59
|
+
|
|
60
|
+
ai_team:
|
|
61
|
+
version: "{{AI_TEAM_VERSION}}"
|
|
62
|
+
|
|
63
|
+
build:
|
|
64
|
+
command: "{{BUILD_COMMAND}}"
|
|
65
|
+
test: "{{TEST_COMMAND}}"
|
|
66
|
+
lint: "{{LINT_COMMAND}}"
|
|
67
|
+
|
|
68
|
+
# Uncomment to use an overlay:
|
|
69
|
+
# overlay: "{{OVERLAY}}"
|
|
70
|
+
|
|
71
|
+
# Custom rules (optional)
|
|
72
|
+
rules:
|
|
73
|
+
test_coverage_threshold: 80
|
|
74
|
+
max_function_lines: 30
|
|
75
|
+
`,
|
|
76
|
+
|
|
77
|
+
'opencode.jsonc': `{
|
|
78
|
+
"$schema": "https://opencode.ai/config.json",
|
|
79
|
+
"model": "default",
|
|
80
|
+
"small_model": "default",
|
|
81
|
+
"default_agent": "build",
|
|
82
|
+
"instructions": ["AGENTS.md"],
|
|
83
|
+
"autoupdate": true,
|
|
84
|
+
"permission": {
|
|
85
|
+
"edit": "ask",
|
|
86
|
+
"bash": "ask"
|
|
87
|
+
},
|
|
88
|
+
"tools": {
|
|
89
|
+
"write": true,
|
|
90
|
+
"edit": true,
|
|
91
|
+
"bash": true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`,
|
|
95
|
+
|
|
96
|
+
'gitignore_additions': `
|
|
97
|
+
# AmazingTeam local foundation (downloaded by \`amazingteam local\`)
|
|
98
|
+
.ai-team-local/
|
|
99
|
+
|
|
100
|
+
# AmazingTeam cache
|
|
101
|
+
.ai-team-cache/
|
|
102
|
+
`
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return templates[name] || '';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getWorkflowTemplate(version) {
|
|
109
|
+
return `# AmazingTeam GitHub Action Workflow
|
|
110
|
+
# This workflow enables AI-powered development in your repository
|
|
111
|
+
|
|
112
|
+
name: AmazingTeam
|
|
113
|
+
|
|
114
|
+
on:
|
|
115
|
+
issue_comment:
|
|
116
|
+
types: [created]
|
|
117
|
+
pull_request_review_comment:
|
|
118
|
+
types: [created]
|
|
119
|
+
|
|
120
|
+
jobs:
|
|
121
|
+
ai-team:
|
|
122
|
+
if: |
|
|
123
|
+
startsWith(github.event.comment.body, '/ai') ||
|
|
124
|
+
startsWith(github.event.comment.body, '/opencode') ||
|
|
125
|
+
startsWith(github.event.comment.body, '/oc')
|
|
126
|
+
|
|
127
|
+
runs-on: ubuntu-latest
|
|
128
|
+
|
|
129
|
+
permissions:
|
|
130
|
+
id-token: write
|
|
131
|
+
contents: write
|
|
132
|
+
pull-requests: write
|
|
133
|
+
issues: write
|
|
134
|
+
|
|
135
|
+
steps:
|
|
136
|
+
- name: Checkout repository
|
|
137
|
+
uses: actions/checkout@v4
|
|
138
|
+
with:
|
|
139
|
+
fetch-depth: 0
|
|
140
|
+
token: \${{ secrets.GITHUB_TOKEN }}
|
|
141
|
+
|
|
142
|
+
- name: Configure git
|
|
143
|
+
run: |
|
|
144
|
+
git config --global user.name "opencode-bot"
|
|
145
|
+
git config --global user.email "opencode-bot@users.noreply.github.com"
|
|
146
|
+
|
|
147
|
+
- name: Setup AmazingTeam
|
|
148
|
+
uses: your-org/amazingteam-action@v${version}
|
|
149
|
+
with:
|
|
150
|
+
version: '${version}'
|
|
151
|
+
config: 'amazingteam.config.yaml'
|
|
152
|
+
|
|
153
|
+
- name: Run OpenCode
|
|
154
|
+
uses: anomalyco/opencode/github@latest
|
|
155
|
+
env:
|
|
156
|
+
ALIBABA_CODING_PLAN_API_KEY: \${{ secrets.ALIBABA_CODING_PLAN_API_KEY }}
|
|
157
|
+
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
158
|
+
with:
|
|
159
|
+
model: alibaba-coding-plan/glm-5
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getLanguageDefaults(language) {
|
|
164
|
+
const defaults = {
|
|
165
|
+
typescript: {
|
|
166
|
+
framework: 'node',
|
|
167
|
+
buildCommand: 'npm run build',
|
|
168
|
+
testCommand: 'npm test',
|
|
169
|
+
lintCommand: 'npm run lint'
|
|
170
|
+
},
|
|
171
|
+
javascript: {
|
|
172
|
+
framework: 'node',
|
|
173
|
+
buildCommand: 'npm run build',
|
|
174
|
+
testCommand: 'npm test',
|
|
175
|
+
lintCommand: 'npm run lint'
|
|
176
|
+
},
|
|
177
|
+
python: {
|
|
178
|
+
framework: 'fastapi',
|
|
179
|
+
buildCommand: 'python -m build',
|
|
180
|
+
testCommand: 'pytest',
|
|
181
|
+
lintCommand: 'ruff check .'
|
|
182
|
+
},
|
|
183
|
+
go: {
|
|
184
|
+
framework: 'gin',
|
|
185
|
+
buildCommand: 'go build ./...',
|
|
186
|
+
testCommand: 'go test ./...',
|
|
187
|
+
lintCommand: 'golangci-lint run'
|
|
188
|
+
},
|
|
189
|
+
java: {
|
|
190
|
+
framework: 'spring',
|
|
191
|
+
buildCommand: './mvnw package',
|
|
192
|
+
testCommand: './mvnw test',
|
|
193
|
+
lintCommand: './mvnw checkstyle:check'
|
|
194
|
+
},
|
|
195
|
+
cpp: {
|
|
196
|
+
framework: 'qt',
|
|
197
|
+
buildCommand: 'cmake --build build',
|
|
198
|
+
testCommand: 'ctest --test-dir build',
|
|
199
|
+
lintCommand: 'clang-tidy'
|
|
200
|
+
},
|
|
201
|
+
rust: {
|
|
202
|
+
framework: 'cargo',
|
|
203
|
+
buildCommand: 'cargo build',
|
|
204
|
+
testCommand: 'cargo test',
|
|
205
|
+
lintCommand: 'cargo clippy'
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
return defaults[language] || defaults.typescript;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function run(options, positional) {
|
|
213
|
+
const rl = createRL();
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
log('\nš AmazingTeam Foundation Initializer\n', 'cyan');
|
|
217
|
+
|
|
218
|
+
const projectPath = process.cwd();
|
|
219
|
+
const projectName = positional[0] || path.basename(projectPath);
|
|
220
|
+
|
|
221
|
+
// Check if already initialized
|
|
222
|
+
const configPath = path.join(projectPath, 'amazingteam.config.yaml');
|
|
223
|
+
if (fileExists(configPath) && !options.force) {
|
|
224
|
+
log('ā ļø AmazingTeam already initialized in this directory.', 'yellow');
|
|
225
|
+
log(' Use --force to reinitialize.\n');
|
|
226
|
+
rl.close();
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Interactive prompts or use options
|
|
231
|
+
let language = options.language;
|
|
232
|
+
let framework = options.framework;
|
|
233
|
+
let description = options.description;
|
|
234
|
+
let overlay = options.overlay;
|
|
235
|
+
|
|
236
|
+
if (!options.language) {
|
|
237
|
+
language = await question(rl, 'Language', 'typescript');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!options.framework) {
|
|
241
|
+
const defaultFramework = getLanguageDefaults(language).framework;
|
|
242
|
+
framework = await question(rl, 'Framework', defaultFramework);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!options.description) {
|
|
246
|
+
description = await question(rl, 'Description', 'My awesome project');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!options.overlay && options.overlay !== null) {
|
|
250
|
+
const overlayAnswer = await question(rl, 'Overlay (leave empty for none)', '');
|
|
251
|
+
overlay = overlayAnswer || null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const langDefaults = getLanguageDefaults(language);
|
|
255
|
+
|
|
256
|
+
log('\nš¦ Creating project structure...', 'blue');
|
|
257
|
+
|
|
258
|
+
// Create directories
|
|
259
|
+
const dirs = [
|
|
260
|
+
'.ai-team/memory/planner',
|
|
261
|
+
'.ai-team/memory/architect',
|
|
262
|
+
'.ai-team/memory/developer',
|
|
263
|
+
'.ai-team/memory/qa',
|
|
264
|
+
'.ai-team/memory/reviewer',
|
|
265
|
+
'.ai-team/memory/triage',
|
|
266
|
+
'.ai-team/memory/ci-analyst',
|
|
267
|
+
'.ai-team/memory/failures',
|
|
268
|
+
'.github/workflows',
|
|
269
|
+
'tasks/_template',
|
|
270
|
+
'src'
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
for (const dir of dirs) {
|
|
274
|
+
const fullPath = path.join(projectPath, dir);
|
|
275
|
+
if (!fileExists(fullPath)) {
|
|
276
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
log('š Creating configuration files...', 'blue');
|
|
281
|
+
|
|
282
|
+
// Generate amazingteam.config.yaml
|
|
283
|
+
let configContent = getTemplate('amazingteam.config.yaml');
|
|
284
|
+
configContent = configContent
|
|
285
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, projectName)
|
|
286
|
+
.replace(/\{\{PROJECT_DESCRIPTION\}\}/g, description)
|
|
287
|
+
.replace(/\{\{LANGUAGE\}\}/g, language)
|
|
288
|
+
.replace(/\{\{FRAMEWORK\}\}/g, framework)
|
|
289
|
+
.replace(/\{\{AI_TEAM_VERSION\}\}/g, VERSION)
|
|
290
|
+
.replace(/\{\{BUILD_COMMAND\}\}/g, langDefaults.buildCommand)
|
|
291
|
+
.replace(/\{\{TEST_COMMAND\}\}/g, langDefaults.testCommand)
|
|
292
|
+
.replace(/\{\{LINT_COMMAND\}\}/g, langDefaults.lintCommand)
|
|
293
|
+
.replace(/\{\{OVERLAY\}\}/g, overlay || '');
|
|
294
|
+
|
|
295
|
+
fs.writeFileSync(configPath, configContent);
|
|
296
|
+
|
|
297
|
+
// Generate opencode.jsonc
|
|
298
|
+
const opencodePath = path.join(projectPath, 'opencode.jsonc');
|
|
299
|
+
fs.writeFileSync(opencodePath, getTemplate('opencode.jsonc'));
|
|
300
|
+
|
|
301
|
+
// Generate workflow
|
|
302
|
+
const workflowPath = path.join(projectPath, '.github', 'workflows', 'amazingteam.yml');
|
|
303
|
+
fs.writeFileSync(workflowPath, getWorkflowTemplate(VERSION));
|
|
304
|
+
|
|
305
|
+
// Update .gitignore
|
|
306
|
+
log('š Updating .gitignore...', 'blue');
|
|
307
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
308
|
+
let gitignoreContent = '';
|
|
309
|
+
|
|
310
|
+
if (fileExists(gitignorePath)) {
|
|
311
|
+
gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
|
|
312
|
+
if (!gitignoreContent.includes('.ai-team-local/')) {
|
|
313
|
+
gitignoreContent += getTemplate('gitignore_additions');
|
|
314
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
fs.writeFileSync(gitignorePath, getTemplate('gitignore_additions').trim() + '\n');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Create placeholder memory files
|
|
321
|
+
log('š Creating memory placeholders...', 'blue');
|
|
322
|
+
const memoryFiles = {
|
|
323
|
+
'planner': ['decomposition_notes.md', 'flow_rules.md'],
|
|
324
|
+
'architect': ['architecture_notes.md', 'module_map.md'],
|
|
325
|
+
'developer': ['implementation_notes.md', 'bug_investigation.md'],
|
|
326
|
+
'qa': ['test_strategy.md', 'validation_notes.md'],
|
|
327
|
+
'reviewer': ['review_notes.md', 'quality_rules.md'],
|
|
328
|
+
'triage': ['classification_heuristics.md', 'debug_notes.md'],
|
|
329
|
+
'ci-analyst': ['failure_patterns.md', 'runbook_references.md'],
|
|
330
|
+
'failures': ['failure_library.md']
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
for (const [role, files] of Object.entries(memoryFiles)) {
|
|
334
|
+
for (const file of files) {
|
|
335
|
+
const filePath = path.join(projectPath, '.ai-team', 'memory', role, file);
|
|
336
|
+
if (!fileExists(filePath)) {
|
|
337
|
+
fs.writeFileSync(filePath, `# ${role} ${file.replace('.md', '').replace(/_/g, ' ')}\n\n`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Create task template
|
|
343
|
+
const taskTemplatePath = path.join(projectPath, 'tasks', '_template', 'task.yaml');
|
|
344
|
+
if (!fileExists(taskTemplatePath)) {
|
|
345
|
+
fs.writeFileSync(taskTemplatePath, `id: template
|
|
346
|
+
title: Task Title
|
|
347
|
+
type: feature
|
|
348
|
+
status: backlog
|
|
349
|
+
priority: medium
|
|
350
|
+
owner_role: developer
|
|
351
|
+
depends_on: []
|
|
352
|
+
blocked_by: []
|
|
353
|
+
acceptance_criteria: []
|
|
354
|
+
risk_level: low
|
|
355
|
+
module_scope: []
|
|
356
|
+
`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
log('\nā
AmazingTeam initialized successfully!\n', 'green');
|
|
360
|
+
|
|
361
|
+
log('Next steps:', 'cyan');
|
|
362
|
+
log(' 1. Review and customize amazingteam.config.yaml');
|
|
363
|
+
log(' 2. Add your GitHub secrets:');
|
|
364
|
+
log(' - ALIBABA_CODING_PLAN_API_KEY or OPENCODE_API_KEY');
|
|
365
|
+
log(' 3. Run `amazingteam local` for local development');
|
|
366
|
+
log(' 4. Create your first issue!\n');
|
|
367
|
+
|
|
368
|
+
log('Configuration:', 'cyan');
|
|
369
|
+
log(` Project: ${projectName}`);
|
|
370
|
+
log(` Language: ${language}`);
|
|
371
|
+
log(` Framework: ${framework}`);
|
|
372
|
+
log(` Version: ${VERSION}`);
|
|
373
|
+
if (overlay) {
|
|
374
|
+
log(` Overlay: ${overlay}`);
|
|
375
|
+
}
|
|
376
|
+
log('');
|
|
377
|
+
|
|
378
|
+
} finally {
|
|
379
|
+
rl.close();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function help() {
|
|
384
|
+
return `
|
|
385
|
+
${COLORS.cyan}amazingteam init${COLORS.reset} - Initialize AmazingTeam in a project
|
|
386
|
+
|
|
387
|
+
${COLORS.yellow}Usage:${COLORS.reset}
|
|
388
|
+
amazingteam init [project-name] [options]
|
|
389
|
+
|
|
390
|
+
${COLORS.yellow}Options:${COLORS.reset}
|
|
391
|
+
--language, -l <lang> Programming language (default: typescript)
|
|
392
|
+
--framework <fw> Framework (default: based on language)
|
|
393
|
+
--overlay, -o <name> Apply overlay (python-backend, web-fullstack, etc.)
|
|
394
|
+
--description, -d <desc> Project description
|
|
395
|
+
--force Force reinitialization
|
|
396
|
+
|
|
397
|
+
${COLORS.yellow}Examples:${COLORS.reset}
|
|
398
|
+
amazingteam init Interactive initialization
|
|
399
|
+
amazingteam init my-project Create project with defaults
|
|
400
|
+
amazingteam init -l python -o python-backend Python with overlay
|
|
401
|
+
amazingteam init --force Reinitialize existing project
|
|
402
|
+
|
|
403
|
+
${COLORS.yellow}Created Files:${COLORS.reset}
|
|
404
|
+
amazingteam.config.yaml Project configuration
|
|
405
|
+
opencode.jsonc OpenCode configuration
|
|
406
|
+
.github/workflows/amazingteam.yml GitHub Action workflow
|
|
407
|
+
.ai-team/memory/ Role memory directories
|
|
408
|
+
tasks/_template/ Task template directory
|
|
409
|
+
`;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
module.exports = { run, help };
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Command
|
|
3
|
+
* Download foundation for local development
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const VERSION = require('../../package.json').version;
|
|
11
|
+
const PACKAGE_NAME = 'amazingteam';
|
|
12
|
+
const REGISTRY = 'https://registry.npmjs.org';
|
|
13
|
+
const CACHE_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.ai-team-cache');
|
|
14
|
+
const LOCAL_DIR = '.ai-team-local';
|
|
15
|
+
|
|
16
|
+
function downloadFromNpm(version, destDir) {
|
|
17
|
+
const url = `${REGISTRY}/${PACKAGE_NAME}/-/${PACKAGE_NAME}-${version}.tgz`;
|
|
18
|
+
const tarballPath = path.join(destDir, `${PACKAGE_NAME}-${version}.tgz`);
|
|
19
|
+
|
|
20
|
+
console.log(`Downloading from NPM: ${url}`);
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
execSync(`curl -L -o "${tarballPath}" "${url}"`, { stdio: 'inherit' });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw new Error(`Failed to download: ${err.message}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return tarballPath;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function extractTarball(tarballPath, destDir) {
|
|
32
|
+
console.log('Extracting...');
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
execSync(`tar -xzf "${tarballPath}" -C "${destDir}"`, { stdio: 'inherit' });
|
|
36
|
+
} catch (err) {
|
|
37
|
+
throw new Error(`Failed to extract: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function readConfig(configPath) {
|
|
42
|
+
if (!fs.existsSync(configPath)) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
47
|
+
const config = {};
|
|
48
|
+
|
|
49
|
+
content.split('\n').forEach(line => {
|
|
50
|
+
const match = line.match(/^(\w+):\s*["']?([^"'\n]+)["']?/);
|
|
51
|
+
if (match) {
|
|
52
|
+
config[match[1]] = match[2];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const nestedMatch = line.match(/^ (\w+):\s*["']?([^"'\n]+)["']?/);
|
|
56
|
+
if (nestedMatch) {
|
|
57
|
+
const parent = line.split(' ')[0]?.match(/^(\w+):/)?.[1];
|
|
58
|
+
if (parent && !config[parent]) {
|
|
59
|
+
config[parent] = {};
|
|
60
|
+
}
|
|
61
|
+
if (config[parent]) {
|
|
62
|
+
config[parent][nestedMatch[1]] = nestedMatch[2];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return config;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function generateLocalOpenCodeConfig(projectDir, foundationDir, config) {
|
|
71
|
+
return `{
|
|
72
|
+
"$schema": "https://opencode.ai/config.json",
|
|
73
|
+
"model": "default",
|
|
74
|
+
"small_model": "default",
|
|
75
|
+
"default_agent": "build",
|
|
76
|
+
"instructions": [
|
|
77
|
+
"${foundationDir}/AGENTS.md",
|
|
78
|
+
"AGENTS.md"
|
|
79
|
+
],
|
|
80
|
+
"autoupdate": true,
|
|
81
|
+
"permission": {
|
|
82
|
+
"edit": "ask",
|
|
83
|
+
"bash": "ask"
|
|
84
|
+
},
|
|
85
|
+
"tools": {
|
|
86
|
+
"write": true,
|
|
87
|
+
"edit": true,
|
|
88
|
+
"bash": true
|
|
89
|
+
},
|
|
90
|
+
"skills": {
|
|
91
|
+
"test-first-feature-dev": {
|
|
92
|
+
"path": "${foundationDir}/.opencode/skills/test-first-feature-dev/SKILL.md"
|
|
93
|
+
},
|
|
94
|
+
"bugfix-playbook": {
|
|
95
|
+
"path": "${foundationDir}/.opencode/skills/bugfix-playbook/SKILL.md"
|
|
96
|
+
},
|
|
97
|
+
"repo-architecture-reader": {
|
|
98
|
+
"path": "${foundationDir}/.opencode/skills/repo-architecture-reader/SKILL.md"
|
|
99
|
+
},
|
|
100
|
+
"task-breakdown-and-dispatch": {
|
|
101
|
+
"path": "${foundationDir}/.opencode/skills/task-breakdown-and-dispatch/SKILL.md"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function run(options, positional) {
|
|
108
|
+
const projectPath = process.cwd();
|
|
109
|
+
const configPath = path.join(projectPath, 'amazingteam.config.yaml');
|
|
110
|
+
const localPath = path.join(projectPath, LOCAL_DIR);
|
|
111
|
+
|
|
112
|
+
console.log('\nš„ Downloading AmazingTeam Foundation for local use\n');
|
|
113
|
+
|
|
114
|
+
// Check if initialized
|
|
115
|
+
if (!fs.existsSync(configPath)) {
|
|
116
|
+
console.error('ā AmazingTeam not initialized in this directory.');
|
|
117
|
+
console.error(' Run "amazingteam init" first.\n');
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Read config
|
|
122
|
+
const config = readConfig(configPath);
|
|
123
|
+
const targetVersion = config?.ai_team?.version || VERSION;
|
|
124
|
+
|
|
125
|
+
console.log(`Target version: ${targetVersion}`);
|
|
126
|
+
|
|
127
|
+
// Check if using local path
|
|
128
|
+
if (options.from) {
|
|
129
|
+
const fromPath = path.resolve(options.from);
|
|
130
|
+
|
|
131
|
+
if (!fs.existsSync(fromPath)) {
|
|
132
|
+
console.error(`ā Local path not found: ${fromPath}\n`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(`Using local foundation: ${fromPath}`);
|
|
137
|
+
|
|
138
|
+
// Create symlink or copy
|
|
139
|
+
if (fs.existsSync(localPath)) {
|
|
140
|
+
fs.rmSync(localPath, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Copy instead of symlink for reliability
|
|
144
|
+
console.log('Copying foundation files...');
|
|
145
|
+
fs.cpSync(fromPath, localPath, { recursive: true });
|
|
146
|
+
|
|
147
|
+
console.log(`\nā
Foundation copied to ${LOCAL_DIR}/\n`);
|
|
148
|
+
} else {
|
|
149
|
+
// Download from NPM
|
|
150
|
+
console.log('Downloading from NPM...\n');
|
|
151
|
+
|
|
152
|
+
// Create cache directory
|
|
153
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
154
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Check cache
|
|
158
|
+
const cachedPath = path.join(CACHE_DIR, `v${targetVersion}`);
|
|
159
|
+
|
|
160
|
+
if (fs.existsSync(cachedPath) && !options.force) {
|
|
161
|
+
console.log(`Using cached version: ${cachedPath}`);
|
|
162
|
+
} else {
|
|
163
|
+
// Download
|
|
164
|
+
const tempDir = path.join(CACHE_DIR, 'temp');
|
|
165
|
+
if (!fs.existsSync(tempDir)) {
|
|
166
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const tarballPath = downloadFromNpm(targetVersion, tempDir);
|
|
171
|
+
extractTarball(tarballPath, tempDir);
|
|
172
|
+
|
|
173
|
+
// Move to cache
|
|
174
|
+
const extractedPath = path.join(tempDir, 'package');
|
|
175
|
+
if (fs.existsSync(cachedPath)) {
|
|
176
|
+
fs.rmSync(cachedPath, { recursive: true });
|
|
177
|
+
}
|
|
178
|
+
fs.renameSync(extractedPath, cachedPath);
|
|
179
|
+
|
|
180
|
+
// Cleanup
|
|
181
|
+
fs.unlinkSync(tarballPath);
|
|
182
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
183
|
+
|
|
184
|
+
console.log('ā
Download complete');
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error('ā Download failed:', error.message);
|
|
187
|
+
console.log('\nAlternatives:');
|
|
188
|
+
console.log(' - Check your network connection');
|
|
189
|
+
console.log(' - Use --from /path/to/local/foundation for offline mode');
|
|
190
|
+
console.log('');
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Copy to local directory
|
|
196
|
+
console.log(`\nCopying to ${LOCAL_DIR}/...`);
|
|
197
|
+
|
|
198
|
+
if (fs.existsSync(localPath)) {
|
|
199
|
+
fs.rmSync(localPath, { recursive: true });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
fs.cpSync(cachedPath, localPath, { recursive: true });
|
|
203
|
+
|
|
204
|
+
console.log('ā
Copy complete');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Generate local opencode.jsonc
|
|
208
|
+
console.log('\nš Generating opencode.jsonc for local development...');
|
|
209
|
+
|
|
210
|
+
const opencodeContent = generateLocalOpenCodeConfig(projectPath, localPath, config);
|
|
211
|
+
const opencodePath = path.join(projectPath, 'opencode.jsonc');
|
|
212
|
+
|
|
213
|
+
// Backup existing if different
|
|
214
|
+
if (fs.existsSync(opencodePath)) {
|
|
215
|
+
const existing = fs.readFileSync(opencodePath, 'utf-8');
|
|
216
|
+
if (existing !== opencodeContent) {
|
|
217
|
+
fs.writeFileSync(opencodePath + '.backup', existing);
|
|
218
|
+
console.log(' (Backed up existing opencode.jsonc)');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
fs.writeFileSync(opencodePath, opencodeContent);
|
|
223
|
+
console.log('ā
Generated opencode.jsonc');
|
|
224
|
+
|
|
225
|
+
// Summary
|
|
226
|
+
console.log('\nš Local setup complete!\n');
|
|
227
|
+
console.log('Foundation files:', LOCAL_DIR);
|
|
228
|
+
console.log('OpenCode config: opencode.jsonc');
|
|
229
|
+
console.log('\nYou can now use OpenCode locally with full AmazingTeam capabilities.\n');
|
|
230
|
+
|
|
231
|
+
// Update .gitignore reminder
|
|
232
|
+
console.log('Reminder: Add .ai-team-local/ to .gitignore if not already done.');
|
|
233
|
+
console.log('');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function help() {
|
|
237
|
+
return `
|
|
238
|
+
amazingteam local - Download foundation for local development
|
|
239
|
+
|
|
240
|
+
Usage:
|
|
241
|
+
amazingteam local [options]
|
|
242
|
+
|
|
243
|
+
Options:
|
|
244
|
+
--from <path> Use local foundation path (offline mode)
|
|
245
|
+
--force Force re-download even if cached
|
|
246
|
+
|
|
247
|
+
Examples:
|
|
248
|
+
amazingteam local Download from NPM
|
|
249
|
+
amazingteam local --from ../foundation Use local copy
|
|
250
|
+
amazingteam local --force Force re-download
|
|
251
|
+
|
|
252
|
+
What it does:
|
|
253
|
+
1. Downloads AmazingTeam Foundation to .ai-team-local/
|
|
254
|
+
2. Generates opencode.jsonc with local paths
|
|
255
|
+
3. Caches downloads in ~/.ai-team-cache/
|
|
256
|
+
|
|
257
|
+
The local foundation allows you to use OpenCode locally
|
|
258
|
+
with all AmazingTeam skills and configurations.
|
|
259
|
+
|
|
260
|
+
Note: .ai-team-local/ should be in .gitignore.
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
module.exports = { run, help };
|