xtrm-tools 0.7.13 → 0.7.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.xtrm/config/hooks.json +10 -0
- package/.xtrm/hooks/specialists-agent-guard.mjs +76 -0
- package/.xtrm/registry.json +440 -412
- package/.xtrm/skills/default/releasing/SKILL.md +49 -45
- package/.xtrm/skills/default/releasing/scripts/xt-reports.ts +18 -0
- package/.xtrm/skills/default/session-close-report/SKILL.md +85 -17
- package/.xtrm/skills/default/specialists-creator/SKILL.md +117 -42
- package/.xtrm/skills/default/specialists-creator/scripts/audit-spec-uniformity.mjs +86 -0
- package/.xtrm/skills/default/specialists-creator/scripts/scaffold-specialist.ts +223 -0
- package/.xtrm/skills/default/specialists-creator/scripts/validate-specialist.ts +1 -1
- package/.xtrm/skills/default/update-specialists/SKILL.md +98 -392
- package/.xtrm/skills/default/using-nodes/SKILL.md +18 -102
- package/.xtrm/skills/default/using-script-specialists/SKILL.md +208 -0
- package/.xtrm/skills/default/using-specialists/SKILL.md +13 -0
- package/.xtrm/skills/default/using-specialists-v2/SKILL.md +105 -15
- package/.xtrm/skills/default/using-specialists-v3/SKILL.md +284 -0
- package/.xtrm/skills/default/using-specialists-v3/evals/evals.json +89 -0
- package/CHANGELOG.md +17 -0
- package/README.md +5 -1
- package/cli/dist/index.cjs +2991 -627
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +3 -2
- package/packages/pi-extensions/.serena/project.yml +11 -0
- package/packages/pi-extensions/package.json +1 -1
- package/scripts/patch-external-pi-tools.mjs +154 -0
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xtrm-tools",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.14",
|
|
4
4
|
"description": "Claude Code tools installer (skills, hooks, MCP servers)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"cli/dist",
|
|
20
20
|
"cli/package.json",
|
|
21
21
|
"scripts/ghgrep.mjs",
|
|
22
|
+
"scripts/patch-external-pi-tools.mjs",
|
|
22
23
|
".xtrm/config",
|
|
23
24
|
".xtrm/hooks",
|
|
24
25
|
"packages/pi-extensions",
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"lint": "echo 'No linting configured'",
|
|
57
58
|
"test": "npm test --workspace cli",
|
|
58
59
|
"version": "npm run sync:cli-version && git add cli/package.json packages/pi-extensions/package.json",
|
|
59
|
-
"prepublishOnly": "npm run sync:cli-version && npm run gen-registry && npm run build",
|
|
60
|
+
"prepublishOnly": "npm run sync:cli-version && node scripts/vendor-specialists-skills.mjs && npm run gen-registry && npm run build",
|
|
60
61
|
"release": "npm publish --tag latest",
|
|
61
62
|
"release:pi-extensions": "npm publish --workspace @jaggerxtrm/pi-extensions --tag latest --access public",
|
|
62
63
|
"release:all": "npm run release && npm run release:pi-extensions",
|
|
@@ -117,3 +117,14 @@ read_only_memory_patterns: []
|
|
|
117
117
|
# Extends the list from the global configuration, merging the two lists.
|
|
118
118
|
# Example: ["_archive/.*", "_episodes/.*"]
|
|
119
119
|
ignored_memory_patterns: []
|
|
120
|
+
|
|
121
|
+
# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos).
|
|
122
|
+
# Paths can be absolute or relative to the project root.
|
|
123
|
+
# Each folder is registered as an LSP workspace folder, enabling language servers to discover
|
|
124
|
+
# symbols and references across package boundaries.
|
|
125
|
+
# Currently supported for: TypeScript.
|
|
126
|
+
# Example:
|
|
127
|
+
# additional_workspace_folders:
|
|
128
|
+
# - ../sibling-package
|
|
129
|
+
# - ../shared-lib
|
|
130
|
+
additional_workspace_folders: []
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
function patchFile(filePath, transforms) {
|
|
8
|
+
if (!fs.existsSync(filePath)) return;
|
|
9
|
+
let text = fs.readFileSync(filePath, 'utf8');
|
|
10
|
+
const original = text;
|
|
11
|
+
for (const t of transforms) text = t(text);
|
|
12
|
+
if (text !== original) fs.writeFileSync(filePath, text, 'utf8');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function injectOnce(text, marker, insert) {
|
|
16
|
+
if (text.includes(insert)) return text;
|
|
17
|
+
if (!text.includes(marker)) return text;
|
|
18
|
+
return text.replace(marker, insert + marker);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function patchSerena(baseDir) {
|
|
22
|
+
const indexPath = path.join(baseDir, 'pi-serena-tools', 'index.ts');
|
|
23
|
+
const responsesPath = path.join(baseDir, 'pi-serena-tools', 'serenaResponses.ts');
|
|
24
|
+
|
|
25
|
+
patchFile(indexPath, [
|
|
26
|
+
(s) => s.includes('from "@mariozechner/pi-tui"') ? s : s.replace(
|
|
27
|
+
'import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";\n',
|
|
28
|
+
'import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";\nimport { Text } from "@mariozechner/pi-tui";\n',
|
|
29
|
+
),
|
|
30
|
+
(s) => injectOnce(
|
|
31
|
+
s,
|
|
32
|
+
' registerSerenaTools({',
|
|
33
|
+
' const originalRegisterTool = pi.registerTool.bind(pi);\n' +
|
|
34
|
+
' (pi).registerTool = (tool) => {\n' +
|
|
35
|
+
' originalRegisterTool({\n' +
|
|
36
|
+
' ...tool,\n' +
|
|
37
|
+
' renderShell: "self",\n' +
|
|
38
|
+
' renderCall: tool.renderCall ?? ((_args, _theme) => new Text("", 0, 0)),\n' +
|
|
39
|
+
' renderResult: tool.renderResult ?? ((result, state, theme) => {\n' +
|
|
40
|
+
' if (state?.isPartial) return new Text(theme.fg("muted", "…"), 0, 0);\n' +
|
|
41
|
+
' const first = (result?.content ?? []).find((c) => c?.type === "text")?.text ?? "";\n' +
|
|
42
|
+
' const line = String(first).split("\\n")[0] || "ok";\n' +
|
|
43
|
+
' return new Text(theme.fg("toolOutput", line), 0, 0);\n' +
|
|
44
|
+
' }),\n' +
|
|
45
|
+
' });\n' +
|
|
46
|
+
' };\n\n'
|
|
47
|
+
),
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
patchFile(responsesPath, [
|
|
51
|
+
(s) => s.includes('import fs from "node:fs";') ? s : `import fs from "node:fs";\nimport path from "node:path";\n${s}`,
|
|
52
|
+
(s) => injectOnce(
|
|
53
|
+
s,
|
|
54
|
+
'export const createWithCommonHandling = (deps: {',
|
|
55
|
+
'function isExternalCompactEnabled() {\n' +
|
|
56
|
+
' try {\n' +
|
|
57
|
+
' const p = path.join(process.env.HOME ?? "", ".pi", "agent", "settings.json");\n' +
|
|
58
|
+
' const cfg = JSON.parse(fs.readFileSync(p, "utf8"));\n' +
|
|
59
|
+
' return cfg?.xtrmExternalCompact !== false;\n' +
|
|
60
|
+
' } catch {\n' +
|
|
61
|
+
' return true;\n' +
|
|
62
|
+
' }\n' +
|
|
63
|
+
'}\n\n'
|
|
64
|
+
),
|
|
65
|
+
(s) => s.replace(
|
|
66
|
+
' const text = await deps.callSerena(toolName, args, timeoutMs);\n return wrapResult(text);',
|
|
67
|
+
' const text = await deps.callSerena(toolName, args, timeoutMs);\n if (!isExternalCompactEnabled()) return wrapResult(text);\n const lines = text ? text.split("\\n").length : 0;\n return { content: [{ type: "text", text: `• serena ${toolName} · ${lines} lines` }] };',
|
|
68
|
+
),
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function patchGitnexus(baseDir) {
|
|
73
|
+
const indexPath = path.join(baseDir, 'pi-gitnexus', 'src', 'index.ts');
|
|
74
|
+
|
|
75
|
+
patchFile(indexPath, [
|
|
76
|
+
(s) => s.includes("from '@mariozechner/pi-tui'") ? s : s.replace(
|
|
77
|
+
"import type { ExtensionAPI, ExtensionContext } from '@mariozechner/pi-coding-agent';\n",
|
|
78
|
+
"import type { ExtensionAPI, ExtensionContext } from '@mariozechner/pi-coding-agent';\nimport { Text } from '@mariozechner/pi-tui';\nimport fs from 'node:fs';\nimport path from 'node:path';\n",
|
|
79
|
+
),
|
|
80
|
+
(s) => injectOnce(
|
|
81
|
+
s,
|
|
82
|
+
"const SEARCH_TOOLS = new Set(['grep', 'find', 'bash', 'read', 'read_many']);",
|
|
83
|
+
"\nfunction isExternalCompactEnabled() {\n" +
|
|
84
|
+
" try {\n" +
|
|
85
|
+
" const p = path.join(process.env.HOME ?? '', '.pi', 'agent', 'settings.json');\n" +
|
|
86
|
+
" const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));\n" +
|
|
87
|
+
" return cfg?.xtrmExternalCompact !== false;\n" +
|
|
88
|
+
" } catch {\n" +
|
|
89
|
+
" return true;\n" +
|
|
90
|
+
" }\n" +
|
|
91
|
+
"}\n"
|
|
92
|
+
),
|
|
93
|
+
(s) => injectOnce(
|
|
94
|
+
s,
|
|
95
|
+
' registerTools(pi);',
|
|
96
|
+
' const originalRegisterTool = pi.registerTool.bind(pi);\n' +
|
|
97
|
+
' (pi).registerTool = (tool) => {\n' +
|
|
98
|
+
' originalRegisterTool({\n' +
|
|
99
|
+
' ...tool,\n' +
|
|
100
|
+
' renderShell: "self",\n' +
|
|
101
|
+
' renderCall: tool.renderCall ?? ((_args, _theme) => new Text("", 0, 0)),\n' +
|
|
102
|
+
' renderResult: tool.renderResult ?? ((result, state, theme) => {\n' +
|
|
103
|
+
' if (state?.isPartial) return new Text(theme.fg("muted", "…"), 0, 0);\n' +
|
|
104
|
+
' const first = (result?.content ?? []).find((c) => c?.type === "text")?.text ?? "";\n' +
|
|
105
|
+
' const line = String(first).split("\\n")[0] || "ok";\n' +
|
|
106
|
+
' return new Text(theme.fg("toolOutput", line), 0, 0);\n' +
|
|
107
|
+
' }),\n' +
|
|
108
|
+
' });\n' +
|
|
109
|
+
' };\n\n'
|
|
110
|
+
),
|
|
111
|
+
(s) => s.replace(
|
|
112
|
+
"if (!event.isError && event.toolName.startsWith('gitnexus_')) {",
|
|
113
|
+
"if (!event.isError && event.toolName.startsWith('gitnexus_') && isExternalCompactEnabled()) {",
|
|
114
|
+
),
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function collectNodeModuleRoots() {
|
|
119
|
+
const roots = new Set();
|
|
120
|
+
|
|
121
|
+
// NVM layout (current primary setup)
|
|
122
|
+
const nvmBase = path.join(homedir(), '.nvm', 'versions', 'node');
|
|
123
|
+
if (fs.existsSync(nvmBase)) {
|
|
124
|
+
for (const v of fs.readdirSync(nvmBase).filter((x) => x.startsWith('v'))) {
|
|
125
|
+
const modules = path.join(nvmBase, v, 'lib', 'node_modules');
|
|
126
|
+
if (fs.existsSync(modules)) roots.add(modules);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Generic npm/pnpm global roots
|
|
131
|
+
for (const cmd of [
|
|
132
|
+
['npm', ['root', '-g']],
|
|
133
|
+
['pnpm', ['root', '-g']],
|
|
134
|
+
]) {
|
|
135
|
+
const [bin, args] = cmd;
|
|
136
|
+
const out = spawnSync(bin, args, { encoding: 'utf8' });
|
|
137
|
+
if (out.status === 0) {
|
|
138
|
+
const root = (out.stdout || '').trim();
|
|
139
|
+
if (root && fs.existsSync(root)) roots.add(root);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return [...roots];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function main() {
|
|
147
|
+
const roots = collectNodeModuleRoots();
|
|
148
|
+
for (const modules of roots) {
|
|
149
|
+
patchSerena(modules);
|
|
150
|
+
patchGitnexus(modules);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
main();
|