ai-project-manage-cli 6.0.53 → 6.0.55
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 +172 -65
- package/package.json +1 -1
- package/template/deploy/README.md +3 -3
- package/template/deploy/deploy.py +564 -0
- package/template/rules/write_doc.md +4 -1
- package/template/skills/apm-dev/SKILL.md +7 -2
- package/template/skills/apm-diff-review/SKILL.md +6 -6
- package/template/skills/apm-write-plan/SKILL.md +19 -12
- package/template/skills/apm-write-plan/api-template.md +35 -0
- package/template/skills/apm-write-plan/plan-template.md +46 -18
package/dist/index.js
CHANGED
|
@@ -81,7 +81,7 @@ function buildAgentWsUrl(httpBase, apiKey) {
|
|
|
81
81
|
|
|
82
82
|
// src/commands/init.ts
|
|
83
83
|
import { join as join4 } from "path";
|
|
84
|
-
import { readFileSync as readFileSync3, writeFileSync as
|
|
84
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
85
85
|
|
|
86
86
|
// src/command-utils.ts
|
|
87
87
|
import {
|
|
@@ -90,7 +90,8 @@ import {
|
|
|
90
90
|
mkdirSync as mkdirSync2,
|
|
91
91
|
readFileSync as readFileSync2,
|
|
92
92
|
readdirSync,
|
|
93
|
-
statSync
|
|
93
|
+
statSync,
|
|
94
|
+
writeFileSync as writeFileSync2
|
|
94
95
|
} from "fs";
|
|
95
96
|
import { basename, dirname, extname, join as join2, resolve as resolve2 } from "path";
|
|
96
97
|
import { fileURLToPath } from "url";
|
|
@@ -183,6 +184,28 @@ function gitignoreIgnoresApm(line) {
|
|
|
183
184
|
if (!pattern) return false;
|
|
184
185
|
return APM_GITIGNORE_PATTERNS.some((re) => re.test(pattern));
|
|
185
186
|
}
|
|
187
|
+
var APM_GITIGNORE_LINE = "**/.apm/**";
|
|
188
|
+
function ensureApmGitignoredInRepo(workdir) {
|
|
189
|
+
const gitignorePath = join2(workdir, ".gitignore");
|
|
190
|
+
const fsGitignorePath = toFsPath(gitignorePath);
|
|
191
|
+
if (!existsSync(fsGitignorePath)) {
|
|
192
|
+
writeFileSync2(fsGitignorePath, `${APM_GITIGNORE_LINE}
|
|
193
|
+
`, "utf8");
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
const content = readFileSync2(fsGitignorePath, "utf8");
|
|
197
|
+
if (content.split(/\r?\n/).some(gitignoreIgnoresApm)) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const suffix = content.endsWith("\n") || content.length === 0 ? "" : "\n";
|
|
201
|
+
writeFileSync2(
|
|
202
|
+
fsGitignorePath,
|
|
203
|
+
`${content}${suffix}${APM_GITIGNORE_LINE}
|
|
204
|
+
`,
|
|
205
|
+
"utf8"
|
|
206
|
+
);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
186
209
|
function assertApmGitignoredInRepo(workdir) {
|
|
187
210
|
const gitignorePath = join2(workdir, ".gitignore");
|
|
188
211
|
const fsGitignorePath = toFsPath(gitignorePath);
|
|
@@ -346,7 +369,7 @@ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
|
346
369
|
|
|
347
370
|
// src/deployment-config-sync.ts
|
|
348
371
|
import { join as join3 } from "path";
|
|
349
|
-
import { writeFileSync as
|
|
372
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
350
373
|
|
|
351
374
|
// src/api/client.ts
|
|
352
375
|
import { createApiClient } from "listpage-http";
|
|
@@ -529,11 +552,11 @@ ${diagnostic ?? ""}
|
|
|
529
552
|
}
|
|
530
553
|
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
531
554
|
const apmConfigPath = toFsPath(join3(targetApmDir, "apm.config.json"));
|
|
532
|
-
|
|
555
|
+
writeFileSync3(apmConfigPath, `${JSON.stringify(parsed, null, 2)}
|
|
533
556
|
`, "utf8");
|
|
534
557
|
const deployDir = join3(targetApmDir, "deploy");
|
|
535
558
|
await ensureDirExists(deployDir);
|
|
536
|
-
|
|
559
|
+
writeFileSync3(
|
|
537
560
|
toFsPath(join3(deployDir, "README.md")),
|
|
538
561
|
config.deploymentDoc ?? "",
|
|
539
562
|
"utf8"
|
|
@@ -543,10 +566,75 @@ ${diagnostic ?? ""}
|
|
|
543
566
|
return { synced: true, repositoryId, configName: config.name };
|
|
544
567
|
}
|
|
545
568
|
|
|
569
|
+
// src/git-utils.ts
|
|
570
|
+
import { execFile as execFile2 } from "child_process";
|
|
571
|
+
import { promisify as promisify2 } from "util";
|
|
572
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
573
|
+
async function execGit(cwd, args, quiet = false) {
|
|
574
|
+
try {
|
|
575
|
+
const { stdout, stderr } = await execFileAsync2("git", args, {
|
|
576
|
+
cwd,
|
|
577
|
+
encoding: "utf8",
|
|
578
|
+
maxBuffer: 10 * 1024 * 1024
|
|
579
|
+
});
|
|
580
|
+
if (!quiet && stderr.trim()) {
|
|
581
|
+
process.stderr.write(stderr);
|
|
582
|
+
}
|
|
583
|
+
return stdout;
|
|
584
|
+
} catch (err) {
|
|
585
|
+
const e = err;
|
|
586
|
+
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
587
|
+
throw new Error(
|
|
588
|
+
`[apm] git ${args.join(" ")} \u5931\u8D25${detail ? `: ${detail}` : ""}`
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
async function isGitRepo(cwd) {
|
|
593
|
+
try {
|
|
594
|
+
await execGit(cwd, ["rev-parse", "--git-dir"], true);
|
|
595
|
+
return true;
|
|
596
|
+
} catch {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
async function hasUpstream(cwd) {
|
|
601
|
+
try {
|
|
602
|
+
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
603
|
+
return true;
|
|
604
|
+
} catch {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
var GITIGNORE_COMMIT_MESSAGE = "chore(apm): ignore .apm directory";
|
|
609
|
+
async function commitAndPushGitignore(workdir) {
|
|
610
|
+
if (!await isGitRepo(workdir)) {
|
|
611
|
+
console.log("[apm] \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93\uFF0C\u8BF7\u624B\u52A8\u63D0\u4EA4 .gitignore");
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
await execGit(workdir, ["add", "--", ".gitignore"]);
|
|
615
|
+
await execGit(workdir, ["commit", "-m", GITIGNORE_COMMIT_MESSAGE]);
|
|
616
|
+
console.log(`[apm] \u5DF2\u63D0\u4EA4 .gitignore: ${GITIGNORE_COMMIT_MESSAGE}`);
|
|
617
|
+
const originUrl = await tryReadGitOriginUrl(workdir);
|
|
618
|
+
if (!originUrl) {
|
|
619
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8 push .gitignore");
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (await hasUpstream(workdir)) {
|
|
623
|
+
await execGit(workdir, ["push"]);
|
|
624
|
+
} else {
|
|
625
|
+
await execGit(workdir, ["push", "-u", "origin", "HEAD"]);
|
|
626
|
+
}
|
|
627
|
+
console.log("[apm] \u5DF2\u63A8\u9001 .gitignore");
|
|
628
|
+
}
|
|
629
|
+
|
|
546
630
|
// src/commands/init.ts
|
|
547
631
|
async function runInit(name) {
|
|
548
632
|
const workdir = resolveWorkdirPath();
|
|
549
633
|
await ensureWorkspaceApmDirForInit(workdir);
|
|
634
|
+
if (ensureApmGitignoredInRepo(workdir)) {
|
|
635
|
+
console.log("[apm] \u5DF2\u5728 .gitignore \u4E2D\u6DFB\u52A0 **/.apm/**");
|
|
636
|
+
await commitAndPushGitignore(workdir);
|
|
637
|
+
}
|
|
550
638
|
const apmDir = workspaceApmDir(workdir);
|
|
551
639
|
await copyTemplateFiles(apmDir, workdir);
|
|
552
640
|
const syncResult = await syncRemoteDeploymentConfig(workdir, apmDir);
|
|
@@ -556,7 +644,7 @@ async function runInit(name) {
|
|
|
556
644
|
const config = readFileSync3(apmConfigPath, "utf8");
|
|
557
645
|
const configJson = JSON.parse(config);
|
|
558
646
|
configJson.name = trimmedName;
|
|
559
|
-
|
|
647
|
+
writeFileSync4(
|
|
560
648
|
apmConfigPath,
|
|
561
649
|
`${JSON.stringify(configJson, null, 2)}
|
|
562
650
|
`,
|
|
@@ -635,9 +723,9 @@ async function runLogin(opts) {
|
|
|
635
723
|
}
|
|
636
724
|
|
|
637
725
|
// src/commands/branch.ts
|
|
638
|
-
import { execFile as
|
|
639
|
-
import { promisify as
|
|
640
|
-
var
|
|
726
|
+
import { execFile as execFile3 } from "child_process";
|
|
727
|
+
import { promisify as promisify3 } from "util";
|
|
728
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
641
729
|
var SESSION_BRANCH_PREFIX = "feat/session-";
|
|
642
730
|
function branchNameForSession(sessionId) {
|
|
643
731
|
const id = sessionId.trim();
|
|
@@ -659,9 +747,9 @@ function sessionIdFromBranchName(branch) {
|
|
|
659
747
|
const sessionId = name.slice(SESSION_BRANCH_PREFIX.length).trim();
|
|
660
748
|
return sessionId || null;
|
|
661
749
|
}
|
|
662
|
-
async function
|
|
750
|
+
async function execGit2(cwd, args, quiet) {
|
|
663
751
|
try {
|
|
664
|
-
const { stdout, stderr } = await
|
|
752
|
+
const { stdout, stderr } = await execFileAsync3("git", args, {
|
|
665
753
|
cwd,
|
|
666
754
|
encoding: "utf8",
|
|
667
755
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -679,18 +767,18 @@ async function execGit(cwd, args, quiet) {
|
|
|
679
767
|
}
|
|
680
768
|
}
|
|
681
769
|
async function ensureGitRepo(cwd) {
|
|
682
|
-
await
|
|
770
|
+
await execGit2(cwd, ["rev-parse", "--git-dir"], true);
|
|
683
771
|
}
|
|
684
772
|
async function getCurrentBranch(cwd) {
|
|
685
|
-
const name = (await
|
|
773
|
+
const name = (await execGit2(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
686
774
|
return name;
|
|
687
775
|
}
|
|
688
776
|
async function isWorkingTreeDirty(cwd) {
|
|
689
|
-
const out = await
|
|
777
|
+
const out = await execGit2(cwd, ["status", "--porcelain"], true);
|
|
690
778
|
return out.trim().length > 0;
|
|
691
779
|
}
|
|
692
780
|
async function remoteHeadBranchExists(cwd, branch) {
|
|
693
|
-
const out = await
|
|
781
|
+
const out = await execGit2(
|
|
694
782
|
cwd,
|
|
695
783
|
["ls-remote", "--heads", "origin", branch],
|
|
696
784
|
true
|
|
@@ -699,7 +787,7 @@ async function remoteHeadBranchExists(cwd, branch) {
|
|
|
699
787
|
}
|
|
700
788
|
async function localBranchExists(cwd, branch) {
|
|
701
789
|
try {
|
|
702
|
-
await
|
|
790
|
+
await execGit2(
|
|
703
791
|
cwd,
|
|
704
792
|
["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
705
793
|
true
|
|
@@ -715,8 +803,8 @@ async function commitWorkingTreeIfDirty(cwd, message) {
|
|
|
715
803
|
return false;
|
|
716
804
|
}
|
|
717
805
|
const commitMessage = message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${await getCurrentBranch(cwd)})`;
|
|
718
|
-
await
|
|
719
|
-
await
|
|
806
|
+
await execGit2(cwd, ["add", "-A"]);
|
|
807
|
+
await execGit2(cwd, ["commit", "-m", commitMessage]);
|
|
720
808
|
console.log(`[apm] \u5DF2\u63D0\u4EA4\u5DE5\u4F5C\u533A\u53D8\u66F4: ${commitMessage}`);
|
|
721
809
|
return true;
|
|
722
810
|
}
|
|
@@ -735,7 +823,7 @@ async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
|
735
823
|
if (current === branch) {
|
|
736
824
|
await commitWorkingTreeIfDirty(cwd, commitMessage);
|
|
737
825
|
} else {
|
|
738
|
-
await
|
|
826
|
+
await execGit2(cwd, [
|
|
739
827
|
"stash",
|
|
740
828
|
"push",
|
|
741
829
|
"-u",
|
|
@@ -746,32 +834,32 @@ async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
|
746
834
|
}
|
|
747
835
|
const onTargetBranch = await getCurrentBranch(cwd) === branch;
|
|
748
836
|
if (onTargetBranch) {
|
|
749
|
-
await
|
|
750
|
-
await
|
|
837
|
+
await execGit2(cwd, ["fetch", "origin", baselineBranch]);
|
|
838
|
+
await execGit2(cwd, ["merge", `origin/${baselineBranch}`, "--no-edit"]);
|
|
751
839
|
} else {
|
|
752
840
|
const remoteExists = await remoteHeadBranchExists(cwd, branch);
|
|
753
841
|
if (remoteExists) {
|
|
754
|
-
await
|
|
755
|
-
await
|
|
842
|
+
await execGit2(cwd, ["fetch", "origin", branch]);
|
|
843
|
+
await execGit2(cwd, ["checkout", "-B", branch, `origin/${branch}`]);
|
|
756
844
|
} else if (await localBranchExists(cwd, branch)) {
|
|
757
845
|
if (await getCurrentBranch(cwd) !== branch) {
|
|
758
|
-
await
|
|
846
|
+
await execGit2(cwd, ["checkout", branch]);
|
|
759
847
|
}
|
|
760
848
|
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
761
849
|
} else {
|
|
762
|
-
await
|
|
850
|
+
await execGit2(cwd, ["fetch", "origin", baselineBranch]);
|
|
763
851
|
try {
|
|
764
|
-
await
|
|
852
|
+
await execGit2(cwd, [
|
|
765
853
|
"checkout",
|
|
766
854
|
"-b",
|
|
767
855
|
branch,
|
|
768
856
|
`origin/${baselineBranch}`
|
|
769
857
|
]);
|
|
770
|
-
await
|
|
858
|
+
await execGit2(cwd, ["push", "-u", "origin", branch]);
|
|
771
859
|
} catch (err) {
|
|
772
860
|
if (await localBranchExists(cwd, branch)) {
|
|
773
861
|
if (await getCurrentBranch(cwd) !== branch) {
|
|
774
|
-
await
|
|
862
|
+
await execGit2(cwd, ["checkout", branch]);
|
|
775
863
|
}
|
|
776
864
|
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
777
865
|
} else {
|
|
@@ -811,12 +899,12 @@ async function runBranch(sessionId, options = {}) {
|
|
|
811
899
|
}
|
|
812
900
|
|
|
813
901
|
// src/commands/clean-branches.ts
|
|
814
|
-
import { execFile as
|
|
815
|
-
import { promisify as
|
|
816
|
-
var
|
|
817
|
-
async function
|
|
902
|
+
import { execFile as execFile4 } from "child_process";
|
|
903
|
+
import { promisify as promisify4 } from "util";
|
|
904
|
+
var execFileAsync4 = promisify4(execFile4);
|
|
905
|
+
async function execGit3(cwd, args, quiet) {
|
|
818
906
|
try {
|
|
819
|
-
const { stdout, stderr } = await
|
|
907
|
+
const { stdout, stderr } = await execFileAsync4("git", args, {
|
|
820
908
|
cwd,
|
|
821
909
|
encoding: "utf8",
|
|
822
910
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -834,21 +922,21 @@ async function execGit2(cwd, args, quiet) {
|
|
|
834
922
|
}
|
|
835
923
|
}
|
|
836
924
|
async function ensureGitRepo2(cwd) {
|
|
837
|
-
await
|
|
925
|
+
await execGit3(cwd, ["rev-parse", "--git-dir"], true);
|
|
838
926
|
}
|
|
839
927
|
async function getCurrentBranch2(cwd) {
|
|
840
|
-
return (await
|
|
928
|
+
return (await execGit3(cwd, ["rev-parse", "--abbrev-ref", "HEAD"], true)).trim();
|
|
841
929
|
}
|
|
842
930
|
async function resolveDefaultBranch(cwd) {
|
|
843
931
|
try {
|
|
844
|
-
const ref = (await
|
|
932
|
+
const ref = (await execGit3(cwd, ["symbolic-ref", "refs/remotes/origin/HEAD"], true)).trim();
|
|
845
933
|
const match = ref.match(/^refs\/remotes\/origin\/(.+)$/);
|
|
846
934
|
if (match?.[1]) {
|
|
847
935
|
return match[1];
|
|
848
936
|
}
|
|
849
937
|
} catch {
|
|
850
938
|
}
|
|
851
|
-
const out = await
|
|
939
|
+
const out = await execGit3(cwd, ["remote", "show", "origin"], true);
|
|
852
940
|
const headLine = out.split(/\r?\n/).find((line) => line.includes("HEAD branch"));
|
|
853
941
|
const branch = headLine?.split(":").pop()?.trim();
|
|
854
942
|
if (branch) {
|
|
@@ -857,7 +945,7 @@ async function resolveDefaultBranch(cwd) {
|
|
|
857
945
|
throw new Error("[apm] \u65E0\u6CD5\u89E3\u6790 origin \u9ED8\u8BA4\u5206\u652F\uFF0C\u8BF7\u5148\u6267\u884C git fetch origin");
|
|
858
946
|
}
|
|
859
947
|
async function listLocalSessionBranches(cwd) {
|
|
860
|
-
const out = await
|
|
948
|
+
const out = await execGit3(
|
|
861
949
|
cwd,
|
|
862
950
|
[
|
|
863
951
|
"for-each-ref",
|
|
@@ -870,7 +958,7 @@ async function listLocalSessionBranches(cwd) {
|
|
|
870
958
|
return out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
871
959
|
}
|
|
872
960
|
async function listRemoteSessionBranches(cwd) {
|
|
873
|
-
const out = await
|
|
961
|
+
const out = await execGit3(
|
|
874
962
|
cwd,
|
|
875
963
|
[
|
|
876
964
|
"for-each-ref",
|
|
@@ -884,7 +972,7 @@ async function listRemoteSessionBranches(cwd) {
|
|
|
884
972
|
}
|
|
885
973
|
async function localBranchExists2(cwd, branch) {
|
|
886
974
|
try {
|
|
887
|
-
await
|
|
975
|
+
await execGit3(
|
|
888
976
|
cwd,
|
|
889
977
|
["show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
890
978
|
true
|
|
@@ -895,7 +983,7 @@ async function localBranchExists2(cwd, branch) {
|
|
|
895
983
|
}
|
|
896
984
|
}
|
|
897
985
|
async function remoteBranchExists(cwd, branch) {
|
|
898
|
-
const out = await
|
|
986
|
+
const out = await execGit3(
|
|
899
987
|
cwd,
|
|
900
988
|
["ls-remote", "--heads", "origin", branch],
|
|
901
989
|
true
|
|
@@ -915,7 +1003,7 @@ async function runCleanBranches(options = {}) {
|
|
|
915
1003
|
const cwd = options.cwd ?? process.cwd();
|
|
916
1004
|
const dryRun = options.dryRun ?? false;
|
|
917
1005
|
await ensureGitRepo2(cwd);
|
|
918
|
-
await
|
|
1006
|
+
await execGit3(cwd, ["fetch", "--prune", "origin"], true);
|
|
919
1007
|
const cfg = await ensureLoggedConfig();
|
|
920
1008
|
const api = createApmApiClient(cfg);
|
|
921
1009
|
const { sessions } = await api.cli.listSessionsForBranchCleanup({});
|
|
@@ -956,15 +1044,15 @@ async function runCleanBranches(options = {}) {
|
|
|
956
1044
|
}
|
|
957
1045
|
if (currentBranch === branch) {
|
|
958
1046
|
defaultBranch ??= await resolveDefaultBranch(cwd);
|
|
959
|
-
await
|
|
1047
|
+
await execGit3(cwd, ["checkout", defaultBranch], true);
|
|
960
1048
|
currentBranch = defaultBranch;
|
|
961
1049
|
}
|
|
962
1050
|
if (await localBranchExists2(cwd, branch)) {
|
|
963
|
-
await
|
|
1051
|
+
await execGit3(cwd, ["branch", "-D", branch], true);
|
|
964
1052
|
console.log(`[apm] \u5DF2\u5220\u9664\u672C\u5730\u5206\u652F ${branch}`);
|
|
965
1053
|
}
|
|
966
1054
|
if (await remoteBranchExists(cwd, branch)) {
|
|
967
|
-
await
|
|
1055
|
+
await execGit3(cwd, ["push", "origin", "--delete", branch], true);
|
|
968
1056
|
console.log(`[apm] \u5DF2\u5220\u9664\u8FDC\u7A0B\u5206\u652F origin/${branch}`);
|
|
969
1057
|
}
|
|
970
1058
|
}
|
|
@@ -976,7 +1064,7 @@ async function runCleanBranches(options = {}) {
|
|
|
976
1064
|
}
|
|
977
1065
|
|
|
978
1066
|
// src/commands/pull.ts
|
|
979
|
-
import { writeFileSync as
|
|
1067
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
980
1068
|
import { join as join8 } from "path";
|
|
981
1069
|
import { stringify as yamlStringify } from "yaml";
|
|
982
1070
|
|
|
@@ -1010,7 +1098,7 @@ function formatSessionMessagesXml(sessionId, messages) {
|
|
|
1010
1098
|
}
|
|
1011
1099
|
|
|
1012
1100
|
// src/commands/sync-session-attachments.ts
|
|
1013
|
-
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as
|
|
1101
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
1014
1102
|
import { join as join5 } from "path";
|
|
1015
1103
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
1016
1104
|
async function downloadAttachment(cfg, attachmentId) {
|
|
@@ -1041,7 +1129,7 @@ function loadManifest(dir) {
|
|
|
1041
1129
|
return { version: 1, attachments: {} };
|
|
1042
1130
|
}
|
|
1043
1131
|
function saveManifest(dir, manifest) {
|
|
1044
|
-
|
|
1132
|
+
writeFileSync5(
|
|
1045
1133
|
join5(dir, MANIFEST_FILE),
|
|
1046
1134
|
`${JSON.stringify(manifest, null, 2)}
|
|
1047
1135
|
`,
|
|
@@ -1075,7 +1163,7 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
|
|
|
1075
1163
|
continue;
|
|
1076
1164
|
}
|
|
1077
1165
|
const buffer = await downloadAttachment(cfg, item.id);
|
|
1078
|
-
|
|
1166
|
+
writeFileSync5(dest, buffer);
|
|
1079
1167
|
nextManifest.attachments[item.id] = {
|
|
1080
1168
|
name: item.name,
|
|
1081
1169
|
createdAt
|
|
@@ -1087,7 +1175,7 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
|
|
|
1087
1175
|
|
|
1088
1176
|
// src/rules-sync.ts
|
|
1089
1177
|
import { basename as basename2, extname as extname2, join as join7 } from "path";
|
|
1090
|
-
import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as
|
|
1178
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
1091
1179
|
|
|
1092
1180
|
// src/skills-sync.ts
|
|
1093
1181
|
import {
|
|
@@ -1098,7 +1186,7 @@ import {
|
|
|
1098
1186
|
readdirSync as readdirSync2,
|
|
1099
1187
|
rmSync,
|
|
1100
1188
|
statSync as statSync2,
|
|
1101
|
-
writeFileSync as
|
|
1189
|
+
writeFileSync as writeFileSync6
|
|
1102
1190
|
} from "fs";
|
|
1103
1191
|
import { join as join6 } from "path";
|
|
1104
1192
|
var AGENTS_TEMPLATE_PATH = join6(CLI_TEMPLATE_DIR, "AGENTS.md");
|
|
@@ -1163,7 +1251,7 @@ function syncSupplementarySkills(skillsDir, list) {
|
|
|
1163
1251
|
}
|
|
1164
1252
|
const skillDir = join6(skillsDir, dirName);
|
|
1165
1253
|
mkdirSync3(skillDir, { recursive: true });
|
|
1166
|
-
|
|
1254
|
+
writeFileSync6(join6(skillDir, "SKILL.md"), skill.content ?? "", "utf8");
|
|
1167
1255
|
written.push(dirName);
|
|
1168
1256
|
}
|
|
1169
1257
|
const removed = [];
|
|
@@ -1205,7 +1293,7 @@ function loadManifest2(rulesDir) {
|
|
|
1205
1293
|
return { version: 1, rules: {} };
|
|
1206
1294
|
}
|
|
1207
1295
|
function saveManifest2(rulesDir, manifest) {
|
|
1208
|
-
|
|
1296
|
+
writeFileSync7(
|
|
1209
1297
|
toFsPath(join7(rulesDir, MANIFEST_FILE2)),
|
|
1210
1298
|
`${JSON.stringify(manifest, null, 2)}
|
|
1211
1299
|
`,
|
|
@@ -1253,7 +1341,7 @@ async function syncPlatformRules(cfg, sessionId, workdirPath, apmRoot) {
|
|
|
1253
1341
|
console.log(`[apm] \u89C4\u5219\u65E0\u53D8\u5316\uFF0C\u5DF2\u8DF3\u8FC7: rules/${fileName}`);
|
|
1254
1342
|
continue;
|
|
1255
1343
|
}
|
|
1256
|
-
|
|
1344
|
+
writeFileSync7(toFsPath(dest), rule.content ?? "", "utf8");
|
|
1257
1345
|
nextManifest.rules[rule.id] = { fileName, updatedAt };
|
|
1258
1346
|
written.push(fileName);
|
|
1259
1347
|
console.log(`[apm] \u5DF2\u540C\u6B65\u5E73\u53F0\u89C4\u5219: rules/${fileName}`);
|
|
@@ -1296,20 +1384,20 @@ async function runPull(sessionId, remoteWorkdir) {
|
|
|
1296
1384
|
const dir = sessionDir(trimmedId, apmRoot);
|
|
1297
1385
|
const docsDir = sessionDocsDir(trimmedId, apmRoot);
|
|
1298
1386
|
await ensureDirExists(docsDir);
|
|
1299
|
-
|
|
1387
|
+
writeFileSync8(
|
|
1300
1388
|
sessionRulePath(trimmedId, apmRoot),
|
|
1301
1389
|
detail.description ?? "",
|
|
1302
1390
|
"utf8"
|
|
1303
1391
|
);
|
|
1304
|
-
|
|
1392
|
+
writeFileSync8(
|
|
1305
1393
|
sessionTaskPath(trimmedId, apmRoot),
|
|
1306
1394
|
detail.task.description ?? "",
|
|
1307
1395
|
"utf8"
|
|
1308
1396
|
);
|
|
1309
|
-
|
|
1397
|
+
writeFileSync8(sessionTodoPath(trimmedId, apmRoot), detail.todo ?? "", "utf8");
|
|
1310
1398
|
for (const doc of documents) {
|
|
1311
1399
|
const fileName = documentLocalFileName(doc.name);
|
|
1312
|
-
|
|
1400
|
+
writeFileSync8(join8(docsDir, fileName), doc.content ?? "", "utf8");
|
|
1313
1401
|
}
|
|
1314
1402
|
const sessionYaml = yamlStringify(
|
|
1315
1403
|
{
|
|
@@ -1326,13 +1414,13 @@ async function runPull(sessionId, remoteWorkdir) {
|
|
|
1326
1414
|
},
|
|
1327
1415
|
{ lineWidth: 0 }
|
|
1328
1416
|
);
|
|
1329
|
-
|
|
1417
|
+
writeFileSync8(
|
|
1330
1418
|
sessionYamlPath(trimmedId, apmRoot),
|
|
1331
1419
|
sessionYaml.endsWith("\n") ? sessionYaml : `${sessionYaml}
|
|
1332
1420
|
`,
|
|
1333
1421
|
"utf8"
|
|
1334
1422
|
);
|
|
1335
|
-
|
|
1423
|
+
writeFileSync8(
|
|
1336
1424
|
sessionMessagesXmlPath(trimmedId, apmRoot),
|
|
1337
1425
|
formatSessionMessagesXml(trimmedId, messages),
|
|
1338
1426
|
"utf8"
|
|
@@ -1394,7 +1482,7 @@ async function runUpdate() {
|
|
|
1394
1482
|
const latest = await fetchLatestPublishedVersion();
|
|
1395
1483
|
if (latest && current === latest) {
|
|
1396
1484
|
console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
|
|
1397
|
-
return;
|
|
1485
|
+
return { didUpdate: false };
|
|
1398
1486
|
}
|
|
1399
1487
|
if (!npmAvailable()) {
|
|
1400
1488
|
console.error(
|
|
@@ -1424,6 +1512,7 @@ async function runUpdate() {
|
|
|
1424
1512
|
`[apm] \u66F4\u65B0\u5B8C\u6210\u3002\u82E5\u7248\u672C\u53F7\u672A\u53D8\u5316\uFF0C\u8BF7\u5728\u65B0\u7EC8\u7AEF\u6267\u884C apm -V \u786E\u8BA4\uFF08\u5168\u5C40\u5B89\u88C5\u8DEF\u5F84\u53EF\u80FD\u672A\u5237\u65B0\uFF09`
|
|
1425
1513
|
);
|
|
1426
1514
|
}
|
|
1515
|
+
return { didUpdate: true };
|
|
1427
1516
|
}
|
|
1428
1517
|
|
|
1429
1518
|
// src/commands/update-skills.ts
|
|
@@ -1653,6 +1742,7 @@ async function runUpdateMessageStatus(options) {
|
|
|
1653
1742
|
}
|
|
1654
1743
|
|
|
1655
1744
|
// src/commands/connect.ts
|
|
1745
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
1656
1746
|
import WebSocket from "ws";
|
|
1657
1747
|
|
|
1658
1748
|
// src/ws/protocol.ts
|
|
@@ -1976,7 +2066,7 @@ ${JSON.stringify(event, null, 2)}
|
|
|
1976
2066
|
}
|
|
1977
2067
|
|
|
1978
2068
|
// src/commands/connect/agent-session-registry.ts
|
|
1979
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as
|
|
2069
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "node:fs";
|
|
1980
2070
|
import { dirname as dirname3, resolve as resolve3 } from "node:path";
|
|
1981
2071
|
function registryPath(workdir, sessionId) {
|
|
1982
2072
|
return resolve3(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
@@ -2004,7 +2094,7 @@ function readRegistry(path10) {
|
|
|
2004
2094
|
}
|
|
2005
2095
|
function writeRegistry(path10, registry) {
|
|
2006
2096
|
mkdirSync5(dirname3(path10), { recursive: true });
|
|
2007
|
-
|
|
2097
|
+
writeFileSync9(path10, `${JSON.stringify(registry, null, 2)}
|
|
2008
2098
|
`, "utf8");
|
|
2009
2099
|
}
|
|
2010
2100
|
function loadSessionAgentId(workdir, sessionId, user) {
|
|
@@ -2333,7 +2423,7 @@ function markPullDone(sessionId, workdir) {
|
|
|
2333
2423
|
}
|
|
2334
2424
|
|
|
2335
2425
|
// src/commands/connect/run-slot-pool.ts
|
|
2336
|
-
var DEFAULT_MAX_CONCURRENT =
|
|
2426
|
+
var DEFAULT_MAX_CONCURRENT = 5;
|
|
2337
2427
|
function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT) {
|
|
2338
2428
|
let active = 0;
|
|
2339
2429
|
const waiters = [];
|
|
@@ -2496,7 +2586,24 @@ function startHeartbeat(ws, clientMachineId) {
|
|
|
2496
2586
|
const timer = setInterval(send, HEARTBEAT_MS);
|
|
2497
2587
|
return () => clearInterval(timer);
|
|
2498
2588
|
}
|
|
2589
|
+
function reexecConnect(options) {
|
|
2590
|
+
const args = [process.argv[1], "connect"];
|
|
2591
|
+
const server = options.server?.trim();
|
|
2592
|
+
if (server) {
|
|
2593
|
+
args.push("--server", server);
|
|
2594
|
+
}
|
|
2595
|
+
const result = spawnSync2(process.execPath, args, { stdio: "inherit" });
|
|
2596
|
+
if (result.error) {
|
|
2597
|
+
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
2598
|
+
process.exit(1);
|
|
2599
|
+
}
|
|
2600
|
+
process.exit(result.status ?? 0);
|
|
2601
|
+
}
|
|
2499
2602
|
async function runConnect(options) {
|
|
2603
|
+
const { didUpdate } = await runUpdate();
|
|
2604
|
+
if (didUpdate) {
|
|
2605
|
+
reexecConnect(options);
|
|
2606
|
+
}
|
|
2500
2607
|
const cfg = await ensureLoggedConfig();
|
|
2501
2608
|
if (options.server?.trim()) {
|
|
2502
2609
|
cfg.baseUrl = options.server.trim().replace(/\/+$/, "");
|
|
@@ -3851,7 +3958,7 @@ function buildProgram() {
|
|
|
3851
3958
|
await runUpdateMessageStatus(opts);
|
|
3852
3959
|
});
|
|
3853
3960
|
program.command("connect").description(
|
|
3854
|
-
"\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C message\uFF08TYPING \u2192 Cursor \u2192 SUCCESS/FAILED\uFF09"
|
|
3961
|
+
"\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C message\uFF08TYPING \u2192 Cursor \u2192 SUCCESS/FAILED\uFF09\uFF1B\u542F\u52A8\u524D\u81EA\u52A8 apm update \u5230\u6700\u65B0\u7248"
|
|
3855
3962
|
).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").action(async (opts) => {
|
|
3856
3963
|
await runConnect(opts);
|
|
3857
3964
|
});
|
package/package.json
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
部署线上环境: `npm run deploy:online`
|
|
5
5
|
|
|
6
6
|
## 后端部署(不区分正式环境和测试环境)
|
|
7
|
-
`python
|
|
7
|
+
`python .apm/deploy/deploy.py`
|
|
8
8
|
|
|
9
9
|
## 前端产物下载地址
|
|
10
10
|
|
|
11
11
|
http://<服务器地址>/dist.zip
|
|
12
|
-
http://<服务器地址>/
|
|
12
|
+
http://<服务器地址>/{name}.jar.zip
|
|
13
13
|
|
|
14
14
|
## 测试地址
|
|
15
|
-
http
|
|
15
|
+
http://<服务器地址>
|