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 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
- const dirStat = statSync(CLI_TEMPLATE_DIR);
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
- if (name) {
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 = name;
193
- writeFileSync2(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
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 = resolve2(cwd);
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
- throw new Error(`Cursor run \u5931\u8D25: ${result.id}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.35",
3
+ "version": "6.0.37",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -1,3 +1,3 @@
1
1
  {
2
2
  "name": ""
3
- }
3
+ }