ai-project-manage-cli 6.0.36 → 6.0.38

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
@@ -84,13 +84,55 @@ import { join as join3 } from "path";
84
84
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
85
85
 
86
86
  // src/command-utils.ts
87
- import { cpSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
88
- import { basename, dirname, extname, join as join2, resolve } from "path";
87
+ import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
88
+ import { basename, dirname, extname, join as join2, resolve as resolve2 } from "path";
89
89
  import { fileURLToPath } from "url";
90
+
91
+ // src/workdir-path.ts
92
+ import { realpathSync } from "fs";
93
+ import { platform } from "os";
94
+ import { resolve } from "path";
95
+ function toFsPath(inputPath) {
96
+ const absolute = resolve(inputPath);
97
+ if (platform() !== "win32") return absolute;
98
+ if (absolute.startsWith("\\\\?\\")) return absolute;
99
+ const normalized = absolute.replace(/\//g, "\\");
100
+ if (normalized.startsWith("\\\\")) {
101
+ return `\\\\?\\UNC\\${normalized.slice(2)}`;
102
+ }
103
+ return `\\\\?\\${normalized}`;
104
+ }
105
+ function normalizeWorkdirPath(path10) {
106
+ let normalized = path10.trim().replace(/\\/g, "/").normalize("NFC");
107
+ if (normalized.startsWith("//?/")) {
108
+ normalized = normalized.slice(4);
109
+ }
110
+ const windowsDrive = /^([A-Za-z]:)\/*(.*)$/.exec(normalized);
111
+ if (windowsDrive) {
112
+ const drive = windowsDrive[1].toLowerCase();
113
+ const rest = windowsDrive[2].replace(/\/+/g, "/").replace(/\/$/, "");
114
+ return rest ? `${drive}/${rest}` : drive;
115
+ }
116
+ normalized = normalized.replace(/\/+/g, "/");
117
+ if (normalized.length > 1 && normalized.endsWith("/")) {
118
+ normalized = normalized.slice(0, -1);
119
+ }
120
+ return normalized;
121
+ }
122
+ function resolveWorkdirPath(cwd = process.cwd()) {
123
+ const absolute = resolve(cwd);
124
+ try {
125
+ return normalizeWorkdirPath(realpathSync.native(absolute));
126
+ } catch {
127
+ return normalizeWorkdirPath(absolute);
128
+ }
129
+ }
130
+
131
+ // src/command-utils.ts
90
132
  var __dirname = dirname(fileURLToPath(import.meta.url));
91
- var CLI_TEMPLATE_DIR = resolve(__dirname, "../template");
92
- function workspaceApmDir(cwd = process.cwd()) {
93
- return resolve(cwd, ".apm");
133
+ var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
134
+ function workspaceApmDir(cwd = resolveWorkdirPath()) {
135
+ return resolve2(resolve2(cwd), ".apm");
94
136
  }
95
137
  var SESSIONS_SUBDIR = "sessions";
96
138
  var SESSION_DOCS_SUBDIR = "docs";
@@ -147,51 +189,119 @@ async function ensureLoggedConfig() {
147
189
  async function ensureDirExists(dir) {
148
190
  mkdirSync2(dir, { recursive: true });
149
191
  }
150
- async function ensureWorkspaceApmDirForInit() {
151
- const dir = workspaceApmDir();
152
- if (!existsSync(dir)) {
153
- mkdirSync2(dir, { recursive: true });
192
+ async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
193
+ const dir = workspaceApmDir(cwd);
194
+ const fsDir = toFsPath(dir);
195
+ if (!existsSync(fsDir)) {
196
+ mkdirSync2(fsDir, { recursive: true });
154
197
  return;
155
198
  }
156
- const st = statSync(dir);
199
+ const st = statSync(fsDir);
157
200
  if (!st.isDirectory()) {
158
201
  throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
159
202
  }
160
- if (readdirSync(dir).length > 0) {
203
+ if (readdirSync(fsDir).length > 0) {
161
204
  throw new Error(
162
205
  "[apm] .apm \u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A\uFF0C\u8BF7\u5148\u5907\u4EFD\u3001\u6E05\u7A7A\u6216\u5220\u9664\u540E\u518D\u6267\u884C init"
163
206
  );
164
207
  }
165
208
  }
166
- async function copyTemplateFiles(targetDir) {
167
- try {
168
- const dirStat = statSync(CLI_TEMPLATE_DIR);
169
- if (!dirStat.isDirectory()) return;
170
- } catch {
209
+ var WORKSPACE_TEMPLATE_SUBDIRS = [
210
+ "sessions",
211
+ "skills",
212
+ "rules",
213
+ "deploy"
214
+ ];
215
+ function shouldSkipTemplateEntry(name) {
216
+ return name === ".DS_Store" || name === "Thumbs.db";
217
+ }
218
+ function copyTemplateEntry(src, dest) {
219
+ const fsSrc = toFsPath(src);
220
+ const fsDest = toFsPath(dest);
221
+ const st = statSync(fsSrc);
222
+ if (st.isDirectory()) {
223
+ mkdirSync2(fsDest, { recursive: true });
224
+ for (const name of readdirSync(fsSrc)) {
225
+ if (shouldSkipTemplateEntry(name)) continue;
226
+ copyTemplateEntry(join2(src, name), join2(dest, name));
227
+ }
171
228
  return;
172
229
  }
173
- const entries = readdirSync(CLI_TEMPLATE_DIR);
174
- await Promise.all(
175
- entries.map(async (name) => {
176
- const src = join2(CLI_TEMPLATE_DIR, name);
177
- const dest = join2(targetDir, name);
178
- cpSync(src, dest, { recursive: true, force: false });
179
- })
230
+ if (!st.isFile()) return;
231
+ mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
232
+ copyFileSync(fsSrc, fsDest);
233
+ }
234
+ function assertTemplateCopiedToApm(apmDir, workdir) {
235
+ const required = [
236
+ "AGENTS.md",
237
+ "apm.config.json",
238
+ "rules",
239
+ "skills",
240
+ "sessions"
241
+ ];
242
+ for (const item of required) {
243
+ const path10 = join2(apmDir, item);
244
+ if (!existsSync(toFsPath(path10))) {
245
+ throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path10}`);
246
+ }
247
+ }
248
+ const leakedRules = join2(workdir, "rules");
249
+ const apmRules = join2(apmDir, "rules");
250
+ if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "reply.md")))) {
251
+ throw new Error(
252
+ `[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
253
+ );
254
+ }
255
+ }
256
+ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
257
+ const resolvedTarget = resolve2(targetDir);
258
+ const templateDir = resolve2(CLI_TEMPLATE_DIR);
259
+ const fsTemplateDir = toFsPath(templateDir);
260
+ if (!existsSync(fsTemplateDir)) {
261
+ throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
262
+ }
263
+ const dirStat = statSync(fsTemplateDir);
264
+ if (!dirStat.isDirectory()) {
265
+ throw new Error(`[apm] CLI \u6A21\u677F\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${templateDir}`);
266
+ }
267
+ const entries = readdirSync(fsTemplateDir).filter(
268
+ (name) => !shouldSkipTemplateEntry(name)
180
269
  );
270
+ if (entries.length === 0) {
271
+ throw new Error(`[apm] CLI \u6A21\u677F\u76EE\u5F55\u4E3A\u7A7A: ${templateDir}`);
272
+ }
273
+ mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
274
+ for (const name of entries) {
275
+ copyTemplateEntry(join2(templateDir, name), join2(resolvedTarget, name));
276
+ }
277
+ for (const subdir of WORKSPACE_TEMPLATE_SUBDIRS) {
278
+ mkdirSync2(toFsPath(join2(resolvedTarget, subdir)), { recursive: true });
279
+ }
280
+ assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
181
281
  }
182
282
 
183
283
  // src/commands/init.ts
184
284
  async function runInit(name) {
185
- await ensureWorkspaceApmDirForInit();
186
- const apmDir = workspaceApmDir();
187
- await copyTemplateFiles(apmDir);
188
- if (name) {
189
- const apmConfigPath = join3(apmDir, "apm.config.json");
285
+ const workdir = resolveWorkdirPath();
286
+ await ensureWorkspaceApmDirForInit(workdir);
287
+ const apmDir = workspaceApmDir(workdir);
288
+ await copyTemplateFiles(apmDir, workdir);
289
+ const trimmedName = name?.trim();
290
+ if (trimmedName) {
291
+ const apmConfigPath = toFsPath(join3(apmDir, "apm.config.json"));
190
292
  const config = readFileSync2(apmConfigPath, "utf8");
191
293
  const configJson = JSON.parse(config);
192
- configJson.name = name;
193
- writeFileSync2(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
294
+ configJson.name = trimmedName;
295
+ writeFileSync2(
296
+ apmConfigPath,
297
+ `${JSON.stringify(configJson, null, 2)}
298
+ `,
299
+ "utf8"
300
+ );
194
301
  }
302
+ console.log(`[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
303
+ console.log(`[apm] \u5DE5\u4F5C\u76EE\u5F55\u8DEF\u5F84\uFF1A${workdir}`);
304
+ console.log("[apm] \u8BF7\u5728\u5E73\u53F0\u300C\u5BA2\u6237\u673A\u7BA1\u7406 \u2192 \u5DE5\u4F5C\u7A7A\u95F4\u300D\u767B\u8BB0\u4E0A\u8FF0\u76EE\u5F55\u8DEF\u5F84");
195
305
  }
196
306
 
197
307
  // src/commands/login.ts
@@ -328,7 +438,6 @@ async function runLogin(opts) {
328
438
 
329
439
  // src/commands/branch.ts
330
440
  import { execFile } from "child_process";
331
- import { resolve as resolve2 } from "path";
332
441
  import { promisify } from "util";
333
442
  var execFileAsync = promisify(execFile);
334
443
  function branchNameForSession(sessionId) {
@@ -476,7 +585,7 @@ async function runBranch(sessionId, options = {}) {
476
585
  const cfg = await ensureLoggedConfig();
477
586
  const api = createApmApiClient(cfg);
478
587
  const cwd = options.cwd ?? process.cwd();
479
- const workdirPath = resolve2(cwd);
588
+ const workdirPath = resolveWorkdirPath(cwd);
480
589
  const baseline = await api.cli.branchBaseline({
481
590
  sessionId: trimmedSessionId,
482
591
  workdirPath
@@ -755,8 +864,8 @@ import { join as join8 } from "path";
755
864
 
756
865
  // src/skills-sync.ts
757
866
  import {
758
- copyFileSync,
759
- cpSync as cpSync2,
867
+ copyFileSync as copyFileSync2,
868
+ cpSync,
760
869
  existsSync as existsSync3,
761
870
  mkdirSync as mkdirSync3,
762
871
  readdirSync as readdirSync2,
@@ -783,7 +892,7 @@ function listBaseSkillDirNames() {
783
892
  function syncAgentsGuide(apmDir) {
784
893
  if (!existsSync3(AGENTS_TEMPLATE_PATH)) return false;
785
894
  mkdirSync3(apmDir, { recursive: true });
786
- copyFileSync(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
895
+ copyFileSync2(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
787
896
  return true;
788
897
  }
789
898
  function listBaseRuleFileNames() {
@@ -799,7 +908,7 @@ function syncBaseRules(rulesDir) {
799
908
  for (const name of names) {
800
909
  const src = join7(BASE_RULES_TEMPLATE_DIR, name);
801
910
  const dest = join7(rulesDir, name);
802
- copyFileSync(src, dest);
911
+ copyFileSync2(src, dest);
803
912
  }
804
913
  return names;
805
914
  }
@@ -809,7 +918,7 @@ function syncBaseSkills(skillsDir) {
809
918
  for (const name of names) {
810
919
  const src = join7(BASE_SKILLS_TEMPLATE_DIR, name);
811
920
  const dest = join7(skillsDir, name);
812
- cpSync2(src, dest, { recursive: true, force: true });
921
+ cpSync(src, dest, { recursive: true, force: true });
813
922
  }
814
923
  return names;
815
924
  }
@@ -2306,7 +2415,7 @@ function assertDeployImageTag(tag) {
2306
2415
  }
2307
2416
 
2308
2417
  // src/commands/deploy/internal/backend-deploy/local-docker-build.ts
2309
- import { platform } from "node:os";
2418
+ import { platform as platform2 } from "node:os";
2310
2419
 
2311
2420
  // src/commands/deploy/internal/backend-deploy/command-runner.ts
2312
2421
  import { execSync } from "child_process";
@@ -2366,7 +2475,7 @@ var CommandRunner = class {
2366
2475
 
2367
2476
  // src/commands/deploy/internal/backend-deploy/local-docker-build.ts
2368
2477
  function dockerBuildPlatformFlags() {
2369
- return platform() === "darwin" ? ["--platform", "linux/amd64"] : [];
2478
+ return platform2() === "darwin" ? ["--platform", "linux/amd64"] : [];
2370
2479
  }
2371
2480
  function buildDockerImageLocally(params, cwd) {
2372
2481
  const platformFlags = dockerBuildPlatformFlags();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.36",
3
+ "version": "6.0.38",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -1,3 +1,3 @@
1
1
  {
2
2
  "name": ""
3
- }
3
+ }
@@ -0,0 +1,15 @@
1
+ ## 前端部署
2
+
3
+ 部署测试环境: `npm run deploy:test`
4
+ 部署线上环境: `npm run deploy:online`
5
+
6
+ ## 后端部署(不区分正式环境和测试环境)
7
+ `python scripts/deploy.py`
8
+
9
+ ## 前端产物下载地址
10
+
11
+ http://<服务器地址>/dist.zip
12
+ http://<服务器地址>/backend_update_jar.zip
13
+
14
+ ## 测试地址
15
+ http://<测试环境>
File without changes