ai-project-manage-cli 8.0.3 → 8.0.5

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
@@ -1119,6 +1119,21 @@ function validateCancel(o) {
1119
1119
  data: { type: "cancel", messageId: o.messageId.trim() }
1120
1120
  };
1121
1121
  }
1122
+ function validateWebIdeStopTerminals(o) {
1123
+ if (o.type !== "webide-stop-terminals") {
1124
+ return { ok: false, reason: "\u671F\u671B webide-stop-terminals" };
1125
+ }
1126
+ if (!nonEmptyString(o.taskId)) {
1127
+ return { ok: false, reason: "webide-stop-terminals \u7F3A\u5C11 taskId" };
1128
+ }
1129
+ return {
1130
+ ok: true,
1131
+ data: {
1132
+ type: "webide-stop-terminals",
1133
+ taskId: o.taskId.trim()
1134
+ }
1135
+ };
1136
+ }
1122
1137
  function validateWebIdeStartProjectPush(o) {
1123
1138
  if (o.type !== "webide-start-project") {
1124
1139
  return { ok: false, reason: "\u671F\u671B webide-start-project" };
@@ -1169,7 +1184,7 @@ function validateAgentWsMessage(value, kind) {
1169
1184
  }
1170
1185
  const o = value;
1171
1186
  const type = o.type;
1172
- if (type !== "heartbeat" && type !== "webide-message" && type !== "cancel" && type !== "webide-start-project") {
1187
+ if (type !== "heartbeat" && type !== "webide-message" && type !== "cancel" && type !== "webide-start-project" && type !== "webide-stop-terminals") {
1173
1188
  return { ok: false, reason: `\u672A\u77E5 type: ${String(type)}` };
1174
1189
  }
1175
1190
  if (kind === "heartbeat" || type === "heartbeat") {
@@ -1181,6 +1196,9 @@ function validateAgentWsMessage(value, kind) {
1181
1196
  if (type === "webide-start-project") {
1182
1197
  return validateWebIdeStartProjectPush(o);
1183
1198
  }
1199
+ if (type === "webide-stop-terminals") {
1200
+ return validateWebIdeStopTerminals(o);
1201
+ }
1184
1202
  return validateWebIdeMessagePush(o);
1185
1203
  }
1186
1204
 
@@ -1382,6 +1400,102 @@ function handleStartProjectAction(payload, ctx) {
1382
1400
  trackActionTask(ctx, task);
1383
1401
  }
1384
1402
 
1403
+ // src/commands/connect/pty-session-mcp.ts
1404
+ init_config();
1405
+ var DEFAULT_PTY_SESSION_PORT = "7788";
1406
+ function resolvePtySessionBaseUrl(env = process.env) {
1407
+ const explicit = env.LOCAL_TERMINAL_URL?.trim();
1408
+ if (explicit) return explicit.replace(/\/+$/, "");
1409
+ const port = env.LOCAL_TERMINAL_PORT?.trim() || DEFAULT_PTY_SESSION_PORT;
1410
+ return `http://127.0.0.1:${port}`;
1411
+ }
1412
+ function asSessionList(data) {
1413
+ if (Array.isArray(data)) return data;
1414
+ if (data && typeof data === "object") {
1415
+ const sessions = data.sessions;
1416
+ if (Array.isArray(sessions)) return sessions;
1417
+ }
1418
+ return [];
1419
+ }
1420
+ async function requestPtyJson(url, token, init) {
1421
+ const res = await fetch(url, {
1422
+ ...init,
1423
+ headers: {
1424
+ Authorization: `Bearer ${token}`,
1425
+ ...init?.headers ?? {}
1426
+ }
1427
+ });
1428
+ if (!res.ok) {
1429
+ throw new Error(`pty-session HTTP ${res.status}`);
1430
+ }
1431
+ try {
1432
+ return await res.json();
1433
+ } catch {
1434
+ return null;
1435
+ }
1436
+ }
1437
+ async function killAllPtySessions(cfg) {
1438
+ const token = resolveApiKey(cfg);
1439
+ if (!token) return 0;
1440
+ const baseUrl = resolvePtySessionBaseUrl();
1441
+ let body;
1442
+ try {
1443
+ body = await requestPtyJson(`${baseUrl}/sessions`, token);
1444
+ } catch (err) {
1445
+ console.warn(
1446
+ "[apm] \u5217\u51FA PTY \u4F1A\u8BDD\u5931\u8D25:",
1447
+ err instanceof Error ? err.message : err
1448
+ );
1449
+ return 0;
1450
+ }
1451
+ const payload = body;
1452
+ if (payload && typeof payload === "object" && payload.ok === false) {
1453
+ return 0;
1454
+ }
1455
+ const data = payload && typeof payload === "object" && "data" in payload ? payload.data : body;
1456
+ const sessions = asSessionList(data);
1457
+ let killed = 0;
1458
+ for (const session of sessions) {
1459
+ const id = session.id?.trim();
1460
+ if (!id) continue;
1461
+ if (session.running === false) continue;
1462
+ try {
1463
+ await requestPtyJson(
1464
+ `${baseUrl}/sessions/${encodeURIComponent(id)}`,
1465
+ token,
1466
+ {
1467
+ method: "DELETE"
1468
+ }
1469
+ );
1470
+ killed += 1;
1471
+ } catch (err) {
1472
+ console.warn(
1473
+ `[apm] \u7ED3\u675F PTY \u4F1A\u8BDD\u5931\u8D25 id=${id}:`,
1474
+ err instanceof Error ? err.message : err
1475
+ );
1476
+ }
1477
+ }
1478
+ return killed;
1479
+ }
1480
+
1481
+ // src/commands/connect/actions/stop-terminals.ts
1482
+ function handleStopTerminalsAction(payload, ctx) {
1483
+ const task = (async () => {
1484
+ try {
1485
+ const killed = await killAllPtySessions(ctx.cfg);
1486
+ console.log(
1487
+ `[apm] webide-stop-terminals taskId=${payload.taskId} killed=${killed}`
1488
+ );
1489
+ } catch (err) {
1490
+ console.warn(
1491
+ `[apm] webide-stop-terminals \u5931\u8D25 taskId=${payload.taskId}:`,
1492
+ err instanceof Error ? err.message : err
1493
+ );
1494
+ }
1495
+ })();
1496
+ trackActionTask(ctx, task);
1497
+ }
1498
+
1385
1499
  // src/commands/connect/actions/index.ts
1386
1500
  function dispatchConnectAction(payload, ctx) {
1387
1501
  switch (payload.type) {
@@ -1396,6 +1510,9 @@ function dispatchConnectAction(payload, ctx) {
1396
1510
  case "webide-start-project":
1397
1511
  handleStartProjectAction(payload, ctx);
1398
1512
  return;
1513
+ case "webide-stop-terminals":
1514
+ handleStopTerminalsAction(payload, ctx);
1515
+ return;
1399
1516
  }
1400
1517
  }
1401
1518
 
@@ -1528,10 +1528,10 @@ function createCursorCustomTools(cfg, options) {
1528
1528
  ...options.enableAppendMessage !== false && options.appendMessageContent ? createAppendMessageCustomTools({
1529
1529
  appendContent: options.appendMessageContent
1530
1530
  }) : {},
1531
- ...createAskQuestionTool({
1531
+ ...options.enableAskQuestion !== false ? createAskQuestionTool({
1532
1532
  onInvoke: options?.onAskQuestion,
1533
1533
  execute: options?.askQuestionExecute
1534
- })
1534
+ }) : {}
1535
1535
  };
1536
1536
  if (options?.taskId && options.workdir) {
1537
1537
  const { cli } = createApmApiClient(cfg);
@@ -1668,6 +1668,7 @@ async function runCursorAgent(cfg, ctx, options) {
1668
1668
  onAskQuestion: options.onAskQuestion,
1669
1669
  appendMessageContent: options.appendMessageContent,
1670
1670
  enableAppendMessage: options.enableAppendMessage,
1671
+ enableAskQuestion: options.enableAskQuestion,
1671
1672
  askQuestionExecute: options.askQuestionExecute,
1672
1673
  enableWebIdePlanTools: options.enableWebIdePlanTools,
1673
1674
  taskId: options.taskId,
@@ -3394,7 +3395,7 @@ async function handleStartProject(cfg, msg, signal) {
3394
3395
  forceSend: true,
3395
3396
  eventSession,
3396
3397
  enableAppendMessage: false,
3397
- askQuestionExecute: async () => "\u8FD9\u662F\u65E0\u4EBA\u503C\u5B88\u7684\u542F\u52A8\u4EFB\u52A1\uFF0C\u8BF7\u6839\u636E deploy.md \u81EA\u884C\u51B3\u5B9A\uFF0C\u4E0D\u8981\u7B49\u5F85\u7528\u6237\u3002",
3398
+ enableAskQuestion: false,
3398
3399
  enableWebIdePlanTools: false,
3399
3400
  enablePtySessionMcp: true,
3400
3401
  enableSandbox: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "8.0.3",
3
+ "version": "8.0.5",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -20,7 +20,7 @@
20
20
 
21
21
  ### 目录
22
22
 
23
- - 项目文档:`.apm/project/<项目ID>/`(索引 `manifest.json`;部署 / 本地 dev 命令以 `deploy.md` 为准,禁止猜测)
23
+ - 项目文档:`.apm/project/<项目ID>/`(索引 `manifest.json`;部署 / 本地 dev 命令以该目录下文件名或路径包含 `deploy` 的文档为准,不必恰好叫 `deploy.md`,禁止猜测)
24
24
  - 任务附件:`.apm/webide/<taskId>/attachments/`(prompt 出现「任务附件」时按路径查看)
25
25
  - 仓库清单:`.apm/workspace-repos.json`(先确认单仓 / 多仓;多仓必须写清改动范围并点名仓库)
26
26
 
@@ -19,17 +19,20 @@
19
19
 
20
20
  ## 启动命令来源
21
21
 
22
- 必须 Read `.apm/project/<项目ID>/deploy.md`(完整路径以本轮 prompt 中给出的为准,勿省略项目 ID),按文档中的 cwd / command / 服务划分创建会话。
22
+ 必须在 `.apm/project/<项目ID>/` 下找到 **文件名或路径包含 deploy** 的文档(不必恰好叫 `deploy.md`,例如 `deploy前端.md`、`deploy/医务系统.md`)。完整目录以本轮 prompt 给出的项目 ID 为准,勿省略。
23
23
 
24
- - 文档不存在或未写明启动方式 结束任务,**禁止猜测命令**。
24
+ 1. Read 该目录的 `manifest.json`,从 `documents[].path` 里挑包含 deploy 的条目,再 Read 该文件。
25
+ 2. 没有 manifest 时 Glob `**/*deploy*`。
26
+ 3. 按文档中的 cwd / command / 服务划分创建会话。
27
+ 4. 文档不存在或未写明启动方式 → 结束任务,**禁止猜测命令**。
25
28
 
26
29
  ## 时机(顶栏启动 / 重启)
27
30
 
28
31
  固定顺序:
29
32
 
30
33
  1. **`list`**
31
- 2. 启动:无对应 `name` 的活会话 → deploy.md `create` + `write`;已有同名活会话则结束,不重起
32
- 3. 重启:先 `kill` 目标 `name`,再按 deploy.md `create` + `write`(不要杀掉其它端)
34
+ 2. 启动:无对应 `name` 的活会话 → 按部署文档 `create` + `write`;已有同名活会话则结束,不重起
35
+ 3. 重启:先 `kill` 目标 `name`,再按部署文档 `create` + `write`(不要杀掉其它端)
33
36
  4. `read` 等待就绪日志 / 端口即可
34
37
 
35
38
  用户在「终端」面板看日志,在「浏览器」面板看客户机外网地址。