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 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
- await copyTemplateFiles(apmDir, workdir);
1221
- const trimmedName = options?.name?.trim();
1222
- if (trimmedName) {
1223
- const apmConfigPath = toFsPath(join3(apmDir, "apm.config.json"));
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
- console.log(`[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
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, { name });
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").action(async (opts) => {
10555
- await runInit(opts.name);
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
- await copyTemplateFiles(apmDir, workdir);
2881
- const trimmedName = options?.name?.trim();
2882
- if (trimmedName) {
2883
- const apmConfigPath = toFsPath(join4(apmDir, "apm.config.json"));
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
- console.log(`[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
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 existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
3313
- import { join as join8 } from "path";
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 = join8(dir, MANIFEST_FILE);
3330
- if (!existsSync8(path)) {
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
- writeFileSync7(
3346
- join8(dir, MANIFEST_FILE),
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 || !existsSync8(dest)) return false;
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 = join8(dir, item.name);
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
- writeFileSync7(dest, buffer);
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 existsSync9,
3401
- readdirSync as readdirSync4,
3333
+ existsSync as existsSync7,
3334
+ readdirSync as readdirSync3,
3402
3335
  readFileSync as readFileSync8,
3403
- rmSync as rmSync3,
3404
- writeFileSync as writeFileSync8
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 join9, relative as relative2, sep } from "path";
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 join9(apmRoot ?? workspaceApmDir(), "project", id);
3354
+ return join7(apmRoot ?? workspaceApmDir(), "project", id);
3422
3355
  }
3423
3356
  function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
3424
3357
  const normalized = normalizeLocalDocumentPath(documentPath);
3425
- return join9(
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 = join9(
3378
+ const manifestPath3 = join7(
3446
3379
  projectDocumentsDir(apmRoot, projectId),
3447
3380
  MANIFEST_FILE2
3448
3381
  );
3449
- if (!existsSync9(manifestPath3)) {
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 (!existsSync9(root)) {
3395
+ if (!existsSync7(root)) {
3463
3396
  return [];
3464
3397
  }
3465
3398
  const paths = [];
3466
3399
  const walk = (dir) => {
3467
- for (const entry of readdirSync4(dir, { withFileTypes: true })) {
3468
- const abs = join9(dir, entry.name);
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
- writeFileSync8(absPath, doc.content, "utf8");
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 (existsSync9(absPath)) {
3597
- rmSync3(absPath, { force: true });
3529
+ if (existsSync7(absPath)) {
3530
+ rmSync2(absPath, { force: true });
3598
3531
  deleted += 1;
3599
3532
  }
3600
3533
  }
3601
- writeFileSync8(
3602
- toFsPath(join9(docsDir, MANIFEST_FILE2)),
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 existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
3667
- import { join as join10 } from "path";
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 join10(apmDir, CLI_VERSION_FILE);
3603
+ return join8(apmDir, CLI_VERSION_FILE);
3671
3604
  }
3672
3605
  function loadManifest2(apmDir) {
3673
3606
  const path = toFsPath(manifestPath2(apmDir));
3674
- if (!existsSync10(path)) {
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
- writeFileSync9(
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 Skills",
3740
+ "\u540C\u6B65 WebIDE \u89C4\u5219",
3806
3741
  async () => {
3807
- await syncWorkspaceSkills(cfg, workdir);
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 Skills",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.38",
3
+ "version": "7.1.39",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -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` 等)。