@astralyn/pi 1.4.6 → 1.4.8

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.
Files changed (253) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/bundle/chunks/{chunk-EYKC6ESU.js → chunk-5VIOGR76.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-KDO6L76C.js → chunk-FODCTZXW.js} +4 -4
  4. package/dist/bundle/chunks/{chunk-RBTJBQWX.js → chunk-I2COK45I.js} +136 -137
  5. package/dist/bundle/chunks/{chunk-AXFWZIHH.js → chunk-MG5XDTXV.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-ALHAFUHP.js → chunk-PU2IWWXV.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-5M3YJ54Z.js → chunk-RO2VH6UZ.js} +1 -1
  8. package/dist/bundle/chunks/{cli-FH77R7JR.js → cli-MEL7SGJD.js} +1 -1
  9. package/dist/bundle/chunks/{execute-5ZQUS52M.js → execute-4CWRNHPO.js} +1 -1
  10. package/dist/bundle/chunks/{runtime-R5CMHJ5P.js → runtime-R3X67XMR.js} +1 -1
  11. package/dist/bundle/chunks/{virtual-modules-KCQU7LOC.js → virtual-modules-BBLD7YLS.js} +1 -1
  12. package/dist/bundle/cli.js +1 -1
  13. package/dist/bundle/index.js +1 -1
  14. package/dist/bundle/rpc-entry.js +1 -1
  15. package/dist/core/agent-session.d.ts +0 -3
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +0 -4
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/extensions/index.d.ts +1 -1
  20. package/dist/core/extensions/index.d.ts.map +1 -1
  21. package/dist/core/extensions/index.js.map +1 -1
  22. package/dist/core/package-manager.d.ts +3 -1
  23. package/dist/core/package-manager.d.ts.map +1 -1
  24. package/dist/core/package-manager.js +10 -0
  25. package/dist/core/package-manager.js.map +1 -1
  26. package/dist/core/resource-loader.d.ts +2 -0
  27. package/dist/core/resource-loader.d.ts.map +1 -1
  28. package/dist/core/resource-loader.js +17 -4
  29. package/dist/core/resource-loader.js.map +1 -1
  30. package/dist/core/settings-manager.d.ts +4 -2
  31. package/dist/core/settings-manager.d.ts.map +1 -1
  32. package/dist/core/settings-manager.js +11 -0
  33. package/dist/core/settings-manager.js.map +1 -1
  34. package/dist/core/settings-schema.d.ts +7 -0
  35. package/dist/core/settings-schema.d.ts.map +1 -1
  36. package/dist/core/settings-schema.js +6 -0
  37. package/dist/core/settings-schema.js.map +1 -1
  38. package/dist/core/skill-invocation.d.ts +46 -0
  39. package/dist/core/skill-invocation.d.ts.map +1 -0
  40. package/dist/core/skill-invocation.js +128 -0
  41. package/dist/core/skill-invocation.js.map +1 -0
  42. package/dist/core/skills.d.ts +10 -0
  43. package/dist/core/skills.d.ts.map +1 -1
  44. package/dist/core/skills.js +23 -0
  45. package/dist/core/skills.js.map +1 -1
  46. package/dist/core/tasks/delivery.d.ts +11 -4
  47. package/dist/core/tasks/delivery.d.ts.map +1 -1
  48. package/dist/core/tasks/delivery.js +9 -9
  49. package/dist/core/tasks/delivery.js.map +1 -1
  50. package/dist/core/tasks/execution.d.ts +10 -3
  51. package/dist/core/tasks/execution.d.ts.map +1 -1
  52. package/dist/core/tasks/execution.js +72 -52
  53. package/dist/core/tasks/execution.js.map +1 -1
  54. package/dist/core/tasks/format.d.ts +0 -2
  55. package/dist/core/tasks/format.d.ts.map +1 -1
  56. package/dist/core/tasks/format.js +1 -16
  57. package/dist/core/tasks/format.js.map +1 -1
  58. package/dist/core/tasks/limits.d.ts +12 -1
  59. package/dist/core/tasks/limits.d.ts.map +1 -1
  60. package/dist/core/tasks/limits.js +20 -1
  61. package/dist/core/tasks/limits.js.map +1 -1
  62. package/dist/core/tasks/output.d.ts +6 -12
  63. package/dist/core/tasks/output.d.ts.map +1 -1
  64. package/dist/core/tasks/output.js +35 -32
  65. package/dist/core/tasks/output.js.map +1 -1
  66. package/dist/core/tasks/record.d.ts +45 -0
  67. package/dist/core/tasks/record.d.ts.map +1 -0
  68. package/dist/core/tasks/record.js +80 -0
  69. package/dist/core/tasks/record.js.map +1 -0
  70. package/dist/core/tasks/runtime.d.ts +14 -14
  71. package/dist/core/tasks/runtime.d.ts.map +1 -1
  72. package/dist/core/tasks/runtime.js +111 -93
  73. package/dist/core/tasks/runtime.js.map +1 -1
  74. package/dist/core/tasks/session.d.ts +0 -1
  75. package/dist/core/tasks/session.d.ts.map +1 -1
  76. package/dist/core/tasks/session.js +7 -8
  77. package/dist/core/tasks/session.js.map +1 -1
  78. package/dist/core/tasks/store.d.ts +18 -25
  79. package/dist/core/tasks/store.d.ts.map +1 -1
  80. package/dist/core/tasks/store.js +42 -40
  81. package/dist/core/tasks/store.js.map +1 -1
  82. package/dist/core/tasks/types.d.ts +96 -17
  83. package/dist/core/tasks/types.d.ts.map +1 -1
  84. package/dist/core/tasks/types.js.map +1 -1
  85. package/dist/core/tools/shell-execution.d.ts +8 -7
  86. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  87. package/dist/core/tools/shell-execution.js +18 -26
  88. package/dist/core/tools/shell-execution.js.map +1 -1
  89. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  90. package/dist/core/tools/shell-tool.js +31 -29
  91. package/dist/core/tools/shell-tool.js.map +1 -1
  92. package/dist/core/usage-totals.d.ts +3 -0
  93. package/dist/core/usage-totals.d.ts.map +1 -1
  94. package/dist/core/usage-totals.js +15 -0
  95. package/dist/core/usage-totals.js.map +1 -1
  96. package/dist/extensions/agent/progress.d.ts.map +1 -1
  97. package/dist/extensions/agent/progress.js +1 -11
  98. package/dist/extensions/agent/progress.js.map +1 -1
  99. package/dist/extensions/agent/settings-host.d.ts +33 -0
  100. package/dist/extensions/agent/settings-host.d.ts.map +1 -0
  101. package/dist/extensions/agent/settings-host.js +75 -0
  102. package/dist/extensions/agent/settings-host.js.map +1 -0
  103. package/dist/extensions/agent/settings.d.ts.map +1 -1
  104. package/dist/extensions/agent/settings.js +18 -7
  105. package/dist/extensions/agent/settings.js.map +1 -1
  106. package/dist/extensions/agent/tool.d.ts.map +1 -1
  107. package/dist/extensions/agent/tool.js +9 -5
  108. package/dist/extensions/agent/tool.js.map +1 -1
  109. package/dist/extensions/agent/worker.d.ts.map +1 -1
  110. package/dist/extensions/agent/worker.js +3 -5
  111. package/dist/extensions/agent/worker.js.map +1 -1
  112. package/dist/extensions/btw/agent.d.ts +1 -1
  113. package/dist/extensions/btw/agent.d.ts.map +1 -1
  114. package/dist/extensions/btw/agent.js +3 -20
  115. package/dist/extensions/btw/agent.js.map +1 -1
  116. package/dist/extensions/cached-compaction/index.d.ts.map +1 -1
  117. package/dist/extensions/cached-compaction/index.js +3 -22
  118. package/dist/extensions/cached-compaction/index.js.map +1 -1
  119. package/dist/extensions/cached-compaction/render.d.ts +1 -0
  120. package/dist/extensions/cached-compaction/render.d.ts.map +1 -1
  121. package/dist/extensions/cached-compaction/render.js +42 -14
  122. package/dist/extensions/cached-compaction/render.js.map +1 -1
  123. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  124. package/dist/extensions/deepwiki/client.js +6 -78
  125. package/dist/extensions/deepwiki/client.js.map +1 -1
  126. package/dist/extensions/deepwiki/transport.d.ts +3 -0
  127. package/dist/extensions/deepwiki/transport.d.ts.map +1 -0
  128. package/dist/extensions/deepwiki/transport.js +96 -0
  129. package/dist/extensions/deepwiki/transport.js.map +1 -0
  130. package/dist/extensions/provider/ui/builtin-data.d.ts +3 -3
  131. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  132. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  133. package/dist/extensions/provider/ui/compat.d.ts +3 -3
  134. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  135. package/dist/extensions/provider/ui/compat.js.map +1 -1
  136. package/dist/extensions/provider/ui/controls.d.ts +2 -2
  137. package/dist/extensions/provider/ui/controls.d.ts.map +1 -1
  138. package/dist/extensions/provider/ui/controls.js.map +1 -1
  139. package/dist/extensions/provider/ui/dialogs.d.ts +3 -3
  140. package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -1
  141. package/dist/extensions/provider/ui/dialogs.js.map +1 -1
  142. package/dist/extensions/provider/ui/dictionary.d.ts +2 -2
  143. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  144. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  145. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  146. package/dist/extensions/provider/ui/editor.js +1 -3
  147. package/dist/extensions/provider/ui/editor.js.map +1 -1
  148. package/dist/extensions/provider/ui/fetch-models.d.ts +2 -2
  149. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  150. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  151. package/dist/extensions/provider/ui/model-fields.d.ts +2 -2
  152. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  153. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  154. package/dist/extensions/provider/ui/model-options.d.ts +6 -6
  155. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  156. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  157. package/dist/extensions/provider/ui/pane.d.ts +21 -12
  158. package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
  159. package/dist/extensions/provider/ui/pane.js.map +1 -1
  160. package/dist/extensions/provider/ui/provider-fields.d.ts +3 -3
  161. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  162. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  163. package/dist/extensions/provider/ui/thinking-map.d.ts +2 -2
  164. package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
  165. package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
  166. package/dist/extensions/run-summary/format.js +1 -1
  167. package/dist/extensions/run-summary/format.js.map +1 -1
  168. package/dist/extensions/statusline/usage.d.ts.map +1 -1
  169. package/dist/extensions/statusline/usage.js +2 -6
  170. package/dist/extensions/statusline/usage.js.map +1 -1
  171. package/dist/extensions/tasks/tool/actions.d.ts +1 -1
  172. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  173. package/dist/extensions/tasks/tool/actions.js +49 -106
  174. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  175. package/dist/extensions/tasks/tool/constants.d.ts +1 -6
  176. package/dist/extensions/tasks/tool/constants.d.ts.map +1 -1
  177. package/dist/extensions/tasks/tool/constants.js +1 -6
  178. package/dist/extensions/tasks/tool/constants.js.map +1 -1
  179. package/dist/extensions/tasks/tool/schema.d.ts +0 -3
  180. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  181. package/dist/extensions/tasks/tool/schema.js +4 -13
  182. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  183. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  184. package/dist/extensions/tasks/tool.js +2 -2
  185. package/dist/extensions/tasks/tool.js.map +1 -1
  186. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  187. package/dist/extensions/tasks/ui/completion-render.js +31 -33
  188. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  189. package/dist/extensions/tasks/ui/layout.d.ts +7 -7
  190. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  191. package/dist/extensions/tasks/ui/layout.js +17 -19
  192. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  193. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  194. package/dist/extensions/tasks/ui/list.js +2 -3
  195. package/dist/extensions/tasks/ui/list.js.map +1 -1
  196. package/dist/extensions/tasks/ui/manager.d.ts +16 -7
  197. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  198. package/dist/extensions/tasks/ui/manager.js +163 -131
  199. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  200. package/dist/extensions/tasks/ui/model.d.ts +25 -0
  201. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  202. package/dist/extensions/tasks/ui/model.js +4 -0
  203. package/dist/extensions/tasks/ui/model.js.map +1 -1
  204. package/dist/extensions/tasks/ui/render.d.ts +1 -1
  205. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  206. package/dist/extensions/tasks/ui/render.js +11 -7
  207. package/dist/extensions/tasks/ui/render.js.map +1 -1
  208. package/dist/extensions/tasks/ui/status.d.ts +15 -0
  209. package/dist/extensions/tasks/ui/status.d.ts.map +1 -0
  210. package/dist/extensions/tasks/ui/status.js +16 -0
  211. package/dist/extensions/tasks/ui/status.js.map +1 -0
  212. package/dist/index.d.ts +1 -1
  213. package/dist/index.d.ts.map +1 -1
  214. package/dist/index.js.map +1 -1
  215. package/dist/modes/interactive/components/config-selector.d.ts +17 -2
  216. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/config-selector.js +199 -18
  218. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  219. package/dist/modes/interactive/components/status-marker.d.ts +2 -1
  220. package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
  221. package/dist/modes/interactive/components/status-marker.js +0 -1
  222. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  223. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  224. package/dist/modes/interactive/interactive-mode.js +7 -1
  225. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  226. package/dist/utils/duration.d.ts +3 -0
  227. package/dist/utils/duration.d.ts.map +1 -0
  228. package/dist/utils/duration.js +17 -0
  229. package/dist/utils/duration.js.map +1 -0
  230. package/dist/utils/number.d.ts +3 -0
  231. package/dist/utils/number.d.ts.map +1 -0
  232. package/dist/utils/number.js +5 -0
  233. package/dist/utils/number.js.map +1 -0
  234. package/docs/bundled/extensions/agent.md +3 -3
  235. package/docs/bundled/extensions/cached-compaction.md +13 -4
  236. package/docs/bundled/extensions/deepwiki.md +3 -1
  237. package/docs/extensions.md +5 -5
  238. package/docs/packages.md +5 -3
  239. package/docs/sdk.md +1 -1
  240. package/docs/session-format.md +1 -1
  241. package/docs/settings.md +11 -0
  242. package/docs/skills.md +23 -0
  243. package/npm-shrinkwrap.json +2 -2
  244. package/package.json +1 -1
  245. package/schemas/settings.schema.json +36 -0
  246. package/dist/extensions/deepwiki/http.d.ts +0 -13
  247. package/dist/extensions/deepwiki/http.d.ts.map +0 -1
  248. package/dist/extensions/deepwiki/http.js +0 -88
  249. package/dist/extensions/deepwiki/http.js.map +0 -1
  250. package/dist/extensions/tasks/ui/task-view.d.ts +0 -8
  251. package/dist/extensions/tasks/ui/task-view.d.ts.map +0 -1
  252. package/dist/extensions/tasks/ui/task-view.js +0 -13
  253. package/dist/extensions/tasks/ui/task-view.js.map +0 -1
@@ -5,11 +5,26 @@ import { homedir } from "node:os";
5
5
  import { basename, dirname, join, relative } from "node:path";
6
6
  import { Container, getKeybindings, Input, matchesKey, Spacer, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
7
7
  import { CONFIG_DIR_NAME } from "../../../config.js";
8
+ import { DefaultPackageManager, } from "../../../core/package-manager.js";
9
+ import { matchInvocation, SkillInvocationPolicy, withInvocation } from "../../../core/skill-invocation.js";
10
+ import { readSkillDisableModelInvocation, resolveSkillEffectiveState, } from "../../../core/skills.js";
8
11
  import { BUILTIN_PATH_PREFIX } from "../../../core/source-info.js";
9
12
  import { canonicalizePath, isLocalPath, resolvePath } from "../../../utils/paths.js";
10
13
  import { theme } from "../theme/theme.js";
11
14
  import { DynamicBorder } from "./dynamic-border.js";
12
15
  import { keyHint, rawKeyHint } from "./keybinding-hints.js";
16
+ function hasResourcePattern(patterns, pattern) {
17
+ const normalized = pattern.replace(/\\/g, "/");
18
+ for (const candidate of patterns) {
19
+ if (candidate.replace(/\\/g, "/") === normalized)
20
+ return true;
21
+ }
22
+ return false;
23
+ }
24
+ /** The invocation override that pins a skill state; Off and inherit leave invocation to the defaults. */
25
+ function stateInvocation(state) {
26
+ return state === "on" ? "model-and-user" : state === "user-only" ? "user-only" : undefined;
27
+ }
13
28
  const RESOURCE_TYPES = ["extensions", "skills", "prompts", "themes"];
14
29
  const RESOURCE_TYPE_LABELS = {
15
30
  extensions: "Extensions",
@@ -101,6 +116,7 @@ function buildGroups(resolved, agentDir) {
101
116
  displayName,
102
117
  groupKey,
103
118
  subgroupKey,
119
+ frontmatterDisableModelInvocation: resourceType === "skills" ? readSkillDisableModelInvocation(path) : undefined,
104
120
  });
105
121
  }
106
122
  };
@@ -142,7 +158,7 @@ class ConfigSelectorHeader {
142
158
  const title = theme.bold(this.writeScope === "project" ? "Project Local Resources" : "Global Resources");
143
159
  const sep = theme.fg("muted", " · ");
144
160
  const switchHint = this.projectModeAvailable ? keyHint("tui.input.tab", "switch mode") + sep : "";
145
- const actionHint = this.writeScope === "project" ? rawKeyHint("space", "cycle inherit/+/-") : rawKeyHint("space", "toggle");
161
+ const actionHint = rawKeyHint("space", "change");
146
162
  const hint = switchHint + actionHint + sep + rawKeyHint("esc", "close");
147
163
  const spacing = Math.max(1, width - visibleWidth(title) - visibleWidth(hint));
148
164
  const scopeHint = this.writeScope === "project"
@@ -173,6 +189,8 @@ class ResourceList {
173
189
  this.agentDir = agentDir;
174
190
  this.writeScope = writeScope;
175
191
  this.inheritedEnabledByKey = this.buildInheritedEnabledMap(groupsByScope.global);
192
+ this.packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
193
+ this.skillInvocation = new SkillInvocationPolicy(settingsManager, this.packageManager);
176
194
  this.searchInput = new Input();
177
195
  // 8 lines of chrome: top spacer + top border + spacer + header (2 lines) + spacer + bottom spacer + bottom border
178
196
  const chrome = 8;
@@ -276,6 +294,8 @@ class ResourceList {
276
294
  }
277
295
  updateItem(item, enabled) {
278
296
  item.enabled = enabled;
297
+ if (this.writeScope === "global")
298
+ this.inheritedEnabledByKey.set(this.getResourceItemKey(item), enabled);
279
299
  // Update in groups too
280
300
  for (const group of this.groups) {
281
301
  for (const subgroup of group.subgroups) {
@@ -323,7 +343,11 @@ class ResourceList {
323
343
  const dimmed = this.isDimmedItem(item);
324
344
  const nameText = isSelected && !dimmed ? theme.bold(item.displayName) : item.displayName;
325
345
  const name = dimmed ? theme.fg("dim", nameText) : nameText;
326
- lines.push(truncateToWidth(`${cursor} ${this.renderCheckbox(item)} ${name}${this.getItemSuffix(item)}`, width, "..."));
346
+ const prefix = `${cursor} ${this.renderCheckbox(item)} `;
347
+ const suffix = this.getItemSuffix(item);
348
+ const nameWidth = Math.max(1, width - visibleWidth(prefix) - visibleWidth(suffix));
349
+ const renderedName = truncateToWidth(name, nameWidth, "...");
350
+ lines.push(truncateToWidth(`${prefix}${renderedName}${suffix}`, width, "..."));
327
351
  }
328
352
  }
329
353
  // Scroll indicator
@@ -394,6 +418,18 @@ class ResourceList {
394
418
  this.filterItems(this.searchInput.getValue());
395
419
  }
396
420
  toggleResource(item) {
421
+ if (item.resourceType === "skills") {
422
+ if (this.writeScope === "project") {
423
+ const state = this.getNextProjectSkillOverrideState(item);
424
+ if (!this.setProjectSkillOverride(item, state))
425
+ return undefined;
426
+ return state === "inherit" ? this.getInheritedSkillEffectiveState(item) !== "off" : state !== "off";
427
+ }
428
+ const currentState = this.getSkillEffectiveState(item);
429
+ const nextState = currentState === "on" ? "user-only" : currentState === "user-only" ? "off" : "on";
430
+ this.setGlobalSkillEffectiveState(item, nextState);
431
+ return nextState !== "off";
432
+ }
397
433
  if (this.writeScope === "project") {
398
434
  const state = this.getNextOverrideState(item);
399
435
  if (!this.setProjectResourceOverride(item, state))
@@ -505,7 +541,81 @@ class ResourceList {
505
541
  this.settingsManager.setPackages(packages);
506
542
  }
507
543
  }
544
+ setGlobalSkillEffectiveState(item, state) {
545
+ const enabled = state !== "off";
546
+ if (item.metadata.origin === "top-level")
547
+ this.toggleTopLevelResource(item, enabled);
548
+ else
549
+ this.togglePackageResource(item, enabled);
550
+ this.setSkillInvocationOverride(item, "user", stateInvocation(state));
551
+ }
552
+ setProjectSkillOverride(item, state) {
553
+ const loadState = state === "inherit" ? "inherit" : state === "off" ? "unload" : "load";
554
+ if (!this.setProjectResourceOverride(item, loadState))
555
+ return false;
556
+ this.setSkillInvocationOverride(item, "project", stateInvocation(state));
557
+ return true;
558
+ }
559
+ /** Runs after the load write, which creates the package entry a project override needs. */
560
+ setSkillInvocationOverride(item, scope, override) {
561
+ const layer = this.skillInvocation.layer(scope, item.metadata);
562
+ if (!layer)
563
+ return;
564
+ const overrides = withInvocation(layer, item.path, override);
565
+ if (item.metadata.origin === "top-level") {
566
+ if (scope === "project")
567
+ this.settingsManager.setProjectSkillInvocationOverrides(overrides);
568
+ else
569
+ this.settingsManager.setSkillInvocationOverrides(overrides);
570
+ return;
571
+ }
572
+ const settings = scope === "project" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();
573
+ const packages = [...(settings.packages ?? [])];
574
+ const pkgIndex = this.skillInvocation.findPackage(scope, item.metadata);
575
+ const current = packages[pkgIndex];
576
+ if (current === undefined || (typeof current === "string" && !overrides))
577
+ return;
578
+ const pkg = typeof current === "string" ? { source: current } : { ...current };
579
+ pkg.skillInvocationOverrides = overrides;
580
+ if (overrides || RESOURCE_TYPES.some((key) => pkg[key] !== undefined))
581
+ packages[pkgIndex] = pkg;
582
+ else if (scope === "project" && pkg.autoload === false)
583
+ packages.splice(pkgIndex, 1);
584
+ else
585
+ packages[pkgIndex] = pkg.source;
586
+ if (scope === "project")
587
+ this.settingsManager.setProjectPackages(packages);
588
+ else
589
+ this.settingsManager.setPackages(packages);
590
+ }
508
591
  renderCheckbox(item) {
592
+ if (item.resourceType === "skills") {
593
+ if (this.writeScope === "project") {
594
+ const state = this.getProjectSkillOverrideState(item);
595
+ if (state === "on")
596
+ return theme.fg("success", "[+]");
597
+ if (state === "user-only")
598
+ return theme.fg("accent", "[u]");
599
+ if (state === "off")
600
+ return theme.fg("warning", "[-]");
601
+ if (state === "load") {
602
+ const effectiveState = this.getSkillEffectiveState(item);
603
+ if (effectiveState === "user-only")
604
+ return theme.fg("accent", "[u]");
605
+ if (effectiveState === "off")
606
+ return theme.fg("warning", "[-]");
607
+ return theme.fg("success", "[+]");
608
+ }
609
+ const inheritedState = this.getInheritedSkillEffectiveState(item);
610
+ return theme.fg("dim", inheritedState === "on" ? "[x]" : inheritedState === "user-only" ? "[u]" : "[ ]");
611
+ }
612
+ const state = this.getSkillEffectiveState(item);
613
+ if (state === "on")
614
+ return theme.fg("success", "[x]");
615
+ if (state === "user-only")
616
+ return theme.fg("accent", "[u]");
617
+ return theme.fg("dim", "[ ]");
618
+ }
509
619
  if (this.writeScope === "project") {
510
620
  const state = this.getProjectOverrideState(item);
511
621
  if (state === "load")
@@ -517,6 +627,21 @@ class ResourceList {
517
627
  return item.enabled ? theme.fg("success", "[x]") : theme.fg("dim", "[ ]");
518
628
  }
519
629
  getItemSuffix(item) {
630
+ if (item.resourceType === "skills") {
631
+ if (this.writeScope === "project") {
632
+ const state = this.getProjectSkillOverrideState(item);
633
+ if (state === "on")
634
+ return theme.fg("muted", " project on");
635
+ if (state === "user-only")
636
+ return theme.fg("muted", " project user only");
637
+ if (state === "off")
638
+ return theme.fg("muted", " project off");
639
+ if (state === "load")
640
+ return theme.fg("muted", " project load");
641
+ return this.isInheritedGlobalItem(item) ? theme.fg("dim", " inherited global") : "";
642
+ }
643
+ return this.getSkillEffectiveState(item) === "user-only" ? theme.fg("accent", " user only") : "";
644
+ }
520
645
  if (this.writeScope !== "project")
521
646
  return "";
522
647
  const state = this.getProjectOverrideState(item);
@@ -527,9 +652,51 @@ class ResourceList {
527
652
  return this.isInheritedGlobalItem(item) ? theme.fg("dim", " inherited global") : "";
528
653
  }
529
654
  isDimmedItem(item) {
530
- return (this.writeScope === "project" &&
531
- this.isInheritedGlobalItem(item) &&
532
- this.getProjectOverrideState(item) === "inherit");
655
+ if (this.writeScope !== "project" || !this.isInheritedGlobalItem(item))
656
+ return false;
657
+ return item.resourceType === "skills"
658
+ ? this.getProjectSkillOverrideState(item) === "inherit"
659
+ : this.getProjectOverrideState(item) === "inherit";
660
+ }
661
+ /** The state settings give a skill in the current mode; global mode ignores project settings. */
662
+ getSkillEffectiveState(item) {
663
+ const scopes = this.writeScope === "project" ? ["project", "user"] : ["user"];
664
+ return resolveSkillEffectiveState({
665
+ enabled: item.enabled,
666
+ invocationOverride: this.skillInvocation.resolve(item.path, item.metadata, scopes),
667
+ frontmatterDisableModelInvocation: item.frontmatterDisableModelInvocation,
668
+ });
669
+ }
670
+ getInheritedSkillEffectiveState(item) {
671
+ return resolveSkillEffectiveState({
672
+ enabled: this.getInheritedEnabled(item),
673
+ invocationOverride: this.skillInvocation.resolve(item.path, item.metadata, ["user"]),
674
+ frontmatterDisableModelInvocation: item.frontmatterDisableModelInvocation,
675
+ });
676
+ }
677
+ getNextProjectSkillOverrideState(item) {
678
+ const states = ["on", "user-only", "off"];
679
+ const inheritedIndex = states.indexOf(this.getInheritedSkillEffectiveState(item));
680
+ const sequence = [...states.slice(inheritedIndex + 1), ...states.slice(0, inheritedIndex + 1)];
681
+ const current = this.getProjectSkillOverrideState(item);
682
+ if (current === "inherit")
683
+ return sequence[0];
684
+ if (current === "load")
685
+ return "inherit";
686
+ const currentIndex = sequence.indexOf(current);
687
+ return sequence[currentIndex + 1] ?? "inherit";
688
+ }
689
+ getProjectSkillOverrideState(item) {
690
+ if (this.writeScope !== "project")
691
+ return "inherit";
692
+ const loadState = this.getProjectOverrideState(item);
693
+ if (loadState === "unload")
694
+ return "off";
695
+ const layer = this.skillInvocation.layer("project", item.metadata);
696
+ const invocation = layer ? matchInvocation(layer, item.path).override : undefined;
697
+ if (invocation)
698
+ return invocation === "user-only" ? "user-only" : "on";
699
+ return loadState;
533
700
  }
534
701
  setProjectResourceOverride(item, state) {
535
702
  return item.metadata.origin === "top-level"
@@ -567,7 +734,7 @@ class ResourceList {
567
734
  }
568
735
  setProjectPackageOverride(item, state) {
569
736
  const packages = [...(this.settingsManager.getProjectSettings().packages ?? [])];
570
- let pkgIndex = packages.findIndex((pkg) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, "project"));
737
+ let pkgIndex = packages.findIndex((pkg) => this.isSamePackage(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, "project"));
571
738
  if (pkgIndex === -1) {
572
739
  if (state === "inherit")
573
740
  return false;
@@ -586,7 +753,8 @@ class ResourceList {
586
753
  if (state !== "inherit")
587
754
  updated.push(`${state === "load" ? "+" : "-"}${pattern}`);
588
755
  pkg[item.resourceType] = updated.length > 0 ? updated : undefined;
589
- if (!RESOURCE_TYPES.some((key) => pkg[key] !== undefined)) {
756
+ if (!RESOURCE_TYPES.some((key) => pkg[key] !== undefined) &&
757
+ pkg.skillInvocationOverrides === undefined) {
590
758
  if (pkg.autoload === false)
591
759
  packages.splice(pkgIndex, 1);
592
760
  else
@@ -616,14 +784,14 @@ class ResourceList {
616
784
  const entries = pkg[item.resourceType];
617
785
  if (entries === undefined)
618
786
  return "inherit";
619
- return this.getOverrideStateFromEntries(entries, new Set([this.getPackageResourcePattern(item)]), pkg.autoload !== false);
787
+ return this.getOverrideStateFromEntries(entries, this.getPackageOverridePatterns(item), pkg.autoload !== false);
620
788
  }
621
789
  getOverrideStateFromEntries(entries, patterns, emptyArrayIsUnload) {
622
790
  if (entries.length === 0 && emptyArrayIsUnload)
623
791
  return "unload";
624
792
  let state = "inherit";
625
793
  for (const entry of entries) {
626
- if (!patterns.has(this.getPatternEntryTarget(entry)))
794
+ if (!hasResourcePattern(patterns, this.getPatternEntryTarget(entry)))
627
795
  continue;
628
796
  if (entry.startsWith("!") || entry.startsWith("-"))
629
797
  state = "unload";
@@ -648,6 +816,13 @@ class ResourceList {
648
816
  ]);
649
817
  if (item.metadata.baseDir)
650
818
  patterns.add(relative(item.metadata.baseDir, item.path));
819
+ if (item.resourceType === "skills" && basename(item.path) === "SKILL.md") {
820
+ const parentDir = dirname(item.path);
821
+ patterns.add(parentDir);
822
+ patterns.add(relative(baseDir, parentDir));
823
+ if (item.metadata.baseDir)
824
+ patterns.add(relative(item.metadata.baseDir, parentDir));
825
+ }
651
826
  return patterns;
652
827
  }
653
828
  getResourcePatternForScope(item, scope) {
@@ -664,20 +839,16 @@ class ResourceList {
664
839
  const sourcePath = resolvePath(source, this.getTopLevelBaseDir(this.getItemScope(item)), { trim: true });
665
840
  return { source: relative(this.getTopLevelBaseDir("project"), sourcePath) || ".", autoload: false };
666
841
  }
667
- packageSourceStringMatches(leftSource, leftScope, rightSource, rightScope) {
668
- if (leftSource === rightSource)
669
- return true;
670
- if (!isLocalPath(leftSource) || !isLocalPath(rightSource))
671
- return false;
672
- const left = resolvePath(leftSource, this.getTopLevelBaseDir(leftScope), { trim: true });
673
- const right = resolvePath(rightSource, this.getTopLevelBaseDir(rightScope), { trim: true });
674
- return left === right;
842
+ /** Package entries match by the identity package loading dedupes on, so `npm:pkg@1` and `npm:pkg` are one package. */
843
+ isSamePackage(leftSource, leftScope, rightSource, rightScope) {
844
+ return (this.packageManager.getPackageIdentity(leftSource, leftScope) ===
845
+ this.packageManager.getPackageIdentity(rightSource, rightScope));
675
846
  }
676
847
  findMatchingPackageSource(item, targetScope) {
677
848
  const settings = targetScope === "project"
678
849
  ? this.settingsManager.getProjectSettings()
679
850
  : this.settingsManager.getGlobalSettings();
680
- return (settings.packages ?? []).find((pkg) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, targetScope));
851
+ return (settings.packages ?? []).find((pkg) => this.isSamePackage(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, targetScope));
681
852
  }
682
853
  getPatternEntryTarget(entry) {
683
854
  return entry.startsWith("!") || entry.startsWith("+") || entry.startsWith("-") ? entry.slice(1) : entry;
@@ -702,6 +873,16 @@ class ResourceList {
702
873
  const baseDir = item.metadata.baseDir ?? dirname(item.path);
703
874
  return relative(baseDir, item.path);
704
875
  }
876
+ /** Package filter entries that name an item; a skill can also be named by its absolute path or directory. */
877
+ getPackageOverridePatterns(item) {
878
+ const pattern = this.getPackageResourcePattern(item);
879
+ if (item.resourceType !== "skills")
880
+ return new Set([pattern]);
881
+ const patterns = new Set([pattern, item.path]);
882
+ if (basename(item.path) === "SKILL.md")
883
+ patterns.add(dirname(pattern)).add(dirname(item.path));
884
+ return patterns;
885
+ }
705
886
  }
706
887
  export class ConfigSelectorComponent extends Container {
707
888
  get focused() {