@warlock.js/core 4.5.0 → 4.6.1

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 (203) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/esm/ai/src/agent/agent.mjs +126 -7
  3. package/esm/ai/src/agent/agent.mjs.map +1 -1
  4. package/esm/ai/src/agent/signature.mjs +57 -0
  5. package/esm/ai/src/agent/signature.mjs.map +1 -0
  6. package/esm/ai/src/agent/snapshot.mjs +101 -0
  7. package/esm/ai/src/agent/snapshot.mjs.map +1 -0
  8. package/esm/ai/src/ai.mjs +37 -1
  9. package/esm/ai/src/ai.mjs.map +1 -1
  10. package/esm/ai/src/errors/agent-drift-error.mjs +31 -0
  11. package/esm/ai/src/errors/agent-drift-error.mjs.map +1 -0
  12. package/esm/ai/src/errors/index.mjs +2 -0
  13. package/esm/ai/src/errors/planner-drift-error.mjs +33 -0
  14. package/esm/ai/src/errors/planner-drift-error.mjs.map +1 -0
  15. package/esm/ai/src/image/image-cost.mjs +55 -0
  16. package/esm/ai/src/image/image-cost.mjs.map +1 -0
  17. package/esm/ai/src/image/image.mjs +112 -0
  18. package/esm/ai/src/image/image.mjs.map +1 -0
  19. package/esm/ai/src/image/index.mjs +4 -0
  20. package/esm/ai/src/index.mjs +20 -0
  21. package/esm/ai/src/planner/planner-run.mjs +161 -6
  22. package/esm/ai/src/planner/planner-run.mjs.map +1 -1
  23. package/esm/ai/src/planner/planner.mjs +25 -1
  24. package/esm/ai/src/planner/planner.mjs.map +1 -1
  25. package/esm/ai/src/planner/snapshot.mjs +95 -0
  26. package/esm/ai/src/planner/snapshot.mjs.map +1 -0
  27. package/esm/ai/src/rag/hybrid/bm25.mjs +51 -0
  28. package/esm/ai/src/rag/hybrid/bm25.mjs.map +1 -0
  29. package/esm/ai/src/rag/hybrid/hybrid-rank.mjs +29 -0
  30. package/esm/ai/src/rag/hybrid/hybrid-rank.mjs.map +1 -0
  31. package/esm/ai/src/rag/hybrid/rrf.mjs +30 -0
  32. package/esm/ai/src/rag/hybrid/rrf.mjs.map +1 -0
  33. package/esm/ai/src/rag/index.mjs +11 -0
  34. package/esm/ai/src/rag/loaders/errors.mjs +25 -0
  35. package/esm/ai/src/rag/loaders/errors.mjs.map +1 -0
  36. package/esm/ai/src/rag/loaders/index.mjs +7 -0
  37. package/esm/ai/src/rag/loaders/load-html.mjs +138 -0
  38. package/esm/ai/src/rag/loaders/load-html.mjs.map +1 -0
  39. package/esm/ai/src/rag/loaders/load-pdf.mjs +150 -0
  40. package/esm/ai/src/rag/loaders/load-pdf.mjs.map +1 -0
  41. package/esm/ai/src/rag/loaders/load-text.mjs +60 -0
  42. package/esm/ai/src/rag/loaders/load-text.mjs.map +1 -0
  43. package/esm/ai/src/rag/loaders/load-web.mjs +89 -0
  44. package/esm/ai/src/rag/loaders/load-web.mjs.map +1 -0
  45. package/esm/ai/src/rag/store/pg-vector-store.mjs +328 -0
  46. package/esm/ai/src/rag/store/pg-vector-store.mjs.map +1 -0
  47. package/esm/ai/src/rag/transforms/multi-query.mjs +41 -0
  48. package/esm/ai/src/rag/transforms/multi-query.mjs.map +1 -0
  49. package/esm/ai/src/speech/index.mjs +3 -0
  50. package/esm/ai/src/speech/speech.mjs +122 -0
  51. package/esm/ai/src/speech/speech.mjs.map +1 -0
  52. package/esm/ai/src/supervisor/entries.mjs +2 -2
  53. package/esm/ai/src/supervisor/entries.mjs.map +1 -1
  54. package/esm/ai/src/transcribe/audio-input.mjs +84 -0
  55. package/esm/ai/src/transcribe/audio-input.mjs.map +1 -0
  56. package/esm/ai/src/transcribe/index.mjs +4 -0
  57. package/esm/ai/src/transcribe/transcribe.mjs +127 -0
  58. package/esm/ai/src/transcribe/transcribe.mjs.map +1 -0
  59. package/esm/ai-openai/src/image.mjs +5 -0
  60. package/esm/ai-openai/src/index.mjs +3 -0
  61. package/esm/ai-openai/src/sdk.mjs +3 -0
  62. package/esm/ai-openai/src/speech.mjs +5 -0
  63. package/esm/ai-openai/src/transcription.mjs +6 -0
  64. package/esm/ai-openai/src/utils/index.mjs +1 -0
  65. package/esm/ai-openai/src/utils/to-openai-messages.mjs +3 -0
  66. package/esm/bootstrap.d.mts.map +1 -1
  67. package/esm/bootstrap.mjs +3 -1
  68. package/esm/bootstrap.mjs.map +1 -1
  69. package/esm/cli/commands/doctor/checks/config.check.mjs +42 -0
  70. package/esm/cli/commands/doctor/checks/config.check.mjs.map +1 -0
  71. package/esm/cli/commands/doctor/checks/connectors.check.mjs +28 -0
  72. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -0
  73. package/esm/cli/commands/doctor/checks/health.check.mjs +35 -0
  74. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -0
  75. package/esm/cli/commands/doctor/checks/index.mjs +25 -0
  76. package/esm/cli/commands/doctor/checks/index.mjs.map +1 -0
  77. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +90 -0
  78. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -0
  79. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs +69 -0
  80. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs.map +1 -0
  81. package/esm/cli/commands/doctor/checks/routes.check.mjs +30 -0
  82. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -0
  83. package/esm/cli/commands/doctor/doctor-command.action.mjs +28 -0
  84. package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -0
  85. package/esm/cli/commands/doctor/format-report.mjs +44 -0
  86. package/esm/cli/commands/doctor/format-report.mjs.map +1 -0
  87. package/esm/cli/commands/doctor/run-checks.mjs +50 -0
  88. package/esm/cli/commands/doctor/run-checks.mjs.map +1 -0
  89. package/esm/cli/commands/doctor.command.mjs +29 -0
  90. package/esm/cli/commands/doctor.command.mjs.map +1 -0
  91. package/esm/cli/commands/generate/templates/stubs.mjs +6 -8
  92. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  93. package/esm/cli/commands/routes/format-routes-table.mjs +129 -0
  94. package/esm/cli/commands/routes/format-routes-table.mjs.map +1 -0
  95. package/esm/cli/commands/routes/route-row.mjs +92 -0
  96. package/esm/cli/commands/routes/route-row.mjs.map +1 -0
  97. package/esm/cli/commands/routes/routes-command.action.mjs +43 -0
  98. package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -0
  99. package/esm/cli/commands/routes.command.mjs +51 -0
  100. package/esm/cli/commands/routes.command.mjs.map +1 -0
  101. package/esm/cli/commands/seed.command.mjs +5 -0
  102. package/esm/cli/commands/seed.command.mjs.map +1 -1
  103. package/esm/cli/framework-cli-commands.mjs +4 -0
  104. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  105. package/esm/config/config-getter.mjs +5 -5
  106. package/esm/config/config-getter.mjs.map +1 -1
  107. package/esm/config/config-loader.mjs +2 -2
  108. package/esm/config/config-loader.mjs.map +1 -1
  109. package/esm/connectors/access-connector.mjs +2 -2
  110. package/esm/connectors/access-connector.mjs.map +1 -1
  111. package/esm/connectors/ai-connector.mjs +2 -2
  112. package/esm/connectors/ai-connector.mjs.map +1 -1
  113. package/esm/connectors/cache-connector.mjs +2 -2
  114. package/esm/connectors/cache-connector.mjs.map +1 -1
  115. package/esm/connectors/database-connector.mjs +2 -2
  116. package/esm/connectors/database-connector.mjs.map +1 -1
  117. package/esm/connectors/herald-connector.mjs +2 -2
  118. package/esm/connectors/herald-connector.mjs.map +1 -1
  119. package/esm/connectors/http-connector.d.mts.map +1 -1
  120. package/esm/connectors/http-connector.mjs +9 -7
  121. package/esm/connectors/http-connector.mjs.map +1 -1
  122. package/esm/connectors/logger-connector.mjs +2 -2
  123. package/esm/connectors/logger-connector.mjs.map +1 -1
  124. package/esm/connectors/mail-connector.mjs +2 -2
  125. package/esm/connectors/mail-connector.mjs.map +1 -1
  126. package/esm/connectors/notifications-connector.mjs +2 -2
  127. package/esm/connectors/notifications-connector.mjs.map +1 -1
  128. package/esm/connectors/socket-connector.mjs +3 -3
  129. package/esm/connectors/socket-connector.mjs.map +1 -1
  130. package/esm/database/index.d.mts +2 -1
  131. package/esm/database/index.mjs +1 -0
  132. package/esm/database/seed-command-action.mjs +44 -4
  133. package/esm/database/seed-command-action.mjs.map +1 -1
  134. package/esm/database/seeds/seed-records-table-migration.mjs +36 -0
  135. package/esm/database/seeds/seed-records-table-migration.mjs.map +1 -0
  136. package/esm/database/seeds/seeder.d.mts +22 -5
  137. package/esm/database/seeds/seeder.d.mts.map +1 -1
  138. package/esm/database/seeds/seeder.errors.d.mts +22 -0
  139. package/esm/database/seeds/seeder.errors.d.mts.map +1 -0
  140. package/esm/database/seeds/seeder.errors.mjs +29 -0
  141. package/esm/database/seeds/seeder.errors.mjs.map +1 -0
  142. package/esm/database/seeds/seeder.mjs.map +1 -1
  143. package/esm/database/seeds/seeders.manager.mjs +90 -11
  144. package/esm/database/seeds/seeders.manager.mjs.map +1 -1
  145. package/esm/database/seeds/types.d.mts +117 -1
  146. package/esm/database/seeds/types.d.mts.map +1 -1
  147. package/esm/database/seeds/utils.mjs +6 -1
  148. package/esm/database/seeds/utils.mjs.map +1 -1
  149. package/esm/dev-server/module-loader.d.mts +12 -0
  150. package/esm/dev-server/module-loader.d.mts.map +1 -1
  151. package/esm/dev-server/module-loader.mjs +30 -2
  152. package/esm/dev-server/module-loader.mjs.map +1 -1
  153. package/esm/http/config.mjs +2 -2
  154. package/esm/http/config.mjs.map +1 -1
  155. package/esm/http/createHttpApplication.mjs +2 -2
  156. package/esm/http/createHttpApplication.mjs.map +1 -1
  157. package/esm/http/health.d.mts +14 -0
  158. package/esm/http/health.d.mts.map +1 -1
  159. package/esm/http/health.mjs +16 -0
  160. package/esm/http/health.mjs.map +1 -1
  161. package/esm/http/middleware/idempotency.middleware.mjs +5 -5
  162. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  163. package/esm/http/middleware/inject-request-context.mjs +2 -2
  164. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  165. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  166. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  167. package/esm/http/plugins.mjs +9 -9
  168. package/esm/http/plugins.mjs.map +1 -1
  169. package/esm/http/response.mjs +5 -5
  170. package/esm/http/response.mjs.map +1 -1
  171. package/esm/http/server.mjs +4 -4
  172. package/esm/http/server.mjs.map +1 -1
  173. package/esm/index.d.mts +4 -3
  174. package/esm/index.mjs +2 -1
  175. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +28 -1
  176. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
  177. package/esm/repositories/adapters/cascade/cascade-query-builder.mjs +39 -0
  178. package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
  179. package/esm/repositories/contracts/index.d.mts +1 -1
  180. package/esm/repositories/contracts/query-builder.contract.d.mts +87 -1
  181. package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
  182. package/esm/repositories/index.d.mts +1 -1
  183. package/esm/repositories/repository.manager.d.mts +99 -1
  184. package/esm/repositories/repository.manager.d.mts.map +1 -1
  185. package/esm/repositories/repository.manager.mjs +128 -0
  186. package/esm/repositories/repository.manager.mjs.map +1 -1
  187. package/esm/router/router.d.mts +9 -0
  188. package/esm/router/router.d.mts.map +1 -1
  189. package/esm/router/router.mjs +21 -1
  190. package/esm/router/router.mjs.map +1 -1
  191. package/esm/utils/paths.mjs +2 -2
  192. package/esm/utils/paths.mjs.map +1 -1
  193. package/esm/validation/validateAll.mjs +2 -2
  194. package/esm/validation/validateAll.mjs.map +1 -1
  195. package/llms-full.txt +427 -45
  196. package/llms.txt +4 -2
  197. package/package.json +9 -9
  198. package/skills/README.md +65 -0
  199. package/skills/health-checks/SKILL.md +13 -0
  200. package/skills/use-repository/SKILL.md +38 -1
  201. package/skills/warlock-doctor/SKILL.md +135 -0
  202. package/skills/warlock-routes/SKILL.md +91 -0
  203. package/skills/write-seeder/SKILL.md +143 -45
@@ -0,0 +1,28 @@
1
+ import { connectorsManager } from "../../../../connectors/connectors-manager.mjs";
2
+
3
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/connectors.check.ts
4
+ /**
5
+ * Reports which connectors are registered and which are currently active. This
6
+ * is informational: a registered-but-inactive connector is normal (it simply
7
+ * has no config wired), so the check passes as long as the manager can be
8
+ * enumerated and reports its active set.
9
+ *
10
+ * Read-only: calls `connectorsManager.list()` and each connector's
11
+ * `isActive()` (a pure getter) only.
12
+ */
13
+ const connectorsCheck = {
14
+ name: "connectors",
15
+ run: () => {
16
+ const connectors = connectorsManager.list();
17
+ const activeNames = connectors.filter((connector) => connector.isActive()).map((connector) => connector.name);
18
+ return {
19
+ name: "connectors",
20
+ status: "ok",
21
+ detail: activeNames.length > 0 ? `${connectors.length} registered, active: ${activeNames.join(", ")}` : `${connectors.length} registered, none active`
22
+ };
23
+ }
24
+ };
25
+
26
+ //#endregion
27
+ export { connectorsCheck };
28
+ //# sourceMappingURL=connectors.check.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectors.check.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/connectors.check.ts"],"sourcesContent":["import { connectorsManager } from \"../../../../connectors/connectors-manager\";\nimport type { DoctorCheck } from \"../check.types\";\n\n/**\n * Reports which connectors are registered and which are currently active. This\n * is informational: a registered-but-inactive connector is normal (it simply\n * has no config wired), so the check passes as long as the manager can be\n * enumerated and reports its active set.\n *\n * Read-only: calls `connectorsManager.list()` and each connector's\n * `isActive()` (a pure getter) only.\n */\nexport const connectorsCheck: DoctorCheck = {\n name: \"connectors\",\n run: () => {\n const connectors = connectorsManager.list();\n const active = connectors.filter((connector) => connector.isActive());\n const activeNames = active.map((connector) => connector.name);\n\n const detail =\n activeNames.length > 0\n ? `${connectors.length} registered, active: ${activeNames.join(\", \")}`\n : `${connectors.length} registered, none active`;\n\n return {\n name: \"connectors\",\n status: \"ok\",\n detail,\n };\n },\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,kBAA+B;CAC1C,MAAM;CACN,WAAW;EACT,MAAM,aAAa,kBAAkB,KAAK;EAE1C,MAAM,cADS,WAAW,QAAQ,cAAc,UAAU,SAAS,CAC1C,CAAC,CAAC,KAAK,cAAc,UAAU,IAAI;EAO5D,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAPA,YAAY,SAAS,IACjB,GAAG,WAAW,OAAO,uBAAuB,YAAY,KAAK,IAAI,MACjE,GAAG,WAAW,OAAO;EAM3B;CACF;AACF"}
@@ -0,0 +1,35 @@
1
+ import { config } from "../../../../config/config-getter.mjs";
2
+
3
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/health.check.ts
4
+ /**
5
+ * Confirms the built-in liveness (`/health`) and readiness (`/ready`)
6
+ * endpoints will be exposed. The HTTP connector registers them automatically
7
+ * unless `http.health.enabled` is explicitly `false`, so this check reads that
8
+ * config flag and the (overridable) paths.
9
+ *
10
+ * Disabling the probes is a deliberate, supported choice but a common
11
+ * misconfiguration in container/orchestrated deployments, so it is surfaced as
12
+ * a `warn` rather than a pass.
13
+ *
14
+ * Read-only: inspects `config.get("http.health")` only.
15
+ */
16
+ const healthCheck = {
17
+ name: "health",
18
+ run: () => {
19
+ const healthConfig = config.get("http.health");
20
+ if (healthConfig?.enabled === false) return {
21
+ name: "health",
22
+ status: "warn",
23
+ detail: "health endpoints disabled (http.health.enabled = false)"
24
+ };
25
+ return {
26
+ name: "health",
27
+ status: "ok",
28
+ detail: `liveness ${healthConfig?.path ?? "/health"} + readiness ${healthConfig?.readinessPath ?? "/ready"} registered`
29
+ };
30
+ }
31
+ };
32
+
33
+ //#endregion
34
+ export { healthCheck };
35
+ //# sourceMappingURL=health.check.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.check.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/health.check.ts"],"sourcesContent":["import { config } from \"../../../../config/config-getter\";\nimport type { DoctorCheck } from \"../check.types\";\n\n/**\n * Confirms the built-in liveness (`/health`) and readiness (`/ready`)\n * endpoints will be exposed. The HTTP connector registers them automatically\n * unless `http.health.enabled` is explicitly `false`, so this check reads that\n * config flag and the (overridable) paths.\n *\n * Disabling the probes is a deliberate, supported choice but a common\n * misconfiguration in container/orchestrated deployments, so it is surfaced as\n * a `warn` rather than a pass.\n *\n * Read-only: inspects `config.get(\"http.health\")` only.\n */\nexport const healthCheck: DoctorCheck = {\n name: \"health\",\n run: () => {\n const healthConfig = config.get(\"http.health\");\n\n if (healthConfig?.enabled === false) {\n return {\n name: \"health\",\n status: \"warn\",\n detail: \"health endpoints disabled (http.health.enabled = false)\",\n };\n }\n\n const livenessPath = healthConfig?.path ?? \"/health\";\n const readinessPath = healthConfig?.readinessPath ?? \"/ready\";\n\n return {\n name: \"health\",\n status: \"ok\",\n detail: `liveness ${livenessPath} + readiness ${readinessPath} registered`,\n };\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;AAeA,MAAa,cAA2B;CACtC,MAAM;CACN,WAAW;EACT,MAAM,eAAe,OAAO,IAAI,aAAa;EAE7C,IAAI,cAAc,YAAY,OAC5B,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ;EACV;EAMF,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,YANW,cAAc,QAAQ,UAMR,eALb,cAAc,iBAAiB,SAKW;EAChE;CACF;AACF"}
@@ -0,0 +1,25 @@
1
+ import { configCheck } from "./config.check.mjs";
2
+ import { connectorsCheck } from "./connectors.check.mjs";
3
+ import { healthCheck } from "./health.check.mjs";
4
+ import { optionalPeersCheck } from "./optional-peers.check.mjs";
5
+ import { releaseHygieneCheck } from "./release-hygiene.check.mjs";
6
+ import { routesCheck } from "./routes.check.mjs";
7
+
8
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/index.ts
9
+ /**
10
+ * The default, ordered set of checks `warlock doctor` runs. Ordering controls
11
+ * the report layout: runtime-surface checks first (routes, config, connectors,
12
+ * peers, health), release hygiene last.
13
+ */
14
+ const defaultDoctorChecks = [
15
+ routesCheck,
16
+ configCheck,
17
+ connectorsCheck,
18
+ optionalPeersCheck,
19
+ healthCheck,
20
+ releaseHygieneCheck
21
+ ];
22
+
23
+ //#endregion
24
+ export { defaultDoctorChecks };
25
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/index.ts"],"sourcesContent":["import type { DoctorCheck } from \"../check.types\";\nimport { configCheck } from \"./config.check\";\nimport { connectorsCheck } from \"./connectors.check\";\nimport { healthCheck } from \"./health.check\";\nimport { optionalPeersCheck } from \"./optional-peers.check\";\nimport { releaseHygieneCheck } from \"./release-hygiene.check\";\nimport { routesCheck } from \"./routes.check\";\n\n/**\n * The default, ordered set of checks `warlock doctor` runs. Ordering controls\n * the report layout: runtime-surface checks first (routes, config, connectors,\n * peers, health), release hygiene last.\n */\nexport const defaultDoctorChecks: DoctorCheck[] = [\n routesCheck,\n configCheck,\n connectorsCheck,\n optionalPeersCheck,\n healthCheck,\n releaseHygieneCheck,\n];\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,sBAAqC;CAChD;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -0,0 +1,90 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/optional-peers.check.ts
4
+ /**
5
+ * The optional peers core knows how to use. Kept in sync with the install
6
+ * targets in the `warlock add` feature registry (sharp, nodemailer, socket.io,
7
+ * the AWS SDK family, redis, the Cascade DB drivers, …).
8
+ */
9
+ const OPTIONAL_PEERS = [
10
+ {
11
+ package: "sharp",
12
+ feature: "image processing"
13
+ },
14
+ {
15
+ package: "nodemailer",
16
+ feature: "mail (SMTP) channel"
17
+ },
18
+ {
19
+ package: "socket.io",
20
+ feature: "realtime socket server"
21
+ },
22
+ {
23
+ package: "@aws-sdk/client-s3",
24
+ feature: "S3 cloud storage"
25
+ },
26
+ {
27
+ package: "@aws-sdk/client-sesv2",
28
+ feature: "Amazon SES mail channel"
29
+ },
30
+ {
31
+ package: "redis",
32
+ feature: "Redis cache driver"
33
+ },
34
+ {
35
+ package: "mongodb",
36
+ feature: "MongoDB database driver"
37
+ },
38
+ {
39
+ package: "pg",
40
+ feature: "Postgres database driver"
41
+ },
42
+ {
43
+ package: "mysql2",
44
+ feature: "MySQL database driver"
45
+ }
46
+ ];
47
+ /**
48
+ * Resolve from the project's working directory, not from core's own
49
+ * `node_modules`, so the probe reflects what the *consuming app* has installed.
50
+ */
51
+ const projectRequire = createRequire(`${process.cwd()}/package.json`);
52
+ /**
53
+ * Whether a package can be resolved from the project. A failed resolve (the
54
+ * normal "not installed" case) is swallowed and reported as missing.
55
+ */
56
+ function isInstalled(packageName) {
57
+ try {
58
+ projectRequire.resolve(packageName);
59
+ return true;
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+ /**
65
+ * Detects which optional peer dependencies are installed and which are not,
66
+ * reporting the features that are consequently unavailable. Missing peers are
67
+ * a `warn` (the feature is simply off), never a `fail`.
68
+ *
69
+ * Read-only: resolves module paths only; never imports or executes the peers.
70
+ */
71
+ const optionalPeersCheck = {
72
+ name: "optional-peers",
73
+ run: () => {
74
+ const missing = OPTIONAL_PEERS.filter((peer) => !isInstalled(peer.package));
75
+ if (missing.length === 0) return {
76
+ name: "optional-peers",
77
+ status: "ok",
78
+ detail: `all ${OPTIONAL_PEERS.length} known optional peers installed`
79
+ };
80
+ return {
81
+ name: "optional-peers",
82
+ status: "warn",
83
+ detail: `not installed → unavailable: ${missing.map((peer) => `${peer.package} (${peer.feature})`).join("; ")}`
84
+ };
85
+ }
86
+ };
87
+
88
+ //#endregion
89
+ export { optionalPeersCheck };
90
+ //# sourceMappingURL=optional-peers.check.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-peers.check.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/optional-peers.check.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type { DoctorCheck } from \"../check.types\";\n\n/**\n * A single optional peer dependency and the feature it unlocks. These are NOT\n * bundled by core — each is loaded lazily by the connector/driver that needs\n * it, so a missing peer simply means that feature is unavailable (a `warn`),\n * never a failure.\n */\ntype OptionalPeer = {\n /** The npm package name to probe via `require.resolve`. */\n package: string;\n\n /** The framework feature this peer enables. */\n feature: string;\n};\n\n/**\n * The optional peers core knows how to use. Kept in sync with the install\n * targets in the `warlock add` feature registry (sharp, nodemailer, socket.io,\n * the AWS SDK family, redis, the Cascade DB drivers, …).\n */\nconst OPTIONAL_PEERS: OptionalPeer[] = [\n { package: \"sharp\", feature: \"image processing\" },\n { package: \"nodemailer\", feature: \"mail (SMTP) channel\" },\n { package: \"socket.io\", feature: \"realtime socket server\" },\n { package: \"@aws-sdk/client-s3\", feature: \"S3 cloud storage\" },\n { package: \"@aws-sdk/client-sesv2\", feature: \"Amazon SES mail channel\" },\n { package: \"redis\", feature: \"Redis cache driver\" },\n { package: \"mongodb\", feature: \"MongoDB database driver\" },\n { package: \"pg\", feature: \"Postgres database driver\" },\n { package: \"mysql2\", feature: \"MySQL database driver\" },\n];\n\n/**\n * Resolve from the project's working directory, not from core's own\n * `node_modules`, so the probe reflects what the *consuming app* has installed.\n */\nconst projectRequire = createRequire(`${process.cwd()}/package.json`);\n\n/**\n * Whether a package can be resolved from the project. A failed resolve (the\n * normal \"not installed\" case) is swallowed and reported as missing.\n */\nfunction isInstalled(packageName: string): boolean {\n try {\n projectRequire.resolve(packageName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Detects which optional peer dependencies are installed and which are not,\n * reporting the features that are consequently unavailable. Missing peers are\n * a `warn` (the feature is simply off), never a `fail`.\n *\n * Read-only: resolves module paths only; never imports or executes the peers.\n */\nexport const optionalPeersCheck: DoctorCheck = {\n name: \"optional-peers\",\n run: () => {\n const missing = OPTIONAL_PEERS.filter((peer) => !isInstalled(peer.package));\n\n if (missing.length === 0) {\n return {\n name: \"optional-peers\",\n status: \"ok\",\n detail: `all ${OPTIONAL_PEERS.length} known optional peers installed`,\n };\n }\n\n const unavailable = missing\n .map((peer) => `${peer.package} (${peer.feature})`)\n .join(\"; \");\n\n return {\n name: \"optional-peers\",\n status: \"warn\",\n detail: `not installed → unavailable: ${unavailable}`,\n };\n },\n};\n"],"mappings":";;;;;;;;AAsBA,MAAM,iBAAiC;CACrC;EAAE,SAAS;EAAS,SAAS;CAAmB;CAChD;EAAE,SAAS;EAAc,SAAS;CAAsB;CACxD;EAAE,SAAS;EAAa,SAAS;CAAyB;CAC1D;EAAE,SAAS;EAAsB,SAAS;CAAmB;CAC7D;EAAE,SAAS;EAAyB,SAAS;CAA0B;CACvE;EAAE,SAAS;EAAS,SAAS;CAAqB;CAClD;EAAE,SAAS;EAAW,SAAS;CAA0B;CACzD;EAAE,SAAS;EAAM,SAAS;CAA2B;CACrD;EAAE,SAAS;EAAU,SAAS;CAAwB;AACxD;;;;;AAMA,MAAM,iBAAiB,cAAc,GAAG,QAAQ,IAAI,EAAE,cAAc;;;;;AAMpE,SAAS,YAAY,aAA8B;CACjD,IAAI;EACF,eAAe,QAAQ,WAAW;EAClC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;AASA,MAAa,qBAAkC;CAC7C,MAAM;CACN,WAAW;EACT,MAAM,UAAU,eAAe,QAAQ,SAAS,CAAC,YAAY,KAAK,OAAO,CAAC;EAE1E,IAAI,QAAQ,WAAW,GACrB,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,OAAO,eAAe,OAAO;EACvC;EAOF,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,gCAPU,QACjB,KAAK,SAAS,GAAG,KAAK,QAAQ,IAAI,KAAK,QAAQ,EAAE,CAAC,CAClD,KAAK,IAK4C;EACpD;CACF;AACF"}
@@ -0,0 +1,69 @@
1
+ import { rootPath } from "../../../../utils/paths.mjs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+
4
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/release-hygiene.check.ts
5
+ /**
6
+ * Parse the top-most `## x.y.z[ - YYYY-MM-DD]` heading out of a CHANGELOG body.
7
+ * Returns `undefined` when no version heading is present.
8
+ */
9
+ function parseTopHeading(changelog) {
10
+ const match = changelog.match(/^##\s+(\d+)\.(\d+)\.(\d+)(?:\s*[-–]\s*(\d{4}-\d{2}-\d{2}))?\s*$/m);
11
+ if (!match) return;
12
+ const [, major, minor, patch, date] = match;
13
+ return {
14
+ version: `${major}.${minor}.${patch}`,
15
+ date
16
+ };
17
+ }
18
+ /**
19
+ * Checks that the project's `package.json` version matches the top-most
20
+ * `## x.y.z` heading in `CHANGELOG.md` — the same version↔changelog invariant
21
+ * the release-hygiene unit guard enforces, surfaced as a pre-release doctor
22
+ * check.
23
+ *
24
+ * Verdicts:
25
+ * - no `CHANGELOG.md` → `warn` (a changelog is recommended, not mandatory);
26
+ * - no parseable heading → `warn`;
27
+ * - heading version ≠ package.json version → `fail`;
28
+ * - otherwise → `ok`.
29
+ *
30
+ * Read-only: reads `package.json` and `CHANGELOG.md` from the project root.
31
+ */
32
+ const releaseHygieneCheck = {
33
+ name: "release-hygiene",
34
+ run: () => {
35
+ const packageJsonPath = rootPath("package.json");
36
+ const changelogPath = rootPath("CHANGELOG.md");
37
+ const pkgVersion = JSON.parse(readFileSync(packageJsonPath, "utf8")).version;
38
+ if (typeof pkgVersion !== "string") return {
39
+ name: "release-hygiene",
40
+ status: "fail",
41
+ detail: "package.json has no string version field"
42
+ };
43
+ if (!existsSync(changelogPath)) return {
44
+ name: "release-hygiene",
45
+ status: "warn",
46
+ detail: `no CHANGELOG.md at project root (package.json is ${pkgVersion})`
47
+ };
48
+ const heading = parseTopHeading(readFileSync(changelogPath, "utf8"));
49
+ if (!heading) return {
50
+ name: "release-hygiene",
51
+ status: "warn",
52
+ detail: "CHANGELOG.md has no parseable `## x.y.z` heading"
53
+ };
54
+ if (heading.version !== pkgVersion) return {
55
+ name: "release-hygiene",
56
+ status: "fail",
57
+ detail: `package.json ${pkgVersion} ≠ top CHANGELOG heading ${heading.version}`
58
+ };
59
+ return {
60
+ name: "release-hygiene",
61
+ status: "ok",
62
+ detail: `package.json and CHANGELOG agree on ${pkgVersion}`
63
+ };
64
+ }
65
+ };
66
+
67
+ //#endregion
68
+ export { releaseHygieneCheck };
69
+ //# sourceMappingURL=release-hygiene.check.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-hygiene.check.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/release-hygiene.check.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { rootPath } from \"../../../../utils/paths\";\nimport type { DoctorCheck } from \"../check.types\";\n\n/**\n * A `## x.y.z` changelog heading with an optional ` - YYYY-MM-DD` suffix.\n * Mirrors the shape parsed by the tier-0 release-hygiene unit guard; inlined\n * here because that guard lives in the test tree and is not importable from\n * `src`.\n */\ntype ChangelogHeading = {\n version: string;\n date?: string;\n};\n\n/**\n * Parse the top-most `## x.y.z[ - YYYY-MM-DD]` heading out of a CHANGELOG body.\n * Returns `undefined` when no version heading is present.\n */\nfunction parseTopHeading(changelog: string): ChangelogHeading | undefined {\n const match = changelog.match(\n /^##\\s+(\\d+)\\.(\\d+)\\.(\\d+)(?:\\s*[-–]\\s*(\\d{4}-\\d{2}-\\d{2}))?\\s*$/m,\n );\n\n if (!match) {\n return undefined;\n }\n\n const [, major, minor, patch, date] = match;\n\n return {\n version: `${major}.${minor}.${patch}`,\n date,\n };\n}\n\n/**\n * Checks that the project's `package.json` version matches the top-most\n * `## x.y.z` heading in `CHANGELOG.md` — the same version↔changelog invariant\n * the release-hygiene unit guard enforces, surfaced as a pre-release doctor\n * check.\n *\n * Verdicts:\n * - no `CHANGELOG.md` → `warn` (a changelog is recommended, not mandatory);\n * - no parseable heading → `warn`;\n * - heading version ≠ package.json version → `fail`;\n * - otherwise → `ok`.\n *\n * Read-only: reads `package.json` and `CHANGELOG.md` from the project root.\n */\nexport const releaseHygieneCheck: DoctorCheck = {\n name: \"release-hygiene\",\n run: () => {\n const packageJsonPath = rootPath(\"package.json\");\n const changelogPath = rootPath(\"CHANGELOG.md\");\n\n const pkgVersion: unknown = JSON.parse(readFileSync(packageJsonPath, \"utf8\")).version;\n\n if (typeof pkgVersion !== \"string\") {\n return {\n name: \"release-hygiene\",\n status: \"fail\",\n detail: \"package.json has no string version field\",\n };\n }\n\n if (!existsSync(changelogPath)) {\n return {\n name: \"release-hygiene\",\n status: \"warn\",\n detail: `no CHANGELOG.md at project root (package.json is ${pkgVersion})`,\n };\n }\n\n const changelog = readFileSync(changelogPath, \"utf8\");\n const heading = parseTopHeading(changelog);\n\n if (!heading) {\n return {\n name: \"release-hygiene\",\n status: \"warn\",\n detail: \"CHANGELOG.md has no parseable `## x.y.z` heading\",\n };\n }\n\n if (heading.version !== pkgVersion) {\n return {\n name: \"release-hygiene\",\n status: \"fail\",\n detail: `package.json ${pkgVersion} ≠ top CHANGELOG heading ${heading.version}`,\n };\n }\n\n return {\n name: \"release-hygiene\",\n status: \"ok\",\n detail: `package.json and CHANGELOG agree on ${pkgVersion}`,\n };\n },\n};\n"],"mappings":";;;;;;;;AAmBA,SAAS,gBAAgB,WAAiD;CACxE,MAAM,QAAQ,UAAU,MACtB,kEACF;CAEA,IAAI,CAAC,OACH;CAGF,MAAM,GAAG,OAAO,OAAO,OAAO,QAAQ;CAEtC,OAAO;EACL,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG;EAC9B;CACF;AACF;;;;;;;;;;;;;;;AAgBA,MAAa,sBAAmC;CAC9C,MAAM;CACN,WAAW;EACT,MAAM,kBAAkB,SAAS,cAAc;EAC/C,MAAM,gBAAgB,SAAS,cAAc;EAE7C,MAAM,aAAsB,KAAK,MAAM,aAAa,iBAAiB,MAAM,CAAC,CAAC,CAAC;EAE9E,IAAI,OAAO,eAAe,UACxB,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ;EACV;EAGF,IAAI,CAAC,WAAW,aAAa,GAC3B,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,oDAAoD,WAAW;EACzE;EAIF,MAAM,UAAU,gBADE,aAAa,eAAe,MACN,CAAC;EAEzC,IAAI,CAAC,SACH,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ;EACV;EAGF,IAAI,QAAQ,YAAY,YACtB,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,gBAAgB,WAAW,2BAA2B,QAAQ;EACxE;EAGF,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,uCAAuC;EACjD;CACF;AACF"}
@@ -0,0 +1,30 @@
1
+ import { router } from "../../../../router/router.mjs";
2
+
3
+ //#region ../@warlock.js/core/src/cli/commands/doctor/checks/routes.check.ts
4
+ /**
5
+ * Reports the number of registered routes. A booted app with zero routes
6
+ * almost always means a route module failed to register silently, so this
7
+ * warns (rather than passing) when the route table is empty.
8
+ *
9
+ * Read-only: introspects the router via `routeCount()` only.
10
+ */
11
+ const routesCheck = {
12
+ name: "routes",
13
+ run: () => {
14
+ const count = router.routeCount();
15
+ if (count === 0) return {
16
+ name: "routes",
17
+ status: "warn",
18
+ detail: "0 routes registered — did a route module fail to load?"
19
+ };
20
+ return {
21
+ name: "routes",
22
+ status: "ok",
23
+ detail: `${count} registered`
24
+ };
25
+ }
26
+ };
27
+
28
+ //#endregion
29
+ export { routesCheck };
30
+ //# sourceMappingURL=routes.check.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.check.mjs","names":[],"sources":["../../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/checks/routes.check.ts"],"sourcesContent":["import { router } from \"../../../../router/router\";\nimport type { DoctorCheck } from \"../check.types\";\n\n/**\n * Reports the number of registered routes. A booted app with zero routes\n * almost always means a route module failed to register silently, so this\n * warns (rather than passing) when the route table is empty.\n *\n * Read-only: introspects the router via `routeCount()` only.\n */\nexport const routesCheck: DoctorCheck = {\n name: \"routes\",\n run: () => {\n const count = router.routeCount();\n\n if (count === 0) {\n return {\n name: \"routes\",\n status: \"warn\",\n detail: \"0 routes registered — did a route module fail to load?\",\n };\n }\n\n return {\n name: \"routes\",\n status: \"ok\",\n detail: `${count} registered`,\n };\n },\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,cAA2B;CACtC,MAAM;CACN,WAAW;EACT,MAAM,QAAQ,OAAO,WAAW;EAEhC,IAAI,UAAU,GACZ,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ;EACV;EAGF,OAAO;GACL,MAAM;GACN,QAAQ;GACR,QAAQ,GAAG,MAAM;EACnB;CACF;AACF"}
@@ -0,0 +1,28 @@
1
+ import { defaultDoctorChecks } from "./checks/index.mjs";
2
+ import { printReport } from "./format-report.mjs";
3
+ import { runChecks } from "./run-checks.mjs";
4
+
5
+ //#region ../@warlock.js/core/src/cli/commands/doctor/doctor-command.action.ts
6
+ /**
7
+ * Action behind `warlock doctor`. Runs the default read-only diagnostic
8
+ * checks, prints the grouped pass/warn/fail report, and — when any check
9
+ * failed — exits the process with a non-zero code so the command signals
10
+ * failure to scripts/CI.
11
+ *
12
+ * A failing check is REPORTED (a line in the report + a non-zero exit), never
13
+ * thrown: the runner converts any thrown check into a `fail` result first.
14
+ *
15
+ * On success this simply returns; the CLI manager then prints its own success
16
+ * banner and exits zero.
17
+ *
18
+ * @param _data Parsed CLI args (unused — doctor takes no positional args).
19
+ */
20
+ async function doctorCommandAction(_data) {
21
+ const report = await runChecks(defaultDoctorChecks);
22
+ printReport(report);
23
+ if (report.hasFailures) process.exit(report.exitCode);
24
+ }
25
+
26
+ //#endregion
27
+ export { doctorCommandAction };
28
+ //# sourceMappingURL=doctor-command.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-command.action.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/doctor-command.action.ts"],"sourcesContent":["import type { CommandActionData } from \"../../types\";\nimport { defaultDoctorChecks } from \"./checks\";\nimport { printReport } from \"./format-report\";\nimport { runChecks } from \"./run-checks\";\n\n/**\n * Action behind `warlock doctor`. Runs the default read-only diagnostic\n * checks, prints the grouped pass/warn/fail report, and — when any check\n * failed — exits the process with a non-zero code so the command signals\n * failure to scripts/CI.\n *\n * A failing check is REPORTED (a line in the report + a non-zero exit), never\n * thrown: the runner converts any thrown check into a `fail` result first.\n *\n * On success this simply returns; the CLI manager then prints its own success\n * banner and exits zero.\n *\n * @param _data Parsed CLI args (unused — doctor takes no positional args).\n */\nexport async function doctorCommandAction(_data: CommandActionData): Promise<void> {\n const report = await runChecks(defaultDoctorChecks);\n\n printReport(report);\n\n if (report.hasFailures) {\n process.exit(report.exitCode);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,eAAsB,oBAAoB,OAAyC;CACjF,MAAM,SAAS,MAAM,UAAU,mBAAmB;CAElD,YAAY,MAAM;CAElB,IAAI,OAAO,aACT,QAAQ,KAAK,OAAO,QAAQ;AAEhC"}
@@ -0,0 +1,44 @@
1
+ import { colors } from "@mongez/copper";
2
+
3
+ //#region ../@warlock.js/core/src/cli/commands/doctor/format-report.ts
4
+ /**
5
+ * The glyph shown beside each check, keyed by status.
6
+ */
7
+ const STATUS_SYMBOL = {
8
+ ok: "✓",
9
+ warn: "⚠",
10
+ fail: "✗"
11
+ };
12
+ /**
13
+ * Colorize a status glyph. Kept separate from {@link STATUS_SYMBOL} so the
14
+ * plain glyphs remain available for snapshot-friendly, color-free assertions.
15
+ */
16
+ function colorizeSymbol(status) {
17
+ const symbol = STATUS_SYMBOL[status];
18
+ switch (status) {
19
+ case "ok": return colors.green(symbol);
20
+ case "warn": return colors.yellow(symbol);
21
+ case "fail": return colors.red(symbol);
22
+ }
23
+ }
24
+ /**
25
+ * Print the report to stdout with colored status glyphs and a colored summary
26
+ * verdict. Thin wrapper over {@link formatReportLines} — the structured report
27
+ * stays the source of truth for the exit code.
28
+ *
29
+ * @param report The aggregated doctor report.
30
+ */
31
+ function printReport(report) {
32
+ for (const result of report.results) {
33
+ const symbol = colorizeSymbol(result.status);
34
+ console.log(`${symbol} ${colors.bold(result.name)}: ${result.detail}`);
35
+ }
36
+ const { ok, warn, fail } = report.summary;
37
+ const summaryLine = `Summary: ${ok} ok, ${warn} warn, ${fail} fail`;
38
+ console.log("");
39
+ console.log(report.hasFailures ? colors.red(summaryLine) : colors.green(summaryLine));
40
+ }
41
+
42
+ //#endregion
43
+ export { printReport };
44
+ //# sourceMappingURL=format-report.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-report.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/format-report.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport type { CheckStatus, DoctorReport } from \"./check.types\";\n\n/**\n * The glyph shown beside each check, keyed by status.\n */\nconst STATUS_SYMBOL: Record<CheckStatus, string> = {\n ok: \"✓\",\n warn: \"⚠\",\n fail: \"✗\",\n};\n\n/**\n * Colorize a status glyph. Kept separate from {@link STATUS_SYMBOL} so the\n * plain glyphs remain available for snapshot-friendly, color-free assertions.\n */\nfunction colorizeSymbol(status: CheckStatus): string {\n const symbol = STATUS_SYMBOL[status];\n\n switch (status) {\n case \"ok\":\n return colors.green(symbol);\n case \"warn\":\n return colors.yellow(symbol);\n case \"fail\":\n return colors.red(symbol);\n }\n}\n\n/**\n * Build the report body as an ordered list of plain (uncolored) lines:\n * one `<symbol> <name>: <detail>` line per check, a blank line, then a summary\n * line. Returned as strings (not printed) so the formatting is unit-testable.\n *\n * @param report The aggregated doctor report.\n * @returns The lines to print, top to bottom.\n */\nexport function formatReportLines(report: DoctorReport): string[] {\n const lines = report.results.map((result) => {\n return `${STATUS_SYMBOL[result.status]} ${result.name}: ${result.detail}`;\n });\n\n const { ok, warn, fail } = report.summary;\n\n lines.push(\"\");\n lines.push(`Summary: ${ok} ok, ${warn} warn, ${fail} fail`);\n\n return lines;\n}\n\n/**\n * Print the report to stdout with colored status glyphs and a colored summary\n * verdict. Thin wrapper over {@link formatReportLines} — the structured report\n * stays the source of truth for the exit code.\n *\n * @param report The aggregated doctor report.\n */\nexport function printReport(report: DoctorReport): void {\n for (const result of report.results) {\n const symbol = colorizeSymbol(result.status);\n\n console.log(`${symbol} ${colors.bold(result.name)}: ${result.detail}`);\n }\n\n const { ok, warn, fail } = report.summary;\n const summaryLine = `Summary: ${ok} ok, ${warn} warn, ${fail} fail`;\n\n console.log(\"\");\n console.log(report.hasFailures ? colors.red(summaryLine) : colors.green(summaryLine));\n}\n"],"mappings":";;;;;;AAMA,MAAM,gBAA6C;CACjD,IAAI;CACJ,MAAM;CACN,MAAM;AACR;;;;;AAMA,SAAS,eAAe,QAA6B;CACnD,MAAM,SAAS,cAAc;CAE7B,QAAQ,QAAR;EACE,KAAK,MACH,OAAO,OAAO,MAAM,MAAM;EAC5B,KAAK,QACH,OAAO,OAAO,OAAO,MAAM;EAC7B,KAAK,QACH,OAAO,OAAO,IAAI,MAAM;CAC5B;AACF;;;;;;;;AA8BA,SAAgB,YAAY,QAA4B;CACtD,KAAK,MAAM,UAAU,OAAO,SAAS;EACnC,MAAM,SAAS,eAAe,OAAO,MAAM;EAE3C,QAAQ,IAAI,GAAG,OAAO,GAAG,OAAO,KAAK,OAAO,IAAI,EAAE,IAAI,OAAO,QAAQ;CACvE;CAEA,MAAM,EAAE,IAAI,MAAM,SAAS,OAAO;CAClC,MAAM,cAAc,YAAY,GAAG,OAAO,KAAK,SAAS,KAAK;CAE7D,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,OAAO,cAAc,OAAO,IAAI,WAAW,IAAI,OAAO,MAAM,WAAW,CAAC;AACtF"}
@@ -0,0 +1,50 @@
1
+ //#region ../@warlock.js/core/src/cli/commands/doctor/run-checks.ts
2
+ /**
3
+ * Run one check defensively: a check that throws (or rejects) is recorded as a
4
+ * `fail` carrying the error message, never re-thrown. This is what keeps
5
+ * `doctor` itself crash-proof — a broken probe degrades to a failed check
6
+ * instead of taking the whole command down.
7
+ */
8
+ async function runOne(check) {
9
+ try {
10
+ return await check.run();
11
+ } catch (error) {
12
+ const message = error instanceof Error ? error.message : String(error);
13
+ return {
14
+ name: check.name,
15
+ status: "fail",
16
+ detail: `check threw: ${message}`
17
+ };
18
+ }
19
+ }
20
+ /**
21
+ * Run every check and aggregate the results into a {@link DoctorReport}.
22
+ *
23
+ * Checks run in registration order. Each is isolated via {@link runOne}, so one
24
+ * throwing check cannot abort the others. The exit code is `1` if any check
25
+ * resolved to `fail`, otherwise `0` — warnings never fail the command.
26
+ *
27
+ * @param checks The diagnostic probes to execute.
28
+ * @returns The aggregated report (results + per-status counts + exit code).
29
+ */
30
+ async function runChecks(checks) {
31
+ const results = [];
32
+ for (const check of checks) results.push(await runOne(check));
33
+ const summary = {
34
+ ok: 0,
35
+ warn: 0,
36
+ fail: 0
37
+ };
38
+ for (const result of results) summary[result.status] += 1;
39
+ const hasFailures = summary.fail > 0;
40
+ return {
41
+ results,
42
+ summary,
43
+ hasFailures,
44
+ exitCode: hasFailures ? 1 : 0
45
+ };
46
+ }
47
+
48
+ //#endregion
49
+ export { runChecks };
50
+ //# sourceMappingURL=run-checks.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-checks.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/core/src/cli/commands/doctor/run-checks.ts"],"sourcesContent":["import type { CheckResult, CheckStatus, DoctorCheck, DoctorReport } from \"./check.types\";\n\n/**\n * Run one check defensively: a check that throws (or rejects) is recorded as a\n * `fail` carrying the error message, never re-thrown. This is what keeps\n * `doctor` itself crash-proof — a broken probe degrades to a failed check\n * instead of taking the whole command down.\n */\nasync function runOne(check: DoctorCheck): Promise<CheckResult> {\n try {\n return await check.run();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n name: check.name,\n status: \"fail\",\n detail: `check threw: ${message}`,\n };\n }\n}\n\n/**\n * Run every check and aggregate the results into a {@link DoctorReport}.\n *\n * Checks run in registration order. Each is isolated via {@link runOne}, so one\n * throwing check cannot abort the others. The exit code is `1` if any check\n * resolved to `fail`, otherwise `0` — warnings never fail the command.\n *\n * @param checks The diagnostic probes to execute.\n * @returns The aggregated report (results + per-status counts + exit code).\n */\nexport async function runChecks(checks: DoctorCheck[]): Promise<DoctorReport> {\n const results: CheckResult[] = [];\n\n for (const check of checks) {\n results.push(await runOne(check));\n }\n\n const summary: Record<CheckStatus, number> = { ok: 0, warn: 0, fail: 0 };\n\n for (const result of results) {\n summary[result.status] += 1;\n }\n\n const hasFailures = summary.fail > 0;\n\n return {\n results,\n summary,\n hasFailures,\n exitCode: hasFailures ? 1 : 0,\n };\n}\n"],"mappings":";;;;;;;AAQA,eAAe,OAAO,OAA0C;CAC9D,IAAI;EACF,OAAO,MAAM,MAAM,IAAI;CACzB,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAErE,OAAO;GACL,MAAM,MAAM;GACZ,QAAQ;GACR,QAAQ,gBAAgB;EAC1B;CACF;AACF;;;;;;;;;;;AAYA,eAAsB,UAAU,QAA8C;CAC5E,MAAM,UAAyB,CAAC;CAEhC,KAAK,MAAM,SAAS,QAClB,QAAQ,KAAK,MAAM,OAAO,KAAK,CAAC;CAGlC,MAAM,UAAuC;EAAE,IAAI;EAAG,MAAM;EAAG,MAAM;CAAE;CAEvE,KAAK,MAAM,UAAU,SACnB,QAAQ,OAAO,WAAW;CAG5B,MAAM,cAAc,QAAQ,OAAO;CAEnC,OAAO;EACL;EACA;EACA;EACA,UAAU,cAAc,IAAI;CAC9B;AACF"}
@@ -0,0 +1,29 @@
1
+ import { command } from "../cli-command.mjs";
2
+ import { doctorCommandAction } from "./doctor/doctor-command.action.mjs";
3
+
4
+ //#region ../@warlock.js/core/src/cli/commands/doctor.command.ts
5
+ /**
6
+ * `warlock doctor` — run a set of READ-ONLY diagnostic checks (routes, config,
7
+ * connectors, optional peers, health endpoints, release hygiene) and print a
8
+ * grouped pass/warn/fail report. Exits non-zero if any check fails.
9
+ *
10
+ * Preload plan: load every config file and bootstrap app code so routes and
11
+ * connectors are registered for introspection, but DELIBERATELY start no
12
+ * connectors — doctor must not open database/cache/socket connections. The
13
+ * connectors check therefore reports the registered set and which (if any) are
14
+ * already active without forcing them up.
15
+ */
16
+ const doctorCommand = command({
17
+ name: "doctor",
18
+ description: "Run read-only health checks (routes, config, connectors, optional peers, health endpoints, release hygiene) and print a pass/warn/fail report",
19
+ action: doctorCommandAction,
20
+ preload: {
21
+ config: true,
22
+ env: true,
23
+ bootstrap: true
24
+ }
25
+ });
26
+
27
+ //#endregion
28
+ export { doctorCommand };
29
+ //# sourceMappingURL=doctor.command.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.command.mjs","names":[],"sources":["../../../../../../../../@warlock.js/core/src/cli/commands/doctor.command.ts"],"sourcesContent":["import { command } from \"../cli-command\";\nimport { doctorCommandAction } from \"./doctor/doctor-command.action\";\n\n/**\n * `warlock doctor` — run a set of READ-ONLY diagnostic checks (routes, config,\n * connectors, optional peers, health endpoints, release hygiene) and print a\n * grouped pass/warn/fail report. Exits non-zero if any check fails.\n *\n * Preload plan: load every config file and bootstrap app code so routes and\n * connectors are registered for introspection, but DELIBERATELY start no\n * connectors — doctor must not open database/cache/socket connections. The\n * connectors check therefore reports the registered set and which (if any) are\n * already active without forcing them up.\n */\nexport const doctorCommand = command({\n name: \"doctor\",\n description:\n \"Run read-only health checks (routes, config, connectors, optional peers, health endpoints, release hygiene) and print a pass/warn/fail report\",\n action: doctorCommandAction,\n preload: {\n config: true,\n env: true,\n bootstrap: true,\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,gBAAgB,QAAQ;CACnC,MAAM;CACN,aACE;CACF,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,KAAK;EACL,WAAW;CACb;AACF,CAAC"}
@@ -333,17 +333,15 @@ export default seeder({
333
333
  name: "Seed ${entity.plural.pascal}",
334
334
  once: true,
335
335
  enabled: true,
336
- run: async () => {
336
+ run: async ({ track }) => {
337
337
  const total = 10;
338
338
  for (let i = 0; i < total; i++) {
339
- await ${entity.singular.pascal}.create({
340
- // TODO: Add more fields
341
- });
339
+ track(
340
+ await ${entity.singular.pascal}.create({
341
+ // TODO: Add more fields
342
+ }),
343
+ );
342
344
  }
343
-
344
- return {
345
- recordsCreated: total,
346
- };
347
345
  },
348
346
  });
349
347
  `;