@pukujan/create-modular-monolith 2.2.1 → 2.2.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 (30) hide show
  1. package/package.json +1 -1
  2. package/template/.cursor/rules/file-exchange-inbox.mdc +1 -1
  3. package/template/ARCHITECTURE_EXPORT_README.md +30 -0
  4. package/template/EXPORT_MANIFEST.json +74 -0
  5. package/template/NOTICE +2 -3
  6. package/template/README.md +1 -61
  7. package/template/backend/package.json +1 -1
  8. package/template/backend/src/modules/model-condenser/services/modelCondenser.service.js +36 -465
  9. package/template/backend/src/modules/model-condenser/tests/unit/modelCondenser.service.test.js +2 -3
  10. package/template/backend/src/shared/utils/consolidatedExport.js +155 -11
  11. package/template/backend/src/shared/utils/consolidatedExport.test.js +50 -0
  12. package/template/docs/README.md +0 -1
  13. package/template/docs/architecture/EVAL_AND_CI.md +68 -41
  14. package/template/docs/architecture/REPO_ARTIFACT_LAYOUT.md +57 -14
  15. package/template/docs/architecture/contracts/consolidatedExports.contract.md +14 -10
  16. package/template/docs/architecture/contracts/manifest.json +17 -0
  17. package/template/file-exchange/README.md +20 -15
  18. package/template/frontend/package.json +1 -1
  19. package/template/package.json +3 -3
  20. package/template/scripts/condense-all.mjs +52 -0
  21. package/template/scripts/condense-file-structure.mjs +19 -10
  22. package/template/scripts/condense-models.mjs +5 -3
  23. package/template/scripts/condense-prompts.mjs +13 -51
  24. package/template/scripts/consolidated-output.mjs +22 -10
  25. package/template/scripts/export-architecture-starter.mjs +389 -0
  26. package/template/scripts/lib/api-inventory.mjs +16 -61
  27. package/template/scripts/lib/repo-tree.mjs +26 -4
  28. package/template/scripts/sync-cli-template.mjs +44 -0
  29. package/template/scripts/write-pre-push-dev-log.mjs +1 -0
  30. package/template/file-exchange/exports/consolidated-models.json +0 -625
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Run all consolidated exports into one dated audit folder:
4
+ * file-exchange/exports/{stamp}_consolidated/
5
+ */
6
+ import { spawn } from "node:child_process";
7
+ import { join, dirname } from "path";
8
+ import { fileURLToPath } from "url";
9
+ import { beginConsolidatedExportSession } from "../backend/src/shared/utils/consolidatedExport.js";
10
+
11
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
12
+
13
+ function runNpm(script) {
14
+ return new Promise((resolve, reject) => {
15
+ const child = spawn("npm", ["run", script], {
16
+ cwd: repoRoot,
17
+ stdio: "inherit",
18
+ env: { ...process.env }
19
+ });
20
+ child.on("exit", (code) => {
21
+ if (code === 0) resolve();
22
+ else reject(new Error(`${script} exited with code ${code}`));
23
+ });
24
+ });
25
+ }
26
+
27
+ async function main() {
28
+ const session = beginConsolidatedExportSession();
29
+ console.log(`Consolidated export session: ${session.exportDir}/`);
30
+
31
+ await runNpm("condense-prompts");
32
+ await runNpm("condense-file-structure");
33
+
34
+ await new Promise((resolve, reject) => {
35
+ const child = spawn("npm", ["run", "condense-models", "--", "--local"], {
36
+ cwd: join(repoRoot, "backend"),
37
+ stdio: "inherit",
38
+ env: { ...process.env }
39
+ });
40
+ child.on("exit", (code) => {
41
+ if (code === 0) resolve();
42
+ else reject(new Error(`condense-models exited with code ${code}`));
43
+ });
44
+ });
45
+
46
+ console.log(`Done → ${session.exportDir}/ (latest copies also at file-exchange/exports/consolidated-*.json)`);
47
+ }
48
+
49
+ main().catch((err) => {
50
+ console.error(err.message || err);
51
+ process.exit(1);
52
+ });
@@ -1,40 +1,49 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Walk the repository and write consolidated-file-structure.json
4
- * (excludes node_modules, .git, dist, build same as tree -I).
3
+ * Write consolidated-file-structure.json — ASCII tree only (no nested JSON tree).
4
+ * Excludes node_modules, .git, dist, build, and runtime batch/export roots.
5
5
  *
6
6
  * Usage: node scripts/condense-file-structure.mjs
7
7
  */
8
8
  import { join, dirname } from "path";
9
9
  import { fileURLToPath } from "url";
10
10
  import { writeConsolidatedArtifact } from "./consolidated-output.mjs";
11
- import { buildRepoTree, TREE_IGNORE_DIRS, TREE_IGNORE_FILES } from "./lib/repo-tree.mjs";
11
+ import {
12
+ buildRepoTree,
13
+ TREE_IGNORE_DIRS,
14
+ TREE_IGNORE_FILES,
15
+ TREE_IGNORE_PREFIXES
16
+ } from "./lib/repo-tree.mjs";
12
17
 
13
18
  const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
14
19
 
15
20
  async function main() {
16
- const { rootName, tree, treeText, stats, flatPaths } = await buildRepoTree(repoRoot);
21
+ const { rootName, treeText, stats } = await buildRepoTree(repoRoot);
17
22
 
18
23
  const doc = {
19
24
  meta: {
20
25
  generatedAt: new Date().toISOString(),
21
26
  repositoryRoot: repoRoot,
27
+ rootName,
22
28
  condensedBy: "condense-file-structure",
23
29
  description:
24
- "Repository file tree for legal-prmpt-eng (excludes node_modules, .git, dist, build).",
30
+ "ASCII repository tree (tree(1)-style). Excludes node_modules, .git, dist, build, and runtime data/ (if present).",
25
31
  excludeDirs: TREE_IGNORE_DIRS,
26
32
  excludeFiles: TREE_IGNORE_FILES,
33
+ excludePrefixes: TREE_IGNORE_PREFIXES,
27
34
  treeIgnoreFlag: 'tree -I "node_modules|.git|dist|build"'
28
35
  },
29
36
  stats,
30
- tree,
31
- treeText,
32
- flatPaths
37
+ treeText
33
38
  };
34
39
 
35
- const { exportPath, modelsPath } = await writeConsolidatedArtifact("fileStructure", doc);
40
+ const { exportPath, datedExportDir, modelsPath } = await writeConsolidatedArtifact(
41
+ "fileStructure",
42
+ doc
43
+ );
44
+ const lineCount = treeText.split("\n").length;
36
45
  console.log(
37
- `Consolidated ${stats.fileCount} files, ${stats.directoryCount} dirs → ${exportPath} (+ ${modelsPath})`
46
+ `Consolidated tree (${lineCount} lines, ${stats.fileCount} files) → ${exportPath} (${datedExportDir}/, mirror ${modelsPath})`
38
47
  );
39
48
  }
40
49
 
@@ -53,11 +53,13 @@ try {
53
53
  await import("../backend/src/shared/utils/consolidatedExport.js");
54
54
  const modelsPath = join(repoRoot, "models", CONSOLIDATED_FILENAMES.models);
55
55
  const json = await readFile(modelsPath, "utf8");
56
- await writeConsolidatedExport(repoRoot, CONSOLIDATED_FILENAMES.models, json);
57
- const exportRel = `${CONSOLIDATED_EXPORT_DIR}/${CONSOLIDATED_FILENAMES.models}`;
56
+ const written = await writeConsolidatedExport(repoRoot, CONSOLIDATED_FILENAMES.models, json, {
57
+ condensedBy: "model-condenser"
58
+ });
58
59
 
59
60
  console.log(`Model condenser: ${result.modelCount} models`);
60
- console.log(` → ${exportRel}`);
61
+ console.log(` → ${written.exportPath} (audit)`);
62
+ console.log(` → ${CONSOLIDATED_EXPORT_DIR}/${CONSOLIDATED_FILENAMES.models} (latest)`);
61
63
  console.log(` → models/${CONSOLIDATED_FILENAMES.models} (API mirror)`);
62
64
  console.log(`Generated at: ${result.generatedAt}`);
63
65
  } catch (error) {
@@ -1,27 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Collect all versioned prompt templates into models/consolidated-prompts.json
4
- * Usage: node scripts/condense-prompts.mjs
3
+ * Collect prompt templates from backend modules into consolidated-prompts.json.
5
4
  */
6
- import { readFile, readdir, stat, access } from "fs/promises";
7
- import { existsSync } from "fs";
5
+ import { readFile, readdir, stat } from "fs/promises";
8
6
  import { join, relative, dirname } from "path";
9
7
  import { fileURLToPath } from "url";
10
8
  import { writeConsolidatedArtifact } from "./consolidated-output.mjs";
11
9
 
12
10
  const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
13
-
14
11
  const SCAN_ROOTS = ["backend/src/modules"];
15
-
16
12
  const PROMPT_EXTENSIONS = [".prompt.md", ".prompt.js"];
17
13
 
18
14
  function extractVariables(text) {
19
15
  const vars = new Set();
20
16
  const re = /\{\{(\w+)\}\}/g;
21
17
  let m;
22
- while ((m = re.exec(text)) !== null) {
23
- vars.add(m[1]);
24
- }
18
+ while ((m = re.exec(text)) !== null) vars.add(m[1]);
25
19
  return [...vars].sort();
26
20
  }
27
21
 
@@ -72,36 +66,12 @@ async function findManifests() {
72
66
  return manifests;
73
67
  }
74
68
 
75
- async function loadDomainPromptVersions() {
76
- const path = join(
77
- repoRoot,
78
- "backend/src/modules/case-filing-ai/prompts/promptVersions.js"
79
- );
80
- if (!existsSync(path)) {
81
- return { sourcePath: null, versions: {} };
82
- }
83
- const raw = await readFile(path, "utf8");
84
- const versions = {};
85
- const blockRe = /(\w+):\s*\{[^}]*id:\s*"([^"]+)"[^}]*masterCaseFiling:\s*"([^"]+)"[^}]*description:\s*"([^"]+)"/gs;
86
- let m;
87
- while ((m = blockRe.exec(raw)) !== null) {
88
- versions[m[2]] = {
89
- key: m[1],
90
- id: m[2],
91
- masterCaseFiling: m[3],
92
- description: m[4]
93
- };
94
- }
95
- return { sourcePath: relative(repoRoot, path), versions };
96
- }
97
-
98
69
  async function main() {
99
70
  const promptFiles = [];
100
71
  for (const root of SCAN_ROOTS) {
101
72
  const found = await walk(join(repoRoot, root));
102
- promptFiles.push(...found.filter((f) => !f.endsWith("manifest.json")));
73
+ promptFiles.push(...found);
103
74
  }
104
-
105
75
  promptFiles.sort();
106
76
 
107
77
  const inventory = [];
@@ -112,11 +82,8 @@ async function main() {
112
82
  const content = await readFile(abs, "utf8");
113
83
  const st = await stat(abs);
114
84
  const moduleMatch = rel.match(/^backend\/src\/modules\/([^/]+)/);
115
- const module = moduleMatch ? moduleMatch[1] : "starter-handoff";
116
- const id = rel
117
- .replace(/^backend\/src\/modules\/[^/]+\/prompts\//, "")
118
- .replace(/^work-log\/handoffs\/[^/]+\/prompts\//, "starter/")
119
- .replace(/[/.]/g, "_");
85
+ const module = moduleMatch ? moduleMatch[1] : "unknown";
86
+ const id = rel.replace(/^backend\/src\/modules\/[^/]+\/prompts\//, "").replace(/[/.]/g, "_");
120
87
 
121
88
  const entry = {
122
89
  id,
@@ -128,31 +95,26 @@ async function main() {
128
95
  modifiedAt: st.mtime.toISOString()
129
96
  };
130
97
  inventory.push(entry);
131
- prompts[rel] = {
132
- ...entry,
133
- content
134
- };
98
+ prompts[rel] = { ...entry, content };
135
99
  }
136
100
 
137
- const domainPromptVersions = await loadDomainPromptVersions();
138
- const moduleManifests = await findManifests();
139
-
140
101
  const doc = {
141
102
  meta: {
142
103
  generatedAt: new Date().toISOString(),
143
104
  repositoryRoot: repoRoot,
144
105
  condensedBy: "condense-prompts",
145
- description: "Consolidated prompt templates across backend modules.",
106
+ description: "Consolidated prompt templates from backend modules.",
146
107
  promptCount: inventory.length
147
108
  },
148
- domainPromptVersions,
149
- moduleManifests,
109
+ moduleManifests: await findManifests(),
150
110
  inventory,
151
111
  prompts
152
112
  };
153
113
 
154
- const { exportPath, modelsPath } = await writeConsolidatedArtifact("prompts", doc);
155
- console.log(`Consolidated ${inventory.length} prompts → ${exportPath} (+ ${modelsPath})`);
114
+ const { exportPath, datedExportDir, modelsPath } = await writeConsolidatedArtifact("prompts", doc);
115
+ console.log(
116
+ `Consolidated ${inventory.length} prompts → ${exportPath} (${datedExportDir}/, mirror ${modelsPath})`
117
+ );
156
118
  }
157
119
 
158
120
  main().catch((err) => {
@@ -4,46 +4,58 @@ import { fileURLToPath } from "url";
4
4
  import {
5
5
  CONSOLIDATED_EXPORT_DIR,
6
6
  CONSOLIDATED_FILENAMES,
7
- writeConsolidatedExport
7
+ writeConsolidatedExport,
8
+ getConsolidatedExportStamp
8
9
  } from "../backend/src/shared/utils/consolidatedExport.js";
9
10
 
10
11
  const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
11
12
 
12
- export { CONSOLIDATED_EXPORT_DIR, CONSOLIDATED_FILENAMES };
13
+ export {
14
+ CONSOLIDATED_EXPORT_DIR,
15
+ CONSOLIDATED_FILENAMES,
16
+ getConsolidatedExportStamp,
17
+ beginConsolidatedExportSession
18
+ } from "../backend/src/shared/utils/consolidatedExport.js";
13
19
 
14
- /** Repo-relative paths: exports/ is primary; models/ mirrors for model-condenser API. */
20
+ /** Repo-relative paths: dated exports/ folder is primary audit trail; models/ is latest mirror. */
15
21
  export const CONSOLIDATED_ARTIFACTS = {
16
22
  models: {
17
23
  filename: CONSOLIDATED_FILENAMES.models,
18
- exportPath: `${CONSOLIDATED_EXPORT_DIR}/${CONSOLIDATED_FILENAMES.models}`,
19
24
  modelsPath: `models/${CONSOLIDATED_FILENAMES.models}`
20
25
  },
21
26
  prompts: {
22
27
  filename: CONSOLIDATED_FILENAMES.prompts,
23
- exportPath: `${CONSOLIDATED_EXPORT_DIR}/${CONSOLIDATED_FILENAMES.prompts}`,
24
28
  modelsPath: `models/${CONSOLIDATED_FILENAMES.prompts}`
25
29
  },
26
30
  fileStructure: {
27
31
  filename: CONSOLIDATED_FILENAMES.fileStructure,
28
- exportPath: `${CONSOLIDATED_EXPORT_DIR}/${CONSOLIDATED_FILENAMES.fileStructure}`,
29
32
  modelsPath: `models/${CONSOLIDATED_FILENAMES.fileStructure}`
30
33
  }
31
34
  };
32
35
 
33
36
  /**
34
- * Write JSON to file-exchange/exports/ (primary) and models/ (API mirror).
37
+ * Write JSON to dated file-exchange/exports/{stamp}_consolidated/ and models/ mirror.
35
38
  * @param {"models"|"prompts"|"fileStructure"} kind
36
39
  * @param {object} doc
37
40
  */
38
41
  export async function writeConsolidatedArtifact(kind, doc) {
39
42
  const spec = CONSOLIDATED_ARTIFACTS[kind];
40
43
  const json = JSON.stringify(doc, null, 2);
41
- await writeConsolidatedExport(repoRoot, spec.filename, json);
44
+ const condensedBy = doc?.meta?.condensedBy ?? null;
45
+ const written = await writeConsolidatedExport(repoRoot, spec.filename, json, {
46
+ condensedBy
47
+ });
48
+
42
49
  const modelsAbs = join(repoRoot, spec.modelsPath);
43
50
  await mkdir(dirname(modelsAbs), { recursive: true });
44
51
  await writeFile(modelsAbs, json);
52
+
45
53
  return {
46
- exportPath: spec.exportPath,
47
- modelsPath: spec.modelsPath
54
+ exportPath: written.exportPath,
55
+ datedExportDir: written.datedExportDir,
56
+ stamp: written.stamp,
57
+ folderName: written.folderName,
58
+ modelsPath: spec.modelsPath,
59
+ latestExportPath: `${CONSOLIDATED_EXPORT_DIR}/${spec.filename}`
48
60
  };
49
61
  }