ai-project-manage-cli 5.0.17 → 5.0.19

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.
Files changed (2) hide show
  1. package/dist/index.js +240 -33
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -231,10 +231,12 @@ var requestConfig = {
231
231
  method: "GET",
232
232
  path: "/cli/documents"
233
233
  }),
234
- listAttachments: defineEndpoint({
235
- method: "GET",
236
- path: "/cli/attachments"
237
- }),
234
+ listAttachments: defineEndpoint(
235
+ {
236
+ method: "GET",
237
+ path: "/cli/attachments"
238
+ }
239
+ ),
238
240
  upsertDocument: defineEndpoint({
239
241
  method: "PUT",
240
242
  path: "/cli/documents/upsert"
@@ -243,6 +245,10 @@ var requestConfig = {
243
245
  method: "PUT",
244
246
  path: "/cli/messages/content"
245
247
  }),
248
+ upsertCursorMessageLog: defineEndpoint({
249
+ method: "PUT",
250
+ path: "/cli/cursor-message-logs"
251
+ }),
246
252
  updateMessageStatus: defineEndpoint({
247
253
  method: "PUT",
248
254
  path: "/cli/messages/status"
@@ -1040,66 +1046,268 @@ function validateAgentWsMessage(value, kind) {
1040
1046
  }
1041
1047
 
1042
1048
  // src/commands/connect/cursor-agent.ts
1043
- import { resolve as resolve3 } from "path";
1044
1049
  import { Agent, CursorAgentError } from "@cursor/sdk";
1045
- var DEFAULT_CURSOR_MODEL = "default";
1046
- function resolveModelId(model) {
1047
- const id = model.trim();
1048
- return id || DEFAULT_CURSOR_MODEL;
1049
- }
1050
- function buildPrompt(ctx) {
1051
- const lines = [
1052
- `\u4F60\u662F${ctx.user}`,
1053
- `\u4F1A\u8BDDID: ${ctx.sessionId}`,
1054
- `\u6D88\u606FID: ${ctx.messageId}`,
1055
- `\u4EFB\u52A1: ${ctx.content}`,
1056
- `\u8BF7\u5148\u9605\u8BFBAPM\u6307\u5357\uFF1A [AGENTS.md](.apm/AGENTS.md)\uFF0C\u4E25\u683C\u6309\u7167\u6307\u5357\u7684\u5DE5\u4F5C\u6D41\u7A0B\u5B8C\u6210\u4EFB\u52A1`
1057
- ];
1058
- return lines.join("\n");
1059
- }
1060
- function extractAssistantTextFromStream(event) {
1061
- if (event.type !== "assistant") {
1062
- return "";
1050
+ import { resolve as resolve3 } from "path";
1051
+
1052
+ // src/session-utils.ts
1053
+ var EventSession = class {
1054
+ events = [];
1055
+ constructor(prompt) {
1056
+ this.events.push({
1057
+ type: "input",
1058
+ content: prompt
1059
+ });
1060
+ }
1061
+ addEvent(event) {
1062
+ const latestEvent = this.events[this.events.length - 1];
1063
+ const formatedEvent = this.formatEvent(event);
1064
+ if (!formatedEvent) {
1065
+ return;
1066
+ }
1067
+ if (formatedEvent.type === "tool_call") {
1068
+ const existingToolCall = this.events.find(
1069
+ (e) => e.type === "tool_call" && e.call_id === formatedEvent.call_id
1070
+ );
1071
+ if (existingToolCall) {
1072
+ existingToolCall.args = formatedEvent.args;
1073
+ existingToolCall.result = formatedEvent.result;
1074
+ existingToolCall.status = formatedEvent.status;
1075
+ return;
1076
+ }
1077
+ this.events.push(formatedEvent);
1078
+ return;
1079
+ }
1080
+ if (formatedEvent.type === "status") {
1081
+ return;
1082
+ }
1083
+ if (formatedEvent.type === "request") {
1084
+ this.events.push(formatedEvent);
1085
+ return;
1086
+ }
1087
+ if (latestEvent?.type === formatedEvent.type) {
1088
+ switch (formatedEvent.type) {
1089
+ case "assistant":
1090
+ latestEvent.content += formatedEvent.content;
1091
+ break;
1092
+ case "thinking":
1093
+ latestEvent.content += formatedEvent.content;
1094
+ break;
1095
+ case "task":
1096
+ latestEvent.status = formatedEvent.status;
1097
+ latestEvent.text = formatedEvent.text;
1098
+ break;
1099
+ }
1100
+ return;
1101
+ }
1102
+ this.events.push(formatedEvent);
1103
+ }
1104
+ formatEvent(event) {
1105
+ switch (event.type) {
1106
+ case "assistant": {
1107
+ let content = "";
1108
+ for (const block of event.message.content) {
1109
+ if (block.type === "text" && block.text) {
1110
+ content += block.text;
1111
+ }
1112
+ }
1113
+ return {
1114
+ type: "assistant",
1115
+ content: content || event.content || ""
1116
+ };
1117
+ }
1118
+ case "thinking":
1119
+ return {
1120
+ type: "thinking",
1121
+ content: event.text || event.content || ""
1122
+ };
1123
+ case "tool_call":
1124
+ return {
1125
+ type: "tool_call",
1126
+ args: event.args,
1127
+ result: event.result,
1128
+ status: event.status,
1129
+ call_id: event.call_id,
1130
+ name: event.name
1131
+ };
1132
+ case "task":
1133
+ return {
1134
+ type: "task",
1135
+ status: event.status,
1136
+ text: event.text
1137
+ };
1138
+ case "request":
1139
+ return {
1140
+ ...event,
1141
+ type: "request"
1142
+ };
1143
+ case "status":
1144
+ return { type: "status", status: event.status, message: event.message };
1145
+ }
1146
+ }
1147
+ /** 合并所有 assistant 片段,供剧场成员回传等场景使用 */
1148
+ getAssistantText() {
1149
+ return this.events.filter((e) => e.type === "assistant").map((e) => String(e.content ?? "")).join("\n").trim();
1150
+ }
1151
+ resolveLogContent() {
1152
+ return this.events.map((event) => {
1153
+ const type = event.type;
1154
+ const content = (function(type2) {
1155
+ if (type2 === "input") {
1156
+ return `## \u7528\u6237\u8F93\u5165
1157
+
1158
+ ${event.content}
1159
+ `;
1160
+ }
1161
+ if (type2 === "assistant") {
1162
+ return `## \u6A21\u578B\u8F93\u51FA
1163
+
1164
+ ${event.content}
1165
+ `;
1166
+ }
1167
+ if (type2 === "thinking") {
1168
+ return `## \u6A21\u578B\u601D\u8003
1169
+
1170
+ ${event.content}
1171
+ `;
1172
+ }
1173
+ if (type2 === "tool_call") {
1174
+ return "````toolcall\n" + JSON.stringify(event, null, 2) + "\n````\n";
1175
+ }
1176
+ return `## \u672A\u77E5\u4E8B\u4EF6\uFF1A${type2}
1177
+
1178
+ \`\`\`json
1179
+ ${JSON.stringify(event, null, 2)}
1180
+ \`\`\``;
1181
+ })(type);
1182
+ return content;
1183
+ }).join("\n");
1063
1184
  }
1064
- const msg = event.message;
1065
- if (!msg?.content) {
1185
+ };
1186
+
1187
+ // src/commands/connect/cursor-message-log.ts
1188
+ function assistantStreamChunk(event) {
1189
+ if (event.type !== "assistant") {
1066
1190
  return "";
1067
1191
  }
1068
1192
  let text = "";
1069
- for (const block of msg.content) {
1193
+ for (const block of event.message.content) {
1070
1194
  if (block.type === "text" && block.text) {
1071
1195
  text += block.text;
1072
1196
  }
1073
1197
  }
1074
1198
  return text;
1075
1199
  }
1076
- async function runCursorAgent(_cfg, ctx) {
1200
+ var CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS = 2e3;
1201
+ function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
1202
+ let lastRunAt = 0;
1203
+ let timer;
1204
+ let latestSession;
1205
+ const execute = async () => {
1206
+ const session = latestSession;
1207
+ if (!session) {
1208
+ return;
1209
+ }
1210
+ lastRunAt = Date.now();
1211
+ try {
1212
+ await syncCursorMessageLog(cfg, ctx, session);
1213
+ } catch (err) {
1214
+ onError(err);
1215
+ }
1216
+ };
1217
+ return {
1218
+ schedule(session) {
1219
+ latestSession = session;
1220
+ const now = Date.now();
1221
+ const elapsed = now - lastRunAt;
1222
+ if (elapsed >= CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS) {
1223
+ if (timer) {
1224
+ clearTimeout(timer);
1225
+ timer = void 0;
1226
+ }
1227
+ void execute();
1228
+ return;
1229
+ }
1230
+ if (timer) {
1231
+ return;
1232
+ }
1233
+ timer = setTimeout(() => {
1234
+ timer = void 0;
1235
+ void execute();
1236
+ }, CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS - elapsed);
1237
+ },
1238
+ async flush(session) {
1239
+ latestSession = session;
1240
+ if (timer) {
1241
+ clearTimeout(timer);
1242
+ timer = void 0;
1243
+ }
1244
+ await execute();
1245
+ }
1246
+ };
1247
+ }
1248
+ async function syncCursorMessageLog(cfg, ctx, session) {
1249
+ const agentId = ctx.agentId.trim();
1250
+ const data = session.resolveLogContent().trim();
1251
+ if (!agentId || !data) {
1252
+ return;
1253
+ }
1254
+ const api = createApmApiClient(cfg);
1255
+ await api.cli.upsertCursorMessageLog({
1256
+ sessionId: ctx.sessionId,
1257
+ messageId: ctx.messageId,
1258
+ agentId,
1259
+ data
1260
+ });
1261
+ }
1262
+
1263
+ // src/commands/connect/cursor-agent.ts
1264
+ var logCtx = (ctx, agentId) => ({
1265
+ sessionId: ctx.sessionId,
1266
+ messageId: ctx.messageId,
1267
+ agentId
1268
+ });
1269
+ async function runCursorAgent(cfg, ctx) {
1077
1270
  const apiKey = ctx.apiKey.trim();
1078
1271
  if (!apiKey) {
1079
1272
  throw new Error("\u7F3A\u5C11 apiKey\uFF0C\u65E0\u6CD5\u8C03\u7528 Cursor SDK");
1080
1273
  }
1081
1274
  const cwd = resolve3(ctx.workdir);
1082
- const prompt = buildPrompt(ctx);
1275
+ const prompt = ctx.prompt;
1083
1276
  console.log(
1084
1277
  `[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} sessionId=${ctx.sessionId} cwd=${cwd}`
1085
1278
  );
1086
1279
  const agent = await Agent.create({
1087
1280
  apiKey,
1088
- model: { id: resolveModelId(ctx.model) },
1281
+ model: { id: ctx.model || "default" },
1089
1282
  local: {
1090
1283
  cwd,
1091
1284
  settingSources: []
1092
1285
  }
1093
1286
  });
1287
+ const eventSession = new EventSession(prompt);
1288
+ const remoteLogCtx = logCtx(ctx, agent.agentId);
1289
+ const syncRemoteLog = createThrottledCursorMessageLogSync(
1290
+ cfg,
1291
+ remoteLogCtx,
1292
+ (err) => {
1293
+ console.warn(
1294
+ "[apm] \u540C\u6B65 Cursor \u6D88\u606F\u65E5\u5FD7\u5931\u8D25:",
1295
+ err instanceof Error ? err.message : err
1296
+ );
1297
+ }
1298
+ );
1094
1299
  try {
1095
1300
  const run = await agent.send(prompt);
1096
1301
  console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
1097
1302
  for await (const event of run.stream()) {
1098
- const chunk = extractAssistantTextFromStream(event);
1303
+ eventSession.addEvent(event);
1304
+ const chunk = assistantStreamChunk(event);
1099
1305
  if (chunk) {
1100
1306
  process.stdout.write(chunk);
1101
1307
  }
1308
+ syncRemoteLog.schedule(eventSession);
1102
1309
  }
1310
+ await syncRemoteLog.flush(eventSession);
1103
1311
  const result = await run.wait();
1104
1312
  if (result.status === "error") {
1105
1313
  throw new Error(`Cursor run \u5931\u8D25: ${result.id}`);
@@ -1159,11 +1367,10 @@ async function handleInboundMessage(cfg, raw) {
1159
1367
  await runCursorAgent(cfg, {
1160
1368
  messageId: msg.messageId,
1161
1369
  sessionId: msg.sessionId,
1162
- content: msg.content,
1370
+ prompt: msg.content,
1163
1371
  model: msg.model,
1164
1372
  apiKey: msg.apiKey,
1165
- workdir: msg.workdir,
1166
- user: msg.user
1373
+ workdir: msg.workdir
1167
1374
  });
1168
1375
  await updateMessageStatus(cfg, messageId, "SUCCESS");
1169
1376
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "5.0.17",
3
+ "version": "5.0.19",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,