ai-project-manage-cli 7.1.38 → 7.1.39
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 +100 -20
- package/dist/webide-message-worker.js +127 -192
- package/package.json +1 -1
- package/template/AGENTS.webide.md +27 -0
package/dist/index.js
CHANGED
|
@@ -1145,8 +1145,12 @@ var WORKSPACE_TEMPLATE_SUBDIRS = [
|
|
|
1145
1145
|
"rules",
|
|
1146
1146
|
"deploy"
|
|
1147
1147
|
];
|
|
1148
|
+
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
1148
1149
|
function shouldSkipTemplateEntry(name) {
|
|
1149
|
-
return name === ".DS_Store" || name === "Thumbs.db";
|
|
1150
|
+
return name === ".DS_Store" || name === "Thumbs.db" || name === WEBIDE_AGENTS_TEMPLATE_NAME;
|
|
1151
|
+
}
|
|
1152
|
+
function isWebIdeRuleFileName(name) {
|
|
1153
|
+
return name.startsWith("webide");
|
|
1150
1154
|
}
|
|
1151
1155
|
function copyTemplateEntry(src, dest) {
|
|
1152
1156
|
const fsSrc = toFsPath(src);
|
|
@@ -1212,26 +1216,96 @@ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
|
1212
1216
|
}
|
|
1213
1217
|
assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
1214
1218
|
}
|
|
1219
|
+
function listWebIdeRuleFileNames(rulesDir) {
|
|
1220
|
+
const fsRulesDir = toFsPath(rulesDir);
|
|
1221
|
+
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
1222
|
+
return [];
|
|
1223
|
+
}
|
|
1224
|
+
return readdirSync(fsRulesDir).filter((name) => {
|
|
1225
|
+
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
1226
|
+
return false;
|
|
1227
|
+
}
|
|
1228
|
+
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
1232
|
+
const required = ["AGENTS.md", "apm.config.json", "rules"];
|
|
1233
|
+
for (const item of required) {
|
|
1234
|
+
const path19 = join2(apmDir, item);
|
|
1235
|
+
if (!existsSync(toFsPath(path19))) {
|
|
1236
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path19}`);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
const rulesDir = join2(apmDir, "rules");
|
|
1240
|
+
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
1241
|
+
if (ruleNames.length === 0) {
|
|
1242
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
1243
|
+
}
|
|
1244
|
+
const leakedRules = join2(workdir, "rules");
|
|
1245
|
+
const apmRules = join2(apmDir, "rules");
|
|
1246
|
+
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
1253
|
+
const resolvedTarget = resolve2(targetDir);
|
|
1254
|
+
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
1255
|
+
const fsTemplateDir = toFsPath(templateDir);
|
|
1256
|
+
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
1257
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
1258
|
+
}
|
|
1259
|
+
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
1260
|
+
if (!existsSync(toFsPath(agentsSrc))) {
|
|
1261
|
+
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
1262
|
+
}
|
|
1263
|
+
const rulesSrc = join2(templateDir, "rules");
|
|
1264
|
+
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
1265
|
+
if (ruleNames.length === 0) {
|
|
1266
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
1267
|
+
}
|
|
1268
|
+
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
1269
|
+
copyFileSync(toFsPath(agentsSrc), toFsPath(join2(resolvedTarget, "AGENTS.md")));
|
|
1270
|
+
copyTemplateEntry(
|
|
1271
|
+
join2(templateDir, "apm.config.json"),
|
|
1272
|
+
join2(resolvedTarget, "apm.config.json")
|
|
1273
|
+
);
|
|
1274
|
+
const rulesDest = join2(resolvedTarget, "rules");
|
|
1275
|
+
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
1276
|
+
for (const name of ruleNames) {
|
|
1277
|
+
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
1278
|
+
}
|
|
1279
|
+
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
1280
|
+
}
|
|
1215
1281
|
|
|
1216
1282
|
// src/commands/init.ts
|
|
1283
|
+
function applyWorkspaceName(apmDir, name) {
|
|
1284
|
+
const trimmedName = name?.trim();
|
|
1285
|
+
if (!trimmedName) return;
|
|
1286
|
+
const apmConfigPath = toFsPath(join3(apmDir, "apm.config.json"));
|
|
1287
|
+
const config = readFileSync2(apmConfigPath, "utf8");
|
|
1288
|
+
const configJson = JSON.parse(config);
|
|
1289
|
+
configJson.name = trimmedName;
|
|
1290
|
+
writeFileSync2(
|
|
1291
|
+
apmConfigPath,
|
|
1292
|
+
`${JSON.stringify(configJson, null, 2)}
|
|
1293
|
+
`,
|
|
1294
|
+
"utf8"
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1217
1297
|
async function initializeWorkspace(workdir, options) {
|
|
1218
1298
|
await ensureWorkspaceApmDirForInit(workdir);
|
|
1219
1299
|
const apmDir = workspaceApmDir(workdir);
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
const config = readFileSync2(apmConfigPath, "utf8");
|
|
1225
|
-
const configJson = JSON.parse(config);
|
|
1226
|
-
configJson.name = trimmedName;
|
|
1227
|
-
writeFileSync2(
|
|
1228
|
-
apmConfigPath,
|
|
1229
|
-
`${JSON.stringify(configJson, null, 2)}
|
|
1230
|
-
`,
|
|
1231
|
-
"utf8"
|
|
1232
|
-
);
|
|
1300
|
+
if (options?.webide) {
|
|
1301
|
+
await copyWebIdeTemplateFiles(apmDir, workdir);
|
|
1302
|
+
} else {
|
|
1303
|
+
await copyTemplateFiles(apmDir, workdir);
|
|
1233
1304
|
}
|
|
1234
|
-
|
|
1305
|
+
applyWorkspaceName(apmDir, options?.name);
|
|
1306
|
+
console.log(
|
|
1307
|
+
options?.webide ? `[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}` : `[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`
|
|
1308
|
+
);
|
|
1235
1309
|
return { didInit: true };
|
|
1236
1310
|
}
|
|
1237
1311
|
async function ensureWorkspaceInitialized(workdir, options) {
|
|
@@ -1239,13 +1313,16 @@ async function ensureWorkspaceInitialized(workdir, options) {
|
|
|
1239
1313
|
return { didInit: false };
|
|
1240
1314
|
}
|
|
1241
1315
|
console.log(
|
|
1242
|
-
`[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
1316
|
+
options?.webide ? `[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u6309 WebIDE \u81EA\u52A8\u521D\u59CB\u5316\u2026` : `[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
1243
1317
|
);
|
|
1244
1318
|
return initializeWorkspace(workdir, options);
|
|
1245
1319
|
}
|
|
1246
|
-
async function runInit(name) {
|
|
1320
|
+
async function runInit(name, options) {
|
|
1247
1321
|
const workdir = resolveWorkdirPath();
|
|
1248
|
-
await initializeWorkspace(workdir, {
|
|
1322
|
+
await initializeWorkspace(workdir, {
|
|
1323
|
+
name,
|
|
1324
|
+
webide: options?.webide === true
|
|
1325
|
+
});
|
|
1249
1326
|
console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
|
|
1250
1327
|
}
|
|
1251
1328
|
|
|
@@ -10551,8 +10628,11 @@ function buildProgram() {
|
|
|
10551
10628
|
).option("--api-key <key>", "\u5BA2\u6237\u673A API Key\uFF08cm_ \u5F00\u5934\uFF09").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u4F8B\u5982 http://127.0.0.1:3000").action(async (opts) => {
|
|
10552
10629
|
await runLogin(opts);
|
|
10553
10630
|
});
|
|
10554
|
-
program.command("init").description("\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u521B\u5EFA .apm \u5E76\u521D\u59CB\u5316\u6A21\u677F").option("--name <name>", "\u5DE5\u4F5C\u76EE\u5F55\u540D\u79F0").
|
|
10555
|
-
|
|
10631
|
+
program.command("init").description("\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u521B\u5EFA .apm \u5E76\u521D\u59CB\u5316\u6A21\u677F").option("--name <name>", "\u5DE5\u4F5C\u76EE\u5F55\u540D\u79F0").option(
|
|
10632
|
+
"--webide",
|
|
10633
|
+
"\u6309 WebIDE \u5DE5\u4F5C\u533A\u521D\u59CB\u5316\uFF1A\u4EC5 webide \u89C4\u5219\u4E0E\u6307\u5357\uFF0C\u4E0D\u542B sessions / skills / deploy"
|
|
10634
|
+
).action(async (opts) => {
|
|
10635
|
+
await runInit(opts.name, { webide: opts.webide === true });
|
|
10556
10636
|
});
|
|
10557
10637
|
program.command("update").description(
|
|
10558
10638
|
`\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5 ${CLI_PACKAGE_NAME}\uFF0C\u9ED8\u8BA4\u66F4\u65B0\u5230\u5F53\u524D\u5927\u7248\u672C\uFF08${parseMajorVersion(
|
|
@@ -659,8 +659,12 @@ var WORKSPACE_TEMPLATE_SUBDIRS = [
|
|
|
659
659
|
"rules",
|
|
660
660
|
"deploy"
|
|
661
661
|
];
|
|
662
|
+
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
662
663
|
function shouldSkipTemplateEntry(name) {
|
|
663
|
-
return name === ".DS_Store" || name === "Thumbs.db";
|
|
664
|
+
return name === ".DS_Store" || name === "Thumbs.db" || name === WEBIDE_AGENTS_TEMPLATE_NAME;
|
|
665
|
+
}
|
|
666
|
+
function isWebIdeRuleFileName(name) {
|
|
667
|
+
return name.startsWith("webide");
|
|
664
668
|
}
|
|
665
669
|
function copyTemplateEntry(src, dest) {
|
|
666
670
|
const fsSrc = toFsPath(src);
|
|
@@ -726,6 +730,68 @@ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
|
726
730
|
}
|
|
727
731
|
assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
728
732
|
}
|
|
733
|
+
function listWebIdeRuleFileNames(rulesDir) {
|
|
734
|
+
const fsRulesDir = toFsPath(rulesDir);
|
|
735
|
+
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
736
|
+
return [];
|
|
737
|
+
}
|
|
738
|
+
return readdirSync(fsRulesDir).filter((name) => {
|
|
739
|
+
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
746
|
+
const required = ["AGENTS.md", "apm.config.json", "rules"];
|
|
747
|
+
for (const item of required) {
|
|
748
|
+
const path = join2(apmDir, item);
|
|
749
|
+
if (!existsSync(toFsPath(path))) {
|
|
750
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
const rulesDir = join2(apmDir, "rules");
|
|
754
|
+
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
755
|
+
if (ruleNames.length === 0) {
|
|
756
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
757
|
+
}
|
|
758
|
+
const leakedRules = join2(workdir, "rules");
|
|
759
|
+
const apmRules = join2(apmDir, "rules");
|
|
760
|
+
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
761
|
+
throw new Error(
|
|
762
|
+
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
767
|
+
const resolvedTarget = resolve2(targetDir);
|
|
768
|
+
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
769
|
+
const fsTemplateDir = toFsPath(templateDir);
|
|
770
|
+
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
771
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
772
|
+
}
|
|
773
|
+
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
774
|
+
if (!existsSync(toFsPath(agentsSrc))) {
|
|
775
|
+
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
776
|
+
}
|
|
777
|
+
const rulesSrc = join2(templateDir, "rules");
|
|
778
|
+
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
779
|
+
if (ruleNames.length === 0) {
|
|
780
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
781
|
+
}
|
|
782
|
+
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
783
|
+
copyFileSync(toFsPath(agentsSrc), toFsPath(join2(resolvedTarget, "AGENTS.md")));
|
|
784
|
+
copyTemplateEntry(
|
|
785
|
+
join2(templateDir, "apm.config.json"),
|
|
786
|
+
join2(resolvedTarget, "apm.config.json")
|
|
787
|
+
);
|
|
788
|
+
const rulesDest = join2(resolvedTarget, "rules");
|
|
789
|
+
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
790
|
+
for (const name of ruleNames) {
|
|
791
|
+
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
792
|
+
}
|
|
793
|
+
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
794
|
+
}
|
|
729
795
|
|
|
730
796
|
// src/workspace-repos.ts
|
|
731
797
|
import {
|
|
@@ -2874,24 +2940,32 @@ function resolveMessageReplyFallback(fallback) {
|
|
|
2874
2940
|
// src/commands/init.ts
|
|
2875
2941
|
import { join as join4 } from "path";
|
|
2876
2942
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
2943
|
+
function applyWorkspaceName(apmDir, name) {
|
|
2944
|
+
const trimmedName = name?.trim();
|
|
2945
|
+
if (!trimmedName) return;
|
|
2946
|
+
const apmConfigPath = toFsPath(join4(apmDir, "apm.config.json"));
|
|
2947
|
+
const config = readFileSync5(apmConfigPath, "utf8");
|
|
2948
|
+
const configJson = JSON.parse(config);
|
|
2949
|
+
configJson.name = trimmedName;
|
|
2950
|
+
writeFileSync5(
|
|
2951
|
+
apmConfigPath,
|
|
2952
|
+
`${JSON.stringify(configJson, null, 2)}
|
|
2953
|
+
`,
|
|
2954
|
+
"utf8"
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2877
2957
|
async function initializeWorkspace(workdir, options) {
|
|
2878
2958
|
await ensureWorkspaceApmDirForInit(workdir);
|
|
2879
2959
|
const apmDir = workspaceApmDir(workdir);
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
const config = readFileSync5(apmConfigPath, "utf8");
|
|
2885
|
-
const configJson = JSON.parse(config);
|
|
2886
|
-
configJson.name = trimmedName;
|
|
2887
|
-
writeFileSync5(
|
|
2888
|
-
apmConfigPath,
|
|
2889
|
-
`${JSON.stringify(configJson, null, 2)}
|
|
2890
|
-
`,
|
|
2891
|
-
"utf8"
|
|
2892
|
-
);
|
|
2960
|
+
if (options?.webide) {
|
|
2961
|
+
await copyWebIdeTemplateFiles(apmDir, workdir);
|
|
2962
|
+
} else {
|
|
2963
|
+
await copyTemplateFiles(apmDir, workdir);
|
|
2893
2964
|
}
|
|
2894
|
-
|
|
2965
|
+
applyWorkspaceName(apmDir, options?.name);
|
|
2966
|
+
console.log(
|
|
2967
|
+
options?.webide ? `[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}` : `[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`
|
|
2968
|
+
);
|
|
2895
2969
|
return { didInit: true };
|
|
2896
2970
|
}
|
|
2897
2971
|
async function ensureWorkspaceInitialized(workdir, options) {
|
|
@@ -2899,7 +2973,7 @@ async function ensureWorkspaceInitialized(workdir, options) {
|
|
|
2899
2973
|
return { didInit: false };
|
|
2900
2974
|
}
|
|
2901
2975
|
console.log(
|
|
2902
|
-
`[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
2976
|
+
options?.webide ? `[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u6309 WebIDE \u81EA\u52A8\u521D\u59CB\u5316\u2026` : `[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
2903
2977
|
);
|
|
2904
2978
|
return initializeWorkspace(workdir, options);
|
|
2905
2979
|
}
|
|
@@ -3167,150 +3241,9 @@ function readCliVersion() {
|
|
|
3167
3241
|
}
|
|
3168
3242
|
}
|
|
3169
3243
|
|
|
3170
|
-
// src/commands/update-skills.ts
|
|
3171
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
|
|
3172
|
-
import { join as join7 } from "path";
|
|
3173
|
-
|
|
3174
|
-
// src/skills-sync.ts
|
|
3175
|
-
import {
|
|
3176
|
-
copyFileSync as copyFileSync2,
|
|
3177
|
-
cpSync,
|
|
3178
|
-
existsSync as existsSync6,
|
|
3179
|
-
mkdirSync as mkdirSync6,
|
|
3180
|
-
readdirSync as readdirSync3,
|
|
3181
|
-
rmSync as rmSync2,
|
|
3182
|
-
statSync as statSync3,
|
|
3183
|
-
writeFileSync as writeFileSync6
|
|
3184
|
-
} from "fs";
|
|
3185
|
-
import { join as join6 } from "path";
|
|
3186
|
-
var AGENTS_TEMPLATE_PATH = join6(CLI_TEMPLATE_DIR, "AGENTS.md");
|
|
3187
|
-
var BASE_SKILLS_TEMPLATE_DIR = join6(CLI_TEMPLATE_DIR, "skills");
|
|
3188
|
-
var BASE_RULES_TEMPLATE_DIR = join6(CLI_TEMPLATE_DIR, "rules");
|
|
3189
|
-
function sanitizeSkillDirName(name) {
|
|
3190
|
-
const trimmed = name.trim();
|
|
3191
|
-
if (!trimmed) return "skill";
|
|
3192
|
-
return trimmed.replace(/[/\\:*?"<>|]/g, "_");
|
|
3193
|
-
}
|
|
3194
|
-
function listBaseSkillDirNames() {
|
|
3195
|
-
if (!existsSync6(BASE_SKILLS_TEMPLATE_DIR)) return [];
|
|
3196
|
-
return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
|
|
3197
|
-
const path = join6(BASE_SKILLS_TEMPLATE_DIR, name);
|
|
3198
|
-
return statSync3(path).isDirectory();
|
|
3199
|
-
});
|
|
3200
|
-
}
|
|
3201
|
-
function syncAgentsGuide(apmDir) {
|
|
3202
|
-
if (!existsSync6(AGENTS_TEMPLATE_PATH)) return false;
|
|
3203
|
-
mkdirSync6(apmDir, { recursive: true });
|
|
3204
|
-
copyFileSync2(AGENTS_TEMPLATE_PATH, join6(apmDir, "AGENTS.md"));
|
|
3205
|
-
return true;
|
|
3206
|
-
}
|
|
3207
|
-
function listBaseRuleFileNames() {
|
|
3208
|
-
if (!existsSync6(BASE_RULES_TEMPLATE_DIR)) return [];
|
|
3209
|
-
return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
|
|
3210
|
-
const path = join6(BASE_RULES_TEMPLATE_DIR, name);
|
|
3211
|
-
return statSync3(path).isFile();
|
|
3212
|
-
});
|
|
3213
|
-
}
|
|
3214
|
-
function syncBaseRules(rulesDir) {
|
|
3215
|
-
mkdirSync6(rulesDir, { recursive: true });
|
|
3216
|
-
const names = listBaseRuleFileNames();
|
|
3217
|
-
for (const name of names) {
|
|
3218
|
-
const src = join6(BASE_RULES_TEMPLATE_DIR, name);
|
|
3219
|
-
const dest = join6(rulesDir, name);
|
|
3220
|
-
copyFileSync2(src, dest);
|
|
3221
|
-
}
|
|
3222
|
-
return names;
|
|
3223
|
-
}
|
|
3224
|
-
function syncBaseSkills(skillsDir) {
|
|
3225
|
-
mkdirSync6(skillsDir, { recursive: true });
|
|
3226
|
-
const names = listBaseSkillDirNames();
|
|
3227
|
-
for (const name of names) {
|
|
3228
|
-
const src = join6(BASE_SKILLS_TEMPLATE_DIR, name);
|
|
3229
|
-
const dest = join6(skillsDir, name);
|
|
3230
|
-
cpSync(src, dest, { recursive: true, force: true });
|
|
3231
|
-
}
|
|
3232
|
-
return names;
|
|
3233
|
-
}
|
|
3234
|
-
function syncSupplementarySkills(skillsDir, list) {
|
|
3235
|
-
const baseNames = new Set(listBaseSkillDirNames());
|
|
3236
|
-
const apiDirNames = /* @__PURE__ */ new Set();
|
|
3237
|
-
const written = [];
|
|
3238
|
-
const skipped = [];
|
|
3239
|
-
for (const skill of list) {
|
|
3240
|
-
const dirName = sanitizeSkillDirName(skill.name);
|
|
3241
|
-
apiDirNames.add(dirName);
|
|
3242
|
-
if (baseNames.has(dirName)) {
|
|
3243
|
-
skipped.push(dirName);
|
|
3244
|
-
continue;
|
|
3245
|
-
}
|
|
3246
|
-
const skillDir = join6(skillsDir, dirName);
|
|
3247
|
-
mkdirSync6(skillDir, { recursive: true });
|
|
3248
|
-
writeFileSync6(join6(skillDir, "SKILL.md"), skill.content ?? "", "utf8");
|
|
3249
|
-
written.push(dirName);
|
|
3250
|
-
}
|
|
3251
|
-
const removed = [];
|
|
3252
|
-
if (!existsSync6(skillsDir)) return { written, skipped, removed };
|
|
3253
|
-
for (const entry of readdirSync3(skillsDir)) {
|
|
3254
|
-
const full = join6(skillsDir, entry);
|
|
3255
|
-
if (!statSync3(full).isDirectory()) continue;
|
|
3256
|
-
if (baseNames.has(entry)) continue;
|
|
3257
|
-
if (apiDirNames.has(entry)) continue;
|
|
3258
|
-
rmSync2(full, { recursive: true, force: true });
|
|
3259
|
-
removed.push(entry);
|
|
3260
|
-
}
|
|
3261
|
-
return { written, skipped, removed };
|
|
3262
|
-
}
|
|
3263
|
-
|
|
3264
|
-
// src/commands/update-skills.ts
|
|
3265
|
-
async function syncWorkspaceSkills(cfg, workdir) {
|
|
3266
|
-
const apmDir = workspaceApmDir(workdir);
|
|
3267
|
-
const fsApmDir = toFsPath(apmDir);
|
|
3268
|
-
if (!existsSync7(fsApmDir)) {
|
|
3269
|
-
throw new Error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
|
|
3270
|
-
}
|
|
3271
|
-
const apmStat = statSync4(fsApmDir);
|
|
3272
|
-
if (!apmStat.isDirectory()) {
|
|
3273
|
-
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${apmDir}`);
|
|
3274
|
-
}
|
|
3275
|
-
const api = createApmApiClient(cfg);
|
|
3276
|
-
const { list } = await api.cli.listSkills({});
|
|
3277
|
-
if (syncAgentsGuide(apmDir)) {
|
|
3278
|
-
console.log("[apm] \u5DF2\u540C\u6B65 APM \u6307\u5357: .apm/AGENTS.md");
|
|
3279
|
-
}
|
|
3280
|
-
const rulesDir = join7(apmDir, "rules");
|
|
3281
|
-
const ruleNames = syncBaseRules(rulesDir);
|
|
3282
|
-
for (const name of ruleNames) {
|
|
3283
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u57FA\u7840\u89C4\u5219: rules/${name}`);
|
|
3284
|
-
}
|
|
3285
|
-
const skillsDir = join7(apmDir, "skills");
|
|
3286
|
-
mkdirSync7(toFsPath(skillsDir), { recursive: true });
|
|
3287
|
-
const baseNames = syncBaseSkills(skillsDir);
|
|
3288
|
-
for (const name of baseNames) {
|
|
3289
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u57FA\u7840\u6280\u80FD: skills/${name}/`);
|
|
3290
|
-
}
|
|
3291
|
-
const { written, skipped, removed } = syncSupplementarySkills(
|
|
3292
|
-
skillsDir,
|
|
3293
|
-
list
|
|
3294
|
-
);
|
|
3295
|
-
for (const name of written) {
|
|
3296
|
-
console.log(`[apm] \u5DF2\u5199\u5165\u8865\u5145\u6280\u80FD: skills/${name}/SKILL.md`);
|
|
3297
|
-
}
|
|
3298
|
-
for (const name of skipped) {
|
|
3299
|
-
console.log(
|
|
3300
|
-
`[apm] \u5DF2\u8DF3\u8FC7\u4E0E\u57FA\u7840\u6280\u80FD\u540C\u540D\u7684\u8865\u5145\u6280\u80FD: ${name}\uFF08\u4FDD\u7559\u6A21\u677F\u7248\u672C\uFF09`
|
|
3301
|
-
);
|
|
3302
|
-
}
|
|
3303
|
-
for (const name of removed) {
|
|
3304
|
-
console.log(`[apm] \u5DF2\u79FB\u9664\u5DF2\u4E0B\u7EBF\u7684\u8865\u5145\u6280\u80FD: skills/${name}/`);
|
|
3305
|
-
}
|
|
3306
|
-
console.log(
|
|
3307
|
-
`[apm] \u540C\u6B65\u5B8C\u6210\uFF1A${ruleNames.length} \u4E2A\u57FA\u7840\u89C4\u5219\uFF0C${baseNames.length} \u4E2A\u57FA\u7840\u6280\u80FD\uFF0C${written.length} \u4E2A\u8865\u5145\u6280\u80FD`
|
|
3308
|
-
);
|
|
3309
|
-
}
|
|
3310
|
-
|
|
3311
3244
|
// src/commands/sync-session-attachments.ts
|
|
3312
|
-
import { existsSync as
|
|
3313
|
-
import { join as
|
|
3245
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
3246
|
+
import { join as join6 } from "path";
|
|
3314
3247
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
3315
3248
|
async function downloadAttachment(cfg, attachmentId) {
|
|
3316
3249
|
const base = cfg.baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -3326,8 +3259,8 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
3326
3259
|
return Buffer.from(await res.arrayBuffer());
|
|
3327
3260
|
}
|
|
3328
3261
|
function loadManifest(dir) {
|
|
3329
|
-
const path =
|
|
3330
|
-
if (!
|
|
3262
|
+
const path = join6(dir, MANIFEST_FILE);
|
|
3263
|
+
if (!existsSync6(path)) {
|
|
3331
3264
|
return { version: 1, attachments: {} };
|
|
3332
3265
|
}
|
|
3333
3266
|
try {
|
|
@@ -3342,15 +3275,15 @@ function loadManifest(dir) {
|
|
|
3342
3275
|
return { version: 1, attachments: {} };
|
|
3343
3276
|
}
|
|
3344
3277
|
function saveManifest(dir, manifest) {
|
|
3345
|
-
|
|
3346
|
-
|
|
3278
|
+
writeFileSync6(
|
|
3279
|
+
join6(dir, MANIFEST_FILE),
|
|
3347
3280
|
`${JSON.stringify(manifest, null, 2)}
|
|
3348
3281
|
`,
|
|
3349
3282
|
"utf8"
|
|
3350
3283
|
);
|
|
3351
3284
|
}
|
|
3352
3285
|
function isAttachmentUpToDate(entry, item, dest) {
|
|
3353
|
-
if (!entry || !
|
|
3286
|
+
if (!entry || !existsSync6(dest)) return false;
|
|
3354
3287
|
if (entry.name !== item.name) return false;
|
|
3355
3288
|
const createdAt = item.createdAt ?? "";
|
|
3356
3289
|
return entry.createdAt === createdAt;
|
|
@@ -3365,7 +3298,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3365
3298
|
const nextManifest = { version: 1, attachments: {} };
|
|
3366
3299
|
const names = [];
|
|
3367
3300
|
for (const item of attachments) {
|
|
3368
|
-
const dest =
|
|
3301
|
+
const dest = join6(dir, item.name);
|
|
3369
3302
|
const entry = manifest.attachments[item.id];
|
|
3370
3303
|
const createdAt = item.createdAt ?? "";
|
|
3371
3304
|
names.push(item.name);
|
|
@@ -3375,7 +3308,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3375
3308
|
continue;
|
|
3376
3309
|
}
|
|
3377
3310
|
const buffer = await downloadAttachment(cfg, item.id);
|
|
3378
|
-
|
|
3311
|
+
writeFileSync6(dest, buffer);
|
|
3379
3312
|
nextManifest.attachments[item.id] = {
|
|
3380
3313
|
name: item.name,
|
|
3381
3314
|
createdAt
|
|
@@ -3397,14 +3330,14 @@ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
|
|
|
3397
3330
|
|
|
3398
3331
|
// src/project-documents-sync.ts
|
|
3399
3332
|
import {
|
|
3400
|
-
existsSync as
|
|
3401
|
-
readdirSync as
|
|
3333
|
+
existsSync as existsSync7,
|
|
3334
|
+
readdirSync as readdirSync3,
|
|
3402
3335
|
readFileSync as readFileSync8,
|
|
3403
|
-
rmSync as
|
|
3404
|
-
writeFileSync as
|
|
3336
|
+
rmSync as rmSync2,
|
|
3337
|
+
writeFileSync as writeFileSync7
|
|
3405
3338
|
} from "fs";
|
|
3406
3339
|
import { createHash } from "crypto";
|
|
3407
|
-
import { dirname as dirname6, join as
|
|
3340
|
+
import { dirname as dirname6, join as join7, relative as relative2, sep } from "path";
|
|
3408
3341
|
var MANIFEST_FILE2 = "manifest.json";
|
|
3409
3342
|
function normalizeProjectIdForPath(projectId) {
|
|
3410
3343
|
const id = projectId.trim();
|
|
@@ -3418,11 +3351,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
3418
3351
|
}
|
|
3419
3352
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
3420
3353
|
const id = normalizeProjectIdForPath(projectId);
|
|
3421
|
-
return
|
|
3354
|
+
return join7(apmRoot ?? workspaceApmDir(), "project", id);
|
|
3422
3355
|
}
|
|
3423
3356
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
3424
3357
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
3425
|
-
return
|
|
3358
|
+
return join7(
|
|
3426
3359
|
projectDocumentsDir(apmRoot, projectId),
|
|
3427
3360
|
...normalized.split("/")
|
|
3428
3361
|
);
|
|
@@ -3442,11 +3375,11 @@ function hashLocalFileContent(content) {
|
|
|
3442
3375
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
3443
3376
|
}
|
|
3444
3377
|
function readLocalManifest(apmRoot, projectId) {
|
|
3445
|
-
const manifestPath3 =
|
|
3378
|
+
const manifestPath3 = join7(
|
|
3446
3379
|
projectDocumentsDir(apmRoot, projectId),
|
|
3447
3380
|
MANIFEST_FILE2
|
|
3448
3381
|
);
|
|
3449
|
-
if (!
|
|
3382
|
+
if (!existsSync7(manifestPath3)) {
|
|
3450
3383
|
return null;
|
|
3451
3384
|
}
|
|
3452
3385
|
try {
|
|
@@ -3459,13 +3392,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
3459
3392
|
}
|
|
3460
3393
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
3461
3394
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
3462
|
-
if (!
|
|
3395
|
+
if (!existsSync7(root)) {
|
|
3463
3396
|
return [];
|
|
3464
3397
|
}
|
|
3465
3398
|
const paths = [];
|
|
3466
3399
|
const walk = (dir) => {
|
|
3467
|
-
for (const entry of
|
|
3468
|
-
const abs =
|
|
3400
|
+
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
3401
|
+
const abs = join7(dir, entry.name);
|
|
3469
3402
|
if (entry.isDirectory()) {
|
|
3470
3403
|
walk(abs);
|
|
3471
3404
|
continue;
|
|
@@ -3584,7 +3517,7 @@ ${diagnostic ?? ""}`);
|
|
|
3584
3517
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
3585
3518
|
);
|
|
3586
3519
|
await ensureDirExists(dirname6(absPath));
|
|
3587
|
-
|
|
3520
|
+
writeFileSync7(absPath, doc.content, "utf8");
|
|
3588
3521
|
downloaded += 1;
|
|
3589
3522
|
}
|
|
3590
3523
|
}
|
|
@@ -3593,13 +3526,13 @@ ${diagnostic ?? ""}`);
|
|
|
3593
3526
|
const absPath = toFsPath(
|
|
3594
3527
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
3595
3528
|
);
|
|
3596
|
-
if (
|
|
3597
|
-
|
|
3529
|
+
if (existsSync7(absPath)) {
|
|
3530
|
+
rmSync2(absPath, { force: true });
|
|
3598
3531
|
deleted += 1;
|
|
3599
3532
|
}
|
|
3600
3533
|
}
|
|
3601
|
-
|
|
3602
|
-
toFsPath(
|
|
3534
|
+
writeFileSync7(
|
|
3535
|
+
toFsPath(join7(docsDir, MANIFEST_FILE2)),
|
|
3603
3536
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
3604
3537
|
`,
|
|
3605
3538
|
"utf8"
|
|
@@ -3663,15 +3596,15 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3663
3596
|
}
|
|
3664
3597
|
|
|
3665
3598
|
// src/commands/connect/cli-version-sync.ts
|
|
3666
|
-
import { existsSync as
|
|
3667
|
-
import { join as
|
|
3599
|
+
import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
3600
|
+
import { join as join8 } from "path";
|
|
3668
3601
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3669
3602
|
function manifestPath2(apmDir) {
|
|
3670
|
-
return
|
|
3603
|
+
return join8(apmDir, CLI_VERSION_FILE);
|
|
3671
3604
|
}
|
|
3672
3605
|
function loadManifest2(apmDir) {
|
|
3673
3606
|
const path = toFsPath(manifestPath2(apmDir));
|
|
3674
|
-
if (!
|
|
3607
|
+
if (!existsSync8(path)) {
|
|
3675
3608
|
return null;
|
|
3676
3609
|
}
|
|
3677
3610
|
try {
|
|
@@ -3687,7 +3620,7 @@ function loadManifest2(apmDir) {
|
|
|
3687
3620
|
}
|
|
3688
3621
|
function saveManifest2(apmDir, cliVersion) {
|
|
3689
3622
|
const manifest = { version: 1, cliVersion };
|
|
3690
|
-
|
|
3623
|
+
writeFileSync8(
|
|
3691
3624
|
toFsPath(manifestPath2(apmDir)),
|
|
3692
3625
|
`${JSON.stringify(manifest, null, 2)}
|
|
3693
3626
|
`,
|
|
@@ -3793,7 +3726,9 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3793
3726
|
await runPrepStep(
|
|
3794
3727
|
"\u521D\u59CB\u5316\u5DE5\u4F5C\u533A",
|
|
3795
3728
|
async () => {
|
|
3796
|
-
const { didInit } = await ensureWorkspaceInitialized(workdir
|
|
3729
|
+
const { didInit } = await ensureWorkspaceInitialized(workdir, {
|
|
3730
|
+
webide: true
|
|
3731
|
+
});
|
|
3797
3732
|
return didInit;
|
|
3798
3733
|
},
|
|
3799
3734
|
(didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
|
|
@@ -3802,9 +3737,9 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3802
3737
|
if (shouldSyncSkillsForCliVersion(workdir, cliVersion)) {
|
|
3803
3738
|
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3804
3739
|
await runPrepStep(
|
|
3805
|
-
"\u540C\u6B65
|
|
3740
|
+
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
3806
3741
|
async () => {
|
|
3807
|
-
await
|
|
3742
|
+
await copyWebIdeTemplateFiles(workspaceApmDir(workdir), workdir);
|
|
3808
3743
|
markSkillsSyncedForCliVersion(workdir, cliVersion);
|
|
3809
3744
|
return cliVersion;
|
|
3810
3745
|
},
|
|
@@ -3812,7 +3747,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3812
3747
|
);
|
|
3813
3748
|
} else {
|
|
3814
3749
|
eventSession.addCliStep(
|
|
3815
|
-
"\u540C\u6B65
|
|
3750
|
+
"\u540C\u6B65 WebIDE \u89C4\u5219",
|
|
3816
3751
|
`\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
|
|
3817
3752
|
"skip"
|
|
3818
3753
|
);
|
package/package.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## WebIDE 指南
|
|
2
|
+
|
|
3
|
+
你正在 WebIDE 工作区中处理任务。本轮要做什么以 prompt 里的 `action` 为准;先 Read 本文件和对应规则,再动手。
|
|
4
|
+
|
|
5
|
+
### 工作原则
|
|
6
|
+
|
|
7
|
+
1. **用户可见内容只走 `AppendMessage`**:进展、评估、改动说明、错误原因、下一步等,一律用 `AppendMessage` 写入(可多次追加)。细则见 `.apm/rules/webide_reply.md`。
|
|
8
|
+
2. **最终自然语言收尾极简**:最多 1 句状态确认(如「本轮已完成」)。禁止复述、扩写或总结 `AppendMessage` 已写内容。
|
|
9
|
+
3. **按本轮 `action` 执行**:不要自行跳阶段;未接到开发指令时不要改代码、不要写计划文档。
|
|
10
|
+
4. 文件读写、搜索与 Shell 必须限制在当前工作区 cwd 内。
|
|
11
|
+
|
|
12
|
+
### 规则(`.apm/rules/`,按需 Read,不要一次读完)
|
|
13
|
+
|
|
14
|
+
- `webide_reply.md`:输出通道(每轮必守)
|
|
15
|
+
- `webide_git_commit.md`:开发 / 修码时的 Git 提交与 push
|
|
16
|
+
- `webide_sql_change.md`:有表结构或 SQL 变更时,须在 `AppendMessage` 中醒目提示
|
|
17
|
+
- `webide_terminal.md`:本地 dev 必须用 WebIDE 终端工具,禁止用 Shell 起长驻进程
|
|
18
|
+
- `webide_testcase.md`:生成测试用例并调用 `UpsertWebIdeTestCases`
|
|
19
|
+
- `webide_merge.md`:验收通过后调用 `MergeWebIdePullRequests`
|
|
20
|
+
|
|
21
|
+
### 目录
|
|
22
|
+
|
|
23
|
+
- 项目文档:`.apm/project/<项目ID>/`(索引 `manifest.json`;部署 / 本地 dev 命令以 `deploy.md` 为准,禁止猜测)
|
|
24
|
+
- 任务附件:`.apm/webide/<taskId>/attachments/`(prompt 出现「任务附件」时按路径查看)
|
|
25
|
+
- 仓库清单:`.apm/workspace-repos.json`(先确认单仓 / 多仓;多仓必须写清改动范围并点名仓库)
|
|
26
|
+
|
|
27
|
+
计划、用例、终端、合并 PR 均走 WebIDE 专用工具(`AskQuestion`、`RecommendPlan`、`UpsertWebIdePlan`、`UpsertWebIdeTestCases`、`StartWebIdeTerminal`、`MergeWebIdePullRequests` 等)。
|