ai-project-manage-cli 4.0.21 → 4.0.23
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 +446 -177
- package/package.json +1 -1
- package/template/theater-skills/README.md +13 -0
- package/template/theater-skills/apm-theater-backend/SKILL.md +115 -0
- package/template/theater-skills/apm-theater-backend/apm-theater-api-template.md +146 -0
- package/template/theater-skills/apm-theater-backend/apm-theater-backend-template.md +132 -0
- package/template/theater-skills/apm-theater-dev/SKILL.md +149 -0
- package/template/theater-skills/apm-theater-prd/SKILL.md +98 -0
package/dist/index.js
CHANGED
|
@@ -154,7 +154,33 @@ var requestConfig = {
|
|
|
154
154
|
path: "/requirement-artifacts/delete"
|
|
155
155
|
})
|
|
156
156
|
},
|
|
157
|
+
theaterSessionArtifact: {
|
|
158
|
+
upsert: defineEndpoint({
|
|
159
|
+
method: "POST",
|
|
160
|
+
path: "/theater-session-artifacts/upsert"
|
|
161
|
+
}),
|
|
162
|
+
create: defineEndpoint({
|
|
163
|
+
method: "POST",
|
|
164
|
+
path: "/theater-session-artifacts/create"
|
|
165
|
+
}),
|
|
166
|
+
update: defineEndpoint({
|
|
167
|
+
method: "POST",
|
|
168
|
+
path: "/theater-session-artifacts/update"
|
|
169
|
+
}),
|
|
170
|
+
list: defineEndpoint({
|
|
171
|
+
method: "GET",
|
|
172
|
+
path: "/theater-session-artifacts/list"
|
|
173
|
+
}),
|
|
174
|
+
get: defineEndpoint({
|
|
175
|
+
method: "GET",
|
|
176
|
+
path: "/theater-session-artifacts/get"
|
|
177
|
+
})
|
|
178
|
+
},
|
|
157
179
|
theater: {
|
|
180
|
+
sessionBranchBaseline: defineEndpoint({
|
|
181
|
+
method: "GET",
|
|
182
|
+
path: "/theater/sessions/branch-baseline"
|
|
183
|
+
}),
|
|
158
184
|
reportMemberAgentProgress: defineEndpoint({
|
|
159
185
|
method: "POST",
|
|
160
186
|
path: "/theater/sessions/report-member-agent-progress"
|
|
@@ -203,6 +229,20 @@ var WORKSPACE_APM_DIR = resolve(process.cwd(), ".apm");
|
|
|
203
229
|
function requirementWorkitemsDir(requirementId, workspaceDir = WORKSPACE_APM_DIR) {
|
|
204
230
|
return join2(workspaceDir, "workitems", requirementId);
|
|
205
231
|
}
|
|
232
|
+
function theaterSessionDir(sessionId, apmRoot = WORKSPACE_APM_DIR) {
|
|
233
|
+
return join2(apmRoot, "theater-sessions", sessionId);
|
|
234
|
+
}
|
|
235
|
+
function normalizeTheaterArtifactFileName(fileName) {
|
|
236
|
+
return fileName.trim().replace(/\\/g, "/").replace(/^\/+/, "").replace(/^docs\//, "");
|
|
237
|
+
}
|
|
238
|
+
function theaterArtifactLocalRelativePath(fileName) {
|
|
239
|
+
const base = normalizeTheaterArtifactFileName(fileName);
|
|
240
|
+
return `docs/${base}`;
|
|
241
|
+
}
|
|
242
|
+
function theaterSessionDocumentPath(sessionId, fileName = "prd.md", apmRoot = WORKSPACE_APM_DIR) {
|
|
243
|
+
const localRelative = theaterArtifactLocalRelativePath(fileName);
|
|
244
|
+
return join2(theaterSessionDir(sessionId, apmRoot), localRelative);
|
|
245
|
+
}
|
|
206
246
|
async function ensureLoggedConfig() {
|
|
207
247
|
const cfg = await ensureApmConfig();
|
|
208
248
|
if (!cfg.token) {
|
|
@@ -377,7 +417,7 @@ async function runComment(requirementId, file, options) {
|
|
|
377
417
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
378
418
|
import WebSocket from "ws";
|
|
379
419
|
import { Agent } from "@cursor/sdk";
|
|
380
|
-
import { join as
|
|
420
|
+
import { join as join7 } from "path";
|
|
381
421
|
|
|
382
422
|
// src/session-utils.ts
|
|
383
423
|
import { appendFileSync } from "fs";
|
|
@@ -780,6 +820,243 @@ async function runPull(requirementId, workspaceDir) {
|
|
|
780
820
|
return WORKITEMS_DIR;
|
|
781
821
|
}
|
|
782
822
|
|
|
823
|
+
// src/commands/pull-theater-session.ts
|
|
824
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
825
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
826
|
+
function normalizeRelativePath(fileName) {
|
|
827
|
+
return theaterArtifactLocalRelativePath(fileName);
|
|
828
|
+
}
|
|
829
|
+
async function runPullTheaterSession(sessionId, apmRoot = WORKSPACE_APM_DIR) {
|
|
830
|
+
const trimmedSessionId = sessionId.trim();
|
|
831
|
+
if (!trimmedSessionId) {
|
|
832
|
+
throw new Error("sessionId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
833
|
+
}
|
|
834
|
+
const cfg = await ensureLoggedConfig();
|
|
835
|
+
const api = createApmApiClient(cfg);
|
|
836
|
+
const sessionDir = theaterSessionDir(trimmedSessionId, apmRoot);
|
|
837
|
+
await ensureDirExists(sessionDir);
|
|
838
|
+
await ensureDirExists(join6(sessionDir, "docs"));
|
|
839
|
+
const pageSize = 500;
|
|
840
|
+
let page = 1;
|
|
841
|
+
const items = [];
|
|
842
|
+
while (true) {
|
|
843
|
+
const batch = await api.theaterSessionArtifact.list({
|
|
844
|
+
sessionId: trimmedSessionId,
|
|
845
|
+
page,
|
|
846
|
+
pageSize
|
|
847
|
+
});
|
|
848
|
+
items.push(...batch.items);
|
|
849
|
+
if (batch.total === 0 || items.length >= batch.total) break;
|
|
850
|
+
page += 1;
|
|
851
|
+
}
|
|
852
|
+
for (const item of items) {
|
|
853
|
+
const art = await api.theaterSessionArtifact.get({
|
|
854
|
+
sessionId: trimmedSessionId,
|
|
855
|
+
artifactId: item.id
|
|
856
|
+
});
|
|
857
|
+
const relativePath = normalizeRelativePath(art.fileName);
|
|
858
|
+
const destPath = join6(sessionDir, relativePath);
|
|
859
|
+
await ensureDirExists(dirname2(destPath));
|
|
860
|
+
writeFileSync4(destPath, art.content, "utf8");
|
|
861
|
+
console.log(`[apm] \u5DF2\u8986\u76D6\u4F1A\u8BDD\u6587\u6863: ${relativePath}`);
|
|
862
|
+
}
|
|
863
|
+
return sessionDir;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/commands/branch.ts
|
|
867
|
+
import { execFile } from "child_process";
|
|
868
|
+
import { resolve as resolve3 } from "path";
|
|
869
|
+
import { promisify } from "util";
|
|
870
|
+
var execFileAsync = promisify(execFile);
|
|
871
|
+
async function fetchBaselineBranchFromApi(requirementId, cwd) {
|
|
872
|
+
const cfg = await ensureLoggedConfig();
|
|
873
|
+
const api = createApmApiClient(cfg);
|
|
874
|
+
const workdirPath = resolve3(cwd);
|
|
875
|
+
const res = await api.cliRequirements.branchBaseline({
|
|
876
|
+
requirementId,
|
|
877
|
+
workdirPath
|
|
878
|
+
});
|
|
879
|
+
if (!res.repositoryId) {
|
|
880
|
+
throw new Error(
|
|
881
|
+
`[apm] \u672A\u5728\u5E73\u53F0\u627E\u5230\u4E0E\u5F53\u524D\u76EE\u5F55\u5339\u914D\u7684\u5DE5\u4F5C\u76EE\u5F55\u767B\u8BB0\uFF1A${workdirPath}
|
|
882
|
+
\u8BF7\u5148\u5728\u5E73\u53F0\u767B\u8BB0\u8BE5\u8DEF\u5F84\u5BF9\u5E94\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0E\u4ED3\u5E93\u3002`
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
const name = (res.defaultBranch ?? "").trim();
|
|
886
|
+
if (!name) {
|
|
887
|
+
throw new Error("[apm] \u5E73\u53F0\u8FD4\u56DE\u7684\u57FA\u7EBF\u5206\u652F\u540D\u4E3A\u7A7A");
|
|
888
|
+
}
|
|
889
|
+
return name;
|
|
890
|
+
}
|
|
891
|
+
async function fetchTheaterBaselineBranchFromApi(sessionId, cwd) {
|
|
892
|
+
const cfg = await ensureLoggedConfig();
|
|
893
|
+
const api = createApmApiClient(cfg);
|
|
894
|
+
const workdirPath = resolve3(cwd);
|
|
895
|
+
const res = await api.theater.sessionBranchBaseline({
|
|
896
|
+
sessionId,
|
|
897
|
+
workdirPath
|
|
898
|
+
});
|
|
899
|
+
if (!res.repositoryId) {
|
|
900
|
+
throw new Error(
|
|
901
|
+
`[apm] \u672A\u5728\u5E73\u53F0\u627E\u5230\u4E0E\u5F53\u524D\u76EE\u5F55\u5339\u914D\u7684\u5DE5\u4F5C\u76EE\u5F55\u767B\u8BB0\uFF1A${workdirPath}
|
|
902
|
+
\u8BF7\u5148\u5728\u5E73\u53F0\u767B\u8BB0\u8BE5\u8DEF\u5F84\u5BF9\u5E94\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0E\u4ED3\u5E93\u3002`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
const name = (res.defaultBranch ?? "").trim();
|
|
906
|
+
if (!name) {
|
|
907
|
+
throw new Error("[apm] \u5E73\u53F0\u8FD4\u56DE\u7684\u57FA\u7EBF\u5206\u652F\u540D\u4E3A\u7A7A");
|
|
908
|
+
}
|
|
909
|
+
return name;
|
|
910
|
+
}
|
|
911
|
+
function branchNameForRequirement(requirementId) {
|
|
912
|
+
const id = requirementId.trim();
|
|
913
|
+
if (!id) {
|
|
914
|
+
throw new Error("[apm] \u9700\u6C42 ID \u4E0D\u80FD\u4E3A\u7A7A");
|
|
915
|
+
}
|
|
916
|
+
if (/[\s/\\]/.test(id)) {
|
|
917
|
+
throw new Error(
|
|
918
|
+
"[apm] \u9700\u6C42 ID \u4E0D\u80FD\u5305\u542B\u7A7A\u767D\u6216\u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u8BF7\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001._- \u7B49"
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
return `feat/req-${id}`;
|
|
922
|
+
}
|
|
923
|
+
var branchNameForTheaterSession = branchNameForRequirement;
|
|
924
|
+
async function execGit(cwd, args, quiet) {
|
|
925
|
+
try {
|
|
926
|
+
const { stdout, stderr } = await execFileAsync("git", args, {
|
|
927
|
+
cwd,
|
|
928
|
+
encoding: "utf8",
|
|
929
|
+
maxBuffer: 10 * 1024 * 1024
|
|
930
|
+
});
|
|
931
|
+
if (!quiet && stderr.trim()) {
|
|
932
|
+
process.stderr.write(stderr);
|
|
933
|
+
}
|
|
934
|
+
return stdout;
|
|
935
|
+
} catch (err) {
|
|
936
|
+
const e = err;
|
|
937
|
+
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
938
|
+
throw new Error(
|
|
939
|
+
`[apm] git ${args.join(" ")} \u5931\u8D25${detail ? `: ${detail}` : ""}`
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
async function ensureGitRepo(cwd) {
|
|
944
|
+
await execGit(cwd, ["rev-parse", "--git-dir"], true);
|
|
945
|
+
}
|
|
946
|
+
async function getCurrentBranch(cwd) {
|
|
947
|
+
const name = (await execGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
948
|
+
return name;
|
|
949
|
+
}
|
|
950
|
+
async function isWorkingTreeDirty(cwd) {
|
|
951
|
+
const out = await execGit(cwd, ["status", "--porcelain"], true);
|
|
952
|
+
return out.trim().length > 0;
|
|
953
|
+
}
|
|
954
|
+
async function remoteHeadBranchExists(cwd, branch) {
|
|
955
|
+
const out = await execGit(
|
|
956
|
+
cwd,
|
|
957
|
+
["ls-remote", "--heads", "origin", branch],
|
|
958
|
+
true
|
|
959
|
+
);
|
|
960
|
+
return out.trim().length > 0;
|
|
961
|
+
}
|
|
962
|
+
async function localBranchExists(cwd, branch) {
|
|
963
|
+
try {
|
|
964
|
+
await execGit(
|
|
965
|
+
cwd,
|
|
966
|
+
["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
967
|
+
true
|
|
968
|
+
);
|
|
969
|
+
return true;
|
|
970
|
+
} catch {
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
function theaterSessionCommitMessage(sessionId, memberKey) {
|
|
975
|
+
const id = sessionId.trim();
|
|
976
|
+
const key = memberKey?.trim();
|
|
977
|
+
return key ? `feat(req-${id}): ${key} theater agent` : `feat(req-${id}): theater agent`;
|
|
978
|
+
}
|
|
979
|
+
async function commitWorkingTreeIfDirty(cwd, message) {
|
|
980
|
+
await ensureGitRepo(cwd);
|
|
981
|
+
if (!await isWorkingTreeDirty(cwd)) {
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
const commitMessage = message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${await getCurrentBranch(cwd)})`;
|
|
985
|
+
await execGit(cwd, ["add", "-A"]);
|
|
986
|
+
await execGit(cwd, ["commit", "-m", commitMessage]);
|
|
987
|
+
console.log(`[apm] \u5DF2\u63D0\u4EA4\u5DE5\u4F5C\u533A\u53D8\u66F4: ${commitMessage}`);
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
async function ensureFeatureBranch(branch, options, fetchBaseline) {
|
|
991
|
+
const cwd = options.cwd ?? process.cwd();
|
|
992
|
+
const commitMessage = options.message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${branch})`;
|
|
993
|
+
await ensureGitRepo(cwd);
|
|
994
|
+
const current = await getCurrentBranch(cwd);
|
|
995
|
+
const dirty = await isWorkingTreeDirty(cwd);
|
|
996
|
+
if (dirty) {
|
|
997
|
+
if (current === branch) {
|
|
998
|
+
await commitWorkingTreeIfDirty(cwd, commitMessage);
|
|
999
|
+
} else {
|
|
1000
|
+
await execGit(cwd, [
|
|
1001
|
+
"stash",
|
|
1002
|
+
"push",
|
|
1003
|
+
"-u",
|
|
1004
|
+
"-m",
|
|
1005
|
+
`apm: switch to ${branch}`
|
|
1006
|
+
]);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const remoteExists = await remoteHeadBranchExists(cwd, branch);
|
|
1010
|
+
if (remoteExists) {
|
|
1011
|
+
await execGit(cwd, ["fetch", "origin", branch]);
|
|
1012
|
+
const hasLocal = await localBranchExists(cwd, branch);
|
|
1013
|
+
if (hasLocal) {
|
|
1014
|
+
await execGit(cwd, ["checkout", branch]);
|
|
1015
|
+
await execGit(cwd, ["pull", "--no-edit"]);
|
|
1016
|
+
} else {
|
|
1017
|
+
await execGit(cwd, ["checkout", "-b", branch, `origin/${branch}`]);
|
|
1018
|
+
}
|
|
1019
|
+
} else {
|
|
1020
|
+
const onBranch = await getCurrentBranch(cwd) === branch;
|
|
1021
|
+
if (!onBranch) {
|
|
1022
|
+
const hasLocal = await localBranchExists(cwd, branch);
|
|
1023
|
+
if (hasLocal) {
|
|
1024
|
+
await execGit(cwd, ["checkout", branch]);
|
|
1025
|
+
} else {
|
|
1026
|
+
const baselineBranch = await fetchBaseline();
|
|
1027
|
+
await execGit(cwd, ["fetch", "origin", baselineBranch]);
|
|
1028
|
+
await execGit(cwd, [
|
|
1029
|
+
"checkout",
|
|
1030
|
+
"-b",
|
|
1031
|
+
branch,
|
|
1032
|
+
`origin/${baselineBranch}`
|
|
1033
|
+
]);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
await execGit(cwd, ["push", "-u", "origin", branch]);
|
|
1037
|
+
}
|
|
1038
|
+
console.log(`[apm] \u5DF2\u5C31\u7EEA\u5206\u652F ${branch}`);
|
|
1039
|
+
return branch;
|
|
1040
|
+
}
|
|
1041
|
+
async function runBranch(requirementId, options = {}) {
|
|
1042
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1043
|
+
const branch = branchNameForRequirement(requirementId);
|
|
1044
|
+
return ensureFeatureBranch(
|
|
1045
|
+
branch,
|
|
1046
|
+
options,
|
|
1047
|
+
() => fetchBaselineBranchFromApi(requirementId, cwd)
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
async function runTheaterSessionBranch(sessionId, options = {}) {
|
|
1051
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1052
|
+
const branch = branchNameForTheaterSession(sessionId);
|
|
1053
|
+
return ensureFeatureBranch(
|
|
1054
|
+
branch,
|
|
1055
|
+
options,
|
|
1056
|
+
() => fetchTheaterBaselineBranchFromApi(sessionId, cwd)
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
783
1060
|
// src/theater-job-report.ts
|
|
784
1061
|
import { randomUUID } from "crypto";
|
|
785
1062
|
function extractErrorMessage(err) {
|
|
@@ -987,6 +1264,7 @@ async function handleTheaterJob(api, ws, payload) {
|
|
|
987
1264
|
throw new Error("THEATER_JOB \u7F3A\u5C11 memberKey");
|
|
988
1265
|
}
|
|
989
1266
|
console.log("[apm] \u5267\u573A\u4F1A\u8BDD:", sessionId, "\u6210\u5458:", memberKey);
|
|
1267
|
+
const apmRoot = join7(payload.cwd, ".apm");
|
|
990
1268
|
let agentId = payload.agentId?.trim() || void 0;
|
|
991
1269
|
try {
|
|
992
1270
|
await reportTheaterProgress(api, ws, { sessionId, memberKey, logId });
|
|
@@ -1002,11 +1280,56 @@ async function handleTheaterJob(api, ws, payload) {
|
|
|
1002
1280
|
});
|
|
1003
1281
|
return;
|
|
1004
1282
|
}
|
|
1283
|
+
try {
|
|
1284
|
+
await runTheaterSessionBranch(sessionId, { cwd: payload.cwd });
|
|
1285
|
+
} catch (branchErr) {
|
|
1286
|
+
logTheaterJobError("\u5207\u6362\u5206\u652F", branchErr, { sessionId, memberKey });
|
|
1287
|
+
await submitTheaterFailure(api, ws, {
|
|
1288
|
+
sessionId,
|
|
1289
|
+
memberKey,
|
|
1290
|
+
logId,
|
|
1291
|
+
agentId,
|
|
1292
|
+
stage: "\u5207\u6362\u5206\u652F",
|
|
1293
|
+
error: extractErrorMessage(branchErr)
|
|
1294
|
+
});
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
try {
|
|
1298
|
+
await runPullTheaterSession(sessionId, apmRoot);
|
|
1299
|
+
} catch (pullErr) {
|
|
1300
|
+
logTheaterJobError("\u62C9\u53D6\u4F1A\u8BDD\u6587\u6863", pullErr, { sessionId, memberKey });
|
|
1301
|
+
await submitTheaterFailure(api, ws, {
|
|
1302
|
+
sessionId,
|
|
1303
|
+
memberKey,
|
|
1304
|
+
logId,
|
|
1305
|
+
agentId,
|
|
1306
|
+
stage: "\u62C9\u53D6\u4F1A\u8BDD\u6587\u6863",
|
|
1307
|
+
error: extractErrorMessage(pullErr)
|
|
1308
|
+
});
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1005
1311
|
try {
|
|
1006
1312
|
const eventSession = new EventSession(payload.prompt);
|
|
1007
1313
|
const agent = await createAgentForJob(payload);
|
|
1008
1314
|
const runResult = await runAgentStream(payload, eventSession, agent);
|
|
1009
1315
|
agentId = runResult.agentId;
|
|
1316
|
+
try {
|
|
1317
|
+
await commitWorkingTreeIfDirty(
|
|
1318
|
+
payload.cwd,
|
|
1319
|
+
theaterSessionCommitMessage(sessionId, memberKey)
|
|
1320
|
+
);
|
|
1321
|
+
} catch (commitErr) {
|
|
1322
|
+
logTheaterJobError("\u63D0\u4EA4\u5DE5\u4F5C\u533A", commitErr, { sessionId, memberKey });
|
|
1323
|
+
await submitTheaterFailure(api, ws, {
|
|
1324
|
+
sessionId,
|
|
1325
|
+
memberKey,
|
|
1326
|
+
logId,
|
|
1327
|
+
agentId,
|
|
1328
|
+
stage: "\u63D0\u4EA4\u5DE5\u4F5C\u533A",
|
|
1329
|
+
error: extractErrorMessage(commitErr)
|
|
1330
|
+
});
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1010
1333
|
const assistantText = eventSession.getAssistantText();
|
|
1011
1334
|
const content = runResult.failed ? runResult.failReason || assistantText || "\u672A\u77E5\u9519\u8BEF" : assistantText || "[Agent \u672A\u4EA7\u751F\u6587\u672C\u8F93\u51FA]";
|
|
1012
1335
|
await submitTheaterResult(api, ws, {
|
|
@@ -1037,7 +1360,7 @@ async function handleTheaterJob(api, ws, payload) {
|
|
|
1037
1360
|
}
|
|
1038
1361
|
}
|
|
1039
1362
|
async function handleWorkflowJob(api, payload) {
|
|
1040
|
-
const apmRoot =
|
|
1363
|
+
const apmRoot = join7(payload.cwd, ".apm");
|
|
1041
1364
|
console.log("[apm] ROOT:", apmRoot);
|
|
1042
1365
|
console.log("[apm] workflow node:", payload.nodeId);
|
|
1043
1366
|
try {
|
|
@@ -1163,17 +1486,17 @@ function runConnect(opts) {
|
|
|
1163
1486
|
}
|
|
1164
1487
|
|
|
1165
1488
|
// src/commands/init.ts
|
|
1166
|
-
import { join as
|
|
1167
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
1489
|
+
import { join as join8 } from "path";
|
|
1490
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
1168
1491
|
async function runInit(name) {
|
|
1169
1492
|
await ensureWorkspaceApmDirForInit();
|
|
1170
1493
|
await copyTemplateFiles(WORKSPACE_APM_DIR);
|
|
1171
1494
|
if (name) {
|
|
1172
|
-
const apmConfigPath =
|
|
1495
|
+
const apmConfigPath = join8(WORKSPACE_APM_DIR, "apm.config.json");
|
|
1173
1496
|
const config = readFileSync4(apmConfigPath, "utf8");
|
|
1174
1497
|
const configJson = JSON.parse(config);
|
|
1175
1498
|
configJson.name = name;
|
|
1176
|
-
|
|
1499
|
+
writeFileSync5(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
|
|
1177
1500
|
}
|
|
1178
1501
|
}
|
|
1179
1502
|
|
|
@@ -1222,156 +1545,12 @@ async function runLogin(opts) {
|
|
|
1222
1545
|
console.log(JSON.stringify({ userId: cfg.userId, baseUrl: cfg.baseUrl }, null, 2));
|
|
1223
1546
|
}
|
|
1224
1547
|
|
|
1225
|
-
// src/commands/branch.ts
|
|
1226
|
-
import { execFile } from "child_process";
|
|
1227
|
-
import { resolve as resolve3 } from "path";
|
|
1228
|
-
import { promisify } from "util";
|
|
1229
|
-
var execFileAsync = promisify(execFile);
|
|
1230
|
-
async function fetchBaselineBranchFromApi(requirementId, cwd) {
|
|
1231
|
-
const cfg = await ensureLoggedConfig();
|
|
1232
|
-
const api = createApmApiClient(cfg);
|
|
1233
|
-
const workdirPath = resolve3(cwd);
|
|
1234
|
-
const res = await api.cliRequirements.branchBaseline({
|
|
1235
|
-
requirementId,
|
|
1236
|
-
workdirPath
|
|
1237
|
-
});
|
|
1238
|
-
if (!res.repositoryId) {
|
|
1239
|
-
throw new Error(
|
|
1240
|
-
`[apm] \u672A\u5728\u5E73\u53F0\u627E\u5230\u4E0E\u5F53\u524D\u76EE\u5F55\u5339\u914D\u7684\u5DE5\u4F5C\u76EE\u5F55\u767B\u8BB0\uFF1A${workdirPath}
|
|
1241
|
-
\u8BF7\u5148\u5728\u5E73\u53F0\u767B\u8BB0\u8BE5\u8DEF\u5F84\u5BF9\u5E94\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0E\u4ED3\u5E93\u3002`
|
|
1242
|
-
);
|
|
1243
|
-
}
|
|
1244
|
-
const name = (res.defaultBranch ?? "").trim();
|
|
1245
|
-
if (!name) {
|
|
1246
|
-
throw new Error("[apm] \u5E73\u53F0\u8FD4\u56DE\u7684\u57FA\u7EBF\u5206\u652F\u540D\u4E3A\u7A7A");
|
|
1247
|
-
}
|
|
1248
|
-
return name;
|
|
1249
|
-
}
|
|
1250
|
-
function branchNameForRequirement(requirementId) {
|
|
1251
|
-
const id = requirementId.trim();
|
|
1252
|
-
if (!id) {
|
|
1253
|
-
throw new Error("[apm] \u9700\u6C42 ID \u4E0D\u80FD\u4E3A\u7A7A");
|
|
1254
|
-
}
|
|
1255
|
-
if (/[\s/\\]/.test(id)) {
|
|
1256
|
-
throw new Error(
|
|
1257
|
-
"[apm] \u9700\u6C42 ID \u4E0D\u80FD\u5305\u542B\u7A7A\u767D\u6216\u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u8BF7\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001._- \u7B49"
|
|
1258
|
-
);
|
|
1259
|
-
}
|
|
1260
|
-
return `feat/req-${id}`;
|
|
1261
|
-
}
|
|
1262
|
-
async function execGit(cwd, args, quiet) {
|
|
1263
|
-
try {
|
|
1264
|
-
const { stdout, stderr } = await execFileAsync("git", args, {
|
|
1265
|
-
cwd,
|
|
1266
|
-
encoding: "utf8",
|
|
1267
|
-
maxBuffer: 10 * 1024 * 1024
|
|
1268
|
-
});
|
|
1269
|
-
if (!quiet && stderr.trim()) {
|
|
1270
|
-
process.stderr.write(stderr);
|
|
1271
|
-
}
|
|
1272
|
-
return stdout;
|
|
1273
|
-
} catch (err) {
|
|
1274
|
-
const e = err;
|
|
1275
|
-
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
1276
|
-
throw new Error(
|
|
1277
|
-
`[apm] git ${args.join(" ")} \u5931\u8D25${detail ? `: ${detail}` : ""}`
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
async function ensureGitRepo(cwd) {
|
|
1282
|
-
await execGit(cwd, ["rev-parse", "--git-dir"], true);
|
|
1283
|
-
}
|
|
1284
|
-
async function getCurrentBranch(cwd) {
|
|
1285
|
-
const name = (await execGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
1286
|
-
return name;
|
|
1287
|
-
}
|
|
1288
|
-
async function isWorkingTreeDirty(cwd) {
|
|
1289
|
-
const out = await execGit(cwd, ["status", "--porcelain"], true);
|
|
1290
|
-
return out.trim().length > 0;
|
|
1291
|
-
}
|
|
1292
|
-
async function remoteHeadBranchExists(cwd, branch) {
|
|
1293
|
-
const out = await execGit(
|
|
1294
|
-
cwd,
|
|
1295
|
-
["ls-remote", "--heads", "origin", branch],
|
|
1296
|
-
true
|
|
1297
|
-
);
|
|
1298
|
-
return out.trim().length > 0;
|
|
1299
|
-
}
|
|
1300
|
-
async function localBranchExists(cwd, branch) {
|
|
1301
|
-
try {
|
|
1302
|
-
await execGit(
|
|
1303
|
-
cwd,
|
|
1304
|
-
["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
1305
|
-
true
|
|
1306
|
-
);
|
|
1307
|
-
return true;
|
|
1308
|
-
} catch {
|
|
1309
|
-
return false;
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
async function runBranch(requirementId, options = {}) {
|
|
1313
|
-
const cwd = options.cwd ?? process.cwd();
|
|
1314
|
-
const branch = branchNameForRequirement(requirementId);
|
|
1315
|
-
const commitMessage = options.message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${branch})`;
|
|
1316
|
-
await ensureGitRepo(cwd);
|
|
1317
|
-
const current = await getCurrentBranch(cwd);
|
|
1318
|
-
const dirty = await isWorkingTreeDirty(cwd);
|
|
1319
|
-
if (dirty) {
|
|
1320
|
-
if (current === branch) {
|
|
1321
|
-
await execGit(cwd, ["add", "-A"]);
|
|
1322
|
-
await execGit(cwd, ["commit", "-m", commitMessage]);
|
|
1323
|
-
} else {
|
|
1324
|
-
await execGit(cwd, [
|
|
1325
|
-
"stash",
|
|
1326
|
-
"push",
|
|
1327
|
-
"-u",
|
|
1328
|
-
"-m",
|
|
1329
|
-
`apm: switch to ${branch}`
|
|
1330
|
-
]);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
const remoteExists = await remoteHeadBranchExists(cwd, branch);
|
|
1334
|
-
if (remoteExists) {
|
|
1335
|
-
await execGit(cwd, ["fetch", "origin", branch]);
|
|
1336
|
-
const hasLocal = await localBranchExists(cwd, branch);
|
|
1337
|
-
if (hasLocal) {
|
|
1338
|
-
await execGit(cwd, ["checkout", branch]);
|
|
1339
|
-
await execGit(cwd, ["pull", "--no-edit"]);
|
|
1340
|
-
} else {
|
|
1341
|
-
await execGit(cwd, ["checkout", "-b", branch, `origin/${branch}`]);
|
|
1342
|
-
}
|
|
1343
|
-
} else {
|
|
1344
|
-
const onBranch = await getCurrentBranch(cwd) === branch;
|
|
1345
|
-
if (!onBranch) {
|
|
1346
|
-
const hasLocal = await localBranchExists(cwd, branch);
|
|
1347
|
-
if (hasLocal) {
|
|
1348
|
-
await execGit(cwd, ["checkout", branch]);
|
|
1349
|
-
} else {
|
|
1350
|
-
const baselineBranch = await fetchBaselineBranchFromApi(
|
|
1351
|
-
requirementId,
|
|
1352
|
-
cwd
|
|
1353
|
-
);
|
|
1354
|
-
await execGit(cwd, ["fetch", "origin", baselineBranch]);
|
|
1355
|
-
await execGit(cwd, [
|
|
1356
|
-
"checkout",
|
|
1357
|
-
"-b",
|
|
1358
|
-
branch,
|
|
1359
|
-
`origin/${baselineBranch}`
|
|
1360
|
-
]);
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
await execGit(cwd, ["push", "-u", "origin", branch]);
|
|
1364
|
-
}
|
|
1365
|
-
console.log(`[apm] \u5DF2\u5C31\u7EEA\u5206\u652F ${branch}`);
|
|
1366
|
-
return branch;
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
1548
|
// src/commands/refine.ts
|
|
1370
1549
|
import { readFileSync as readFileSync5 } from "fs";
|
|
1371
|
-
import { join as
|
|
1550
|
+
import { join as join9 } from "path";
|
|
1372
1551
|
async function runRefine(requirementId) {
|
|
1373
1552
|
const cfg = await ensureLoggedConfig();
|
|
1374
|
-
const filePath =
|
|
1553
|
+
const filePath = join9(WORKSPACE_APM_DIR, "workitems", requirementId, "prd.md");
|
|
1375
1554
|
const content = readFileSync5(filePath, "utf8");
|
|
1376
1555
|
const api = createApmApiClient(cfg);
|
|
1377
1556
|
const data = await api.cliRequirements.refine({ requirementId, content });
|
|
@@ -1383,13 +1562,13 @@ import { spawnSync } from "child_process";
|
|
|
1383
1562
|
|
|
1384
1563
|
// src/version.ts
|
|
1385
1564
|
import { readFileSync as readFileSync6 } from "fs";
|
|
1386
|
-
import { dirname as
|
|
1565
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
1387
1566
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1388
1567
|
var CLI_PACKAGE_NAME = "ai-project-manage-cli";
|
|
1389
1568
|
function readCliVersion() {
|
|
1390
1569
|
try {
|
|
1391
|
-
const dir =
|
|
1392
|
-
const pkgPath =
|
|
1570
|
+
const dir = dirname3(fileURLToPath2(import.meta.url));
|
|
1571
|
+
const pkgPath = join10(dir, "..", "package.json");
|
|
1393
1572
|
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
1394
1573
|
return pkg.version ?? "0.0.0";
|
|
1395
1574
|
} catch {
|
|
@@ -1458,8 +1637,8 @@ async function runUpdate() {
|
|
|
1458
1637
|
|
|
1459
1638
|
// src/commands/update-skills.ts
|
|
1460
1639
|
import { cpSync as cpSync2, existsSync as existsSync4, rmSync, statSync as statSync3 } from "fs";
|
|
1461
|
-
import { join as
|
|
1462
|
-
var TEMPLATE_SKILLS_DIR =
|
|
1640
|
+
import { join as join11 } from "path";
|
|
1641
|
+
var TEMPLATE_SKILLS_DIR = join11(CLI_TEMPLATE_DIR, "skills");
|
|
1463
1642
|
async function runUpdateSkills() {
|
|
1464
1643
|
const apmDir = WORKSPACE_APM_DIR;
|
|
1465
1644
|
if (!existsSync4(apmDir)) {
|
|
@@ -1479,7 +1658,7 @@ async function runUpdateSkills() {
|
|
|
1479
1658
|
if (!templateStat.isDirectory()) {
|
|
1480
1659
|
throw new Error(`[apm] \u5185\u7F6E\u6280\u80FD\u6A21\u677F\u4E0D\u662F\u76EE\u5F55: ${TEMPLATE_SKILLS_DIR}`);
|
|
1481
1660
|
}
|
|
1482
|
-
const skillsDir =
|
|
1661
|
+
const skillsDir = join11(apmDir, "skills");
|
|
1483
1662
|
if (existsSync4(skillsDir)) {
|
|
1484
1663
|
rmSync(skillsDir, { recursive: true, force: true });
|
|
1485
1664
|
}
|
|
@@ -1488,6 +1667,77 @@ async function runUpdateSkills() {
|
|
|
1488
1667
|
console.log("[apm] \u5DF2\u66F4\u65B0 .apm/skills");
|
|
1489
1668
|
}
|
|
1490
1669
|
|
|
1670
|
+
// src/commands/update-theater-skills.ts
|
|
1671
|
+
import { cpSync as cpSync3, existsSync as existsSync5, rmSync as rmSync2, statSync as statSync4 } from "fs";
|
|
1672
|
+
import { join as join12 } from "path";
|
|
1673
|
+
var TEMPLATE_THEATER_SKILLS_DIR = join12(CLI_TEMPLATE_DIR, "theater-skills");
|
|
1674
|
+
async function runUpdateTheaterSkills() {
|
|
1675
|
+
const apmDir = WORKSPACE_APM_DIR;
|
|
1676
|
+
if (!existsSync5(apmDir)) {
|
|
1677
|
+
console.error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
|
|
1678
|
+
process.exit(1);
|
|
1679
|
+
}
|
|
1680
|
+
const apmStat = statSync4(apmDir);
|
|
1681
|
+
if (!apmStat.isDirectory()) {
|
|
1682
|
+
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${apmDir}`);
|
|
1683
|
+
}
|
|
1684
|
+
let templateStat;
|
|
1685
|
+
try {
|
|
1686
|
+
templateStat = statSync4(TEMPLATE_THEATER_SKILLS_DIR);
|
|
1687
|
+
} catch {
|
|
1688
|
+
throw new Error(
|
|
1689
|
+
`[apm] \u5185\u7F6E\u5267\u573A\u6280\u80FD\u6A21\u677F\u4E0D\u5B58\u5728: ${TEMPLATE_THEATER_SKILLS_DIR}`
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
if (!templateStat.isDirectory()) {
|
|
1693
|
+
throw new Error(
|
|
1694
|
+
`[apm] \u5185\u7F6E\u5267\u573A\u6280\u80FD\u6A21\u677F\u4E0D\u662F\u76EE\u5F55: ${TEMPLATE_THEATER_SKILLS_DIR}`
|
|
1695
|
+
);
|
|
1696
|
+
}
|
|
1697
|
+
const theaterSkillsDir = join12(apmDir, "theater-skills");
|
|
1698
|
+
if (existsSync5(theaterSkillsDir)) {
|
|
1699
|
+
rmSync2(theaterSkillsDir, { recursive: true, force: true });
|
|
1700
|
+
}
|
|
1701
|
+
await ensureDirExists(apmDir);
|
|
1702
|
+
cpSync3(TEMPLATE_THEATER_SKILLS_DIR, theaterSkillsDir, { recursive: true });
|
|
1703
|
+
console.log("[apm] \u5DF2\u66F4\u65B0 .apm/theater-skills");
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// src/commands/sync-session-document.ts
|
|
1707
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
1708
|
+
var DEFAULT_FILE = "prd.md";
|
|
1709
|
+
async function runSyncSessionDocument(sessionId, options) {
|
|
1710
|
+
const trimmedSessionId = sessionId.trim();
|
|
1711
|
+
if (!trimmedSessionId) {
|
|
1712
|
+
console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
1713
|
+
process.exit(1);
|
|
1714
|
+
}
|
|
1715
|
+
const fileArg = (options?.file?.trim() || DEFAULT_FILE).replace(/\\/g, "/");
|
|
1716
|
+
const apmRoot = options?.apmRoot ?? WORKSPACE_APM_DIR;
|
|
1717
|
+
const localRelativePath = theaterArtifactLocalRelativePath(fileArg);
|
|
1718
|
+
const absPath = theaterSessionDocumentPath(
|
|
1719
|
+
trimmedSessionId,
|
|
1720
|
+
fileArg,
|
|
1721
|
+
apmRoot
|
|
1722
|
+
);
|
|
1723
|
+
if (!existsSync6(absPath)) {
|
|
1724
|
+
console.error(`[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}
|
|
1725
|
+
\u8BF7\u5148\u521B\u5EFA\u8BE5\u6587\u4EF6\u540E\u518D\u540C\u6B65`);
|
|
1726
|
+
process.exit(1);
|
|
1727
|
+
}
|
|
1728
|
+
const content = readFileSync7(absPath, "utf8");
|
|
1729
|
+
const cfg = await ensureLoggedConfig();
|
|
1730
|
+
const api = createApmApiClient(cfg);
|
|
1731
|
+
const data = await api.theaterSessionArtifact.upsert({
|
|
1732
|
+
sessionId: trimmedSessionId,
|
|
1733
|
+
fileName: normalizeTheaterArtifactFileName(fileArg),
|
|
1734
|
+
content
|
|
1735
|
+
});
|
|
1736
|
+
console.log(
|
|
1737
|
+
`[apm] \u5DF2\u540C\u6B65\u4F1A\u8BDD\u6587\u6863: ${localRelativePath} \u2192 ${data.fileName} (artifactId=${data.id})`
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1491
1741
|
// src/commands/update-dev-status.ts
|
|
1492
1742
|
async function runUpdateDevStatus(requirementId, status) {
|
|
1493
1743
|
const cfg = await ensureLoggedConfig();
|
|
@@ -1514,19 +1764,19 @@ async function runUpdateStatus(requirementId, status) {
|
|
|
1514
1764
|
import path5 from "node:path";
|
|
1515
1765
|
|
|
1516
1766
|
// src/commands/deploy/internal/apm-config.ts
|
|
1517
|
-
import { existsSync as
|
|
1767
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "node:fs";
|
|
1518
1768
|
import { resolve as resolve4 } from "node:path";
|
|
1519
1769
|
function loadApmConfig(options) {
|
|
1520
1770
|
const p = resolve4(
|
|
1521
1771
|
process.cwd(),
|
|
1522
1772
|
options?.configPath ?? resolve4(WORKSPACE_APM_DIR, "apm.config.json")
|
|
1523
1773
|
);
|
|
1524
|
-
if (!
|
|
1774
|
+
if (!existsSync7(p)) {
|
|
1525
1775
|
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
1526
1776
|
process.exit(1);
|
|
1527
1777
|
}
|
|
1528
1778
|
try {
|
|
1529
|
-
const raw =
|
|
1779
|
+
const raw = readFileSync8(p, "utf8");
|
|
1530
1780
|
return JSON.parse(raw);
|
|
1531
1781
|
} catch (e) {
|
|
1532
1782
|
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
@@ -1625,7 +1875,7 @@ import path4 from "node:path";
|
|
|
1625
1875
|
import Docker from "dockerode";
|
|
1626
1876
|
|
|
1627
1877
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
1628
|
-
import { existsSync as
|
|
1878
|
+
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "node:fs";
|
|
1629
1879
|
import path from "node:path";
|
|
1630
1880
|
function asOptionalTlsBuffer(value) {
|
|
1631
1881
|
if (typeof value !== "string") {
|
|
@@ -1637,8 +1887,8 @@ function asOptionalTlsBuffer(value) {
|
|
|
1637
1887
|
if (normalized === "") {
|
|
1638
1888
|
return void 0;
|
|
1639
1889
|
}
|
|
1640
|
-
if (
|
|
1641
|
-
return
|
|
1890
|
+
if (existsSync8(normalized)) {
|
|
1891
|
+
return readFileSync9(normalized);
|
|
1642
1892
|
}
|
|
1643
1893
|
const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
|
|
1644
1894
|
if (looksLikePath) {
|
|
@@ -1848,7 +2098,7 @@ var DockerodeClient = class {
|
|
|
1848
2098
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
1849
2099
|
|
|
1850
2100
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
1851
|
-
import { existsSync as
|
|
2101
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, statSync as statSync5 } from "node:fs";
|
|
1852
2102
|
import path2 from "node:path";
|
|
1853
2103
|
function stripSurroundingQuotes(value) {
|
|
1854
2104
|
const t = value.trim();
|
|
@@ -1865,10 +2115,10 @@ function loadEnvFromFile(envFilePath) {
|
|
|
1865
2115
|
return {};
|
|
1866
2116
|
}
|
|
1867
2117
|
const targetPath = path2.resolve(envFilePath);
|
|
1868
|
-
if (!
|
|
2118
|
+
if (!existsSync9(targetPath) || !statSync5(targetPath).isFile()) {
|
|
1869
2119
|
return {};
|
|
1870
2120
|
}
|
|
1871
|
-
const raw =
|
|
2121
|
+
const raw = readFileSync10(targetPath, "utf-8");
|
|
1872
2122
|
const result = {};
|
|
1873
2123
|
for (const line of raw.split(/\r?\n/)) {
|
|
1874
2124
|
const normalized = line.trim();
|
|
@@ -2039,12 +2289,12 @@ function dockerPushImage(params, cwd) {
|
|
|
2039
2289
|
}
|
|
2040
2290
|
|
|
2041
2291
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
2042
|
-
import { existsSync as
|
|
2292
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
2043
2293
|
import path3 from "node:path";
|
|
2044
2294
|
function resolveDockerBuildPaths(cwd) {
|
|
2045
2295
|
const dockerfilePath = path3.join(cwd, "Dockerfile");
|
|
2046
2296
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
2047
|
-
if (!
|
|
2297
|
+
if (!existsSync10(dockerfilePath)) {
|
|
2048
2298
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
2049
2299
|
}
|
|
2050
2300
|
Logger.info("\u2713 Dockerfile \u5B58\u5728");
|
|
@@ -2173,16 +2423,16 @@ import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
|
|
|
2173
2423
|
import path7 from "node:path";
|
|
2174
2424
|
|
|
2175
2425
|
// src/commands/deploy/internal/load-apm-dotenv.ts
|
|
2176
|
-
import { existsSync as
|
|
2177
|
-
import { join as
|
|
2426
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11 } from "node:fs";
|
|
2427
|
+
import { join as join13 } from "node:path";
|
|
2178
2428
|
function loadApmDotEnvIfPresent() {
|
|
2179
|
-
const p =
|
|
2180
|
-
if (!
|
|
2429
|
+
const p = join13(WORKSPACE_APM_DIR, ".env");
|
|
2430
|
+
if (!existsSync11(p)) {
|
|
2181
2431
|
return;
|
|
2182
2432
|
}
|
|
2183
2433
|
let text;
|
|
2184
2434
|
try {
|
|
2185
|
-
text =
|
|
2435
|
+
text = readFileSync11(p, "utf8");
|
|
2186
2436
|
} catch {
|
|
2187
2437
|
return;
|
|
2188
2438
|
}
|
|
@@ -2207,14 +2457,14 @@ function loadApmDotEnvIfPresent() {
|
|
|
2207
2457
|
}
|
|
2208
2458
|
|
|
2209
2459
|
// src/commands/deploy/internal/minio.ts
|
|
2210
|
-
import { statSync as
|
|
2460
|
+
import { statSync as statSync6 } from "node:fs";
|
|
2211
2461
|
import { readdir, readFile } from "node:fs/promises";
|
|
2212
2462
|
import path6 from "node:path";
|
|
2213
2463
|
import * as Minio from "minio";
|
|
2214
2464
|
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
2215
2465
|
async function isDirectoryPath(dir) {
|
|
2216
2466
|
try {
|
|
2217
|
-
const st =
|
|
2467
|
+
const st = statSync6(dir);
|
|
2218
2468
|
return st.isDirectory();
|
|
2219
2469
|
} catch {
|
|
2220
2470
|
return false;
|
|
@@ -2244,7 +2494,7 @@ async function collectFiles(root) {
|
|
|
2244
2494
|
if (e.isDirectory()) {
|
|
2245
2495
|
await walk(abs, rel);
|
|
2246
2496
|
} else if (e.isFile()) {
|
|
2247
|
-
const st =
|
|
2497
|
+
const st = statSync6(abs);
|
|
2248
2498
|
out.push({
|
|
2249
2499
|
absPath: abs,
|
|
2250
2500
|
relativePath: rel.replace(/\\/g, "/"),
|
|
@@ -2566,6 +2816,25 @@ function buildProgram() {
|
|
|
2566
2816
|
).action(async () => {
|
|
2567
2817
|
await runUpdateSkills();
|
|
2568
2818
|
});
|
|
2819
|
+
program.command("update-theater-skills").description(
|
|
2820
|
+
"\u5220\u9664\u5DE5\u4F5C\u533A .apm/theater-skills \u540E\uFF0C\u4ECE\u5F53\u524D CLI \u5185\u7F6E\u6A21\u677F\u91CD\u65B0\u590D\u5236\u5267\u573A\u6280\u80FD\u76EE\u5F55"
|
|
2821
|
+
).action(async () => {
|
|
2822
|
+
await runUpdateTheaterSkills();
|
|
2823
|
+
});
|
|
2824
|
+
program.command("pull-session").description(
|
|
2825
|
+
"\u5C06\u5E73\u53F0\u5267\u573A\u4F1A\u8BDD\u4EA7\u7269\u6587\u6863\u4E0B\u8F7D\u5230 .apm/theater-sessions/<sessionId>/\uFF08\u5982 docs/prd.md\uFF09\uFF1B\u672C\u5730\u5DF2\u6709\u540C\u540D\u6587\u4EF6\u65F6\u8986\u76D6"
|
|
2826
|
+
).argument("<sessionId>", "\u5267\u573A\u4F1A\u8BDD ID").action(async (sessionId) => {
|
|
2827
|
+
const dir = await runPullTheaterSession(sessionId);
|
|
2828
|
+
console.log(`[apm] \u4F1A\u8BDD\u6587\u6863\u76EE\u5F55: ${dir}`);
|
|
2829
|
+
});
|
|
2830
|
+
program.command("sync-session-document").description(
|
|
2831
|
+
"\u5C06 .apm/theater-sessions/<sessionId>/docs/ \u4E0B Markdown \u6587\u6863 upsert \u5230\u5E73\u53F0\u4F1A\u8BDD\u4EA7\u7269\uFF08\u4E0D\u542B\u5BF9\u8BDD\u65E5\u5FD7\uFF09"
|
|
2832
|
+
).argument("<sessionId>", "\u5267\u573A\u4F1A\u8BDD ID").option(
|
|
2833
|
+
"--file <path>",
|
|
2834
|
+
"\u6587\u6863\u540D\u6216\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 prd.md\u3001docs/backend.md\uFF1B\u672C\u5730\u56FA\u5B9A\u843D\u5728 docs/ \u4E0B\uFF09"
|
|
2835
|
+
).action(async (sessionId, opts) => {
|
|
2836
|
+
await runSyncSessionDocument(sessionId, { file: opts.file });
|
|
2837
|
+
});
|
|
2569
2838
|
program.command("pull").description(
|
|
2570
2839
|
"GET /api/cli/requirements/pull\uFF0C\u540C\u6B65\u6570\u636E\u4E0E\u9644\u4EF6\u5230 .apm/workitems/<\u9700\u6C42ID>"
|
|
2571
2840
|
).argument("<requirementId>", "\u9700\u6C42 ID").action(async (requirementId) => {
|