pi-skillful 0.3.7 → 0.3.9

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 CHANGED
@@ -1,11 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.9 - 2026-06-14
4
+
3
5
  All notable changes to this project will be documented in this file.
4
6
 
5
7
  This project follows the spirit of [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and uses semantic versioning for releases.
6
8
 
7
9
  ## [Unreleased]
8
10
 
11
+ ### Fixed
12
+
13
+ - Skipped Pi package-bundled skills when applying hidden-skill and toggle-slot configuration so `skillful` only affects global and project skills.
14
+
15
+ ## [0.3.8] - 2026-06-06
16
+
17
+ ### Changed
18
+
19
+ - Aligned package structure with monorepo guidelines (added root `index.ts` re-export, `src/index.ts`, fixed extension entry point).
20
+ - Update `author` field to full name for monorepo consistency.
21
+
9
22
  ## [0.3.7] - 2026-05-20
10
23
 
11
24
  ### Changed
package/README.md CHANGED
@@ -37,6 +37,8 @@ Hidden skills:
37
37
  - remain loaded by Pi;
38
38
  - remain available for explicit invocation with `/skill:name`, including inline invocation.
39
39
 
40
+ Skills bundled in Pi packages are never affected by `skillful`; only global and project skills can be hidden or toggled.
41
+
40
42
  Configuration is stored under the `skillful` key in Pi settings:
41
43
 
42
44
  ```json
@@ -60,7 +62,7 @@ Open the menu with:
60
62
  /skillful
61
63
  ```
62
64
 
63
- The menu lists all loaded skills alphabetically. Toggle a skill off or on in the active scope. Use the Global/Project tabs to choose which settings file to edit. In the Project tab, inherited on/off values are shown normally; project overrides are highlighted. Press `1` through `9` on a selected skill to assign or clear that scope's session toggle slot. Visibility and toggle slots are independent.
65
+ The menu lists configurable skills alphabetically. Toggle a skill off or on in the active scope. Use the Global/Project tabs to choose which settings file to edit. In the Project tab, inherited on/off values are shown normally; project overrides are highlighted. Press `1` through `9` on a selected skill to assign or clear that scope's session toggle slot. Visibility and toggle slots are independent.
64
66
 
65
67
  Pi's startup `[Skills]` list also highlights hidden skills in the error color (red in the default dark theme).
66
68
 
@@ -88,7 +90,7 @@ Configured slots appear on the prompt editor's top border as `N skill-name`. Pro
88
90
 
89
91
  `toggleModifier` defaults to `"alt"`. Supported values are `"alt"`, `"ctrl"`, `"ctrl+shift"`, `"alt+shift"`, `"ctrl+alt"`, and `"ctrl+alt+shift"`. Change it if your terminal reserves `alt+number` shortcuts.
90
92
 
91
- On app startup, non-hidden skills are active and hidden skills are inactive. Within a running Pi process, `/new` preserves the current toggle state for the new session. Resuming, forking, cloning, reloading, or restarting Pi resets toggle state from settings. Inline `/skill:name` invocation remains explicit and works even when that skill is inactive.
93
+ On app startup, non-hidden skills are active and hidden skills are inactive. Within a running Pi process, `/new` preserves the current toggle state for the new session. Resuming, forking, cloning, reloading, or restarting Pi resets toggle state from settings. Inline `/skill:name` invocation remains explicit and works even when that skill is inactive. Skills bundled in Pi packages are never modified by these toggles.
92
94
 
93
95
  ## Installation
94
96
 
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from "./extensions/index.js";
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "pi-skillful",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Pi package with skill invocation and visibility improvements.",
5
5
  "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.ts"
8
+ },
6
9
  "license": "MIT",
7
- "author": "jvm",
10
+ "author": "Jose Mocito",
8
11
  "repository": {
9
12
  "type": "git",
10
13
  "url": "git+https://github.com/jvm/pi-mono.git",
@@ -22,10 +25,11 @@
22
25
  ],
23
26
  "pi": {
24
27
  "extensions": [
25
- "./extensions/index.ts"
28
+ "./index.ts"
26
29
  ]
27
30
  },
28
31
  "files": [
32
+ "index.ts",
29
33
  "extensions",
30
34
  "src",
31
35
  "banner.png",
@@ -41,9 +45,9 @@
41
45
  "@earendil-works/pi-tui": "*"
42
46
  },
43
47
  "devDependencies": {
44
- "@earendil-works/pi-coding-agent": "^0.74.0",
45
- "@earendil-works/pi-tui": "^0.74.0",
46
- "@types/node": "^25.6.0",
48
+ "@earendil-works/pi-coding-agent": "^0.78.0",
49
+ "@earendil-works/pi-tui": "^0.78.0",
50
+ "@types/node": "^25.6.2",
47
51
  "typescript": "^6.0.3"
48
52
  },
49
53
  "scripts": {
@@ -11,7 +11,7 @@ import {
11
11
  type SkillToggleSlot,
12
12
  } from "../config.js";
13
13
  import { replaceSkillsSection } from "../skill-prompt.js";
14
- import { listLoadedSkills } from "../skills.js";
14
+ import { isTopLevelSkill, listLoadedSkills } from "../skills.js";
15
15
 
16
16
  const WIDGET_KEY = "pi-skillful-session-toggles";
17
17
  const STORE_KEY = Symbol.for("pi-skillful.sessionSkillTogglesStore");
@@ -97,10 +97,9 @@ export default function sessionSkillToggles(pi: ExtensionAPI) {
97
97
  pi.on("before_agent_start", (event) => {
98
98
  if (state.slots.length === 0 || !event.systemPromptOptions.skills?.length) return;
99
99
 
100
- const updatedSkills: Skill[] = event.systemPromptOptions.skills.map((skill) => ({
101
- ...skill,
102
- disableModelInvocation: !isSkillActive(normalizeSkillName(skill.name)),
103
- }));
100
+ const updatedSkills: Skill[] = event.systemPromptOptions.skills.map((skill) =>
101
+ isTopLevelSkill(skill) ? { ...skill, disableModelInvocation: !isSkillActive(normalizeSkillName(skill.name)) } : skill,
102
+ );
104
103
 
105
104
  const systemPrompt = replaceSkillsSection(event.systemPrompt, updatedSkills);
106
105
  if (!systemPrompt) return;
@@ -164,7 +163,11 @@ function configuredToggleSlots(
164
163
  pi: ExtensionAPI,
165
164
  toggleSlots: Partial<Record<SkillToggleSlot, string>>,
166
165
  ): ToggleSlotState[] {
167
- const loadedSkillNames = new Set(listLoadedSkills(pi.getCommands()).map((skill) => skill.name));
166
+ const loadedSkillNames = new Set(
167
+ listLoadedSkills(pi.getCommands())
168
+ .filter(isTopLevelSkill)
169
+ .map((skill) => skill.name),
170
+ );
168
171
  return SKILL_TOGGLE_SLOTS.flatMap((slot): ToggleSlotState[] => {
169
172
  const skillName = toggleSlots[slot];
170
173
  if (!skillName || !loadedSkillNames.has(skillName)) return [];
@@ -20,7 +20,7 @@ import {
20
20
  writeToggleSlots,
21
21
  } from "../config.js";
22
22
  import { replaceSkillsSection } from "../skill-prompt.js";
23
- import { listLoadedSkills, type LoadedSkillInfo } from "../skills.js";
23
+ import { isTopLevelSkill, listLoadedSkills, type LoadedSkillInfo } from "../skills.js";
24
24
  import { hasActiveSessionSkillToggles, refreshSessionSkillToggles } from "./session-skill-toggles.js";
25
25
  const SCOPES: SkillfulScope[] = ["global", "project"];
26
26
  const STORE_KEY = Symbol.for("pi-skillful.skillVisibilityStore");
@@ -95,7 +95,7 @@ export default function skillVisibility(pi: ExtensionAPI) {
95
95
  if (hidden.size === 0 || !event.systemPromptOptions.skills?.length) return;
96
96
 
97
97
  const filteredSkills: Skill[] = event.systemPromptOptions.skills.map((skill) =>
98
- hidden.has(skill.name) ? { ...skill, disableModelInvocation: true } : skill,
98
+ isTopLevelSkill(skill) && hidden.has(skill.name) ? { ...skill, disableModelInvocation: true } : skill,
99
99
  );
100
100
  const systemPrompt = replaceSkillsSection(event.systemPrompt, filteredSkills);
101
101
  if (!systemPrompt) return;
@@ -239,7 +239,7 @@ function buildColorizedSkillList(names: string[], hidden: Set<string>, theme: Th
239
239
  }
240
240
 
241
241
  function getSkillItems(pi: ExtensionAPI): SkillListItem[] {
242
- return listLoadedSkills(pi.getCommands());
242
+ return listLoadedSkills(pi.getCommands()).filter(isTopLevelSkill);
243
243
  }
244
244
 
245
245
  class SkillfulVisibilityMenu implements Component {
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { reportInstallTelemetry } from "./install-telemetry.js";
package/src/skills.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { dirname } from "node:path";
3
+ import type { SourceInfo } from "@earendil-works/pi-coding-agent";
3
4
  import { normalizeSkillName } from "./config.js";
4
5
 
5
6
  export interface SkillCommandInfo {
@@ -11,12 +12,14 @@ export interface SkillCommandInfo {
11
12
  export interface LoadedSkillInfo {
12
13
  name: string;
13
14
  description: string;
15
+ sourceInfo: SourceInfo;
14
16
  }
15
17
 
16
18
  interface CommandLike {
17
19
  name: string;
18
20
  source: string;
19
21
  description?: string;
22
+ sourceInfo: SourceInfo;
20
23
  }
21
24
 
22
25
  export function listLoadedSkills(commands: Iterable<CommandLike>): LoadedSkillInfo[] {
@@ -25,11 +28,15 @@ export function listLoadedSkills(commands: Iterable<CommandLike>): LoadedSkillIn
25
28
  if (command.source !== "skill") continue;
26
29
  const name = normalizeSkillName(command.name);
27
30
  if (!name) continue;
28
- byName.set(name, { name, description: command.description ?? "" });
31
+ byName.set(name, { name, description: command.description ?? "", sourceInfo: command.sourceInfo });
29
32
  }
30
33
  return Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
31
34
  }
32
35
 
36
+ export function isTopLevelSkill(skill: { sourceInfo: { origin: SourceInfo["origin"] } }): boolean {
37
+ return skill.sourceInfo.origin === "top-level";
38
+ }
39
+
33
40
  export function stripFrontmatter(markdown: string): string {
34
41
  const normalized = markdown.replace(/^\uFEFF/, "");
35
42
  const match = normalized.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);