monomind 2.5.1 → 2.5.3

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 (324) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/packages/@monomind/cli/.claude/agents/design/design-monodesign.md +6 -6
  4. package/packages/@monomind/cli/.claude/agents/github/repo-architect.md +3 -3
  5. package/packages/@monomind/cli/.claude/agents/github/sync-coordinator.md +2 -2
  6. package/packages/@monomind/cli/.claude/agents/specialists/integration-architect.md +4 -4
  7. package/packages/@monomind/cli/.claude/commands/github/repo-architect.md +4 -4
  8. package/packages/@monomind/cli/.claude/commands/github/sync-coordinator.md +2 -2
  9. package/packages/@monomind/cli/.claude/commands/mastermind/_repeat.md +4 -4
  10. package/packages/@monomind/cli/.claude/commands/mastermind/approvev1.md +4 -4
  11. package/packages/@monomind/cli/.claude/commands/mastermind/architect.md +6 -6
  12. package/packages/@monomind/cli/.claude/commands/mastermind/autodev.md +5 -5
  13. package/packages/@monomind/cli/.claude/commands/mastermind/brain.md +2 -2
  14. package/packages/@monomind/cli/.claude/commands/mastermind/build.md +6 -6
  15. package/packages/@monomind/cli/.claude/commands/mastermind/code-review.md +2 -2
  16. package/packages/@monomind/cli/.claude/commands/mastermind/content.md +6 -6
  17. package/packages/@monomind/cli/.claude/commands/mastermind/createorg.md +4 -4
  18. package/packages/@monomind/cli/.claude/commands/mastermind/createtask.md +3 -3
  19. package/packages/@monomind/cli/.claude/commands/mastermind/debug.md +5 -5
  20. package/packages/@monomind/cli/.claude/commands/mastermind/design.md +5 -5
  21. package/packages/@monomind/cli/.claude/commands/mastermind/do.md +2 -2
  22. package/packages/@monomind/cli/.claude/commands/mastermind/execute.md +5 -5
  23. package/packages/@monomind/cli/.claude/commands/mastermind/finance.md +6 -6
  24. package/packages/@monomind/cli/.claude/commands/mastermind/finish.md +5 -5
  25. package/packages/@monomind/cli/.claude/commands/mastermind/idea.md +6 -6
  26. package/packages/@monomind/cli/.claude/commands/mastermind/ideate.md +5 -5
  27. package/packages/@monomind/cli/.claude/commands/mastermind/improve.md +6 -6
  28. package/packages/@monomind/cli/.claude/commands/mastermind/marketing.md +6 -6
  29. package/packages/@monomind/cli/.claude/commands/mastermind/master.md +54 -54
  30. package/packages/@monomind/cli/.claude/commands/mastermind/ops.md +6 -6
  31. package/packages/@monomind/cli/.claude/commands/mastermind/orgs.md +2 -2
  32. package/packages/@monomind/cli/.claude/commands/mastermind/orgstatus.md +2 -2
  33. package/packages/@monomind/cli/.claude/commands/mastermind/plan.md +5 -5
  34. package/packages/@monomind/cli/.claude/commands/mastermind/receive-review.md +5 -5
  35. package/packages/@monomind/cli/.claude/commands/mastermind/release.md +6 -6
  36. package/packages/@monomind/cli/.claude/commands/mastermind/research.md +6 -6
  37. package/packages/@monomind/cli/.claude/commands/mastermind/review.md +6 -6
  38. package/packages/@monomind/cli/.claude/commands/mastermind/runorg.md +4 -4
  39. package/packages/@monomind/cli/.claude/commands/mastermind/runorgv1.md +5 -5
  40. package/packages/@monomind/cli/.claude/commands/mastermind/sales.md +6 -6
  41. package/packages/@monomind/cli/.claude/commands/mastermind/skill-builder.md +5 -5
  42. package/packages/@monomind/cli/.claude/commands/mastermind/stoporg.md +3 -3
  43. package/packages/@monomind/cli/.claude/commands/mastermind/taskdev.md +5 -5
  44. package/packages/@monomind/cli/.claude/commands/mastermind/tdd.md +5 -5
  45. package/packages/@monomind/cli/.claude/commands/mastermind/techport.md +5 -5
  46. package/packages/@monomind/cli/.claude/commands/mastermind/verify.md +5 -5
  47. package/packages/@monomind/cli/.claude/commands/mastermind/worktree.md +5 -5
  48. package/packages/@monomind/cli/.claude/helpers/control-start.cjs +30 -0
  49. package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +2 -2
  50. package/packages/@monomind/cli/.claude/helpers/extras-registry.json +1 -1
  51. package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +2 -2
  52. package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +2 -2
  53. package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +1 -1
  54. package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +1 -1
  55. package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +1 -1
  56. package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +11 -11
  57. package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +2 -2
  58. package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +8 -8
  59. package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +44 -12
  60. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/access.md → mastermind-access/SKILL.md} +2 -2
  61. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/activity.md → mastermind-activity/SKILL.md} +2 -2
  62. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/adapter-manager.md → mastermind-adapter-manager/SKILL.md} +2 -2
  63. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/adapters.md → mastermind-adapters/SKILL.md} +2 -2
  64. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/agent-detail.md → mastermind-agent-detail/SKILL.md} +2 -2
  65. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/agents.md → mastermind-agents/SKILL.md} +2 -2
  66. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/approval-detail.md → mastermind-approval-detail/SKILL.md} +2 -2
  67. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/approvev1.md → mastermind-approvev1/SKILL.md} +2 -2
  68. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/architect.md → mastermind-architect/SKILL.md} +7 -7
  69. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/autodev.md → mastermind-autodev/SKILL.md} +10 -10
  70. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/backup.md → mastermind-backup/SKILL.md} +2 -2
  71. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/bootstrap.md → mastermind-bootstrap/SKILL.md} +2 -2
  72. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/budgets.md → mastermind-budgets/SKILL.md} +2 -2
  73. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/build.md → mastermind-build/SKILL.md} +5 -5
  74. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/companies.md → mastermind-companies/SKILL.md} +2 -2
  75. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/content.md → mastermind-content/SKILL.md} +5 -5
  76. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/costs.md → mastermind-costs/SKILL.md} +2 -2
  77. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/createorg.md → mastermind-createorg/SKILL.md} +3 -3
  78. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/debug.md → mastermind-debug/SKILL.md} +4 -4
  79. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/_delegation.md → mastermind-delegation/SKILL.md} +1 -1
  80. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/design.md → mastermind-design/SKILL.md} +9 -9
  81. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/diagnose.md → mastermind-diagnose/SKILL.md} +2 -2
  82. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/env.md → mastermind-env/SKILL.md} +2 -2
  83. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/environments.md → mastermind-environments/SKILL.md} +2 -2
  84. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/execute.md → mastermind-execute/SKILL.md} +10 -10
  85. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/export.md → mastermind-export/SKILL.md} +2 -2
  86. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/finance.md → mastermind-finance/SKILL.md} +5 -5
  87. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/goal-detail.md → mastermind-goal-detail/SKILL.md} +2 -2
  88. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/goals.md → mastermind-goals/SKILL.md} +2 -2
  89. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/heartbeatv1.md → mastermind-heartbeatv1/SKILL.md} +2 -2
  90. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/idea.md → mastermind-idea/SKILL.md} +7 -7
  91. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/import.md → mastermind-import/SKILL.md} +2 -2
  92. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/inbox.md → mastermind-inbox/SKILL.md} +2 -2
  93. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/instance.md → mastermind-instance/SKILL.md} +2 -2
  94. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/instance-settings.md → mastermind-instance-settings/SKILL.md} +2 -2
  95. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/invite-landing.md → mastermind-invite-landing/SKILL.md} +2 -2
  96. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/invites.md → mastermind-invites/SKILL.md} +2 -2
  97. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/issue-detail.md → mastermind-issue-detail/SKILL.md} +2 -2
  98. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/issues.md → mastermind-issues/SKILL.md} +2 -2
  99. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/join-queue.md → mastermind-join-queue/SKILL.md} +2 -2
  100. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/liveness.md → mastermind-liveness/SKILL.md} +2 -2
  101. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/marketing.md → mastermind-marketing/SKILL.md} +8 -8
  102. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/memory.md → mastermind-memory/SKILL.md} +2 -2
  103. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/monitor.md → mastermind-monitor/SKILL.md} +2 -2
  104. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/my-issues.md → mastermind-my-issues/SKILL.md} +2 -2
  105. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/new-agent.md → mastermind-new-agent/SKILL.md} +2 -2
  106. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/ops.md → mastermind-ops/SKILL.md} +5 -5
  107. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/org-chart.md → mastermind-org-chart/SKILL.md} +2 -2
  108. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/org-settings.md → mastermind-org-settings/SKILL.md} +2 -2
  109. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/orgs.md → mastermind-orgs/SKILL.md} +1 -1
  110. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/orgstatus.md → mastermind-orgstatus/SKILL.md} +2 -2
  111. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/plan.md → mastermind-plan/SKILL.md} +7 -7
  112. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/plan-to-tasks.md → mastermind-plan-to-tasks/SKILL.md} +2 -2
  113. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/plugin-manager.md → mastermind-plugin-manager/SKILL.md} +2 -2
  114. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/plugin-settings.md → mastermind-plugin-settings/SKILL.md} +2 -2
  115. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/plugins.md → mastermind-plugins/SKILL.md} +2 -2
  116. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/profile.md → mastermind-profile/SKILL.md} +2 -2
  117. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/project-detail.md → mastermind-project-detail/SKILL.md} +2 -2
  118. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/project-workspace.md → mastermind-project-workspace/SKILL.md} +2 -2
  119. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/projects.md → mastermind-projects/SKILL.md} +2 -2
  120. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/_protocol.md → mastermind-protocol/SKILL.md} +3 -3
  121. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/release.md → mastermind-release/SKILL.md} +5 -5
  122. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/_repeat.md → mastermind-repeat/SKILL.md} +2 -2
  123. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/research.md → mastermind-research/SKILL.md} +5 -5
  124. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/review.md → mastermind-review/SKILL.md} +5 -5
  125. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/routine-detail.md → mastermind-routine-detail/SKILL.md} +2 -2
  126. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/routines.md → mastermind-routines/SKILL.md} +2 -2
  127. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/runorgv1.md → mastermind-runorgv1/SKILL.md} +2 -2
  128. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/sales.md → mastermind-sales/SKILL.md} +5 -5
  129. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/search.md → mastermind-search/SKILL.md} +2 -2
  130. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/secrets.md → mastermind-secrets/SKILL.md} +2 -2
  131. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/skill-builder.md → mastermind-skill-builder/SKILL.md} +16 -14
  132. package/packages/@monomind/cli/.claude/skills/mastermind-skills/{skills.md → SKILL.md} +2 -2
  133. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/stoporg.md → mastermind-stoporg/SKILL.md} +2 -2
  134. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/taskdev.md → mastermind-taskdev/SKILL.md} +6 -6
  135. package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-taskdev}/implementer-prompt.md +1 -1
  136. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/tasks.md → mastermind-tasks/SKILL.md} +2 -2
  137. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/tdd.md → mastermind-tdd/SKILL.md} +4 -4
  138. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/techport.md → mastermind-techport/SKILL.md} +6 -6
  139. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/threads.md → mastermind-threads/SKILL.md} +2 -2
  140. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/tree-control.md → mastermind-tree-control/SKILL.md} +2 -2
  141. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/verify.md → mastermind-verify/SKILL.md} +1 -1
  142. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/wiki.md → mastermind-wiki/SKILL.md} +2 -2
  143. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/workspace-detail.md → mastermind-workspace-detail/SKILL.md} +2 -2
  144. package/packages/@monomind/cli/.claude/skills/{mastermind-skills/workspaces.md → mastermind-workspaces/SKILL.md} +2 -2
  145. package/packages/@monomind/cli/.claude/skills/monodesign/SKILL.md +114 -190
  146. package/packages/@monomind/cli/.claude/skills/monodesign/adapt.md +1 -1
  147. package/packages/@monomind/cli/.claude/skills/monodesign/agents/monodesign-asset-producer.md +4 -4
  148. package/packages/@monomind/cli/.claude/skills/monodesign/agents/monodesign-manual-edit-applier.md +103 -0
  149. package/packages/@monomind/cli/.claude/skills/monodesign/audit.md +1 -1
  150. package/packages/@monomind/cli/.claude/skills/monodesign/craft.md +2 -2
  151. package/packages/@monomind/cli/.claude/skills/monodesign/critique.md +1 -1
  152. package/packages/@monomind/cli/.claude/skills/monodesign/init.md +30 -0
  153. package/packages/@monomind/cli/.claude/skills/monodesign/layout.md +36 -0
  154. package/packages/@monomind/cli/.claude/skills/monodesign/live.md +19 -44
  155. package/packages/@monomind/cli/.claude/skills/monodesign/reference/adapt.md +122 -0
  156. package/packages/@monomind/cli/.claude/skills/monodesign/reference/adapt.native.md +58 -0
  157. package/packages/@monomind/cli/.claude/skills/monodesign/reference/android.md +40 -0
  158. package/packages/@monomind/cli/.claude/skills/monodesign/reference/animate.md +39 -11
  159. package/packages/@monomind/cli/.claude/skills/monodesign/reference/antipatterns-catalog.md +67 -16
  160. package/packages/@monomind/cli/.claude/skills/monodesign/reference/audit.md +5 -3
  161. package/packages/@monomind/cli/.claude/skills/monodesign/reference/audit.native.md +139 -0
  162. package/packages/@monomind/cli/.claude/skills/monodesign/reference/bolder.md +71 -64
  163. package/packages/@monomind/cli/.claude/skills/monodesign/reference/brand.md +12 -18
  164. package/packages/@monomind/cli/.claude/skills/monodesign/reference/clarify.md +114 -0
  165. package/packages/@monomind/cli/.claude/skills/monodesign/reference/codex.md +4 -6
  166. package/packages/@monomind/cli/.claude/skills/monodesign/reference/colorize.md +108 -5
  167. package/packages/@monomind/cli/.claude/skills/monodesign/reference/craft.md +70 -143
  168. package/packages/@monomind/cli/.claude/skills/monodesign/reference/critique.md +635 -68
  169. package/packages/@monomind/cli/.claude/skills/monodesign/reference/delight.md +1 -1
  170. package/packages/@monomind/cli/.claude/skills/monodesign/reference/distill.md +1 -1
  171. package/packages/@monomind/cli/.claude/skills/monodesign/reference/document.md +24 -22
  172. package/packages/@monomind/cli/.claude/skills/monodesign/reference/extract.md +1 -1
  173. package/packages/@monomind/cli/.claude/skills/monodesign/reference/hooks.md +22 -29
  174. package/packages/@monomind/cli/.claude/skills/monodesign/reference/init.md +221 -0
  175. package/packages/@monomind/cli/.claude/skills/monodesign/reference/interaction-design.md +0 -6
  176. package/packages/@monomind/cli/.claude/skills/monodesign/reference/ios.md +45 -0
  177. package/packages/@monomind/cli/.claude/skills/monodesign/reference/layout.md +57 -13
  178. package/packages/@monomind/cli/.claude/skills/monodesign/reference/live.md +159 -71
  179. package/packages/@monomind/cli/.claude/skills/monodesign/reference/overdrive.md +1 -1
  180. package/packages/@monomind/cli/.claude/skills/monodesign/reference/personas.md +1 -1
  181. package/packages/@monomind/cli/.claude/skills/monodesign/reference/polish.md +16 -8
  182. package/packages/@monomind/cli/.claude/skills/monodesign/reference/pre-delivery-checklist.md +1 -1
  183. package/packages/@monomind/cli/.claude/skills/monodesign/reference/product.md +1 -3
  184. package/packages/@monomind/cli/.claude/skills/monodesign/reference/quieter.md +1 -1
  185. package/packages/@monomind/cli/.claude/skills/monodesign/reference/shape.md +27 -13
  186. package/packages/@monomind/cli/.claude/skills/monodesign/reference/teach.md +6 -152
  187. package/packages/@monomind/cli/.claude/skills/monodesign/reference/typeset.md +180 -3
  188. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/command-metadata.json +94 -0
  189. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/context-signals.mjs +260 -0
  190. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/context.mjs +1061 -0
  191. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/critique-storage.mjs +416 -0
  192. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detect-csp.mjs +198 -0
  193. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detect.mjs +33 -0
  194. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +1962 -0
  195. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/cli/main.mjs +321 -0
  196. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/design-system.mjs +814 -0
  197. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +5601 -0
  198. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/detect-antipatterns.mjs +50 -0
  199. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/browser/detect-url.mjs +259 -0
  200. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/browser/drivers.mjs +258 -0
  201. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +636 -0
  202. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +1015 -0
  203. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +253 -0
  204. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/visual/screenshot-contrast.mjs +198 -0
  205. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/findings.mjs +12 -0
  206. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/css-regions.mjs +181 -0
  207. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/fixers.mjs +373 -0
  208. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/index.mjs +426 -0
  209. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +198 -0
  210. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/profile/profiler.mjs +166 -0
  211. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +563 -0
  212. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +2995 -0
  213. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/color.mjs +124 -0
  214. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +101 -0
  215. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/fonts.mjs +30 -0
  216. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +148 -0
  217. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/page.mjs +7 -0
  218. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-admin.mjs +661 -0
  219. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-before-edit.mjs +516 -0
  220. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-lib.mjs +1776 -0
  221. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook.mjs +61 -0
  222. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/design-parser.mjs +842 -0
  223. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/is-generated.mjs +69 -0
  224. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +640 -0
  225. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +129 -0
  226. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/provider.mjs +4 -0
  227. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/target-args.mjs +42 -0
  228. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/browser-script-parts.mjs +50 -0
  229. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/completion.mjs +19 -0
  230. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/event-validation.mjs +137 -0
  231. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/insert-ui.mjs +458 -0
  232. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-apply.mjs +939 -0
  233. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-edit-routes.mjs +357 -0
  234. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +152 -0
  235. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/session-store.mjs +293 -0
  236. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/svelte-component.mjs +826 -0
  237. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +274 -0
  238. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/ui-core.mjs +180 -0
  239. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/vocabulary.mjs +36 -0
  240. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-accept.mjs +812 -0
  241. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser-dom.js +146 -0
  242. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser-session.js +123 -0
  243. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser.js +11240 -0
  244. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +1241 -0
  245. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-complete.mjs +75 -0
  246. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +683 -0
  247. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +51 -0
  248. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-inject.mjs +583 -0
  249. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-insert.mjs +272 -0
  250. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +363 -0
  251. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-poll.mjs +384 -0
  252. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-resume.mjs +94 -0
  253. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-server.mjs +1137 -0
  254. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-status.mjs +61 -0
  255. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-target.mjs +30 -0
  256. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-wrap.mjs +894 -0
  257. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live.mjs +297 -0
  258. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/modern-screenshot.umd.js +14 -0
  259. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/palette.mjs +633 -0
  260. package/packages/@monomind/cli/.claude/skills/monodesign/scripts/pin.mjs +221 -0
  261. package/packages/@monomind/cli/.claude/skills/monodesign/teach.md +7 -58
  262. package/packages/@monomind/cli/README.md +1 -1
  263. package/packages/@monomind/cli/dist/src/commands/design-detect.d.ts +7 -1
  264. package/packages/@monomind/cli/dist/src/commands/design-detect.js +131 -38
  265. package/packages/@monomind/cli/dist/src/commands/design-palette.d.ts +0 -1
  266. package/packages/@monomind/cli/dist/src/commands/design-palette.js +2 -3
  267. package/packages/@monomind/cli/dist/src/commands/doc.js +72 -15
  268. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.d.ts +5 -1
  269. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.js +24 -1
  270. package/packages/@monomind/cli/dist/src/commands/doctor.js +3 -3
  271. package/packages/@monomind/cli/dist/src/commands/hooks-workers.d.ts +1 -1
  272. package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +8 -8
  273. package/packages/@monomind/cli/dist/src/commands/init.js +2 -2
  274. package/packages/@monomind/cli/dist/src/commands/org.js +109 -9
  275. package/packages/@monomind/cli/dist/src/index.d.ts +1 -1
  276. package/packages/@monomind/cli/dist/src/index.js +3 -3
  277. package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +5 -5
  278. package/packages/@monomind/cli/dist/src/init/executor.js +17 -6
  279. package/packages/@monomind/cli/dist/src/knowledge/document-pipeline.d.ts +2 -0
  280. package/packages/@monomind/cli/dist/src/knowledge/document-pipeline.js +4 -1
  281. package/packages/@monomind/cli/dist/src/mcp-server.js +2 -2
  282. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.d.ts +1 -1
  283. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.js +1 -1
  284. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-routing.js +2 -2
  285. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +1 -1
  286. package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +38 -7
  287. package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.d.ts +8 -3
  288. package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.js +193 -31
  289. package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +33 -0
  290. package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +166 -17
  291. package/packages/@monomind/cli/dist/src/memory/memory-kg.d.ts +186 -0
  292. package/packages/@monomind/cli/dist/src/memory/memory-kg.js +450 -0
  293. package/packages/@monomind/cli/dist/src/memory/query-router.d.ts +44 -0
  294. package/packages/@monomind/cli/dist/src/memory/query-router.js +113 -0
  295. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +18 -0
  296. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +249 -12
  297. package/packages/@monomind/cli/dist/src/orgrt/migrate.js +7 -0
  298. package/packages/@monomind/cli/dist/src/orgrt/policy.js +7 -0
  299. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +24 -1
  300. package/packages/@monomind/cli/dist/src/orgrt/session.js +18 -3
  301. package/packages/@monomind/cli/dist/src/orgrt/templates.d.ts +1 -0
  302. package/packages/@monomind/cli/dist/src/orgrt/templates.js +9 -4
  303. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +15 -0
  304. package/packages/@monomind/cli/dist/src/orgrt/types.js +2 -0
  305. package/packages/@monomind/cli/dist/src/routing/embed-worker.js +1 -1
  306. package/packages/@monomind/cli/dist/src/routing/llm-caller.js +1 -1
  307. package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +1 -1
  308. package/packages/@monomind/cli/dist/src/ui/dashboard.html +176 -26
  309. package/packages/@monomind/cli/dist/src/ui/orgs.html +24 -0
  310. package/packages/@monomind/cli/dist/src/ui/server.mjs +162 -12
  311. package/packages/@monomind/cli/dist/src/update/checker.js +3 -3
  312. package/packages/@monomind/cli/package.json +8 -6
  313. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/_agent-select.md → mastermind-agent-select/SKILL.md} +0 -0
  314. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/finish.md → mastermind-finish/SKILL.md} +0 -0
  315. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/_intake.md → mastermind-intake/SKILL.md} +0 -0
  316. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-marketing}/references/copywriting-frameworks.md +0 -0
  317. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-marketing}/references/persuasion-psychology.md +0 -0
  318. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/monotask.md → mastermind-monotask/SKILL.md} +0 -0
  319. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/receive-review.md → mastermind-receive-review/SKILL.md} +0 -0
  320. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/runorg.md → mastermind-runorg/SKILL.md} +0 -0
  321. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-taskdev}/code-quality-reviewer-prompt.md +0 -0
  322. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-taskdev}/final-reviewer-prompt.md +0 -0
  323. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills → mastermind-taskdev}/spec-reviewer-prompt.md +0 -0
  324. /package/packages/@monomind/cli/.claude/skills/{mastermind-skills/worktree.md → mastermind-worktree/SKILL.md} +0 -0
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Anti-Pattern Detector for Monodesign
5
+ * Copyright (c) 2026 Paul Bakaus
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ *
8
+ * Public API facade. Runtime engines live under cli/engine/engines/.
9
+ */
10
+
11
+ import { detectCli } from './cli/main.mjs';
12
+
13
+ export { ANTIPATTERNS, RULE_ENGINE_SUPPORT, getAntipattern, getRulesForCategory, getRuleEngineSupport } from './registry/antipatterns.mjs';
14
+ export { SAFE_TAGS, BORDER_SAFE_TAGS, OVERUSED_FONTS, GENERIC_FONTS, KNOWN_SERIF_FONTS } from './shared/constants.mjs';
15
+ export { isNeutralColor, parseRgb, relativeLuminance, contrastRatio, parseGradientColors, hasChroma, getHue, colorToHex } from './shared/color.mjs';
16
+ export { isFullPage } from './shared/page.mjs';
17
+ export {
18
+ checkElementBorders,
19
+ checkElementMotion,
20
+ checkElementGlow,
21
+ checkPageTypography,
22
+ checkPageLayout,
23
+ checkHtmlPatterns,
24
+ } from './rules/checks.mjs';
25
+ export { createDetectorProfile, summarizeDetectorProfile } from './profile/profiler.mjs';
26
+ export {
27
+ parseFrontmatter as parseDesignFrontmatter,
28
+ normalizeDesignSystem,
29
+ loadDesignSystemForCwd,
30
+ checkSourceDesignSystem,
31
+ collectStaticDesignSystemFindings,
32
+ } from './design-system.mjs';
33
+ export { detectHtml } from './engines/static-html/detect-html.mjs';
34
+ export { detectUrl, createBrowserDetector } from './engines/browser/detect-url.mjs';
35
+ export { detectText, extractStyleBlocks, extractCSSinJS } from './engines/regex/detect-text.mjs';
36
+ export {
37
+ walkDir,
38
+ SCANNABLE_EXTENSIONS,
39
+ SKIP_DIRS,
40
+ buildImportGraph,
41
+ resolveImport,
42
+ detectFrameworkConfig,
43
+ isPortListening,
44
+ FRAMEWORK_CONFIGS,
45
+ } from './node/file-system.mjs';
46
+ export { formatFindings, detectCli } from './cli/main.mjs';
47
+
48
+ const isMainModule = process.argv[1]?.endsWith('detect-antipatterns.mjs') ||
49
+ process.argv[1]?.endsWith('detect-antipatterns.mjs/');
50
+ if (isMainModule) detectCli();
@@ -0,0 +1,259 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ import { finding } from '../../findings.mjs';
6
+ import { filterByProviders } from '../../registry/antipatterns.mjs';
7
+ import { profileFindingsAsync, profileStep, profileStepAsync } from '../../profile/profiler.mjs';
8
+ import { captureVisualContrastCandidate } from '../visual/screenshot-contrast.mjs';
9
+ import { launchDetectionBrowser, normalizeBrowserHandle } from './drivers.mjs';
10
+
11
+ function serializeDesignSystemForBrowser(designSystem) {
12
+ if (!designSystem?.present) return null;
13
+ return {
14
+ present: true,
15
+ hasFonts: designSystem.hasFonts === true,
16
+ allowedFonts: Array.from(designSystem.allowedFonts || []),
17
+ hasColors: designSystem.hasColors === true,
18
+ allowedColors: Array.from(designSystem.allowedColorKeys?.values?.() || [])
19
+ .map(entry => entry?.color)
20
+ .filter(color => color && Number.isFinite(color.r) && Number.isFinite(color.g) && Number.isFinite(color.b))
21
+ .map(color => ({ r: color.r, g: color.g, b: color.b })),
22
+ hasRadii: designSystem.hasRadii === true,
23
+ allowedRadii: (designSystem.allowedRadii || [])
24
+ .map(entry => Number(entry?.px))
25
+ .filter(px => Number.isFinite(px)),
26
+ hasPillRadius: designSystem.hasPillRadius === true,
27
+ };
28
+ }
29
+
30
+ async function runVisualContrastFallback(page, serializedGroups, options, profile, target) {
31
+ if (options?.visualContrast === false) return [];
32
+ const maxCandidates = Number.isFinite(options?.visualContrastMaxCandidates)
33
+ ? options.visualContrastMaxCandidates
34
+ : 12;
35
+ const scrollOffscreen = options?.visualContrastScrollOffscreen !== false;
36
+ const existingLowContrastSelectors = new Set(
37
+ serializedGroups
38
+ .filter(group => group.findings?.some(f => f.type === 'low-contrast'))
39
+ .map(group => group.selector)
40
+ .filter(Boolean)
41
+ );
42
+
43
+ let browserAnalyses = [];
44
+ const findings = [];
45
+ if (options?.visualContrastBrowser !== false) {
46
+ const browserFindings = await profileFindingsAsync(profile, {
47
+ engine: 'browser',
48
+ phase: 'visual-contrast',
49
+ ruleId: 'browser-fallback',
50
+ target,
51
+ }, async () => {
52
+ browserAnalyses = await page.evaluate(async ({ maxCandidates, scrollOffscreen }) => {
53
+ if (typeof window.monodesignAnalyzeVisualContrast !== 'function') return [];
54
+ return window.monodesignAnalyzeVisualContrast({ maxCandidates, scrollOffscreen });
55
+ }, { maxCandidates, scrollOffscreen });
56
+ return browserAnalyses
57
+ .filter(result => result.finding && !existingLowContrastSelectors.has(result.selector))
58
+ .map(result => result.finding);
59
+ });
60
+ findings.push(...browserFindings);
61
+ }
62
+
63
+ let candidates = browserAnalyses.length > 0 ? browserAnalyses : [];
64
+ if (candidates.length === 0) {
65
+ candidates = await profileStepAsync(profile, {
66
+ engine: 'browser',
67
+ phase: 'visual-contrast',
68
+ ruleId: 'collect-candidates',
69
+ target,
70
+ }, () => page.evaluate(({ maxCandidates }) => {
71
+ if (typeof window.monodesignCollectVisualContrastCandidates !== 'function') return [];
72
+ return window.monodesignCollectVisualContrastCandidates({ maxCandidates });
73
+ }, { maxCandidates }));
74
+ }
75
+
76
+ const viewport = options?.viewport || { width: 1280, height: 800 };
77
+ const browserResolvedSelectors = new Set(
78
+ browserAnalyses
79
+ .filter(result => result.status === 'fail' || result.status === 'pass')
80
+ .map(result => result.selector)
81
+ .filter(Boolean)
82
+ );
83
+ const filtered = candidates.filter(candidate =>
84
+ !existingLowContrastSelectors.has(candidate.selector) &&
85
+ !browserResolvedSelectors.has(candidate.selector)
86
+ );
87
+ if (options?.visualContrastPixel === false) return findings;
88
+ for (const candidate of filtered) {
89
+ const result = await profileFindingsAsync(profile, {
90
+ engine: 'browser',
91
+ phase: 'visual-contrast',
92
+ ruleId: 'pixel-diff',
93
+ target,
94
+ }, async () => {
95
+ const finding = await captureVisualContrastCandidate(page, candidate, viewport);
96
+ return finding ? [finding] : [];
97
+ });
98
+ findings.push(...result);
99
+ }
100
+ return findings;
101
+ }
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // Browser detection (for URLs) — driver-based: monobrowse (native CDP,
105
+ // preferred) with puppeteer as fallback. See ./drivers.mjs for the seam.
106
+ // ---------------------------------------------------------------------------
107
+
108
+ async function detectUrl(url, options = {}) {
109
+ const profile = options?.profile;
110
+ const waitUntil = options?.waitUntil || 'networkidle0';
111
+ const settleMs = Number.isFinite(options?.settleMs) ? options.settleMs : 0;
112
+ const viewport = options?.viewport || { width: 1280, height: 800 };
113
+ // options.browser accepts either a driver handle (from createBrowserDetector)
114
+ // or a raw puppeteer Browser (legacy callers).
115
+ const externalBrowser = options?.browser ? normalizeBrowserHandle(options.browser) : null;
116
+
117
+ // Read the browser detection script — reuse it instead of reimplementing
118
+ const browserScriptPath = path.resolve(
119
+ path.dirname(fileURLToPath(import.meta.url)),
120
+ '..',
121
+ '..',
122
+ 'detect-antipatterns-browser.js'
123
+ );
124
+ let browserScript;
125
+ try {
126
+ browserScript = profileStep(profile, {
127
+ engine: 'browser',
128
+ phase: 'setup',
129
+ ruleId: 'read-browser-script',
130
+ target: url,
131
+ }, () => fs.readFileSync(browserScriptPath, 'utf-8'));
132
+ } catch {
133
+ throw new Error(`Browser script not found at ${browserScriptPath}`);
134
+ }
135
+
136
+ const browser = externalBrowser || await profileStepAsync(profile, {
137
+ engine: 'browser',
138
+ phase: 'load',
139
+ ruleId: 'launch-browser',
140
+ target: url,
141
+ }, () => launchDetectionBrowser({ launchArgs: options?.launchArgs, headless: true }));
142
+ const page = await profileStepAsync(profile, {
143
+ engine: 'browser',
144
+ phase: 'load',
145
+ ruleId: 'new-page',
146
+ target: url,
147
+ }, () => browser.newPage());
148
+ let results = [];
149
+ try {
150
+ await profileStepAsync(profile, {
151
+ engine: 'browser',
152
+ phase: 'load',
153
+ ruleId: 'set-viewport',
154
+ target: url,
155
+ }, () => page.setViewport(viewport));
156
+ await profileStepAsync(profile, {
157
+ engine: 'browser',
158
+ phase: 'load',
159
+ ruleId: `goto:${waitUntil}`,
160
+ target: url,
161
+ }, () => page.goto(url, { waitUntil, timeout: 30000 }));
162
+ if (settleMs > 0) {
163
+ await profileStepAsync(profile, {
164
+ engine: 'browser',
165
+ phase: 'load',
166
+ ruleId: 'settle',
167
+ target: url,
168
+ }, () => new Promise(resolve => setTimeout(resolve, settleMs)));
169
+ }
170
+
171
+ // Inject the browser detection script and collect results
172
+ const browserDesignSystem = serializeDesignSystemForBrowser(options?.designSystem);
173
+ await profileStepAsync(profile, {
174
+ engine: 'browser',
175
+ phase: 'scan',
176
+ ruleId: 'configure-pure-detect',
177
+ target: url,
178
+ }, () => page.evaluate((designSystem) => {
179
+ window.__MONODESIGN_CONFIG__ = {
180
+ ...(window.__MONODESIGN_CONFIG__ || {}),
181
+ autoScan: false,
182
+ ...(designSystem ? { designSystem } : {}),
183
+ };
184
+ }, browserDesignSystem));
185
+ await profileStepAsync(profile, {
186
+ engine: 'browser',
187
+ phase: 'scan',
188
+ ruleId: 'inject-browser-script',
189
+ target: url,
190
+ }, () => page.evaluate(browserScript));
191
+ let serializedGroups = [];
192
+ results = await profileFindingsAsync(profile, {
193
+ engine: 'browser',
194
+ phase: 'scan',
195
+ ruleId: 'browser-scan',
196
+ target: url,
197
+ }, async () => {
198
+ serializedGroups = await page.evaluate(() => {
199
+ if (!window.monodesignDetect) return [];
200
+ return window.monodesignDetect({ decorate: false, serialize: true });
201
+ });
202
+ return serializedGroups.flatMap(({ findings }) =>
203
+ findings.map(f => ({ id: f.type, snippet: f.detail, ignoreValue: f.ignoreValue || '' }))
204
+ );
205
+ });
206
+ const visualFindings = await runVisualContrastFallback(page, serializedGroups, options, profile, url);
207
+ results.push(...visualFindings);
208
+ } finally {
209
+ await profileStepAsync(profile, {
210
+ engine: 'browser',
211
+ phase: 'load',
212
+ ruleId: 'close-page',
213
+ target: url,
214
+ }, () => page.close().catch(() => {}));
215
+ if (!externalBrowser) {
216
+ await profileStepAsync(profile, {
217
+ engine: 'browser',
218
+ phase: 'load',
219
+ ruleId: 'close-browser',
220
+ target: url,
221
+ }, () => browser.close());
222
+ }
223
+ }
224
+ return filterByProviders(results.map(f => {
225
+ const item = finding(f.id, url, f.snippet);
226
+ if (f.ignoreValue) item.ignoreValue = f.ignoreValue;
227
+ return item;
228
+ }), options.providers);
229
+ }
230
+
231
+ async function createBrowserDetector(options = {}) {
232
+ // Pooled reuse for multiple URLs. `browser` is a driver handle (monobrowse
233
+ // or puppeteer); pass a raw puppeteer Browser via options.browser to reuse
234
+ // an externally managed instance.
235
+ const browser = options.browser
236
+ ? normalizeBrowserHandle(options.browser)
237
+ : await launchDetectionBrowser({ launchArgs: options.launchArgs, headless: options.headless ?? true });
238
+ const ownsBrowser = !options.browser;
239
+ const defaults = {
240
+ waitUntil: options.waitUntil || 'load',
241
+ settleMs: Number.isFinite(options.settleMs) ? options.settleMs : 100,
242
+ viewport: options.viewport || { width: 1280, height: 800 },
243
+ };
244
+ return {
245
+ browser,
246
+ async detectUrl(url, scanOptions = {}) {
247
+ return detectUrl(url, {
248
+ ...defaults,
249
+ ...scanOptions,
250
+ browser,
251
+ });
252
+ },
253
+ async close() {
254
+ if (ownsBrowser) await browser.close().catch(() => {});
255
+ },
256
+ };
257
+ }
258
+
259
+ export { runVisualContrastFallback, detectUrl, createBrowserDetector };
@@ -0,0 +1,258 @@
1
+ //
2
+ // Browser driver seam for URL detection.
3
+ //
4
+ // The detection engine (detect-url.mjs) and the visual-contrast fallback
5
+ // (engines/visual/screenshot-contrast.mjs) only need a tiny, puppeteer-shaped
6
+ // page surface:
7
+ //
8
+ // browser: { driverName, newPage(): Promise<page>, close(): Promise<void> }
9
+ // page: {
10
+ // setViewport({ width, height })
11
+ // goto(url, { waitUntil, timeout })
12
+ // evaluate(fnOrExpressionString, ...serializableArgs) -> serializable value
13
+ // screenshot({ encoding: 'base64', clip?, captureBeyondViewport? }) -> base64 string
14
+ // close()
15
+ // }
16
+ //
17
+ // Two drivers implement it:
18
+ // - monobrowse (preferred): @monoes/monobrowse, the monorepo's native CDP
19
+ // client. Drives a locally installed Chrome/Edge/Chromium — no bundled
20
+ // Chromium download needed. Supports the full surface including clip
21
+ // screenshots (Page.captureScreenshot) and evaluate roundtrips
22
+ // (Runtime.evaluate), so the visual-contrast pixel fallback runs under it.
23
+ // - puppeteer (fallback): the original optionalDependency path, kept for
24
+ // environments that have puppeteer + its downloaded Chrome but no system
25
+ // browser. A raw puppeteer Page already satisfies the page surface, so the
26
+ // puppeteer driver returns real puppeteer pages untouched.
27
+ //
28
+ // Selection: MONODESIGN_BROWSER_DRIVER=monobrowse|puppeteer forces one;
29
+ // otherwise monobrowse is tried first and puppeteer is the fallback.
30
+
31
+ const DRIVER_ENV = 'MONODESIGN_BROWSER_DRIVER';
32
+
33
+ // Ports we launch headless Chrome on for detection runs. Deliberately away
34
+ // from 9222 (the default `monomind browse` port): we must never attach to a
35
+ // browser we did not launch, because browser.close() issues Browser.close.
36
+ const MONOBROWSE_PORT_MIN = 9520;
37
+ const MONOBROWSE_PORT_RANGE = 380;
38
+
39
+ function serializeEvalArg(arg) {
40
+ const json = JSON.stringify(arg);
41
+ return json === undefined ? 'undefined' : json;
42
+ }
43
+
44
+ function mapWaitUntil(waitUntil) {
45
+ if (waitUntil === 'domcontentloaded') return 'domcontentloaded';
46
+ if (waitUntil === 'networkidle0' || waitUntil === 'networkidle2' || waitUntil === 'networkidle') return 'networkidle';
47
+ return 'load';
48
+ }
49
+
50
+ function withTimeout(promise, ms, label) {
51
+ let handle;
52
+ const timeout = new Promise((_, reject) => {
53
+ handle = setTimeout(() => reject(new Error(`Timeout waiting for ${label} after ${ms}ms`)), ms);
54
+ handle.unref?.();
55
+ });
56
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(handle));
57
+ }
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // monobrowse driver
61
+ // ---------------------------------------------------------------------------
62
+
63
+ function createMonobrowsePage(mb, client, sessionId, targetId, port) {
64
+ return {
65
+ async setViewport({ width, height }) {
66
+ await mb.setViewport(client, sessionId, width, height);
67
+ },
68
+ async goto(url, { waitUntil = 'load', timeout = 30000 } = {}) {
69
+ const condition = mapWaitUntil(waitUntil);
70
+ if (condition === 'networkidle') {
71
+ const nav = await client.send('Page.navigate', { url }, sessionId);
72
+ if (nav?.errorText) throw new Error(`Navigation to ${url} failed: ${nav.errorText}`);
73
+ await mb.waitForLoad(client, sessionId, 'networkidle', timeout);
74
+ return;
75
+ }
76
+ // Register the lifecycle listener BEFORE navigating so a fast page load
77
+ // cannot slip past it (waitForLoad's readyState pre-check would otherwise
78
+ // race against the previous document's readyState).
79
+ const event = condition === 'load' ? 'Page.loadEventFired' : 'Page.domContentEventFired';
80
+ const [eventPromise, cancel] = client.onceWithOff(event, sessionId);
81
+ try {
82
+ const nav = await client.send('Page.navigate', { url }, sessionId);
83
+ if (nav?.errorText) throw new Error(`Navigation to ${url} failed: ${nav.errorText}`);
84
+ await withTimeout(eventPromise, timeout, condition);
85
+ } finally {
86
+ cancel();
87
+ }
88
+ },
89
+ async evaluate(fnOrExpression, ...args) {
90
+ const expression = typeof fnOrExpression === 'function'
91
+ ? `(${String(fnOrExpression)})(${args.map(serializeEvalArg).join(', ')})`
92
+ : String(fnOrExpression);
93
+ const result = await client.send('Runtime.evaluate', {
94
+ expression,
95
+ returnByValue: true,
96
+ awaitPromise: true,
97
+ }, sessionId);
98
+ if (result?.exceptionDetails) {
99
+ const details = result.exceptionDetails;
100
+ throw new Error(details.exception?.description || details.exception?.value || details.text || 'Evaluation failed');
101
+ }
102
+ return result?.result?.value;
103
+ },
104
+ // Always returns a base64 string (the only mode the engine uses).
105
+ async screenshot({ clip } = {}) {
106
+ const params = { format: 'png' };
107
+ if (clip) {
108
+ params.clip = { x: clip.x, y: clip.y, width: clip.width, height: clip.height, scale: 1 };
109
+ params.captureBeyondViewport = true;
110
+ }
111
+ const result = await client.send('Page.captureScreenshot', params, sessionId);
112
+ return result?.data;
113
+ },
114
+ async close() {
115
+ // HTTP endpoint works regardless of which domains the ws connection has.
116
+ try {
117
+ await fetch(`http://127.0.0.1:${port}/json/close/${encodeURIComponent(targetId)}`);
118
+ } catch {
119
+ // Tab may already be gone; browser close cleans up anything left.
120
+ }
121
+ client.close();
122
+ },
123
+ };
124
+ }
125
+
126
+ async function launchMonobrowseBrowser(options = {}) {
127
+ const mb = await import('@monoes/monobrowse');
128
+ const headless = options.headless ?? true;
129
+ const launchArgs = options.launchArgs || (process.env.CI ? ['--no-sandbox', '--disable-setuid-sandbox'] : []);
130
+
131
+ const forcedPort = Number(process.env.MONODESIGN_MONOBROWSE_PORT);
132
+ let port = null;
133
+ if (Number.isInteger(forcedPort) && forcedPort > 0) {
134
+ port = forcedPort;
135
+ } else {
136
+ // Pick a free-looking port; skip ports where a CDP endpoint already
137
+ // listens so we never take over (and later Browser.close) someone
138
+ // else's browser session.
139
+ for (let attempt = 0; attempt < 5 && port === null; attempt++) {
140
+ const candidate = MONOBROWSE_PORT_MIN + Math.floor(Math.random() * MONOBROWSE_PORT_RANGE);
141
+ if (!(await mb.isPortOpen(candidate))) port = candidate;
142
+ }
143
+ if (port === null) throw new Error('Could not find a free CDP port for monobrowse');
144
+ }
145
+
146
+ const launchedPort = await mb.launchBrowser({ port, headless, args: launchArgs });
147
+ // Control connection (to the initial about:blank tab) — used for lifecycle
148
+ // commands; detection pages get their own dedicated connections.
149
+ const control = await mb.connectToTarget(launchedPort);
150
+
151
+ async function openPage() {
152
+ const target = await mb.fetchNewTarget(launchedPort, 'about:blank');
153
+ const wsUrl = target.webSocketDebuggerUrl || `ws://127.0.0.1:${launchedPort}/devtools/page/${target.id}`;
154
+ const client = new mb.CdpClient();
155
+ await client.connect(wsUrl);
156
+ const { sessionId } = await client.send('Target.attachToTarget', { targetId: target.id, flatten: true });
157
+ await Promise.all([
158
+ client.send('Page.enable', {}, sessionId),
159
+ client.send('Runtime.enable', {}, sessionId),
160
+ client.send('Network.enable', {}, sessionId),
161
+ ]);
162
+ return createMonobrowsePage(mb, client, sessionId, target.id, launchedPort);
163
+ }
164
+
165
+ return {
166
+ driverName: 'monobrowse',
167
+ newPage: openPage,
168
+ async close() {
169
+ try {
170
+ if (typeof mb.closeBrowser === 'function') {
171
+ // Newer monobrowse: graceful Browser.close with PID-kill fallback.
172
+ await mb.closeBrowser(control.client, launchedPort);
173
+ } else {
174
+ // Published 1.0.3 has no closeBrowser export — send the CDP
175
+ // Browser.close command directly (best effort, short timeout).
176
+ await withTimeout(control.client.send('Browser.close', {}), 3000, 'Browser.close').catch(() => {});
177
+ }
178
+ } finally {
179
+ control.client.close();
180
+ }
181
+ },
182
+ };
183
+ }
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // puppeteer driver (original behavior, kept as fallback)
187
+ // ---------------------------------------------------------------------------
188
+
189
+ function wrapPuppeteerBrowser(browser) {
190
+ return {
191
+ driverName: 'puppeteer',
192
+ raw: browser,
193
+ newPage: () => browser.newPage(),
194
+ close: () => browser.close(),
195
+ };
196
+ }
197
+
198
+ async function launchPuppeteerBrowser(options = {}) {
199
+ let puppeteer;
200
+ try {
201
+ puppeteer = await import('puppeteer');
202
+ } catch {
203
+ throw new Error('puppeteer is required for URL scanning. Install: npm install puppeteer');
204
+ }
205
+ // CI runners (GitHub Actions Ubuntu) block unprivileged user namespaces, so
206
+ // Chrome can't initialize its sandbox there. Disable the sandbox only when
207
+ // running in CI; local users keep the default hardened launch.
208
+ const launchArgs = options.launchArgs || (process.env.CI ? ['--no-sandbox', '--disable-setuid-sandbox'] : []);
209
+ const browser = await puppeteer.default.launch({
210
+ headless: options.headless ?? true,
211
+ args: launchArgs,
212
+ });
213
+ return wrapPuppeteerBrowser(browser);
214
+ }
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // Selection
218
+ // ---------------------------------------------------------------------------
219
+
220
+ /** Accepts either a driver browser handle or a raw puppeteer Browser. */
221
+ function normalizeBrowserHandle(browser) {
222
+ if (!browser) return null;
223
+ if (browser.driverName && typeof browser.newPage === 'function') return browser;
224
+ if (typeof browser.newPage === 'function') return wrapPuppeteerBrowser(browser);
225
+ throw new Error('Unsupported browser handle passed to detectUrl (expected a driver handle or puppeteer Browser)');
226
+ }
227
+
228
+ async function launchDetectionBrowser(options = {}) {
229
+ const forced = (process.env[DRIVER_ENV] || '').trim().toLowerCase();
230
+ if (forced && forced !== 'monobrowse' && forced !== 'puppeteer') {
231
+ throw new Error(`Invalid ${DRIVER_ENV}=${forced} (expected "monobrowse" or "puppeteer")`);
232
+ }
233
+ const order = forced ? [forced] : ['monobrowse', 'puppeteer'];
234
+ const errors = [];
235
+ for (const name of order) {
236
+ try {
237
+ return name === 'monobrowse'
238
+ ? await launchMonobrowseBrowser(options)
239
+ : await launchPuppeteerBrowser(options);
240
+ } catch (error) {
241
+ errors.push(`${name}: ${error?.message || error}`);
242
+ }
243
+ }
244
+ throw new Error(
245
+ 'A browser is required for URL scanning and no driver could start one ' +
246
+ `(${errors.join(' | ')}). ` +
247
+ 'Install Google Chrome/Chromium/Edge for the native @monoes/monobrowse driver, ' +
248
+ 'or puppeteer is required for URL scanning. Install: npm install puppeteer'
249
+ );
250
+ }
251
+
252
+ export {
253
+ launchDetectionBrowser,
254
+ launchMonobrowseBrowser,
255
+ launchPuppeteerBrowser,
256
+ normalizeBrowserHandle,
257
+ wrapPuppeteerBrowser,
258
+ };