xtrm-tools 0.5.26 → 0.5.28

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.
@@ -27021,19 +27021,19 @@ var require_esprima = __commonJS({
27021
27021
  }
27022
27022
  return error49;
27023
27023
  };
27024
- ErrorHandler2.prototype.createError = function(index, line, col2, description) {
27024
+ ErrorHandler2.prototype.createError = function(index, line, col, description) {
27025
27025
  var msg = "Line " + line + ": " + description;
27026
- var error49 = this.constructError(msg, col2);
27026
+ var error49 = this.constructError(msg, col);
27027
27027
  error49.index = index;
27028
27028
  error49.lineNumber = line;
27029
27029
  error49.description = description;
27030
27030
  return error49;
27031
27031
  };
27032
- ErrorHandler2.prototype.throwError = function(index, line, col2, description) {
27033
- throw this.createError(index, line, col2, description);
27032
+ ErrorHandler2.prototype.throwError = function(index, line, col, description) {
27033
+ throw this.createError(index, line, col, description);
27034
27034
  };
27035
- ErrorHandler2.prototype.tolerateError = function(index, line, col2, description) {
27036
- var error49 = this.createError(index, line, col2, description);
27035
+ ErrorHandler2.prototype.tolerateError = function(index, line, col, description) {
27036
+ var error49 = this.createError(index, line, col, description);
27037
27037
  if (this.tolerant) {
27038
27038
  this.recordError(error49);
27039
27039
  } else {
@@ -32847,19 +32847,19 @@ var require_layout_manager = __commonJS({
32847
32847
  var Cell = require_cell();
32848
32848
  var { ColSpanCell, RowSpanCell } = Cell;
32849
32849
  (function() {
32850
- function next(alloc, col2) {
32851
- if (alloc[col2] > 0) {
32852
- return next(alloc, col2 + 1);
32850
+ function next(alloc, col) {
32851
+ if (alloc[col] > 0) {
32852
+ return next(alloc, col + 1);
32853
32853
  }
32854
- return col2;
32854
+ return col;
32855
32855
  }
32856
32856
  function layoutTable(table) {
32857
32857
  let alloc = {};
32858
32858
  table.forEach(function(row, rowIndex) {
32859
- let col2 = 0;
32859
+ let col = 0;
32860
32860
  row.forEach(function(cell) {
32861
32861
  cell.y = rowIndex;
32862
- cell.x = rowIndex ? next(alloc, col2) : col2;
32862
+ cell.x = rowIndex ? next(alloc, col) : col;
32863
32863
  const rowSpan = cell.rowSpan || 1;
32864
32864
  const colSpan = cell.colSpan || 1;
32865
32865
  if (rowSpan > 1) {
@@ -32867,7 +32867,7 @@ var require_layout_manager = __commonJS({
32867
32867
  alloc[cell.x + cs] = rowSpan;
32868
32868
  }
32869
32869
  }
32870
- col2 = cell.x + colSpan;
32870
+ col = cell.x + colSpan;
32871
32871
  });
32872
32872
  Object.keys(alloc).forEach((idx) => {
32873
32873
  alloc[idx]--;
@@ -33039,29 +33039,29 @@ var require_layout_manager = __commonJS({
33039
33039
  for (let k = spanners.length - 1; k >= 0; k--) {
33040
33040
  let cell = spanners[k];
33041
33041
  let span = cell[colSpan];
33042
- let col2 = cell[x];
33043
- let existingWidth = result[col2];
33044
- let editableCols = typeof vals[col2] === "number" ? 0 : 1;
33042
+ let col = cell[x];
33043
+ let existingWidth = result[col];
33044
+ let editableCols = typeof vals[col] === "number" ? 0 : 1;
33045
33045
  if (typeof existingWidth === "number") {
33046
33046
  for (let i = 1; i < span; i++) {
33047
- existingWidth += 1 + result[col2 + i];
33048
- if (typeof vals[col2 + i] !== "number") {
33047
+ existingWidth += 1 + result[col + i];
33048
+ if (typeof vals[col + i] !== "number") {
33049
33049
  editableCols++;
33050
33050
  }
33051
33051
  }
33052
33052
  } else {
33053
33053
  existingWidth = desiredWidth === "desiredWidth" ? cell.desiredWidth - 1 : 1;
33054
- if (!auto[col2] || auto[col2] < existingWidth) {
33055
- auto[col2] = existingWidth;
33054
+ if (!auto[col] || auto[col] < existingWidth) {
33055
+ auto[col] = existingWidth;
33056
33056
  }
33057
33057
  }
33058
33058
  if (cell[desiredWidth] > existingWidth) {
33059
33059
  let i = 0;
33060
33060
  while (editableCols > 0 && cell[desiredWidth] > existingWidth) {
33061
- if (typeof vals[col2 + i] !== "number") {
33061
+ if (typeof vals[col + i] !== "number") {
33062
33062
  let dif = Math.round((cell[desiredWidth] - existingWidth) / editableCols);
33063
33063
  existingWidth += dif;
33064
- result[col2 + i] += dif;
33064
+ result[col + i] += dif;
33065
33065
  editableCols--;
33066
33066
  }
33067
33067
  i++;
@@ -35746,7 +35746,7 @@ var Listr = class {
35746
35746
  };
35747
35747
 
35748
35748
  // src/commands/install.ts
35749
- var import_fs_extra11 = __toESM(require_lib2(), 1);
35749
+ var import_fs_extra12 = __toESM(require_lib2(), 1);
35750
35750
  var import_os5 = __toESM(require("os"), 1);
35751
35751
 
35752
35752
  // src/core/context.ts
@@ -40801,36 +40801,49 @@ var sym = {
40801
40801
  };
40802
40802
 
40803
40803
  // src/commands/install.ts
40804
- var import_path11 = __toESM(require("path"), 1);
40804
+ var import_path12 = __toESM(require("path"), 1);
40805
40805
 
40806
40806
  // src/commands/pi-install.ts
40807
- var import_fs_extra10 = __toESM(require_lib2(), 1);
40808
- var import_path10 = __toESM(require("path"), 1);
40807
+ var import_fs_extra11 = __toESM(require_lib2(), 1);
40808
+ var import_path11 = __toESM(require("path"), 1);
40809
40809
  var import_node_child_process = require("child_process");
40810
40810
  var import_node_os4 = require("os");
40811
- var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path10.default.join((0, import_node_os4.homedir)(), ".pi", "agent");
40811
+
40812
+ // src/utils/pi-extensions.ts
40813
+ var import_fs_extra10 = __toESM(require_lib2(), 1);
40814
+ var import_path10 = __toESM(require("path"), 1);
40815
+ async function syncManagedPiExtensions({
40816
+ sourceDir,
40817
+ targetDir,
40818
+ dryRun = false,
40819
+ log
40820
+ }) {
40821
+ if (!await import_fs_extra10.default.pathExists(sourceDir)) return 0;
40822
+ if (!dryRun) {
40823
+ await import_fs_extra10.default.ensureDir(import_path10.default.dirname(targetDir));
40824
+ await import_fs_extra10.default.copy(sourceDir, targetDir, { overwrite: true });
40825
+ }
40826
+ const entries = await import_fs_extra10.default.readdir(sourceDir, { withFileTypes: true });
40827
+ const managedPackages = entries.filter((entry) => entry.isDirectory()).length;
40828
+ if (log) {
40829
+ if (dryRun) {
40830
+ log(` [DRY RUN] sync extensions ${sourceDir} -> ${targetDir}`);
40831
+ }
40832
+ log(` Pi will auto-discover ${managedPackages} extension package(s) from ${targetDir}`);
40833
+ }
40834
+ return managedPackages;
40835
+ }
40836
+
40837
+ // src/commands/pi-install.ts
40838
+ var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path11.default.join((0, import_node_os4.homedir)(), ".pi", "agent");
40812
40839
  function isPiInstalled() {
40813
40840
  const r = (0, import_node_child_process.spawnSync)("pi", ["--version"], { encoding: "utf8", stdio: "pipe" });
40814
40841
  return r.status === 0;
40815
40842
  }
40816
- async function listExtensionDirs(baseDir) {
40817
- if (!await import_fs_extra10.default.pathExists(baseDir)) return [];
40818
- const entries = await import_fs_extra10.default.readdir(baseDir, { withFileTypes: true });
40819
- const extDirs = [];
40820
- for (const entry of entries) {
40821
- if (!entry.isDirectory()) continue;
40822
- const extPath = import_path10.default.join(baseDir, entry.name);
40823
- const pkgPath = import_path10.default.join(extPath, "package.json");
40824
- if (await import_fs_extra10.default.pathExists(pkgPath)) {
40825
- extDirs.push(extPath);
40826
- }
40827
- }
40828
- return extDirs;
40829
- }
40830
40843
  async function runPiInstall(dryRun = false) {
40831
40844
  const repoRoot = await findRepoRoot();
40832
- const piConfigDir = import_path10.default.join(repoRoot, "config", "pi");
40833
- const schemaPath = import_path10.default.join(piConfigDir, "install-schema.json");
40845
+ const piConfigDir = import_path11.default.join(repoRoot, "config", "pi");
40846
+ const schemaPath = import_path11.default.join(piConfigDir, "install-schema.json");
40834
40847
  console.log(t.bold("\n \u2699 Pi extensions + packages"));
40835
40848
  if (!isPiInstalled()) {
40836
40849
  console.log(kleur_default.yellow(" pi not found \u2014 installing oh-pi globally..."));
@@ -40848,37 +40861,22 @@ async function runPiInstall(dryRun = false) {
40848
40861
  const v = (0, import_node_child_process.spawnSync)("pi", ["--version"], { encoding: "utf8" });
40849
40862
  console.log(t.success(` \u2713 pi ${v.stdout.trim()} already installed`));
40850
40863
  }
40851
- const extensionsSrc = import_path10.default.join(piConfigDir, "extensions");
40852
- const extensionsDst = import_path10.default.join(PI_AGENT_DIR, "extensions");
40853
- if (await import_fs_extra10.default.pathExists(extensionsSrc)) {
40854
- if (!dryRun) {
40855
- await import_fs_extra10.default.ensureDir(PI_AGENT_DIR);
40856
- await import_fs_extra10.default.copy(extensionsSrc, extensionsDst, { overwrite: true });
40857
- }
40858
- console.log(t.success(` ${sym.ok} extensions synced`));
40859
- const extDirs = await listExtensionDirs(extensionsDst);
40860
- if (extDirs.length > 0) {
40861
- console.log(kleur_default.dim(` Registering ${extDirs.length} extensions...`));
40862
- for (const extPath of extDirs) {
40863
- const extName = import_path10.default.basename(extPath);
40864
- if (dryRun) {
40865
- console.log(kleur_default.cyan(` [DRY RUN] pi install -l ~/.pi/agent/extensions/${extName}`));
40866
- continue;
40867
- }
40868
- const r = (0, import_node_child_process.spawnSync)("pi", ["install", "-l", extPath], { stdio: "pipe", encoding: "utf8" });
40869
- if (r.status === 0) {
40870
- console.log(t.success(` ${sym.ok} ${extName} registered`));
40871
- } else {
40872
- console.log(kleur_default.yellow(` \u26A0 ${extName} \u2014 registration failed`));
40873
- }
40874
- }
40875
- }
40864
+ const extensionsSrc = import_path11.default.join(piConfigDir, "extensions");
40865
+ const extensionsDst = import_path11.default.join(PI_AGENT_DIR, "extensions");
40866
+ const managedPackages = await syncManagedPiExtensions({
40867
+ sourceDir: extensionsSrc,
40868
+ targetDir: extensionsDst,
40869
+ dryRun,
40870
+ log: (message) => console.log(kleur_default.dim(message))
40871
+ });
40872
+ if (managedPackages > 0) {
40873
+ console.log(t.success(` ${sym.ok} extensions synced (${managedPackages} packages)`));
40876
40874
  }
40877
- if (!await import_fs_extra10.default.pathExists(schemaPath)) {
40875
+ if (!await import_fs_extra11.default.pathExists(schemaPath)) {
40878
40876
  console.log(kleur_default.dim(" No install-schema.json found, skipping packages"));
40879
40877
  return;
40880
40878
  }
40881
- const schema = await import_fs_extra10.default.readJson(schemaPath);
40879
+ const schema = await import_fs_extra11.default.readJson(schemaPath);
40882
40880
  for (const pkg of schema.packages) {
40883
40881
  if (dryRun) {
40884
40882
  console.log(kleur_default.cyan(` [DRY RUN] pi install ${pkg}`));
@@ -40944,7 +40942,7 @@ function formatTargetLabel(target) {
40944
40942
  const normalized = target.replace(/\\/g, "/").toLowerCase();
40945
40943
  if (normalized.endsWith("/.agents/skills") || normalized.includes("/.agents/skills/")) return "~/.agents/skills";
40946
40944
  if (normalized.endsWith("/.claude") || normalized.includes("/.claude/")) return "~/.claude";
40947
- return import_path11.default.basename(target);
40945
+ return import_path12.default.basename(target);
40948
40946
  }
40949
40947
  function isBeadsInstalled() {
40950
40948
  try {
@@ -40974,15 +40972,15 @@ async function needsSettingsSync(repoRoot, target) {
40974
40972
  const normalizedTarget = target.replace(/\\/g, "/").toLowerCase();
40975
40973
  if (normalizedTarget.includes(".agents/skills")) return false;
40976
40974
  if (detectAgent(target) === "claude") return false;
40977
- const hooksTemplatePath = import_path11.default.join(repoRoot, "config", "hooks.json");
40978
- if (!await import_fs_extra11.default.pathExists(hooksTemplatePath)) return false;
40979
- const requiredEvents = Object.keys((await import_fs_extra11.default.readJson(hooksTemplatePath)).hooks ?? {});
40975
+ const hooksTemplatePath = import_path12.default.join(repoRoot, "config", "hooks.json");
40976
+ if (!await import_fs_extra12.default.pathExists(hooksTemplatePath)) return false;
40977
+ const requiredEvents = Object.keys((await import_fs_extra12.default.readJson(hooksTemplatePath)).hooks ?? {});
40980
40978
  if (requiredEvents.length === 0) return false;
40981
- const targetSettingsPath = import_path11.default.join(target, "settings.json");
40982
- if (!await import_fs_extra11.default.pathExists(targetSettingsPath)) return true;
40979
+ const targetSettingsPath = import_path12.default.join(target, "settings.json");
40980
+ if (!await import_fs_extra12.default.pathExists(targetSettingsPath)) return true;
40983
40981
  let settings = {};
40984
40982
  try {
40985
- settings = await import_fs_extra11.default.readJson(targetSettingsPath);
40983
+ settings = await import_fs_extra12.default.readJson(targetSettingsPath);
40986
40984
  } catch {
40987
40985
  return true;
40988
40986
  }
@@ -41027,46 +41025,46 @@ async function installOfficialClaudePlugins(dryRun) {
41027
41025
  }
41028
41026
  async function cleanStalePrePluginFiles(repoRoot, dryRun) {
41029
41027
  const home = import_os5.default.homedir();
41030
- const staleHooksDir = import_path11.default.join(home, ".claude", "hooks");
41031
- const staleSkillsDir = import_path11.default.join(home, ".claude", "skills");
41032
- const settingsPath = import_path11.default.join(home, ".claude", "settings.json");
41028
+ const staleHooksDir = import_path12.default.join(home, ".claude", "hooks");
41029
+ const staleSkillsDir = import_path12.default.join(home, ".claude", "skills");
41030
+ const settingsPath = import_path12.default.join(home, ".claude", "settings.json");
41033
41031
  const removed = [];
41034
- const repoHooksDir = import_path11.default.join(repoRoot, "hooks");
41035
- if (await import_fs_extra11.default.pathExists(repoHooksDir) && await import_fs_extra11.default.pathExists(staleHooksDir)) {
41036
- const repoHookNames = (await import_fs_extra11.default.readdir(repoHooksDir)).filter((n) => n !== "README.md" && n !== "hooks.json");
41032
+ const repoHooksDir = import_path12.default.join(repoRoot, "hooks");
41033
+ if (await import_fs_extra12.default.pathExists(repoHooksDir) && await import_fs_extra12.default.pathExists(staleHooksDir)) {
41034
+ const repoHookNames = (await import_fs_extra12.default.readdir(repoHooksDir)).filter((n) => n !== "README.md" && n !== "hooks.json");
41037
41035
  for (const name of repoHookNames) {
41038
- const staleFile = import_path11.default.join(staleHooksDir, name);
41039
- if (await import_fs_extra11.default.pathExists(staleFile)) {
41036
+ const staleFile = import_path12.default.join(staleHooksDir, name);
41037
+ if (await import_fs_extra12.default.pathExists(staleFile)) {
41040
41038
  if (dryRun) {
41041
41039
  console.log(t.accent(` [DRY RUN] Would remove stale hook: ~/.claude/hooks/${name}`));
41042
41040
  } else {
41043
- await import_fs_extra11.default.remove(staleFile);
41041
+ await import_fs_extra12.default.remove(staleFile);
41044
41042
  console.log(t.muted(` \u2717 Removed stale hook: ~/.claude/hooks/${name}`));
41045
41043
  }
41046
41044
  removed.push(`hooks/${name}`);
41047
41045
  }
41048
41046
  }
41049
41047
  }
41050
- const repoSkillsDir = import_path11.default.join(repoRoot, "skills");
41051
- if (await import_fs_extra11.default.pathExists(repoSkillsDir) && await import_fs_extra11.default.pathExists(staleSkillsDir)) {
41052
- const repoSkillNames = (await import_fs_extra11.default.readdir(repoSkillsDir)).filter((n) => !n.startsWith("."));
41048
+ const repoSkillsDir = import_path12.default.join(repoRoot, "skills");
41049
+ if (await import_fs_extra12.default.pathExists(repoSkillsDir) && await import_fs_extra12.default.pathExists(staleSkillsDir)) {
41050
+ const repoSkillNames = (await import_fs_extra12.default.readdir(repoSkillsDir)).filter((n) => !n.startsWith("."));
41053
41051
  for (const name of repoSkillNames) {
41054
- const staleDir = import_path11.default.join(staleSkillsDir, name);
41055
- if (await import_fs_extra11.default.pathExists(staleDir)) {
41052
+ const staleDir = import_path12.default.join(staleSkillsDir, name);
41053
+ if (await import_fs_extra12.default.pathExists(staleDir)) {
41056
41054
  if (dryRun) {
41057
41055
  console.log(t.accent(` [DRY RUN] Would remove stale skill: ~/.claude/skills/${name}`));
41058
41056
  } else {
41059
- await import_fs_extra11.default.remove(staleDir);
41057
+ await import_fs_extra12.default.remove(staleDir);
41060
41058
  console.log(t.muted(` \u2717 Removed stale skill: ~/.claude/skills/${name}`));
41061
41059
  }
41062
41060
  removed.push(`skills/${name}`);
41063
41061
  }
41064
41062
  }
41065
41063
  }
41066
- if (await import_fs_extra11.default.pathExists(settingsPath)) {
41064
+ if (await import_fs_extra12.default.pathExists(settingsPath)) {
41067
41065
  let settings;
41068
41066
  try {
41069
- settings = await import_fs_extra11.default.readJson(settingsPath);
41067
+ settings = await import_fs_extra12.default.readJson(settingsPath);
41070
41068
  } catch {
41071
41069
  settings = null;
41072
41070
  }
@@ -41107,7 +41105,7 @@ async function cleanStalePrePluginFiles(repoRoot, dryRun) {
41107
41105
  }
41108
41106
  }
41109
41107
  if (settingsModified && !dryRun) {
41110
- await import_fs_extra11.default.writeJson(settingsPath, settings, { spaces: 2 });
41108
+ await import_fs_extra12.default.writeJson(settingsPath, settings, { spaces: 2 });
41111
41109
  }
41112
41110
  }
41113
41111
  }
@@ -41123,7 +41121,7 @@ async function installPlugin(repoRoot, dryRun) {
41123
41121
  await installOfficialClaudePlugins(true);
41124
41122
  return;
41125
41123
  }
41126
- const xtrmPkgRoot = import_path11.default.resolve(__dirname, "..", "..");
41124
+ const xtrmPkgRoot = import_path12.default.resolve(__dirname, "..", "..");
41127
41125
  (0, import_child_process3.spawnSync)("claude", ["plugin", "marketplace", "add", xtrmPkgRoot, "--scope", "user"], { stdio: "pipe" });
41128
41126
  const listResult = (0, import_child_process3.spawnSync)("claude", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
41129
41127
  if (listResult.stdout?.includes("xtrm-tools@xtrm-tools")) {
@@ -41499,31 +41497,31 @@ function createClaudeCommand() {
41499
41497
  }
41500
41498
 
41501
41499
  // src/commands/pi.ts
41502
- var import_path13 = __toESM(require("path"), 1);
41500
+ var import_path14 = __toESM(require("path"), 1);
41503
41501
  var import_node_child_process5 = require("child_process");
41504
41502
  var import_node_os7 = require("os");
41505
- var import_fs_extra13 = __toESM(require_lib2(), 1);
41503
+ var import_fs_extra14 = __toESM(require_lib2(), 1);
41506
41504
 
41507
41505
  // src/commands/install-pi.ts
41508
41506
  var import_prompts2 = __toESM(require_prompts3(), 1);
41509
- var import_fs_extra12 = __toESM(require_lib2(), 1);
41510
- var import_path12 = __toESM(require("path"), 1);
41507
+ var import_fs_extra13 = __toESM(require_lib2(), 1);
41508
+ var import_path13 = __toESM(require("path"), 1);
41511
41509
  var import_node_child_process4 = require("child_process");
41512
41510
  var import_node_os6 = require("os");
41513
- var PI_AGENT_DIR2 = process.env.PI_AGENT_DIR || import_path12.default.join((0, import_node_os6.homedir)(), ".pi", "agent");
41511
+ var PI_AGENT_DIR2 = process.env.PI_AGENT_DIR || import_path13.default.join((0, import_node_os6.homedir)(), ".pi", "agent");
41514
41512
  function fillTemplate(template, values) {
41515
41513
  return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? "");
41516
41514
  }
41517
41515
  function readExistingPiValues(piAgentDir) {
41518
41516
  const values = {};
41519
41517
  try {
41520
- const auth = JSON.parse(require("fs").readFileSync(import_path12.default.join(piAgentDir, "auth.json"), "utf8"));
41518
+ const auth = JSON.parse(require("fs").readFileSync(import_path13.default.join(piAgentDir, "auth.json"), "utf8"));
41521
41519
  if (auth?.dashscope?.key) values["DASHSCOPE_API_KEY"] = auth.dashscope.key;
41522
41520
  if (auth?.zai?.key) values["ZAI_API_KEY"] = auth.zai.key;
41523
41521
  } catch {
41524
41522
  }
41525
41523
  try {
41526
- const models = JSON.parse(require("fs").readFileSync(import_path12.default.join(piAgentDir, "models.json"), "utf8"));
41524
+ const models = JSON.parse(require("fs").readFileSync(import_path13.default.join(piAgentDir, "models.json"), "utf8"));
41527
41525
  if (!values["DASHSCOPE_API_KEY"] && models?.providers?.dashscope?.apiKey) {
41528
41526
  values["DASHSCOPE_API_KEY"] = models.providers.dashscope.apiKey;
41529
41527
  }
@@ -41534,15 +41532,15 @@ function readExistingPiValues(piAgentDir) {
41534
41532
  function isPiInstalled2() {
41535
41533
  return (0, import_node_child_process4.spawnSync)("pi", ["--version"], { encoding: "utf8" }).status === 0;
41536
41534
  }
41537
- async function listExtensionDirs2(baseDir) {
41538
- if (!await import_fs_extra12.default.pathExists(baseDir)) return [];
41539
- const entries = await import_fs_extra12.default.readdir(baseDir, { withFileTypes: true });
41535
+ async function listExtensionDirs(baseDir) {
41536
+ if (!await import_fs_extra13.default.pathExists(baseDir)) return [];
41537
+ const entries = await import_fs_extra13.default.readdir(baseDir, { withFileTypes: true });
41540
41538
  const extDirs = [];
41541
41539
  for (const entry of entries) {
41542
41540
  if (!entry.isDirectory()) continue;
41543
- const extPath = import_path12.default.join(baseDir, entry.name);
41544
- const pkgPath = import_path12.default.join(extPath, "package.json");
41545
- if (await import_fs_extra12.default.pathExists(pkgPath)) {
41541
+ const extPath = import_path13.default.join(baseDir, entry.name);
41542
+ const pkgPath = import_path13.default.join(extPath, "package.json");
41543
+ if (await import_fs_extra13.default.pathExists(pkgPath)) {
41546
41544
  extDirs.push(entry.name);
41547
41545
  }
41548
41546
  }
@@ -41550,37 +41548,37 @@ async function listExtensionDirs2(baseDir) {
41550
41548
  }
41551
41549
  async function fileSha256(filePath) {
41552
41550
  const crypto2 = await import("crypto");
41553
- const content = await import_fs_extra12.default.readFile(filePath);
41551
+ const content = await import_fs_extra13.default.readFile(filePath);
41554
41552
  return crypto2.createHash("sha256").update(content).digest("hex");
41555
41553
  }
41556
41554
  async function extensionHash(extDir) {
41557
- const pkgPath = import_path12.default.join(extDir, "package.json");
41558
- const indexPath = import_path12.default.join(extDir, "index.ts");
41555
+ const pkgPath = import_path13.default.join(extDir, "package.json");
41556
+ const indexPath = import_path13.default.join(extDir, "index.ts");
41559
41557
  const hashes = [];
41560
- if (await import_fs_extra12.default.pathExists(pkgPath)) {
41558
+ if (await import_fs_extra13.default.pathExists(pkgPath)) {
41561
41559
  hashes.push(await fileSha256(pkgPath));
41562
41560
  }
41563
- if (await import_fs_extra12.default.pathExists(indexPath)) {
41561
+ if (await import_fs_extra13.default.pathExists(indexPath)) {
41564
41562
  hashes.push(await fileSha256(indexPath));
41565
41563
  }
41566
41564
  return hashes.join(":");
41567
41565
  }
41568
41566
  async function diffPiExtensions(sourceDir, targetDir) {
41569
- const sourceAbs = import_path12.default.resolve(sourceDir);
41570
- const targetAbs = import_path12.default.resolve(targetDir);
41571
- const sourceExts = await listExtensionDirs2(sourceAbs);
41567
+ const sourceAbs = import_path13.default.resolve(sourceDir);
41568
+ const targetAbs = import_path13.default.resolve(targetDir);
41569
+ const sourceExts = await listExtensionDirs(sourceAbs);
41572
41570
  const missing = [];
41573
41571
  const stale = [];
41574
41572
  const upToDate = [];
41575
41573
  for (const extName of sourceExts) {
41576
- const srcExtPath = import_path12.default.join(sourceAbs, extName);
41577
- const dstExtPath = import_path12.default.join(targetAbs, extName);
41578
- if (!await import_fs_extra12.default.pathExists(dstExtPath)) {
41574
+ const srcExtPath = import_path13.default.join(sourceAbs, extName);
41575
+ const dstExtPath = import_path13.default.join(targetAbs, extName);
41576
+ if (!await import_fs_extra13.default.pathExists(dstExtPath)) {
41579
41577
  missing.push(extName);
41580
41578
  continue;
41581
41579
  }
41582
- const dstPkgPath = import_path12.default.join(dstExtPath, "package.json");
41583
- if (!await import_fs_extra12.default.pathExists(dstPkgPath)) {
41580
+ const dstPkgPath = import_path13.default.join(dstExtPath, "package.json");
41581
+ if (!await import_fs_extra13.default.pathExists(dstPkgPath)) {
41584
41582
  missing.push(extName);
41585
41583
  continue;
41586
41584
  }
@@ -41619,10 +41617,10 @@ function createInstallPiCommand() {
41619
41617
  cmd.description("Install Pi coding agent with providers, extensions, and npm packages").option("-y, --yes", "Skip confirmation prompts", false).option("--check", "Check Pi extension deployment drift without writing changes", false).action(async (opts) => {
41620
41618
  const { yes, check: check2 } = opts;
41621
41619
  const repoRoot = await findRepoRoot();
41622
- const piConfigDir = import_path12.default.join(repoRoot, "config", "pi");
41620
+ const piConfigDir = import_path13.default.join(repoRoot, "config", "pi");
41623
41621
  if (check2) {
41624
- const sourceDir = import_path12.default.join(piConfigDir, "extensions");
41625
- const targetDir = import_path12.default.join(PI_AGENT_DIR2, "extensions");
41622
+ const sourceDir = import_path13.default.join(piConfigDir, "extensions");
41623
+ const targetDir = import_path13.default.join(PI_AGENT_DIR2, "extensions");
41626
41624
  const diff = await diffPiExtensions(sourceDir, targetDir);
41627
41625
  printPiCheckSummary(diff);
41628
41626
  if (diff.missing.length > 0 || diff.stale.length > 0) {
@@ -41645,7 +41643,7 @@ function createInstallPiCommand() {
41645
41643
  console.log(t.success(` pi ${v.stdout.trim()} already installed
41646
41644
  `));
41647
41645
  }
41648
- const schema = await import_fs_extra12.default.readJson(import_path12.default.join(piConfigDir, "install-schema.json"));
41646
+ const schema = await import_fs_extra13.default.readJson(import_path13.default.join(piConfigDir, "install-schema.json"));
41649
41647
  const existing = readExistingPiValues(PI_AGENT_DIR2);
41650
41648
  const values = { ...existing };
41651
41649
  console.log(t.bold(" API Keys\n"));
@@ -41661,37 +41659,30 @@ function createInstallPiCommand() {
41661
41659
  const { value } = await (0, import_prompts2.default)({ type: field.secret ? "password" : "text", name: "value", message: ` ${field.label}`, hint: field.hint, validate: (v) => field.required && !v ? "Required" : true });
41662
41660
  if (value) values[field.key] = value;
41663
41661
  }
41664
- await import_fs_extra12.default.ensureDir(PI_AGENT_DIR2);
41662
+ await import_fs_extra13.default.ensureDir(PI_AGENT_DIR2);
41665
41663
  console.log(t.muted(`
41666
41664
  Writing config to ${PI_AGENT_DIR2}`));
41667
41665
  for (const name of ["models.json", "auth.json", "settings.json"]) {
41668
- const destPath = import_path12.default.join(PI_AGENT_DIR2, name);
41669
- if (name === "auth.json" && await import_fs_extra12.default.pathExists(destPath) && !yes) {
41666
+ const destPath = import_path13.default.join(PI_AGENT_DIR2, name);
41667
+ if (name === "auth.json" && await import_fs_extra13.default.pathExists(destPath) && !yes) {
41670
41668
  const { overwrite } = await (0, import_prompts2.default)({ type: "confirm", name: "overwrite", message: ` ${name} already exists \u2014 overwrite? (OAuth tokens will be lost)`, initial: false });
41671
41669
  if (!overwrite) {
41672
41670
  console.log(t.muted(` skipped ${name}`));
41673
41671
  continue;
41674
41672
  }
41675
41673
  }
41676
- const raw = await import_fs_extra12.default.readFile(import_path12.default.join(piConfigDir, `${name}.template`), "utf8");
41677
- await import_fs_extra12.default.writeFile(destPath, fillTemplate(raw, values), "utf8");
41674
+ const raw = await import_fs_extra13.default.readFile(import_path13.default.join(piConfigDir, `${name}.template`), "utf8");
41675
+ await import_fs_extra13.default.writeFile(destPath, fillTemplate(raw, values), "utf8");
41678
41676
  console.log(t.success(` ${sym.ok} ${name}`));
41679
41677
  }
41680
- await import_fs_extra12.default.copy(import_path12.default.join(piConfigDir, "extensions"), import_path12.default.join(PI_AGENT_DIR2, "extensions"), { overwrite: true });
41681
- console.log(t.success(` ${sym.ok} extensions/`));
41682
- const extDirs = await listExtensionDirs2(import_path12.default.join(PI_AGENT_DIR2, "extensions"));
41683
- if (extDirs.length > 0) {
41684
- console.log(kleur_default.dim(`
41685
- Registering ${extDirs.length} extensions...`));
41686
- for (const extName of extDirs) {
41687
- const extPath = import_path12.default.join(PI_AGENT_DIR2, "extensions", extName);
41688
- const r = (0, import_node_child_process4.spawnSync)("pi", ["install", "-l", extPath], { stdio: "pipe", encoding: "utf8" });
41689
- if (r.status === 0) {
41690
- console.log(t.success(` ${sym.ok} ${extName} registered`));
41691
- } else {
41692
- console.log(kleur_default.yellow(` \u26A0 ${extName} \u2014 registration failed`));
41693
- }
41694
- }
41678
+ const managedPackages = await syncManagedPiExtensions({
41679
+ sourceDir: import_path13.default.join(piConfigDir, "extensions"),
41680
+ targetDir: import_path13.default.join(PI_AGENT_DIR2, "extensions"),
41681
+ dryRun: false,
41682
+ log: (message) => console.log(kleur_default.dim(` ${message}`))
41683
+ });
41684
+ if (managedPackages > 0) {
41685
+ console.log(t.success(` ${sym.ok} extensions/ (${managedPackages} packages)`));
41695
41686
  }
41696
41687
  console.log(t.bold("\n npm Packages\n"));
41697
41688
  for (const pkg of schema.packages) {
@@ -41709,7 +41700,7 @@ function createInstallPiCommand() {
41709
41700
  }
41710
41701
 
41711
41702
  // src/commands/pi.ts
41712
- var PI_AGENT_DIR3 = process.env.PI_AGENT_DIR || import_path13.default.join((0, import_node_os7.homedir)(), ".pi", "agent");
41703
+ var PI_AGENT_DIR3 = process.env.PI_AGENT_DIR || import_path14.default.join((0, import_node_os7.homedir)(), ".pi", "agent");
41713
41704
  function createPiCommand() {
41714
41705
  const cmd = new Command("pi").description("Launch a Pi session in a sandboxed worktree, or manage the Pi runtime").argument("[name]", "Optional session name \u2014 used as xt/<name> branch (random if omitted)").action(async (name) => {
41715
41706
  await launchWorktreeSession({ runtime: "pi", name });
@@ -41732,8 +41723,8 @@ function createPiCommand() {
41732
41723
  return;
41733
41724
  }
41734
41725
  const repoRoot = await findRepoRoot();
41735
- const sourceDir = import_path13.default.join(repoRoot, "config", "pi", "extensions");
41736
- const targetDir = import_path13.default.join(PI_AGENT_DIR3, "extensions");
41726
+ const sourceDir = import_path14.default.join(repoRoot, "config", "pi", "extensions");
41727
+ const targetDir = import_path14.default.join(PI_AGENT_DIR3, "extensions");
41737
41728
  const diff = await diffPiExtensions(sourceDir, targetDir);
41738
41729
  if (diff.missing.length === 0 && diff.stale.length === 0) {
41739
41730
  console.log(t.success(` \u2713 extensions up-to-date (${diff.upToDate.length} deployed)`));
@@ -41755,9 +41746,9 @@ function createPiCommand() {
41755
41746
  allOk = false;
41756
41747
  }
41757
41748
  const repoRoot = await findRepoRoot();
41758
- const piConfigDir = import_path13.default.join(repoRoot, "config", "pi");
41759
- const sourceDir = import_path13.default.join(piConfigDir, "extensions");
41760
- const targetDir = import_path13.default.join(PI_AGENT_DIR3, "extensions");
41749
+ const piConfigDir = import_path14.default.join(repoRoot, "config", "pi");
41750
+ const sourceDir = import_path14.default.join(piConfigDir, "extensions");
41751
+ const targetDir = import_path14.default.join(PI_AGENT_DIR3, "extensions");
41761
41752
  const diff = await diffPiExtensions(sourceDir, targetDir);
41762
41753
  if (diff.missing.length === 0 && diff.stale.length === 0) {
41763
41754
  console.log(t.success(` \u2713 extensions deployed (${diff.upToDate.length})`));
@@ -41765,11 +41756,11 @@ function createPiCommand() {
41765
41756
  console.log(kleur_default.yellow(` \u26A0 extension drift (${diff.missing.length} missing, ${diff.stale.length} stale)`));
41766
41757
  allOk = false;
41767
41758
  }
41768
- const schemaPath = import_path13.default.join(piConfigDir, "install-schema.json");
41769
- if (await import_fs_extra13.default.pathExists(schemaPath)) {
41759
+ const schemaPath = import_path14.default.join(piConfigDir, "install-schema.json");
41760
+ if (await import_fs_extra14.default.pathExists(schemaPath)) {
41770
41761
  try {
41771
41762
  (0, import_node_child_process5.execSync)("pi --version", { stdio: "ignore" });
41772
- const schema = await import_fs_extra13.default.readJson(schemaPath);
41763
+ const schema = await import_fs_extra14.default.readJson(schemaPath);
41773
41764
  const listResult = (0, import_node_child_process5.spawnSync)("pi", ["list"], { encoding: "utf8", stdio: "pipe" });
41774
41765
  const installed = listResult.stdout ?? "";
41775
41766
  const missing = schema.packages.filter((p) => !installed.includes(p.replace("npm:", "")));
@@ -41797,43 +41788,43 @@ function createPiCommand() {
41797
41788
  }
41798
41789
 
41799
41790
  // src/commands/init.ts
41800
- var import_path15 = __toESM(require("path"), 1);
41801
- var import_fs_extra15 = __toESM(require_lib2(), 1);
41791
+ var import_path16 = __toESM(require("path"), 1);
41792
+ var import_fs_extra16 = __toESM(require_lib2(), 1);
41802
41793
  var import_child_process4 = require("child_process");
41803
41794
 
41804
41795
  // src/commands/install-service-skills.ts
41805
- var import_path14 = __toESM(require("path"), 1);
41806
- var import_fs_extra14 = __toESM(require_lib2(), 1);
41796
+ var import_path15 = __toESM(require("path"), 1);
41797
+ var import_fs_extra15 = __toESM(require_lib2(), 1);
41807
41798
  function resolvePkgRoot() {
41808
41799
  const candidates = [
41809
- import_path14.default.resolve(__dirname, "../.."),
41810
- import_path14.default.resolve(__dirname, "../../..")
41800
+ import_path15.default.resolve(__dirname, "../.."),
41801
+ import_path15.default.resolve(__dirname, "../../..")
41811
41802
  ];
41812
- const match = candidates.find((candidate) => import_fs_extra14.default.existsSync(import_path14.default.join(candidate, "project-skills")));
41803
+ const match = candidates.find((candidate) => import_fs_extra15.default.existsSync(import_path15.default.join(candidate, "project-skills")));
41813
41804
  if (!match) {
41814
41805
  throw new Error("Unable to locate project-skills directory from CLI runtime.");
41815
41806
  }
41816
41807
  return match;
41817
41808
  }
41818
41809
  var PKG_ROOT = resolvePkgRoot();
41819
- var SKILLS_SRC = import_path14.default.join(PKG_ROOT, "project-skills", "service-skills-set", ".claude");
41810
+ var SKILLS_SRC = import_path15.default.join(PKG_ROOT, "project-skills", "service-skills-set", ".claude");
41820
41811
 
41821
41812
  // src/commands/init.ts
41822
41813
  function resolvePkgRoot2() {
41823
41814
  const candidates = [
41824
- import_path15.default.resolve(__dirname, "../.."),
41825
- import_path15.default.resolve(__dirname, "../../..")
41815
+ import_path16.default.resolve(__dirname, "../.."),
41816
+ import_path16.default.resolve(__dirname, "../../..")
41826
41817
  ];
41827
- const match = candidates.find((candidate) => import_fs_extra15.default.existsSync(import_path15.default.join(candidate, "project-skills")));
41818
+ const match = candidates.find((candidate) => import_fs_extra16.default.existsSync(import_path16.default.join(candidate, "project-skills")));
41828
41819
  if (!match) {
41829
41820
  throw new Error("Unable to locate project-skills directory from CLI runtime.");
41830
41821
  }
41831
41822
  return match;
41832
41823
  }
41833
41824
  var PKG_ROOT2 = resolvePkgRoot2();
41834
- var PROJECT_SKILLS_DIR = import_path15.default.join(PKG_ROOT2, "project-skills");
41835
- var MCP_CORE_CONFIG_PATH = import_path15.default.join(PKG_ROOT2, "config", "mcp_servers.json");
41836
- var INSTRUCTIONS_DIR = import_path15.default.join(PKG_ROOT2, "config", "instructions");
41825
+ var PROJECT_SKILLS_DIR = import_path16.default.join(PKG_ROOT2, "project-skills");
41826
+ var MCP_CORE_CONFIG_PATH = import_path16.default.join(PKG_ROOT2, "config", "mcp_servers.json");
41827
+ var INSTRUCTIONS_DIR = import_path16.default.join(PKG_ROOT2, "config", "instructions");
41837
41828
  var XTRM_BLOCK_START = "<!-- xtrm:start -->";
41838
41829
  var XTRM_BLOCK_END = "<!-- xtrm:end -->";
41839
41830
  function parseComposeServices(content) {
@@ -41859,8 +41850,8 @@ function parseComposeServices(content) {
41859
41850
  return [...services];
41860
41851
  }
41861
41852
  async function detectProjectFeatures(projectRoot) {
41862
- const hasTypeScript = await import_fs_extra15.default.pathExists(import_path15.default.join(projectRoot, "tsconfig.json"));
41863
- const hasPython = await import_fs_extra15.default.pathExists(import_path15.default.join(projectRoot, "pyproject.toml")) || await import_fs_extra15.default.pathExists(import_path15.default.join(projectRoot, "setup.py")) || await import_fs_extra15.default.pathExists(import_path15.default.join(projectRoot, "requirements.txt"));
41853
+ const hasTypeScript = await import_fs_extra16.default.pathExists(import_path16.default.join(projectRoot, "tsconfig.json"));
41854
+ const hasPython = await import_fs_extra16.default.pathExists(import_path16.default.join(projectRoot, "pyproject.toml")) || await import_fs_extra16.default.pathExists(import_path16.default.join(projectRoot, "setup.py")) || await import_fs_extra16.default.pathExists(import_path16.default.join(projectRoot, "requirements.txt"));
41864
41855
  const composeCandidates = [
41865
41856
  "docker-compose.yml",
41866
41857
  "docker-compose.yaml",
@@ -41869,19 +41860,19 @@ async function detectProjectFeatures(projectRoot) {
41869
41860
  ];
41870
41861
  const dockerServices = /* @__PURE__ */ new Set();
41871
41862
  for (const composeFile of composeCandidates) {
41872
- const composePath = import_path15.default.join(projectRoot, composeFile);
41873
- if (!await import_fs_extra15.default.pathExists(composePath)) continue;
41863
+ const composePath = import_path16.default.join(projectRoot, composeFile);
41864
+ if (!await import_fs_extra16.default.pathExists(composePath)) continue;
41874
41865
  try {
41875
- const content = await import_fs_extra15.default.readFile(composePath, "utf8");
41866
+ const content = await import_fs_extra16.default.readFile(composePath, "utf8");
41876
41867
  for (const service of parseComposeServices(content)) {
41877
41868
  dockerServices.add(service);
41878
41869
  }
41879
41870
  } catch {
41880
41871
  }
41881
41872
  }
41882
- const hasDockerfile = await import_fs_extra15.default.pathExists(import_path15.default.join(projectRoot, "Dockerfile"));
41873
+ const hasDockerfile = await import_fs_extra16.default.pathExists(import_path16.default.join(projectRoot, "Dockerfile"));
41883
41874
  if (hasDockerfile && dockerServices.size === 0) {
41884
- dockerServices.add(import_path15.default.basename(projectRoot));
41875
+ dockerServices.add(import_path16.default.basename(projectRoot));
41885
41876
  }
41886
41877
  return {
41887
41878
  hasTypeScript,
@@ -41915,20 +41906,20 @@ async function injectProjectInstructionHeaders(projectRoot) {
41915
41906
  ];
41916
41907
  console.log(kleur_default.bold("Injecting xtrm agent instruction headers..."));
41917
41908
  for (const target of targets) {
41918
- const templatePath = import_path15.default.join(INSTRUCTIONS_DIR, target.template);
41919
- if (!await import_fs_extra15.default.pathExists(templatePath)) {
41909
+ const templatePath = import_path16.default.join(INSTRUCTIONS_DIR, target.template);
41910
+ if (!await import_fs_extra16.default.pathExists(templatePath)) {
41920
41911
  console.log(kleur_default.yellow(` \u26A0 Missing template: ${target.template}`));
41921
41912
  continue;
41922
41913
  }
41923
- const template = await import_fs_extra15.default.readFile(templatePath, "utf8");
41924
- const outputPath = import_path15.default.join(projectRoot, target.output);
41925
- const existing = await import_fs_extra15.default.pathExists(outputPath) ? await import_fs_extra15.default.readFile(outputPath, "utf8") : "";
41914
+ const template = await import_fs_extra16.default.readFile(templatePath, "utf8");
41915
+ const outputPath = import_path16.default.join(projectRoot, target.output);
41916
+ const existing = await import_fs_extra16.default.pathExists(outputPath) ? await import_fs_extra16.default.readFile(outputPath, "utf8") : "";
41926
41917
  const next = upsertManagedBlock(existing, template);
41927
41918
  if (next === existing) {
41928
41919
  console.log(kleur_default.dim(` \u2713 ${target.output} already up to date`));
41929
41920
  continue;
41930
41921
  }
41931
- await import_fs_extra15.default.writeFile(outputPath, next.endsWith("\n") ? next : `${next}
41922
+ await import_fs_extra16.default.writeFile(outputPath, next.endsWith("\n") ? next : `${next}
41932
41923
  `, "utf8");
41933
41924
  console.log(`${kleur_default.green(" \u2713")} updated ${target.output}`);
41934
41925
  }
@@ -42065,14 +42056,14 @@ function getProjectRoot() {
42065
42056
  if (result.status !== 0) {
42066
42057
  throw new Error("Not inside a git repository. Run this command from your target project directory.");
42067
42058
  }
42068
- return import_path15.default.resolve(result.stdout.trim());
42059
+ return import_path16.default.resolve(result.stdout.trim());
42069
42060
  }
42070
42061
 
42071
42062
  // src/commands/status.ts
42072
42063
  var import_prompts3 = __toESM(require_prompts3(), 1);
42073
42064
 
42074
42065
  // src/core/manifest.ts
42075
- var import_path16 = require("path");
42066
+ var import_path17 = require("path");
42076
42067
 
42077
42068
  // ../node_modules/zod/v4/classic/external.js
42078
42069
  var external_exports = {};
@@ -55881,17 +55872,17 @@ var ManifestSchema = external_exports.object({
55881
55872
  // src/core/manifest.ts
55882
55873
  var MANIFEST_FILE = ".jaggers-sync-manifest.json";
55883
55874
  function getManifestPath(projectDir) {
55884
- return (0, import_path16.join)(projectDir, MANIFEST_FILE);
55875
+ return (0, import_path17.join)(projectDir, MANIFEST_FILE);
55885
55876
  }
55886
55877
 
55887
55878
  // src/commands/status.ts
55888
- var import_fs_extra16 = __toESM(require_lib2(), 1);
55889
- var import_path17 = __toESM(require("path"), 1);
55879
+ var import_fs_extra17 = __toESM(require_lib2(), 1);
55880
+ var import_path18 = __toESM(require("path"), 1);
55890
55881
  function formatTargetLabel2(target) {
55891
55882
  const normalized = target.replace(/\\/g, "/").toLowerCase();
55892
55883
  if (normalized.endsWith("/.agents/skills") || normalized.includes("/.agents/skills/")) return "~/.agents/skills";
55893
55884
  if (normalized.endsWith("/.claude") || normalized.includes("/.claude/")) return "~/.claude";
55894
- return import_path17.default.basename(target);
55885
+ return import_path18.default.basename(target);
55895
55886
  }
55896
55887
  function formatRelativeTime(timestamp) {
55897
55888
  const now = Date.now();
@@ -55911,7 +55902,7 @@ function createStatusCommand() {
55911
55902
  const candidates = getCandidatePaths();
55912
55903
  const targets = [];
55913
55904
  for (const c of candidates) {
55914
- if (await import_fs_extra16.default.pathExists(c.path)) targets.push(c.path);
55905
+ if (await import_fs_extra17.default.pathExists(c.path)) targets.push(c.path);
55915
55906
  }
55916
55907
  if (targets.length === 0) {
55917
55908
  console.log(kleur_default.yellow("\n No agent environments found (~/.claude, ~/.agents/skills)\n"));
@@ -55922,8 +55913,8 @@ function createStatusCommand() {
55922
55913
  const manifestPath = getManifestPath(target);
55923
55914
  let lastSync = null;
55924
55915
  try {
55925
- if (await import_fs_extra16.default.pathExists(manifestPath)) {
55926
- const manifest = await import_fs_extra16.default.readJson(manifestPath);
55916
+ if (await import_fs_extra17.default.pathExists(manifestPath)) {
55917
+ const manifest = await import_fs_extra17.default.readJson(manifestPath);
55927
55918
  if (manifest.lastSync) lastSync = manifest.lastSync;
55928
55919
  }
55929
55920
  } catch {
@@ -56015,127 +56006,91 @@ function createResetCommand() {
56015
56006
  }
56016
56007
 
56017
56008
  // src/commands/help.ts
56018
- var import_path18 = __toESM(require("path"), 1);
56019
- var import_fs_extra17 = __toESM(require_lib2(), 1);
56020
- var HOOK_CATALOG = [
56021
- { file: "using-xtrm-reminder.mjs", event: "SessionStart", desc: "Injects using-xtrm session operating manual into system prompt" },
56022
- { file: "gitnexus/gitnexus-hook.cjs", event: "PostToolUse", desc: "Adds GitNexus context for search and Serena tooling" },
56023
- { file: "quality-check.cjs", event: "PostToolUse", desc: "Runs JS/TS quality checks on mutating edits" },
56024
- { file: "quality-check.py", event: "PostToolUse", desc: "Runs Python quality checks on mutating edits" },
56025
- { file: "quality-check-env.mjs", event: "SessionStart", desc: "Warns if tsc/ruff/eslint are missing at session start" },
56026
- { file: "worktree-boundary.mjs", event: "PreToolUse", desc: "Blocks edits outside .xtrm/worktrees when in worktree session" },
56027
- { file: "statusline.mjs", event: "statusLine", desc: "Renders 2-line status: XTRM model branch + claim/open issues" },
56028
- { file: "beads-edit-gate.mjs", event: "PreToolUse", desc: "Blocks file edits if no beads issue is claimed", beads: true },
56029
- { file: "beads-commit-gate.mjs", event: "PreToolUse", desc: "Blocks commits when no beads issue is in progress", beads: true },
56030
- { file: "beads-stop-gate.mjs", event: "Stop", desc: "Blocks stop when there is an unclosed in_progress claim", beads: true },
56031
- { file: "beads-memory-gate.mjs", event: "Stop", desc: "Prompts memory save when claim was closed this session", beads: true },
56032
- { file: "beads-compact-save.mjs", event: "PreCompact", desc: "Saves claim state across /compact", beads: true },
56033
- { file: "beads-compact-restore.mjs", event: "SessionStart", desc: "Restores claim state after /compact", beads: true },
56034
- { file: "beads-claim-sync.mjs", event: "PostToolUse", desc: "Notifies on bd update --claim; auto-commits on bd close", sessionFlow: true }
56035
- ];
56036
- async function readSkillsFromDir(dir) {
56037
- if (!await import_fs_extra17.default.pathExists(dir)) return [];
56038
- const entries = await import_fs_extra17.default.readdir(dir);
56039
- const skills = [];
56040
- for (const name of entries.sort()) {
56041
- const skillMd = import_path18.default.join(dir, name, "SKILL.md");
56042
- if (!await import_fs_extra17.default.pathExists(skillMd)) continue;
56043
- const content = await import_fs_extra17.default.readFile(skillMd, "utf8");
56044
- const m = content.match(/^description:\s*(.+)$/m);
56045
- skills.push({ name, desc: m ? m[1].replace(/^["']|["']$/g, "").trim() : "" });
56046
- }
56047
- return skills;
56048
- }
56049
- function resolvePkgRootFallback() {
56050
- const candidates = [
56051
- import_path18.default.resolve(__dirname, "../.."),
56052
- import_path18.default.resolve(__dirname, "../../..")
56053
- ];
56054
- const match = candidates.find(
56055
- (candidate) => import_fs_extra17.default.existsSync(import_path18.default.join(candidate, "skills")) || import_fs_extra17.default.existsSync(import_path18.default.join(candidate, "project-skills"))
56056
- );
56057
- return match || null;
56058
- }
56059
- function col(s, width) {
56060
- return s.length >= width ? s.slice(0, width - 1) + "\u2026" : s.padEnd(width);
56009
+ function section(title, lines) {
56010
+ return [title, ...lines, ""].join("\n");
56061
56011
  }
56062
56012
  function createHelpCommand() {
56063
- return new Command("help").description("Show help information and component catalogue").action(async () => {
56064
- let repoRoot;
56065
- try {
56066
- repoRoot = await findRepoRoot();
56067
- } catch {
56068
- repoRoot = "";
56069
- }
56070
- const pkgRoot = resolvePkgRootFallback();
56071
- const skillsRoot = repoRoot || pkgRoot || "";
56072
- const skills = skillsRoot ? await readSkillsFromDir(import_path18.default.join(skillsRoot, "skills")) : [];
56073
- const W = 80;
56074
- const hr = kleur_default.dim("-".repeat(W));
56075
- const section = (title) => `
56076
- ${kleur_default.bold().cyan(title)}
56077
- ${hr}`;
56078
- const installSection = [
56079
- section("INSTALL COMMANDS"),
56080
- "",
56081
- ` ${kleur_default.bold("xtrm install")}`,
56082
- ` ${kleur_default.dim("Install plugin + skills + hooks + MCP servers.")}`,
56083
- ` ${kleur_default.dim("Checks for beads+dolt and prompts to install if missing.")}`,
56084
- "",
56085
- ` ${kleur_default.dim("Flags: --dry-run --yes / -y --no-mcp --force --prune --backport")}`
56086
- ].join("\n");
56087
- const general = HOOK_CATALOG.filter((h) => !h.beads && !h.sessionFlow);
56088
- const beads = HOOK_CATALOG.filter((h) => h.beads);
56089
- const sessionFlow = HOOK_CATALOG.filter((h) => h.sessionFlow);
56090
- const hookRows = (hooks) => hooks.map(
56091
- (h) => ` ${kleur_default.white(col(h.file, 34))}${kleur_default.yellow(col(h.event, 20))}${kleur_default.dim(h.desc)}`
56092
- ).join("\n");
56093
- const hooksSection = [
56094
- section("GLOBAL HOOKS"),
56013
+ return new Command("help").description("Show rich CLI help in a plain text format").action(async () => {
56014
+ const blocks = [];
56015
+ blocks.push(section("XTRM CLI", [
56016
+ " xtrm and xt are equivalent commands.",
56017
+ " Use xt for short workflow commands (xt claude, xt pi, xt end)."
56018
+ ]));
56019
+ blocks.push(section("USAGE", [
56020
+ " xtrm <command> [subcommand] [options]",
56021
+ " xt <command> [subcommand] [options]"
56022
+ ]));
56023
+ blocks.push(section("CORE WORKFLOW", [
56024
+ " 1) Start a runtime session in a worktree:",
56025
+ " xt claude [name] or xt pi [name]",
56026
+ " 2) Do your work in that worktree/branch.",
56027
+ " 3) Finish with:",
56028
+ " xt end",
56029
+ " 4) Manage old worktrees when needed:",
56030
+ " xt worktree list | xt worktree clean"
56031
+ ]));
56032
+ blocks.push(section("PRIMARY COMMANDS", [
56033
+ " xtrm install [target-selector] [options]",
56034
+ " Install/sync tools, hooks, skills, and MCP wiring.",
56035
+ " Options: --dry-run, --yes/-y, --prune, --backport",
56095
56036
  "",
56096
- kleur_default.dim(" " + col("File", 34) + col("Event", 20) + "Description"),
56037
+ " xtrm status [--json]",
56038
+ " Show pending changes for detected environments.",
56097
56039
  "",
56098
- hookRows(general),
56040
+ " xtrm clean [options]",
56041
+ " Remove orphaned hooks/skills and stale hook wiring entries.",
56042
+ " Options: --dry-run, --hooks-only, --skills-only, --yes/-y",
56099
56043
  "",
56100
- ` ${kleur_default.dim("beads gate hooks (xtrm install all -- require beads+dolt):")}`,
56101
- hookRows(beads),
56044
+ " xtrm init",
56045
+ " Initialize project-level workflow setup.",
56102
56046
  "",
56103
- ` ${kleur_default.dim("session-flow hooks:")}`,
56104
- hookRows(sessionFlow)
56105
- ].join("\n");
56106
- const skillRows = skills.map((s) => {
56107
- const desc = s.desc.length > 46 ? s.desc.slice(0, 45) + "\u2026" : s.desc;
56108
- return ` ${kleur_default.white(col(s.name, 30))}${kleur_default.dim(desc)}`;
56109
- }).join("\n");
56110
- const skillsSection = [
56111
- section(`SKILLS ${kleur_default.dim("(" + skills.length + " available)")}`),
56047
+ " xtrm docs show [filter] [--raw] [--json]",
56048
+ " Show frontmatter for README/CHANGELOG/docs/*.md.",
56112
56049
  "",
56113
- skills.length ? skillRows : kleur_default.dim(" (none found -- run from repo root to see skills)")
56114
- ].join("\n");
56115
- const otherSection = [
56116
- section("OTHER COMMANDS"),
56050
+ " xtrm debug [options]",
56051
+ " Stream xtrm event log (tool calls, gates, session/bd lifecycle).",
56052
+ " Options: --follow, --all, --session <id>, --type <domain>, --json",
56117
56053
  "",
56118
- ` ${kleur_default.bold("xtrm status")} ${kleur_default.dim("Show pending changes without applying them")}`,
56119
- ` ${kleur_default.bold("xtrm clean")} ${kleur_default.dim("Remove orphaned hooks and skills not in canonical repo")}`,
56120
- ` ${kleur_default.bold("xtrm init")} ${kleur_default.dim("Initialize project data (beads, gitnexus, service-registry)")}`,
56121
- ` ${kleur_default.bold("xtrm docs show")} ${kleur_default.dim("Display frontmatter for README, CHANGELOG, docs/*.md")}`,
56122
- ` ${kleur_default.bold("xtrm debug")} ${kleur_default.dim("Watch xtrm hook and bd lifecycle events in real time")}`,
56123
- ` ${kleur_default.bold("xtrm reset")} ${kleur_default.dim("Clear saved preferences and start fresh")}`,
56124
- ` ${kleur_default.bold("xtrm end")} ${kleur_default.dim("Close worktree session: rebase, push, PR, link issues, cleanup")}`,
56125
- ` ${kleur_default.bold("xtrm worktree list")} ${kleur_default.dim("List all active xt/* worktrees with status")}`,
56126
- ` ${kleur_default.bold("xtrm worktree clean")} ${kleur_default.dim("Remove worktrees whose branch has been merged into main")}`,
56127
- ` ${kleur_default.bold("xtrm help")} ${kleur_default.dim("Show this overview")}`
56128
- ].join("\n");
56129
- const resourcesSection = [
56130
- section("RESOURCES"),
56054
+ " xtrm reset",
56055
+ " Clear saved CLI preferences.",
56131
56056
  "",
56132
- ` Repository https://github.com/Jaggerxtrm/xtrm-tools`,
56133
- ` Issues https://github.com/Jaggerxtrm/xtrm-tools/issues`,
56057
+ " xtrm help",
56058
+ " Show this help page."
56059
+ ]));
56060
+ blocks.push(section("RUNTIME COMMANDS", [
56061
+ " xt claude [name]",
56062
+ " Launch Claude in a sandboxed xt/<name> worktree.",
56063
+ " xt claude install [--dry-run]",
56064
+ " Install/refresh xtrm Claude plugin + official plugins.",
56065
+ " xt claude status | xt claude doctor | xt claude reload",
56134
56066
  "",
56135
- ` ${kleur_default.dim("Run 'xtrm <command> --help' for command-specific options.")}`,
56136
- ""
56137
- ].join("\n");
56138
- console.log([installSection, hooksSection, skillsSection, otherSection, resourcesSection].join("\n"));
56067
+ " xt pi [name]",
56068
+ " Launch Pi in a sandboxed xt/<name> worktree.",
56069
+ " xt pi install [--dry-run]",
56070
+ " Non-interactive extension sync + package install.",
56071
+ " xt pi setup",
56072
+ " Interactive first-time setup.",
56073
+ " xt pi status | xt pi doctor | xt pi reload"
56074
+ ]));
56075
+ blocks.push(section("WORKTREE COMMANDS", [
56076
+ " xt worktree list",
56077
+ " List active xt/* worktrees and merge status.",
56078
+ " xt worktree clean [--yes/-y]",
56079
+ " Remove worktrees already merged into main.",
56080
+ " xt worktree remove <name> [--yes/-y]",
56081
+ " Remove a specific xt worktree by name or path."
56082
+ ]));
56083
+ blocks.push(section("SESSION CLOSE", [
56084
+ " xt end [options]",
56085
+ " Rebase to origin/main, push, open PR, link issues, and optionally clean worktree.",
56086
+ " Options: --draft, --keep, --yes/-y"
56087
+ ]));
56088
+ blocks.push(section("NOTES", [
56089
+ " - Banner is shown only for xtrm install.",
56090
+ " - For command-level details, run: xtrm <command> --help",
56091
+ " - For subcommand details, run: xtrm <command> <subcommand> --help"
56092
+ ]));
56093
+ process.stdout.write(blocks.join("\n"));
56139
56094
  });
56140
56095
  }
56141
56096
 
@@ -56145,7 +56100,6 @@ var import_path19 = __toESM(require("path"), 1);
56145
56100
  var import_os6 = require("os");
56146
56101
  var CANONICAL_HOOKS = /* @__PURE__ */ new Set([
56147
56102
  "using-xtrm-reminder.mjs",
56148
- "serena-workflow-reminder.py",
56149
56103
  "beads-gate-core.mjs",
56150
56104
  "beads-gate-utils.mjs",
56151
56105
  "beads-gate-messages.mjs",
@@ -56156,13 +56110,16 @@ var CANONICAL_HOOKS = /* @__PURE__ */ new Set([
56156
56110
  "beads-claim-sync.mjs",
56157
56111
  "beads-compact-save.mjs",
56158
56112
  "beads-compact-restore.mjs",
56113
+ "worktree-boundary.mjs",
56159
56114
  "statusline.mjs",
56160
56115
  "quality-check.cjs",
56161
56116
  "quality-check-env.mjs",
56162
56117
  "quality-check.py",
56118
+ "xtrm-logger.mjs",
56119
+ "xtrm-tool-logger.mjs",
56120
+ "xtrm-session-logger.mjs",
56163
56121
  "gitnexus",
56164
56122
  // directory
56165
- "statusline-starship.sh",
56166
56123
  "README.md"
56167
56124
  ]);
56168
56125
  var CANONICAL_SKILLS = /* @__PURE__ */ new Set([
@@ -57321,9 +57278,9 @@ process.on("unhandledRejection", (reason) => {
57321
57278
  process.exit(1);
57322
57279
  });
57323
57280
  var isHelpOrVersion = process.argv.some((a) => a === "--help" || a === "-h" || a === "--version" || a === "-V");
57324
- var isViewerCommand = ["debug", "status"].includes(process.argv[2] ?? "");
57281
+ var isInstallCommand = (process.argv[2] ?? "") === "install";
57325
57282
  (async () => {
57326
- if (!isHelpOrVersion && !isViewerCommand) {
57283
+ if (!isHelpOrVersion && isInstallCommand) {
57327
57284
  await printBanner(version2);
57328
57285
  }
57329
57286
  program2.parseAsync(process.argv);