@spences10/pi-skills 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scott Spence
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # @spences10/pi-skills
2
+
3
+ [![built with vite+](https://img.shields.io/badge/built%20with-Vite+-646CFF?logo=vite&logoColor=white)](https://viteplus.dev)
4
+ [![tested with vitest](https://img.shields.io/badge/tested%20with-Vitest-6E9F18?logo=vitest&logoColor=white)](https://vitest.dev)
5
+
6
+ Pi extension for managing and importing Agent Skills from Pi, Claude,
7
+ and plugin sources.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pi install npm:@spences10/pi-skills
13
+ ```
14
+
15
+ Local development from this monorepo:
16
+
17
+ ```bash
18
+ pnpm --filter @spences10/pi-skills run build
19
+ pi install ./packages/pi-skills
20
+ # or for one run only
21
+ pi -e ./packages/pi-skills
22
+ ```
23
+
24
+ ## What it does
25
+
26
+ Pi already has native skill discovery. This package adds a management
27
+ layer for mixed skill ecosystems:
28
+
29
+ - discovers Pi-native skills in `~/.pi/agent/skills`
30
+ - discovers user-local Claude skills in `~/.claude/skills`
31
+ - discovers skills bundled inside installed Claude plugins
32
+ - imports plugin skills into Pi-native skill storage
33
+ - syncs imported skills when upstream plugin content changes
34
+ - provides a `/skills` command and interactive picker
35
+
36
+ Imported skills are copied into:
37
+
38
+ ```text
39
+ ~/.pi/agent/skills/<skill-name>
40
+ ```
41
+
42
+ Import metadata is stored beside each imported skill so sync can
43
+ detect local edits and upstream changes.
44
+
45
+ ## Commands
46
+
47
+ ```text
48
+ /skills
49
+ /skills import <key-or-name>
50
+ /skills sync <key-or-name>
51
+ /skills refresh
52
+ /skills defaults all-enabled
53
+ /skills defaults all-disabled
54
+ ```
55
+
56
+ With a UI available, `/skills` opens an interactive manager. In
57
+ headless mode, use the subcommands directly.
58
+
59
+ ## Skill enablement
60
+
61
+ The extension tracks enabled/disabled state in its own config and
62
+ contributes enabled managed skill paths during Pi resource discovery.
63
+
64
+ In a custom harness such as `my-pi`, this can be combined with a
65
+ resource filter to enforce disabled skills. In vanilla `pi`, Pi's own
66
+ default skill discovery can still load skills from default locations,
67
+ so use `pi config` or settings filters when you need hard disable
68
+ semantics.
69
+
70
+ ## Using from a custom harness
71
+
72
+ ```ts
73
+ import skills, { create_skills_manager } from '@spences10/pi-skills';
74
+
75
+ // pass `skills` as an ExtensionFactory to your Pi runtime
76
+ const manager = create_skills_manager();
77
+ ```
78
+
79
+ `my-pi` imports this package directly and uses
80
+ `create_skills_manager()` to enforce its built-in skill toggle
81
+ behavior.
82
+
83
+ ## Development
84
+
85
+ ```bash
86
+ pnpm --filter @spences10/pi-skills run check
87
+ pnpm --filter @spences10/pi-skills run test
88
+ pnpm --filter @spences10/pi-skills run build
89
+ ```
90
+
91
+ ## License
92
+
93
+ MIT
@@ -0,0 +1,10 @@
1
+ export interface SkillsConfig {
2
+ version: number;
3
+ enabled: Record<string, boolean>;
4
+ defaults: 'all-enabled' | 'all-disabled';
5
+ }
6
+ export declare function get_config_path(): string;
7
+ export declare function load_skills_config(): SkillsConfig;
8
+ export declare function save_skills_config(config: SkillsConfig): void;
9
+ export declare function make_skill_key(name: string, source: string): string;
10
+ export declare function is_skill_enabled(config: SkillsConfig, key: string): boolean;
package/dist/config.js ADDED
@@ -0,0 +1,50 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ const DEFAULT_CONFIG = {
5
+ version: 1,
6
+ enabled: {},
7
+ defaults: 'all-disabled',
8
+ };
9
+ export function get_config_path() {
10
+ const xdg = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
11
+ return join(xdg, 'my-pi', 'skills.json');
12
+ }
13
+ export function load_skills_config() {
14
+ const path = get_config_path();
15
+ if (!existsSync(path))
16
+ return { ...DEFAULT_CONFIG };
17
+ try {
18
+ const raw = readFileSync(path, 'utf-8');
19
+ const parsed = JSON.parse(raw);
20
+ return {
21
+ version: parsed.version ?? 1,
22
+ enabled: parsed.enabled ?? {},
23
+ defaults: parsed.defaults ?? 'all-enabled',
24
+ };
25
+ }
26
+ catch {
27
+ return { ...DEFAULT_CONFIG };
28
+ }
29
+ }
30
+ export function save_skills_config(config) {
31
+ const path = get_config_path();
32
+ const dir = dirname(path);
33
+ if (!existsSync(dir)) {
34
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
35
+ }
36
+ const tmp = `${path}.tmp-${Date.now()}`;
37
+ writeFileSync(tmp, JSON.stringify(config, null, '\t') + '\n', {
38
+ mode: 0o600,
39
+ });
40
+ renameSync(tmp, path);
41
+ }
42
+ export function make_skill_key(name, source) {
43
+ return `${name}@${source}`;
44
+ }
45
+ export function is_skill_enabled(config, key) {
46
+ if (key in config.enabled)
47
+ return config.enabled[key];
48
+ return config.defaults === 'all-enabled';
49
+ }
50
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,aAAa,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQ1C,MAAM,cAAc,GAAiB;IACpC,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,cAAc;CACxB,CAAC;AAEF,MAAM,UAAU,eAAe;IAC9B,MAAM,GAAG,GACR,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,kBAAkB;IACjC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAEpD,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA0B,CAAC;QACxD,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC;YAC5B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;YAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,aAAa;SAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACtD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACxC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE;QAC7D,IAAI,EAAE,KAAK;KACX,CAAC,CAAC;IACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAc;IAC1D,OAAO,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,MAAoB,EACpB,GAAW;IAEX,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,QAAQ,KAAK,aAAa,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type DiscoveredSkill, type ImportedSkillMetadata } from './scanner.js';
2
+ export interface ImportSkillResult {
3
+ skillDir: string;
4
+ metadata: ImportedSkillMetadata;
5
+ }
6
+ export declare function import_external_skill(skill: DiscoveredSkill): ImportSkillResult;
7
+ export interface SyncSkillResult {
8
+ skillDir: string;
9
+ metadata: ImportedSkillMetadata;
10
+ changed: boolean;
11
+ }
12
+ export declare function sync_imported_skill(skill: DiscoveredSkill): SyncSkillResult;
@@ -0,0 +1,147 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join, relative, resolve } from 'node:path';
5
+ import { IMPORT_METADATA_FILE, } from './scanner.js';
6
+ const IMPORT_METADATA_VERSION = 1;
7
+ function get_managed_skills_dir() {
8
+ return join(homedir(), '.pi', 'agent', 'skills');
9
+ }
10
+ function ensure_dir(path) {
11
+ mkdirSync(path, { recursive: true, mode: 0o700 });
12
+ }
13
+ function list_files_recursively(dir) {
14
+ const files = [];
15
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
16
+ const full_path = join(dir, entry.name);
17
+ if (entry.name === IMPORT_METADATA_FILE)
18
+ continue;
19
+ if (entry.isDirectory()) {
20
+ files.push(...list_files_recursively(full_path));
21
+ continue;
22
+ }
23
+ if (entry.isFile()) {
24
+ files.push(full_path);
25
+ }
26
+ }
27
+ return files.sort((a, b) => a.localeCompare(b));
28
+ }
29
+ function hash_directory(dir) {
30
+ const hash = createHash('sha256');
31
+ for (const file of list_files_recursively(dir)) {
32
+ hash.update(relative(dir, file));
33
+ hash.update('\0');
34
+ hash.update(readFileSync(file));
35
+ hash.update('\0');
36
+ }
37
+ return hash.digest('hex');
38
+ }
39
+ function read_metadata(base_dir) {
40
+ const path = join(base_dir, IMPORT_METADATA_FILE);
41
+ if (!existsSync(path))
42
+ return undefined;
43
+ try {
44
+ return JSON.parse(readFileSync(path, 'utf-8'));
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ function write_metadata(base_dir, metadata) {
51
+ writeFileSync(join(base_dir, IMPORT_METADATA_FILE), JSON.stringify(metadata, null, '\t') + '\n', { mode: 0o600 });
52
+ }
53
+ function replace_directory(source_dir, dest_dir) {
54
+ const parent_dir = dirname(dest_dir);
55
+ ensure_dir(parent_dir);
56
+ const tmp_dir = join(parent_dir, `.${resolve(dest_dir).split('/').pop()}.tmp-${Date.now()}`);
57
+ rmSync(tmp_dir, { recursive: true, force: true });
58
+ cpSync(source_dir, tmp_dir, {
59
+ recursive: true,
60
+ preserveTimestamps: true,
61
+ verbatimSymlinks: false,
62
+ });
63
+ rmSync(dest_dir, { recursive: true, force: true });
64
+ cpSync(tmp_dir, dest_dir, {
65
+ recursive: true,
66
+ preserveTimestamps: true,
67
+ verbatimSymlinks: false,
68
+ });
69
+ rmSync(tmp_dir, { recursive: true, force: true });
70
+ }
71
+ export function import_external_skill(skill) {
72
+ if (skill.kind !== 'external') {
73
+ throw new Error(`Skill ${skill.name} is not importable`);
74
+ }
75
+ const managed_root = get_managed_skills_dir();
76
+ ensure_dir(managed_root);
77
+ const skill_dir = join(managed_root, skill.name);
78
+ const existing = existsSync(skill_dir);
79
+ if (existing) {
80
+ const existing_stat = statSync(skill_dir);
81
+ if (!existing_stat.isDirectory()) {
82
+ throw new Error(`${skill_dir} exists and is not a directory`);
83
+ }
84
+ const existing_metadata = read_metadata(skill_dir);
85
+ if (!existing_metadata) {
86
+ throw new Error(`Refusing to overwrite existing unmanaged skill at ${skill_dir}`);
87
+ }
88
+ }
89
+ replace_directory(skill.baseDir, skill_dir);
90
+ const upstream_hash = hash_directory(skill.baseDir);
91
+ const imported_hash = hash_directory(skill_dir);
92
+ const now = new Date().toISOString();
93
+ const metadata = {
94
+ version: IMPORT_METADATA_VERSION,
95
+ source: skill.source,
96
+ upstream_skill_path: skill.skillPath,
97
+ upstream_base_dir: skill.baseDir,
98
+ upstream_install_path: skill.plugin?.installPath,
99
+ upstream_version: skill.plugin?.version,
100
+ upstream_git_commit_sha: skill.plugin?.gitCommitSha,
101
+ imported_at: now,
102
+ last_synced_at: now,
103
+ imported_hash,
104
+ upstream_hash,
105
+ };
106
+ write_metadata(skill_dir, metadata);
107
+ return {
108
+ skillDir: skill_dir,
109
+ metadata,
110
+ };
111
+ }
112
+ export function sync_imported_skill(skill) {
113
+ if (skill.kind !== 'managed' || !skill.import_meta) {
114
+ throw new Error(`Skill ${skill.name} is not managed by my-pi sync`);
115
+ }
116
+ const metadata = skill.import_meta;
117
+ if (!existsSync(metadata.upstream_base_dir)) {
118
+ throw new Error(`Upstream source no longer exists: ${metadata.upstream_base_dir}`);
119
+ }
120
+ const current_hash = hash_directory(skill.baseDir);
121
+ if (current_hash !== metadata.imported_hash) {
122
+ throw new Error(`Refusing to sync ${skill.name}; local changes detected in ${skill.baseDir}`);
123
+ }
124
+ const upstream_hash = hash_directory(metadata.upstream_base_dir);
125
+ if (upstream_hash === metadata.upstream_hash) {
126
+ return {
127
+ skillDir: skill.baseDir,
128
+ metadata,
129
+ changed: false,
130
+ };
131
+ }
132
+ replace_directory(metadata.upstream_base_dir, skill.baseDir);
133
+ const imported_hash = hash_directory(skill.baseDir);
134
+ const updated = {
135
+ ...metadata,
136
+ last_synced_at: new Date().toISOString(),
137
+ imported_hash,
138
+ upstream_hash,
139
+ };
140
+ write_metadata(skill.baseDir, updated);
141
+ return {
142
+ skillDir: skill.baseDir,
143
+ metadata: updated,
144
+ changed: true,
145
+ };
146
+ }
147
+ //# sourceMappingURL=importer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';
2
+ export { create_skills_manager } from './manager.js';
3
+ export type { ManagedSkill, SkillsManager } from './manager.js';
4
+ export default function skills(pi: ExtensionAPI): Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,414 @@
1
+ import { Container, SettingsList, Text, } from '@mariozechner/pi-tui';
2
+ import { create_skills_manager, } from './manager.js';
3
+ export { create_skills_manager } from './manager.js';
4
+ const ENABLED = '[x]';
5
+ const DISABLED = '[ ]';
6
+ const SYNC = '[~]';
7
+ const IMPORTED_LABEL = '[=]';
8
+ function sort_skills(skills) {
9
+ return [...skills].sort((a, b) => {
10
+ const by_name = a.name.localeCompare(b.name);
11
+ if (by_name !== 0)
12
+ return by_name;
13
+ const by_source = a.source.localeCompare(b.source);
14
+ if (by_source !== 0)
15
+ return by_source;
16
+ return a.key.localeCompare(b.key);
17
+ });
18
+ }
19
+ function find_matching_imported_skill(managed_skills, skill) {
20
+ const exact_match = managed_skills.find((candidate) => candidate.import_meta?.source === skill.source &&
21
+ (candidate.import_meta.upstream_skill_path ===
22
+ skill.skillPath ||
23
+ candidate.import_meta.upstream_base_dir === skill.baseDir));
24
+ if (exact_match)
25
+ return exact_match;
26
+ return managed_skills.find((candidate) => candidate.import_meta?.source === skill.source &&
27
+ candidate.name === skill.name);
28
+ }
29
+ function get_importable_state(managed_skills, skill) {
30
+ const imported = find_matching_imported_skill(managed_skills, skill);
31
+ if (imported?.import_meta) {
32
+ const version_changed = Boolean(skill.plugin?.version &&
33
+ imported.import_meta.upstream_version &&
34
+ skill.plugin.version !== imported.import_meta.upstream_version);
35
+ const sha_changed = Boolean(skill.plugin?.gitCommitSha &&
36
+ imported.import_meta.upstream_git_commit_sha &&
37
+ skill.plugin.gitCommitSha !==
38
+ imported.import_meta.upstream_git_commit_sha);
39
+ if (version_changed || sha_changed) {
40
+ return {
41
+ label: 'sync',
42
+ detail: 'Press Enter to sync the imported copy and reload',
43
+ action: 'sync',
44
+ };
45
+ }
46
+ return {
47
+ label: 'imported',
48
+ detail: `Already imported to ${imported.baseDir}`,
49
+ action: null,
50
+ };
51
+ }
52
+ const managed_conflict = managed_skills.find((candidate) => candidate.name === skill.name);
53
+ if (managed_conflict) {
54
+ return {
55
+ label: 'managed',
56
+ detail: `Already managed at ${managed_conflict.baseDir}`,
57
+ action: null,
58
+ };
59
+ }
60
+ return {
61
+ label: 'import',
62
+ detail: 'Press Enter to import into pi-native skills and reload',
63
+ action: 'import',
64
+ };
65
+ }
66
+ function to_setting_item(skill) {
67
+ const detail_lines = [
68
+ `${skill.source} • ${skill.key}`,
69
+ skill.description,
70
+ skill.baseDir,
71
+ ];
72
+ if (skill.import_meta?.upstream_version) {
73
+ detail_lines.push(`upstream: ${skill.import_meta.upstream_version}${skill.import_meta.upstream_git_commit_sha ? ` • ${skill.import_meta.upstream_git_commit_sha.slice(0, 12)}` : ''}`);
74
+ }
75
+ return {
76
+ id: skill.key,
77
+ label: skill.name,
78
+ description: detail_lines.join('\n'),
79
+ currentValue: skill.enabled ? ENABLED : DISABLED,
80
+ values: [ENABLED, DISABLED],
81
+ };
82
+ }
83
+ function to_importable_setting_item(managed_skills, skill) {
84
+ const state = get_importable_state(managed_skills, skill);
85
+ const detail_lines = [
86
+ `${skill.source} • ${skill.key}`,
87
+ skill.description,
88
+ skill.baseDir,
89
+ ];
90
+ if (skill.plugin?.version) {
91
+ detail_lines.push(`plugin: ${skill.plugin.version}${skill.plugin.gitCommitSha ? ` • ${skill.plugin.gitCommitSha.slice(0, 12)}` : ''}`);
92
+ }
93
+ if (state.action === 'import') {
94
+ return {
95
+ id: skill.key,
96
+ label: skill.name,
97
+ description: detail_lines.join('\n'),
98
+ currentValue: DISABLED,
99
+ values: [ENABLED, DISABLED],
100
+ };
101
+ }
102
+ if (state.action === 'sync') {
103
+ detail_lines.push('enter to sync');
104
+ return {
105
+ id: skill.key,
106
+ label: skill.name,
107
+ description: detail_lines.join('\n'),
108
+ currentValue: SYNC,
109
+ values: [SYNC],
110
+ };
111
+ }
112
+ detail_lines.push(state.detail);
113
+ return {
114
+ id: skill.key,
115
+ label: skill.name,
116
+ description: detail_lines.join('\n'),
117
+ currentValue: IMPORTED_LABEL,
118
+ };
119
+ }
120
+ function sets_equal(a, b) {
121
+ if (a.size !== b.size)
122
+ return false;
123
+ for (const value of a) {
124
+ if (!b.has(value))
125
+ return false;
126
+ }
127
+ return true;
128
+ }
129
+ // Default export for Pi Package / additionalExtensionPaths loading
130
+ export default async function skills(pi) {
131
+ const mgr = create_skills_manager();
132
+ const subs = ['import', 'sync', 'refresh', 'defaults'];
133
+ pi.registerCommand('skills', {
134
+ description: 'Manage pi-native skills and import external skills',
135
+ getArgumentCompletions: (prefix) => {
136
+ const parts = prefix.trim().split(/\s+/);
137
+ if (parts.length <= 1) {
138
+ return subs
139
+ .filter((s) => s.startsWith(parts[0] || ''))
140
+ .map((s) => ({ value: s, label: s }));
141
+ }
142
+ if (parts[0] === 'import') {
143
+ const q = parts.slice(1).join(' ').toLowerCase();
144
+ return sort_skills(mgr.discover_importable())
145
+ .filter((s) => s.key.toLowerCase().includes(q) ||
146
+ s.name.toLowerCase().includes(q))
147
+ .slice(0, 20)
148
+ .map((s) => ({
149
+ value: `${parts[0]} ${s.key}`,
150
+ label: s.key,
151
+ }));
152
+ }
153
+ if (parts[0] === 'sync') {
154
+ const q = parts.slice(1).join(' ').toLowerCase();
155
+ return sort_skills(mgr
156
+ .discover()
157
+ .filter((skill) => Boolean(skill.import_meta)))
158
+ .filter((s) => s.key.toLowerCase().includes(q) ||
159
+ s.name.toLowerCase().includes(q))
160
+ .slice(0, 20)
161
+ .map((s) => ({
162
+ value: `${parts[0]} ${s.key}`,
163
+ label: s.key,
164
+ }));
165
+ }
166
+ return null;
167
+ },
168
+ handler: async (args, ctx) => {
169
+ const trimmed = args.trim();
170
+ if (!trimmed && ctx.hasUI) {
171
+ const discovered = sort_skills(mgr.discover());
172
+ const importable = sort_skills(mgr.discover_importable());
173
+ if (discovered.length === 0 && importable.length === 0) {
174
+ ctx.ui.notify('No managed or importable skills found');
175
+ return;
176
+ }
177
+ const initial_enabled = new Set(discovered
178
+ .filter((skill) => skill.enabled)
179
+ .map((skill) => skill.key));
180
+ const current_enabled = new Set(initial_enabled);
181
+ const queued_imports = new Set();
182
+ let reload_notice = null;
183
+ const managed_items = discovered.map(to_setting_item);
184
+ const importable_items = importable.map((skill) => to_importable_setting_item(discovered, skill));
185
+ const all_items = [];
186
+ if (managed_items.length > 0) {
187
+ all_items.push({
188
+ id: '__header_managed__',
189
+ label: `── Managed (${managed_items.length}) ──`,
190
+ description: '',
191
+ currentValue: '',
192
+ });
193
+ all_items.push(...managed_items);
194
+ }
195
+ if (importable_items.length > 0) {
196
+ all_items.push({
197
+ id: '__header_importable__',
198
+ label: `── Importable (${importable_items.length}) ──`,
199
+ description: '',
200
+ currentValue: '',
201
+ });
202
+ all_items.push(...importable_items);
203
+ }
204
+ const managed_keys = new Set(discovered.map((s) => s.key));
205
+ const importable_map = new Map(importable.map((s) => [s.key, s]));
206
+ await ctx.ui.custom((tui, theme, _kb, done) => {
207
+ const list = new SettingsList(all_items, Math.min(Math.max(all_items.length + 4, 8), 22), {
208
+ cursor: theme.fg('accent', '›'),
209
+ label: (text, selected) => {
210
+ if (text.startsWith('──') && text.endsWith('──')) {
211
+ return theme.fg('dim', theme.bold(text));
212
+ }
213
+ return selected ? theme.fg('accent', text) : text;
214
+ },
215
+ value: (text, selected) => {
216
+ const color = text === ENABLED
217
+ ? 'success'
218
+ : text === SYNC
219
+ ? 'warning'
220
+ : text === IMPORTED_LABEL
221
+ ? 'success'
222
+ : 'dim';
223
+ const rendered = theme.fg(color, text);
224
+ return selected
225
+ ? theme.bold(theme.fg('accent', rendered))
226
+ : rendered;
227
+ },
228
+ description: (text) => theme.fg('muted', text),
229
+ hint: (text) => theme.fg('dim', text),
230
+ }, (id, new_value) => {
231
+ if (id.startsWith('__header_'))
232
+ return;
233
+ if (managed_keys.has(id)) {
234
+ if (new_value === ENABLED) {
235
+ current_enabled.add(id);
236
+ mgr.enable(id);
237
+ }
238
+ else {
239
+ current_enabled.delete(id);
240
+ mgr.disable(id);
241
+ }
242
+ return;
243
+ }
244
+ const import_skill = importable_map.get(id);
245
+ if (!import_skill)
246
+ return;
247
+ const state = get_importable_state(discovered, import_skill);
248
+ if (state.action === 'import') {
249
+ if (new_value === ENABLED) {
250
+ queued_imports.add(id);
251
+ }
252
+ else {
253
+ queued_imports.delete(id);
254
+ }
255
+ return;
256
+ }
257
+ if (state.action === 'sync') {
258
+ const imported_skill = find_matching_imported_skill(discovered, import_skill);
259
+ if (!imported_skill) {
260
+ ctx.ui.notify(`Imported copy for ${import_skill.name} was not found`, 'warning');
261
+ return;
262
+ }
263
+ try {
264
+ const result = mgr.sync_skill(imported_skill.key);
265
+ if (result.changed) {
266
+ reload_notice = `Synced ${import_skill.name}. Reloading...`;
267
+ done(undefined);
268
+ }
269
+ else {
270
+ ctx.ui.notify(`${import_skill.name} is already up to date.`, 'info');
271
+ }
272
+ }
273
+ catch (error) {
274
+ ctx.ui.notify(error instanceof Error
275
+ ? error.message
276
+ : String(error), 'warning');
277
+ }
278
+ }
279
+ }, () => done(undefined), { enableSearch: true });
280
+ const container = new Container();
281
+ container.addChild({
282
+ render: () => {
283
+ const enabled = current_enabled.size;
284
+ const disabled = discovered.length - enabled;
285
+ const queued = queued_imports.size;
286
+ const parts = [
287
+ `${enabled} enabled`,
288
+ `${disabled} disabled`,
289
+ ];
290
+ if (importable.length > 0) {
291
+ parts.push(`${importable.length} importable`);
292
+ }
293
+ if (queued > 0) {
294
+ parts.push(`${queued} queued for import`);
295
+ }
296
+ return [
297
+ theme.fg('accent', theme.bold('Skills')),
298
+ theme.fg('muted', parts.join(' • ')),
299
+ '',
300
+ ];
301
+ },
302
+ invalidate: () => { },
303
+ });
304
+ container.addChild({
305
+ render(width) {
306
+ return list.render(width);
307
+ },
308
+ invalidate() {
309
+ list.invalidate();
310
+ },
311
+ });
312
+ container.addChild(new Text(theme.fg('dim', 'search filters • enter toggles • esc close'), 0, 1));
313
+ return {
314
+ render(width) {
315
+ return container.render(width);
316
+ },
317
+ invalidate() {
318
+ container.invalidate();
319
+ },
320
+ handleInput(data) {
321
+ list.handleInput(data);
322
+ tui.requestRender();
323
+ },
324
+ };
325
+ });
326
+ if (queued_imports.size > 0) {
327
+ const imported_names = [];
328
+ for (const key of queued_imports) {
329
+ try {
330
+ mgr.import_skill(key);
331
+ imported_names.push(key);
332
+ }
333
+ catch (error) {
334
+ ctx.ui.notify(error instanceof Error
335
+ ? error.message
336
+ : String(error), 'warning');
337
+ }
338
+ }
339
+ if (imported_names.length > 0) {
340
+ reload_notice = `Imported ${imported_names.length} skill(s). Reloading...`;
341
+ }
342
+ }
343
+ if (reload_notice) {
344
+ ctx.ui.notify(reload_notice, 'info');
345
+ await ctx.reload();
346
+ return;
347
+ }
348
+ if (!sets_equal(initial_enabled, current_enabled)) {
349
+ ctx.ui.notify('Reloading to apply updated skills...', 'info');
350
+ await ctx.reload();
351
+ return;
352
+ }
353
+ return;
354
+ }
355
+ const [sub, ...rest] = (trimmed || 'list').split(/\s+/);
356
+ const arg = rest.join(' ');
357
+ switch (sub) {
358
+ case 'import': {
359
+ if (!arg) {
360
+ ctx.ui.notify('Usage: /skills import <key|name>', 'warning');
361
+ return;
362
+ }
363
+ try {
364
+ const result = mgr.import_skill(arg);
365
+ ctx.ui.notify(`Imported ${arg} to ${result.skillDir}. Reloading...`, 'info');
366
+ await ctx.reload();
367
+ return;
368
+ }
369
+ catch (error) {
370
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), 'warning');
371
+ return;
372
+ }
373
+ }
374
+ case 'sync': {
375
+ if (!arg) {
376
+ ctx.ui.notify('Usage: /skills sync <key|name>', 'warning');
377
+ return;
378
+ }
379
+ try {
380
+ const result = mgr.sync_skill(arg);
381
+ ctx.ui.notify(result.changed
382
+ ? `Synced ${arg}. Reloading...`
383
+ : `${arg} is already up to date.`, 'info');
384
+ if (result.changed) {
385
+ await ctx.reload();
386
+ }
387
+ return;
388
+ }
389
+ catch (error) {
390
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), 'warning');
391
+ return;
392
+ }
393
+ }
394
+ case 'refresh': {
395
+ mgr.refresh();
396
+ ctx.ui.notify(`Rescanned: ${mgr.discover().length} managed skills, ${mgr.discover_importable().length} importable skills found`);
397
+ break;
398
+ }
399
+ case 'defaults': {
400
+ if (arg !== 'all-enabled' && arg !== 'all-disabled') {
401
+ ctx.ui.notify('Usage: /skills defaults <all-enabled|all-disabled>', 'warning');
402
+ return;
403
+ }
404
+ mgr.set_defaults(arg);
405
+ ctx.ui.notify(`Default policy: ${arg}`);
406
+ break;
407
+ }
408
+ default:
409
+ ctx.ui.notify(`Unknown: ${sub}. Use: ${subs.join(', ')}`, 'warning');
410
+ }
411
+ },
412
+ });
413
+ }
414
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type ImportSkillResult, type SyncSkillResult } from './importer.js';
2
+ import { type DiscoveredSkill } from './scanner.js';
3
+ export interface ManagedSkill extends DiscoveredSkill {
4
+ key: string;
5
+ enabled: boolean;
6
+ }
7
+ export interface SkillsManager {
8
+ discover(): ManagedSkill[];
9
+ discover_importable(): ManagedSkill[];
10
+ get_enabled_skill_paths(): string[];
11
+ /** Check if a skill should pass through pi's skillsOverride */
12
+ is_enabled_by_skill(name: string, filePath: string): boolean;
13
+ enable(key: string): boolean;
14
+ disable(key: string): boolean;
15
+ toggle(key: string): boolean;
16
+ search(query: string): ManagedSkill[];
17
+ search_importable(query: string): ManagedSkill[];
18
+ set_defaults(policy: 'all-enabled' | 'all-disabled'): void;
19
+ import_skill(key_or_name: string): ImportSkillResult & {
20
+ key: string;
21
+ };
22
+ sync_skill(key_or_name: string): SyncSkillResult & {
23
+ key: string;
24
+ };
25
+ refresh(): void;
26
+ }
27
+ export declare function create_skills_manager(): SkillsManager;
@@ -0,0 +1,135 @@
1
+ import { is_skill_enabled, load_skills_config, make_skill_key, save_skills_config, } from './config.js';
2
+ import { import_external_skill, sync_imported_skill, } from './importer.js';
3
+ import { scan_importable_skills, scan_managed_skills, } from './scanner.js';
4
+ function resolve_skill_key(skill) {
5
+ return make_skill_key(skill.name, skill.source);
6
+ }
7
+ function match_skill_by_key_or_name(skills, key_or_name) {
8
+ const exact_key = skills.find((skill) => resolve_skill_key(skill) === key_or_name);
9
+ if (exact_key)
10
+ return exact_key;
11
+ const by_name = skills.filter((skill) => skill.name === key_or_name);
12
+ if (by_name.length === 1) {
13
+ return by_name[0];
14
+ }
15
+ if (by_name.length > 1) {
16
+ throw new Error(`Multiple skills named ${key_or_name}. Use an exact key instead.`);
17
+ }
18
+ throw new Error(`Unknown skill: ${key_or_name}`);
19
+ }
20
+ export function create_skills_manager() {
21
+ let config = load_skills_config();
22
+ let managed_cache = null;
23
+ let importable_cache = null;
24
+ function get_managed() {
25
+ if (!managed_cache) {
26
+ managed_cache = scan_managed_skills();
27
+ }
28
+ return managed_cache;
29
+ }
30
+ function get_importable() {
31
+ if (!importable_cache) {
32
+ importable_cache = scan_importable_skills();
33
+ }
34
+ return importable_cache;
35
+ }
36
+ function to_managed(skill) {
37
+ const key = resolve_skill_key(skill);
38
+ return {
39
+ ...skill,
40
+ key,
41
+ enabled: skill.kind === 'managed'
42
+ ? is_skill_enabled(config, key)
43
+ : false,
44
+ };
45
+ }
46
+ function get_enabled_managed_skills() {
47
+ return get_managed()
48
+ .filter((skill) => is_skill_enabled(config, resolve_skill_key(skill)))
49
+ .map(to_managed);
50
+ }
51
+ return {
52
+ discover() {
53
+ return get_managed().map(to_managed);
54
+ },
55
+ discover_importable() {
56
+ return get_importable().map(to_managed);
57
+ },
58
+ is_enabled_by_skill(name, filePath) {
59
+ const discovered = get_managed();
60
+ const match = discovered.find((s) => s.skillPath === filePath);
61
+ if (match) {
62
+ return is_skill_enabled(config, resolve_skill_key(match));
63
+ }
64
+ const by_name = discovered.find((s) => s.name === name);
65
+ if (by_name) {
66
+ return is_skill_enabled(config, resolve_skill_key(by_name));
67
+ }
68
+ // Unknown skill sources should remain enabled so pi's native
69
+ // discovery keeps working for project and other default locations.
70
+ return true;
71
+ },
72
+ get_enabled_skill_paths() {
73
+ return get_enabled_managed_skills().map((skill) => skill.baseDir);
74
+ },
75
+ enable(key) {
76
+ config.enabled[key] = true;
77
+ save_skills_config(config);
78
+ return true;
79
+ },
80
+ disable(key) {
81
+ config.enabled[key] = false;
82
+ save_skills_config(config);
83
+ return false;
84
+ },
85
+ toggle(key) {
86
+ const current = is_skill_enabled(config, key);
87
+ config.enabled[key] = !current;
88
+ save_skills_config(config);
89
+ return !current;
90
+ },
91
+ search(query) {
92
+ const q = query.toLowerCase();
93
+ return this.discover().filter((s) => s.name.toLowerCase().includes(q) ||
94
+ s.description.toLowerCase().includes(q) ||
95
+ s.source.toLowerCase().includes(q));
96
+ },
97
+ search_importable(query) {
98
+ const q = query.toLowerCase();
99
+ return this.discover_importable().filter((s) => s.name.toLowerCase().includes(q) ||
100
+ s.description.toLowerCase().includes(q) ||
101
+ s.source.toLowerCase().includes(q));
102
+ },
103
+ set_defaults(policy) {
104
+ config.defaults = policy;
105
+ save_skills_config(config);
106
+ },
107
+ import_skill(key_or_name) {
108
+ const skill = match_skill_by_key_or_name(get_importable(), key_or_name);
109
+ const result = import_external_skill(skill);
110
+ const managed_key = make_skill_key(skill.name, 'pi-native');
111
+ config.enabled[managed_key] = true;
112
+ save_skills_config(config);
113
+ this.refresh();
114
+ return {
115
+ ...result,
116
+ key: managed_key,
117
+ };
118
+ },
119
+ sync_skill(key_or_name) {
120
+ const skill = match_skill_by_key_or_name(get_managed(), key_or_name);
121
+ const result = sync_imported_skill(skill);
122
+ this.refresh();
123
+ return {
124
+ ...result,
125
+ key: resolve_skill_key(skill),
126
+ };
127
+ },
128
+ refresh() {
129
+ managed_cache = null;
130
+ importable_cache = null;
131
+ config = load_skills_config();
132
+ },
133
+ };
134
+ }
135
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export declare const IMPORT_METADATA_FILE = ".my-pi-source.json";
2
+ export interface InstalledPlugin {
3
+ scope: string;
4
+ installPath: string;
5
+ version: string;
6
+ installedAt?: string;
7
+ lastUpdated?: string;
8
+ gitCommitSha?: string;
9
+ }
10
+ export interface ImportedSkillMetadata {
11
+ version: number;
12
+ source: string;
13
+ upstream_skill_path: string;
14
+ upstream_base_dir: string;
15
+ upstream_install_path?: string;
16
+ upstream_version?: string;
17
+ upstream_git_commit_sha?: string;
18
+ imported_at: string;
19
+ last_synced_at: string;
20
+ imported_hash: string;
21
+ upstream_hash: string;
22
+ }
23
+ export interface PluginSkillSource {
24
+ pluginId: string;
25
+ installPath: string;
26
+ version: string;
27
+ gitCommitSha?: string;
28
+ }
29
+ export interface DiscoveredSkill {
30
+ name: string;
31
+ description: string;
32
+ skillPath: string;
33
+ baseDir: string;
34
+ source: string;
35
+ kind: 'managed' | 'external';
36
+ plugin?: PluginSkillSource;
37
+ import_meta?: ImportedSkillMetadata;
38
+ }
39
+ export declare function scan_managed_skills(): DiscoveredSkill[];
40
+ export declare function scan_importable_skills(): DiscoveredSkill[];
41
+ export declare function scan_all_skills(): DiscoveredSkill[];
@@ -0,0 +1,169 @@
1
+ import { parseFrontmatter, } from '@mariozechner/pi-coding-agent';
2
+ import { existsSync, globSync, readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { basename, dirname, join, resolve } from 'node:path';
5
+ export const IMPORT_METADATA_FILE = '.my-pi-source.json';
6
+ function read_installed_plugins() {
7
+ const path = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
8
+ if (!existsSync(path))
9
+ return null;
10
+ try {
11
+ return JSON.parse(readFileSync(path, 'utf-8'));
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ function parse_skill_md(skill_path) {
18
+ try {
19
+ const content = readFileSync(skill_path, 'utf-8');
20
+ const { frontmatter } = parseFrontmatter(content);
21
+ const description = frontmatter?.description;
22
+ if (!description)
23
+ return null;
24
+ const name = frontmatter?.name || basename(dirname(skill_path));
25
+ return { name, description: description.trim() };
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function read_import_metadata(base_dir) {
32
+ const metadata_path = join(base_dir, IMPORT_METADATA_FILE);
33
+ if (!existsSync(metadata_path))
34
+ return undefined;
35
+ try {
36
+ return JSON.parse(readFileSync(metadata_path, 'utf-8'));
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ function scan_dir_for_skills(dir, options) {
43
+ if (!existsSync(dir))
44
+ return [];
45
+ const results = [];
46
+ const direct = join(dir, 'SKILL.md');
47
+ const include_direct_root_skill = options.include_direct_root_skill ?? true;
48
+ if (include_direct_root_skill && existsSync(direct)) {
49
+ const parsed = parse_skill_md(direct);
50
+ if (parsed) {
51
+ results.push({
52
+ ...parsed,
53
+ skillPath: direct,
54
+ baseDir: dir,
55
+ source: options.source,
56
+ kind: options.kind,
57
+ plugin: options.plugin,
58
+ import_meta: options.kind === 'managed'
59
+ ? read_import_metadata(dir)
60
+ : undefined,
61
+ });
62
+ }
63
+ return results;
64
+ }
65
+ try {
66
+ const matches = globSync('*/SKILL.md', { cwd: dir });
67
+ for (const match of matches) {
68
+ const full_path = resolve(dir, match);
69
+ const parsed = parse_skill_md(full_path);
70
+ if (parsed) {
71
+ const base_dir = dirname(full_path);
72
+ results.push({
73
+ ...parsed,
74
+ skillPath: full_path,
75
+ baseDir: base_dir,
76
+ source: options.source,
77
+ kind: options.kind,
78
+ plugin: options.plugin,
79
+ import_meta: options.kind === 'managed'
80
+ ? read_import_metadata(base_dir)
81
+ : undefined,
82
+ });
83
+ }
84
+ }
85
+ }
86
+ catch {
87
+ // skip inaccessible dirs
88
+ }
89
+ return results;
90
+ }
91
+ function dedupe_by_skill_path(skills) {
92
+ const seen = new Set();
93
+ const deduped = [];
94
+ for (const skill of skills) {
95
+ if (seen.has(skill.skillPath))
96
+ continue;
97
+ seen.add(skill.skillPath);
98
+ deduped.push(skill);
99
+ }
100
+ return deduped;
101
+ }
102
+ export function scan_managed_skills() {
103
+ const skills = [];
104
+ for (const skill of scan_dir_for_skills(join(homedir(), '.claude', 'skills'), {
105
+ source: 'user-local',
106
+ kind: 'managed',
107
+ })) {
108
+ skills.push(skill);
109
+ }
110
+ for (const skill of scan_dir_for_skills(join(homedir(), '.pi', 'agent', 'skills'), {
111
+ source: 'pi-native',
112
+ kind: 'managed',
113
+ include_direct_root_skill: false,
114
+ })) {
115
+ skills.push(skill);
116
+ }
117
+ return dedupe_by_skill_path(skills);
118
+ }
119
+ export function scan_importable_skills() {
120
+ const skills = [];
121
+ const plugins = read_installed_plugins();
122
+ if (!plugins?.plugins)
123
+ return skills;
124
+ for (const [plugin_id, entries] of Object.entries(plugins.plugins)) {
125
+ const entry = entries[0];
126
+ if (!entry?.installPath || !existsSync(entry.installPath))
127
+ continue;
128
+ const source = `plugin:${plugin_id}`;
129
+ const plugin = {
130
+ pluginId: plugin_id,
131
+ installPath: entry.installPath,
132
+ version: entry.version,
133
+ gitCommitSha: entry.gitCommitSha,
134
+ };
135
+ for (const skill of scan_dir_for_skills(join(entry.installPath, 'skills'), {
136
+ source,
137
+ kind: 'external',
138
+ plugin,
139
+ })) {
140
+ skills.push(skill);
141
+ }
142
+ for (const skill of scan_dir_for_skills(join(entry.installPath, '.pi', 'skills'), {
143
+ source,
144
+ kind: 'external',
145
+ plugin,
146
+ })) {
147
+ skills.push(skill);
148
+ }
149
+ const direct_root_skill = join(entry.installPath, 'SKILL.md');
150
+ if (existsSync(direct_root_skill)) {
151
+ const parsed = parse_skill_md(direct_root_skill);
152
+ if (parsed) {
153
+ skills.push({
154
+ ...parsed,
155
+ skillPath: direct_root_skill,
156
+ baseDir: entry.installPath,
157
+ source,
158
+ kind: 'external',
159
+ plugin,
160
+ });
161
+ }
162
+ }
163
+ }
164
+ return dedupe_by_skill_path(skills);
165
+ }
166
+ export function scan_all_skills() {
167
+ return [...scan_managed_skills(), ...scan_importable_skills()];
168
+ }
169
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,gBAAgB,GAEhB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,CAAC,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAgDzD,SAAS,sBAAsB;IAC9B,MAAM,IAAI,GAAG,IAAI,CAChB,OAAO,EAAE,EACT,SAAS,EACT,SAAS,EACT,wBAAwB,CACxB,CAAC;IACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAChB,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CACH,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,SAAS,cAAc,CACtB,UAAkB;IAElB,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,EAAE,WAAW,EAAE,GACpB,gBAAgB,CAAmB,OAAO,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,WAAW,EAAE,WAAW,CAAC;QAC7C,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAE9B,MAAM,IAAI,GAAG,WAAW,EAAE,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAChE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,SAAS,oBAAoB,CAC5B,QAAgB;IAEhB,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IAC3D,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,SAAS,CAAC;IAEjD,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAChB,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CACX,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAC3B,GAAW,EACX,OAKC;IAED,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACrC,MAAM,yBAAyB,GAC9B,OAAO,CAAC,yBAAyB,IAAI,IAAI,CAAC;IAE3C,IAAI,yBAAyB,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC;gBACZ,GAAG,MAAM;gBACT,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,GAAG;gBACZ,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,WAAW,EACV,OAAO,CAAC,IAAI,KAAK,SAAS;oBACzB,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC;oBAC3B,CAAC,CAAC,SAAS;aACb,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACrD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC;oBACZ,GAAG,MAAM;oBACT,SAAS,EAAE,SAAS;oBACpB,OAAO,EAAE,QAAQ;oBACjB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,WAAW,EACV,OAAO,CAAC,IAAI,KAAK,SAAS;wBACzB,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC;wBAChC,CAAC,CAAC,SAAS;iBACb,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,yBAAyB;IAC1B,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,oBAAoB,CAC5B,MAAyB;IAEzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;YAAE,SAAS;QACxC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB;IAClC,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,KAAK,IAAI,mBAAmB,CACtC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EACpC;QACC,MAAM,EAAE,YAAY;QACpB,IAAI,EAAE,SAAS;KACf,CACD,EAAE,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,mBAAmB,CACtC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EACzC;QACC,MAAM,EAAE,WAAW;QACnB,IAAI,EAAE,SAAS;QACf,yBAAyB,EAAE,KAAK;KAChC,CACD,EAAE,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACrC,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE,OAAO;QAAE,OAAO,MAAM,CAAC;IAErC,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAChD,OAAO,CAAC,OAAO,CACf,EAAE,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;YACxD,SAAS;QAEV,MAAM,MAAM,GAAG,UAAU,SAAS,EAAE,CAAC;QACrC,MAAM,MAAM,GAAsB;YACjC,QAAQ,EAAE,SAAS;YACnB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;SAChC,CAAC;QAEF,KAAK,MAAM,KAAK,IAAI,mBAAmB,CACtC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,EACjC;YACC,MAAM;YACN,IAAI,EAAE,UAAU;YAChB,MAAM;SACN,CACD,EAAE,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,mBAAmB,CACtC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,EACxC;YACC,MAAM;YACN,IAAI,EAAE,UAAU;YAChB,MAAM;SACN,CACD,EAAE,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAC9D,IAAI,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;YACjD,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC;oBACX,GAAG,MAAM;oBACT,SAAS,EAAE,iBAAiB;oBAC5B,OAAO,EAAE,KAAK,CAAC,WAAW;oBAC1B,MAAM;oBACN,IAAI,EAAE,UAAU;oBAChB,MAAM;iBACN,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,CAAC,GAAG,mBAAmB,EAAE,EAAE,GAAG,sBAAsB,EAAE,CAAC,CAAC;AAChE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@spences10/pi-skills",
3
+ "version": "0.0.1",
4
+ "description": "Pi extension for managing and importing Agent Skills from Pi, Claude, and plugin sources",
5
+ "keywords": [
6
+ "agent-skills",
7
+ "pi",
8
+ "pi-package",
9
+ "skills"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "Scott Spence <me@scottspence.com>",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/spences10/my-pi.git",
16
+ "directory": "packages/pi-skills"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "type": "module",
23
+ "main": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ }
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "dependencies": {
35
+ "@mariozechner/pi-coding-agent": "^0.70.2",
36
+ "@mariozechner/pi-tui": "^0.70.2"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^25.6.0",
40
+ "typescript": "^5.9.3",
41
+ "vitest": "^4.1.5"
42
+ },
43
+ "engines": {
44
+ "node": ">=22.0.0"
45
+ },
46
+ "pi": {
47
+ "extensions": [
48
+ "./dist/index.js"
49
+ ]
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.build.json",
53
+ "check": "tsc --noEmit -p tsconfig.json",
54
+ "test": "vitest run"
55
+ }
56
+ }