ai-project-manage-cli 7.1.17 → 7.1.18

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.
@@ -342,6 +342,36 @@ function requireRemoteWorkdir(workdir) {
342
342
  import { execFile } from "child_process";
343
343
  import { promisify } from "util";
344
344
  var execFileAsync = promisify(execFile);
345
+ function toHttpsGitRemoteUrl(raw) {
346
+ let s = raw.trim();
347
+ if (!s) return null;
348
+ const sshScp = /^git@([^:]+):(.+)$/.exec(s);
349
+ if (sshScp) {
350
+ s = `https://${sshScp[1]}/${sshScp[2]}`;
351
+ } else {
352
+ const sshUri = /^ssh:\/\/(?:git@)?([^/]+)\/(.+)$/i.exec(s);
353
+ if (sshUri) {
354
+ s = `https://${sshUri[1]}/${sshUri[2]}`;
355
+ } else if (/^http:\/\//i.test(s)) {
356
+ s = `https://${s.slice("http://".length)}`;
357
+ } else if (!/^https:\/\//i.test(s)) {
358
+ const scpLike = /^([^/:]+):(.+)$/.exec(s);
359
+ if (scpLike && !scpLike[1].includes(".")) {
360
+ return null;
361
+ }
362
+ if (scpLike) {
363
+ s = `https://${scpLike[1]}/${scpLike[2]}`;
364
+ } else if (s.includes("/")) {
365
+ s = `https://${s}`;
366
+ } else {
367
+ return null;
368
+ }
369
+ }
370
+ }
371
+ s = s.replace(/\/+$/, "");
372
+ if (!/^https:\/\//i.test(s)) return null;
373
+ return s;
374
+ }
345
375
  async function tryReadGitOriginUrl(cwd) {
346
376
  try {
347
377
  const { stdout } = await execFileAsync(
@@ -355,6 +385,11 @@ async function tryReadGitOriginUrl(cwd) {
355
385
  return null;
356
386
  }
357
387
  }
388
+ async function tryReadHttpsGitOriginUrl(cwd) {
389
+ const raw = await tryReadGitOriginUrl(cwd);
390
+ if (!raw) return null;
391
+ return toHttpsGitRemoteUrl(raw);
392
+ }
358
393
 
359
394
  // src/git-utils.ts
360
395
  import { execFile as execFile2 } from "child_process";
@@ -718,7 +753,7 @@ import {
718
753
  statSync as statSync2,
719
754
  writeFileSync as writeFileSync3
720
755
  } from "fs";
721
- import { basename as basename2, join as join3, relative, resolve as resolve3 } from "path";
756
+ import { basename as basename2, dirname as dirname2, join as join3, relative, resolve as resolve3 } from "path";
722
757
  var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
723
758
  var WORKSPACE_REPOS_VERSION = 1;
724
759
  var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([".apm", "node_modules"]);
@@ -743,6 +778,20 @@ function toRelativeRepoPath(workdir, repoAbs) {
743
778
  const rel = relative(workdir, repoAbs).replace(/\\/g, "/");
744
779
  return rel === "" ? "." : rel;
745
780
  }
781
+ function normalizeRepoEntry(raw) {
782
+ if (!raw || typeof raw !== "object") return null;
783
+ const o = raw;
784
+ if (typeof o.path !== "string" || !o.path.trim()) return null;
785
+ const entry = {
786
+ path: o.path.trim().replace(/\\/g, "/")
787
+ };
788
+ if (typeof o.remoteUrl === "string" && o.remoteUrl.trim()) {
789
+ entry.remoteUrl = o.remoteUrl.trim();
790
+ } else if (o.remoteUrl === null) {
791
+ entry.remoteUrl = null;
792
+ }
793
+ return entry;
794
+ }
746
795
  function readManifest(workdir) {
747
796
  const path = toFsPath(manifestPath(workdir));
748
797
  if (!existsSync2(path)) {
@@ -764,7 +813,17 @@ function readManifest(workdir) {
764
813
  if (typeof raw.workdir !== "string" || !raw.workdir.trim()) {
765
814
  return null;
766
815
  }
767
- return raw;
816
+ const repos = raw.repos.map((item) => normalizeRepoEntry(item)).filter((item) => item != null);
817
+ if (repos.length === 0) {
818
+ return null;
819
+ }
820
+ return {
821
+ version: WORKSPACE_REPOS_VERSION,
822
+ kind: raw.kind,
823
+ workdir: raw.workdir,
824
+ repos,
825
+ scannedAt: typeof raw.scannedAt === "string" && raw.scannedAt.trim() ? raw.scannedAt : (/* @__PURE__ */ new Date()).toISOString()
826
+ };
768
827
  } catch {
769
828
  return null;
770
829
  }
@@ -859,6 +918,31 @@ function loadWorkspaceReposCache(workdirInput) {
859
918
  workdir
860
919
  };
861
920
  }
921
+ async function enrichWorkspaceReposRemoteUrls(manifest) {
922
+ let changed = false;
923
+ const repos = [];
924
+ for (const entry of manifest.repos) {
925
+ const abs = absoluteRepoPath(manifest.workdir, entry);
926
+ const remoteUrl = await tryReadHttpsGitOriginUrl(abs);
927
+ const next = {
928
+ path: entry.path,
929
+ remoteUrl: remoteUrl || null
930
+ };
931
+ if ((entry.remoteUrl ?? null) !== next.remoteUrl) {
932
+ changed = true;
933
+ }
934
+ repos.push(next);
935
+ }
936
+ const nextManifest = {
937
+ ...manifest,
938
+ repos,
939
+ scannedAt: changed ? (/* @__PURE__ */ new Date()).toISOString() : manifest.scannedAt
940
+ };
941
+ if (changed) {
942
+ writeManifest(manifest.workdir, nextManifest);
943
+ }
944
+ return nextManifest;
945
+ }
862
946
  function resolveWorkspaceRepos(workdirInput, options) {
863
947
  const workdir = resolveWorkdirPath(workdirInput);
864
948
  if (!options?.forceRescan) {
@@ -871,6 +955,15 @@ function resolveWorkspaceRepos(workdirInput, options) {
871
955
  }
872
956
  }
873
957
  const scanned = scanWorkspaceRepos(workdir);
958
+ const previous = readManifest(workdir);
959
+ if (previous) {
960
+ const prevByPath = new Map(previous.repos.map((r) => [r.path, r]));
961
+ scanned.repos = scanned.repos.map((entry) => {
962
+ const old = prevByPath.get(entry.path);
963
+ if (!old?.remoteUrl) return entry;
964
+ return { ...entry, remoteUrl: old.remoteUrl };
965
+ });
966
+ }
874
967
  writeManifest(workdir, scanned);
875
968
  console.log(
876
969
  `[apm] \u5DF2\u626B\u63CF\u5DE5\u4F5C\u533A\u4ED3\u5E93 kind=${scanned.kind} repos=${scanned.repos.map((r) => r.path).join(", ")} \u2192 .apm/${WORKSPACE_REPOS_MANIFEST}`
@@ -1329,7 +1422,7 @@ ${JSON.stringify(event, null, 2)}
1329
1422
 
1330
1423
  // src/commands/connect/agent-session-registry.ts
1331
1424
  import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
1332
- import { dirname as dirname2, resolve as resolve4 } from "node:path";
1425
+ import { dirname as dirname3, resolve as resolve4 } from "node:path";
1333
1426
  function registryPath(workdir, sessionId) {
1334
1427
  return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
1335
1428
  }
@@ -1355,7 +1448,7 @@ function readRegistry(path) {
1355
1448
  return {};
1356
1449
  }
1357
1450
  function writeRegistry(path, registry) {
1358
- mkdirSync4(dirname2(path), { recursive: true });
1451
+ mkdirSync4(dirname3(path), { recursive: true });
1359
1452
  writeFileSync4(path, `${JSON.stringify(registry, null, 2)}
1360
1453
  `, "utf8");
1361
1454
  }
@@ -2279,7 +2372,7 @@ async function runCursorAgent(cfg, ctx, options) {
2279
2372
 
2280
2373
  // src/commands/connect/webide-agent-registry.ts
2281
2374
  import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
2282
- import { dirname as dirname3, resolve as resolve5 } from "node:path";
2375
+ import { dirname as dirname4, resolve as resolve5 } from "node:path";
2283
2376
  function registryPath2(workdir, taskId) {
2284
2377
  return resolve5(workdir, ".apm", "webide", taskId, "cursor-agent.json");
2285
2378
  }
@@ -2300,7 +2393,7 @@ function readRegistry2(path) {
2300
2393
  return {};
2301
2394
  }
2302
2395
  function writeRegistry2(path, registry) {
2303
- mkdirSync6(dirname3(path), { recursive: true });
2396
+ mkdirSync6(dirname4(path), { recursive: true });
2304
2397
  writeFileSync5(path, `${JSON.stringify(registry, null, 2)}
2305
2398
  `, "utf8");
2306
2399
  }
@@ -2682,7 +2775,7 @@ import {
2682
2775
  writeFileSync as writeFileSync7
2683
2776
  } from "fs";
2684
2777
  import { createHash } from "crypto";
2685
- import { dirname as dirname4, join as join6, relative as relative2, sep } from "path";
2778
+ import { dirname as dirname5, join as join6, relative as relative2, sep } from "path";
2686
2779
  var MANIFEST_FILE = "manifest.json";
2687
2780
  function normalizeProjectIdForPath(projectId) {
2688
2781
  const id = projectId.trim();
@@ -2861,7 +2954,7 @@ ${diagnostic ?? ""}`);
2861
2954
  const absPath = toFsPath(
2862
2955
  projectDocumentLocalPath(targetApmDir, projectId, doc.path)
2863
2956
  );
2864
- await ensureDirExists(dirname4(absPath));
2957
+ await ensureDirExists(dirname5(absPath));
2865
2958
  writeFileSync7(absPath, doc.content, "utf8");
2866
2959
  downloaded += 1;
2867
2960
  }
@@ -3047,11 +3140,11 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
3047
3140
 
3048
3141
  // src/version.ts
3049
3142
  import { readFileSync as readFileSync8 } from "fs";
3050
- import { dirname as dirname5, join as join8 } from "path";
3143
+ import { dirname as dirname6, join as join8 } from "path";
3051
3144
  import { fileURLToPath as fileURLToPath2 } from "url";
3052
3145
  function readCliVersion() {
3053
3146
  try {
3054
- const dir = dirname5(fileURLToPath2(import.meta.url));
3147
+ const dir = dirname6(fileURLToPath2(import.meta.url));
3055
3148
  const pkgPath = join8(dir, "..", "package.json");
3056
3149
  const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
3057
3150
  return pkg.version ?? "0.0.0";
@@ -3385,7 +3478,15 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
3385
3478
  await syncWorkspaceSkills(cfg, workdir);
3386
3479
  markSkillsSyncedForCliVersion(workdir, cliVersion);
3387
3480
  }
3388
- resolveWorkspaceRepos(workdir);
3481
+ const workspaceRepos = resolveWorkspaceRepos(workdir);
3482
+ try {
3483
+ await enrichWorkspaceReposRemoteUrls(workspaceRepos);
3484
+ } catch (err) {
3485
+ console.warn(
3486
+ "[apm] \u8865\u9F50 workspace-repos remoteUrl \u5931\u8D25:",
3487
+ err instanceof Error ? err.message : err
3488
+ );
3489
+ }
3389
3490
  if (shouldRunBranch(branchCacheKey, workdir)) {
3390
3491
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3391
3492
  const branchResult = await runTaskBranch(taskId, { cwd: workdir });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.17",
3
+ "version": "7.1.18",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,