xtrm-tools 0.5.28 → 0.5.30
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +19 -3
- package/README.md +13 -37
- package/cli/dist/index.cjs +311 -161
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/config/instructions/agents-top.md +1 -1
- package/config/instructions/claude-top.md +1 -1
- package/config/pi/extensions/beads/index.ts +68 -7
- package/config/pi/extensions/core/guard-rules.ts +0 -2
- package/config/pi/extensions/custom-footer/index.ts +5 -6
- package/hooks/beads-claim-sync.mjs +18 -6
- package/hooks/beads-gate-messages.mjs +5 -2
- package/hooks/beads-memory-gate.mjs +20 -7
- package/hooks/statusline.mjs +44 -8
- package/package.json +3 -2
- package/plugins/xtrm-tools/.claude-plugin/plugin.json +1 -1
- package/plugins/xtrm-tools/hooks/beads-claim-sync.mjs +18 -6
- package/plugins/xtrm-tools/hooks/beads-gate-messages.mjs +5 -2
- package/plugins/xtrm-tools/hooks/beads-memory-gate.mjs +20 -7
- package/plugins/xtrm-tools/hooks/statusline.mjs +44 -8
- package/plugins/xtrm-tools/skills/sync-docs/SKILL.md +57 -2
- package/plugins/xtrm-tools/skills/sync-docs/scripts/drift_detector.py +1 -1
- package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_metadata.py +1 -1
- package/plugins/xtrm-tools/skills/xt-end/SKILL.md +4 -4
- package/plugins/xtrm-tools/skills/xt-merge/SKILL.md +190 -0
- package/skills/sync-docs/SKILL.md +57 -2
- package/skills/sync-docs/scripts/drift_detector.py +1 -1
- package/skills/sync-docs/scripts/validate_metadata.py +1 -1
- package/skills/xt-end/SKILL.md +4 -4
- package/skills/xt-merge/SKILL.md +190 -0
package/cli/dist/index.cjs
CHANGED
|
@@ -30319,10 +30319,10 @@ var require_stringify = __commonJS({
|
|
|
30319
30319
|
replacer = null;
|
|
30320
30320
|
indent2 = EMPTY;
|
|
30321
30321
|
};
|
|
30322
|
-
var
|
|
30322
|
+
var join7 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + LF + gap : two ? two.trimRight() + LF + gap : EMPTY;
|
|
30323
30323
|
var join_content = (inside, value, gap) => {
|
|
30324
30324
|
const comment = process_comments(value, PREFIX_BEFORE, gap + indent2, true);
|
|
30325
|
-
return
|
|
30325
|
+
return join7(comment, inside, gap);
|
|
30326
30326
|
};
|
|
30327
30327
|
var array_stringify = (value, gap) => {
|
|
30328
30328
|
const deeper_gap = gap + indent2;
|
|
@@ -30333,7 +30333,7 @@ var require_stringify = __commonJS({
|
|
|
30333
30333
|
if (i !== 0) {
|
|
30334
30334
|
inside += COMMA;
|
|
30335
30335
|
}
|
|
30336
|
-
const before =
|
|
30336
|
+
const before = join7(
|
|
30337
30337
|
after_comma,
|
|
30338
30338
|
process_comments(value, BEFORE(i), deeper_gap),
|
|
30339
30339
|
deeper_gap
|
|
@@ -30343,7 +30343,7 @@ var require_stringify = __commonJS({
|
|
|
30343
30343
|
inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
|
|
30344
30344
|
after_comma = process_comments(value, AFTER(i), deeper_gap);
|
|
30345
30345
|
}
|
|
30346
|
-
inside +=
|
|
30346
|
+
inside += join7(
|
|
30347
30347
|
after_comma,
|
|
30348
30348
|
process_comments(value, PREFIX_AFTER, deeper_gap),
|
|
30349
30349
|
deeper_gap
|
|
@@ -30368,7 +30368,7 @@ var require_stringify = __commonJS({
|
|
|
30368
30368
|
inside += COMMA;
|
|
30369
30369
|
}
|
|
30370
30370
|
first = false;
|
|
30371
|
-
const before =
|
|
30371
|
+
const before = join7(
|
|
30372
30372
|
after_comma,
|
|
30373
30373
|
process_comments(value, BEFORE(key), deeper_gap),
|
|
30374
30374
|
deeper_gap
|
|
@@ -30378,7 +30378,7 @@ var require_stringify = __commonJS({
|
|
|
30378
30378
|
after_comma = process_comments(value, AFTER(key), deeper_gap);
|
|
30379
30379
|
};
|
|
30380
30380
|
keys.forEach(iteratee);
|
|
30381
|
-
inside +=
|
|
30381
|
+
inside += join7(
|
|
30382
30382
|
after_comma,
|
|
30383
30383
|
process_comments(value, PREFIX_AFTER, deeper_gap),
|
|
30384
30384
|
deeper_gap
|
|
@@ -33827,8 +33827,8 @@ var init_boxen = __esm({
|
|
|
33827
33827
|
});
|
|
33828
33828
|
|
|
33829
33829
|
// src/index.ts
|
|
33830
|
-
var
|
|
33831
|
-
var
|
|
33830
|
+
var import_node_fs7 = require("fs");
|
|
33831
|
+
var import_node_path8 = require("path");
|
|
33832
33832
|
|
|
33833
33833
|
// ../node_modules/commander/esm.mjs
|
|
33834
33834
|
var import_index = __toESM(require_commander(), 1);
|
|
@@ -40806,12 +40806,111 @@ var import_path12 = __toESM(require("path"), 1);
|
|
|
40806
40806
|
// src/commands/pi-install.ts
|
|
40807
40807
|
var import_fs_extra11 = __toESM(require_lib2(), 1);
|
|
40808
40808
|
var import_path11 = __toESM(require("path"), 1);
|
|
40809
|
-
var
|
|
40809
|
+
var import_node_child_process2 = require("child_process");
|
|
40810
40810
|
var import_node_os4 = require("os");
|
|
40811
40811
|
|
|
40812
40812
|
// src/utils/pi-extensions.ts
|
|
40813
40813
|
var import_fs_extra10 = __toESM(require_lib2(), 1);
|
|
40814
40814
|
var import_path10 = __toESM(require("path"), 1);
|
|
40815
|
+
var import_node_child_process = require("child_process");
|
|
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(entry.name);
|
|
40826
|
+
}
|
|
40827
|
+
}
|
|
40828
|
+
return extDirs.sort();
|
|
40829
|
+
}
|
|
40830
|
+
async function fileSha256(filePath) {
|
|
40831
|
+
const crypto2 = await import("crypto");
|
|
40832
|
+
const content = await import_fs_extra10.default.readFile(filePath);
|
|
40833
|
+
return crypto2.createHash("sha256").update(content).digest("hex");
|
|
40834
|
+
}
|
|
40835
|
+
async function extensionHash(extDir) {
|
|
40836
|
+
const pkgPath = import_path10.default.join(extDir, "package.json");
|
|
40837
|
+
const indexPath = import_path10.default.join(extDir, "index.ts");
|
|
40838
|
+
const hashes = [];
|
|
40839
|
+
if (await import_fs_extra10.default.pathExists(pkgPath)) {
|
|
40840
|
+
hashes.push(await fileSha256(pkgPath));
|
|
40841
|
+
}
|
|
40842
|
+
if (await import_fs_extra10.default.pathExists(indexPath)) {
|
|
40843
|
+
hashes.push(await fileSha256(indexPath));
|
|
40844
|
+
}
|
|
40845
|
+
return hashes.join(":");
|
|
40846
|
+
}
|
|
40847
|
+
async function diffPiExtensions(sourceDir, targetDir) {
|
|
40848
|
+
const sourceAbs = import_path10.default.resolve(sourceDir);
|
|
40849
|
+
const targetAbs = import_path10.default.resolve(targetDir);
|
|
40850
|
+
const sourceExts = await listExtensionDirs(sourceAbs);
|
|
40851
|
+
const missing = [];
|
|
40852
|
+
const stale = [];
|
|
40853
|
+
const upToDate = [];
|
|
40854
|
+
for (const extName of sourceExts) {
|
|
40855
|
+
const srcExtPath = import_path10.default.join(sourceAbs, extName);
|
|
40856
|
+
const dstExtPath = import_path10.default.join(targetAbs, extName);
|
|
40857
|
+
if (!await import_fs_extra10.default.pathExists(dstExtPath)) {
|
|
40858
|
+
missing.push(extName);
|
|
40859
|
+
continue;
|
|
40860
|
+
}
|
|
40861
|
+
const dstPkgPath = import_path10.default.join(dstExtPath, "package.json");
|
|
40862
|
+
if (!await import_fs_extra10.default.pathExists(dstPkgPath)) {
|
|
40863
|
+
missing.push(extName);
|
|
40864
|
+
continue;
|
|
40865
|
+
}
|
|
40866
|
+
const [srcHash, dstHash] = await Promise.all([
|
|
40867
|
+
extensionHash(srcExtPath),
|
|
40868
|
+
extensionHash(dstExtPath)
|
|
40869
|
+
]);
|
|
40870
|
+
if (srcHash !== dstHash) {
|
|
40871
|
+
stale.push(extName);
|
|
40872
|
+
} else {
|
|
40873
|
+
upToDate.push(extName);
|
|
40874
|
+
}
|
|
40875
|
+
}
|
|
40876
|
+
return { missing, stale, upToDate };
|
|
40877
|
+
}
|
|
40878
|
+
function getInstalledPiPackages() {
|
|
40879
|
+
const result = (0, import_node_child_process.spawnSync)("pi", ["list"], { encoding: "utf8", stdio: "pipe" });
|
|
40880
|
+
if (result.status !== 0) return [];
|
|
40881
|
+
const output = result.stdout;
|
|
40882
|
+
const packages = [];
|
|
40883
|
+
let inUserPackages = false;
|
|
40884
|
+
for (const line of output.split("\n")) {
|
|
40885
|
+
if (line.includes("User packages:")) {
|
|
40886
|
+
inUserPackages = true;
|
|
40887
|
+
continue;
|
|
40888
|
+
}
|
|
40889
|
+
if (line.includes("Project packages:")) {
|
|
40890
|
+
inUserPackages = false;
|
|
40891
|
+
continue;
|
|
40892
|
+
}
|
|
40893
|
+
if (inUserPackages) {
|
|
40894
|
+
const match = line.match(/^\s+(npm:[\w\-/@]+)/);
|
|
40895
|
+
if (match) {
|
|
40896
|
+
packages.push(match[1]);
|
|
40897
|
+
}
|
|
40898
|
+
}
|
|
40899
|
+
}
|
|
40900
|
+
return packages.sort();
|
|
40901
|
+
}
|
|
40902
|
+
async function piPreCheck(sourceExtDir, targetExtDir, requiredPackages) {
|
|
40903
|
+
const extensions = await diffPiExtensions(sourceExtDir, targetExtDir);
|
|
40904
|
+
const installedPkgs = getInstalledPiPackages();
|
|
40905
|
+
const needed = requiredPackages.filter((pkg) => !installedPkgs.includes(pkg));
|
|
40906
|
+
return {
|
|
40907
|
+
extensions,
|
|
40908
|
+
packages: {
|
|
40909
|
+
installed: installedPkgs,
|
|
40910
|
+
needed
|
|
40911
|
+
}
|
|
40912
|
+
};
|
|
40913
|
+
}
|
|
40815
40914
|
async function syncManagedPiExtensions({
|
|
40816
40915
|
sourceDir,
|
|
40817
40916
|
targetDir,
|
|
@@ -40819,25 +40918,40 @@ async function syncManagedPiExtensions({
|
|
|
40819
40918
|
log
|
|
40820
40919
|
}) {
|
|
40821
40920
|
if (!await import_fs_extra10.default.pathExists(sourceDir)) return 0;
|
|
40921
|
+
const diff = await diffPiExtensions(sourceDir, targetDir);
|
|
40922
|
+
const toSync = [...diff.missing, ...diff.stale];
|
|
40923
|
+
if (toSync.length === 0) {
|
|
40924
|
+
if (log) {
|
|
40925
|
+
log(` \u2713 All ${diff.upToDate.length} extensions up-to-date, skipping sync`);
|
|
40926
|
+
}
|
|
40927
|
+
return diff.upToDate.length;
|
|
40928
|
+
}
|
|
40822
40929
|
if (!dryRun) {
|
|
40823
|
-
await import_fs_extra10.default.ensureDir(
|
|
40824
|
-
|
|
40930
|
+
await import_fs_extra10.default.ensureDir(targetDir);
|
|
40931
|
+
for (const extName of toSync) {
|
|
40932
|
+
const srcPath = import_path10.default.join(sourceDir, extName);
|
|
40933
|
+
const dstPath = import_path10.default.join(targetDir, extName);
|
|
40934
|
+
await import_fs_extra10.default.copy(srcPath, dstPath, { overwrite: true });
|
|
40935
|
+
if (log) {
|
|
40936
|
+
log(` ${diff.missing.includes(extName) ? "+" : "\u21BB"} ${extName}`);
|
|
40937
|
+
}
|
|
40938
|
+
}
|
|
40939
|
+
} else {
|
|
40940
|
+
if (log) {
|
|
40941
|
+
log(` [DRY RUN] would sync ${toSync.length} extensions: ${toSync.join(", ")}`);
|
|
40942
|
+
}
|
|
40825
40943
|
}
|
|
40826
|
-
const entries = await import_fs_extra10.default.readdir(sourceDir, { withFileTypes: true });
|
|
40827
|
-
const managedPackages = entries.filter((entry) => entry.isDirectory()).length;
|
|
40828
40944
|
if (log) {
|
|
40829
|
-
|
|
40830
|
-
|
|
40831
|
-
}
|
|
40832
|
-
log(` Pi will auto-discover ${managedPackages} extension package(s) from ${targetDir}`);
|
|
40945
|
+
const action = dryRun ? "would sync" : "synced";
|
|
40946
|
+
log(` ${action} ${toSync.length} extension(s), skipped ${diff.upToDate.length} up-to-date`);
|
|
40833
40947
|
}
|
|
40834
|
-
return
|
|
40948
|
+
return diff.upToDate.length + toSync.length;
|
|
40835
40949
|
}
|
|
40836
40950
|
|
|
40837
40951
|
// src/commands/pi-install.ts
|
|
40838
40952
|
var PI_AGENT_DIR = process.env.PI_AGENT_DIR || import_path11.default.join((0, import_node_os4.homedir)(), ".pi", "agent");
|
|
40839
40953
|
function isPiInstalled() {
|
|
40840
|
-
const r = (0,
|
|
40954
|
+
const r = (0, import_node_child_process2.spawnSync)("pi", ["--version"], { encoding: "utf8", stdio: "pipe" });
|
|
40841
40955
|
return r.status === 0;
|
|
40842
40956
|
}
|
|
40843
40957
|
async function runPiInstall(dryRun = false) {
|
|
@@ -40848,7 +40962,7 @@ async function runPiInstall(dryRun = false) {
|
|
|
40848
40962
|
if (!isPiInstalled()) {
|
|
40849
40963
|
console.log(kleur_default.yellow(" pi not found \u2014 installing oh-pi globally..."));
|
|
40850
40964
|
if (!dryRun) {
|
|
40851
|
-
const r = (0,
|
|
40965
|
+
const r = (0, import_node_child_process2.spawnSync)("npm", ["install", "-g", "oh-pi"], { stdio: "inherit" });
|
|
40852
40966
|
if (r.status !== 0) {
|
|
40853
40967
|
console.error(kleur_default.red(" \u2717 Failed to install oh-pi. Run: npm install -g oh-pi\n"));
|
|
40854
40968
|
return;
|
|
@@ -40858,35 +40972,46 @@ async function runPiInstall(dryRun = false) {
|
|
|
40858
40972
|
}
|
|
40859
40973
|
console.log(t.success(" \u2713 pi installed"));
|
|
40860
40974
|
} else {
|
|
40861
|
-
const v = (0,
|
|
40975
|
+
const v = (0, import_node_child_process2.spawnSync)("pi", ["--version"], { encoding: "utf8" });
|
|
40862
40976
|
console.log(t.success(` \u2713 pi ${v.stdout.trim()} already installed`));
|
|
40863
40977
|
}
|
|
40978
|
+
let packages = [];
|
|
40979
|
+
if (await import_fs_extra11.default.pathExists(schemaPath)) {
|
|
40980
|
+
const schema = await import_fs_extra11.default.readJson(schemaPath);
|
|
40981
|
+
packages = schema.packages;
|
|
40982
|
+
}
|
|
40864
40983
|
const extensionsSrc = import_path11.default.join(piConfigDir, "extensions");
|
|
40865
40984
|
const extensionsDst = import_path11.default.join(PI_AGENT_DIR, "extensions");
|
|
40985
|
+
const preCheck = await piPreCheck(extensionsSrc, extensionsDst, packages);
|
|
40986
|
+
const extTotal = preCheck.extensions.missing.length + preCheck.extensions.stale.length + preCheck.extensions.upToDate.length;
|
|
40987
|
+
const pkgTotal = packages.length;
|
|
40988
|
+
console.log(kleur_default.dim(`
|
|
40989
|
+
Pre-check:`));
|
|
40990
|
+
console.log(kleur_default.dim(` Extensions: ${preCheck.extensions.upToDate.length}/${extTotal} up-to-date, ${preCheck.extensions.stale.length} stale, ${preCheck.extensions.missing.length} missing`));
|
|
40991
|
+
console.log(kleur_default.dim(` Packages: ${preCheck.packages.installed.length}/${pkgTotal} installed, ${preCheck.packages.needed.length} needed`));
|
|
40866
40992
|
const managedPackages = await syncManagedPiExtensions({
|
|
40867
40993
|
sourceDir: extensionsSrc,
|
|
40868
40994
|
targetDir: extensionsDst,
|
|
40869
40995
|
dryRun,
|
|
40870
|
-
log: (message) => console.log(kleur_default.dim(message))
|
|
40996
|
+
log: (message) => console.log(kleur_default.dim(` ${message}`))
|
|
40871
40997
|
});
|
|
40872
|
-
if (
|
|
40873
|
-
console.log(t.
|
|
40874
|
-
|
|
40875
|
-
|
|
40876
|
-
console.log(kleur_default.dim(" No install-schema.json found, skipping packages"));
|
|
40877
|
-
return;
|
|
40878
|
-
}
|
|
40879
|
-
const schema = await import_fs_extra11.default.readJson(schemaPath);
|
|
40880
|
-
for (const pkg of schema.packages) {
|
|
40881
|
-
if (dryRun) {
|
|
40882
|
-
console.log(kleur_default.cyan(` [DRY RUN] pi install ${pkg}`));
|
|
40883
|
-
continue;
|
|
40884
|
-
}
|
|
40885
|
-
const r = (0, import_node_child_process.spawnSync)("pi", ["install", pkg], { stdio: "pipe", encoding: "utf8" });
|
|
40886
|
-
if (r.status === 0) {
|
|
40887
|
-
console.log(t.success(` ${sym.ok} ${pkg}`));
|
|
40998
|
+
if (packages.length > 0) {
|
|
40999
|
+
console.log(t.bold("\n npm Packages"));
|
|
41000
|
+
if (preCheck.packages.needed.length === 0) {
|
|
41001
|
+
console.log(kleur_default.dim(` \u2713 All ${packages.length} packages already installed`));
|
|
40888
41002
|
} else {
|
|
40889
|
-
|
|
41003
|
+
for (const pkg of preCheck.packages.needed) {
|
|
41004
|
+
if (dryRun) {
|
|
41005
|
+
console.log(kleur_default.cyan(` [DRY RUN] pi install ${pkg}`));
|
|
41006
|
+
continue;
|
|
41007
|
+
}
|
|
41008
|
+
const r = (0, import_node_child_process2.spawnSync)("pi", ["install", pkg], { stdio: "pipe", encoding: "utf8" });
|
|
41009
|
+
if (r.status === 0) {
|
|
41010
|
+
console.log(t.success(` ${sym.ok} ${pkg}`));
|
|
41011
|
+
} else {
|
|
41012
|
+
console.log(kleur_default.yellow(` \u26A0 ${pkg} \u2014 install failed (run manually: pi install ${pkg})`));
|
|
41013
|
+
}
|
|
41014
|
+
}
|
|
40890
41015
|
}
|
|
40891
41016
|
}
|
|
40892
41017
|
console.log("");
|
|
@@ -41113,8 +41238,30 @@ async function cleanStalePrePluginFiles(repoRoot, dryRun) {
|
|
|
41113
41238
|
console.log(t.success(" \u2713 No stale pre-plugin files found"));
|
|
41114
41239
|
}
|
|
41115
41240
|
}
|
|
41241
|
+
function warnIfOutdated() {
|
|
41242
|
+
try {
|
|
41243
|
+
const localPkg = JSON.parse(import_fs_extra12.default.readFileSync(import_path12.default.resolve(__dirname, "../package.json"), "utf8"));
|
|
41244
|
+
const result = (0, import_child_process3.spawnSync)("npm", ["show", "xtrm-tools", "version", "--json"], {
|
|
41245
|
+
encoding: "utf8",
|
|
41246
|
+
stdio: "pipe",
|
|
41247
|
+
timeout: 5e3
|
|
41248
|
+
});
|
|
41249
|
+
if (result.status !== 0 || !result.stdout) return;
|
|
41250
|
+
const npmVersion = JSON.parse(result.stdout.trim());
|
|
41251
|
+
const parse4 = (v) => v.split(".").map(Number);
|
|
41252
|
+
const [lMaj, lMin, lPat] = parse4(localPkg.version);
|
|
41253
|
+
const [rMaj, rMin, rPat] = parse4(npmVersion);
|
|
41254
|
+
const isNewer = rMaj > lMaj || rMaj === lMaj && rMin > lMin || rMaj === lMaj && rMin === lMin && rPat > lPat;
|
|
41255
|
+
if (isNewer) {
|
|
41256
|
+
console.log(t.warning(` \u26A0 npm has a newer version (${npmVersion} > ${localPkg.version})`));
|
|
41257
|
+
console.log(t.label(" Run: npm install -g xtrm-tools@latest"));
|
|
41258
|
+
}
|
|
41259
|
+
} catch {
|
|
41260
|
+
}
|
|
41261
|
+
}
|
|
41116
41262
|
async function installPlugin(repoRoot, dryRun) {
|
|
41117
41263
|
console.log(t.bold("\n \u2699 xtrm-tools (Claude Code plugin)"));
|
|
41264
|
+
warnIfOutdated();
|
|
41118
41265
|
if (dryRun) {
|
|
41119
41266
|
console.log(t.accent(" [DRY RUN] Would register xtrm-tools marketplace and install plugin\n"));
|
|
41120
41267
|
await cleanStalePrePluginFiles(repoRoot, true);
|
|
@@ -41132,6 +41279,23 @@ async function installPlugin(repoRoot, dryRun) {
|
|
|
41132
41279
|
console.log(t.warning(" \u21BB Restart Claude Code for the new plugin hooks to take effect"));
|
|
41133
41280
|
await cleanStalePrePluginFiles(repoRoot, dryRun);
|
|
41134
41281
|
await installOfficialClaudePlugins(false);
|
|
41282
|
+
installUserStatusLine(dryRun);
|
|
41283
|
+
}
|
|
41284
|
+
function installUserStatusLine(dryRun) {
|
|
41285
|
+
try {
|
|
41286
|
+
const scriptPath = import_path12.default.resolve(__dirname, "..", "..", "hooks", "statusline.mjs");
|
|
41287
|
+
if (!import_fs_extra12.default.existsSync(scriptPath)) return;
|
|
41288
|
+
const settingsPath = import_path12.default.join(import_os5.default.homedir(), ".claude", "settings.json");
|
|
41289
|
+
const settings = import_fs_extra12.default.existsSync(settingsPath) ? JSON.parse(import_fs_extra12.default.readFileSync(settingsPath, "utf8")) : {};
|
|
41290
|
+
if (dryRun) {
|
|
41291
|
+
console.log(t.accent(` [DRY RUN] Would write statusLine \u2192 ${scriptPath}`));
|
|
41292
|
+
return;
|
|
41293
|
+
}
|
|
41294
|
+
settings.statusLine = { type: "command", command: `node ${scriptPath}`, padding: 1 };
|
|
41295
|
+
import_fs_extra12.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
41296
|
+
console.log(t.success(` \u2713 statusLine registered in ~/.claude/settings.json`));
|
|
41297
|
+
} catch {
|
|
41298
|
+
}
|
|
41135
41299
|
}
|
|
41136
41300
|
function createInstallAllCommand() {
|
|
41137
41301
|
return new Command("all").description("[deprecated] Use xtrm install").option("--dry-run", "Preview changes without making any modifications", false).option("-y, --yes", "Skip confirmation prompts", false).option("--no-mcp", "Skip MCP server registration", false).option("--force", "Overwrite locally drifted files", false).action(async (_opts) => {
|
|
@@ -41314,18 +41478,18 @@ function createInstallCommand() {
|
|
|
41314
41478
|
}
|
|
41315
41479
|
|
|
41316
41480
|
// src/commands/claude.ts
|
|
41317
|
-
var
|
|
41481
|
+
var import_node_child_process4 = require("child_process");
|
|
41318
41482
|
|
|
41319
41483
|
// src/utils/worktree-session.ts
|
|
41320
41484
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
41321
|
-
var
|
|
41485
|
+
var import_node_child_process3 = require("child_process");
|
|
41322
41486
|
var import_node_fs4 = require("fs");
|
|
41323
41487
|
var import_node_os5 = require("os");
|
|
41324
41488
|
function randomSlug(len = 4) {
|
|
41325
41489
|
return Math.random().toString(36).slice(2, 2 + len);
|
|
41326
41490
|
}
|
|
41327
41491
|
function gitRepoRoot(cwd) {
|
|
41328
|
-
const r = (0,
|
|
41492
|
+
const r = (0, import_node_child_process3.spawnSync)("git", ["rev-parse", "--show-toplevel"], {
|
|
41329
41493
|
cwd,
|
|
41330
41494
|
stdio: "pipe",
|
|
41331
41495
|
encoding: "utf8"
|
|
@@ -41364,7 +41528,7 @@ async function launchWorktreeSession(opts) {
|
|
|
41364
41528
|
console.log(kleur_default.dim(` worktree: ${worktreePath}`));
|
|
41365
41529
|
console.log(kleur_default.dim(` branch: ${branchName}
|
|
41366
41530
|
`));
|
|
41367
|
-
const bdResult = (0,
|
|
41531
|
+
const bdResult = (0, import_node_child_process3.spawnSync)("bd", ["worktree", "create", worktreePath, "--branch", branchName], {
|
|
41368
41532
|
cwd: repoRoot,
|
|
41369
41533
|
stdio: "inherit"
|
|
41370
41534
|
});
|
|
@@ -41372,12 +41536,12 @@ async function launchWorktreeSession(opts) {
|
|
|
41372
41536
|
if (bdResult.status !== 0 && !bdResult.error) {
|
|
41373
41537
|
console.log(kleur_default.dim(" beads: no database found, creating worktree without redirect"));
|
|
41374
41538
|
}
|
|
41375
|
-
const branchExists = (0,
|
|
41539
|
+
const branchExists = (0, import_node_child_process3.spawnSync)("git", ["rev-parse", "--verify", branchName], {
|
|
41376
41540
|
cwd: repoRoot,
|
|
41377
41541
|
stdio: "pipe"
|
|
41378
41542
|
}).status === 0;
|
|
41379
41543
|
const gitArgs = branchExists ? ["worktree", "add", worktreePath, branchName] : ["worktree", "add", "-b", branchName, worktreePath];
|
|
41380
|
-
const gitResult = (0,
|
|
41544
|
+
const gitResult = (0, import_node_child_process3.spawnSync)("git", gitArgs, { cwd: repoRoot, stdio: "inherit" });
|
|
41381
41545
|
if (gitResult.status !== 0) {
|
|
41382
41546
|
console.error(kleur_default.red(`
|
|
41383
41547
|
\u2717 Failed to create worktree at ${worktreePath}
|
|
@@ -41404,7 +41568,7 @@ async function launchWorktreeSession(opts) {
|
|
|
41404
41568
|
}
|
|
41405
41569
|
const runtimeCmd = runtime === "claude" ? "claude" : "pi";
|
|
41406
41570
|
const runtimeArgs = runtime === "claude" ? ["--dangerously-skip-permissions"] : [];
|
|
41407
|
-
const launchResult = (0,
|
|
41571
|
+
const launchResult = (0, import_node_child_process3.spawnSync)(runtimeCmd, runtimeArgs, {
|
|
41408
41572
|
cwd: worktreePath,
|
|
41409
41573
|
stdio: "inherit"
|
|
41410
41574
|
});
|
|
@@ -41427,14 +41591,14 @@ function createClaudeCommand() {
|
|
|
41427
41591
|
cmd.command("status").description("Show Claude CLI version, plugin status, and hook wiring").action(async () => {
|
|
41428
41592
|
console.log(t.bold("\n Claude Code Status\n"));
|
|
41429
41593
|
try {
|
|
41430
|
-
const version3 = (0,
|
|
41594
|
+
const version3 = (0, import_node_child_process4.execSync)("claude --version", { encoding: "utf8", stdio: "pipe" }).trim();
|
|
41431
41595
|
console.log(t.success(` \u2713 claude CLI: ${version3}`));
|
|
41432
41596
|
} catch {
|
|
41433
41597
|
console.log(kleur_default.red(" \u2717 claude CLI not found"));
|
|
41434
41598
|
console.log("");
|
|
41435
41599
|
return;
|
|
41436
41600
|
}
|
|
41437
|
-
const listResult = (0,
|
|
41601
|
+
const listResult = (0, import_node_child_process4.spawnSync)("claude", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
|
|
41438
41602
|
const pluginOutput = listResult.stdout ?? "";
|
|
41439
41603
|
if (pluginOutput.includes("xtrm-tools")) {
|
|
41440
41604
|
console.log(t.success(" \u2713 xtrm-tools plugin installed"));
|
|
@@ -41442,7 +41606,7 @@ function createClaudeCommand() {
|
|
|
41442
41606
|
console.log(kleur_default.yellow(" \u26A0 xtrm-tools plugin not installed \u2014 run: xt claude install"));
|
|
41443
41607
|
}
|
|
41444
41608
|
try {
|
|
41445
|
-
(0,
|
|
41609
|
+
(0, import_node_child_process4.execSync)("bd --version", { stdio: "ignore" });
|
|
41446
41610
|
console.log(t.success(" \u2713 beads (bd) available"));
|
|
41447
41611
|
} catch {
|
|
41448
41612
|
console.log(kleur_default.dim(" \u25CB beads (bd) not installed"));
|
|
@@ -41453,13 +41617,13 @@ function createClaudeCommand() {
|
|
|
41453
41617
|
console.log(t.bold("\n Claude Code Doctor\n"));
|
|
41454
41618
|
let allOk = true;
|
|
41455
41619
|
try {
|
|
41456
|
-
(0,
|
|
41620
|
+
(0, import_node_child_process4.execSync)("claude --version", { stdio: "ignore" });
|
|
41457
41621
|
console.log(t.success(" \u2713 claude CLI available"));
|
|
41458
41622
|
} catch {
|
|
41459
41623
|
console.log(kleur_default.red(" \u2717 claude CLI not found \u2014 install Claude Code"));
|
|
41460
41624
|
allOk = false;
|
|
41461
41625
|
}
|
|
41462
|
-
const listResult = (0,
|
|
41626
|
+
const listResult = (0, import_node_child_process4.spawnSync)("claude", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
|
|
41463
41627
|
if (listResult.stdout?.includes("xtrm-tools")) {
|
|
41464
41628
|
console.log(t.success(" \u2713 xtrm-tools plugin installed"));
|
|
41465
41629
|
} else {
|
|
@@ -41467,21 +41631,21 @@ function createClaudeCommand() {
|
|
|
41467
41631
|
allOk = false;
|
|
41468
41632
|
}
|
|
41469
41633
|
try {
|
|
41470
|
-
(0,
|
|
41634
|
+
(0, import_node_child_process4.execSync)("bd --version", { stdio: "ignore" });
|
|
41471
41635
|
console.log(t.success(" \u2713 beads (bd) installed"));
|
|
41472
41636
|
} catch {
|
|
41473
41637
|
console.log(kleur_default.yellow(" \u26A0 beads not installed \u2014 run: npm install -g @beads/bd"));
|
|
41474
41638
|
allOk = false;
|
|
41475
41639
|
}
|
|
41476
41640
|
try {
|
|
41477
|
-
(0,
|
|
41641
|
+
(0, import_node_child_process4.execSync)("dolt version", { stdio: "ignore" });
|
|
41478
41642
|
console.log(t.success(" \u2713 dolt installed"));
|
|
41479
41643
|
} catch {
|
|
41480
41644
|
console.log(kleur_default.yellow(" \u26A0 dolt not installed \u2014 required for beads storage"));
|
|
41481
41645
|
allOk = false;
|
|
41482
41646
|
}
|
|
41483
41647
|
try {
|
|
41484
|
-
(0,
|
|
41648
|
+
(0, import_node_child_process4.execSync)("gitnexus --version", { stdio: "ignore" });
|
|
41485
41649
|
console.log(t.success(" \u2713 gitnexus installed"));
|
|
41486
41650
|
} catch {
|
|
41487
41651
|
console.log(kleur_default.dim(" \u25CB gitnexus not installed (optional) \u2014 npm install -g gitnexus"));
|
|
@@ -41498,7 +41662,7 @@ function createClaudeCommand() {
|
|
|
41498
41662
|
|
|
41499
41663
|
// src/commands/pi.ts
|
|
41500
41664
|
var import_path14 = __toESM(require("path"), 1);
|
|
41501
|
-
var
|
|
41665
|
+
var import_node_child_process6 = require("child_process");
|
|
41502
41666
|
var import_node_os7 = require("os");
|
|
41503
41667
|
var import_fs_extra14 = __toESM(require_lib2(), 1);
|
|
41504
41668
|
|
|
@@ -41506,7 +41670,7 @@ var import_fs_extra14 = __toESM(require_lib2(), 1);
|
|
|
41506
41670
|
var import_prompts2 = __toESM(require_prompts3(), 1);
|
|
41507
41671
|
var import_fs_extra13 = __toESM(require_lib2(), 1);
|
|
41508
41672
|
var import_path13 = __toESM(require("path"), 1);
|
|
41509
|
-
var
|
|
41673
|
+
var import_node_child_process5 = require("child_process");
|
|
41510
41674
|
var import_node_os6 = require("os");
|
|
41511
41675
|
var PI_AGENT_DIR2 = process.env.PI_AGENT_DIR || import_path13.default.join((0, import_node_os6.homedir)(), ".pi", "agent");
|
|
41512
41676
|
function fillTemplate(template, values) {
|
|
@@ -41530,69 +41694,7 @@ function readExistingPiValues(piAgentDir) {
|
|
|
41530
41694
|
return values;
|
|
41531
41695
|
}
|
|
41532
41696
|
function isPiInstalled2() {
|
|
41533
|
-
return (0,
|
|
41534
|
-
}
|
|
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 });
|
|
41538
|
-
const extDirs = [];
|
|
41539
|
-
for (const entry of entries) {
|
|
41540
|
-
if (!entry.isDirectory()) continue;
|
|
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)) {
|
|
41544
|
-
extDirs.push(entry.name);
|
|
41545
|
-
}
|
|
41546
|
-
}
|
|
41547
|
-
return extDirs.sort();
|
|
41548
|
-
}
|
|
41549
|
-
async function fileSha256(filePath) {
|
|
41550
|
-
const crypto2 = await import("crypto");
|
|
41551
|
-
const content = await import_fs_extra13.default.readFile(filePath);
|
|
41552
|
-
return crypto2.createHash("sha256").update(content).digest("hex");
|
|
41553
|
-
}
|
|
41554
|
-
async function extensionHash(extDir) {
|
|
41555
|
-
const pkgPath = import_path13.default.join(extDir, "package.json");
|
|
41556
|
-
const indexPath = import_path13.default.join(extDir, "index.ts");
|
|
41557
|
-
const hashes = [];
|
|
41558
|
-
if (await import_fs_extra13.default.pathExists(pkgPath)) {
|
|
41559
|
-
hashes.push(await fileSha256(pkgPath));
|
|
41560
|
-
}
|
|
41561
|
-
if (await import_fs_extra13.default.pathExists(indexPath)) {
|
|
41562
|
-
hashes.push(await fileSha256(indexPath));
|
|
41563
|
-
}
|
|
41564
|
-
return hashes.join(":");
|
|
41565
|
-
}
|
|
41566
|
-
async function diffPiExtensions(sourceDir, targetDir) {
|
|
41567
|
-
const sourceAbs = import_path13.default.resolve(sourceDir);
|
|
41568
|
-
const targetAbs = import_path13.default.resolve(targetDir);
|
|
41569
|
-
const sourceExts = await listExtensionDirs(sourceAbs);
|
|
41570
|
-
const missing = [];
|
|
41571
|
-
const stale = [];
|
|
41572
|
-
const upToDate = [];
|
|
41573
|
-
for (const extName of sourceExts) {
|
|
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)) {
|
|
41577
|
-
missing.push(extName);
|
|
41578
|
-
continue;
|
|
41579
|
-
}
|
|
41580
|
-
const dstPkgPath = import_path13.default.join(dstExtPath, "package.json");
|
|
41581
|
-
if (!await import_fs_extra13.default.pathExists(dstPkgPath)) {
|
|
41582
|
-
missing.push(extName);
|
|
41583
|
-
continue;
|
|
41584
|
-
}
|
|
41585
|
-
const [srcHash, dstHash] = await Promise.all([
|
|
41586
|
-
extensionHash(srcExtPath),
|
|
41587
|
-
extensionHash(dstExtPath)
|
|
41588
|
-
]);
|
|
41589
|
-
if (srcHash !== dstHash) {
|
|
41590
|
-
stale.push(extName);
|
|
41591
|
-
} else {
|
|
41592
|
-
upToDate.push(extName);
|
|
41593
|
-
}
|
|
41594
|
-
}
|
|
41595
|
-
return { missing, stale, upToDate };
|
|
41697
|
+
return (0, import_node_child_process5.spawnSync)("pi", ["--version"], { encoding: "utf8" }).status === 0;
|
|
41596
41698
|
}
|
|
41597
41699
|
function printPiCheckSummary(diff) {
|
|
41598
41700
|
const totalDiff = diff.missing.length + diff.stale.length;
|
|
@@ -41632,14 +41734,14 @@ function createInstallPiCommand() {
|
|
|
41632
41734
|
console.log(t.bold("\n Pi Coding Agent Setup\n"));
|
|
41633
41735
|
if (!isPiInstalled2()) {
|
|
41634
41736
|
console.log(kleur_default.yellow(" pi not found \u2014 installing oh-pi globally...\n"));
|
|
41635
|
-
const r = (0,
|
|
41737
|
+
const r = (0, import_node_child_process5.spawnSync)("npm", ["install", "-g", "oh-pi"], { stdio: "inherit" });
|
|
41636
41738
|
if (r.status !== 0) {
|
|
41637
41739
|
console.error(kleur_default.red("\n Failed to install oh-pi. Run: npm install -g oh-pi\n"));
|
|
41638
41740
|
process.exit(1);
|
|
41639
41741
|
}
|
|
41640
41742
|
console.log(t.success(" pi installed\n"));
|
|
41641
41743
|
} else {
|
|
41642
|
-
const v = (0,
|
|
41744
|
+
const v = (0, import_node_child_process5.spawnSync)("pi", ["--version"], { encoding: "utf8" });
|
|
41643
41745
|
console.log(t.success(` pi ${v.stdout.trim()} already installed
|
|
41644
41746
|
`));
|
|
41645
41747
|
}
|
|
@@ -41675,9 +41777,17 @@ function createInstallPiCommand() {
|
|
|
41675
41777
|
await import_fs_extra13.default.writeFile(destPath, fillTemplate(raw, values), "utf8");
|
|
41676
41778
|
console.log(t.success(` ${sym.ok} ${name}`));
|
|
41677
41779
|
}
|
|
41780
|
+
const extensionsSrc = import_path13.default.join(piConfigDir, "extensions");
|
|
41781
|
+
const extensionsDst = import_path13.default.join(PI_AGENT_DIR2, "extensions");
|
|
41782
|
+
const preCheck = await piPreCheck(extensionsSrc, extensionsDst, schema.packages);
|
|
41783
|
+
const extTotal = preCheck.extensions.missing.length + preCheck.extensions.stale.length + preCheck.extensions.upToDate.length;
|
|
41784
|
+
console.log(kleur_default.dim(`
|
|
41785
|
+
Pre-check:`));
|
|
41786
|
+
console.log(kleur_default.dim(` Extensions: ${preCheck.extensions.upToDate.length}/${extTotal} up-to-date, ${preCheck.extensions.stale.length} stale, ${preCheck.extensions.missing.length} missing`));
|
|
41787
|
+
console.log(kleur_default.dim(` Packages: ${preCheck.packages.installed.length}/${schema.packages.length} installed, ${preCheck.packages.needed.length} needed`));
|
|
41678
41788
|
const managedPackages = await syncManagedPiExtensions({
|
|
41679
|
-
sourceDir:
|
|
41680
|
-
targetDir:
|
|
41789
|
+
sourceDir: extensionsSrc,
|
|
41790
|
+
targetDir: extensionsDst,
|
|
41681
41791
|
dryRun: false,
|
|
41682
41792
|
log: (message) => console.log(kleur_default.dim(` ${message}`))
|
|
41683
41793
|
});
|
|
@@ -41685,10 +41795,14 @@ function createInstallPiCommand() {
|
|
|
41685
41795
|
console.log(t.success(` ${sym.ok} extensions/ (${managedPackages} packages)`));
|
|
41686
41796
|
}
|
|
41687
41797
|
console.log(t.bold("\n npm Packages\n"));
|
|
41688
|
-
|
|
41689
|
-
|
|
41690
|
-
|
|
41691
|
-
|
|
41798
|
+
if (preCheck.packages.needed.length === 0) {
|
|
41799
|
+
console.log(kleur_default.dim(` \u2713 All ${schema.packages.length} packages already installed`));
|
|
41800
|
+
} else {
|
|
41801
|
+
for (const pkg of preCheck.packages.needed) {
|
|
41802
|
+
const r = (0, import_node_child_process5.spawnSync)("pi", ["install", pkg], { stdio: "inherit" });
|
|
41803
|
+
if (r.status === 0) console.log(t.success(` ${sym.ok} ${pkg}`));
|
|
41804
|
+
else console.log(kleur_default.yellow(` ${pkg} \u2014 failed, run manually: pi install ${pkg}`));
|
|
41805
|
+
}
|
|
41692
41806
|
}
|
|
41693
41807
|
console.log(t.bold("\n OAuth (manual steps)\n"));
|
|
41694
41808
|
for (const provider of schema.oauth_providers) {
|
|
@@ -41714,7 +41828,7 @@ function createPiCommand() {
|
|
|
41714
41828
|
cmd.addCommand(piSetup);
|
|
41715
41829
|
cmd.command("status").description("Check Pi version and extension deployment drift").action(async () => {
|
|
41716
41830
|
console.log(t.bold("\n Pi Runtime Status\n"));
|
|
41717
|
-
const piResult = (0,
|
|
41831
|
+
const piResult = (0, import_node_child_process6.spawnSync)("pi", ["--version"], { encoding: "utf8", stdio: "pipe" });
|
|
41718
41832
|
if (piResult.status === 0) {
|
|
41719
41833
|
console.log(t.success(` \u2713 pi ${piResult.stdout.trim()} installed`));
|
|
41720
41834
|
} else {
|
|
@@ -41738,7 +41852,7 @@ function createPiCommand() {
|
|
|
41738
41852
|
cmd.command("doctor").description("Diagnostic checks: pi installed, extensions deployed, packages present").action(async () => {
|
|
41739
41853
|
console.log(t.bold("\n Pi Doctor\n"));
|
|
41740
41854
|
let allOk = true;
|
|
41741
|
-
const piResult = (0,
|
|
41855
|
+
const piResult = (0, import_node_child_process6.spawnSync)("pi", ["--version"], { encoding: "utf8", stdio: "pipe" });
|
|
41742
41856
|
if (piResult.status === 0) {
|
|
41743
41857
|
console.log(t.success(` \u2713 pi ${piResult.stdout.trim()} installed`));
|
|
41744
41858
|
} else {
|
|
@@ -41759,9 +41873,9 @@ function createPiCommand() {
|
|
|
41759
41873
|
const schemaPath = import_path14.default.join(piConfigDir, "install-schema.json");
|
|
41760
41874
|
if (await import_fs_extra14.default.pathExists(schemaPath)) {
|
|
41761
41875
|
try {
|
|
41762
|
-
(0,
|
|
41876
|
+
(0, import_node_child_process6.execSync)("pi --version", { stdio: "ignore" });
|
|
41763
41877
|
const schema = await import_fs_extra14.default.readJson(schemaPath);
|
|
41764
|
-
const listResult = (0,
|
|
41878
|
+
const listResult = (0, import_node_child_process6.spawnSync)("pi", ["list"], { encoding: "utf8", stdio: "pipe" });
|
|
41765
41879
|
const installed = listResult.stdout ?? "";
|
|
41766
41880
|
const missing = schema.packages.filter((p) => !installed.includes(p.replace("npm:", "")));
|
|
41767
41881
|
if (missing.length === 0) {
|
|
@@ -56389,13 +56503,13 @@ function createCleanCommand() {
|
|
|
56389
56503
|
|
|
56390
56504
|
// src/commands/end.ts
|
|
56391
56505
|
var import_prompts4 = __toESM(require_prompts3(), 1);
|
|
56392
|
-
var
|
|
56506
|
+
var import_node_child_process7 = require("child_process");
|
|
56393
56507
|
function git(args, cwd) {
|
|
56394
|
-
const r = (0,
|
|
56508
|
+
const r = (0, import_node_child_process7.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
56395
56509
|
return { ok: r.status === 0, out: (r.stdout ?? "").trim(), err: (r.stderr ?? "").trim() };
|
|
56396
56510
|
}
|
|
56397
56511
|
function bd(args, cwd) {
|
|
56398
|
-
const r = (0,
|
|
56512
|
+
const r = (0, import_node_child_process7.spawnSync)("bd", args, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
56399
56513
|
return { ok: r.status === 0, out: (r.stdout ?? "").trim() };
|
|
56400
56514
|
}
|
|
56401
56515
|
function extractIssueIds(commitLog) {
|
|
@@ -56442,7 +56556,7 @@ function buildPrBody(issues, commitLog, diffStat, branch) {
|
|
|
56442
56556
|
return lines.join("\n");
|
|
56443
56557
|
}
|
|
56444
56558
|
function createEndCommand() {
|
|
56445
|
-
return new Command("end").description("Close session: rebase, push, open PR, link beads issues, clean up worktree").option("--draft", "Open PR as draft", false).option("--keep", "Keep worktree after PR creation (default: prompt)", false).option("-y, --yes", "Skip confirmation prompts", false).action(async (opts) => {
|
|
56559
|
+
return new Command("end").description("Close session: rebase, push, open PR, link beads issues, clean up worktree").option("--draft", "Open PR as draft", false).option("--keep", "Keep worktree after PR creation (default: prompt)", false).option("-y, --yes", "Skip confirmation prompts", false).option("--dry-run", "Preview PR title, body, and linked issues without pushing or creating PR", false).action(async (opts) => {
|
|
56446
56560
|
const cwd = process.cwd();
|
|
56447
56561
|
const branchResult = git(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
56448
56562
|
const branch = branchResult.out;
|
|
@@ -56466,7 +56580,14 @@ function createEndCommand() {
|
|
|
56466
56580
|
console.log(t.bold(`
|
|
56467
56581
|
xt end \u2014 closing session on ${branch}
|
|
56468
56582
|
`));
|
|
56469
|
-
|
|
56583
|
+
let defaultBranch = "main";
|
|
56584
|
+
const symRef = git(["symbolic-ref", "refs/remotes/origin/HEAD", "--short"], cwd);
|
|
56585
|
+
if (symRef.ok && symRef.out) {
|
|
56586
|
+
defaultBranch = symRef.out.replace("origin/", "");
|
|
56587
|
+
} else if (git(["rev-parse", "--verify", "origin/master"], cwd).ok) {
|
|
56588
|
+
defaultBranch = "master";
|
|
56589
|
+
}
|
|
56590
|
+
const logResult = git(["log", `origin/${defaultBranch}..HEAD`, "--oneline"], cwd);
|
|
56470
56591
|
const issueIds = extractIssueIds(logResult.out);
|
|
56471
56592
|
const issues = [];
|
|
56472
56593
|
for (const id of issueIds) {
|
|
@@ -56490,10 +56611,28 @@ function createEndCommand() {
|
|
|
56490
56611
|
} else {
|
|
56491
56612
|
console.log(kleur_default.dim(" \u25CB No beads issues found in commit log"));
|
|
56492
56613
|
}
|
|
56493
|
-
|
|
56494
|
-
|
|
56495
|
-
|
|
56496
|
-
|
|
56614
|
+
if (opts.dryRun) {
|
|
56615
|
+
const fullLog2 = git(["log", `origin/${defaultBranch}..HEAD`, "--oneline"], cwd).out;
|
|
56616
|
+
const diffStat2 = git(["diff", `origin/${defaultBranch}`, "--stat"], cwd).out;
|
|
56617
|
+
const prTitle2 = buildPrTitle(issues);
|
|
56618
|
+
const prBody2 = buildPrBody(issues, fullLog2, diffStat2, branch);
|
|
56619
|
+
console.log(t.bold("\n [DRY RUN] PR preview\n"));
|
|
56620
|
+
console.log(` ${kleur_default.bold("Title:")} ${prTitle2}`);
|
|
56621
|
+
if (issues.length > 0) {
|
|
56622
|
+
console.log(` ${kleur_default.bold("Issues:")} ${issueIds.join(", ")}`);
|
|
56623
|
+
}
|
|
56624
|
+
console.log(`
|
|
56625
|
+
${kleur_default.bold("Body:")}`);
|
|
56626
|
+
for (const line of prBody2.split("\n")) {
|
|
56627
|
+
console.log(` ${kleur_default.dim(line)}`);
|
|
56628
|
+
}
|
|
56629
|
+
console.log(t.accent("\n [DRY RUN] No changes made \u2014 re-run without --dry-run to push and create PR\n"));
|
|
56630
|
+
return;
|
|
56631
|
+
}
|
|
56632
|
+
console.log(kleur_default.dim(` Fetching origin/${defaultBranch}...`));
|
|
56633
|
+
git(["fetch", "origin", defaultBranch], cwd);
|
|
56634
|
+
console.log(kleur_default.dim(` Rebasing onto origin/${defaultBranch}...`));
|
|
56635
|
+
const rebaseResult = git(["rebase", `origin/${defaultBranch}`], cwd);
|
|
56497
56636
|
if (!rebaseResult.ok) {
|
|
56498
56637
|
const conflicts = git(["diff", "--name-only", "--diff-filter=U"], cwd).out;
|
|
56499
56638
|
console.error(kleur_default.red("\n \u2717 Rebase conflicts detected:\n"));
|
|
@@ -56505,7 +56644,7 @@ function createEndCommand() {
|
|
|
56505
56644
|
));
|
|
56506
56645
|
process.exit(1);
|
|
56507
56646
|
}
|
|
56508
|
-
console.log(t.success(
|
|
56647
|
+
console.log(t.success(` \u2713 Rebased onto origin/${defaultBranch}`));
|
|
56509
56648
|
console.log(kleur_default.dim(" Pushing branch..."));
|
|
56510
56649
|
const pushResult = git(["push", "origin", branch, "--force-with-lease"], cwd);
|
|
56511
56650
|
if (!pushResult.ok) {
|
|
@@ -56516,14 +56655,14 @@ function createEndCommand() {
|
|
|
56516
56655
|
process.exit(1);
|
|
56517
56656
|
}
|
|
56518
56657
|
console.log(t.success(` \u2713 Pushed ${branch}`));
|
|
56519
|
-
const fullLog = git(["log",
|
|
56520
|
-
const diffStat = git(["diff",
|
|
56658
|
+
const fullLog = git(["log", `origin/${defaultBranch}..HEAD`, "--oneline"], cwd).out;
|
|
56659
|
+
const diffStat = git(["diff", `origin/${defaultBranch}`, "--stat"], cwd).out;
|
|
56521
56660
|
const prTitle = buildPrTitle(issues);
|
|
56522
56661
|
const prBody = buildPrBody(issues, fullLog, diffStat, branch);
|
|
56523
56662
|
console.log(kleur_default.dim(" Creating PR..."));
|
|
56524
56663
|
const prArgs = ["pr", "create", "--title", prTitle, "--body", prBody];
|
|
56525
56664
|
if (opts.draft) prArgs.push("--draft");
|
|
56526
|
-
const prResult = (0,
|
|
56665
|
+
const prResult = (0, import_node_child_process7.spawnSync)("gh", prArgs, { cwd, encoding: "utf8", stdio: "pipe" });
|
|
56527
56666
|
if (prResult.status !== 0) {
|
|
56528
56667
|
console.error(kleur_default.red(`
|
|
56529
56668
|
\u2717 PR creation failed:
|
|
@@ -56553,7 +56692,7 @@ function createEndCommand() {
|
|
|
56553
56692
|
if (doRemove) {
|
|
56554
56693
|
try {
|
|
56555
56694
|
const repoRoot = git(["rev-parse", "--show-toplevel"], cwd).out;
|
|
56556
|
-
const removeResult = (0,
|
|
56695
|
+
const removeResult = (0, import_node_child_process7.spawnSync)(
|
|
56557
56696
|
"git",
|
|
56558
56697
|
["worktree", "remove", cwd, "--force"],
|
|
56559
56698
|
{ cwd: repoRoot, encoding: "utf8", stdio: "pipe" }
|
|
@@ -56577,9 +56716,11 @@ function createEndCommand() {
|
|
|
56577
56716
|
|
|
56578
56717
|
// src/commands/worktree.ts
|
|
56579
56718
|
var import_prompts5 = __toESM(require_prompts3(), 1);
|
|
56580
|
-
var
|
|
56719
|
+
var import_node_child_process8 = require("child_process");
|
|
56720
|
+
var import_node_fs5 = require("fs");
|
|
56721
|
+
var import_node_path6 = require("path");
|
|
56581
56722
|
function listXtWorktrees(repoRoot) {
|
|
56582
|
-
const r = (0,
|
|
56723
|
+
const r = (0, import_node_child_process8.spawnSync)("git", ["worktree", "list", "--porcelain"], {
|
|
56583
56724
|
cwd: repoRoot,
|
|
56584
56725
|
encoding: "utf8",
|
|
56585
56726
|
stdio: "pipe"
|
|
@@ -56608,7 +56749,7 @@ function listXtWorktrees(repoRoot) {
|
|
|
56608
56749
|
}
|
|
56609
56750
|
function isMergedIntoMain(branch, repoRoot) {
|
|
56610
56751
|
const branchShort = branch.replace("refs/heads/", "");
|
|
56611
|
-
const r = (0,
|
|
56752
|
+
const r = (0, import_node_child_process8.spawnSync)("git", ["branch", "--merged", "origin/main", "--list", branchShort], {
|
|
56612
56753
|
cwd: repoRoot,
|
|
56613
56754
|
encoding: "utf8",
|
|
56614
56755
|
stdio: "pipe"
|
|
@@ -56616,7 +56757,7 @@ function isMergedIntoMain(branch, repoRoot) {
|
|
|
56616
56757
|
return (r.stdout ?? "").includes(branchShort);
|
|
56617
56758
|
}
|
|
56618
56759
|
function getRepoRoot(cwd) {
|
|
56619
|
-
const r = (0,
|
|
56760
|
+
const r = (0, import_node_child_process8.spawnSync)("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf8", stdio: "pipe" });
|
|
56620
56761
|
return r.ok ? r.stdout.trim() : cwd;
|
|
56621
56762
|
}
|
|
56622
56763
|
function createWorktreeCommand() {
|
|
@@ -56670,13 +56811,14 @@ function createWorktreeCommand() {
|
|
|
56670
56811
|
return;
|
|
56671
56812
|
}
|
|
56672
56813
|
for (const wt of merged) {
|
|
56673
|
-
const r = (0,
|
|
56814
|
+
const r = (0, import_node_child_process8.spawnSync)("git", ["worktree", "remove", wt.path, "--force"], {
|
|
56674
56815
|
cwd: repoRoot,
|
|
56675
56816
|
encoding: "utf8",
|
|
56676
56817
|
stdio: "pipe"
|
|
56677
56818
|
});
|
|
56678
56819
|
if (r.status === 0) {
|
|
56679
56820
|
console.log(t.success(` \u2713 Removed ${wt.path}`));
|
|
56821
|
+
clearStatuslineClaim(repoRoot);
|
|
56680
56822
|
} else {
|
|
56681
56823
|
console.log(kleur_default.yellow(` \u26A0 Could not remove ${wt.path}: ${(r.stderr ?? "").trim()}`));
|
|
56682
56824
|
}
|
|
@@ -56710,12 +56852,13 @@ function createWorktreeCommand() {
|
|
|
56710
56852
|
console.log(kleur_default.dim(" Cancelled\n"));
|
|
56711
56853
|
return;
|
|
56712
56854
|
}
|
|
56713
|
-
const r = (0,
|
|
56855
|
+
const r = (0, import_node_child_process8.spawnSync)("git", ["worktree", "remove", target.path, "--force"], {
|
|
56714
56856
|
cwd: repoRoot,
|
|
56715
56857
|
encoding: "utf8",
|
|
56716
56858
|
stdio: "pipe"
|
|
56717
56859
|
});
|
|
56718
56860
|
if (r.status === 0) {
|
|
56861
|
+
clearStatuslineClaim(repoRoot);
|
|
56719
56862
|
console.log(t.success(`
|
|
56720
56863
|
\u2713 Removed ${target.path}
|
|
56721
56864
|
`));
|
|
@@ -56728,6 +56871,13 @@ function createWorktreeCommand() {
|
|
|
56728
56871
|
});
|
|
56729
56872
|
return cmd;
|
|
56730
56873
|
}
|
|
56874
|
+
function clearStatuslineClaim(repoRoot) {
|
|
56875
|
+
try {
|
|
56876
|
+
const claimFile = (0, import_node_path6.join)(repoRoot, ".xtrm", "statusline-claim");
|
|
56877
|
+
if ((0, import_node_fs5.existsSync)(claimFile)) (0, import_node_fs5.unlinkSync)(claimFile);
|
|
56878
|
+
} catch {
|
|
56879
|
+
}
|
|
56880
|
+
}
|
|
56731
56881
|
|
|
56732
56882
|
// src/commands/docs.ts
|
|
56733
56883
|
var import_fs_extra19 = __toESM(require_lib2(), 1);
|
|
@@ -56858,9 +57008,9 @@ function createDocsCommand() {
|
|
|
56858
57008
|
}
|
|
56859
57009
|
|
|
56860
57010
|
// src/commands/debug.ts
|
|
56861
|
-
var
|
|
56862
|
-
var
|
|
56863
|
-
var
|
|
57011
|
+
var import_node_child_process9 = require("child_process");
|
|
57012
|
+
var import_node_fs6 = require("fs");
|
|
57013
|
+
var import_node_path7 = require("path");
|
|
56864
57014
|
var KIND_LABELS = {
|
|
56865
57015
|
"session.start": { label: "SESS+", color: kleur_default.green },
|
|
56866
57016
|
"session.end": { label: "SESS-", color: kleur_default.white },
|
|
@@ -56960,14 +57110,14 @@ function buildDetail(event) {
|
|
|
56960
57110
|
}
|
|
56961
57111
|
if (event.kind === "tool.call") {
|
|
56962
57112
|
if (d?.cmd) parts.push(kleur_default.dim(d.cmd.slice(0, 72)));
|
|
56963
|
-
if (d?.file) parts.push(kleur_default.dim((0,
|
|
57113
|
+
if (d?.file) parts.push(kleur_default.dim((0, import_node_path7.basename)(d.file)));
|
|
56964
57114
|
if (d?.pattern) parts.push(kleur_default.dim(`/${d.pattern}/`));
|
|
56965
57115
|
if (d?.url) parts.push(kleur_default.dim(d.url.slice(0, 72)));
|
|
56966
57116
|
if (d?.query) parts.push(kleur_default.dim(d.query.slice(0, 72)));
|
|
56967
57117
|
if (d?.prompt) parts.push(kleur_default.dim(d.prompt.slice(0, 72)));
|
|
56968
57118
|
} else {
|
|
56969
57119
|
if (event.issue_id) parts.push(kleur_default.yellow(event.issue_id));
|
|
56970
|
-
if (d?.file) parts.push(kleur_default.dim((0,
|
|
57120
|
+
if (d?.file) parts.push(kleur_default.dim((0, import_node_path7.basename)(d.file)));
|
|
56971
57121
|
if (d?.reason_code) parts.push(kleur_default.dim(`[${d.reason_code}]`));
|
|
56972
57122
|
if (event.worktree) parts.push(kleur_default.dim(`wt:${event.worktree}`));
|
|
56973
57123
|
}
|
|
@@ -56984,8 +57134,8 @@ function formatLine(event, colorMap) {
|
|
|
56984
57134
|
function findDbPath(cwd) {
|
|
56985
57135
|
let dir = cwd;
|
|
56986
57136
|
for (let i = 0; i < 10; i++) {
|
|
56987
|
-
if ((0,
|
|
56988
|
-
const parent = (0,
|
|
57137
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path7.join)(dir, ".beads"))) return (0, import_node_path7.join)(dir, ".xtrm", "debug.db");
|
|
57138
|
+
const parent = (0, import_node_path7.join)(dir, "..");
|
|
56989
57139
|
if (parent === dir) break;
|
|
56990
57140
|
dir = parent;
|
|
56991
57141
|
}
|
|
@@ -57006,7 +57156,7 @@ function buildWhere(opts, base) {
|
|
|
57006
57156
|
}
|
|
57007
57157
|
function queryEvents(dbPath, where, limit) {
|
|
57008
57158
|
const sql = `SELECT id,ts,session_id,runtime,worktree,kind,tool_name,outcome,issue_id,duration_ms,data FROM events${where ? ` WHERE ${where}` : ""} ORDER BY id ASC LIMIT ${limit}`;
|
|
57009
|
-
const result = (0,
|
|
57159
|
+
const result = (0, import_node_child_process9.spawnSync)("sqlite3", [dbPath, "-json", sql], {
|
|
57010
57160
|
stdio: ["pipe", "pipe", "pipe"],
|
|
57011
57161
|
encoding: "utf8",
|
|
57012
57162
|
timeout: 5e3
|
|
@@ -57046,7 +57196,7 @@ function createDebugCommand() {
|
|
|
57046
57196
|
return new Command("debug").description("Watch xtrm events: tool calls, gate decisions, bd lifecycle").option("-f, --follow", "Follow new events (default)", false).option("--all", "Show full history and exit", false).option("--session <id>", "Filter by session ID (prefix match)").option("--type <domain>", "Filter by domain: tool | gate | bd | session").option("--json", "Output raw JSON lines", false).action((opts) => {
|
|
57047
57197
|
const cwd = process.cwd();
|
|
57048
57198
|
const dbPath = findDbPath(cwd);
|
|
57049
|
-
if (!dbPath || !(0,
|
|
57199
|
+
if (!dbPath || !(0, import_node_fs6.existsSync)(dbPath)) return;
|
|
57050
57200
|
if (opts.all) {
|
|
57051
57201
|
const events = queryEvents(dbPath, buildWhere(opts, ""), 1e3);
|
|
57052
57202
|
const colorMap = buildColorMap(events);
|
|
@@ -57231,7 +57381,7 @@ async function printBanner(version3) {
|
|
|
57231
57381
|
// src/index.ts
|
|
57232
57382
|
var version2 = "0.0.0";
|
|
57233
57383
|
try {
|
|
57234
|
-
version2 = JSON.parse((0,
|
|
57384
|
+
version2 = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path8.resolve)(__dirname, "../package.json"), "utf8")).version;
|
|
57235
57385
|
} catch {
|
|
57236
57386
|
}
|
|
57237
57387
|
var program2 = new Command();
|