reeboot 1.3.3 → 1.3.4
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/container/entrypoint.sh +55 -3
- package/dist/agent-runner/index.d.ts.map +1 -1
- package/dist/agent-runner/index.js +3 -9
- package/dist/agent-runner/index.js.map +1 -1
- package/dist/agent-runner/pi-runner.d.ts +3 -1
- package/dist/agent-runner/pi-runner.d.ts.map +1 -1
- package/dist/agent-runner/pi-runner.js +81 -7
- package/dist/agent-runner/pi-runner.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +3 -0
- package/dist/context.js.map +1 -1
- package/dist/extensions/confirm-destructive.d.ts +9 -0
- package/dist/extensions/confirm-destructive.d.ts.map +1 -0
- package/dist/extensions/confirm-destructive.js +43 -0
- package/dist/extensions/confirm-destructive.js.map +1 -0
- package/dist/extensions/custom-compaction.d.ts +17 -0
- package/dist/extensions/custom-compaction.d.ts.map +1 -0
- package/dist/extensions/custom-compaction.js +99 -0
- package/dist/extensions/custom-compaction.js.map +1 -0
- package/dist/extensions/loader.d.ts.map +1 -1
- package/dist/extensions/loader.js +24 -16
- package/dist/extensions/loader.js.map +1 -1
- package/dist/extensions/protected-paths.d.ts +9 -0
- package/dist/extensions/protected-paths.d.ts.map +1 -0
- package/dist/extensions/protected-paths.js +24 -0
- package/dist/extensions/protected-paths.js.map +1 -0
- package/dist/extensions/scheduler-tool.d.ts +31 -0
- package/dist/extensions/scheduler-tool.d.ts.map +1 -0
- package/dist/extensions/scheduler-tool.js +341 -0
- package/dist/extensions/scheduler-tool.js.map +1 -0
- package/dist/extensions/session-name.d.ts +11 -0
- package/dist/extensions/session-name.d.ts.map +1 -0
- package/dist/extensions/session-name.js +25 -0
- package/dist/extensions/session-name.js.map +1 -0
- package/dist/extensions/skill-manager.d.ts +49 -0
- package/dist/extensions/skill-manager.d.ts.map +1 -0
- package/dist/extensions/skill-manager.js +368 -0
- package/dist/extensions/skill-manager.js.map +1 -0
- package/dist/extensions/token-meter.d.ts +11 -0
- package/dist/extensions/token-meter.d.ts.map +1 -0
- package/dist/extensions/token-meter.js +46 -0
- package/dist/extensions/token-meter.js.map +1 -0
- package/dist/extensions/web-search.d.ts +39 -0
- package/dist/extensions/web-search.d.ts.map +1 -0
- package/dist/extensions/web-search.js +366 -0
- package/dist/extensions/web-search.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/setup-wizard.d.ts +1 -0
- package/dist/setup-wizard.d.ts.map +1 -1
- package/dist/setup-wizard.js +4 -3
- package/dist/setup-wizard.js.map +1 -1
- package/dist/utils/agent-dir.d.ts +11 -0
- package/dist/utils/agent-dir.d.ts.map +1 -0
- package/dist/utils/agent-dir.js +26 -0
- package/dist/utils/agent-dir.js.map +1 -0
- package/dist/wizard/detect-pi-auth.d.ts +19 -0
- package/dist/wizard/detect-pi-auth.d.ts.map +1 -0
- package/dist/wizard/detect-pi-auth.js +36 -0
- package/dist/wizard/detect-pi-auth.js.map +1 -0
- package/dist/wizard/index.d.ts.map +1 -1
- package/dist/wizard/index.js +1 -0
- package/dist/wizard/index.js.map +1 -1
- package/dist/wizard/probe-searxng.d.ts +9 -0
- package/dist/wizard/probe-searxng.d.ts.map +1 -0
- package/dist/wizard/probe-searxng.js +30 -0
- package/dist/wizard/probe-searxng.js.map +1 -0
- package/dist/wizard/steps/launch.d.ts +1 -0
- package/dist/wizard/steps/launch.d.ts.map +1 -1
- package/dist/wizard/steps/launch.js +5 -4
- package/dist/wizard/steps/launch.js.map +1 -1
- package/dist/wizard/steps/provider.d.ts +1 -0
- package/dist/wizard/steps/provider.d.ts.map +1 -1
- package/dist/wizard/steps/provider.js +18 -1
- package/dist/wizard/steps/provider.js.map +1 -1
- package/dist/wizard/steps/web-search.js +33 -10
- package/dist/wizard/steps/web-search.js.map +1 -1
- package/extensions/web-search.ts +2 -3
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Manager Extension
|
|
3
|
+
*
|
|
4
|
+
* Manages permanent and ephemeral skills for the reeboot agent:
|
|
5
|
+
* - Permanent skills: registered via resources_discover at startup
|
|
6
|
+
* - Ephemeral skills: loaded on demand via load_skill tool, TTL-based expiry,
|
|
7
|
+
* injected into system prompt via before_agent_start
|
|
8
|
+
* - Persistence: active ephemeral skills stored in ~/.reeboot/active-skills.json
|
|
9
|
+
* - Catalog: resolves skill names from bundled catalog and extended catalog
|
|
10
|
+
*/
|
|
11
|
+
import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';
|
|
12
|
+
import type { Config } from '../src/config.js';
|
|
13
|
+
export interface ActiveSkill {
|
|
14
|
+
name: string;
|
|
15
|
+
skillDir: string;
|
|
16
|
+
description: string;
|
|
17
|
+
expiresAt: number;
|
|
18
|
+
}
|
|
19
|
+
interface SkillMeta {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Search each root for <root>/<name>/SKILL.md.
|
|
25
|
+
* Returns the skill directory path (not SKILL.md) or null.
|
|
26
|
+
* Case-insensitive name match.
|
|
27
|
+
*/
|
|
28
|
+
export declare function findSkill(name: string, roots: string[]): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Read SKILL.md frontmatter and parse name + description.
|
|
31
|
+
* Uses simple regex; does not require a YAML library.
|
|
32
|
+
* Returns null on any parse error.
|
|
33
|
+
*/
|
|
34
|
+
export declare function readSkillMeta(skillDir: string): SkillMeta | null;
|
|
35
|
+
export declare class ActiveSkillStore {
|
|
36
|
+
private _skills;
|
|
37
|
+
load(name: string, skillDir: string, description: string, ttlMs: number): void;
|
|
38
|
+
unload(name: string): boolean;
|
|
39
|
+
/** Returns only non-expired skills (does not mutate). */
|
|
40
|
+
getActive(): ActiveSkill[];
|
|
41
|
+
/** Removes expired skills and returns their names. */
|
|
42
|
+
pruneExpired(): string[];
|
|
43
|
+
/** Replace entire store from an array (used on restore). */
|
|
44
|
+
restoreFrom(skills: ActiveSkill[]): void;
|
|
45
|
+
toArray(): ActiveSkill[];
|
|
46
|
+
}
|
|
47
|
+
export declare function skillManagerExtension(pi: ExtensionAPI, config: Config, persistPath?: string): void;
|
|
48
|
+
export default skillManagerExtension;
|
|
49
|
+
//# sourceMappingURL=skill-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-manager.d.ts","sourceRoot":"","sources":["../../src/extensions/skill-manager.ts"],"names":[],"mappings":"AACA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAa/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAID;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAwBtE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAmBhE;AA6BD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAuC;IAEtD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK9E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B,yDAAyD;IACzD,SAAS,IAAI,WAAW,EAAE;IAK1B,sDAAsD;IACtD,YAAY,IAAI,MAAM,EAAE;IAYxB,4DAA4D;IAC5D,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI;IAOxC,OAAO,IAAI,WAAW,EAAE;CAGzB;AAsCD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAA6B,GACzC,IAAI,CA8MN;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Skill Manager Extension
|
|
4
|
+
*
|
|
5
|
+
* Manages permanent and ephemeral skills for the reeboot agent:
|
|
6
|
+
* - Permanent skills: registered via resources_discover at startup
|
|
7
|
+
* - Ephemeral skills: loaded on demand via load_skill tool, TTL-based expiry,
|
|
8
|
+
* injected into system prompt via before_agent_start
|
|
9
|
+
* - Persistence: active ephemeral skills stored in ~/.reeboot/active-skills.json
|
|
10
|
+
* - Catalog: resolves skill names from bundled catalog and extended catalog
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
|
|
13
|
+
import { join, dirname } from 'path';
|
|
14
|
+
import { homedir } from 'os';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
import { Type } from '@sinclair/typebox';
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
// Resolve package root (same logic as loader.ts: dist/extensions → dist/ → reeboot/)
|
|
19
|
+
const PACKAGE_ROOT = join(__dirname, '../../');
|
|
20
|
+
const BUNDLED_SKILLS_DIR = join(PACKAGE_ROOT, 'skills');
|
|
21
|
+
// Default persist path
|
|
22
|
+
const DEFAULT_PERSIST_PATH = join(homedir(), '.reeboot', 'active-skills.json');
|
|
23
|
+
// ─── Catalog Resolution ───────────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Search each root for <root>/<name>/SKILL.md.
|
|
26
|
+
* Returns the skill directory path (not SKILL.md) or null.
|
|
27
|
+
* Case-insensitive name match.
|
|
28
|
+
*/
|
|
29
|
+
export function findSkill(name, roots) {
|
|
30
|
+
const lowerName = name.toLowerCase();
|
|
31
|
+
for (const root of roots) {
|
|
32
|
+
if (!existsSync(root))
|
|
33
|
+
continue;
|
|
34
|
+
const skillDir = join(root, name);
|
|
35
|
+
if (existsSync(join(skillDir, 'SKILL.md'))) {
|
|
36
|
+
return skillDir;
|
|
37
|
+
}
|
|
38
|
+
// Try case-insensitive scan
|
|
39
|
+
try {
|
|
40
|
+
const entries = readdirSync(root, { withFileTypes: true });
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (entry.isDirectory() && entry.name.toLowerCase() === lowerName) {
|
|
43
|
+
const candidate = join(root, entry.name);
|
|
44
|
+
if (existsSync(join(candidate, 'SKILL.md'))) {
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Root not accessible — skip
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read SKILL.md frontmatter and parse name + description.
|
|
58
|
+
* Uses simple regex; does not require a YAML library.
|
|
59
|
+
* Returns null on any parse error.
|
|
60
|
+
*/
|
|
61
|
+
export function readSkillMeta(skillDir) {
|
|
62
|
+
const skillMdPath = join(skillDir, 'SKILL.md');
|
|
63
|
+
if (!existsSync(skillMdPath))
|
|
64
|
+
return null;
|
|
65
|
+
try {
|
|
66
|
+
const content = readFileSync(skillMdPath, 'utf-8');
|
|
67
|
+
// Extract frontmatter between --- delimiters
|
|
68
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
69
|
+
if (!fmMatch)
|
|
70
|
+
return null;
|
|
71
|
+
const frontmatter = fmMatch[1];
|
|
72
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
73
|
+
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
74
|
+
if (!nameMatch || !descMatch)
|
|
75
|
+
return null;
|
|
76
|
+
return {
|
|
77
|
+
name: nameMatch[1].trim(),
|
|
78
|
+
description: descMatch[1].trim(),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns the list of catalog root directories to search, in order:
|
|
87
|
+
* 1. Bundled catalog: <package_root>/skills/
|
|
88
|
+
* 2. Extended catalog: config.skills.catalog_path or ~/.reeboot/skills-catalog/
|
|
89
|
+
*/
|
|
90
|
+
function resolveCatalogRoots(config) {
|
|
91
|
+
const roots = [];
|
|
92
|
+
// 1. Bundled catalog (may not exist yet — handled gracefully)
|
|
93
|
+
roots.push(BUNDLED_SKILLS_DIR);
|
|
94
|
+
// 2. Extended catalog
|
|
95
|
+
const skillsConfig = config?.skills;
|
|
96
|
+
if (skillsConfig?.catalog_path) {
|
|
97
|
+
roots.push(skillsConfig.catalog_path);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const defaultCatalog = join(homedir(), '.reeboot', 'skills-catalog');
|
|
101
|
+
if (existsSync(defaultCatalog)) {
|
|
102
|
+
roots.push(defaultCatalog);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return roots;
|
|
106
|
+
}
|
|
107
|
+
// ─── ActiveSkillStore ─────────────────────────────────────────────────────────
|
|
108
|
+
export class ActiveSkillStore {
|
|
109
|
+
_skills = new Map();
|
|
110
|
+
load(name, skillDir, description, ttlMs) {
|
|
111
|
+
const expiresAt = Date.now() + ttlMs;
|
|
112
|
+
this._skills.set(name, { name, skillDir, description, expiresAt });
|
|
113
|
+
}
|
|
114
|
+
unload(name) {
|
|
115
|
+
return this._skills.delete(name);
|
|
116
|
+
}
|
|
117
|
+
/** Returns only non-expired skills (does not mutate). */
|
|
118
|
+
getActive() {
|
|
119
|
+
const now = Date.now();
|
|
120
|
+
return Array.from(this._skills.values()).filter((s) => s.expiresAt > now);
|
|
121
|
+
}
|
|
122
|
+
/** Removes expired skills and returns their names. */
|
|
123
|
+
pruneExpired() {
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
const removed = [];
|
|
126
|
+
for (const [name, skill] of this._skills.entries()) {
|
|
127
|
+
if (skill.expiresAt <= now) {
|
|
128
|
+
this._skills.delete(name);
|
|
129
|
+
removed.push(name);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return removed;
|
|
133
|
+
}
|
|
134
|
+
/** Replace entire store from an array (used on restore). */
|
|
135
|
+
restoreFrom(skills) {
|
|
136
|
+
this._skills.clear();
|
|
137
|
+
for (const s of skills) {
|
|
138
|
+
this._skills.set(s.name, s);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
toArray() {
|
|
142
|
+
return Array.from(this._skills.values());
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// ─── Persistence ─────────────────────────────────────────────────────────────
|
|
146
|
+
/**
|
|
147
|
+
* Write active skills to disk as JSON array.
|
|
148
|
+
* Creates parent directories if needed.
|
|
149
|
+
*/
|
|
150
|
+
function persistStore(store, path) {
|
|
151
|
+
try {
|
|
152
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
153
|
+
const data = store.getActive();
|
|
154
|
+
writeFileSync(path, JSON.stringify(data, null, 2), 'utf-8');
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
console.warn('[skill-manager] failed to persist active skills:', err);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Read active skills from disk.
|
|
162
|
+
* Discards expired entries (expiresAt <= now).
|
|
163
|
+
* Returns empty map on missing/corrupted file.
|
|
164
|
+
*/
|
|
165
|
+
function restoreStore(path, now) {
|
|
166
|
+
if (!existsSync(path))
|
|
167
|
+
return [];
|
|
168
|
+
try {
|
|
169
|
+
const raw = readFileSync(path, 'utf-8');
|
|
170
|
+
const data = JSON.parse(raw);
|
|
171
|
+
if (!Array.isArray(data))
|
|
172
|
+
return [];
|
|
173
|
+
return data.filter((s) => s.expiresAt > now);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
console.warn('[skill-manager] failed to restore active skills from disk:', err);
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ─── Extension Default Export ─────────────────────────────────────────────────
|
|
181
|
+
export function skillManagerExtension(pi, config, persistPath = DEFAULT_PERSIST_PATH) {
|
|
182
|
+
const skillsConfig = config?.skills ?? {
|
|
183
|
+
permanent: [],
|
|
184
|
+
ephemeral_ttl_minutes: 60,
|
|
185
|
+
catalog_path: '',
|
|
186
|
+
};
|
|
187
|
+
const store = new ActiveSkillStore();
|
|
188
|
+
const catalogRoots = resolveCatalogRoots(config);
|
|
189
|
+
// ── Restore persisted active skills on startup ────────────────────────────
|
|
190
|
+
const restored = restoreStore(persistPath, Date.now());
|
|
191
|
+
if (restored.length > 0) {
|
|
192
|
+
store.restoreFrom(restored);
|
|
193
|
+
}
|
|
194
|
+
// ── Permanent Skills — resources_discover ─────────────────────────────────
|
|
195
|
+
pi.on('resources_discover', async () => {
|
|
196
|
+
const skillPaths = [];
|
|
197
|
+
for (const name of skillsConfig.permanent ?? []) {
|
|
198
|
+
const dir = findSkill(name, catalogRoots);
|
|
199
|
+
if (dir) {
|
|
200
|
+
skillPaths.push(dir);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
console.warn(`[skill-manager] permanent skill not found in catalog: ${name}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { skillPaths };
|
|
207
|
+
});
|
|
208
|
+
// ── Ephemeral Skills — before_agent_start injection ───────────────────────
|
|
209
|
+
pi.on('before_agent_start', async (event) => {
|
|
210
|
+
const active = store.getActive();
|
|
211
|
+
if (active.length === 0)
|
|
212
|
+
return undefined;
|
|
213
|
+
const now = Date.now();
|
|
214
|
+
const xml = [
|
|
215
|
+
'\n<active_skills>',
|
|
216
|
+
...active.map((s) => {
|
|
217
|
+
const minsLeft = Math.max(1, Math.round((s.expiresAt - now) / 60_000));
|
|
218
|
+
return ` <skill name="${s.name}">\n <description>${s.description}</description>\n <expires_in>${minsLeft} minutes</expires_in>\n </skill>`;
|
|
219
|
+
}),
|
|
220
|
+
'</active_skills>',
|
|
221
|
+
].join('\n');
|
|
222
|
+
return { systemPrompt: event.systemPrompt + xml };
|
|
223
|
+
});
|
|
224
|
+
// ── TTL Expiry Loop ───────────────────────────────────────────────────────
|
|
225
|
+
const loop = setInterval(() => {
|
|
226
|
+
const removed = store.pruneExpired();
|
|
227
|
+
if (removed.length > 0) {
|
|
228
|
+
persistStore(store, persistPath);
|
|
229
|
+
}
|
|
230
|
+
}, 60_000);
|
|
231
|
+
pi.on('session_shutdown', async () => {
|
|
232
|
+
clearInterval(loop);
|
|
233
|
+
});
|
|
234
|
+
// ── load_skill tool ───────────────────────────────────────────────────────
|
|
235
|
+
pi.registerTool({
|
|
236
|
+
name: 'load_skill',
|
|
237
|
+
label: 'Load Skill',
|
|
238
|
+
description: 'Load a skill from the catalog into active context for a limited time.',
|
|
239
|
+
parameters: Type.Object({
|
|
240
|
+
name: Type.String({ description: 'Skill name to load' }),
|
|
241
|
+
ttl_minutes: Type.Optional(Type.Number({
|
|
242
|
+
description: 'How long to keep skill active (minutes). Defaults to config value.',
|
|
243
|
+
})),
|
|
244
|
+
}),
|
|
245
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
246
|
+
const skillName = params.name;
|
|
247
|
+
const ttl = params.ttl_minutes ?? skillsConfig.ephemeral_ttl_minutes ?? 60;
|
|
248
|
+
const ttlMs = ttl * 60 * 1000;
|
|
249
|
+
const skillDir = findSkill(skillName, catalogRoots);
|
|
250
|
+
if (!skillDir) {
|
|
251
|
+
return {
|
|
252
|
+
content: [
|
|
253
|
+
{
|
|
254
|
+
type: 'text',
|
|
255
|
+
text: `skill "${skillName}" not found in catalog`,
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const meta = readSkillMeta(skillDir);
|
|
261
|
+
const description = meta?.description ?? skillName;
|
|
262
|
+
store.load(skillName, skillDir, description, ttlMs);
|
|
263
|
+
persistStore(store, persistPath);
|
|
264
|
+
const expiresAt = Date.now() + ttlMs;
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: 'text',
|
|
269
|
+
text: `Loaded skill "${skillName}" for ${ttl} minutes.`,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
details: {
|
|
273
|
+
name: skillName,
|
|
274
|
+
expiresAt: new Date(expiresAt).toISOString(),
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
// ── unload_skill tool ─────────────────────────────────────────────────────
|
|
280
|
+
pi.registerTool({
|
|
281
|
+
name: 'unload_skill',
|
|
282
|
+
label: 'Unload Skill',
|
|
283
|
+
description: 'Remove an active ephemeral skill from context immediately.',
|
|
284
|
+
parameters: Type.Object({
|
|
285
|
+
name: Type.String({ description: 'Skill name to unload' }),
|
|
286
|
+
}),
|
|
287
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
288
|
+
const skillName = params.name;
|
|
289
|
+
// Check if active before unload
|
|
290
|
+
const active = store.getActive();
|
|
291
|
+
const isActive = active.some((s) => s.name === skillName);
|
|
292
|
+
if (!isActive) {
|
|
293
|
+
return {
|
|
294
|
+
content: [
|
|
295
|
+
{
|
|
296
|
+
type: 'text',
|
|
297
|
+
text: `skill "${skillName}" is not active`,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
store.unload(skillName);
|
|
303
|
+
persistStore(store, persistPath);
|
|
304
|
+
return {
|
|
305
|
+
content: [
|
|
306
|
+
{
|
|
307
|
+
type: 'text',
|
|
308
|
+
text: `Unloaded skill "${skillName}".`,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
// ── list_available_skills tool ────────────────────────────────────────────
|
|
315
|
+
pi.registerTool({
|
|
316
|
+
name: 'list_available_skills',
|
|
317
|
+
label: 'List Available Skills',
|
|
318
|
+
description: 'List all skills available in the catalog. Optionally filter by keyword.',
|
|
319
|
+
parameters: Type.Object({
|
|
320
|
+
query: Type.Optional(Type.String({
|
|
321
|
+
description: 'Optional keyword filter (case-insensitive substring match on name or description)',
|
|
322
|
+
})),
|
|
323
|
+
}),
|
|
324
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
325
|
+
const query = params.query;
|
|
326
|
+
// Scan all catalog roots for skills
|
|
327
|
+
const allSkills = [];
|
|
328
|
+
const seen = new Set();
|
|
329
|
+
for (const root of catalogRoots) {
|
|
330
|
+
if (!existsSync(root))
|
|
331
|
+
continue;
|
|
332
|
+
try {
|
|
333
|
+
const entries = readdirSync(root, { withFileTypes: true });
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
if (!entry.isDirectory())
|
|
336
|
+
continue;
|
|
337
|
+
const skillDir = join(root, entry.name);
|
|
338
|
+
const skillMdPath = join(skillDir, 'SKILL.md');
|
|
339
|
+
if (!existsSync(skillMdPath))
|
|
340
|
+
continue;
|
|
341
|
+
const meta = readSkillMeta(skillDir);
|
|
342
|
+
if (!meta)
|
|
343
|
+
continue;
|
|
344
|
+
if (seen.has(meta.name))
|
|
345
|
+
continue; // bundled takes priority
|
|
346
|
+
seen.add(meta.name);
|
|
347
|
+
allSkills.push({ name: meta.name, description: meta.description });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
// Root not accessible — skip
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// Apply keyword filter if provided
|
|
355
|
+
let results = allSkills;
|
|
356
|
+
if (query && query.trim()) {
|
|
357
|
+
const lowerQuery = query.toLowerCase();
|
|
358
|
+
results = allSkills.filter((s) => s.name.toLowerCase().includes(lowerQuery) ||
|
|
359
|
+
s.description.toLowerCase().includes(lowerQuery));
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
content: [{ type: 'text', text: JSON.stringify(results) }],
|
|
363
|
+
};
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
export default skillManagerExtension;
|
|
368
|
+
//# sourceMappingURL=skill-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-manager.js","sourceRoot":"","sources":["../../src/extensions/skill-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Meter Extension
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to agent_end events and inserts a usage row into the SQLite
|
|
5
|
+
* `usage` table via getDb() from the reeboot DB module.
|
|
6
|
+
*
|
|
7
|
+
* The context_id is derived from the cwd (basename of the context workspace).
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';
|
|
10
|
+
export default function (pi: ExtensionAPI): void;
|
|
11
|
+
//# sourceMappingURL=token-meter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-meter.d.ts","sourceRoot":"","sources":["../../src/extensions/token-meter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAwCxC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Meter Extension
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to agent_end events and inserts a usage row into the SQLite
|
|
5
|
+
* `usage` table via getDb() from the reeboot DB module.
|
|
6
|
+
*
|
|
7
|
+
* The context_id is derived from the cwd (basename of the context workspace).
|
|
8
|
+
*/
|
|
9
|
+
export default function (pi) {
|
|
10
|
+
pi.on('agent_end', async (event, ctx) => {
|
|
11
|
+
// Extract the last assistant message to get token usage
|
|
12
|
+
const messages = event.messages;
|
|
13
|
+
let inputTokens = 0;
|
|
14
|
+
let outputTokens = 0;
|
|
15
|
+
let modelId = '';
|
|
16
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
17
|
+
const m = messages[i];
|
|
18
|
+
if (m.role === 'assistant') {
|
|
19
|
+
if (m.usage) {
|
|
20
|
+
inputTokens = m.usage.inputTokens ?? 0;
|
|
21
|
+
outputTokens = m.usage.outputTokens ?? 0;
|
|
22
|
+
}
|
|
23
|
+
if (m.model) {
|
|
24
|
+
modelId = typeof m.model === 'string' ? m.model : (m.model.id ?? '');
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (inputTokens === 0 && outputTokens === 0)
|
|
30
|
+
return;
|
|
31
|
+
// Derive context_id from the context workspace path (basename)
|
|
32
|
+
const path = await import('path');
|
|
33
|
+
const contextId = path.basename(ctx.cwd);
|
|
34
|
+
try {
|
|
35
|
+
// Dynamic import to avoid circular deps when extension is loaded outside reeboot
|
|
36
|
+
const { getDb } = await import('../db/index.js');
|
|
37
|
+
const db = getDb();
|
|
38
|
+
db.prepare(`INSERT INTO usage (context_id, input_tokens, output_tokens, model)
|
|
39
|
+
VALUES (?, ?, ?, ?)`).run(contextId, inputTokens, outputTokens, modelId);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// DB may not be available in test/standalone contexts — silently skip
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=token-meter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-meter.js","sourceRoot":"","sources":["../../src/extensions/token-meter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,CAAC,OAAO,WAAW,EAAgB;IACvC,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACtC,wDAAwD;QACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAiB,CAAC;QACzC,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC3B,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;oBACZ,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;oBACvC,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;gBAC3C,CAAC;gBACD,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;oBACZ,OAAO,GAAG,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvE,CAAC;gBACD,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,WAAW,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC;YAAE,OAAO;QAEpD,+DAA+D;QAC/D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEzC,IAAI,CAAC;YACH,iFAAiF;YACjF,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACjD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;YACnB,EAAE,CAAC,OAAO,CACR;6BACqB,CACtB,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,sEAAsE;QACxE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Search Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers two pi tools:
|
|
5
|
+
* - fetch_url (always registered, regardless of provider)
|
|
6
|
+
* - web_search (registered when config.search.provider ≠ "none")
|
|
7
|
+
*
|
|
8
|
+
* Supports 6 search backends: DuckDuckGo (zero-config), Brave, Tavily,
|
|
9
|
+
* Serper, Exa (all API-key), SearXNG (self-hosted Docker).
|
|
10
|
+
*
|
|
11
|
+
* API key resolution: config.search.apiKey → env var fallback.
|
|
12
|
+
* SearXNG: health-checks on load; falls back to DDG if unreachable.
|
|
13
|
+
*/
|
|
14
|
+
import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';
|
|
15
|
+
export interface SearchResult {
|
|
16
|
+
title: string;
|
|
17
|
+
url: string;
|
|
18
|
+
snippet: string;
|
|
19
|
+
}
|
|
20
|
+
export interface SearchConfig {
|
|
21
|
+
provider?: string;
|
|
22
|
+
apiKey?: string;
|
|
23
|
+
searxngBaseUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function fetchAndExtract(url: string): Promise<string>;
|
|
26
|
+
export declare function searchDuckDuckGo(query: string, limit: number): Promise<SearchResult[]>;
|
|
27
|
+
export declare function searchBrave(query: string, apiKey: string, limit: number): Promise<SearchResult[]>;
|
|
28
|
+
export declare function searchTavily(query: string, apiKey: string, limit: number): Promise<SearchResult[]>;
|
|
29
|
+
export declare function searchSerper(query: string, apiKey: string, limit: number): Promise<SearchResult[]>;
|
|
30
|
+
export declare function searchExa(query: string, apiKey: string, limit: number): Promise<SearchResult[]>;
|
|
31
|
+
export declare function searchSearXNG(query: string, baseUrl: string, limit: number): Promise<SearchResult[]>;
|
|
32
|
+
export declare function checkSearXNGHealth(baseUrl: string): Promise<string>;
|
|
33
|
+
export declare function resolveApiKey(config: SearchConfig): string | undefined;
|
|
34
|
+
export declare function searchBackend(provider: string, config: SearchConfig, params: {
|
|
35
|
+
query: string;
|
|
36
|
+
limit: number;
|
|
37
|
+
}): Promise<SearchResult[]>;
|
|
38
|
+
export default function webSearchExtension(pi: ExtensionAPI, reebotConfig?: any): Promise<void>;
|
|
39
|
+
//# sourceMappingURL=web-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/extensions/web-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAUlE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgClE;AAID,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CAmDzB;AAID,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CA2BzB;AAID,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CAyBzB;AAID,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CA4BzB;AAID,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CA+BzB;AAID,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,EAAE,CAAC,CAsBzB;AAID,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYzE;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAgBtE;AAID,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC,OAAO,CAAC,YAAY,EAAE,CAAC,CAiCzB;AAID,wBAA8B,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAyEpG"}
|