ai-project-manage-cli 6.0.50 → 6.0.52
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 +264 -22
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -81,10 +81,17 @@ function buildAgentWsUrl(httpBase, apiKey) {
|
|
|
81
81
|
|
|
82
82
|
// src/commands/init.ts
|
|
83
83
|
import { join as join4 } from "path";
|
|
84
|
-
import { readFileSync as
|
|
84
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
85
85
|
|
|
86
86
|
// src/command-utils.ts
|
|
87
|
-
import {
|
|
87
|
+
import {
|
|
88
|
+
copyFileSync,
|
|
89
|
+
existsSync,
|
|
90
|
+
mkdirSync as mkdirSync2,
|
|
91
|
+
readFileSync as readFileSync2,
|
|
92
|
+
readdirSync,
|
|
93
|
+
statSync
|
|
94
|
+
} from "fs";
|
|
88
95
|
import { basename, dirname, extname, join as join2, resolve as resolve2 } from "path";
|
|
89
96
|
import { fileURLToPath } from "url";
|
|
90
97
|
|
|
@@ -141,6 +148,56 @@ var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
|
141
148
|
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
142
149
|
return resolve2(resolve2(cwd), ".apm");
|
|
143
150
|
}
|
|
151
|
+
function assertWorkspaceApmDirExists(workdir) {
|
|
152
|
+
const apmDir = workspaceApmDir(workdir);
|
|
153
|
+
const fsApmDir = toFsPath(apmDir);
|
|
154
|
+
if (!existsSync(fsApmDir)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u4E0B\u672A\u68C0\u6D4B\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5728\u8BE5\u4ED3\u5E93\u6839\u76EE\u5F55\u6267\u884C apm init \u5B8C\u6210\u63A5\u5165\u3002`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
const st = statSync(fsApmDir);
|
|
160
|
+
if (!st.isDirectory()) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u4E0B\u7684 .apm \u4E0D\u662F\u76EE\u5F55\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730\u63A5\u5165\u72B6\u6001\u3002`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
var APM_GITIGNORE_PATTERNS = [
|
|
167
|
+
/^\.apm\/?$/,
|
|
168
|
+
/^\.apm\/\*\*$/,
|
|
169
|
+
/^\*\*\/\.apm\/?$/,
|
|
170
|
+
/^\*\*\/\.apm\/\*\*$/,
|
|
171
|
+
/^\/\.apm\/?$/,
|
|
172
|
+
/^\/\.apm\/\*\*$/
|
|
173
|
+
];
|
|
174
|
+
function normalizeGitignorePattern(line) {
|
|
175
|
+
const trimmed = line.trim();
|
|
176
|
+
if (!trimmed || trimmed.startsWith("#")) return "";
|
|
177
|
+
if (trimmed.startsWith("!")) return "";
|
|
178
|
+
const hashIndex = trimmed.indexOf("#");
|
|
179
|
+
return (hashIndex >= 0 ? trimmed.slice(0, hashIndex) : trimmed).trim();
|
|
180
|
+
}
|
|
181
|
+
function gitignoreIgnoresApm(line) {
|
|
182
|
+
const pattern = normalizeGitignorePattern(line);
|
|
183
|
+
if (!pattern) return false;
|
|
184
|
+
return APM_GITIGNORE_PATTERNS.some((re) => re.test(pattern));
|
|
185
|
+
}
|
|
186
|
+
function assertApmGitignoredInRepo(workdir) {
|
|
187
|
+
const gitignorePath = join2(workdir, ".gitignore");
|
|
188
|
+
const fsGitignorePath = toFsPath(gitignorePath);
|
|
189
|
+
if (!existsSync(fsGitignorePath)) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u7F3A\u5C11 .gitignore \u6587\u4EF6\uFF0C\u8BF7\u6DFB\u52A0\u5BF9 .apm \u7684\u5FFD\u7565\u89C4\u5219\uFF08\u4F8B\u5982 **/.apm/**\uFF09\uFF0C\u907F\u514D\u672C\u5730\u4F1A\u8BDD\u4E0E\u90E8\u7F72\u51ED\u636E\u88AB\u63D0\u4EA4\u3002`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const content = readFileSync2(fsGitignorePath, "utf8");
|
|
195
|
+
if (!content.split(/\r?\n/).some(gitignoreIgnoresApm)) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u7684 .gitignore \u672A\u5FFD\u7565 .apm\uFF0C\u8BF7\u6DFB\u52A0 **/.apm/** \u6216 .apm/\uFF0C\u907F\u514D\u672C\u5730\u4F1A\u8BDD\u4E0E\u90E8\u7F72\u51ED\u636E\u88AB\u63D0\u4EA4\u3002`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
144
201
|
var SESSIONS_SUBDIR = "sessions";
|
|
145
202
|
var SESSION_DOCS_SUBDIR = "docs";
|
|
146
203
|
var SESSION_ATTACHMENTS_SUBDIR = "attachments";
|
|
@@ -350,6 +407,10 @@ var requestConfig = {
|
|
|
350
407
|
method: "GET",
|
|
351
408
|
path: "/cli/tasks/branch-baseline"
|
|
352
409
|
}),
|
|
410
|
+
listSessionsForBranchCleanup: defineEndpoint({
|
|
411
|
+
method: "GET",
|
|
412
|
+
path: "/cli/sessions/branch-cleanup"
|
|
413
|
+
}),
|
|
353
414
|
workspaceBaseline: defineEndpoint({
|
|
354
415
|
method: "GET",
|
|
355
416
|
path: "/cli/workspaces/baseline"
|
|
@@ -492,7 +553,7 @@ async function runInit(name) {
|
|
|
492
553
|
const trimmedName = name?.trim();
|
|
493
554
|
if (trimmedName) {
|
|
494
555
|
const apmConfigPath = toFsPath(join4(apmDir, "apm.config.json"));
|
|
495
|
-
const config =
|
|
556
|
+
const config = readFileSync3(apmConfigPath, "utf8");
|
|
496
557
|
const configJson = JSON.parse(config);
|
|
497
558
|
configJson.name = trimmedName;
|
|
498
559
|
writeFileSync3(
|
|
@@ -577,6 +638,7 @@ async function runLogin(opts) {
|
|
|
577
638
|
import { execFile as execFile2 } from "child_process";
|
|
578
639
|
import { promisify as promisify2 } from "util";
|
|
579
640
|
var execFileAsync2 = promisify2(execFile2);
|
|
641
|
+
var SESSION_BRANCH_PREFIX = "feat/session-";
|
|
580
642
|
function branchNameForSession(sessionId) {
|
|
581
643
|
const id = sessionId.trim();
|
|
582
644
|
if (!id) {
|
|
@@ -587,7 +649,15 @@ function branchNameForSession(sessionId) {
|
|
|
587
649
|
"[apm] \u4F1A\u8BDD ID \u4E0D\u80FD\u5305\u542B\u7A7A\u767D\u6216\u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u8BF7\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001._- \u7B49"
|
|
588
650
|
);
|
|
589
651
|
}
|
|
590
|
-
return
|
|
652
|
+
return `${SESSION_BRANCH_PREFIX}${id}`;
|
|
653
|
+
}
|
|
654
|
+
function sessionIdFromBranchName(branch) {
|
|
655
|
+
const name = branch.trim().replace(/^origin\//, "");
|
|
656
|
+
if (!name.startsWith(SESSION_BRANCH_PREFIX)) {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
const sessionId = name.slice(SESSION_BRANCH_PREFIX.length).trim();
|
|
660
|
+
return sessionId || null;
|
|
591
661
|
}
|
|
592
662
|
async function execGit(cwd, args, quiet) {
|
|
593
663
|
try {
|
|
@@ -740,6 +810,171 @@ async function runBranch(sessionId, options = {}) {
|
|
|
740
810
|
return ensureFeatureBranch(branch, baselineBranch, options);
|
|
741
811
|
}
|
|
742
812
|
|
|
813
|
+
// src/commands/clean-branches.ts
|
|
814
|
+
import { execFile as execFile3 } from "child_process";
|
|
815
|
+
import { promisify as promisify3 } from "util";
|
|
816
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
817
|
+
async function execGit2(cwd, args, quiet) {
|
|
818
|
+
try {
|
|
819
|
+
const { stdout, stderr } = await execFileAsync3("git", args, {
|
|
820
|
+
cwd,
|
|
821
|
+
encoding: "utf8",
|
|
822
|
+
maxBuffer: 10 * 1024 * 1024
|
|
823
|
+
});
|
|
824
|
+
if (!quiet && stderr.trim()) {
|
|
825
|
+
process.stderr.write(stderr);
|
|
826
|
+
}
|
|
827
|
+
return stdout;
|
|
828
|
+
} catch (err) {
|
|
829
|
+
const e = err;
|
|
830
|
+
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
831
|
+
throw new Error(
|
|
832
|
+
`[apm] git ${args.join(" ")} \u5931\u8D25${detail ? `: ${detail}` : ""}`
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
async function ensureGitRepo2(cwd) {
|
|
837
|
+
await execGit2(cwd, ["rev-parse", "--git-dir"], true);
|
|
838
|
+
}
|
|
839
|
+
async function getCurrentBranch2(cwd) {
|
|
840
|
+
return (await execGit2(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
841
|
+
}
|
|
842
|
+
async function resolveDefaultBranch(cwd) {
|
|
843
|
+
try {
|
|
844
|
+
const ref = (await execGit2(cwd, ["symbolic-ref", "refs/remotes/origin/HEAD"], true)).trim();
|
|
845
|
+
const match = ref.match(/^refs\/remotes\/origin\/(.+)$/);
|
|
846
|
+
if (match?.[1]) {
|
|
847
|
+
return match[1];
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
}
|
|
851
|
+
const out = await execGit2(cwd, ["remote", "show", "origin"], true);
|
|
852
|
+
const headLine = out.split(/\r?\n/).find((line) => line.includes("HEAD branch"));
|
|
853
|
+
const branch = headLine?.split(":").pop()?.trim();
|
|
854
|
+
if (branch) {
|
|
855
|
+
return branch;
|
|
856
|
+
}
|
|
857
|
+
throw new Error("[apm] \u65E0\u6CD5\u89E3\u6790 origin \u9ED8\u8BA4\u5206\u652F\uFF0C\u8BF7\u5148\u6267\u884C git fetch origin");
|
|
858
|
+
}
|
|
859
|
+
async function listLocalSessionBranches(cwd) {
|
|
860
|
+
const out = await execGit2(
|
|
861
|
+
cwd,
|
|
862
|
+
[
|
|
863
|
+
"for-each-ref",
|
|
864
|
+
"--format=%(refname:short)",
|
|
865
|
+
"refs/heads/",
|
|
866
|
+
SESSION_BRANCH_PREFIX + "*"
|
|
867
|
+
],
|
|
868
|
+
true
|
|
869
|
+
);
|
|
870
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
871
|
+
}
|
|
872
|
+
async function listRemoteSessionBranches(cwd) {
|
|
873
|
+
const out = await execGit2(
|
|
874
|
+
cwd,
|
|
875
|
+
[
|
|
876
|
+
"for-each-ref",
|
|
877
|
+
"--format=%(refname:short)",
|
|
878
|
+
"refs/remotes/origin/",
|
|
879
|
+
SESSION_BRANCH_PREFIX + "*"
|
|
880
|
+
],
|
|
881
|
+
true
|
|
882
|
+
);
|
|
883
|
+
return out.split(/\r?\n/).map((line) => line.trim().replace(/^origin\//, "")).filter(Boolean);
|
|
884
|
+
}
|
|
885
|
+
async function localBranchExists2(cwd, branch) {
|
|
886
|
+
try {
|
|
887
|
+
await execGit2(
|
|
888
|
+
cwd,
|
|
889
|
+
["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
890
|
+
true
|
|
891
|
+
);
|
|
892
|
+
return true;
|
|
893
|
+
} catch {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async function remoteBranchExists(cwd, branch) {
|
|
898
|
+
const out = await execGit2(
|
|
899
|
+
cwd,
|
|
900
|
+
["ls-remote", "--heads", "origin", branch],
|
|
901
|
+
true
|
|
902
|
+
);
|
|
903
|
+
return out.trim().length > 0;
|
|
904
|
+
}
|
|
905
|
+
function reasonForCleanup(sessionId, sessionStatusById) {
|
|
906
|
+
if (!sessionStatusById.has(sessionId)) {
|
|
907
|
+
return "\u6C9F\u901A\u7FA4\u4E0D\u5728\u4EFB\u52A1\u5217\u8868\u4E2D";
|
|
908
|
+
}
|
|
909
|
+
if (sessionStatusById.get(sessionId) === "COMPLETED") {
|
|
910
|
+
return "\u5173\u8054\u4EFB\u52A1\u5DF2\u5B8C\u6210";
|
|
911
|
+
}
|
|
912
|
+
return "\u4FDD\u7559";
|
|
913
|
+
}
|
|
914
|
+
async function runCleanBranches(options = {}) {
|
|
915
|
+
const cwd = options.cwd ?? process.cwd();
|
|
916
|
+
const dryRun = options.dryRun ?? false;
|
|
917
|
+
await ensureGitRepo2(cwd);
|
|
918
|
+
await execGit2(cwd, ["fetch", "--prune", "origin"], true);
|
|
919
|
+
const cfg = await ensureLoggedConfig();
|
|
920
|
+
const api = createApmApiClient(cfg);
|
|
921
|
+
const { sessions } = await api.cli.listSessionsForBranchCleanup({});
|
|
922
|
+
const sessionStatusById = new Map(
|
|
923
|
+
sessions.map((item) => [item.sessionId, item.taskStatus])
|
|
924
|
+
);
|
|
925
|
+
const branchNames = /* @__PURE__ */ new Set([
|
|
926
|
+
...await listLocalSessionBranches(cwd),
|
|
927
|
+
...await listRemoteSessionBranches(cwd)
|
|
928
|
+
]);
|
|
929
|
+
if (branchNames.size === 0) {
|
|
930
|
+
console.log("[apm] \u672A\u53D1\u73B0 feat/session-* \u5206\u652F");
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
const toDelete = [...branchNames].map((branch) => {
|
|
934
|
+
const sessionId = sessionIdFromBranchName(branch);
|
|
935
|
+
if (!sessionId) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
const reason = reasonForCleanup(sessionId, sessionStatusById);
|
|
939
|
+
if (reason === "\u4FDD\u7559") {
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
942
|
+
return { branch, sessionId, reason };
|
|
943
|
+
}).filter((item) => item != null).sort((a, b) => a.branch.localeCompare(b.branch));
|
|
944
|
+
if (toDelete.length === 0) {
|
|
945
|
+
console.log("[apm] \u6CA1\u6709\u9700\u8981\u6E05\u7406\u7684 feat/session-* \u5206\u652F");
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
let currentBranch = await getCurrentBranch2(cwd);
|
|
949
|
+
let defaultBranch = null;
|
|
950
|
+
for (const item of toDelete) {
|
|
951
|
+
const { branch, sessionId, reason } = item;
|
|
952
|
+
const label = `${branch} (${sessionId}: ${reason})`;
|
|
953
|
+
if (dryRun) {
|
|
954
|
+
console.log(`[apm] [dry-run] \u5C06\u5220\u9664 ${label}`);
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
if (currentBranch === branch) {
|
|
958
|
+
defaultBranch ??= await resolveDefaultBranch(cwd);
|
|
959
|
+
await execGit2(cwd, ["checkout", defaultBranch], true);
|
|
960
|
+
currentBranch = defaultBranch;
|
|
961
|
+
}
|
|
962
|
+
if (await localBranchExists2(cwd, branch)) {
|
|
963
|
+
await execGit2(cwd, ["branch", "-D", branch], true);
|
|
964
|
+
console.log(`[apm] \u5DF2\u5220\u9664\u672C\u5730\u5206\u652F ${branch}`);
|
|
965
|
+
}
|
|
966
|
+
if (await remoteBranchExists(cwd, branch)) {
|
|
967
|
+
await execGit2(cwd, ["push", "origin", "--delete", branch], true);
|
|
968
|
+
console.log(`[apm] \u5DF2\u5220\u9664\u8FDC\u7A0B\u5206\u652F origin/${branch}`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
if (dryRun) {
|
|
972
|
+
console.log(`[apm] [dry-run] \u5171 ${toDelete.length} \u4E2A\u5206\u652F\u5F85\u6E05\u7406`);
|
|
973
|
+
} else {
|
|
974
|
+
console.log(`[apm] \u5DF2\u6E05\u7406 ${toDelete.length} \u4E2A feat/session-* \u5206\u652F`);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
743
978
|
// src/commands/pull.ts
|
|
744
979
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
745
980
|
import { join as join8 } from "path";
|
|
@@ -775,7 +1010,7 @@ function formatSessionMessagesXml(sessionId, messages) {
|
|
|
775
1010
|
}
|
|
776
1011
|
|
|
777
1012
|
// src/commands/sync-session-attachments.ts
|
|
778
|
-
import { existsSync as existsSync3, readFileSync as
|
|
1013
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
779
1014
|
import { join as join5 } from "path";
|
|
780
1015
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
781
1016
|
async function downloadAttachment(cfg, attachmentId) {
|
|
@@ -796,7 +1031,7 @@ function loadManifest(dir) {
|
|
|
796
1031
|
}
|
|
797
1032
|
try {
|
|
798
1033
|
const parsed = JSON.parse(
|
|
799
|
-
|
|
1034
|
+
readFileSync4(path10, "utf8")
|
|
800
1035
|
);
|
|
801
1036
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
802
1037
|
return parsed;
|
|
@@ -852,7 +1087,7 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
|
|
|
852
1087
|
|
|
853
1088
|
// src/rules-sync.ts
|
|
854
1089
|
import { basename as basename2, extname as extname2, join as join7 } from "path";
|
|
855
|
-
import { existsSync as existsSync5, readFileSync as
|
|
1090
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
856
1091
|
|
|
857
1092
|
// src/skills-sync.ts
|
|
858
1093
|
import {
|
|
@@ -960,7 +1195,7 @@ function loadManifest2(rulesDir) {
|
|
|
960
1195
|
}
|
|
961
1196
|
try {
|
|
962
1197
|
const parsed = JSON.parse(
|
|
963
|
-
|
|
1198
|
+
readFileSync5(toFsPath(path10), "utf8")
|
|
964
1199
|
);
|
|
965
1200
|
if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
|
|
966
1201
|
return parsed;
|
|
@@ -985,7 +1220,7 @@ function isRuleUpToDate(entry, rule, dest) {
|
|
|
985
1220
|
if (entry.fileName !== ruleLocalFileName(rule.name)) return false;
|
|
986
1221
|
const updatedAt = rule.updatedAt ?? "";
|
|
987
1222
|
if (entry.updatedAt !== updatedAt) return false;
|
|
988
|
-
const localContent =
|
|
1223
|
+
const localContent = readFileSync5(toFsPath(dest), "utf8");
|
|
989
1224
|
return localContent === (rule.content ?? "");
|
|
990
1225
|
}
|
|
991
1226
|
async function syncPlatformRules(cfg, sessionId, workdirPath, apmRoot) {
|
|
@@ -1112,7 +1347,7 @@ async function runPull(sessionId, remoteWorkdir) {
|
|
|
1112
1347
|
import { spawnSync } from "child_process";
|
|
1113
1348
|
|
|
1114
1349
|
// src/version.ts
|
|
1115
|
-
import { readFileSync as
|
|
1350
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
1116
1351
|
import { dirname as dirname2, join as join9 } from "path";
|
|
1117
1352
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1118
1353
|
var CLI_PACKAGE_NAME = "ai-project-manage-cli";
|
|
@@ -1120,7 +1355,7 @@ function readCliVersion() {
|
|
|
1120
1355
|
try {
|
|
1121
1356
|
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
1122
1357
|
const pkgPath = join9(dir, "..", "package.json");
|
|
1123
|
-
const pkg = JSON.parse(
|
|
1358
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
1124
1359
|
return pkg.version ?? "0.0.0";
|
|
1125
1360
|
} catch {
|
|
1126
1361
|
return "0.0.0";
|
|
@@ -1266,7 +1501,7 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
1266
1501
|
import { basename as basename3 } from "path";
|
|
1267
1502
|
|
|
1268
1503
|
// src/commands/sync-session-documents.ts
|
|
1269
|
-
import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as
|
|
1504
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
|
|
1270
1505
|
import { join as join11 } from "path";
|
|
1271
1506
|
function listLocalMarkdownFiles(docsDir) {
|
|
1272
1507
|
if (!existsSync8(docsDir)) {
|
|
@@ -1285,7 +1520,7 @@ function remoteDocumentByLocalName(remoteDocuments, localFileName) {
|
|
|
1285
1520
|
}
|
|
1286
1521
|
async function upsertLocalDocumentFile(api, sessionId, docsDir, fileName) {
|
|
1287
1522
|
const absPath = join11(docsDir, fileName);
|
|
1288
|
-
const content =
|
|
1523
|
+
const content = readFileSync7(absPath, "utf8");
|
|
1289
1524
|
const name = documentPlatformName(absPath);
|
|
1290
1525
|
return api.cli.upsertDocument({
|
|
1291
1526
|
sessionId,
|
|
@@ -1308,7 +1543,7 @@ async function syncSessionDocuments(cfg, sessionId, apmRoot, options) {
|
|
|
1308
1543
|
let synced = 0;
|
|
1309
1544
|
for (const fileName of localFiles) {
|
|
1310
1545
|
const absPath = join11(docsDir, fileName);
|
|
1311
|
-
const content =
|
|
1546
|
+
const content = readFileSync7(absPath, "utf8");
|
|
1312
1547
|
const remote = remoteDocumentByLocalName(remoteDocuments, fileName);
|
|
1313
1548
|
if (remote && remote.content === content) {
|
|
1314
1549
|
continue;
|
|
@@ -1741,7 +1976,7 @@ ${JSON.stringify(event, null, 2)}
|
|
|
1741
1976
|
}
|
|
1742
1977
|
|
|
1743
1978
|
// src/commands/connect/agent-session-registry.ts
|
|
1744
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as
|
|
1979
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "node:fs";
|
|
1745
1980
|
import { dirname as dirname3, resolve as resolve3 } from "node:path";
|
|
1746
1981
|
function registryPath(workdir, sessionId) {
|
|
1747
1982
|
return resolve3(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
@@ -1751,7 +1986,7 @@ function readRegistry(path10) {
|
|
|
1751
1986
|
return {};
|
|
1752
1987
|
}
|
|
1753
1988
|
try {
|
|
1754
|
-
const parsed = JSON.parse(
|
|
1989
|
+
const parsed = JSON.parse(readFileSync8(path10, "utf8"));
|
|
1755
1990
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1756
1991
|
const result = {};
|
|
1757
1992
|
for (const [key, value] of Object.entries(
|
|
@@ -2159,6 +2394,8 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
|
|
|
2159
2394
|
};
|
|
2160
2395
|
try {
|
|
2161
2396
|
if (signal.aborted) return;
|
|
2397
|
+
assertWorkspaceApmDirExists(workdir);
|
|
2398
|
+
assertApmGitignoredInRepo(workdir);
|
|
2162
2399
|
await runStep(
|
|
2163
2400
|
"status-typing",
|
|
2164
2401
|
() => updateMessageStatus(cfg, messageId, "TYPING")
|
|
@@ -2411,7 +2648,7 @@ async function runCreatePr(options) {
|
|
|
2411
2648
|
import path5 from "node:path";
|
|
2412
2649
|
|
|
2413
2650
|
// src/commands/deploy/internal/apm-config.ts
|
|
2414
|
-
import { existsSync as existsSync11, readFileSync as
|
|
2651
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
|
|
2415
2652
|
import { resolve as resolve4 } from "node:path";
|
|
2416
2653
|
function loadApmConfig(options) {
|
|
2417
2654
|
const p = resolve4(
|
|
@@ -2423,7 +2660,7 @@ function loadApmConfig(options) {
|
|
|
2423
2660
|
process.exit(1);
|
|
2424
2661
|
}
|
|
2425
2662
|
try {
|
|
2426
|
-
const raw =
|
|
2663
|
+
const raw = readFileSync9(p, "utf8");
|
|
2427
2664
|
return JSON.parse(raw);
|
|
2428
2665
|
} catch (e) {
|
|
2429
2666
|
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
@@ -2545,7 +2782,7 @@ import path4 from "node:path";
|
|
|
2545
2782
|
import Docker from "dockerode";
|
|
2546
2783
|
|
|
2547
2784
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
2548
|
-
import { existsSync as existsSync12, readFileSync as
|
|
2785
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
2549
2786
|
import path from "node:path";
|
|
2550
2787
|
function asOptionalTlsBuffer(value) {
|
|
2551
2788
|
if (typeof value !== "string") {
|
|
@@ -2558,7 +2795,7 @@ function asOptionalTlsBuffer(value) {
|
|
|
2558
2795
|
return void 0;
|
|
2559
2796
|
}
|
|
2560
2797
|
if (existsSync12(normalized)) {
|
|
2561
|
-
return
|
|
2798
|
+
return readFileSync10(normalized);
|
|
2562
2799
|
}
|
|
2563
2800
|
const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
|
|
2564
2801
|
if (looksLikePath) {
|
|
@@ -2768,7 +3005,7 @@ var DockerodeClient = class {
|
|
|
2768
3005
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
2769
3006
|
|
|
2770
3007
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
2771
|
-
import { existsSync as existsSync13, readFileSync as
|
|
3008
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11, statSync as statSync5 } from "node:fs";
|
|
2772
3009
|
import path2 from "node:path";
|
|
2773
3010
|
function stripSurroundingQuotes(value) {
|
|
2774
3011
|
const t = value.trim();
|
|
@@ -2788,7 +3025,7 @@ function loadEnvFromFile(envFilePath) {
|
|
|
2788
3025
|
if (!existsSync13(targetPath) || !statSync5(targetPath).isFile()) {
|
|
2789
3026
|
return {};
|
|
2790
3027
|
}
|
|
2791
|
-
const raw =
|
|
3028
|
+
const raw = readFileSync11(targetPath, "utf-8");
|
|
2792
3029
|
const result = {};
|
|
2793
3030
|
for (const line of raw.split(/\r?\n/)) {
|
|
2794
3031
|
const normalized = line.trim();
|
|
@@ -3624,6 +3861,11 @@ function buildProgram() {
|
|
|
3624
3861
|
).action(async (sessionId, opts) => {
|
|
3625
3862
|
await runBranch(sessionId, { message: opts.message });
|
|
3626
3863
|
});
|
|
3864
|
+
program.command("clean-branches").description(
|
|
3865
|
+
"\u6E05\u7406\u672C\u5730\u4E0E\u8FDC\u7A0B feat/session-* \u5206\u652F\uFF1A\u6C9F\u901A\u7FA4\u4E0D\u5728\u4EFB\u52A1\u5217\u8868\u4E2D\uFF0C\u6216\u5173\u8054\u4EFB\u52A1\u5DF2\u5B8C\u6210\u65F6\u5220\u9664"
|
|
3866
|
+
).option("--dry-run", "\u4EC5\u5217\u51FA\u5C06\u88AB\u5220\u9664\u7684\u5206\u652F\uFF0C\u4E0D\u5B9E\u9645\u6267\u884C").action(async (opts) => {
|
|
3867
|
+
await runCleanBranches({ dryRun: opts.dryRun });
|
|
3868
|
+
});
|
|
3627
3869
|
program.command("create-pr").description(
|
|
3628
3870
|
"\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u7684\u4F1A\u8BDD\u7279\u6027\u5206\u652F\u521B\u5EFA PR\uFF08\u6807\u9898\u81EA\u52A8\u52A0 [AI] \u6807\u8BC6\uFF1B\u8FDC\u7A0B\u521B\u5EFA\u5931\u8D25\u65F6\u5E73\u53F0\u6570\u636E\u56DE\u6EDA\uFF09"
|
|
3629
3871
|
).requiredOption("--session <sessionId>", "\u6C9F\u901A\u7FA4 ID").requiredOption("--title <title>", "PR \u6807\u9898").option("--content <content>", "PR \u6B63\u6587\uFF08Markdown\uFF09", "").action(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-project-manage-cli",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.52",
|
|
4
4
|
"description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@types/ssh2-sftp-client": "~9.0.6"
|
|
28
28
|
},
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": ">=
|
|
30
|
+
"node": ">=22.13.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@bufbuild/protobuf": "1.10.0",
|