xtrm-tools 0.7.7 → 0.7.9
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/.xtrm/config/hooks.json +0 -3
- package/.xtrm/registry.json +537 -565
- package/.xtrm/skills/default/gitnexus-cli/SKILL.md +82 -0
- package/.xtrm/skills/default/gitnexus-exploring/SKILL.md +78 -0
- package/.xtrm/skills/default/gitnexus-guide/SKILL.md +64 -0
- package/.xtrm/skills/default/init-session/SKILL.md +3 -0
- package/.xtrm/skills/default/last30days/SKILL.md +1 -1
- package/.xtrm/skills/default/last30days/scripts/lib/youtube_yt.py +59 -40
- package/.xtrm/skills/default/sync-docs/references/doc-structure.md +1 -1
- package/.xtrm/skills/default/sync-docs/references/schema.md +1 -1
- package/.xtrm/skills/default/sync-docs/scripts/doc_structure_analyzer.py +2 -2
- package/.xtrm/skills/default/using-specialists/SKILL.md +346 -138
- package/.xtrm/skills/default/using-specialists/SKILL.safe.md +1082 -0
- package/.xtrm/skills/default/using-specialists/SKILL.ultra.md +1082 -0
- package/.xtrm/skills/default/vaultctl/SKILL.md +150 -0
- package/CHANGELOG.md +4 -4
- package/cli/dist/index.cjs +328 -192
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +8 -8
- package/packages/pi-extensions/MIGRATION_NOTES.md +39 -0
- package/packages/pi-extensions/README.md +43 -0
- package/packages/pi-extensions/extensions/README.md +5 -0
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/package.json +1 -4
- package/packages/pi-extensions/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/package.json +9 -2
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/quality-gates/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/quality-gates/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/service-skills/index.ts +1 -1
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/service-skills/package.json +1 -4
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/session-flow/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/session-flow/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/index.ts +1 -1
- package/packages/pi-extensions/package.json +46 -0
- package/packages/pi-extensions/src/core/README.md +9 -0
- package/{.xtrm/ext-src/core/lib.ts → packages/pi-extensions/src/core/index.ts} +3 -1
- package/packages/pi-extensions/src/extensions/auto-session-name.ts +3 -0
- package/packages/pi-extensions/src/extensions/auto-update.ts +3 -0
- package/packages/pi-extensions/src/extensions/beads.ts +3 -0
- package/packages/pi-extensions/src/extensions/compact-header.ts +3 -0
- package/packages/pi-extensions/src/extensions/custom-footer.ts +3 -0
- package/packages/pi-extensions/src/extensions/custom-provider-qwen-cli.ts +3 -0
- package/packages/pi-extensions/src/extensions/git-checkpoint.ts +3 -0
- package/packages/pi-extensions/src/extensions/lsp-bootstrap.ts +3 -0
- package/packages/pi-extensions/src/extensions/pi-serena-compact.ts +3 -0
- package/packages/pi-extensions/src/extensions/quality-gates.ts +3 -0
- package/packages/pi-extensions/src/extensions/service-skills.ts +3 -0
- package/packages/pi-extensions/src/extensions/session-flow.ts +3 -0
- package/packages/pi-extensions/src/extensions/xtrm-loader.ts +3 -0
- package/packages/pi-extensions/src/extensions/xtrm-ui.ts +3 -0
- package/packages/pi-extensions/src/index.ts +9 -0
- package/packages/pi-extensions/src/registry.ts +52 -0
- package/packages/pi-extensions/src/shared/index.ts +1 -0
- package/packages/pi-extensions/src/shared/legacy-path-map.ts +23 -0
- package/.xtrm/config/pi/extensions/core/package.json +0 -18
- package/.xtrm/config/pi/extensions/custom-provider-qwen-cli/package.json +0 -1
- package/.xtrm/config/pi/extensions/quality-gates/index.ts +0 -66
- package/.xtrm/config/pi/extensions/service-skills/package.json +0 -19
- package/.xtrm/config/pi/extensions/session-flow/index.ts +0 -96
- package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-dark.json +0 -89
- package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-light.json +0 -89
- package/.xtrm/ext-src/auto-session-name/index.ts +0 -29
- package/.xtrm/ext-src/auto-session-name/package.json +0 -16
- package/.xtrm/ext-src/auto-update/index.ts +0 -71
- package/.xtrm/ext-src/auto-update/package.json +0 -16
- package/.xtrm/ext-src/beads/index.ts +0 -232
- package/.xtrm/ext-src/beads/package.json +0 -19
- package/.xtrm/ext-src/compact-header/index.ts +0 -69
- package/.xtrm/ext-src/compact-header/package.json +0 -16
- package/.xtrm/ext-src/core/adapter.ts +0 -52
- package/.xtrm/ext-src/core/guard-rules.ts +0 -100
- package/.xtrm/ext-src/core/logger.ts +0 -45
- package/.xtrm/ext-src/core/package.json +0 -18
- package/.xtrm/ext-src/core/runner.ts +0 -71
- package/.xtrm/ext-src/core/session-state.ts +0 -59
- package/.xtrm/ext-src/custom-footer/index.ts +0 -398
- package/.xtrm/ext-src/custom-footer/package.json +0 -19
- package/.xtrm/ext-src/custom-provider-qwen-cli/index.ts +0 -363
- package/.xtrm/ext-src/custom-provider-qwen-cli/package.json +0 -1
- package/.xtrm/ext-src/git-checkpoint/index.ts +0 -53
- package/.xtrm/ext-src/git-checkpoint/package.json +0 -16
- package/.xtrm/ext-src/lsp-bootstrap/index.ts +0 -134
- package/.xtrm/ext-src/lsp-bootstrap/package.json +0 -17
- package/.xtrm/ext-src/pi-serena-compact/index.ts +0 -121
- package/.xtrm/ext-src/pi-serena-compact/package.json +0 -16
- package/.xtrm/ext-src/quality-gates/package.json +0 -19
- package/.xtrm/ext-src/service-skills/index.ts +0 -108
- package/.xtrm/ext-src/session-flow/package.json +0 -19
- package/.xtrm/ext-src/xtrm-loader/index.ts +0 -152
- package/.xtrm/ext-src/xtrm-loader/package.json +0 -19
- package/.xtrm/ext-src/xtrm-ui/format.ts +0 -282
- package/.xtrm/ext-src/xtrm-ui/index.ts +0 -1112
- package/.xtrm/ext-src/xtrm-ui/package.json +0 -21
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.combined.log +0 -0
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stderr.log +0 -0
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stdout.log +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-provider-qwen-cli/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/format.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/package.json +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/adapter.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/guard-rules.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/lib.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/logger.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/runner.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/session-state.ts +0 -0
- /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-dark.json +0 -0
- /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-light.json +0 -0
package/cli/dist/index.cjs
CHANGED
|
@@ -43891,6 +43891,13 @@ async function setRuntimeEnabledPacks(skillsRoot, runtime, packNames) {
|
|
|
43891
43891
|
}
|
|
43892
43892
|
|
|
43893
43893
|
// src/core/skills-materializer.ts
|
|
43894
|
+
var PI_NPM_PROVIDED_SKILLS = /* @__PURE__ */ new Set([
|
|
43895
|
+
"gitnexus-debugging",
|
|
43896
|
+
"gitnexus-exploring",
|
|
43897
|
+
"gitnexus-impact-analysis",
|
|
43898
|
+
"gitnexus-pr-review",
|
|
43899
|
+
"gitnexus-refactoring"
|
|
43900
|
+
]);
|
|
43894
43901
|
function sortByName(entries) {
|
|
43895
43902
|
return [...entries].sort((a, b) => a.name.localeCompare(b.name));
|
|
43896
43903
|
}
|
|
@@ -43929,11 +43936,12 @@ async function selectRuntimeSkills(runtime, skillsRoot) {
|
|
|
43929
43936
|
const defaultSkills = await discoverDefaultSkills(skillsRoot);
|
|
43930
43937
|
const enabledPackSkills = await collectEnabledPackSkills(skillsRoot, enabledPacks);
|
|
43931
43938
|
const allSkills = sortByName([...defaultSkills, ...enabledPackSkills]);
|
|
43932
|
-
|
|
43939
|
+
const filteredSkills = runtime === "pi" ? allSkills.filter((s) => !PI_NPM_PROVIDED_SKILLS.has(s.name)) : allSkills;
|
|
43940
|
+
assertNoRuntimeCollisions(runtime, filteredSkills);
|
|
43933
43941
|
return {
|
|
43934
43942
|
runtime,
|
|
43935
43943
|
enabledPacks: [...enabledPacks],
|
|
43936
|
-
skills:
|
|
43944
|
+
skills: filteredSkills
|
|
43937
43945
|
};
|
|
43938
43946
|
}
|
|
43939
43947
|
async function buildRuntimeTempView(runtime, skillsRoot, selectedSkills) {
|
|
@@ -44102,6 +44110,26 @@ function resolveStatuslineScript(worktreePath) {
|
|
|
44102
44110
|
if ((0, import_node_fs.existsSync)(repoStatusline)) return repoStatusline;
|
|
44103
44111
|
return null;
|
|
44104
44112
|
}
|
|
44113
|
+
function ensureWorktreeSpecialists(worktreePath, mainRepoPath) {
|
|
44114
|
+
const worktreeSpecialistsRoot = import_node_path5.default.join(worktreePath, ".specialists");
|
|
44115
|
+
(0, import_node_fs.mkdirSync)(worktreeSpecialistsRoot, { recursive: true });
|
|
44116
|
+
const specialistDirs = ["default", "user"];
|
|
44117
|
+
for (const dirName of specialistDirs) {
|
|
44118
|
+
const sourceDir = import_node_path5.default.join(mainRepoPath, ".specialists", dirName);
|
|
44119
|
+
if (!(0, import_node_fs.existsSync)(sourceDir)) continue;
|
|
44120
|
+
const targetDir = import_node_path5.default.join(worktreeSpecialistsRoot, dirName);
|
|
44121
|
+
const symlinkTarget = import_node_path5.default.relative(import_node_path5.default.dirname(targetDir), sourceDir);
|
|
44122
|
+
try {
|
|
44123
|
+
const existing = (0, import_node_fs.lstatSync)(targetDir);
|
|
44124
|
+
if (existing.isSymbolicLink() && (0, import_node_fs.readlinkSync)(targetDir) === symlinkTarget) {
|
|
44125
|
+
continue;
|
|
44126
|
+
}
|
|
44127
|
+
(0, import_node_fs.rmSync)(targetDir, { recursive: true, force: true });
|
|
44128
|
+
} catch {
|
|
44129
|
+
}
|
|
44130
|
+
(0, import_node_fs.symlinkSync)(symlinkTarget, targetDir, "dir");
|
|
44131
|
+
}
|
|
44132
|
+
}
|
|
44105
44133
|
function sessionMetaPath(worktreePath) {
|
|
44106
44134
|
return import_node_path5.default.join(worktreePath, ".xtrm", "session-meta.json");
|
|
44107
44135
|
}
|
|
@@ -44209,6 +44237,12 @@ async function launchWorktreeSession(opts) {
|
|
|
44209
44237
|
}
|
|
44210
44238
|
}
|
|
44211
44239
|
}
|
|
44240
|
+
try {
|
|
44241
|
+
ensureWorktreeSpecialists(worktreePath, mainRepoRoot);
|
|
44242
|
+
} catch (error48) {
|
|
44243
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
44244
|
+
console.log(kleur_default.dim(` warning: could not provision specialist definitions (${message})`));
|
|
44245
|
+
}
|
|
44212
44246
|
const localSettings = {};
|
|
44213
44247
|
const statuslinePath = resolveStatuslineScript(worktreePath);
|
|
44214
44248
|
if (statuslinePath) {
|
|
@@ -44735,21 +44769,51 @@ var import_child_process3 = require("child_process");
|
|
|
44735
44769
|
var import_fs_extra9 = __toESM(require_lib(), 1);
|
|
44736
44770
|
var import_path4 = __toESM(require("path"), 1);
|
|
44737
44771
|
var import_node_os = require("os");
|
|
44772
|
+
var MANAGED_PI_EXTENSION_SOURCE_CANDIDATES = [
|
|
44773
|
+
["packages", "pi-extensions", "extensions"],
|
|
44774
|
+
[".xtrm", "extensions"]
|
|
44775
|
+
];
|
|
44776
|
+
function resolveFirstExistingPath(rootDir, candidates) {
|
|
44777
|
+
for (const candidate of candidates) {
|
|
44778
|
+
const candidatePath = import_path4.default.join(rootDir, ...candidate);
|
|
44779
|
+
if (import_fs_extra9.default.existsSync(candidatePath)) {
|
|
44780
|
+
return candidatePath;
|
|
44781
|
+
}
|
|
44782
|
+
}
|
|
44783
|
+
return null;
|
|
44784
|
+
}
|
|
44738
44785
|
function resolvePkgRoot() {
|
|
44739
44786
|
const candidates = [
|
|
44740
44787
|
import_path4.default.resolve(__dirname, "../.."),
|
|
44741
44788
|
import_path4.default.resolve(__dirname, "../../..")
|
|
44742
44789
|
];
|
|
44743
|
-
for (const
|
|
44744
|
-
if (
|
|
44790
|
+
for (const candidateRoot of candidates) {
|
|
44791
|
+
if (resolveFirstExistingPath(candidateRoot, MANAGED_PI_EXTENSION_SOURCE_CANDIDATES)) {
|
|
44792
|
+
return candidateRoot;
|
|
44793
|
+
}
|
|
44745
44794
|
}
|
|
44746
44795
|
return candidates[0];
|
|
44747
44796
|
}
|
|
44797
|
+
function resolveManagedPiExtensionsSourceDir(pkgRoot = resolvePkgRoot()) {
|
|
44798
|
+
return resolveFirstExistingPath(pkgRoot, MANAGED_PI_EXTENSION_SOURCE_CANDIDATES);
|
|
44799
|
+
}
|
|
44800
|
+
function resolveManagedPiCoreSourceDir(pkgRoot = resolvePkgRoot()) {
|
|
44801
|
+
return resolveFirstExistingPath(pkgRoot, [
|
|
44802
|
+
["packages", "pi-extensions", "src", "core"],
|
|
44803
|
+
[".xtrm", "extensions", "core"]
|
|
44804
|
+
]);
|
|
44805
|
+
}
|
|
44748
44806
|
var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path4.default.join((0, import_node_os.homedir)(), ".pi", "agent");
|
|
44749
44807
|
var PI_MCP_ADAPTER_OVERRIDE_DIR = import_path4.default.join(PI_AGENT_DIR, "extensions", "pi-mcp-adapter");
|
|
44750
44808
|
var PI_MCP_ADAPTER_REQUIRED_ENTRY = "commands.js";
|
|
44751
44809
|
var PROJECT_EXTENSIONS_ENTRY = "../.xtrm/extensions";
|
|
44752
44810
|
var PROJECT_SKILLS_ENTRY = "../.xtrm/skills/active/pi";
|
|
44811
|
+
var PROJECT_EXTENSION_PACKAGE_ID = "npm:@jaggerxtrm/pi-extensions";
|
|
44812
|
+
var CONFLICTING_PI_PACKAGE_IDS = /* @__PURE__ */ new Set(["npm:pi-dex"]);
|
|
44813
|
+
var LEGACY_PROJECT_EXTENSION_ENTRIES = /* @__PURE__ */ new Set([
|
|
44814
|
+
PROJECT_EXTENSIONS_ENTRY,
|
|
44815
|
+
".xtrm/extensions"
|
|
44816
|
+
]);
|
|
44753
44817
|
var MANAGED_EXTENSIONS = [
|
|
44754
44818
|
{ id: "core", displayName: "@xtrm/pi-core", isLibrary: true, required: true },
|
|
44755
44819
|
{ id: "auto-session-name", displayName: "auto-session-name", required: false },
|
|
@@ -44779,6 +44843,10 @@ var ALWAYS_GLOBAL_INSTALL_PACKAGE_IDS = /* @__PURE__ */ new Set([
|
|
|
44779
44843
|
"npm:pi-gitnexus",
|
|
44780
44844
|
"npm:pi-serena-tools"
|
|
44781
44845
|
]);
|
|
44846
|
+
var PROJECT_REQUIRED_PACKAGE_IDS = [
|
|
44847
|
+
PROJECT_EXTENSION_PACKAGE_ID,
|
|
44848
|
+
...MANAGED_PACKAGES.map((pkg) => pkg.id)
|
|
44849
|
+
];
|
|
44782
44850
|
function getInstalledPiPackages() {
|
|
44783
44851
|
const result = (0, import_child_process3.spawnSync)("pi", ["list"], { encoding: "utf8", stdio: "pipe" });
|
|
44784
44852
|
if (result.status !== 0) return [];
|
|
@@ -44913,6 +44981,20 @@ function renderPiRuntimePlan(plan) {
|
|
|
44913
44981
|
console.log(kleur_default.yellow(" \u26A0 Missing required items.\n"));
|
|
44914
44982
|
}
|
|
44915
44983
|
}
|
|
44984
|
+
function getProjectRequiredPackageStatuses(installedPkgIds) {
|
|
44985
|
+
return PROJECT_REQUIRED_PACKAGE_IDS.map((packageId) => {
|
|
44986
|
+
const managed = MANAGED_PACKAGES.find((pkg2) => pkg2.id === packageId);
|
|
44987
|
+
const pkg = managed ?? {
|
|
44988
|
+
id: PROJECT_EXTENSION_PACKAGE_ID,
|
|
44989
|
+
displayName: "@jaggerxtrm/pi-extensions",
|
|
44990
|
+
required: true
|
|
44991
|
+
};
|
|
44992
|
+
return {
|
|
44993
|
+
pkg,
|
|
44994
|
+
installed: installedPkgIds.includes(packageId)
|
|
44995
|
+
};
|
|
44996
|
+
});
|
|
44997
|
+
}
|
|
44916
44998
|
function mergePiSyncResults(base, incoming) {
|
|
44917
44999
|
return {
|
|
44918
45000
|
extensionsAdded: [...base.extensionsAdded, ...incoming.extensionsAdded],
|
|
@@ -44933,10 +45015,63 @@ async function isPackagePresentInPiAgent(agentDir, piPackageId) {
|
|
|
44933
45015
|
const packageDir = import_path4.default.join(agentDir, "npm", "node_modules", npmPackageName);
|
|
44934
45016
|
return import_fs_extra9.default.pathExists(packageDir);
|
|
44935
45017
|
}
|
|
44936
|
-
|
|
44937
|
-
|
|
44938
|
-
|
|
44939
|
-
|
|
45018
|
+
var NPMJS_REGISTRY_URL = "https://registry.npmjs.org";
|
|
45019
|
+
function runPiPackageInstall(piPackageId, env2) {
|
|
45020
|
+
const installResult = (0, import_child_process3.spawnSync)("pi", ["install", piPackageId], {
|
|
45021
|
+
stdio: "pipe",
|
|
45022
|
+
encoding: "utf8",
|
|
45023
|
+
env: env2
|
|
45024
|
+
});
|
|
45025
|
+
return {
|
|
45026
|
+
status: installResult.status,
|
|
45027
|
+
stdout: installResult.stdout ?? "",
|
|
45028
|
+
stderr: installResult.stderr ?? ""
|
|
45029
|
+
};
|
|
45030
|
+
}
|
|
45031
|
+
function getPiPackageInstallOutput(result) {
|
|
45032
|
+
return `${result.stdout}
|
|
45033
|
+
${result.stderr}`.trim();
|
|
45034
|
+
}
|
|
45035
|
+
function buildNpmjsRegistryEnv(baseEnv = process.env) {
|
|
45036
|
+
return {
|
|
45037
|
+
...baseEnv,
|
|
45038
|
+
NPM_CONFIG_REGISTRY: NPMJS_REGISTRY_URL,
|
|
45039
|
+
npm_config_registry: NPMJS_REGISTRY_URL
|
|
45040
|
+
};
|
|
45041
|
+
}
|
|
45042
|
+
function shouldRetryPiInstallViaNpmjs(piPackageId, output) {
|
|
45043
|
+
if (piPackageId !== PROJECT_EXTENSION_PACKAGE_ID) return false;
|
|
45044
|
+
const normalizedOutput = output.toLowerCase();
|
|
45045
|
+
return normalizedOutput.includes("npmmirror") && normalizedOutput.includes("404");
|
|
45046
|
+
}
|
|
45047
|
+
function getPiPackageInstallFailureHint(piPackageId, output) {
|
|
45048
|
+
if (!shouldRetryPiInstallViaNpmjs(piPackageId, output)) {
|
|
45049
|
+
return [];
|
|
45050
|
+
}
|
|
45051
|
+
return [
|
|
45052
|
+
`detected registry mirror 404 for ${piPackageId}`,
|
|
45053
|
+
`best fix: npm config set @jaggerxtrm:registry ${NPMJS_REGISTRY_URL}`
|
|
45054
|
+
];
|
|
45055
|
+
}
|
|
45056
|
+
function installPiPackageWithFallback(piPackageId, log, installRunner = runPiPackageInstall) {
|
|
45057
|
+
const initialResult = installRunner(piPackageId);
|
|
45058
|
+
const initialOutput = getPiPackageInstallOutput(initialResult);
|
|
45059
|
+
if ((initialResult.status ?? 1) === 0) {
|
|
45060
|
+
return { status: initialResult.status, output: initialOutput, retriedWithNpmjs: false };
|
|
45061
|
+
}
|
|
45062
|
+
if (!shouldRetryPiInstallViaNpmjs(piPackageId, initialOutput)) {
|
|
45063
|
+
return { status: initialResult.status, output: initialOutput, retriedWithNpmjs: false };
|
|
45064
|
+
}
|
|
45065
|
+
log?.(kleur_default.dim(`Detected npmmirror 404 for ${piPackageId}; retrying via ${NPMJS_REGISTRY_URL}`));
|
|
45066
|
+
const retriedResult = installRunner(piPackageId, buildNpmjsRegistryEnv());
|
|
45067
|
+
const retriedOutput = getPiPackageInstallOutput(retriedResult);
|
|
45068
|
+
return {
|
|
45069
|
+
status: retriedResult.status,
|
|
45070
|
+
output: [initialOutput, retriedOutput].filter(Boolean).join("\n"),
|
|
45071
|
+
retriedWithNpmjs: true
|
|
45072
|
+
};
|
|
45073
|
+
}
|
|
45074
|
+
async function ensureAlwaysGlobalPiPackages(dryRun, log, agentDir = PI_AGENT_DIR, installRunner = runPiPackageInstall) {
|
|
44940
45075
|
const installed = [];
|
|
44941
45076
|
const failed = [];
|
|
44942
45077
|
const packagesToEnsure = MANAGED_PACKAGES.filter((pkg) => ALWAYS_GLOBAL_INSTALL_PACKAGE_IDS.has(pkg.id));
|
|
@@ -44948,14 +45083,17 @@ async function ensureAlwaysGlobalPiPackages(dryRun, log, agentDir = PI_AGENT_DIR
|
|
|
44948
45083
|
log?.(`[DRY RUN] pi install ${pkg.id}`);
|
|
44949
45084
|
continue;
|
|
44950
45085
|
}
|
|
44951
|
-
const
|
|
44952
|
-
if (
|
|
45086
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log, installRunner);
|
|
45087
|
+
if (installAttempt.status === 0) {
|
|
44953
45088
|
installed.push(pkg.id);
|
|
44954
|
-
log?.(`${sym.ok} ${pkg.displayName} (global)`);
|
|
45089
|
+
log?.(`${sym.ok} ${pkg.displayName} (global${installAttempt.retriedWithNpmjs ? ", npmjs fallback" : ""})`);
|
|
44955
45090
|
continue;
|
|
44956
45091
|
}
|
|
44957
45092
|
failed.push(pkg.id);
|
|
44958
45093
|
log?.(kleur_default.yellow(`\u26A0 ${pkg.displayName} \u2014 global install failed`));
|
|
45094
|
+
for (const hint of getPiPackageInstallFailureHint(pkg.id, installAttempt.output)) {
|
|
45095
|
+
log?.(kleur_default.yellow(` \u2192 ${hint}`));
|
|
45096
|
+
}
|
|
44959
45097
|
}
|
|
44960
45098
|
return { installed, failed };
|
|
44961
45099
|
}
|
|
@@ -45095,30 +45233,90 @@ async function cleanupLegacyProjectExtensionCopies(projectRoot, dryRun, log) {
|
|
|
45095
45233
|
}
|
|
45096
45234
|
return { removed, failed };
|
|
45097
45235
|
}
|
|
45236
|
+
function normalizeStringArray(value) {
|
|
45237
|
+
if (!Array.isArray(value)) return [];
|
|
45238
|
+
return value.filter((entry) => typeof entry === "string");
|
|
45239
|
+
}
|
|
45240
|
+
function pruneConflictingPiPackageEntries(entries) {
|
|
45241
|
+
const kept = [];
|
|
45242
|
+
const removed = [];
|
|
45243
|
+
for (const entry of entries) {
|
|
45244
|
+
if (CONFLICTING_PI_PACKAGE_IDS.has(entry)) {
|
|
45245
|
+
removed.push(entry);
|
|
45246
|
+
continue;
|
|
45247
|
+
}
|
|
45248
|
+
kept.push(entry);
|
|
45249
|
+
}
|
|
45250
|
+
return { kept, removed };
|
|
45251
|
+
}
|
|
45252
|
+
async function pruneConflictingPiPackagesFromSettings(settingsPath, scopeLabel, dryRun, log) {
|
|
45253
|
+
if (!await import_fs_extra9.default.pathExists(settingsPath)) {
|
|
45254
|
+
return [];
|
|
45255
|
+
}
|
|
45256
|
+
let existingSettings = {};
|
|
45257
|
+
try {
|
|
45258
|
+
existingSettings = await import_fs_extra9.default.readJson(settingsPath);
|
|
45259
|
+
} catch {
|
|
45260
|
+
return [];
|
|
45261
|
+
}
|
|
45262
|
+
const existingPackages = normalizeStringArray(existingSettings.packages);
|
|
45263
|
+
const { kept, removed } = pruneConflictingPiPackageEntries(existingPackages);
|
|
45264
|
+
if (removed.length === 0) {
|
|
45265
|
+
return [];
|
|
45266
|
+
}
|
|
45267
|
+
if (dryRun) {
|
|
45268
|
+
log?.(kleur_default.dim(`[DRY RUN] would remove conflicting Pi package(s) from ${scopeLabel}: ${removed.join(", ")}`));
|
|
45269
|
+
return removed;
|
|
45270
|
+
}
|
|
45271
|
+
await import_fs_extra9.default.writeJson(settingsPath, { ...existingSettings, packages: kept }, { spaces: 2 });
|
|
45272
|
+
log?.(kleur_default.dim(`Removed conflicting Pi package(s) from ${scopeLabel}: ${removed.join(", ")}`));
|
|
45273
|
+
return removed;
|
|
45274
|
+
}
|
|
45275
|
+
async function cleanupConflictingPiPackageSettings(projectRoot, dryRun, log) {
|
|
45276
|
+
await pruneConflictingPiPackagesFromSettings(
|
|
45277
|
+
import_path4.default.join(PI_AGENT_DIR, "settings.json"),
|
|
45278
|
+
"~/.pi/agent/settings.json",
|
|
45279
|
+
dryRun,
|
|
45280
|
+
log
|
|
45281
|
+
);
|
|
45282
|
+
await pruneConflictingPiPackagesFromSettings(
|
|
45283
|
+
import_path4.default.join(projectRoot, ".pi", "settings.json"),
|
|
45284
|
+
`${projectRoot}/.pi/settings.json`,
|
|
45285
|
+
dryRun,
|
|
45286
|
+
log
|
|
45287
|
+
);
|
|
45288
|
+
}
|
|
45098
45289
|
async function updatePiSettings(projectRoot, dryRun, log) {
|
|
45099
|
-
const
|
|
45290
|
+
const piDirPath = import_path4.default.join(projectRoot, ".pi");
|
|
45291
|
+
const piSettingsPath = import_path4.default.join(piDirPath, "settings.json");
|
|
45100
45292
|
if (dryRun) {
|
|
45101
|
-
log?.(kleur_default.dim(`[DRY RUN] would
|
|
45293
|
+
log?.(kleur_default.dim(`[DRY RUN] would ensure .pi/settings.json with ${PROJECT_EXTENSION_PACKAGE_ID}`));
|
|
45102
45294
|
return;
|
|
45103
45295
|
}
|
|
45296
|
+
await import_fs_extra9.default.ensureDir(piDirPath);
|
|
45104
45297
|
let existingSettings = {};
|
|
45105
45298
|
try {
|
|
45106
45299
|
existingSettings = await import_fs_extra9.default.readJson(piSettingsPath);
|
|
45107
45300
|
} catch {
|
|
45108
|
-
|
|
45109
|
-
|
|
45110
|
-
|
|
45111
|
-
);
|
|
45112
|
-
|
|
45113
|
-
|
|
45301
|
+
existingSettings = {};
|
|
45302
|
+
}
|
|
45303
|
+
const LEGACY_PACKAGE_IDS = /* @__PURE__ */ new Set(["npm:@xtrm/pi-extensions", "./extensions/"]);
|
|
45304
|
+
const existingProjectPackages = normalizeStringArray(existingSettings.packages).filter((entry) => !LEGACY_PACKAGE_IDS.has(entry) && !entry.startsWith("./extensions/"));
|
|
45305
|
+
const { kept: existingPackages } = pruneConflictingPiPackageEntries(existingProjectPackages);
|
|
45306
|
+
if (!existingPackages.includes(PROJECT_EXTENSION_PACKAGE_ID)) {
|
|
45307
|
+
existingPackages.push(PROJECT_EXTENSION_PACKAGE_ID);
|
|
45308
|
+
}
|
|
45309
|
+
const existingSkills = normalizeStringArray(existingSettings.skills).filter((entry) => entry !== PROJECT_SKILLS_ENTRY);
|
|
45310
|
+
existingSkills.unshift(PROJECT_SKILLS_ENTRY);
|
|
45311
|
+
const existingExtensions = normalizeStringArray(existingSettings.extensions).filter((entry) => !LEGACY_PROJECT_EXTENSION_ENTRIES.has(entry));
|
|
45312
|
+
const nextSettings = {
|
|
45114
45313
|
...existingSettings,
|
|
45115
|
-
extensions:
|
|
45116
|
-
|
|
45117
|
-
|
|
45118
|
-
|
|
45119
|
-
|
|
45120
|
-
|
|
45121
|
-
log?.(kleur_default.dim(`Updated .pi/settings.json \u2192 global extensions + packages + .xtrm/skills/active/pi`));
|
|
45314
|
+
extensions: existingExtensions,
|
|
45315
|
+
skills: existingSkills,
|
|
45316
|
+
packages: existingPackages
|
|
45317
|
+
};
|
|
45318
|
+
await import_fs_extra9.default.writeJson(piSettingsPath, nextSettings, { spaces: 2 });
|
|
45319
|
+
log?.(kleur_default.dim(`Updated .pi/settings.json \u2192 ${PROJECT_EXTENSION_PACKAGE_ID} + ${PROJECT_SKILLS_ENTRY}`));
|
|
45122
45320
|
}
|
|
45123
45321
|
async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
45124
45322
|
const {
|
|
@@ -45188,13 +45386,16 @@ async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
|
45188
45386
|
continue;
|
|
45189
45387
|
}
|
|
45190
45388
|
try {
|
|
45191
|
-
const
|
|
45192
|
-
if (
|
|
45389
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log);
|
|
45390
|
+
if (installAttempt.status === 0) {
|
|
45193
45391
|
result.packagesInstalled.push(pkg.id);
|
|
45194
|
-
log(`${sym.ok} ${pkg.displayName}`);
|
|
45392
|
+
log(`${sym.ok} ${pkg.displayName}${installAttempt.retriedWithNpmjs ? " (npmjs fallback)" : ""}`);
|
|
45195
45393
|
} else {
|
|
45196
45394
|
result.failed.push(pkg.id);
|
|
45197
45395
|
log(kleur_default.yellow(`\u26A0 ${pkg.displayName} \u2014 install failed`));
|
|
45396
|
+
for (const hint of getPiPackageInstallFailureHint(pkg.id, installAttempt.output)) {
|
|
45397
|
+
log(kleur_default.yellow(` \u2192 ${hint}`));
|
|
45398
|
+
}
|
|
45198
45399
|
}
|
|
45199
45400
|
} catch (err) {
|
|
45200
45401
|
result.failed.push(pkg.id);
|
|
@@ -45203,114 +45404,20 @@ async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
|
45203
45404
|
}
|
|
45204
45405
|
return result;
|
|
45205
45406
|
}
|
|
45206
|
-
var EXTENSION_SOURCE_DIR = "ext-src";
|
|
45207
|
-
async function linkExtensionsToGlobal(repoRoot, dryRun = false, log = (msg) => console.log(kleur_default.dim(` ${msg}`))) {
|
|
45208
|
-
const globalExtDir = import_path4.default.join(PI_AGENT_DIR, "extensions");
|
|
45209
|
-
const repoExtDir = import_path4.default.join(repoRoot, ".xtrm", EXTENSION_SOURCE_DIR);
|
|
45210
|
-
const linked = [];
|
|
45211
|
-
const failed = [];
|
|
45212
|
-
if (!await import_fs_extra9.default.pathExists(repoExtDir)) {
|
|
45213
|
-
log("No .xtrm/ext-src/ found \u2014 skipping global link");
|
|
45214
|
-
return { linked, failed };
|
|
45215
|
-
}
|
|
45216
|
-
if (dryRun) {
|
|
45217
|
-
log("[DRY RUN] would create extension symlinks in ~/.pi/agent/extensions/");
|
|
45218
|
-
return { linked, failed };
|
|
45219
|
-
}
|
|
45220
|
-
await import_fs_extra9.default.ensureDir(globalExtDir);
|
|
45221
|
-
const coreNodeModulesDir = import_path4.default.join(globalExtDir, "node_modules", "@xtrm");
|
|
45222
|
-
const coreSymlinkPath = import_path4.default.join(coreNodeModulesDir, "pi-core");
|
|
45223
|
-
const coreRelativeTarget = import_path4.default.join("..", "..", "core");
|
|
45224
|
-
try {
|
|
45225
|
-
await import_fs_extra9.default.ensureDir(coreNodeModulesDir);
|
|
45226
|
-
const existing = await import_fs_extra9.default.lstat(coreSymlinkPath).catch(() => null);
|
|
45227
|
-
if (existing) await import_fs_extra9.default.remove(coreSymlinkPath);
|
|
45228
|
-
await import_fs_extra9.default.symlink(coreRelativeTarget, coreSymlinkPath);
|
|
45229
|
-
log("\u2713 @xtrm/pi-core \u2192 global node_modules");
|
|
45230
|
-
} catch (err) {
|
|
45231
|
-
log(kleur_default.yellow(`\u26A0 @xtrm/pi-core symlink: ${err}`));
|
|
45232
|
-
}
|
|
45233
|
-
const entries = await import_fs_extra9.default.readdir(repoExtDir, { withFileTypes: true });
|
|
45234
|
-
for (const entry of entries) {
|
|
45235
|
-
if (!entry.isDirectory()) continue;
|
|
45236
|
-
if (entry.name === "node_modules") continue;
|
|
45237
|
-
const extPath = import_path4.default.join(repoExtDir, entry.name);
|
|
45238
|
-
const globalLink = import_path4.default.join(globalExtDir, entry.name);
|
|
45239
|
-
try {
|
|
45240
|
-
const existing = await import_fs_extra9.default.lstat(globalLink).catch(() => null);
|
|
45241
|
-
if (existing) {
|
|
45242
|
-
if (existing.isSymbolicLink()) {
|
|
45243
|
-
const currentTarget = await import_fs_extra9.default.readlink(globalLink);
|
|
45244
|
-
const resolvedTarget = import_path4.default.resolve(import_path4.default.dirname(globalLink), currentTarget);
|
|
45245
|
-
if (resolvedTarget === import_path4.default.resolve(extPath)) {
|
|
45246
|
-
continue;
|
|
45247
|
-
}
|
|
45248
|
-
}
|
|
45249
|
-
await import_fs_extra9.default.remove(globalLink);
|
|
45250
|
-
}
|
|
45251
|
-
await import_fs_extra9.default.symlink(extPath, globalLink);
|
|
45252
|
-
linked.push(entry.name);
|
|
45253
|
-
log(`\u2713 ${entry.name} \u2192 .xtrm/${EXTENSION_SOURCE_DIR}/${entry.name}`);
|
|
45254
|
-
} catch (err) {
|
|
45255
|
-
failed.push(entry.name);
|
|
45256
|
-
log(kleur_default.red(`\u2717 ${entry.name}: ${err}`));
|
|
45257
|
-
}
|
|
45258
|
-
}
|
|
45259
|
-
return { linked, failed };
|
|
45260
|
-
}
|
|
45261
|
-
async function ensureNpmPackageExtensionSymlinks(log) {
|
|
45262
|
-
const os9 = require("os");
|
|
45263
|
-
const homeDir = os9.homedir();
|
|
45264
|
-
const extensionsDir = import_path4.default.join(homeDir, ".pi", "agent", "extensions");
|
|
45265
|
-
await import_fs_extra9.default.ensureDir(extensionsDir);
|
|
45266
|
-
const npmPrefix = (0, import_child_process3.spawnSync)("npm", ["prefix", "-g"], { encoding: "utf8" }).stdout.trim();
|
|
45267
|
-
const globalNodeModules = import_path4.default.join(npmPrefix, "lib", "node_modules");
|
|
45268
|
-
const npmPackages = [
|
|
45269
|
-
{ packageName: "pi-gitnexus", symlinkName: "gitnexus" },
|
|
45270
|
-
{ packageName: "pi-serena-tools", symlinkName: "serena" }
|
|
45271
|
-
];
|
|
45272
|
-
for (const { packageName, symlinkName } of npmPackages) {
|
|
45273
|
-
const packagePath = import_path4.default.join(globalNodeModules, packageName);
|
|
45274
|
-
const symlinkPath = import_path4.default.join(extensionsDir, symlinkName);
|
|
45275
|
-
const packageExists = await import_fs_extra9.default.pathExists(packagePath);
|
|
45276
|
-
if (!packageExists) {
|
|
45277
|
-
log?.(kleur_default.yellow(` \u26A0 ${packageName} not found in ${globalNodeModules}, skipping symlink`));
|
|
45278
|
-
continue;
|
|
45279
|
-
}
|
|
45280
|
-
const symlinkExists = await import_fs_extra9.default.lstat(symlinkPath).catch(() => null);
|
|
45281
|
-
if (symlinkExists?.isSymbolicLink()) {
|
|
45282
|
-
const currentTarget = await import_fs_extra9.default.readlink(symlinkPath);
|
|
45283
|
-
const resolvedTarget = import_path4.default.resolve(extensionsDir, currentTarget);
|
|
45284
|
-
if (resolvedTarget === packagePath) {
|
|
45285
|
-
log?.(kleur_default.dim(` \u2713 ${symlinkName} symlink already correct`));
|
|
45286
|
-
continue;
|
|
45287
|
-
}
|
|
45288
|
-
log?.(kleur_default.dim(` Removing stale ${symlinkName} symlink`));
|
|
45289
|
-
await import_fs_extra9.default.remove(symlinkPath);
|
|
45290
|
-
} else if (symlinkExists) {
|
|
45291
|
-
log?.(kleur_default.dim(` Removing stale ${symlinkName} (not a symlink)`));
|
|
45292
|
-
await import_fs_extra9.default.remove(symlinkPath);
|
|
45293
|
-
}
|
|
45294
|
-
const relativeTarget = import_path4.default.relative(extensionsDir, packagePath);
|
|
45295
|
-
await import_fs_extra9.default.symlink(relativeTarget, symlinkPath);
|
|
45296
|
-
log?.(kleur_default.dim(` Created ${symlinkName} symlink \u2192 ${relativeTarget}`));
|
|
45297
|
-
}
|
|
45298
|
-
}
|
|
45299
45407
|
async function runPiRuntimeSync(opts = {}) {
|
|
45300
45408
|
const { dryRun = false, isGlobal = false, projectRoot } = opts;
|
|
45301
45409
|
const pkgRoot = resolvePkgRoot();
|
|
45302
|
-
const sourceDir =
|
|
45410
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(pkgRoot);
|
|
45303
45411
|
const resolvedProjectRoot = projectRoot || process.cwd();
|
|
45304
45412
|
const log = (msg) => console.log(kleur_default.dim(` ${msg}`));
|
|
45305
|
-
const
|
|
45413
|
+
const result = {
|
|
45306
45414
|
extensionsAdded: [],
|
|
45307
45415
|
extensionsUpdated: [],
|
|
45308
45416
|
extensionsRemoved: [],
|
|
45309
45417
|
packagesInstalled: [],
|
|
45310
45418
|
failed: []
|
|
45311
45419
|
};
|
|
45312
|
-
|
|
45313
|
-
if (!await import_fs_extra9.default.pathExists(sourceDir)) {
|
|
45420
|
+
if (!sourceDir || !await import_fs_extra9.default.pathExists(sourceDir)) {
|
|
45314
45421
|
console.log(kleur_default.dim("\n Managed extensions: skipped (not bundled in npm package)\n"));
|
|
45315
45422
|
return result;
|
|
45316
45423
|
}
|
|
@@ -45318,6 +45425,7 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45318
45425
|
if (preflight.staleOverride.remediated) {
|
|
45319
45426
|
result.extensionsRemoved.push("pi-mcp-adapter");
|
|
45320
45427
|
}
|
|
45428
|
+
await cleanupConflictingPiPackageSettings(resolvedProjectRoot, dryRun, log);
|
|
45321
45429
|
if (isGlobal) {
|
|
45322
45430
|
const targetDir = import_path4.default.join(PI_AGENT_DIR, "extensions");
|
|
45323
45431
|
const plan = await inventoryPiRuntime(sourceDir, targetDir);
|
|
@@ -45330,32 +45438,47 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45330
45438
|
});
|
|
45331
45439
|
return mergePiSyncResults(result, synced);
|
|
45332
45440
|
}
|
|
45333
|
-
const linkResult = await linkExtensionsToGlobal(resolvedProjectRoot, dryRun, log);
|
|
45334
|
-
result.extensionsAdded.push(...linkResult.linked);
|
|
45335
|
-
result.failed.push(...linkResult.failed);
|
|
45336
|
-
await ensureNpmPackageExtensionSymlinks(log);
|
|
45337
45441
|
const installedPkgIds = getInstalledPiPackages();
|
|
45338
|
-
const packageStatuses =
|
|
45339
|
-
const missingPackages =
|
|
45340
|
-
for (const pkg of MANAGED_PACKAGES) {
|
|
45341
|
-
const isInstalled = installedPkgIds.includes(pkg.id);
|
|
45342
|
-
const status = { pkg, installed: isInstalled };
|
|
45343
|
-
packageStatuses.push(status);
|
|
45344
|
-
if (!isInstalled) missingPackages.push(status);
|
|
45345
|
-
}
|
|
45442
|
+
const packageStatuses = getProjectRequiredPackageStatuses(installedPkgIds);
|
|
45443
|
+
const missingPackages = packageStatuses.filter((status) => !status.installed);
|
|
45346
45444
|
console.log(kleur_default.bold("\n Pi Runtime"));
|
|
45347
45445
|
console.log(kleur_default.dim(" " + "-".repeat(50)));
|
|
45348
|
-
|
|
45349
|
-
|
|
45446
|
+
const extensionPackageInstalled = packageStatuses.some(
|
|
45447
|
+
(status) => status.pkg.id === PROJECT_EXTENSION_PACKAGE_ID && status.installed
|
|
45448
|
+
);
|
|
45449
|
+
console.log(kleur_default.dim(` Extensions: ${extensionPackageInstalled ? "package installed" : "package missing"} (${PROJECT_EXTENSION_PACKAGE_ID})`));
|
|
45450
|
+
const pkgOk = packageStatuses.filter((status) => status.installed).length;
|
|
45350
45451
|
console.log(kleur_default.dim(` Packages: ${pkgOk}/${packageStatuses.length} installed`));
|
|
45351
45452
|
if (missingPackages.length > 0) {
|
|
45352
|
-
const names = missingPackages.map((
|
|
45453
|
+
const names = missingPackages.map((status) => status.pkg.displayName).join(", ");
|
|
45353
45454
|
console.log(kleur_default.yellow(` Missing: ${names}`));
|
|
45354
45455
|
}
|
|
45355
45456
|
console.log(kleur_default.dim(" " + "-".repeat(50)));
|
|
45356
45457
|
const legacyCleanup = await cleanupLegacyProjectExtensionCopies(resolvedProjectRoot, dryRun, log);
|
|
45357
45458
|
result.extensionsRemoved.push(...legacyCleanup.removed);
|
|
45358
45459
|
result.failed.push(...legacyCleanup.failed);
|
|
45460
|
+
const globalExtDir = import_path4.default.join(PI_AGENT_DIR, "extensions");
|
|
45461
|
+
if (await import_fs_extra9.default.pathExists(globalExtDir)) {
|
|
45462
|
+
const MANAGED_EXT_IDS = new Set(MANAGED_EXTENSIONS.map((e) => e.id));
|
|
45463
|
+
const STALE_SYMLINKS = /* @__PURE__ */ new Set([...MANAGED_EXT_IDS, "core", "gitnexus", "serena"]);
|
|
45464
|
+
const globalEntries = await import_fs_extra9.default.readdir(globalExtDir, { withFileTypes: true });
|
|
45465
|
+
for (const entry of globalEntries) {
|
|
45466
|
+
if (entry.isSymbolicLink() && STALE_SYMLINKS.has(entry.name)) {
|
|
45467
|
+
if (!dryRun) {
|
|
45468
|
+
await import_fs_extra9.default.remove(import_path4.default.join(globalExtDir, entry.name));
|
|
45469
|
+
}
|
|
45470
|
+
result.extensionsRemoved.push(entry.name);
|
|
45471
|
+
log(`Removed stale global symlink: ${entry.name}`);
|
|
45472
|
+
}
|
|
45473
|
+
}
|
|
45474
|
+
const staleNodeModules = import_path4.default.join(globalExtDir, "node_modules");
|
|
45475
|
+
if (await import_fs_extra9.default.pathExists(staleNodeModules)) {
|
|
45476
|
+
if (!dryRun) {
|
|
45477
|
+
await import_fs_extra9.default.remove(staleNodeModules);
|
|
45478
|
+
}
|
|
45479
|
+
log("Removed stale global extensions/node_modules");
|
|
45480
|
+
}
|
|
45481
|
+
}
|
|
45359
45482
|
for (const status of missingPackages) {
|
|
45360
45483
|
const { pkg } = status;
|
|
45361
45484
|
if (dryRun) {
|
|
@@ -45363,13 +45486,16 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45363
45486
|
continue;
|
|
45364
45487
|
}
|
|
45365
45488
|
try {
|
|
45366
|
-
const
|
|
45367
|
-
if (
|
|
45489
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log);
|
|
45490
|
+
if (installAttempt.status === 0) {
|
|
45368
45491
|
result.packagesInstalled.push(pkg.id);
|
|
45369
|
-
log(`${sym.ok} ${pkg.displayName}`);
|
|
45370
|
-
|
|
45371
|
-
|
|
45372
|
-
|
|
45492
|
+
log(`${sym.ok} ${pkg.displayName}${installAttempt.retriedWithNpmjs ? " (npmjs fallback)" : ""}`);
|
|
45493
|
+
continue;
|
|
45494
|
+
}
|
|
45495
|
+
result.failed.push(pkg.id);
|
|
45496
|
+
log(kleur_default.yellow(`\u26A0 ${pkg.displayName} \u2014 install failed`));
|
|
45497
|
+
for (const hint of getPiPackageInstallFailureHint(pkg.id, installAttempt.output)) {
|
|
45498
|
+
log(kleur_default.yellow(` \u2192 ${hint}`));
|
|
45373
45499
|
}
|
|
45374
45500
|
} catch (err) {
|
|
45375
45501
|
result.failed.push(pkg.id);
|
|
@@ -45391,12 +45517,8 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45391
45517
|
}
|
|
45392
45518
|
}
|
|
45393
45519
|
await updatePiSettings(resolvedProjectRoot, dryRun, log);
|
|
45394
|
-
const requiredFailed = missingPackages.filter(
|
|
45395
|
-
|
|
45396
|
-
);
|
|
45397
|
-
if (missingPackages.length === 0 || result.failed.length === 0) {
|
|
45398
|
-
console.log(t.success(" \u2713 All required items present.\n"));
|
|
45399
|
-
} else if (requiredFailed.length === 0) {
|
|
45520
|
+
const requiredFailed = missingPackages.filter((status) => status.pkg.required && result.failed.includes(status.pkg.id));
|
|
45521
|
+
if (requiredFailed.length === 0) {
|
|
45400
45522
|
console.log(t.success(" \u2713 All required items present.\n"));
|
|
45401
45523
|
} else {
|
|
45402
45524
|
console.log(kleur_default.yellow(" \u26A0 Missing required items.\n"));
|
|
@@ -45633,21 +45755,21 @@ function hasSettingsEntry(entries, expectedEntry) {
|
|
|
45633
45755
|
});
|
|
45634
45756
|
}
|
|
45635
45757
|
async function getPiProjectPointer(projectRoot) {
|
|
45636
|
-
const projectExtensionsDir = import_path7.default.join(projectRoot, ".xtrm", "extensions");
|
|
45637
45758
|
const settingsPath = import_path7.default.join(projectRoot, ".pi", "settings.json");
|
|
45638
|
-
const hasProjectExtensions = await import_fs_extra11.default.pathExists(projectExtensionsDir);
|
|
45639
45759
|
const hasSettingsFile = await import_fs_extra11.default.pathExists(settingsPath);
|
|
45640
45760
|
if (!hasSettingsFile) {
|
|
45641
|
-
return {
|
|
45761
|
+
return { hasProjectSettings: false, hasProjectExtensionPackage: false, pointsToXtrmExtensions: false };
|
|
45642
45762
|
}
|
|
45643
45763
|
try {
|
|
45644
45764
|
const settings = await import_fs_extra11.default.readJson(settingsPath);
|
|
45765
|
+
const packageEntries = Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
|
|
45645
45766
|
return {
|
|
45646
|
-
|
|
45767
|
+
hasProjectSettings: true,
|
|
45768
|
+
hasProjectExtensionPackage: packageEntries.includes("npm:@jaggerxtrm/pi-extensions"),
|
|
45647
45769
|
pointsToXtrmExtensions: hasSettingsEntry(settings.extensions, "../.xtrm/extensions")
|
|
45648
45770
|
};
|
|
45649
45771
|
} catch {
|
|
45650
|
-
return {
|
|
45772
|
+
return { hasProjectSettings: true, hasProjectExtensionPackage: false, pointsToXtrmExtensions: false };
|
|
45651
45773
|
}
|
|
45652
45774
|
}
|
|
45653
45775
|
function createPiCommand() {
|
|
@@ -45671,31 +45793,29 @@ function createPiCommand() {
|
|
|
45671
45793
|
const projectRoot = resolveProjectRoot();
|
|
45672
45794
|
const pointer = await getPiProjectPointer(projectRoot);
|
|
45673
45795
|
const bundleRoot = await findRepoRoot();
|
|
45674
|
-
const sourceDir =
|
|
45796
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(bundleRoot);
|
|
45675
45797
|
const globalTargetDir = import_path7.default.join(PI_AGENT_DIR4, "extensions");
|
|
45676
|
-
if (!await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45798
|
+
if (!sourceDir || !await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45677
45799
|
console.log(kleur_default.dim(" \u25CB managed extensions not bundled in this install\n"));
|
|
45678
45800
|
return;
|
|
45679
45801
|
}
|
|
45680
45802
|
const plan = await inventoryPiRuntime(sourceDir, globalTargetDir);
|
|
45681
45803
|
const pkgOk = plan.packages.filter((s) => s.installed).length;
|
|
45682
|
-
|
|
45804
|
+
const projectScoped = pointer.hasProjectExtensionPackage || pointer.pointsToXtrmExtensions;
|
|
45805
|
+
if (projectScoped) {
|
|
45683
45806
|
console.log(kleur_default.dim(" Scope: project"));
|
|
45684
|
-
console.log(kleur_default.dim(
|
|
45807
|
+
console.log(kleur_default.dim(` Extensions: package mode (npm:@jaggerxtrm/pi-extensions${pointer.hasProjectExtensionPackage ? "" : " missing"})`));
|
|
45685
45808
|
} else {
|
|
45686
45809
|
console.log(kleur_default.dim(" Scope: global"));
|
|
45687
45810
|
const extOk = plan.extensions.filter((s) => s.installed && !s.stale).length;
|
|
45688
45811
|
console.log(kleur_default.dim(` Extensions: ${extOk}/${plan.extensions.length} up-to-date`));
|
|
45689
45812
|
}
|
|
45690
45813
|
console.log(kleur_default.dim(` Packages: ${pkgOk}/${plan.packages.length} installed`));
|
|
45691
|
-
if (pointer.hasProjectExtensions && !pointer.pointsToXtrmExtensions) {
|
|
45692
|
-
console.log(kleur_default.yellow(" Settings: .pi/settings.json is not pointing to ../.xtrm/extensions"));
|
|
45693
|
-
}
|
|
45694
45814
|
if (plan.missingPackages.length > 0) {
|
|
45695
45815
|
const names = plan.missingPackages.map((s) => s.pkg.displayName).join(", ");
|
|
45696
45816
|
console.log(kleur_default.yellow(` Packages: ${names}`));
|
|
45697
45817
|
}
|
|
45698
|
-
if (!
|
|
45818
|
+
if (!projectScoped) {
|
|
45699
45819
|
if (plan.missingExtensions.length > 0) {
|
|
45700
45820
|
const names = plan.missingExtensions.map((s) => s.ext.displayName).join(", ");
|
|
45701
45821
|
console.log(kleur_default.yellow(` Missing: ${names}`));
|
|
@@ -45708,13 +45828,16 @@ function createPiCommand() {
|
|
|
45708
45828
|
console.log(kleur_default.red(` Orphaned: ${plan.orphanedExtensions.join(", ")}`));
|
|
45709
45829
|
}
|
|
45710
45830
|
}
|
|
45711
|
-
const
|
|
45712
|
-
const hasGlobalDrift = !
|
|
45831
|
+
const hasProjectSettingsDrift = !pointer.hasProjectSettings || !pointer.hasProjectExtensionPackage;
|
|
45832
|
+
const hasGlobalDrift = !projectScoped && !plan.allPresent;
|
|
45713
45833
|
const hasPackageDrift = plan.missingPackages.length > 0;
|
|
45714
|
-
if (
|
|
45834
|
+
if (!hasProjectSettingsDrift && !hasGlobalDrift && !hasPackageDrift) {
|
|
45715
45835
|
console.log(t.success("\n \u2713 Pi runtime configuration looks healthy\n"));
|
|
45716
45836
|
return;
|
|
45717
45837
|
}
|
|
45838
|
+
if (hasProjectSettingsDrift) {
|
|
45839
|
+
console.log(kleur_default.yellow(" Settings: .pi/settings.json missing managed npm:@jaggerxtrm/pi-extensions entry"));
|
|
45840
|
+
}
|
|
45718
45841
|
console.log(kleur_default.dim("\n \u2192 run: xt pi reload\n"));
|
|
45719
45842
|
});
|
|
45720
45843
|
cmd.command("doctor").description("Diagnostic checks: pi installed, extensions deployed, packages present, orphaned extensions").action(async () => {
|
|
@@ -45745,7 +45868,8 @@ function createPiCommand() {
|
|
|
45745
45868
|
const projectRoot = resolveProjectRoot();
|
|
45746
45869
|
const pointer = await getPiProjectPointer(projectRoot);
|
|
45747
45870
|
const bundleRoot = await findRepoRoot();
|
|
45748
|
-
const sourceDir =
|
|
45871
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(bundleRoot);
|
|
45872
|
+
const coreSourceDir = resolveManagedPiCoreSourceDir(bundleRoot);
|
|
45749
45873
|
const globalTargetDir = import_path7.default.join(PI_AGENT_DIR4, "extensions");
|
|
45750
45874
|
try {
|
|
45751
45875
|
const staleOverride = await remediateStalePiMcpAdapterOverride(false);
|
|
@@ -45762,7 +45886,7 @@ function createPiCommand() {
|
|
|
45762
45886
|
allOk = false;
|
|
45763
45887
|
}
|
|
45764
45888
|
try {
|
|
45765
|
-
const coreStatus = await ensureCorePackageSymlink(
|
|
45889
|
+
const coreStatus = coreSourceDir ? await ensureCorePackageSymlink(coreSourceDir, projectRoot, false) : "missing-source";
|
|
45766
45890
|
if (coreStatus === "repaired" || coreStatus === "created") {
|
|
45767
45891
|
console.log(t.success(" \u2713 repaired .xtrm/extensions/node_modules/@xtrm/pi-core symlink"));
|
|
45768
45892
|
} else if (coreStatus === "ok") {
|
|
@@ -45774,15 +45898,21 @@ function createPiCommand() {
|
|
|
45774
45898
|
console.log(kleur_default.yellow(` \u26A0 failed to ensure @xtrm/pi-core symlink: ${error48}`));
|
|
45775
45899
|
allOk = false;
|
|
45776
45900
|
}
|
|
45777
|
-
if (!await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45901
|
+
if (!sourceDir || !await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45778
45902
|
console.log(kleur_default.dim(" \u25CB managed extensions not bundled in this install"));
|
|
45779
45903
|
} else {
|
|
45780
45904
|
const plan = await inventoryPiRuntime(sourceDir, globalTargetDir);
|
|
45781
|
-
|
|
45782
|
-
|
|
45783
|
-
|
|
45784
|
-
console.log(kleur_default.yellow(" \u26A0 .pi/settings.json does not include ../.xtrm/extensions"));
|
|
45905
|
+
const projectScoped = pointer.hasProjectExtensionPackage || pointer.pointsToXtrmExtensions;
|
|
45906
|
+
if (!pointer.hasProjectSettings) {
|
|
45907
|
+
console.log(kleur_default.yellow(" \u26A0 missing .pi/settings.json; run xt pi reload to bootstrap project Pi settings"));
|
|
45785
45908
|
allOk = false;
|
|
45909
|
+
} else if (projectScoped) {
|
|
45910
|
+
if (pointer.hasProjectExtensionPackage) {
|
|
45911
|
+
console.log(t.success(" \u2713 project runtime uses npm:@jaggerxtrm/pi-extensions"));
|
|
45912
|
+
} else {
|
|
45913
|
+
console.log(kleur_default.yellow(" \u26A0 legacy project extension pointer detected; run xt pi reload to migrate"));
|
|
45914
|
+
allOk = false;
|
|
45915
|
+
}
|
|
45786
45916
|
} else if (plan.missingExtensions.length === 0 && plan.staleExtensions.length === 0 && plan.orphanedExtensions.length === 0) {
|
|
45787
45917
|
console.log(t.success(` \u2713 global extensions deployed (${plan.extensions.length})`));
|
|
45788
45918
|
} else {
|
|
@@ -45997,12 +46127,16 @@ async function installFromRegistry(params) {
|
|
|
45997
46127
|
installed: 0,
|
|
45998
46128
|
upToDate: drift.upToDate.length,
|
|
45999
46129
|
driftedSkipped: drift.drifted.length,
|
|
46000
|
-
forced: 0
|
|
46130
|
+
forced: 0,
|
|
46131
|
+
expectedInstalls: 0,
|
|
46132
|
+
missingSourceSkipped: 0
|
|
46001
46133
|
};
|
|
46002
46134
|
}
|
|
46003
46135
|
}
|
|
46004
46136
|
let installed = 0;
|
|
46005
46137
|
let forced = 0;
|
|
46138
|
+
let expectedInstalls = 0;
|
|
46139
|
+
let missingSourceSkipped = 0;
|
|
46006
46140
|
for (const asset of Object.values(registry2.assets)) {
|
|
46007
46141
|
for (const [filePath] of Object.entries(asset.files)) {
|
|
46008
46142
|
const relativePath = toUserRelativePath(asset.source_dir, filePath);
|
|
@@ -46025,6 +46159,13 @@ async function installFromRegistry(params) {
|
|
|
46025
46159
|
if (isDrifted && force) {
|
|
46026
46160
|
forced += 1;
|
|
46027
46161
|
}
|
|
46162
|
+
expectedInstalls += 1;
|
|
46163
|
+
const sourceExists = await import_fs_extra13.default.pathExists(sourcePath);
|
|
46164
|
+
if (!sourceExists) {
|
|
46165
|
+
missingSourceSkipped += 1;
|
|
46166
|
+
console.log(kleur_default.yellow(` \u26A0 Skipping missing source file: ${toPosix2(import_path8.default.relative(packageRoot, sourcePath))}`));
|
|
46167
|
+
continue;
|
|
46168
|
+
}
|
|
46028
46169
|
if (dryRun) {
|
|
46029
46170
|
const action = isDrifted ? "overwrite" : "install";
|
|
46030
46171
|
console.log(kleur_default.dim(` [DRY RUN] would ${action} ${relativePath}`));
|
|
@@ -46040,7 +46181,9 @@ async function installFromRegistry(params) {
|
|
|
46040
46181
|
installed,
|
|
46041
46182
|
upToDate: upToDateSet.size,
|
|
46042
46183
|
driftedSkipped: force ? 0 : driftedSet.size,
|
|
46043
|
-
forced
|
|
46184
|
+
forced,
|
|
46185
|
+
expectedInstalls,
|
|
46186
|
+
missingSourceSkipped
|
|
46044
46187
|
};
|
|
46045
46188
|
}
|
|
46046
46189
|
|
|
@@ -46558,9 +46701,8 @@ function verifyClaudeRuntime(projectRoot) {
|
|
|
46558
46701
|
return fallbackResult;
|
|
46559
46702
|
}
|
|
46560
46703
|
async function verifyPiRuntime(projectRoot) {
|
|
46561
|
-
const
|
|
46562
|
-
|
|
46563
|
-
if (!await import_fs_extra16.default.pathExists(sourceDir)) {
|
|
46704
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir();
|
|
46705
|
+
if (!sourceDir || !await import_fs_extra16.default.pathExists(sourceDir)) {
|
|
46564
46706
|
return {
|
|
46565
46707
|
extensions: [],
|
|
46566
46708
|
packages: [],
|
|
@@ -46586,16 +46728,6 @@ ${gnStatus.stderr ?? ""}`.toLowerCase();
|
|
|
46586
46728
|
const instructionHeaders = agentsMd || claudeMd;
|
|
46587
46729
|
return { beadsInitialized, gitnexusIndexed, instructionHeaders };
|
|
46588
46730
|
}
|
|
46589
|
-
function resolvePkgRoot2() {
|
|
46590
|
-
const candidates = [
|
|
46591
|
-
import_path10.default.resolve(__dirname, "../.."),
|
|
46592
|
-
import_path10.default.resolve(__dirname, "../../..")
|
|
46593
|
-
];
|
|
46594
|
-
for (const c of candidates) {
|
|
46595
|
-
if (import_fs_extra16.default.existsSync(import_path10.default.join(c, ".xtrm", "extensions"))) return c;
|
|
46596
|
-
}
|
|
46597
|
-
return candidates[0];
|
|
46598
|
-
}
|
|
46599
46731
|
async function runInitVerification(projectRoot) {
|
|
46600
46732
|
const machinePlan = verifyMachineBootstrap();
|
|
46601
46733
|
const claudeResult = verifyClaudeRuntime(projectRoot);
|
|
@@ -48617,7 +48749,7 @@ async function runProjectInit(opts = {}) {
|
|
|
48617
48749
|
const userXtrmDir = ctx.targets[0];
|
|
48618
48750
|
const registryPath = import_path15.default.join(packageRoot, ".xtrm", "registry.json");
|
|
48619
48751
|
const registry2 = await import_fs_extra21.default.readJson(registryPath);
|
|
48620
|
-
await installFromRegistry({
|
|
48752
|
+
const registryInstallStats = await installFromRegistry({
|
|
48621
48753
|
packageRoot,
|
|
48622
48754
|
registry: registry2,
|
|
48623
48755
|
userXtrmDir,
|
|
@@ -48625,6 +48757,10 @@ async function runProjectInit(opts = {}) {
|
|
|
48625
48757
|
force: false,
|
|
48626
48758
|
yes: true
|
|
48627
48759
|
});
|
|
48760
|
+
if (registryInstallStats.missingSourceSkipped > 0) {
|
|
48761
|
+
console.log(kleur_default.yellow(` \u26A0 Registry/source mismatch: skipped ${registryInstallStats.missingSourceSkipped} missing source file${registryInstallStats.missingSourceSkipped === 1 ? "" : "s"}.`));
|
|
48762
|
+
console.log(kleur_default.yellow(" Init continued, but some skills/files may be absent until registry payload is corrected."));
|
|
48763
|
+
}
|
|
48628
48764
|
await scaffoldSkillsDefaultFromPackage({ packageRoot, userXtrmDir, dryRun: false });
|
|
48629
48765
|
const mcpSync = await syncProjectMcpConfig(projectRoot, { preserveExistingFile: true });
|
|
48630
48766
|
if (mcpSync.wroteFile) {
|