@tailor-platform/erp-kit 0.5.0 → 0.6.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.
- package/CHANGELOG.md +24 -0
- package/dist/cli.mjs +139 -35
- package/package.json +1 -1
- package/skills/erp-kit-app-5-impl-backend/SKILL.md +10 -5
- package/skills/erp-kit-app-7-impl-review/SKILL.md +1 -1
- package/skills/erp-kit-module-6-impl-review/SKILL.md +39 -17
- package/src/commands/generate-doc.ts +1 -1
- package/src/commands/init-module.test.ts +17 -3
- package/src/commands/init-module.ts +0 -12
- package/src/commands/lib/discovery.test.ts +13 -3
- package/src/commands/lib/discovery.ts +10 -2
- package/src/commands/lib/paths.ts +4 -2
- package/src/commands/lib/sync-check-tests.test.ts +84 -6
- package/src/commands/lib/sync-check-tests.ts +63 -3
- package/src/commands/sync-check.ts +7 -3
- package/src/generator/generate-app-code.ts +51 -16
- package/src/generator/generate-code-boilerplate.test.ts +9 -1
- package/src/generator/generate-stubs.ts +4 -0
- package/src/generator/scaffold.ts +6 -2
- package/src/generator/stub-templates.test.ts +11 -0
- package/src/generator/stub-templates.ts +22 -1
- package/src/mdschema.ts +39 -3
- package/src/modules/inventory/docs/features/inventory-adjustment.md +2 -1
- package/src/modules/inventory/docs/features/scrap-management.md +39 -1
- package/src/modules/manufacturing/README.md +63 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.test.ts +166 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.ts +173 -0
- package/src/modules/manufacturing/command/activateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateRouting.test.ts +152 -0
- package/src/modules/manufacturing/command/activateRouting.ts +92 -0
- package/src/modules/manufacturing/command/activateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateWorkCenter.test.ts +135 -0
- package/src/modules/manufacturing/command/activateWorkCenter.ts +91 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.test.ts +151 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.ts +114 -0
- package/src/modules/manufacturing/command/closeProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/closeProductionOrder.test.ts +126 -0
- package/src/modules/manufacturing/command/closeProductionOrder.ts +87 -0
- package/src/modules/manufacturing/command/completeProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/completeProductionOrder.test.ts +132 -0
- package/src/modules/manufacturing/command/completeProductionOrder.ts +97 -0
- package/src/modules/manufacturing/command/completeWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/completeWorkOrder.test.ts +369 -0
- package/src/modules/manufacturing/command/completeWorkOrder.ts +212 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.test.ts +210 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.ts +176 -0
- package/src/modules/manufacturing/command/createProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/createProductionOrder.test.ts +160 -0
- package/src/modules/manufacturing/command/createProductionOrder.ts +129 -0
- package/src/modules/manufacturing/command/createRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/createRouting.test.ts +168 -0
- package/src/modules/manufacturing/command/createRouting.ts +128 -0
- package/src/modules/manufacturing/command/createWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/createWorkCenter.test.ts +148 -0
- package/src/modules/manufacturing/command/createWorkCenter.ts +131 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.test.ts +103 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.ts +78 -0
- package/src/modules/manufacturing/command/deactivateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateRouting.test.ts +112 -0
- package/src/modules/manufacturing/command/deactivateRouting.ts +76 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.test.ts +113 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.ts +85 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.test.ts +118 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.ts +82 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.generated.ts +6 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.test.ts +183 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.ts +139 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.generated.ts +6 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.test.ts +120 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.ts +110 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.test.ts +220 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.ts +450 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.test.ts +196 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.ts +98 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.generated.ts +6 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.test.ts +204 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.ts +129 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.test.ts +185 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.ts +95 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.test.ts +122 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.ts +94 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.generated.ts +6 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.test.ts +231 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.ts +137 -0
- package/src/modules/manufacturing/command/startWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/startWorkOrder.test.ts +118 -0
- package/src/modules/manufacturing/command/startWorkOrder.ts +126 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.test.ts +153 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.ts +106 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.test.ts +140 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.ts +131 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.test.ts +149 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.ts +174 -0
- package/src/modules/manufacturing/command/updateProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateProductionOrder.test.ts +112 -0
- package/src/modules/manufacturing/command/updateProductionOrder.ts +145 -0
- package/src/modules/manufacturing/command/updateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateRouting.test.ts +211 -0
- package/src/modules/manufacturing/command/updateRouting.ts +124 -0
- package/src/modules/manufacturing/command/updateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateWorkCenter.test.ts +152 -0
- package/src/modules/manufacturing/command/updateWorkCenter.ts +137 -0
- package/src/modules/manufacturing/db/.gitkeep +0 -0
- package/src/modules/manufacturing/db/billOfMaterial.ts +70 -0
- package/src/modules/manufacturing/db/billOfMaterialLine.ts +49 -0
- package/src/modules/manufacturing/db/costVarianceLine.ts +53 -0
- package/src/modules/manufacturing/db/manufacturingCostLine.ts +35 -0
- package/src/modules/manufacturing/db/manufacturingCostSettlementRecord.ts +39 -0
- package/src/modules/manufacturing/db/manufacturingCostSummary.ts +59 -0
- package/src/modules/manufacturing/db/productionOrder.ts +83 -0
- package/src/modules/manufacturing/db/productionOrderBomSnapshot.ts +44 -0
- package/src/modules/manufacturing/db/productionOrderCostBaseline.ts +44 -0
- package/src/modules/manufacturing/db/productionOrderMaterialRequirement.ts +57 -0
- package/src/modules/manufacturing/db/productionOrderRoutingSnapshot.ts +43 -0
- package/src/modules/manufacturing/db/routing.ts +63 -0
- package/src/modules/manufacturing/db/routingOperation.ts +57 -0
- package/src/modules/manufacturing/db/workCenter.ts +87 -0
- package/src/modules/manufacturing/db/workOrder.ts +65 -0
- package/src/modules/manufacturing/db/workOrderExecutionEvent.ts +54 -0
- package/src/modules/manufacturing/docs/commands/ActivateBillOfMaterial.md +50 -0
- package/src/modules/manufacturing/docs/commands/ActivateRouting.md +48 -0
- package/src/modules/manufacturing/docs/commands/ActivateWorkCenter.md +49 -0
- package/src/modules/manufacturing/docs/commands/CancelProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/CloseProductionOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/CompleteProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/CompleteWorkOrder.md +66 -0
- package/src/modules/manufacturing/docs/commands/CreateBillOfMaterial.md +54 -0
- package/src/modules/manufacturing/docs/commands/CreateProductionOrder.md +49 -0
- package/src/modules/manufacturing/docs/commands/CreateRouting.md +50 -0
- package/src/modules/manufacturing/docs/commands/CreateWorkCenter.md +51 -0
- package/src/modules/manufacturing/docs/commands/DeactivateBillOfMaterial.md +45 -0
- package/src/modules/manufacturing/docs/commands/DeactivateRouting.md +45 -0
- package/src/modules/manufacturing/docs/commands/DeactivateWorkCenter.md +45 -0
- package/src/modules/manufacturing/docs/commands/PauseWorkOrder.md +44 -0
- package/src/modules/manufacturing/docs/commands/RecordInventoryIssueOutcome.md +59 -0
- package/src/modules/manufacturing/docs/commands/RecordManufacturingCostSettlementAcknowledgment.md +49 -0
- package/src/modules/manufacturing/docs/commands/ReleaseProductionOrder.md +57 -0
- package/src/modules/manufacturing/docs/commands/ReopenProductionOrder.md +54 -0
- package/src/modules/manufacturing/docs/commands/ReportWorkOrderProgress.md +53 -0
- package/src/modules/manufacturing/docs/commands/RescheduleProductionOrder.md +45 -0
- package/src/modules/manufacturing/docs/commands/ResumeWorkOrder.md +44 -0
- package/src/modules/manufacturing/docs/commands/ReviewManufacturingCostSummary.md +52 -0
- package/src/modules/manufacturing/docs/commands/StartWorkOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/TechnicallyCompleteProductionOrder.md +51 -0
- package/src/modules/manufacturing/docs/commands/UnreleaseProductionOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/UpdateBillOfMaterial.md +48 -0
- package/src/modules/manufacturing/docs/commands/UpdateProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/UpdateRouting.md +52 -0
- package/src/modules/manufacturing/docs/commands/UpdateWorkCenter.md +48 -0
- package/src/modules/manufacturing/docs/features/bill-of-material-management.md +83 -0
- package/src/modules/manufacturing/docs/features/manufacturing-cost-and-variance.md +191 -0
- package/src/modules/manufacturing/docs/features/production-order-lifecycle.md +103 -0
- package/src/modules/manufacturing/docs/features/routing-and-work-center-definition.md +63 -0
- package/src/modules/manufacturing/docs/features/work-order-execution.md +115 -0
- package/src/modules/manufacturing/docs/models/BillOfMaterial.md +60 -0
- package/src/modules/manufacturing/docs/models/ManufacturingCostSummary.md +66 -0
- package/src/modules/manufacturing/docs/models/ProductionOrder.md +76 -0
- package/src/modules/manufacturing/docs/models/Routing.md +58 -0
- package/src/modules/manufacturing/docs/models/WorkCenter.md +56 -0
- package/src/modules/manufacturing/docs/models/WorkOrder.md +63 -0
- package/src/modules/manufacturing/docs/queries/DetectBillOfMaterialCircularReference.md +39 -0
- package/src/modules/manufacturing/docs/queries/ExplodeBillOfMaterial.md +56 -0
- package/src/modules/manufacturing/docs/queries/GetBillOfMaterial.md +37 -0
- package/src/modules/manufacturing/docs/queries/GetManufacturingCostSummary.md +39 -0
- package/src/modules/manufacturing/docs/queries/GetProductionOrder.md +37 -0
- package/src/modules/manufacturing/docs/queries/GetRouting.md +39 -0
- package/src/modules/manufacturing/docs/queries/GetWorkCenter.md +35 -0
- package/src/modules/manufacturing/docs/queries/GetWorkOrder.md +38 -0
- package/src/modules/manufacturing/docs/queries/ListBillOfMaterialsByItem.md +42 -0
- package/src/modules/manufacturing/docs/queries/ListManufacturingCostSummariesByStatus.md +41 -0
- package/src/modules/manufacturing/docs/queries/ListProductionOrdersByStatus.md +41 -0
- package/src/modules/manufacturing/docs/queries/ListRoutingsByItem.md +42 -0
- package/src/modules/manufacturing/docs/queries/ListWorkCentersBySite.md +38 -0
- package/src/modules/manufacturing/docs/queries/ListWorkOrdersByProductionOrder.md +39 -0
- package/src/modules/manufacturing/docs/queries/ListWorkOrdersByWorkCenter.md +43 -0
- package/src/modules/manufacturing/executor/.gitkeep +0 -0
- package/src/modules/manufacturing/generated/enums.ts +113 -0
- package/src/modules/manufacturing/generated/kysely-tailordb.ts +247 -0
- package/src/modules/manufacturing/index.ts +2 -0
- package/src/modules/manufacturing/lib/_db_deps.ts +22 -0
- package/src/modules/manufacturing/lib/errors.generated.ts +592 -0
- package/src/modules/manufacturing/lib/permissions.generated.ts +35 -0
- package/src/modules/manufacturing/lib/types.ts +111 -0
- package/src/modules/manufacturing/module.ts +226 -0
- package/src/modules/manufacturing/permissions.ts +3 -0
- package/src/modules/manufacturing/query/.gitkeep +0 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.generated.ts +5 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.test.ts +115 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.ts +79 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.generated.ts +5 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.test.ts +445 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.ts +306 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.generated.ts +5 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.test.ts +64 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.ts +27 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.generated.ts +5 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.test.ts +147 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.ts +46 -0
- package/src/modules/manufacturing/query/getProductionOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/getProductionOrder.test.ts +139 -0
- package/src/modules/manufacturing/query/getProductionOrder.ts +84 -0
- package/src/modules/manufacturing/query/getRouting.generated.ts +5 -0
- package/src/modules/manufacturing/query/getRouting.test.ts +71 -0
- package/src/modules/manufacturing/query/getRouting.ts +34 -0
- package/src/modules/manufacturing/query/getWorkCenter.generated.ts +5 -0
- package/src/modules/manufacturing/query/getWorkCenter.test.ts +37 -0
- package/src/modules/manufacturing/query/getWorkCenter.ts +21 -0
- package/src/modules/manufacturing/query/getWorkOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/getWorkOrder.test.ts +73 -0
- package/src/modules/manufacturing/query/getWorkOrder.ts +28 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.generated.ts +5 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.test.ts +107 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.ts +58 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.generated.ts +5 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.test.ts +96 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.ts +77 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.generated.ts +5 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.test.ts +121 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.ts +83 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.generated.ts +5 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.test.ts +110 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.ts +54 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.test.ts +81 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.ts +70 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.test.ts +102 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.ts +53 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.test.ts +143 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.ts +56 -0
- package/src/modules/manufacturing/seed/index.ts +19 -0
- package/src/modules/manufacturing/tailor.config.ts +13 -0
- package/src/modules/manufacturing/tailor.d.ts +13 -0
- package/src/modules/manufacturing/testing/commandTestUtils.ts +29 -0
- package/src/modules/manufacturing/testing/fixtures.ts +402 -0
- package/templates/scaffold/app/backend/package.json +9 -2
- package/templates/scaffold/app/backend/src/tests/utils/graphql-client.ts +66 -0
- package/templates/scaffold/app/backend/src/tests/utils/setup.ts +21 -0
- package/templates/scaffold/app/backend/tsconfig.json +9 -2
- package/templates/scaffold/app/backend/vitest.config.ts +35 -0
- package/templates/scaffold/app/frontend/package.json +2 -2
- package/templates/scaffold/module/__dot__gitignore +3 -0
- package/templates/scaffold/module/eslint.config.js +31 -0
- package/templates/scaffold/module/generated/kysely-tailordb.ts +3 -0
- package/templates/scaffold/module/lib/types.ts +1 -6
- package/templates/scaffold/module/package.json +26 -0
- package/templates/scaffold/module/tsconfig.json +16 -0
- /package/{templates/scaffold/module/generated → src/modules/manufacturing/command}/.gitkeep +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @tailor-platform/erp-kit
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0cb94dc: - Add manufacturing module with BOM, work orders, and production tracking
|
|
8
|
+
- Add story test case sync-check and stub generation for `erp-kit test` command
|
|
9
|
+
- Update workspace creation instructions and deployment steps in skills
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 0cb94dc: - Fix relative shared imports to use package self-reference for consistent module resolution
|
|
14
|
+
- Fix priority calibration in requirements review skill to improve accuracy
|
|
15
|
+
- Fix severity validation in module-2 requirements review skill
|
|
16
|
+
- Update module-4-plan-review skill and regenerate .agents/skills
|
|
17
|
+
|
|
18
|
+
## 0.5.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- fb40e4d: - Fix mdschema binary resolution to use platform-specific native binaries, enabling Windows support
|
|
23
|
+
- Fix init commands to be idempotent when directory already exists instead of erroring
|
|
24
|
+
- Add package.json and dev tooling to module template
|
|
25
|
+
- Update app skill to use erp-kit app generate seed
|
|
26
|
+
|
|
3
27
|
## 0.5.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { arg, defineCommand, runMain } from "politty";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import chalk from "chalk";
|
|
6
|
-
import fs, { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
6
|
+
import fs, { existsSync, globSync, readFileSync, readdirSync } from "node:fs";
|
|
7
7
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
8
8
|
import { execFile, execSync } from "node:child_process";
|
|
9
9
|
import fg from "fast-glob";
|
|
@@ -364,12 +364,35 @@ function runLicenseCheck(configPath) {
|
|
|
364
364
|
//#endregion
|
|
365
365
|
//#region src/mdschema.ts
|
|
366
366
|
const require = createRequire(import.meta.url);
|
|
367
|
+
const PLATFORMS = {
|
|
368
|
+
darwin: {
|
|
369
|
+
arm64: "@jackchuka/mdschema-darwin-arm64",
|
|
370
|
+
x64: "@jackchuka/mdschema-darwin-x64"
|
|
371
|
+
},
|
|
372
|
+
linux: {
|
|
373
|
+
arm64: "@jackchuka/mdschema-linux-arm64",
|
|
374
|
+
x64: "@jackchuka/mdschema-linux-x64"
|
|
375
|
+
},
|
|
376
|
+
win32: {
|
|
377
|
+
arm64: "@jackchuka/mdschema-windows-arm64",
|
|
378
|
+
x64: "@jackchuka/mdschema-windows-x64"
|
|
379
|
+
}
|
|
380
|
+
};
|
|
367
381
|
function getMdschemaBin() {
|
|
368
382
|
const pkgPath = require.resolve("@jackchuka/mdschema/package.json");
|
|
369
|
-
const
|
|
370
|
-
const
|
|
383
|
+
const pkgDir = path.dirname(pkgPath);
|
|
384
|
+
const mdschemaRequire = createRequire(pkgPath);
|
|
385
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
386
|
+
const pkg = PLATFORMS[process.platform]?.[process.arch];
|
|
387
|
+
if (pkg) try {
|
|
388
|
+
return mdschemaRequire.resolve(`${pkg}/bin/mdschema${ext}`);
|
|
389
|
+
} catch {}
|
|
390
|
+
const localBin = path.join(pkgDir, "bin", `mdschema${ext}`);
|
|
391
|
+
if (fs.existsSync(localBin)) return localBin;
|
|
392
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
393
|
+
const bin = typeof pkgJson.bin === "string" ? pkgJson.bin : pkgJson.bin?.mdschema;
|
|
371
394
|
if (!bin) throw new Error("Could not resolve mdschema binary from package.json bin field");
|
|
372
|
-
return path.join(
|
|
395
|
+
return path.join(pkgDir, bin);
|
|
373
396
|
}
|
|
374
397
|
function runMdschema(args, cwd) {
|
|
375
398
|
return new Promise((resolve) => {
|
|
@@ -429,11 +452,12 @@ const MODULE_PATHS = {
|
|
|
429
452
|
}
|
|
430
453
|
};
|
|
431
454
|
const APP_PATHS = {
|
|
432
|
-
|
|
455
|
+
tests: { stories: "backend/src/tests/stories" },
|
|
433
456
|
docs: {
|
|
434
457
|
resolver: "docs/resolver",
|
|
435
458
|
actors: "docs/actors",
|
|
436
459
|
businessFlow: "docs/business-flow",
|
|
460
|
+
story: "story",
|
|
437
461
|
screen: "docs/screen"
|
|
438
462
|
}
|
|
439
463
|
};
|
|
@@ -469,7 +493,14 @@ function appComposeCategories(root) {
|
|
|
469
493
|
exclusions: [/\.test\.ts$/, /^index\.ts$/]
|
|
470
494
|
}];
|
|
471
495
|
}
|
|
472
|
-
function
|
|
496
|
+
function appTestCaseCategories(root) {
|
|
497
|
+
return {
|
|
498
|
+
name: "story-test-case",
|
|
499
|
+
docPattern: `${root}/*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.docs.story}/*.md`,
|
|
500
|
+
testDir: APP_PATHS.tests.stories
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function moduleTestCaseCategories(root) {
|
|
473
504
|
return [{
|
|
474
505
|
name: "command-test-case",
|
|
475
506
|
docPattern: `${root}/*/${MODULE_PATHS.docs.commands}/*.md`,
|
|
@@ -513,7 +544,7 @@ function buildCheckTargets(config) {
|
|
|
513
544
|
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/README.md`,
|
|
514
545
|
schemaKey: "business-flow"
|
|
515
546
|
}, {
|
|
516
|
-
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.
|
|
547
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.docs.story}/*.md`,
|
|
517
548
|
schemaKey: "story"
|
|
518
549
|
}, {
|
|
519
550
|
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.screen}/*.md`,
|
|
@@ -552,10 +583,6 @@ async function runCheck(config, cwd) {
|
|
|
552
583
|
//#region src/commands/init-module.ts
|
|
553
584
|
function runInitModule(name, dir) {
|
|
554
585
|
const moduleDir = path.resolve(dir, name);
|
|
555
|
-
if (fs.existsSync(moduleDir)) {
|
|
556
|
-
console.error(`Directory already exists: ${moduleDir}`);
|
|
557
|
-
return 1;
|
|
558
|
-
}
|
|
559
586
|
fs.mkdirSync(moduleDir, { recursive: true });
|
|
560
587
|
return 0;
|
|
561
588
|
}
|
|
@@ -578,10 +605,6 @@ async function runInitModuleWithReadme(name, dir, cwd) {
|
|
|
578
605
|
}
|
|
579
606
|
function runInitApp(name, dir) {
|
|
580
607
|
const appDir = path.resolve(dir, name);
|
|
581
|
-
if (fs.existsSync(appDir)) {
|
|
582
|
-
console.error(`Directory already exists: ${appDir}`);
|
|
583
|
-
return 1;
|
|
584
|
-
}
|
|
585
608
|
fs.mkdirSync(appDir, { recursive: true });
|
|
586
609
|
return 0;
|
|
587
610
|
}
|
|
@@ -727,9 +750,9 @@ function parseItDescriptionsFromTest(content) {
|
|
|
727
750
|
function toCamelCase(pascalCase) {
|
|
728
751
|
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
729
752
|
}
|
|
730
|
-
async function
|
|
753
|
+
async function runModuleTestCaseSyncCheck(root, cwd) {
|
|
731
754
|
const errors = [];
|
|
732
|
-
const categories =
|
|
755
|
+
const categories = moduleTestCaseCategories(root);
|
|
733
756
|
for (const category of categories) {
|
|
734
757
|
const docPaths = await fg(category.docPattern, { cwd });
|
|
735
758
|
for (const docPath of docPaths) {
|
|
@@ -765,15 +788,57 @@ async function runTestCaseSyncCheck(root, cwd) {
|
|
|
765
788
|
}
|
|
766
789
|
return errors;
|
|
767
790
|
}
|
|
791
|
+
function resolveStoryTestPath(docPath, testDir) {
|
|
792
|
+
const match = /^(.+)\/docs\/business-flow\/([^/]+)\/story\/([^/]+)\.md$/.exec(docPath);
|
|
793
|
+
if (!match) return null;
|
|
794
|
+
const [, appPath, flow, name] = match;
|
|
795
|
+
return `${appPath}/${testDir}/${flow}/${name}.test.ts`;
|
|
796
|
+
}
|
|
797
|
+
async function runAppTestCaseSyncCheck(appRoot, cwd) {
|
|
798
|
+
const errors = [];
|
|
799
|
+
const config = appTestCaseCategories(appRoot);
|
|
800
|
+
const docPaths = await fg(config.docPattern, { cwd });
|
|
801
|
+
for (const docPath of docPaths) {
|
|
802
|
+
const docFullPath = path.join(cwd, docPath);
|
|
803
|
+
const docTestCases = parseTestCasesFromDoc(fs.readFileSync(docFullPath, "utf-8"));
|
|
804
|
+
if (docTestCases.length === 0) continue;
|
|
805
|
+
const testPath = resolveStoryTestPath(docPath, config.testDir);
|
|
806
|
+
if (!testPath) continue;
|
|
807
|
+
const testFullPath = path.join(cwd, testPath);
|
|
808
|
+
if (!fs.existsSync(testFullPath)) continue;
|
|
809
|
+
const itDescriptions = parseItDescriptionsFromTest(fs.readFileSync(testFullPath, "utf-8"));
|
|
810
|
+
const docSet = new Set(docTestCases);
|
|
811
|
+
const testSet = new Set(itDescriptions);
|
|
812
|
+
for (const docCase of docSet) if (!testSet.has(docCase)) errors.push({
|
|
813
|
+
type: "missing-test-case",
|
|
814
|
+
category: config.name,
|
|
815
|
+
docPath,
|
|
816
|
+
sourcePath: testPath,
|
|
817
|
+
expectedBasename: docCase
|
|
818
|
+
});
|
|
819
|
+
for (const testCase of testSet) if (!docSet.has(testCase)) errors.push({
|
|
820
|
+
type: "extra-test-case",
|
|
821
|
+
category: config.name,
|
|
822
|
+
docPath,
|
|
823
|
+
sourcePath: testPath,
|
|
824
|
+
expectedBasename: testCase
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
return errors;
|
|
828
|
+
}
|
|
768
829
|
//#endregion
|
|
769
830
|
//#region src/commands/sync-check.ts
|
|
770
831
|
async function runSyncCheck(config, cwd) {
|
|
771
832
|
const sourceResult = await runSourceSyncCheck(config, cwd);
|
|
772
833
|
if (config.modulesRoot) {
|
|
773
|
-
const testCaseErrors = await
|
|
834
|
+
const testCaseErrors = await runModuleTestCaseSyncCheck(config.modulesRoot, cwd);
|
|
774
835
|
sourceResult.errors.push(...testCaseErrors);
|
|
775
|
-
sourceResult.exitCode = sourceResult.errors.length > 0 ? 1 : 0;
|
|
776
836
|
}
|
|
837
|
+
if (config.appRoot) {
|
|
838
|
+
const storyErrors = await runAppTestCaseSyncCheck(config.appRoot, cwd);
|
|
839
|
+
sourceResult.errors.push(...storyErrors);
|
|
840
|
+
}
|
|
841
|
+
sourceResult.exitCode = sourceResult.errors.length > 0 ? 1 : 0;
|
|
777
842
|
return sourceResult;
|
|
778
843
|
}
|
|
779
844
|
function formatSyncCheckReport(result) {
|
|
@@ -1077,10 +1142,22 @@ describe("${name}", () => {
|
|
|
1077
1142
|
expect(resolver.default.name).toBe("${name}");
|
|
1078
1143
|
});
|
|
1079
1144
|
});
|
|
1145
|
+
`;
|
|
1146
|
+
} },
|
|
1147
|
+
storyTest: { render: (name, testCases) => {
|
|
1148
|
+
return `import { describe, expect, inject, it } from "vitest";
|
|
1149
|
+
import { createGraphQLClient } from "@/tests/utils/graphql-client";
|
|
1150
|
+
|
|
1151
|
+
describe("${name}", () => {
|
|
1152
|
+
const graphQLClient = createGraphQLClient(inject("url"), inject("token"));
|
|
1153
|
+
|
|
1154
|
+
${testCases.map((tc) => ` it("${tc}", async () => {\n // TODO: implement\n });`).join("\n\n")}
|
|
1155
|
+
});
|
|
1080
1156
|
`;
|
|
1081
1157
|
} }
|
|
1082
1158
|
};
|
|
1083
|
-
function renderStub(type, name) {
|
|
1159
|
+
function renderStub(type, name, testCases) {
|
|
1160
|
+
if (type === "storyTest") return templates.storyTest.render(name, testCases);
|
|
1084
1161
|
return templates[type].render(name);
|
|
1085
1162
|
}
|
|
1086
1163
|
//#endregion
|
|
@@ -1106,6 +1183,9 @@ function generateResolverStub(resolverName) {
|
|
|
1106
1183
|
function generateResolverTestStub(resolverName) {
|
|
1107
1184
|
return renderStub("resolverTest", resolverName);
|
|
1108
1185
|
}
|
|
1186
|
+
function generateStoryTestStub(name, testCases) {
|
|
1187
|
+
return renderStub("storyTest", name, testCases);
|
|
1188
|
+
}
|
|
1109
1189
|
//#endregion
|
|
1110
1190
|
//#region src/generator/scaffold.ts
|
|
1111
1191
|
function copyTemplateDir(srcDir, destDir, replacements, placeholderFiles) {
|
|
@@ -1129,7 +1209,16 @@ function copyTemplateDir(srcDir, destDir, replacements, placeholderFiles) {
|
|
|
1129
1209
|
}
|
|
1130
1210
|
}
|
|
1131
1211
|
function scaffoldModuleBoilerplate(moduleDir, moduleName) {
|
|
1132
|
-
|
|
1212
|
+
const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "module");
|
|
1213
|
+
const erpKitVersion = readErpKitVersion();
|
|
1214
|
+
copyTemplateDir(templateDir, moduleDir, {
|
|
1215
|
+
"template-module": moduleName,
|
|
1216
|
+
"\"workspace:*\"": `"${erpKitVersion}"`
|
|
1217
|
+
}, new Set([
|
|
1218
|
+
"package.json",
|
|
1219
|
+
"permissions.ts",
|
|
1220
|
+
"tailor.config.ts"
|
|
1221
|
+
]));
|
|
1133
1222
|
}
|
|
1134
1223
|
function scaffoldAppBoilerplate(appDir, appName) {
|
|
1135
1224
|
const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "app");
|
|
@@ -1290,7 +1379,7 @@ function resolveDocPath(type, name, modulePath) {
|
|
|
1290
1379
|
if (type === "story") {
|
|
1291
1380
|
const parts = name.split("/");
|
|
1292
1381
|
if (parts.length !== 2) throw new Error(`Story name must be "<flow>/<story>" (e.g., "onboarding/admin--create-user")`);
|
|
1293
|
-
return path.join(modulePath, APP_PATHS.docs.businessFlow, parts[0], APP_PATHS.
|
|
1382
|
+
return path.join(modulePath, APP_PATHS.docs.businessFlow, parts[0], APP_PATHS.docs.story, `${parts[1]}.md`);
|
|
1294
1383
|
}
|
|
1295
1384
|
if (MODULE_DIR_MAP[type]) return path.join(modulePath, MODULE_DIR_MAP[type], `${name}.md`);
|
|
1296
1385
|
if (APP_DIR_MAP[type]) return path.join(modulePath, APP_DIR_MAP[type], `${name}.md`);
|
|
@@ -1516,19 +1605,16 @@ function parseExceptionHandlingFromRaw(markdown) {
|
|
|
1516
1605
|
function runGenerateAppCode(appPath) {
|
|
1517
1606
|
const appName = path.basename(appPath);
|
|
1518
1607
|
scaffoldAppBoilerplate(appPath, appName);
|
|
1608
|
+
generateResolverStubs(appPath, appName);
|
|
1609
|
+
generateStoryTestStubs(appPath, appName);
|
|
1610
|
+
return 0;
|
|
1611
|
+
}
|
|
1612
|
+
function generateResolverStubs(appPath, appName) {
|
|
1519
1613
|
const docsDir = path.join(appPath, "docs", "resolver");
|
|
1520
|
-
|
|
1521
|
-
if (!fs.existsSync(docsDir)) {
|
|
1522
|
-
console.log(`No docs/resolver/ directory found — skipping resolver generation`);
|
|
1523
|
-
console.log(`Generated boilerplate for ${appName}`);
|
|
1524
|
-
return 0;
|
|
1525
|
-
}
|
|
1614
|
+
if (!fs.existsSync(docsDir)) return;
|
|
1526
1615
|
const mdFiles = fs.readdirSync(docsDir).filter((f) => f.endsWith(".md"));
|
|
1527
|
-
if (mdFiles.length === 0)
|
|
1528
|
-
|
|
1529
|
-
console.log(`Generated boilerplate for ${appName}`);
|
|
1530
|
-
return 0;
|
|
1531
|
-
}
|
|
1616
|
+
if (mdFiles.length === 0) return;
|
|
1617
|
+
const resolverDir = path.join(appPath, "backend", "src", "resolvers");
|
|
1532
1618
|
fs.mkdirSync(resolverDir, { recursive: true });
|
|
1533
1619
|
let generated = 0;
|
|
1534
1620
|
for (const file of mdFiles) {
|
|
@@ -1546,8 +1632,26 @@ function runGenerateAppCode(appPath) {
|
|
|
1546
1632
|
console.log(` scaffolded ${path.relative(appPath, testFile)}`);
|
|
1547
1633
|
}
|
|
1548
1634
|
}
|
|
1549
|
-
console.log(`Scaffolded ${generated} resolver(s) for ${appName}`);
|
|
1550
|
-
|
|
1635
|
+
if (generated > 0) console.log(`Scaffolded ${generated} resolver(s) for ${appName}`);
|
|
1636
|
+
}
|
|
1637
|
+
function generateStoryTestStubs(appPath, appName) {
|
|
1638
|
+
const storyDocs = globSync(path.join(appPath, "docs/business-flow/*/story/*.md"));
|
|
1639
|
+
let generated = 0;
|
|
1640
|
+
for (const storyDocPath of storyDocs) {
|
|
1641
|
+
const testCases = parseTestCasesFromDoc(fs.readFileSync(storyDocPath, "utf-8"));
|
|
1642
|
+
if (testCases.length === 0) continue;
|
|
1643
|
+
const match = /\/docs\/business-flow\/([^/]+)\/story\/([^/]+)\.md$/.exec(storyDocPath);
|
|
1644
|
+
if (!match) continue;
|
|
1645
|
+
const [, flow, storyName] = match;
|
|
1646
|
+
const testDir = path.join(appPath, APP_PATHS.tests.stories, flow);
|
|
1647
|
+
const testFile = path.join(testDir, `${storyName}.test.ts`);
|
|
1648
|
+
if (fs.existsSync(testFile)) continue;
|
|
1649
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
1650
|
+
fs.writeFileSync(testFile, generateStoryTestStub(storyName, testCases));
|
|
1651
|
+
console.log(` scaffolded ${path.relative(appPath, testFile)}`);
|
|
1652
|
+
generated++;
|
|
1653
|
+
}
|
|
1654
|
+
if (generated > 0) console.log(`Scaffolded ${generated} story test(s) for ${appName}`);
|
|
1551
1655
|
}
|
|
1552
1656
|
//#endregion
|
|
1553
1657
|
//#region src/shared/uuidv5.ts
|
package/package.json
CHANGED
|
@@ -90,7 +90,10 @@ For each resolver, check whether its spec (`docs/resolver/*.md`) documents error
|
|
|
90
90
|
|
|
91
91
|
Do not directly mutate module-owned tables via Kysely — always use module commands.
|
|
92
92
|
|
|
93
|
+
After resolvers are done, implement the story integration test stubs generated in Phase 1b (`backend/src/tests/stories/`). Each stub has `it()` descriptions from the story doc's `## Test Cases`. Use the scaffolded GraphQL client and `inject("url")` / `inject("token")` to call resolvers. Run `pnpm test:integration` and `pnpm erp-kit app sync-check` to verify.
|
|
94
|
+
|
|
93
95
|
> **Parallelize if possible:** Dispatch one agent per resolver. Each agent writes only to its own files:
|
|
96
|
+
>
|
|
94
97
|
> - `src/resolvers/<resolverName>.ts`
|
|
95
98
|
> - `src/executors/<resolverName>.ts`
|
|
96
99
|
>
|
|
@@ -99,16 +102,18 @@ Do not directly mutate module-owned tables via Kysely — always use module comm
|
|
|
99
102
|
### Phase 5: Generated Files
|
|
100
103
|
|
|
101
104
|
- **Kysely types** (`src/generated/kysely-tailordb.ts`) — Auto-generated by `pnpm generate` after deployment. Before deployment, create a minimal placeholder so the codebase typechecks.
|
|
102
|
-
- **Seed data** (`seed/`) — `exec.mjs` runner + `data/*.jsonl` (records) and `data/*.schema.ts` (validation).
|
|
105
|
+
- **Seed data** (`seed/`) — `exec.mjs` runner + `data/*.jsonl` (records) and `data/*.schema.ts` (validation).
|
|
106
|
+
1. **Module seed** — Run `pnpm erp-kit app generate seed -p <app-path>` to generate module-provided defaults (currencies, units, UoM categories, exchange rates). This writes JSONL files to `seed/data/`, skipping files that already exist.
|
|
107
|
+
2. **App-specific seed** — Manually create seed records for permissions, roles, test users, and domain-specific data. Seeded users must have concrete permission keys required by the wired modules.
|
|
103
108
|
|
|
104
109
|
### Phase 6: Deploy Backend & Next Steps
|
|
105
110
|
|
|
106
111
|
Frontend implementation requires a deployed backend (for GraphQL schema generation). Prompt the user to:
|
|
107
112
|
|
|
108
|
-
1. Create a workspace and configure `.env` (including `TAILOR_PLATFORM_WORKSPACE_ID`)
|
|
109
|
-
2. Run `pnpm deploy` and `pnpm generate`
|
|
110
|
-
3. Run `pnpm seed` if seed data was created
|
|
111
|
-
4. Retrieve OAuth2 client ID via `tailor-sdk oauth2client get default --json` for frontend `.env`
|
|
113
|
+
1. Create a workspace via `tailor-sdk workspace create --name <NAME> --region <us-west|asia-northeast>` and configure `.env` (including `TAILOR_PLATFORM_WORKSPACE_ID`)
|
|
114
|
+
2. Run `pnpm run deploy` and `pnpm run generate`
|
|
115
|
+
3. Run `pnpm run seed` if seed data was created
|
|
116
|
+
4. Retrieve OAuth2 client ID via `tailor-sdk oauth2client get default --json --env-file-if-exists .env` for frontend `.env`
|
|
112
117
|
|
|
113
118
|
Wait for the user to confirm deployment is complete before proceeding.
|
|
114
119
|
|
|
@@ -63,7 +63,7 @@ cd <APP_ROOT>/frontend && pnpm lint && pnpm typecheck && pnpm build
|
|
|
63
63
|
erp-kit app sync-check -p <APP_ROOT>/..
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Report pass/fail for each check. `sync-check` detects missing resolver implementations
|
|
66
|
+
Report pass/fail for each check. `sync-check` detects missing resolver implementations, orphaned docs, and story doc ↔ integration test case mismatches, so groups A-C agents can skip file-existence checks and focus on content parity.
|
|
67
67
|
|
|
68
68
|
## Step 3: Aggregate Results
|
|
69
69
|
|
|
@@ -31,35 +31,57 @@ Define shared context for all agents:
|
|
|
31
31
|
|
|
32
32
|
Verify at least `MODEL_DOCS`, `COMMAND_DOCS`, or `QUERY_DOCS` is non-empty. If no docs exist, stop with: "No docs found for module <MODULE_NAME>."
|
|
33
33
|
|
|
34
|
-
## Step 2: Dispatch Agents (parallelize
|
|
34
|
+
## Step 2: Dispatch Agents (parallelize ALL agents in a single message)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
Each agent receives: MODULE_NAME, all relevant doc/code/test file paths for its domain.
|
|
38
|
-
Each agent runs all parity perspectives (doc→code, error, doc→test) internally and returns: structured JSON per [references/impl-parity-report-format.md](references/impl-parity-report-format.md).
|
|
39
|
-
If a doc or code directory is empty, the agent reports "no files found" and skips.
|
|
36
|
+
Split each parity check into its own agent, then further split by file batches when there are many files. Target **~5 agents per domain** (model, command, query) for maximum parallelism. Launch **ALL agents in a single message** — do NOT wait for one domain to finish before starting another.
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
If a doc or code directory is empty, skip that agent entirely.
|
|
39
|
+
|
|
40
|
+
### Splitting Strategy
|
|
41
|
+
|
|
42
|
+
1. **Each parity check type = separate agent** (never combine different check types in one agent)
|
|
43
|
+
2. **File batching**: If a check has more than 5 doc files, split docs into batches of 3-5 files each. Each batch becomes its own agent running the same check type on a subset of files.
|
|
44
|
+
3. **Corresponding code/test files**: When batching by doc files, include only the matching code and test files for those specific docs (match by filename stem, e.g., `docs/commands/createFoo.md` → `command/createFoo.ts` + `command/createFoo.test.ts`).
|
|
45
|
+
|
|
46
|
+
### Agent Table
|
|
47
|
+
|
|
48
|
+
| Check Type | Domain | Prompt Template | Inputs per agent |
|
|
49
|
+
| ---------- | ------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
50
|
+
| M-1 | Model | [references/model-doc-code-parity.md](references/model-doc-code-parity.md) | MODEL_DOCS (batch), MODEL_CODE (matching) |
|
|
51
|
+
| C-1 | Command | [references/command-doc-code-parity.md](references/command-doc-code-parity.md) | COMMAND_DOCS (batch), COMMAND_CODE (matching) |
|
|
52
|
+
| C-2 | Command | [references/command-error-implementation-parity.md](references/command-error-implementation-parity.md) | COMMAND_DOCS (batch), COMMAND_CODE (matching), ERROR_DEFS |
|
|
53
|
+
| C-3 | Command | [references/command-doc-test-parity.md](references/command-doc-test-parity.md) | COMMAND_DOCS (batch), COMMAND_TEST_CODE (matching) |
|
|
54
|
+
| Q-1 | Query | [references/query-doc-code-parity.md](references/query-doc-code-parity.md) | QUERY_DOCS (batch), QUERY_CODE (matching) |
|
|
55
|
+
| Q-2 | Query | [references/query-error-implementation-parity.md](references/query-error-implementation-parity.md) | QUERY_DOCS (batch), QUERY_CODE (matching), ERROR_DEFS |
|
|
56
|
+
| Q-3 | Query | [references/query-doc-test-parity.md](references/query-doc-test-parity.md) | QUERY_DOCS (batch), QUERY_TEST_CODE (matching) |
|
|
57
|
+
|
|
58
|
+
### Batching Example
|
|
59
|
+
|
|
60
|
+
If a module has 8 command docs: split into 3 batches (3+3+2). Each batch spawns 3 agents (C-1, C-2, C-3) → 9 command agents total. If it has 4 command docs: no batching needed, 3 agents (C-1, C-2, C-3).
|
|
61
|
+
|
|
62
|
+
For model docs: if 6 models → 2 batches (3+3) → 2 agents (M-1 × 2). If 3 models → 1 agent.
|
|
63
|
+
|
|
64
|
+
### Agent Dispatch
|
|
46
65
|
|
|
47
66
|
For each agent:
|
|
48
67
|
|
|
49
|
-
1. Read
|
|
68
|
+
1. Read the prompt template file for that check type
|
|
50
69
|
2. Replace `{{MODULE_NAME}}` with the resolved module name
|
|
51
|
-
3. Replace `{{MODEL_DOCS}}`, `{{COMMAND_DOCS}}`, `{{QUERY_DOCS}}`, `{{MODEL_CODE}}`, `{{COMMAND_CODE}}`, `{{QUERY_CODE}}`, `{{COMMAND_TEST_CODE}}`, `{{QUERY_TEST_CODE}}`, `{{ERROR_DEFS}}` with the actual file paths
|
|
52
|
-
4.
|
|
70
|
+
3. Replace template placeholders (`{{MODEL_DOCS}}`, `{{COMMAND_DOCS}}`, `{{QUERY_DOCS}}`, `{{MODEL_CODE}}`, `{{COMMAND_CODE}}`, `{{QUERY_CODE}}`, `{{COMMAND_TEST_CODE}}`, `{{QUERY_TEST_CODE}}`, `{{ERROR_DEFS}}`) with the actual file paths **for this batch only**
|
|
71
|
+
4. Dispatch the agent with the filled prompt
|
|
72
|
+
|
|
73
|
+
**IMPORTANT**: Launch ALL agents across ALL domains in a single parallel message. Do not serialize by domain.
|
|
53
74
|
|
|
54
75
|
## Step 3: Aggregate Results
|
|
55
76
|
|
|
56
77
|
After ALL agents return:
|
|
57
78
|
|
|
58
79
|
1. Collect the JSON results from each agent
|
|
59
|
-
2. Merge
|
|
60
|
-
3. Merge all `
|
|
61
|
-
4.
|
|
62
|
-
5.
|
|
80
|
+
2. **Merge batches**: If a check type was split across multiple batches (e.g., C-1 batch 1 + C-1 batch 2), merge their `gaps[]` and `inconsistencies[]` into a single result per check type
|
|
81
|
+
3. Merge all `gaps[]` arrays across all check types into a single list
|
|
82
|
+
4. Merge all `inconsistencies[]` arrays into a single list
|
|
83
|
+
5. Deduplicate: if two gaps share the same `source + target + check`, keep only one
|
|
84
|
+
6. Calculate totals across all summaries
|
|
63
85
|
|
|
64
86
|
## Step 4: Severity Validation
|
|
65
87
|
|
|
@@ -14,12 +14,19 @@ describe("runInitModule", () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it("creates module directory", () => {
|
|
17
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-module-test-"));
|
|
18
|
+
const exitCode = runInitModule("my-module", tmpDir);
|
|
19
|
+
expect(exitCode).toBe(0);
|
|
20
|
+
expect(fs.existsSync(path.join(tmpDir, "my-module"))).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("succeeds if module directory already exists", () => {
|
|
17
24
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-module-test-"));
|
|
18
25
|
const moduleDir = path.join(tmpDir, "my-module");
|
|
19
26
|
fs.mkdirSync(moduleDir, { recursive: true });
|
|
20
27
|
|
|
21
28
|
const exitCode = runInitModule("my-module", tmpDir);
|
|
22
|
-
expect(exitCode).toBe(
|
|
29
|
+
expect(exitCode).toBe(0);
|
|
23
30
|
});
|
|
24
31
|
});
|
|
25
32
|
|
|
@@ -32,12 +39,19 @@ describe("runInitApp", () => {
|
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
|
|
35
|
-
it("
|
|
42
|
+
it("creates app directory", () => {
|
|
43
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-app-test-"));
|
|
44
|
+
const exitCode = runInitApp("my-app", tmpDir);
|
|
45
|
+
expect(exitCode).toBe(0);
|
|
46
|
+
expect(fs.existsSync(path.join(tmpDir, "my-app"))).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("succeeds if app directory already exists", () => {
|
|
36
50
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-app-test-"));
|
|
37
51
|
const appDir = path.join(tmpDir, "my-app");
|
|
38
52
|
fs.mkdirSync(appDir, { recursive: true });
|
|
39
53
|
|
|
40
54
|
const exitCode = runInitApp("my-app", tmpDir);
|
|
41
|
-
expect(exitCode).toBe(
|
|
55
|
+
expect(exitCode).toBe(0);
|
|
42
56
|
});
|
|
43
57
|
});
|
|
@@ -5,12 +5,6 @@ import { MODULE_SCHEMAS, APP_COMPOSE_SCHEMAS } from "../schemas";
|
|
|
5
5
|
|
|
6
6
|
export function runInitModule(name: string, dir: string): number {
|
|
7
7
|
const moduleDir = path.resolve(dir, name);
|
|
8
|
-
|
|
9
|
-
if (fs.existsSync(moduleDir)) {
|
|
10
|
-
console.error(`Directory already exists: ${moduleDir}`);
|
|
11
|
-
return 1;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
8
|
fs.mkdirSync(moduleDir, { recursive: true });
|
|
15
9
|
return 0;
|
|
16
10
|
}
|
|
@@ -40,12 +34,6 @@ export async function runInitModuleWithReadme(
|
|
|
40
34
|
|
|
41
35
|
export function runInitApp(name: string, dir: string): number {
|
|
42
36
|
const appDir = path.resolve(dir, name);
|
|
43
|
-
|
|
44
|
-
if (fs.existsSync(appDir)) {
|
|
45
|
-
console.error(`Directory already exists: ${appDir}`);
|
|
46
|
-
return 1;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
37
|
fs.mkdirSync(appDir, { recursive: true });
|
|
50
38
|
return 0;
|
|
51
39
|
}
|
|
@@ -2,7 +2,8 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import {
|
|
3
3
|
moduleCategories,
|
|
4
4
|
appComposeCategories,
|
|
5
|
-
|
|
5
|
+
moduleTestCaseCategories,
|
|
6
|
+
appTestCaseCategories,
|
|
6
7
|
buildCheckTargets,
|
|
7
8
|
} from "./discovery";
|
|
8
9
|
|
|
@@ -35,15 +36,24 @@ describe("appComposeCategories", () => {
|
|
|
35
36
|
});
|
|
36
37
|
});
|
|
37
38
|
|
|
38
|
-
describe("
|
|
39
|
+
describe("moduleTestCaseCategories", () => {
|
|
39
40
|
it("produces command and query test case categories", () => {
|
|
40
|
-
const cats =
|
|
41
|
+
const cats = moduleTestCaseCategories("modules");
|
|
41
42
|
expect(cats).toHaveLength(2);
|
|
42
43
|
expect(cats[0].testDir).toBe("command");
|
|
43
44
|
expect(cats[1].testDir).toBe("query");
|
|
44
45
|
});
|
|
45
46
|
});
|
|
46
47
|
|
|
48
|
+
describe("appTestCaseCategories", () => {
|
|
49
|
+
it("produces story test case category with correct pattern", () => {
|
|
50
|
+
const cats = appTestCaseCategories("apps");
|
|
51
|
+
expect(cats.name).toBe("story-test-case");
|
|
52
|
+
expect(cats.docPattern).toBe("apps/*/docs/business-flow/*/story/*.md");
|
|
53
|
+
expect(cats.testDir).toBe("backend/src/tests/stories");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
47
57
|
describe("buildCheckTargets", () => {
|
|
48
58
|
it("builds module check targets", () => {
|
|
49
59
|
const targets = buildCheckTargets({ modulesRoot: "modules" });
|
|
@@ -52,7 +52,15 @@ export function appComposeCategories(root: string): CategoryConfig[] {
|
|
|
52
52
|
];
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function
|
|
55
|
+
export function appTestCaseCategories(root: string): TestCaseCategoryConfig {
|
|
56
|
+
return {
|
|
57
|
+
name: "story-test-case",
|
|
58
|
+
docPattern: `${root}/*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.docs.story}/*.md`,
|
|
59
|
+
testDir: APP_PATHS.tests.stories,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function moduleTestCaseCategories(root: string): TestCaseCategoryConfig[] {
|
|
56
64
|
return [
|
|
57
65
|
{
|
|
58
66
|
name: "command-test-case",
|
|
@@ -94,7 +102,7 @@ export function buildCheckTargets(config: {
|
|
|
94
102
|
schemaKey: "business-flow",
|
|
95
103
|
},
|
|
96
104
|
{
|
|
97
|
-
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.
|
|
105
|
+
glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.businessFlow}/*/${APP_PATHS.docs.story}/*.md`,
|
|
98
106
|
schemaKey: "story",
|
|
99
107
|
},
|
|
100
108
|
{ glob: `${a}/[a-zA-Z]*/${APP_PATHS.docs.screen}/*.md`, schemaKey: "screen" },
|
|
@@ -11,12 +11,14 @@ export const MODULE_PATHS = {
|
|
|
11
11
|
} as const;
|
|
12
12
|
|
|
13
13
|
export const APP_PATHS = {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
tests: {
|
|
15
|
+
stories: "backend/src/tests/stories",
|
|
16
|
+
},
|
|
16
17
|
docs: {
|
|
17
18
|
resolver: "docs/resolver",
|
|
18
19
|
actors: "docs/actors",
|
|
19
20
|
businessFlow: "docs/business-flow",
|
|
21
|
+
story: "story",
|
|
20
22
|
screen: "docs/screen",
|
|
21
23
|
},
|
|
22
24
|
} as const;
|