@pieai/pro-gov 0.9.0 → 0.9.1
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 +132 -65
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -211,12 +211,12 @@ function toUnixPath2(path) {
|
|
|
211
211
|
// src/asset-registry/loader.ts
|
|
212
212
|
import { createHash as createHash2 } from "node:crypto";
|
|
213
213
|
import { existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
|
|
214
|
-
import { dirname as dirname2, join as join5, relative as
|
|
214
|
+
import { dirname as dirname2, join as join5, relative as relative4 } from "node:path";
|
|
215
215
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
216
216
|
|
|
217
217
|
// src/asset-registry/registry.ts
|
|
218
|
-
import { existsSync as existsSync4, lstatSync, readdirSync as readdirSync4 } from "node:fs";
|
|
219
|
-
import { isAbsolute, join as join4, posix } from "node:path";
|
|
218
|
+
import { existsSync as existsSync4, lstatSync, readdirSync as readdirSync4, realpathSync } from "node:fs";
|
|
219
|
+
import { isAbsolute, join as join4, posix, relative as relative3, sep } from "node:path";
|
|
220
220
|
var supportedFamilies = /* @__PURE__ */ new Set([
|
|
221
221
|
"pie-skills",
|
|
222
222
|
"npx-skills",
|
|
@@ -427,6 +427,13 @@ function validateAssetRegistry(registry, options = {}) {
|
|
|
427
427
|
path: asset.sourcePath,
|
|
428
428
|
message: `Asset source path does not exist: ${asset.sourcePath}`
|
|
429
429
|
});
|
|
430
|
+
} else if (!isWithinAgentAssetsDir(options.agentAssetsDir, sourceAbsolutePath)) {
|
|
431
|
+
issues.push({
|
|
432
|
+
type: "source-target-escape",
|
|
433
|
+
id: asset.id,
|
|
434
|
+
path: asset.sourcePath,
|
|
435
|
+
message: `Asset source resolves outside agent-assets: ${asset.sourcePath}`
|
|
436
|
+
});
|
|
430
437
|
} else if (asset.kind === "skill") {
|
|
431
438
|
if (asset.sourceKind === "local-pack") {
|
|
432
439
|
if (!isLocalSkillPack(sourceAbsolutePath)) {
|
|
@@ -483,6 +490,16 @@ function isSafeRegistrySourcePath(sourcePath) {
|
|
|
483
490
|
function normalizeRegistrySourcePath(sourcePath) {
|
|
484
491
|
return posix.normalize(sourcePath.replaceAll("\\", "/"));
|
|
485
492
|
}
|
|
493
|
+
function isWithinAgentAssetsDir(agentAssetsDir, sourceAbsolutePath) {
|
|
494
|
+
try {
|
|
495
|
+
const agentAssetsRealPath = realpathSync(agentAssetsDir);
|
|
496
|
+
const sourceRealPath = realpathSync(sourceAbsolutePath);
|
|
497
|
+
const relativePath = relative3(agentAssetsRealPath, sourceRealPath);
|
|
498
|
+
return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);
|
|
499
|
+
} catch {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
486
503
|
function pathExistsEvenIfDanglingSymlink(path) {
|
|
487
504
|
try {
|
|
488
505
|
lstatSync(path);
|
|
@@ -544,7 +561,7 @@ function hashAgentAssetContent(asset, agentAssetsDir) {
|
|
|
544
561
|
function hashAssetPathContent(sourceAbsolutePath) {
|
|
545
562
|
const hash = createHash2("sha256");
|
|
546
563
|
for (const filePath of listFiles3(sourceAbsolutePath)) {
|
|
547
|
-
const relativePath = toUnixPath3(
|
|
564
|
+
const relativePath = toUnixPath3(relative4(sourceAbsolutePath, filePath));
|
|
548
565
|
hash.update(relativePath);
|
|
549
566
|
hash.update("\0");
|
|
550
567
|
hash.update(readFileSync3(filePath));
|
|
@@ -712,15 +729,15 @@ import {
|
|
|
712
729
|
lstatSync as lstatSync3,
|
|
713
730
|
mkdirSync as mkdirSync2,
|
|
714
731
|
readlinkSync as readlinkSync2,
|
|
715
|
-
realpathSync as
|
|
732
|
+
realpathSync as realpathSync3,
|
|
716
733
|
symlinkSync,
|
|
717
734
|
unlinkSync,
|
|
718
735
|
writeFileSync
|
|
719
736
|
} from "node:fs";
|
|
720
|
-
import { dirname as dirname4, join as join8, relative as
|
|
737
|
+
import { dirname as dirname4, join as join8, relative as relative5, resolve as resolve2 } from "node:path";
|
|
721
738
|
|
|
722
739
|
// src/asset-targets/install-plan.ts
|
|
723
|
-
import { existsSync as existsSync7, lstatSync as lstatSync2, readFileSync as readFileSync4, readlinkSync, realpathSync, statSync as statSync3 } from "node:fs";
|
|
740
|
+
import { existsSync as existsSync7, lstatSync as lstatSync2, readFileSync as readFileSync4, readlinkSync, realpathSync as realpathSync2, statSync as statSync3 } from "node:fs";
|
|
724
741
|
import { basename, dirname as dirname3, join as join7, resolve } from "node:path";
|
|
725
742
|
function createAssetInstallPlan(options) {
|
|
726
743
|
const placement = options.placement ?? "registry";
|
|
@@ -872,7 +889,7 @@ function createAssetAction(asset, agentAssetsDir, targetDir, host, placement, ma
|
|
|
872
889
|
if (managedEntry && managedEntry.delivery === "snapshot") {
|
|
873
890
|
throw new Error(`Refusing to replace managed snapshot with a symlink: ${targetPath}`);
|
|
874
891
|
}
|
|
875
|
-
if (stats.isSymbolicLink() && existsSync7(targetAbsolutePath) &&
|
|
892
|
+
if (stats.isSymbolicLink() && existsSync7(targetAbsolutePath) && realpathSync2(targetAbsolutePath) === realpathSync2(sourcePath)) {
|
|
876
893
|
return {
|
|
877
894
|
type: "adopt-existing-symlink",
|
|
878
895
|
assetId: asset.id,
|
|
@@ -913,7 +930,7 @@ function createSnapshotAction(options) {
|
|
|
913
930
|
}
|
|
914
931
|
const stats = lstatSync2(options.targetAbsolutePath);
|
|
915
932
|
if (stats.isSymbolicLink()) {
|
|
916
|
-
if (existsSync7(options.targetAbsolutePath) &&
|
|
933
|
+
if (existsSync7(options.targetAbsolutePath) && realpathSync2(options.targetAbsolutePath) === realpathSync2(options.sourcePath) && hashAssetPathContent(options.targetAbsolutePath) === contentHash) {
|
|
917
934
|
return {
|
|
918
935
|
type: "migrate-symlink-to-snapshot",
|
|
919
936
|
assetId: options.asset.id,
|
|
@@ -1031,7 +1048,7 @@ function createLegacyClaudeAdoptions(options) {
|
|
|
1031
1048
|
const targetAbsolutePath = join7(options.targetDir, targetPath);
|
|
1032
1049
|
const compatibilityRootPath = join7(options.targetDir, ".claude/skills");
|
|
1033
1050
|
const canonicalRootPath = join7(options.targetDir, ".agents/skills");
|
|
1034
|
-
if (!lstatSync2(canonicalRootPath).isDirectory() || !lstatSync2(compatibilityRootPath).isSymbolicLink() || readlinkSync(compatibilityRootPath) !== "../.agents/skills" ||
|
|
1051
|
+
if (!lstatSync2(canonicalRootPath).isDirectory() || !lstatSync2(compatibilityRootPath).isSymbolicLink() || readlinkSync(compatibilityRootPath) !== "../.agents/skills" || realpathSync2(compatibilityRootPath) !== realpathSync2(canonicalRootPath)) {
|
|
1035
1052
|
throw new Error(
|
|
1036
1053
|
`Legacy Claude compatibility root is not the exact canonical alias for ${entry.id}.`
|
|
1037
1054
|
);
|
|
@@ -1044,7 +1061,7 @@ function createLegacyClaudeAdoptions(options) {
|
|
|
1044
1061
|
const legacyAbsolutePath = join7(options.targetDir, entry.targetPath);
|
|
1045
1062
|
const legacyStat = lstatSync2(legacyAbsolutePath);
|
|
1046
1063
|
const expectedSourcePath = join7(options.agentAssetsDir, entry.sourcePath);
|
|
1047
|
-
if (!targetStat.isSymbolicLink() || !legacyStat.isSymbolicLink() || targetStat.dev !== legacyStat.dev || targetStat.ino !== legacyStat.ino ||
|
|
1064
|
+
if (!targetStat.isSymbolicLink() || !legacyStat.isSymbolicLink() || targetStat.dev !== legacyStat.dev || targetStat.ino !== legacyStat.ino || realpathSync2(targetAbsolutePath) !== realpathSync2(expectedSourcePath)) {
|
|
1048
1065
|
throw new Error(`Legacy Claude skill target cannot be safely adopted: ${entry.targetPath}`);
|
|
1049
1066
|
}
|
|
1050
1067
|
const action = {
|
|
@@ -1175,7 +1192,7 @@ function applyAction(targetDir, action) {
|
|
|
1175
1192
|
}
|
|
1176
1193
|
mkdirSync2(dirname4(targetAbsolutePath), { recursive: true });
|
|
1177
1194
|
const sourceAbsolutePath = resolve2(action.sourcePath);
|
|
1178
|
-
const symlinkTarget =
|
|
1195
|
+
const symlinkTarget = relative5(realpathSync3(dirname4(targetAbsolutePath)), realpathSync3(sourceAbsolutePath)) || ".";
|
|
1179
1196
|
if (action.type === "symlink") {
|
|
1180
1197
|
if (pathExistsEvenIfDanglingSymlink3(targetAbsolutePath)) {
|
|
1181
1198
|
throw new Error(`Refusing to overwrite unmanaged target: ${action.targetPath}`);
|
|
@@ -1199,7 +1216,7 @@ function validateExistingSymlink(targetDir, action) {
|
|
|
1199
1216
|
throw new Error(`Refusing unsafe existing symlink adoption: ${action.targetPath}`);
|
|
1200
1217
|
}
|
|
1201
1218
|
const targetAbsolutePath = join8(targetDir, action.targetPath);
|
|
1202
|
-
if (!lstatSync3(targetAbsolutePath).isSymbolicLink() ||
|
|
1219
|
+
if (!lstatSync3(targetAbsolutePath).isSymbolicLink() || realpathSync3(targetAbsolutePath) !== realpathSync3(action.sourcePath)) {
|
|
1203
1220
|
throw new Error(`Existing skill symlink changed before apply: ${action.targetPath}`);
|
|
1204
1221
|
}
|
|
1205
1222
|
}
|
|
@@ -1226,7 +1243,7 @@ function validateSnapshotAction(targetDir, action) {
|
|
|
1226
1243
|
return;
|
|
1227
1244
|
}
|
|
1228
1245
|
if (action.type === "migrate-symlink-to-snapshot") {
|
|
1229
|
-
if (!pathExistsEvenIfDanglingSymlink3(targetAbsolutePath) || !lstatSync3(targetAbsolutePath).isSymbolicLink() || !existsSync8(targetAbsolutePath) ||
|
|
1246
|
+
if (!pathExistsEvenIfDanglingSymlink3(targetAbsolutePath) || !lstatSync3(targetAbsolutePath).isSymbolicLink() || !existsSync8(targetAbsolutePath) || realpathSync3(targetAbsolutePath) !== realpathSync3(action.sourcePath) || hashAssetPathContent(targetAbsolutePath) !== action.contentHash) {
|
|
1230
1247
|
throw new Error(`Snapshot symlink changed before apply: ${action.targetPath}`);
|
|
1231
1248
|
}
|
|
1232
1249
|
return;
|
|
@@ -1272,14 +1289,14 @@ function validateAdoptedSymlink(targetDir, action) {
|
|
|
1272
1289
|
const compatibilityRootPath = join8(targetDir, action.compatibilityRootPath);
|
|
1273
1290
|
const targetAbsolutePath = join8(targetDir, action.targetPath);
|
|
1274
1291
|
const legacyAbsolutePath = join8(targetDir, action.legacyTargetPath);
|
|
1275
|
-
if (!lstatSync3(canonicalRootPath).isDirectory() || !lstatSync3(compatibilityRootPath).isSymbolicLink() || readlinkSync2(compatibilityRootPath) !== action.expectedCompatibilityRawTarget ||
|
|
1292
|
+
if (!lstatSync3(canonicalRootPath).isDirectory() || !lstatSync3(compatibilityRootPath).isSymbolicLink() || readlinkSync2(compatibilityRootPath) !== action.expectedCompatibilityRawTarget || realpathSync3(compatibilityRootPath) !== realpathSync3(canonicalRootPath)) {
|
|
1276
1293
|
throw new Error(
|
|
1277
1294
|
`Legacy Claude compatibility alias changed before apply: ${action.compatibilityRootPath}`
|
|
1278
1295
|
);
|
|
1279
1296
|
}
|
|
1280
1297
|
const targetStat = lstatSync3(targetAbsolutePath);
|
|
1281
1298
|
const legacyStat = lstatSync3(legacyAbsolutePath);
|
|
1282
|
-
if (!targetStat.isSymbolicLink() || !legacyStat.isSymbolicLink() || targetStat.dev !== legacyStat.dev || targetStat.ino !== legacyStat.ino || targetStat.dev !== action.expectedDevice || targetStat.ino !== action.expectedInode ||
|
|
1299
|
+
if (!targetStat.isSymbolicLink() || !legacyStat.isSymbolicLink() || targetStat.dev !== legacyStat.dev || targetStat.ino !== legacyStat.ino || targetStat.dev !== action.expectedDevice || targetStat.ino !== action.expectedInode || realpathSync3(targetAbsolutePath) !== realpathSync3(action.sourcePath)) {
|
|
1283
1300
|
throw new Error(`Legacy Claude skill target changed before apply: ${action.targetPath}`);
|
|
1284
1301
|
}
|
|
1285
1302
|
}
|
|
@@ -1312,7 +1329,7 @@ function pathExistsEvenIfDanglingSymlink3(path) {
|
|
|
1312
1329
|
}
|
|
1313
1330
|
|
|
1314
1331
|
// src/asset-targets/check.ts
|
|
1315
|
-
import { existsSync as existsSync9, lstatSync as lstatSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
1332
|
+
import { existsSync as existsSync9, lstatSync as lstatSync4, readFileSync as readFileSync5, realpathSync as realpathSync4 } from "node:fs";
|
|
1316
1333
|
import { join as join9 } from "node:path";
|
|
1317
1334
|
function checkInstalledAssets(options) {
|
|
1318
1335
|
const lockfilePath = join9(options.targetDir, ".pro-gov/assets.lock.json");
|
|
@@ -1469,6 +1486,18 @@ function checkInstalledAssets(options) {
|
|
|
1469
1486
|
});
|
|
1470
1487
|
continue;
|
|
1471
1488
|
}
|
|
1489
|
+
if (delivery === "symlink") {
|
|
1490
|
+
const expectedSource = realpathSync4(sourceAbsolutePath);
|
|
1491
|
+
const actualSource = realpathSync4(targetAbsolutePath);
|
|
1492
|
+
if (expectedSource !== actualSource) {
|
|
1493
|
+
issues.push({
|
|
1494
|
+
type: "symlink-source-drift",
|
|
1495
|
+
id: entry.id,
|
|
1496
|
+
targetPath: entry.targetPath,
|
|
1497
|
+
message: `Managed symlink does not resolve to its registered source: ${entry.targetPath}`
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1472
1501
|
const currentSourceHash = hashAgentAssetContent(asset, options.agentAssetsDir);
|
|
1473
1502
|
if ((delivery === "snapshot" || targetHashMatchesLock) && currentSourceHash !== entry.contentHash) {
|
|
1474
1503
|
issues.push({
|
|
@@ -2222,25 +2251,26 @@ function runPackageDoctor(_args, dependencies = {}) {
|
|
|
2222
2251
|
function runDoctor(args) {
|
|
2223
2252
|
return runPackageDoctor(args);
|
|
2224
2253
|
}
|
|
2225
|
-
function checkDocGov() {
|
|
2226
|
-
const
|
|
2254
|
+
function checkDocGov(options = {}) {
|
|
2255
|
+
const run = options.run ?? ((command2, args) => spawnSync2(command2, args, {
|
|
2227
2256
|
encoding: "utf8",
|
|
2228
2257
|
stdio: "ignore"
|
|
2229
|
-
});
|
|
2230
|
-
|
|
2231
|
-
return { ok: true, message: "doc-gov: available on PATH" };
|
|
2232
|
-
}
|
|
2233
|
-
const dependencyCli = resolveDocGovDependencyCli();
|
|
2258
|
+
}));
|
|
2259
|
+
const dependencyCli = (options.resolveDependencyCli ?? resolveDocGovDependencyCli)();
|
|
2234
2260
|
if (!dependencyCli) {
|
|
2261
|
+
const fromPath = run("doc-gov", ["--help"]);
|
|
2262
|
+
if (!fromPath.error && fromPath.status === 0) {
|
|
2263
|
+
return {
|
|
2264
|
+
ok: false,
|
|
2265
|
+
message: "doc-gov: found only on PATH; the required local @pieai/doc-gov package dependency is unavailable."
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2235
2268
|
return {
|
|
2236
2269
|
ok: false,
|
|
2237
|
-
message: "doc-gov: not found; install @pieai/doc-gov beside @pieai/pro-gov
|
|
2270
|
+
message: "doc-gov: not found; install the required @pieai/doc-gov package dependency beside @pieai/pro-gov."
|
|
2238
2271
|
};
|
|
2239
2272
|
}
|
|
2240
|
-
const fromDependency =
|
|
2241
|
-
encoding: "utf8",
|
|
2242
|
-
stdio: "ignore"
|
|
2243
|
-
});
|
|
2273
|
+
const fromDependency = run(process.execPath, [dependencyCli, "--help"]);
|
|
2244
2274
|
if (!fromDependency.error && fromDependency.status === 0) {
|
|
2245
2275
|
return { ok: true, message: "doc-gov: available via package dependency" };
|
|
2246
2276
|
}
|
|
@@ -2416,7 +2446,7 @@ import {
|
|
|
2416
2446
|
writeFileSync as writeFileSync4
|
|
2417
2447
|
} from "node:fs";
|
|
2418
2448
|
import { homedir } from "node:os";
|
|
2419
|
-
import { dirname as dirname8, join as join14, relative as
|
|
2449
|
+
import { dirname as dirname8, join as join14, relative as relative6, resolve as resolve3 } from "node:path";
|
|
2420
2450
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
2421
2451
|
var ROOT_DEFINITIONS = [
|
|
2422
2452
|
{
|
|
@@ -2857,7 +2887,7 @@ function countImmediateEntries(path) {
|
|
|
2857
2887
|
}
|
|
2858
2888
|
function displayPath(path, homePath) {
|
|
2859
2889
|
const absolute = resolve3(path);
|
|
2860
|
-
const withinHome =
|
|
2890
|
+
const withinHome = relative6(homePath, absolute);
|
|
2861
2891
|
if (withinHome === "") return "~";
|
|
2862
2892
|
if (!withinHome.startsWith("..")) return `~/${withinHome}`;
|
|
2863
2893
|
return absolute;
|
|
@@ -3983,7 +4013,7 @@ function printUsage2() {
|
|
|
3983
4013
|
|
|
3984
4014
|
// src/learning/recall.ts
|
|
3985
4015
|
import { existsSync as existsSync15, readdirSync as readdirSync8, readFileSync as readFileSync10 } from "node:fs";
|
|
3986
|
-
import { basename as basename3, join as join15, relative as
|
|
4016
|
+
import { basename as basename3, join as join15, relative as relative7 } from "node:path";
|
|
3987
4017
|
function recallLearnings(root, options) {
|
|
3988
4018
|
const query = options.query.trim();
|
|
3989
4019
|
const terms = tokenize(query);
|
|
@@ -4038,7 +4068,7 @@ function readLearningRecord(root, absolutePath) {
|
|
|
4038
4068
|
const parsed = splitFrontmatter(content);
|
|
4039
4069
|
const body = parsed.body;
|
|
4040
4070
|
return {
|
|
4041
|
-
relativePath: normalizePath(
|
|
4071
|
+
relativePath: normalizePath(relative7(root, absolutePath)),
|
|
4042
4072
|
title: findTitle(parsed.frontmatter, body) ?? titleFromPath(absolutePath),
|
|
4043
4073
|
metadata: parsed.frontmatter,
|
|
4044
4074
|
body
|
|
@@ -4120,7 +4150,7 @@ function cleanMarkdownLine(input) {
|
|
|
4120
4150
|
|
|
4121
4151
|
// src/learning/capture.ts
|
|
4122
4152
|
import { existsSync as existsSync16, mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4123
|
-
import { basename as basename4, join as join16, relative as
|
|
4153
|
+
import { basename as basename4, join as join16, relative as relative8 } from "node:path";
|
|
4124
4154
|
function captureLearning(root, options) {
|
|
4125
4155
|
const title = options.title.trim();
|
|
4126
4156
|
const summary = options.summary.trim();
|
|
@@ -4134,7 +4164,7 @@ function captureLearning(root, options) {
|
|
|
4134
4164
|
const idSlug = basename4(path, ".md");
|
|
4135
4165
|
writeFileSync6(path, renderLearning({ title, summary, category, moduleName, idSlug }));
|
|
4136
4166
|
return {
|
|
4137
|
-
relativePath: normalizePath2(
|
|
4167
|
+
relativePath: normalizePath2(relative8(root, path)),
|
|
4138
4168
|
title,
|
|
4139
4169
|
captureMode: "pgs-native"
|
|
4140
4170
|
};
|
|
@@ -4758,7 +4788,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
4758
4788
|
import { join as join22 } from "node:path";
|
|
4759
4789
|
|
|
4760
4790
|
// src/host-ssot.ts
|
|
4761
|
-
import { lstatSync as lstatSync7, readlinkSync as readlinkSync3, realpathSync as
|
|
4791
|
+
import { lstatSync as lstatSync7, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "node:fs";
|
|
4762
4792
|
import { dirname as dirname12, isAbsolute as isAbsolute4, join as join18, resolve as resolve6 } from "node:path";
|
|
4763
4793
|
function inspectProjectHostSsot(root) {
|
|
4764
4794
|
const agentsEntry = inspectCanonicalPath(root, "AGENTS.md");
|
|
@@ -4808,7 +4838,7 @@ function inspectCanonicalPath(root, path) {
|
|
|
4808
4838
|
if (!stat) return { path, status: "missing" };
|
|
4809
4839
|
if (stat.isSymbolicLink()) {
|
|
4810
4840
|
try {
|
|
4811
|
-
|
|
4841
|
+
realpathSync5(absolutePath);
|
|
4812
4842
|
return { path, status: "symlink" };
|
|
4813
4843
|
} catch {
|
|
4814
4844
|
return { path, status: "dangling-symlink" };
|
|
@@ -4842,7 +4872,7 @@ function inspectCompatibilityLink(root, path, expectedRawTarget) {
|
|
|
4842
4872
|
}
|
|
4843
4873
|
let targetMatches = false;
|
|
4844
4874
|
try {
|
|
4845
|
-
targetMatches =
|
|
4875
|
+
targetMatches = realpathSync5(absolutePath) === realpathSync5(expectedPath);
|
|
4846
4876
|
} catch {
|
|
4847
4877
|
return { ...base, rawTarget, resolvedTarget, status: "dangling-symlink" };
|
|
4848
4878
|
}
|
|
@@ -5036,7 +5066,7 @@ function readPackageJson(path) {
|
|
|
5036
5066
|
// src/repository-files.ts
|
|
5037
5067
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
5038
5068
|
import { existsSync as existsSync20, readdirSync as readdirSync10 } from "node:fs";
|
|
5039
|
-
import { isAbsolute as isAbsolute5, join as join21, posix as posix3, relative as
|
|
5069
|
+
import { isAbsolute as isAbsolute5, join as join21, posix as posix3, relative as relative9 } from "node:path";
|
|
5040
5070
|
var gitMaxBufferBytes = 64 * 1024 * 1024;
|
|
5041
5071
|
var RepositoryFileDiscoveryError = class extends Error {
|
|
5042
5072
|
constructor(message) {
|
|
@@ -5104,7 +5134,7 @@ function discoverFilesystemFiles(root, options) {
|
|
|
5104
5134
|
continue;
|
|
5105
5135
|
}
|
|
5106
5136
|
if (!entry.isFile()) continue;
|
|
5107
|
-
const relativePath = normalizeRepositoryRelativePath(
|
|
5137
|
+
const relativePath = normalizeRepositoryRelativePath(relative9(root, absolutePath));
|
|
5108
5138
|
if (isSafeRepositoryRelativePath(relativePath) && (options.fallbackIncludeFile?.(relativePath) ?? true)) {
|
|
5109
5139
|
files.add(relativePath);
|
|
5110
5140
|
}
|
|
@@ -5954,15 +5984,15 @@ import { homedir as homedir5 } from "node:os";
|
|
|
5954
5984
|
import { dirname as dirname17, join as join33, resolve as resolve9 } from "node:path";
|
|
5955
5985
|
|
|
5956
5986
|
// src/portfolio/ai-health/entries.ts
|
|
5957
|
-
import { existsSync as existsSync26, lstatSync as lstatSync11, realpathSync as
|
|
5987
|
+
import { existsSync as existsSync26, lstatSync as lstatSync11, realpathSync as realpathSync7 } from "node:fs";
|
|
5958
5988
|
import { join as join26 } from "node:path";
|
|
5959
5989
|
|
|
5960
5990
|
// src/portfolio/ai-health/shared.ts
|
|
5961
5991
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
5962
|
-
import { existsSync as existsSync25, lstatSync as lstatSync10, readFileSync as readFileSync17, readdirSync as readdirSync11, realpathSync as
|
|
5992
|
+
import { existsSync as existsSync25, lstatSync as lstatSync10, readFileSync as readFileSync17, readdirSync as readdirSync11, realpathSync as realpathSync6, statSync as statSync7 } from "node:fs";
|
|
5963
5993
|
function safeRealpath(path) {
|
|
5964
5994
|
try {
|
|
5965
|
-
return
|
|
5995
|
+
return realpathSync6(path);
|
|
5966
5996
|
} catch {
|
|
5967
5997
|
return void 0;
|
|
5968
5998
|
}
|
|
@@ -6074,7 +6104,7 @@ function inspectEntries(root) {
|
|
|
6074
6104
|
const info = lstatSync11(claudePath);
|
|
6075
6105
|
if (info.isSymbolicLink()) {
|
|
6076
6106
|
try {
|
|
6077
|
-
claude =
|
|
6107
|
+
claude = realpathSync7(claudePath) === realpathSync7(agentsPath) ? "agents-symlink" : "custom";
|
|
6078
6108
|
} catch {
|
|
6079
6109
|
claude = "dangling-symlink";
|
|
6080
6110
|
}
|
|
@@ -6107,7 +6137,7 @@ function inspectAgentLinks(root) {
|
|
|
6107
6137
|
let kind = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "directory" : "file";
|
|
6108
6138
|
if (stat.isSymbolicLink()) {
|
|
6109
6139
|
try {
|
|
6110
|
-
|
|
6140
|
+
realpathSync7(path);
|
|
6111
6141
|
} catch {
|
|
6112
6142
|
kind = "dangling-symlink";
|
|
6113
6143
|
}
|
|
@@ -6126,7 +6156,7 @@ function inspectOptionalEntry(root, filename, agentsPath) {
|
|
|
6126
6156
|
const info = lstatSync11(path);
|
|
6127
6157
|
if (info.isSymbolicLink()) {
|
|
6128
6158
|
try {
|
|
6129
|
-
return
|
|
6159
|
+
return realpathSync7(path) === realpathSync7(agentsPath) ? "agents-symlink" : "custom";
|
|
6130
6160
|
} catch {
|
|
6131
6161
|
return "dangling-symlink";
|
|
6132
6162
|
}
|
|
@@ -6257,12 +6287,12 @@ function inspectGit2(root) {
|
|
|
6257
6287
|
// src/portfolio/ai-health/hosts.ts
|
|
6258
6288
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
6259
6289
|
import { existsSync as existsSync28 } from "node:fs";
|
|
6260
|
-
import { join as join28, resolve as resolve8, sep as
|
|
6290
|
+
import { join as join28, resolve as resolve8, sep as sep3 } from "node:path";
|
|
6261
6291
|
|
|
6262
6292
|
// src/portfolio/ai-health/devspace.ts
|
|
6263
6293
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
6264
6294
|
import { existsSync as existsSync27, statSync as statSync8 } from "node:fs";
|
|
6265
|
-
import { join as join27, relative as
|
|
6295
|
+
import { join as join27, relative as relative10, resolve as resolve7, sep as sep2 } from "node:path";
|
|
6266
6296
|
function inspectDevSpaceHealth(options) {
|
|
6267
6297
|
const run = options.run ?? runDevSpaceCommand;
|
|
6268
6298
|
const configDirectory = join27(options.homeDir, ".devspace");
|
|
@@ -6368,8 +6398,8 @@ function isLoopbackHost(host) {
|
|
|
6368
6398
|
return ["127.0.0.1", "localhost", "::1"].includes(host.trim().toLowerCase());
|
|
6369
6399
|
}
|
|
6370
6400
|
function isPathInside(path, root) {
|
|
6371
|
-
const fromRoot =
|
|
6372
|
-
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${
|
|
6401
|
+
const fromRoot = relative10(resolve7(root), resolve7(path));
|
|
6402
|
+
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${sep2}`);
|
|
6373
6403
|
}
|
|
6374
6404
|
|
|
6375
6405
|
// src/portfolio/ai-health/hosts.ts
|
|
@@ -6498,7 +6528,7 @@ function inspectGrokProject(root, homeDir, grokVersion) {
|
|
|
6498
6528
|
if (!isRecord3(item) || !isRecord3(item.source)) continue;
|
|
6499
6529
|
const type = item.source.type;
|
|
6500
6530
|
const path = item.source.path;
|
|
6501
|
-
if (typeof path === "string" && path.includes(
|
|
6531
|
+
if (typeof path === "string" && path.includes(sep3 + ".grok" + sep3 + "bundled" + sep3))
|
|
6502
6532
|
skillCounts.bundled += 1;
|
|
6503
6533
|
else if (type === "project") skillCounts.project += 1;
|
|
6504
6534
|
else if (type === "plugin") skillCounts.plugin += 1;
|
|
@@ -6537,19 +6567,19 @@ function inferGrokMcpScope(name, sourceType, sourcePath, root, homeDir, userClau
|
|
|
6537
6567
|
const resolvedRoot = safeRealpath(root) ?? resolve8(root);
|
|
6538
6568
|
if (resolvedSource === join28(resolvedRoot, MCP_DISCOVERY_PATHS.project.claudeCodeShared))
|
|
6539
6569
|
return "project-shared";
|
|
6540
|
-
if (resolvedSource.startsWith(resolvedRoot +
|
|
6570
|
+
if (resolvedSource.startsWith(resolvedRoot + sep3)) return "project";
|
|
6541
6571
|
if (homeDir && resolvedSource === join28(resolve8(homeDir), MCP_DISCOVERY_PATHS.user.claudeCode)) {
|
|
6542
6572
|
if (localClaudeNames.has(name)) return "project-local";
|
|
6543
6573
|
if (userClaudeNames.has(name)) return "user";
|
|
6544
6574
|
}
|
|
6545
|
-
if (homeDir && resolvedSource.startsWith(resolve8(homeDir) +
|
|
6575
|
+
if (homeDir && resolvedSource.startsWith(resolve8(homeDir) + sep3)) return "user";
|
|
6546
6576
|
if (sourceType === "project") return "project";
|
|
6547
6577
|
return "unknown";
|
|
6548
6578
|
}
|
|
6549
6579
|
|
|
6550
6580
|
// src/portfolio/ai-health/secrets.ts
|
|
6551
6581
|
import { existsSync as existsSync29, lstatSync as lstatSync12, readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
|
|
6552
|
-
import { join as join29, relative as
|
|
6582
|
+
import { join as join29, relative as relative11, sep as sep4 } from "node:path";
|
|
6553
6583
|
function inspectRepositorySecrets(root, id, secretsRoot, isRepository, environmentPolicy) {
|
|
6554
6584
|
const centralPath = join29(secretsRoot, id);
|
|
6555
6585
|
const centralRealPath = safeRealpath(centralPath);
|
|
@@ -6600,7 +6630,7 @@ function collectEnvironmentFiles(root, current = root, depth = 0) {
|
|
|
6600
6630
|
if (!SKIP_ENV_DIRECTORIES.has(entry.name))
|
|
6601
6631
|
found.push(...collectEnvironmentFiles(root, join29(current, entry.name), depth + 1));
|
|
6602
6632
|
} else if (isEnvironmentFilename(entry.name) && !isProviderGeneratedEnvironmentFile(entry.name)) {
|
|
6603
|
-
found.push(
|
|
6633
|
+
found.push(relative11(root, join29(current, entry.name)));
|
|
6604
6634
|
}
|
|
6605
6635
|
}
|
|
6606
6636
|
} catch {
|
|
@@ -6615,7 +6645,7 @@ function collectCentralSecretFiles(root, current = root, depth = 0) {
|
|
|
6615
6645
|
for (const entry of readdirSync12(current, { withFileTypes: true })) {
|
|
6616
6646
|
const path = join29(current, entry.name);
|
|
6617
6647
|
if (entry.isDirectory()) found.push(...collectCentralSecretFiles(root, path, depth + 1));
|
|
6618
|
-
else found.push({ path:
|
|
6648
|
+
else found.push({ path: relative11(root, path), mode: modeString(lstatSync12(path).mode) });
|
|
6619
6649
|
}
|
|
6620
6650
|
} catch {
|
|
6621
6651
|
return found;
|
|
@@ -6642,8 +6672,8 @@ function pointsInside(path, expectedRoot) {
|
|
|
6642
6672
|
if (!expectedRoot || !lstatSync12(path).isSymbolicLink()) return false;
|
|
6643
6673
|
const target = safeRealpath(path);
|
|
6644
6674
|
if (!target) return false;
|
|
6645
|
-
const fromRoot =
|
|
6646
|
-
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${
|
|
6675
|
+
const fromRoot = relative11(expectedRoot, target);
|
|
6676
|
+
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${sep4}`);
|
|
6647
6677
|
}
|
|
6648
6678
|
function hasUnsafeCentralSecretPermissions(secrets) {
|
|
6649
6679
|
return secrets.centralDirectory === "present" && (secrets.centralMode !== "700" || secrets.centralFiles.some((file) => file.mode !== "600"));
|
|
@@ -6653,7 +6683,7 @@ function inspectSecretsRoot(path) {
|
|
|
6653
6683
|
}
|
|
6654
6684
|
|
|
6655
6685
|
// src/portfolio/ai-health/skills.ts
|
|
6656
|
-
import { existsSync as existsSync30, lstatSync as lstatSync13, realpathSync as
|
|
6686
|
+
import { existsSync as existsSync30, lstatSync as lstatSync13, realpathSync as realpathSync8 } from "node:fs";
|
|
6657
6687
|
import { join as join30 } from "node:path";
|
|
6658
6688
|
function countAutomaticSkillsNeedingReview(skills) {
|
|
6659
6689
|
return skills.automatic.filter(
|
|
@@ -6741,7 +6771,7 @@ function inspectSkillItem(skillRoot, directory, name, managed, registeredSkills)
|
|
|
6741
6771
|
let kind = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "directory" : "file";
|
|
6742
6772
|
let realPath;
|
|
6743
6773
|
try {
|
|
6744
|
-
realPath =
|
|
6774
|
+
realPath = realpathSync8(path);
|
|
6745
6775
|
} catch {
|
|
6746
6776
|
if (stat.isSymbolicLink()) kind = "dangling-symlink";
|
|
6747
6777
|
}
|
|
@@ -6802,8 +6832,8 @@ function inspectClaudeSkillRoot(root) {
|
|
|
6802
6832
|
const stat = lstatSync13(path);
|
|
6803
6833
|
if (stat.isSymbolicLink()) {
|
|
6804
6834
|
try {
|
|
6805
|
-
const target =
|
|
6806
|
-
return target ===
|
|
6835
|
+
const target = realpathSync8(path);
|
|
6836
|
+
return target === realpathSync8(join30(root, ".agents/skills")) ? "shared-root" : "other";
|
|
6807
6837
|
} catch {
|
|
6808
6838
|
return "dangling-symlink";
|
|
6809
6839
|
}
|
|
@@ -7568,8 +7598,12 @@ function runPortfolioDoctor(args) {
|
|
|
7568
7598
|
console.error(`Unknown portfolio target: ${options.value.targetId}`);
|
|
7569
7599
|
return 1;
|
|
7570
7600
|
}
|
|
7601
|
+
const agentAssetsDir = findPortfolioAgentAssetsDir(loaded.manifest);
|
|
7602
|
+
if (loaded.manifest.executionEngine?.path && !agentAssetsDir) {
|
|
7603
|
+
return reportMissingPortfolioRegistry(loaded, options.value.json);
|
|
7604
|
+
}
|
|
7571
7605
|
const loadedAssets = loadAgentAssetRegistry({
|
|
7572
|
-
agentAssetsDir
|
|
7606
|
+
agentAssetsDir
|
|
7573
7607
|
});
|
|
7574
7608
|
if (loadedAssets.issues.length > 0) {
|
|
7575
7609
|
for (const issue of loadedAssets.issues) console.error(`${issue.type}: ${issue.message}`);
|
|
@@ -7670,8 +7704,12 @@ function runPortfolioPlan(args) {
|
|
|
7670
7704
|
console.error(`Unknown portfolio target: ${options.value.targetId}`);
|
|
7671
7705
|
return 1;
|
|
7672
7706
|
}
|
|
7707
|
+
const agentAssetsDir = findPortfolioAgentAssetsDir(loaded.manifest);
|
|
7708
|
+
if (loaded.manifest.executionEngine?.path && !agentAssetsDir) {
|
|
7709
|
+
return reportMissingPortfolioRegistry(loaded, options.value.json);
|
|
7710
|
+
}
|
|
7673
7711
|
const loadedAssets = loadAgentAssetRegistry({
|
|
7674
|
-
agentAssetsDir
|
|
7712
|
+
agentAssetsDir
|
|
7675
7713
|
});
|
|
7676
7714
|
if (loadedAssets.issues.length > 0) {
|
|
7677
7715
|
for (const issue of loadedAssets.issues) {
|
|
@@ -7760,8 +7798,12 @@ function runPortfolioAssetsCheck(args) {
|
|
|
7760
7798
|
console.error(`Unknown portfolio target: ${options.value.targetId}`);
|
|
7761
7799
|
return 1;
|
|
7762
7800
|
}
|
|
7801
|
+
const agentAssetsDir = findPortfolioAgentAssetsDir(loaded.manifest);
|
|
7802
|
+
if (loaded.manifest.executionEngine?.path && !agentAssetsDir) {
|
|
7803
|
+
return reportMissingPortfolioRegistry(loaded, options.value.json);
|
|
7804
|
+
}
|
|
7763
7805
|
const loadedAssets = loadAgentAssetRegistry({
|
|
7764
|
-
agentAssetsDir
|
|
7806
|
+
agentAssetsDir
|
|
7765
7807
|
});
|
|
7766
7808
|
if (loadedAssets.issues.length > 0) {
|
|
7767
7809
|
if (options.value.json) {
|
|
@@ -7874,6 +7916,31 @@ function findPortfolioAgentAssetsDir(manifest) {
|
|
|
7874
7916
|
const agentAssetsDir = manifest?.executionEngine?.path ? join34(manifest.executionEngine.path, "agent-assets") : void 0;
|
|
7875
7917
|
return agentAssetsDir && existsSync33(join34(agentAssetsDir, "registry.json")) ? agentAssetsDir : void 0;
|
|
7876
7918
|
}
|
|
7919
|
+
function reportMissingPortfolioRegistry(loaded, json) {
|
|
7920
|
+
const expectedPath = loaded.manifest?.executionEngine?.path ? join34(loaded.manifest.executionEngine.path, "agent-assets/registry.json") : "executionEngine.path/agent-assets/registry.json";
|
|
7921
|
+
const issue = {
|
|
7922
|
+
type: "missing-control-plane-registry",
|
|
7923
|
+
message: `Portfolio control-plane registry is required at ${expectedPath}; refusing the package fallback registry.`
|
|
7924
|
+
};
|
|
7925
|
+
if (json) {
|
|
7926
|
+
console.log(
|
|
7927
|
+
JSON.stringify(
|
|
7928
|
+
{
|
|
7929
|
+
ok: false,
|
|
7930
|
+
configPath: loaded.configPath,
|
|
7931
|
+
portfolioId: loaded.manifest?.portfolioId,
|
|
7932
|
+
issues: [issue],
|
|
7933
|
+
targets: []
|
|
7934
|
+
},
|
|
7935
|
+
null,
|
|
7936
|
+
2
|
|
7937
|
+
)
|
|
7938
|
+
);
|
|
7939
|
+
} else {
|
|
7940
|
+
console.error(`${issue.type}: ${issue.message}`);
|
|
7941
|
+
}
|
|
7942
|
+
return 1;
|
|
7943
|
+
}
|
|
7877
7944
|
function printUsage5() {
|
|
7878
7945
|
console.error("Usage:");
|
|
7879
7946
|
console.error(" pro-gov portfolio check --config <path> [--json]");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pieai/pro-gov",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
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.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@pieai/swimmer-ui-kit": "1.3.2",
|