@renxqoo/renx-code 0.0.4 → 0.0.6

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 (210) hide show
  1. package/README.md +82 -51
  2. package/bin/renx.cjs +16 -0
  3. package/package.json +2 -45
  4. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  5. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  6. package/src/agent/runtime/runtime.test.ts +7 -4
  7. package/src/agent/runtime/runtime.ts +3 -9
  8. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  9. package/src/agent/runtime/source-modules.test.ts +16 -35
  10. package/src/agent/runtime/source-modules.ts +17 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  13. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  14. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  15. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  16. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  17. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  33. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  34. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  35. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  36. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  37. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  38. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  39. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  40. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  41. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  42. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  43. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  44. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  45. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  46. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  47. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  48. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  49. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  50. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  51. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  52. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  53. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  54. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  55. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  56. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  57. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  59. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  75. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  76. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  77. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  78. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  79. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  80. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  81. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  82. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  83. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  122. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  123. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  124. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  125. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  126. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  127. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  129. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  130. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  131. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  132. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  133. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  134. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  135. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  136. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  137. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  138. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  139. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  140. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  141. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  142. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  143. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  144. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  145. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  146. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  147. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  148. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  149. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  150. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  151. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  152. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  153. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  154. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  155. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  156. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  157. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  158. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  159. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  160. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  161. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  162. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  163. package/vendor/agent-root/src/agent/types.ts +232 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  167. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  168. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  169. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  170. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  171. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  172. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  173. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  174. package/vendor/agent-root/src/config/index.ts +54 -0
  175. package/vendor/agent-root/src/config/loader.ts +431 -0
  176. package/vendor/agent-root/src/config/paths.ts +30 -0
  177. package/vendor/agent-root/src/config/runtime.ts +163 -0
  178. package/vendor/agent-root/src/config/types.ts +70 -0
  179. package/vendor/agent-root/src/logger/index.ts +57 -0
  180. package/vendor/agent-root/src/logger/logger.ts +819 -0
  181. package/vendor/agent-root/src/logger/types.ts +150 -0
  182. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  183. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  185. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  186. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  187. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  190. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  191. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  192. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  193. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  194. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  195. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  196. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  197. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  198. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  199. package/vendor/agent-root/src/providers/index.ts +76 -0
  200. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  201. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  202. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  203. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  204. package/vendor/agent-root/src/providers/registry.ts +135 -0
  205. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  206. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  207. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  208. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  209. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  210. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,543 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ parseFrontmatter,
4
+ stripFrontmatter,
5
+ extractFileRefs,
6
+ extractShellCommands,
7
+ deriveDescriptionFromMarkdown,
8
+ formatSkillForContext,
9
+ isValidSkillName,
10
+ } from '../skill/parser';
11
+
12
+ describe('parseFrontmatter', () => {
13
+ it('parses valid frontmatter', () => {
14
+ const content = `---
15
+ name: test-skill
16
+ description: A test skill
17
+ license: MIT
18
+ version: 1.0.0
19
+ author: Test Author
20
+ ---
21
+ # Test Skill
22
+ This is a test skill.`;
23
+
24
+ const result = parseFrontmatter(content);
25
+ expect(result).toEqual({
26
+ name: 'test-skill',
27
+ description: 'A test skill',
28
+ license: 'MIT',
29
+ version: '1.0.0',
30
+ author: 'Test Author',
31
+ });
32
+ });
33
+
34
+ it('parses frontmatter with quoted values', () => {
35
+ const content = `---
36
+ name: "test-skill"
37
+ description: 'A test skill'
38
+ ---
39
+ Content`;
40
+
41
+ const result = parseFrontmatter(content);
42
+ expect(result).toEqual({
43
+ name: 'test-skill',
44
+ description: 'A test skill',
45
+ });
46
+ });
47
+
48
+ it('returns null for missing frontmatter', () => {
49
+ const content = `# Test Skill
50
+ This is a test skill.`;
51
+
52
+ const result = parseFrontmatter(content);
53
+ expect(result).toBeNull();
54
+ });
55
+
56
+ it('returns null for incomplete frontmatter', () => {
57
+ const content = `---
58
+ name: test-skill
59
+ ---
60
+ Content`;
61
+
62
+ const result = parseFrontmatter(content);
63
+ expect(result).toBeNull();
64
+ });
65
+
66
+ it('returns null for frontmatter without name', () => {
67
+ const content = `---
68
+ description: A test skill
69
+ ---
70
+ Content`;
71
+
72
+ const result = parseFrontmatter(content);
73
+ expect(result).toBeNull();
74
+ });
75
+
76
+ it('returns null for frontmatter without description', () => {
77
+ const content = `---
78
+ name: test-skill
79
+ ---
80
+ Content`;
81
+
82
+ const result = parseFrontmatter(content);
83
+ expect(result).toBeNull();
84
+ });
85
+
86
+ it('handles frontmatter with extra whitespace', () => {
87
+ const content = `---
88
+ name: test-skill
89
+ description: A test skill
90
+ ---
91
+ Content`;
92
+
93
+ const result = parseFrontmatter(content);
94
+ expect(result).toEqual({
95
+ name: 'test-skill',
96
+ description: 'A test skill',
97
+ });
98
+ });
99
+
100
+ it('handles frontmatter with empty lines', () => {
101
+ const content = `---
102
+ name: test-skill
103
+
104
+ description: A test skill
105
+ ---
106
+ Content`;
107
+
108
+ const result = parseFrontmatter(content);
109
+ expect(result).toEqual({
110
+ name: 'test-skill',
111
+ description: 'A test skill',
112
+ });
113
+ });
114
+
115
+ it('handles frontmatter with colons in values', () => {
116
+ const content = `---
117
+ name: test-skill
118
+ description: A test skill: with colons
119
+ ---
120
+ Content`;
121
+
122
+ const result = parseFrontmatter(content);
123
+ expect(result).toEqual({
124
+ name: 'test-skill',
125
+ description: 'A test skill: with colons',
126
+ });
127
+ });
128
+
129
+ it('handles frontmatter with special characters', () => {
130
+ const content = `---
131
+ name: test-skill
132
+ description: A test skill with special chars: !@#$%^&*()
133
+ ---
134
+ Content`;
135
+
136
+ const result = parseFrontmatter(content);
137
+ expect(result).toEqual({
138
+ name: 'test-skill',
139
+ description: 'A test skill with special chars: !@#$%^&*()',
140
+ });
141
+ });
142
+ });
143
+
144
+ describe('stripFrontmatter', () => {
145
+ it('strips frontmatter from content', () => {
146
+ const content = `---
147
+ name: test-skill
148
+ description: A test skill
149
+ ---
150
+ # Test Skill
151
+ This is a test skill.`;
152
+
153
+ const result = stripFrontmatter(content);
154
+ expect(result).toBe(`# Test Skill
155
+ This is a test skill.`);
156
+ });
157
+
158
+ it('returns original content when no frontmatter', () => {
159
+ const content = `# Test Skill
160
+ This is a test skill.`;
161
+
162
+ const result = stripFrontmatter(content);
163
+ expect(result).toBe(content);
164
+ });
165
+
166
+ it('handles frontmatter with trailing newline', () => {
167
+ const content = `---
168
+ name: test-skill
169
+ description: A test skill
170
+ ---
171
+
172
+ # Test Skill`;
173
+
174
+ const result = stripFrontmatter(content);
175
+ expect(result).toBe(`# Test Skill`);
176
+ });
177
+
178
+ it('handles frontmatter without trailing newline', () => {
179
+ const content = `---
180
+ name: test-skill
181
+ description: A test skill
182
+ ---
183
+ # Test Skill`;
184
+
185
+ const result = stripFrontmatter(content);
186
+ expect(result).toBe(`# Test Skill`);
187
+ });
188
+
189
+ it('handles empty content', () => {
190
+ const result = stripFrontmatter('');
191
+ expect(result).toBe('');
192
+ });
193
+
194
+ it('handles content with only frontmatter', () => {
195
+ const content = `---
196
+ name: test-skill
197
+ description: A test skill
198
+ ---`;
199
+
200
+ const result = stripFrontmatter(content);
201
+ expect(result).toBe('');
202
+ });
203
+ });
204
+
205
+ describe('extractFileRefs', () => {
206
+ it('extracts file references', () => {
207
+ const content = `Check @file.txt and @./path/to/file.js for details.`;
208
+ const result = extractFileRefs(content);
209
+ expect(result).toEqual(['file.txt', './path/to/file.js']);
210
+ });
211
+
212
+ it('extracts file references with different extensions', () => {
213
+ const content = `Files: @file.txt, @file.js, @file.ts, @file.json, @file.md`;
214
+ const result = extractFileRefs(content);
215
+ expect(result).toEqual(['file.txt', 'file.js', 'file.ts', 'file.json', 'file.md']);
216
+ });
217
+
218
+ it('extracts file references with paths', () => {
219
+ const content = `Files: @./relative/path.txt, @../parent/path.txt, @/absolute/path.txt`;
220
+ const result = extractFileRefs(content);
221
+ expect(result).toEqual(['./relative/path.txt', '../parent/path.txt', '/absolute/path.txt']);
222
+ });
223
+
224
+ it('extracts file references with backslashes', () => {
225
+ const content = `Files: @.\\relative\\path.txt, @..\\parent\\path.txt`;
226
+ const result = extractFileRefs(content);
227
+ expect(result).toEqual(['.\\relative\\path.txt', '..\\parent\\path.txt']);
228
+ });
229
+
230
+ it('does not extract file references in code blocks', () => {
231
+ const content = `\`@file.txt\` is in code block.`;
232
+ const result = extractFileRefs(content);
233
+ expect(result).toEqual([]);
234
+ });
235
+
236
+ it('does not extract file references in words', () => {
237
+ const content = `email@example.com is not a file reference.`;
238
+ const result = extractFileRefs(content);
239
+ expect(result).toEqual([]);
240
+ });
241
+
242
+ it('handles empty content', () => {
243
+ const result = extractFileRefs('');
244
+ expect(result).toEqual([]);
245
+ });
246
+
247
+ it('handles content with no file references', () => {
248
+ const content = `This is just text without any file references.`;
249
+ const result = extractFileRefs(content);
250
+ expect(result).toEqual([]);
251
+ });
252
+
253
+ it('deduplicates file references', () => {
254
+ const content = `@file.txt and @file.txt again.`;
255
+ const result = extractFileRefs(content);
256
+ expect(result).toEqual(['file.txt']);
257
+ });
258
+
259
+ it('extracts file references with complex paths', () => {
260
+ const content = `@./path/to/file-name_123.txt and @../other/path/file.name.js`;
261
+ const result = extractFileRefs(content);
262
+ expect(result).toEqual(['./path/to/file-name_123.txt', '../other/path/file.name.js']);
263
+ });
264
+ });
265
+
266
+ describe('extractShellCommands', () => {
267
+ it('extracts shell commands', () => {
268
+ const content = `Run !\`ls -la\` and !\`pwd\` commands.`;
269
+ const result = extractShellCommands(content);
270
+ expect(result).toEqual(['ls -la', 'pwd']);
271
+ });
272
+
273
+ it('extracts shell commands with arguments', () => {
274
+ const content = `Run !\`git status\` and !\`npm install --save\`.`;
275
+ const result = extractShellCommands(content);
276
+ expect(result).toEqual(['git status', 'npm install --save']);
277
+ });
278
+
279
+ it('extracts shell commands with pipes', () => {
280
+ const content = `Run !\`ls -la | grep test\`.`;
281
+ const result = extractShellCommands(content);
282
+ expect(result).toEqual(['ls -la | grep test']);
283
+ });
284
+
285
+ it('extracts shell commands with redirections', () => {
286
+ const content = `Run !\`echo "test" > file.txt\`.`;
287
+ const result = extractShellCommands(content);
288
+ expect(result).toEqual(['echo "test" > file.txt']);
289
+ });
290
+
291
+ it('does not extract shell commands in regular backticks', () => {
292
+ const content = `\`ls -la\` is not a shell command.`;
293
+ const result = extractShellCommands(content);
294
+ expect(result).toEqual([]);
295
+ });
296
+
297
+ it('handles empty content', () => {
298
+ const result = extractShellCommands('');
299
+ expect(result).toEqual([]);
300
+ });
301
+
302
+ it('handles content with no shell commands', () => {
303
+ const content = `This is just text without any shell commands.`;
304
+ const result = extractShellCommands(content);
305
+ expect(result).toEqual([]);
306
+ });
307
+
308
+ it('deduplicates shell commands', () => {
309
+ const content = `!\`ls -la\` and !\`ls -la\` again.`;
310
+ const result = extractShellCommands(content);
311
+ expect(result).toEqual(['ls -la']);
312
+ });
313
+
314
+ it('extracts shell commands with special characters', () => {
315
+ const content = `Run !\`echo "Hello, World!"\` and !\`ls -la | grep "test"\`.`;
316
+ const result = extractShellCommands(content);
317
+ expect(result).toEqual(['echo "Hello, World!"', 'ls -la | grep "test"']);
318
+ });
319
+ });
320
+
321
+ describe('deriveDescriptionFromMarkdown', () => {
322
+ it('derives description from first non-heading line', () => {
323
+ const content = `# Test Skill
324
+ This is a test skill description.
325
+ More content here.`;
326
+
327
+ const result = deriveDescriptionFromMarkdown(content);
328
+ expect(result).toBe('This is a test skill description.');
329
+ });
330
+
331
+ it('skips heading lines', () => {
332
+ const content = `# Test Skill
333
+ ## Subheading
334
+ This is the actual description.`;
335
+
336
+ const result = deriveDescriptionFromMarkdown(content);
337
+ expect(result).toBe('This is the actual description.');
338
+ });
339
+
340
+ it('truncates long descriptions', () => {
341
+ const longText = 'A'.repeat(200);
342
+ const content = `# Test Skill
343
+ ${longText}`;
344
+
345
+ const result = deriveDescriptionFromMarkdown(content);
346
+ expect(result).toBe('A'.repeat(177) + '...');
347
+ });
348
+
349
+ it('handles empty content', () => {
350
+ const result = deriveDescriptionFromMarkdown('');
351
+ expect(result).toBe('No description provided');
352
+ });
353
+
354
+ it('handles content with only headings', () => {
355
+ const content = `# Test Skill
356
+ ## Subheading
357
+ ### Another heading`;
358
+
359
+ const result = deriveDescriptionFromMarkdown(content);
360
+ expect(result).toBe('No description provided');
361
+ });
362
+
363
+ it('handles content with frontmatter', () => {
364
+ const content = `---
365
+ name: test-skill
366
+ description: A test skill
367
+ ---
368
+ # Test Skill
369
+ This is the actual content.`;
370
+
371
+ const result = deriveDescriptionFromMarkdown(content);
372
+ expect(result).toBe('This is the actual content.');
373
+ });
374
+
375
+ it('handles content with empty lines', () => {
376
+ const content = `# Test Skill
377
+
378
+ This is the description after empty lines.`;
379
+
380
+ const result = deriveDescriptionFromMarkdown(content);
381
+ expect(result).toBe('This is the description after empty lines.');
382
+ });
383
+
384
+ it('handles content with whitespace', () => {
385
+ const content = `# Test Skill
386
+
387
+ This is the description with whitespace.`;
388
+
389
+ const result = deriveDescriptionFromMarkdown(content);
390
+ expect(result).toBe('This is the description with whitespace.');
391
+ });
392
+ });
393
+
394
+ describe('formatSkillForContext', () => {
395
+ it('formats skill with all fields', () => {
396
+ const skill = {
397
+ metadata: {
398
+ name: 'test-skill',
399
+ description: 'A test skill',
400
+ path: '/path/to/skill',
401
+ },
402
+ content: 'Skill content here.',
403
+ fileRefs: ['file1.txt', 'file2.js'],
404
+ shellCommands: ['ls -la', 'pwd'],
405
+ };
406
+
407
+ const result = formatSkillForContext(skill);
408
+ expect(result).toContain('## Skill: test-skill');
409
+ expect(result).toContain('Description: A test skill');
410
+ expect(result).toContain('Base directory: /path/to/skill');
411
+ expect(result).toContain('Referenced files:');
412
+ expect(result).toContain('- file1.txt');
413
+ expect(result).toContain('- file2.js');
414
+ expect(result).toContain('Shell commands:');
415
+ expect(result).toContain('- !`ls -la`');
416
+ expect(result).toContain('- !`pwd`');
417
+ expect(result).toContain('Skill content here.');
418
+ });
419
+
420
+ it('formats skill without file refs', () => {
421
+ const skill = {
422
+ metadata: {
423
+ name: 'test-skill',
424
+ description: 'A test skill',
425
+ path: '/path/to/skill',
426
+ },
427
+ content: 'Skill content here.',
428
+ fileRefs: [],
429
+ shellCommands: ['ls -la'],
430
+ };
431
+
432
+ const result = formatSkillForContext(skill);
433
+ expect(result).not.toContain('Referenced files:');
434
+ expect(result).toContain('Shell commands:');
435
+ });
436
+
437
+ it('formats skill without shell commands', () => {
438
+ const skill = {
439
+ metadata: {
440
+ name: 'test-skill',
441
+ description: 'A test skill',
442
+ path: '/path/to/skill',
443
+ },
444
+ content: 'Skill content here.',
445
+ fileRefs: ['file1.txt'],
446
+ shellCommands: [],
447
+ };
448
+
449
+ const result = formatSkillForContext(skill);
450
+ expect(result).toContain('Referenced files:');
451
+ expect(result).not.toContain('Shell commands:');
452
+ });
453
+
454
+ it('formats skill without file refs and shell commands', () => {
455
+ const skill = {
456
+ metadata: {
457
+ name: 'test-skill',
458
+ description: 'A test skill',
459
+ path: '/path/to/skill',
460
+ },
461
+ content: 'Skill content here.',
462
+ fileRefs: [],
463
+ shellCommands: [],
464
+ };
465
+
466
+ const result = formatSkillForContext(skill);
467
+ expect(result).not.toContain('Referenced files:');
468
+ expect(result).not.toContain('Shell commands:');
469
+ });
470
+ });
471
+
472
+ describe('isValidSkillName', () => {
473
+ it('returns true for valid skill names', () => {
474
+ expect(isValidSkillName('test-skill')).toBe(true);
475
+ expect(isValidSkillName('test.skill')).toBe(true);
476
+ expect(isValidSkillName('test_skill')).toBe(true);
477
+ expect(isValidSkillName('test123')).toBe(true);
478
+ expect(isValidSkillName('test-skill-123')).toBe(true);
479
+ expect(isValidSkillName('test.skill.123')).toBe(true);
480
+ expect(isValidSkillName('test_skill_123')).toBe(true);
481
+ });
482
+
483
+ it('returns false for empty name', () => {
484
+ expect(isValidSkillName('')).toBe(false);
485
+ });
486
+
487
+ it('returns false for name longer than 64 characters', () => {
488
+ const longName = 'a'.repeat(65);
489
+ expect(isValidSkillName(longName)).toBe(false);
490
+ });
491
+
492
+ it('returns false for name with invalid characters', () => {
493
+ expect(isValidSkillName('Test-Skill')).toBe(false); // uppercase
494
+ expect(isValidSkillName('test skill')).toBe(false); // space
495
+ expect(isValidSkillName('test@skill')).toBe(false); // @
496
+ expect(isValidSkillName('test#skill')).toBe(false); // #
497
+ expect(isValidSkillName('test$skill')).toBe(false); // $
498
+ expect(isValidSkillName('test%skill')).toBe(false); // %
499
+ expect(isValidSkillName('test^skill')).toBe(false); // ^
500
+ expect(isValidSkillName('test&skill')).toBe(false); // &
501
+ expect(isValidSkillName('test*skill')).toBe(false); // *
502
+ expect(isValidSkillName('test(skill')).toBe(false); // (
503
+ expect(isValidSkillName('test)skill')).toBe(false); // )
504
+ expect(isValidSkillName('test+skill')).toBe(false); // +
505
+ expect(isValidSkillName('test=skill')).toBe(false); // =
506
+ expect(isValidSkillName('test[skill')).toBe(false); // [
507
+ expect(isValidSkillName('test]skill')).toBe(false); // ]
508
+ expect(isValidSkillName('test{skill')).toBe(false); // {
509
+ expect(isValidSkillName('test}skill')).toBe(false); // }
510
+ expect(isValidSkillName('test|skill')).toBe(false); // |
511
+ expect(isValidSkillName('test\\skill')).toBe(false); // \
512
+ expect(isValidSkillName('test/skill')).toBe(false); // /
513
+ expect(isValidSkillName('test:skill')).toBe(false); // :
514
+ expect(isValidSkillName('test;skill')).toBe(false); // ;
515
+ expect(isValidSkillName('test"skill')).toBe(false); // "
516
+ expect(isValidSkillName("test'skill")).toBe(false); // '
517
+ expect(isValidSkillName('test<skill')).toBe(false); // <
518
+ expect(isValidSkillName('test>skill')).toBe(false); // >
519
+ expect(isValidSkillName('test,skill')).toBe(false); // ,
520
+ expect(isValidSkillName('test--skill')).toBe(false); // double dash
521
+ });
522
+
523
+ it('returns false for name starting or ending with special characters', () => {
524
+ expect(isValidSkillName('-test-skill')).toBe(false); // leading dash
525
+ expect(isValidSkillName('test-skill-')).toBe(false); // trailing dash
526
+ // Note: dots and underscores are allowed at start/end
527
+ expect(isValidSkillName('.test.skill')).toBe(true); // leading dot is allowed
528
+ expect(isValidSkillName('test.skill.')).toBe(true); // trailing dot is allowed
529
+ expect(isValidSkillName('_test_skill')).toBe(true); // leading underscore is allowed
530
+ expect(isValidSkillName('test_skill_')).toBe(true); // trailing underscore is allowed
531
+ });
532
+
533
+ it('returns true for name with exactly 64 characters', () => {
534
+ const validName = 'a'.repeat(64);
535
+ expect(isValidSkillName(validName)).toBe(true);
536
+ });
537
+
538
+ it('returns true for name with mixed valid characters', () => {
539
+ expect(isValidSkillName('test-skill_123.456')).toBe(true);
540
+ expect(isValidSkillName('test.skill-123_456')).toBe(true);
541
+ expect(isValidSkillName('test_skill-123.456')).toBe(true);
542
+ });
543
+ });