ai-project-manage-cli 6.0.35 → 6.0.37
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/dist/index.js +85 -17
- package/package.json +1 -1
- package/template/apm.config.json +1 -1
package/dist/index.js
CHANGED
|
@@ -164,20 +164,51 @@ async function ensureWorkspaceApmDirForInit() {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
async function copyTemplateFiles(targetDir) {
|
|
167
|
+
if (!existsSync(CLI_TEMPLATE_DIR)) {
|
|
168
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${CLI_TEMPLATE_DIR}`);
|
|
169
|
+
}
|
|
170
|
+
const dirStat = statSync(CLI_TEMPLATE_DIR);
|
|
171
|
+
if (!dirStat.isDirectory()) {
|
|
172
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${CLI_TEMPLATE_DIR}`);
|
|
173
|
+
}
|
|
174
|
+
const entries = readdirSync(CLI_TEMPLATE_DIR);
|
|
175
|
+
if (entries.length === 0) {
|
|
176
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u76EE\u5F55\u4E3A\u7A7A: ${CLI_TEMPLATE_DIR}`);
|
|
177
|
+
}
|
|
178
|
+
for (const name of entries) {
|
|
179
|
+
const src = join2(CLI_TEMPLATE_DIR, name);
|
|
180
|
+
const dest = join2(targetDir, name);
|
|
181
|
+
cpSync(src, dest, { recursive: true, force: false });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/workdir-path.ts
|
|
186
|
+
import { realpathSync } from "fs";
|
|
187
|
+
import { resolve as resolve2 } from "path";
|
|
188
|
+
function normalizeWorkdirPath(path10) {
|
|
189
|
+
let normalized = path10.trim().replace(/\\/g, "/").normalize("NFC");
|
|
190
|
+
if (normalized.startsWith("//?/")) {
|
|
191
|
+
normalized = normalized.slice(4);
|
|
192
|
+
}
|
|
193
|
+
const windowsDrive = /^([A-Za-z]:)\/*(.*)$/.exec(normalized);
|
|
194
|
+
if (windowsDrive) {
|
|
195
|
+
const drive = windowsDrive[1].toLowerCase();
|
|
196
|
+
const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
|
|
197
|
+
return rest ? `${drive}/${rest}` : drive;
|
|
198
|
+
}
|
|
199
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
200
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
201
|
+
normalized = normalized.slice(0, -1);
|
|
202
|
+
}
|
|
203
|
+
return normalized;
|
|
204
|
+
}
|
|
205
|
+
function resolveWorkdirPath(cwd = process.cwd()) {
|
|
206
|
+
const absolute = resolve2(cwd);
|
|
167
207
|
try {
|
|
168
|
-
|
|
169
|
-
if (!dirStat.isDirectory()) return;
|
|
208
|
+
return normalizeWorkdirPath(realpathSync.native(absolute));
|
|
170
209
|
} catch {
|
|
171
|
-
return;
|
|
210
|
+
return normalizeWorkdirPath(absolute);
|
|
172
211
|
}
|
|
173
|
-
const entries = readdirSync(CLI_TEMPLATE_DIR);
|
|
174
|
-
await Promise.all(
|
|
175
|
-
entries.map(async (name) => {
|
|
176
|
-
const src = join2(CLI_TEMPLATE_DIR, name);
|
|
177
|
-
const dest = join2(targetDir, name);
|
|
178
|
-
cpSync(src, dest, { recursive: true, force: false });
|
|
179
|
-
})
|
|
180
|
-
);
|
|
181
212
|
}
|
|
182
213
|
|
|
183
214
|
// src/commands/init.ts
|
|
@@ -185,13 +216,23 @@ async function runInit(name) {
|
|
|
185
216
|
await ensureWorkspaceApmDirForInit();
|
|
186
217
|
const apmDir = workspaceApmDir();
|
|
187
218
|
await copyTemplateFiles(apmDir);
|
|
188
|
-
|
|
219
|
+
const trimmedName = name?.trim();
|
|
220
|
+
if (trimmedName) {
|
|
189
221
|
const apmConfigPath = join3(apmDir, "apm.config.json");
|
|
190
222
|
const config = readFileSync2(apmConfigPath, "utf8");
|
|
191
223
|
const configJson = JSON.parse(config);
|
|
192
|
-
configJson.name =
|
|
193
|
-
writeFileSync2(
|
|
224
|
+
configJson.name = trimmedName;
|
|
225
|
+
writeFileSync2(
|
|
226
|
+
apmConfigPath,
|
|
227
|
+
`${JSON.stringify(configJson, null, 2)}
|
|
228
|
+
`,
|
|
229
|
+
"utf8"
|
|
230
|
+
);
|
|
194
231
|
}
|
|
232
|
+
const workdir = resolveWorkdirPath();
|
|
233
|
+
console.log(`[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
234
|
+
console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
|
|
235
|
+
console.log("[apm] \u8BF7\u5728\u5E73\u53F0\u300C\u5BA2\u6237\u673A\u7BA1\u7406 \u2192 \u5DE5\u4F5C\u7A7A\u95F4\u300D\u767B\u8BB0\u4E0A\u8FF0\u76EE\u5F55\u8DEF\u5F84");
|
|
195
236
|
}
|
|
196
237
|
|
|
197
238
|
// src/commands/login.ts
|
|
@@ -328,7 +369,6 @@ async function runLogin(opts) {
|
|
|
328
369
|
|
|
329
370
|
// src/commands/branch.ts
|
|
330
371
|
import { execFile } from "child_process";
|
|
331
|
-
import { resolve as resolve2 } from "path";
|
|
332
372
|
import { promisify } from "util";
|
|
333
373
|
var execFileAsync = promisify(execFile);
|
|
334
374
|
function branchNameForSession(sessionId) {
|
|
@@ -476,7 +516,7 @@ async function runBranch(sessionId, options = {}) {
|
|
|
476
516
|
const cfg = await ensureLoggedConfig();
|
|
477
517
|
const api = createApmApiClient(cfg);
|
|
478
518
|
const cwd = options.cwd ?? process.cwd();
|
|
479
|
-
const workdirPath =
|
|
519
|
+
const workdirPath = resolveWorkdirPath(cwd);
|
|
480
520
|
const baseline = await api.cli.branchBaseline({
|
|
481
521
|
sessionId: trimmedSessionId,
|
|
482
522
|
workdirPath
|
|
@@ -1440,6 +1480,19 @@ var logCtx = (ctx, agentId) => ({
|
|
|
1440
1480
|
messageId: ctx.messageId,
|
|
1441
1481
|
agentId
|
|
1442
1482
|
});
|
|
1483
|
+
function formatCursorRunFailure(runId, options) {
|
|
1484
|
+
const details = [
|
|
1485
|
+
options?.statusError?.trim(),
|
|
1486
|
+
options?.resultText?.trim()
|
|
1487
|
+
].filter((value, index, arr) => {
|
|
1488
|
+
if (!value) return false;
|
|
1489
|
+
return arr.indexOf(value) === index;
|
|
1490
|
+
});
|
|
1491
|
+
if (details.length === 0) {
|
|
1492
|
+
return `Cursor run \u5931\u8D25: ${runId}`;
|
|
1493
|
+
}
|
|
1494
|
+
return `Cursor run \u5931\u8D25: ${runId} \u2014 ${details.join("\uFF1B")}`;
|
|
1495
|
+
}
|
|
1443
1496
|
async function runCursorAgent(cfg, ctx, options) {
|
|
1444
1497
|
const signal = options?.signal;
|
|
1445
1498
|
logAbortSignalStats(signal, "runCursorAgent:start");
|
|
@@ -1487,18 +1540,33 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
1487
1540
|
activeRun = run;
|
|
1488
1541
|
logAbortSignalStats(signal, "runCursorAgent:after-send");
|
|
1489
1542
|
console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
|
|
1543
|
+
let lastRunErrorStatus;
|
|
1490
1544
|
for await (const event of run.stream()) {
|
|
1491
1545
|
if (signal?.aborted) {
|
|
1492
1546
|
abortRun();
|
|
1493
1547
|
throw new Error("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u4EFB\u52A1\u4E2D\u65AD");
|
|
1494
1548
|
}
|
|
1549
|
+
if (event.type === "status" && event.status === "ERROR") {
|
|
1550
|
+
const message = event.message?.trim();
|
|
1551
|
+
if (message) {
|
|
1552
|
+
lastRunErrorStatus = message;
|
|
1553
|
+
console.error(
|
|
1554
|
+
`[apm] Cursor run status=ERROR runId=${run.id}: ${message}`
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1495
1558
|
eventSession.addEvent(event);
|
|
1496
1559
|
syncRemoteLog.schedule(eventSession);
|
|
1497
1560
|
}
|
|
1498
1561
|
await syncRemoteLog.flush(eventSession);
|
|
1499
1562
|
const result = await run.wait();
|
|
1500
1563
|
if (result.status === "error") {
|
|
1501
|
-
|
|
1564
|
+
const failureMessage = formatCursorRunFailure(result.id, {
|
|
1565
|
+
statusError: lastRunErrorStatus,
|
|
1566
|
+
resultText: result.result
|
|
1567
|
+
});
|
|
1568
|
+
console.error(`[apm] ${failureMessage}`);
|
|
1569
|
+
throw new Error(failureMessage);
|
|
1502
1570
|
}
|
|
1503
1571
|
if (result.status === "cancelled") {
|
|
1504
1572
|
throw new Error(`Cursor run \u5DF2\u53D6\u6D88: ${result.id}`);
|
package/package.json
CHANGED
package/template/apm.config.json
CHANGED