xtrm-tools 2.0.0 → 2.0.2
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/CHANGELOG.md +8 -0
- package/README.md +13 -14
- package/cli/dist/index.cjs +78 -29
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
12
12
|
### Added
|
|
13
13
|
|
|
14
14
|
- **`AGENTS.md` — bd (beads) issue tracking section**: Comprehensive reference for the `bd` CLI covering session protocol, issue creation, dependency management, search/view commands, advanced features (`agent`, `gate`, `mol`, `audit`), and a bd vs TodoWrite decision table.
|
|
15
|
+
- **`xtrm install project all` / `xtrm install project '*'`**: Non-interactive install of every available project skill into the current repository.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **Claude-only target detection**: `xtrm install all` now enumerates Claude Code targets only, instead of surfacing stale Gemini/Qwen/Agents paths.
|
|
20
|
+
- **Project-skill install-all coverage**: Added regression tests to verify merged hook counts and copied assets across all shipped project skills.
|
|
15
21
|
|
|
16
22
|
### Roadmap
|
|
17
23
|
|
|
@@ -38,6 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
38
44
|
#### Installation Commands
|
|
39
45
|
- **`xtrm install`**: Global installation (replaces `sync`)
|
|
40
46
|
- **`xtrm install all` / `xtrm install '*'`**: Non-interactive global install across all known targets
|
|
47
|
+
- **`~/.agents/skills`**: Skills-only target added so the installed `skills/` tree is available without touching hooks/config
|
|
48
|
+
- **`xtrm install project all` / `xtrm install project '*'`**: Install every project-specific skill package into the current repository
|
|
41
49
|
- **`xtrm install project <tool-name>`**: Install project-specific skill package
|
|
42
50
|
- **`xtrm install project list`**: List available project skills with descriptions
|
|
43
51
|
|
package/README.md
CHANGED
|
@@ -221,7 +221,7 @@ Task intake and service routing for Docker service projects.
|
|
|
221
221
|
| Skill | Description | Hook Type |
|
|
222
222
|
|-------|-------------|-----------|
|
|
223
223
|
| `service-skills-set` | Docker service expertise — gives Claude persistent knowledge about your services | SessionStart, PreToolUse, PostToolUse |
|
|
224
|
-
| `tdd-guard` | Enforce Test-Driven Development — blocks implementation until failing tests exist | PreToolUse, UserPromptSubmit |
|
|
224
|
+
| `tdd-guard` | Enforce Test-Driven Development — blocks implementation until failing tests exist | SessionStart, PreToolUse, UserPromptSubmit |
|
|
225
225
|
| `ts-quality-gate` | TypeScript/ESLint/Prettier quality gate — runs on every edit, auto-fixes issues | PostToolUse |
|
|
226
226
|
| `py-quality-gate` | Python ruff/mypy quality gate — linting, formatting, and type checking | PostToolUse |
|
|
227
227
|
| `main-guard` | Git branch protection — blocks direct edits to main/master branches | PreToolUse |
|
|
@@ -239,6 +239,8 @@ xtrm install project tdd-guard # TDD enforcement
|
|
|
239
239
|
xtrm install project ts-quality-gate # TypeScript quality
|
|
240
240
|
xtrm install project py-quality-gate # Python quality
|
|
241
241
|
xtrm install project main-guard # Git branch protection
|
|
242
|
+
xtrm install project all # Install every available project skill
|
|
243
|
+
xtrm install project '*' # Same as above; quote to avoid shell expansion
|
|
242
244
|
```
|
|
243
245
|
|
|
244
246
|
**Note:** Project skills install Claude hooks and skills into your project's `.claude/` directory. Some skills require additional manual setup (e.g., installing npm packages or Python dependencies). Always read the documentation at `.claude/docs/<skill>-readme.md` after installation.
|
|
@@ -315,10 +317,10 @@ The main command. Detects your agent environments, calculates what's changed, an
|
|
|
315
317
|
|
|
316
318
|
```bash
|
|
317
319
|
xtrm install # interactive — prompts for targets and confirmation
|
|
318
|
-
xtrm install all # install to all
|
|
320
|
+
xtrm install all # install to all Claude Code targets without target prompt
|
|
319
321
|
xtrm install '*' # same as above; quote * to avoid shell expansion
|
|
320
322
|
xtrm install --dry-run # preview what WOULD change, write nothing
|
|
321
|
-
xtrm install all --dry-run -y # non-interactive preview across all targets
|
|
323
|
+
xtrm install all --dry-run -y # non-interactive preview across all Claude targets
|
|
322
324
|
xtrm install -y # skip confirmation prompts (CI-friendly)
|
|
323
325
|
xtrm install --prune # also remove system items no longer in the repo
|
|
324
326
|
xtrm install --backport # reverse direction: copy drifted local edits → repo
|
|
@@ -330,7 +332,7 @@ xtrm install --backport # reverse direction: copy drifted local edits → re
|
|
|
330
332
|
- **boxen summary card**: Completion summary with green/yellow border based on drift
|
|
331
333
|
- **Themed output**: Semantic colors (success, error, warning, muted, accent) via `theme.ts`
|
|
332
334
|
- **Interactive consent**: Multiselect for MCP servers (space to toggle, all pre-selected)
|
|
333
|
-
- **Auto-detection**: Scans `~/.claude`,
|
|
335
|
+
- **Auto-detection**: Scans Claude Code targets automatically (`~/.claude`, `%APPDATA%/Claude` on Windows) plus the `.agents/skills` cache for skills-only sync
|
|
334
336
|
- **Inline sync**: `status` command offers to apply sync immediately after showing changes
|
|
335
337
|
- **Single confirmation**: See full plan across all targets, confirm once
|
|
336
338
|
- **Safety guards**: Prune mode aborts on read failures; clean errors (no stack traces)
|
|
@@ -339,15 +341,12 @@ xtrm install --backport # reverse direction: copy drifted local edits → re
|
|
|
339
341
|
|
|
340
342
|
**What it syncs per target environment:**
|
|
341
343
|
|
|
342
|
-
| Item | Claude
|
|
343
|
-
| --------------- | -------------------- |
|
|
344
|
-
| `skills/` | ✅ copy/symlink | ✅
|
|
345
|
-
| `hooks/` | ✅ copy/symlink |
|
|
346
|
-
| `settings.json` | ✅ safe merge |
|
|
347
|
-
| MCP servers | `mcp add` CLI |
|
|
348
|
-
| Slash commands | auto-generated | `.toml` files | `.toml` files | ❌ skipped |
|
|
349
|
-
|
|
350
|
-
**New in v1.7.0**: `~/.agents/skills` is now a first-class sync target for skills-only sync (no hooks/config/MCP).
|
|
344
|
+
| Item | Claude Code (full) | `~/.agents/skills` (skills-only) |
|
|
345
|
+
| --------------- | -------------------- | --------------------------------- |
|
|
346
|
+
| `skills/` | ✅ copy/symlink | ✅ direct copy |
|
|
347
|
+
| `hooks/` | ✅ copy/symlink | ❌ skipped |
|
|
348
|
+
| `settings.json` | ✅ safe merge | ❌ skipped |
|
|
349
|
+
| MCP servers | `mcp add` CLI | ❌ skipped |
|
|
351
350
|
|
|
352
351
|
**Diff categories shown before sync:**
|
|
353
352
|
|
|
@@ -374,7 +373,7 @@ xtrm status --json # machine-readable output
|
|
|
374
373
|
```
|
|
375
374
|
|
|
376
375
|
**Output includes (v1.7.0+)**:
|
|
377
|
-
- Auto-detected environments:
|
|
376
|
+
- Auto-detected environments: Claude Code targets and the `~/.agents/skills` cache
|
|
378
377
|
- cli-table3 formatted table with per-target change breakdown
|
|
379
378
|
- Last synced time (relative: "3 hours ago")
|
|
380
379
|
- Item counts from manifest (skills, hooks, config)
|
package/cli/dist/index.cjs
CHANGED
|
@@ -37026,22 +37026,25 @@ var Conf = class {
|
|
|
37026
37026
|
|
|
37027
37027
|
// src/core/context.ts
|
|
37028
37028
|
var import_prompts = __toESM(require_prompts3(), 1);
|
|
37029
|
-
var config =
|
|
37030
|
-
|
|
37031
|
-
|
|
37032
|
-
|
|
37029
|
+
var config = null;
|
|
37030
|
+
function getConfig() {
|
|
37031
|
+
if (!config) {
|
|
37032
|
+
config = new Conf({
|
|
37033
|
+
projectName: "xtrm-cli",
|
|
37034
|
+
defaults: {
|
|
37035
|
+
syncMode: "copy"
|
|
37036
|
+
}
|
|
37037
|
+
});
|
|
37033
37038
|
}
|
|
37034
|
-
|
|
37039
|
+
return config;
|
|
37040
|
+
}
|
|
37035
37041
|
function getCandidatePaths() {
|
|
37036
37042
|
const home = import_os2.default.homedir();
|
|
37037
37043
|
const appData = process.env.APPDATA;
|
|
37038
37044
|
const isWindows3 = process.platform === "win32";
|
|
37039
37045
|
const paths = [
|
|
37040
37046
|
{ label: ".claude", path: import_path.default.join(home, ".claude") },
|
|
37041
|
-
{ label: ".
|
|
37042
|
-
{ label: ".qwen", path: import_path.default.join(home, ".qwen") },
|
|
37043
|
-
{ label: "~/.gemini/antigravity", path: import_path.default.join(home, ".gemini", "antigravity") },
|
|
37044
|
-
{ label: "~/.agents/skills", path: import_path.default.join(home, ".agents", "skills") }
|
|
37047
|
+
{ label: ".agents/skills", path: import_path.default.join(home, ".agents", "skills") }
|
|
37045
37048
|
];
|
|
37046
37049
|
if (isWindows3 && appData) {
|
|
37047
37050
|
paths.push({ label: "Claude (AppData)", path: import_path.default.join(appData, "Claude") });
|
|
@@ -37062,6 +37065,7 @@ async function getContext(options = {}) {
|
|
|
37062
37065
|
const candidates = getCandidatePaths();
|
|
37063
37066
|
const directTargets = resolveTargets(selector, candidates);
|
|
37064
37067
|
if (directTargets) {
|
|
37068
|
+
const activeConfig2 = getConfig();
|
|
37065
37069
|
if (createMissingDirs) {
|
|
37066
37070
|
for (const target of directTargets) {
|
|
37067
37071
|
await import_fs_extra.default.ensureDir(target);
|
|
@@ -37069,10 +37073,11 @@ async function getContext(options = {}) {
|
|
|
37069
37073
|
}
|
|
37070
37074
|
return {
|
|
37071
37075
|
targets: directTargets,
|
|
37072
|
-
syncMode:
|
|
37073
|
-
config
|
|
37076
|
+
syncMode: activeConfig2.get("syncMode"),
|
|
37077
|
+
config: activeConfig2
|
|
37074
37078
|
};
|
|
37075
37079
|
}
|
|
37080
|
+
const activeConfig = getConfig();
|
|
37076
37081
|
for (const c of candidates) {
|
|
37077
37082
|
const exists = await import_fs_extra.default.pathExists(c.path);
|
|
37078
37083
|
const icon = exists ? kleur_default.green("\u25CF") : kleur_default.gray("\u25CB");
|
|
@@ -37108,12 +37113,12 @@ async function getContext(options = {}) {
|
|
|
37108
37113
|
}
|
|
37109
37114
|
return {
|
|
37110
37115
|
targets: response.targets,
|
|
37111
|
-
syncMode:
|
|
37112
|
-
config
|
|
37116
|
+
syncMode: activeConfig.get("syncMode"),
|
|
37117
|
+
config: activeConfig
|
|
37113
37118
|
};
|
|
37114
37119
|
}
|
|
37115
37120
|
function resetContext() {
|
|
37116
|
-
|
|
37121
|
+
getConfig().clear();
|
|
37117
37122
|
console.log(kleur_default.yellow("Configuration cleared."));
|
|
37118
37123
|
}
|
|
37119
37124
|
|
|
@@ -40671,6 +40676,21 @@ function resolvePkgRoot() {
|
|
|
40671
40676
|
}
|
|
40672
40677
|
var PKG_ROOT = resolvePkgRoot();
|
|
40673
40678
|
var PROJECT_SKILLS_DIR = import_path10.default.join(PKG_ROOT, "project-skills");
|
|
40679
|
+
async function getAvailableProjectSkills() {
|
|
40680
|
+
if (!await import_fs_extra10.default.pathExists(PROJECT_SKILLS_DIR)) {
|
|
40681
|
+
return [];
|
|
40682
|
+
}
|
|
40683
|
+
const entries = await import_fs_extra10.default.readdir(PROJECT_SKILLS_DIR);
|
|
40684
|
+
const skills2 = [];
|
|
40685
|
+
for (const entry of entries) {
|
|
40686
|
+
const entryPath = import_path10.default.join(PROJECT_SKILLS_DIR, entry);
|
|
40687
|
+
const stat = await import_fs_extra10.default.stat(entryPath);
|
|
40688
|
+
if (stat.isDirectory()) {
|
|
40689
|
+
skills2.push(entry);
|
|
40690
|
+
}
|
|
40691
|
+
}
|
|
40692
|
+
return skills2.sort();
|
|
40693
|
+
}
|
|
40674
40694
|
function deepMergeHooks(existing, incoming) {
|
|
40675
40695
|
const result = { ...existing };
|
|
40676
40696
|
if (!result.hooks) result.hooks = {};
|
|
@@ -40789,26 +40809,41 @@ async function installProjectSkill(toolName, projectRootOverride) {
|
|
|
40789
40809
|
}
|
|
40790
40810
|
console.log(kleur_default.green(" \u2713 Installation complete!\n"));
|
|
40791
40811
|
}
|
|
40812
|
+
async function installAllProjectSkills(projectRootOverride) {
|
|
40813
|
+
const skills2 = await getAvailableProjectSkills();
|
|
40814
|
+
if (skills2.length === 0) {
|
|
40815
|
+
console.log(kleur_default.dim(" No project skills available.\n"));
|
|
40816
|
+
return;
|
|
40817
|
+
}
|
|
40818
|
+
const projectRoot = projectRootOverride ?? getProjectRoot();
|
|
40819
|
+
console.log(kleur_default.bold(`
|
|
40820
|
+
Installing ${skills2.length} project skills:
|
|
40821
|
+
`));
|
|
40822
|
+
for (const skill of skills2) {
|
|
40823
|
+
console.log(kleur_default.dim(` \u2022 ${skill}`));
|
|
40824
|
+
}
|
|
40825
|
+
console.log("");
|
|
40826
|
+
for (const skill of skills2) {
|
|
40827
|
+
await installProjectSkill(skill, projectRoot);
|
|
40828
|
+
}
|
|
40829
|
+
}
|
|
40792
40830
|
async function listProjectSkills() {
|
|
40793
|
-
|
|
40831
|
+
const entries = await getAvailableProjectSkills();
|
|
40832
|
+
if (entries.length === 0) {
|
|
40794
40833
|
console.log(kleur_default.dim(" No project skills available.\n"));
|
|
40795
40834
|
return;
|
|
40796
40835
|
}
|
|
40797
|
-
const
|
|
40798
|
-
const skills = [];
|
|
40836
|
+
const skills2 = [];
|
|
40799
40837
|
for (const entry of entries) {
|
|
40800
|
-
const
|
|
40801
|
-
const stat = await import_fs_extra10.default.stat(entryPath);
|
|
40802
|
-
if (!stat.isDirectory()) continue;
|
|
40803
|
-
const readmePath = import_path10.default.join(entryPath, "README.md");
|
|
40838
|
+
const readmePath = import_path10.default.join(PROJECT_SKILLS_DIR, entry, "README.md");
|
|
40804
40839
|
let description = "No description available";
|
|
40805
40840
|
if (await import_fs_extra10.default.pathExists(readmePath)) {
|
|
40806
40841
|
const readmeContent = await import_fs_extra10.default.readFile(readmePath, "utf8");
|
|
40807
40842
|
description = extractReadmeDescription(readmeContent).slice(0, 80);
|
|
40808
40843
|
}
|
|
40809
|
-
|
|
40844
|
+
skills2.push({ name: entry, description });
|
|
40810
40845
|
}
|
|
40811
|
-
if (
|
|
40846
|
+
if (skills2.length === 0) {
|
|
40812
40847
|
console.log(kleur_default.dim(" No project skills available.\n"));
|
|
40813
40848
|
return;
|
|
40814
40849
|
}
|
|
@@ -40819,12 +40854,13 @@ async function listProjectSkills() {
|
|
|
40819
40854
|
colWidths: [25, 60],
|
|
40820
40855
|
style: { head: [], border: [] }
|
|
40821
40856
|
});
|
|
40822
|
-
for (const skill of
|
|
40857
|
+
for (const skill of skills2) {
|
|
40823
40858
|
table.push([kleur_default.white(skill.name), kleur_default.dim(skill.description)]);
|
|
40824
40859
|
}
|
|
40825
40860
|
console.log(table.toString());
|
|
40826
40861
|
console.log(kleur_default.bold("\n\nUsage:\n"));
|
|
40827
40862
|
console.log(kleur_default.dim(" xtrm install project <skill-name> Install a project skill"));
|
|
40863
|
+
console.log(kleur_default.dim(" xtrm install project all Install all project skills"));
|
|
40828
40864
|
console.log(kleur_default.dim(" xtrm install project list List available skills\n"));
|
|
40829
40865
|
console.log(kleur_default.bold("Example:\n"));
|
|
40830
40866
|
console.log(kleur_default.dim(" xtrm install project tdd-guard\n"));
|
|
@@ -40843,6 +40879,10 @@ function createInstallProjectCommand() {
|
|
|
40843
40879
|
const installProjectCmd = new Command("project").description("Install a project-specific skill package");
|
|
40844
40880
|
installProjectCmd.argument("<tool-name>", "Name of the project skill to install").action(async (toolName) => {
|
|
40845
40881
|
try {
|
|
40882
|
+
if (toolName === "all" || toolName === "*") {
|
|
40883
|
+
await installAllProjectSkills();
|
|
40884
|
+
return;
|
|
40885
|
+
}
|
|
40846
40886
|
await installProjectSkill(toolName);
|
|
40847
40887
|
} catch (err) {
|
|
40848
40888
|
console.error(kleur_default.red(`
|
|
@@ -54958,10 +54998,10 @@ ${kleur_default.cyan("COMMANDS:")}
|
|
|
54958
54998
|
|
|
54959
54999
|
Examples:
|
|
54960
55000
|
xtrm install # Interactive install with confirmation
|
|
54961
|
-
xtrm install all # Install to all
|
|
55001
|
+
xtrm install all # Install to all Claude Code targets without prompting
|
|
54962
55002
|
xtrm install '*' # Same as above; quote to avoid shell expansion
|
|
54963
55003
|
xtrm install --dry-run # Preview what would be installed
|
|
54964
|
-
xtrm install all --dry-run -y # CI-friendly preview across all targets
|
|
55004
|
+
xtrm install all --dry-run -y # CI-friendly preview across all Claude targets
|
|
54965
55005
|
xtrm install -y # Non-interactive install
|
|
54966
55006
|
|
|
54967
55007
|
${kleur_default.bold("install project")} <tool-name>
|
|
@@ -54973,6 +55013,8 @@ ${kleur_default.cyan("COMMANDS:")}
|
|
|
54973
55013
|
Examples:
|
|
54974
55014
|
xtrm install project tdd-guard # Install TDD Guard
|
|
54975
55015
|
xtrm install project ts-quality-gate # Install TypeScript Quality Gate
|
|
55016
|
+
xtrm install project all # Install every available project skill
|
|
55017
|
+
xtrm install project '*' # Same as above; quote to avoid shell expansion
|
|
54976
55018
|
|
|
54977
55019
|
${kleur_default.bold("install project list")}
|
|
54978
55020
|
List all available project skills with descriptions and usage examples.
|
|
@@ -55007,6 +55049,13 @@ ${kleur_default.cyan("PROJECT SKILLS:")}
|
|
|
55007
55049
|
\u2022 ${kleur_default.white("py-quality-gate")} \u2014 Python ruff/mypy quality gate (PostToolUse)
|
|
55008
55050
|
\u2022 ${kleur_default.white("main-guard")} \u2014 Git branch protection (PreToolUse)
|
|
55009
55051
|
|
|
55052
|
+
${kleur_default.cyan("INSTALL TARGETS:")}
|
|
55053
|
+
|
|
55054
|
+
xtrm-tools v2.0.0 installs into Claude Code targets and the `.agents / skills` cache:
|
|
55055
|
+
• ~/.claude
|
|
55056
|
+
• %APPDATA%/Claude on Windows
|
|
55057
|
+
• ~/.agents/skills (skills-only copy)
|
|
55058
|
+
|
|
55010
55059
|
${kleur_default.cyan("ARCHITECTURE:")}
|
|
55011
55060
|
|
|
55012
55061
|
xtrm-tools v2.0.0 supports Claude Code exclusively. This decision was made
|
|
@@ -55018,9 +55067,9 @@ ${kleur_default.cyan("ARCHITECTURE:")}
|
|
|
55018
55067
|
|
|
55019
55068
|
${kleur_default.cyan("RESOURCES:")}
|
|
55020
55069
|
|
|
55021
|
-
|
|
55022
|
-
|
|
55023
|
-
|
|
55070
|
+
• Repository: https://github.com/Jaggerxtrm/xtrm-tools
|
|
55071
|
+
• Documentation: See README.md in the repository
|
|
55072
|
+
• Report Issues: https://github.com/Jaggerxtrm/xtrm-tools/issues
|
|
55024
55073
|
|
|
55025
55074
|
${kleur_default.dim("Run 'xtrm <command> --help' for more information on a specific command.")}
|
|
55026
55075
|
`);
|