@doxbrix/doxloop 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/CHANGELOG.md +1145 -0
  2. package/README.md +422 -227
  3. package/assets/doxbrix-preview.css +77 -15
  4. package/contracts/agent-events-v1.schema.json +1 -0
  5. package/contracts/coverage-v1.schema.json +59 -0
  6. package/contracts/drift-v1.schema.json +1 -0
  7. package/contracts/evaluation-v1.schema.json +62 -0
  8. package/contracts/quality-codes-v1.json +1 -0
  9. package/contracts/quality-report-v1.schema.json +1 -0
  10. package/contracts/validation-v1.schema.json +1 -0
  11. package/dist/agent-failure.d.ts +36 -0
  12. package/dist/agent-failure.js +98 -0
  13. package/dist/agent-isolation.d.ts +17 -0
  14. package/dist/agent-isolation.js +94 -0
  15. package/dist/agent-log.d.ts +197 -0
  16. package/dist/agent-log.js +1094 -0
  17. package/dist/agent-process.d.ts +63 -0
  18. package/dist/agent-process.js +128 -0
  19. package/dist/agent-reply.d.ts +47 -0
  20. package/dist/agent-reply.js +315 -0
  21. package/dist/agents.d.ts +24 -5
  22. package/dist/agents.js +60 -9
  23. package/dist/api-coverage.d.ts +11 -0
  24. package/dist/api-coverage.js +72 -0
  25. package/dist/application-probe.d.ts +28 -0
  26. package/dist/application-probe.js +93 -0
  27. package/dist/application-url.d.ts +14 -0
  28. package/dist/application-url.js +26 -0
  29. package/dist/args.js +15 -0
  30. package/dist/artifact-deploy.d.ts +9 -0
  31. package/dist/artifact-deploy.js +28 -8
  32. package/dist/assets.d.ts +72 -0
  33. package/dist/assets.js +382 -0
  34. package/dist/auth.d.ts +10 -0
  35. package/dist/auth.js +38 -9
  36. package/dist/author.d.ts +206 -4
  37. package/dist/author.js +1650 -52
  38. package/dist/authoring-batches.d.ts +190 -0
  39. package/dist/authoring-batches.js +489 -0
  40. package/dist/authoring-postpass.d.ts +79 -0
  41. package/dist/authoring-postpass.js +1289 -0
  42. package/dist/authoring-progress.d.ts +95 -0
  43. package/dist/authoring-progress.js +269 -0
  44. package/dist/autosync.d.ts +56 -0
  45. package/dist/autosync.js +442 -0
  46. package/dist/batch-artifacts.d.ts +81 -0
  47. package/dist/batch-artifacts.js +412 -0
  48. package/dist/batch-limits.d.ts +37 -0
  49. package/dist/batch-limits.js +80 -0
  50. package/dist/branding.d.ts +41 -0
  51. package/dist/branding.js +229 -0
  52. package/dist/bundle-upload.d.ts +26 -0
  53. package/dist/bundle-upload.js +99 -0
  54. package/dist/capture-auth.d.ts +95 -0
  55. package/dist/capture-auth.js +204 -0
  56. package/dist/capture.d.ts +48 -0
  57. package/dist/capture.js +20 -1
  58. package/dist/cli.js +839 -32
  59. package/dist/content-links.d.ts +10 -0
  60. package/dist/content-links.js +49 -0
  61. package/dist/contract-validation.d.ts +4 -0
  62. package/dist/contract-validation.js +25 -0
  63. package/dist/coverage-actions.d.ts +8 -0
  64. package/dist/coverage-actions.js +71 -0
  65. package/dist/coverage-resolutions.d.ts +16 -0
  66. package/dist/coverage-resolutions.js +58 -0
  67. package/dist/db.d.ts +37 -0
  68. package/dist/db.js +288 -0
  69. package/dist/demo.d.ts +12 -0
  70. package/dist/demo.js +122 -0
  71. package/dist/deploy-credentials.d.ts +7 -0
  72. package/dist/deploy-credentials.js +76 -0
  73. package/dist/deploy-targets/github-pages.d.ts +3 -0
  74. package/dist/deploy-targets/github-pages.js +100 -0
  75. package/dist/deploy-targets/index.d.ts +8 -0
  76. package/dist/deploy-targets/index.js +78 -0
  77. package/dist/deploy-targets/netlify.d.ts +3 -0
  78. package/dist/deploy-targets/netlify.js +49 -0
  79. package/dist/deploy-targets/types.d.ts +32 -0
  80. package/dist/deploy-targets/types.js +2 -0
  81. package/dist/deploy-targets/vercel.d.ts +3 -0
  82. package/dist/deploy-targets/vercel.js +95 -0
  83. package/dist/deploy.d.ts +9 -0
  84. package/dist/deploy.js +87 -13
  85. package/dist/deterministic-capture.d.ts +90 -0
  86. package/dist/deterministic-capture.js +435 -0
  87. package/dist/direct-edit.d.ts +40 -0
  88. package/dist/direct-edit.js +159 -0
  89. package/dist/docs-crawl.d.ts +86 -0
  90. package/dist/docs-crawl.js +536 -0
  91. package/dist/docs-site.d.ts +49 -0
  92. package/dist/docs-site.js +233 -0
  93. package/dist/doctor.js +8 -0
  94. package/dist/documentation-collections.d.ts +23 -0
  95. package/dist/documentation-collections.js +191 -0
  96. package/dist/documentation-plan.d.ts +253 -0
  97. package/dist/documentation-plan.js +2563 -0
  98. package/dist/doxbrix-build.d.ts +19 -0
  99. package/dist/doxbrix-build.js +167 -0
  100. package/dist/doxbrix-markdown.d.ts +9 -0
  101. package/dist/doxbrix-markdown.js +115 -14
  102. package/dist/drift.d.ts +10 -0
  103. package/dist/drift.js +164 -0
  104. package/dist/evaluation.d.ts +46 -0
  105. package/dist/evaluation.js +113 -0
  106. package/dist/evidence-pack.d.ts +47 -0
  107. package/dist/evidence-pack.js +358 -0
  108. package/dist/evidence.d.ts +25 -0
  109. package/dist/evidence.js +175 -0
  110. package/dist/fs.d.ts +8 -2
  111. package/dist/fs.js +41 -11
  112. package/dist/generator-api.d.ts +89 -0
  113. package/dist/generator-preflight.d.ts +27 -0
  114. package/dist/generator-preflight.js +105 -0
  115. package/dist/generator-runtime.d.ts +7 -0
  116. package/dist/generator-runtime.js +17 -1
  117. package/dist/generators.d.ts +24 -2
  118. package/dist/generators.js +54 -1
  119. package/dist/git-delivery.d.ts +17 -0
  120. package/dist/git-delivery.js +123 -0
  121. package/dist/globs.d.ts +16 -0
  122. package/dist/globs.js +65 -0
  123. package/dist/glossary.d.ts +26 -0
  124. package/dist/glossary.js +179 -0
  125. package/dist/history.d.ts +106 -0
  126. package/dist/history.js +600 -0
  127. package/dist/html-markdown.d.ts +46 -0
  128. package/dist/html-markdown.js +423 -0
  129. package/dist/interactive.js +3 -0
  130. package/dist/job-events.d.ts +74 -0
  131. package/dist/job-events.js +377 -0
  132. package/dist/keep-awake.d.ts +50 -0
  133. package/dist/keep-awake.js +123 -0
  134. package/dist/local-source-snapshot.d.ts +20 -0
  135. package/dist/local-source-snapshot.js +61 -0
  136. package/dist/mintlify-detect.d.ts +3 -0
  137. package/dist/mintlify-detect.js +18 -0
  138. package/dist/mintlify-import.d.ts +75 -0
  139. package/dist/mintlify-import.js +190 -0
  140. package/dist/navigation.d.ts +98 -0
  141. package/dist/navigation.js +310 -0
  142. package/dist/openapi.d.ts +60 -0
  143. package/dist/openapi.js +439 -0
  144. package/dist/page-editor-bridge.d.ts +3 -0
  145. package/dist/page-editor-bridge.js +109 -0
  146. package/dist/page-editor-preview.d.ts +10 -0
  147. package/dist/page-editor-preview.js +55 -0
  148. package/dist/page-extension.d.ts +9 -0
  149. package/dist/page-extension.js +15 -0
  150. package/dist/page-metadata.d.ts +28 -0
  151. package/dist/page-metadata.js +166 -0
  152. package/dist/page-operations.d.ts +34 -0
  153. package/dist/page-operations.js +215 -0
  154. package/dist/page-routes.d.ts +4 -0
  155. package/dist/page-routes.js +61 -0
  156. package/dist/pages.d.ts +20 -0
  157. package/dist/pages.js +184 -0
  158. package/dist/plan-generator.d.ts +3 -0
  159. package/dist/plan-generator.js +21 -0
  160. package/dist/plan-navigation.d.ts +11 -0
  161. package/dist/plan-navigation.js +30 -0
  162. package/dist/planning-captures.d.ts +20 -0
  163. package/dist/planning-captures.js +143 -0
  164. package/dist/planning-research.d.ts +135 -0
  165. package/dist/planning-research.js +472 -0
  166. package/dist/planning-triage.d.ts +23 -0
  167. package/dist/planning-triage.js +131 -0
  168. package/dist/preview.d.ts +24 -0
  169. package/dist/preview.js +280 -29
  170. package/dist/project-detect.d.ts +36 -0
  171. package/dist/project-detect.js +251 -0
  172. package/dist/project-import.d.ts +54 -0
  173. package/dist/project-import.js +157 -0
  174. package/dist/project-lock.d.ts +6 -0
  175. package/dist/project-lock.js +96 -0
  176. package/dist/project-registry.d.ts +25 -0
  177. package/dist/project-registry.js +79 -0
  178. package/dist/project.d.ts +35 -3
  179. package/dist/project.js +388 -38
  180. package/dist/prompts.d.ts +9 -0
  181. package/dist/prompts.js +25 -0
  182. package/dist/proposal-replay.d.ts +32 -0
  183. package/dist/proposal-replay.js +99 -0
  184. package/dist/quality-claims.d.ts +8 -0
  185. package/dist/quality-claims.js +168 -0
  186. package/dist/quality-config.d.ts +5 -0
  187. package/dist/quality-config.js +84 -0
  188. package/dist/quality-contract.d.ts +37 -0
  189. package/dist/quality-contract.js +46 -0
  190. package/dist/quality-examples.d.ts +4 -0
  191. package/dist/quality-examples.js +233 -0
  192. package/dist/quality-gates.d.ts +16 -0
  193. package/dist/quality-gates.js +192 -0
  194. package/dist/quality-links.d.ts +7 -0
  195. package/dist/quality-links.js +149 -0
  196. package/dist/quality-lint.d.ts +6 -0
  197. package/dist/quality-lint.js +124 -0
  198. package/dist/quality-rendered.d.ts +11 -0
  199. package/dist/quality-rendered.js +222 -0
  200. package/dist/quality-schema.d.ts +3 -0
  201. package/dist/quality-schema.js +71 -0
  202. package/dist/release-notes.d.ts +44 -0
  203. package/dist/release-notes.js +183 -0
  204. package/dist/remote-monitor.d.ts +16 -0
  205. package/dist/remote-monitor.js +74 -0
  206. package/dist/remote-source.d.ts +34 -0
  207. package/dist/remote-source.js +426 -0
  208. package/dist/review-diff.d.ts +82 -0
  209. package/dist/review-diff.js +400 -0
  210. package/dist/review-learning.d.ts +11 -0
  211. package/dist/review-learning.js +60 -0
  212. package/dist/review-render.d.ts +38 -0
  213. package/dist/review-render.js +224 -0
  214. package/dist/review-report.d.ts +9 -0
  215. package/dist/review-report.js +89 -0
  216. package/dist/review-ui.d.ts +14 -0
  217. package/dist/review-ui.js +1248 -0
  218. package/dist/schedule.d.ts +78 -0
  219. package/dist/schedule.js +480 -0
  220. package/dist/screen-capture-provider.d.ts +52 -0
  221. package/dist/screen-capture-provider.js +218 -0
  222. package/dist/screenshot-workflow.d.ts +167 -0
  223. package/dist/screenshot-workflow.js +1237 -0
  224. package/dist/settings.d.ts +1 -1
  225. package/dist/settings.js +95 -7
  226. package/dist/site-export.d.ts +18 -0
  227. package/dist/site-export.js +87 -0
  228. package/dist/source-connectors.d.ts +33 -0
  229. package/dist/source-connectors.js +268 -0
  230. package/dist/source-discovery.d.ts +132 -0
  231. package/dist/source-discovery.js +823 -0
  232. package/dist/source-intelligence.d.ts +9 -0
  233. package/dist/source-intelligence.js +306 -0
  234. package/dist/sync-review.d.ts +28 -0
  235. package/dist/sync-review.js +264 -0
  236. package/dist/sync-runs.d.ts +192 -0
  237. package/dist/sync-runs.js +2244 -0
  238. package/dist/sync.d.ts +35 -0
  239. package/dist/sync.js +298 -32
  240. package/dist/text-diff.d.ts +9 -0
  241. package/dist/text-diff.js +59 -0
  242. package/dist/types.d.ts +946 -1
  243. package/dist/ui/assets/doxloop-logo-light-De7Nx7j7.png +0 -0
  244. package/dist/ui/assets/index-BHBYU2aG.css +1 -0
  245. package/dist/ui/assets/index-Cq3RPQiC.js +33 -0
  246. package/dist/ui/index.html +18 -0
  247. package/dist/ui-server.d.ts +83 -0
  248. package/dist/ui-server.js +3532 -0
  249. package/dist/usage-budget.d.ts +28 -0
  250. package/dist/usage-budget.js +90 -0
  251. package/dist/validation.d.ts +25 -1
  252. package/dist/validation.js +312 -26
  253. package/dist/workspace-tools.d.ts +54 -0
  254. package/dist/workspace-tools.js +123 -0
  255. package/docs/agent-compatibility.md +49 -32
  256. package/docs/ci-and-automation.md +105 -66
  257. package/docs/doxbrix-http-api.md +8 -1
  258. package/docs/existing-documentation.md +80 -0
  259. package/docs/generation-performance.md +108 -0
  260. package/docs/generator-authoring.md +68 -5
  261. package/docs/generator-selection.md +50 -13
  262. package/docs/mintlify-import.md +71 -0
  263. package/docs/openapi-security.md +25 -0
  264. package/docs/project-format.md +331 -36
  265. package/docs/release-quality.md +158 -0
  266. package/docs/releasing.md +72 -0
  267. package/docs/review-workflows.md +51 -0
  268. package/docs/security-model.md +102 -39
  269. package/docs/troubleshooting.md +226 -93
  270. package/package.json +46 -15
  271. package/scripts/test-auto-screenshot.mjs +172 -0
  272. package/skills/doxloop-authoring/SKILL.md +242 -361
  273. package/skills/doxloop-authoring/references/existing-documentation.md +94 -0
  274. package/skills/doxloop-authoring/references/navigation-architecture.md +18 -7
  275. package/skills/doxloop-authoring/references/page-depth.md +169 -0
  276. package/skills/doxloop-authoring/references/project-format.md +106 -7
  277. package/skills/doxloop-authoring/references/quality.md +10 -0
  278. package/skills/doxloop-authoring/references/screenshot-manifest.md +113 -0
  279. package/skills/doxloop-authoring/references/screenshots.md +149 -235
  280. package/skills/doxloop-authoring/references/workflows.md +76 -0
  281. package/skills/doxloop-doxbrix/SKILL.md +38 -22
  282. package/skills/doxloop-doxbrix/references/api-endpoints.md +15 -14
  283. package/skills/doxloop-doxbrix/references/components.md +30 -3
  284. package/skills/doxloop-doxbrix/references/manifest.md +3 -2
  285. package/vendor/doxbrix-import/LICENSE +202 -0
  286. package/vendor/doxbrix-import/README.md +17 -0
  287. package/vendor/doxbrix-import/UPSTREAM.json +47 -0
  288. package/vendor/doxbrix-import/dist/docs/frontmatter.d.ts +13 -0
  289. package/vendor/doxbrix-import/dist/docs/frontmatter.js +83 -0
  290. package/vendor/doxbrix-import/dist/docs/import.d.ts +21 -0
  291. package/vendor/doxbrix-import/dist/docs/import.js +147 -0
  292. package/vendor/doxbrix-import/dist/docs/manifest.d.ts +163 -0
  293. package/vendor/doxbrix-import/dist/docs/manifest.js +64 -0
  294. package/vendor/doxbrix-import/dist/docs/project.d.ts +25 -0
  295. package/vendor/doxbrix-import/dist/docs/project.js +77 -0
  296. package/vendor/doxbrix-import/dist/docs/starter.d.ts +4 -0
  297. package/vendor/doxbrix-import/dist/docs/starter.js +11 -0
  298. package/vendor/doxbrix-import/dist/importer.d.ts +227 -0
  299. package/vendor/doxbrix-import/dist/importer.js +1567 -0
  300. package/vendor/doxbrix-import/dist/mintlify-openapi.d.ts +37 -0
  301. package/vendor/doxbrix-import/dist/mintlify-openapi.js +305 -0
  302. package/vendor/doxbrix-import/dist/safe-path.d.ts +9 -0
  303. package/vendor/doxbrix-import/dist/safe-path.js +47 -0
  304. package/dist/agents.d.ts.map +0 -1
  305. package/dist/agents.js.map +0 -1
  306. package/dist/args.d.ts.map +0 -1
  307. package/dist/args.js.map +0 -1
  308. package/dist/artifact-deploy.d.ts.map +0 -1
  309. package/dist/artifact-deploy.js.map +0 -1
  310. package/dist/auth.d.ts.map +0 -1
  311. package/dist/auth.js.map +0 -1
  312. package/dist/author.d.ts.map +0 -1
  313. package/dist/author.js.map +0 -1
  314. package/dist/capture.d.ts.map +0 -1
  315. package/dist/capture.js.map +0 -1
  316. package/dist/cli.d.ts.map +0 -1
  317. package/dist/cli.js.map +0 -1
  318. package/dist/deploy.d.ts.map +0 -1
  319. package/dist/deploy.js.map +0 -1
  320. package/dist/deployment-visibility.d.ts.map +0 -1
  321. package/dist/deployment-visibility.js.map +0 -1
  322. package/dist/doctor.d.ts.map +0 -1
  323. package/dist/doctor.js.map +0 -1
  324. package/dist/doxbrix-markdown.d.ts.map +0 -1
  325. package/dist/doxbrix-markdown.js.map +0 -1
  326. package/dist/errors.d.ts.map +0 -1
  327. package/dist/errors.js.map +0 -1
  328. package/dist/fs.d.ts.map +0 -1
  329. package/dist/fs.js.map +0 -1
  330. package/dist/generator-api.d.ts.map +0 -1
  331. package/dist/generator-api.js.map +0 -1
  332. package/dist/generator-manager.d.ts.map +0 -1
  333. package/dist/generator-manager.js.map +0 -1
  334. package/dist/generator-runtime.d.ts.map +0 -1
  335. package/dist/generator-runtime.js.map +0 -1
  336. package/dist/generators.d.ts.map +0 -1
  337. package/dist/generators.js.map +0 -1
  338. package/dist/interactive.d.ts.map +0 -1
  339. package/dist/interactive.js.map +0 -1
  340. package/dist/preview.d.ts.map +0 -1
  341. package/dist/preview.js.map +0 -1
  342. package/dist/progress.d.ts.map +0 -1
  343. package/dist/progress.js.map +0 -1
  344. package/dist/project.d.ts.map +0 -1
  345. package/dist/project.js.map +0 -1
  346. package/dist/prompts.d.ts.map +0 -1
  347. package/dist/prompts.js.map +0 -1
  348. package/dist/settings.d.ts.map +0 -1
  349. package/dist/settings.js.map +0 -1
  350. package/dist/sync.d.ts.map +0 -1
  351. package/dist/sync.js.map +0 -1
  352. package/dist/types.d.ts.map +0 -1
  353. package/dist/types.js.map +0 -1
  354. package/dist/validation.d.ts.map +0 -1
  355. package/dist/validation.js.map +0 -1
  356. package/dist/version.d.ts.map +0 -1
  357. package/dist/version.js.map +0 -1
@@ -0,0 +1,423 @@
1
+ /**
2
+ * Dependency-free HTML to Markdown conversion for crawled documentation pages.
3
+ *
4
+ * The converter is intentionally tolerant: documentation sites ship imperfect
5
+ * HTML, and the output feeds an agent that reads Markdown for context rather
6
+ * than a renderer that needs exact fidelity. Navigation chrome, scripts,
7
+ * styles, and hidden elements are dropped before conversion.
8
+ */
9
+ const VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr']);
10
+ const RAW_TEXT_ELEMENTS = new Set(['script', 'style', 'noscript', 'template', 'svg', 'iframe', 'canvas', 'textarea']);
11
+ const DROPPED_ELEMENTS = new Set([...RAW_TEXT_ELEMENTS, 'head', 'nav', 'header', 'footer', 'aside', 'button', 'form', 'select', 'dialog']);
12
+ const BLOCK_ELEMENTS = new Set(['address', 'article', 'blockquote', 'details', 'div', 'dl', 'dd', 'dt', 'fieldset', 'figcaption', 'figure', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'li', 'main', 'ol', 'p', 'pre', 'section', 'summary', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul', 'body', 'html']);
13
+ const CHROME_PATTERN = /(^|[\s_-])(nav|navbar|sidebar|toc|table-of-contents|breadcrumbs?|footer|header|banner|cookie|announcement|skip-link|edit-page|pagination|prev-next|feedback|search)([\s_-]|$)/i;
14
+ /** Block elements whose start tag implicitly closes an open paragraph. */
15
+ const P_CLOSERS = new Set(['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'pre', 'section', 'table', 'ul']);
16
+ const ENTITIES = {
17
+ amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ', copy: '©', reg: '®', trade: '™', hellip: '…',
18
+ mdash: '—', ndash: '–', lsquo: '‘', rsquo: '’', ldquo: '“', rdquo: '”', laquo: '«', raquo: '»', middot: '·', bull: '•', rarr: '→', larr: '←',
19
+ };
20
+ export function decodeEntities(value) {
21
+ return value.replace(/&(#x[0-9a-f]+|#\d+|[a-z][a-z0-9]*);/gi, (match, entity) => {
22
+ if (entity[0] === '#') {
23
+ const code = entity[1]?.toLowerCase() === 'x' ? Number.parseInt(entity.slice(2), 16) : Number.parseInt(entity.slice(1), 10);
24
+ return Number.isFinite(code) && code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match;
25
+ }
26
+ return ENTITIES[entity.toLowerCase()] ?? match;
27
+ });
28
+ }
29
+ /** Parse tolerant HTML into a lightweight tree. */
30
+ export function parseHtml(html) {
31
+ const root = { type: 'element', name: '#root', attributes: {}, children: [] };
32
+ const stack = [root];
33
+ let index = 0;
34
+ const length = html.length;
35
+ while (index < length) {
36
+ const open = html.indexOf('<', index);
37
+ if (open === -1) {
38
+ appendText(stack[stack.length - 1], html.slice(index));
39
+ break;
40
+ }
41
+ if (open > index)
42
+ appendText(stack[stack.length - 1], html.slice(index, open));
43
+ if (html.startsWith('<!--', open)) {
44
+ const close = html.indexOf('-->', open + 4);
45
+ index = close === -1 ? length : close + 3;
46
+ continue;
47
+ }
48
+ if (html.startsWith('<!', open) || html.startsWith('<?', open)) {
49
+ const close = html.indexOf('>', open);
50
+ index = close === -1 ? length : close + 1;
51
+ continue;
52
+ }
53
+ const close = findTagEnd(html, open);
54
+ if (close === -1) {
55
+ appendText(stack[stack.length - 1], html.slice(open));
56
+ break;
57
+ }
58
+ const rawTag = html.slice(open + 1, close);
59
+ index = close + 1;
60
+ if (rawTag.startsWith('/')) {
61
+ const name = rawTag.slice(1).trim().toLowerCase();
62
+ for (let depth = stack.length - 1; depth > 0; depth -= 1) {
63
+ if (stack[depth].name === name) {
64
+ stack.length = depth;
65
+ break;
66
+ }
67
+ }
68
+ continue;
69
+ }
70
+ const { name, attributes, selfClosing } = parseTag(rawTag);
71
+ if (!name)
72
+ continue;
73
+ const node = { type: 'element', name, attributes, children: [] };
74
+ closeImplied(stack, name);
75
+ stack[stack.length - 1].children.push(node);
76
+ if (selfClosing || VOID_ELEMENTS.has(name))
77
+ continue;
78
+ if (RAW_TEXT_ELEMENTS.has(name)) {
79
+ const end = findClosingTag(html, index, name);
80
+ node.children.push({ type: 'text', attributes: {}, children: [], text: html.slice(index, end.start) });
81
+ index = end.end;
82
+ continue;
83
+ }
84
+ stack.push(node);
85
+ }
86
+ return root;
87
+ }
88
+ function findTagEnd(html, open) {
89
+ let quote;
90
+ for (let index = open + 1; index < html.length; index += 1) {
91
+ const char = html[index];
92
+ if (quote) {
93
+ if (char === quote)
94
+ quote = undefined;
95
+ continue;
96
+ }
97
+ if (char === '"' || char === "'")
98
+ quote = char;
99
+ else if (char === '>')
100
+ return index;
101
+ }
102
+ return -1;
103
+ }
104
+ function findClosingTag(html, from, name) {
105
+ const pattern = new RegExp(`</${name}\\s*>`, 'ig');
106
+ pattern.lastIndex = from;
107
+ const match = pattern.exec(html);
108
+ if (!match)
109
+ return { start: html.length, end: html.length };
110
+ return { start: match.index, end: match.index + match[0].length };
111
+ }
112
+ function parseTag(raw) {
113
+ const selfClosing = raw.trimEnd().endsWith('/');
114
+ const body = selfClosing ? raw.trimEnd().slice(0, -1) : raw;
115
+ const nameMatch = /^\s*([a-zA-Z][\w:-]*)/.exec(body);
116
+ if (!nameMatch)
117
+ return { name: '', attributes: {}, selfClosing };
118
+ const name = nameMatch[1].toLowerCase();
119
+ const attributes = {};
120
+ const attributePattern = /([^\s=/"'<>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
121
+ attributePattern.lastIndex = nameMatch[0].length;
122
+ let match;
123
+ while ((match = attributePattern.exec(body))) {
124
+ const key = match[1].toLowerCase();
125
+ attributes[key] = decodeEntities(match[2] ?? match[3] ?? match[4] ?? '');
126
+ }
127
+ return { name, attributes, selfClosing };
128
+ }
129
+ function closeImplied(stack, incoming) {
130
+ const current = stack[stack.length - 1]?.name;
131
+ if (!current)
132
+ return;
133
+ if (incoming === 'li' && current === 'li')
134
+ stack.pop();
135
+ else if (current === 'p' && (incoming === 'p' || P_CLOSERS.has(incoming)))
136
+ stack.pop();
137
+ else if ((incoming === 'dt' || incoming === 'dd') && (current === 'dt' || current === 'dd'))
138
+ stack.pop();
139
+ else if (incoming === 'tr' && (current === 'td' || current === 'th')) {
140
+ stack.pop();
141
+ if (stack[stack.length - 1]?.name === 'tr')
142
+ stack.pop();
143
+ }
144
+ else if (incoming === 'tr' && current === 'tr')
145
+ stack.pop();
146
+ else if ((incoming === 'td' || incoming === 'th') && (current === 'td' || current === 'th'))
147
+ stack.pop();
148
+ else if (incoming === 'option' && current === 'option')
149
+ stack.pop();
150
+ }
151
+ function appendText(parent, text) {
152
+ if (text.length === 0)
153
+ return;
154
+ parent.children.push({ type: 'text', attributes: {}, children: [], text });
155
+ }
156
+ /** Convert an HTML document into a Markdown summary of its main content. */
157
+ export function summarizeHtmlDocument(html) {
158
+ const root = parseHtml(html);
159
+ const head = findFirst(root, (node) => node.name === 'head');
160
+ const title = textOf(findFirst(head ?? root, (node) => node.name === 'title')).trim() || undefined;
161
+ const metas = collect(head ?? root, (node) => node.name === 'meta');
162
+ const meta = (key) => {
163
+ const hit = metas.find((node) => (node.attributes.name ?? node.attributes.property ?? '').toLowerCase() === key);
164
+ return hit?.attributes.content?.trim() || undefined;
165
+ };
166
+ const canonical = collect(head ?? root, (node) => node.name === 'link').find((node) => (node.attributes.rel ?? '').toLowerCase().split(/\s+/).includes('canonical'))?.attributes.href;
167
+ const htmlElement = findFirst(root, (node) => node.name === 'html');
168
+ const body = findFirst(root, (node) => node.name === 'body') ?? root;
169
+ const links = collect(body, (node) => node.name === 'a').map((node) => node.attributes.href ?? '').filter(Boolean);
170
+ const main = selectMainContent(body);
171
+ const markdown = renderMarkdown(main).split('\n').map((line) => (line.trim() === '' ? '' : line.replace(/\s+$/g, ''))).join('\n').replace(/\n{3,}/g, '\n\n').trim();
172
+ const headings = collect(main, (node) => /^h[1-6]$/.test(node.name ?? '')).map((node) => ({ level: Number(node.name.slice(1)), text: inlineText(node).trim() })).filter((item) => item.text);
173
+ const images = collect(main, (node) => node.name === 'img').map((node) => node.attributes.src ?? node.attributes['data-src'] ?? '').filter(Boolean);
174
+ const description = meta('description') ?? meta('og:description');
175
+ const generator = meta('generator');
176
+ const language = htmlElement?.attributes.lang;
177
+ return {
178
+ ...(title ? { title } : {}),
179
+ ...(description ? { description } : {}),
180
+ ...(canonical ? { canonical } : {}),
181
+ ...(generator ? { generator } : {}),
182
+ ...(language ? { language } : {}),
183
+ links: unique(links),
184
+ images: unique(images),
185
+ headings,
186
+ markdown,
187
+ words: markdown.split(/\s+/).filter((token) => /[\p{L}\p{N}]/u.test(token)).length,
188
+ };
189
+ }
190
+ function selectMainContent(body) {
191
+ const candidates = [
192
+ findFirst(body, (node) => node.name === 'main'),
193
+ findFirst(body, (node) => node.attributes.role === 'main'),
194
+ findFirst(body, (node) => node.name === 'article'),
195
+ findFirst(body, (node) => /(^|\s)(content|markdown-body|theme-doc-markdown|docs-content|md-content|document|prose)(\s|$)/i.test(node.attributes.class ?? '') || /^(content|main-content|docs-content)$/i.test(node.attributes.id ?? '')),
196
+ ].filter((node) => Boolean(node));
197
+ return candidates[0] ?? body;
198
+ }
199
+ function isDropped(node) {
200
+ if (node.type !== 'element')
201
+ return false;
202
+ if (DROPPED_ELEMENTS.has(node.name))
203
+ return true;
204
+ if (node.attributes.hidden !== undefined || node.attributes['aria-hidden'] === 'true')
205
+ return true;
206
+ if (/display\s*:\s*none/i.test(node.attributes.style ?? ''))
207
+ return true;
208
+ const role = (node.attributes.role ?? '').toLowerCase();
209
+ if (['navigation', 'banner', 'contentinfo', 'complementary', 'search', 'menu', 'menubar', 'toolbar'].includes(role))
210
+ return true;
211
+ const marker = `${node.attributes.class ?? ''} ${node.attributes.id ?? ''}`;
212
+ return CHROME_PATTERN.test(marker);
213
+ }
214
+ function renderMarkdown(node) {
215
+ return renderChildren(node, { listDepth: 0 });
216
+ }
217
+ function renderChildren(node, context) {
218
+ return node.children.map((child) => renderNode(child, context)).join('');
219
+ }
220
+ function renderNode(node, context) {
221
+ if (node.type === 'text') {
222
+ if (context.preformatted)
223
+ return decodeEntities(node.text ?? '');
224
+ return decodeEntities(node.text ?? '').replace(/\s+/g, ' ');
225
+ }
226
+ if (isDropped(node))
227
+ return '';
228
+ const name = node.name;
229
+ switch (name) {
230
+ case 'h1':
231
+ case 'h2':
232
+ case 'h3':
233
+ case 'h4':
234
+ case 'h5':
235
+ case 'h6': {
236
+ const text = inlineText(node).trim();
237
+ return text ? `\n\n${'#'.repeat(Number(name.slice(1)))} ${text}\n\n` : '';
238
+ }
239
+ case 'p':
240
+ case 'div':
241
+ case 'section':
242
+ case 'article':
243
+ case 'main':
244
+ case 'figure':
245
+ case 'figcaption':
246
+ case 'details':
247
+ case 'summary':
248
+ case 'address':
249
+ case 'dl':
250
+ case 'fieldset':
251
+ case 'body':
252
+ case 'html': {
253
+ const inner = renderChildren(node, context);
254
+ return BLOCK_ELEMENTS.has(name) && name !== 'div' ? `\n\n${inner.trim()}\n\n` : `\n${inner}\n`;
255
+ }
256
+ case 'br': return ' \n';
257
+ case 'hr': return '\n\n---\n\n';
258
+ case 'strong':
259
+ case 'b': {
260
+ const text = renderChildren(node, context).trim();
261
+ return text ? `**${text}**` : '';
262
+ }
263
+ case 'em':
264
+ case 'i': {
265
+ const text = renderChildren(node, context).trim();
266
+ return text ? `*${text}*` : '';
267
+ }
268
+ case 'del':
269
+ case 's': {
270
+ const text = renderChildren(node, context).trim();
271
+ return text ? `~~${text}~~` : '';
272
+ }
273
+ case 'code':
274
+ case 'kbd':
275
+ case 'samp': {
276
+ if (context.preformatted)
277
+ return renderChildren(node, context);
278
+ const text = textOf(node).replace(/\s+/g, ' ').trim();
279
+ return text ? `\`${text}\`` : '';
280
+ }
281
+ case 'pre': {
282
+ const codeChild = node.children.find((child) => child.type === 'element' && child.name === 'code');
283
+ const language = detectLanguage(node) ?? (codeChild ? detectLanguage(codeChild) : undefined) ?? '';
284
+ const text = renderChildren(node, { ...context, preformatted: true }).replace(/^\n+|\n+$/g, '');
285
+ return `\n\n\`\`\`${language}\n${text}\n\`\`\`\n\n`;
286
+ }
287
+ case 'a': {
288
+ const text = renderChildren(node, context).trim();
289
+ const href = node.attributes.href?.trim();
290
+ if (!href || href.startsWith('#') || href.startsWith('javascript:'))
291
+ return text;
292
+ return text ? `[${text}](${href})` : '';
293
+ }
294
+ case 'img': {
295
+ const source = node.attributes.src ?? node.attributes['data-src'];
296
+ if (!source)
297
+ return '';
298
+ return `![${(node.attributes.alt ?? '').trim()}](${source})`;
299
+ }
300
+ case 'ul':
301
+ case 'ol': {
302
+ const ordered = name === 'ol';
303
+ const items = node.children.filter((child) => child.type === 'element' && child.name === 'li' && !isDropped(child));
304
+ const indent = ' '.repeat(context.listDepth);
305
+ const lines = items.map((item, position) => {
306
+ const marker = ordered ? `${position + 1}.` : '-';
307
+ const content = renderChildren(item, { listDepth: context.listDepth + 1, ordered }).trim().replace(/\n{2,}/g, '\n').split('\n').map((line, index) => (index === 0 || /^\s*(?:[-*]|\d+\.)\s/.test(line) ? line : `${indent} ${line}`)).join('\n');
308
+ return `${indent}${marker} ${content}`;
309
+ });
310
+ return context.listDepth === 0 ? `\n\n${lines.join('\n')}\n\n` : `\n${lines.join('\n')}`;
311
+ }
312
+ case 'li': return renderChildren(node, context);
313
+ case 'dt': return `\n\n**${inlineText(node).trim()}**\n`;
314
+ case 'dd': return `\n: ${renderChildren(node, context).trim()}\n`;
315
+ case 'blockquote': {
316
+ const inner = renderChildren(node, context).trim();
317
+ return inner ? `\n\n${inner.split('\n').map((line) => `> ${line}`).join('\n')}\n\n` : '';
318
+ }
319
+ case 'table': return `\n\n${renderTable(node)}\n\n`;
320
+ case 'span':
321
+ case 'label':
322
+ case 'small':
323
+ case 'sup':
324
+ case 'sub':
325
+ case 'mark':
326
+ case 'abbr':
327
+ case 'cite':
328
+ case 'q':
329
+ case 'time':
330
+ case 'u':
331
+ case 'font':
332
+ case 'center':
333
+ return renderChildren(node, context);
334
+ default:
335
+ return renderChildren(node, context);
336
+ }
337
+ }
338
+ function detectLanguage(node) {
339
+ const marker = `${node.attributes.class ?? ''} ${node.attributes['data-language'] ?? ''} ${node.attributes['data-lang'] ?? ''}`;
340
+ const match = /(?:language|lang)-([\w+#-]+)/i.exec(marker) ?? /(?:^|\s)(bash|shell|sh|zsh|json|yaml|yml|ts|typescript|js|javascript|python|py|go|rust|java|ruby|php|sql|toml|xml|html|css|graphql|http|dockerfile|csharp|kotlin|swift)(?:\s|$)/i.exec(marker);
341
+ return match?.[1]?.toLowerCase();
342
+ }
343
+ function renderTable(table) {
344
+ const rows = collect(table, (node) => node.name === 'tr').map((row) => row.children.filter((cell) => cell.type === 'element' && (cell.name === 'td' || cell.name === 'th')).map((cell) => renderChildren(cell, { listDepth: 0 }).replace(/\s+/g, ' ').replace(/\|/g, '\\|').trim()));
345
+ const populated = rows.filter((row) => row.length > 0);
346
+ if (populated.length === 0)
347
+ return '';
348
+ const width = Math.max(...populated.map((row) => row.length));
349
+ const pad = (row) => [...row, ...Array.from({ length: width - row.length }, () => '')];
350
+ const [header, ...body] = populated;
351
+ const lines = [`| ${pad(header).join(' | ')} |`, `| ${Array.from({ length: width }, () => '---').join(' | ')} |`, ...body.map((row) => `| ${pad(row).join(' | ')} |`)];
352
+ return lines.join('\n');
353
+ }
354
+ function inlineText(node) {
355
+ return renderChildren(node, { listDepth: 0 }).replace(/\s+/g, ' ').trim();
356
+ }
357
+ function textOf(node) {
358
+ if (!node)
359
+ return '';
360
+ if (node.type === 'text')
361
+ return decodeEntities(node.text ?? '');
362
+ return node.children.map(textOf).join('');
363
+ }
364
+ function findFirst(node, predicate) {
365
+ for (const child of node.children) {
366
+ if (child.type !== 'element')
367
+ continue;
368
+ if (predicate(child))
369
+ return child;
370
+ const nested = findFirst(child, predicate);
371
+ if (nested)
372
+ return nested;
373
+ }
374
+ return undefined;
375
+ }
376
+ function collect(node, predicate, results = []) {
377
+ for (const child of node.children) {
378
+ if (child.type !== 'element')
379
+ continue;
380
+ if (predicate(child))
381
+ results.push(child);
382
+ collect(child, predicate, results);
383
+ }
384
+ return results;
385
+ }
386
+ function unique(values) {
387
+ return [...new Set(values)];
388
+ }
389
+ /**
390
+ * The same summary for a page served as Markdown. Mintlify, GitBook, and
391
+ * other client-rendered docs sites send an empty HTML shell to a crawler but
392
+ * serve each page's source at `<page>.md` (and list those URLs in llms.txt).
393
+ * Their own "documentation index" preamble is dropped.
394
+ */
395
+ export function summarizeMarkdownDocument(source) {
396
+ let text = source.replace(/\r\n/g, '\n');
397
+ let frontmatterTitle;
398
+ let frontmatterDescription;
399
+ const frontmatter = /^---\n([\s\S]*?)\n---\n?/.exec(text);
400
+ if (frontmatter) {
401
+ frontmatterTitle = /^title:\s*["']?(.+?)["']?\s*$/m.exec(frontmatter[1])?.[1];
402
+ frontmatterDescription = /^description:\s*["']?(.+?)["']?\s*$/m.exec(frontmatter[1])?.[1];
403
+ text = text.slice(frontmatter[0].length);
404
+ }
405
+ // Mintlify prefixes every page with a quoted pointer to llms.txt.
406
+ text = text.replace(/^(?:>[^\n]*\n)+\n*/, (block) => /llms\.txt|documentation index/i.test(block) ? '' : block).trim();
407
+ const withoutCode = text.replace(/```[\s\S]*?```/g, ' ');
408
+ const headings = [...withoutCode.matchAll(/^(#{1,6})\s+(.+?)\s*#*\s*$/gm)].map((match) => ({ level: match[1].length, text: match[2].replace(/[*_`]/g, '').trim() })).filter((item) => item.text);
409
+ const images = [...text.matchAll(/!\[[^\]]*\]\(\s*<?([^)\s>]+)>?[^)]*\)/g)].map((match) => match[1]);
410
+ const links = [...text.matchAll(/(?<!!)\[[^\]]*\]\(\s*<?([^)\s>]+)>?[^)]*\)/g)].map((match) => match[1]);
411
+ const description = frontmatterDescription ?? /^#\s+.+\n+>\s*(.+)$/m.exec(text)?.[1]?.trim();
412
+ const words = withoutCode.replace(/!\[[^\]]*\]\([^)]*\)|\]\([^)]*\)|[#>*_`|[\]-]/g, ' ').split(/\s+/).filter((word) => /[\p{L}\p{N}]/u.test(word)).length;
413
+ return {
414
+ ...(frontmatterTitle ?? headings.find((heading) => heading.level === 1)?.text ? { title: frontmatterTitle ?? headings.find((heading) => heading.level === 1).text } : {}),
415
+ ...(description ? { description } : {}),
416
+ links,
417
+ images,
418
+ headings,
419
+ markdown: text,
420
+ words,
421
+ };
422
+ }
423
+ //# sourceMappingURL=html-markdown.js.map
@@ -145,6 +145,9 @@ export function replayInitCommand(plan) {
145
145
  if ((source.kind ?? 'directory') === 'openapi') {
146
146
  parts.push('--spec', quoteArgument(`${source.name}=${source.path}`));
147
147
  }
148
+ else if ((source.kind ?? 'directory') === 'docs-site') {
149
+ parts.push('--docs', quoteArgument(`${source.name}=${source.site?.url ?? source.path}`));
150
+ }
148
151
  else {
149
152
  parts.push('--source', quoteArgument(`${source.name}=${source.path}`));
150
153
  }
@@ -0,0 +1,74 @@
1
+ export type WorkflowStageStatus = 'pending' | 'running' | 'completed' | 'failed';
2
+ export interface WorkflowStageProgress {
3
+ done: number;
4
+ total?: number;
5
+ }
6
+ export interface WorkflowStage {
7
+ id: string;
8
+ label: string;
9
+ status: WorkflowStageStatus;
10
+ startedAt?: string;
11
+ finishedAt?: string;
12
+ /** Work counted so far, such as pages written out of pages planned. */
13
+ progress?: WorkflowStageProgress;
14
+ }
15
+ export declare function formatJobLineStamp(at?: Date): string;
16
+ /** Prefix a log line with the time it arrived; event lines and already stamped lines pass through. */
17
+ export declare function stampJobLine(line: string, at?: Date): string;
18
+ export declare function stripJobLineStamp(line: string): string;
19
+ /**
20
+ * What a job concluded, for the control center to announce once the job
21
+ * settles: a source check reports whether anything changed and whether a
22
+ * proposal was drafted.
23
+ */
24
+ export interface JobOutcome {
25
+ kind: 'sync';
26
+ status: 'current' | 'stale' | 'proposal' | 'skipped' | 'failed' | 'unknown';
27
+ /** Reader-facing summary, one sentence. */
28
+ message: string;
29
+ /** Stale pages counted by the check. */
30
+ pages?: number;
31
+ /** Proposal drafted by the check, when one was. */
32
+ proposalId?: string;
33
+ }
34
+ export declare function jobOutcomeLine(outcome: JobOutcome, at?: string): string;
35
+ /** Report a job outcome to a control center that started this CLI; a terminal already saw the text. */
36
+ export declare function emitJobOutcome(outcome: JobOutcome): void;
37
+ export declare function parseJobOutcomeLine(line: string): JobOutcome | undefined;
38
+ export declare function parseJobOutcome(raw: unknown): JobOutcome | undefined;
39
+ /** Serialize one stage event as the line the UI server reads from a CLI job. */
40
+ export declare function workflowStageLine(id: string, label: string, status: WorkflowStageStatus, progress?: WorkflowStageProgress, at?: string): string;
41
+ /**
42
+ * Report a workflow stage. A CLI run started by the control center streams
43
+ * machine-readable events; a person watching a terminal gets a plain line.
44
+ */
45
+ export declare function emitWorkflowStage(id: string, label: string, status: WorkflowStageStatus, progress?: WorkflowStageProgress): void;
46
+ export declare function formatStageProgress(progress: WorkflowStageProgress | undefined): string;
47
+ export declare function applyWorkflowStageLine(stages: WorkflowStage[], line: string): void;
48
+ export declare function finishWorkflowStages(stages: WorkflowStage[], status: 'completed' | 'failed', at?: string): void;
49
+ export declare function parseWorkflowStage(raw: unknown): WorkflowStage | undefined;
50
+ export declare function stripAnsi(value: string): string;
51
+ /**
52
+ * Clean one raw output line for the job log, or drop it: ANSI colour codes
53
+ * are stripped, Codex's "Reading additional input from stdin..." notice is
54
+ * dropped, and Codex's internal tracing lines are condensed to one readable
55
+ * sentence. Event lines pass through untouched.
56
+ */
57
+ export declare function cleanJobOutputLine(line: string): string | undefined;
58
+ export declare function cleanJobOutputLines(lines: string[]): string[];
59
+ /**
60
+ * Keeps an agent's machine-readable replies out of the live activity view:
61
+ * a `<doxloop-plan>` block or a pretty-printed JSON document becomes one
62
+ * summary line ("Plan reply received: 62 pages") instead of hundreds of
63
+ * lines that push the useful ones out of the window. Parallel sessions are
64
+ * tracked by their `[task] ` prefix. The full job log keeps the raw reply.
65
+ */
66
+ export declare class JobLogDisplayFilter {
67
+ private readonly blocks;
68
+ push(lines: string[]): string[];
69
+ /** Summaries for blocks still open when the job ends. */
70
+ finish(): string[];
71
+ private line;
72
+ private continueBlock;
73
+ }
74
+ //# sourceMappingURL=job-events.d.ts.map