mn-ws 0.0.0-stage → 0.2.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 (165) hide show
  1. package/assets/groups.json +10 -0
  2. package/assets/mn-ws/SKILL.md +55 -0
  3. package/assets/mn-ws/hooks.json +14 -0
  4. package/assets/mn-ws/install/inject-root.mjs +26 -0
  5. package/bin/ws.mjs +13 -0
  6. package/dist/core/auth.d.ts +194 -0
  7. package/dist/core/auth.d.ts.map +1 -0
  8. package/dist/core/auth.js +331 -0
  9. package/dist/core/auth.js.map +1 -0
  10. package/dist/core/brand.d.ts +11 -0
  11. package/dist/core/brand.d.ts.map +1 -0
  12. package/dist/core/brand.js +7 -0
  13. package/dist/core/brand.js.map +1 -0
  14. package/dist/core/bridge.d.ts +106 -0
  15. package/dist/core/bridge.d.ts.map +1 -0
  16. package/dist/core/bridge.js +308 -0
  17. package/dist/core/bridge.js.map +1 -0
  18. package/dist/core/config.d.ts +174 -0
  19. package/dist/core/config.d.ts.map +1 -0
  20. package/dist/core/config.js +417 -0
  21. package/dist/core/config.js.map +1 -0
  22. package/dist/core/controller.d.ts +64 -0
  23. package/dist/core/controller.d.ts.map +1 -0
  24. package/dist/core/controller.js +100 -0
  25. package/dist/core/controller.js.map +1 -0
  26. package/dist/core/errors/index.d.ts +30 -0
  27. package/dist/core/errors/index.d.ts.map +1 -0
  28. package/dist/core/errors/index.js +88 -0
  29. package/dist/core/errors/index.js.map +1 -0
  30. package/dist/core/open.d.ts +3 -0
  31. package/dist/core/open.d.ts.map +1 -0
  32. package/dist/core/open.js +27 -0
  33. package/dist/core/open.js.map +1 -0
  34. package/dist/core/paths.d.ts +15 -0
  35. package/dist/core/paths.d.ts.map +1 -0
  36. package/dist/core/paths.js +50 -0
  37. package/dist/core/paths.js.map +1 -0
  38. package/dist/core/serve-port.d.ts +73 -0
  39. package/dist/core/serve-port.d.ts.map +1 -0
  40. package/dist/core/serve-port.js +134 -0
  41. package/dist/core/serve-port.js.map +1 -0
  42. package/dist/core/session.d.ts +78 -0
  43. package/dist/core/session.d.ts.map +1 -0
  44. package/dist/core/session.js +124 -0
  45. package/dist/core/session.js.map +1 -0
  46. package/dist/core/skills/bus.d.ts +29 -0
  47. package/dist/core/skills/bus.d.ts.map +1 -0
  48. package/dist/core/skills/bus.js +114 -0
  49. package/dist/core/skills/bus.js.map +1 -0
  50. package/dist/core/skills/get.d.ts +17 -0
  51. package/dist/core/skills/get.d.ts.map +1 -0
  52. package/dist/core/skills/get.js +87 -0
  53. package/dist/core/skills/get.js.map +1 -0
  54. package/dist/core/skills/handlers.d.ts +22 -0
  55. package/dist/core/skills/handlers.d.ts.map +1 -0
  56. package/dist/core/skills/handlers.js +86 -0
  57. package/dist/core/skills/handlers.js.map +1 -0
  58. package/dist/core/skills/index.d.ts +47 -0
  59. package/dist/core/skills/index.d.ts.map +1 -0
  60. package/dist/core/skills/index.js +268 -0
  61. package/dist/core/skills/index.js.map +1 -0
  62. package/dist/core/skills/install.d.ts +18 -0
  63. package/dist/core/skills/install.d.ts.map +1 -0
  64. package/dist/core/skills/install.js +123 -0
  65. package/dist/core/skills/install.js.map +1 -0
  66. package/dist/core/skills/text-util.d.ts +2 -0
  67. package/dist/core/skills/text-util.d.ts.map +1 -0
  68. package/dist/core/skills/text-util.js +14 -0
  69. package/dist/core/skills/text-util.js.map +1 -0
  70. package/dist/core/store.d.ts +29 -0
  71. package/dist/core/store.d.ts.map +1 -0
  72. package/dist/core/store.js +100 -0
  73. package/dist/core/store.js.map +1 -0
  74. package/dist/core/views.d.ts +11 -0
  75. package/dist/core/views.d.ts.map +1 -0
  76. package/dist/core/views.js +20 -0
  77. package/dist/core/views.js.map +1 -0
  78. package/dist/index.d.ts +6 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +8 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/modules/auth/index.d.ts +73 -0
  83. package/dist/modules/auth/index.d.ts.map +1 -0
  84. package/dist/modules/auth/index.js +64 -0
  85. package/dist/modules/auth/index.js.map +1 -0
  86. package/dist/modules/auth/service.d.ts +98 -0
  87. package/dist/modules/auth/service.d.ts.map +1 -0
  88. package/dist/modules/auth/service.js +200 -0
  89. package/dist/modules/auth/service.js.map +1 -0
  90. package/dist/modules/bridge/index.d.ts +73 -0
  91. package/dist/modules/bridge/index.d.ts.map +1 -0
  92. package/dist/modules/bridge/index.js +89 -0
  93. package/dist/modules/bridge/index.js.map +1 -0
  94. package/dist/modules/bridge/service.d.ts +75 -0
  95. package/dist/modules/bridge/service.d.ts.map +1 -0
  96. package/dist/modules/bridge/service.js +134 -0
  97. package/dist/modules/bridge/service.js.map +1 -0
  98. package/dist/modules/home/index.d.ts +95 -0
  99. package/dist/modules/home/index.d.ts.map +1 -0
  100. package/dist/modules/home/index.js +123 -0
  101. package/dist/modules/home/index.js.map +1 -0
  102. package/dist/modules/home/service.d.ts +48 -0
  103. package/dist/modules/home/service.d.ts.map +1 -0
  104. package/dist/modules/home/service.js +195 -0
  105. package/dist/modules/home/service.js.map +1 -0
  106. package/dist/modules/skill/index.d.ts +78 -0
  107. package/dist/modules/skill/index.d.ts.map +1 -0
  108. package/dist/modules/skill/index.js +132 -0
  109. package/dist/modules/skill/index.js.map +1 -0
  110. package/dist/runtime/api.d.ts +24 -0
  111. package/dist/runtime/api.d.ts.map +1 -0
  112. package/dist/runtime/api.js +140 -0
  113. package/dist/runtime/api.js.map +1 -0
  114. package/dist/runtime/cli.d.ts +23 -0
  115. package/dist/runtime/cli.d.ts.map +1 -0
  116. package/dist/runtime/cli.js +410 -0
  117. package/dist/runtime/cli.js.map +1 -0
  118. package/dist/runtime/help.d.ts +29 -0
  119. package/dist/runtime/help.d.ts.map +1 -0
  120. package/dist/runtime/help.js +89 -0
  121. package/dist/runtime/help.js.map +1 -0
  122. package/dist/runtime/registry.d.ts +318 -0
  123. package/dist/runtime/registry.d.ts.map +1 -0
  124. package/dist/runtime/registry.js +75 -0
  125. package/dist/runtime/registry.js.map +1 -0
  126. package/dist/runtime/server.d.ts +10 -0
  127. package/dist/runtime/server.d.ts.map +1 -0
  128. package/dist/runtime/server.js +127 -0
  129. package/dist/runtime/server.js.map +1 -0
  130. package/dist/runtime/spec.d.ts +32 -0
  131. package/dist/runtime/spec.d.ts.map +1 -0
  132. package/dist/runtime/spec.js +180 -0
  133. package/dist/runtime/spec.js.map +1 -0
  134. package/dist/runtime/types/action.d.ts +101 -0
  135. package/dist/runtime/types/action.d.ts.map +1 -0
  136. package/dist/runtime/types/action.js +19 -0
  137. package/dist/runtime/types/action.js.map +1 -0
  138. package/dist/runtime/types/client.d.ts +39 -0
  139. package/dist/runtime/types/client.d.ts.map +1 -0
  140. package/dist/runtime/types/client.js +2 -0
  141. package/dist/runtime/types/client.js.map +1 -0
  142. package/dist/runtime/types/http.d.ts +22 -0
  143. package/dist/runtime/types/http.d.ts.map +1 -0
  144. package/dist/runtime/types/http.js +6 -0
  145. package/dist/runtime/types/http.js.map +1 -0
  146. package/dist/runtime/types/module.d.ts +72 -0
  147. package/dist/runtime/types/module.d.ts.map +1 -0
  148. package/dist/runtime/types/module.js +15 -0
  149. package/dist/runtime/types/module.js.map +1 -0
  150. package/dist/web/public/assets/CliHints-BOxU-Duc.js +1 -0
  151. package/dist/web/public/assets/index-BTRKdMIW.js +50 -0
  152. package/dist/web/public/assets/index-BjGe8ggI.css +1 -0
  153. package/dist/web/public/assets/view-CE4tnCuy.js +1 -0
  154. package/dist/web/public/assets/view-CEQ2uPxE.js +1 -0
  155. package/dist/web/public/favicon-16.png +0 -0
  156. package/dist/web/public/favicon-32.png +0 -0
  157. package/dist/web/public/favicon-48.png +0 -0
  158. package/dist/web/public/favicon.ico +0 -0
  159. package/dist/web/public/index.html +19 -0
  160. package/dist/web/public/logo-rounded.png +0 -0
  161. package/dist/web/public/logo-rounded.svg +6 -0
  162. package/dist/web/public/logo.png +0 -0
  163. package/dist/web/public/logo.svg +6 -0
  164. package/package.json +64 -4
  165. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { type HookHandlerSpec } from './handlers.js';
2
+ export declare const HOOK_CONFIG_FILE = "hooks.json";
3
+ export interface HookRule {
4
+ match: string;
5
+ hooks: HookHandlerSpec[];
6
+ }
7
+ export interface HookConfig {
8
+ dir: string;
9
+ hooks: Record<string, HookRule[]>;
10
+ }
11
+ export declare function loadHookConfig(dir: string): Promise<HookConfig | null>;
12
+ export interface HookOutcome {
13
+ ran: number;
14
+ blocked: boolean;
15
+ reason?: string;
16
+ by: string;
17
+ vars: Record<string, string>;
18
+ data: unknown[];
19
+ }
20
+ interface RunEventInput {
21
+ event: string;
22
+ target: string;
23
+ configs: Array<HookConfig | null>;
24
+ fields?: Record<string, unknown>;
25
+ }
26
+ export declare function runHookEvent(input: RunEventInput): Promise<HookOutcome>;
27
+ export declare function emit(event: string, target: string, config: HookConfig | null, fields?: Record<string, unknown>): Promise<HookOutcome>;
28
+ export {};
29
+ //# sourceMappingURL=bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../../src/core/skills/bus.ts"],"names":[],"mappings":"AAyBA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACnC;AAGD,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA4C5E;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAElC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAID,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAiC7E;AAGD,wBAAsB,IAAI,CACxB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,WAAW,CAAC,CAEtB"}
@@ -0,0 +1,114 @@
1
+ // 通用 hook 总线:配置文件桥接、match 过滤、无限事件平面。
2
+ //
3
+ // 模型参考 Claude Code hooks(settings.json → hooks → 事件组 → matcher → handlers),
4
+ // 在 nx-nx 内落地为每个 skill / 项目可自带的 hooks.json:
5
+ //
6
+ // {
7
+ // "version": 1,
8
+ // "hooks": {
9
+ // "<任意事件名>": [
10
+ // { "match": "<正则,匹配 target>",
11
+ // "hooks": [ { "type": "module", "use": "./x.mjs" },
12
+ // { "type": "command", "command": "node y.mjs" } ] }
13
+ // ]
14
+ // }
15
+ // }
16
+ //
17
+ // 关键性质:
18
+ // 1. 事件平面开放——核心不枚举事件,任意字符串都能注册与触发(无限平面扩展)
19
+ // 2. match = 正则白名单,只在 target 命中时执行该规则
20
+ // 3. handler 顺序执行;decision.vars 聚合、decision.block 立即阻断
21
+ // 4. 配置 schema / 坏 JSON / 坏正则一律显眼报错(作者资产,不静默)
22
+ import fsp from 'node:fs/promises';
23
+ import { existsSync } from 'node:fs';
24
+ import { join } from 'node:path';
25
+ import { specError } from '../errors/index.js';
26
+ import { runHandler, } from './handlers.js';
27
+ export const HOOK_CONFIG_FILE = 'hooks.json';
28
+ // 加载目录下的 hooks.json;不存在 → null(无钩子);坏 JSON / schema 错 → 抛错。
29
+ export async function loadHookConfig(dir) {
30
+ const file = join(dir, HOOK_CONFIG_FILE);
31
+ if (!existsSync(file))
32
+ return null;
33
+ let raw;
34
+ try {
35
+ raw = await fsp.readFile(file, 'utf8');
36
+ }
37
+ catch (e) {
38
+ throw specError(`无法读取 ${HOOK_CONFIG_FILE}: ${String(e.message || e)}`);
39
+ }
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(raw);
43
+ }
44
+ catch {
45
+ throw specError(`${HOOK_CONFIG_FILE} 不是合法 JSON(目录: ${dir})`);
46
+ }
47
+ const groups = parsed.hooks;
48
+ if (!groups || typeof groups !== 'object') {
49
+ throw specError(`${HOOK_CONFIG_FILE} schema 错误:缺少 hooks 对象(目录: ${dir})`);
50
+ }
51
+ for (const [event, rules] of Object.entries(groups)) {
52
+ if (!Array.isArray(rules) || !rules.length) {
53
+ throw specError(`${HOOK_CONFIG_FILE} 事件 "${event}" 必须是非空规则数组`);
54
+ }
55
+ for (const rule of rules) {
56
+ if (typeof rule.match !== 'string' || !rule.match) {
57
+ throw specError(`${HOOK_CONFIG_FILE} 事件 "${event}" 的规则缺少非空 match`);
58
+ }
59
+ try {
60
+ new RegExp(rule.match);
61
+ }
62
+ catch (e) {
63
+ throw specError(`${HOOK_CONFIG_FILE} 事件 "${event}" 的 match 不是合法正则: ${rule.match}(${String(e.message)})`);
64
+ }
65
+ if (!Array.isArray(rule.hooks) || !rule.hooks.length) {
66
+ throw specError(`${HOOK_CONFIG_FILE} 事件 "${event}" 的规则缺少非空 hooks 数组`);
67
+ }
68
+ }
69
+ }
70
+ return { dir, hooks: groups };
71
+ }
72
+ // 触发一个事件:汇总各配置中该事件的规则,match 命中则顺序执行 handlers。
73
+ // 事件名任意——总线不认识固定平面,新事件无需改核心。
74
+ export async function runHookEvent(input) {
75
+ const outcome = { ran: 0, blocked: false, vars: {}, data: [], by: '' };
76
+ for (const config of input.configs) {
77
+ if (!config)
78
+ continue;
79
+ const rules = config.hooks[input.event];
80
+ if (!rules)
81
+ continue;
82
+ for (const rule of rules) {
83
+ if (!new RegExp(rule.match).test(input.target))
84
+ continue;
85
+ const payload = {
86
+ ...input.fields,
87
+ event: input.event,
88
+ target: input.target,
89
+ match: rule.match,
90
+ cwd: input.fields?.cwd || process.cwd(),
91
+ };
92
+ for (const handler of rule.hooks) {
93
+ const decision = await runHandler(handler, config.dir, payload);
94
+ outcome.ran++;
95
+ if (decision?.vars)
96
+ Object.assign(outcome.vars, decision.vars);
97
+ if (decision?.data !== undefined)
98
+ outcome.data.push(decision.data);
99
+ if (decision?.block) {
100
+ outcome.blocked = true;
101
+ outcome.reason = decision.block;
102
+ outcome.by = handler.use || handler.command || 'handler';
103
+ return outcome;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return outcome;
109
+ }
110
+ // 便捷封装:单配置来源。
111
+ export async function emit(event, target, config, fields) {
112
+ return runHookEvent({ event, target, configs: [config], fields });
113
+ }
114
+ //# sourceMappingURL=bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bus.js","sourceRoot":"","sources":["../../../src/core/skills/bus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { installOne } from './index.js';
2
+ export interface SkillGetResult {
3
+ skillName: string;
4
+ ref: string;
5
+ content: string;
6
+ contentBytes: number;
7
+ install: Awaited<ReturnType<typeof installOne>>;
8
+ }
9
+ export declare function listRefs(name: unknown): Promise<string[]>;
10
+ export declare function getSkill(name: unknown, opts?: {
11
+ ref?: string;
12
+ to?: string;
13
+ force?: boolean;
14
+ }): Promise<SkillGetResult>;
15
+ export declare function skillGetPrefix(name: string, ref: string): string;
16
+ export declare function installStatusLine(r: Awaited<ReturnType<typeof installOne>>): string;
17
+ //# sourceMappingURL=get.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/core/skills/get.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+B,UAAU,EAAE,MAAM,YAAY,CAAC;AAIrE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;CACjD;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAS/D;AA+BD,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,OAAO,EACb,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACxD,OAAO,CAAC,cAAc,CAAC,CAiBzB;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,GAAG,MAAM,CAOnF"}
@@ -0,0 +1,87 @@
1
+ // skill get:把指定 skill 的文档导出给外部 agent,并顺手幂等安装。
2
+ // 与 skills.ts 分开:一个管安装/分组,一个管文档读取,各自不超限。
3
+ import fsp from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { badInput, notFound } from '../errors/index.js';
7
+ import { assertSafeName } from '../paths.js';
8
+ import { assetsDir, defaultSkillsDir, installOne } from './index.js';
9
+ const SENTINEL = '# --- begin skill content (do not modify this line) ---';
10
+ export async function listRefs(name) {
11
+ const safe = assertSafeName(name, 'skill 名');
12
+ const dir = join(assetsDir(), safe, 'references');
13
+ try {
14
+ const entries = await fsp.readdir(dir);
15
+ return entries.filter((f) => f.endsWith('.md')).map((f) => f.replace(/\.md$/, '')).sort();
16
+ }
17
+ catch {
18
+ return [];
19
+ }
20
+ }
21
+ // 解析 ref 到 skill 内的相对路径:
22
+ // 空 / SKILL.md → SKILL.md;裸名 → references/<裸名>.md(再退到 <裸名>.md);
23
+ // 含 / 的显式路径去掉 ./ 前缀。任何 '..' 或越界一律拒绝。
24
+ async function resolveRefPath(name, ref) {
25
+ let rel;
26
+ if (!ref || ref === 'SKILL.md') {
27
+ rel = 'SKILL.md';
28
+ }
29
+ else if (ref.includes('/')) {
30
+ rel = ref.replace(/^\.\//, '');
31
+ }
32
+ else {
33
+ const a = join(assetsDir(), name, 'references', `${ref}.md`);
34
+ const b = join(assetsDir(), name, `${ref}.md`);
35
+ rel = existsSync(a) ? join('references', `${ref}.md`) : existsSync(b) ? `${ref}.md` : null;
36
+ if (!rel) {
37
+ const refs = await listRefs(name);
38
+ throw badInput(`未知 ref: ${ref}(可用: SKILL.md, ${refs.join(', ')})`);
39
+ }
40
+ }
41
+ if (rel.split(/[\\/]/).includes('..')) {
42
+ throw badInput(`ref 路径不允许包含 '..': ${ref}`);
43
+ }
44
+ const base = join(assetsDir(), name);
45
+ const resolved = join(base, rel);
46
+ if (!resolved.startsWith(base))
47
+ throw badInput(`ref 越界: ${ref}`);
48
+ // 文档路径随包跨平台分发,统一用正斜杠
49
+ return rel.replace(/\\/g, '/');
50
+ }
51
+ export async function getSkill(name, opts = {}) {
52
+ const safe = assertSafeName(name, 'skill 名');
53
+ if (!existsSync(join(assetsDir(), safe, 'SKILL.md'))) {
54
+ throw notFound(`未找到内置 skill: ${safe}`);
55
+ }
56
+ const rel = await resolveRefPath(safe, opts.ref || '');
57
+ const file = join(assetsDir(), safe, rel);
58
+ let content;
59
+ try {
60
+ content = await fsp.readFile(file, 'utf8');
61
+ }
62
+ catch {
63
+ throw notFound(`未找到 skill 文档: ${safe}/${rel}`);
64
+ }
65
+ const install = await installOne(safe, { to: opts.to || defaultSkillsDir(), force: opts.force });
66
+ return { skillName: safe, ref: rel, content, contentBytes: Buffer.byteLength(content, 'utf8'), install };
67
+ }
68
+ // 人读模式的前缀:sentinel 行给 agent 明确的复制边界。
69
+ export function skillGetPrefix(name, ref) {
70
+ return [
71
+ `# === ${name} skill context ===`,
72
+ `# 以下内容来自 ${name} skill 的 ${ref || 'SKILL.md'}。`,
73
+ `# 建议:把 sentinel 行之后的全文复制到 .claude/skills/${name}/ 下,便于后续会话复用。`,
74
+ SENTINEL,
75
+ '',
76
+ ].join('\n');
77
+ }
78
+ export function installStatusLine(r) {
79
+ if (r.status === 'conflict') {
80
+ return `-- install 状态 --\n冲突: ${r.path}(${r.files} 个文件不同;确认覆盖加 --force)`;
81
+ }
82
+ if (r.status === 'skipped')
83
+ return `-- install 状态 --\n已是最新: ${r.path}`;
84
+ const verb = r.replaced ? '已替换' : '已安装';
85
+ return `-- install 状态 --\n${verb}: ${r.path}(${r.files} 个文件)`;
86
+ }
87
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.js","sourceRoot":"","sources":["../../../src/core/skills/get.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface HookHandlerSpec {
2
+ type?: 'module' | 'command';
3
+ use?: string;
4
+ command?: string;
5
+ timeoutMs?: number;
6
+ }
7
+ export type HookPayload = {
8
+ event: string;
9
+ target: string;
10
+ match: string;
11
+ cwd: string;
12
+ [k: string]: unknown;
13
+ };
14
+ export interface HookDecision {
15
+ block?: string;
16
+ vars?: Record<string, string>;
17
+ data?: unknown;
18
+ }
19
+ export declare function runModuleHandler(spec: HookHandlerSpec, configDir: string, payload: HookPayload): Promise<HookDecision | void>;
20
+ export declare function runCommandHandler(spec: HookHandlerSpec, configDir: string, payload: HookPayload): Promise<HookDecision | void>;
21
+ export declare function runHandler(spec: HookHandlerSpec, configDir: string, payload: HookPayload): Promise<HookDecision | void>;
22
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/core/skills/handlers.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE5B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AAGF,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqB9B;AAGD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA8C9B;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAK9B"}
@@ -0,0 +1,86 @@
1
+ // hook handler 执行器:两种类型,同一套 payload / decision 协议。
2
+ //
3
+ // module: import 配置目录内的 ESM 模块,调用导出函数,函数返回 decision
4
+ // command:spawn 子进程(语言无关),payload JSON 走 stdin;
5
+ // stdout 的 JSON 为 decision;exit 2 = 阻断(stderr 作为反馈,
6
+ // 对齐 Claude Code hooks 的 blocking 约定);其余非 0 = 执行错误
7
+ import { spawn } from 'node:child_process';
8
+ import { existsSync } from 'node:fs';
9
+ import { isAbsolute, resolve, sep } from 'node:path';
10
+ import { pathToFileURL } from 'node:url';
11
+ import { external, specError } from '../errors/index.js';
12
+ const DEFAULT_TIMEOUT_MS = 15_000;
13
+ // module handler:解析并校验路径(必须在配置目录内),import 后调用。
14
+ export async function runModuleHandler(spec, configDir, payload) {
15
+ if (!spec.use)
16
+ throw specError('module handler 缺少 "use" 字段');
17
+ const parts = spec.use.split('#');
18
+ const rel = parts[0] || '';
19
+ const exportName = parts[1];
20
+ const abs = isAbsolute(rel) ? rel : resolve(configDir, rel);
21
+ // 防越界:解析结果必须仍在配置目录内
22
+ const inside = abs === configDir || abs.startsWith(configDir.endsWith(sep) ? configDir : configDir + sep);
23
+ if (!inside) {
24
+ throw specError(`hook 模块路径越出配置目录: ${spec.use}`);
25
+ }
26
+ if (!existsSync(abs))
27
+ throw specError(`hook 模块不存在: ${spec.use}`);
28
+ const mod = await import(pathToFileURL(abs).href);
29
+ const fn = exportName ? mod[exportName] : mod.default;
30
+ if (typeof fn !== 'function') {
31
+ throw specError(`hook 模块 ${spec.use} 的 ${exportName || 'default'} 不是函数`);
32
+ }
33
+ return (await fn(payload));
34
+ }
35
+ // command handler:子进程 + stdin JSON + stdout JSON / exit 2 阻断。
36
+ export function runCommandHandler(spec, configDir, payload) {
37
+ if (!spec.command || !spec.command.trim()) {
38
+ throw specError('command handler 缺少 "command" 字段');
39
+ }
40
+ const timeoutMs = spec.timeoutMs || DEFAULT_TIMEOUT_MS;
41
+ return new Promise((resolvePromise, rejectPromise) => {
42
+ const child = spawn(spec.command, {
43
+ cwd: configDir,
44
+ shell: true,
45
+ stdio: ['pipe', 'pipe', 'pipe'],
46
+ });
47
+ let stdout = '';
48
+ let stderr = '';
49
+ const timer = setTimeout(() => {
50
+ child.kill('SIGTERM');
51
+ rejectPromise(external(`hook 命令超时(${timeoutMs}ms): ${spec.command}`));
52
+ }, timeoutMs);
53
+ child.stdout.on('data', (b) => (stdout += b.toString()));
54
+ child.stderr.on('data', (b) => (stderr += b.toString()));
55
+ child.on('error', rejectPromise);
56
+ child.on('close', (code) => {
57
+ clearTimeout(timer);
58
+ if (code === 0) {
59
+ const t = stdout.trim();
60
+ if (!t)
61
+ return resolvePromise();
62
+ try {
63
+ return resolvePromise(JSON.parse(t));
64
+ }
65
+ catch {
66
+ return rejectPromise(external(`hook 命令 stdout 不是合法 JSON: ${spec.command}(${t.slice(0, 80)})`));
67
+ }
68
+ }
69
+ if (code === 2) {
70
+ return resolvePromise({ block: stderr.trim() || `hook 阻断: ${spec.command}` });
71
+ }
72
+ rejectPromise(external(`hook 命令退出码 ${code}: ${spec.command}${stderr ? '\n' + stderr.trim() : ''}`));
73
+ });
74
+ child.stdin.write(JSON.stringify(payload));
75
+ child.stdin.end();
76
+ });
77
+ }
78
+ export async function runHandler(spec, configDir, payload) {
79
+ const type = spec.type || (spec.command ? 'command' : 'module');
80
+ if (type === 'command')
81
+ return runCommandHandler(spec, configDir, payload);
82
+ if (type === 'module')
83
+ return runModuleHandler(spec, configDir, payload);
84
+ throw specError(`未知 hook handler 类型: ${String(type)}`);
85
+ }
86
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/core/skills/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { type AbsolutePath } from '../brand.js';
2
+ export declare function assetsDir(): AbsolutePath;
3
+ export declare const defaultSkillsDir: () => AbsolutePath;
4
+ export interface GroupSpec {
5
+ skills: string[];
6
+ summary?: string;
7
+ }
8
+ export interface GroupsManifest {
9
+ groups: Record<string, GroupSpec>;
10
+ defaultGroup: string | null;
11
+ source: 'manifest' | 'assets-dirs';
12
+ warning?: string;
13
+ }
14
+ export declare function loadGroups(): Promise<GroupsManifest>;
15
+ export declare function bundledSkillNames(): Promise<string[]>;
16
+ export interface InstallResult {
17
+ status: 'ok' | 'conflict' | 'skipped';
18
+ name: string;
19
+ path: string;
20
+ files: number;
21
+ installed?: boolean;
22
+ replaced?: boolean;
23
+ }
24
+ export declare function inspectInstall(name: unknown, toRoot?: string): Promise<{
25
+ name: string;
26
+ path: string;
27
+ changed: string[];
28
+ dstExisted: boolean;
29
+ }>;
30
+ export declare function installOne(name: unknown, opts?: {
31
+ to?: string;
32
+ force?: boolean;
33
+ }): Promise<InstallResult>;
34
+ export interface GroupInstallResult {
35
+ status: 'ok' | 'conflict';
36
+ group: string;
37
+ skills: InstallResult[];
38
+ }
39
+ export declare function installGroup(group: unknown, opts?: {
40
+ to?: string;
41
+ force?: boolean;
42
+ }): Promise<GroupInstallResult>;
43
+ export declare function installAll(opts?: {
44
+ to?: string;
45
+ force?: boolean;
46
+ }): Promise<GroupInstallResult>;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/skills/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAYhE,wBAAgB,SAAS,IAAI,YAAY,CAYxC;AAED,eAAO,MAAM,gBAAgB,QAAO,YAC0D,CAAC;AAE/F,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC,CA2C1D;AAkBD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAW3D;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAID,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAUjF;AAOD,wBAAsB,UAAU,CAC9B,IAAI,EAAE,OAAO,EACb,IAAI,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,OAAO,CAAC,aAAa,CAAC,CAyDxB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,IAAI,GAAG,UAAU,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAGD,wBAAsB,YAAY,CAChC,KAAK,EAAE,OAAO,EACd,IAAI,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AAID,wBAAsB,UAAU,CAC9B,IAAI,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,OAAO,CAAC,kBAAkB,CAAC,CAI7B"}