@pieai/pro-gov 0.9.1 → 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.
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"notes": "Public rule for choosing evidence lanes and requiring fresh verification before completion.",
|
|
26
26
|
"promotion": {
|
|
27
27
|
"privateSourcePath": "rules/pie-rules/ai-in-the-loop.md",
|
|
28
|
-
"privateSourceHash": "sha256:
|
|
28
|
+
"privateSourceHash": "sha256:344eba8c3b1f3130ed33e4b6a4511a332e2ca477e6a40ad7d4c73006197f5445",
|
|
29
29
|
"publicHash": "sha256:911702baf6ea1d724e41ea1876d23d80f4de8dfaaadbf1399a40c982c810224c",
|
|
30
30
|
"sanitized": true,
|
|
31
|
-
"lastReviewed": "2026-08-
|
|
32
|
-
"reviewNotes": "Reviewed after the private source gained governed front matter and normalized formatting. The public copy intentionally keeps the portable evidence-loop method without the private Grok compatibility lane or project governance metadata."
|
|
31
|
+
"lastReviewed": "2026-08-20",
|
|
32
|
+
"reviewNotes": "Reviewed after the private source gained governed front matter and normalized formatting. The public copy intentionally keeps the portable evidence-loop method without the private Grok compatibility lane or project governance metadata. Re-reviewed 2026-08-20: the private source moved by Markdown table padding only, with no wording change, so the sanitized public copy is unaffected and only the private hash is re-pinned."
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
{
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Seeded by `pro-gov init`. This file is project-local after seeding — add
|
|
2
|
+
# your own build outputs and generated paths freely.
|
|
3
|
+
|
|
4
|
+
# Dependencies and build output
|
|
5
|
+
node_modules
|
|
6
|
+
dist
|
|
7
|
+
build
|
|
8
|
+
coverage
|
|
9
|
+
out
|
|
10
|
+
.next
|
|
11
|
+
.turbo
|
|
12
|
+
.tmp
|
|
13
|
+
|
|
14
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
15
|
+
# PGS-managed content — DO NOT REFORMAT. Keep these entries.
|
|
16
|
+
#
|
|
17
|
+
# `pro-gov sync --check` byte-compares docs/governance against the packaged
|
|
18
|
+
# starter, and `pro-gov portfolio assets-check` byte-compares the shared-rule
|
|
19
|
+
# snapshots. A formatter that only pads Markdown table cells is enough to fail
|
|
20
|
+
# both, and the guardrails cannot tell cosmetic padding from a real local edit
|
|
21
|
+
# — re-applying the asset then refuses with asset-lock-drift.
|
|
22
|
+
#
|
|
23
|
+
# If you need one of these files changed, change it upstream in Project
|
|
24
|
+
# Governance System and re-sync; do not restyle it here.
|
|
25
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
26
|
+
docs/governance
|
|
27
|
+
docs/policy/shared-rules
|
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
|
|
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) =>
|
|
2256
|
-
|
|
2257
|
-
|
|
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"]);
|
|
@@ -2328,7 +2359,10 @@ function classifyOwnership(targetPath) {
|
|
|
2328
2359
|
if (targetPath === "lefthook.yml" || targetPath === ".github/workflows/docs-check.yml") {
|
|
2329
2360
|
return "optional-guardrail";
|
|
2330
2361
|
}
|
|
2331
|
-
if (targetPath === "AGENTS.md" ||
|
|
2362
|
+
if (targetPath === "AGENTS.md" || // Seeded so a new project starts with the managed paths protected from its
|
|
2363
|
+
// formatter, then owned locally — every project adds its own build outputs,
|
|
2364
|
+
// so this must not be byte-compared by `sync --check`.
|
|
2365
|
+
targetPath === ".oxfmtignore" || targetPath === "docs/policy/best-practice-for-this-project.md" || targetPath === "docs/reference/documentation-map.md" || targetPath === "docs/reference/execution/current-work.md") {
|
|
2332
2366
|
return "project-local-seed";
|
|
2333
2367
|
}
|
|
2334
2368
|
return "shared";
|
|
@@ -2501,28 +2535,28 @@ var ROOT_DEFINITIONS = [
|
|
|
2501
2535
|
{
|
|
2502
2536
|
id: "pnpm-store",
|
|
2503
2537
|
label: "pnpm Store",
|
|
2504
|
-
relativePath: "Library/pnpm/store",
|
|
2538
|
+
relativePath: process.platform === "win32" ? "AppData/Local/pnpm/store" : "Library/pnpm/store",
|
|
2505
2539
|
kind: "package-cache",
|
|
2506
2540
|
note: "pnpm \u5185\u5BB9\u5BFB\u5740\u4ED3\u5E93\uFF1B\u6E05\u7406\u65F6\u53EA\u5EFA\u8BAE pnpm store prune\u3002"
|
|
2507
2541
|
},
|
|
2508
2542
|
{
|
|
2509
2543
|
id: "playwright",
|
|
2510
2544
|
label: "Playwright \u6D4F\u89C8\u5668",
|
|
2511
|
-
relativePath: "Library/Caches/ms-playwright",
|
|
2545
|
+
relativePath: process.platform === "win32" ? "AppData/Local/ms-playwright" : "Library/Caches/ms-playwright",
|
|
2512
2546
|
kind: "browser-cache",
|
|
2513
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"
|
|
2514
2548
|
},
|
|
2515
2549
|
{
|
|
2516
2550
|
id: "claude-desktop",
|
|
2517
2551
|
label: "Claude Desktop",
|
|
2518
|
-
relativePath: "Library/Application Support/Claude",
|
|
2552
|
+
relativePath: process.platform === "win32" ? "AppData/Roaming/Claude" : "Library/Application Support/Claude",
|
|
2519
2553
|
kind: "ai-host",
|
|
2520
2554
|
note: "\u684C\u9762\u5E94\u7528\u8FD0\u884C\u6570\u636E\uFF0C\u9ED8\u8BA4\u53D7\u4FDD\u62A4\u3002"
|
|
2521
2555
|
},
|
|
2522
2556
|
{
|
|
2523
2557
|
id: "cursor-desktop",
|
|
2524
2558
|
label: "Cursor Desktop",
|
|
2525
|
-
relativePath: "Library/Application Support/Cursor",
|
|
2559
|
+
relativePath: process.platform === "win32" ? "AppData/Roaming/Cursor" : "Library/Application Support/Cursor",
|
|
2526
2560
|
kind: "ai-host",
|
|
2527
2561
|
note: "\u684C\u9762\u5E94\u7528\u8FD0\u884C\u6570\u636E\uFF0C\u9ED8\u8BA4\u53D7\u4FDD\u62A4\u3002"
|
|
2528
2562
|
}
|
|
@@ -2590,11 +2624,17 @@ function inspectHost(options = {}) {
|
|
|
2590
2624
|
function inspectAgentBrowser(options) {
|
|
2591
2625
|
const command2 = options.command ?? "agent-browser";
|
|
2592
2626
|
try {
|
|
2593
|
-
const
|
|
2627
|
+
const result = spawnPlatformSync(command2, ["--version"], {
|
|
2594
2628
|
encoding: "utf8",
|
|
2595
2629
|
stdio: ["ignore", "pipe", "ignore"],
|
|
2596
|
-
|
|
2597
|
-
|
|
2630
|
+
// Host scans can run alongside the full portfolio test matrix. Keep the
|
|
2631
|
+
// probe bounded, but leave enough headroom for a busy Node process to
|
|
2632
|
+
// spawn the pinned CLI instead of misclassifying a slow start as an
|
|
2633
|
+
// unparseable version.
|
|
2634
|
+
timeout: 1e4
|
|
2635
|
+
});
|
|
2636
|
+
if (result.error || result.status !== 0) throw result.error ?? new Error("command failed");
|
|
2637
|
+
const output = result.stdout.trim();
|
|
2598
2638
|
const installedVersion = output.match(/(?:^|\s)(\d+\.\d+\.\d+)(?:\s|$)/)?.[1];
|
|
2599
2639
|
if (!installedVersion) {
|
|
2600
2640
|
return {
|
|
@@ -2753,7 +2793,12 @@ function inspectFindings(homePath) {
|
|
|
2753
2793
|
id: "pnpm-store",
|
|
2754
2794
|
rootId: "pnpm-store",
|
|
2755
2795
|
label: "pnpm \u672A\u5F15\u7528\u5305\u5019\u9009",
|
|
2756
|
-
paths: [
|
|
2796
|
+
paths: [
|
|
2797
|
+
join14(
|
|
2798
|
+
homePath,
|
|
2799
|
+
process.platform === "win32" ? "AppData/Local/pnpm/store" : "Library/pnpm/store"
|
|
2800
|
+
)
|
|
2801
|
+
],
|
|
2757
2802
|
category: "cache",
|
|
2758
2803
|
confidence: "high",
|
|
2759
2804
|
disposition: "native-tool",
|
|
@@ -2765,7 +2810,13 @@ function inspectFindings(homePath) {
|
|
|
2765
2810
|
id: "playwright-browsers",
|
|
2766
2811
|
rootId: "playwright",
|
|
2767
2812
|
label: "Playwright \u6D4F\u89C8\u5668\u7248\u672C",
|
|
2768
|
-
paths: [
|
|
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
|
+
],
|
|
2769
2820
|
category: "duplicate-runtime",
|
|
2770
2821
|
confidence: "medium",
|
|
2771
2822
|
disposition: "native-tool",
|
|
@@ -2787,6 +2838,8 @@ function inspectFindings(homePath) {
|
|
|
2787
2838
|
});
|
|
2788
2839
|
}
|
|
2789
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";
|
|
2790
2843
|
return [
|
|
2791
2844
|
{
|
|
2792
2845
|
label: "\u914D\u7F6E\u4E0E\u8EAB\u4EFD\u8FB9\u754C",
|
|
@@ -2805,7 +2858,7 @@ function buildProtections(homePath) {
|
|
|
2805
2858
|
},
|
|
2806
2859
|
{
|
|
2807
2860
|
label: "\u684C\u9762\u5BBF\u4E3B\u8FD0\u884C\u6570\u636E",
|
|
2808
|
-
paths: [
|
|
2861
|
+
paths: [claudeDesktopPath, cursorDesktopPath],
|
|
2809
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"
|
|
2810
2863
|
}
|
|
2811
2864
|
].map((protection) => ({
|
|
@@ -2889,7 +2942,7 @@ function displayPath(path, homePath) {
|
|
|
2889
2942
|
const absolute = resolve3(path);
|
|
2890
2943
|
const withinHome = relative6(homePath, absolute);
|
|
2891
2944
|
if (withinHome === "") return "~";
|
|
2892
|
-
if (!withinHome.startsWith("..")) return `~/${withinHome}`;
|
|
2945
|
+
if (!withinHome.startsWith("..")) return `~/${withinHome.replaceAll("\\", "/")}`;
|
|
2893
2946
|
return absolute;
|
|
2894
2947
|
}
|
|
2895
2948
|
function undisplayPath(path, homePath) {
|
|
@@ -4782,7 +4835,7 @@ function formatLink(link) {
|
|
|
4782
4835
|
}
|
|
4783
4836
|
|
|
4784
4837
|
// src/lens/scan.ts
|
|
4785
|
-
import { spawnSync as
|
|
4838
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
4786
4839
|
import { existsSync as existsSync21, readFileSync as readFileSync13, statSync as statSync6 } from "node:fs";
|
|
4787
4840
|
import { homedir as homedir3 } from "node:os";
|
|
4788
4841
|
import { join as join22 } from "node:path";
|
|
@@ -4858,7 +4911,7 @@ function inspectCompatibilityLink(root, path, expectedRawTarget) {
|
|
|
4858
4911
|
if (stat.isDirectory()) return { ...base, status: "directory" };
|
|
4859
4912
|
return { ...base, status: "other" };
|
|
4860
4913
|
}
|
|
4861
|
-
const rawTarget = readlinkSync3(absolutePath);
|
|
4914
|
+
const rawTarget = normalizeSymlinkTarget(readlinkSync3(absolutePath));
|
|
4862
4915
|
const resolvedTarget = resolve6(dirname12(absolutePath), rawTarget);
|
|
4863
4916
|
const expectedPath = resolve6(dirname12(absolutePath), expectedRawTarget);
|
|
4864
4917
|
const targetStat = safeLstat2(resolvedTarget);
|
|
@@ -5064,7 +5117,7 @@ function readPackageJson(path) {
|
|
|
5064
5117
|
}
|
|
5065
5118
|
|
|
5066
5119
|
// src/repository-files.ts
|
|
5067
|
-
import { spawnSync as
|
|
5120
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
5068
5121
|
import { existsSync as existsSync20, readdirSync as readdirSync10 } from "node:fs";
|
|
5069
5122
|
import { isAbsolute as isAbsolute5, join as join21, posix as posix3, relative as relative9 } from "node:path";
|
|
5070
5123
|
var gitMaxBufferBytes = 64 * 1024 * 1024;
|
|
@@ -5147,7 +5200,7 @@ function isSafeRepositoryRelativePath(path) {
|
|
|
5147
5200
|
return path !== "" && path !== "." && !isAbsolute5(path) && !/^[a-zA-Z]:\//.test(path) && path !== ".." && !path.startsWith("../");
|
|
5148
5201
|
}
|
|
5149
5202
|
function runGit(root, args) {
|
|
5150
|
-
const result =
|
|
5203
|
+
const result = spawnSync2("git", ["-C", root, ...args], {
|
|
5151
5204
|
encoding: "utf8",
|
|
5152
5205
|
maxBuffer: gitMaxBufferBytes,
|
|
5153
5206
|
env: { ...process.env, LANG: "C", LC_ALL: "C" }
|
|
@@ -5230,7 +5283,7 @@ function readGitState(targetDir) {
|
|
|
5230
5283
|
};
|
|
5231
5284
|
}
|
|
5232
5285
|
function runGit2(targetDir, args) {
|
|
5233
|
-
const result =
|
|
5286
|
+
const result = spawnSync3("git", ["-C", targetDir, ...args], {
|
|
5234
5287
|
encoding: "utf8",
|
|
5235
5288
|
maxBuffer: 64 * 1024 * 1024
|
|
5236
5289
|
});
|
|
@@ -5408,7 +5461,7 @@ import { existsSync as existsSync33, readFileSync as readFileSync18 } from "node
|
|
|
5408
5461
|
import { join as join34 } from "node:path";
|
|
5409
5462
|
|
|
5410
5463
|
// src/portfolio/doctor.ts
|
|
5411
|
-
import { spawnSync as
|
|
5464
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5412
5465
|
import { existsSync as existsSync24, readFileSync as readFileSync16 } from "node:fs";
|
|
5413
5466
|
import { createRequire as createRequire2 } from "node:module";
|
|
5414
5467
|
import { homedir as homedir4 } from "node:os";
|
|
@@ -5416,7 +5469,6 @@ import { dirname as dirname15, join as join25 } from "node:path";
|
|
|
5416
5469
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
5417
5470
|
|
|
5418
5471
|
// src/host-tooling/inventory.ts
|
|
5419
|
-
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5420
5472
|
function inspectHostTooling(requirements, runner = defaultRunner2) {
|
|
5421
5473
|
const hosts = [];
|
|
5422
5474
|
const issues = [];
|
|
@@ -5490,7 +5542,7 @@ function parseHostPlugins(host, value) {
|
|
|
5490
5542
|
});
|
|
5491
5543
|
}
|
|
5492
5544
|
function defaultRunner2({ command: command2 }) {
|
|
5493
|
-
const result =
|
|
5545
|
+
const result = spawnPlatformSync(command2[0] ?? "", command2.slice(1), {
|
|
5494
5546
|
encoding: "utf8",
|
|
5495
5547
|
timeout: 1e4
|
|
5496
5548
|
});
|
|
@@ -5605,7 +5657,7 @@ function pathIsSymlink(path) {
|
|
|
5605
5657
|
}
|
|
5606
5658
|
|
|
5607
5659
|
// src/portfolio/version-policy.ts
|
|
5608
|
-
import { spawnSync as
|
|
5660
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
5609
5661
|
import { existsSync as existsSync23, lstatSync as lstatSync9, readFileSync as readFileSync15 } from "node:fs";
|
|
5610
5662
|
import { dirname as dirname14, join as join24 } from "node:path";
|
|
5611
5663
|
function inspectVersionPolicy(root, policy, projectType) {
|
|
@@ -5697,7 +5749,7 @@ function inspectRuntime(expectedName, expectedVersion) {
|
|
|
5697
5749
|
function readRuntimeVersion(name) {
|
|
5698
5750
|
if (name === "node") return process.versions.node;
|
|
5699
5751
|
if (name !== "deno") return void 0;
|
|
5700
|
-
const result =
|
|
5752
|
+
const result = spawnSync4("deno", ["--version"], { encoding: "utf8" });
|
|
5701
5753
|
if (result.status !== 0) return void 0;
|
|
5702
5754
|
return /^deno\s+(\d+\.\d+\.\d+)/m.exec(result.stdout)?.[1];
|
|
5703
5755
|
}
|
|
@@ -5915,7 +5967,7 @@ function runTargetChecks(target) {
|
|
|
5915
5967
|
];
|
|
5916
5968
|
return commands.map((command2) => {
|
|
5917
5969
|
if (!existsSync24(command2.cli)) return { name: command2.name, status: null };
|
|
5918
|
-
const result =
|
|
5970
|
+
const result = spawnSync5(process.execPath, [command2.cli, ...command2.args], {
|
|
5919
5971
|
cwd: target.path,
|
|
5920
5972
|
encoding: "utf8",
|
|
5921
5973
|
timeout: 3e4
|
|
@@ -5924,13 +5976,13 @@ function runTargetChecks(target) {
|
|
|
5924
5976
|
});
|
|
5925
5977
|
}
|
|
5926
5978
|
function inspectGit(path) {
|
|
5927
|
-
const inside =
|
|
5979
|
+
const inside = spawnSync5("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
5928
5980
|
cwd: path,
|
|
5929
5981
|
encoding: "utf8"
|
|
5930
5982
|
});
|
|
5931
5983
|
if (inside.status !== 0) return { isRepository: false, dirty: false };
|
|
5932
|
-
const status =
|
|
5933
|
-
const branch =
|
|
5984
|
+
const status = spawnSync5("git", ["status", "--porcelain"], { cwd: path, encoding: "utf8" });
|
|
5985
|
+
const branch = spawnSync5("git", ["branch", "--show-current"], { cwd: path, encoding: "utf8" });
|
|
5934
5986
|
return {
|
|
5935
5987
|
isRepository: true,
|
|
5936
5988
|
dirty: status.stdout.trim().length > 0,
|
|
@@ -5999,12 +6051,13 @@ function safeRealpath(path) {
|
|
|
5999
6051
|
}
|
|
6000
6052
|
function commandVersion(command2) {
|
|
6001
6053
|
try {
|
|
6002
|
-
const
|
|
6054
|
+
const result = spawnPlatformSync(command2, ["version"], {
|
|
6003
6055
|
encoding: "utf8",
|
|
6004
6056
|
stdio: ["ignore", "pipe", "ignore"],
|
|
6005
6057
|
timeout: 3e3
|
|
6006
6058
|
});
|
|
6007
|
-
|
|
6059
|
+
if (result.error || result.status !== 0) return void 0;
|
|
6060
|
+
return result.stdout.match(/\b\d+\.\d+\.\d+\b/)?.[0];
|
|
6008
6061
|
} catch {
|
|
6009
6062
|
return void 0;
|
|
6010
6063
|
}
|
|
@@ -6285,12 +6338,10 @@ function inspectGit2(root) {
|
|
|
6285
6338
|
}
|
|
6286
6339
|
|
|
6287
6340
|
// src/portfolio/ai-health/hosts.ts
|
|
6288
|
-
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
6289
6341
|
import { existsSync as existsSync28 } from "node:fs";
|
|
6290
6342
|
import { join as join28, resolve as resolve8, sep as sep3 } from "node:path";
|
|
6291
6343
|
|
|
6292
6344
|
// src/portfolio/ai-health/devspace.ts
|
|
6293
|
-
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
6294
6345
|
import { existsSync as existsSync27, statSync as statSync8 } from "node:fs";
|
|
6295
6346
|
import { join as join27, relative as relative10, resolve as resolve7, sep as sep2 } from "node:path";
|
|
6296
6347
|
function inspectDevSpaceHealth(options) {
|
|
@@ -6306,9 +6357,9 @@ function inspectDevSpaceHealth(options) {
|
|
|
6306
6357
|
5e3
|
|
6307
6358
|
);
|
|
6308
6359
|
const latestVersion = latestResult.ok ? latestResult.stdout.match(/\b\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?\b/)?.[0] : void 0;
|
|
6309
|
-
const processResult = run("pgrep", ["-f", "devspace serve"], 3e3);
|
|
6310
|
-
const pid = processResult.ok ? processResult.stdout.match(/\b\d+\b/)?.[0] : void 0;
|
|
6311
|
-
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;
|
|
6312
6363
|
const processToolMode = processEnvironment?.ok ? processEnvironment.stdout.match(
|
|
6313
6364
|
/(?:^|\s)DEVSPACE_TOOL_MODE=(minimal|full|codex)(?:\s|$)/
|
|
6314
6365
|
)?.[1] : void 0;
|
|
@@ -6320,9 +6371,9 @@ function inspectDevSpaceHealth(options) {
|
|
|
6320
6371
|
(repositoryPath) => allowedRoots.some((root) => isPathInside(repositoryPath, root))
|
|
6321
6372
|
) ? "complete" : "partial";
|
|
6322
6373
|
const bind = configExists && typeof configValue.host === "string" ? isLoopbackHost(configValue.host) ? "loopback" : "non-loopback" : "unknown";
|
|
6323
|
-
const directoryMode = existsSync27(configDirectory) ? modeString(statSync8(configDirectory).mode) : void 0;
|
|
6324
|
-
const fileMode = existsSync27(configPath) ? modeString(statSync8(configPath).mode) : void 0;
|
|
6325
|
-
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;
|
|
6326
6377
|
const update = installedVersion && latestVersion ? installedVersion === latestVersion ? "current" : "available" : "unknown";
|
|
6327
6378
|
const recommendations = [];
|
|
6328
6379
|
let status = "healthy";
|
|
@@ -6346,7 +6397,7 @@ function inspectDevSpaceHealth(options) {
|
|
|
6346
6397
|
if (doctor === "failed") unhealthy("devspace doctor \u672A\u901A\u8FC7\u3002");
|
|
6347
6398
|
if (portfolioCoverage === "partial") attention("DevSpace allowedRoots \u6CA1\u6709\u8986\u76D6\u5168\u90E8\u5DF2\u767B\u8BB0\u4ED3\u5E93\u3002");
|
|
6348
6399
|
if (installedResult.ok && !pid) attention("DevSpace \u5DF2\u5B89\u88C5\u4F46\u5F53\u524D\u6CA1\u6709\u8FD0\u884C\u3002");
|
|
6349
|
-
if (options.expectedToolMode && pid && processToolMode !== options.expectedToolMode) {
|
|
6400
|
+
if (options.expectedToolMode && pid && processToolMode !== void 0 && processToolMode !== options.expectedToolMode) {
|
|
6350
6401
|
attention(
|
|
6351
6402
|
`\u8FD0\u884C\u4E2D\u7684 DevSpace \u5DE5\u5177\u6A21\u5F0F\u4E3A ${processToolMode ?? "unknown"}\uFF0C\u671F\u671B ${options.expectedToolMode}\u3002`
|
|
6352
6403
|
);
|
|
@@ -6381,18 +6432,12 @@ function inspectDevSpaceHealth(options) {
|
|
|
6381
6432
|
};
|
|
6382
6433
|
}
|
|
6383
6434
|
function runDevSpaceCommand(command2, args, timeout) {
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
timeout
|
|
6391
|
-
})
|
|
6392
|
-
};
|
|
6393
|
-
} catch {
|
|
6394
|
-
return { ok: false, stdout: "" };
|
|
6395
|
-
}
|
|
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 };
|
|
6396
6441
|
}
|
|
6397
6442
|
function isLoopbackHost(host) {
|
|
6398
6443
|
return ["127.0.0.1", "localhost", "::1"].includes(host.trim().toLowerCase());
|
|
@@ -6483,16 +6528,16 @@ function inspectGrokProject(root, homeDir, grokVersion) {
|
|
|
6483
6528
|
});
|
|
6484
6529
|
if (!grokVersion) return empty("unavailable");
|
|
6485
6530
|
try {
|
|
6486
|
-
const
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
);
|
|
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);
|
|
6496
6541
|
if (!isRecord3(value)) return empty("failed");
|
|
6497
6542
|
const userClaudeNames = new Set(
|
|
6498
6543
|
jsonObjectKeys(join28(homeDir, MCP_DISCOVERY_PATHS.user.claudeCode), "mcpServers")
|
|
@@ -6580,6 +6625,7 @@ function inferGrokMcpScope(name, sourceType, sourcePath, root, homeDir, userClau
|
|
|
6580
6625
|
// src/portfolio/ai-health/secrets.ts
|
|
6581
6626
|
import { existsSync as existsSync29, lstatSync as lstatSync12, readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
|
|
6582
6627
|
import { join as join29, relative as relative11, sep as sep4 } from "node:path";
|
|
6628
|
+
var supportsPosixModes = process.platform !== "win32";
|
|
6583
6629
|
function inspectRepositorySecrets(root, id, secretsRoot, isRepository, environmentPolicy) {
|
|
6584
6630
|
const centralPath = join29(secretsRoot, id);
|
|
6585
6631
|
const centralRealPath = safeRealpath(centralPath);
|
|
@@ -6601,7 +6647,7 @@ function inspectRepositorySecrets(root, id, secretsRoot, isRepository, environme
|
|
|
6601
6647
|
});
|
|
6602
6648
|
return {
|
|
6603
6649
|
centralDirectory: existsSync29(centralPath) ? "present" : "absent",
|
|
6604
|
-
centralMode: existsSync29(centralPath) ? modeString(statSync9(centralPath).mode) : void 0,
|
|
6650
|
+
centralMode: supportsPosixModes && existsSync29(centralPath) ? modeString(statSync9(centralPath).mode) : void 0,
|
|
6605
6651
|
centralFiles: existsSync29(centralPath) ? collectCentralSecretFiles(centralPath) : [],
|
|
6606
6652
|
repositoryEnvFiles: envFiles
|
|
6607
6653
|
};
|
|
@@ -6630,7 +6676,7 @@ function collectEnvironmentFiles(root, current = root, depth = 0) {
|
|
|
6630
6676
|
if (!SKIP_ENV_DIRECTORIES.has(entry.name))
|
|
6631
6677
|
found.push(...collectEnvironmentFiles(root, join29(current, entry.name), depth + 1));
|
|
6632
6678
|
} else if (isEnvironmentFilename(entry.name) && !isProviderGeneratedEnvironmentFile(entry.name)) {
|
|
6633
|
-
found.push(relative11(root, join29(current, entry.name)));
|
|
6679
|
+
found.push(relative11(root, join29(current, entry.name)).replaceAll("\\", "/"));
|
|
6634
6680
|
}
|
|
6635
6681
|
}
|
|
6636
6682
|
} catch {
|
|
@@ -6645,7 +6691,11 @@ function collectCentralSecretFiles(root, current = root, depth = 0) {
|
|
|
6645
6691
|
for (const entry of readdirSync12(current, { withFileTypes: true })) {
|
|
6646
6692
|
const path = join29(current, entry.name);
|
|
6647
6693
|
if (entry.isDirectory()) found.push(...collectCentralSecretFiles(root, path, depth + 1));
|
|
6648
|
-
else
|
|
6694
|
+
else
|
|
6695
|
+
found.push({
|
|
6696
|
+
path: relative11(root, path).replaceAll("\\", "/"),
|
|
6697
|
+
mode: supportsPosixModes ? modeString(lstatSync12(path).mode) : "unknown"
|
|
6698
|
+
});
|
|
6649
6699
|
}
|
|
6650
6700
|
} catch {
|
|
6651
6701
|
return found;
|
|
@@ -6676,10 +6726,15 @@ function pointsInside(path, expectedRoot) {
|
|
|
6676
6726
|
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${sep4}`);
|
|
6677
6727
|
}
|
|
6678
6728
|
function hasUnsafeCentralSecretPermissions(secrets) {
|
|
6729
|
+
if (!supportsPosixModes) return false;
|
|
6679
6730
|
return secrets.centralDirectory === "present" && (secrets.centralMode !== "700" || secrets.centralFiles.some((file) => file.mode !== "600"));
|
|
6680
6731
|
}
|
|
6681
6732
|
function inspectSecretsRoot(path) {
|
|
6682
|
-
return existsSync29(path) ? {
|
|
6733
|
+
return existsSync29(path) ? {
|
|
6734
|
+
path,
|
|
6735
|
+
exists: true,
|
|
6736
|
+
...supportsPosixModes ? { mode: modeString(statSync9(path).mode) } : {}
|
|
6737
|
+
} : { path, exists: false };
|
|
6683
6738
|
}
|
|
6684
6739
|
|
|
6685
6740
|
// src/portfolio/ai-health/skills.ts
|
|
@@ -7918,9 +7973,10 @@ function findPortfolioAgentAssetsDir(manifest) {
|
|
|
7918
7973
|
}
|
|
7919
7974
|
function reportMissingPortfolioRegistry(loaded, json) {
|
|
7920
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("\\", "/");
|
|
7921
7977
|
const issue = {
|
|
7922
7978
|
type: "missing-control-plane-registry",
|
|
7923
|
-
message: `Portfolio control-plane registry is required at ${
|
|
7979
|
+
message: `Portfolio control-plane registry is required at ${displayExpectedPath}; refusing the package fallback registry.`
|
|
7924
7980
|
};
|
|
7925
7981
|
if (json) {
|
|
7926
7982
|
console.log(
|
|
@@ -8015,7 +8071,7 @@ function runSync(args) {
|
|
|
8015
8071
|
continue;
|
|
8016
8072
|
}
|
|
8017
8073
|
if (file.kind === "symlink") {
|
|
8018
|
-
if (!stat.isSymbolicLink() || readlinkSync4(targetPath) !== file.linkTarget) {
|
|
8074
|
+
if (!stat.isSymbolicLink() || normalizeSymlinkTarget(readlinkSync4(targetPath)) !== file.linkTarget) {
|
|
8019
8075
|
console.log(`different: ${file.targetPath}`);
|
|
8020
8076
|
differences += 1;
|
|
8021
8077
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pieai/pro-gov",
|
|
3
|
-
"version": "0.9.
|
|
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.
|
|
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
|
|
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"
|