@trac3r/oh-my-god 2.2.11

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 (638) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/INSTALL-VERIFICATION-INDEX.md +51 -0
  3. package/LICENSE +21 -0
  4. package/OMG-setup.sh +2549 -0
  5. package/QUICK-REFERENCE.md +58 -0
  6. package/README.md +207 -0
  7. package/agents/__init__.py +1 -0
  8. package/agents/__pycache__/model_roles.cpython-313.pyc +0 -0
  9. package/agents/_model_roles.yaml +26 -0
  10. package/agents/designer.md +67 -0
  11. package/agents/explore.md +60 -0
  12. package/agents/model_roles.py +196 -0
  13. package/agents/omg-api-builder.md +23 -0
  14. package/agents/omg-architect-mode.md +41 -0
  15. package/agents/omg-architect.md +13 -0
  16. package/agents/omg-backend-engineer.md +41 -0
  17. package/agents/omg-critic.md +16 -0
  18. package/agents/omg-database-engineer.md +41 -0
  19. package/agents/omg-escalation-router.md +17 -0
  20. package/agents/omg-executor.md +12 -0
  21. package/agents/omg-frontend-designer.md +41 -0
  22. package/agents/omg-implement-mode.md +49 -0
  23. package/agents/omg-infra-engineer.md +41 -0
  24. package/agents/omg-qa-tester.md +16 -0
  25. package/agents/omg-research-mode.md +41 -0
  26. package/agents/omg-security-auditor.md +41 -0
  27. package/agents/omg-testing-engineer.md +41 -0
  28. package/agents/plan.md +80 -0
  29. package/agents/quick_task.md +64 -0
  30. package/agents/reviewer.md +83 -0
  31. package/agents/task.md +71 -0
  32. package/bin/omg +41 -0
  33. package/commands/OMG:ai-commit.md +113 -0
  34. package/commands/OMG:api-twin.md +22 -0
  35. package/commands/OMG:arch.md +313 -0
  36. package/commands/OMG:browser.md +29 -0
  37. package/commands/OMG:ccg.md +22 -0
  38. package/commands/OMG:compat.md +57 -0
  39. package/commands/OMG:cost.md +181 -0
  40. package/commands/OMG:crazy.md +125 -0
  41. package/commands/OMG:create-agent.md +183 -0
  42. package/commands/OMG:deep-plan.md +18 -0
  43. package/commands/OMG:deps.md +248 -0
  44. package/commands/OMG:diagnose-plugins.md +33 -0
  45. package/commands/OMG:doctor.md +37 -0
  46. package/commands/OMG:domain-init.md +11 -0
  47. package/commands/OMG:escalate.md +52 -0
  48. package/commands/OMG:forge.md +103 -0
  49. package/commands/OMG:health-check.md +48 -0
  50. package/commands/OMG:init.md +134 -0
  51. package/commands/OMG:issue.md +56 -0
  52. package/commands/OMG:mode.md +44 -0
  53. package/commands/OMG:playwright.md +17 -0
  54. package/commands/OMG:preflight.md +26 -0
  55. package/commands/OMG:preset.md +49 -0
  56. package/commands/OMG:profile-review.md +58 -0
  57. package/commands/OMG:project-init.md +11 -0
  58. package/commands/OMG:ralph-start.md +43 -0
  59. package/commands/OMG:ralph-stop.md +23 -0
  60. package/commands/OMG:security-check.md +28 -0
  61. package/commands/OMG:session-branch.md +101 -0
  62. package/commands/OMG:session-fork.md +57 -0
  63. package/commands/OMG:session-merge.md +138 -0
  64. package/commands/OMG:setup.md +82 -0
  65. package/commands/OMG:ship.md +18 -0
  66. package/commands/OMG:stats.md +225 -0
  67. package/commands/OMG:teams.md +54 -0
  68. package/commands/OMG:theme.md +44 -0
  69. package/commands/OMG:validate.md +59 -0
  70. package/commands/__init__.py +1 -0
  71. package/docs/command-surface.md +55 -0
  72. package/docs/install/claude-code.md +53 -0
  73. package/docs/install/codex.md +45 -0
  74. package/docs/install/gemini.md +43 -0
  75. package/docs/install/github-action.md +81 -0
  76. package/docs/install/github-app-required-checks.md +107 -0
  77. package/docs/install/github-app.md +161 -0
  78. package/docs/install/kimi.md +43 -0
  79. package/docs/install/opencode.md +38 -0
  80. package/docs/proof.md +182 -0
  81. package/hooks/__init__.py +0 -0
  82. package/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  83. package/hooks/__pycache__/_agent_registry.cpython-313.pyc +0 -0
  84. package/hooks/__pycache__/_analytics.cpython-313.pyc +0 -0
  85. package/hooks/__pycache__/_budget.cpython-313.pyc +0 -0
  86. package/hooks/__pycache__/_common.cpython-313.pyc +0 -0
  87. package/hooks/__pycache__/_compression_optimizer.cpython-313.pyc +0 -0
  88. package/hooks/__pycache__/_cost_ledger.cpython-313.pyc +0 -0
  89. package/hooks/__pycache__/_learnings.cpython-313.pyc +0 -0
  90. package/hooks/__pycache__/_memory.cpython-313.pyc +0 -0
  91. package/hooks/__pycache__/_post_write.cpython-313.pyc +0 -0
  92. package/hooks/__pycache__/_protected_context.cpython-313.pyc +0 -0
  93. package/hooks/__pycache__/_token_counter.cpython-313.pyc +0 -0
  94. package/hooks/__pycache__/branch_manager.cpython-313.pyc +0 -0
  95. package/hooks/__pycache__/budget_governor.cpython-313.pyc +0 -0
  96. package/hooks/__pycache__/circuit-breaker.cpython-313.pyc +0 -0
  97. package/hooks/__pycache__/compression_feedback.cpython-313.pyc +0 -0
  98. package/hooks/__pycache__/config-guard.cpython-313.pyc +0 -0
  99. package/hooks/__pycache__/context_pressure.cpython-313.pyc +0 -0
  100. package/hooks/__pycache__/credential_store.cpython-313.pyc +0 -0
  101. package/hooks/__pycache__/fetch-rate-limits.cpython-313.pyc +0 -0
  102. package/hooks/__pycache__/firewall.cpython-313.pyc +0 -0
  103. package/hooks/__pycache__/hashline-formatter-bridge.cpython-313.pyc +0 -0
  104. package/hooks/__pycache__/hashline-injector.cpython-313.pyc +0 -0
  105. package/hooks/__pycache__/hashline-validator.cpython-313.pyc +0 -0
  106. package/hooks/__pycache__/idle-detector.cpython-313.pyc +0 -0
  107. package/hooks/__pycache__/instructions-loaded.cpython-313.pyc +0 -0
  108. package/hooks/__pycache__/intentgate-keyword-detector.cpython-313.pyc +0 -0
  109. package/hooks/__pycache__/magic-keyword-router.cpython-313.pyc +0 -0
  110. package/hooks/__pycache__/policy_engine.cpython-313.pyc +0 -0
  111. package/hooks/__pycache__/post-tool-failure.cpython-313.pyc +0 -0
  112. package/hooks/__pycache__/post-write.cpython-313.pyc +0 -0
  113. package/hooks/__pycache__/post_write.cpython-313.pyc +0 -0
  114. package/hooks/__pycache__/pre-compact.cpython-313.pyc +0 -0
  115. package/hooks/__pycache__/pre-tool-inject.cpython-313.pyc +0 -0
  116. package/hooks/__pycache__/prompt-enhancer.cpython-313.pyc +0 -0
  117. package/hooks/__pycache__/quality-runner.cpython-313.pyc +0 -0
  118. package/hooks/__pycache__/query.cpython-313.pyc +0 -0
  119. package/hooks/__pycache__/secret-guard.cpython-313.pyc +0 -0
  120. package/hooks/__pycache__/secret_audit.cpython-313.pyc +0 -0
  121. package/hooks/__pycache__/security_validators.cpython-313.pyc +0 -0
  122. package/hooks/__pycache__/session-end-capture.cpython-313.pyc +0 -0
  123. package/hooks/__pycache__/session-start.cpython-313.pyc +0 -0
  124. package/hooks/__pycache__/setup_wizard.cpython-313.pyc +0 -0
  125. package/hooks/__pycache__/shadow_manager.cpython-313.pyc +0 -0
  126. package/hooks/__pycache__/state_migration.cpython-313.pyc +0 -0
  127. package/hooks/__pycache__/stop-gate.cpython-313.pyc +0 -0
  128. package/hooks/__pycache__/stop_dispatcher.cpython-313.pyc +0 -0
  129. package/hooks/__pycache__/tdd-gate.cpython-313.pyc +0 -0
  130. package/hooks/__pycache__/terms-guard.cpython-313.pyc +0 -0
  131. package/hooks/__pycache__/test-validator.cpython-313.pyc +0 -0
  132. package/hooks/__pycache__/test_generator_hook.cpython-313.pyc +0 -0
  133. package/hooks/__pycache__/todo-state-tracker.cpython-313.pyc +0 -0
  134. package/hooks/__pycache__/tool-ledger.cpython-313.pyc +0 -0
  135. package/hooks/__pycache__/trust_review.cpython-313.pyc +0 -0
  136. package/hooks/__pycache__/user-prompt-submit.cpython-313.pyc +0 -0
  137. package/hooks/_agent_registry.py +481 -0
  138. package/hooks/_analytics.py +291 -0
  139. package/hooks/_budget.py +31 -0
  140. package/hooks/_common.py +761 -0
  141. package/hooks/_compression_optimizer.py +119 -0
  142. package/hooks/_cost_ledger.py +176 -0
  143. package/hooks/_learnings.py +126 -0
  144. package/hooks/_memory.py +103 -0
  145. package/hooks/_post_write.py +46 -0
  146. package/hooks/_protected_context.py +150 -0
  147. package/hooks/_token_counter.py +221 -0
  148. package/hooks/branch_manager.py +255 -0
  149. package/hooks/budget_governor.py +326 -0
  150. package/hooks/circuit-breaker.py +270 -0
  151. package/hooks/compression_feedback.py +254 -0
  152. package/hooks/config-guard.py +193 -0
  153. package/hooks/context_pressure.py +119 -0
  154. package/hooks/credential_store.py +970 -0
  155. package/hooks/fetch-rate-limits.py +212 -0
  156. package/hooks/firewall.py +323 -0
  157. package/hooks/hashline-formatter-bridge.py +224 -0
  158. package/hooks/hashline-injector.py +273 -0
  159. package/hooks/hashline-validator.py +216 -0
  160. package/hooks/idle-detector.py +97 -0
  161. package/hooks/instructions-loaded.py +26 -0
  162. package/hooks/intentgate-keyword-detector.py +200 -0
  163. package/hooks/magic-keyword-router.py +195 -0
  164. package/hooks/policy_engine.py +767 -0
  165. package/hooks/post-tool-failure.py +19 -0
  166. package/hooks/post-write.py +233 -0
  167. package/hooks/pre-compact.py +470 -0
  168. package/hooks/pre-tool-inject.py +98 -0
  169. package/hooks/prompt-enhancer.py +879 -0
  170. package/hooks/quality-runner.py +191 -0
  171. package/hooks/query.py +512 -0
  172. package/hooks/secret-guard.py +120 -0
  173. package/hooks/secret_audit.py +144 -0
  174. package/hooks/security_validators.py +93 -0
  175. package/hooks/session-end-capture.py +505 -0
  176. package/hooks/session-start.py +261 -0
  177. package/hooks/setup_wizard.py +1101 -0
  178. package/hooks/shadow_manager.py +476 -0
  179. package/hooks/state_migration.py +228 -0
  180. package/hooks/stop-gate.py +7 -0
  181. package/hooks/stop_dispatcher.py +1259 -0
  182. package/hooks/tdd-gate.py +10 -0
  183. package/hooks/terms-guard.py +98 -0
  184. package/hooks/test-validator.py +462 -0
  185. package/hooks/test_generator_hook.py +123 -0
  186. package/hooks/todo-state-tracker.py +114 -0
  187. package/hooks/tool-ledger.py +165 -0
  188. package/hooks/trust_review.py +662 -0
  189. package/hooks/user-prompt-submit.py +12 -0
  190. package/hud/omg-hud.mjs +1571 -0
  191. package/lab/__init__.py +1 -0
  192. package/lab/__pycache__/__init__.cpython-313.pyc +0 -0
  193. package/lab/__pycache__/axolotl_adapter.cpython-313.pyc +0 -0
  194. package/lab/__pycache__/forge_runner.cpython-313.pyc +0 -0
  195. package/lab/__pycache__/gazebo_adapter.cpython-313.pyc +0 -0
  196. package/lab/__pycache__/isaac_gym_adapter.cpython-313.pyc +0 -0
  197. package/lab/__pycache__/mock_isaac_env.cpython-313.pyc +0 -0
  198. package/lab/__pycache__/pipeline.cpython-313.pyc +0 -0
  199. package/lab/__pycache__/policies.cpython-313.pyc +0 -0
  200. package/lab/__pycache__/pybullet_adapter.cpython-313.pyc +0 -0
  201. package/lab/axolotl_adapter.py +531 -0
  202. package/lab/forge_runner.py +103 -0
  203. package/lab/gazebo_adapter.py +168 -0
  204. package/lab/isaac_gym_adapter.py +190 -0
  205. package/lab/mock_isaac_env.py +47 -0
  206. package/lab/pipeline.py +712 -0
  207. package/lab/policies.py +52 -0
  208. package/lab/pybullet_adapter.py +192 -0
  209. package/package.json +61 -0
  210. package/plugins/README.md +78 -0
  211. package/plugins/__init__.py +1 -0
  212. package/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
  213. package/plugins/advanced/commands/OMG-code-review.md +114 -0
  214. package/plugins/advanced/commands/OMG-deep-plan.md +266 -0
  215. package/plugins/advanced/commands/OMG-handoff.md +115 -0
  216. package/plugins/advanced/commands/OMG-learn.md +110 -0
  217. package/plugins/advanced/commands/OMG-maintainer.md +31 -0
  218. package/plugins/advanced/commands/OMG-ralph-start.md +43 -0
  219. package/plugins/advanced/commands/OMG-ralph-stop.md +23 -0
  220. package/plugins/advanced/commands/OMG-security-review.md +16 -0
  221. package/plugins/advanced/commands/OMG-sequential-thinking.md +20 -0
  222. package/plugins/advanced/commands/OMG-ship.md +46 -0
  223. package/plugins/advanced/commands/OMG:code-review.md +114 -0
  224. package/plugins/advanced/commands/OMG:deep-plan.md +266 -0
  225. package/plugins/advanced/commands/OMG:handoff.md +115 -0
  226. package/plugins/advanced/commands/OMG:learn.md +110 -0
  227. package/plugins/advanced/commands/OMG:maintainer.md +31 -0
  228. package/plugins/advanced/commands/OMG:ralph-start.md +43 -0
  229. package/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
  230. package/plugins/advanced/commands/OMG:security-review.md +16 -0
  231. package/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
  232. package/plugins/advanced/commands/OMG:ship.md +46 -0
  233. package/plugins/advanced/plugin.json +104 -0
  234. package/plugins/core/plugin.json +204 -0
  235. package/plugins/dephealth/__init__.py +0 -0
  236. package/plugins/dephealth/__pycache__/__init__.cpython-313.pyc +0 -0
  237. package/plugins/dephealth/__pycache__/cve_scanner.cpython-313.pyc +0 -0
  238. package/plugins/dephealth/__pycache__/license_checker.cpython-313.pyc +0 -0
  239. package/plugins/dephealth/__pycache__/manifest_detector.cpython-313.pyc +0 -0
  240. package/plugins/dephealth/__pycache__/vuln_analyzer.cpython-313.pyc +0 -0
  241. package/plugins/dephealth/cve_scanner.py +279 -0
  242. package/plugins/dephealth/license_checker.py +135 -0
  243. package/plugins/dephealth/manifest_detector.py +423 -0
  244. package/plugins/dephealth/vuln_analyzer.py +176 -0
  245. package/plugins/testgen/__init__.py +0 -0
  246. package/plugins/testgen/__pycache__/__init__.cpython-313.pyc +0 -0
  247. package/plugins/testgen/__pycache__/codamosa_engine.cpython-313.pyc +0 -0
  248. package/plugins/testgen/__pycache__/edge_case_synthesizer.cpython-313.pyc +0 -0
  249. package/plugins/testgen/__pycache__/framework_detector.cpython-313.pyc +0 -0
  250. package/plugins/testgen/__pycache__/skeleton_generator.cpython-313.pyc +0 -0
  251. package/plugins/testgen/codamosa_engine.py +402 -0
  252. package/plugins/testgen/edge_case_synthesizer.py +184 -0
  253. package/plugins/testgen/framework_detector.py +271 -0
  254. package/plugins/testgen/skeleton_generator.py +219 -0
  255. package/plugins/viz/__init__.py +0 -0
  256. package/plugins/viz/__pycache__/__init__.cpython-313.pyc +0 -0
  257. package/plugins/viz/__pycache__/ast_parser.cpython-313.pyc +0 -0
  258. package/plugins/viz/__pycache__/diagram_generator.cpython-313.pyc +0 -0
  259. package/plugins/viz/__pycache__/graph_builder.cpython-313.pyc +0 -0
  260. package/plugins/viz/__pycache__/native_parsers.cpython-313.pyc +0 -0
  261. package/plugins/viz/__pycache__/regex_parser.cpython-313.pyc +0 -0
  262. package/plugins/viz/ast_parser.py +139 -0
  263. package/plugins/viz/diagram_generator.py +192 -0
  264. package/plugins/viz/graph_builder.py +444 -0
  265. package/plugins/viz/native_parsers.py +259 -0
  266. package/plugins/viz/regex_parser.py +112 -0
  267. package/pyproject.toml +143 -0
  268. package/registry/__init__.py +1 -0
  269. package/registry/__pycache__/__init__.cpython-313.pyc +0 -0
  270. package/registry/__pycache__/approval_artifact.cpython-313.pyc +0 -0
  271. package/registry/__pycache__/verify_artifact.cpython-313.pyc +0 -0
  272. package/registry/approval_artifact.py +236 -0
  273. package/registry/bundles/algorithms.yaml +45 -0
  274. package/registry/bundles/api-twin.yaml +48 -0
  275. package/registry/bundles/ast-pack.yaml +80 -0
  276. package/registry/bundles/claim-judge.yaml +49 -0
  277. package/registry/bundles/control-plane.yaml +192 -0
  278. package/registry/bundles/data-lineage.yaml +47 -0
  279. package/registry/bundles/delta-classifier.yaml +47 -0
  280. package/registry/bundles/eval-gate.yaml +47 -0
  281. package/registry/bundles/hash-edit.yaml +73 -0
  282. package/registry/bundles/health.yaml +45 -0
  283. package/registry/bundles/hook-governor.yaml +101 -0
  284. package/registry/bundles/incident-replay.yaml +47 -0
  285. package/registry/bundles/lsp-pack.yaml +80 -0
  286. package/registry/bundles/mcp-fabric.yaml +53 -0
  287. package/registry/bundles/plan-council.yaml +56 -0
  288. package/registry/bundles/preflight.yaml +48 -0
  289. package/registry/bundles/proof-gate.yaml +49 -0
  290. package/registry/bundles/remote-supervisor.yaml +49 -0
  291. package/registry/bundles/robotics.yaml +45 -0
  292. package/registry/bundles/secure-worktree-pipeline.yaml +69 -0
  293. package/registry/bundles/security-check.yaml +50 -0
  294. package/registry/bundles/terminal-lane.yaml +61 -0
  295. package/registry/bundles/test-intent-lock.yaml +49 -0
  296. package/registry/bundles/tracebank.yaml +47 -0
  297. package/registry/bundles/vision.yaml +45 -0
  298. package/registry/omg-capability.schema.json +378 -0
  299. package/registry/policy-packs/airgapped.lock.json +11 -0
  300. package/registry/policy-packs/airgapped.signature.json +10 -0
  301. package/registry/policy-packs/airgapped.yaml +16 -0
  302. package/registry/policy-packs/fintech.lock.json +11 -0
  303. package/registry/policy-packs/fintech.signature.json +10 -0
  304. package/registry/policy-packs/fintech.yaml +15 -0
  305. package/registry/policy-packs/locked-prod.lock.json +11 -0
  306. package/registry/policy-packs/locked-prod.signature.json +10 -0
  307. package/registry/policy-packs/locked-prod.yaml +18 -0
  308. package/registry/trusted_signers.json +44 -0
  309. package/registry/verify_artifact.py +493 -0
  310. package/runtime/__init__.py +36 -0
  311. package/runtime/__pycache__/__init__.cpython-313.pyc +0 -0
  312. package/runtime/__pycache__/adoption.cpython-313.pyc +0 -0
  313. package/runtime/__pycache__/agent_selector.cpython-313.pyc +0 -0
  314. package/runtime/__pycache__/api_twin.cpython-313.pyc +0 -0
  315. package/runtime/__pycache__/architecture_signal.cpython-313.pyc +0 -0
  316. package/runtime/__pycache__/artifact_parsers.cpython-313.pyc +0 -0
  317. package/runtime/__pycache__/asset_loader.cpython-313.pyc +0 -0
  318. package/runtime/__pycache__/background_verification.cpython-313.pyc +0 -0
  319. package/runtime/__pycache__/budget_envelopes.cpython-313.pyc +0 -0
  320. package/runtime/__pycache__/business_workflow.cpython-313.pyc +0 -0
  321. package/runtime/__pycache__/canonical_surface.cpython-313.pyc +0 -0
  322. package/runtime/__pycache__/canonical_taxonomy.cpython-313.pyc +0 -0
  323. package/runtime/__pycache__/claim_judge.cpython-313.pyc +0 -0
  324. package/runtime/__pycache__/cli_provider.cpython-313.pyc +0 -0
  325. package/runtime/__pycache__/compat.cpython-313.pyc +0 -0
  326. package/runtime/__pycache__/complexity_scorer.cpython-313.pyc +0 -0
  327. package/runtime/__pycache__/compliance_governor.cpython-313.pyc +0 -0
  328. package/runtime/__pycache__/config_transaction.cpython-313.pyc +0 -0
  329. package/runtime/__pycache__/context_compiler.cpython-313.pyc +0 -0
  330. package/runtime/__pycache__/context_engine.cpython-313.pyc +0 -0
  331. package/runtime/__pycache__/context_limits.cpython-313.pyc +0 -0
  332. package/runtime/__pycache__/contract_compiler.cpython-313.pyc +0 -0
  333. package/runtime/__pycache__/custom_agent_loader.cpython-313.pyc +0 -0
  334. package/runtime/__pycache__/data_lineage.cpython-313.pyc +0 -0
  335. package/runtime/__pycache__/defense_state.cpython-313.pyc +0 -0
  336. package/runtime/__pycache__/delta_classifier.cpython-313.pyc +0 -0
  337. package/runtime/__pycache__/dispatcher.cpython-313.pyc +0 -0
  338. package/runtime/__pycache__/doc_generator.cpython-313.pyc +0 -0
  339. package/runtime/__pycache__/domain_packs.cpython-313.pyc +0 -0
  340. package/runtime/__pycache__/ecosystem.cpython-313.pyc +0 -0
  341. package/runtime/__pycache__/equalizer.cpython-313.pyc +0 -0
  342. package/runtime/__pycache__/eval_gate.cpython-313.pyc +0 -0
  343. package/runtime/__pycache__/evidence_narrator.cpython-313.pyc +0 -0
  344. package/runtime/__pycache__/evidence_query.cpython-313.pyc +0 -0
  345. package/runtime/__pycache__/evidence_registry.cpython-313.pyc +0 -0
  346. package/runtime/__pycache__/evidence_requirements.cpython-313.pyc +0 -0
  347. package/runtime/__pycache__/exec_kernel.cpython-313.pyc +0 -0
  348. package/runtime/__pycache__/explainer_formatter.cpython-313.pyc +0 -0
  349. package/runtime/__pycache__/feature_registry.cpython-313.pyc +0 -0
  350. package/runtime/__pycache__/forge_agents.cpython-313.pyc +0 -0
  351. package/runtime/__pycache__/forge_contracts.cpython-313.pyc +0 -0
  352. package/runtime/__pycache__/forge_domains.cpython-313.pyc +0 -0
  353. package/runtime/__pycache__/forge_run_id.cpython-313.pyc +0 -0
  354. package/runtime/__pycache__/github_integration.cpython-313.pyc +0 -0
  355. package/runtime/__pycache__/github_review_bot.cpython-313.pyc +0 -0
  356. package/runtime/__pycache__/github_review_contract.cpython-313.pyc +0 -0
  357. package/runtime/__pycache__/github_review_formatter.cpython-313.pyc +0 -0
  358. package/runtime/__pycache__/guide_assert.cpython-313.pyc +0 -0
  359. package/runtime/__pycache__/hook_governor.cpython-313.pyc +0 -0
  360. package/runtime/__pycache__/host_parity.cpython-313.pyc +0 -0
  361. package/runtime/__pycache__/incident_replay.cpython-313.pyc +0 -0
  362. package/runtime/__pycache__/install_planner.cpython-313.pyc +0 -0
  363. package/runtime/__pycache__/interaction_journal.cpython-313.pyc +0 -0
  364. package/runtime/__pycache__/issue_surface.cpython-313.pyc +0 -0
  365. package/runtime/__pycache__/legacy_compat.cpython-313.pyc +0 -0
  366. package/runtime/__pycache__/mcp_config_writers.cpython-313.pyc +0 -0
  367. package/runtime/__pycache__/mcp_lifecycle.cpython-313.pyc +0 -0
  368. package/runtime/__pycache__/mcp_memory_server.cpython-313.pyc +0 -0
  369. package/runtime/__pycache__/memory_store.cpython-313.pyc +0 -0
  370. package/runtime/__pycache__/merge_writer.cpython-313.pyc +0 -0
  371. package/runtime/__pycache__/music_omr_testbed.cpython-313.pyc +0 -0
  372. package/runtime/__pycache__/mutation_gate.cpython-313.pyc +0 -0
  373. package/runtime/__pycache__/omc_compat.cpython-313.pyc +0 -0
  374. package/runtime/__pycache__/omg_browser_cli.cpython-313.pyc +0 -0
  375. package/runtime/__pycache__/omg_mcp_server.cpython-313.pyc +0 -0
  376. package/runtime/__pycache__/opus_plan.cpython-313.pyc +0 -0
  377. package/runtime/__pycache__/playwright_adapter.cpython-313.pyc +0 -0
  378. package/runtime/__pycache__/playwright_pack.cpython-313.pyc +0 -0
  379. package/runtime/__pycache__/plugin_diagnostics.cpython-313.pyc +0 -0
  380. package/runtime/__pycache__/plugin_interop.cpython-313.pyc +0 -0
  381. package/runtime/__pycache__/policy_pack_loader.cpython-313.pyc +0 -0
  382. package/runtime/__pycache__/preflight.cpython-313.pyc +0 -0
  383. package/runtime/__pycache__/profile_io.cpython-313.pyc +0 -0
  384. package/runtime/__pycache__/prompt_compiler.cpython-313.pyc +0 -0
  385. package/runtime/__pycache__/proof_chain.cpython-313.pyc +0 -0
  386. package/runtime/__pycache__/proof_gate.cpython-313.pyc +0 -0
  387. package/runtime/__pycache__/provider_parity_eval.cpython-313.pyc +0 -0
  388. package/runtime/__pycache__/release_artifact_audit.cpython-313.pyc +0 -0
  389. package/runtime/__pycache__/release_run_coordinator.cpython-313.pyc +0 -0
  390. package/runtime/__pycache__/release_surface_compiler.cpython-313.pyc +0 -0
  391. package/runtime/__pycache__/release_surface_registry.cpython-313.pyc +0 -0
  392. package/runtime/__pycache__/release_surfaces.cpython-313.pyc +0 -0
  393. package/runtime/__pycache__/remote_supervisor.cpython-313.pyc +0 -0
  394. package/runtime/__pycache__/repro_pack.cpython-313.pyc +0 -0
  395. package/runtime/__pycache__/rollback_manifest.cpython-313.pyc +0 -0
  396. package/runtime/__pycache__/router_critics.cpython-313.pyc +0 -0
  397. package/runtime/__pycache__/router_executor.cpython-313.pyc +0 -0
  398. package/runtime/__pycache__/router_selector.cpython-313.pyc +0 -0
  399. package/runtime/__pycache__/runtime_contracts.cpython-313.pyc +0 -0
  400. package/runtime/__pycache__/runtime_profile.cpython-313.pyc +0 -0
  401. package/runtime/__pycache__/security_check.cpython-313.pyc +0 -0
  402. package/runtime/__pycache__/session_health.cpython-313.pyc +0 -0
  403. package/runtime/__pycache__/skill_evolution.cpython-313.pyc +0 -0
  404. package/runtime/__pycache__/skill_registry.cpython-313.pyc +0 -0
  405. package/runtime/__pycache__/subagent_dispatcher.cpython-313.pyc +0 -0
  406. package/runtime/__pycache__/subscription_tiers.cpython-313.pyc +0 -0
  407. package/runtime/__pycache__/team_router.cpython-313.pyc +0 -0
  408. package/runtime/__pycache__/test_intent_lock.cpython-313-pytest-9.0.2.pyc +0 -0
  409. package/runtime/__pycache__/test_intent_lock.cpython-313.pyc +0 -0
  410. package/runtime/__pycache__/tmux_session_manager.cpython-313.pyc +0 -0
  411. package/runtime/__pycache__/tool_fabric.cpython-313.pyc +0 -0
  412. package/runtime/__pycache__/tool_plan_gate.cpython-313.pyc +0 -0
  413. package/runtime/__pycache__/tool_relevance.cpython-313.pyc +0 -0
  414. package/runtime/__pycache__/tracebank.cpython-313.pyc +0 -0
  415. package/runtime/__pycache__/untrusted_content.cpython-313.pyc +0 -0
  416. package/runtime/__pycache__/validate.cpython-313.pyc +0 -0
  417. package/runtime/__pycache__/verdict_schema.cpython-313.pyc +0 -0
  418. package/runtime/__pycache__/verification_controller.cpython-313.pyc +0 -0
  419. package/runtime/__pycache__/verification_loop.cpython-313.pyc +0 -0
  420. package/runtime/__pycache__/vision_artifacts.cpython-313.pyc +0 -0
  421. package/runtime/__pycache__/vision_cache.cpython-313.pyc +0 -0
  422. package/runtime/__pycache__/vision_jobs.cpython-313.pyc +0 -0
  423. package/runtime/__pycache__/worker_watchdog.cpython-313.pyc +0 -0
  424. package/runtime/adapters/__init__.py +13 -0
  425. package/runtime/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
  426. package/runtime/adapters/__pycache__/claude.cpython-313.pyc +0 -0
  427. package/runtime/adapters/__pycache__/gpt.cpython-313.pyc +0 -0
  428. package/runtime/adapters/__pycache__/local.cpython-313.pyc +0 -0
  429. package/runtime/adapters/claude.py +63 -0
  430. package/runtime/adapters/gpt.py +56 -0
  431. package/runtime/adapters/local.py +56 -0
  432. package/runtime/adoption.py +280 -0
  433. package/runtime/api_twin.py +450 -0
  434. package/runtime/architecture_signal.py +226 -0
  435. package/runtime/artifact_parsers.py +161 -0
  436. package/runtime/asset_loader.py +62 -0
  437. package/runtime/background_verification.py +178 -0
  438. package/runtime/budget_envelopes.py +398 -0
  439. package/runtime/business_workflow.py +234 -0
  440. package/runtime/canonical_surface.py +53 -0
  441. package/runtime/canonical_taxonomy.py +27 -0
  442. package/runtime/claim_judge.py +648 -0
  443. package/runtime/cli_provider.py +105 -0
  444. package/runtime/compat.py +2222 -0
  445. package/runtime/complexity_scorer.py +148 -0
  446. package/runtime/compliance_governor.py +505 -0
  447. package/runtime/config_transaction.py +304 -0
  448. package/runtime/context_compiler.py +131 -0
  449. package/runtime/context_engine.py +708 -0
  450. package/runtime/context_limits.py +363 -0
  451. package/runtime/contract_compiler.py +3664 -0
  452. package/runtime/custom_agent_loader.py +366 -0
  453. package/runtime/data_lineage.py +244 -0
  454. package/runtime/defense_state.py +261 -0
  455. package/runtime/delta_classifier.py +231 -0
  456. package/runtime/dispatcher.py +47 -0
  457. package/runtime/doc_generator.py +319 -0
  458. package/runtime/domain_packs.py +75 -0
  459. package/runtime/ecosystem.py +371 -0
  460. package/runtime/equalizer.py +268 -0
  461. package/runtime/eval_gate.py +96 -0
  462. package/runtime/evidence_narrator.py +147 -0
  463. package/runtime/evidence_query.py +303 -0
  464. package/runtime/evidence_registry.py +16 -0
  465. package/runtime/evidence_requirements.py +157 -0
  466. package/runtime/exec_kernel.py +267 -0
  467. package/runtime/explainer_formatter.py +82 -0
  468. package/runtime/feature_registry.py +109 -0
  469. package/runtime/forge_agents.py +915 -0
  470. package/runtime/forge_contracts.py +519 -0
  471. package/runtime/forge_domains.py +68 -0
  472. package/runtime/forge_run_id.py +86 -0
  473. package/runtime/guide_assert.py +135 -0
  474. package/runtime/hook_governor.py +156 -0
  475. package/runtime/host_parity.py +373 -0
  476. package/runtime/incident_replay.py +310 -0
  477. package/runtime/install_planner.py +617 -0
  478. package/runtime/interaction_journal.py +566 -0
  479. package/runtime/issue_surface.py +472 -0
  480. package/runtime/legacy_compat.py +7 -0
  481. package/runtime/mcp_config_writers.py +360 -0
  482. package/runtime/mcp_lifecycle.py +175 -0
  483. package/runtime/mcp_memory_server.py +220 -0
  484. package/runtime/memory_parsers/__init__.py +0 -0
  485. package/runtime/memory_parsers/__pycache__/__init__.cpython-313.pyc +0 -0
  486. package/runtime/memory_parsers/__pycache__/chatgpt_parser.cpython-313.pyc +0 -0
  487. package/runtime/memory_parsers/__pycache__/claude_import.cpython-313.pyc +0 -0
  488. package/runtime/memory_parsers/__pycache__/export.cpython-313.pyc +0 -0
  489. package/runtime/memory_parsers/__pycache__/gemini_import.cpython-313.pyc +0 -0
  490. package/runtime/memory_parsers/__pycache__/kimi_import.cpython-313.pyc +0 -0
  491. package/runtime/memory_parsers/chatgpt_parser.py +257 -0
  492. package/runtime/memory_parsers/claude_import.py +107 -0
  493. package/runtime/memory_parsers/export.py +97 -0
  494. package/runtime/memory_parsers/gemini_import.py +91 -0
  495. package/runtime/memory_parsers/kimi_import.py +91 -0
  496. package/runtime/memory_store.py +1182 -0
  497. package/runtime/merge_writer.py +445 -0
  498. package/runtime/music_omr_testbed.py +336 -0
  499. package/runtime/mutation_gate.py +320 -0
  500. package/runtime/omc_compat.py +7 -0
  501. package/runtime/omg_browser_cli.py +95 -0
  502. package/runtime/omg_compat_contract_snapshot.json +936 -0
  503. package/runtime/omg_contract_snapshot.json +936 -0
  504. package/runtime/omg_mcp_server.py +306 -0
  505. package/runtime/playwright_adapter.py +39 -0
  506. package/runtime/playwright_pack.py +253 -0
  507. package/runtime/plugin_diagnostics.py +308 -0
  508. package/runtime/plugin_interop.py +1060 -0
  509. package/runtime/policy_pack_loader.py +147 -0
  510. package/runtime/preflight.py +135 -0
  511. package/runtime/profile_io.py +328 -0
  512. package/runtime/proof_chain.py +472 -0
  513. package/runtime/proof_gate.py +442 -0
  514. package/runtime/provider_parity_eval.py +109 -0
  515. package/runtime/providers/__init__.py +0 -0
  516. package/runtime/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  517. package/runtime/providers/__pycache__/codex_provider.cpython-313.pyc +0 -0
  518. package/runtime/providers/__pycache__/gemini_provider.cpython-313.pyc +0 -0
  519. package/runtime/providers/__pycache__/kimi_provider.cpython-313.pyc +0 -0
  520. package/runtime/providers/__pycache__/opencode_provider.cpython-313.pyc +0 -0
  521. package/runtime/providers/codex_provider.py +129 -0
  522. package/runtime/providers/gemini_provider.py +143 -0
  523. package/runtime/providers/kimi_provider.py +167 -0
  524. package/runtime/providers/opencode_provider.py +99 -0
  525. package/runtime/release_artifact_audit.py +556 -0
  526. package/runtime/release_run_coordinator.py +574 -0
  527. package/runtime/release_surface_compiler.py +643 -0
  528. package/runtime/release_surface_registry.py +283 -0
  529. package/runtime/release_surfaces.py +320 -0
  530. package/runtime/remote_supervisor.py +79 -0
  531. package/runtime/repro_pack.py +398 -0
  532. package/runtime/rollback_manifest.py +143 -0
  533. package/runtime/router_critics.py +229 -0
  534. package/runtime/router_executor.py +142 -0
  535. package/runtime/router_selector.py +99 -0
  536. package/runtime/runtime_contracts.py +292 -0
  537. package/runtime/runtime_profile.py +133 -0
  538. package/runtime/security_check.py +1094 -0
  539. package/runtime/session_health.py +546 -0
  540. package/runtime/skill_evolution.py +221 -0
  541. package/runtime/skill_registry.py +53 -0
  542. package/runtime/subagent_dispatcher.py +604 -0
  543. package/runtime/subscription_tiers.py +258 -0
  544. package/runtime/team_router.py +1399 -0
  545. package/runtime/test_intent_lock.py +543 -0
  546. package/runtime/tmux_session_manager.py +172 -0
  547. package/runtime/tool_fabric.py +570 -0
  548. package/runtime/tool_plan_gate.py +460 -0
  549. package/runtime/tracebank.py +125 -0
  550. package/runtime/untrusted_content.py +360 -0
  551. package/runtime/validate.py +293 -0
  552. package/runtime/verdict_schema.py +198 -0
  553. package/runtime/verification_controller.py +235 -0
  554. package/runtime/verification_loop.py +73 -0
  555. package/runtime/vision_artifacts.py +31 -0
  556. package/runtime/vision_cache.py +38 -0
  557. package/runtime/vision_jobs.py +92 -0
  558. package/runtime/worker_watchdog.py +526 -0
  559. package/scripts/__pycache__/audit-published-artifact.cpython-313.pyc +0 -0
  560. package/scripts/__pycache__/check-doc-parity.cpython-313.pyc +0 -0
  561. package/scripts/__pycache__/check-omg-standalone-clean.cpython-313.pyc +0 -0
  562. package/scripts/__pycache__/github_review_helpers.cpython-313.pyc +0 -0
  563. package/scripts/__pycache__/omg.cpython-313.pyc +0 -0
  564. package/scripts/__pycache__/prepare-release-proof-fixtures.cpython-313.pyc +0 -0
  565. package/scripts/__pycache__/sync-release-identity.cpython-313.pyc +0 -0
  566. package/scripts/__pycache__/validate-release-identity.cpython-313.pyc +0 -0
  567. package/scripts/audit-published-artifact.py +59 -0
  568. package/scripts/check-omg-compat-contract-snapshot.py +137 -0
  569. package/scripts/check-omg-contract-snapshot.py +12 -0
  570. package/scripts/check-omg-public-ready.py +273 -0
  571. package/scripts/check-omg-standalone-clean.py +133 -0
  572. package/scripts/emit_host_parity.py +72 -0
  573. package/scripts/legacy_to_omg_migrate.py +29 -0
  574. package/scripts/migrate-legacy.py +464 -0
  575. package/scripts/omc_to_omg_migrate.py +12 -0
  576. package/scripts/omg.py +2962 -0
  577. package/scripts/pre-release-check.sh +38 -0
  578. package/scripts/prepare-release-proof-fixtures.py +602 -0
  579. package/scripts/print-canonical-version.py +80 -0
  580. package/scripts/settings-merge.py +289 -0
  581. package/scripts/sync-release-identity.py +481 -0
  582. package/scripts/validate-release-identity.py +632 -0
  583. package/scripts/verify-no-omc.sh +5 -0
  584. package/scripts/verify-standalone.sh +35 -0
  585. package/settings.json +751 -0
  586. package/tools/__init__.py +2 -0
  587. package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  588. package/tools/__pycache__/browser_consent.cpython-313.pyc +0 -0
  589. package/tools/__pycache__/browser_stealth.cpython-313.pyc +0 -0
  590. package/tools/__pycache__/browser_tool.cpython-313.pyc +0 -0
  591. package/tools/__pycache__/changelog_generator.cpython-313.pyc +0 -0
  592. package/tools/__pycache__/commit_splitter.cpython-313.pyc +0 -0
  593. package/tools/__pycache__/config_discovery.cpython-313.pyc +0 -0
  594. package/tools/__pycache__/config_merger.cpython-313.pyc +0 -0
  595. package/tools/__pycache__/dashboard_generator.cpython-313.pyc +0 -0
  596. package/tools/__pycache__/git_inspector.cpython-313.pyc +0 -0
  597. package/tools/__pycache__/lsp_client.cpython-313.pyc +0 -0
  598. package/tools/__pycache__/lsp_operations.cpython-313.pyc +0 -0
  599. package/tools/__pycache__/pr_generator.cpython-313.pyc +0 -0
  600. package/tools/__pycache__/python_repl.cpython-313.pyc +0 -0
  601. package/tools/__pycache__/python_sandbox.cpython-313.pyc +0 -0
  602. package/tools/__pycache__/session_snapshot.cpython-313.pyc +0 -0
  603. package/tools/__pycache__/ssh_manager.cpython-313.pyc +0 -0
  604. package/tools/__pycache__/theme_engine.cpython-313.pyc +0 -0
  605. package/tools/__pycache__/theme_selector.cpython-313.pyc +0 -0
  606. package/tools/__pycache__/web_search.cpython-313.pyc +0 -0
  607. package/tools/browser_consent.py +289 -0
  608. package/tools/browser_stealth.py +481 -0
  609. package/tools/browser_tool.py +448 -0
  610. package/tools/changelog_generator.py +347 -0
  611. package/tools/commit_splitter.py +749 -0
  612. package/tools/config_discovery.py +151 -0
  613. package/tools/config_merger.py +449 -0
  614. package/tools/dashboard_generator.py +300 -0
  615. package/tools/git_inspector.py +298 -0
  616. package/tools/lsp_client.py +275 -0
  617. package/tools/lsp_discovery.py +231 -0
  618. package/tools/lsp_operations.py +392 -0
  619. package/tools/pr_generator.py +404 -0
  620. package/tools/python_repl.py +712 -0
  621. package/tools/python_sandbox.py +768 -0
  622. package/tools/search_providers/__init__.py +77 -0
  623. package/tools/search_providers/__pycache__/__init__.cpython-313.pyc +0 -0
  624. package/tools/search_providers/__pycache__/brave.cpython-313.pyc +0 -0
  625. package/tools/search_providers/__pycache__/exa.cpython-313.pyc +0 -0
  626. package/tools/search_providers/__pycache__/jina.cpython-313.pyc +0 -0
  627. package/tools/search_providers/__pycache__/perplexity.cpython-313.pyc +0 -0
  628. package/tools/search_providers/__pycache__/synthetic.cpython-313.pyc +0 -0
  629. package/tools/search_providers/brave.py +115 -0
  630. package/tools/search_providers/exa.py +116 -0
  631. package/tools/search_providers/jina.py +104 -0
  632. package/tools/search_providers/perplexity.py +139 -0
  633. package/tools/search_providers/synthetic.py +74 -0
  634. package/tools/session_snapshot.py +851 -0
  635. package/tools/ssh_manager.py +912 -0
  636. package/tools/theme_engine.py +296 -0
  637. package/tools/theme_selector.py +137 -0
  638. package/tools/web_search.py +675 -0
@@ -0,0 +1,1571 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OMG HUD — Standalone statusline for Claude Code.
4
+ *
5
+ * Supports legacy OMC HUD options from ~/.claude/settings.json via `omcHud`
6
+ * and native options via `omgHud`.
7
+ */
8
+
9
+ import { readFileSync, existsSync, readdirSync, realpathSync, statSync } from "node:fs";
10
+ import { basename, dirname, join } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ import { homedir } from "node:os";
13
+ import { execFileSync } from "node:child_process";
14
+
15
+ // ── ANSI helpers ────────────────────────────────────────────────────────────
16
+ const ESC = "\x1b[";
17
+ const bold = (t) => `${ESC}1m${t}${ESC}0m`;
18
+ const dim = (t) => `${ESC}2m${t}${ESC}0m`;
19
+ const green = (t) => `${ESC}32m${t}${ESC}0m`;
20
+ const yellow = (t) => `${ESC}33m${t}${ESC}0m`;
21
+ const red = (t) => `${ESC}31m${t}${ESC}0m`;
22
+ const magenta = (t) => `${ESC}35m${t}${ESC}0m`;
23
+ const cyan = (t) => `${ESC}36m${t}${ESC}0m`;
24
+
25
+ function readOmgVersion() {
26
+ const scriptPath = realpathSync(fileURLToPath(import.meta.url));
27
+ const scriptDir = dirname(scriptPath);
28
+ const claudeDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
29
+
30
+ try {
31
+ const pluginJsonPath = join(scriptDir, "..", ".claude-plugin", "plugin.json");
32
+ const pluginJson = JSON.parse(readFileSync(pluginJsonPath, "utf8"));
33
+ if (typeof pluginJson?.version === "string" && pluginJson.version.trim()) {
34
+ return pluginJson.version.trim();
35
+ }
36
+ } catch {
37
+ // fall through to git tag fallback
38
+ }
39
+
40
+ try {
41
+ const settingsJson = JSON.parse(readFileSync(join(claudeDir, "settings.json"), "utf8"));
42
+ const version = settingsJson?._omg?._version;
43
+ if (typeof version === "string" && version.trim()) {
44
+ return version.trim();
45
+ }
46
+ } catch {
47
+ // fall through to cache and hook fallbacks
48
+ }
49
+
50
+ try {
51
+ const hooksVersion = readFileSync(join(claudeDir, "hooks", ".omg-version"), "utf8").trim();
52
+ if (hooksVersion) {
53
+ return hooksVersion.replace(/^v/, "").trim();
54
+ }
55
+ } catch {
56
+ // fall through to plugin cache fallback
57
+ }
58
+
59
+ try {
60
+ const pluginCacheDir = join(claudeDir, "plugins", "cache", "omg", "omg");
61
+ const versions = readdirSync(pluginCacheDir)
62
+ .filter((entry) => /^\d+\.\d+\.\d+/.test(entry))
63
+ .sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
64
+ const latest = versions.at(-1);
65
+ if (latest) {
66
+ const pluginJson = JSON.parse(
67
+ readFileSync(join(pluginCacheDir, latest, ".claude-plugin", "plugin.json"), "utf8"),
68
+ );
69
+ if (typeof pluginJson?.version === "string" && pluginJson.version.trim()) {
70
+ return pluginJson.version.trim();
71
+ }
72
+ }
73
+ } catch {
74
+ // fall through to git tag fallback
75
+ }
76
+
77
+ try {
78
+ const rootDir = join(scriptDir, "..");
79
+ const latestTag = execFileSync("git", ["describe", "--tags", "--abbrev=0"], {
80
+ cwd: rootDir,
81
+ encoding: "utf8",
82
+ stdio: ["ignore", "pipe", "ignore"],
83
+ }).trim();
84
+ const normalized = latestTag.replace(/^v/, "").trim();
85
+ if (normalized) return normalized;
86
+ } catch {
87
+ // fall through to static fallback
88
+ }
89
+
90
+ return "2.2.11";
91
+ }
92
+
93
+ const OMG_VERSION = readOmgVersion();
94
+
95
+ const DEFAULT_HUD_CONFIG = {
96
+ preset: "standard",
97
+ elements: {
98
+ cwd: true,
99
+ cwdFormat: "relative",
100
+ gitRepo: false,
101
+ gitBranch: false,
102
+ model: false,
103
+ modelFormat: "short",
104
+ omcLabel: true,
105
+ rateLimits: true,
106
+ promptTime: true,
107
+ sessionHealth: true,
108
+ contextBar: true,
109
+ activeSkills: true,
110
+ lastSkill: true,
111
+ showCallCounts: false,
112
+ ralph: true,
113
+ autopilot: true,
114
+ prdStory: true,
115
+ agents: true,
116
+ agentsFormat: "count",
117
+ backgroundTasks: true,
118
+ todos: true,
119
+ thinking: true,
120
+ thinkingFormat: "text",
121
+ permissionStatus: false,
122
+ useBars: false,
123
+ maxOutputLines: 4,
124
+ safeMode: true,
125
+ inventory: true,
126
+ },
127
+ thresholds: {
128
+ contextWarning: 70,
129
+ contextCompactSuggestion: 80,
130
+ contextCritical: 85,
131
+ ralphWarning: 7,
132
+ },
133
+ contextLimitWarning: {
134
+ threshold: 80,
135
+ autoCompact: false,
136
+ },
137
+ };
138
+
139
+ const PRESET_CONFIGS = {
140
+ minimal: {
141
+ cwd: true,
142
+ cwdFormat: "folder",
143
+ gitRepo: false,
144
+ gitBranch: false,
145
+ model: false,
146
+ modelFormat: "short",
147
+ omcLabel: true,
148
+ rateLimits: true,
149
+ activeSkills: true,
150
+ lastSkill: true,
151
+ contextBar: false,
152
+ promptTime: false,
153
+ sessionHealth: false,
154
+ ralph: true,
155
+ autopilot: true,
156
+ prdStory: false,
157
+ agents: true,
158
+ agentsFormat: "count",
159
+ backgroundTasks: false,
160
+ todos: true,
161
+ thinking: false,
162
+ thinkingFormat: "text",
163
+ permissionStatus: false,
164
+ useBars: false,
165
+ showCallCounts: false,
166
+ maxOutputLines: 2,
167
+ safeMode: true,
168
+ inventory: true,
169
+ },
170
+ standard: {
171
+ cwd: true,
172
+ cwdFormat: "relative",
173
+ gitRepo: false,
174
+ gitBranch: true,
175
+ model: false,
176
+ modelFormat: "short",
177
+ omcLabel: true,
178
+ rateLimits: true,
179
+ activeSkills: true,
180
+ lastSkill: true,
181
+ contextBar: true,
182
+ promptTime: true,
183
+ sessionHealth: true,
184
+ ralph: true,
185
+ autopilot: true,
186
+ prdStory: true,
187
+ agents: true,
188
+ agentsFormat: "count",
189
+ backgroundTasks: true,
190
+ todos: true,
191
+ thinking: true,
192
+ thinkingFormat: "text",
193
+ permissionStatus: false,
194
+ useBars: true,
195
+ showCallCounts: false,
196
+ maxOutputLines: 4,
197
+ safeMode: true,
198
+ inventory: true,
199
+ },
200
+ full: {
201
+ cwd: true,
202
+ cwdFormat: "relative",
203
+ gitRepo: true,
204
+ gitBranch: true,
205
+ model: false,
206
+ modelFormat: "short",
207
+ omcLabel: true,
208
+ rateLimits: true,
209
+ activeSkills: true,
210
+ lastSkill: true,
211
+ contextBar: true,
212
+ promptTime: true,
213
+ sessionHealth: true,
214
+ ralph: true,
215
+ autopilot: true,
216
+ prdStory: true,
217
+ agents: true,
218
+ agentsFormat: "count",
219
+ backgroundTasks: true,
220
+ todos: true,
221
+ thinking: true,
222
+ thinkingFormat: "text",
223
+ permissionStatus: false,
224
+ useBars: true,
225
+ showCallCounts: false,
226
+ maxOutputLines: 12,
227
+ safeMode: true,
228
+ inventory: true,
229
+ },
230
+ dense: {
231
+ cwd: true,
232
+ cwdFormat: "relative",
233
+ gitRepo: true,
234
+ gitBranch: true,
235
+ model: false,
236
+ modelFormat: "short",
237
+ omcLabel: true,
238
+ rateLimits: true,
239
+ activeSkills: true,
240
+ lastSkill: true,
241
+ contextBar: true,
242
+ promptTime: true,
243
+ sessionHealth: true,
244
+ ralph: true,
245
+ autopilot: true,
246
+ prdStory: true,
247
+ agents: true,
248
+ agentsFormat: "count",
249
+ backgroundTasks: true,
250
+ todos: true,
251
+ thinking: true,
252
+ thinkingFormat: "text",
253
+ permissionStatus: false,
254
+ useBars: true,
255
+ showCallCounts: false,
256
+ maxOutputLines: 6,
257
+ safeMode: true,
258
+ inventory: true,
259
+ },
260
+ opencode: {
261
+ cwd: true,
262
+ cwdFormat: "relative",
263
+ gitRepo: false,
264
+ gitBranch: true,
265
+ model: false,
266
+ modelFormat: "short",
267
+ omcLabel: true,
268
+ rateLimits: false,
269
+ activeSkills: true,
270
+ lastSkill: true,
271
+ contextBar: true,
272
+ promptTime: true,
273
+ sessionHealth: true,
274
+ ralph: true,
275
+ autopilot: true,
276
+ prdStory: false,
277
+ agents: true,
278
+ agentsFormat: "count",
279
+ backgroundTasks: false,
280
+ todos: true,
281
+ thinking: true,
282
+ thinkingFormat: "text",
283
+ permissionStatus: false,
284
+ useBars: false,
285
+ showCallCounts: false,
286
+ maxOutputLines: 4,
287
+ safeMode: true,
288
+ inventory: true,
289
+ },
290
+ };
291
+
292
+ const HUD_PRESET_ALIASES = {
293
+ focused: "standard",
294
+ };
295
+
296
+ function resolveHudPreset(preset) {
297
+ const requested = typeof preset === "string" ? preset : DEFAULT_HUD_CONFIG.preset;
298
+ const canonical = HUD_PRESET_ALIASES[requested] || requested;
299
+ if (PRESET_CONFIGS[canonical]) return canonical;
300
+ return DEFAULT_HUD_CONFIG.preset;
301
+ }
302
+
303
+ function countByExt(dirPath, ext) {
304
+ if (!existsSync(dirPath)) return 0;
305
+ try {
306
+ return readdirSync(dirPath, { withFileTypes: true }).filter(
307
+ (entry) => entry.isFile() && entry.name.endsWith(ext)
308
+ ).length;
309
+ } catch {
310
+ return 0;
311
+ }
312
+ }
313
+
314
+ function getRuntimeInventory() {
315
+ const claudeDir = getClaudeConfigDir();
316
+ return {
317
+ agents: countByExt(join(claudeDir, "agents"), ".md"),
318
+ hooks: countByExt(join(claudeDir, "hooks"), ".py"),
319
+ commands: countByExt(join(claudeDir, "commands"), ".md"),
320
+ rules: countByExt(join(claudeDir, "rules"), ".md"),
321
+ };
322
+ }
323
+
324
+ function renderInventory(inv) {
325
+ if (!inv) return null;
326
+ return `\u{1F9F0}agents:${cyan(String(inv.agents))}`;
327
+ }
328
+
329
+ function parseModeToken(mode) {
330
+ const raw = String(mode || "");
331
+ const lower = raw.toLowerCase();
332
+ const base = lower.split("#")[0].split(":")[0];
333
+ const iterMatch = raw.match(/#(\d+)/);
334
+ const iter = iterMatch ? iterMatch[1] : "";
335
+ const phase = raw.includes(":") ? raw.split(":").slice(1).join(":") : "";
336
+ return { base, iter, phase };
337
+ }
338
+
339
+ function renderModeBadge(mode) {
340
+ const { base, iter, phase } = parseModeToken(mode);
341
+ let key = base;
342
+ let icon = "\u2699";
343
+ let title = (base || "mode").toUpperCase();
344
+ let colorFn = magenta;
345
+
346
+ if (base === "ultrawork" || base === "ulw") {
347
+ key = "ulw";
348
+ icon = "\u26A1";
349
+ title = "ULW";
350
+ colorFn = yellow;
351
+ } else if (base === "team" || base === "crazy") {
352
+ key = "crazy";
353
+ icon = "\u{1F92F}";
354
+ title = "CRAZY";
355
+ colorFn = red;
356
+ } else if (base === "ralph") {
357
+ key = "ralph";
358
+ icon = "\u{1F9E0}";
359
+ title = "RALPH";
360
+ colorFn = green;
361
+ } else if (base === "autopilot") {
362
+ key = "autopilot";
363
+ icon = "\u{1F6E0}";
364
+ title = "AUTOPILOT";
365
+ colorFn = cyan;
366
+ }
367
+
368
+ const extra = `${iter ? `#${iter}` : ""}${phase ? `:${phase}` : ""}`;
369
+ return { key, text: colorFn(`${icon}${title}${extra}`) };
370
+ }
371
+
372
+ function renderModeBadges(modes, opts = {}) {
373
+ if (!Array.isArray(modes) || modes.length === 0) return null;
374
+ const hideRalph = !!opts.hideRalph;
375
+ const hideAutopilot = !!opts.hideAutopilot;
376
+ const seen = new Set();
377
+ const badges = [];
378
+
379
+ for (const mode of modes) {
380
+ const badge = renderModeBadge(mode);
381
+ if (hideRalph && badge.key === "ralph") continue;
382
+ if (hideAutopilot && badge.key === "autopilot") continue;
383
+ if (seen.has(badge.key)) continue;
384
+ seen.add(badge.key);
385
+ badges.push(badge.text);
386
+ }
387
+
388
+ if (badges.length === 0) return null;
389
+ return badges.join("+");
390
+ }
391
+
392
+ function colorByPercent(value, label, warning = 60, critical = 85) {
393
+ if (value >= critical) return red(`${label}`);
394
+ if (value >= warning) return yellow(`${label}`);
395
+ return green(`${label}`);
396
+ }
397
+
398
+ function readJsonSafe(path) {
399
+ try {
400
+ if (!existsSync(path)) return null;
401
+ return JSON.parse(readFileSync(path, "utf8"));
402
+ } catch {
403
+ return null;
404
+ }
405
+ }
406
+
407
+ function getClaudeConfigDir() {
408
+ return process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
409
+ }
410
+
411
+ function readRawHudConfig() {
412
+ const claudeDir = getClaudeConfigDir();
413
+ const settingsPath = join(claudeDir, "settings.json");
414
+ const settings = readJsonSafe(settingsPath) || {};
415
+ if (settings.omgHud) return settings.omgHud;
416
+ if (settings.omcHud) return settings.omcHud;
417
+
418
+ // OMC legacy HUD config fallback.
419
+ const legacyPath = join(claudeDir, ".omc", "hud-config.json");
420
+ return readJsonSafe(legacyPath) || {};
421
+ }
422
+
423
+ function readHudConfig() {
424
+ const source = readRawHudConfig();
425
+ const preset = resolveHudPreset(source.preset);
426
+ const presetElements = PRESET_CONFIGS[preset] || {};
427
+ const elements = {
428
+ ...DEFAULT_HUD_CONFIG.elements,
429
+ ...presetElements,
430
+ ...(source.elements || {}),
431
+ };
432
+ const thresholds = {
433
+ ...DEFAULT_HUD_CONFIG.thresholds,
434
+ ...(source.thresholds || {}),
435
+ };
436
+ const contextLimitWarning = {
437
+ ...DEFAULT_HUD_CONFIG.contextLimitWarning,
438
+ ...(source.contextLimitWarning || {}),
439
+ };
440
+ return { preset, elements, thresholds, contextLimitWarning };
441
+ }
442
+
443
+ async function readStdin() {
444
+ if (process.stdin.isTTY) return null;
445
+ const chunks = [];
446
+ process.stdin.setEncoding("utf8");
447
+ for await (const chunk of process.stdin) chunks.push(chunk);
448
+ const raw = chunks.join("");
449
+ if (!raw.trim()) return null;
450
+ try {
451
+ return JSON.parse(raw);
452
+ } catch {
453
+ return null;
454
+ }
455
+ }
456
+
457
+ function getContextPercent(stdin) {
458
+ let pct = stdin?.context_window?.used_percentage;
459
+ if (typeof pct === "number" && !Number.isNaN(pct)) {
460
+ if (pct > 0 && pct <= 1) pct *= 100;
461
+ return Math.min(100, Math.max(0, Math.round(pct)));
462
+ }
463
+ const size = stdin?.context_window?.context_window_size;
464
+ if (!size || size <= 0) return 0;
465
+ const usage = stdin?.context_window?.current_usage ?? {};
466
+ const tokens =
467
+ (usage.input_tokens ?? 0) +
468
+ (usage.cache_creation_input_tokens ?? 0) +
469
+ (usage.cache_read_input_tokens ?? 0);
470
+ return Math.min(100, Math.round((tokens / size) * 100));
471
+ }
472
+
473
+ function formatModelName(id, format) {
474
+ if (!id) return "?";
475
+ if (format === "full") return id;
476
+
477
+ const lower = id.toLowerCase();
478
+ let family = "";
479
+ if (lower.includes("opus")) family = "opus";
480
+ else if (lower.includes("sonnet")) family = "sonnet";
481
+ else if (lower.includes("haiku")) family = "haiku";
482
+ else family = id.split("/").pop()?.split("-")[0] || id;
483
+
484
+ if (format !== "versioned") return family;
485
+
486
+ const m = lower.match(/-(\d)-(\d)(?:-|$)/);
487
+ if (m) {
488
+ return `${family} ${m[1]}.${m[2]}`;
489
+ }
490
+ return family;
491
+ }
492
+
493
+ function getModelShort(stdin, format = "short") {
494
+ const id = stdin?.model?.id ?? stdin?.model?.display_name ?? "";
495
+ return formatModelName(id, format);
496
+ }
497
+
498
+ function getModelId(stdin) {
499
+ const fromStdin = stdin?.model?.id ?? stdin?.model?.display_name ?? "";
500
+ const fromEnv = process.env.CLAUDE_MODEL || process.env.OMG_MODEL_ID || process.env.OPENAI_MODEL || "";
501
+ return String(fromStdin || fromEnv || "").trim();
502
+ }
503
+
504
+ function isKnownModelHost(modelId) {
505
+ const lower = String(modelId || "").toLowerCase();
506
+ if (!lower) return false;
507
+ return (
508
+ lower.startsWith("claude") ||
509
+ lower.startsWith("gpt") ||
510
+ lower.startsWith("o3") ||
511
+ lower.startsWith("o4") ||
512
+ lower.startsWith("gemini") ||
513
+ lower.startsWith("kimi") ||
514
+ lower.startsWith("moonshot")
515
+ );
516
+ }
517
+
518
+ function getHostAwareCompactionTrigger(cwd, modelId) {
519
+ const fallback = 200_000;
520
+ if (!isKnownModelHost(modelId)) {
521
+ return fallback;
522
+ }
523
+
524
+ const projectDir = cwd || process.cwd();
525
+ try {
526
+ const output = execFileSync(
527
+ "python3",
528
+ [
529
+ "-c",
530
+ "import os; from runtime.context_limits import compaction_trigger; m=(os.environ.get('OMG_MODEL_ID') or '').strip(); print(int(compaction_trigger(m)))",
531
+ ],
532
+ {
533
+ cwd: projectDir,
534
+ encoding: "utf8",
535
+ stdio: ["ignore", "pipe", "ignore"],
536
+ env: {
537
+ ...process.env,
538
+ OMG_MODEL_ID: String(modelId || "").trim(),
539
+ },
540
+ },
541
+ ).trim();
542
+ const parsed = Number(output);
543
+ if (Number.isFinite(parsed) && parsed > 0) {
544
+ return Math.round(parsed);
545
+ }
546
+ } catch {
547
+ // fallback below
548
+ }
549
+ return fallback;
550
+ }
551
+
552
+ function getCompactWarningThreshold(stdin, cfg, cwd) {
553
+ const configuredPercent = Number(
554
+ cfg.contextLimitWarning.threshold ?? cfg.thresholds.contextCompactSuggestion ?? 80,
555
+ );
556
+ const contextWindowSize = Number(stdin?.context_window?.context_window_size ?? 0);
557
+ const modelId = getModelId(stdin);
558
+ const triggerTokens = getHostAwareCompactionTrigger(cwd, modelId);
559
+ if (contextWindowSize > 0 && Number.isFinite(contextWindowSize)) {
560
+ const derivedPercent = Math.round((triggerTokens / contextWindowSize) * 100);
561
+ return Math.max(1, Math.min(100, derivedPercent));
562
+ }
563
+ return configuredPercent;
564
+ }
565
+
566
+ function sessionDuration(transcriptPath) {
567
+ if (!transcriptPath || !existsSync(transcriptPath)) return null;
568
+ try {
569
+ const fd = readFileSync(transcriptPath, "utf8");
570
+ const nlIdx = fd.indexOf("\n");
571
+ const firstLine = fd.slice(0, nlIdx >= 0 ? nlIdx : Math.min(fd.length, 2000));
572
+ if (!firstLine.trim()) return null;
573
+ const first = JSON.parse(firstLine);
574
+ const raw = first?.timestamp ?? first?.ts;
575
+ if (!raw) return null;
576
+ const start = new Date(raw);
577
+ if (isNaN(start.getTime())) return null;
578
+ const mins = Math.floor((Date.now() - start.getTime()) / 60_000);
579
+ if (mins < 0 || mins > 10080) return null; // sanity: max 7 days
580
+ return `${mins}m`;
581
+ } catch {
582
+ return null;
583
+ }
584
+ }
585
+
586
+ function getGitInfo(cwd) {
587
+ try {
588
+ const root = execFileSync("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
589
+ encoding: "utf8",
590
+ stdio: ["ignore", "pipe", "ignore"],
591
+ }).trim();
592
+ const branch = execFileSync("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"], {
593
+ encoding: "utf8",
594
+ stdio: ["ignore", "pipe", "ignore"],
595
+ }).trim();
596
+ return { repo: basename(root), branch };
597
+ } catch {
598
+ return { repo: null, branch: null };
599
+ }
600
+ }
601
+
602
+ function renderCwd(cwd, format) {
603
+ if (!cwd) return null;
604
+ if (format === "absolute") return cwd;
605
+ if (format === "folder") return basename(cwd);
606
+ const home = homedir();
607
+ if (cwd.startsWith(home)) return `~${cwd.slice(home.length) || "/"}`;
608
+ return cwd;
609
+ }
610
+
611
+ function formatClock(iso) {
612
+ try {
613
+ const dt = new Date(iso);
614
+ if (isNaN(dt.getTime())) return null;
615
+ const hh = String(dt.getHours()).padStart(2, "0");
616
+ const mm = String(dt.getMinutes()).padStart(2, "0");
617
+ const ss = String(dt.getSeconds()).padStart(2, "0");
618
+ return `${hh}:${mm}:${ss}`;
619
+ } catch {
620
+ return null;
621
+ }
622
+ }
623
+
624
+ function renderBar(percent, width = 10) {
625
+ const clamped = Math.max(0, Math.min(100, Number(percent) || 0));
626
+ const filled = Math.round((clamped / 100) * width);
627
+ return `[${"█".repeat(filled)}${"░".repeat(Math.max(0, width - filled))}]`;
628
+ }
629
+
630
+ function getLastPromptTime(cwd) {
631
+ const candidates = [
632
+ join(cwd, ".omg", "state", "hud-state.json"),
633
+ join(cwd, ".omc", "state", "hud-state.json"),
634
+ join(cwd, ".omc", "hud-state.json"),
635
+ ];
636
+ for (const p of candidates) {
637
+ const state = readJsonSafe(p);
638
+ if (state?.lastPromptTimestamp) {
639
+ const t = formatClock(state.lastPromptTimestamp);
640
+ if (t) return t;
641
+ }
642
+ }
643
+ return null;
644
+ }
645
+
646
+ function readOmgState(cwd) {
647
+ const stateDir = join(cwd, ".omg", "state");
648
+ const result = {
649
+ modes: [],
650
+ currentMode: null,
651
+ hookCount: 0,
652
+ profile: null,
653
+ ralph: null,
654
+ autopilot: null,
655
+ prd: null,
656
+ backgroundTasks: [],
657
+ };
658
+
659
+ const modeFiles = [
660
+ ["ralph", "ralph-state.json"],
661
+ ["ultrawork", "ultrawork-state.json"],
662
+ ["autopilot", "autopilot-state.json"],
663
+ ["ultrapilot", "ultrapilot-state.json"],
664
+ ["team", "team-state.json"],
665
+ ["pipeline", "pipeline-state.json"],
666
+ ["ultraqa", "ultraqa-state.json"],
667
+ ];
668
+
669
+ for (const [name, file] of modeFiles) {
670
+ const state = readJsonSafe(join(stateDir, file));
671
+ if (state?.active) {
672
+ const iter = state.iteration ? `#${state.iteration}` : "";
673
+ const phase = state.current_phase ? `:${state.current_phase}` : "";
674
+ result.modes.push(`${name}${iter}${phase}`);
675
+ }
676
+ }
677
+
678
+ const persistent = readJsonSafe(join(stateDir, "persistent-mode.json"));
679
+ if (persistent?.status === "active" && persistent?.mode) {
680
+ if (!result.modes.includes(persistent.mode)) {
681
+ result.modes.push(String(persistent.mode));
682
+ }
683
+ }
684
+
685
+ const modeState = readJsonSafe(join(stateDir, "mode.json"));
686
+ if (modeState && typeof modeState === "object") {
687
+ const candidate = modeState.mode || modeState.current_mode || modeState.name;
688
+ if (typeof candidate === "string" && candidate.trim()) {
689
+ result.currentMode = candidate.trim().toLowerCase();
690
+ }
691
+ }
692
+
693
+ const ralphState = readJsonSafe(join(stateDir, "ralph-state.json"));
694
+ if (ralphState?.active) {
695
+ result.ralph = {
696
+ active: true,
697
+ iteration: ralphState.iteration || 0,
698
+ maxIterations: ralphState.maxIterations || ralphState.max_iterations || 10,
699
+ };
700
+ }
701
+
702
+ const autopilotState = readJsonSafe(join(stateDir, "autopilot-state.json"));
703
+ if (autopilotState?.active) {
704
+ result.autopilot = {
705
+ active: true,
706
+ phase: autopilotState.phase || autopilotState.current_phase || "execution",
707
+ iteration: autopilotState.iteration || 1,
708
+ maxIterations: autopilotState.maxIterations || autopilotState.max_iterations || 10,
709
+ tasksCompleted: autopilotState.tasksCompleted || autopilotState.tasks_completed || 0,
710
+ tasksTotal: autopilotState.tasksTotal || autopilotState.tasks_total || 0,
711
+ };
712
+ }
713
+
714
+ const prdState = readJsonSafe(join(stateDir, "prd-state.json"));
715
+ if (prdState) {
716
+ result.prd = {
717
+ currentStoryId: prdState.currentStoryId || prdState.current_story_id || null,
718
+ completed: prdState.completed || 0,
719
+ total: prdState.total || 0,
720
+ };
721
+ }
722
+
723
+ const hudState = readJsonSafe(join(stateDir, "hud-state.json"));
724
+ if (hudState?.backgroundTasks && Array.isArray(hudState.backgroundTasks)) {
725
+ result.backgroundTasks = hudState.backgroundTasks.filter((t) => t.status === "running");
726
+ }
727
+
728
+ try {
729
+ const yamlPath = join(stateDir, "profile.yaml");
730
+ if (existsSync(yamlPath)) {
731
+ const text = readFileSync(yamlPath, "utf8");
732
+ const nameMatch = text.match(/^name:\s*["']?(.+?)["']?\s*$/m);
733
+ if (nameMatch) result.profile = nameMatch[1];
734
+ }
735
+ } catch {
736
+ // ignore
737
+ }
738
+
739
+ const ledger = join(stateDir, "ledger", "tool-ledger.jsonl");
740
+ if (existsSync(ledger)) {
741
+ try {
742
+ const buf = readFileSync(ledger);
743
+ let count = 0;
744
+ for (let i = 0; i < buf.length; i++) {
745
+ if (buf[i] === 10) count++;
746
+ }
747
+ if (buf.length > 0 && count === 0) count = 1;
748
+ result.hookCount = count;
749
+ } catch {
750
+ // ignore
751
+ }
752
+ }
753
+ return result;
754
+ }
755
+
756
+ function readBackgroundVerificationState(stateDir) {
757
+ const filePath = join(stateDir, "background-verification.json");
758
+ const data = readJsonSafe(filePath);
759
+ if (!data || data.schema !== "BackgroundVerificationState") return null;
760
+ return {
761
+ status: data.status || "unknown",
762
+ blockers: Array.isArray(data.blockers) ? data.blockers : [],
763
+ evidence_links: Array.isArray(data.evidence_links) ? data.evidence_links : [],
764
+ progress: data.progress || {},
765
+ updated_at: data.updated_at || null,
766
+ };
767
+ }
768
+
769
+ function readActiveRunId(stateDir) {
770
+ const activeRunPath = join(dirname(stateDir), "shadow", "active-run");
771
+ try {
772
+ if (existsSync(activeRunPath)) {
773
+ const value = readFileSync(activeRunPath, "utf8").trim();
774
+ if (value) return value;
775
+ }
776
+ } catch {
777
+ return readActiveCoordinatorRunId(stateDir);
778
+ }
779
+ return readActiveCoordinatorRunId(stateDir);
780
+ }
781
+
782
+ function readActiveCoordinatorRunId(stateDir) {
783
+ const projectDir = dirname(dirname(stateDir));
784
+ try {
785
+ const output = execFileSync(
786
+ "python3",
787
+ [
788
+ "-c",
789
+ "from runtime.release_run_coordinator import get_active_coordinator_run_id; import os; print(get_active_coordinator_run_id(os.environ.get('OMG_HUD_PROJECT_DIR')) or '')",
790
+ ],
791
+ {
792
+ cwd: projectDir,
793
+ encoding: "utf8",
794
+ stdio: ["ignore", "pipe", "ignore"],
795
+ env: {
796
+ ...process.env,
797
+ OMG_HUD_PROJECT_DIR: projectDir,
798
+ },
799
+ },
800
+ ).trim();
801
+ return output || null;
802
+ } catch {
803
+ return null;
804
+ }
805
+ }
806
+
807
+ function normalizeVerificationState(data) {
808
+ if (!data || typeof data !== "object") return null;
809
+ const schema = data.schema;
810
+ if (schema !== "VerificationControllerState" && schema !== "BackgroundVerificationState") {
811
+ return null;
812
+ }
813
+ return {
814
+ status: data.status || "unknown",
815
+ blockers: Array.isArray(data.blockers) ? data.blockers : [],
816
+ evidence_links: Array.isArray(data.evidence_links) ? data.evidence_links : [],
817
+ progress: data.progress || {},
818
+ updated_at: data.updated_at || null,
819
+ run_id: data.run_id || null,
820
+ };
821
+ }
822
+
823
+ function readVerificationState(stateDir) {
824
+ const activeRunId = readActiveRunId(stateDir);
825
+ if (!activeRunId) {
826
+ return {
827
+ status: "no_active_run",
828
+ blockers: [],
829
+ evidence_links: [],
830
+ progress: {},
831
+ updated_at: null,
832
+ run_id: null,
833
+ };
834
+ }
835
+ const candidates = [];
836
+ candidates.push(join(stateDir, "verification_controller", `${activeRunId}.json`));
837
+ candidates.push(join(stateDir, "verification_controller", "latest.json"));
838
+ candidates.push(join(stateDir, "background-verification.json"));
839
+
840
+ for (const candidate of candidates) {
841
+ const normalized = normalizeVerificationState(readJsonSafe(candidate));
842
+ if (activeRunId && normalized?.run_id && normalized.run_id !== activeRunId) {
843
+ continue;
844
+ }
845
+ if (normalized) return normalized;
846
+ }
847
+ return null;
848
+ }
849
+
850
+ function readLatestSessionHealth(stateDir) {
851
+ const healthDir = join(stateDir, "session_health");
852
+ if (!existsSync(healthDir)) return null;
853
+ try {
854
+ const activeRunId = readActiveRunId(stateDir);
855
+ const candidates = [];
856
+ if (activeRunId) {
857
+ candidates.push(join(healthDir, `${activeRunId}.json`));
858
+ }
859
+ candidates.push(join(healthDir, "latest.json"));
860
+ for (const candidate of candidates) {
861
+ const data = readJsonSafe(candidate);
862
+ if (activeRunId && data?.run_id && data.run_id !== activeRunId) continue;
863
+ if (data?.schema === "SessionHealth") return data;
864
+ }
865
+
866
+ const files = readdirSync(healthDir)
867
+ .filter((f) => f.endsWith(".json") && !f.endsWith(".tmp") && f !== "latest.json")
868
+ .map((f) => {
869
+ const fullPath = join(healthDir, f);
870
+ try {
871
+ return { fullPath, mtimeMs: statSync(fullPath).mtimeMs };
872
+ } catch {
873
+ return null;
874
+ }
875
+ })
876
+ .filter(Boolean)
877
+ .sort((a, b) => b.mtimeMs - a.mtimeMs);
878
+ for (const file of files) {
879
+ const data = readJsonSafe(file.fullPath);
880
+ if (activeRunId && data?.run_id && data.run_id !== activeRunId) continue;
881
+ if (data?.schema === "SessionHealth") return data;
882
+ }
883
+ return null;
884
+ } catch {
885
+ return null;
886
+ }
887
+ }
888
+
889
+ function readSessionHealthFromStdin(stdin) {
890
+ if (stdin?.session_health && typeof stdin.session_health === "object") {
891
+ const sh = stdin.session_health;
892
+ if (sh.schema === "SessionHealth") return sh;
893
+ }
894
+ return null;
895
+ }
896
+
897
+ const STALENESS_THRESHOLD_MS = 5 * 60 * 1000;
898
+
899
+ function isSessionHealthStale(health) {
900
+ if (!health || !health.updated_at) return false;
901
+ const updatedMs = new Date(health.updated_at).getTime();
902
+ if (isNaN(updatedMs)) return false;
903
+ return Date.now() - updatedMs > STALENESS_THRESHOLD_MS;
904
+ }
905
+
906
+ function renderSessionHealth(health) {
907
+ if (!health) return null;
908
+ const contamination = typeof health.contamination_risk === "number" ? health.contamination_risk : 0;
909
+ const overthinking = typeof health.overthinking_score === "number" ? health.overthinking_score : 0;
910
+ const ctxHealth = typeof health.context_health === "number" ? health.context_health : 1;
911
+ const action = health.recommended_action || "continue";
912
+
913
+ const contPct = Math.round(contamination * 100);
914
+ const overPct = Math.round(overthinking * 100);
915
+ const healthPct = Math.round(ctxHealth * 100);
916
+
917
+ const stale = isSessionHealthStale(health);
918
+ const contColor = stale ? dim : contamination >= 0.7 ? red : contamination >= 0.3 ? yellow : green;
919
+ const overColor = stale ? dim : overthinking >= 0.85 ? red : overthinking >= 0.5 ? yellow : green;
920
+ const healthColor = stale ? dim : ctxHealth <= 0.2 ? red : ctxHealth <= 0.4 ? yellow : green;
921
+
922
+ let badge = "";
923
+ if (action === "block") badge = ` ${red("BLOCK")}`;
924
+ else if (action === "reflect") badge = ` ${yellow("REFLECT")}`;
925
+ else if (action === "warn") badge = ` ${yellow("WARN")}`;
926
+ if (stale) badge += ` ${yellow("[STALE]")}`;
927
+
928
+ return (
929
+ `contam:${contColor(`${contPct}%`)} ` +
930
+ `overthink:${overColor(`${overPct}%`)} ` +
931
+ `health:${healthColor(`${healthPct}%`)}` +
932
+ badge
933
+ );
934
+ }
935
+
936
+ function parseTranscript(transcriptPath) {
937
+ const result = {
938
+ tools: 0,
939
+ agents: 0,
940
+ skills: 0,
941
+ runningAgentCount: 0,
942
+ todos: [],
943
+ lastSkill: null,
944
+ thinkingActive: false,
945
+ pendingPermission: null,
946
+ };
947
+ if (!transcriptPath || !existsSync(transcriptPath)) return result;
948
+ try {
949
+ const content = readFileSync(transcriptPath, "utf8");
950
+ const lines = content.split("\n");
951
+ const agentMap = new Map();
952
+ const STALE_MS = 30 * 60 * 1000;
953
+ let lastThinkingTs = 0;
954
+ let pendingToolUse = null;
955
+ const resolvedIds = new Set();
956
+
957
+ const parseEpochMs = (raw) => {
958
+ if (typeof raw === "number" && Number.isFinite(raw)) return raw;
959
+ if (typeof raw !== "string" || raw.length === 0) return Date.now();
960
+ const t = Date.parse(raw);
961
+ return Number.isNaN(t) ? Date.now() : t;
962
+ };
963
+
964
+ for (const line of lines) {
965
+ if (!line.trim()) continue;
966
+ try {
967
+ const entry = JSON.parse(line);
968
+ const entryTs = parseEpochMs(entry.timestamp || entry.ts);
969
+
970
+ if (entry.type === "assistant" && Array.isArray(entry.message?.content)) {
971
+ for (const block of entry.message.content) {
972
+ if (block.type === "thinking" || block.type === "reasoning") {
973
+ lastThinkingTs = entryTs;
974
+ }
975
+
976
+ if (block.type === "tool_use") {
977
+ const name = block.name || "";
978
+ const input = block.input || {};
979
+ const id = block.id || "";
980
+
981
+ if (name === "Task" || name === "proxy_Task") {
982
+ result.agents++;
983
+ agentMap.set(id, {
984
+ type: input.agent_type || input.type || "unknown",
985
+ description: input.description || "",
986
+ startTime: entryTs,
987
+ });
988
+ } else if (name === "Skill" || name === "proxy_Skill") {
989
+ result.skills++;
990
+ const skillName = input.skill_name || input.name || "";
991
+ if (skillName) {
992
+ result.lastSkill = skillName.split(":").pop() || skillName;
993
+ }
994
+ } else if (name === "TodoWrite" || name === "proxy_TodoWrite") {
995
+ if (Array.isArray(input.todos)) {
996
+ result.todos = input.todos;
997
+ }
998
+ } else {
999
+ result.tools++;
1000
+ }
1001
+
1002
+ pendingToolUse = {
1003
+ id,
1004
+ toolName: name.replace(/^proxy_/, ""),
1005
+ target: input.command || input.filePath || input.path || "",
1006
+ };
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+ if (entry.type === "tool" || entry.type === "tool_result") {
1012
+ const useId = entry.tool_use_id || entry.id || "";
1013
+ if (useId) {
1014
+ resolvedIds.add(useId);
1015
+ if (agentMap.has(useId)) {
1016
+ agentMap.delete(useId);
1017
+ }
1018
+ if (pendingToolUse && pendingToolUse.id === useId) {
1019
+ pendingToolUse = null;
1020
+ }
1021
+ }
1022
+ }
1023
+ } catch {
1024
+ // skip unparseable lines
1025
+ }
1026
+ }
1027
+
1028
+ const now = Date.now();
1029
+ for (const [id, agent] of agentMap) {
1030
+ if (!resolvedIds.has(id) && now - agent.startTime < STALE_MS) {
1031
+ result.runningAgentCount++;
1032
+ }
1033
+ }
1034
+
1035
+ result.thinkingActive = lastThinkingTs > 0;
1036
+
1037
+ if (pendingToolUse && !resolvedIds.has(pendingToolUse.id)) {
1038
+ result.pendingPermission = {
1039
+ toolName: pendingToolUse.toolName,
1040
+ targetSummary: pendingToolUse.target ? String(pendingToolUse.target).slice(0, 40) : "",
1041
+ };
1042
+ }
1043
+ } catch {
1044
+ // ignore read errors
1045
+ }
1046
+ return result;
1047
+ }
1048
+
1049
+ function renderRalph(ralph, thresholds) {
1050
+ if (!ralph?.active) return null;
1051
+ const { iteration, maxIterations } = ralph;
1052
+ const ralphWarn = thresholds?.ralphWarning ?? 7;
1053
+ const criticalThreshold = Math.floor(maxIterations * 0.9);
1054
+ let colorFn = green;
1055
+ if (iteration >= criticalThreshold) colorFn = red;
1056
+ else if (iteration >= ralphWarn) colorFn = yellow;
1057
+ return `ralph:${colorFn(`${iteration}/${maxIterations}`)}`;
1058
+ }
1059
+
1060
+ function renderAutopilot(autopilot) {
1061
+ if (!autopilot?.active) return null;
1062
+ const phaseNames = {
1063
+ expansion: "Expand",
1064
+ planning: "Plan",
1065
+ execution: "Build",
1066
+ qa: "QA",
1067
+ validation: "Verify",
1068
+ complete: "Done",
1069
+ failed: "Failed",
1070
+ };
1071
+ const phaseIndex = { expansion: 1, planning: 2, execution: 3, qa: 4, validation: 5, complete: 5, failed: 0 };
1072
+ const { phase, tasksCompleted, tasksTotal } = autopilot;
1073
+ const phaseNum = phaseIndex[phase] || 0;
1074
+ const phaseName = phaseNames[phase] || phase;
1075
+ let phaseColor = cyan;
1076
+ if (phase === "complete") phaseColor = green;
1077
+ else if (phase === "failed") phaseColor = red;
1078
+ else if (phase === "qa") phaseColor = yellow;
1079
+ else if (phase === "validation") phaseColor = magenta;
1080
+ let output = `${cyan("[AUTOPILOT]")} Phase ${phaseColor(`${phaseNum}/5`)}: ${phaseName}`;
1081
+ if (phase === "execution" && tasksTotal > 0) {
1082
+ const taskColor = tasksCompleted === tasksTotal ? green : yellow;
1083
+ output += ` | Tasks: ${taskColor(`${tasksCompleted || 0}/${tasksTotal}`)}`;
1084
+ }
1085
+ return output;
1086
+ }
1087
+
1088
+ function renderLastSkill(skillName) {
1089
+ if (!skillName) return null;
1090
+ return cyan(`skill:${skillName}`);
1091
+ }
1092
+
1093
+ function renderThinking(active, format) {
1094
+ if (!active) return null;
1095
+ switch (format) {
1096
+ case "bubble":
1097
+ return "\u{1F4AD}";
1098
+ case "brain":
1099
+ return "\u{1F9E0}";
1100
+ case "face":
1101
+ return "\u{1F914}";
1102
+ case "text":
1103
+ default:
1104
+ return cyan("thinking");
1105
+ }
1106
+ }
1107
+
1108
+ function renderRunningAgents(count) {
1109
+ if (count <= 0) return null;
1110
+ return `agents:${cyan(String(count))}`;
1111
+ }
1112
+
1113
+ function renderBackgroundTasks(tasks) {
1114
+ if (!tasks || tasks.length === 0) return null;
1115
+ const running = tasks.length;
1116
+ const MAX = 5;
1117
+ let colorFn = green;
1118
+ if (running >= MAX) colorFn = yellow;
1119
+ else if (running >= MAX - 1) colorFn = cyan;
1120
+ return `bg:${colorFn(`${running}/${MAX}`)}`;
1121
+ }
1122
+
1123
+ function renderVerificationStatus(state) {
1124
+ if (!state) return dim("verification: unknown");
1125
+ if (state.status === "no_active_run") {
1126
+ return dim("verification: no active run");
1127
+ }
1128
+ const { status, blockers, evidence_links, progress } = state;
1129
+ const blockerCount = blockers.length;
1130
+ const latestEvidence = evidence_links.length > 0
1131
+ ? evidence_links[evidence_links.length - 1]
1132
+ : null;
1133
+ const evidenceSuffix = latestEvidence
1134
+ ? ` ${dim(`evidence:${basename(latestEvidence)}`)}`
1135
+ : "";
1136
+
1137
+ // Build progress suffix from step/total when available
1138
+ const step = progress && typeof progress.step === "number" ? progress.step : null;
1139
+ const total = progress && typeof progress.total === "number" ? progress.total : null;
1140
+ const currentStage = progress && progress.current_stage ? progress.current_stage : null;
1141
+ let progressSuffix = "";
1142
+ if (step !== null && total !== null && status === "running") {
1143
+ progressSuffix = ` ${dim(`[${step}/${total}]`)}`;
1144
+ if (currentStage) {
1145
+ progressSuffix += ` ${dim(currentStage)}`;
1146
+ }
1147
+ }
1148
+
1149
+ if (status === "ok") {
1150
+ return green("\u2713 verification ok") + evidenceSuffix;
1151
+ }
1152
+ if (status === "running") {
1153
+ return yellow("\u27F3 verification running") + progressSuffix + evidenceSuffix;
1154
+ }
1155
+ if (status === "error" || status === "blocked") {
1156
+ const blockerSuffix = blockerCount > 0 ? ` (${blockerCount} blockers)` : "";
1157
+ return red(`\u2717 verification blocked${blockerSuffix}`) + evidenceSuffix;
1158
+ }
1159
+ return dim("verification: unknown");
1160
+ }
1161
+
1162
+ function renderTodos(todos) {
1163
+ if (!todos || todos.length === 0) return null;
1164
+ const completed = todos.filter((t) => t.status === "completed").length;
1165
+ const total = todos.length;
1166
+ const pct = (completed / total) * 100;
1167
+ let colorFn = cyan;
1168
+ if (pct >= 80) colorFn = green;
1169
+ else if (pct >= 50) colorFn = yellow;
1170
+ const inProgress = todos.find((t) => t.status === "in_progress");
1171
+ let result = `todos:${colorFn(`${completed}/${total}`)}`;
1172
+ if (inProgress) {
1173
+ const desc = (inProgress.content || "...").slice(0, 30);
1174
+ result += ` ${dim(`(working: ${desc})`)}`;
1175
+ }
1176
+ return result;
1177
+ }
1178
+
1179
+ function renderPermission(pending) {
1180
+ if (!pending) return null;
1181
+ return `${yellow("APPROVE?")} ${dim(pending.toolName.toLowerCase())}:${pending.targetSummary}`;
1182
+ }
1183
+
1184
+ function renderPrd(prd) {
1185
+ if (!prd) return null;
1186
+ const { currentStoryId, completed, total } = prd;
1187
+ if (total > 0 && completed === total) return green("PRD:done");
1188
+ if (currentStoryId) {
1189
+ const progress = total > 0 ? ` ${dim(`(${completed}/${total})`)}` : "";
1190
+ return `${cyan(currentStoryId)}${progress}`;
1191
+ }
1192
+ if (total > 0) return dim(`PRD:${completed}/${total}`);
1193
+ return null;
1194
+ }
1195
+
1196
+ function readRateLimits() {
1197
+ const claudeDir = getClaudeConfigDir();
1198
+ const cachePaths = [
1199
+ join(claudeDir, "omg-runtime", ".usage-cache.json"),
1200
+ join(claudeDir, "plugins", "oh-my-claudecode", ".usage-cache.json"),
1201
+ join(claudeDir, ".omg", "usage-cache.json"),
1202
+ join(homedir(), ".omg", "usage-cache.json"),
1203
+ ];
1204
+ for (const p of cachePaths) {
1205
+ const raw = readJsonSafe(p);
1206
+ if (!raw) continue;
1207
+ // Handle wrapped format: { timestamp, data, source }
1208
+ const data = raw.data ?? raw;
1209
+ if (data.hourly || data.daily || data.weekly) return data;
1210
+ if (typeof data.fiveHourPercent === "number" || typeof data.weeklyPercent === "number") return data;
1211
+ }
1212
+ return null;
1213
+ }
1214
+
1215
+ function toNumberOrZero(value) {
1216
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
1217
+ }
1218
+
1219
+ function getSessionTokenTotal(stdin) {
1220
+ const usage = stdin?.context_window?.current_usage ?? {};
1221
+ const input = toNumberOrZero(usage.input_tokens);
1222
+ const output = toNumberOrZero(usage.output_tokens);
1223
+ const cacheCreation = toNumberOrZero(usage.cache_creation_input_tokens);
1224
+ const cacheRead = toNumberOrZero(usage.cache_read_input_tokens);
1225
+ const total = input + output + cacheCreation + cacheRead;
1226
+ return total > 0 ? total : null;
1227
+ }
1228
+
1229
+ function formatDateKeyLocal(date) {
1230
+ const y = String(date.getFullYear());
1231
+ const m = String(date.getMonth() + 1).padStart(2, "0");
1232
+ const d = String(date.getDate()).padStart(2, "0");
1233
+ return `${y}-${m}-${d}`;
1234
+ }
1235
+
1236
+ function formatDateKeyUtc(date) {
1237
+ const y = String(date.getUTCFullYear());
1238
+ const m = String(date.getUTCMonth() + 1).padStart(2, "0");
1239
+ const d = String(date.getUTCDate()).padStart(2, "0");
1240
+ return `${y}-${m}-${d}`;
1241
+ }
1242
+
1243
+ function getDateKeysForLastDays(days) {
1244
+ const keys = new Set();
1245
+ const now = new Date();
1246
+ for (let i = 0; i < days; i++) {
1247
+ const day = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
1248
+ keys.add(formatDateKeyLocal(day));
1249
+ keys.add(formatDateKeyUtc(day));
1250
+ }
1251
+ return keys;
1252
+ }
1253
+
1254
+ function getStatsDailyModelTokens() {
1255
+ const claudeDir = getClaudeConfigDir();
1256
+ const statsPath = join(claudeDir, "stats-cache.json");
1257
+ const stats = readJsonSafe(statsPath);
1258
+ if (!stats || !Array.isArray(stats.dailyModelTokens)) return [];
1259
+ return stats.dailyModelTokens;
1260
+ }
1261
+
1262
+ function sumTokensByDateKeys(rows, dateKeys) {
1263
+ let total = 0;
1264
+ for (const row of rows) {
1265
+ if (!row || typeof row !== "object") continue;
1266
+ const dateKey = typeof row.date === "string" ? row.date : null;
1267
+ if (!dateKey || !dateKeys.has(dateKey)) continue;
1268
+
1269
+ const tokensByModel = row.tokensByModel;
1270
+ if (!tokensByModel || typeof tokensByModel !== "object") continue;
1271
+ for (const value of Object.values(tokensByModel)) {
1272
+ total += toNumberOrZero(value);
1273
+ }
1274
+ }
1275
+ return total > 0 ? total : null;
1276
+ }
1277
+
1278
+ function getDailyTokenTotalFromStatsCache() {
1279
+ const rows = getStatsDailyModelTokens();
1280
+ if (rows.length === 0) return null;
1281
+ const today = new Date();
1282
+ const keys = new Set([formatDateKeyLocal(today), formatDateKeyUtc(today)]);
1283
+ return sumTokensByDateKeys(rows, keys);
1284
+ }
1285
+
1286
+ function getWeeklyTokenTotalFromStatsCache() {
1287
+ const rows = getStatsDailyModelTokens();
1288
+ if (rows.length === 0) return null;
1289
+ const keys = getDateKeysForLastDays(7);
1290
+ return sumTokensByDateKeys(rows, keys);
1291
+ }
1292
+
1293
+ function formatTokenCount(value) {
1294
+ const n = Math.max(0, Math.round(Number(value) || 0));
1295
+ if (n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1)}B`;
1296
+ if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
1297
+ if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
1298
+ return String(n);
1299
+ }
1300
+
1301
+ function renderTokenUsageTotals(sessionTotal, dailyTotal, weeklyTotal) {
1302
+ // Only show token counts when we have actual data from stats-cache
1303
+ // Rate limits (session: X%; weekly: Y%) are shown separately by renderRateLimits
1304
+ const parts = [];
1305
+ if (typeof sessionTotal === "number" && sessionTotal > 0) {
1306
+ parts.push(`session:${green(formatTokenCount(sessionTotal))}`);
1307
+ }
1308
+ if (typeof dailyTotal === "number" && dailyTotal > 0) {
1309
+ parts.push(`daily:${green(formatTokenCount(dailyTotal))}`);
1310
+ }
1311
+ if (typeof weeklyTotal === "number" && weeklyTotal > 0) {
1312
+ parts.push(`weekly:${green(formatTokenCount(weeklyTotal))}`);
1313
+ }
1314
+ return parts.length > 0 ? parts.join("; ") : null;
1315
+ }
1316
+
1317
+ function formatResetTime(dateStr) {
1318
+ if (!dateStr) return null;
1319
+ const resetMs = new Date(dateStr).getTime();
1320
+ const diffMs = resetMs - Date.now();
1321
+ if (diffMs <= 0 || isNaN(diffMs)) return null;
1322
+ const diffMinutes = Math.floor(diffMs / 60000);
1323
+ const diffHours = Math.floor(diffMinutes / 60);
1324
+ const diffDays = Math.floor(diffHours / 24);
1325
+ if (diffDays > 0) {
1326
+ return `${diffDays}d${diffHours % 24}h`;
1327
+ }
1328
+ return `${diffHours}h${diffMinutes % 60}m`;
1329
+ }
1330
+
1331
+ function renderRateLimits(limits) {
1332
+ if (!limits) return null;
1333
+ let sessionPart = null;
1334
+ let weeklyPart = null;
1335
+
1336
+ // Session token limit (5-hour rolling window)
1337
+ if (limits.hourly) {
1338
+ const h = limits.hourly;
1339
+ const pct = h.limit > 0 ? Math.round((1 - h.remaining / h.limit) * 100) : 0;
1340
+ const safePct = Math.min(100, Math.max(0, pct));
1341
+ const leftPct = Math.max(0, 100 - safePct);
1342
+ const reset = formatResetTime(h.resetsAt);
1343
+ const resetPart = reset ? dim(` (${reset})`) : "";
1344
+ sessionPart = `session:${green(`${leftPct}%`)}${resetPart}`;
1345
+ } else if (typeof limits.fiveHourPercent === "number") {
1346
+ const p = Math.min(100, Math.max(0, Math.round(limits.fiveHourPercent)));
1347
+ const leftPct = Math.max(0, 100 - p);
1348
+ const reset = formatResetTime(limits.fiveHourResetsAt);
1349
+ const resetPart = reset ? dim(` (${reset})`) : "";
1350
+ sessionPart = `session:${green(`${leftPct}%`)}${resetPart}`;
1351
+ }
1352
+
1353
+ // Weekly token limit
1354
+ if (limits.weekly) {
1355
+ const w = limits.weekly;
1356
+ const pct = w.limit > 0 ? Math.round((1 - w.remaining / w.limit) * 100) : 0;
1357
+ const safePct = Math.min(100, Math.max(0, pct));
1358
+ const leftPct = Math.max(0, 100 - safePct);
1359
+ const reset = formatResetTime(w.resetsAt);
1360
+ const resetPart = reset ? dim(` (${reset})`) : "";
1361
+ weeklyPart = `weekly:${green(`${leftPct}%`)}${resetPart}`;
1362
+ } else if (typeof limits.weeklyPercent === "number") {
1363
+ const p = Math.min(100, Math.max(0, Math.round(limits.weeklyPercent)));
1364
+ const leftPct = Math.max(0, 100 - p);
1365
+ const reset = formatResetTime(limits.weeklyResetsAt);
1366
+ const resetPart = reset ? dim(` (${reset})`) : "";
1367
+ weeklyPart = `weekly:${green(`${leftPct}%`)}${resetPart}`;
1368
+ }
1369
+ if (sessionPart && weeklyPart) return `${sessionPart}; ${weeklyPart}`;
1370
+ return sessionPart || weeklyPart;
1371
+ }
1372
+
1373
+ function toSafeText(text) {
1374
+ const ansiColorCodeRegex = new RegExp("\\x1b\\[[0-9;]*m", "g");
1375
+ return String(text)
1376
+ .replace(ansiColorCodeRegex, "")
1377
+ .replace(/⚠/g, "WARN");
1378
+ }
1379
+
1380
+ function limitOutputLines(lines, maxLines) {
1381
+ const limit = Math.max(1, Number(maxLines) || DEFAULT_HUD_CONFIG.elements.maxOutputLines);
1382
+ return lines.slice(0, limit);
1383
+ }
1384
+
1385
+ async function main() {
1386
+ try {
1387
+ const stdin = await readStdin();
1388
+ if (!stdin) {
1389
+ console.log(`${bold("[OMG]")} waiting...`);
1390
+ return;
1391
+ }
1392
+
1393
+ const cfg = readHudConfig();
1394
+ const cwd = stdin.cwd || process.cwd();
1395
+ const ctxPct = getContextPercent(stdin);
1396
+ const model = getModelShort(stdin, cfg.elements.modelFormat || "short");
1397
+ const duration = sessionDuration(stdin.transcript_path);
1398
+ const omgState = readOmgState(cwd);
1399
+ const transcript = parseTranscript(stdin.transcript_path);
1400
+ const rateLimits = readRateLimits();
1401
+ const sessionTokenTotal = getSessionTokenTotal(stdin);
1402
+ const dailyTokenTotal = getDailyTokenTotalFromStatsCache();
1403
+ const weeklyTokenTotal = getWeeklyTokenTotalFromStatsCache();
1404
+ const git = getGitInfo(cwd);
1405
+ const promptTime = getLastPromptTime(cwd);
1406
+ const inventory = getRuntimeInventory();
1407
+
1408
+ const warning = Number(cfg.thresholds.contextWarning ?? 60);
1409
+ const critical = Number(cfg.thresholds.contextCritical ?? 85);
1410
+ const compactThreshold = getCompactWarningThreshold(stdin, cfg, cwd);
1411
+
1412
+ const els = [];
1413
+
1414
+ // Git info (optional, on same line in OMG)
1415
+ if (cfg.elements.cwd) {
1416
+ const cwdText = renderCwd(cwd, cfg.elements.cwdFormat || "relative");
1417
+ if (cwdText) els.push(`\u{1F4C1}${dim("dir:")}${dim(cwdText)}`);
1418
+ }
1419
+ if (cfg.elements.gitRepo && git.repo) {
1420
+ els.push(dim(git.repo));
1421
+ }
1422
+ if (cfg.elements.gitBranch && git.branch) {
1423
+ els.push(dim(git.branch));
1424
+ }
1425
+
1426
+ // [OMG#X.Y.Z] label
1427
+ if (cfg.elements.omcLabel !== false) {
1428
+ els.push(bold(`[OMG#${OMG_VERSION}]`));
1429
+ }
1430
+
1431
+ // Rate limits
1432
+ if (cfg.elements.rateLimits !== false) {
1433
+ const rl = renderRateLimits(rateLimits);
1434
+ if (rl) els.push(rl);
1435
+ }
1436
+
1437
+ const totals = renderTokenUsageTotals(sessionTokenTotal, dailyTokenTotal, weeklyTokenTotal);
1438
+ if (totals) els.push(totals);
1439
+
1440
+ // Permission status (disabled by default)
1441
+ if (cfg.elements.permissionStatus && transcript.pendingPermission) {
1442
+ const perm = renderPermission(transcript.pendingPermission);
1443
+ if (perm) els.push(perm);
1444
+ }
1445
+
1446
+ // Thinking indicator
1447
+ if (cfg.elements.thinking && transcript.thinkingActive) {
1448
+ const think = renderThinking(true, cfg.elements.thinkingFormat || "text");
1449
+ if (think) els.push(think);
1450
+ }
1451
+
1452
+ // Prompt time
1453
+ if (cfg.elements.promptTime && promptTime) {
1454
+ els.push(`prompt:${green(promptTime)}`);
1455
+ }
1456
+
1457
+ // Session duration
1458
+ if (cfg.elements.sessionHealth !== false && duration) {
1459
+ els.push(`session:${green(duration)}`);
1460
+ }
1461
+
1462
+ // Ralph (rich format)
1463
+ if (cfg.elements.ralph !== false && omgState.ralph) {
1464
+ const ralphEl = renderRalph(omgState.ralph, cfg.thresholds);
1465
+ if (ralphEl) els.push(ralphEl);
1466
+ }
1467
+
1468
+ // Autopilot (rich format)
1469
+ if (cfg.elements.autopilot !== false && omgState.autopilot) {
1470
+ const apEl = renderAutopilot(omgState.autopilot);
1471
+ if (apEl) els.push(apEl);
1472
+ }
1473
+
1474
+ // PRD story
1475
+ if (cfg.elements.prdStory && omgState.prd) {
1476
+ const prdEl = renderPrd(omgState.prd);
1477
+ if (prdEl) els.push(prdEl);
1478
+ }
1479
+
1480
+ // Active skills (modes) + last skill
1481
+ if (cfg.elements.activeSkills !== false) {
1482
+ if (omgState.currentMode) {
1483
+ els.push(`mode:${cyan(omgState.currentMode)}`);
1484
+ }
1485
+ const modeBadges = renderModeBadges(omgState.modes, {
1486
+ hideRalph: !!omgState.ralph,
1487
+ hideAutopilot: !!omgState.autopilot,
1488
+ });
1489
+ if (modeBadges) els.push(modeBadges);
1490
+ // Last skill from transcript
1491
+ if (cfg.elements.lastSkill !== false && transcript.lastSkill) {
1492
+ // Don't show if skill name matches an active mode
1493
+ if (!omgState.modes.some((m) => m.startsWith(transcript.lastSkill))) {
1494
+ const skillEl = renderLastSkill(transcript.lastSkill);
1495
+ if (skillEl) els.push(skillEl);
1496
+ }
1497
+ }
1498
+ } else if (cfg.elements.lastSkill !== false && transcript.lastSkill) {
1499
+ const skillEl = renderLastSkill(transcript.lastSkill);
1500
+ if (skillEl) els.push(skillEl);
1501
+ }
1502
+
1503
+ // Context bar
1504
+ if (cfg.elements.contextBar !== false) {
1505
+ let suffix = "";
1506
+ if (ctxPct >= critical) suffix = " CRITICAL";
1507
+ else if (ctxPct >= compactThreshold) suffix = " COMPRESS?";
1508
+ const ctxLabel = cfg.elements.useBars ? `${renderBar(ctxPct)} ${ctxPct}%${suffix}` : `${ctxPct}%${suffix}`;
1509
+ els.push(`\u{1F9E0}context:${colorByPercent(ctxPct, ctxLabel, warning, critical)}`);
1510
+ }
1511
+
1512
+ // Active agents
1513
+ if (cfg.elements.agents !== false) {
1514
+ const agentsEl = renderRunningAgents(transcript.runningAgentCount);
1515
+ if (agentsEl) els.push(agentsEl);
1516
+ }
1517
+
1518
+ // Runtime inventory (installed components)
1519
+ if (cfg.elements.inventory !== false) {
1520
+ const invEl = renderInventory(inventory);
1521
+ if (invEl) els.push(invEl);
1522
+ }
1523
+
1524
+ // Background tasks
1525
+ if (cfg.elements.backgroundTasks) {
1526
+ const bgEl = renderBackgroundTasks(omgState.backgroundTasks);
1527
+ if (bgEl) els.push(bgEl);
1528
+ }
1529
+
1530
+ const verificationStateDir = join(cwd, ".omg", "state");
1531
+ const verificationState = readVerificationState(verificationStateDir);
1532
+ els.push(renderVerificationStatus(verificationState));
1533
+
1534
+ // Session health monitor
1535
+ if (cfg.elements.sessionHealth !== false) {
1536
+ const sessionHealth =
1537
+ readSessionHealthFromStdin(stdin) ||
1538
+ readLatestSessionHealth(verificationStateDir);
1539
+ const healthEl = renderSessionHealth(sessionHealth);
1540
+ if (healthEl) els.push(healthEl);
1541
+ }
1542
+
1543
+ // Model name
1544
+ if (cfg.elements.model !== false && model && model !== "?") {
1545
+ els.push(dim(model));
1546
+ }
1547
+
1548
+ const details = [];
1549
+ if (ctxPct >= compactThreshold) {
1550
+ details.push(red(` ⚠ context at ${ctxPct}% — consider /compact`));
1551
+ }
1552
+ // Todos detail line
1553
+ if (cfg.elements.todos) {
1554
+ const todosEl = renderTodos(transcript.todos);
1555
+ if (todosEl) details.push(` ${todosEl}`);
1556
+ }
1557
+
1558
+ const sep = dim(" | ");
1559
+ const lines = [els.join(sep), ...details];
1560
+ const safeMode = cfg.elements.safeMode !== false;
1561
+ const finalLines = limitOutputLines(lines, cfg.elements.maxOutputLines).map((line) =>
1562
+ safeMode ? toSafeText(line) : line
1563
+ );
1564
+ console.log(finalLines.join("\n"));
1565
+ } catch (err) {
1566
+ console.log(`${bold("[OMG]")} HUD error`);
1567
+ console.error("[OMG HUD Error]", err instanceof Error ? err.message : err);
1568
+ }
1569
+ }
1570
+
1571
+ main();