@pactosigna/records 0.1.7 → 0.1.8

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.
package/dist/cli.js CHANGED
@@ -876,7 +876,7 @@ ${probabilityLabels[labelIndex]}`,
876
876
  };
877
877
  }
878
878
 
879
- // ../schemas/dist/index.js
879
+ // ../../node_modules/.pnpm/@pactosigna+schemas@0.1.19/node_modules/@pactosigna/schemas/dist/index.js
880
880
  import { z as z2 } from "zod";
881
881
  import { z as z22 } from "zod";
882
882
  import { z as z3 } from "zod";
@@ -3212,18 +3212,7 @@ var DocumentSignoffStatusResponseSchema = z33.object({
3212
3212
  var DocumentExportResponseSchema = z33.object({
3213
3213
  message: z33.string()
3214
3214
  });
3215
- var CompiledDocumentPresetSchema = z43.enum([
3216
- "srs",
3217
- "prs",
3218
- "dmr",
3219
- "risk",
3220
- "hld",
3221
- "sdd",
3222
- "vv",
3223
- "uef",
3224
- "csf",
3225
- "cer"
3226
- ]);
3215
+ var CompiledDocumentPresetSchema = z43.enum(["srs", "prs", "dmr", "risk"]);
3227
3216
  var CompiledDocumentQuerySchema = z43.object({
3228
3217
  organizationId: z43.string().min(1),
3229
3218
  repositoryId: z43.string().min(1).optional(),
@@ -5524,9 +5513,95 @@ function generateCer(input) {
5524
5513
 
5525
5514
  // src/github/changelog.ts
5526
5515
  import { execFileSync } from "child_process";
5527
- import { resolve as resolve5 } from "path";
5528
- import { readFileSync as readFileSync5 } from "fs";
5516
+ import { resolve as resolve6 } from "path";
5517
+ import { readFileSync as readFileSync6 } from "fs";
5518
+ import matter4 from "gray-matter";
5519
+
5520
+ // src/github/drm-parser.ts
5521
+ import { readdirSync as readdirSync2, readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
5522
+ import { resolve as resolve5, join as join2 } from "path";
5529
5523
  import matter3 from "gray-matter";
5524
+ function parseDrmDocsTable(body) {
5525
+ const startTag = "<!-- DRM:DOCS_START -->";
5526
+ const endTag = "<!-- DRM:DOCS_END -->";
5527
+ const startIdx = body.indexOf(startTag);
5528
+ const endIdx = body.indexOf(endTag);
5529
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) return [];
5530
+ const block = body.slice(startIdx + startTag.length, endIdx).trim();
5531
+ const lines = block.split("\n");
5532
+ const entries = [];
5533
+ for (const line of lines) {
5534
+ if (!line.startsWith("|")) continue;
5535
+ const cells = line.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
5536
+ if (cells.length < 2) continue;
5537
+ const action = cells[0].toUpperCase();
5538
+ if (action === "ACTION" || /^-+$/.test(action) || action === "NONE") continue;
5539
+ if (action !== "CREATE" && action !== "UPDATE") continue;
5540
+ const target = cells[1];
5541
+ const reason = cells.length > 2 ? cells[cells.length - 1] : "";
5542
+ entries.push({
5543
+ action,
5544
+ target,
5545
+ reason
5546
+ });
5547
+ }
5548
+ return entries;
5549
+ }
5550
+ var DRM_FOLDERS = ["docs/change/drm", "docs/design-review"];
5551
+ function readDrmFiles(rootDir) {
5552
+ const drms = [];
5553
+ for (const folder of DRM_FOLDERS) {
5554
+ const fullPath = resolve5(rootDir, folder);
5555
+ if (!existsSync4(fullPath)) continue;
5556
+ let files;
5557
+ try {
5558
+ files = readdirSync2(fullPath).filter((f) => f.endsWith(".md"));
5559
+ } catch {
5560
+ continue;
5561
+ }
5562
+ for (const file of files) {
5563
+ const filePath = join2(folder, file);
5564
+ const raw = readFileSync5(resolve5(rootDir, filePath), "utf-8");
5565
+ const { data, content } = matter3(raw);
5566
+ if (!data.id || !data.title) continue;
5567
+ const docEntries = parseDrmDocsTable(content);
5568
+ drms.push({
5569
+ id: data.id,
5570
+ title: data.title,
5571
+ status: data.status ?? "unknown",
5572
+ releasePlan: data.release_plan,
5573
+ docEntries
5574
+ });
5575
+ }
5576
+ }
5577
+ return drms.sort((a, b) => a.id.localeCompare(b.id, void 0, { numeric: true }));
5578
+ }
5579
+ function extractDocIdFromPath(target) {
5580
+ const filename = target.split("/").pop() ?? target;
5581
+ return filename.replace(/\.md$/, "");
5582
+ }
5583
+
5584
+ // src/github/changelog.ts
5585
+ function buildSmartChangelog(rootDir, version, date) {
5586
+ const drms = readDrmFiles(rootDir);
5587
+ const entries = buildRevisionEntriesFromDrms(drms, version, date);
5588
+ if (entries.length === 0) {
5589
+ return buildChangelog(rootDir, version, date);
5590
+ }
5591
+ return entries;
5592
+ }
5593
+ function buildRevisionEntriesFromDrms(drms, version, date) {
5594
+ const withDocEntries = drms.filter((drm) => drm.docEntries.length > 0);
5595
+ if (withDocEntries.length === 0) return [];
5596
+ return withDocEntries.map((drm) => {
5597
+ const reasons = drm.docEntries.map((entry) => {
5598
+ const docId = extractDocIdFromPath(entry.target);
5599
+ return entry.reason ? `${docId}: ${entry.reason}` : docId;
5600
+ });
5601
+ const description = `[${drm.id}] ${reasons.join("; ")}`;
5602
+ return { revision: version, date, description };
5603
+ });
5604
+ }
5530
5605
  function buildChangelog(rootDir, version, date) {
5531
5606
  let previousTag = null;
5532
5607
  try {
@@ -5559,8 +5634,8 @@ function buildChangelog(rootDir, version, date) {
5559
5634
  const descriptions = [];
5560
5635
  for (const file of changedFiles.slice(0, 20)) {
5561
5636
  try {
5562
- const raw = readFileSync5(resolve5(rootDir, file), "utf-8");
5563
- const { data } = matter3(raw);
5637
+ const raw = readFileSync6(resolve6(rootDir, file), "utf-8");
5638
+ const { data } = matter4(raw);
5564
5639
  if (data.id && data.title) {
5565
5640
  descriptions.push(`${data.id}: ${data.title}`);
5566
5641
  }
@@ -5606,7 +5681,7 @@ async function generate(options) {
5606
5681
  const outDir = options.outputDir ?? pathResolve(options.rootDir, "out");
5607
5682
  mkdirSync(outDir, { recursive: true });
5608
5683
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
5609
- const revisionHistory = buildChangelog(options.rootDir, options.version, date);
5684
+ const revisionHistory = buildSmartChangelog(options.rootDir, options.version, date);
5610
5685
  const fonts = {
5611
5686
  Helvetica: {
5612
5687
  normal: "Helvetica",
@@ -5662,11 +5737,11 @@ function getDraftReleaseVersion() {
5662
5737
 
5663
5738
  // src/github/publish.ts
5664
5739
  import { execFileSync as execFileSync3 } from "child_process";
5665
- import { readdirSync as readdirSync2 } from "fs";
5666
- import { resolve as resolve6 } from "path";
5740
+ import { readdirSync as readdirSync3 } from "fs";
5741
+ import { resolve as resolve7 } from "path";
5667
5742
  function publishDraftRelease(version, outputDir) {
5668
5743
  const tag = `v${version}`;
5669
- const pdfFiles = readdirSync2(outputDir).filter((f) => f.endsWith(".pdf")).map((f) => resolve6(outputDir, f));
5744
+ const pdfFiles = readdirSync3(outputDir).filter((f) => f.endsWith(".pdf")).map((f) => resolve7(outputDir, f));
5670
5745
  if (pdfFiles.length === 0) {
5671
5746
  throw new Error("No PDF files found to upload");
5672
5747
  }
@@ -1,3 +1,26 @@
1
1
  import type { RevisionEntry } from '../pdf/layout.js';
2
+ import type { ParsedDrm } from './drm-parser.js';
3
+ /**
4
+ * Build revision entries from DRM (Design Review Meeting) files.
5
+ *
6
+ * Reads DRM markdown files from the repository, extracts document-to-reason
7
+ * mappings from DRM:DOCS tables, and produces meaningful revision descriptions.
8
+ * Falls back to `buildChangelog()` if no DRM files with doc entries are found.
9
+ *
10
+ * @param rootDir - Repository root directory
11
+ * @param version - Release version string (e.g., "1.2.0")
12
+ * @param date - Release date in ISO format (e.g., "2026-03-28")
13
+ * @returns Revision entries with DRM-sourced descriptions
14
+ */
15
+ export declare function buildSmartChangelog(rootDir: string, version: string, date: string): RevisionEntry[];
16
+ /**
17
+ * Build revision entries from parsed DRM data.
18
+ *
19
+ * Groups DRM doc entries by DRM ID and produces one revision entry per DRM,
20
+ * with a description summarizing the affected documents and reasons.
21
+ *
22
+ * Exported for unit testing without filesystem access.
23
+ */
24
+ export declare function buildRevisionEntriesFromDrms(drms: ParsedDrm[], version: string, date: string): RevisionEntry[];
2
25
  export declare function buildChangelog(rootDir: string, version: string, date: string): RevisionEntry[];
3
26
  //# sourceMappingURL=changelog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/github/changelog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAkD9F"}
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/github/changelog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,aAAa,EAAE,CASjB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,SAAS,EAAE,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,aAAa,EAAE,CAcjB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAkD9F"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * DRM (Design Review Meeting) Parser
3
+ *
4
+ * Parses DRM markdown files from git repositories to extract
5
+ * document-to-reason mappings from DRM:DOCS tables.
6
+ *
7
+ * The DRM:DOCS table format uses HTML comment markers:
8
+ *
9
+ * ```markdown
10
+ * <!-- DRM:DOCS_START -->
11
+ * | Action | Target | Reason |
12
+ * |--------|--------|--------|
13
+ * | UPDATE | docs/software/requirements/SRS-001.md | Added validation gate |
14
+ * <!-- DRM:DOCS_END -->
15
+ * ```
16
+ *
17
+ * This module is a standalone copy of the parsing logic from
18
+ * scripts/traceability/drm-check.ts, kept independent to avoid
19
+ * adding cross-package dependencies to the offline records CLI.
20
+ */
21
+ export interface DrmDocEntry {
22
+ action: 'CREATE' | 'UPDATE';
23
+ target: string;
24
+ reason: string;
25
+ }
26
+ export interface ParsedDrm {
27
+ id: string;
28
+ title: string;
29
+ status: string;
30
+ releasePlan?: string;
31
+ docEntries: DrmDocEntry[];
32
+ }
33
+ /**
34
+ * Parses a DRM:DOCS marker block from a markdown body.
35
+ *
36
+ * Extracts rows from the table between `<!-- DRM:DOCS_START -->` and
37
+ * `<!-- DRM:DOCS_END -->` markers. Each row maps an action (CREATE/UPDATE)
38
+ * to a target file path and a human-readable reason.
39
+ */
40
+ export declare function parseDrmDocsTable(body: string): DrmDocEntry[];
41
+ /**
42
+ * Reads all DRM markdown files from the repository.
43
+ *
44
+ * Searches known DRM folders (`docs/change/drm`, `docs/design-review`)
45
+ * and parses each file's frontmatter and DRM:DOCS table.
46
+ *
47
+ * @param rootDir - Repository root directory
48
+ * @returns Parsed DRM entries, sorted by ID
49
+ */
50
+ export declare function readDrmFiles(rootDir: string): ParsedDrm[];
51
+ /**
52
+ * Extracts the document ID from a file path.
53
+ *
54
+ * @example
55
+ * extractDocIdFromPath('docs/software/requirements/SRS-001.md') => 'SRS-001'
56
+ */
57
+ export declare function extractDocIdFromPath(target: string): string;
58
+ //# sourceMappingURL=drm-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drm-parser.d.ts","sourceRoot":"","sources":["../../src/github/drm-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,WAAW,EAAE,CAAC;CAC3B;AAMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAyC7D;AASD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAkCzD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG3D"}
package/dist/index.js CHANGED
@@ -1355,9 +1355,95 @@ function generateCer(input) {
1355
1355
 
1356
1356
  // src/github/changelog.ts
1357
1357
  import { execFileSync } from "child_process";
1358
- import { resolve as resolve5 } from "path";
1359
- import { readFileSync as readFileSync5 } from "fs";
1358
+ import { resolve as resolve6 } from "path";
1359
+ import { readFileSync as readFileSync6 } from "fs";
1360
+ import matter3 from "gray-matter";
1361
+
1362
+ // src/github/drm-parser.ts
1363
+ import { readdirSync as readdirSync2, readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
1364
+ import { resolve as resolve5, join as join2 } from "path";
1360
1365
  import matter2 from "gray-matter";
1366
+ function parseDrmDocsTable(body) {
1367
+ const startTag = "<!-- DRM:DOCS_START -->";
1368
+ const endTag = "<!-- DRM:DOCS_END -->";
1369
+ const startIdx = body.indexOf(startTag);
1370
+ const endIdx = body.indexOf(endTag);
1371
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) return [];
1372
+ const block = body.slice(startIdx + startTag.length, endIdx).trim();
1373
+ const lines = block.split("\n");
1374
+ const entries = [];
1375
+ for (const line of lines) {
1376
+ if (!line.startsWith("|")) continue;
1377
+ const cells = line.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
1378
+ if (cells.length < 2) continue;
1379
+ const action = cells[0].toUpperCase();
1380
+ if (action === "ACTION" || /^-+$/.test(action) || action === "NONE") continue;
1381
+ if (action !== "CREATE" && action !== "UPDATE") continue;
1382
+ const target = cells[1];
1383
+ const reason = cells.length > 2 ? cells[cells.length - 1] : "";
1384
+ entries.push({
1385
+ action,
1386
+ target,
1387
+ reason
1388
+ });
1389
+ }
1390
+ return entries;
1391
+ }
1392
+ var DRM_FOLDERS = ["docs/change/drm", "docs/design-review"];
1393
+ function readDrmFiles(rootDir) {
1394
+ const drms = [];
1395
+ for (const folder of DRM_FOLDERS) {
1396
+ const fullPath = resolve5(rootDir, folder);
1397
+ if (!existsSync4(fullPath)) continue;
1398
+ let files;
1399
+ try {
1400
+ files = readdirSync2(fullPath).filter((f) => f.endsWith(".md"));
1401
+ } catch {
1402
+ continue;
1403
+ }
1404
+ for (const file of files) {
1405
+ const filePath = join2(folder, file);
1406
+ const raw = readFileSync5(resolve5(rootDir, filePath), "utf-8");
1407
+ const { data, content } = matter2(raw);
1408
+ if (!data.id || !data.title) continue;
1409
+ const docEntries = parseDrmDocsTable(content);
1410
+ drms.push({
1411
+ id: data.id,
1412
+ title: data.title,
1413
+ status: data.status ?? "unknown",
1414
+ releasePlan: data.release_plan,
1415
+ docEntries
1416
+ });
1417
+ }
1418
+ }
1419
+ return drms.sort((a, b) => a.id.localeCompare(b.id, void 0, { numeric: true }));
1420
+ }
1421
+ function extractDocIdFromPath(target) {
1422
+ const filename = target.split("/").pop() ?? target;
1423
+ return filename.replace(/\.md$/, "");
1424
+ }
1425
+
1426
+ // src/github/changelog.ts
1427
+ function buildSmartChangelog(rootDir, version, date) {
1428
+ const drms = readDrmFiles(rootDir);
1429
+ const entries = buildRevisionEntriesFromDrms(drms, version, date);
1430
+ if (entries.length === 0) {
1431
+ return buildChangelog(rootDir, version, date);
1432
+ }
1433
+ return entries;
1434
+ }
1435
+ function buildRevisionEntriesFromDrms(drms, version, date) {
1436
+ const withDocEntries = drms.filter((drm) => drm.docEntries.length > 0);
1437
+ if (withDocEntries.length === 0) return [];
1438
+ return withDocEntries.map((drm) => {
1439
+ const reasons = drm.docEntries.map((entry) => {
1440
+ const docId = extractDocIdFromPath(entry.target);
1441
+ return entry.reason ? `${docId}: ${entry.reason}` : docId;
1442
+ });
1443
+ const description = `[${drm.id}] ${reasons.join("; ")}`;
1444
+ return { revision: version, date, description };
1445
+ });
1446
+ }
1361
1447
  function buildChangelog(rootDir, version, date) {
1362
1448
  let previousTag = null;
1363
1449
  try {
@@ -1390,8 +1476,8 @@ function buildChangelog(rootDir, version, date) {
1390
1476
  const descriptions = [];
1391
1477
  for (const file of changedFiles.slice(0, 20)) {
1392
1478
  try {
1393
- const raw = readFileSync5(resolve5(rootDir, file), "utf-8");
1394
- const { data } = matter2(raw);
1479
+ const raw = readFileSync6(resolve6(rootDir, file), "utf-8");
1480
+ const { data } = matter3(raw);
1395
1481
  if (data.id && data.title) {
1396
1482
  descriptions.push(`${data.id}: ${data.title}`);
1397
1483
  }
@@ -1437,7 +1523,7 @@ async function generate(options) {
1437
1523
  const outDir = options.outputDir ?? pathResolve(options.rootDir, "out");
1438
1524
  mkdirSync(outDir, { recursive: true });
1439
1525
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1440
- const revisionHistory = buildChangelog(options.rootDir, options.version, date);
1526
+ const revisionHistory = buildSmartChangelog(options.rootDir, options.version, date);
1441
1527
  const fonts = {
1442
1528
  Helvetica: {
1443
1529
  normal: "Helvetica",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pactosigna/records",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "description": "Generate audit-ready regulatory PDF records from PactoSigna-compliant git repositories",
6
6
  "publishConfig": {
@@ -41,7 +41,7 @@
41
41
  "typescript": "^5.7.2",
42
42
  "vitest": "^3.0.0",
43
43
  "zod": "^3.24.1",
44
- "@pactosigna/schemas": "0.1.0"
44
+ "@pactosigna/schemas": "0.1.19"
45
45
  },
46
46
  "repository": {
47
47
  "type": "git",