@crouton-kit/crouter 0.3.18 → 0.3.19

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 (257) hide show
  1. package/dist/build-root.js +6 -0
  2. package/dist/builtin-memory/crouter-development/marketplaces.md +164 -0
  3. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +58 -0
  4. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +60 -0
  5. package/dist/builtin-memory/crouter-development/personas.md +117 -0
  6. package/dist/builtin-memory/crouter-development/plugins.md +163 -0
  7. package/dist/builtin-memory/design.md +60 -0
  8. package/dist/builtin-memory/development.md +116 -0
  9. package/dist/builtin-memory/planning.md +66 -0
  10. package/dist/builtin-memory/spec.md +99 -0
  11. package/dist/builtin-personas/design/orchestrator.md +1 -1
  12. package/dist/builtin-personas/developer/orchestrator.md +1 -1
  13. package/dist/builtin-personas/lifecycle/resident.md +1 -1
  14. package/dist/builtin-personas/lifecycle/terminal.md +5 -2
  15. package/dist/builtin-personas/orchestration-kernel.md +15 -24
  16. package/dist/builtin-personas/plan/orchestrator.md +1 -1
  17. package/dist/builtin-personas/runtime-base.md +6 -3
  18. package/dist/builtin-personas/spec/orchestrator.md +1 -1
  19. package/dist/builtin-personas/waiting.md +8 -0
  20. package/dist/builtin-skills/skills/crouter-development/personas/orchestrator-prompt/SKILL.md +1 -1
  21. package/dist/builtin-skills/skills/crouter-development/plugins/SKILL.md +2 -2
  22. package/dist/builtin-views/_lib/states.mjs +161 -0
  23. package/dist/builtin-views/canvas/client.mjs +303 -0
  24. package/dist/builtin-views/canvas/view.mjs +576 -0
  25. package/dist/builtin-views/git-pr/client.mjs +440 -0
  26. package/dist/builtin-views/git-pr/view.mjs +675 -0
  27. package/dist/builtin-views/inbox/_lib/render.mjs +177 -0
  28. package/dist/builtin-views/inbox/sources/gmail.mjs +965 -0
  29. package/dist/builtin-views/inbox/sources/linkedin.mjs +427 -0
  30. package/dist/builtin-views/inbox/view.mjs +889 -0
  31. package/dist/builtin-views/linkedin/client.mjs +610 -0
  32. package/dist/builtin-views/linkedin/view.mjs +1171 -0
  33. package/dist/clients/attach/attach-cmd.d.ts +2 -0
  34. package/dist/clients/attach/attach-cmd.js +354 -0
  35. package/dist/clients/attach/chat-view.d.ts +77 -0
  36. package/dist/clients/attach/chat-view.js +450 -0
  37. package/dist/clients/attach/clipboard-image.d.ts +16 -0
  38. package/dist/clients/attach/clipboard-image.js +113 -0
  39. package/dist/clients/attach/config-load.d.ts +31 -0
  40. package/dist/clients/attach/config-load.js +113 -0
  41. package/dist/clients/attach/extension-dialogs.d.ts +29 -0
  42. package/dist/clients/attach/extension-dialogs.js +101 -0
  43. package/dist/clients/attach/input-controller.d.ts +54 -0
  44. package/dist/clients/attach/input-controller.js +204 -0
  45. package/dist/clients/attach/slash-commands.d.ts +36 -0
  46. package/dist/clients/attach/slash-commands.js +200 -0
  47. package/dist/clients/attach/view-socket.d.ts +48 -0
  48. package/dist/clients/attach/view-socket.js +126 -0
  49. package/dist/commands/attention.js +3 -3
  50. package/dist/commands/canvas-prune.js +1 -1
  51. package/dist/commands/daemon.js +3 -2
  52. package/dist/commands/human/prompts.js +1 -1
  53. package/dist/commands/human/queue.js +43 -8
  54. package/dist/commands/human/shared.d.ts +2 -0
  55. package/dist/commands/memory/find.d.ts +1 -0
  56. package/dist/commands/memory/find.js +180 -0
  57. package/dist/commands/memory/lint.d.ts +1 -0
  58. package/dist/commands/memory/lint.js +140 -0
  59. package/dist/commands/memory/list.d.ts +1 -0
  60. package/dist/commands/memory/list.js +79 -0
  61. package/dist/commands/memory/read.js +103 -0
  62. package/dist/commands/memory/shared.d.ts +30 -0
  63. package/dist/commands/memory/shared.js +122 -0
  64. package/dist/commands/memory/write.d.ts +1 -0
  65. package/dist/commands/memory/write.js +85 -0
  66. package/dist/commands/memory.d.ts +2 -0
  67. package/dist/commands/memory.js +27 -0
  68. package/dist/commands/node.d.ts +3 -2
  69. package/dist/commands/node.js +607 -61
  70. package/dist/commands/pkg/market-manage.js +1 -1
  71. package/dist/commands/push.js +6 -6
  72. package/dist/commands/revive.js +1 -1
  73. package/dist/commands/skill/author.js +1 -1
  74. package/dist/commands/skill/shared.d.ts +1 -8
  75. package/dist/commands/skill/shared.js +2 -55
  76. package/dist/commands/skill.js +9 -14
  77. package/dist/commands/sys/doctor.js +1 -1
  78. package/dist/commands/sys/update.js +1 -1
  79. package/dist/commands/view-cycle.d.ts +2 -0
  80. package/dist/commands/view-cycle.js +125 -0
  81. package/dist/commands/view-list.d.ts +2 -0
  82. package/dist/commands/view-list.js +66 -0
  83. package/dist/commands/view-new.d.ts +2 -0
  84. package/dist/commands/view-new.js +70 -0
  85. package/dist/commands/view-pick.d.ts +2 -0
  86. package/dist/commands/view-pick.js +119 -0
  87. package/dist/commands/view-run.d.ts +2 -0
  88. package/dist/commands/view-run.js +191 -0
  89. package/dist/commands/view.d.ts +2 -0
  90. package/dist/commands/view.js +29 -0
  91. package/dist/core/__tests__/broker-lifecycle.test.d.ts +1 -0
  92. package/dist/core/__tests__/broker-lifecycle.test.js +677 -0
  93. package/dist/core/__tests__/broker-sdk-wiring.test.d.ts +1 -0
  94. package/dist/core/__tests__/broker-sdk-wiring.test.js +166 -0
  95. package/dist/core/__tests__/cascade-close.test.js +12 -2
  96. package/dist/core/__tests__/child-death-wake.test.d.ts +1 -0
  97. package/dist/core/__tests__/child-death-wake.test.js +245 -0
  98. package/dist/core/__tests__/context-intro.test.js +76 -62
  99. package/dist/core/__tests__/daemon-boot.test.js +14 -5
  100. package/dist/core/__tests__/daemon-liveness.test.js +34 -9
  101. package/dist/core/__tests__/detach-focus.test.d.ts +1 -0
  102. package/dist/core/__tests__/detach-focus.test.js +206 -0
  103. package/dist/core/__tests__/draw-style.test.d.ts +1 -0
  104. package/dist/core/__tests__/draw-style.test.js +258 -0
  105. package/dist/core/__tests__/fixtures/c3-custom-provider-ext.d.ts +2 -0
  106. package/dist/core/__tests__/fixtures/c3-custom-provider-ext.js +18 -0
  107. package/dist/core/__tests__/fixtures/fake-engine.d.ts +138 -0
  108. package/dist/core/__tests__/fixtures/fake-engine.js +614 -0
  109. package/dist/core/__tests__/fixtures/fake-pi-host.js +1 -0
  110. package/dist/core/__tests__/flagship-lifecycle.test.js +7 -1
  111. package/dist/core/__tests__/frame-decoder-perf.test.d.ts +1 -0
  112. package/dist/core/__tests__/frame-decoder-perf.test.js +198 -0
  113. package/dist/core/__tests__/helpers/harness.d.ts +9 -0
  114. package/dist/core/__tests__/helpers/harness.js +111 -1
  115. package/dist/core/__tests__/home-session.test.js +41 -8
  116. package/dist/core/__tests__/human-new-window-regression.test.d.ts +1 -0
  117. package/dist/core/__tests__/human-new-window-regression.test.js +101 -0
  118. package/dist/core/__tests__/kickoff.test.js +37 -3
  119. package/dist/core/__tests__/live-mutation.test.js +50 -33
  120. package/dist/core/__tests__/memory.test.js +23 -115
  121. package/dist/core/__tests__/placement-focus.test.js +5 -0
  122. package/dist/core/__tests__/placement-teardown.test.js +54 -11
  123. package/dist/core/__tests__/relaunch.test.js +4 -3
  124. package/dist/core/__tests__/review-render-pane-regression.test.d.ts +1 -0
  125. package/dist/core/__tests__/review-render-pane-regression.test.js +133 -0
  126. package/dist/core/__tests__/spawn-root.test.js +10 -0
  127. package/dist/core/__tests__/spike-harness.test.js +1 -0
  128. package/dist/core/__tests__/wake-bearings.test.d.ts +1 -0
  129. package/dist/core/__tests__/wake-bearings.test.js +156 -0
  130. package/dist/core/__tests__/wake-origin.test.d.ts +1 -0
  131. package/dist/core/__tests__/wake-origin.test.js +110 -0
  132. package/dist/core/bootstrap.js +1 -1
  133. package/dist/core/canvas/browse/__tests__/render.test.js +1 -0
  134. package/dist/core/canvas/browse/app.js +24 -2
  135. package/dist/core/canvas/browse/model.d.ts +38 -2
  136. package/dist/core/canvas/browse/model.js +134 -10
  137. package/dist/core/canvas/browse/render.d.ts +6 -12
  138. package/dist/core/canvas/browse/render.js +72 -104
  139. package/dist/core/canvas/canvas.js +15 -22
  140. package/dist/core/canvas/db.js +46 -0
  141. package/dist/core/canvas/index.d.ts +1 -0
  142. package/dist/core/canvas/index.js +1 -0
  143. package/dist/core/canvas/pid.d.ts +4 -0
  144. package/dist/core/canvas/pid.js +23 -0
  145. package/dist/core/canvas/render.d.ts +11 -2
  146. package/dist/core/canvas/render.js +69 -0
  147. package/dist/core/canvas/types.d.ts +85 -3
  148. package/dist/core/canvas/wakeups.d.ts +76 -0
  149. package/dist/core/canvas/wakeups.js +185 -0
  150. package/dist/core/config.js +4 -1
  151. package/dist/core/frontmatter.js +37 -124
  152. package/dist/core/memory-resolver.d.ts +49 -0
  153. package/dist/core/memory-resolver.js +141 -0
  154. package/dist/core/personas/loader.d.ts +7 -0
  155. package/dist/core/personas/loader.js +36 -5
  156. package/dist/core/personas/resolve.js +13 -3
  157. package/dist/core/predicate.d.ts +63 -0
  158. package/dist/core/predicate.js +189 -0
  159. package/dist/core/resolver.js +26 -5
  160. package/dist/core/runtime/bearings.d.ts +53 -12
  161. package/dist/core/runtime/bearings.js +132 -59
  162. package/dist/core/runtime/broker-cli.d.ts +1 -0
  163. package/dist/core/runtime/broker-cli.js +46 -0
  164. package/dist/core/runtime/broker-protocol.d.ts +332 -0
  165. package/dist/core/runtime/broker-protocol.js +153 -0
  166. package/dist/core/runtime/broker-sdk.d.ts +48 -0
  167. package/dist/core/runtime/broker-sdk.js +72 -0
  168. package/dist/core/runtime/broker.d.ts +55 -0
  169. package/dist/core/runtime/broker.js +1128 -0
  170. package/dist/core/runtime/close.js +35 -6
  171. package/dist/core/runtime/host.d.ts +53 -0
  172. package/dist/core/runtime/host.js +186 -0
  173. package/dist/core/runtime/kickoff.d.ts +2 -1
  174. package/dist/core/runtime/kickoff.js +91 -5
  175. package/dist/core/runtime/launch.d.ts +45 -2
  176. package/dist/core/runtime/launch.js +65 -2
  177. package/dist/core/runtime/lifecycle.js +23 -6
  178. package/dist/core/runtime/memory.d.ts +2 -42
  179. package/dist/core/runtime/memory.js +11 -162
  180. package/dist/core/runtime/nodes.d.ts +33 -0
  181. package/dist/core/runtime/nodes.js +59 -1
  182. package/dist/core/runtime/persona.js +21 -11
  183. package/dist/core/runtime/pi-vendored.d.ts +18 -0
  184. package/dist/core/runtime/pi-vendored.js +49 -0
  185. package/dist/core/runtime/placement.d.ts +32 -14
  186. package/dist/core/runtime/placement.js +206 -52
  187. package/dist/core/runtime/promote.d.ts +0 -6
  188. package/dist/core/runtime/promote.js +1 -12
  189. package/dist/core/runtime/{demote.d.ts → recycle.d.ts} +5 -5
  190. package/dist/core/runtime/{demote.js → recycle.js} +27 -11
  191. package/dist/core/runtime/reset.js +8 -6
  192. package/dist/core/runtime/revive.d.ts +2 -0
  193. package/dist/core/runtime/revive.js +34 -34
  194. package/dist/core/runtime/spawn.d.ts +19 -0
  195. package/dist/core/runtime/spawn.js +75 -22
  196. package/dist/core/runtime/stop-guard.d.ts +1 -1
  197. package/dist/core/runtime/stop-guard.js +6 -1
  198. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  199. package/dist/core/runtime/tmux-chrome.js +1 -1
  200. package/dist/core/runtime/tmux.d.ts +28 -0
  201. package/dist/core/runtime/tmux.js +80 -6
  202. package/dist/core/scope.d.ts +11 -0
  203. package/dist/core/scope.js +39 -0
  204. package/dist/core/spawn.d.ts +5 -0
  205. package/dist/core/spawn.js +20 -2
  206. package/dist/core/substrate/gate.d.ts +13 -0
  207. package/dist/core/substrate/gate.js +21 -0
  208. package/dist/core/substrate/index.d.ts +7 -0
  209. package/dist/core/substrate/index.js +18 -0
  210. package/dist/core/substrate/on-read.d.ts +14 -0
  211. package/dist/core/substrate/on-read.js +292 -0
  212. package/dist/core/substrate/render.d.ts +25 -0
  213. package/dist/core/substrate/render.js +256 -0
  214. package/dist/core/substrate/schema.d.ts +76 -0
  215. package/dist/core/substrate/schema.js +124 -0
  216. package/dist/core/substrate/session-cache.d.ts +30 -0
  217. package/dist/core/substrate/session-cache.js +77 -0
  218. package/dist/core/substrate/subject.d.ts +41 -0
  219. package/dist/core/substrate/subject.js +54 -0
  220. package/dist/core/tui/contract.d.ts +83 -0
  221. package/dist/core/tui/contract.js +8 -0
  222. package/dist/core/tui/draw.d.ts +96 -0
  223. package/dist/core/tui/draw.js +339 -0
  224. package/dist/core/tui/host.d.ts +29 -0
  225. package/dist/core/tui/host.js +379 -0
  226. package/dist/core/tui/loader.d.ts +16 -0
  227. package/dist/core/tui/loader.js +94 -0
  228. package/dist/core/{canvas/browse → tui}/terminal.js +7 -6
  229. package/dist/core/wake.d.ts +86 -0
  230. package/dist/core/wake.js +308 -0
  231. package/dist/daemon/crtrd.d.ts +29 -4
  232. package/dist/daemon/crtrd.js +662 -46
  233. package/dist/pi-extensions/__tests__/canvas-context-intro.test.d.ts +1 -0
  234. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +171 -0
  235. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +19 -12
  236. package/dist/pi-extensions/canvas-commands.d.ts +3 -0
  237. package/dist/pi-extensions/canvas-commands.js +10 -0
  238. package/dist/pi-extensions/canvas-context-intro.d.ts +17 -0
  239. package/dist/pi-extensions/canvas-context-intro.js +55 -15
  240. package/dist/pi-extensions/canvas-doc-substrate.d.ts +44 -0
  241. package/dist/pi-extensions/canvas-doc-substrate.js +112 -0
  242. package/dist/pi-extensions/canvas-nav.d.ts +3 -0
  243. package/dist/pi-extensions/canvas-nav.js +87 -23
  244. package/dist/pi-extensions/canvas-stophook.js +17 -8
  245. package/dist/pi-extensions/canvas-view.d.ts +21 -0
  246. package/dist/pi-extensions/canvas-view.js +75 -0
  247. package/dist/prompts/skill.js +19 -26
  248. package/dist/prompts/view.d.ts +7 -0
  249. package/dist/prompts/view.js +101 -0
  250. package/dist/types.d.ts +4 -0
  251. package/dist/types.js +1 -0
  252. package/package.json +9 -4
  253. package/dist/commands/skill/find.d.ts +0 -4
  254. package/dist/commands/skill/find.js +0 -257
  255. package/dist/commands/skill/read.js +0 -91
  256. /package/dist/commands/{skill → memory}/read.d.ts +0 -0
  257. /package/dist/core/{canvas/browse → tui}/terminal.d.ts +0 -0
@@ -1,257 +0,0 @@
1
- import { join } from 'node:path';
2
- import { defineLeaf, defineBranch } from '../../core/command.js';
3
- import { usage } from '../../core/errors.js';
4
- import { SCOPE_SKILL_PLUGIN, SKILLS_DIR } from '../../types.js';
5
- import { listScopes, scopeSkillsDir } from '../../core/scope.js';
6
- import { listAllSkills, listInstalledPlugins } from '../../core/resolver.js';
7
- import { paginate } from '../../core/pagination.js';
8
- import { walkFiles, readText } from '../../core/fs-utils.js';
9
- export const findList = defineLeaf({
10
- name: 'list',
11
- description: 'paginated list of installed skills',
12
- whenToUse: 'browse the whole catalog of installed skills, paginated, when you want to see everything that is available rather than hunt for a particular topic — supports --scope, --plugin, and --full filters to narrow or enrich the listing. Use `crtr skill find search` instead when you already have a topic or keyword in mind.',
13
- help: {
14
- name: 'skill find list',
15
- summary: 'paginated list of installed skills',
16
- params: [
17
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: 'Default: all.' },
18
- { kind: 'flag', name: 'plugin', type: 'string', required: false, constraint: 'Filter to a single plugin name.' },
19
- { kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: 'When present, includes disabled skills.' },
20
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: 'Max 200.' },
21
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: 'Opaque token from next_cursor. Omit on first call.' },
22
- { kind: 'flag', name: 'full', type: 'bool', required: false, constraint: 'When present, includes each skill\'s description in items. Off by default to keep enumerations cheap; pair with --plugin or --limit to bound cost.' },
23
- ],
24
- output: [
25
- { name: 'items', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope, enabled, disabled_in?}. With --full, each item also includes description. Sorted by scope then plugin then name ascending.' },
26
- { name: 'next_cursor', type: 'string | null', required: true, constraint: 'null means no more items.' },
27
- { name: 'total', type: 'integer | null', required: true, constraint: 'Exact when cheap; null otherwise.' },
28
- { name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands for drilling into an item or refining the list.' },
29
- ],
30
- outputKind: 'object',
31
- effects: ['None. Read-only.'],
32
- },
33
- run: async (input) => {
34
- const scopeStr = input['scope'];
35
- const pluginFilter = input['plugin'];
36
- const includeDisabled = input['includeDisabled'];
37
- const limitRaw = input['limit'];
38
- const limit = Math.min(Math.max(1, limitRaw), 200);
39
- const cursor = input['cursor'];
40
- const full = input['full'];
41
- const scopes = listScopes(scopeStr);
42
- const skills = scopes
43
- .flatMap((s) => listAllSkills(s))
44
- .filter((sk) => {
45
- if (pluginFilter !== undefined && sk.plugin !== pluginFilter)
46
- return false;
47
- if (!includeDisabled && !sk.enabled)
48
- return false;
49
- return true;
50
- });
51
- // Sort by scope then plugin then name ascending
52
- const scopeOrder = { project: 0, user: 1, builtin: 2 };
53
- skills.sort((a, b) => {
54
- const so = (scopeOrder[a.scope] !== undefined ? scopeOrder[a.scope] : 3) -
55
- (scopeOrder[b.scope] !== undefined ? scopeOrder[b.scope] : 3);
56
- if (so !== 0)
57
- return so;
58
- const po = a.plugin.localeCompare(b.plugin);
59
- if (po !== 0)
60
- return po;
61
- return a.name.localeCompare(b.name);
62
- });
63
- const keyOf = (sk) => `${sk.scope}/${sk.plugin}/${sk.name}`;
64
- const params = {};
65
- if (limit !== undefined)
66
- params.limit = limit;
67
- if (cursor !== undefined)
68
- params.cursor = cursor;
69
- const result = paginate(skills, params, {
70
- defaultLimit: 50,
71
- maxLimit: 200,
72
- keyOf,
73
- total: 'count',
74
- });
75
- return {
76
- items: result.items.map((sk) => {
77
- const base = {
78
- name: sk.name,
79
- plugin: sk.plugin,
80
- scope: sk.scope,
81
- enabled: sk.enabled,
82
- disabled_in: sk.disabledIn !== undefined ? sk.disabledIn : null,
83
- };
84
- if (full) {
85
- base['description'] = sk.frontmatter.description !== undefined ? sk.frontmatter.description : null;
86
- }
87
- return base;
88
- }),
89
- next_cursor: result.next_cursor,
90
- total: result.total,
91
- follow_up: 'Use `crtr skill read <name>` for the full SKILL.md body. Run `crtr skill find list -h` for filters and verbosity.',
92
- };
93
- },
94
- });
95
- export const findSearch = defineLeaf({
96
- name: 'search',
97
- description: 'keyword search across name/description/keywords',
98
- whenToUse: 'you have a topic, keyword, or problem in mind but not the exact skill name — search ranks installed skills by how well your terms match their name, description, and keywords (add --search-body to also look inside SKILL.md bodies). Reach for it to answer questions like is there a skill for writing tests, anything on prompt design, do we have a debugging workflow. Use `crtr skill find list` instead to browse the whole catalog when you have no particular topic in mind, and `crtr skill find grep` when you need an exact regex or literal-string match across skill bodies rather than a ranked topic match.',
99
- help: {
100
- name: 'skill find search',
101
- summary: 'search skills by name, description, and keywords',
102
- params: [
103
- { kind: 'positional', name: 'query', required: true, constraint: 'Whitespace-separated terms matched case-insensitively against name, description, and keywords; skills matching more terms rank higher.' },
104
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: 'Default: all.' },
105
- { kind: 'flag', name: 'plugin', type: 'string', required: false, constraint: 'Filter to a single plugin name.' },
106
- { kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: 'When present, includes disabled skills.' },
107
- { kind: 'flag', name: 'search-body', type: 'bool', required: false, constraint: 'When present, also searches inside SKILL.md body text.' },
108
- ],
109
- output: [
110
- { name: 'query', type: 'string', required: true, constraint: 'Echo of the input query.' },
111
- { name: 'hits', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope, score, description}. Sorted by score descending. description is the frontmatter line — the discriminator for picking which hit to read in full.' },
112
- { name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands for drilling into a hit or refining the search.' },
113
- ],
114
- outputKind: 'object',
115
- effects: ['None. Read-only.'],
116
- },
117
- run: async (input) => {
118
- const query = input['query'];
119
- const scopeStr = input['scope'];
120
- const pluginFilter = input['plugin'];
121
- const includeDisabled = input['includeDisabled'];
122
- const searchBody = input['searchBody'];
123
- const terms = query
124
- .toLowerCase()
125
- .split(/\s+/)
126
- .filter((t) => t.length > 0);
127
- if (terms.length === 0)
128
- throw usage('query must contain at least one non-whitespace term');
129
- const scopes = listScopes(scopeStr);
130
- const candidates = scopes
131
- .flatMap((s) => listAllSkills(s))
132
- .filter((sk) => {
133
- if (pluginFilter !== undefined && sk.plugin !== pluginFilter)
134
- return false;
135
- if (!includeDisabled && !sk.enabled)
136
- return false;
137
- return true;
138
- });
139
- const hits = [];
140
- for (const sk of candidates) {
141
- const matchedSet = new Set();
142
- let score = 0;
143
- const nameLc = sk.name.toLowerCase();
144
- const descLc = sk.frontmatter.description !== undefined ? sk.frontmatter.description.toLowerCase() : null;
145
- const kwsLc = sk.frontmatter.keywords !== undefined ? sk.frontmatter.keywords.map((k) => k.toLowerCase()) : null;
146
- const bodyLc = searchBody ? readText(sk.path).toLowerCase() : null;
147
- for (const term of terms) {
148
- if (nameLc.includes(term)) {
149
- score += 10;
150
- matchedSet.add('name');
151
- }
152
- if (descLc !== null && descLc.includes(term)) {
153
- score += 4;
154
- matchedSet.add('description');
155
- }
156
- if (kwsLc !== null && kwsLc.some((k) => k.includes(term))) {
157
- score += 6;
158
- matchedSet.add('keywords');
159
- }
160
- if (bodyLc !== null && bodyLc.includes(term)) {
161
- score += 1;
162
- matchedSet.add('body');
163
- }
164
- }
165
- if (score > 0)
166
- hits.push({ skill: sk, score, matched: Array.from(matchedSet) });
167
- }
168
- hits.sort((a, b) => b.score - a.score || a.skill.name.localeCompare(b.skill.name));
169
- return {
170
- query,
171
- hits: hits.map((h) => ({
172
- name: h.skill.name,
173
- plugin: h.skill.plugin,
174
- scope: h.skill.scope,
175
- score: h.score,
176
- description: h.skill.frontmatter.description !== undefined ? h.skill.frontmatter.description : null,
177
- })),
178
- follow_up: 'Use `crtr skill read <name>` for the full SKILL.md body. Run `crtr skill find search -h` for filters.',
179
- };
180
- },
181
- });
182
- export const findGrep = defineLeaf({
183
- name: 'grep',
184
- description: 'regex search across SKILL.md bodies',
185
- whenToUse: 'you need to find which skills contain a specific literal string or regex pattern in their SKILL.md body — an exact text match, not a ranked topic search: locating every skill that mentions a command name, a flag, or an exact phrase. Use `crtr skill find search` instead when you want skills matched by topic or keyword rather than exact body text.',
186
- help: {
187
- name: 'skill find grep',
188
- summary: 'search skill file contents for a regex pattern',
189
- params: [
190
- { kind: 'positional', name: 'pattern', required: true, constraint: 'ECMAScript regex. Applied to each line of every SKILL.md file.' },
191
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: 'Default: all.' },
192
- { kind: 'flag', name: 'plugin', type: 'string', required: false, constraint: 'Filter to a single plugin name.' },
193
- ],
194
- output: [
195
- { name: 'matches', type: 'object[]', required: true, constraint: 'Each: {path, line, text}. path is absolute. Sorted by path then line ascending.' },
196
- ],
197
- outputKind: 'object',
198
- effects: ['None. Read-only.'],
199
- },
200
- run: async (input) => {
201
- const pattern = input['pattern'];
202
- const scopeStr = input['scope'];
203
- const pluginFilter = input['plugin'];
204
- let regex;
205
- try {
206
- regex = new RegExp(pattern);
207
- }
208
- catch {
209
- throw usage(`invalid regex pattern: ${pattern}`);
210
- }
211
- const scopes = listScopes(scopeStr);
212
- const skillsDirs = [];
213
- for (const s of scopes) {
214
- if (pluginFilter === undefined || pluginFilter === SCOPE_SKILL_PLUGIN) {
215
- const root = scopeSkillsDir(s);
216
- if (root)
217
- skillsDirs.push(root);
218
- }
219
- for (const plugin of listInstalledPlugins(s)) {
220
- if (!plugin.enabled)
221
- continue;
222
- if (pluginFilter !== undefined && plugin.name !== pluginFilter)
223
- continue;
224
- skillsDirs.push(join(plugin.root, SKILLS_DIR));
225
- }
226
- }
227
- const matchLines = [];
228
- for (const skillsDir of skillsDirs) {
229
- const files = walkFiles(skillsDir);
230
- for (const file of files) {
231
- const content = readText(file);
232
- const lines = content.split('\n');
233
- lines.forEach((lineText, idx) => {
234
- if (regex.test(lineText)) {
235
- matchLines.push({ path: file, line: idx + 1, text: lineText });
236
- }
237
- });
238
- }
239
- }
240
- // Sort by path then line ascending
241
- matchLines.sort((a, b) => {
242
- const pc = a.path.localeCompare(b.path);
243
- return pc !== 0 ? pc : a.line - b.line;
244
- });
245
- return { matches: matchLines };
246
- },
247
- });
248
- export const findBranch = defineBranch({
249
- name: 'find',
250
- description: 'list, search, or grep skills',
251
- whenToUse: 'you do not yet know which skill applies and need to discover what is installed — list to browse the whole catalog, search to rank skills by topic or keyword, grep to match exact text inside skill bodies.',
252
- help: {
253
- name: 'skill find',
254
- summary: 'discover skills by listing, keyword search, or body grep',
255
- },
256
- children: [findList, findSearch, findGrep],
257
- });
@@ -1,91 +0,0 @@
1
- import { defineLeaf } from '../../core/command.js';
2
- import { CrtrError } from '../../core/errors.js';
3
- import { resolveSkill, resolveCategory, buildCategoryIndex, } from '../../core/resolver.js';
4
- import { resolveScopeArg } from '../../core/scope.js';
5
- import { parseFrontmatter } from '../../core/frontmatter.js';
6
- import { readText } from '../../core/fs-utils.js';
7
- import { appendNeighbors } from './shared.js';
8
- export const readLeaf = defineLeaf({
9
- name: 'read',
10
- description: 'load SKILL.md body + metadata for a named skill',
11
- whenToUse: 'a task in front of you matches a skill that is already loaded — read it BEFORE you start improvising, not after. Reach for it the moment you are about to do something a skill covers: adopting a documented workflow that fits the task at hand, following a methodology before writing a spec or a plan, picking up the house conventions for a tool or framework, replaying a runbook for an operation you have run before. Takes the crtr skill name as a positional (a crtr identifier, never a file path — do not cat or find SKILL.md off disk) and returns the SKILL.md body plus its resolution metadata; add --no-body to just confirm a skill exists or locate it. Reach for `crtr skill find` first when you do not yet know which skill applies.',
12
- help: {
13
- name: 'skill read',
14
- summary: 'load SKILL.md body and resolution metadata for a named skill',
15
- params: [
16
- { kind: 'positional', name: 'name', required: true, constraint: 'Skill identifier. Forms: <name>, <plugin>/<name>, <scope>/<name>, <scope>/<plugin>/<name>.' },
17
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Narrows resolution when name is ambiguous.' },
18
- { kind: 'flag', name: 'plugin', type: 'string', required: false, constraint: 'Narrows resolution to a specific plugin.' },
19
- { kind: 'flag', name: 'frontmatter', type: 'bool', required: false, constraint: 'When present, includes YAML frontmatter in the output content.' },
20
- { kind: 'flag', name: 'no-body', type: 'bool', required: false, constraint: 'When present, omits the body — returns resolution metadata only. Use to confirm a skill exists or locate it without loading SKILL.md.' },
21
- ],
22
- output: [
23
- { name: 'name', type: 'string', required: true, constraint: 'Resolved skill name, or category id when the name resolved to a group.' },
24
- { name: 'kind', type: 'string', required: false, constraint: '"category" when the name resolved to a group rather than a single skill.' },
25
- { name: 'count', type: 'integer', required: false, constraint: 'Number of skills in the category. Present when kind is "category".' },
26
- { name: 'plugin', type: 'string', required: false, constraint: 'Plugin the skill belongs to. Omitted for category reads.' },
27
- { name: 'scope', type: 'string', required: false, constraint: 'Scope the skill was resolved from. Omitted for category reads.' },
28
- { name: 'path', type: 'string', required: false, constraint: 'Absolute path to SKILL.md. Omitted for category reads.' },
29
- { name: 'content', type: 'string', required: false, constraint: 'SKILL.md body or category index. Omitted when --no-body is set.' },
30
- { name: 'follow_up', type: 'string', required: false, constraint: 'Hints at variant flags or next commands. Omitted when --no-body is set.' },
31
- ],
32
- outputKind: 'object',
33
- effects: ['None. Read-only.'],
34
- },
35
- run: async (input) => {
36
- const nameRaw = input['name'];
37
- const scopeStr = input['scope'];
38
- const pluginFilter = input['plugin'];
39
- const includeFrontmatter = input['frontmatter'];
40
- const noBody = input['noBody'];
41
- const resolveOpts = {};
42
- if (scopeStr !== undefined) {
43
- const resolved = resolveScopeArg(scopeStr);
44
- if (resolved !== 'all')
45
- resolveOpts.scope = resolved;
46
- }
47
- if (pluginFilter !== undefined)
48
- resolveOpts.pluginFilter = pluginFilter;
49
- let skillObj;
50
- let notFoundErr;
51
- try {
52
- skillObj = resolveSkill(nameRaw, resolveOpts);
53
- }
54
- catch (e) {
55
- if (e instanceof CrtrError && e.code === 'not_found') {
56
- notFoundErr = e;
57
- }
58
- else {
59
- throw e;
60
- }
61
- }
62
- if (skillObj === undefined) {
63
- const cat = resolveCategory(nameRaw, resolveOpts);
64
- if (cat !== null) {
65
- if (noBody)
66
- return { name: cat.id, kind: 'category', count: cat.skills.length };
67
- return {
68
- name: cat.id,
69
- kind: 'category',
70
- count: cat.skills.length,
71
- content: buildCategoryIndex(cat),
72
- follow_up: 'Read a listed skill with `crtr skill read <id>`.',
73
- };
74
- }
75
- throw notFoundErr;
76
- }
77
- const out = {
78
- name: skillObj.name,
79
- plugin: skillObj.plugin,
80
- scope: skillObj.scope,
81
- path: skillObj.path,
82
- };
83
- if (noBody)
84
- return out;
85
- const rawContent = readText(skillObj.path);
86
- const rawBody = includeFrontmatter ? rawContent : parseFrontmatter(rawContent).body;
87
- out['content'] = appendNeighbors(skillObj, rawBody);
88
- out['follow_up'] = 'Add --no-body to skip the body and return path/scope/plugin only. Add --frontmatter to include YAML frontmatter in content.';
89
- return out;
90
- },
91
- });
File without changes
File without changes