pi-nested-skills 0.2.2 → 0.4.0

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.ts +37 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-nested-skills",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "Pi extension for recursive nested-skill discovery and aliases",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -62,7 +62,7 @@
62
62
  "@earendil-works/pi-tui": ">=0.80.0"
63
63
  },
64
64
  "dependencies": {
65
- "pi-extensions-i18n": "^0.4.1"
65
+ "pi-extensions-i18n": "^0.6.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@earendil-works/pi-coding-agent": "0.85.1",
package/src/index.ts CHANGED
@@ -5,13 +5,28 @@ import type {
5
5
  } from "@earendil-works/pi-coding-agent";
6
6
  import { fuzzyFilter } from "@earendil-works/pi-tui";
7
7
  import type { AutocompleteItem, AutocompleteProvider } from "@earendil-works/pi-tui";
8
- import { createTranslator, loadCatalog } from "pi-extensions-i18n";
8
+ import {
9
+ createTranslator,
10
+ loadCatalog,
11
+ installNoticeRenderer,
12
+ notifyWithSource,
13
+ type NoticeColor,
14
+ type NoticeLevel,
15
+ type NoticeSource,
16
+ } from "pi-extensions-i18n";
9
17
  import { loadConfig, parseConfig, saveConfig, type LoadedNestedSkillsConfig } from "./config.ts";
10
18
  import { scanSkillRoots, type NestedSkill, type SkillScanResult } from "./skills.ts";
11
19
 
12
20
  const messages = loadCatalog(new URL("../locales/index.json", import.meta.url));
13
21
  const i18n = createTranslator(messages);
14
22
 
23
+ /** 本扩展的提示标签;短且唯一,便于在会话里定位来源。 */
24
+ const NOTICE_TAG = "skills";
25
+ /** 提示标签颜色;与其它扩展错开,避免看起来像同一条消息。 */
26
+ const NOTICE_COLOR: NoticeColor = "success";
27
+ /** 本扩展的提示来源。 */
28
+ const NOTICE_SOURCE: NoticeSource = { tag: NOTICE_TAG, color: NOTICE_COLOR };
29
+
15
30
  const COMMAND_NAME = "skills";
16
31
  const COMMAND_ALIASES = [COMMAND_NAME] as const;
17
32
  const CONFIG_COMMAND_ALIASES = ["config:nested-skills", "nested-skills-config", "pi-nested-skills-config"] as const;
@@ -19,14 +34,19 @@ const CONFIG_RESET_COMMAND = "reset";
19
34
  const DEFAULT_CONFIG_ROOT = "skills";
20
35
  const ROOT_INPUT_SEPARATOR = ",";
21
36
  const ROOT_DISPLAY_SEPARATOR = ", ";
22
- const NOTICE_WARNING = "warning" as const;
23
- const NOTICE_INFO = "info" as const;
24
- const NOTICE_ERROR = "error" as const;
37
+ const NOTICE_WARNING: NoticeLevel = "warning";
38
+ const NOTICE_INFO: NoticeLevel = "info";
39
+ const NOTICE_ERROR: NoticeLevel = "error";
25
40
  const SKILL_COMMAND_PREFIX = "skill:";
26
41
  const INPUT_SOURCES = new Set(["interactive", "rpc"]);
27
42
 
28
43
  type SkillCommandContext = ExtensionCommandContext;
29
44
 
45
+ /** 统一的带来源提示出口,保持所有 notify 调用点只传正文与级别。 */
46
+ function notify(ctx: ExtensionContext, message: string, level: NoticeLevel): void {
47
+ notifyWithSource({ ctx, source: NOTICE_SOURCE, level, message });
48
+ }
49
+
30
50
  interface SkillCandidate {
31
51
  alias: string;
32
52
  skill: NestedSkill;
@@ -210,22 +230,22 @@ function registerConfigCommand(pi: ExtensionAPI): void {
210
230
  handler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {
211
231
  const argument = args.trim();
212
232
  if (argument && argument !== CONFIG_RESET_COMMAND) {
213
- ctx.ui.notify(i18n.t("configCommandUsage"), NOTICE_WARNING);
233
+ notify(ctx, i18n.t("configCommandUsage"), NOTICE_WARNING);
214
234
  return;
215
235
  }
216
236
  if (argument === CONFIG_RESET_COMMAND) {
217
237
  try {
218
238
  const path = saveConfig(parseConfig({ skillRoots: [DEFAULT_CONFIG_ROOT] }));
219
- ctx.ui.notify(i18n.t("configCommandSaved", { path }), NOTICE_INFO);
239
+ notify(ctx, i18n.t("configCommandSaved", { path }), NOTICE_INFO);
220
240
  } catch (error) {
221
- ctx.ui.notify(i18n.t("configCommandInvalid", {
241
+ notify(ctx, i18n.t("configCommandInvalid", {
222
242
  error: error instanceof Error ? error.message : String(error),
223
243
  }), NOTICE_ERROR);
224
244
  }
225
245
  return;
226
246
  }
227
247
  if (!ctx.hasUI) {
228
- ctx.ui.notify(i18n.t("configCommandInteractiveOnly"), NOTICE_WARNING);
248
+ notify(ctx, i18n.t("configCommandInteractiveOnly"), NOTICE_WARNING);
229
249
  return;
230
250
  }
231
251
 
@@ -238,9 +258,9 @@ function registerConfigCommand(pi: ExtensionAPI): void {
238
258
  try {
239
259
  const roots = input.split(ROOT_INPUT_SEPARATOR).map((root) => root.trim()).filter(Boolean);
240
260
  const path = saveConfig(parseConfig({ skillRoots: roots }));
241
- ctx.ui.notify(i18n.t("configCommandSaved", { path }), NOTICE_INFO);
261
+ notify(ctx, i18n.t("configCommandSaved", { path }), NOTICE_INFO);
242
262
  } catch (error) {
243
- ctx.ui.notify(i18n.t("configCommandInvalid", {
263
+ notify(ctx, i18n.t("configCommandInvalid", {
244
264
  error: error instanceof Error ? error.message : String(error),
245
265
  }), NOTICE_ERROR);
246
266
  }
@@ -264,16 +284,18 @@ function registerSkillsCommand(pi: ExtensionAPI, index: SkillIndex): void {
264
284
  function notifyDiagnostics(ctx: ExtensionContext, loaded: LoadedNestedSkillsConfig, index: SkillIndex): void {
265
285
  if (!ctx.hasUI) return;
266
286
  for (const warning of loaded.warnings) {
267
- ctx.ui.notify(i18n.t("configWarning", { reason: warning }), NOTICE_WARNING);
287
+ notify(ctx, i18n.t("configWarning", { reason: warning }), NOTICE_WARNING);
268
288
  }
269
289
  for (const warning of index.warnings) {
270
- ctx.ui.notify(
290
+ notify(
291
+ ctx,
271
292
  i18n.t("scanWarning", { path: warning.path, reason: warning.reason }),
272
293
  NOTICE_WARNING,
273
294
  );
274
295
  }
275
296
  if (loaded.explicit && index.skills.length === 0) {
276
- ctx.ui.notify(
297
+ notify(
298
+ ctx,
277
299
  i18n.t("noSkills", { roots: loaded.config.skillRoots.join(", ") || i18n.t("noRoots") }),
278
300
  NOTICE_WARNING,
279
301
  );
@@ -282,6 +304,8 @@ function notifyDiagnostics(ctx: ExtensionContext, loaded: LoadedNestedSkillsConf
282
304
 
283
305
  /** 注册递归技能别名,同时把实际技能正文交给 Pi 原生技能加载和展开流程。 */
284
306
  export default function nestedSkillsExtension(pi: ExtensionAPI): void {
307
+ // 提示画成会话区里的带底色消息块;渲染器在本包这个模块实例里注册一次。
308
+ installNoticeRenderer(pi);
285
309
  const loaded = loadConfig();
286
310
  const scan = scanSkillRoots(loaded.config.skillRoots);
287
311
  const index = buildSkillIndex(scan);