@pieai/pro-gov 0.5.3 → 0.5.4
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/cli.js
CHANGED
|
@@ -3585,25 +3585,35 @@ import {
|
|
|
3585
3585
|
statSync as statSync4,
|
|
3586
3586
|
writeFileSync as writeFileSync7
|
|
3587
3587
|
} from "node:fs";
|
|
3588
|
+
import { homedir } from "node:os";
|
|
3588
3589
|
import { dirname as dirname12, join as join20, relative as relative8, resolve as resolve4, sep } from "node:path";
|
|
3589
3590
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
3590
3591
|
function inspectPortfolioAiHealth(options) {
|
|
3591
3592
|
const endpoints = collectEndpoints(options.manifest);
|
|
3592
3593
|
const secretsRoot = options.secretsRoot ?? join20(dirname12(options.manifest.controlPlane?.path ?? endpoints[0]?.endpoint.path ?? process.cwd()), ".secrets");
|
|
3593
|
-
const homeDir = options.homeDir ?? process.env.HOME ??
|
|
3594
|
+
const homeDir = options.homeDir ?? process.env.HOME ?? homedir();
|
|
3595
|
+
const grokVersion = commandVersion("grok");
|
|
3594
3596
|
const executionEngineRoot = options.manifest.executionEngine?.path;
|
|
3595
3597
|
const skillRegistry = inspectSkillRegistry(executionEngineRoot);
|
|
3596
3598
|
const expectedPackageVersion = packageVersion(join20(executionEngineRoot ?? "", "packages/pro-gov/package.json"));
|
|
3597
|
-
const repositories = endpoints.map(({ endpoint, role }) => inspectRepository(
|
|
3599
|
+
const repositories = endpoints.map(({ endpoint, role }) => inspectRepository(
|
|
3600
|
+
endpoint,
|
|
3601
|
+
role,
|
|
3602
|
+
secretsRoot,
|
|
3603
|
+
homeDir,
|
|
3604
|
+
expectedPackageVersion,
|
|
3605
|
+
options.manifest.technologyGovernance,
|
|
3606
|
+
grokVersion
|
|
3607
|
+
));
|
|
3598
3608
|
const summary = { healthy: 0, attention: 0, unhealthy: 0 };
|
|
3599
3609
|
for (const repository of repositories) summary[repository.status] += 1;
|
|
3600
3610
|
return {
|
|
3601
|
-
schemaVersion:
|
|
3611
|
+
schemaVersion: 2,
|
|
3602
3612
|
portfolioId: options.manifest.portfolioId,
|
|
3603
3613
|
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3604
|
-
privacy: "Names, paths, counts, and configuration
|
|
3614
|
+
privacy: "Names, paths, counts, scopes, and configuration origins only. Secret values, environment values, MCP commands, arguments, URLs, headers, and MCP environment maps are never retained or rendered.",
|
|
3605
3615
|
secretsRoot: inspectSecretsRoot(secretsRoot),
|
|
3606
|
-
|
|
3616
|
+
hostEnvironment: inspectHostEnvironment(homeDir, grokVersion),
|
|
3607
3617
|
skillRegistry,
|
|
3608
3618
|
technologyGovernance: {
|
|
3609
3619
|
strategySource: options.manifest.technologyGovernance?.strategySource,
|
|
@@ -3643,17 +3653,21 @@ function collectEndpoints(manifest) {
|
|
|
3643
3653
|
return true;
|
|
3644
3654
|
});
|
|
3645
3655
|
}
|
|
3646
|
-
function inspectRepository(endpoint, role, secretsRoot, expectedPackageVersion, technologyGovernance) {
|
|
3656
|
+
function inspectRepository(endpoint, role, secretsRoot, homeDir, expectedPackageVersion, technologyGovernance, grokVersion) {
|
|
3647
3657
|
const root = endpoint.path;
|
|
3648
3658
|
const git = inspectGit2(root);
|
|
3649
3659
|
const entries = inspectEntries(root);
|
|
3650
|
-
const
|
|
3660
|
+
const grokInspection = inspectGrokProject(root, homeDir, grokVersion);
|
|
3661
|
+
const skills = inspectSkills(root, grokInspection);
|
|
3651
3662
|
const hooks = inspectHooks(root);
|
|
3652
3663
|
const docs = inspectDocs(root, role === "execution-engine" ? void 0 : expectedPackageVersion);
|
|
3653
3664
|
const mcp = {
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3665
|
+
codexProject: tomlMcpNames(join20(root, ".codex/config.toml")),
|
|
3666
|
+
claudeCodeProjectShared: jsonObjectKeys(join20(root, ".mcp.json"), "mcpServers"),
|
|
3667
|
+
claudeCodeProjectLocal: claudeProjectLocalMcpNames(homeDir, root),
|
|
3668
|
+
grokProject: tomlMcpNames(join20(root, ".grok/config.toml")),
|
|
3669
|
+
grokEffective: grokInspection.effectiveMcp,
|
|
3670
|
+
grokInspection: grokInspection.inspection
|
|
3657
3671
|
};
|
|
3658
3672
|
const secrets = inspectRepositorySecrets(root, endpoint.id, secretsRoot, git.isRepository, endpoint.environmentPolicy);
|
|
3659
3673
|
const projectModel = inspectProjectModel(root, endpoint, technologyGovernance);
|
|
@@ -3821,7 +3835,7 @@ function inspectOptionalEntry(root, filename, agentsPath) {
|
|
|
3821
3835
|
const content = safeRead(path);
|
|
3822
3836
|
return /AGENTS\.md/.test(content) && content.length < 2e3 ? "thin-adapter" : "custom";
|
|
3823
3837
|
}
|
|
3824
|
-
function inspectSkills(root) {
|
|
3838
|
+
function inspectSkills(root, grokInspection) {
|
|
3825
3839
|
const lock = readJson3(join20(root, ".pro-gov/assets.lock.json"));
|
|
3826
3840
|
const managed = /* @__PURE__ */ new Set();
|
|
3827
3841
|
const bundleIds = stringArray(isRecord3(lock) ? lock.bundleIds : void 0);
|
|
@@ -3857,6 +3871,12 @@ function inspectSkills(root) {
|
|
|
3857
3871
|
installed: canonical.filter((item) => item.managed && item.kind !== "dangling-symlink").length,
|
|
3858
3872
|
discoverable: canonical.filter((item) => item.kind !== "dangling-symlink").length,
|
|
3859
3873
|
runtime: "unobservable"
|
|
3874
|
+
},
|
|
3875
|
+
hosts: {
|
|
3876
|
+
codexProject: canonical.filter((item) => item.kind !== "dangling-symlink").length,
|
|
3877
|
+
claudeCodeProject: inspectSkillRoot(join20(root, ".claude/skills")).names.length,
|
|
3878
|
+
grokNativeProject: inspectSkillRoot(join20(root, ".grok/skills")).names.length,
|
|
3879
|
+
grokEffective: grokInspection.skills
|
|
3860
3880
|
}
|
|
3861
3881
|
};
|
|
3862
3882
|
}
|
|
@@ -3967,13 +3987,147 @@ function hasUnsafeCentralSecretPermissions(secrets) {
|
|
|
3967
3987
|
function inspectSecretsRoot(path) {
|
|
3968
3988
|
return existsSync21(path) ? { path, exists: true, mode: modeString(statSync4(path).mode) } : { path, exists: false };
|
|
3969
3989
|
}
|
|
3970
|
-
function
|
|
3971
|
-
|
|
3990
|
+
function inspectHostEnvironment(homeDir, grokVersion) {
|
|
3991
|
+
const codexConfig = join20(homeDir, ".codex/config.toml");
|
|
3992
|
+
const claudeConfig = join20(homeDir, ".claude.json");
|
|
3993
|
+
const grokConfig = join20(homeDir, ".grok/config.toml");
|
|
3972
3994
|
return {
|
|
3973
|
-
|
|
3974
|
-
|
|
3995
|
+
mcp: {
|
|
3996
|
+
codexUser: { path: codexConfig, names: tomlMcpNames(codexConfig) },
|
|
3997
|
+
claudeCodeUser: { path: claudeConfig, names: jsonObjectKeys(claudeConfig, "mcpServers") },
|
|
3998
|
+
grokUser: { path: grokConfig, names: tomlMcpNames(grokConfig) }
|
|
3999
|
+
},
|
|
4000
|
+
skills: {
|
|
4001
|
+
codexUser: inspectSkillRoot(join20(homeDir, ".agents/skills")),
|
|
4002
|
+
claudeCodeUser: inspectSkillRoot(join20(homeDir, ".claude/skills")),
|
|
4003
|
+
grokUser: inspectSkillRoot(join20(homeDir, ".grok/skills")),
|
|
4004
|
+
grokAgentsCompatibility: inspectSkillRoot(join20(homeDir, ".agents/skills")),
|
|
4005
|
+
grokClaudeCompatibility: inspectSkillRoot(join20(homeDir, ".claude/skills"))
|
|
4006
|
+
},
|
|
4007
|
+
grok: {
|
|
4008
|
+
available: grokVersion !== void 0,
|
|
4009
|
+
...grokVersion ? { version: grokVersion } : {},
|
|
4010
|
+
inspectionCommand: "grok inspect --json"
|
|
4011
|
+
}
|
|
3975
4012
|
};
|
|
3976
4013
|
}
|
|
4014
|
+
function inspectSkillRoot(path) {
|
|
4015
|
+
const exists = pathLexists(path) && safeIsDirectory(path);
|
|
4016
|
+
const names = exists ? safeReadDir(path).filter((name) => !name.startsWith(".") && existsSync21(join20(path, name, "SKILL.md"))) : [];
|
|
4017
|
+
return { path, exists, names };
|
|
4018
|
+
}
|
|
4019
|
+
function claudeProjectLocalMcpNames(homeDir, root) {
|
|
4020
|
+
if (!homeDir) return [];
|
|
4021
|
+
const value = readJson3(join20(homeDir, ".claude.json"));
|
|
4022
|
+
if (!isRecord3(value) || !isRecord3(value.projects)) return [];
|
|
4023
|
+
const candidates = new Set([resolve4(root), safeRealpath(root)].filter((path) => Boolean(path)));
|
|
4024
|
+
const names = /* @__PURE__ */ new Set();
|
|
4025
|
+
for (const [path, project] of Object.entries(value.projects)) {
|
|
4026
|
+
const projectPaths = [resolve4(path), safeRealpath(path)].filter((candidate) => Boolean(candidate));
|
|
4027
|
+
if (!projectPaths.some((candidate) => candidates.has(candidate)) || !isRecord3(project) || !isRecord3(project.mcpServers)) continue;
|
|
4028
|
+
for (const name of Object.keys(project.mcpServers)) names.add(name);
|
|
4029
|
+
}
|
|
4030
|
+
return [...names].sort();
|
|
4031
|
+
}
|
|
4032
|
+
function commandVersion(command2) {
|
|
4033
|
+
try {
|
|
4034
|
+
const output = execFileSync(command2, ["version"], {
|
|
4035
|
+
encoding: "utf8",
|
|
4036
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4037
|
+
timeout: 3e3
|
|
4038
|
+
});
|
|
4039
|
+
return output.match(/\b\d+\.\d+\.\d+\b/)?.[0];
|
|
4040
|
+
} catch {
|
|
4041
|
+
return void 0;
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
function inspectGrokProject(root, homeDir, grokVersion) {
|
|
4045
|
+
const empty = (inspection) => ({
|
|
4046
|
+
inspection,
|
|
4047
|
+
effectiveMcp: [],
|
|
4048
|
+
skills: { inspection, total: 0, project: 0, userOrCompatible: 0, plugin: 0, bundled: 0 },
|
|
4049
|
+
claudeCompatibility: "unknown",
|
|
4050
|
+
cursorCompatibility: "unknown"
|
|
4051
|
+
});
|
|
4052
|
+
if (!grokVersion) return empty("unavailable");
|
|
4053
|
+
try {
|
|
4054
|
+
const value = JSON.parse(execFileSync("grok", ["inspect", "--json"], {
|
|
4055
|
+
cwd: root,
|
|
4056
|
+
encoding: "utf8",
|
|
4057
|
+
env: { ...process.env, HOME: homeDir, GROK_HOME: join20(homeDir, ".grok") },
|
|
4058
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
4059
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4060
|
+
timeout: 8e3
|
|
4061
|
+
}));
|
|
4062
|
+
if (!isRecord3(value)) return empty("failed");
|
|
4063
|
+
const userClaudeNames = new Set(jsonObjectKeys(join20(homeDir, ".claude.json"), "mcpServers"));
|
|
4064
|
+
const localClaudeNames = new Set(claudeProjectLocalMcpNames(homeDir, root));
|
|
4065
|
+
const effectiveMcp = Array.isArray(value.mcpServers) ? value.mcpServers.flatMap((item) => {
|
|
4066
|
+
if (!isRecord3(item) || typeof item.name !== "string") return [];
|
|
4067
|
+
const source = isRecord3(item.source) ? item.source : {};
|
|
4068
|
+
const sourceType = typeof source.type === "string" ? source.type : "unknown";
|
|
4069
|
+
const sourcePath = typeof source.path === "string" ? source.path : void 0;
|
|
4070
|
+
const vendor = typeof item.vendor === "string" ? item.vendor : sourceType;
|
|
4071
|
+
return [{
|
|
4072
|
+
name: item.name,
|
|
4073
|
+
vendor,
|
|
4074
|
+
scope: inferGrokMcpScope(item.name, sourceType, sourcePath, root, homeDir, userClaudeNames, localClaudeNames),
|
|
4075
|
+
sourceType,
|
|
4076
|
+
...sourcePath ? { sourcePath } : {}
|
|
4077
|
+
}];
|
|
4078
|
+
}) : [];
|
|
4079
|
+
const skillCounts = { project: 0, userOrCompatible: 0, plugin: 0, bundled: 0 };
|
|
4080
|
+
if (Array.isArray(value.skills)) {
|
|
4081
|
+
for (const item of value.skills) {
|
|
4082
|
+
if (!isRecord3(item) || !isRecord3(item.source)) continue;
|
|
4083
|
+
const type = item.source.type;
|
|
4084
|
+
const path = item.source.path;
|
|
4085
|
+
if (typeof path === "string" && path.includes(sep + ".grok" + sep + "bundled" + sep)) skillCounts.bundled += 1;
|
|
4086
|
+
else if (type === "project") skillCounts.project += 1;
|
|
4087
|
+
else if (type === "plugin") skillCounts.plugin += 1;
|
|
4088
|
+
else skillCounts.userOrCompatible += 1;
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
const cells = isRecord3(value.externalCompat) && Array.isArray(value.externalCompat.cells) ? value.externalCompat.cells : [];
|
|
4092
|
+
return {
|
|
4093
|
+
inspection: "ok",
|
|
4094
|
+
effectiveMcp,
|
|
4095
|
+
skills: {
|
|
4096
|
+
inspection: "ok",
|
|
4097
|
+
total: skillCounts.project + skillCounts.userOrCompatible + skillCounts.plugin + skillCounts.bundled,
|
|
4098
|
+
...skillCounts
|
|
4099
|
+
},
|
|
4100
|
+
claudeCompatibility: compatibilityEnabled(cells, "claude"),
|
|
4101
|
+
cursorCompatibility: compatibilityEnabled(cells, "cursor")
|
|
4102
|
+
};
|
|
4103
|
+
} catch {
|
|
4104
|
+
return empty("failed");
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
function compatibilityEnabled(cells, vendor) {
|
|
4108
|
+
const matching = cells.filter((cell) => isRecord3(cell) && cell.vendor === vendor);
|
|
4109
|
+
if (matching.length === 0) return "unknown";
|
|
4110
|
+
return matching.some((cell) => isRecord3(cell) && cell.enabled === true);
|
|
4111
|
+
}
|
|
4112
|
+
function inferGrokMcpScope(name, sourceType, sourcePath, root, homeDir, userClaudeNames, localClaudeNames) {
|
|
4113
|
+
if (!sourcePath) {
|
|
4114
|
+
if (sourceType === "project") return "project";
|
|
4115
|
+
if (localClaudeNames.has(name)) return "project-local";
|
|
4116
|
+
if (userClaudeNames.has(name)) return "user";
|
|
4117
|
+
return "unknown";
|
|
4118
|
+
}
|
|
4119
|
+
const resolvedSource = safeRealpath(sourcePath) ?? resolve4(sourcePath);
|
|
4120
|
+
const resolvedRoot = safeRealpath(root) ?? resolve4(root);
|
|
4121
|
+
if (resolvedSource === join20(resolvedRoot, ".mcp.json")) return "project-shared";
|
|
4122
|
+
if (resolvedSource.startsWith(resolvedRoot + sep)) return "project";
|
|
4123
|
+
if (homeDir && resolvedSource === join20(resolve4(homeDir), ".claude.json")) {
|
|
4124
|
+
if (localClaudeNames.has(name)) return "project-local";
|
|
4125
|
+
if (userClaudeNames.has(name)) return "user";
|
|
4126
|
+
}
|
|
4127
|
+
if (homeDir && resolvedSource.startsWith(resolve4(homeDir) + sep)) return "user";
|
|
4128
|
+
if (sourceType === "project") return "project";
|
|
4129
|
+
return "unknown";
|
|
4130
|
+
}
|
|
3977
4131
|
var HOOK_EVENT_NAMES = /* @__PURE__ */ new Set([
|
|
3978
4132
|
"PreToolUse",
|
|
3979
4133
|
"PostToolUse",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pieai/pro-gov",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
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.5.
|
|
38
|
+
"@pieai/doc-gov": "^0.5.4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@pieai/swimmer-ui-kit": "1.0.1",
|