ai-project-manage-cli 4.0.17 → 4.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 +213 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -155,6 +155,10 @@ var requestConfig = {
155
155
  })
156
156
  },
157
157
  theater: {
158
+ reportMemberAgentProgress: defineEndpoint({
159
+ method: "POST",
160
+ path: "/theater/sessions/report-member-agent-progress"
161
+ }),
158
162
  submitMemberResponse: defineEndpoint({
159
163
  method: "POST",
160
164
  path: "/theater/sessions/submit-member-response"
@@ -370,7 +374,7 @@ async function runComment(requirementId, file, options) {
370
374
  }
371
375
 
372
376
  // src/commands/connect.ts
373
- import { randomUUID } from "crypto";
377
+ import { randomUUID as randomUUID2 } from "crypto";
374
378
  import WebSocket from "ws";
375
379
  import { Agent } from "@cursor/sdk";
376
380
  import { join as join6 } from "path";
@@ -777,11 +781,149 @@ async function runPull(requirementId, workspaceDir) {
777
781
  return WORKITEMS_DIR;
778
782
  }
779
783
 
784
+ // src/theater-job-report.ts
785
+ import { randomUUID } from "crypto";
786
+ function extractErrorMessage(err) {
787
+ if (err instanceof Error && err.message.trim()) {
788
+ return err.message.trim();
789
+ }
790
+ if (typeof err === "string" && err.trim()) {
791
+ return err.trim();
792
+ }
793
+ if (typeof err === "object" && err && "message" in err) {
794
+ const msg = err.message;
795
+ if (typeof msg === "string" && msg.trim()) return msg.trim();
796
+ if (Array.isArray(msg)) return msg.map(String).join("\uFF1B");
797
+ }
798
+ return "\u672A\u77E5\u9519\u8BEF";
799
+ }
800
+ function isUnauthorizedMessage(msg) {
801
+ return msg.includes("\u672A\u767B\u5F55") || /401/.test(msg);
802
+ }
803
+ function sendTheaterReportWs(ws, payload) {
804
+ return new Promise((resolve5, reject) => {
805
+ const msg_id = randomUUID();
806
+ const timer = setTimeout(() => {
807
+ ws.off("message", onMessage);
808
+ reject(new Error("WebSocket \u4E0A\u62A5\u8D85\u65F6"));
809
+ }, 3e4);
810
+ const onMessage = (data) => {
811
+ const text = typeof data === "string" ? data : data.toString();
812
+ let frame;
813
+ try {
814
+ frame = JSON.parse(text);
815
+ } catch {
816
+ return;
817
+ }
818
+ if (frame.msg_id !== msg_id) return;
819
+ clearTimeout(timer);
820
+ ws.off("message", onMessage);
821
+ if (frame.type === "ERROR") {
822
+ reject(
823
+ new Error(frame.payload?.message?.trim() || "WebSocket \u4E0A\u62A5\u5931\u8D25")
824
+ );
825
+ return;
826
+ }
827
+ if (frame.type === "ACK") {
828
+ resolve5();
829
+ return;
830
+ }
831
+ };
832
+ ws.on("message", onMessage);
833
+ ws.send(
834
+ JSON.stringify({
835
+ type: "THEATER_REPORT",
836
+ msg_id,
837
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
838
+ payload
839
+ })
840
+ );
841
+ });
842
+ }
843
+ async function reportTheaterProgress(api, ws, params) {
844
+ const body = {
845
+ sessionId: params.sessionId,
846
+ memberKey: params.memberKey,
847
+ status: "IN_PROGRESS",
848
+ logId: params.logId
849
+ };
850
+ try {
851
+ await api.theater.reportMemberAgentProgress(body);
852
+ } catch (err) {
853
+ const msg = extractErrorMessage(err);
854
+ if (!isUnauthorizedMessage(msg)) throw err;
855
+ await sendTheaterReportWs(ws, { action: "progress", ...body });
856
+ }
857
+ }
858
+ async function submitTheaterResult(api, ws, params) {
859
+ const body = {
860
+ sessionId: params.sessionId,
861
+ memberKey: params.memberKey,
862
+ content: params.content,
863
+ agentId: params.agentId ?? "",
864
+ agentStatus: params.agentStatus,
865
+ logId: params.logId
866
+ };
867
+ try {
868
+ await api.theater.submitMemberResponse(body);
869
+ } catch (err) {
870
+ const msg = extractErrorMessage(err);
871
+ if (!isUnauthorizedMessage(msg)) throw err;
872
+ await sendTheaterReportWs(ws, {
873
+ action: "submit",
874
+ sessionId: params.sessionId,
875
+ memberKey: params.memberKey,
876
+ content: params.content,
877
+ agentId: params.agentId,
878
+ agentStatus: params.agentStatus,
879
+ logId: params.logId
880
+ });
881
+ }
882
+ }
883
+ async function submitTheaterFailure(api, ws, params) {
884
+ const content = `[${params.stage}] ${params.error}`;
885
+ try {
886
+ await submitTheaterResult(api, ws, {
887
+ sessionId: params.sessionId,
888
+ memberKey: params.memberKey,
889
+ content,
890
+ agentId: params.agentId,
891
+ agentStatus: "FAILED",
892
+ logId: params.logId
893
+ });
894
+ return true;
895
+ } catch (submitErr) {
896
+ console.error(
897
+ "[apm] \u65E0\u6CD5\u5C06\u5931\u8D25\u72B6\u6001\u5199\u5165\u5267\u573A\u4F1A\u8BDD:",
898
+ extractErrorMessage(submitErr)
899
+ );
900
+ return false;
901
+ }
902
+ }
903
+ function logTheaterJobError(stage, err, meta) {
904
+ const msg = extractErrorMessage(err);
905
+ const ctx = [
906
+ meta?.sessionId ? `session=${meta.sessionId}` : "",
907
+ meta?.memberKey ? `member=${meta.memberKey}` : ""
908
+ ].filter(Boolean).join(" ");
909
+ console.error(
910
+ `[apm] \u5267\u573A THEATER_JOB \u5931\u8D25 \xB7 \u9636\u6BB5=${stage}${ctx ? ` \xB7 ${ctx}` : ""} \xB7 ${msg}`
911
+ );
912
+ if (isUnauthorizedMessage(msg)) {
913
+ console.error("[apm] \u63D0\u793A: \u8BF7\u6267\u884C apm login \u91CD\u65B0\u767B\u5F55\u540E\u518D\u8BD5");
914
+ }
915
+ }
916
+
780
917
  // src/commands/connect.ts
918
+ var DEFAULT_AGENT_MODEL_ID = "default";
919
+ function resolveAgentModelId(model) {
920
+ const id = model?.trim();
921
+ return id || DEFAULT_AGENT_MODEL_ID;
922
+ }
781
923
  async function createAgentForJob(payload) {
782
924
  const options = {
783
925
  apiKey: payload.apiKey,
784
- model: { id: payload.model ?? "default" },
926
+ model: { id: resolveAgentModelId(payload.model) },
785
927
  local: { cwd: payload.cwd }
786
928
  };
787
929
  if (payload.agentId) {
@@ -835,9 +977,10 @@ async function runAgentStream(payload, session, agent) {
835
977
  }
836
978
  return { agentId: run.agentId, failed, failReason };
837
979
  }
838
- async function handleTheaterJob(api, payload) {
980
+ async function handleTheaterJob(api, ws, payload) {
839
981
  const sessionId = payload.theaterSessionId.trim();
840
982
  const memberKey = payload.memberKey.trim();
983
+ const logId = payload.logId?.trim() || void 0;
841
984
  if (!sessionId) {
842
985
  throw new Error("THEATER_JOB \u7F3A\u5C11 theaterSessionId");
843
986
  }
@@ -845,29 +988,53 @@ async function handleTheaterJob(api, payload) {
845
988
  throw new Error("THEATER_JOB \u7F3A\u5C11 memberKey");
846
989
  }
847
990
  console.log("[apm] \u5267\u573A\u4F1A\u8BDD:", sessionId, "\u6210\u5458:", memberKey);
848
- const eventSession = new EventSession(payload.prompt);
849
- const agent = await createAgentForJob(payload);
850
- const { agentId, failed, failReason } = await runAgentStream(
851
- payload,
852
- eventSession,
853
- agent
854
- );
855
- const assistantText = eventSession.getAssistantText();
856
- const content = failed ? `[Agent \u6267\u884C\u5931\u8D25] ${failReason || "\u672A\u77E5\u9519\u8BEF"}` : assistantText || "[Agent \u672A\u4EA7\u751F\u6587\u672C\u8F93\u51FA]";
857
- const result = await api.theater.submitMemberResponse({
858
- sessionId,
859
- memberKey,
860
- content,
861
- agentId,
862
- logId: payload.logId?.trim() || void 0
863
- });
864
- console.log(
865
- "[apm] \u5267\u573A\u6210\u5458\u56DE\u590D\u5DF2\u63D0\u4EA4",
866
- failed ? "(\u542B\u5931\u8D25\u8BF4\u660E)" : "",
867
- result.clearedPending ? "\xB7 \u5DF2\u6E05\u9664\u5F85\u56DE\u590D" : ""
868
- );
869
- if (result.canAdvance) {
870
- console.log("[apm] \u53EF\u624B\u52A8\u63A8\u8FDB\u4E3B\u6301\u8F6E\u6B21\uFF08autoPlay \u5173\u95ED\uFF09");
991
+ let agentId = payload.agentId?.trim() || void 0;
992
+ try {
993
+ await reportTheaterProgress(api, ws, { sessionId, memberKey, logId });
994
+ } catch (err) {
995
+ logTheaterJobError("\u4E0A\u62A5\u6267\u884C\u8FDB\u5EA6", err, { sessionId, memberKey });
996
+ await submitTheaterFailure(api, ws, {
997
+ sessionId,
998
+ memberKey,
999
+ logId,
1000
+ agentId,
1001
+ stage: "\u4E0A\u62A5\u8FDB\u5EA6",
1002
+ error: extractErrorMessage(err)
1003
+ });
1004
+ return;
1005
+ }
1006
+ try {
1007
+ const eventSession = new EventSession(payload.prompt);
1008
+ const agent = await createAgentForJob(payload);
1009
+ const runResult = await runAgentStream(payload, eventSession, agent);
1010
+ agentId = runResult.agentId;
1011
+ const assistantText = eventSession.getAssistantText();
1012
+ const content = runResult.failed ? runResult.failReason || assistantText || "\u672A\u77E5\u9519\u8BEF" : assistantText || "[Agent \u672A\u4EA7\u751F\u6587\u672C\u8F93\u51FA]";
1013
+ await submitTheaterResult(api, ws, {
1014
+ sessionId,
1015
+ memberKey,
1016
+ content,
1017
+ agentId,
1018
+ agentStatus: runResult.failed ? "FAILED" : "SUCCESS",
1019
+ logId
1020
+ });
1021
+ console.log(
1022
+ "[apm] \u5267\u573A\u6210\u5458\u56DE\u590D\u5DF2\u63D0\u4EA4",
1023
+ runResult.failed ? "(\u6267\u884C\u5931\u8D25)" : ""
1024
+ );
1025
+ } catch (err) {
1026
+ logTheaterJobError("\u6267\u884C\u6216\u63D0\u4EA4\u56DE\u590D", err, { sessionId, memberKey });
1027
+ const reported = await submitTheaterFailure(api, ws, {
1028
+ sessionId,
1029
+ memberKey,
1030
+ logId,
1031
+ agentId,
1032
+ stage: "\u6267\u884C\u4EFB\u52A1",
1033
+ error: extractErrorMessage(err)
1034
+ });
1035
+ if (reported) {
1036
+ console.error("[apm] \u5DF2\u5C06\u5931\u8D25\u539F\u56E0\u5199\u5165\u5267\u573A\u4F1A\u8BDD\uFF0C\u53EF\u5728\u7F51\u9875\u67E5\u770B");
1037
+ }
871
1038
  }
872
1039
  }
873
1040
  async function handleWorkflowJob(api, payload) {
@@ -947,7 +1114,7 @@ function runConnect(opts) {
947
1114
  const sendHeartbeat = () => {
948
1115
  const frame = {
949
1116
  type: "HEARTBEAT",
950
- msg_id: randomUUID(),
1117
+ msg_id: randomUUID2(),
951
1118
  ts: (/* @__PURE__ */ new Date()).toISOString(),
952
1119
  payload: {}
953
1120
  };
@@ -959,22 +1126,31 @@ function runConnect(opts) {
959
1126
  });
960
1127
  ws.on("message", async (data) => {
961
1128
  const text = typeof data === "string" ? data : data.toString();
1129
+ let msg;
962
1130
  try {
963
- const msg = JSON.parse(text);
964
- if (msg.type === "THEATER_JOB") {
965
- await handleTheaterJob(api, msg.payload);
966
- return;
967
- }
968
- if (msg.type === "JOB") {
969
- await handleWorkflowJob(api, msg.payload);
970
- return;
971
- }
1131
+ msg = JSON.parse(text);
972
1132
  } catch (err) {
973
1133
  console.error(
974
1134
  "[apm] \u65E0\u6CD5\u89E3\u6790 WebSocket \u6D88\u606F:",
975
1135
  text,
976
1136
  err.message
977
1137
  );
1138
+ return;
1139
+ }
1140
+ try {
1141
+ const jobType = msg.type;
1142
+ if (jobType === "THEATER_JOB") {
1143
+ await handleTheaterJob(api, ws, msg.payload);
1144
+ return;
1145
+ }
1146
+ if (jobType === "JOB") {
1147
+ await handleWorkflowJob(api, msg.payload);
1148
+ return;
1149
+ }
1150
+ } catch (err) {
1151
+ const jobType = msg.type;
1152
+ const label = jobType === "THEATER_JOB" ? "\u5267\u573A THEATER_JOB" : jobType === "JOB" ? "\u5DE5\u4F5C\u6D41 JOB" : String(jobType);
1153
+ console.error(`[apm] ${label} \u5904\u7406\u5931\u8D25:`, extractErrorMessage(err));
978
1154
  }
979
1155
  });
980
1156
  ws.on("error", (err) => {
@@ -2033,7 +2209,7 @@ function loadApmDotEnvIfPresent() {
2033
2209
 
2034
2210
  // src/commands/deploy/internal/minio.ts
2035
2211
  import { statSync as statSync5 } from "node:fs";
2036
- import { readdir } from "node:fs/promises";
2212
+ import { readdir, readFile } from "node:fs/promises";
2037
2213
  import path6 from "node:path";
2038
2214
  import * as Minio from "minio";
2039
2215
  var DEFAULT_MAX_FILE_SIZE_MB = 50;
@@ -2083,7 +2259,6 @@ async function collectFiles(root) {
2083
2259
  return out;
2084
2260
  }
2085
2261
  async function readArtifactFile(absPath) {
2086
- const { readFile } = await import("node:fs/promises");
2087
2262
  return readFile(absPath);
2088
2263
  }
2089
2264
  function toMB(bytes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "4.0.17",
3
+ "version": "4.0.19",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,