@pieai/pro-gov 0.9.2 → 0.9.3

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.
Files changed (2) hide show
  1. package/dist/cli.js +121 -72
  2. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -60,7 +60,6 @@ function loadAgentAssetBundles(agentAssetsDir) {
60
60
 
61
61
  // src/asset-npx/maintenance.ts
62
62
  import { createHash } from "node:crypto";
63
- import { spawnSync } from "node:child_process";
64
63
  import {
65
64
  cpSync,
66
65
  existsSync as existsSync3,
@@ -72,6 +71,29 @@ import {
72
71
  } from "node:fs";
73
72
  import { join as join3, relative as relative2 } from "node:path";
74
73
  import { tmpdir } from "node:os";
74
+
75
+ // src/command-runner.ts
76
+ import {
77
+ spawnSync
78
+ } from "node:child_process";
79
+ function spawnPlatformSync(command2, args, options) {
80
+ if (process.platform !== "win32") return spawnSync(command2, args, options);
81
+ const commandLine = [command2, ...args].map(quoteWindowsArgument).join(" ");
82
+ return spawnSync(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", `"${commandLine}"`], {
83
+ ...options,
84
+ // The command line above is intentionally assembled for cmd.exe. Without
85
+ // this flag Node escapes its quotes before cmd.exe can parse them.
86
+ windowsVerbatimArguments: true
87
+ });
88
+ }
89
+ function quoteWindowsArgument(value) {
90
+ if (value.length === 0 || /[\s"&|<>^]/.test(value)) {
91
+ return `"${value.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1")}"`;
92
+ }
93
+ return value;
94
+ }
95
+
96
+ // src/asset-npx/maintenance.ts
75
97
  function createNpxSkillsMaintenancePlan(options) {
76
98
  assertNativeNpxRoot(options.npxRoot);
77
99
  if (options.operation === "add" && !options.source) {
@@ -140,7 +162,8 @@ function buildNpxCommand(options) {
140
162
  return command2;
141
163
  }
142
164
  function defaultRunner({ command: command2, cwd, timeoutMs }) {
143
- const result = spawnSync(command2[0] ?? "npx", command2.slice(1), {
165
+ const commandName = command2[0] ?? "npx";
166
+ const result = spawnPlatformSync(commandName, command2.slice(1), {
144
167
  cwd,
145
168
  encoding: "utf8",
146
169
  timeout: timeoutMs
@@ -739,6 +762,13 @@ import { dirname as dirname4, join as join8, relative as relative5, resolve as r
739
762
  // src/asset-targets/install-plan.ts
740
763
  import { existsSync as existsSync7, lstatSync as lstatSync2, readFileSync as readFileSync4, readlinkSync, realpathSync as realpathSync2, statSync as statSync3 } from "node:fs";
741
764
  import { basename, dirname as dirname3, join as join7, resolve } from "node:path";
765
+
766
+ // src/symlinks.ts
767
+ function normalizeSymlinkTarget(target) {
768
+ return target.replaceAll("\\", "/");
769
+ }
770
+
771
+ // src/asset-targets/install-plan.ts
742
772
  function createAssetInstallPlan(options) {
743
773
  const placement = options.placement ?? "registry";
744
774
  const assetsById = new Map(options.registry.assets.map((asset) => [asset.id, asset]));
@@ -1048,7 +1078,7 @@ function createLegacyClaudeAdoptions(options) {
1048
1078
  const targetAbsolutePath = join7(options.targetDir, targetPath);
1049
1079
  const compatibilityRootPath = join7(options.targetDir, ".claude/skills");
1050
1080
  const canonicalRootPath = join7(options.targetDir, ".agents/skills");
1051
- if (!lstatSync2(canonicalRootPath).isDirectory() || !lstatSync2(compatibilityRootPath).isSymbolicLink() || readlinkSync(compatibilityRootPath) !== "../.agents/skills" || realpathSync2(compatibilityRootPath) !== realpathSync2(canonicalRootPath)) {
1081
+ if (!lstatSync2(canonicalRootPath).isDirectory() || !lstatSync2(compatibilityRootPath).isSymbolicLink() || normalizeSymlinkTarget(readlinkSync(compatibilityRootPath)) !== "../.agents/skills" || realpathSync2(compatibilityRootPath) !== realpathSync2(canonicalRootPath)) {
1052
1082
  throw new Error(
1053
1083
  `Legacy Claude compatibility root is not the exact canonical alias for ${entry.id}.`
1054
1084
  );
@@ -1289,7 +1319,7 @@ function validateAdoptedSymlink(targetDir, action) {
1289
1319
  const compatibilityRootPath = join8(targetDir, action.compatibilityRootPath);
1290
1320
  const targetAbsolutePath = join8(targetDir, action.targetPath);
1291
1321
  const legacyAbsolutePath = join8(targetDir, action.legacyTargetPath);
1292
- if (!lstatSync3(canonicalRootPath).isDirectory() || !lstatSync3(compatibilityRootPath).isSymbolicLink() || readlinkSync2(compatibilityRootPath) !== action.expectedCompatibilityRawTarget || realpathSync3(compatibilityRootPath) !== realpathSync3(canonicalRootPath)) {
1322
+ if (!lstatSync3(canonicalRootPath).isDirectory() || !lstatSync3(compatibilityRootPath).isSymbolicLink() || normalizeSymlinkTarget(readlinkSync2(compatibilityRootPath)) !== action.expectedCompatibilityRawTarget || realpathSync3(compatibilityRootPath) !== realpathSync3(canonicalRootPath)) {
1293
1323
  throw new Error(
1294
1324
  `Legacy Claude compatibility alias changed before apply: ${action.compatibilityRootPath}`
1295
1325
  );
@@ -2217,7 +2247,6 @@ function printNpxUsage() {
2217
2247
  }
2218
2248
 
2219
2249
  // src/commands/doctor.ts
2220
- import { spawnSync as spawnSync2 } from "node:child_process";
2221
2250
  import { existsSync as existsSync12 } from "node:fs";
2222
2251
  import { createRequire } from "node:module";
2223
2252
  import { dirname as dirname6, join as join12 } from "node:path";
@@ -2252,10 +2281,12 @@ function runDoctor(args) {
2252
2281
  return runPackageDoctor(args);
2253
2282
  }
2254
2283
  function checkDocGov(options = {}) {
2255
- const run = options.run ?? ((command2, args) => spawnSync2(command2, args, {
2256
- encoding: "utf8",
2257
- stdio: "ignore"
2258
- }));
2284
+ const run = options.run ?? ((command2, args) => {
2285
+ return spawnPlatformSync(command2, args, {
2286
+ encoding: "utf8",
2287
+ stdio: "ignore"
2288
+ });
2289
+ });
2259
2290
  const dependencyCli = (options.resolveDependencyCli ?? resolveDocGovDependencyCli)();
2260
2291
  if (!dependencyCli) {
2261
2292
  const fromPath = run("doc-gov", ["--help"]);
@@ -2504,28 +2535,28 @@ var ROOT_DEFINITIONS = [
2504
2535
  {
2505
2536
  id: "pnpm-store",
2506
2537
  label: "pnpm Store",
2507
- relativePath: "Library/pnpm/store",
2538
+ relativePath: process.platform === "win32" ? "AppData/Local/pnpm/store" : "Library/pnpm/store",
2508
2539
  kind: "package-cache",
2509
2540
  note: "pnpm \u5185\u5BB9\u5BFB\u5740\u4ED3\u5E93\uFF1B\u6E05\u7406\u65F6\u53EA\u5EFA\u8BAE pnpm store prune\u3002"
2510
2541
  },
2511
2542
  {
2512
2543
  id: "playwright",
2513
2544
  label: "Playwright \u6D4F\u89C8\u5668",
2514
- relativePath: "Library/Caches/ms-playwright",
2545
+ relativePath: process.platform === "win32" ? "AppData/Local/ms-playwright" : "Library/Caches/ms-playwright",
2515
2546
  kind: "browser-cache",
2516
2547
  note: "\u6D4B\u8BD5\u6D4F\u89C8\u5668\u4E8C\u8FDB\u5236\u7F13\u5B58\uFF1B\u7248\u672C\u5806\u79EF\u53EF\u80FD\u9020\u6210\u663E\u8457\u78C1\u76D8\u5360\u7528\u3002"
2517
2548
  },
2518
2549
  {
2519
2550
  id: "claude-desktop",
2520
2551
  label: "Claude Desktop",
2521
- relativePath: "Library/Application Support/Claude",
2552
+ relativePath: process.platform === "win32" ? "AppData/Roaming/Claude" : "Library/Application Support/Claude",
2522
2553
  kind: "ai-host",
2523
2554
  note: "\u684C\u9762\u5E94\u7528\u8FD0\u884C\u6570\u636E\uFF0C\u9ED8\u8BA4\u53D7\u4FDD\u62A4\u3002"
2524
2555
  },
2525
2556
  {
2526
2557
  id: "cursor-desktop",
2527
2558
  label: "Cursor Desktop",
2528
- relativePath: "Library/Application Support/Cursor",
2559
+ relativePath: process.platform === "win32" ? "AppData/Roaming/Cursor" : "Library/Application Support/Cursor",
2529
2560
  kind: "ai-host",
2530
2561
  note: "\u684C\u9762\u5E94\u7528\u8FD0\u884C\u6570\u636E\uFF0C\u9ED8\u8BA4\u53D7\u4FDD\u62A4\u3002"
2531
2562
  }
@@ -2593,7 +2624,7 @@ function inspectHost(options = {}) {
2593
2624
  function inspectAgentBrowser(options) {
2594
2625
  const command2 = options.command ?? "agent-browser";
2595
2626
  try {
2596
- const output = execFileSync(command2, ["--version"], {
2627
+ const result = spawnPlatformSync(command2, ["--version"], {
2597
2628
  encoding: "utf8",
2598
2629
  stdio: ["ignore", "pipe", "ignore"],
2599
2630
  // Host scans can run alongside the full portfolio test matrix. Keep the
@@ -2601,7 +2632,9 @@ function inspectAgentBrowser(options) {
2601
2632
  // spawn the pinned CLI instead of misclassifying a slow start as an
2602
2633
  // unparseable version.
2603
2634
  timeout: 1e4
2604
- }).trim();
2635
+ });
2636
+ if (result.error || result.status !== 0) throw result.error ?? new Error("command failed");
2637
+ const output = result.stdout.trim();
2605
2638
  const installedVersion = output.match(/(?:^|\s)(\d+\.\d+\.\d+)(?:\s|$)/)?.[1];
2606
2639
  if (!installedVersion) {
2607
2640
  return {
@@ -2760,7 +2793,12 @@ function inspectFindings(homePath) {
2760
2793
  id: "pnpm-store",
2761
2794
  rootId: "pnpm-store",
2762
2795
  label: "pnpm \u672A\u5F15\u7528\u5305\u5019\u9009",
2763
- paths: [join14(homePath, "Library/pnpm/store")],
2796
+ paths: [
2797
+ join14(
2798
+ homePath,
2799
+ process.platform === "win32" ? "AppData/Local/pnpm/store" : "Library/pnpm/store"
2800
+ )
2801
+ ],
2764
2802
  category: "cache",
2765
2803
  confidence: "high",
2766
2804
  disposition: "native-tool",
@@ -2772,7 +2810,13 @@ function inspectFindings(homePath) {
2772
2810
  id: "playwright-browsers",
2773
2811
  rootId: "playwright",
2774
2812
  label: "Playwright \u6D4F\u89C8\u5668\u7248\u672C",
2775
- paths: [join14(homePath, "Library/Caches/ms-playwright"), join14(homePath, ".cache/ms-playwright")],
2813
+ paths: [
2814
+ join14(
2815
+ homePath,
2816
+ process.platform === "win32" ? "AppData/Local/ms-playwright" : "Library/Caches/ms-playwright"
2817
+ ),
2818
+ join14(homePath, ".cache/ms-playwright")
2819
+ ],
2776
2820
  category: "duplicate-runtime",
2777
2821
  confidence: "medium",
2778
2822
  disposition: "native-tool",
@@ -2794,6 +2838,8 @@ function inspectFindings(homePath) {
2794
2838
  });
2795
2839
  }
2796
2840
  function buildProtections(homePath) {
2841
+ const claudeDesktopPath = process.platform === "win32" ? "~/AppData/Roaming/Claude" : "~/Library/Application Support/Claude";
2842
+ const cursorDesktopPath = process.platform === "win32" ? "~/AppData/Roaming/Cursor" : "~/Library/Application Support/Cursor";
2797
2843
  return [
2798
2844
  {
2799
2845
  label: "\u914D\u7F6E\u4E0E\u8EAB\u4EFD\u8FB9\u754C",
@@ -2812,7 +2858,7 @@ function buildProtections(homePath) {
2812
2858
  },
2813
2859
  {
2814
2860
  label: "\u684C\u9762\u5BBF\u4E3B\u8FD0\u884C\u6570\u636E",
2815
- paths: ["~/Library/Application Support/Claude", "~/Library/Application Support/Cursor"],
2861
+ paths: [claudeDesktopPath, cursorDesktopPath],
2816
2862
  reason: "\u5E94\u7528\u6570\u636E\u5E93\u4E0E\u8FD0\u884C\u72B6\u6001\u6DF7\u5728\u5176\u4E2D\uFF0C\u4E0D\u80FD\u628A\u6574\u4E2A\u76EE\u5F55\u5F53\u7F13\u5B58\u3002"
2817
2863
  }
2818
2864
  ].map((protection) => ({
@@ -2896,7 +2942,7 @@ function displayPath(path, homePath) {
2896
2942
  const absolute = resolve3(path);
2897
2943
  const withinHome = relative6(homePath, absolute);
2898
2944
  if (withinHome === "") return "~";
2899
- if (!withinHome.startsWith("..")) return `~/${withinHome}`;
2945
+ if (!withinHome.startsWith("..")) return `~/${withinHome.replaceAll("\\", "/")}`;
2900
2946
  return absolute;
2901
2947
  }
2902
2948
  function undisplayPath(path, homePath) {
@@ -4789,7 +4835,7 @@ function formatLink(link) {
4789
4835
  }
4790
4836
 
4791
4837
  // src/lens/scan.ts
4792
- import { spawnSync as spawnSync4 } from "node:child_process";
4838
+ import { spawnSync as spawnSync3 } from "node:child_process";
4793
4839
  import { existsSync as existsSync21, readFileSync as readFileSync13, statSync as statSync6 } from "node:fs";
4794
4840
  import { homedir as homedir3 } from "node:os";
4795
4841
  import { join as join22 } from "node:path";
@@ -4865,7 +4911,7 @@ function inspectCompatibilityLink(root, path, expectedRawTarget) {
4865
4911
  if (stat.isDirectory()) return { ...base, status: "directory" };
4866
4912
  return { ...base, status: "other" };
4867
4913
  }
4868
- const rawTarget = readlinkSync3(absolutePath);
4914
+ const rawTarget = normalizeSymlinkTarget(readlinkSync3(absolutePath));
4869
4915
  const resolvedTarget = resolve6(dirname12(absolutePath), rawTarget);
4870
4916
  const expectedPath = resolve6(dirname12(absolutePath), expectedRawTarget);
4871
4917
  const targetStat = safeLstat2(resolvedTarget);
@@ -5071,7 +5117,7 @@ function readPackageJson(path) {
5071
5117
  }
5072
5118
 
5073
5119
  // src/repository-files.ts
5074
- import { spawnSync as spawnSync3 } from "node:child_process";
5120
+ import { spawnSync as spawnSync2 } from "node:child_process";
5075
5121
  import { existsSync as existsSync20, readdirSync as readdirSync10 } from "node:fs";
5076
5122
  import { isAbsolute as isAbsolute5, join as join21, posix as posix3, relative as relative9 } from "node:path";
5077
5123
  var gitMaxBufferBytes = 64 * 1024 * 1024;
@@ -5154,7 +5200,7 @@ function isSafeRepositoryRelativePath(path) {
5154
5200
  return path !== "" && path !== "." && !isAbsolute5(path) && !/^[a-zA-Z]:\//.test(path) && path !== ".." && !path.startsWith("../");
5155
5201
  }
5156
5202
  function runGit(root, args) {
5157
- const result = spawnSync3("git", ["-C", root, ...args], {
5203
+ const result = spawnSync2("git", ["-C", root, ...args], {
5158
5204
  encoding: "utf8",
5159
5205
  maxBuffer: gitMaxBufferBytes,
5160
5206
  env: { ...process.env, LANG: "C", LC_ALL: "C" }
@@ -5237,7 +5283,7 @@ function readGitState(targetDir) {
5237
5283
  };
5238
5284
  }
5239
5285
  function runGit2(targetDir, args) {
5240
- const result = spawnSync4("git", ["-C", targetDir, ...args], {
5286
+ const result = spawnSync3("git", ["-C", targetDir, ...args], {
5241
5287
  encoding: "utf8",
5242
5288
  maxBuffer: 64 * 1024 * 1024
5243
5289
  });
@@ -5415,7 +5461,7 @@ import { existsSync as existsSync33, readFileSync as readFileSync18 } from "node
5415
5461
  import { join as join34 } from "node:path";
5416
5462
 
5417
5463
  // src/portfolio/doctor.ts
5418
- import { spawnSync as spawnSync7 } from "node:child_process";
5464
+ import { spawnSync as spawnSync5 } from "node:child_process";
5419
5465
  import { existsSync as existsSync24, readFileSync as readFileSync16 } from "node:fs";
5420
5466
  import { createRequire as createRequire2 } from "node:module";
5421
5467
  import { homedir as homedir4 } from "node:os";
@@ -5423,7 +5469,6 @@ import { dirname as dirname15, join as join25 } from "node:path";
5423
5469
  import { fileURLToPath as fileURLToPath4 } from "node:url";
5424
5470
 
5425
5471
  // src/host-tooling/inventory.ts
5426
- import { spawnSync as spawnSync5 } from "node:child_process";
5427
5472
  function inspectHostTooling(requirements, runner = defaultRunner2) {
5428
5473
  const hosts = [];
5429
5474
  const issues = [];
@@ -5497,7 +5542,7 @@ function parseHostPlugins(host, value) {
5497
5542
  });
5498
5543
  }
5499
5544
  function defaultRunner2({ command: command2 }) {
5500
- const result = spawnSync5(command2[0] ?? "", command2.slice(1), {
5545
+ const result = spawnPlatformSync(command2[0] ?? "", command2.slice(1), {
5501
5546
  encoding: "utf8",
5502
5547
  timeout: 1e4
5503
5548
  });
@@ -5612,7 +5657,7 @@ function pathIsSymlink(path) {
5612
5657
  }
5613
5658
 
5614
5659
  // src/portfolio/version-policy.ts
5615
- import { spawnSync as spawnSync6 } from "node:child_process";
5660
+ import { spawnSync as spawnSync4 } from "node:child_process";
5616
5661
  import { existsSync as existsSync23, lstatSync as lstatSync9, readFileSync as readFileSync15 } from "node:fs";
5617
5662
  import { dirname as dirname14, join as join24 } from "node:path";
5618
5663
  function inspectVersionPolicy(root, policy, projectType) {
@@ -5704,7 +5749,7 @@ function inspectRuntime(expectedName, expectedVersion) {
5704
5749
  function readRuntimeVersion(name) {
5705
5750
  if (name === "node") return process.versions.node;
5706
5751
  if (name !== "deno") return void 0;
5707
- const result = spawnSync6("deno", ["--version"], { encoding: "utf8" });
5752
+ const result = spawnSync4("deno", ["--version"], { encoding: "utf8" });
5708
5753
  if (result.status !== 0) return void 0;
5709
5754
  return /^deno\s+(\d+\.\d+\.\d+)/m.exec(result.stdout)?.[1];
5710
5755
  }
@@ -5922,7 +5967,7 @@ function runTargetChecks(target) {
5922
5967
  ];
5923
5968
  return commands.map((command2) => {
5924
5969
  if (!existsSync24(command2.cli)) return { name: command2.name, status: null };
5925
- const result = spawnSync7(process.execPath, [command2.cli, ...command2.args], {
5970
+ const result = spawnSync5(process.execPath, [command2.cli, ...command2.args], {
5926
5971
  cwd: target.path,
5927
5972
  encoding: "utf8",
5928
5973
  timeout: 3e4
@@ -5931,13 +5976,13 @@ function runTargetChecks(target) {
5931
5976
  });
5932
5977
  }
5933
5978
  function inspectGit(path) {
5934
- const inside = spawnSync7("git", ["rev-parse", "--is-inside-work-tree"], {
5979
+ const inside = spawnSync5("git", ["rev-parse", "--is-inside-work-tree"], {
5935
5980
  cwd: path,
5936
5981
  encoding: "utf8"
5937
5982
  });
5938
5983
  if (inside.status !== 0) return { isRepository: false, dirty: false };
5939
- const status = spawnSync7("git", ["status", "--porcelain"], { cwd: path, encoding: "utf8" });
5940
- const branch = spawnSync7("git", ["branch", "--show-current"], { cwd: path, encoding: "utf8" });
5984
+ const status = spawnSync5("git", ["status", "--porcelain"], { cwd: path, encoding: "utf8" });
5985
+ const branch = spawnSync5("git", ["branch", "--show-current"], { cwd: path, encoding: "utf8" });
5941
5986
  return {
5942
5987
  isRepository: true,
5943
5988
  dirty: status.stdout.trim().length > 0,
@@ -6006,12 +6051,13 @@ function safeRealpath(path) {
6006
6051
  }
6007
6052
  function commandVersion(command2) {
6008
6053
  try {
6009
- const output = execFileSync2(command2, ["version"], {
6054
+ const result = spawnPlatformSync(command2, ["version"], {
6010
6055
  encoding: "utf8",
6011
6056
  stdio: ["ignore", "pipe", "ignore"],
6012
6057
  timeout: 3e3
6013
6058
  });
6014
- return output.match(/\b\d+\.\d+\.\d+\b/)?.[0];
6059
+ if (result.error || result.status !== 0) return void 0;
6060
+ return result.stdout.match(/\b\d+\.\d+\.\d+\b/)?.[0];
6015
6061
  } catch {
6016
6062
  return void 0;
6017
6063
  }
@@ -6292,12 +6338,10 @@ function inspectGit2(root) {
6292
6338
  }
6293
6339
 
6294
6340
  // src/portfolio/ai-health/hosts.ts
6295
- import { execFileSync as execFileSync5 } from "node:child_process";
6296
6341
  import { existsSync as existsSync28 } from "node:fs";
6297
6342
  import { join as join28, resolve as resolve8, sep as sep3 } from "node:path";
6298
6343
 
6299
6344
  // src/portfolio/ai-health/devspace.ts
6300
- import { execFileSync as execFileSync4 } from "node:child_process";
6301
6345
  import { existsSync as existsSync27, statSync as statSync8 } from "node:fs";
6302
6346
  import { join as join27, relative as relative10, resolve as resolve7, sep as sep2 } from "node:path";
6303
6347
  function inspectDevSpaceHealth(options) {
@@ -6313,9 +6357,9 @@ function inspectDevSpaceHealth(options) {
6313
6357
  5e3
6314
6358
  );
6315
6359
  const latestVersion = latestResult.ok ? latestResult.stdout.match(/\b\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?\b/)?.[0] : void 0;
6316
- const processResult = run("pgrep", ["-f", "devspace serve"], 3e3);
6317
- const pid = processResult.ok ? processResult.stdout.match(/\b\d+\b/)?.[0] : void 0;
6318
- const processEnvironment = pid ? run("ps", ["eww", "-p", pid, "-o", "command="], 3e3) : void 0;
6360
+ const processResult = process.platform === "win32" ? run("tasklist", ["/FI", "IMAGENAME eq devspace.exe", "/FO", "CSV", "/NH"], 3e3) : run("pgrep", ["-f", "devspace serve"], 3e3);
6361
+ const pid = processResult.ok ? process.platform === "win32" ? processResult.stdout.match(/"devspace\.exe","(\d+)"/i)?.[1] : processResult.stdout.match(/\b\d+\b/)?.[0] : void 0;
6362
+ const processEnvironment = process.platform !== "win32" && pid ? run("ps", ["eww", "-p", pid, "-o", "command="], 3e3) : void 0;
6319
6363
  const processToolMode = processEnvironment?.ok ? processEnvironment.stdout.match(
6320
6364
  /(?:^|\s)DEVSPACE_TOOL_MODE=(minimal|full|codex)(?:\s|$)/
6321
6365
  )?.[1] : void 0;
@@ -6327,9 +6371,9 @@ function inspectDevSpaceHealth(options) {
6327
6371
  (repositoryPath) => allowedRoots.some((root) => isPathInside(repositoryPath, root))
6328
6372
  ) ? "complete" : "partial";
6329
6373
  const bind = configExists && typeof configValue.host === "string" ? isLoopbackHost(configValue.host) ? "loopback" : "non-loopback" : "unknown";
6330
- const directoryMode = existsSync27(configDirectory) ? modeString(statSync8(configDirectory).mode) : void 0;
6331
- const fileMode = existsSync27(configPath) ? modeString(statSync8(configPath).mode) : void 0;
6332
- const authMode = existsSync27(authPath) ? modeString(statSync8(authPath).mode) : void 0;
6374
+ const directoryMode = process.platform !== "win32" && existsSync27(configDirectory) ? modeString(statSync8(configDirectory).mode) : void 0;
6375
+ const fileMode = process.platform !== "win32" && existsSync27(configPath) ? modeString(statSync8(configPath).mode) : void 0;
6376
+ const authMode = process.platform !== "win32" && existsSync27(authPath) ? modeString(statSync8(authPath).mode) : void 0;
6333
6377
  const update = installedVersion && latestVersion ? installedVersion === latestVersion ? "current" : "available" : "unknown";
6334
6378
  const recommendations = [];
6335
6379
  let status = "healthy";
@@ -6353,7 +6397,7 @@ function inspectDevSpaceHealth(options) {
6353
6397
  if (doctor === "failed") unhealthy("devspace doctor \u672A\u901A\u8FC7\u3002");
6354
6398
  if (portfolioCoverage === "partial") attention("DevSpace allowedRoots \u6CA1\u6709\u8986\u76D6\u5168\u90E8\u5DF2\u767B\u8BB0\u4ED3\u5E93\u3002");
6355
6399
  if (installedResult.ok && !pid) attention("DevSpace \u5DF2\u5B89\u88C5\u4F46\u5F53\u524D\u6CA1\u6709\u8FD0\u884C\u3002");
6356
- if (options.expectedToolMode && pid && processToolMode !== options.expectedToolMode) {
6400
+ if (options.expectedToolMode && pid && processToolMode !== void 0 && processToolMode !== options.expectedToolMode) {
6357
6401
  attention(
6358
6402
  `\u8FD0\u884C\u4E2D\u7684 DevSpace \u5DE5\u5177\u6A21\u5F0F\u4E3A ${processToolMode ?? "unknown"}\uFF0C\u671F\u671B ${options.expectedToolMode}\u3002`
6359
6403
  );
@@ -6388,18 +6432,12 @@ function inspectDevSpaceHealth(options) {
6388
6432
  };
6389
6433
  }
6390
6434
  function runDevSpaceCommand(command2, args, timeout) {
6391
- try {
6392
- return {
6393
- ok: true,
6394
- stdout: execFileSync4(command2, args, {
6395
- encoding: "utf8",
6396
- stdio: ["ignore", "pipe", "ignore"],
6397
- timeout
6398
- })
6399
- };
6400
- } catch {
6401
- return { ok: false, stdout: "" };
6402
- }
6435
+ const result = spawnPlatformSync(command2, args, {
6436
+ encoding: "utf8",
6437
+ stdio: ["ignore", "pipe", "ignore"],
6438
+ timeout
6439
+ });
6440
+ return result.error || result.status !== 0 ? { ok: false, stdout: "" } : { ok: true, stdout: result.stdout };
6403
6441
  }
6404
6442
  function isLoopbackHost(host) {
6405
6443
  return ["127.0.0.1", "localhost", "::1"].includes(host.trim().toLowerCase());
@@ -6490,16 +6528,16 @@ function inspectGrokProject(root, homeDir, grokVersion) {
6490
6528
  });
6491
6529
  if (!grokVersion) return empty("unavailable");
6492
6530
  try {
6493
- const value = JSON.parse(
6494
- execFileSync5("grok", ["inspect", "--json"], {
6495
- cwd: root,
6496
- encoding: "utf8",
6497
- env: { ...process.env, HOME: homeDir, GROK_HOME: join28(homeDir, ".grok") },
6498
- maxBuffer: 10 * 1024 * 1024,
6499
- stdio: ["ignore", "pipe", "ignore"],
6500
- timeout: 8e3
6501
- })
6502
- );
6531
+ const result = spawnPlatformSync("grok", ["inspect", "--json"], {
6532
+ cwd: root,
6533
+ encoding: "utf8",
6534
+ env: { ...process.env, HOME: homeDir, GROK_HOME: join28(homeDir, ".grok") },
6535
+ maxBuffer: 10 * 1024 * 1024,
6536
+ stdio: ["ignore", "pipe", "ignore"],
6537
+ timeout: 8e3
6538
+ });
6539
+ if (result.error || result.status !== 0) return empty("failed");
6540
+ const value = JSON.parse(result.stdout);
6503
6541
  if (!isRecord3(value)) return empty("failed");
6504
6542
  const userClaudeNames = new Set(
6505
6543
  jsonObjectKeys(join28(homeDir, MCP_DISCOVERY_PATHS.user.claudeCode), "mcpServers")
@@ -6587,6 +6625,7 @@ function inferGrokMcpScope(name, sourceType, sourcePath, root, homeDir, userClau
6587
6625
  // src/portfolio/ai-health/secrets.ts
6588
6626
  import { existsSync as existsSync29, lstatSync as lstatSync12, readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
6589
6627
  import { join as join29, relative as relative11, sep as sep4 } from "node:path";
6628
+ var supportsPosixModes = process.platform !== "win32";
6590
6629
  function inspectRepositorySecrets(root, id, secretsRoot, isRepository, environmentPolicy) {
6591
6630
  const centralPath = join29(secretsRoot, id);
6592
6631
  const centralRealPath = safeRealpath(centralPath);
@@ -6608,7 +6647,7 @@ function inspectRepositorySecrets(root, id, secretsRoot, isRepository, environme
6608
6647
  });
6609
6648
  return {
6610
6649
  centralDirectory: existsSync29(centralPath) ? "present" : "absent",
6611
- centralMode: existsSync29(centralPath) ? modeString(statSync9(centralPath).mode) : void 0,
6650
+ centralMode: supportsPosixModes && existsSync29(centralPath) ? modeString(statSync9(centralPath).mode) : void 0,
6612
6651
  centralFiles: existsSync29(centralPath) ? collectCentralSecretFiles(centralPath) : [],
6613
6652
  repositoryEnvFiles: envFiles
6614
6653
  };
@@ -6637,7 +6676,7 @@ function collectEnvironmentFiles(root, current = root, depth = 0) {
6637
6676
  if (!SKIP_ENV_DIRECTORIES.has(entry.name))
6638
6677
  found.push(...collectEnvironmentFiles(root, join29(current, entry.name), depth + 1));
6639
6678
  } else if (isEnvironmentFilename(entry.name) && !isProviderGeneratedEnvironmentFile(entry.name)) {
6640
- found.push(relative11(root, join29(current, entry.name)));
6679
+ found.push(relative11(root, join29(current, entry.name)).replaceAll("\\", "/"));
6641
6680
  }
6642
6681
  }
6643
6682
  } catch {
@@ -6652,7 +6691,11 @@ function collectCentralSecretFiles(root, current = root, depth = 0) {
6652
6691
  for (const entry of readdirSync12(current, { withFileTypes: true })) {
6653
6692
  const path = join29(current, entry.name);
6654
6693
  if (entry.isDirectory()) found.push(...collectCentralSecretFiles(root, path, depth + 1));
6655
- else found.push({ path: relative11(root, path), mode: modeString(lstatSync12(path).mode) });
6694
+ else
6695
+ found.push({
6696
+ path: relative11(root, path).replaceAll("\\", "/"),
6697
+ mode: supportsPosixModes ? modeString(lstatSync12(path).mode) : "unknown"
6698
+ });
6656
6699
  }
6657
6700
  } catch {
6658
6701
  return found;
@@ -6683,10 +6726,15 @@ function pointsInside(path, expectedRoot) {
6683
6726
  return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${sep4}`);
6684
6727
  }
6685
6728
  function hasUnsafeCentralSecretPermissions(secrets) {
6729
+ if (!supportsPosixModes) return false;
6686
6730
  return secrets.centralDirectory === "present" && (secrets.centralMode !== "700" || secrets.centralFiles.some((file) => file.mode !== "600"));
6687
6731
  }
6688
6732
  function inspectSecretsRoot(path) {
6689
- return existsSync29(path) ? { path, exists: true, mode: modeString(statSync9(path).mode) } : { path, exists: false };
6733
+ return existsSync29(path) ? {
6734
+ path,
6735
+ exists: true,
6736
+ ...supportsPosixModes ? { mode: modeString(statSync9(path).mode) } : {}
6737
+ } : { path, exists: false };
6690
6738
  }
6691
6739
 
6692
6740
  // src/portfolio/ai-health/skills.ts
@@ -7925,9 +7973,10 @@ function findPortfolioAgentAssetsDir(manifest) {
7925
7973
  }
7926
7974
  function reportMissingPortfolioRegistry(loaded, json) {
7927
7975
  const expectedPath = loaded.manifest?.executionEngine?.path ? join34(loaded.manifest.executionEngine.path, "agent-assets/registry.json") : "executionEngine.path/agent-assets/registry.json";
7976
+ const displayExpectedPath = expectedPath.replaceAll("\\", "/");
7928
7977
  const issue = {
7929
7978
  type: "missing-control-plane-registry",
7930
- message: `Portfolio control-plane registry is required at ${expectedPath}; refusing the package fallback registry.`
7979
+ message: `Portfolio control-plane registry is required at ${displayExpectedPath}; refusing the package fallback registry.`
7931
7980
  };
7932
7981
  if (json) {
7933
7982
  console.log(
@@ -8022,7 +8071,7 @@ function runSync(args) {
8022
8071
  continue;
8023
8072
  }
8024
8073
  if (file.kind === "symlink") {
8025
- if (!stat.isSymbolicLink() || readlinkSync4(targetPath) !== file.linkTarget) {
8074
+ if (!stat.isSymbolicLink() || normalizeSymlinkTarget(readlinkSync4(targetPath)) !== file.linkTarget) {
8026
8075
  console.log(`different: ${file.targetPath}`);
8027
8076
  differences += 1;
8028
8077
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pieai/pro-gov",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "Project-level distribution kit for Project Governance System.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@pieai/doc-gov": "^0.9.2"
38
+ "@pieai/doc-gov": "^0.9.3"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@pieai/swimmer-ui-kit": "1.3.2",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "scripts": {
55
55
  "dev": "tsx src/cli.ts",
56
- "build": "node scripts/build-dashboard.mjs && node scripts/copy-assets.mjs && esbuild src/cli.ts --bundle --platform=node --format=esm --target=node24 --banner:js=\"#!/usr/bin/env node\" --outfile=dist/cli.js && chmod +x dist/cli.js",
56
+ "build": "node scripts/build.mjs",
57
57
  "pretest": "pnpm --filter @pieai/doc-gov build && pnpm build",
58
58
  "test": "tsx --test src/*.test.ts src/**/*.test.ts",
59
59
  "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.dashboard.json --noEmit"