ai-project-manage-cli 5.0.18 → 5.0.20
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 +238 -19
- package/package.json +1 -1
- package/template/rules/reply.md +1 -0
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"
|
|
@@ -477,10 +483,9 @@ async function runBranch(sessionId, options = {}) {
|
|
|
477
483
|
workdirPath
|
|
478
484
|
});
|
|
479
485
|
if (!baseline.repositoryId) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
);
|
|
486
|
+
const detail = baseline.diagnostic?.message ?? `\u672A\u5728\u5E73\u53F0\u627E\u5230\u4E0E\u5F53\u524D\u76EE\u5F55\u5339\u914D\u7684\u5DE5\u4F5C\u76EE\u5F55\u767B\u8BB0\uFF1A${workdirPath}\uFF08\u89C4\u8303\u5316\uFF1A${baseline.workdirPath}\uFF09
|
|
487
|
+
\u8BF7\u5148\u5728\u5E73\u53F0\u767B\u8BB0\u8BE5\u8DEF\u5F84\u5BF9\u5E94\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0E\u4ED3\u5E93\u3002`;
|
|
488
|
+
throw new Error(`[apm] ${detail}`);
|
|
484
489
|
}
|
|
485
490
|
const baselineBranch = (baseline.defaultBranch ?? "").trim();
|
|
486
491
|
if (!baselineBranch) {
|
|
@@ -1042,23 +1047,225 @@ function validateAgentWsMessage(value, kind) {
|
|
|
1042
1047
|
// src/commands/connect/cursor-agent.ts
|
|
1043
1048
|
import { Agent, CursorAgentError } from "@cursor/sdk";
|
|
1044
1049
|
import { resolve as resolve3 } from "path";
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1050
|
+
|
|
1051
|
+
// src/session-utils.ts
|
|
1052
|
+
var EventSession = class {
|
|
1053
|
+
events = [];
|
|
1054
|
+
constructor(prompt) {
|
|
1055
|
+
this.events.push({
|
|
1056
|
+
type: "input",
|
|
1057
|
+
content: prompt
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
addEvent(event) {
|
|
1061
|
+
const latestEvent = this.events[this.events.length - 1];
|
|
1062
|
+
const formatedEvent = this.formatEvent(event);
|
|
1063
|
+
if (!formatedEvent) {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
if (formatedEvent.type === "tool_call") {
|
|
1067
|
+
const existingToolCall = this.events.find(
|
|
1068
|
+
(e) => e.type === "tool_call" && e.call_id === formatedEvent.call_id
|
|
1069
|
+
);
|
|
1070
|
+
if (existingToolCall) {
|
|
1071
|
+
existingToolCall.args = formatedEvent.args;
|
|
1072
|
+
existingToolCall.result = formatedEvent.result;
|
|
1073
|
+
existingToolCall.status = formatedEvent.status;
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
this.events.push(formatedEvent);
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (formatedEvent.type === "status") {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
if (formatedEvent.type === "request") {
|
|
1083
|
+
this.events.push(formatedEvent);
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
if (latestEvent?.type === formatedEvent.type) {
|
|
1087
|
+
switch (formatedEvent.type) {
|
|
1088
|
+
case "assistant":
|
|
1089
|
+
latestEvent.content += formatedEvent.content;
|
|
1090
|
+
break;
|
|
1091
|
+
case "thinking":
|
|
1092
|
+
latestEvent.content += formatedEvent.content;
|
|
1093
|
+
break;
|
|
1094
|
+
case "task":
|
|
1095
|
+
latestEvent.status = formatedEvent.status;
|
|
1096
|
+
latestEvent.text = formatedEvent.text;
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
this.events.push(formatedEvent);
|
|
1102
|
+
}
|
|
1103
|
+
formatEvent(event) {
|
|
1104
|
+
switch (event.type) {
|
|
1105
|
+
case "assistant": {
|
|
1106
|
+
let content = "";
|
|
1107
|
+
for (const block of event.message.content) {
|
|
1108
|
+
if (block.type === "text" && block.text) {
|
|
1109
|
+
content += block.text;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return {
|
|
1113
|
+
type: "assistant",
|
|
1114
|
+
content: content || event.content || ""
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
case "thinking":
|
|
1118
|
+
return {
|
|
1119
|
+
type: "thinking",
|
|
1120
|
+
content: event.text || event.content || ""
|
|
1121
|
+
};
|
|
1122
|
+
case "tool_call":
|
|
1123
|
+
return {
|
|
1124
|
+
type: "tool_call",
|
|
1125
|
+
args: event.args,
|
|
1126
|
+
result: event.result,
|
|
1127
|
+
status: event.status,
|
|
1128
|
+
call_id: event.call_id,
|
|
1129
|
+
name: event.name
|
|
1130
|
+
};
|
|
1131
|
+
case "task":
|
|
1132
|
+
return {
|
|
1133
|
+
type: "task",
|
|
1134
|
+
status: event.status,
|
|
1135
|
+
text: event.text
|
|
1136
|
+
};
|
|
1137
|
+
case "request":
|
|
1138
|
+
return {
|
|
1139
|
+
...event,
|
|
1140
|
+
type: "request"
|
|
1141
|
+
};
|
|
1142
|
+
case "status":
|
|
1143
|
+
return { type: "status", status: event.status, message: event.message };
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
/** 合并所有 assistant 片段,供剧场成员回传等场景使用 */
|
|
1147
|
+
getAssistantText() {
|
|
1148
|
+
return this.events.filter((e) => e.type === "assistant").map((e) => String(e.content ?? "")).join("\n").trim();
|
|
1149
|
+
}
|
|
1150
|
+
resolveLogContent() {
|
|
1151
|
+
return this.events.map((event) => {
|
|
1152
|
+
const type = event.type;
|
|
1153
|
+
const content = (function(type2) {
|
|
1154
|
+
if (type2 === "input") {
|
|
1155
|
+
return `## \u7528\u6237\u8F93\u5165
|
|
1156
|
+
|
|
1157
|
+
${event.content}
|
|
1158
|
+
`;
|
|
1159
|
+
}
|
|
1160
|
+
if (type2 === "assistant") {
|
|
1161
|
+
return `## \u6A21\u578B\u8F93\u51FA
|
|
1162
|
+
|
|
1163
|
+
${event.content}
|
|
1164
|
+
`;
|
|
1165
|
+
}
|
|
1166
|
+
if (type2 === "thinking") {
|
|
1167
|
+
return `## \u6A21\u578B\u601D\u8003
|
|
1168
|
+
|
|
1169
|
+
${event.content}
|
|
1170
|
+
`;
|
|
1171
|
+
}
|
|
1172
|
+
if (type2 === "tool_call") {
|
|
1173
|
+
return "````toolcall\n" + JSON.stringify(event, null, 2) + "\n````\n";
|
|
1174
|
+
}
|
|
1175
|
+
return `## \u672A\u77E5\u4E8B\u4EF6\uFF1A${type2}
|
|
1176
|
+
|
|
1177
|
+
\`\`\`json
|
|
1178
|
+
${JSON.stringify(event, null, 2)}
|
|
1179
|
+
\`\`\``;
|
|
1180
|
+
})(type);
|
|
1181
|
+
return content;
|
|
1182
|
+
}).join("\n");
|
|
1048
1183
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
// src/commands/connect/cursor-message-log.ts
|
|
1187
|
+
function assistantStreamChunk(event) {
|
|
1188
|
+
if (event.type !== "assistant") {
|
|
1051
1189
|
return "";
|
|
1052
1190
|
}
|
|
1053
1191
|
let text = "";
|
|
1054
|
-
for (const block of
|
|
1192
|
+
for (const block of event.message.content) {
|
|
1055
1193
|
if (block.type === "text" && block.text) {
|
|
1056
1194
|
text += block.text;
|
|
1057
1195
|
}
|
|
1058
1196
|
}
|
|
1059
1197
|
return text;
|
|
1060
1198
|
}
|
|
1061
|
-
|
|
1199
|
+
var CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS = 2e3;
|
|
1200
|
+
function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
|
|
1201
|
+
let lastRunAt = 0;
|
|
1202
|
+
let timer;
|
|
1203
|
+
let latestSession;
|
|
1204
|
+
const execute = async () => {
|
|
1205
|
+
const session = latestSession;
|
|
1206
|
+
if (!session) {
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
lastRunAt = Date.now();
|
|
1210
|
+
try {
|
|
1211
|
+
await syncCursorMessageLog(cfg, ctx, session);
|
|
1212
|
+
} catch (err) {
|
|
1213
|
+
onError(err);
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
return {
|
|
1217
|
+
schedule(session) {
|
|
1218
|
+
latestSession = session;
|
|
1219
|
+
const now = Date.now();
|
|
1220
|
+
const elapsed = now - lastRunAt;
|
|
1221
|
+
if (elapsed >= CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS) {
|
|
1222
|
+
if (timer) {
|
|
1223
|
+
clearTimeout(timer);
|
|
1224
|
+
timer = void 0;
|
|
1225
|
+
}
|
|
1226
|
+
void execute();
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
if (timer) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
timer = setTimeout(() => {
|
|
1233
|
+
timer = void 0;
|
|
1234
|
+
void execute();
|
|
1235
|
+
}, CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS - elapsed);
|
|
1236
|
+
},
|
|
1237
|
+
async flush(session) {
|
|
1238
|
+
latestSession = session;
|
|
1239
|
+
if (timer) {
|
|
1240
|
+
clearTimeout(timer);
|
|
1241
|
+
timer = void 0;
|
|
1242
|
+
}
|
|
1243
|
+
await execute();
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
async function syncCursorMessageLog(cfg, ctx, session) {
|
|
1248
|
+
const agentId = ctx.agentId.trim();
|
|
1249
|
+
const data = session.resolveLogContent().trim();
|
|
1250
|
+
if (!agentId || !data) {
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
const api = createApmApiClient(cfg);
|
|
1254
|
+
await api.cli.upsertCursorMessageLog({
|
|
1255
|
+
sessionId: ctx.sessionId,
|
|
1256
|
+
messageId: ctx.messageId,
|
|
1257
|
+
agentId,
|
|
1258
|
+
data
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/commands/connect/cursor-agent.ts
|
|
1263
|
+
var logCtx = (ctx, agentId) => ({
|
|
1264
|
+
sessionId: ctx.sessionId,
|
|
1265
|
+
messageId: ctx.messageId,
|
|
1266
|
+
agentId
|
|
1267
|
+
});
|
|
1268
|
+
async function runCursorAgent(cfg, ctx) {
|
|
1062
1269
|
const apiKey = ctx.apiKey.trim();
|
|
1063
1270
|
if (!apiKey) {
|
|
1064
1271
|
throw new Error("\u7F3A\u5C11 apiKey\uFF0C\u65E0\u6CD5\u8C03\u7528 Cursor SDK");
|
|
@@ -1076,15 +1283,27 @@ async function runCursorAgent(_cfg, ctx) {
|
|
|
1076
1283
|
settingSources: []
|
|
1077
1284
|
}
|
|
1078
1285
|
});
|
|
1286
|
+
const eventSession = new EventSession(prompt);
|
|
1287
|
+
const remoteLogCtx = logCtx(ctx, agent.agentId);
|
|
1288
|
+
const syncRemoteLog = createThrottledCursorMessageLogSync(
|
|
1289
|
+
cfg,
|
|
1290
|
+
remoteLogCtx,
|
|
1291
|
+
(err) => {
|
|
1292
|
+
console.warn(
|
|
1293
|
+
"[apm] \u540C\u6B65 Cursor \u6D88\u606F\u65E5\u5FD7\u5931\u8D25:",
|
|
1294
|
+
err instanceof Error ? err.message : err
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
);
|
|
1079
1298
|
try {
|
|
1080
1299
|
const run = await agent.send(prompt);
|
|
1081
1300
|
console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
|
|
1082
1301
|
for await (const event of run.stream()) {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
}
|
|
1302
|
+
eventSession.addEvent(event);
|
|
1303
|
+
const chunk = assistantStreamChunk(event);
|
|
1304
|
+
syncRemoteLog.schedule(eventSession);
|
|
1087
1305
|
}
|
|
1306
|
+
await syncRemoteLog.flush(eventSession);
|
|
1088
1307
|
const result = await run.wait();
|
|
1089
1308
|
if (result.status === "error") {
|
|
1090
1309
|
throw new Error(`Cursor run \u5931\u8D25: ${result.id}`);
|
package/package.json
CHANGED
package/template/rules/reply.md
CHANGED