@polderlabs/bizar 6.2.5 → 6.3.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 (329) hide show
  1. package/.claude/CLAUDE.md +15 -0
  2. package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
  3. package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
  4. package/.claude/agents/_shared/SKILLS.md +109 -0
  5. package/.claude/agents/agent-browser.md +80 -0
  6. package/.claude/agents/baldr.md +49 -0
  7. package/.claude/agents/forseti.md +51 -0
  8. package/.claude/agents/frigg.md +42 -0
  9. package/.claude/agents/heimdall.md +33 -0
  10. package/.claude/agents/hermod.md +53 -0
  11. package/.claude/agents/mimir.md +49 -0
  12. package/.claude/agents/odin.md +287 -0
  13. package/.claude/agents/quick.md +34 -0
  14. package/.claude/agents/semble-search.md +50 -0
  15. package/.claude/agents/thor.md +53 -0
  16. package/.claude/agents/tyr.md +56 -0
  17. package/.claude/agents/vidarr.md +54 -0
  18. package/.claude/agents/vor.md +53 -0
  19. package/.claude/commands/audit.md +25 -0
  20. package/.claude/commands/bizar.md +22 -0
  21. package/.claude/commands/explain.md +17 -0
  22. package/.claude/commands/init.md +29 -0
  23. package/.claude/commands/learn.md +44 -0
  24. package/.claude/commands/plan.md +35 -0
  25. package/.claude/commands/plow-through.md +50 -0
  26. package/.claude/commands/pr-review.md +49 -0
  27. package/.claude/commands/setup-provider.md +96 -0
  28. package/.claude/commands/tailscale-serve.md +100 -0
  29. package/.claude/commands/team.md +132 -0
  30. package/.claude/commands/test.md +62 -0
  31. package/.claude/commands/validate.md +68 -0
  32. package/.claude/commands/visual-plan.md +24 -0
  33. package/.claude/hooks/README.md +92 -0
  34. package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
  35. package/.claude/hooks/pretooluse-bash.mjs +81 -0
  36. package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
  37. package/.claude/hooks/sessionend-recall.mjs +74 -0
  38. package/.claude/hooks/sessionstart-prime.mjs +80 -0
  39. package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
  40. package/.claude/settings.json +116 -0
  41. package/.claude/skills/9router/SKILL.md +80 -0
  42. package/.claude/skills/9router-chat/SKILL.md +73 -0
  43. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  44. package/.claude/skills/9router-image/SKILL.md +86 -0
  45. package/.claude/skills/9router-stt/SKILL.md +79 -0
  46. package/.claude/skills/9router-tts/SKILL.md +80 -0
  47. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  48. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  49. package/.claude/skills/bizar/README.md +9 -0
  50. package/.claude/skills/bizar/SKILL.md +450 -0
  51. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  52. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  53. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  54. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  55. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  56. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  57. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  58. package/.claude/skills/cpp-testing/README.md +28 -0
  59. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  60. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  61. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  62. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  63. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  64. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  65. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  66. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  67. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  68. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  69. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  70. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  71. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  72. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  73. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  74. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  75. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  76. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  78. package/.claude/skills/glyph/SKILL.md +163 -0
  79. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  80. package/.claude/skills/lightrag/SKILL.md +81 -0
  81. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  82. package/.claude/skills/obsidian/SKILL.md +306 -0
  83. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  84. package/.claude/skills/self-improvement/SKILL.md +64 -0
  85. package/README.md +87 -59
  86. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
  88. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
  89. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
  90. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
  91. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
  92. package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
  93. package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
  94. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
  95. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
  96. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
  97. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
  98. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
  99. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
  100. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
  101. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
  102. package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
  103. package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
  104. package/bizar-dash/dist/index.html +6 -6
  105. package/bizar-dash/dist/mobile.html +2 -2
  106. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  107. package/bizar-dash/src/server/api.mjs +4 -4
  108. package/bizar-dash/src/server/background-store.mjs +15 -16
  109. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  110. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  111. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  112. package/bizar-dash/src/server/claude-info.mjs +412 -0
  113. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  114. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  115. package/bizar-dash/src/server/providers-store.mjs +22 -49
  116. package/bizar-dash/src/server/routes/background.mjs +24 -20
  117. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  118. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  119. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  120. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  121. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  122. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  123. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  124. package/cli/bin.mjs +17 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/validate.mjs +252 -325
  128. package/cli/dev-link.test.mjs +11 -11
  129. package/cli/doctor.mjs +131 -213
  130. package/cli/install.mjs +33 -37
  131. package/cli/install.test.mjs +9 -9
  132. package/cli/provision-claude.mjs +893 -0
  133. package/cli/provision.mjs +224 -227
  134. package/cli/utils.mjs +72 -58
  135. package/config/AGENTS.md +28 -28
  136. package/install.sh +66 -44
  137. package/package.json +19 -11
  138. package/packages/sdk/ARCHITECTURE.md +40 -36
  139. package/packages/sdk/package-lock.json +32 -0
  140. package/packages/sdk/package.json +15 -5
  141. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  142. package/packages/sdk/src/fingerprint.ts +0 -0
  143. package/packages/sdk/src/index.ts +38 -73
  144. package/packages/sdk/src/mcp/bin.ts +51 -0
  145. package/packages/sdk/src/mcp/server.ts +498 -0
  146. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  147. package/packages/sdk/tests/sdk.test.mjs +148 -0
  148. package/packages/sdk/vitest.config.ts +1 -1
  149. package/scripts/bh-full-e2e.mjs +166 -363
  150. package/scripts/check-deps.mjs +28 -46
  151. package/scripts/mirror-claude-md.sh +78 -0
  152. package/scripts/test-in-container.sh +31 -9
  153. package/templates/clean-state-checklist.md +3 -3
  154. package/templates/sprint-contract.md +2 -2
  155. package/bizar-dash/.bizar/activity.log +0 -3
  156. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  157. package/bizar-dash/.omx/state/session.json +0 -10
  158. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  159. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  160. package/bizar-dash/bizar-design/canvas.html +0 -281
  161. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  162. package/bizar-dash/bizar-design/components.css +0 -1665
  163. package/bizar-dash/bizar-design/components.html +0 -557
  164. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  165. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  166. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  167. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  168. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  169. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  170. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  172. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  174. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/icons.svg +0 -44
  176. package/bizar-dash/bizar-design/index.html +0 -192
  177. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  178. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  179. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  180. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  181. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  182. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  183. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  185. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/prototype.js +0 -114
  189. package/bizar-dash/bizar-design/tokens.css +0 -106
  190. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  191. package/bizar-dash/node_modules/.package-lock.json +0 -6
  192. package/bizar-dash/package-lock.json +0 -6
  193. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  194. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  195. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  196. package/cli/commands/cline-cmd.mjs +0 -289
  197. package/cli/commands/validate.test.mjs +0 -379
  198. package/cli/doctor.test.mjs +0 -350
  199. package/config/cline.json.template +0 -342
  200. package/packages/sdk/src/client.ts +0 -188
  201. package/packages/sdk/src/cline-events.ts +0 -134
  202. package/packages/sdk/src/cline-types.ts +0 -66
  203. package/packages/sdk/src/cline.ts +0 -339
  204. package/packages/sdk/src/errors.ts +0 -129
  205. package/packages/sdk/src/events.ts +0 -153
  206. package/packages/sdk/src/types.ts +0 -176
  207. package/packages/sdk/tests/client.test.ts +0 -217
  208. package/packages/sdk/tests/errors.test.ts +0 -108
  209. package/packages/sdk/tests/events.test.ts +0 -139
  210. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  211. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  212. package/plugins/bizar/ARCHITECTURE.md +0 -142
  213. package/plugins/bizar/CONSTRAINTS.md +0 -67
  214. package/plugins/bizar/LICENSE +0 -21
  215. package/plugins/bizar/README.md +0 -448
  216. package/plugins/bizar/index.ts +0 -925
  217. package/plugins/bizar/package.json +0 -39
  218. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  219. package/plugins/bizar/src/background-state.ts +0 -641
  220. package/plugins/bizar/src/background.ts +0 -1806
  221. package/plugins/bizar/src/cline-runner.ts +0 -203
  222. package/plugins/bizar/src/clineruntime.ts +0 -227
  223. package/plugins/bizar/src/commands-impl.ts +0 -151
  224. package/plugins/bizar/src/commands.ts +0 -1799
  225. package/plugins/bizar/src/compaction.d.mts +0 -48
  226. package/plugins/bizar/src/compaction.mjs +0 -192
  227. package/plugins/bizar/src/dashboard-client.ts +0 -233
  228. package/plugins/bizar/src/event-stream.ts +0 -606
  229. package/plugins/bizar/src/fingerprint.ts +0 -120
  230. package/plugins/bizar/src/handoff.ts +0 -79
  231. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  232. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  233. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  234. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  235. package/plugins/bizar/src/http-client.ts +0 -467
  236. package/plugins/bizar/src/key-rotation.ts +0 -218
  237. package/plugins/bizar/src/logger.ts +0 -144
  238. package/plugins/bizar/src/loop-engineering.ts +0 -241
  239. package/plugins/bizar/src/loop.ts +0 -176
  240. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  241. package/plugins/bizar/src/odin.ts +0 -227
  242. package/plugins/bizar/src/options.ts +0 -470
  243. package/plugins/bizar/src/plan-fs.ts +0 -323
  244. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  245. package/plugins/bizar/src/report.ts +0 -178
  246. package/plugins/bizar/src/research-prompt.ts +0 -35
  247. package/plugins/bizar/src/serve-info.ts +0 -228
  248. package/plugins/bizar/src/serve.ts +0 -496
  249. package/plugins/bizar/src/settings.ts +0 -349
  250. package/plugins/bizar/src/state.ts +0 -298
  251. package/plugins/bizar/src/tool-discipline.ts +0 -105
  252. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  253. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  254. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  255. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  256. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  257. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  258. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  259. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  260. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  261. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  262. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  263. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  264. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  265. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  266. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  267. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  268. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  269. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  270. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  271. package/plugins/bizar/src/tools/sandbox.ts +0 -232
  272. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  273. package/plugins/bizar/src/tools/team-status.ts +0 -76
  274. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  275. package/plugins/bizar/src/trajectory.ts +0 -104
  276. package/plugins/bizar/tests/README.md +0 -99
  277. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  278. package/plugins/bizar/tests/background-state.test.ts +0 -277
  279. package/plugins/bizar/tests/background.test.ts +0 -402
  280. package/plugins/bizar/tests/block.test.ts +0 -195
  281. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  282. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  283. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  284. package/plugins/bizar/tests/commands.test.ts +0 -584
  285. package/plugins/bizar/tests/compaction.test.ts +0 -264
  286. package/plugins/bizar/tests/config.test.ts +0 -128
  287. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  288. package/plugins/bizar/tests/dispose.test.ts +0 -336
  289. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  290. package/plugins/bizar/tests/event.test.ts +0 -262
  291. package/plugins/bizar/tests/fingerprint.test.ts +0 -190
  292. package/plugins/bizar/tests/http-client.test.ts +0 -404
  293. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  294. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  295. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  296. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  297. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  298. package/plugins/bizar/tests/loop.test.ts +0 -397
  299. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  300. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  301. package/plugins/bizar/tests/odin.test.ts +0 -125
  302. package/plugins/bizar/tests/options.test.ts +0 -329
  303. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  304. package/plugins/bizar/tests/safety.test.ts +0 -281
  305. package/plugins/bizar/tests/serve.test.ts +0 -339
  306. package/plugins/bizar/tests/settings.test.ts +0 -351
  307. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  308. package/plugins/bizar/tests/state.test.ts +0 -276
  309. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  310. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  311. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  312. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  313. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  314. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  315. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  316. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  317. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  318. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  319. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  320. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  321. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  322. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  323. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  324. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  325. package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
  326. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  327. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  328. package/plugins/bizar/tsconfig.json +0 -29
  329. package/scripts/mirror-agents-md.sh +0 -69
@@ -0,0 +1,214 @@
1
+ # FreeRTOS patterns
2
+
3
+ ESP-IDF v5 uses FreeRTOS. Most of these patterns are the same as FreeRTOS elsewhere; the ESP32-specific bits are task pinning, ISR rules (no blocking), and `portTICK_PERIOD_MS`.
4
+
5
+ ## Task lifecycle
6
+
7
+ Create, run, delete:
8
+
9
+ ```cpp
10
+ void acquisition_task(void *arg) {
11
+ while (true) {
12
+ // ... do work, sleep, wait on a queue ...
13
+ }
14
+ vTaskDelete(nullptr); // never reached in a normal acquisition loop
15
+ }
16
+
17
+ void start() {
18
+ xTaskCreatePinnedToCore(
19
+ acquisition_task, // task function
20
+ "acq", // name (shown in runtime stats)
21
+ 4096, // stack depth in WORDS (not bytes) on ESP32
22
+ nullptr, // arg
23
+ 20, // priority (0 = idle, higher = more preemptive)
24
+ nullptr, // optional task handle
25
+ 1 // core ID (0 = APP CPU on classic ESP32, 1 = PRO CPU)
26
+ );
27
+ }
28
+ ```
29
+
30
+ Notes:
31
+
32
+ - Stack depth is in **words**, not bytes. On ESP32 (32-bit) `4096` = 16 KB. Allocate generously for tasks with deep call chains; oversized stack wastes DRAM but undersized stack corrupts memory silently.
33
+ - Pass `nullptr` if you do not need the handle. Use the handle later for `vTaskSuspend` / `vTaskResume` / `vTaskDelete`.
34
+ - Pinning is mandatory for acquisition paths — non-pinned tasks can bounce between cores and lose cache locality.
35
+
36
+ `(AMS7)` AMS7 acquisition tasks run at priority 20+, pinned to core 0 (APP CPU). The PRO CPU (core 1) handles BLE/Wi-Fi by default.
37
+
38
+ ## Priorities
39
+
40
+ | Range | Use for |
41
+ |--------|------------------------------------------------------------|
42
+ | 0 | Idle task only — do not use |
43
+ | 1–4 | Normal app tasks, command handling, BLE host |
44
+ | 5–19 | Latency-sensitive but not real-time (rate control, queues) |
45
+ | 20–24 | Real-time acquisition, time-critical ISRs |
46
+
47
+ Do not stack many tasks at priority 20+ — round-robin between them defeats the point.
48
+
49
+ ## Pinning to cores
50
+
51
+ ESP32 dual-core (Xtensa LX6):
52
+
53
+ - **Core 0 (APP CPU)** — protocol stacks (Wi-Fi, BLE), low-level drivers.
54
+ - **Core 1 (PRO CPU)** — `app_main` runs here by default.
55
+
56
+ Pick a split that puts time-critical work on the under-used core. `xTaskCreatePinnedToCore(handle, name, stack, arg, prio, handle_out, core_id)`.
57
+
58
+ ESP32-S3 / C3 / H2 are single-core: pinning is a no-op but the API still works.
59
+
60
+ ## Queues
61
+
62
+ Producer/consumer with bounded queues. Decouples ISR rate from task rate.
63
+
64
+ ```cpp
65
+ QueueHandle_t evt_q = xQueueCreate(16, sizeof(uint32_t));
66
+
67
+ // Producer (task context)
68
+ uint32_t pin = read_pin();
69
+ xQueueSend(evt_q, &pin, pdMS_TO_TICKS(10));
70
+
71
+ // Consumer
72
+ uint32_t pin;
73
+ if (xQueueReceive(evt_q, &pin, portMAX_DELAY) == pdTRUE) {
74
+ handle(pin);
75
+ }
76
+ ```
77
+
78
+ Use `portMAX_DELAY` only when the consumer must never return. Use `pdMS_TO_TICKS(N)` when the consumer should time out (e.g., to check a "stop" flag).
79
+
80
+ ## ISR → task handoff
81
+
82
+ ISRs must not block. The standard handoff uses `xQueueSendFromISR` and the higher-priority-task-woken flag:
83
+
84
+ ```cpp
85
+ static QueueHandle_t gpio_evt_q;
86
+
87
+ void IRAM_ATTR gpio_isr(void *arg) {
88
+ uint32_t pin = (uint32_t)arg;
89
+ BaseType_t hpw = pdFALSE;
90
+ xQueueSendFromISR(gpio_evt_q, &pin, &hpw);
91
+ if (hpw == pdTRUE) portYIELD_FROM_ISR();
92
+ }
93
+
94
+ void consumer_task(void *arg) {
95
+ uint32_t pin;
96
+ while (true) {
97
+ if (xQueueReceive(gpio_evt_q, &pin, portMAX_DELAY) == pdTRUE) {
98
+ // process pin (NOT in ISR context — can block here)
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ Alternatives:
105
+
106
+ - `xTaskNotifyFromISR` / `xTaskNotifyWait` — single-task notifications, very fast.
107
+ - `xTimerPendFunctionCallFromISR` — defer a callback into the timer service task (useful for one-shot IRAM work).
108
+ - Direct event bits with `xEventGroupSetBitsFromISR` — broadcast to multiple waiters.
109
+
110
+ ## Stream and ring buffers
111
+
112
+ For variable-length byte streams (e.g., SPI DMA into a parser):
113
+
114
+ ```cpp
115
+ StreamBufferHandle_t sb = xStreamBufferCreate(2048, 256); // total, trigger
116
+ // Producer (DMA ISR)
117
+ xStreamBufferSendFromISR(sb, data, len, &hpw);
118
+ // Consumer task
119
+ uint8_t buf[256];
120
+ size_t got = xStreamBufferReceive(sb, buf, sizeof(buf), pdMS_TO_TICKS(100));
121
+ ```
122
+
123
+ `xRingbufferCreate` (IDF) is the lock-free variant — better for high-rate ISR streams where the producer must never wait.
124
+
125
+ ## Semaphores and mutexes
126
+
127
+ ```cpp
128
+ SemaphoreHandle_t ready = xSemaphoreCreateBinary();
129
+ xSemaphoreGive(ready);
130
+ xSemaphoreTake(ready, portMAX_DELAY);
131
+
132
+ SemaphoreHandle_t in_flight = xSemaphoreCreateCounting(4, 0); // max 4, starts empty
133
+ ```
134
+
135
+ Mutexes for shared resources:
136
+
137
+ ```cpp
138
+ SemaphoreHandle_t cfg_lock = xSemaphoreCreateMutex();
139
+ if (xSemaphoreTake(cfg_lock, pdMS_TO_TICKS(100)) == pdTRUE) {
140
+ // ... access shared resource ...
141
+ xSemaphoreGive(cfg_lock);
142
+ }
143
+ ```
144
+
145
+ **Recursive mutexes** (`xSemaphoreCreateRecursiveMutex`) for code that may take the same lock twice in a call chain.
146
+
147
+ ## Timers
148
+
149
+ ```cpp
150
+ TimerHandle_t t = xTimerCreate("rate", pdMS_TO_TICKS(1000), pdTRUE, nullptr, [](TimerHandle_t x) {
151
+ // fired every 1000 ms; called in the timer service task (NOT ISR context)
152
+ });
153
+ xTimerStart(t, 0);
154
+ ```
155
+
156
+ One-shot for delayed work:
157
+
158
+ ```cpp
159
+ TimerHandle_t oneshot = xTimerCreate("once", pdMS_TO_TICKS(50), pdFALSE, nullptr, cb);
160
+ xTimerStart(oneshot, 0);
161
+ ```
162
+
163
+ ## Event groups
164
+
165
+ Useful when a task must wait for several subsystems to be ready before proceeding:
166
+
167
+ ```cpp
168
+ EventGroupHandle_t eg = xEventGroupCreate();
169
+ xEventGroupSetBits(eg, BIT_SD_READY | BIT_BLE_READY | BIT_ACQ_READY);
170
+
171
+ EventBits_t bits = xEventGroupWaitBits(
172
+ eg,
173
+ BIT_SD_READY | BIT_BLE_READY | BIT_ACQ_READY,
174
+ pdFALSE, // don't clear on exit
175
+ pdTRUE, // wait for ALL bits
176
+ portMAX_DELAY
177
+ );
178
+ ```
179
+
180
+ ## Watchdog
181
+
182
+ The IDF task watchdog resets the system if a task does not feed it within a window. Always feed:
183
+
184
+ ```cpp
185
+ void heavy_task(void *arg) {
186
+ while (true) {
187
+ // chunk of work
188
+ vTaskDelay(pdMS_TO_TICKS(10)); // yields — watchdog is fed by idle
189
+ // OR if you spin:
190
+ // vTaskDelay(1); // minimum yield
191
+ }
192
+ }
193
+ ```
194
+
195
+ If a task really must spin for >1 second (rare), subscribe it to the watchdog and call `esp_task_wdt_reset()` periodically. Long ISR-disabled windows also trip the watchdog — keep them < one tick (`portTICK_PERIOD_MS` = 10 ms by default).
196
+
197
+ ## portTICK_PERIOD_MS
198
+
199
+ Always convert via `pdMS_TO_TICKS(ms)`:
200
+
201
+ ```cpp
202
+ vTaskDelay(pdMS_TO_TICKS(100)); // 100 ms regardless of tick rate
203
+ xQueueReceive(q, &x, pdMS_TO_TICKS(50));
204
+ ```
205
+
206
+ Never multiply by hand (`ms * portTICK_PERIOD_MS`) — it lies when the tick rate changes.
207
+
208
+ ## Common pitfalls
209
+
210
+ - **Blocking in an ISR.** Symptom: hard fault or watchdog reset. Fix: defer to a task via `xQueueSendFromISR` / `xTaskNotifyFromISR`.
211
+ - **Stack too small.** Symptom: random crashes after a few minutes, often deep in call chains. Fix: bump stack depth, or enable `CONFIG_COMPILER_STACK_CHECK_MODE_NORM` to catch overflows at runtime.
212
+ - **Priority inversion.** Symptom: low-priority task holds a mutex, blocks a high-priority task. Fix: `xSemaphoreCreateRecursiveMutex` and keep critical sections short.
213
+ - **Forgetting `portYIELD_FROM_ISR`.** Symptom: producer wakes the consumer but the consumer doesn't run until the next tick. Fix: check the `xHigherPriorityTaskWoken` returned from `*FromISR` and yield.
214
+ - **Non-pinned tasks bouncing cores.** Symptom: jittery timing, occasional cache misses. Fix: pin acquisition and protocol tasks explicitly.
@@ -0,0 +1,164 @@
1
+ # Host-side tests
2
+
3
+ ESP-IDF firmware that depends on FreeRTOS, drivers, and NVS cannot run on the host. But policy modules, payload encoders/decoders, pure-C++ algorithms, and protocol parsers can — and should — be unit-tested on the host with a normal C++ toolchain.
4
+
5
+ `(AMS7)` AMS7's host tests are deliberately lightweight: one `.cpp` test file + one `run_*_test.sh` shell wrapper. No CMake host build, no fakes library, no GoogleTest. The whole test is `g++ -std=c++17 ... && ./a.out`.
6
+
7
+ For larger projects with GoogleTest / Catch2 / fakes, see the **`cpp-testing`** skill.
8
+
9
+ ## AMS7 pattern (test + run script)
10
+
11
+ A typical test file in `tests/connectivity/`:
12
+
13
+ ```cpp
14
+ // tests/connectivity/espnow_imu_frame_test.cpp
15
+ #include <cassert>
16
+ #include <cstdio>
17
+
18
+ #include "espnow_imu_frame.hpp"
19
+
20
+ int main() {
21
+ core_espnow_imu_frame_v1_t frame = {};
22
+ espnow_imu_frame_init(&frame, 0x1234U, 9U, 55U,
23
+ 1, -2, 3, -4, 5, -6);
24
+
25
+ assert(frame.magic == CORE_ESPNOW_IMU_MAGIC);
26
+ assert(frame.version == CORE_ESPNOW_IMU_VERSION);
27
+ assert(frame.frame_type == CORE_ESPNOW_FRAME_IMU_RAW);
28
+ assert(frame.id == 0x1234U);
29
+ assert(frame.seq == 9U);
30
+ assert(frame.age_ms == 55U);
31
+ assert(frame.accel_x == 1);
32
+ assert(frame.accel_y == -2);
33
+ assert(frame.accel_z == 3);
34
+ assert(frame.gyro_x == -4);
35
+ assert(frame.gyro_y == 5);
36
+ assert(frame.gyro_z == -6);
37
+
38
+ std::puts("espnow_imu_frame_test: ok");
39
+ return 0;
40
+ }
41
+ ```
42
+
43
+ And the wrapper `tests/connectivity/run_espnow_imu_frame_test.sh`:
44
+
45
+ ```bash
46
+ #!/usr/bin/env bash
47
+ set -euo pipefail
48
+
49
+ g++ -std=c++17 \
50
+ tests/connectivity/espnow_imu_frame_test.cpp \
51
+ main/connectivity/espnow_imu_frame.cpp \
52
+ -I main/connectivity \
53
+ -o /tmp/espnow_imu_frame_test
54
+
55
+ /tmp/espnow_imu_frame_test
56
+ ```
57
+
58
+ Run it:
59
+
60
+ ```bash
61
+ bash tests/connectivity/run_espnow_imu_frame_test.sh
62
+ ```
63
+
64
+ The wrapper does three things: compile, link, run. Add `g++` flags (`-Wall -Wextra -Werror`) for stricter checking.
65
+
66
+ ## What can be host-tested
67
+
68
+ - **Packed structs and frame encoders** — `espnow_*_frame_*`, `gateway_command_*`, `marker_*`. Pure data marshalling.
69
+ - **Policy modules** — `connectivity_mode_policy`, `electrode_detach_gate`, `acquisition_command_policy`. Pure decision logic.
70
+ - **Pure algorithms** — `hr_fused`, `resp_fallback`, `summary_metrics`. Make sure they don't `malloc` or call FreeRTOS and they're trivially host-testable.
71
+ - **State machines** — anything that's a transition table plus a few event handlers.
72
+
73
+ ## What must NOT be host-tested
74
+
75
+ - Anything that includes `<freertos/FreeRTOS.h>`.
76
+ - Anything that includes `esp_log.h` (unless you fake it).
77
+ - Anything that includes driver headers (`driver/spi_master.h`, `driver/i2c.h`).
78
+ - Anything that pulls in NVS, BLE, Wi-Fi, ESP-NOW stacks.
79
+
80
+ If a header you want to test transitively includes one of these, factor the pure logic out into a separate translation unit. The split is usually: `policy.hpp/cpp` for pure logic, `policy_runtime.cpp` for the FreeRTOS-aware glue.
81
+
82
+ ## Fakes for FreeRTOS (when you need them)
83
+
84
+ If you have a real CMake host project (not the AMS7 minimal pattern) and want to test code that touches FreeRTOS, use the **`cpp-testing`** skill's fakes recipe. The minimum useful fakes:
85
+
86
+ - `fake_freertos.h` — declares the FreeRTOS API surface used by the code under test, with hooks (`xQueueCreate` returns a recorded handle, etc.).
87
+ - `fake_log.h` — empty `ESP_LOG*` macros or a recorded message list.
88
+
89
+ Keep fakes local to the test, not in `main/`. Use `BUILD_ONLY_FAKES` or a separate `tests/host/` CMake target.
90
+
91
+ ## CMake host project (alternative to per-test shell scripts)
92
+
93
+ For larger suites:
94
+
95
+ ```cmake
96
+ # tests/host/CMakeLists.txt
97
+ cmake_minimum_required(VERSION 3.16)
98
+ project(ams7_host_tests CXX)
99
+
100
+ set(CMAKE_CXX_STANDARD 17)
101
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
102
+
103
+ add_executable(test_espnow_imu
104
+ ../../main/connectivity/espnow_imu_frame.cpp
105
+ espnow_imu_frame_test.cpp
106
+ )
107
+ target_include_directories(test_espnow_imu PRIVATE
108
+ ${CMAKE_SOURCE_DIR}/../../main/connectivity
109
+ )
110
+ ```
111
+
112
+ ```bash
113
+ cmake -S tests/host -B tests/host/build
114
+ cmake --build tests/host/build
115
+ ./tests/host/build/test_espnow_imu
116
+ ```
117
+
118
+ Tradeoffs vs the AMS7 minimal pattern:
119
+
120
+ | Aspect | AMS7 shell wrapper | CMake host project |
121
+ |------------------|---------------------------------|---------------------------|
122
+ | Setup cost | Zero — one shell script per test| One CMakeLists to maintain |
123
+ | Linking firmware | Direct `g++ ... file.cpp` | Same, via CMake rules |
124
+ | Adding fakes | None | Add a `fake/` directory |
125
+ | Test discovery | Manual | `ctest` |
126
+ | CI integration | `find tests -name run_*.sh` | `ctest --output-on-failure` |
127
+ | Build parallelism| Sequential | Parallel via `cmake --build` |
128
+
129
+ Both are valid. AMS7 picks the shell wrapper because every test is one file and one assertion set — `ctest` overhead is not worth it.
130
+
131
+ ## Tests vs fixtures
132
+
133
+ AMS7 has `tests/fixtures/` for replay inputs (recorded sensor traces used to drive host tests):
134
+
135
+ ```cpp
136
+ // tests/fixtures/replay/ecg_2024-09-12.bin — raw bytes recorded from a real run
137
+ ```
138
+
139
+ Load fixtures in tests via `std::ifstream` rather than copy-pasting bytes into the test source.
140
+
141
+ ## Common pitfalls
142
+
143
+ - **Including `<esp_log.h>` from a header that's host-tested.** Fix: forward-declare the log macros in the header, include the real one only in `.cpp`. Or include the AMS7 fake `tests/support/host_include/esp_log.h` if one exists.
144
+ - **`malloc` in pure logic.** Symptom: host test runs fine but firmware crashes from fragmentation. Fix: allocate in the wrapper, pass a buffer in.
145
+ - **Globals with static initialization.** Symptom: works on host, fails on target because init order is different. Fix: prefer explicit `init()` calls.
146
+ - **Asserting on floating-point equality.** Use a tolerance: `assert(std::abs(a - b) < 1e-3)`.
147
+ - **Forgetting `-Werror` in CI.** Compile-only warnings become ship-time bugs. The AMS7 host tests are silent on warnings by default; consider adding `-Wall -Wextra` to your shell wrappers.
148
+ - **Test passes on host, fails on firmware.** The two are usually equivalent for pure logic, but always cross-check with a firmware-side integration test (a debug print, a recorded trace, or an ESP-NOW roundtrip).
149
+
150
+ ## When to grow beyond the minimal pattern
151
+
152
+ Stay with the shell wrapper while:
153
+
154
+ - Test count is < ~30.
155
+ - Each test is one `.cpp` plus one shell script.
156
+ - No fakes needed.
157
+ - CI just iterates `tests/ -name run_*.sh`.
158
+
159
+ Migrate to a CMake host project when:
160
+
161
+ - You need `ctest` for CI parallelism and reporting.
162
+ - You need fakes (FreeRTOS, log, drivers).
163
+ - A test needs to link multiple firmware modules together.
164
+ - You want fixtures automatically discovered.
@@ -0,0 +1,157 @@
1
+ # idf.py commands
2
+
3
+ `idf.py` is the single entry point to ESP-IDF v5. All commands assume the IDF environment is sourced:
4
+
5
+ ```bash
6
+ source esp/esp-idf/export.sh
7
+ ```
8
+
9
+ If `idf.py` is not on PATH, `scripts/idf_env.sh` will print the source line and tell you whether the env is healthy.
10
+
11
+ ## Core workflow
12
+
13
+ ```bash
14
+ idf.py build # compile (incremental)
15
+ idf.py -p /dev/ttyUSB0 flash # write image to board
16
+ idf.py -p /dev/ttyUSB0 monitor # serial console (Ctrl-] to exit)
17
+ idf.py -p /dev/ttyUSB0 flash monitor # flash then monitor in one shot
18
+ ```
19
+
20
+ `-p` is the serial port. Linux: `/dev/ttyUSB0` or `/dev/ttyACM0`. macOS: `/dev/cu.usbserial-*`. Windows: `COM3`.
21
+
22
+ ## Configuration
23
+
24
+ ```bash
25
+ idf.py menuconfig # TUI Kconfig editor
26
+ idf.py menuconfig --no-target # don't ask to set target
27
+ idf.py save-defconfig # write minimal defconfig from current settings
28
+ ```
29
+
30
+ `menuconfig` writes the result to `sdkconfig`. To apply a layered profile:
31
+
32
+ ```bash
33
+ idf.py -B build_espnow_flow -C . \
34
+ --sdkconfig sdkconfig.espnow_flow \
35
+ build flash
36
+ ```
37
+
38
+ The `-B build_<name>` puts the build output in `build_<name>/`, leaving the default `build/` clean.
39
+
40
+ ## Build inspection
41
+
42
+ ```bash
43
+ idf.py size # text: app partition + IRAM + DRAM
44
+ idf.py size --format json # machine-readable for tooling
45
+ idf.py size --format csv # spreadsheet-friendly
46
+ idf.py size --output-file size.json
47
+ idf.py size-components # per-component breakdown
48
+ ```
49
+
50
+ `idf.py size` exit code is 0 on success regardless of size; size policy lives in project-specific tools.
51
+
52
+ ## Cleaning
53
+
54
+ ```bash
55
+ idf.py clean # remove build artifacts but keep config
56
+ idf.py fullclean # remove build/ AND sdkconfig (then menuconfig again)
57
+ idf.py -B build_espnow_flow clean # clean a specific build dir
58
+ ```
59
+
60
+ `fullclean` is destructive — it deletes your local `sdkconfig` overrides. Commit your `sdkconfig` and any profile files first.
61
+
62
+ ## Target and project
63
+
64
+ ```bash
65
+ idf.py set-target esp32 # esp32 / esp32s2 / esp32s3 / esp32c3 / esp32h2
66
+ idf.py create-project foo # scaffold a new project from a template
67
+ idf.py add-dependency "owner/repo^1.2.3" # pull into managed_components/
68
+ ```
69
+
70
+ After `set-target`, ESP-IDF regenerates component configs — clean build artifacts:
71
+
72
+ ```bash
73
+ idf.py set-target esp32s3 && idf.py build
74
+ ```
75
+
76
+ ## Partition table
77
+
78
+ ```bash
79
+ idf.py partition-table # regenerate partition_table/*.bin from partitions.csv
80
+ idf.py erase-flash # erase entire flash (use with care)
81
+ ```
82
+
83
+ `partitions.csv` is at the project root; `idf.py menuconfig → Partition Table` selects which CSV to use. Common layouts:
84
+
85
+ - `partitions_singleapp.csv` — single OTA-less app partition
86
+ - `partitions_two_ota.csv` — A/B OTA slots (default for OTA-enabled projects)
87
+ - A custom CSV — declare `app`, `data`, `nvs`, `phy_init`, `storage` partitions with explicit sizes
88
+
89
+ `(AMS7)` The AMS7 partition table reserves a large `storage` partition for SD-aware OTA staging.
90
+
91
+ ## Monitor filters
92
+
93
+ ```bash
94
+ idf.py -p /dev/ttyUSB0 monitor --print-filter="*:I" # only INFO and above
95
+ idf.py monitor --print-filter="ams7driver:I espnow_summary:W" # per-tag levels
96
+ idf.py monitor --elf <elf_path> # decode panic backtraces
97
+ ```
98
+
99
+ `-d` disables line-ending conversion (binary output). `-t` adds a timestamp prefix.
100
+
101
+ Inside the monitor, useful key bindings:
102
+
103
+ - `Ctrl-]` — exit
104
+ - `Ctrl-T` — toggle menu (send break, change filter, etc.)
105
+
106
+ ## Build flags
107
+
108
+ ```bash
109
+ idf.py -DCMAKE_BUILD_TYPE=Debug build # Debug / Release / RelWithDebInfo / MinSizeRel
110
+ idf.py -DCONFIG_COMPILER_OPTIMIZATION_PERF=y build # enable IDF performance optimizations
111
+ idf.py -DSDKCONFIG_DEFAULTS=sdkconfig.espnow_flow build
112
+ ```
113
+
114
+ `-DSDKCONFIG_DEFAULTS` is equivalent to the `--sdkconfig` CLI flag and is useful for CI.
115
+
116
+ ## OpenOCD / debugging
117
+
118
+ ```bash
119
+ idf.py openocd # start OpenOCD for JTAG debugging
120
+ idf.py gdb # start xtensa-esp32-elf-gdb
121
+ idf.py gdbgui # GDB with a frontend
122
+ idf.py app-flash # flash only the app partition
123
+ idf.py bootloader-flash # flash only the bootloader
124
+ ```
125
+
126
+ GDB requires an `openocd` server on the default port (3333).
127
+
128
+ ## OTA
129
+
130
+ ```bash
131
+ idf.py app # build the app, ready for OTA push
132
+ idf.py ota # ... or `idf.py app` then push via HTTP
133
+ ```
134
+
135
+ For SD-card OTA staging: copy `build/<project>.bin` to the SD card under the OTA path your bootloader expects, then reboot.
136
+
137
+ ## Useful exit-code patterns
138
+
139
+ ```bash
140
+ # CI: build, then size check
141
+ idf.py build && idf.py size
142
+
143
+ # AMS7: full CI gate
144
+ source esp/esp-idf/export.sh
145
+ idf.py build
146
+ tools/check_idf_size_budget.py
147
+ ```
148
+
149
+ `scripts/size_check.sh` wraps the AMS7-specific size policy and falls back to `idf.py size` when run in a non-AMS7 project.
150
+
151
+ ## Common pitfalls
152
+
153
+ - **Forgot to source the env.** Symptom: `idf.py: command not found`. Fix: `source esp/esp-idf/export.sh` per shell session.
154
+ - **Wrong target.** Symptom: linker errors about `esp_image_header_t` size mismatches or missing `esp_hw_support`. Fix: `idf.py set-target esp32` then rebuild.
155
+ - **`sdkconfig` drift.** Symptom: subtle behavior changes after a `git pull`. Fix: `idf.py menuconfig` to re-resolve, or `git checkout sdkconfig` and re-apply.
156
+ - **`-B build_<flow>` left stale.** Symptom: build picks up old sources. Fix: `idf.py -B build_<flow> fullclean`.
157
+ - **Monitor hangs on macOS.** Use `/dev/cu.usbserial-*` not `/dev/tty.usbserial-*` (the `tty.` node blocks open while the driver holds it).
@@ -0,0 +1,159 @@
1
+ # Kconfig
2
+
3
+ Kconfig is the build-time configuration system ESP-IDF inherits from the Linux kernel. Options live in `Kconfig` files, are presented through `idf.py menuconfig`, and resolve to `CONFIG_*` macros visible in C/C++.
4
+
5
+ ## Where Kconfig files live
6
+
7
+ ESP-IDF automatically sources a `Kconfig` file from every registered component. The top-level `Kconfig.projbuild` is required and seeds the project menu. Conventions:
8
+
9
+ - `main/Kconfig` — app-level options. Always include `main "AMS7 Project Options"` style menus.
10
+ - `components/<name>/Kconfig` — component-private options; only visible if the component is included in the build.
11
+ - `Kconfig.projbuild` — root-level options that gate top-of-tree decisions.
12
+
13
+ `(AMS7)` AMS7 puts its entire menu under `main/Kconfig` (single file, ~430 lines), with the menu title `"AMS7 Project Options"`. Every project-defined option uses the `AMS7_*` prefix.
14
+
15
+ ## Adding a simple bool option
16
+
17
+ ```kconfig
18
+ menu "Connectivity Workflow"
19
+
20
+ config AMS7_SUMMARY_ENABLE
21
+ bool "Enable ESP-NOW summary workflow"
22
+ default n
23
+ help
24
+ Master switch for the recording workflow that starts with BLE
25
+ control and then switches to ESP-NOW summary mode after
26
+ acquisition begins. Keep disabled to preserve the BLE-only
27
+ workflow.
28
+
29
+ endmenu
30
+ ```
31
+
32
+ The `CONFIG_AMS7_SUMMARY_ENABLE` macro is then visible everywhere in C/C++:
33
+
34
+ ```cpp
35
+ #if CONFIG_AMS7_SUMMARY_ENABLE
36
+ init_espnow_summary();
37
+ #endif
38
+ ```
39
+
40
+ ## Types
41
+
42
+ | Type | C macro | Notes |
43
+ |-------------|--------------------------------------|----------------------------------------|
44
+ | `bool` | `CONFIG_FOO` (1 or undefined) | `default y` or `default n` |
45
+ | `int` | `CONFIG_FOO` (int literal) | `range MIN MAX` is recommended |
46
+ | `hex` | `CONFIG_FOO` (hex literal) | Useful for bitmasks and addresses |
47
+ | `string` | `CONFIG_FOO` (string literal) | `default "literal"` |
48
+ | `choice` | selects one of several values | Use for mutually-exclusive options |
49
+
50
+ ```kconfig
51
+ config AMS7_HR_HOLD_MS
52
+ int "Hold time for fused HR before fallback (ms)"
53
+ depends on AMS7_VITALS_ENABLE
54
+ range 0 60000
55
+ default 10000
56
+ help
57
+ How long to keep reporting fused HR after the fused pipeline
58
+ reports a confident beat, before falling back to the simple
59
+ backend. 0 disables the hold.
60
+ ```
61
+
62
+ In code:
63
+
64
+ ```cpp
65
+ #if CONFIG_AMS7_HR_HOLD_MS > 0
66
+ const TickType_t kHoldTicks = pdMS_TO_TICKS(CONFIG_AMS7_HR_HOLD_MS);
67
+ #endif
68
+ ```
69
+
70
+ `menuconfig` values are stored in `sdkconfig` as `CONFIG_<NAME>=<value>` lines. `idf.py menuconfig` is the editor.
71
+
72
+ ## Dependencies and implications
73
+
74
+ ```kconfig
75
+ config AMS7_BLE_VITALS_ENABLE
76
+ bool "Enable custom BLE vitals characteristic"
77
+ depends on AMS7_VITALS_ENABLE
78
+ default y
79
+ ```
80
+
81
+ - `depends on AMS7_VITALS_ENABLE` — option is **invisible** unless `AMS7_VITALS_ENABLE=y`. Selecting it auto-selects the dep.
82
+ - `select AMS7_ESPNOW_ENABLE` — when **this** option is enabled, force `AMS7_ESPNOW_ENABLE=y`.
83
+ - `imply AMS7_ESPNOW_LIVE_ECG_ENABLE` — when **this** option is enabled, set `AMS7_ESPNOW_LIVE_ECG_ENABLE=y` unless the user explicitly disabled it (softer than `select`).
84
+
85
+ `select` chains can cause cycles if used carelessly — prefer `depends on` for prerequisites.
86
+
87
+ ## Ranges
88
+
89
+ ```kconfig
90
+ config AMS7_ESPNOW_WIFI_CHANNEL
91
+ int "ESP-NOW Wi-Fi channel"
92
+ range 1 13
93
+ default 6
94
+ ```
95
+
96
+ The value is validated by menuconfig; `range` rejects out-of-range entries.
97
+
98
+ ## Choices
99
+
100
+ ```kconfig
101
+ choice AMS7_HR_BACKEND
102
+ prompt "Heart-rate backend"
103
+ default AMS7_HR_BACKEND_FUSED
104
+ depends on AMS7_VITALS_ENABLE
105
+
106
+ config AMS7_HR_BACKEND_SIMPLE
107
+ bool "Simple R-peak detector"
108
+
109
+ config AMS7_HR_BACKEND_FUSED
110
+ bool "Fused multi-source pipeline"
111
+
112
+ endchoice
113
+ ```
114
+
115
+ Only one of the listed `config`s can be `y` at a time. Use `# CONFIG_AMS7_HR_BACKEND_FUSED is not set` to switch.
116
+
117
+ ## Sourcing custom Kconfig files
118
+
119
+ In a component's top-level `Kconfig` (sourced automatically), include sub-files:
120
+
121
+ ```kconfig
122
+ mainmenu "My Component"
123
+
124
+ menu "Sensor Options"
125
+ source "Kconfig.sensor"
126
+ endmenu
127
+ ```
128
+
129
+ Or in `CMakeLists.txt`, register the file as part of the component:
130
+
131
+ ```cmake
132
+ idf_component_register(
133
+ ...
134
+ KCONFIG
135
+ "Kconfig"
136
+ )
137
+ ```
138
+
139
+ For project-wide overlays, create `sdkconfig.espnow_flow` (or similar) and pass `--sdkconfig` to `idf.py`. Layers are applied in order: defaults, then `sdkconfig`, then any `--sdkconfig` files.
140
+
141
+ ## Help text
142
+
143
+ Always include a `help` block. menuconfig shows it on the option's help line; the project documentation pulls it from `Kconfig` when generating reference. Keep it under ~10 lines.
144
+
145
+ ## AMS7 conventions (project-specific)
146
+
147
+ - Prefix every project-defined option with `AMS7_`. Never use `CONFIG_FOO` for an AMS7-introduced symbol.
148
+ - Group options by feature in `menu "..."` blocks. AMS7 groups: Connectivity Workflow, Vitals, ESP-NOW, Logging, etc.
149
+ - Default to `n` for any feature that increases IRAM/flash — acquisition builds are size-sensitive.
150
+ - For "trial debug" toggles, name them `*_TRIAL_DEBUG_LOG_ENABLE` and gate `ESP_LOG*` calls behind them — never compile trial-debug logs into release by default.
151
+ - Add a `help` block on every option. AMS7 reviewers check for missing help text.
152
+
153
+ ## Common pitfalls
154
+
155
+ - **Forgetting `default`.** menuconfig prompts for a value on first use; this is annoying. Always set a sensible default.
156
+ - **`select` cycle.** `A select B; B select A` causes menuconfig to error. Use `depends on` instead.
157
+ - **Component Kconfig included in disabled component.** If a component's Kconfig has options, that component must be discoverable. Check `EXTRA_COMPONENT_DIRS` in `CMakeLists.txt`.
158
+ - **Renaming an option without a migration.** Renaming `AMS7_X` to `AMS7_Y` leaves `sdkconfig` referring to the old name. `menuconfig` will silently drop the new option. Fix: add a `config AMS7_Y` with `default AMS7_X` then remove `AMS7_X`.
159
+ - **`range` on a `bool`.** Doesn't make sense — Kconfig will refuse. Use a `choice` instead.