xtrm-tools 0.7.4 → 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/pi/extensions/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.combined.log +7 -0
- package/.xtrm/config/pi/extensions/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stderr.log +0 -0
- package/.xtrm/config/pi/extensions/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stdout.log +7 -0
- 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 +392 -194
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +8 -7
- 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/config/pi → 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/config/pi → packages/pi-extensions}/extensions/service-skills/package.json +1 -4
- package/{.xtrm/config/pi → 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/packages/pi-extensions/src/core/index.ts +5 -0
- 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/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-dark.json +3 -7
- package/{.xtrm/config/pi/extensions/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-light.json +0 -4
- 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 → 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/cli/dist/index.cjs
CHANGED
|
@@ -29623,11 +29623,15 @@ async function runClaudeRuntimeSyncPhase(opts) {
|
|
|
29623
29623
|
const hooksConfig = await import_fs_extra2.default.readJson(hooksConfigPath);
|
|
29624
29624
|
const projectHooksDir = import_path2.default.join(repoRoot, ".xtrm", "hooks");
|
|
29625
29625
|
const generatedHooks = resolveHooksForProjectRuntime(hooksConfig.hooks ?? {}, projectHooksDir);
|
|
29626
|
+
const generatedStatusLine = resolveStatusLineForProjectRuntime(hooksConfig.statusLine, projectHooksDir);
|
|
29626
29627
|
const settingsPath = isGlobal ? import_path2.default.join(import_os.default.homedir(), ".claude", "settings.json") : import_path2.default.join(repoRoot, ".claude", "settings.json");
|
|
29627
29628
|
const hasExistingSettings = await import_fs_extra2.default.pathExists(settingsPath);
|
|
29628
29629
|
const baseSettings = await readBaseSettings(settingsTemplatePath);
|
|
29629
29630
|
const existingSettings = hasExistingSettings ? await readSettings(settingsPath) : {};
|
|
29630
29631
|
const mergedSettings = hasExistingSettings ? { ...existingSettings, hooks: generatedHooks } : { ...baseSettings, hooks: generatedHooks };
|
|
29632
|
+
if (generatedStatusLine) {
|
|
29633
|
+
mergedSettings.statusLine = generatedStatusLine;
|
|
29634
|
+
}
|
|
29631
29635
|
if (prune) {
|
|
29632
29636
|
delete mergedSettings.enabledPlugins;
|
|
29633
29637
|
delete mergedSettings.extraKnownMarketplaces;
|
|
@@ -29671,6 +29675,7 @@ async function runClaudeRuntimeSyncPhase(opts) {
|
|
|
29671
29675
|
console.log(t.success(" \u2713 Removed plugin-era settings keys (enabledPlugins, extraKnownMarketplaces)"));
|
|
29672
29676
|
}
|
|
29673
29677
|
console.log(t.success(" \u2713 Claude settings hooks synced\n"));
|
|
29678
|
+
await ensureGlobalStatusLine();
|
|
29674
29679
|
return {
|
|
29675
29680
|
settingsPath,
|
|
29676
29681
|
hooksEventsWritten,
|
|
@@ -29678,6 +29683,24 @@ async function runClaudeRuntimeSyncPhase(opts) {
|
|
|
29678
29683
|
wroteSettings: true
|
|
29679
29684
|
};
|
|
29680
29685
|
}
|
|
29686
|
+
async function ensureGlobalStatusLine() {
|
|
29687
|
+
const homeDir = import_os.default.homedir();
|
|
29688
|
+
const statuslineHookPath = import_path2.default.join(homeDir, ".xtrm", "hooks", "statusline.mjs");
|
|
29689
|
+
const globalSettingsPath = import_path2.default.join(homeDir, ".claude", "settings.json");
|
|
29690
|
+
if (!await import_fs_extra2.default.pathExists(statuslineHookPath)) {
|
|
29691
|
+
return;
|
|
29692
|
+
}
|
|
29693
|
+
const expectedCommand = `node "${statuslineHookPath}"`;
|
|
29694
|
+
const settings = await readSettings(globalSettingsPath);
|
|
29695
|
+
const currentCommand = settings.statusLine?.command;
|
|
29696
|
+
if (currentCommand === expectedCommand) {
|
|
29697
|
+
return;
|
|
29698
|
+
}
|
|
29699
|
+
settings.statusLine = { type: "command", command: expectedCommand };
|
|
29700
|
+
await import_fs_extra2.default.ensureDir(import_path2.default.dirname(globalSettingsPath));
|
|
29701
|
+
await import_fs_extra2.default.writeJson(globalSettingsPath, settings, { spaces: 2 });
|
|
29702
|
+
console.log(t.success(` \u2713 Wired statusline \u2192 ~/.xtrm/hooks/statusline.mjs`));
|
|
29703
|
+
}
|
|
29681
29704
|
function resolveHooksForProjectRuntime(hooks, projectHooksDir) {
|
|
29682
29705
|
const normalizedHooksDir = normalizeHookCommandPath(projectHooksDir);
|
|
29683
29706
|
const rewrittenHooks = {};
|
|
@@ -29697,6 +29720,36 @@ function resolveHooksForProjectRuntime(hooks, projectHooksDir) {
|
|
|
29697
29720
|
}
|
|
29698
29721
|
return rewrittenHooks;
|
|
29699
29722
|
}
|
|
29723
|
+
function resolveStatusLineForProjectRuntime(statusLineConfig, projectHooksDir) {
|
|
29724
|
+
if (!statusLineConfig?.script) {
|
|
29725
|
+
return void 0;
|
|
29726
|
+
}
|
|
29727
|
+
const normalizedHooksDir = normalizeHookCommandPath(projectHooksDir);
|
|
29728
|
+
const resolvedScriptPath = resolveStatusLineScriptPath(statusLineConfig.script, normalizedHooksDir);
|
|
29729
|
+
return {
|
|
29730
|
+
type: "command",
|
|
29731
|
+
command: buildScriptCommand(statusLineConfig.script, resolvedScriptPath)
|
|
29732
|
+
};
|
|
29733
|
+
}
|
|
29734
|
+
function resolveStatusLineScriptPath(script, normalizedHooksDir) {
|
|
29735
|
+
const pluginRootPattern = /^(?:\$\{CLAUDE_PLUGIN_ROOT\}|\$CLAUDE_PLUGIN_ROOT)\/hooks\/(.+)$/;
|
|
29736
|
+
const pluginRootMatch = script.match(pluginRootPattern);
|
|
29737
|
+
if (pluginRootMatch?.[1]) {
|
|
29738
|
+
return normalizeHookCommandPath(import_path2.default.join(normalizedHooksDir, pluginRootMatch[1]));
|
|
29739
|
+
}
|
|
29740
|
+
return normalizeHookCommandPath(import_path2.default.join(normalizedHooksDir, script));
|
|
29741
|
+
}
|
|
29742
|
+
function buildScriptCommand(scriptName, resolvedPath) {
|
|
29743
|
+
const ext = import_path2.default.extname(scriptName).toLowerCase();
|
|
29744
|
+
if (ext === ".js" || ext === ".cjs" || ext === ".mjs") {
|
|
29745
|
+
return `node "${resolvedPath}"`;
|
|
29746
|
+
}
|
|
29747
|
+
if (ext === ".sh") {
|
|
29748
|
+
return `bash "${resolvedPath}"`;
|
|
29749
|
+
}
|
|
29750
|
+
const pythonBin = process.platform === "win32" ? "python" : "python3";
|
|
29751
|
+
return `${pythonBin} "${resolvedPath}"`;
|
|
29752
|
+
}
|
|
29700
29753
|
function rewritePluginRootCommandToProjectHookPath(command, normalizedHooksDir) {
|
|
29701
29754
|
const pluginRootPatterns = [
|
|
29702
29755
|
/\$\{CLAUDE_PLUGIN_ROOT\}\/hooks\/([^\s"']+)/g,
|
|
@@ -43838,6 +43891,13 @@ async function setRuntimeEnabledPacks(skillsRoot, runtime, packNames) {
|
|
|
43838
43891
|
}
|
|
43839
43892
|
|
|
43840
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
|
+
]);
|
|
43841
43901
|
function sortByName(entries) {
|
|
43842
43902
|
return [...entries].sort((a, b) => a.name.localeCompare(b.name));
|
|
43843
43903
|
}
|
|
@@ -43876,11 +43936,12 @@ async function selectRuntimeSkills(runtime, skillsRoot) {
|
|
|
43876
43936
|
const defaultSkills = await discoverDefaultSkills(skillsRoot);
|
|
43877
43937
|
const enabledPackSkills = await collectEnabledPackSkills(skillsRoot, enabledPacks);
|
|
43878
43938
|
const allSkills = sortByName([...defaultSkills, ...enabledPackSkills]);
|
|
43879
|
-
|
|
43939
|
+
const filteredSkills = runtime === "pi" ? allSkills.filter((s) => !PI_NPM_PROVIDED_SKILLS.has(s.name)) : allSkills;
|
|
43940
|
+
assertNoRuntimeCollisions(runtime, filteredSkills);
|
|
43880
43941
|
return {
|
|
43881
43942
|
runtime,
|
|
43882
43943
|
enabledPacks: [...enabledPacks],
|
|
43883
|
-
skills:
|
|
43944
|
+
skills: filteredSkills
|
|
43884
43945
|
};
|
|
43885
43946
|
}
|
|
43886
43947
|
async function buildRuntimeTempView(runtime, skillsRoot, selectedSkills) {
|
|
@@ -44049,6 +44110,26 @@ function resolveStatuslineScript(worktreePath) {
|
|
|
44049
44110
|
if ((0, import_node_fs.existsSync)(repoStatusline)) return repoStatusline;
|
|
44050
44111
|
return null;
|
|
44051
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
|
+
}
|
|
44052
44133
|
function sessionMetaPath(worktreePath) {
|
|
44053
44134
|
return import_node_path5.default.join(worktreePath, ".xtrm", "session-meta.json");
|
|
44054
44135
|
}
|
|
@@ -44156,6 +44237,12 @@ async function launchWorktreeSession(opts) {
|
|
|
44156
44237
|
}
|
|
44157
44238
|
}
|
|
44158
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
|
+
}
|
|
44159
44246
|
const localSettings = {};
|
|
44160
44247
|
const statuslinePath = resolveStatuslineScript(worktreePath);
|
|
44161
44248
|
if (statuslinePath) {
|
|
@@ -44682,21 +44769,51 @@ var import_child_process3 = require("child_process");
|
|
|
44682
44769
|
var import_fs_extra9 = __toESM(require_lib(), 1);
|
|
44683
44770
|
var import_path4 = __toESM(require("path"), 1);
|
|
44684
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
|
+
}
|
|
44685
44785
|
function resolvePkgRoot() {
|
|
44686
44786
|
const candidates = [
|
|
44687
44787
|
import_path4.default.resolve(__dirname, "../.."),
|
|
44688
44788
|
import_path4.default.resolve(__dirname, "../../..")
|
|
44689
44789
|
];
|
|
44690
|
-
for (const
|
|
44691
|
-
if (
|
|
44790
|
+
for (const candidateRoot of candidates) {
|
|
44791
|
+
if (resolveFirstExistingPath(candidateRoot, MANAGED_PI_EXTENSION_SOURCE_CANDIDATES)) {
|
|
44792
|
+
return candidateRoot;
|
|
44793
|
+
}
|
|
44692
44794
|
}
|
|
44693
44795
|
return candidates[0];
|
|
44694
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
|
+
}
|
|
44695
44806
|
var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path4.default.join((0, import_node_os.homedir)(), ".pi", "agent");
|
|
44696
44807
|
var PI_MCP_ADAPTER_OVERRIDE_DIR = import_path4.default.join(PI_AGENT_DIR, "extensions", "pi-mcp-adapter");
|
|
44697
44808
|
var PI_MCP_ADAPTER_REQUIRED_ENTRY = "commands.js";
|
|
44698
44809
|
var PROJECT_EXTENSIONS_ENTRY = "../.xtrm/extensions";
|
|
44699
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
|
+
]);
|
|
44700
44817
|
var MANAGED_EXTENSIONS = [
|
|
44701
44818
|
{ id: "core", displayName: "@xtrm/pi-core", isLibrary: true, required: true },
|
|
44702
44819
|
{ id: "auto-session-name", displayName: "auto-session-name", required: false },
|
|
@@ -44726,6 +44843,10 @@ var ALWAYS_GLOBAL_INSTALL_PACKAGE_IDS = /* @__PURE__ */ new Set([
|
|
|
44726
44843
|
"npm:pi-gitnexus",
|
|
44727
44844
|
"npm:pi-serena-tools"
|
|
44728
44845
|
]);
|
|
44846
|
+
var PROJECT_REQUIRED_PACKAGE_IDS = [
|
|
44847
|
+
PROJECT_EXTENSION_PACKAGE_ID,
|
|
44848
|
+
...MANAGED_PACKAGES.map((pkg) => pkg.id)
|
|
44849
|
+
];
|
|
44729
44850
|
function getInstalledPiPackages() {
|
|
44730
44851
|
const result = (0, import_child_process3.spawnSync)("pi", ["list"], { encoding: "utf8", stdio: "pipe" });
|
|
44731
44852
|
if (result.status !== 0) return [];
|
|
@@ -44860,6 +44981,20 @@ function renderPiRuntimePlan(plan) {
|
|
|
44860
44981
|
console.log(kleur_default.yellow(" \u26A0 Missing required items.\n"));
|
|
44861
44982
|
}
|
|
44862
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
|
+
}
|
|
44863
44998
|
function mergePiSyncResults(base, incoming) {
|
|
44864
44999
|
return {
|
|
44865
45000
|
extensionsAdded: [...base.extensionsAdded, ...incoming.extensionsAdded],
|
|
@@ -44880,10 +45015,63 @@ async function isPackagePresentInPiAgent(agentDir, piPackageId) {
|
|
|
44880
45015
|
const packageDir = import_path4.default.join(agentDir, "npm", "node_modules", npmPackageName);
|
|
44881
45016
|
return import_fs_extra9.default.pathExists(packageDir);
|
|
44882
45017
|
}
|
|
44883
|
-
|
|
44884
|
-
|
|
44885
|
-
|
|
44886
|
-
|
|
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) {
|
|
44887
45075
|
const installed = [];
|
|
44888
45076
|
const failed = [];
|
|
44889
45077
|
const packagesToEnsure = MANAGED_PACKAGES.filter((pkg) => ALWAYS_GLOBAL_INSTALL_PACKAGE_IDS.has(pkg.id));
|
|
@@ -44895,14 +45083,17 @@ async function ensureAlwaysGlobalPiPackages(dryRun, log, agentDir = PI_AGENT_DIR
|
|
|
44895
45083
|
log?.(`[DRY RUN] pi install ${pkg.id}`);
|
|
44896
45084
|
continue;
|
|
44897
45085
|
}
|
|
44898
|
-
const
|
|
44899
|
-
if (
|
|
45086
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log, installRunner);
|
|
45087
|
+
if (installAttempt.status === 0) {
|
|
44900
45088
|
installed.push(pkg.id);
|
|
44901
|
-
log?.(`${sym.ok} ${pkg.displayName} (global)`);
|
|
45089
|
+
log?.(`${sym.ok} ${pkg.displayName} (global${installAttempt.retriedWithNpmjs ? ", npmjs fallback" : ""})`);
|
|
44902
45090
|
continue;
|
|
44903
45091
|
}
|
|
44904
45092
|
failed.push(pkg.id);
|
|
44905
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
|
+
}
|
|
44906
45097
|
}
|
|
44907
45098
|
return { installed, failed };
|
|
44908
45099
|
}
|
|
@@ -45042,30 +45233,90 @@ async function cleanupLegacyProjectExtensionCopies(projectRoot, dryRun, log) {
|
|
|
45042
45233
|
}
|
|
45043
45234
|
return { removed, failed };
|
|
45044
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
|
+
}
|
|
45045
45289
|
async function updatePiSettings(projectRoot, dryRun, log) {
|
|
45046
|
-
const
|
|
45290
|
+
const piDirPath = import_path4.default.join(projectRoot, ".pi");
|
|
45291
|
+
const piSettingsPath = import_path4.default.join(piDirPath, "settings.json");
|
|
45047
45292
|
if (dryRun) {
|
|
45048
|
-
log?.(kleur_default.dim(`[DRY RUN] would
|
|
45293
|
+
log?.(kleur_default.dim(`[DRY RUN] would ensure .pi/settings.json with ${PROJECT_EXTENSION_PACKAGE_ID}`));
|
|
45049
45294
|
return;
|
|
45050
45295
|
}
|
|
45296
|
+
await import_fs_extra9.default.ensureDir(piDirPath);
|
|
45051
45297
|
let existingSettings = {};
|
|
45052
45298
|
try {
|
|
45053
45299
|
existingSettings = await import_fs_extra9.default.readJson(piSettingsPath);
|
|
45054
45300
|
} catch {
|
|
45055
|
-
|
|
45056
|
-
|
|
45057
|
-
|
|
45058
|
-
);
|
|
45059
|
-
|
|
45060
|
-
|
|
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 = {
|
|
45061
45313
|
...existingSettings,
|
|
45062
|
-
extensions:
|
|
45063
|
-
|
|
45064
|
-
|
|
45065
|
-
|
|
45066
|
-
|
|
45067
|
-
|
|
45068
|
-
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}`));
|
|
45069
45320
|
}
|
|
45070
45321
|
async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
45071
45322
|
const {
|
|
@@ -45135,13 +45386,16 @@ async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
|
45135
45386
|
continue;
|
|
45136
45387
|
}
|
|
45137
45388
|
try {
|
|
45138
|
-
const
|
|
45139
|
-
if (
|
|
45389
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log);
|
|
45390
|
+
if (installAttempt.status === 0) {
|
|
45140
45391
|
result.packagesInstalled.push(pkg.id);
|
|
45141
|
-
log(`${sym.ok} ${pkg.displayName}`);
|
|
45392
|
+
log(`${sym.ok} ${pkg.displayName}${installAttempt.retriedWithNpmjs ? " (npmjs fallback)" : ""}`);
|
|
45142
45393
|
} else {
|
|
45143
45394
|
result.failed.push(pkg.id);
|
|
45144
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
|
+
}
|
|
45145
45399
|
}
|
|
45146
45400
|
} catch (err) {
|
|
45147
45401
|
result.failed.push(pkg.id);
|
|
@@ -45150,114 +45404,20 @@ async function executePiSync(plan, sourceDir, targetDir, opts = {}) {
|
|
|
45150
45404
|
}
|
|
45151
45405
|
return result;
|
|
45152
45406
|
}
|
|
45153
|
-
var EXTENSION_SOURCE_DIR = "ext-src";
|
|
45154
|
-
async function linkExtensionsToGlobal(repoRoot, dryRun = false, log = (msg) => console.log(kleur_default.dim(` ${msg}`))) {
|
|
45155
|
-
const globalExtDir = import_path4.default.join(PI_AGENT_DIR, "extensions");
|
|
45156
|
-
const repoExtDir = import_path4.default.join(repoRoot, ".xtrm", EXTENSION_SOURCE_DIR);
|
|
45157
|
-
const linked = [];
|
|
45158
|
-
const failed = [];
|
|
45159
|
-
if (!await import_fs_extra9.default.pathExists(repoExtDir)) {
|
|
45160
|
-
log("No .xtrm/ext-src/ found \u2014 skipping global link");
|
|
45161
|
-
return { linked, failed };
|
|
45162
|
-
}
|
|
45163
|
-
if (dryRun) {
|
|
45164
|
-
log("[DRY RUN] would create extension symlinks in ~/.pi/agent/extensions/");
|
|
45165
|
-
return { linked, failed };
|
|
45166
|
-
}
|
|
45167
|
-
await import_fs_extra9.default.ensureDir(globalExtDir);
|
|
45168
|
-
const coreNodeModulesDir = import_path4.default.join(globalExtDir, "node_modules", "@xtrm");
|
|
45169
|
-
const coreSymlinkPath = import_path4.default.join(coreNodeModulesDir, "pi-core");
|
|
45170
|
-
const coreRelativeTarget = import_path4.default.join("..", "..", "core");
|
|
45171
|
-
try {
|
|
45172
|
-
await import_fs_extra9.default.ensureDir(coreNodeModulesDir);
|
|
45173
|
-
const existing = await import_fs_extra9.default.lstat(coreSymlinkPath).catch(() => null);
|
|
45174
|
-
if (existing) await import_fs_extra9.default.remove(coreSymlinkPath);
|
|
45175
|
-
await import_fs_extra9.default.symlink(coreRelativeTarget, coreSymlinkPath);
|
|
45176
|
-
log("\u2713 @xtrm/pi-core \u2192 global node_modules");
|
|
45177
|
-
} catch (err) {
|
|
45178
|
-
log(kleur_default.yellow(`\u26A0 @xtrm/pi-core symlink: ${err}`));
|
|
45179
|
-
}
|
|
45180
|
-
const entries = await import_fs_extra9.default.readdir(repoExtDir, { withFileTypes: true });
|
|
45181
|
-
for (const entry of entries) {
|
|
45182
|
-
if (!entry.isDirectory()) continue;
|
|
45183
|
-
if (entry.name === "node_modules") continue;
|
|
45184
|
-
const extPath = import_path4.default.join(repoExtDir, entry.name);
|
|
45185
|
-
const globalLink = import_path4.default.join(globalExtDir, entry.name);
|
|
45186
|
-
try {
|
|
45187
|
-
const existing = await import_fs_extra9.default.lstat(globalLink).catch(() => null);
|
|
45188
|
-
if (existing) {
|
|
45189
|
-
if (existing.isSymbolicLink()) {
|
|
45190
|
-
const currentTarget = await import_fs_extra9.default.readlink(globalLink);
|
|
45191
|
-
const resolvedTarget = import_path4.default.resolve(import_path4.default.dirname(globalLink), currentTarget);
|
|
45192
|
-
if (resolvedTarget === import_path4.default.resolve(extPath)) {
|
|
45193
|
-
continue;
|
|
45194
|
-
}
|
|
45195
|
-
}
|
|
45196
|
-
await import_fs_extra9.default.remove(globalLink);
|
|
45197
|
-
}
|
|
45198
|
-
await import_fs_extra9.default.symlink(extPath, globalLink);
|
|
45199
|
-
linked.push(entry.name);
|
|
45200
|
-
log(`\u2713 ${entry.name} \u2192 .xtrm/${EXTENSION_SOURCE_DIR}/${entry.name}`);
|
|
45201
|
-
} catch (err) {
|
|
45202
|
-
failed.push(entry.name);
|
|
45203
|
-
log(kleur_default.red(`\u2717 ${entry.name}: ${err}`));
|
|
45204
|
-
}
|
|
45205
|
-
}
|
|
45206
|
-
return { linked, failed };
|
|
45207
|
-
}
|
|
45208
|
-
async function ensureNpmPackageExtensionSymlinks(log) {
|
|
45209
|
-
const os9 = require("os");
|
|
45210
|
-
const homeDir = os9.homedir();
|
|
45211
|
-
const extensionsDir = import_path4.default.join(homeDir, ".pi", "agent", "extensions");
|
|
45212
|
-
await import_fs_extra9.default.ensureDir(extensionsDir);
|
|
45213
|
-
const npmPrefix = (0, import_child_process3.spawnSync)("npm", ["prefix", "-g"], { encoding: "utf8" }).stdout.trim();
|
|
45214
|
-
const globalNodeModules = import_path4.default.join(npmPrefix, "lib", "node_modules");
|
|
45215
|
-
const npmPackages = [
|
|
45216
|
-
{ packageName: "pi-gitnexus", symlinkName: "gitnexus" },
|
|
45217
|
-
{ packageName: "pi-serena-tools", symlinkName: "serena" }
|
|
45218
|
-
];
|
|
45219
|
-
for (const { packageName, symlinkName } of npmPackages) {
|
|
45220
|
-
const packagePath = import_path4.default.join(globalNodeModules, packageName);
|
|
45221
|
-
const symlinkPath = import_path4.default.join(extensionsDir, symlinkName);
|
|
45222
|
-
const packageExists = await import_fs_extra9.default.pathExists(packagePath);
|
|
45223
|
-
if (!packageExists) {
|
|
45224
|
-
log?.(kleur_default.yellow(` \u26A0 ${packageName} not found in ${globalNodeModules}, skipping symlink`));
|
|
45225
|
-
continue;
|
|
45226
|
-
}
|
|
45227
|
-
const symlinkExists = await import_fs_extra9.default.lstat(symlinkPath).catch(() => null);
|
|
45228
|
-
if (symlinkExists?.isSymbolicLink()) {
|
|
45229
|
-
const currentTarget = await import_fs_extra9.default.readlink(symlinkPath);
|
|
45230
|
-
const resolvedTarget = import_path4.default.resolve(extensionsDir, currentTarget);
|
|
45231
|
-
if (resolvedTarget === packagePath) {
|
|
45232
|
-
log?.(kleur_default.dim(` \u2713 ${symlinkName} symlink already correct`));
|
|
45233
|
-
continue;
|
|
45234
|
-
}
|
|
45235
|
-
log?.(kleur_default.dim(` Removing stale ${symlinkName} symlink`));
|
|
45236
|
-
await import_fs_extra9.default.remove(symlinkPath);
|
|
45237
|
-
} else if (symlinkExists) {
|
|
45238
|
-
log?.(kleur_default.dim(` Removing stale ${symlinkName} (not a symlink)`));
|
|
45239
|
-
await import_fs_extra9.default.remove(symlinkPath);
|
|
45240
|
-
}
|
|
45241
|
-
const relativeTarget = import_path4.default.relative(extensionsDir, packagePath);
|
|
45242
|
-
await import_fs_extra9.default.symlink(relativeTarget, symlinkPath);
|
|
45243
|
-
log?.(kleur_default.dim(` Created ${symlinkName} symlink \u2192 ${relativeTarget}`));
|
|
45244
|
-
}
|
|
45245
|
-
}
|
|
45246
45407
|
async function runPiRuntimeSync(opts = {}) {
|
|
45247
45408
|
const { dryRun = false, isGlobal = false, projectRoot } = opts;
|
|
45248
45409
|
const pkgRoot = resolvePkgRoot();
|
|
45249
|
-
const sourceDir =
|
|
45410
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(pkgRoot);
|
|
45250
45411
|
const resolvedProjectRoot = projectRoot || process.cwd();
|
|
45251
45412
|
const log = (msg) => console.log(kleur_default.dim(` ${msg}`));
|
|
45252
|
-
const
|
|
45413
|
+
const result = {
|
|
45253
45414
|
extensionsAdded: [],
|
|
45254
45415
|
extensionsUpdated: [],
|
|
45255
45416
|
extensionsRemoved: [],
|
|
45256
45417
|
packagesInstalled: [],
|
|
45257
45418
|
failed: []
|
|
45258
45419
|
};
|
|
45259
|
-
|
|
45260
|
-
if (!await import_fs_extra9.default.pathExists(sourceDir)) {
|
|
45420
|
+
if (!sourceDir || !await import_fs_extra9.default.pathExists(sourceDir)) {
|
|
45261
45421
|
console.log(kleur_default.dim("\n Managed extensions: skipped (not bundled in npm package)\n"));
|
|
45262
45422
|
return result;
|
|
45263
45423
|
}
|
|
@@ -45265,6 +45425,7 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45265
45425
|
if (preflight.staleOverride.remediated) {
|
|
45266
45426
|
result.extensionsRemoved.push("pi-mcp-adapter");
|
|
45267
45427
|
}
|
|
45428
|
+
await cleanupConflictingPiPackageSettings(resolvedProjectRoot, dryRun, log);
|
|
45268
45429
|
if (isGlobal) {
|
|
45269
45430
|
const targetDir = import_path4.default.join(PI_AGENT_DIR, "extensions");
|
|
45270
45431
|
const plan = await inventoryPiRuntime(sourceDir, targetDir);
|
|
@@ -45277,32 +45438,47 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45277
45438
|
});
|
|
45278
45439
|
return mergePiSyncResults(result, synced);
|
|
45279
45440
|
}
|
|
45280
|
-
const linkResult = await linkExtensionsToGlobal(resolvedProjectRoot, dryRun, log);
|
|
45281
|
-
result.extensionsAdded.push(...linkResult.linked);
|
|
45282
|
-
result.failed.push(...linkResult.failed);
|
|
45283
|
-
await ensureNpmPackageExtensionSymlinks(log);
|
|
45284
45441
|
const installedPkgIds = getInstalledPiPackages();
|
|
45285
|
-
const packageStatuses =
|
|
45286
|
-
const missingPackages =
|
|
45287
|
-
for (const pkg of MANAGED_PACKAGES) {
|
|
45288
|
-
const isInstalled = installedPkgIds.includes(pkg.id);
|
|
45289
|
-
const status = { pkg, installed: isInstalled };
|
|
45290
|
-
packageStatuses.push(status);
|
|
45291
|
-
if (!isInstalled) missingPackages.push(status);
|
|
45292
|
-
}
|
|
45442
|
+
const packageStatuses = getProjectRequiredPackageStatuses(installedPkgIds);
|
|
45443
|
+
const missingPackages = packageStatuses.filter((status) => !status.installed);
|
|
45293
45444
|
console.log(kleur_default.bold("\n Pi Runtime"));
|
|
45294
45445
|
console.log(kleur_default.dim(" " + "-".repeat(50)));
|
|
45295
|
-
|
|
45296
|
-
|
|
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;
|
|
45297
45451
|
console.log(kleur_default.dim(` Packages: ${pkgOk}/${packageStatuses.length} installed`));
|
|
45298
45452
|
if (missingPackages.length > 0) {
|
|
45299
|
-
const names = missingPackages.map((
|
|
45453
|
+
const names = missingPackages.map((status) => status.pkg.displayName).join(", ");
|
|
45300
45454
|
console.log(kleur_default.yellow(` Missing: ${names}`));
|
|
45301
45455
|
}
|
|
45302
45456
|
console.log(kleur_default.dim(" " + "-".repeat(50)));
|
|
45303
45457
|
const legacyCleanup = await cleanupLegacyProjectExtensionCopies(resolvedProjectRoot, dryRun, log);
|
|
45304
45458
|
result.extensionsRemoved.push(...legacyCleanup.removed);
|
|
45305
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
|
+
}
|
|
45306
45482
|
for (const status of missingPackages) {
|
|
45307
45483
|
const { pkg } = status;
|
|
45308
45484
|
if (dryRun) {
|
|
@@ -45310,13 +45486,16 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45310
45486
|
continue;
|
|
45311
45487
|
}
|
|
45312
45488
|
try {
|
|
45313
|
-
const
|
|
45314
|
-
if (
|
|
45489
|
+
const installAttempt = installPiPackageWithFallback(pkg.id, log);
|
|
45490
|
+
if (installAttempt.status === 0) {
|
|
45315
45491
|
result.packagesInstalled.push(pkg.id);
|
|
45316
|
-
log(`${sym.ok} ${pkg.displayName}`);
|
|
45317
|
-
|
|
45318
|
-
|
|
45319
|
-
|
|
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}`));
|
|
45320
45499
|
}
|
|
45321
45500
|
} catch (err) {
|
|
45322
45501
|
result.failed.push(pkg.id);
|
|
@@ -45338,12 +45517,8 @@ async function runPiRuntimeSync(opts = {}) {
|
|
|
45338
45517
|
}
|
|
45339
45518
|
}
|
|
45340
45519
|
await updatePiSettings(resolvedProjectRoot, dryRun, log);
|
|
45341
|
-
const requiredFailed = missingPackages.filter(
|
|
45342
|
-
|
|
45343
|
-
);
|
|
45344
|
-
if (missingPackages.length === 0 || result.failed.length === 0) {
|
|
45345
|
-
console.log(t.success(" \u2713 All required items present.\n"));
|
|
45346
|
-
} 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) {
|
|
45347
45522
|
console.log(t.success(" \u2713 All required items present.\n"));
|
|
45348
45523
|
} else {
|
|
45349
45524
|
console.log(kleur_default.yellow(" \u26A0 Missing required items.\n"));
|
|
@@ -45580,21 +45755,21 @@ function hasSettingsEntry(entries, expectedEntry) {
|
|
|
45580
45755
|
});
|
|
45581
45756
|
}
|
|
45582
45757
|
async function getPiProjectPointer(projectRoot) {
|
|
45583
|
-
const projectExtensionsDir = import_path7.default.join(projectRoot, ".xtrm", "extensions");
|
|
45584
45758
|
const settingsPath = import_path7.default.join(projectRoot, ".pi", "settings.json");
|
|
45585
|
-
const hasProjectExtensions = await import_fs_extra11.default.pathExists(projectExtensionsDir);
|
|
45586
45759
|
const hasSettingsFile = await import_fs_extra11.default.pathExists(settingsPath);
|
|
45587
45760
|
if (!hasSettingsFile) {
|
|
45588
|
-
return {
|
|
45761
|
+
return { hasProjectSettings: false, hasProjectExtensionPackage: false, pointsToXtrmExtensions: false };
|
|
45589
45762
|
}
|
|
45590
45763
|
try {
|
|
45591
45764
|
const settings = await import_fs_extra11.default.readJson(settingsPath);
|
|
45765
|
+
const packageEntries = Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
|
|
45592
45766
|
return {
|
|
45593
|
-
|
|
45767
|
+
hasProjectSettings: true,
|
|
45768
|
+
hasProjectExtensionPackage: packageEntries.includes("npm:@jaggerxtrm/pi-extensions"),
|
|
45594
45769
|
pointsToXtrmExtensions: hasSettingsEntry(settings.extensions, "../.xtrm/extensions")
|
|
45595
45770
|
};
|
|
45596
45771
|
} catch {
|
|
45597
|
-
return {
|
|
45772
|
+
return { hasProjectSettings: true, hasProjectExtensionPackage: false, pointsToXtrmExtensions: false };
|
|
45598
45773
|
}
|
|
45599
45774
|
}
|
|
45600
45775
|
function createPiCommand() {
|
|
@@ -45618,31 +45793,29 @@ function createPiCommand() {
|
|
|
45618
45793
|
const projectRoot = resolveProjectRoot();
|
|
45619
45794
|
const pointer = await getPiProjectPointer(projectRoot);
|
|
45620
45795
|
const bundleRoot = await findRepoRoot();
|
|
45621
|
-
const sourceDir =
|
|
45796
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(bundleRoot);
|
|
45622
45797
|
const globalTargetDir = import_path7.default.join(PI_AGENT_DIR4, "extensions");
|
|
45623
|
-
if (!await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45798
|
+
if (!sourceDir || !await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45624
45799
|
console.log(kleur_default.dim(" \u25CB managed extensions not bundled in this install\n"));
|
|
45625
45800
|
return;
|
|
45626
45801
|
}
|
|
45627
45802
|
const plan = await inventoryPiRuntime(sourceDir, globalTargetDir);
|
|
45628
45803
|
const pkgOk = plan.packages.filter((s) => s.installed).length;
|
|
45629
|
-
|
|
45804
|
+
const projectScoped = pointer.hasProjectExtensionPackage || pointer.pointsToXtrmExtensions;
|
|
45805
|
+
if (projectScoped) {
|
|
45630
45806
|
console.log(kleur_default.dim(" Scope: project"));
|
|
45631
|
-
console.log(kleur_default.dim(
|
|
45807
|
+
console.log(kleur_default.dim(` Extensions: package mode (npm:@jaggerxtrm/pi-extensions${pointer.hasProjectExtensionPackage ? "" : " missing"})`));
|
|
45632
45808
|
} else {
|
|
45633
45809
|
console.log(kleur_default.dim(" Scope: global"));
|
|
45634
45810
|
const extOk = plan.extensions.filter((s) => s.installed && !s.stale).length;
|
|
45635
45811
|
console.log(kleur_default.dim(` Extensions: ${extOk}/${plan.extensions.length} up-to-date`));
|
|
45636
45812
|
}
|
|
45637
45813
|
console.log(kleur_default.dim(` Packages: ${pkgOk}/${plan.packages.length} installed`));
|
|
45638
|
-
if (pointer.hasProjectExtensions && !pointer.pointsToXtrmExtensions) {
|
|
45639
|
-
console.log(kleur_default.yellow(" Settings: .pi/settings.json is not pointing to ../.xtrm/extensions"));
|
|
45640
|
-
}
|
|
45641
45814
|
if (plan.missingPackages.length > 0) {
|
|
45642
45815
|
const names = plan.missingPackages.map((s) => s.pkg.displayName).join(", ");
|
|
45643
45816
|
console.log(kleur_default.yellow(` Packages: ${names}`));
|
|
45644
45817
|
}
|
|
45645
|
-
if (!
|
|
45818
|
+
if (!projectScoped) {
|
|
45646
45819
|
if (plan.missingExtensions.length > 0) {
|
|
45647
45820
|
const names = plan.missingExtensions.map((s) => s.ext.displayName).join(", ");
|
|
45648
45821
|
console.log(kleur_default.yellow(` Missing: ${names}`));
|
|
@@ -45655,13 +45828,16 @@ function createPiCommand() {
|
|
|
45655
45828
|
console.log(kleur_default.red(` Orphaned: ${plan.orphanedExtensions.join(", ")}`));
|
|
45656
45829
|
}
|
|
45657
45830
|
}
|
|
45658
|
-
const
|
|
45659
|
-
const hasGlobalDrift = !
|
|
45831
|
+
const hasProjectSettingsDrift = !pointer.hasProjectSettings || !pointer.hasProjectExtensionPackage;
|
|
45832
|
+
const hasGlobalDrift = !projectScoped && !plan.allPresent;
|
|
45660
45833
|
const hasPackageDrift = plan.missingPackages.length > 0;
|
|
45661
|
-
if (
|
|
45834
|
+
if (!hasProjectSettingsDrift && !hasGlobalDrift && !hasPackageDrift) {
|
|
45662
45835
|
console.log(t.success("\n \u2713 Pi runtime configuration looks healthy\n"));
|
|
45663
45836
|
return;
|
|
45664
45837
|
}
|
|
45838
|
+
if (hasProjectSettingsDrift) {
|
|
45839
|
+
console.log(kleur_default.yellow(" Settings: .pi/settings.json missing managed npm:@jaggerxtrm/pi-extensions entry"));
|
|
45840
|
+
}
|
|
45665
45841
|
console.log(kleur_default.dim("\n \u2192 run: xt pi reload\n"));
|
|
45666
45842
|
});
|
|
45667
45843
|
cmd.command("doctor").description("Diagnostic checks: pi installed, extensions deployed, packages present, orphaned extensions").action(async () => {
|
|
@@ -45692,7 +45868,8 @@ function createPiCommand() {
|
|
|
45692
45868
|
const projectRoot = resolveProjectRoot();
|
|
45693
45869
|
const pointer = await getPiProjectPointer(projectRoot);
|
|
45694
45870
|
const bundleRoot = await findRepoRoot();
|
|
45695
|
-
const sourceDir =
|
|
45871
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir(bundleRoot);
|
|
45872
|
+
const coreSourceDir = resolveManagedPiCoreSourceDir(bundleRoot);
|
|
45696
45873
|
const globalTargetDir = import_path7.default.join(PI_AGENT_DIR4, "extensions");
|
|
45697
45874
|
try {
|
|
45698
45875
|
const staleOverride = await remediateStalePiMcpAdapterOverride(false);
|
|
@@ -45709,7 +45886,7 @@ function createPiCommand() {
|
|
|
45709
45886
|
allOk = false;
|
|
45710
45887
|
}
|
|
45711
45888
|
try {
|
|
45712
|
-
const coreStatus = await ensureCorePackageSymlink(
|
|
45889
|
+
const coreStatus = coreSourceDir ? await ensureCorePackageSymlink(coreSourceDir, projectRoot, false) : "missing-source";
|
|
45713
45890
|
if (coreStatus === "repaired" || coreStatus === "created") {
|
|
45714
45891
|
console.log(t.success(" \u2713 repaired .xtrm/extensions/node_modules/@xtrm/pi-core symlink"));
|
|
45715
45892
|
} else if (coreStatus === "ok") {
|
|
@@ -45721,15 +45898,21 @@ function createPiCommand() {
|
|
|
45721
45898
|
console.log(kleur_default.yellow(` \u26A0 failed to ensure @xtrm/pi-core symlink: ${error48}`));
|
|
45722
45899
|
allOk = false;
|
|
45723
45900
|
}
|
|
45724
|
-
if (!await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45901
|
+
if (!sourceDir || !await import_fs_extra11.default.pathExists(sourceDir)) {
|
|
45725
45902
|
console.log(kleur_default.dim(" \u25CB managed extensions not bundled in this install"));
|
|
45726
45903
|
} else {
|
|
45727
45904
|
const plan = await inventoryPiRuntime(sourceDir, globalTargetDir);
|
|
45728
|
-
|
|
45729
|
-
|
|
45730
|
-
|
|
45731
|
-
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"));
|
|
45732
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
|
+
}
|
|
45733
45916
|
} else if (plan.missingExtensions.length === 0 && plan.staleExtensions.length === 0 && plan.orphanedExtensions.length === 0) {
|
|
45734
45917
|
console.log(t.success(` \u2713 global extensions deployed (${plan.extensions.length})`));
|
|
45735
45918
|
} else {
|
|
@@ -45867,8 +46050,17 @@ async function scaffoldSkillsDefaultFromPackage(params) {
|
|
|
45867
46050
|
const { packageRoot, userXtrmDir, dryRun } = params;
|
|
45868
46051
|
const sourceDir = import_path8.default.join(packageRoot, ".xtrm", "skills", "default");
|
|
45869
46052
|
const targetDir = import_path8.default.join(userXtrmDir, "skills", "default");
|
|
45870
|
-
|
|
45871
|
-
|
|
46053
|
+
const stat = await import_fs_extra13.default.lstat(targetDir).catch(() => null);
|
|
46054
|
+
if (stat) {
|
|
46055
|
+
if (stat.isSymbolicLink()) {
|
|
46056
|
+
const isValid = await import_fs_extra13.default.pathExists(targetDir);
|
|
46057
|
+
if (isValid) {
|
|
46058
|
+
return "noop";
|
|
46059
|
+
}
|
|
46060
|
+
await import_fs_extra13.default.remove(targetDir);
|
|
46061
|
+
} else {
|
|
46062
|
+
return "noop";
|
|
46063
|
+
}
|
|
45872
46064
|
}
|
|
45873
46065
|
if (dryRun) {
|
|
45874
46066
|
return "noop";
|
|
@@ -45935,12 +46127,16 @@ async function installFromRegistry(params) {
|
|
|
45935
46127
|
installed: 0,
|
|
45936
46128
|
upToDate: drift.upToDate.length,
|
|
45937
46129
|
driftedSkipped: drift.drifted.length,
|
|
45938
|
-
forced: 0
|
|
46130
|
+
forced: 0,
|
|
46131
|
+
expectedInstalls: 0,
|
|
46132
|
+
missingSourceSkipped: 0
|
|
45939
46133
|
};
|
|
45940
46134
|
}
|
|
45941
46135
|
}
|
|
45942
46136
|
let installed = 0;
|
|
45943
46137
|
let forced = 0;
|
|
46138
|
+
let expectedInstalls = 0;
|
|
46139
|
+
let missingSourceSkipped = 0;
|
|
45944
46140
|
for (const asset of Object.values(registry2.assets)) {
|
|
45945
46141
|
for (const [filePath] of Object.entries(asset.files)) {
|
|
45946
46142
|
const relativePath = toUserRelativePath(asset.source_dir, filePath);
|
|
@@ -45963,6 +46159,13 @@ async function installFromRegistry(params) {
|
|
|
45963
46159
|
if (isDrifted && force) {
|
|
45964
46160
|
forced += 1;
|
|
45965
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
|
+
}
|
|
45966
46169
|
if (dryRun) {
|
|
45967
46170
|
const action = isDrifted ? "overwrite" : "install";
|
|
45968
46171
|
console.log(kleur_default.dim(` [DRY RUN] would ${action} ${relativePath}`));
|
|
@@ -45978,7 +46181,9 @@ async function installFromRegistry(params) {
|
|
|
45978
46181
|
installed,
|
|
45979
46182
|
upToDate: upToDateSet.size,
|
|
45980
46183
|
driftedSkipped: force ? 0 : driftedSet.size,
|
|
45981
|
-
forced
|
|
46184
|
+
forced,
|
|
46185
|
+
expectedInstalls,
|
|
46186
|
+
missingSourceSkipped
|
|
45982
46187
|
};
|
|
45983
46188
|
}
|
|
45984
46189
|
|
|
@@ -46496,9 +46701,8 @@ function verifyClaudeRuntime(projectRoot) {
|
|
|
46496
46701
|
return fallbackResult;
|
|
46497
46702
|
}
|
|
46498
46703
|
async function verifyPiRuntime(projectRoot) {
|
|
46499
|
-
const
|
|
46500
|
-
|
|
46501
|
-
if (!await import_fs_extra16.default.pathExists(sourceDir)) {
|
|
46704
|
+
const sourceDir = resolveManagedPiExtensionsSourceDir();
|
|
46705
|
+
if (!sourceDir || !await import_fs_extra16.default.pathExists(sourceDir)) {
|
|
46502
46706
|
return {
|
|
46503
46707
|
extensions: [],
|
|
46504
46708
|
packages: [],
|
|
@@ -46524,16 +46728,6 @@ ${gnStatus.stderr ?? ""}`.toLowerCase();
|
|
|
46524
46728
|
const instructionHeaders = agentsMd || claudeMd;
|
|
46525
46729
|
return { beadsInitialized, gitnexusIndexed, instructionHeaders };
|
|
46526
46730
|
}
|
|
46527
|
-
function resolvePkgRoot2() {
|
|
46528
|
-
const candidates = [
|
|
46529
|
-
import_path10.default.resolve(__dirname, "../.."),
|
|
46530
|
-
import_path10.default.resolve(__dirname, "../../..")
|
|
46531
|
-
];
|
|
46532
|
-
for (const c of candidates) {
|
|
46533
|
-
if (import_fs_extra16.default.existsSync(import_path10.default.join(c, ".xtrm", "extensions"))) return c;
|
|
46534
|
-
}
|
|
46535
|
-
return candidates[0];
|
|
46536
|
-
}
|
|
46537
46731
|
async function runInitVerification(projectRoot) {
|
|
46538
46732
|
const machinePlan = verifyMachineBootstrap();
|
|
46539
46733
|
const claudeResult = verifyClaudeRuntime(projectRoot);
|
|
@@ -48555,7 +48749,7 @@ async function runProjectInit(opts = {}) {
|
|
|
48555
48749
|
const userXtrmDir = ctx.targets[0];
|
|
48556
48750
|
const registryPath = import_path15.default.join(packageRoot, ".xtrm", "registry.json");
|
|
48557
48751
|
const registry2 = await import_fs_extra21.default.readJson(registryPath);
|
|
48558
|
-
await installFromRegistry({
|
|
48752
|
+
const registryInstallStats = await installFromRegistry({
|
|
48559
48753
|
packageRoot,
|
|
48560
48754
|
registry: registry2,
|
|
48561
48755
|
userXtrmDir,
|
|
@@ -48563,6 +48757,10 @@ async function runProjectInit(opts = {}) {
|
|
|
48563
48757
|
force: false,
|
|
48564
48758
|
yes: true
|
|
48565
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
|
+
}
|
|
48566
48764
|
await scaffoldSkillsDefaultFromPackage({ packageRoot, userXtrmDir, dryRun: false });
|
|
48567
48765
|
const mcpSync = await syncProjectMcpConfig(projectRoot, { preserveExistingFile: true });
|
|
48568
48766
|
if (mcpSync.wroteFile) {
|