kimaki 0.26.0 → 0.28.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 (302) hide show
  1. package/dist/agent-model.e2e.test.js +250 -164
  2. package/dist/anthropic-account-identity.js +9 -1
  3. package/dist/anthropic-auth-plugin.js +10 -13
  4. package/dist/anthropic-auth-plugin.test.js +17 -0
  5. package/dist/anthropic-auth-state.js +1 -0
  6. package/dist/bash-tool-schema-plugin.js +32 -0
  7. package/dist/bash-tool-schema-plugin.test.js +49 -0
  8. package/dist/bin.js +73 -19
  9. package/dist/cli-commands/maintenance.js +46 -7
  10. package/dist/cli-commands/project.js +11 -27
  11. package/dist/cli-commands/send.js +30 -1
  12. package/dist/cli-commands/session.js +322 -90
  13. package/dist/cli-commands/task.js +34 -15
  14. package/dist/cli-parsing.test.js +83 -4
  15. package/dist/cli-runner.js +44 -8
  16. package/dist/cli-runner.test.js +27 -0
  17. package/dist/cli-send-thread.e2e.test.js +9 -9
  18. package/dist/cli.js +32 -0
  19. package/dist/commands/abort.js +5 -1
  20. package/dist/commands/action-buttons.js +2 -1
  21. package/dist/commands/add-project.js +4 -7
  22. package/dist/commands/agent.js +164 -32
  23. package/dist/commands/ask-question.js +23 -33
  24. package/dist/commands/ask-question.test.js +43 -1
  25. package/dist/commands/btw.js +28 -6
  26. package/dist/commands/file-upload.js +2 -1
  27. package/dist/commands/fork-subagent.js +2 -4
  28. package/dist/commands/fork.js +4 -4
  29. package/dist/commands/last-sessions.js +17 -10
  30. package/dist/commands/login.js +6 -0
  31. package/dist/commands/merge-worktree.js +47 -14
  32. package/dist/commands/model-variant.js +8 -1
  33. package/dist/commands/model.js +16 -9
  34. package/dist/commands/multioauth.js +1 -0
  35. package/dist/commands/new-worktree.js +170 -102
  36. package/dist/commands/queue.js +3 -2
  37. package/dist/commands/resume.js +4 -4
  38. package/dist/commands/session.js +78 -63
  39. package/dist/commands/user-command.js +6 -8
  40. package/dist/commands/worktrees.js +5 -13
  41. package/dist/config.js +16 -1
  42. package/dist/cpu-profiler.js +211 -0
  43. package/dist/cpu-profiler.test.js +160 -0
  44. package/dist/database.js +152 -3
  45. package/dist/db.js +33 -0
  46. package/dist/db.test.js +267 -1
  47. package/dist/default-channel-provisioning.test.js +148 -0
  48. package/dist/discord-bot.js +517 -488
  49. package/dist/discord-command-registration.js +25 -10
  50. package/dist/discord-command-registration.test.js +17 -0
  51. package/dist/discord-utils.js +97 -5
  52. package/dist/discord-utils.test.js +151 -1
  53. package/dist/errors.js +10 -0
  54. package/dist/exec-async.js +17 -5
  55. package/dist/external-directory-permissions.e2e.test.js +11 -7
  56. package/dist/external-directory-project-deny.e2e.test.js +5 -3
  57. package/dist/external-opencode-sync.js +94 -17
  58. package/dist/external-opencode-sync.test.js +206 -0
  59. package/dist/extract-sdk-error-message.test.js +13 -0
  60. package/dist/file-edit-log.js +197 -0
  61. package/dist/file-edit-log.test.js +258 -0
  62. package/dist/format-tables.js +52 -0
  63. package/dist/format-tables.test.js +93 -0
  64. package/dist/gateway-proxy-reconnect.e2e.test.js +28 -8
  65. package/dist/gateway-proxy.e2e.test.js +18 -18
  66. package/dist/git-worktree-core.js +182 -17
  67. package/dist/interaction-handler.js +416 -398
  68. package/dist/ipc-tools-plugin.js +68 -3
  69. package/dist/kimaki-opencode-plugin-loading.e2e.test.js +122 -58
  70. package/dist/kimaki-opencode-plugin.js +9 -3
  71. package/dist/kimaki-workspace-adaptor.js +33 -10
  72. package/dist/logger.js +11 -1
  73. package/dist/markdown.js +3 -1
  74. package/dist/markdown.test.js +11 -3
  75. package/dist/message-formatting.js +181 -51
  76. package/dist/message-formatting.test.js +529 -22
  77. package/dist/message-preprocessing.js +105 -1
  78. package/dist/oauth-rotation-shared.js +10 -0
  79. package/dist/openai-auth-plugin.js +1 -0
  80. package/dist/openai-auth-state.js +1 -0
  81. package/dist/opencode-command.js +28 -0
  82. package/dist/opencode-command.test.js +109 -1
  83. package/dist/opencode-interrupt-plugin.js +4 -0
  84. package/dist/opencode-interrupt-plugin.test.js +24 -0
  85. package/dist/opencode.js +82 -15
  86. package/dist/project-add.test.js +62 -0
  87. package/dist/question-abort-clears-dropdown.e2e.test.js +89 -0
  88. package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +150 -0
  89. package/dist/question-text-before-dropdown.e2e.test.js +52 -0
  90. package/dist/queue-advanced-abort.e2e.test.js +8 -10
  91. package/dist/queue-advanced-action-buttons.e2e.test.js +8 -8
  92. package/dist/queue-advanced-e2e-setup.js +78 -5
  93. package/dist/queue-advanced-footer.e2e.test.js +60 -269
  94. package/dist/queue-advanced-model-switch.e2e.test.js +9 -11
  95. package/dist/queue-advanced-permissions-typing.e2e.test.js +15 -15
  96. package/dist/queue-advanced-question.e2e.test.js +32 -27
  97. package/dist/queue-advanced-typing-interrupt.e2e.test.js +10 -12
  98. package/dist/queue-advanced-typing.e2e.test.js +7 -9
  99. package/dist/queue-delete-message.e2e.test.js +3 -3
  100. package/dist/queue-drain-after-interactive-ui.e2e.test.js +5 -5
  101. package/dist/queue-interrupt-drain.e2e.test.js +122 -12
  102. package/dist/queue-question-select-drain.e2e.test.js +34 -132
  103. package/dist/runtime-lifecycle.e2e.test.js +21 -51
  104. package/dist/schema.js +35 -1
  105. package/dist/session-handler/event-stream-state.js +391 -50
  106. package/dist/session-handler/event-stream-state.test.js +736 -8
  107. package/dist/session-handler/model-utils.js +172 -5
  108. package/dist/session-handler/model-utils.test.js +445 -0
  109. package/dist/session-handler/opencode-session-event-log.js +30 -1
  110. package/dist/session-handler/thread-ingress.test.js +41 -0
  111. package/dist/session-handler/thread-runtime-state.js +2 -0
  112. package/dist/session-handler/thread-session-runtime-summary.test.js +121 -0
  113. package/dist/session-handler/thread-session-runtime.js +574 -299
  114. package/dist/session-search.js +123 -4
  115. package/dist/session-search.test.js +248 -1
  116. package/dist/session-sleep.test.js +224 -0
  117. package/dist/session-title-rename.test.js +37 -39
  118. package/dist/sleep.e2e.test.js +494 -0
  119. package/dist/startup-time.e2e.test.js +2 -1
  120. package/dist/store.js +3 -0
  121. package/dist/system-message.js +102 -16
  122. package/dist/system-message.test.js +192 -15
  123. package/dist/task-runner.js +96 -5
  124. package/dist/task-schedule.js +87 -1
  125. package/dist/task-schedule.test.js +149 -1
  126. package/dist/test-utils.js +17 -9
  127. package/dist/thinking-utils.js +10 -0
  128. package/dist/thinking-utils.test.js +35 -0
  129. package/dist/thread-message-queue.e2e.test.js +65 -213
  130. package/dist/undo-redo.e2e.test.js +17 -9
  131. package/dist/voice-attachment.js +23 -1
  132. package/dist/voice-handler.js +21 -4
  133. package/dist/voice-message.e2e.test.js +144 -30
  134. package/dist/voice-routing-input.e2e.test.js +195 -0
  135. package/dist/voice-routing-question.e2e.test.js +125 -0
  136. package/dist/voice.js +28 -8
  137. package/dist/voice.test.js +96 -30
  138. package/dist/worktree-clone-isolation.e2e.test.js +188 -0
  139. package/dist/worktree-lifecycle.e2e.test.js +55 -36
  140. package/dist/worktrees.js +226 -443
  141. package/dist/worktrees.test.js +435 -58
  142. package/dist/xai-auth-plugin.js +1 -0
  143. package/dist/xai-auth-state.js +1 -0
  144. package/package.json +8 -6
  145. package/skills/bump-holocron-consumers/SKILL.md +137 -0
  146. package/skills/critique/SKILL.md +4 -4
  147. package/skills/errore/SKILL.md +60 -218
  148. package/skills/goke/SKILL.md +150 -10
  149. package/skills/holocron/SKILL.md +154 -17
  150. package/skills/npm-package/SKILL.md +55 -35
  151. package/skills/profano/SKILL.md +17 -2
  152. package/skills/spiceflow/SKILL.md +39 -3
  153. package/skills/strada/SKILL.md +39 -0
  154. package/skills/zele/SKILL.md +19 -0
  155. package/src/agent-model.e2e.test.ts +287 -186
  156. package/src/anthropic-account-identity.ts +20 -1
  157. package/src/anthropic-auth-plugin.test.ts +19 -0
  158. package/src/anthropic-auth-plugin.ts +12 -16
  159. package/src/anthropic-auth-state.ts +1 -0
  160. package/src/bash-tool-schema-plugin.test.ts +55 -0
  161. package/src/bash-tool-schema-plugin.ts +46 -0
  162. package/src/bin.ts +78 -26
  163. package/src/cli-commands/maintenance.ts +59 -13
  164. package/src/cli-commands/project.ts +14 -35
  165. package/src/cli-commands/send.ts +31 -1
  166. package/src/cli-commands/session.ts +374 -114
  167. package/src/cli-commands/task.ts +34 -15
  168. package/src/cli-parsing.test.ts +103 -4
  169. package/src/cli-runner.test.ts +49 -0
  170. package/src/cli-runner.ts +44 -7
  171. package/src/cli-send-thread.e2e.test.ts +9 -11
  172. package/src/cli.ts +53 -0
  173. package/src/commands/abort.ts +6 -1
  174. package/src/commands/action-buttons.ts +2 -1
  175. package/src/commands/add-project.ts +4 -8
  176. package/src/commands/agent.ts +205 -29
  177. package/src/commands/ask-question.test.ts +48 -1
  178. package/src/commands/ask-question.ts +23 -33
  179. package/src/commands/btw.ts +40 -5
  180. package/src/commands/file-upload.ts +2 -1
  181. package/src/commands/fork-subagent.ts +2 -3
  182. package/src/commands/fork.ts +4 -3
  183. package/src/commands/last-sessions.ts +10 -4
  184. package/src/commands/login.ts +6 -0
  185. package/src/commands/merge-worktree.ts +54 -16
  186. package/src/commands/model-variant.ts +9 -1
  187. package/src/commands/model.ts +20 -9
  188. package/src/commands/multioauth.ts +1 -0
  189. package/src/commands/new-worktree.ts +138 -55
  190. package/src/commands/queue.ts +3 -2
  191. package/src/commands/resume.ts +4 -3
  192. package/src/commands/session.ts +94 -70
  193. package/src/commands/user-command.ts +6 -6
  194. package/src/commands/worktrees.ts +5 -12
  195. package/src/config.ts +18 -1
  196. package/src/cpu-profiler.test.ts +183 -0
  197. package/src/cpu-profiler.ts +293 -0
  198. package/src/database.ts +235 -3
  199. package/src/db.test.ts +293 -0
  200. package/src/db.ts +38 -0
  201. package/src/default-channel-provisioning.test.ts +155 -0
  202. package/src/discord-bot.ts +78 -36
  203. package/src/discord-command-registration.test.ts +20 -0
  204. package/src/discord-command-registration.ts +42 -12
  205. package/src/discord-utils.test.ts +176 -0
  206. package/src/discord-utils.ts +152 -7
  207. package/src/errors.ts +12 -0
  208. package/src/exec-async.ts +20 -11
  209. package/src/external-directory-permissions.e2e.test.ts +11 -7
  210. package/src/external-directory-project-deny.e2e.test.ts +5 -3
  211. package/src/external-opencode-sync.test.ts +248 -0
  212. package/src/external-opencode-sync.ts +122 -19
  213. package/src/extract-sdk-error-message.test.ts +18 -0
  214. package/src/file-edit-log.test.ts +287 -0
  215. package/src/file-edit-log.ts +283 -0
  216. package/src/format-tables.test.ts +101 -0
  217. package/src/format-tables.ts +75 -0
  218. package/src/gateway-proxy-reconnect.e2e.test.ts +38 -8
  219. package/src/gateway-proxy.e2e.test.ts +18 -17
  220. package/src/git-worktree-core.ts +247 -20
  221. package/src/interaction-handler.ts +36 -13
  222. package/src/ipc-tools-plugin.ts +82 -5
  223. package/src/kimaki-opencode-plugin-loading.e2e.test.ts +188 -97
  224. package/src/kimaki-opencode-plugin.ts +9 -3
  225. package/src/kimaki-workspace-adaptor.ts +40 -11
  226. package/src/logger.ts +14 -4
  227. package/src/markdown.test.ts +13 -3
  228. package/src/markdown.ts +4 -1
  229. package/src/message-formatting.test.ts +672 -25
  230. package/src/message-formatting.ts +242 -53
  231. package/src/message-preprocessing.ts +116 -1
  232. package/src/oauth-rotation-shared.ts +10 -0
  233. package/src/openai-auth-plugin.ts +1 -0
  234. package/src/openai-auth-state.ts +1 -0
  235. package/src/opencode-command.test.ts +140 -0
  236. package/src/opencode-command.ts +38 -0
  237. package/src/opencode-interrupt-plugin.test.ts +32 -0
  238. package/src/opencode-interrupt-plugin.ts +3 -0
  239. package/src/opencode.ts +115 -15
  240. package/src/project-add.test.ts +80 -0
  241. package/src/question-abort-clears-dropdown.e2e.test.ts +109 -0
  242. package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +172 -0
  243. package/src/question-text-before-dropdown.e2e.test.ts +67 -0
  244. package/src/queue-advanced-abort.e2e.test.ts +8 -9
  245. package/src/queue-advanced-action-buttons.e2e.test.ts +8 -8
  246. package/src/queue-advanced-e2e-setup.ts +83 -4
  247. package/src/queue-advanced-footer.e2e.test.ts +67 -315
  248. package/src/queue-advanced-model-switch.e2e.test.ts +9 -10
  249. package/src/queue-advanced-permissions-typing.e2e.test.ts +15 -15
  250. package/src/queue-advanced-question.e2e.test.ts +36 -30
  251. package/src/queue-advanced-typing-interrupt.e2e.test.ts +11 -11
  252. package/src/queue-advanced-typing.e2e.test.ts +8 -8
  253. package/src/queue-delete-message.e2e.test.ts +3 -3
  254. package/src/queue-drain-after-interactive-ui.e2e.test.ts +5 -5
  255. package/src/queue-interrupt-drain.e2e.test.ts +133 -12
  256. package/src/queue-question-select-drain.e2e.test.ts +36 -161
  257. package/src/runtime-lifecycle.e2e.test.ts +21 -54
  258. package/src/schema.sql +15 -2
  259. package/src/schema.ts +37 -1
  260. package/src/session-handler/event-stream-state.test.ts +790 -7
  261. package/src/session-handler/event-stream-state.ts +568 -53
  262. package/src/session-handler/model-utils.test.ts +537 -0
  263. package/src/session-handler/model-utils.ts +281 -5
  264. package/src/session-handler/opencode-session-event-log.ts +31 -1
  265. package/src/session-handler/thread-ingress.test.ts +54 -0
  266. package/src/session-handler/thread-runtime-state.ts +3 -0
  267. package/src/session-handler/thread-session-runtime-summary.test.ts +169 -0
  268. package/src/session-handler/thread-session-runtime.ts +712 -358
  269. package/src/session-search.test.ts +281 -0
  270. package/src/session-search.ts +241 -7
  271. package/src/session-sleep.test.ts +294 -0
  272. package/src/session-title-rename.test.ts +54 -48
  273. package/src/sleep.e2e.test.ts +565 -0
  274. package/src/startup-time.e2e.test.ts +5 -1
  275. package/src/store.ts +22 -0
  276. package/src/system-message.test.ts +226 -15
  277. package/src/system-message.ts +130 -16
  278. package/src/task-runner.ts +138 -3
  279. package/src/task-schedule.test.ts +170 -0
  280. package/src/task-schedule.ts +141 -1
  281. package/src/test-utils.ts +21 -10
  282. package/src/thinking-utils.test.ts +46 -0
  283. package/src/thinking-utils.ts +21 -0
  284. package/src/thread-message-queue.e2e.test.ts +65 -245
  285. package/src/undo-redo.e2e.test.ts +17 -9
  286. package/src/voice-attachment.ts +29 -1
  287. package/src/voice-handler.ts +23 -4
  288. package/src/voice-message.e2e.test.ts +149 -29
  289. package/src/voice-routing-input.e2e.test.ts +203 -0
  290. package/src/voice-routing-question.e2e.test.ts +131 -0
  291. package/src/voice.test.ts +107 -29
  292. package/src/voice.ts +34 -6
  293. package/src/worktree-clone-isolation.e2e.test.ts +213 -0
  294. package/src/worktree-lifecycle.e2e.test.ts +55 -35
  295. package/src/worktrees.test.ts +505 -64
  296. package/src/worktrees.ts +257 -603
  297. package/src/xai-auth-plugin.ts +1 -0
  298. package/src/xai-auth-state.ts +1 -0
  299. package/dist/message-finish-field.e2e.test.js +0 -169
  300. package/dist/subagent-rate-limit-plugin.js +0 -184
  301. package/src/message-finish-field.e2e.test.ts +0 -196
  302. package/src/subagent-rate-limit-plugin.ts +0 -228
@@ -5,8 +5,9 @@ description: >
5
5
  with Standard Schema support (Zod, Valibot, ArkType). Use goke when building CLI
6
6
  tools — it handles commands, subcommands, options, type coercion, help generation,
7
7
  and more. Schema-based options give you automatic type inference, coercion from
8
- strings, and help text generation. ALWAYS read this skill when a repo uses goke
9
- for its CLI.
8
+ strings, and help text generation. Pair with `@goke/mcp` to generate CLI
9
+ commands automatically from an MCP server. ALWAYS read this skill when a repo
10
+ uses goke for its CLI.
10
11
  version: 0.0.1
11
12
  ---
12
13
 
@@ -30,14 +31,51 @@ npm install goke # or bun, pnpm, etc
30
31
 
31
32
  ## Quick Notes
32
33
 
33
- - Core APIs: `cli.option`, `cli.use`, `cli.version`, `cli.help`, `cli.completions`, `cli.parse`
34
+ - Core APIs: `cli.option`, `cli.use`, `cli.section`, `cli.version`, `cli.help`, `cli.completions`, `cli.parse`
34
35
  - Prefer injected `{ fs, console, process }` over globals
35
36
  - Use relative paths with injected `fs`; if a helper needs current-cwd semantics, pass injected `process.cwd` into that helper
36
37
  - For JustBash compatibility tests, import the existing CLI from app code instead of defining a new CLI inside the test
37
38
  - **Never install `picocolors`, `chalk`, `kleur`, or any color library.** Use `import { colors } from 'goke'` instead. It's a vendored picocolors with zero extra dependencies.
39
+ - Use [`@goke/mcp`](https://github.com/remorses/goke/tree/main/mcp) to generate CLI commands from an MCP server. `addMcpCommands({ cli, getMcpUrl, loadCache, saveCache })` discovers tools and registers a typed command for each one.
38
40
 
39
41
  The README is the source of truth for rules, examples, testing patterns, JustBash integration, and API details.
40
42
 
43
+ ## Reporting goke bugs
44
+
45
+ If you find a bug in goke, **always open a GitHub issue with the `gh` CLI**. Do not only mention it in chat.
46
+
47
+ ```bash
48
+ gh issue create --repo remorses/goke --title "Short bug title" --body "$(cat <<'EOF'
49
+ **Model:** grok-4.6
50
+ **Harness:** OpenCode / Kimaki
51
+
52
+ **What happened**
53
+ Describe the unexpected behavior.
54
+
55
+ **Relevant goke code**
56
+ Paste the CLI definition or goke API usage from this package that triggered the bug.
57
+
58
+ **Reproduction**
59
+ Minimal example that fails:
60
+
61
+ ```ts
62
+ import { goke } from 'goke'
63
+
64
+ const cli = goke('mycli')
65
+ cli.command('deploy', 'Deploy').action(() => {})
66
+ cli.parse()
67
+ ```
68
+ EOF
69
+ )"
70
+ ```
71
+
72
+ Always include in the issue body:
73
+
74
+ - the **model** used (for example `grok-4.6`, `claude-opus-4-6`)
75
+ - the **harness** (for example OpenCode, Claude Code, Cursor, Codex)
76
+ - the **relevant goke code** from this package that hit the bug
77
+ - a **minimal reproduction** example
78
+
41
79
  If the README or this skill mentions a `goke` export that is missing from the installed package, upgrade `goke` to latest first before adding workarounds or custom local detection code:
42
80
 
43
81
  ```bash
@@ -72,15 +110,30 @@ if (isAgent) {
72
110
  }
73
111
  ```
74
112
 
75
- When guarding interactive prompts, check `isAgent` alongside `!process.stdin.isTTY`:
113
+ `isAgent` is for **skipping interactive prompts that have a CLI flag alternative** (e.g. `--env staging` instead of a clack select). Use it to require the flag and fail with a usage hint instead of hanging on stdin:
76
114
 
77
115
  ```ts
78
- if (isAgent || !process.stdin.isTTY) {
79
- console.error('Missing --env. Usage: deploy --env staging|production')
116
+ if (!env) {
117
+ if (isAgent || !process.stdin.isTTY) {
118
+ console.error('Missing --env. Usage: deploy --env staging|production')
119
+ process.exit(1)
120
+ }
121
+ // ... clack prompt fallback
122
+ }
123
+ ```
124
+
125
+ **Never use `isAgent` to block commands that have no flag alternative**, like device-flow login. Those commands don't read stdin at all; they open a browser, print a code, and poll. The only real requirement is a TTY for spinner output. Use `!process.stdin.isTTY` or `!process.stdout.isTTY` alone for those:
126
+
127
+ ```ts
128
+ // login command — no flag alternative, agent can run it in tuistory
129
+ if (!process.stdin.isTTY) {
130
+ console.error('Login requires a terminal. Run in tuistory or tmux.')
80
131
  process.exit(1)
81
132
  }
82
133
  ```
83
134
 
135
+ Agents can run login commands in a PTY via tuistory and complete the browser flow with playwriter. Blocking them with `isAgent` makes login impossible from agent contexts.
136
+
84
137
  Supported agents: `cursor`, `claude`, `devin`, `replit`, `gemini`, `codex`, `auggie`, `opencode`, `kiro`, `goose`, `pi`. Set `AI_AGENT` env var to override.
85
138
 
86
139
  ## Long-Running Interactive Commands
@@ -96,16 +149,22 @@ cli
96
149
  .command('login', 'Authenticate with browser login')
97
150
  .action(async (options, ctx) => {
98
151
  if (ctx.daemon.isDaemon) {
99
- // ── DAEMON: run the long-running flow in background ──
100
- const result = await startOAuthFlow({ /* ... */ })
152
+ // ── DAEMON: create the URL, hand it to the foreground, then wait ──
153
+ const flow = await startOAuthFlow({ /* ... */ })
154
+ ctx.daemon.publishStartupMessage(`Authorize: ${flow.authorizationUrl}`)
155
+ ctx.daemon.ready()
156
+ const result = await flow.waitForApproval()
101
157
  if (result.success) saveAuth(result)
102
158
  return // daemon exits, PID file is cleaned up
103
159
  }
104
160
 
105
161
  // ── CLIENT: decide foreground vs background ──
106
162
  if (isAgent) {
107
- // Agent mode: start daemon and return immediately
108
- await ctx.daemon.start({ timeoutMs: 10 * 60 * 1000 })
163
+ // Agent mode: return after the daemon publishes its authorization URL
164
+ await ctx.daemon.start({
165
+ waitForStartup: true,
166
+ timeoutMs: 10 * 60 * 1000,
167
+ })
109
168
  ctx.console.log('Login running in background.')
110
169
  ctx.console.log('After approving in browser, verify with: mycli me')
111
170
  return
@@ -117,6 +176,8 @@ cli
117
176
  })
118
177
  ```
119
178
 
179
+ Use `waitForStartup: true` when the daemon creates an OAuth URL, device code, or other value that the agent must see before the foreground command returns. Publish ordered messages with `publishStartupMessage(message, { stream: 'stdout' | 'stderr' })`, then call `ready()`. Detached stdio remains ignored. Attached mode still receives the messages directly and waits for the daemon to exit.
180
+
120
181
  Add a `me` command (exits 0 if logged in, 1 if not) so agents can poll for completion. Use `ctx.daemon.forCommand('login')` to check the login daemon status from other commands. See the **Background Daemons** section in the goke README for the full pattern, including `env` passthrough and PID file safety.
121
182
 
122
183
  ## Shell Completions
@@ -220,6 +281,17 @@ project remove
220
281
 
221
282
  Pick **singular or plural** for the noun and stick with it across the entire CLI. If `project list` exists, don't add `projects add`.
222
283
 
284
+ **Always group namespaced commands with `.section()`.** Commands that share a parent word (`get pods`, `get services`, `auth login`) must sit under a named heading in root help. Call `cli.section('Get')` before registering that group. Use `.command(...).section('Name')` when one command belongs in a different group.
285
+
286
+ ```ts
287
+ cli.section('Get')
288
+ cli.command('get pods', 'List pods')
289
+ cli.command('get services', 'List services')
290
+
291
+ cli.section('Describe')
292
+ cli.command('describe pod <name>', 'Describe a pod')
293
+ ```
294
+
223
295
  ### Consistent verbs
224
296
 
225
297
  Choose one verb per action and reuse it everywhere:
@@ -233,6 +305,16 @@ Choose one verb per action and reuse it everywhere:
233
305
 
234
306
  Check which verbs the CLI already uses and match them. If existing commands use `add`, every new "create something" command should also use `add`.
235
307
 
308
+ ### Never mix different ID kinds in positionals
309
+
310
+ All positionals of a command must identify the same kind of thing. Never give the first positional a different meaning than the rest (e.g. `events <recordingId> [...eventIds]`): a call like `events 1 4 7` is unreadable because the first number silently refers to a different entity. Move the parent/scoping ID to an optional flag with a sensible default and keep positionals homogeneous:
311
+
312
+ ```ts
313
+ cli
314
+ .command('recorder events [...eventIds]', 'Print recorded events')
315
+ .option('-r, --recording <id>', 'Recording ID (defaults to the latest recording)')
316
+ ```
317
+
236
318
  ## Prefer Optional Flags Over Required Flags
237
319
 
238
320
  **Never make a flag required when it can be optional with an interactive fallback.** Required flags force users to read `--help` before they can run anything. Optional flags let them run the bare command and discover options progressively through prompts.
@@ -301,6 +383,19 @@ if (!options.name) {
301
383
  }
302
384
  ```
303
385
 
386
+ ## Error Messages with Recovery Hints
387
+
388
+ **Every error message should include a hint showing how to fix or rerun the command.** When a CLI exits with an error, the user (or agent) should be able to copy-paste a corrected command immediately instead of reading `--help`.
389
+
390
+ ```ts
391
+ console.error('Failed to detect local port.')
392
+ console.error('If your server prints the port in an unusual format, specify it explicitly:')
393
+ console.error(` mycli serve -p <port> -- ${shellQuote(args)}`)
394
+ process.exit(1)
395
+ ```
396
+
397
+ Include the user's original arguments in the suggested command when possible, so the hint is directly copy-pasteable. For timeouts, show how long it waited so the user knows whether to wait longer or try a different approach.
398
+
304
399
  ## Interactive Prompts with @clack/prompts
305
400
 
306
401
  Use `@clack/prompts` for interactive CLI prompts like `select`, `confirm`, and text input.
@@ -553,3 +648,48 @@ cli
553
648
  - Developers can point to `http://localhost:3000` during development without losing their production token
554
649
  - Switching servers is just `--api-url` or setting an env var; no re-login needed if the server was used before
555
650
  ```
651
+
652
+ ## MCP CLIs (`@goke/mcp`)
653
+
654
+ Use `addMcpCommands` from `@goke/mcp`. Do not hide `--help` behind a token. Put token steps on a `config` command. Never write `isSetupCmd` or a first-run prompt that blocks no-args.
655
+
656
+ Use `getMcpUrl` plus `getHeaders` for HTTP Bearer tokens. Use `getMcpTransport` for stdio or any custom transport.
657
+
658
+ ```ts
659
+ await addMcpCommands({
660
+ cli,
661
+ getMcpUrl: () => MCP_URL,
662
+ getHeaders: () => {
663
+ const token = process.env.TOKEN || loadConfig().token
664
+ if (!token) return
665
+ return { Authorization: `Bearer ${token}` }
666
+ },
667
+ loadCache: () => loadConfig().cache,
668
+ saveCache: (cache) => saveConfig({ cache }),
669
+ })
670
+ ```
671
+
672
+ ## Writing a Skill for a goke CLI
673
+
674
+ When creating a SKILL.md for a CLI built with goke, keep it **thin**. The skill is a bridge between the agent and the canonical docs, not a copy of them.
675
+
676
+ ### Structure
677
+
678
+ 1. **Always start with `--help`.** The CLI self-documents commands, options, and examples via goke's help generator. Make agents read it first, in full, every session. Add a "Read the help first" section with `mycli --help` and a rule to never truncate with `head`, `tail`, or `sed -n`.
679
+
680
+ 2. **Point at canonical docs.** If the CLI has a docs site with `llms-full.txt` (e.g. built with Holocron), tell agents to `curl -s https://mycli.dev/llms-full.txt` as the single source of truth. For OSS repos without a docs site, curl the raw README from GitHub: `curl -s https://raw.githubusercontent.com/owner/repo/main/README.md`. Add a "never truncate" rule next to the curl command. Optionally list 3-4 individual page URLs for the most common quick lookups.
681
+
682
+ 3. **Install and auth.** Just the commands, one per line, minimal prose. Start with `which mycli` so agents check before installing. Then `npm install -g mycli`, `mycli auth check`, `mycli auth login`, and `mycli auth set --key` for CI.
683
+
684
+ 4. **Gotchas.** Agent-specific knowledge that is not obvious from `--help` or the docs. Things like browser flows that need user interaction, remote vs local file path restrictions, implicit defaults that cause silent failures, and subscription requirements.
685
+
686
+ 5. **MCP alternative.** If the CLI has an MCP server, include the one-liner install command.
687
+
688
+ ### What NOT to put in the skill
689
+
690
+ - **Command reference** — already in `--help` output
691
+ - **Workflow examples** — belong in the docs site (quickstart, guides)
692
+ - **Option descriptions** — already in Zod `.describe()` strings that goke renders in help
693
+ - **Output format details** — covered by `--help` and docs
694
+
695
+ If a section in the skill duplicates content from `--help` or the docs, delete it. The agent will fetch the canonical source.
@@ -4,7 +4,8 @@ repo: https://github.com/remorses/holocron
4
4
  description: >
5
5
  Holocron is a Mintlify-compatible docs site generator and Vite plugin.
6
6
  Use this skill when creating, migrating, customizing, or deploying a
7
- Holocron documentation site.
7
+ Holocron documentation site. Also load when writing index.mdx, page
8
+ titles, hideTitle, Above heroes, or homepage SEO for Google brand ranking.
8
9
  ---
9
10
 
10
11
  # Holocron
@@ -182,6 +183,7 @@ README as the index page:
182
183
 
183
184
  ```mdx
184
185
  ---
186
+ $schema: https://holocron.so/frontmatter.json
185
187
  title: My Project
186
188
  ---
187
189
 
@@ -304,9 +306,56 @@ title: Quickstart
304
306
  description: Build and deploy your first Holocron docs site.
305
307
  icon: lucide:rocket
306
308
  tag: NEW
309
+ prompt: |
310
+ Write the Quickstart from @/cli/src/create.ts.
311
+ ---
312
+ ```
313
+
314
+ ### Record the generation prompt
315
+
316
+ Every documentation page you create must include a **`prompt`** field that
317
+ records the instruction and sources used to generate that page. When editing an
318
+ older page without one, add it when you can identify the real sources. Write the
319
+ original generation recipe, not a maintenance instruction.
320
+
321
+ Use **`@/path`** for source files and folders from the **repository root**.
322
+ Use `@./path` or `@../path` only when the source sits next to the MDX page.
323
+ Prefix remote sources with **`@https://`**. Bare URLs are not references. Do
324
+ not invent sources, and update the prompt when source locations or page scope
325
+ change.
326
+
327
+ ```yaml
328
+ ---
329
+ $schema: https://holocron.so/frontmatter.json
330
+ title: Authentication
331
+ prompt: |
332
+ Write the authentication guide from @/src/auth/ and
333
+ @/src/middleware/session.ts.
334
+ Use @https://github.com/example/project/releases for recent behavior.
335
+
336
+ Explain sessions, API keys, and GitHub Actions OIDC.
337
+ Include a complete TypeScript example for every method.
307
338
  ---
308
339
  ```
309
340
 
341
+ Holocron Maintain extracts these references and reruns the generation prompt
342
+ when a source changes. A folder reference matches changes to any tracked file
343
+ inside that folder.
344
+
345
+ ### Migrating an existing docs site
346
+
347
+ When moving a docs site to Holocron, write each `prompt` as if the page was
348
+ authored from scratch. Keep it a short summary of what the page documents.
349
+
350
+ Do not mention migration, recreation, or the old docs URL. Do not add
351
+ `@https://old-site/...` references. The source site is going away after the
352
+ move unless the user says otherwise.
353
+
354
+ ```yaml
355
+ prompt: |
356
+ Document connecting the first integration, role access, and chat validation.
357
+ ```
358
+
310
359
  **Title** should be **50-60 characters** max. It appears in the OG image at large
311
360
  font size, in the browser tab, and in search results. Keep it concise and
312
361
  descriptive.
@@ -319,6 +368,7 @@ the full title still appears in the page heading, browser tab, and OG image.
319
368
 
320
369
  ```mdx
321
370
  ---
371
+ $schema: https://holocron.so/frontmatter.json
322
372
  title: Configuring Authentication Providers
323
373
  sidebarTitle: Auth Providers
324
374
  ---
@@ -328,35 +378,121 @@ sidebarTitle: Auth Providers
328
378
  below the title and in search engine snippets. Write a single sentence that
329
379
  summarizes the page content. Longer descriptions get truncated with an ellipsis.
330
380
 
331
- ## Page titles (MUST follow)
381
+ ## Page titles and SEO (MUST follow)
382
+
383
+ Google title links and snippets come from on-page title, H1, and description.
384
+ See [title links](https://developers.google.com/search/docs/appearance/title-link)
385
+ and [snippets](https://developers.google.com/search/docs/appearance/snippet).
386
+
387
+ Holocron already appends the site name. `buildPageTitle` renders
388
+ `{page title} — {site name}` unless `title` already starts with the site name.
389
+ **Do not put the site name in `title` or in the H1.** That doubles the brand
390
+ (`Kimaki: … — Kimaki`). Write the ranking keywords only. Let Holocron add
391
+ ` — {site name}`.
332
392
 
333
- Holocron renders the browser `<title>` as `{page title} — {site name}`. Two
334
- frontmatter fields control what appears where:
393
+ Two frontmatter fields:
335
394
 
336
- - **`title`** — browser tab, Google results, OG image, page heading. Write for SEO.
337
- - **`sidebarTitle`** — sidebar navigation only. Write for scannability (short label).
395
+ - **`title`** — browser tab, Google title link, OG image, and the injected H1. Write for SEO. Put the keywords this page should rank for.
396
+ - **`sidebarTitle`** — sidebar only. Short label, under 30 characters.
338
397
 
339
- **Always set both.** `title` is the full descriptive phrase; `sidebarTitle` is
340
- the short sidebar label. Without `sidebarTitle`, the full title shows in the
341
- sidebar and often wraps or looks verbose.
398
+ **Always set both.** Without `sidebarTitle`, the long SEO title wraps in the 230px sidebar.
399
+
400
+ **Always quote frontmatter strings.** YAML treats `:` as a map. `title: Kimaki: AI agents` is nested YAML. Holocron then drops all frontmatter, and the browser title becomes the first body heading. Quote `title` and `description`. Holocron warns when an unquoted value contains `:`, and when a parsed key contains a space and `:`.
342
401
 
343
402
  ```mdx
344
403
  ---
345
- title: Open-source browser automation for AI agents
404
+ $schema: https://holocron.so/frontmatter.json
405
+ title: "Open-source browser automation"
346
406
  sidebarTitle: Home
347
- description: Automate any browser with a simple TypeScript API.
407
+ description: "Automate any browser with a TypeScript API. Control Chrome from a CLI or agent."
348
408
  ---
349
409
  ```
350
410
 
351
- Browser tab: `Open-source browser automation for AI agents — Playwriter`
411
+ Browser tab: `Open-source browser automation — Playwriter`
412
+ Injected H1: `Open-source browser automation`
352
413
  Sidebar: `Home`
353
414
 
354
- **Rules:**
415
+ On most pages Holocron injects `title` as the only H1, so **title and H1 are the same**. Keep it that way. Do not add another `#` or `<h1>` in the body.
416
+
417
+ **Title rules:**
418
+
419
+ - **Put ranking keywords in `title`.** The homepage title is the most important. Docs pages use the topic keywords (`Subscriptions`, `Worktrees`), not `Introduction` or `Overview`.
420
+ - **Never start `title` with the site name.** Holocron already appends ` — {site name}`.
421
+ - **Never set `title` identical to the site name.** A title of `Playwriter` becomes `Playwriter — Playwriter`.
422
+ - **Every `title` MUST be unique, descriptive, and concise.** Google truncates long titles. Avoid keyword stuffing and boilerplate that only changes one word.
423
+ - **`index.mdx` MUST use `sidebarTitle: Home`** (or `Overview`). See Homepage SEO below.
424
+
425
+ **H1 rules:**
426
+
427
+ - **One H1 per page.** It must contain the same ranking keywords as `title`. Prefer the exact `title` text. Holocron does this automatically when it injects the title.
428
+ - Google uses the first prominent H1 as a title-link source. Extra H1s with the same weight can steal the tab title (`Quick Start — Site`). Heading count is not a ranking penalty. A clear main title is.
429
+
430
+ **Description rules:**
431
+
432
+ `description` becomes `<meta name="description">`. Google may use it as the snippet when it describes the page better than on-page text.
433
+
434
+ - **Unique per page.** Site-wide copy on every page is useless in search results.
435
+ - **Summarize this page**, in one or two sentences. Not a keyword list.
436
+ - **Include ranking keywords naturally.** Do not stuff. Do not repeat the site name just because the title suffix already has it. The homepage may name the product once if that is the summary.
437
+ - **Be specific.** Length has no hard cap. Google truncates to the device width. Aim for a short pitch, about 120 to 160 characters.
438
+ - Quote the YAML string.
439
+
440
+ ```yaml
441
+ description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
442
+ ```
443
+
444
+ ## Homepage SEO
445
+
446
+ The homepage title is the strongest brand query signal. Put the keywords people search in `title` and H1. Let Holocron append the site name.
447
+
448
+ ```mdx
449
+ ---
450
+ $schema: https://holocron.so/frontmatter.json
451
+ title: "AI coding agents from Discord"
452
+ sidebarTitle: Home
453
+ description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
454
+ ---
455
+ ```
456
+
457
+ Browser tab: `AI coding agents from Discord — Kimaki`
458
+ H1: `AI coding agents from Discord`
355
459
 
356
- - **Never set `title` identical to the site name.** `Playwriter — Playwriter` is redundant.
357
- - **Every `title` MUST be descriptive, not a generic label.** `Introduction`, `Getting Started`, `Overview` say nothing in a browser tab. Write what the page covers.
358
- - **Every `title` MUST be unique across the site.**
359
- - **`index.mdx` MUST use `sidebarTitle: Home`** (or `Overview`) and a descriptive `title`.
460
+ **One H1, same keywords as `title`.** Holocron injects that H1 unless the page has `<Above>` or `hideTitle: true`. A custom hero that also renders `<h1>` next to an injected title creates two H1s.
461
+
462
+ **If the page has `<Above>`, that hero owns the H1.** Holocron skips the injected title. Set the hero H1 to the same text as `title`. Do not put the site name in the hero H1. Never write `#` or `<h1>` in the MDX body below it. The first body section must be `##`. Extra H1s are demoted to H2.
463
+
464
+ ```mdx
465
+ ---
466
+ title: "AI coding agents from Discord"
467
+ sidebarTitle: Home
468
+ description: "Run AI coding agents from Discord. Each channel is a project, each thread is a session."
469
+ ---
470
+
471
+ <Above>
472
+ <HeroSection />
473
+ </Above>
474
+ ```
475
+
476
+ ```tsx
477
+ <h1>
478
+ <span>AI coding agents</span>
479
+ <span>from Discord.</span>
480
+ </h1>
481
+ ```
482
+
483
+ If there is no custom hero, do **not** set `hideTitle`. Let Holocron inject `title` as the only H1.
484
+
485
+ **Do not make `/` a clone of GitHub.** Importing `README.md` under the hero is fine. The homepage still needs its own title, H1, and description. If `/` is the same text as GitHub, Google prefers GitHub plus a unique inner docs page.
486
+
487
+ A **logo link to `/`** is weak. Fix title, H1, and description first.
488
+
489
+ After deploy, fetch the live HTML and check:
490
+
491
+ ```bash
492
+ curl -sL -A 'Mozilla/5.0 (compatible; Googlebot/2.1)' 'https://example.com/' -o /tmp/home.html
493
+ ```
494
+
495
+ Confirm **exactly one `<h1>`**, that H1 text matches `title`, and `<title>` is `{title} — {site name}` with the site name only at the end. Rank will not move until Google recrawls.
360
496
 
361
497
  ## Page modes — hiding sidebars
362
498
 
@@ -369,6 +505,7 @@ In both modes the content can feel too wide. Use **`maxWidth`** to constrain it:
369
505
 
370
506
  ```yaml
371
507
  ---
508
+ $schema: https://holocron.so/frontmatter.json
372
509
  mode: "custom"
373
510
  maxWidth: 700
374
511
  ---
@@ -3,8 +3,9 @@ name: npm-package
3
3
  description: >
4
4
  Opinionated TypeScript npm package template for ESM packages. Enforces
5
5
  src→dist builds with tsc, strict TypeScript defaults, explicit exports, and
6
- publish-safe package metadata. Use this when creating or updating any npm
7
- package in this repo.
6
+ publish-safe package metadata. Relative source imports must use .ts or .tsx
7
+ (never .js); tsc rewrites them via rewriteRelativeImportExtensions. Use this
8
+ when creating or updating any npm package in this repo.
8
9
  version: 0.0.1
9
10
  ---
10
11
 
@@ -45,19 +46,36 @@ Use this skill when scaffolding or fixing npm packages.
45
46
  README at the repository root. Package READMEs don't get read by anyone.
46
47
  The root README is the single source of truth for the whole project.
47
48
  10. `scripts.build` should be `tsc && chmod +x dist/cli.js` (skip the chmod if
48
- the package has no bin). No bundling. Do not delete `dist/` in `build` by
49
- default because forcing a clean build on every local build can cause
50
- issues. Optionally include running scripts with `tsx` if needed to
51
- generate build artifacts.
52
- 11. `prepublishOnly` must always do the cleanup before `build` (optionally run
53
- generation before build when required). Always add this script:
49
+ the package has no bin). No bundling. Optionally include running scripts
50
+ with `tsx` if needed to generate build artifacts.
51
+
52
+ **Never put `rm -rf`, `rimraf`, or any delete in `build`.** `build` runs on
53
+ every edit, watch loop, and CI test job. Deleting `dist/` there breaks live
54
+ dev servers that hold it in their module graph (Bun fails with `Failed to
55
+ load bundled module '<pkg>/dist/index.js'` until restarted) and throws away
56
+ incremental compilation. A stale file only matters in a published tarball,
57
+ which `prepublishOnly` already handles.
58
+
59
+ 11. `prepublishOnly` is the **only** place a delete belongs. It keeps a file
60
+ deleted from `src/` out of the published package:
54
61
  ```json
55
62
  { "prepublishOnly": "rimraf dist \"*.tsbuildinfo\" && pnpm build" }
56
63
  ```
57
- This ensures `dist/` is fresh before every `npm publish`, so deleted files
58
- do not accidentally stay in the published package. Use `rimraf` here
59
- instead of bare shell globs so the script behaves the same in zsh, bash,
60
- and Windows shells even when no `.tsbuildinfo` file exists.
64
+ **Always use `rimraf`, never `rm -rf`.** This holds for every package.json
65
+ script, not just this one. `rm -rf` is not portable to Windows, and with no
66
+ `.tsbuildinfo` present zsh aborts `rm -rf dist *.tsbuildinfo` with `no
67
+ matches found`, so the build after `&&` never runs and you publish a stale
68
+ `dist/`. `sh` and `bash` only survive because `rm -f` ignores the literal
69
+ unmatched name. Install `rimraf` as a devDependency; never rely on
70
+ `npx`/`bunx` at publish time.
71
+
72
+ When the package also has a publish guard, chain it first so the guard
73
+ still runs before anything is deleted:
74
+ ```json
75
+ {
76
+ "prepublishOnly": "node -e \"if (!process.env.CI) process.exit(1)\" && rimraf dist \"*.tsbuildinfo\" && pnpm build"
77
+ }
78
+ ```
61
79
 
62
80
  ## bin field
63
81
 
@@ -175,33 +193,33 @@ Use Node ESM-compatible compiler settings:
175
193
 
176
194
  - Always use "rootDir": "src"
177
195
  - Add `"DOM"` to `lib` only when browser globals are needed.
178
- - Use `.ts` and `.tsx` extensions in source imports. `tsc` rewrites them to
179
- `.js` in the emitted `dist/` output automatically via
180
- `rewriteRelativeImportExtensions`. This means source code works directly in
181
- runtimes like `tsx`, `bun`, and frameworks like Next.js that expect `.ts`
182
- extensions, while the published `dist/` has correct `.js` imports that Node.js
183
- and other consumers resolve without issues.
184
-
185
- ```ts
186
- // source (src/index.ts) — use .ts/.tsx extensions
187
- import { helper } from "./utils.ts";
188
- import { Button } from "./button.tsx";
189
-
190
- // emitted output (dist/index.js) — tsc rewrites to .js
191
- // import { helper } from './utils.js'
192
- // import { Button } from './button.js'
193
- ```
194
-
195
- - Only relative imports are rewritten. Path aliases (`paths` in tsconfig) are
196
- not supported by `rewriteRelativeImportExtensions` — this is fine since npm
197
- packages should use relative imports anyway.
198
- - Requires TypeScript 5.7+.
196
+ - Requires TypeScript 5.7+ (`rewriteRelativeImportExtensions`).
199
197
  - Install `@types/node` as a dev dependency whenever Node APIs are used.
200
198
  - If generation is required, keep generators in `scripts/*.ts` and invoke them
201
199
  from package scripts before build/publish.
202
200
 
203
201
  > IMPORTANT! always use rootDir src. if there are other root level folders that should be type checked you should create other tsconfig.json files inside those folder. DO NOT add other folders inside src or the dist/ will contain dist/src, dist/other-folder. which breaks imports. the tsconfig.json inside these other folders can be minimal, using noEmit true, declaration false. Because usually these folders do not need to be emitted or compiled. just type checked. tests should still be put inside src. other folders can be things like `scripts` or `fixtures`.
204
202
 
203
+ ## Relative imports
204
+
205
+ Always write `.ts` or `.tsx` in relative source imports. Never write `.js`.
206
+
207
+ TypeScript 5.7+ rewrites those extensions to `.js` in `dist/` when
208
+ `rewriteRelativeImportExtensions` is on. Source then runs as-is in `tsx`,
209
+ `bun`, Next.js, and Node type-stripping. Published JS still resolves.
210
+
211
+ ```ts
212
+ import { helper } from "./utils.ts";
213
+ import { Button } from "./button.tsx";
214
+ ```
215
+
216
+ `tsc` emits `./utils.js` and `./button.js`. Only relative paths (`./`, `../`)
217
+ are rewritten. Path aliases, `#` imports, and bare specifiers are not. npm
218
+ packages should use relative imports anyway.
219
+
220
+ Docs: [rewriteRelativeImportExtensions](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions),
221
+ [TypeScript 5.7 path rewriting](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-7.html#path-rewriting-for-relative-paths).
222
+
205
223
  ## Preferred exports template
206
224
 
207
225
  ```json
@@ -355,7 +373,7 @@ Source of truth: [TypeScript Modules Reference — package.json "imports" and se
355
373
 
356
374
  ## tests location
357
375
 
358
- test files should be close with the associated source files. for example if you have an utils.ts file you will create utils.test.ts file next to it. with tests, importing from utils. preferred testing framework is vitest (or bun if project already using `bun test` or depends on bun APIs, rare)
376
+ test files should be close with the associated source files. for example if you have an utils.ts file you will create utils.test.ts file next to it. with tests, importing from `./utils.ts`. preferred testing framework is vitest (or bun if project already using `bun test` or depends on bun APIs, rare)
359
377
 
360
378
  ## Agent skill
361
379
 
@@ -665,8 +683,10 @@ To make peer dependencies optional, add `peerDependenciesMeta`:
665
683
 
666
684
  ## common mistakes
667
685
 
686
+ - never write `.js` in relative source imports. use `.ts` or `.tsx`. tsc rewrites them in `dist/`
668
687
  - if you need to use zod always use latest version
669
688
  - always install packages as dev dependencies if used only for scripts, testing or types only
670
- - if the package uses `rimraf` in scripts, install it as a dev dependency instead of relying on platform-specific shell behavior
689
+ - never use `rm -rf` in a package.json script. always use `rimraf`, installed as a dev dependency. `rm -rf` is not portable to Windows and zsh aborts the whole `&&` chain when a glob matches nothing
690
+ - never delete anything in `build`. deletes belong in `prepublishOnly` only
671
691
  - never use em-dashes (—) or dashes as inline separators (like `word - word`) in README or documentation. instead restructure the sentence: use periods to split into two sentences, colons, commas, or parentheses
672
692
  - never add badge images (shields.io, etc.) or any images you don't have locally in the repo. don't invent image URLs
@@ -1,6 +1,13 @@
1
1
  ---
2
2
  name: profano
3
- description: CLI tool to analyze V8 .cpuprofile files and Chrome Performance traces and print top functions by self-time or total-time in the terminal. ALWAYS load this skill when CPU profiling JavaScript or TypeScript programs (Node, Vitest, Bun, Chrome DevTools exports) — it shows how to generate .cpuprofile files and how to inspect them from the terminal without opening Chrome DevTools.
3
+ repo: remorses/profano
4
+ description: >
5
+ CLI tool to analyze V8 .cpuprofile files and Chrome Performance traces and
6
+ print top functions by self-time or total-time in the terminal. ALWAYS load
7
+ this skill when CPU profiling JavaScript or TypeScript programs (Node, Vitest,
8
+ Bun, Chrome DevTools exports, Cloudflare Workers startup or request CPU).
9
+ It shows how to generate .cpuprofile files and how to inspect them from the
10
+ terminal without opening Chrome DevTools.
4
11
  ---
5
12
 
6
13
  # profano
@@ -13,6 +20,14 @@ Every time you use profano, you MUST fetch the latest README and read it in full
13
20
  curl -s https://raw.githubusercontent.com/remorses/profano/main/README.md # NEVER pipe to head/tail, read in full
14
21
  ```
15
22
 
16
- The README covers generating `.cpuprofile` files (Node, Vitest, Bun, Chrome Performance traces, browser pages via playwriter, React component profiling), all CLI options, and how to read the output columns.
23
+ The README covers generating `.cpuprofile` files (Node, Vitest, Bun, **Cloudflare Workers** startup and request, Chrome Performance traces, browser pages via playwriter, React component profiling), all CLI options, and how to read the output columns.
17
24
 
18
25
  Chrome Performance **Save profile** writes a trace JSON. Pass it to `profano Trace.json` directly. Do not convert it first.
26
+
27
+ ## Cloudflare Workers
28
+
29
+ A Worker needs **two** profiles. Startup is `wrangler check startup`. A request is `wrangler dev --inspector-port 9230` plus `profano workers request <url>`. `wrangler tail` `cpuTime` is only a total. Never paste a one-off CDP script; use the CLI command.
30
+
31
+ Do **not** copy `dist/` to a temp folder unless `wrangler check startup` errors about two wrangler configs with different base paths. That copy is an exception, not the default.
32
+
33
+ Trust the **function mix** in a local profile. Do not treat local milliseconds as Cloudflare CPU.