@rlarua/agentteams-cli 0.0.8 → 0.0.10
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 +201 -0
- package/README.md +120 -131
- package/dist/commands/convention.d.ts.map +1 -1
- package/dist/commands/convention.js +98 -31
- package/dist/commands/convention.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +295 -17
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +70 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/spinner.d.ts +6 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +34 -0
- package/dist/utils/spinner.js.map +1 -0
- package/package.json +5 -3
- package/DEVELOPMENT.md +0 -234
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
import { loadConfig, findProjectConfig } from "../utils/config.js";
|
|
5
|
+
import { withSpinner } from "../utils/spinner.js";
|
|
5
6
|
const CONVENTION_DIR = ".agentteams";
|
|
6
7
|
const LEGACY_CONVENTION_DOWNLOAD_DIR = "conventions";
|
|
7
8
|
const CONVENTION_INDEX_FILE = "convention.md";
|
|
@@ -82,6 +83,59 @@ function buildConventionFileName(convention) {
|
|
|
82
83
|
const prefix = titleSegment.length > 0 ? titleSegment : "convention";
|
|
83
84
|
return `${prefix}.md`;
|
|
84
85
|
}
|
|
86
|
+
function normalizeMarkdownFileName(input) {
|
|
87
|
+
const trimmed = input.trim();
|
|
88
|
+
const base = trimmed.toLowerCase().endsWith('.md')
|
|
89
|
+
? trimmed.slice(0, -3)
|
|
90
|
+
: trimmed;
|
|
91
|
+
const safeBase = toSafeFileName(base);
|
|
92
|
+
const resolvedBase = safeBase.length > 0 ? safeBase : 'guide';
|
|
93
|
+
return `${resolvedBase}.md`;
|
|
94
|
+
}
|
|
95
|
+
function buildPlatformGuideFileName(guide) {
|
|
96
|
+
if (typeof guide.fileName === 'string' && guide.fileName.trim().length > 0) {
|
|
97
|
+
return normalizeMarkdownFileName(guide.fileName);
|
|
98
|
+
}
|
|
99
|
+
if (typeof guide.title === 'string' && guide.title.trim().length > 0) {
|
|
100
|
+
return `${toSafeFileName(guide.title)}.md`;
|
|
101
|
+
}
|
|
102
|
+
return 'guide.md';
|
|
103
|
+
}
|
|
104
|
+
async function downloadPlatformGuides(projectRoot, apiUrl, headers) {
|
|
105
|
+
try {
|
|
106
|
+
const response = await axios.get(`${apiUrl}/api/platform/guides`, { headers });
|
|
107
|
+
const guides = response.data?.data;
|
|
108
|
+
if (!Array.isArray(guides) || guides.length === 0) {
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
const baseDir = join(projectRoot, CONVENTION_DIR, 'platform', 'guides');
|
|
112
|
+
rmSync(baseDir, { recursive: true, force: true });
|
|
113
|
+
mkdirSync(baseDir, { recursive: true });
|
|
114
|
+
const fileNameCount = new Map();
|
|
115
|
+
let written = 0;
|
|
116
|
+
for (const guide of guides) {
|
|
117
|
+
if (!guide || typeof guide.content !== 'string') {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const baseFileName = buildPlatformGuideFileName(guide);
|
|
121
|
+
const seenCount = fileNameCount.get(baseFileName) ?? 0;
|
|
122
|
+
fileNameCount.set(baseFileName, seenCount + 1);
|
|
123
|
+
const fileName = seenCount === 0
|
|
124
|
+
? baseFileName
|
|
125
|
+
: baseFileName.replace(/\.md$/, `-${seenCount + 1}.md`);
|
|
126
|
+
const filePath = join(baseDir, fileName);
|
|
127
|
+
writeFileSync(filePath, guide.content, 'utf-8');
|
|
128
|
+
written += 1;
|
|
129
|
+
}
|
|
130
|
+
return written;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (axios.isAxiosError(error) && error.response?.status === 404) {
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
85
139
|
async function downloadReportingTemplate(projectRoot, config, apiUrl, headers) {
|
|
86
140
|
const agentConfigResponse = await axios.get(`${apiUrl}/api/projects/${config.projectId}/agent-configs`, { headers });
|
|
87
141
|
const agentConfigs = agentConfigResponse.data?.data;
|
|
@@ -111,44 +165,57 @@ export async function conventionDownload(options) {
|
|
|
111
165
|
if (!existsSync(conventionRoot)) {
|
|
112
166
|
throw new Error(`Convention directory not found: ${conventionRoot}\nRun 'agentteams init' first.`);
|
|
113
167
|
}
|
|
114
|
-
const hasReportingTemplate = await downloadReportingTemplate(projectRoot, config, apiUrl, headers);
|
|
115
|
-
const
|
|
116
|
-
const conventions =
|
|
168
|
+
const hasReportingTemplate = await withSpinner('Downloading reporting template...', () => downloadReportingTemplate(projectRoot, config, apiUrl, headers));
|
|
169
|
+
const platformGuideCount = await withSpinner('Downloading platform guides...', () => downloadPlatformGuides(projectRoot, apiUrl, headers));
|
|
170
|
+
const conventions = await withSpinner('Downloading conventions...', async () => {
|
|
171
|
+
const listResponse = await axios.get(`${apiUrl}/api/projects/${config.projectId}/conventions`, { headers });
|
|
172
|
+
const conventionList = listResponse.data?.data;
|
|
173
|
+
if (!conventionList || conventionList.length === 0) {
|
|
174
|
+
return conventionList;
|
|
175
|
+
}
|
|
176
|
+
const legacyDir = join(projectRoot, CONVENTION_DIR, LEGACY_CONVENTION_DOWNLOAD_DIR);
|
|
177
|
+
rmSync(legacyDir, { recursive: true, force: true });
|
|
178
|
+
const categoryDirs = new Set();
|
|
179
|
+
for (const convention of conventionList) {
|
|
180
|
+
const categoryName = typeof convention.category === "string" ? convention.category : "";
|
|
181
|
+
categoryDirs.add(toSafeDirectoryName(categoryName));
|
|
182
|
+
}
|
|
183
|
+
for (const categoryDir of categoryDirs) {
|
|
184
|
+
rmSync(join(projectRoot, CONVENTION_DIR, categoryDir), { recursive: true, force: true });
|
|
185
|
+
mkdirSync(join(projectRoot, CONVENTION_DIR, categoryDir), { recursive: true });
|
|
186
|
+
}
|
|
187
|
+
const fileNameCount = new Map();
|
|
188
|
+
for (const convention of conventionList) {
|
|
189
|
+
const downloadResponse = await axios.get(`${apiUrl}/api/projects/${config.projectId}/conventions/${convention.id}/download`, { headers, responseType: "text" });
|
|
190
|
+
const baseFileName = buildConventionFileName(convention);
|
|
191
|
+
const categoryName = typeof convention.category === "string" ? convention.category : "";
|
|
192
|
+
const categoryDir = toSafeDirectoryName(categoryName);
|
|
193
|
+
const duplicateKey = `${categoryDir}/${baseFileName}`;
|
|
194
|
+
const seenCount = fileNameCount.get(duplicateKey) ?? 0;
|
|
195
|
+
fileNameCount.set(duplicateKey, seenCount + 1);
|
|
196
|
+
const fileName = seenCount === 0
|
|
197
|
+
? baseFileName
|
|
198
|
+
: baseFileName.replace(/\.md$/, `-${seenCount + 1}.md`);
|
|
199
|
+
const filePath = join(projectRoot, CONVENTION_DIR, categoryDir, fileName);
|
|
200
|
+
writeFileSync(filePath, downloadResponse.data, "utf-8");
|
|
201
|
+
}
|
|
202
|
+
return conventionList;
|
|
203
|
+
});
|
|
117
204
|
if (!conventions || conventions.length === 0) {
|
|
118
205
|
if (hasReportingTemplate) {
|
|
119
|
-
|
|
206
|
+
const platformLine = platformGuideCount > 0
|
|
207
|
+
? `\nDownloaded ${platformGuideCount} platform guide file(s) into ${CONVENTION_DIR}/platform/guides`
|
|
208
|
+
: '';
|
|
209
|
+
return `Convention sync completed.\nUpdated ${CONVENTION_DIR}/${CONVENTION_INDEX_FILE}\nNo project conventions found.${platformLine}`;
|
|
120
210
|
}
|
|
121
211
|
throw new Error("No conventions found for this project. Create one via the web dashboard first.");
|
|
122
212
|
}
|
|
123
|
-
const legacyDir = join(projectRoot, CONVENTION_DIR, LEGACY_CONVENTION_DOWNLOAD_DIR);
|
|
124
|
-
rmSync(legacyDir, { recursive: true, force: true });
|
|
125
|
-
const categoryDirs = new Set();
|
|
126
|
-
for (const convention of conventions) {
|
|
127
|
-
const categoryName = typeof convention.category === "string" ? convention.category : "";
|
|
128
|
-
categoryDirs.add(toSafeDirectoryName(categoryName));
|
|
129
|
-
}
|
|
130
|
-
for (const categoryDir of categoryDirs) {
|
|
131
|
-
rmSync(join(projectRoot, CONVENTION_DIR, categoryDir), { recursive: true, force: true });
|
|
132
|
-
mkdirSync(join(projectRoot, CONVENTION_DIR, categoryDir), { recursive: true });
|
|
133
|
-
}
|
|
134
|
-
const fileNameCount = new Map();
|
|
135
|
-
for (const convention of conventions) {
|
|
136
|
-
const downloadResponse = await axios.get(`${apiUrl}/api/projects/${config.projectId}/conventions/${convention.id}/download`, { headers, responseType: "text" });
|
|
137
|
-
const baseFileName = buildConventionFileName(convention);
|
|
138
|
-
const categoryName = typeof convention.category === "string" ? convention.category : "";
|
|
139
|
-
const categoryDir = toSafeDirectoryName(categoryName);
|
|
140
|
-
const duplicateKey = `${categoryDir}/${baseFileName}`;
|
|
141
|
-
const seenCount = fileNameCount.get(duplicateKey) ?? 0;
|
|
142
|
-
fileNameCount.set(duplicateKey, seenCount + 1);
|
|
143
|
-
const fileName = seenCount === 0
|
|
144
|
-
? baseFileName
|
|
145
|
-
: baseFileName.replace(/\.md$/, `-${seenCount + 1}.md`);
|
|
146
|
-
const filePath = join(projectRoot, CONVENTION_DIR, categoryDir, fileName);
|
|
147
|
-
writeFileSync(filePath, downloadResponse.data, "utf-8");
|
|
148
|
-
}
|
|
149
213
|
const reportingLine = hasReportingTemplate
|
|
150
214
|
? `Updated ${CONVENTION_DIR}/${CONVENTION_INDEX_FILE}\n`
|
|
151
215
|
: "";
|
|
152
|
-
|
|
216
|
+
const platformLine = platformGuideCount > 0
|
|
217
|
+
? `Downloaded ${platformGuideCount} platform guide file(s) into ${CONVENTION_DIR}/platform/guides\n`
|
|
218
|
+
: "";
|
|
219
|
+
return `Convention sync completed.\n${reportingLine}${platformLine}Downloaded ${conventions.length} file(s) into category directories under ${CONVENTION_DIR}`;
|
|
153
220
|
}
|
|
154
221
|
//# sourceMappingURL=convention.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convention.js","sourceRoot":"","sources":["../../src/commands/convention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"convention.js","sourceRoot":"","sources":["../../src/commands/convention.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AA4BA,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,GAAG,CAAC,CA4Gd"}
|
package/dist/commands/index.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync, rmSync, readdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
2
4
|
import { executeInitCommand } from './init.js';
|
|
3
5
|
import { conventionList, conventionShow, conventionDownload, } from './convention.js';
|
|
4
6
|
import { agentConfigList, agentConfigGet, agentConfigDelete } from './agentConfig.js';
|
|
5
7
|
import { dependencyList, dependencyCreate, dependencyDelete } from './dependency.js';
|
|
6
|
-
import { loadConfig } from '../utils/config.js';
|
|
8
|
+
import { loadConfig, findProjectConfig } from '../utils/config.js';
|
|
9
|
+
import { withSpinner, printFileInfo } from '../utils/spinner.js';
|
|
10
|
+
function findProjectRoot() {
|
|
11
|
+
const configPath = findProjectConfig(process.cwd());
|
|
12
|
+
if (!configPath)
|
|
13
|
+
return null;
|
|
14
|
+
return resolve(configPath, '..', '..');
|
|
15
|
+
}
|
|
16
|
+
function toSafeFileName(input) {
|
|
17
|
+
return input
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
20
|
+
.replace(/^-+|-+$/g, '')
|
|
21
|
+
.slice(0, 60);
|
|
22
|
+
}
|
|
7
23
|
export async function executeCommand(resource, action, options) {
|
|
8
24
|
switch (resource) {
|
|
9
25
|
case 'init':
|
|
@@ -56,7 +72,30 @@ export async function executeCommand(resource, action, options) {
|
|
|
56
72
|
return executeReportCommand(apiUrl, headers, action, {
|
|
57
73
|
...options,
|
|
58
74
|
projectId: config.projectId,
|
|
59
|
-
|
|
75
|
+
defaultCreatedBy: config.agentName
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
case 'postmortem': {
|
|
79
|
+
const configOverrides = {
|
|
80
|
+
...(typeof options.apiKey === 'string' && options.apiKey.length > 0 ? { apiKey: options.apiKey } : {}),
|
|
81
|
+
...(typeof options.apiUrl === 'string' && options.apiUrl.length > 0 ? { apiUrl: options.apiUrl } : {}),
|
|
82
|
+
...(typeof options.teamId === 'string' && options.teamId.length > 0 ? { teamId: options.teamId } : {}),
|
|
83
|
+
...(typeof options.projectId === 'string' && options.projectId.length > 0 ? { projectId: options.projectId } : {}),
|
|
84
|
+
...(typeof options.agentName === 'string' && options.agentName.length > 0 ? { agentName: options.agentName } : {})
|
|
85
|
+
};
|
|
86
|
+
const config = loadConfig(configOverrides);
|
|
87
|
+
if (!config) {
|
|
88
|
+
throw new Error("Configuration not found. Run 'agentteams init' first or set AGENTTEAMS_* environment variables.");
|
|
89
|
+
}
|
|
90
|
+
const apiUrl = config.apiUrl.endsWith('/') ? config.apiUrl.slice(0, -1) : config.apiUrl;
|
|
91
|
+
const headers = {
|
|
92
|
+
'X-API-Key': config.apiKey,
|
|
93
|
+
'Content-Type': 'application/json'
|
|
94
|
+
};
|
|
95
|
+
return executePostMortemCommand(apiUrl, headers, action, {
|
|
96
|
+
...options,
|
|
97
|
+
projectId: config.projectId,
|
|
98
|
+
defaultCreatedBy: config.agentName
|
|
60
99
|
});
|
|
61
100
|
}
|
|
62
101
|
case 'dependency':
|
|
@@ -91,7 +130,17 @@ async function executeStatusCommand(apiUrl, projectId, headers, action, options)
|
|
|
91
130
|
return response.data;
|
|
92
131
|
}
|
|
93
132
|
case 'list': {
|
|
94
|
-
const
|
|
133
|
+
const params = {};
|
|
134
|
+
const page = toPositiveInteger(options.page);
|
|
135
|
+
const pageSize = toPositiveInteger(options.pageSize);
|
|
136
|
+
if (page !== undefined)
|
|
137
|
+
params.page = page;
|
|
138
|
+
if (pageSize !== undefined)
|
|
139
|
+
params.pageSize = pageSize;
|
|
140
|
+
const requestConfig = Object.keys(params).length > 0
|
|
141
|
+
? { headers, params }
|
|
142
|
+
: { headers };
|
|
143
|
+
const response = await axios.get(baseUrl, requestConfig);
|
|
95
144
|
return response.data;
|
|
96
145
|
}
|
|
97
146
|
case 'get': {
|
|
@@ -129,7 +178,25 @@ async function executePlanCommand(apiUrl, projectId, headers, action, options) {
|
|
|
129
178
|
const baseUrl = `${apiUrl}/api/projects/${projectId}/plans`;
|
|
130
179
|
switch (action) {
|
|
131
180
|
case 'list': {
|
|
132
|
-
const
|
|
181
|
+
const params = {};
|
|
182
|
+
if (options.title)
|
|
183
|
+
params.title = options.title;
|
|
184
|
+
if (options.search)
|
|
185
|
+
params.search = options.search;
|
|
186
|
+
if (options.status)
|
|
187
|
+
params.status = options.status;
|
|
188
|
+
if (options.assignedTo)
|
|
189
|
+
params.assignedTo = options.assignedTo;
|
|
190
|
+
const page = toPositiveInteger(options.page);
|
|
191
|
+
const pageSize = toPositiveInteger(options.pageSize);
|
|
192
|
+
if (page !== undefined)
|
|
193
|
+
params.page = page;
|
|
194
|
+
if (pageSize !== undefined)
|
|
195
|
+
params.pageSize = pageSize;
|
|
196
|
+
const requestConfig = Object.keys(params).length > 0
|
|
197
|
+
? { headers, params }
|
|
198
|
+
: { headers };
|
|
199
|
+
const response = await axios.get(baseUrl, requestConfig);
|
|
133
200
|
return response.data;
|
|
134
201
|
}
|
|
135
202
|
case 'get': {
|
|
@@ -143,15 +210,24 @@ async function executePlanCommand(apiUrl, projectId, headers, action, options) {
|
|
|
143
210
|
case 'create': {
|
|
144
211
|
if (!options.title)
|
|
145
212
|
throw new Error('--title is required for plan create');
|
|
146
|
-
|
|
147
|
-
|
|
213
|
+
let content = options.content;
|
|
214
|
+
if (options.file) {
|
|
215
|
+
const filePath = resolve(options.file);
|
|
216
|
+
if (!existsSync(filePath)) {
|
|
217
|
+
throw new Error(`File not found: ${options.file}`);
|
|
218
|
+
}
|
|
219
|
+
content = readFileSync(filePath, 'utf-8');
|
|
220
|
+
printFileInfo(options.file, content);
|
|
148
221
|
}
|
|
149
|
-
|
|
222
|
+
if (!content || content.trim().length === 0) {
|
|
223
|
+
throw new Error('--content or --file is required for plan create');
|
|
224
|
+
}
|
|
225
|
+
const response = await withSpinner('Creating plan...', () => axios.post(baseUrl, {
|
|
150
226
|
title: options.title,
|
|
151
|
-
|
|
227
|
+
content,
|
|
152
228
|
priority: options.priority ?? 'MEDIUM',
|
|
153
229
|
status: options.status,
|
|
154
|
-
}, { headers });
|
|
230
|
+
}, { headers }), 'Plan created');
|
|
155
231
|
return response.data;
|
|
156
232
|
}
|
|
157
233
|
case 'update': {
|
|
@@ -160,13 +236,22 @@ async function executePlanCommand(apiUrl, projectId, headers, action, options) {
|
|
|
160
236
|
const body = {};
|
|
161
237
|
if (options.title)
|
|
162
238
|
body.title = options.title;
|
|
163
|
-
if (options.
|
|
164
|
-
|
|
239
|
+
if (options.file) {
|
|
240
|
+
const filePath = resolve(options.file);
|
|
241
|
+
if (!existsSync(filePath)) {
|
|
242
|
+
throw new Error(`File not found: ${options.file}`);
|
|
243
|
+
}
|
|
244
|
+
body.content = readFileSync(filePath, 'utf-8');
|
|
245
|
+
printFileInfo(options.file, body.content);
|
|
246
|
+
}
|
|
247
|
+
else if (options.content) {
|
|
248
|
+
body.content = options.content;
|
|
249
|
+
}
|
|
165
250
|
if (options.status)
|
|
166
251
|
body.status = options.status;
|
|
167
252
|
if (options.priority)
|
|
168
253
|
body.priority = options.priority;
|
|
169
|
-
const response = await axios.put(`${baseUrl}/${options.id}`, body, { headers });
|
|
254
|
+
const response = await withSpinner('Updating plan...', () => axios.put(`${baseUrl}/${options.id}`, body, { headers }), 'Plan updated');
|
|
170
255
|
return response.data;
|
|
171
256
|
}
|
|
172
257
|
case 'delete': {
|
|
@@ -183,6 +268,78 @@ async function executePlanCommand(apiUrl, projectId, headers, action, options) {
|
|
|
183
268
|
const response = await axios.post(`${baseUrl}/${options.id}/assign`, { assignedTo: options.agent }, { headers });
|
|
184
269
|
return response.data;
|
|
185
270
|
}
|
|
271
|
+
case 'download': {
|
|
272
|
+
if (!options.id)
|
|
273
|
+
throw new Error('--id is required for plan download');
|
|
274
|
+
const result = await withSpinner('Downloading plan...', async () => {
|
|
275
|
+
const response = await axios.get(`${baseUrl}/${options.id}`, { headers });
|
|
276
|
+
const plan = response.data.data;
|
|
277
|
+
const projectRoot = findProjectRoot();
|
|
278
|
+
if (!projectRoot) {
|
|
279
|
+
throw new Error("Project root not found. Run 'agentteams init' first.");
|
|
280
|
+
}
|
|
281
|
+
const activePlanDir = join(projectRoot, '.agentteams', 'active-plan');
|
|
282
|
+
if (!existsSync(activePlanDir)) {
|
|
283
|
+
mkdirSync(activePlanDir, { recursive: true });
|
|
284
|
+
}
|
|
285
|
+
const safeName = toSafeFileName(plan.title) || 'plan';
|
|
286
|
+
const fileName = `${safeName}.md`;
|
|
287
|
+
const filePath = join(activePlanDir, fileName);
|
|
288
|
+
const frontmatter = [
|
|
289
|
+
'---',
|
|
290
|
+
`planId: ${plan.id}`,
|
|
291
|
+
`title: ${plan.title}`,
|
|
292
|
+
`status: ${plan.status}`,
|
|
293
|
+
`priority: ${plan.priority}`,
|
|
294
|
+
`downloadedAt: ${new Date().toISOString()}`,
|
|
295
|
+
'---',
|
|
296
|
+
].join('\n');
|
|
297
|
+
const markdown = plan.contentMarkdown ?? '';
|
|
298
|
+
writeFileSync(filePath, `${frontmatter}\n\n${markdown}`, 'utf-8');
|
|
299
|
+
return {
|
|
300
|
+
message: `Plan downloaded to ${fileName}`,
|
|
301
|
+
filePath: `.agentteams/active-plan/${fileName}`,
|
|
302
|
+
};
|
|
303
|
+
}, 'Plan downloaded');
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
case 'cleanup': {
|
|
307
|
+
const projectRoot = findProjectRoot();
|
|
308
|
+
if (!projectRoot) {
|
|
309
|
+
throw new Error("Project root not found. Run 'agentteams init' first.");
|
|
310
|
+
}
|
|
311
|
+
const activePlanDir = join(projectRoot, '.agentteams', 'active-plan');
|
|
312
|
+
if (!existsSync(activePlanDir)) {
|
|
313
|
+
return { message: 'No active-plan directory found.', deletedFiles: [] };
|
|
314
|
+
}
|
|
315
|
+
const deletedFiles = await withSpinner('Cleaning up plan files...', async () => {
|
|
316
|
+
const allFiles = readdirSync(activePlanDir).filter((f) => f.endsWith('.md'));
|
|
317
|
+
const deleted = [];
|
|
318
|
+
if (options.id) {
|
|
319
|
+
for (const file of allFiles) {
|
|
320
|
+
const content = readFileSync(join(activePlanDir, file), 'utf-8');
|
|
321
|
+
const match = content.match(/^planId:\s*(.+)$/m);
|
|
322
|
+
if (match && match[1].trim() === options.id) {
|
|
323
|
+
rmSync(join(activePlanDir, file));
|
|
324
|
+
deleted.push(file);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
for (const file of allFiles) {
|
|
330
|
+
rmSync(join(activePlanDir, file));
|
|
331
|
+
deleted.push(file);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return deleted;
|
|
335
|
+
}, `Cleaned up plan files`);
|
|
336
|
+
return {
|
|
337
|
+
message: deletedFiles.length > 0
|
|
338
|
+
? `Deleted ${deletedFiles.length} file(s).`
|
|
339
|
+
: 'No matching files found.',
|
|
340
|
+
deletedFiles,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
186
343
|
default:
|
|
187
344
|
throw new Error(`Unknown action: ${action}`);
|
|
188
345
|
}
|
|
@@ -194,7 +351,19 @@ async function executeCommentCommand(apiUrl, projectId, headers, action, options
|
|
|
194
351
|
case 'list': {
|
|
195
352
|
if (!options.planId)
|
|
196
353
|
throw new Error('--plan-id is required for comment list');
|
|
197
|
-
const
|
|
354
|
+
const params = {};
|
|
355
|
+
if (options.type)
|
|
356
|
+
params.type = options.type;
|
|
357
|
+
const page = toPositiveInteger(options.page);
|
|
358
|
+
const pageSize = toPositiveInteger(options.pageSize);
|
|
359
|
+
if (page !== undefined)
|
|
360
|
+
params.page = page;
|
|
361
|
+
if (pageSize !== undefined)
|
|
362
|
+
params.pageSize = pageSize;
|
|
363
|
+
const requestConfig = Object.keys(params).length > 0
|
|
364
|
+
? { headers, params }
|
|
365
|
+
: { headers };
|
|
366
|
+
const response = await axios.get(`${planBaseUrl}/${options.planId}/comments`, requestConfig);
|
|
198
367
|
return response.data;
|
|
199
368
|
}
|
|
200
369
|
case 'get': {
|
|
@@ -241,7 +410,25 @@ async function executeReportCommand(apiUrl, headers, action, options) {
|
|
|
241
410
|
const baseUrl = `${apiUrl}/api/projects/${options.projectId}/completion-reports`;
|
|
242
411
|
switch (action) {
|
|
243
412
|
case 'list': {
|
|
244
|
-
const
|
|
413
|
+
const params = {};
|
|
414
|
+
if (options.planId)
|
|
415
|
+
params.planId = options.planId;
|
|
416
|
+
if (options.reportType)
|
|
417
|
+
params.reportType = options.reportType;
|
|
418
|
+
if (options.status)
|
|
419
|
+
params.status = options.status;
|
|
420
|
+
if (options.createdBy)
|
|
421
|
+
params.createdBy = options.createdBy;
|
|
422
|
+
const page = toPositiveInteger(options.page);
|
|
423
|
+
const pageSize = toPositiveInteger(options.pageSize);
|
|
424
|
+
if (page !== undefined)
|
|
425
|
+
params.page = page;
|
|
426
|
+
if (pageSize !== undefined)
|
|
427
|
+
params.pageSize = pageSize;
|
|
428
|
+
const requestConfig = Object.keys(params).length > 0
|
|
429
|
+
? { headers, params }
|
|
430
|
+
: { headers };
|
|
431
|
+
const response = await axios.get(baseUrl, requestConfig);
|
|
245
432
|
return response.data;
|
|
246
433
|
}
|
|
247
434
|
case 'get': {
|
|
@@ -262,15 +449,17 @@ async function executeReportCommand(apiUrl, headers, action, options) {
|
|
|
262
449
|
}
|
|
263
450
|
const reportType = options.reportType ?? 'IMPL_PLAN';
|
|
264
451
|
const status = options.status ?? 'COMPLETED';
|
|
265
|
-
const createdBy = options.createdBy
|
|
266
|
-
|
|
452
|
+
const createdBy = options.createdBy
|
|
453
|
+
?? options.defaultCreatedBy
|
|
454
|
+
?? '__cli__';
|
|
455
|
+
const response = await withSpinner('Creating report...', () => axios.post(baseUrl, {
|
|
267
456
|
planId: options.planId,
|
|
268
457
|
title,
|
|
269
458
|
content,
|
|
270
459
|
reportType,
|
|
271
460
|
status,
|
|
272
461
|
createdBy
|
|
273
|
-
}, { headers });
|
|
462
|
+
}, { headers }), 'Report created');
|
|
274
463
|
return response.data;
|
|
275
464
|
}
|
|
276
465
|
case 'update': {
|
|
@@ -300,6 +489,85 @@ async function executeReportCommand(apiUrl, headers, action, options) {
|
|
|
300
489
|
throw new Error(`Unknown action: ${action}`);
|
|
301
490
|
}
|
|
302
491
|
}
|
|
492
|
+
async function executePostMortemCommand(apiUrl, headers, action, options) {
|
|
493
|
+
if (!options.projectId || typeof options.projectId !== 'string') {
|
|
494
|
+
throw new Error('--project-id is required (or configure AGENTTEAMS_PROJECT_ID / .agentteams/config.json)');
|
|
495
|
+
}
|
|
496
|
+
const baseUrl = `${apiUrl}/api/projects/${options.projectId}/post-mortems`;
|
|
497
|
+
switch (action) {
|
|
498
|
+
case 'list': {
|
|
499
|
+
const params = {};
|
|
500
|
+
if (options.planId)
|
|
501
|
+
params.planId = options.planId;
|
|
502
|
+
if (options.status)
|
|
503
|
+
params.status = options.status;
|
|
504
|
+
if (options.createdBy)
|
|
505
|
+
params.createdBy = options.createdBy;
|
|
506
|
+
const page = toPositiveInteger(options.page);
|
|
507
|
+
const pageSize = toPositiveInteger(options.pageSize);
|
|
508
|
+
if (page !== undefined)
|
|
509
|
+
params.page = page;
|
|
510
|
+
if (pageSize !== undefined)
|
|
511
|
+
params.pageSize = pageSize;
|
|
512
|
+
const requestConfig = Object.keys(params).length > 0
|
|
513
|
+
? { headers, params }
|
|
514
|
+
: { headers };
|
|
515
|
+
const response = await axios.get(baseUrl, requestConfig);
|
|
516
|
+
return response.data;
|
|
517
|
+
}
|
|
518
|
+
case 'get': {
|
|
519
|
+
if (!options.id)
|
|
520
|
+
throw new Error('--id is required for postmortem get');
|
|
521
|
+
const response = await axios.get(`${baseUrl}/${options.id}`, { headers });
|
|
522
|
+
return response.data;
|
|
523
|
+
}
|
|
524
|
+
case 'create': {
|
|
525
|
+
if (!options.title)
|
|
526
|
+
throw new Error('--title is required for postmortem create');
|
|
527
|
+
if (!options.content)
|
|
528
|
+
throw new Error('--content is required for postmortem create');
|
|
529
|
+
if (options.actionItems === undefined)
|
|
530
|
+
throw new Error('--action-items is required for postmortem create');
|
|
531
|
+
const response = await withSpinner('Creating post-mortem...', () => axios.post(baseUrl, {
|
|
532
|
+
planId: options.planId,
|
|
533
|
+
title: options.title,
|
|
534
|
+
content: options.content,
|
|
535
|
+
actionItems: splitCsv(options.actionItems),
|
|
536
|
+
status: options.status,
|
|
537
|
+
createdBy: options.createdBy
|
|
538
|
+
?? options.defaultCreatedBy
|
|
539
|
+
?? '__cli__'
|
|
540
|
+
}, { headers }), 'Post-mortem created');
|
|
541
|
+
return response.data;
|
|
542
|
+
}
|
|
543
|
+
case 'update': {
|
|
544
|
+
if (!options.id)
|
|
545
|
+
throw new Error('--id is required for postmortem update');
|
|
546
|
+
const body = {};
|
|
547
|
+
if (Object.prototype.hasOwnProperty.call(options, 'planId')) {
|
|
548
|
+
body.planId = options.planId;
|
|
549
|
+
}
|
|
550
|
+
if (options.title)
|
|
551
|
+
body.title = options.title;
|
|
552
|
+
if (options.content)
|
|
553
|
+
body.content = options.content;
|
|
554
|
+
if (options.actionItems !== undefined)
|
|
555
|
+
body.actionItems = splitCsv(options.actionItems);
|
|
556
|
+
if (options.status)
|
|
557
|
+
body.status = options.status;
|
|
558
|
+
const response = await axios.put(`${baseUrl}/${options.id}`, body, { headers });
|
|
559
|
+
return response.data;
|
|
560
|
+
}
|
|
561
|
+
case 'delete': {
|
|
562
|
+
if (!options.id)
|
|
563
|
+
throw new Error('--id is required for postmortem delete');
|
|
564
|
+
await axios.delete(`${baseUrl}/${options.id}`, { headers });
|
|
565
|
+
return { message: `PostMortem ${options.id} deleted successfully` };
|
|
566
|
+
}
|
|
567
|
+
default:
|
|
568
|
+
throw new Error(`Unknown action: ${action}`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
303
571
|
function toDetailsAsMarkdown(details) {
|
|
304
572
|
if (typeof details !== 'string' || details.trim().length === 0) {
|
|
305
573
|
return undefined;
|
|
@@ -388,6 +656,16 @@ function splitCsv(value) {
|
|
|
388
656
|
.map((item) => item.trim())
|
|
389
657
|
.filter((item) => item.length > 0);
|
|
390
658
|
}
|
|
659
|
+
function toPositiveInteger(value) {
|
|
660
|
+
if (typeof value === 'number' && Number.isInteger(value) && value > 0) {
|
|
661
|
+
return value;
|
|
662
|
+
}
|
|
663
|
+
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
|
664
|
+
const parsed = Number.parseInt(value, 10);
|
|
665
|
+
return parsed > 0 ? parsed : undefined;
|
|
666
|
+
}
|
|
667
|
+
return undefined;
|
|
668
|
+
}
|
|
391
669
|
async function executeConfigCommand(action) {
|
|
392
670
|
switch (action) {
|
|
393
671
|
case 'whoami': {
|