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.
- package/dist/index.js +240 -33
- 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
|
-
|
|
236
|
-
|
|
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
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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
|
-
|
|
1065
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|