pi-skillful 0.3.2 → 0.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/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ This project follows the spirit of [Keep a Changelog](https://keepachangelog.com
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.4] - 2026-05-12
10
+
11
+ ### Changed
12
+
13
+ - Preserve session skill toggle state across `/new` within the same Pi process.
14
+
15
+ ## [0.3.3] - 2026-05-12
16
+
17
+ ### Fixed
18
+
19
+ - Fixed session skill toggles so hidden skills toggled active are included in the next system prompt.
20
+
9
21
  ## [0.3.2] - 2026-05-10
10
22
 
11
23
  ### Fixed
package/README.md CHANGED
@@ -88,7 +88,7 @@ Configured slots appear on the prompt editor's top border as `N skill-name`. Lon
88
88
 
89
89
  `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
90
 
91
- On session start, non-hidden skills are active and hidden skills are inactive. Starting, resuming, or forking a session resets toggle state from settings. Inline `/skill:name` invocation remains explicit and works even when that skill is inactive.
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.
92
92
 
93
93
  ## Installation
94
94
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-skillful",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Pi package with skill invocation and visibility improvements.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -39,6 +39,7 @@ interface SessionToggleState {
39
39
  }
40
40
 
41
41
  let state: SessionToggleState = createEmptyState();
42
+ let preservedNewSessionActiveBySkill: { cwd: string; activeBySkill: Map<string, boolean> } | undefined;
42
43
 
43
44
  export default function sessionSkillToggles(pi: ExtensionAPI) {
44
45
  for (const modifier of SUPPORTED_TOGGLE_MODIFIERS) {
@@ -53,7 +54,7 @@ export default function sessionSkillToggles(pi: ExtensionAPI) {
53
54
  }
54
55
  }
55
56
 
56
- pi.on("session_start", async (_event, ctx) => {
57
+ pi.on("session_start", async (event, ctx) => {
57
58
  const settings = await readEffectiveSkillfulSettings(ctx.cwd);
58
59
  const loadedSkillNames = new Set(listLoadedSkills(pi.getCommands()).map((s) => s.name));
59
60
  const slots = SKILL_TOGGLE_SLOTS.flatMap((slot): ToggleSlotState[] => {
@@ -62,12 +63,23 @@ export default function sessionSkillToggles(pi: ExtensionAPI) {
62
63
  return [{ slot, skillName }];
63
64
  });
64
65
 
66
+ const preservedActiveBySkill =
67
+ event.reason === "new" && preservedNewSessionActiveBySkill?.cwd === ctx.cwd
68
+ ? preservedNewSessionActiveBySkill.activeBySkill
69
+ : undefined;
70
+ preservedNewSessionActiveBySkill = undefined;
71
+
65
72
  state = {
66
73
  cwd: ctx.cwd,
67
74
  modifier: settings.toggleModifier,
68
75
  hiddenSkills: settings.hiddenSkillSet,
69
76
  slots,
70
- activeBySkill: new Map(slots.map(({ skillName }) => [skillName, !settings.hiddenSkillSet.has(skillName)])),
77
+ activeBySkill: new Map(
78
+ slots.map(({ skillName }) => [
79
+ skillName,
80
+ preservedActiveBySkill?.get(skillName) ?? !settings.hiddenSkillSet.has(skillName),
81
+ ]),
82
+ ),
71
83
  installedEditor: false,
72
84
  installedWidget: false,
73
85
  previousEditorFactory: undefined,
@@ -92,9 +104,11 @@ export default function sessionSkillToggles(pi: ExtensionAPI) {
92
104
  return { systemPrompt };
93
105
  });
94
106
 
95
- pi.on("session_shutdown", (_event, ctx) => {
107
+ pi.on("session_shutdown", (event, ctx) => {
96
108
  if (state.installedEditor) ctx.ui.setEditorComponent(state.previousEditorFactory);
97
109
  if (state.installedWidget) ctx.ui.setWidget(WIDGET_KEY, undefined);
110
+ preservedNewSessionActiveBySkill =
111
+ event.reason === "new" ? { cwd: state.cwd, activeBySkill: new Map(state.activeBySkill) } : undefined;
98
112
  state = createEmptyState();
99
113
  });
100
114
  }
@@ -114,6 +128,10 @@ function createEmptyState(): SessionToggleState {
114
128
  };
115
129
  }
116
130
 
131
+ export function hasActiveSessionSkillToggles(): boolean {
132
+ return state.slots.length > 0;
133
+ }
134
+
117
135
  function isSkillActive(skillName: string): boolean {
118
136
  return state.activeBySkill.get(skillName) ?? !state.hiddenSkills.has(skillName);
119
137
  }
@@ -17,6 +17,7 @@ import {
17
17
  } from "../config.js";
18
18
  import { replaceSkillsSection } from "../skill-prompt.js";
19
19
  import { listLoadedSkills, type LoadedSkillInfo } from "../skills.js";
20
+ import { hasActiveSessionSkillToggles } from "./session-skill-toggles.js";
20
21
  const SCOPES: SkillfulScope[] = ["global", "project"];
21
22
  const STORE_KEY = Symbol.for("pi-skillful.skillVisibilityStore");
22
23
  const STARTUP_PATCH_KEY = Symbol.for("pi-skillful.startupPatchV2");
@@ -60,6 +61,8 @@ export default function skillVisibility(pi: ExtensionAPI) {
60
61
  });
61
62
 
62
63
  pi.on("before_agent_start", async (event, ctx) => {
64
+ if (hasActiveSessionSkillToggles()) return;
65
+
63
66
  const hidden = await refreshHiddenSkillCache(ctx.cwd);
64
67
  if (hidden.size === 0 || !event.systemPromptOptions.skills?.length) return;
65
68