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