@polderlabs/bizar 6.2.4 → 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 (332) 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 +31 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/sandbox.mjs +220 -0
  128. package/cli/commands/validate.mjs +252 -288
  129. package/cli/dev-link.test.mjs +11 -11
  130. package/cli/doctor.mjs +131 -213
  131. package/cli/install.mjs +33 -37
  132. package/cli/install.test.mjs +9 -9
  133. package/cli/provision-claude.mjs +893 -0
  134. package/cli/provision.mjs +330 -226
  135. package/cli/provision.test.mjs +102 -0
  136. package/cli/utils.mjs +72 -58
  137. package/config/AGENTS.md +28 -28
  138. package/config/agents/_shared/AGENT_BASELINE.md +104 -684
  139. package/config/skills/bizar/SKILL.md +197 -0
  140. package/config/skills/cubesandbox/SKILL.md +148 -0
  141. package/config/skills/harness-engineering/SKILL.md +142 -0
  142. package/install.sh +66 -44
  143. package/package.json +19 -11
  144. package/packages/sdk/ARCHITECTURE.md +40 -36
  145. package/packages/sdk/package-lock.json +32 -0
  146. package/packages/sdk/package.json +15 -5
  147. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  148. package/packages/sdk/src/fingerprint.ts +0 -0
  149. package/packages/sdk/src/index.ts +38 -73
  150. package/packages/sdk/src/mcp/bin.ts +51 -0
  151. package/packages/sdk/src/mcp/server.ts +498 -0
  152. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  153. package/packages/sdk/tests/sdk.test.mjs +148 -0
  154. package/packages/sdk/vitest.config.ts +1 -1
  155. package/scripts/bh-full-e2e.mjs +166 -363
  156. package/scripts/check-deps.mjs +28 -46
  157. package/scripts/mirror-claude-md.sh +78 -0
  158. package/scripts/test-in-container.sh +157 -0
  159. package/templates/clean-state-checklist.md +3 -3
  160. package/templates/sprint-contract.md +2 -2
  161. package/bizar-dash/.bizar/activity.log +0 -3
  162. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  163. package/bizar-dash/.omx/state/session.json +0 -10
  164. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  165. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  166. package/bizar-dash/bizar-design/canvas.html +0 -281
  167. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  168. package/bizar-dash/bizar-design/components.css +0 -1665
  169. package/bizar-dash/bizar-design/components.html +0 -557
  170. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  172. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  174. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  176. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  177. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  178. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  179. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  180. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  181. package/bizar-dash/bizar-design/icons.svg +0 -44
  182. package/bizar-dash/bizar-design/index.html +0 -192
  183. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  185. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  189. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  190. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  191. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  192. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  193. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  194. package/bizar-dash/bizar-design/prototype.js +0 -114
  195. package/bizar-dash/bizar-design/tokens.css +0 -106
  196. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  197. package/bizar-dash/node_modules/.package-lock.json +0 -6
  198. package/bizar-dash/package-lock.json +0 -6
  199. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  200. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  201. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  202. package/cli/commands/cline-cmd.mjs +0 -289
  203. package/cli/commands/validate.test.mjs +0 -344
  204. package/cli/doctor.test.mjs +0 -350
  205. package/config/cline.json.template +0 -342
  206. package/packages/sdk/src/client.ts +0 -188
  207. package/packages/sdk/src/cline-events.ts +0 -134
  208. package/packages/sdk/src/cline-types.ts +0 -66
  209. package/packages/sdk/src/cline.ts +0 -339
  210. package/packages/sdk/src/errors.ts +0 -129
  211. package/packages/sdk/src/events.ts +0 -153
  212. package/packages/sdk/src/types.ts +0 -176
  213. package/packages/sdk/tests/client.test.ts +0 -217
  214. package/packages/sdk/tests/errors.test.ts +0 -108
  215. package/packages/sdk/tests/events.test.ts +0 -139
  216. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  217. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  218. package/plugins/bizar/ARCHITECTURE.md +0 -142
  219. package/plugins/bizar/CONSTRAINTS.md +0 -67
  220. package/plugins/bizar/LICENSE +0 -21
  221. package/plugins/bizar/README.md +0 -448
  222. package/plugins/bizar/index.ts +0 -872
  223. package/plugins/bizar/package.json +0 -39
  224. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  225. package/plugins/bizar/src/background-state.ts +0 -641
  226. package/plugins/bizar/src/background.ts +0 -1806
  227. package/plugins/bizar/src/cline-runner.ts +0 -203
  228. package/plugins/bizar/src/clineruntime.ts +0 -227
  229. package/plugins/bizar/src/commands-impl.ts +0 -151
  230. package/plugins/bizar/src/commands.ts +0 -1799
  231. package/plugins/bizar/src/compaction.d.mts +0 -48
  232. package/plugins/bizar/src/compaction.mjs +0 -192
  233. package/plugins/bizar/src/dashboard-client.ts +0 -233
  234. package/plugins/bizar/src/event-stream.ts +0 -606
  235. package/plugins/bizar/src/fingerprint.ts +0 -120
  236. package/plugins/bizar/src/handoff.ts +0 -79
  237. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  238. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  239. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  240. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  241. package/plugins/bizar/src/http-client.ts +0 -467
  242. package/plugins/bizar/src/key-rotation.ts +0 -218
  243. package/plugins/bizar/src/logger.ts +0 -144
  244. package/plugins/bizar/src/loop-engineering.ts +0 -241
  245. package/plugins/bizar/src/loop.ts +0 -176
  246. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  247. package/plugins/bizar/src/odin.ts +0 -227
  248. package/plugins/bizar/src/options.ts +0 -470
  249. package/plugins/bizar/src/plan-fs.ts +0 -323
  250. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  251. package/plugins/bizar/src/report.ts +0 -178
  252. package/plugins/bizar/src/research-prompt.ts +0 -35
  253. package/plugins/bizar/src/serve-info.ts +0 -228
  254. package/plugins/bizar/src/serve.ts +0 -496
  255. package/plugins/bizar/src/settings.ts +0 -349
  256. package/plugins/bizar/src/state.ts +0 -298
  257. package/plugins/bizar/src/tool-discipline.ts +0 -105
  258. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  259. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  260. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  261. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  262. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  263. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  264. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  265. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  266. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  267. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  268. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  269. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  270. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  271. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  272. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  273. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  274. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  275. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  276. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  277. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  278. package/plugins/bizar/src/tools/team-status.ts +0 -76
  279. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  280. package/plugins/bizar/src/trajectory.ts +0 -104
  281. package/plugins/bizar/tests/README.md +0 -99
  282. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  283. package/plugins/bizar/tests/background-state.test.ts +0 -277
  284. package/plugins/bizar/tests/background.test.ts +0 -402
  285. package/plugins/bizar/tests/block.test.ts +0 -195
  286. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  287. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  288. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  289. package/plugins/bizar/tests/commands.test.ts +0 -584
  290. package/plugins/bizar/tests/compaction.test.ts +0 -264
  291. package/plugins/bizar/tests/config.test.ts +0 -128
  292. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  293. package/plugins/bizar/tests/dispose.test.ts +0 -336
  294. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  295. package/plugins/bizar/tests/event.test.ts +0 -262
  296. package/plugins/bizar/tests/fingerprint.test.ts +0 -162
  297. package/plugins/bizar/tests/http-client.test.ts +0 -404
  298. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  299. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  300. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  301. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  302. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  303. package/plugins/bizar/tests/loop.test.ts +0 -397
  304. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  305. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  306. package/plugins/bizar/tests/odin.test.ts +0 -125
  307. package/plugins/bizar/tests/options.test.ts +0 -329
  308. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  309. package/plugins/bizar/tests/safety.test.ts +0 -256
  310. package/plugins/bizar/tests/serve.test.ts +0 -339
  311. package/plugins/bizar/tests/settings.test.ts +0 -351
  312. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  313. package/plugins/bizar/tests/state.test.ts +0 -276
  314. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  315. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  316. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  317. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  318. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  319. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  320. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  321. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  322. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  323. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  324. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  325. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  326. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  327. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  328. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  329. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  330. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  331. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  332. package/plugins/bizar/tsconfig.json +0 -29
@@ -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.