@doxbrix/doxloop 0.1.4 → 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 +1153 -0
  2. package/README.md +422 -226
  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 +40 -4
  22. package/dist/agents.js +115 -11
  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 +16 -15
  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 +33 -4
  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 +50 -28
  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,183 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join, resolve } from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ import { DoxloopError } from './errors.js';
6
+ import { pathExists } from './fs.js';
7
+ import { loadProject, sourceKind } from './project.js';
8
+ const execute = promisify(execFile);
9
+ /**
10
+ * Deterministic inputs for a release-notes plan: the commits and changed files
11
+ * between two Git refs of every Git-backed source, plus the section of the
12
+ * product's own changelog that names the release. The planner and writer get
13
+ * this inventory verbatim, so the page is grounded in the actual commit range
14
+ * rather than in what the agent remembers about the product.
15
+ */
16
+ export const MAX_RELEASE_COMMITS = 200;
17
+ export const MAX_RELEASE_FILES = 300;
18
+ const MAX_BODY_CHARS = 400;
19
+ const MAX_CHANGELOG_CHARS = 6000;
20
+ const CHANGELOG_NAMES = ['changelog', 'changes', 'history', 'releases', 'release-notes', 'news'];
21
+ const SAFE_REF = /^(?!-)[\w./@^~{}+-]{1,120}$/;
22
+ /** Directory sources whose checkout is a Git repository. */
23
+ export async function gitBackedSources(root, project) {
24
+ const output = [];
25
+ for (const source of project.sources) {
26
+ if (sourceKind(source) !== 'directory')
27
+ continue;
28
+ if (await isGitRepository(resolve(root, source.path)))
29
+ output.push(source);
30
+ }
31
+ return output;
32
+ }
33
+ export async function listSourceRefs(root, sourceName) {
34
+ const project = await loadProject(root);
35
+ const source = project.sources.find((entry) => entry.name === sourceName);
36
+ if (!source || sourceKind(source) !== 'directory')
37
+ throw new DoxloopError(`"${sourceName}" is not a directory source.`, 2);
38
+ const path = resolve(root, source.path);
39
+ if (!(await isGitRepository(path)))
40
+ throw new DoxloopError(`"${sourceName}" is not a Git checkout, so it has no release refs.`, 2);
41
+ // The last sort key is primary: newest first, with version order breaking ties created in the same second.
42
+ const tags = lines(await git(path, ['tag', '--sort=-version:refname', '--sort=-creatordate', '--merged', 'HEAD'])).slice(0, 100);
43
+ const branches = lines(await git(path, ['branch', '--format=%(refname:short)'])).slice(0, 50);
44
+ const head = (await git(path, ['rev-parse', '--short', 'HEAD'])).trim();
45
+ const suggested = tags.length >= 2
46
+ ? { from: tags[1], to: tags[0], version: tags[0] }
47
+ : tags.length === 1
48
+ ? { from: tags[0], to: 'HEAD', version: `${tags[0]} (unreleased changes)` }
49
+ : undefined;
50
+ return { source: source.name, tags, branches, head, ...(suggested ? { suggested } : {}) };
51
+ }
52
+ export async function collectReleaseInventory(root, project, input) {
53
+ const version = input.version.trim();
54
+ if (!version || version.length > 60)
55
+ throw new DoxloopError('Release notes need a version label, such as v0.2.0.', 2);
56
+ const from = validRef(input.from, 'Starting ref');
57
+ const to = validRef(input.to, 'Ending ref');
58
+ const candidates = await gitBackedSources(root, project);
59
+ const selected = input.sources?.length
60
+ ? candidates.filter((source) => input.sources.includes(source.name))
61
+ : candidates;
62
+ if (selected.length === 0) {
63
+ throw new DoxloopError(input.sources?.length
64
+ ? `None of ${input.sources.join(', ')} is a Git-backed directory source.`
65
+ : 'Release notes need at least one directory source that is a Git checkout. Connect the product repository under Sources first.', 2);
66
+ }
67
+ const sources = [];
68
+ for (const source of selected) {
69
+ sources.push(await inventorySource(root, source, from, to, version));
70
+ }
71
+ return { version, from, to, collectedAt: new Date().toISOString(), sources };
72
+ }
73
+ async function inventorySource(root, source, from, to, version) {
74
+ const path = resolve(root, source.path);
75
+ for (const ref of [from, to]) {
76
+ try {
77
+ await git(path, ['rev-parse', '--verify', '--quiet', `${ref}^{commit}`]);
78
+ }
79
+ catch {
80
+ throw new DoxloopError(`"${ref}" is not a commit, tag, or branch in source "${source.name}".`, 2);
81
+ }
82
+ }
83
+ const log = await git(path, [
84
+ 'log', '--no-merges', '--date=short', `--max-count=${MAX_RELEASE_COMMITS + 1}`,
85
+ '--format=%H%x1f%ad%x1f%an%x1f%s%x1f%b%x1e', `${from}..${to}`,
86
+ ]);
87
+ const commits = log.split('\x1e').map((entry) => entry.trim()).filter(Boolean).map((entry) => {
88
+ const [hash = '', date = '', author = '', subject = '', body = ''] = entry.split('\x1f');
89
+ const trimmedBody = body.trim().replace(/\s+/g, ' ').slice(0, MAX_BODY_CHARS);
90
+ return { hash: hash.slice(0, 12), date, author, subject: subject.trim(), ...(trimmedBody ? { body: trimmedBody } : {}) };
91
+ });
92
+ const truncatedCommits = commits.length > MAX_RELEASE_COMMITS;
93
+ const diff = lines(await git(path, ['diff', '--name-status', from, to]));
94
+ const changedFiles = diff.slice(0, MAX_RELEASE_FILES).map((line) => line.replace(/\t+/g, ' '));
95
+ const changelog = await changelogExcerpt(path, version);
96
+ return {
97
+ source: source.name,
98
+ from,
99
+ to,
100
+ commits: commits.slice(0, MAX_RELEASE_COMMITS),
101
+ changedFiles,
102
+ truncated: truncatedCommits || diff.length > MAX_RELEASE_FILES,
103
+ ...(changelog ? { changelog } : {}),
104
+ };
105
+ }
106
+ /** The changelog section that names the version, or the top of the file when no section matches. */
107
+ export async function changelogExcerpt(sourceRoot, version) {
108
+ let entries;
109
+ try {
110
+ entries = await readdir(sourceRoot);
111
+ }
112
+ catch {
113
+ return undefined;
114
+ }
115
+ const file = entries.find((entry) => CHANGELOG_NAMES.includes(entry.replace(/\.(md|mdx|markdown|txt|rst)$/i, '').toLowerCase()));
116
+ if (!file)
117
+ return undefined;
118
+ const text = await readFile(join(sourceRoot, file), 'utf8');
119
+ return { path: file, excerpt: extractVersionSection(text, version) };
120
+ }
121
+ export function extractVersionSection(text, version) {
122
+ const lines = text.split(/\r?\n/);
123
+ const needle = version.replace(/^v/i, '').toLowerCase();
124
+ const isHeading = (line) => /^#{1,3}\s/.test(line) || /^(?:version|release)\b/i.test(line);
125
+ const level = (line) => (/^(#{1,3})\s/.exec(line)?.[1]?.length ?? 1);
126
+ const start = lines.findIndex((line) => isHeading(line) && line.toLowerCase().includes(needle));
127
+ if (start === -1)
128
+ return text.slice(0, MAX_CHANGELOG_CHARS);
129
+ const startLevel = level(lines[start]);
130
+ let end = lines.length;
131
+ for (let index = start + 1; index < lines.length; index += 1) {
132
+ if (isHeading(lines[index]) && level(lines[index]) <= startLevel) {
133
+ end = index;
134
+ break;
135
+ }
136
+ }
137
+ return lines.slice(start, end).join('\n').trim().slice(0, MAX_CHANGELOG_CHARS);
138
+ }
139
+ /** The inventory as the planner and writer read it. */
140
+ export function formatReleaseInventory(inventory) {
141
+ const parts = [`Release: ${inventory.version} (${inventory.from}..${inventory.to}, collected ${inventory.collectedAt.slice(0, 10)})`];
142
+ for (const source of inventory.sources) {
143
+ parts.push(`\nSource "${source.source}": ${source.commits.length} commit${source.commits.length === 1 ? '' : 's'}, ${source.changedFiles.length} changed file${source.changedFiles.length === 1 ? '' : 's'}${source.truncated ? ' (truncated)' : ''}`);
144
+ if (source.changelog)
145
+ parts.push(`Changelog (${source.changelog.path}):\n${source.changelog.excerpt}`);
146
+ if (source.commits.length > 0) {
147
+ parts.push('Commits, newest first:');
148
+ for (const commit of source.commits)
149
+ parts.push(`- ${commit.date} ${commit.hash} ${commit.subject}${commit.body ? ` — ${commit.body}` : ''}`);
150
+ }
151
+ if (source.changedFiles.length > 0)
152
+ parts.push(`Changed files:\n${source.changedFiles.map((file) => `- ${file}`).join('\n')}`);
153
+ }
154
+ return parts.join('\n');
155
+ }
156
+ export function releaseNotesPagePath(version) {
157
+ const slug = version.trim().toLowerCase().replace(/^v(?=\d)/, '').replace(/[^a-z0-9.]+/g, '-').replace(/^-+|-+$/g, '') || 'latest';
158
+ return `release-notes/${slug}`;
159
+ }
160
+ function validRef(value, label) {
161
+ const ref = value.trim();
162
+ if (!SAFE_REF.test(ref))
163
+ throw new DoxloopError(`${label} must be a Git tag, branch, or commit.`, 2);
164
+ return ref;
165
+ }
166
+ async function isGitRepository(path) {
167
+ if (!(await pathExists(path)))
168
+ return false;
169
+ try {
170
+ return (await git(path, ['rev-parse', '--is-inside-work-tree'])).trim() === 'true';
171
+ }
172
+ catch {
173
+ return false;
174
+ }
175
+ }
176
+ async function git(path, args) {
177
+ const result = await execute('git', ['-C', path, ...args], { maxBuffer: 32 * 1024 * 1024 });
178
+ return result.stdout;
179
+ }
180
+ function lines(value) {
181
+ return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
182
+ }
183
+ //# sourceMappingURL=release-notes.js.map
@@ -0,0 +1,16 @@
1
+ import type { DoxloopProject, RemoteSource, SourceChange, SyncState } from './types.js';
2
+ export interface RemoteMonitorResult {
3
+ project: DoxloopProject;
4
+ changes: SourceChange[];
5
+ nextState: SyncState;
6
+ }
7
+ /** Verify read access to a configured remote Git branch without downloading source. */
8
+ export declare function testRemoteSource(remote: RemoteSource): Promise<{
9
+ head: string;
10
+ }>;
11
+ /**
12
+ * Observe configured product repositories without writing to the user's source
13
+ * checkout. Managed snapshots live outside the documentation project.
14
+ */
15
+ export declare function monitorRemoteSources(root: string, project: DoxloopProject): Promise<RemoteMonitorResult>;
16
+ //# sourceMappingURL=remote-monitor.d.ts.map
@@ -0,0 +1,74 @@
1
+ import { sourceKind } from './project.js';
2
+ import { changedFilesInRemoteScope, materializeRemoteSource, remoteChangedFiles, remoteHead, } from './remote-source.js';
3
+ import { collectSourceChanges, readSyncState } from './sync.js';
4
+ /** Verify read access to a configured remote Git branch without downloading source. */
5
+ export async function testRemoteSource(remote) {
6
+ return { head: await remoteHead(remote) };
7
+ }
8
+ /**
9
+ * Observe configured product repositories without writing to the user's source
10
+ * checkout. Managed snapshots live outside the documentation project.
11
+ */
12
+ export async function monitorRemoteSources(root, project) {
13
+ const previous = await readSyncState(root);
14
+ const nextState = {
15
+ schemaVersion: 1,
16
+ sources: { ...previous.sources },
17
+ };
18
+ const changes = [];
19
+ const sources = [];
20
+ for (const source of project.sources) {
21
+ if (sourceKind(source) === 'openapi') {
22
+ changes.push(...await collectSourceChanges(root, [source]));
23
+ sources.push(source);
24
+ continue;
25
+ }
26
+ if (!source.remote) {
27
+ changes.push(...await collectSourceChanges(root, [source]));
28
+ sources.push(source);
29
+ continue;
30
+ }
31
+ const head = await remoteHead(source.remote);
32
+ const record = previous.sources[source.name];
33
+ if (!record) {
34
+ const snapshot = await materializeRemoteSource(root, source, head);
35
+ changes.push({ ...source, path: snapshot.path, kind: 'no-baseline', head, uncommittedFiles: [] });
36
+ sources.push({ ...source, path: snapshot.path });
37
+ nextState.sources[source.name] = {
38
+ commit: head,
39
+ recordedAt: new Date().toISOString(),
40
+ };
41
+ continue;
42
+ }
43
+ if (record.commit === head) {
44
+ changes.push({
45
+ ...source,
46
+ kind: 'unchanged',
47
+ baseline: record.commit,
48
+ head,
49
+ changedFiles: [],
50
+ uncommittedFiles: [],
51
+ });
52
+ sources.push(source);
53
+ continue;
54
+ }
55
+ const changedFiles = changedFilesInRemoteScope(await remoteChangedFiles(source.remote, record.commit, head), source.remote.subdirectory);
56
+ const snapshot = await materializeRemoteSource(root, source, head);
57
+ changes.push({
58
+ ...source,
59
+ path: snapshot.path,
60
+ kind: 'changed',
61
+ baseline: record.commit,
62
+ head,
63
+ changedFiles,
64
+ uncommittedFiles: [],
65
+ });
66
+ sources.push({ ...source, path: snapshot.path });
67
+ nextState.sources[source.name] = {
68
+ commit: head,
69
+ recordedAt: new Date().toISOString(),
70
+ };
71
+ }
72
+ return { project: { ...project, sources }, changes, nextState };
73
+ }
74
+ //# sourceMappingURL=remote-monitor.js.map
@@ -0,0 +1,34 @@
1
+ import type { RemoteSource, SourceBinding } from './types.js';
2
+ export interface GitCredential {
3
+ username?: string;
4
+ secret: string;
5
+ }
6
+ export interface RemoteBranch {
7
+ name: string;
8
+ head: string;
9
+ }
10
+ /** Validate a provider-neutral Git clone URL without embedding credentials. */
11
+ export declare function parseGitRepository(value: string): string;
12
+ /** Keep private-repository credentials in memory for this Doxloop UI session. */
13
+ export declare function rememberRemoteCredential(repository: string, username: string | undefined, secret: string | undefined): void;
14
+ /**
15
+ * Forward UI-session credentials to Doxloop child processes without writing
16
+ * them to the project configuration or placing them on a command line.
17
+ */
18
+ export declare function remoteCredentialEnvironment(): NodeJS.ProcessEnv;
19
+ /** Accept GitHub web/clone URLs or owner/name and return the canonical slug. */
20
+ export declare function parseGitHubRepository(value: string): string;
21
+ export declare function listRemoteBranches(remote: RemoteSource): Promise<RemoteBranch[]>;
22
+ export declare function remoteHead(remote: RemoteSource): Promise<string>;
23
+ /** List repository folders without checking out file contents. */
24
+ export declare function listRemoteDirectories(remote: RemoteSource): Promise<string[]>;
25
+ export declare function remoteChangedFiles(remote: RemoteSource, baseline: string, head: string): Promise<string[]>;
26
+ /** Download a provider snapshot outside the documentation deployment boundary. */
27
+ export declare function materializeRemoteSource(root: string, source: Pick<SourceBinding, 'name' | 'remote'>, requestedHead?: string): Promise<{
28
+ path: string;
29
+ head: string;
30
+ files: number;
31
+ }>;
32
+ export declare function changedFilesInRemoteScope(files: string[], subdirectory?: string): string[];
33
+ export declare function portableSourcePath(root: string, sourcePath: string): string;
34
+ //# sourceMappingURL=remote-source.d.ts.map