@yss123/cage-cli 0.2.0 → 0.3.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/README.md +47 -3
- package/bin/cage.js +5 -0
- package/bin/create-cage-app.js +5 -0
- package/dist/analyze.d.ts +16 -0
- package/dist/analyze.js +18 -2
- package/dist/analyze.js.map +1 -1
- package/dist/baseline.d.ts +8 -0
- package/dist/baseline.js +13 -0
- package/dist/baseline.js.map +1 -1
- package/dist/bootstrap.d.ts +20 -0
- package/dist/bootstrap.js +75 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +49 -5
- package/dist/budget.js.map +1 -1
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.js +133 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/config.d.ts +31 -2
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +14 -0
- package/dist/context.js +35 -2
- package/dist/context.js.map +1 -1
- package/dist/create-prompt.d.ts +7 -0
- package/dist/create-prompt.js +12 -0
- package/dist/create-prompt.js.map +1 -1
- package/dist/create.d.ts +21 -1
- package/dist/create.js +23 -1
- package/dist/create.js.map +1 -1
- package/dist/derive.d.ts +23 -0
- package/dist/derive.js +40 -0
- package/dist/derive.js.map +1 -1
- package/dist/dev.d.ts +6 -0
- package/dist/dev.js +11 -0
- package/dist/dev.js.map +1 -1
- package/dist/doctor.d.ts +98 -0
- package/dist/doctor.js +93 -0
- package/dist/doctor.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -1
- package/dist/findings.d.ts +27 -0
- package/dist/findings.js +20 -0
- package/dist/findings.js.map +1 -1
- package/dist/gen/contracts.d.ts +28 -0
- package/dist/gen/contracts.js +52 -12
- package/dist/gen/contracts.js.map +1 -1
- package/dist/gen/index.d.ts +26 -0
- package/dist/gen/index.js +69 -1
- package/dist/gen/index.js.map +1 -1
- package/dist/gen/zod-code.d.ts +42 -0
- package/dist/gen/zod-code.js +178 -16
- package/dist/gen/zod-code.js.map +1 -1
- package/dist/graph-approvals.d.ts +60 -0
- package/dist/graph-approvals.js +80 -0
- package/dist/graph-approvals.js.map +1 -0
- package/dist/graph-business.d.ts +135 -0
- package/dist/graph-business.js +404 -0
- package/dist/graph-business.js.map +1 -0
- package/dist/graph-command.d.ts +17 -0
- package/dist/graph-command.js +21 -0
- package/dist/graph-command.js.map +1 -1
- package/dist/graph-model.d.ts +44 -0
- package/dist/graph-model.js +36 -3
- package/dist/graph-model.js.map +1 -1
- package/dist/graph-presentation.d.ts +16 -0
- package/dist/graph-presentation.js +10 -1
- package/dist/graph-presentation.js.map +1 -1
- package/dist/graph-query.d.ts +95 -0
- package/dist/graph-query.js +62 -0
- package/dist/graph-query.js.map +1 -1
- package/dist/graph-relations.d.ts +20 -0
- package/dist/graph-relations.js +34 -4
- package/dist/graph-relations.js.map +1 -1
- package/dist/graph-search.d.ts +35 -0
- package/dist/graph-search.js +36 -0
- package/dist/graph-search.js.map +1 -1
- package/dist/graph-snapshot.d.ts +26 -0
- package/dist/graph-snapshot.js +30 -1
- package/dist/graph-snapshot.js.map +1 -1
- package/dist/graph.d.ts +13 -2
- package/dist/graph.js +59 -4
- package/dist/graph.js.map +1 -1
- package/dist/impact.d.ts +50 -0
- package/dist/impact.js +62 -2
- package/dist/impact.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +12 -0
- package/dist/init.js +15 -0
- package/dist/init.js.map +1 -1
- package/dist/load.d.ts +10 -0
- package/dist/load.js +15 -0
- package/dist/load.js.map +1 -1
- package/dist/main.d.ts +6 -0
- package/dist/main.js +93 -5
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +12 -0
- package/dist/migrate.js +17 -0
- package/dist/migrate.js.map +1 -1
- package/dist/ontology.d.ts +67 -2
- package/dist/ontology.js +89 -2
- package/dist/ontology.js.map +1 -1
- package/dist/process-rules.d.ts +21 -0
- package/dist/process-rules.js +100 -0
- package/dist/process-rules.js.map +1 -0
- package/dist/process.d.ts +32 -0
- package/dist/process.js +32 -0
- package/dist/process.js.map +1 -1
- package/dist/project-structure.d.ts +5 -0
- package/dist/project-structure.js +10 -0
- package/dist/project-structure.js.map +1 -1
- package/dist/registration.d.ts +16 -0
- package/dist/registration.js +56 -0
- package/dist/registration.js.map +1 -0
- package/dist/rules.d.ts +52 -0
- package/dist/rules.js +58 -0
- package/dist/rules.js.map +1 -1
- package/dist/runtime-diagnostics.d.ts +27 -0
- package/dist/runtime-diagnostics.js +60 -0
- package/dist/runtime-diagnostics.js.map +1 -0
- package/dist/snapshots.d.ts +40 -0
- package/dist/snapshots.js +62 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/static-check.d.ts +33 -0
- package/dist/static-check.js +37 -1
- package/dist/static-check.js.map +1 -1
- package/dist/sync.d.ts +11 -0
- package/dist/sync.js +65 -8
- package/dist/sync.js.map +1 -1
- package/dist/upgrade.d.ts +16 -0
- package/dist/upgrade.js +21 -0
- package/dist/upgrade.js.map +1 -1
- package/dist/verify.d.ts +14 -0
- package/dist/verify.js +19 -0
- package/dist/verify.js.map +1 -1
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -1
- package/graph-ui/app.js +321 -27
- package/graph-ui/approval-flow.js +165 -0
- package/graph-ui/business.css +985 -0
- package/graph-ui/business.js +549 -0
- package/graph-ui/flowchart-interaction.js +177 -0
- package/graph-ui/flowchart.js +1059 -0
- package/graph-ui/graph-approvals.js +79 -0
- package/graph-ui/graph-business.js +403 -0
- package/graph-ui/graph-model.js +36 -3
- package/graph-ui/graph-relations.js +34 -4
- package/graph-ui/graph-search.js +36 -0
- package/graph-ui/index.html +26 -12
- package/graph-ui/model.js +28 -0
- package/graph-ui/relations.js +4 -0
- package/graph-ui/structure.js +44 -0
- package/graph-ui/style.css +12 -0
- package/package.json +6 -4
- package/templates/app/.dockerignore +2 -0
- package/templates/app/.env.example +10 -0
- package/templates/app/AGENTS.md +49 -9
- package/templates/app/README.md +4 -1
- package/templates/app/_gitignore +1 -0
- package/templates/app/apps/api/package.json +2 -2
- package/templates/app/apps/api/src/main.ts +5 -1
- package/templates/app/apps/api/src/worker.ts +3 -0
- package/templates/app/apps/web/index.html +1 -0
- package/templates/app/apps/web/package.json +7 -3
- package/templates/app/apps/web/src/app/app.tsx +122 -12
- package/templates/app/apps/web/src/app/styles/global.css +88 -8
- package/templates/app/apps/web/src/app/use-session.ts +43 -0
- package/templates/app/apps/web/src/app/workspace-layout.tsx +58 -19
- package/templates/app/apps/web/src/main.tsx +5 -0
- package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
- package/templates/app/apps/web/src/modules/approval/index.ts +4 -0
- package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
- package/templates/app/apps/web/src/modules/auth/index.ts +4 -0
- package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
- package/templates/app/apps/web/src/modules/inventory/index.ts +4 -0
- package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
- package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
- package/templates/app/apps/web/src/modules/purchase/index.ts +5 -0
- package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
- package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/app/apps/web/src/shared/hooks/use-command.ts +13 -0
- package/templates/app/apps/web/src/shared/lib/error-message.ts +9 -0
- package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/app/apps/web/src/shared/ui/notice.tsx +7 -0
- package/templates/app/apps/web/src/shared/ui/page-heading.tsx +7 -0
- package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/app/apps/web/vite.config.ts +5 -0
- package/templates/app/cage.config.json +9 -0
- package/templates/app/db/migrations/0002_draft.sql +12 -0
- package/templates/app/db/migrations/0003_draft.sql +8 -0
- package/templates/app/deploy/nginx.conf +52 -0
- package/templates/app/docs/ai/README.md +21 -0
- package/templates/app/docs/ai/architecture.md +26 -0
- package/templates/app/docs/ai/commenting.md +203 -0
- package/templates/app/docs/ai/diagnostics.md +80 -0
- package/templates/app/docs/ai/files.md +93 -0
- package/templates/app/docs/ai/intelligence.md +348 -0
- package/templates/app/docs/ai/ontology-context.md +59 -4
- package/templates/app/docs/ai/primitives.md +33 -0
- package/templates/app/docs/ai/project-structure.md +8 -3
- package/templates/app/docs/ai/purchase-example.md +16 -2
- package/templates/app/docs/ai/recipes.md +9 -1
- package/templates/app/docs/ai/routing.md +86 -0
- package/templates/app/docs/ai/troubleshooting.md +5 -0
- package/templates/app/docs/ai/workflow.md +24 -11
- package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/app/docs/errors/CAGE-APPR-001.md +7 -6
- package/templates/app/docs/errors/CAGE-APPR-002.md +2 -2
- package/templates/app/docs/errors/CAGE-APPR-003.md +1 -1
- package/templates/app/docs/errors/CAGE-APPR-004.md +4 -4
- package/templates/app/docs/errors/CAGE-APPR-005.md +1 -1
- package/templates/app/docs/errors/CAGE-APPR-006.md +12 -6
- package/templates/app/docs/errors/CAGE-APPR-007.md +3 -3
- package/templates/app/docs/errors/CAGE-APPR-010.md +5 -5
- package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/app/docs/errors/CAGE-AUTH-001.md +1 -1
- package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/app/docs/errors/CAGE-BUDGET-001.md +1 -1
- package/templates/app/docs/errors/CAGE-BUDGET-002.md +1 -1
- package/templates/app/docs/errors/CAGE-BUDGET-003.md +1 -1
- package/templates/app/docs/errors/CAGE-CMD-002.md +1 -1
- package/templates/app/docs/errors/CAGE-CMD-003.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-001.md +3 -3
- package/templates/app/docs/errors/CAGE-CONN-002.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-003.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-004.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-005.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-006.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-007.md +6 -6
- package/templates/app/docs/errors/CAGE-CONN-008.md +5 -5
- package/templates/app/docs/errors/CAGE-CONN-009.md +6 -6
- package/templates/app/docs/errors/CAGE-CONN-010.md +6 -6
- package/templates/app/docs/errors/CAGE-CONN-011.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-012.md +1 -1
- package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/app/docs/errors/CAGE-CREATE-001.md +10 -9
- package/templates/app/docs/errors/CAGE-DECL-001.md +2 -2
- package/templates/app/docs/errors/CAGE-DECL-002.md +7 -6
- package/templates/app/docs/errors/CAGE-DECL-003.md +1 -1
- package/templates/app/docs/errors/CAGE-DECL-004.md +1 -1
- package/templates/app/docs/errors/CAGE-DEP-001.md +2 -2
- package/templates/app/docs/errors/CAGE-DEP-002.md +1 -1
- package/templates/app/docs/errors/CAGE-DEP-003.md +2 -2
- package/templates/app/docs/errors/CAGE-DEP-004.md +1 -1
- package/templates/app/docs/errors/CAGE-DEP-005.md +1 -1
- package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/app/docs/errors/CAGE-DLQ-001.md +2 -2
- package/templates/app/docs/errors/CAGE-ENV-001.md +4 -4
- package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/app/docs/errors/CAGE-EVENT-001.md +1 -1
- package/templates/app/docs/errors/CAGE-EVENT-002.md +7 -7
- package/templates/app/docs/errors/CAGE-FIELD-001.md +2 -2
- package/templates/app/docs/errors/CAGE-FIELD-002.md +1 -1
- package/templates/app/docs/errors/CAGE-FIELD-003.md +1 -1
- package/templates/app/docs/errors/CAGE-FIELD-004.md +1 -1
- package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/app/docs/errors/CAGE-GEN-001.md +2 -2
- package/templates/app/docs/errors/CAGE-GEN-002.md +1 -1
- package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/app/docs/errors/CAGE-GRANT-001.md +3 -3
- package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
- package/templates/app/docs/errors/CAGE-GRANT-003.md +7 -6
- package/templates/app/docs/errors/CAGE-IMPACT-001.md +2 -2
- package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/app/docs/errors/CAGE-INIT-001.md +1 -1
- package/templates/app/docs/errors/CAGE-INIT-002.md +1 -1
- package/templates/app/docs/errors/CAGE-INIT-003.md +2 -2
- package/templates/app/docs/errors/CAGE-INIT-004.md +1 -1
- package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/app/docs/errors/CAGE-JOB-001.md +1 -1
- package/templates/app/docs/errors/CAGE-JOB-002.md +1 -1
- package/templates/app/docs/errors/CAGE-JOB-003.md +1 -1
- package/templates/app/docs/errors/CAGE-LINT-001.md +1 -1
- package/templates/app/docs/errors/CAGE-MIG-001.md +1 -1
- package/templates/app/docs/errors/CAGE-MIG-002.md +1 -1
- package/templates/app/docs/errors/CAGE-MIG-005.md +1 -1
- package/templates/app/docs/errors/CAGE-NAME-001.md +1 -1
- package/templates/app/docs/errors/CAGE-NAME-002.md +1 -1
- package/templates/app/docs/errors/CAGE-NAME-003.md +3 -3
- package/templates/app/docs/errors/CAGE-NAME-004.md +1 -1
- package/templates/app/docs/errors/CAGE-NAME-005.md +1 -1
- package/templates/app/docs/errors/CAGE-NAME-006.md +1 -1
- package/templates/app/docs/errors/CAGE-ORG-001.md +7 -6
- package/templates/app/docs/errors/CAGE-PAIR-002.md +6 -5
- package/templates/app/docs/errors/CAGE-QUERY-001.md +1 -1
- package/templates/app/docs/errors/CAGE-QUERY-002.md +2 -2
- package/templates/app/docs/errors/CAGE-QUERY-003.md +7 -6
- package/templates/app/docs/errors/CAGE-REACT-001.md +3 -3
- package/templates/app/docs/errors/CAGE-REACT-002.md +1 -1
- package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/app/docs/errors/CAGE-READS-001.md +9 -6
- package/templates/app/docs/errors/CAGE-REG-001.md +13 -12
- package/templates/app/docs/errors/CAGE-REG-002.md +2 -1
- package/templates/app/docs/errors/CAGE-REG-003.md +1 -1
- package/templates/app/docs/errors/CAGE-REL-001.md +14 -14
- package/templates/app/docs/errors/CAGE-ROUTE-001.md +7 -6
- package/templates/app/docs/errors/CAGE-SCOPE-001.md +1 -1
- package/templates/app/docs/errors/CAGE-SCOPE-002.md +2 -2
- package/templates/app/docs/errors/CAGE-SECRET-001.md +2 -2
- package/templates/app/docs/errors/CAGE-SECRET-002.md +1 -1
- package/templates/app/docs/errors/CAGE-SENS-001.md +5 -5
- package/templates/app/docs/errors/CAGE-SQL-001.md +1 -1
- package/templates/app/docs/errors/CAGE-SQL-002.md +1 -1
- package/templates/app/docs/errors/CAGE-STATE-001.md +3 -3
- package/templates/app/docs/errors/CAGE-STATE-002.md +1 -1
- package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
- package/templates/app/docs/errors/CAGE-STATE-004.md +1 -1
- package/templates/app/docs/errors/CAGE-STATE-005.md +3 -2
- package/templates/app/docs/errors/CAGE-STATE-010.md +5 -5
- package/templates/app/docs/errors/CAGE-STATE-011.md +5 -5
- package/templates/app/docs/errors/CAGE-STRUCT-001.md +1 -1
- package/templates/app/docs/errors/CAGE-STRUCT-002.md +1 -1
- package/templates/app/docs/errors/CAGE-SYNC-001.md +3 -2
- package/templates/app/docs/errors/CAGE-TEST-001.md +1 -1
- package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/app/docs/errors/CAGE-UNSAFE-001.md +3 -2
- package/templates/app/docs/errors/CAGE-UPGRADE-001.md +2 -2
- package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/app/docs/errors/README.md +50 -0
- package/templates/app/package.json +3 -3
- package/templates/app/packages/contracts/package.json +1 -1
- package/templates/app/packages/contracts/src/aggregates/dept/index.ts +10 -10
- package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +5 -5
- package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
- package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
- package/templates/app/packages/contracts/src/aggregates/role/index.ts +15 -15
- package/templates/app/packages/contracts/src/aggregates/user/index.ts +16 -16
- package/templates/app/packages/contracts/src/index.ts +7 -1
- package/templates/app/packages/contracts/src/queries/index.ts +2 -2
- package/templates/app/packages/domain/package.json +5 -4
- package/templates/app/packages/domain/src/index.ts +4 -0
- package/templates/app/packages/domain/src/integrations/erp.ts +15 -0
- package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/app/packages/domain/src/modules/inventory/index.ts +1 -0
- package/templates/app/packages/domain/src/modules/inventory/inventory.ts +12 -0
- package/templates/app/packages/domain/src/modules/purchase/approvals.ts +22 -1
- package/templates/app/packages/domain/src/modules/purchase/index.ts +1 -0
- package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/app/packages/domain/src/modules/purchase/jobs.ts +5 -0
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
- package/templates/app/packages/domain/src/modules/purchase/queries.ts +5 -0
- package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +6 -0
- package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/.dockerignore +2 -0
- package/templates/blank/.env.example +10 -0
- package/templates/blank/AGENTS.md +49 -9
- package/templates/blank/README.md +4 -1
- package/templates/blank/_gitignore +1 -0
- package/templates/blank/apps/api/package.json +1 -1
- package/templates/blank/apps/api/src/main.ts +4 -1
- package/templates/blank/apps/api/src/worker.ts +2 -0
- package/templates/blank/apps/web/index.html +1 -0
- package/templates/blank/apps/web/package.json +7 -3
- package/templates/blank/apps/web/src/app/app.tsx +80 -18
- package/templates/blank/apps/web/src/app/styles/global.css +90 -0
- package/templates/blank/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/apps/web/src/app/workspace-layout.tsx +30 -5
- package/templates/blank/apps/web/src/main.tsx +5 -0
- package/templates/blank/apps/web/src/modules/auth/index.ts +4 -0
- package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +18 -1
- package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
- package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
- package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
- package/templates/blank/apps/web/src/modules/workspace/index.ts +4 -0
- package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +17 -0
- package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
- package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/apps/web/src/shared/ui/brand.tsx +10 -2
- package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/apps/web/vite.config.ts +5 -0
- package/templates/blank/deploy/nginx.conf +52 -0
- package/templates/blank/docs/ai/README.md +21 -0
- package/templates/blank/docs/ai/architecture.md +26 -0
- package/templates/blank/docs/ai/commenting.md +203 -0
- package/templates/blank/docs/ai/diagnostics.md +80 -0
- package/templates/blank/docs/ai/files.md +93 -0
- package/templates/blank/docs/ai/intelligence.md +348 -0
- package/templates/blank/docs/ai/ontology-context.md +59 -4
- package/templates/blank/docs/ai/primitives.md +33 -0
- package/templates/blank/docs/ai/project-structure.md +8 -3
- package/templates/blank/docs/ai/purchase-example.md +16 -2
- package/templates/blank/docs/ai/recipes.md +9 -1
- package/templates/blank/docs/ai/routing.md +86 -0
- package/templates/blank/docs/ai/troubleshooting.md +5 -0
- package/templates/blank/docs/ai/workflow.md +24 -11
- package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/blank/docs/errors/CAGE-APPR-001.md +7 -6
- package/templates/blank/docs/errors/CAGE-APPR-002.md +2 -2
- package/templates/blank/docs/errors/CAGE-APPR-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-APPR-004.md +4 -4
- package/templates/blank/docs/errors/CAGE-APPR-005.md +1 -1
- package/templates/blank/docs/errors/CAGE-APPR-006.md +12 -6
- package/templates/blank/docs/errors/CAGE-APPR-007.md +3 -3
- package/templates/blank/docs/errors/CAGE-APPR-010.md +5 -5
- package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-AUTH-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-BUDGET-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-BUDGET-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-CMD-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-CMD-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-001.md +3 -3
- package/templates/blank/docs/errors/CAGE-CONN-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-005.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-006.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-007.md +6 -6
- package/templates/blank/docs/errors/CAGE-CONN-008.md +5 -5
- package/templates/blank/docs/errors/CAGE-CONN-009.md +6 -6
- package/templates/blank/docs/errors/CAGE-CONN-010.md +6 -6
- package/templates/blank/docs/errors/CAGE-CONN-011.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-012.md +1 -1
- package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/blank/docs/errors/CAGE-CREATE-001.md +10 -9
- package/templates/blank/docs/errors/CAGE-DECL-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-DECL-002.md +7 -6
- package/templates/blank/docs/errors/CAGE-DECL-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-DECL-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-DEP-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-DEP-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-DEP-003.md +2 -2
- package/templates/blank/docs/errors/CAGE-DEP-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-DEP-005.md +1 -1
- package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-DLQ-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-ENV-001.md +4 -4
- package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-EVENT-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-EVENT-002.md +7 -7
- package/templates/blank/docs/errors/CAGE-FIELD-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-FIELD-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-FIELD-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-FIELD-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/blank/docs/errors/CAGE-GEN-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-GEN-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/blank/docs/errors/CAGE-GRANT-001.md +3 -3
- package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
- package/templates/blank/docs/errors/CAGE-GRANT-003.md +7 -6
- package/templates/blank/docs/errors/CAGE-IMPACT-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/blank/docs/errors/CAGE-INIT-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-INIT-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-INIT-003.md +2 -2
- package/templates/blank/docs/errors/CAGE-INIT-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/blank/docs/errors/CAGE-JOB-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-JOB-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-JOB-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-LINT-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-MIG-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-MIG-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-MIG-005.md +1 -1
- package/templates/blank/docs/errors/CAGE-NAME-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-NAME-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-NAME-003.md +3 -3
- package/templates/blank/docs/errors/CAGE-NAME-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-NAME-005.md +1 -1
- package/templates/blank/docs/errors/CAGE-NAME-006.md +1 -1
- package/templates/blank/docs/errors/CAGE-ORG-001.md +7 -6
- package/templates/blank/docs/errors/CAGE-PAIR-002.md +6 -5
- package/templates/blank/docs/errors/CAGE-QUERY-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-QUERY-002.md +2 -2
- package/templates/blank/docs/errors/CAGE-QUERY-003.md +7 -6
- package/templates/blank/docs/errors/CAGE-REACT-001.md +3 -3
- package/templates/blank/docs/errors/CAGE-REACT-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/blank/docs/errors/CAGE-READS-001.md +9 -6
- package/templates/blank/docs/errors/CAGE-REG-001.md +13 -12
- package/templates/blank/docs/errors/CAGE-REG-002.md +2 -1
- package/templates/blank/docs/errors/CAGE-REG-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-REL-001.md +14 -14
- package/templates/blank/docs/errors/CAGE-ROUTE-001.md +7 -6
- package/templates/blank/docs/errors/CAGE-SCOPE-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-SCOPE-002.md +2 -2
- package/templates/blank/docs/errors/CAGE-SECRET-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-SECRET-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-SENS-001.md +5 -5
- package/templates/blank/docs/errors/CAGE-SQL-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-SQL-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-STATE-001.md +3 -3
- package/templates/blank/docs/errors/CAGE-STATE-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
- package/templates/blank/docs/errors/CAGE-STATE-004.md +1 -1
- package/templates/blank/docs/errors/CAGE-STATE-005.md +3 -2
- package/templates/blank/docs/errors/CAGE-STATE-010.md +5 -5
- package/templates/blank/docs/errors/CAGE-STATE-011.md +5 -5
- package/templates/blank/docs/errors/CAGE-STRUCT-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-STRUCT-002.md +1 -1
- package/templates/blank/docs/errors/CAGE-SYNC-001.md +3 -2
- package/templates/blank/docs/errors/CAGE-TEST-001.md +1 -1
- package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +3 -2
- package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +2 -2
- package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/blank/docs/errors/README.md +50 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +5 -1
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +3 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +122 -12
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +88 -8
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +58 -19
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +4 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +4 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +4 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +13 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +9 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +7 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +7 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/docs/examples/purchase-admin/cage.config.json +9 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +10 -10
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +5 -5
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +15 -15
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +16 -16
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +7 -1
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +2 -2
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +4 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +15 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +1 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +12 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +22 -1
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +1 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +6 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/package.json +3 -3
- package/templates/blank/packages/contracts/package.json +1 -1
- package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +10 -10
- package/templates/blank/packages/contracts/src/aggregates/role/index.ts +15 -15
- package/templates/blank/packages/contracts/src/aggregates/user/index.ts +16 -16
- package/templates/blank/packages/contracts/src/index.ts +1 -1
- package/templates/blank/packages/contracts/src/queries/index.ts +1 -1
- package/templates/blank/packages/domain/package.json +5 -4
- package/templates/blank/packages/domain/src/index.ts +2 -1
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
两种模板使用同一规则:采购模板提供完整业务,空白模板保留认证和工作台。不要为小功能创建空目录;文件确实承担独立职责时再拆分。
|
|
6
6
|
|
|
7
|
+
目录表达代码归属,[详细中文注释规范](commenting.md)说明每个文件及接口如何被理解和使用。框架与脚手架应用的新建、修改源码都必须执行这份规范,职责说明和实现一起交付。
|
|
8
|
+
|
|
7
9
|
## 项目分工
|
|
8
10
|
|
|
9
11
|
```text
|
|
@@ -14,8 +16,9 @@
|
|
|
14
16
|
│ │ └─ worker.ts # 启动异步任务,按环境装配连接器 fake
|
|
15
17
|
│ └─ web/src/
|
|
16
18
|
│ ├─ main.tsx # 挂载 React、全局 Provider 和样式
|
|
17
|
-
│ ├─ app/ #
|
|
19
|
+
│ ├─ app/ # 会话恢复、URL 路由、布局、模块组合
|
|
18
20
|
│ │ ├─ app.tsx
|
|
21
|
+
│ │ ├─ use-session.ts # 会话恢复和 401 回跳,不把网络故障当成未登录
|
|
19
22
|
│ │ ├─ workspace-layout.tsx
|
|
20
23
|
│ │ └─ styles/global.css
|
|
21
24
|
│ ├─ modules/ # 按业务命名,一个模块内管理它的页面和交互
|
|
@@ -71,7 +74,7 @@
|
|
|
71
74
|
3. 需要驱动其他模块时,把 reaction 放在 `workflows/expense-xxx.ts`,从双方模块公开入口取声明。第三方接口放 `integrations/<系统名>.ts`,声明 hosts、schema、secret 名、outbound/inbound,不直接发网络请求。
|
|
72
75
|
4. 运行 `pnpm gen`,审查 `contracts/src/aggregates/expense/index.ts` 和迁移草稿。根 `@app/contracts` 自动导出 Expense API/类型。不要在 contracts 里手工建“报销 service”。
|
|
73
76
|
5. 在 `apps/web/src/modules/expense/pages/expense-list-page.tsx` 使用生成 hooks。新建表单放该模块 `components/expense-form.tsx`,模块专用 hooks 放自己的 `hooks`,专用接口封装按需放自己的 `api`,专用常量留在模块内。
|
|
74
|
-
6. 从前端模块 `index.ts` 导出页面,应用壳从 `../modules/expense`
|
|
77
|
+
6. 从前端模块 `index.ts` 导出页面,应用壳从 `../modules/expense` 引入并注册列表、详情 URL,通过 Outlet 放入工作台布局。导航用 Link/NavLink,筛选和分页用 useSearchParams;弹窗和提交状态留在页面,不把整个页面切换写成 useState。按[路由指南](routing.md)验收深链接、刷新、前进后退和登录回跳。
|
|
75
78
|
|
|
76
79
|
前后端可以有相同的业务模块名,但文件不混放:领域定义授权和行为,前端管理交互,通过生成契约连接。API 启动入口维持薄壳,普通业务无需新增 controller/service/repository。
|
|
77
80
|
|
|
@@ -107,7 +110,9 @@
|
|
|
107
110
|
- 入口只挂载或组合;页面主要描述页面流程。表单、表格或交互已承担独立职责时再抽取,避免一个大组件处理所有业务,也避免每个按钮都新建文件。
|
|
108
111
|
- 全局主题、reset、基础布局放 `app/styles`;业务专用样式与组件就近放置,可用 CSS Modules。不要把所有新增业务样式长期追加进一个全局文件。当前范例保留既有全局主题,结构调整不重新设计界面。
|
|
109
112
|
- 单测与被测代码相邻,使用 `*.test.ts(x)`。需要真实业务链路的集成用例与所属业务模块相邻;框架的测试发现递归查找,不必为它回到 src 根目录。
|
|
110
|
-
-
|
|
113
|
+
- 新建和修改的手写源码文件必须有中文职责、主要调用链与运行边界说明;模块入口也要说明公开职责。导出函数/类/声明、React 组件/hooks、接口及类型字段使用中文 JSDoc,复杂私有函数与关键分支解释具体步骤、原因和边界,详细要求见[注释规范](commenting.md)。
|
|
114
|
+
- 业务字段说明单位、格式、空值与来源;命令说明输入、权限、状态、读依赖、事件、事务与失败行为;页面说明 URL、数据加载、权限和错误交互;测试说明意图与覆盖边界;脚本说明前置条件、写入/覆盖等副作用。修改已有代码时同步补齐受影响的上下游注释,不能只更新当前实现。
|
|
115
|
+
- 注释必须准确、充分,不以“代码自解释”免除必要说明,不用每行语法翻译、注释字数或比例充数。生成注释从声明/生成器维护,已执行或已发布迁移不可因补注释而重写。不加无业务价值的防御分支和静默兜底;脚本使用 TypeScript,不新增 `.mjs`。
|
|
111
116
|
|
|
112
117
|
## 自动约束与整理已有项目
|
|
113
118
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
| `packages/domain/src/workflows/purchase-inventory.ts` | 同事务建锁、异步释放 | acquires/releases 的配对及 map 返回 null 的原因 |
|
|
15
15
|
| `packages/domain/src/modules/purchase/approvals.ts` | 启动/取消审批、条件步骤与选人 | routable、部门负责人、角色 code、结论命令 |
|
|
16
16
|
| `packages/domain/src/integrations/erp.ts` | 出站推单、成功回写、入站回调 | 白名单、secret 名、schema、幂等与 HMAC |
|
|
17
|
+
| `packages/domain/src/integrations/intelligence.ts` | 消费框架托管模型和本体助理 | Admin 配置连接,通用工具由框架生成 |
|
|
17
18
|
| `packages/domain/src/modules/purchase/queries.ts` | 按状态汇总 | reads、安全视图、命名参数 |
|
|
18
19
|
| `packages/domain/src/modules/purchase/jobs.ts` | 过期草稿取消 | reads/calls 和 job 调用身份 |
|
|
19
20
|
| `apps/api/src/main.ts`、`apps/api/src/worker.ts` | 如何启动框架与 worker | 保持薄装配,fake 只用于相应环境 |
|
|
@@ -27,7 +28,10 @@
|
|
|
27
28
|
```text
|
|
28
29
|
采购员新建 → draft
|
|
29
30
|
→ submit → pending_approval + OrderSubmitted(同事务提交)
|
|
30
|
-
→ worker 消费事件 →
|
|
31
|
+
→ worker 消费事件 → AI 材料预审
|
|
32
|
+
→ 材料不足:returnForChanges → draft,补充用途后重新提交、从头审核
|
|
33
|
+
→ 疑难材料:在本节点创建人工接管待办
|
|
34
|
+
→ 材料清楚:通过本节点,创建经理待办
|
|
31
35
|
→ 经理审批;金额 > 50000 时还有财务步骤
|
|
32
36
|
→ 流程完成 → 调用 approve
|
|
33
37
|
→ 职责分离、额度、库存检查
|
|
@@ -68,7 +72,11 @@ submit 返回成功只表示单据和事件已提交,不表示待办、ERP 或
|
|
|
68
72
|
| 对象 | 配置要点 |
|
|
69
73
|
| --- | --- |
|
|
70
74
|
| 采购员 | 创建/查看/提交/取消采购单等所需能力,所属部门,以及采购单数据范围 |
|
|
71
|
-
|
|
|
75
|
+
| 智能助理使用人 | 显式授予 `Sys.ai.use`;编辑用途还需 `PurchaseOrder.explainPurpose` |
|
|
76
|
+
| 模型管理者 | `Sys.ai.models.manage`;在 `/admin/#/models` 配置并启用 `main`,部署主密钥见[智能能力指南](intelligence.md) |
|
|
77
|
+
| 助理性格管理者 | `Sys.ai.personalities.manage`;在 `/admin/#/personalities` 编辑预设、自定义性格、设置默认并试聊 |
|
|
78
|
+
| AI 预审角色 | 创建 code 为 `purchase_ai_reviewer` 的角色,授予 `PurchaseOrder.read/returnForChanges` 及覆盖申请范围的数据权限;本例 AI 仅预审,不执行最终 approve |
|
|
79
|
+
| 经理 | `PurchaseOrder.read/approve/reject/returnForChanges`,适当数据范围,`approve` 的 `ceiling` 额度参数 |
|
|
72
80
|
| 部门 | 将采购员所属部门的负责人设为经理;不能为空 |
|
|
73
81
|
| 财务 | 角色 **code** 为 `finance`,给实际用户分配;配置审批所需权限、范围及额度 |
|
|
74
82
|
| 库存台账 | 预先登记与采购明细相同的 sku,数量满足演示检查 |
|
|
@@ -76,6 +84,12 @@ submit 返回成功只表示单据和事件已提交,不表示待办、ERP 或
|
|
|
76
84
|
|
|
77
85
|
经理与提单人必须是不同用户。配置“负责人”决定选谁;配置角色能力与范围决定此人能否完成结论命令,两者都需要。金额 **大于** 50,000 才追加财务步骤,恰好 50,000 不满足 gt 条件。
|
|
78
86
|
|
|
87
|
+
可分别准备“采购办公用品”、说明实际使用场景的完整用途、含“紧急采购”的用途,体验退回、通过本节点和转人工。真实模型的判定应按实际样例验收;故障默认转人工,不能当作正常审查通过。详情页显示历史理由、修改建议及审核轮次;用途编辑框的未保存内容会经 SDK 一起传给助理,服务端重新核对当前单据与权限。
|
|
88
|
+
|
|
89
|
+
拥有 `Sys.ai.use` 的用户在所有业务页面右下角都有助理入口,点击打开悬浮对话窗,收起后继续执行当前任务。工作台、采购列表/详情、库存和待办分别提供页面语义;列表带筛选与可见记录,详情带单据引用和未保存用途。应用壳只挂载一个 `AssistantScope`,业务页面通过 `AssistantPage` 注册上下文,所以站内切页保留对话,但下一条消息使用新页面的快照。不同页面拥有独立的 `AiPageContext` 身份,旧任务要求补充页面时不能提交新页面代替。登录页和独立的 `/admin/` 不挂载业务助理。
|
|
90
|
+
|
|
91
|
+
悬浮窗的“相处方式”选择器消费框架 `useAssistant` 的性格目录和切换接口。默认跟随 Admin 设置,也可为当前会话选择其他已启用性格;切换不清空对话,旧回复保留生成时的性格名称。采购范例没有单独的性格表或 Prompt 拼接逻辑,AI 审批继续使用原节点策略。
|
|
92
|
+
|
|
79
93
|
## 页面如何使用框架
|
|
80
94
|
|
|
81
95
|
采购页和库存页通过 `@app/contracts` 获取方法、快照类型和查询 hooks。命令成功后刷新相应列表;失败时按 code/domainCode 展示原因。只有允许 user 调用的命令才生成页面方法,因此审批通过应使用待办接口。
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
本页用于把用户的业务描述转成 Cage 项目的可执行修改。按需要读对应配方即可,不需要修改框架内部。
|
|
6
6
|
|
|
7
|
+
需要 AI 审批、业务助理、随页聊天、模型管理或性格配置时,先用 `cage capabilities` 查框架能力,再按[原生智能化指南](intelligence.md)接入。普通业务建模仍按下文声明聚合和命令;接入已有框架服务无需另建一套通用后端。
|
|
8
|
+
|
|
7
9
|
## 先把需求落到一张业务表
|
|
8
10
|
|
|
9
11
|
开始编码前,从用户需求或现有业务中确定以下信息。能从上下文确认的直接使用;真正缺失且影响实现的再询问,不要为技术细节反复让用户确认。
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
|
|
23
25
|
按[最小便笺业务](primitives.md)新增 `packages/domain/src/modules/<业务>/<对象>.ts`:字段、范围、不变量、create/update/archive 命令。采用唯一的导出名和必要的 `name` 覆盖,避免 index 的 `export *` 丢失重名符号。
|
|
24
26
|
|
|
25
|
-
从模块 index 到 domain 入口导出后运行 check/gen,审查迁移,再在 `apps/web/src/modules/<业务>` 使用生成 contracts
|
|
27
|
+
从模块 index 到 domain 入口导出后运行 check/gen,审查迁移,再在 `apps/web/src/modules/<业务>` 使用生成 contracts 做列表、详情、表单和操作按钮,经模块公开入口注册到 app 路由。列表和详情都有独立 URL,筛选/分页进入 query,按[浏览器配方](routing.md)检查导航。最后给角色授权并补图谱中文名。完整归属规则见[目录规范](project-structure.md)。不要手写后端增删改查路由、ORM 实体与 repository,也不要复制框架鉴权代码。
|
|
26
28
|
|
|
27
29
|
完成标准:授权用户能创建和修改,范围外数据不可见,归档后的允许行为符合业务要求,生成契约和迁移一致。没有审批需求时不必添加审批;没有外部系统时不必添加连接器。
|
|
28
30
|
|
|
@@ -42,6 +44,12 @@
|
|
|
42
44
|
|
|
43
45
|
完成标准:提交生成待办、正确的人审批、越权和自审批拒绝、取消能结束待办、资源配对完整。任意流程设计器、动态 JS 选人、转签/加签不属于当前现成能力,需要明确扩展范围。
|
|
44
46
|
|
|
47
|
+
## 加入 AI 审批或随页助理
|
|
48
|
+
|
|
49
|
+
先检查 domain 是否已经导出 `ai()`,再按需求修改已有声明或启用一次。AI 审批配置在业务模块的现有 `step` 内,填写 `kind: 'ai'`、审核策略、取证字段/查询与 `handoff`,由 `approval` 绑定自动执行角色和结论命令。业务助理使用框架生成的工具,前端通过 `useAssistant` 与 `useAiPageContext` 接入当前页面;悬浮窗、Markdown 和确认交互由应用实现。
|
|
50
|
+
|
|
51
|
+
模型地址、协议和密钥通过 `managedModel` 对应的 Admin 配置管理,性格也使用框架现有管理页。先完成系统迁移和必要授权,按[智能化指南](intelligence.md)的接入顺序、SDK 示例和验收步骤验证。分别说明框架支持、应用已启用和真实联调结果;空白模板中的参考代码不参与运行。
|
|
52
|
+
|
|
45
53
|
## 增加报表或复杂列表
|
|
46
54
|
|
|
47
55
|
普通分页和详情先使用生成的 list/get;汇总、联表等需求再添加 query。写清 reads、输入 schema,选择参数化 SQL 或 build;只查对应 safe 视图,不为“报表方便”切到管理员连接。
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 业务前端路由与浏览器验收
|
|
2
|
+
|
|
3
|
+
[返回学习入口](README.md) · [工程目录](project-structure.md) · [开发步骤](workflow.md)
|
|
4
|
+
|
|
5
|
+
多页面业务默认使用 React Router 的 BrowserRouter。列表、详情、报表等可独立访问的页面必须有 URL;在 app 中统一组合路由和工作台布局,页面从模块 index.ts 导出。useState 用于弹窗、未提交表单和按钮忙碌状态。筛选、分页和需要分享的选项使用 useSearchParams。
|
|
6
|
+
|
|
7
|
+
本页对应后续开发版本的模板改进;已发布的 0.2.0 项目需要按本页迁入路由实现,不能只升级依赖就认为旧页面已完成改造。框架包无需维护客户的页面地址。
|
|
8
|
+
|
|
9
|
+
## 模板中的可运行示例
|
|
10
|
+
|
|
11
|
+
| 页面 | 空白模板 | 采购模板 |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| 登录 | `/login` | `/login` |
|
|
14
|
+
| 工作台 | `/workspace` | `/workspace` |
|
|
15
|
+
| 列表 | `/directory/users?page=2` | `/procurement/orders?status=draft&page=2` |
|
|
16
|
+
| 详情 | `/directory/users/:id` | `/procurement/orders/:id` |
|
|
17
|
+
| 其他业务 | 按实际需求新增 | `/inventory`、`/approvals` |
|
|
18
|
+
| 404 | 未匹配页面显示“页面不存在” | 同左 |
|
|
19
|
+
|
|
20
|
+
`:id` 替换成真实记录 ID。空白模板的成员目录读取已有 User 组织模型,不注册额外业务、演示表或虚假数据;列表与详情均需要 User.read,数据范围由安全接口落实。采购待办的 businessKey 由 app 映射成采购详情链接,审批模块不直接导入采购模块。
|
|
21
|
+
|
|
22
|
+
在应用根目录运行 pnpm dev 后访问终端打印的 Web 地址。先在系统管理配置真实账号与权限,再从列表复制某条记录的详情 URL,用于刷新和新标签页测试。
|
|
23
|
+
|
|
24
|
+
## 新增一项业务页面
|
|
25
|
+
|
|
26
|
+
1. 在 `apps/web/src/modules/<业务>/pages` 编写列表、详情和表单,从模块 index.ts 导出。详情用 useParams 读取 ID,再用生成的 use对象(id) 获取记录;不要求先打开列表,也不从组件状态或上一页传来的对象直接认定记录存在。
|
|
27
|
+
2. 在 `apps/web/src/app/app.tsx` 注册列表与详情 Route。放在已有会话守卫和 WorkspaceLayout 之下,使页面通过 Outlet 渲染。新增实际页面时扩展路由表;不要再添加 tab/page useState 来选择整页。
|
|
28
|
+
3. 导航使用 Link / NavLink;完整页面地址可收藏、复制或新标签页打开。列表筛选和分页通过 useSearchParams 更新,刷新和前进后退恢复相应查询。
|
|
29
|
+
4. 需要 read 能力的页面用共享 RequireCapability 提供直接访问时的提示;服务端返回 FORBIDDEN 时显示权限提示,NOT_FOUND 显示“记录不存在,或不在当前可访问范围”。401 由会话回调进入登录。不要把 403 当成登录失效,也不要通过放宽读权限解决页面导航问题。
|
|
30
|
+
5. 用下面的浏览器配方验收,并报告通过、跳过与未执行。构建和 cage verify 通过,只证明其各自检查范围,不能据此宣称路由体验正确。
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// app 中的组合片段:页面通过所属模块的 index.ts 导出。
|
|
34
|
+
<Route element={<WorkspaceLayout onLogout={onLogout} />}>
|
|
35
|
+
<Route path="procurement/orders" element={<PurchaseOrdersPage />} />
|
|
36
|
+
<Route path="procurement/orders/:id" element={<PurchaseOrderDetailPage />} />
|
|
37
|
+
</Route>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
片段只展示路由与布局关系。实际代码参考本模板 app.tsx,保留会话守卫、页面 props 和能力提示。`cage/no-manual-routes` 限制手写后端业务 HTTP 路由,不禁止 React Router;前端导航不会生成能力或授予数据访问权。
|
|
41
|
+
|
|
42
|
+
## 登录后返回原地址
|
|
43
|
+
|
|
44
|
+
应用启动先 loadMe 恢复会话。未登录访问详情时,守卫使用 replace 导航到 `/login?returnTo=编码后的原路径`,包含 query 和 hash。登录完成再次 replace 回原页面,避免浏览器后退反复落入登录页。
|
|
45
|
+
|
|
46
|
+
`shared/lib/navigation.ts` 的 loginReturnTo 只接受应用内页面,排除外站、登录循环及 API/admin 等服务端入口;不要直接把用户提供的任意 returnTo 交给 location.href。网络错误显示重试界面并保留地址,只有 UNAUTHENTICATED 才要求重新登录。运行中会话过期同样保存当前 URL,并清除上一账号的查询缓存。
|
|
47
|
+
|
|
48
|
+
前端路由守卫只改善导航与提示。请求仍由 Cage HTTP 和内核检查会话、能力、租户、数据范围与掩码;直接请求接口必须得到相同约束。
|
|
49
|
+
|
|
50
|
+
## 与系统管理及部署共存
|
|
51
|
+
|
|
52
|
+
| 路径 | 所有者 |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `/login`、`/workspace`、客户业务页面 | React Router |
|
|
55
|
+
| `/admin`、`/admin/` 及其脚本/样式 | Cage 系统管理 |
|
|
56
|
+
| `/api/`、`/auth/`、`/hooks/` | Cage HTTP 接口 |
|
|
57
|
+
| `/assets/` | Vite 构建资源 |
|
|
58
|
+
|
|
59
|
+
进入 `/admin/` 使用普通 `<a href="/admin/">`,让浏览器请求独立管理入口;应用内部页面使用 Link。不要在 React 中注册覆盖 /admin 或 /auth 的页面。Vite 配置已代理 API、认证与管理请求,开发环境支持业务深链接刷新。
|
|
60
|
+
|
|
61
|
+
生产可选两种部署方式:
|
|
62
|
+
|
|
63
|
+
- **Cage 托管 Web**:API 启动时提供 webDir,标准入口读取 WEB_DIR;将其设置为 apps/web/dist 的绝对路径。模板 Dockerfile 已复制构建产物并设置 WEB_DIR=/app/web。浏览器 GET/HEAD 页面请求可回退到 index.html,React 决定详情或 404;API、管理和丢失资源返回各自错误,不应变成业务首页。
|
|
64
|
+
- **Nginx 托管 Web**:参考项目 `deploy/nginx.conf`,将 root 指向真实 dist,将 API/admin/auth/hooks 代理到 Cage;业务页面使用 try_files 回退到 index.html,/assets/ 缺失时直接 404。示例按 Nginx 与 API 在同一主机、API 端口 3000 编写;按部署拓扑修改上游。仅复制 dist 到没有 SPA 回退的静态服务器会导致详情刷新 404。
|
|
65
|
+
|
|
66
|
+
上线前用实际反向代理地址验收深链接。Vite 开发环境成功,不代表 Nginx、CDN 或生产容器已配置正确。
|
|
67
|
+
|
|
68
|
+
## 浏览器验收配方
|
|
69
|
+
|
|
70
|
+
准备一条有权读取的真实记录和两个测试账号:有 read 能力及范围的账号、没有该能力的账号。测试账号和记录在独立验收环境准备,不修改生产角色。
|
|
71
|
+
|
|
72
|
+
| 操作 | 预期结果 |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| 复制列表中某条详情 URL,在新标签页粘贴 | 直接加载对应记录,无需先访问列表 |
|
|
75
|
+
| 在详情页刷新 | URL 和记录保持一致 |
|
|
76
|
+
| 列表 → 详情 → 另一页面,再点浏览器后退、前进 | 地址、页面内容与导航高亮同步变化 |
|
|
77
|
+
| 改变列表筛选/分页,复制地址或刷新 | 条件与列表恢复,不返回工作台或第一页 |
|
|
78
|
+
| 未登录打开带 query/hash 的详情 URL | 进入登录;成功后回到原 URL,保留 query/hash |
|
|
79
|
+
| 在业务页使测试会话过期,再触发读取 | 进入登录;重新登录后回到原页面,旧账号缓存不残留 |
|
|
80
|
+
| 无 read 能力账号直接访问有效详情地址 | 显示权限提示,直接请求 API 仍为 403 |
|
|
81
|
+
| 有 read 能力但记录位于范围外 | 显示记录不可用,直接请求 API 为 404,不泄露记录是否存在 |
|
|
82
|
+
| 访问不存在的业务路径 | 显示应用 404,并有返回工作台入口 |
|
|
83
|
+
| 访问 /admin/,以及缺失的 API/JS/CSS | 管理入口独立可用;缺失接口或资源不返回业务 index.html |
|
|
84
|
+
| 在实际部署地址重复深链接和刷新步骤 | 正常加载,浏览器控制台无脚本 MIME 错误 |
|
|
85
|
+
|
|
86
|
+
验收记录写明模板、地址、操作和结果。模拟 API 的浏览器检查可以证明导航行为;真实权限、范围和数据库链路需要相应集成验收,二者分别报告。
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
先保留完整诊断的 code、源码位置、reason/fix、requestId 或 outboxId。检查所在阶段,再修复原因;不要通过改业务状态、给全局权限、注释约束或禁用 lint 消除现象。
|
|
6
6
|
|
|
7
|
+
先执行 `pnpm exec cage doctor` 查看各阶段证据;异步动作按 requestId/outboxId/业务对象用 `cage timeline` 关联实际执行记录。能力、范围、调用身份或额度不清楚时,有权诊断的管理员可使用 `cage explain`,不会执行目标命令。完整参数与权限见[诊断指南](diagnostics.md)。
|
|
8
|
+
|
|
7
9
|
## 按现象定位
|
|
8
10
|
|
|
9
11
|
| 现象 | 先查什么 | 常见原因 |
|
|
@@ -15,6 +17,9 @@
|
|
|
15
17
|
| 详情 404 | 记录 id、租户和数据范围 | 不存在或在范围外;不能仅凭 404 断言被删除 |
|
|
16
18
|
| 列表为空 | read 能力、范围与相应字段 | 默认本人范围、无 owner 字段或部门不匹配 |
|
|
17
19
|
| 电话看不到明文 | sensitive 标注、unmask 能力 | 默认掩码是正常安全行为 |
|
|
20
|
+
| 有明文能力但读取报 CAGE-AUDIT-001 | requestId、审计库可用性与权限 | 可靠审计未成功,框架拒绝交付结果 |
|
|
21
|
+
| 生产服务拒绝启动 | CAGE-ENV-002/003、Cookie 密钥与 bootstrap 参数 | 关键配置不合格,或试图在日常启动时隐式初始化 |
|
|
22
|
+
| 任务时间线有 CAGE-WORKER-002 | API/worker 版本、注册指纹和消费者清单 | 旧进程或必要消费者缺失,不能把 done 当作已执行 |
|
|
18
23
|
| 提交成功但无待办 | worker、outbox/死信、审批路由 | 未投递、缺审批人、没有匹配的绑定/路由 |
|
|
19
24
|
| 已批准但 ERP 单号未回写 | worker、同步记录、死信、环境/fake | 密钥/白名单/响应错误,或异步还未完成 |
|
|
20
25
|
| 已取消但锁未释放 | 释放事件、反应、死信 | 先前消息阻塞、map 条件不匹配或遗漏释放 |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 开发步骤与交付要求
|
|
2
2
|
|
|
3
|
-
[返回学习入口](README.md) · [范例导读](purchase-example.md)
|
|
3
|
+
[返回学习入口](README.md) · [范例导读](purchase-example.md) · [详细中文注释](commenting.md)
|
|
4
4
|
|
|
5
5
|
本页命令在**应用根目录**执行,除非注明“框架根目录”。使用项目安装的 CLI:`pnpm exec cage ...`。项目脚本可简写为 `pnpm gen / pnpm migrate / pnpm dev / pnpm verify`;不要假定机器已全局安装 cage。
|
|
6
6
|
|
|
@@ -18,39 +18,44 @@ pnpm build:app
|
|
|
18
18
|
pnpm gen
|
|
19
19
|
# 审查 db/migrations 中的迁移草稿,再执行:
|
|
20
20
|
pnpm migrate
|
|
21
|
+
# 迁移后显式初始化组织,目标是新的受限凭据文件;父目录需存在。
|
|
22
|
+
pnpm exec cage bootstrap --credentials-file .cage/admin-credentials.json
|
|
21
23
|
pnpm dev
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
`init` 自动创建独立账号与随机密码,填写 APP/READ/MIGRATE 连接和 Cookie 密钥,成功后删除文件中的管理员连接。三个连接使用同一数据库。已有 Cage 集群账号时复用原连接,不能重置其他应用的账号密码。生产环境可由平台直接提供账号连接,不必执行本地 init。
|
|
25
27
|
|
|
28
|
+
`bootstrap` 独立初始化组织,不自动授予业务能力。管理员凭据只进入新的受限文件,不进入服务控制台;已有用户时不重置。交付后移除凭据文件。日常 API 启动不初始化组织;生产缺少合格 Cookie 密钥会拒绝启动。具体文件权限与诊断用法见[能力发现与状态诊断](diagnostics.md)。
|
|
29
|
+
|
|
26
30
|
`.env.example` 是配置说明,`.env` 是本机私密配置,二者不混用。CLI 自动加载应用 `.env`,部署环境同名变量优先。API 和 worker 启动需重启后读取变更;不要输出整个 `.env` 排障。
|
|
27
31
|
|
|
28
32
|
框架仓库首次先在根目录 `pnpm install`、`pnpm build`,再进入 `examples/purchase-admin` 配置。`dev` 不自动执行迁移;生成新迁移后要审查并显式运行 migrate。
|
|
29
33
|
|
|
30
34
|
## 做一项业务修改
|
|
31
35
|
|
|
32
|
-
1. 读 AGENTS.md
|
|
33
|
-
2.
|
|
34
|
-
3. 在所属领域模块写字段、状态、不变量和命令输入;再实现 handler、事件、查询与审批。跨模块反应放 workflows,第三方协议放 integrations。从模块 index 到 domain 总入口逐层导出,避免跨文件 export
|
|
36
|
+
1. 读 AGENTS.md、[目录规范](project-structure.md)和[详细中文注释规范](commenting.md),确认需求落在领域模块、前端模块、组织配置还是框架。先 `pnpm exec cage context "需求关键词"`,按需 `graph search/inspect/path` 定位,确认候选入口后阅读对应源码、范例与测试;证据和边界见[本体上下文指南](ontology-context.md)。发现能力缺口先说明,不编造 API。
|
|
37
|
+
2. 涉及已存在业务含义变化时,**修改前**运行 `pnpm exec cage snapshot save before-change` 保存命名基线;也可使用真实 Git 提交或独立本体图文件。
|
|
38
|
+
3. 在所属领域模块写字段、状态、不变量和命令输入;再实现 handler、事件、查询与审批。跨模块反应放 workflows,第三方协议放 integrations。从模块 index 到 domain 总入口逐层导出,避免跨文件 export 名冲突。同步编写详细中文注释:文件职责与调用链、导出声明及输入字段、权限/状态/reads/事件/事务、关键步骤和失败边界;涉及已有行为时补齐受影响的上下游说明。
|
|
35
39
|
4. `pnpm exec cage check` 检查声明和图规则;`pnpm gen` 更新契约与迁移草稿。聚合和命令填写中文 `description`,需要覆盖时补 `cage.config.json` 的 `graph.labels`(如 `aggregate:Note`、`command:Note.archive`、`capability:Note.export`)。这些名称同时用于图谱和 `/admin` 授权界面;修改后重启 API。不重命名实际能力点来实现翻译。在图谱确认连接与资源生命周期。
|
|
36
40
|
5. 审查数据库变更,特别是非空字段、数据回填、删列和索引。已执行的迁移不可改写。需要落库时显式 `pnpm migrate`。
|
|
37
|
-
6. 页面和表单放 `apps/web/src/modules/<业务>`,从模块公开入口接入 app
|
|
38
|
-
7.
|
|
41
|
+
6. 页面和表单放 `apps/web/src/modules/<业务>`,从模块公开入口接入 app 的 URL 路由;依赖生成 contracts,处理失败结果。列表、详情等多页面使用 React Router,筛选和分页进入 URL;组件状态只管理页面内临时交互。新增能力由管理员授权,页面按钮可用 `useCan` 控制。按[路由与浏览器验收](routing.md)检查直达、刷新、前进后退和登录回跳。
|
|
42
|
+
7. 补足重要业务反例并运行相关验证;测试解释夹具目的、所保护的规则和覆盖边界。按注释规范审查本次 diff,核对页面、组件/hooks、类型字段、脚本副作用和恢复流程的说明是否完整准确。提交源声明、契约和审查过的迁移,报告跳过及未执行项。
|
|
39
43
|
|
|
40
44
|
### 如何保存和比较基线
|
|
41
45
|
|
|
42
46
|
```powershell
|
|
43
|
-
#
|
|
44
|
-
pnpm exec cage
|
|
45
|
-
Copy-Item .cage/ontology.json .cage/before-change.json
|
|
47
|
+
# 修改前执行;同名快照不会覆盖。
|
|
48
|
+
pnpm exec cage snapshot save before-change
|
|
46
49
|
# 修改 domain 后执行:
|
|
47
|
-
pnpm exec cage impact --
|
|
50
|
+
pnpm exec cage impact --snapshot before-change
|
|
48
51
|
# 或与真实可用的 Git 提交比较;下面的 main 应按仓库实际情况替换。
|
|
49
52
|
pnpm exec cage impact --base main
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
基线文件要保留到验收结束。影响分析用于找到相关命令、约束、审批、查询和候选测试,不能当作不需验证的证明。没有 Git 提交时不要为了让命令成功而擅自创建/推送远端。
|
|
53
56
|
|
|
57
|
+
`context` 和图谱查询只返回查询结果,不更新当前图文件或命名基线;`analyze/gen` 更新当前图。快照来源时间、版本与图指纹随报告保存。
|
|
58
|
+
|
|
54
59
|
## 常见需求的具体改法
|
|
55
60
|
|
|
56
61
|
| 需求 | 做法 | 必查项 |
|
|
@@ -82,6 +87,8 @@ if (!result.ok) {
|
|
|
82
87
|
|
|
83
88
|
对自定义 HTTP 协议能力使用 `@yss123/cage-client`;它负责会话、CSRF 和类型化结果。需让多个提交共享幂等键时,按当前客户端接口显式传递同一次业务操作的 key,并在页面阻止重复进行中的提交。生成契约的方法签名以 `packages/contracts/src` 为准,不假设每个命令方法都支持自定义 options。
|
|
84
89
|
|
|
90
|
+
生成方法最后的请求选项支持 `signal/timeoutMs/idempotencyKey`。底层返回 `CageResult`;`useCageCommand` 成功返回业务数据、失败抛出 `CageCommandError`,因此 mutation 的 `isSuccess` 表示业务成功。退出、401、切换账号时订阅 `client.subscribe` 取消用户查询并清除应用缓存,范例 `apps/web/src/app/use-session.ts` 展示了接法。
|
|
91
|
+
|
|
85
92
|
### 导入和导出属于业务页面
|
|
86
93
|
|
|
87
94
|
框架提供通用异步接口与任务查询,页面放在哪里由具体业务决定。
|
|
@@ -98,6 +105,9 @@ CSV 编码、限制、SDK 与完整接口见本项目自带的[业务页导入
|
|
|
98
105
|
| 命令 | 用途 | 主要输出 |
|
|
99
106
|
| --- | --- | --- |
|
|
100
107
|
| `pnpm exec cage analyze` | 抽取显式声明与源码位置 | `.cage/ontology.json` |
|
|
108
|
+
| `pnpm exec cage capabilities 关键词 --format json` | 查询当前安装版本的公开能力 | 公开签名、声明位置和学习入口 |
|
|
109
|
+
| `pnpm exec cage doctor` | 统一核对注册、生成、构建及可用运行证据 | pass / fail / unknown 与下一步;见[诊断指南](diagnostics.md) |
|
|
110
|
+
| `pnpm exec cage snapshot save 名称` | 保存不可覆盖的命名基线 | `.cage/snapshots`;配合 `impact --snapshot 名称` |
|
|
101
111
|
| `pnpm exec cage check` | 静态检查、注册表与图规则 | 终端 `code/at/reason/fix` |
|
|
102
112
|
| `pnpm exec cage graph` | 启动中文本体图谱 | 默认 `http://127.0.0.1:15418`,按终端地址访问 |
|
|
103
113
|
| `pnpm exec cage context "需求或节点"` | 开发前取得相关子图、原因、源码与候选验证 | 默认终端 Markdown;`--format json --out .cage/context.json` 保存结构化报告 |
|
|
@@ -117,8 +127,10 @@ CSV 编码、限制、SDK 与完整接口见本项目自带的[业务页导入
|
|
|
117
127
|
## 验证要与改动匹配
|
|
118
128
|
|
|
119
129
|
- 文档、文案、可逆的小改动:检查链接、格式、资料分发;不需要重复运行全套数据库测试。
|
|
130
|
+
- 所有源码变更:按[注释交付清单](commenting.md#交付前逐项核对)人工核对中文职责、接口与关键流程说明;静态检查不能替代注释准确性检查。仅补注释时不新增复述实现的测试、不改写已执行迁移。
|
|
120
131
|
- 命令/约束/反应变化:针对成功路径及真正的风险增加用例,如越权拒绝、额度边界、资源释放、同事务回滚。不要写只复述实现的测试。
|
|
121
132
|
- 领域结构变化:check、gen、生成一致性、类型检查;有数据库影响时在独立测试库验证迁移和读写。
|
|
133
|
+
- 页面或导航变化:构建后按[浏览器配方](routing.md)实际操作,包含深链接、新标签页、刷新、前进后退、登录回跳、无权限和 404。check/verify 不自动执行浏览器验收;未操作时明确报告未执行,不能写“页面功能完整”。
|
|
122
134
|
- 发布前:按项目要求执行完整 verify/build/test,核对分发包。没有执行的项目明确写出原因。
|
|
123
135
|
|
|
124
136
|
测试使用真实 PostgreSQL。`CAGE_TEST_DATABASE_URL` 供独立测试集群使用,测试工具会准备角色和临时数据库;不要指向业务/生产集群。没有设置时 testkit 可使用内嵌的真实 PostgreSQL,这与 dev 的固定已有库流程不同。
|
|
@@ -133,7 +145,8 @@ CSV 编码、限制、SDK 与完整接口见本项目自带的[业务页导入
|
|
|
133
145
|
先用 cage context 查询现有业务,必要时 graph inspect/path,确认候选与关系后阅读实现。
|
|
134
146
|
说明字段、状态、能力与范围、事件/资源的影响,再修改 domain、生成契约和迁移草稿、接入业务页面。
|
|
135
147
|
使用真实公开 API;不要手写业务路由、直接写表或新增本地数据库生命周期命令。
|
|
148
|
+
按 docs/ai/commenting.md 给新建和修改代码写详细中文注释,覆盖职责、API/字段、步骤、原因和边界,同步修正相关上下游说明。
|
|
136
149
|
按改动运行必要检查,报告通过/跳过/未执行项和需要的管理员配置。
|
|
137
150
|
```
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
交付说明至少包含行为变化、源文件、生成物/迁移、角色授权需求、详细中文注释覆盖的主要职责与边界、验证结果,以及尚未做的真实外部联调。注释未覆盖项如实说明,不能用聊天中的解释代替源码注释。遇到错误先修复根因;不把待办未生成、任务已接受或 fake 成功写成业务全部完成。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CAGE-AI-001:智能运行时声明无效
|
|
2
|
+
|
|
3
|
+
[返回错误码册](README.md) · [业务排错](../ai/troubleshooting.md)
|
|
4
|
+
|
|
5
|
+
> 本页由框架生成。正反例为局部声明或操作说明,完整写法见业务开发指南及本项目 domain。
|
|
6
|
+
|
|
7
|
+
## 何时出现
|
|
8
|
+
|
|
9
|
+
阶段:领域声明 / 模型与运行预算配置。
|
|
10
|
+
|
|
11
|
+
模型引用未配置、重复启用 AI 运行时,或上下文预算、重试、并发、超时、队列参数非法。
|
|
12
|
+
|
|
13
|
+
## 修复步骤
|
|
14
|
+
|
|
15
|
+
1. 在 domain 顶层导出一个 ai({ models, assistant }) 声明,审批 step 的 model 引用同名模型。
|
|
16
|
+
2. 预算与并发为正整数;maxModelRetries 为 0 至 8,context.maxTools 最多 128(包含通用工具)。并发最多 32,单次运行 timeoutMs 最多 300000。API 与 worker 使用相同声明和模型配置。
|
|
17
|
+
|
|
18
|
+
## 正例
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
ai({ models: { main: provider }, assistant: { model: 'main', limits: { maxSteps: 8 } } })
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 反例
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
ai({ models: {}, assistant: { model: 'missing', limits: { maxSteps: 0 } } })
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 修复后验证
|
|
31
|
+
|
|
32
|
+
重跑 cage check、迁移与相关测试,再以真实角色验证助理和审批;fake 成功不代表真实模型联调完成。
|
|
33
|
+
|
|
34
|
+
## 框架内的检查位置
|
|
35
|
+
|
|
36
|
+
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
37
|
+
|
|
38
|
+
- `packages/ai/src/index.ts:54`
|
|
39
|
+
- `packages/ai/src/index.ts:61`
|
|
40
|
+
- `packages/ai/src/index.ts:74`
|
|
41
|
+
- `packages/ai/src/index.ts:82`
|
|
42
|
+
- `packages/ai/src/index.ts:86`
|
|
43
|
+
- `packages/ai/src/index.ts:88`
|
|
44
|
+
- `packages/ai/src/index.ts:89`
|
|
45
|
+
- `packages/ai/src/index.ts:90`
|
|
46
|
+
- `packages/ai/src/index.ts:92`
|
|
47
|
+
- `packages/ai/src/index.ts:94`
|
|
48
|
+
- `packages/ai/src/index.ts:96`
|
|
49
|
+
- `packages/ai/src/index.ts:126`
|
|
50
|
+
- `packages/ai/src/index.ts:130`
|
|
51
|
+
- `packages/ai/src/index.ts:132`
|
|
52
|
+
|
|
53
|
+
实现片段(位置随框架版本更新):
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
/**
|
|
57
|
+
* 校验扩展唯一性与审批模型引用,无效配置以 CAGE-AI-001 拒绝。
|
|
58
|
+
*/
|
|
59
|
+
validate(registry: Registry): void;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
@@ -34,14 +34,15 @@ routable: ['managerName'] // 聚合没有该字段
|
|
|
34
34
|
|
|
35
35
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
36
36
|
|
|
37
|
-
- `packages/
|
|
37
|
+
- `packages/approval/src/route.ts:159`
|
|
38
|
+
- `packages/kernel/src/primitives/flow.ts:245`
|
|
38
39
|
|
|
39
40
|
实现片段(位置随框架版本更新):
|
|
40
41
|
|
|
41
42
|
```ts
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
for (const field of s.context.fields) if (!binding.agg.fields[field] || binding.agg.fields[field].isHidden)
|
|
44
|
+
throw declError('CAGE-APPR-001', `AI 上下文字段 ${field} 不存在或不可公开`);
|
|
45
|
+
for (const query of s.context.queries ?? []) if (!registry.queries.some(q => q.name === query))
|
|
46
|
+
throw declError('CAGE-REG-001', `AI 步骤引用的查询 ${query} 未导出`);
|
|
47
|
+
}
|
|
47
48
|
```
|
|
@@ -34,12 +34,12 @@ PurchaseOrder 的审批绑定使用 approvePurchaseOrder 命令
|
|
|
34
34
|
|
|
35
35
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
36
36
|
|
|
37
|
-
- `packages/kernel/src/primitives/flow.ts:
|
|
37
|
+
- `packages/kernel/src/primitives/flow.ts:248`
|
|
38
38
|
|
|
39
39
|
实现片段(位置随框架版本更新):
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
-
for (const c of [def.onApproved, def.onRejected]) {
|
|
42
|
+
for (const c of [def.onApproved, def.onRejected, ...(def.onReturned ? [def.onReturned] : [])]) {
|
|
43
43
|
if (c.agg !== agg) throw declError('CAGE-APPR-002', `审批结论命令必须属于 ${agg.name}`);
|
|
44
44
|
if (!c.invokedBy.includes('process')) {
|
|
45
45
|
throw declError('CAGE-APPR-003', `审批结论命令必须声明 invokedBy: 'process'`);
|
|
@@ -34,14 +34,14 @@ approval(..., { process: 'po-approval', ... }) 与 route('po-approval', ...)
|
|
|
34
34
|
|
|
35
35
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
36
36
|
|
|
37
|
-
- `packages/approval/src/bridge.ts:
|
|
37
|
+
- `packages/approval/src/bridge.ts:14`
|
|
38
38
|
|
|
39
39
|
实现片段(位置随框架版本更新):
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
const binding = k.registry.approvalByProcess(r.process);
|
|
43
43
|
if (!binding) throw new Error(`[CAGE-APPR-004] 没有流程 ${r.process} 的审批绑定`);
|
|
44
|
-
const cmd = r.outcome === 'approved' ? binding.a.onApproved : binding.a.onRejected;
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const cmd = r.outcome === 'approved' ? binding.a.onApproved : r.outcome === 'returned' ? binding.a.onReturned : binding.a.onRejected;
|
|
45
|
+
if (!cmd) throw new Error('[CAGE-APPR-006] 审批未绑定退回修改命令');
|
|
46
|
+
let ctx: Ctx;
|
|
47
47
|
```
|
|
@@ -34,14 +34,20 @@ route('po-approval', [])
|
|
|
34
34
|
|
|
35
35
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
36
36
|
|
|
37
|
-
- `packages/approval/src/
|
|
37
|
+
- `packages/approval/src/bridge.ts:16`
|
|
38
|
+
- `packages/approval/src/engine.ts:70`
|
|
39
|
+
- `packages/approval/src/route.ts:66`
|
|
40
|
+
- `packages/approval/src/route.ts:68`
|
|
41
|
+
- `packages/approval/src/route.ts:127`
|
|
42
|
+
- `packages/approval/src/route.ts:154`
|
|
43
|
+
- `packages/approval/src/route.ts:156`
|
|
38
44
|
|
|
39
45
|
实现片段(位置随框架版本更新):
|
|
40
46
|
|
|
41
47
|
```ts
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
48
|
+
const cmd = r.outcome === 'approved' ? binding.a.onApproved : r.outcome === 'returned' ? binding.a.onReturned : binding.a.onRejected;
|
|
49
|
+
if (!cmd) throw new Error('[CAGE-APPR-006] 审批未绑定退回修改命令');
|
|
50
|
+
let ctx: Ctx;
|
|
51
|
+
if (r.lastApprover) {
|
|
52
|
+
const user = await k.contextFor(r.lastApprover, r.tenantId);
|
|
47
53
|
```
|
|
@@ -37,14 +37,14 @@ deptLeader('deptId'):给该部门设置负责人;role('finance'):给实际
|
|
|
37
37
|
|
|
38
38
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
39
39
|
|
|
40
|
-
- `packages/approval/src/engine.ts:
|
|
40
|
+
- `packages/approval/src/engine.ts:81`
|
|
41
41
|
|
|
42
42
|
实现片段(位置随框架版本更新):
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
if (who.length === 0) {
|
|
46
|
-
throw new Error(`[CAGE-APPR-007] 流程 ${this.route.process} 第 ${index + 1} 步「${
|
|
46
|
+
throw new Error(`[CAGE-APPR-007] 流程 ${this.route.process} 第 ${index + 1} 步「${title}」找不到审批人,请在 /admin 配置部门负责人或角色`);
|
|
47
47
|
}
|
|
48
48
|
for (const assignee of new Set(who)) {
|
|
49
|
-
await tx.insertInto('flow.approval_task').values({ instance_id: instanceId, tenant_id: tenantId, step: index, title
|
|
49
|
+
await tx.insertInto('flow.approval_task').values({ instance_id: instanceId, tenant_id: tenantId, step: index, title, assignee }).execute();
|
|
50
50
|
```
|
|
@@ -34,15 +34,15 @@ approve 被 poApproval.onApproved 引用,或 acquireLock 被 lockOnApprove 引
|
|
|
34
34
|
|
|
35
35
|
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
36
36
|
|
|
37
|
-
- `packages/cli/src/rules.ts:
|
|
38
|
-
- `packages/cli/src/rules.ts:
|
|
37
|
+
- `packages/cli/src/rules.ts:175`
|
|
38
|
+
- `packages/cli/src/rules.ts:189`
|
|
39
39
|
|
|
40
40
|
实现片段(位置随框架版本更新):
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
43
|
|
|
44
44
|
/** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
/**
|
|
46
|
+
* 检查仅流程/外部可调用的命令是否有声明调用入口。
|
|
47
|
+
* @param g 当前图。
|
|
48
48
|
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# CAGE-AUDIT-001:可靠读取审计失败
|
|
2
|
+
|
|
3
|
+
[返回错误码册](README.md) · [业务排错](../ai/troubleshooting.md)
|
|
4
|
+
|
|
5
|
+
> 本页由框架生成。正反例为局部声明或操作说明,完整写法见业务开发指南及本项目 domain。
|
|
6
|
+
|
|
7
|
+
## 何时出现
|
|
8
|
+
|
|
9
|
+
阶段:安全读侧 / 查询。
|
|
10
|
+
|
|
11
|
+
敏感明文读取,或声明 audit.purpose 的查询,无法完成交付前的审计写入。请求拒绝交付结果。
|
|
12
|
+
|
|
13
|
+
## 修复步骤
|
|
14
|
+
|
|
15
|
+
1. 凭 requestId 检查审计存储、写账号权限和数据库可用性;修复后重新读取。
|
|
16
|
+
2. 不要吞掉审计异常、去除敏感声明或改用基表绕过审计。查询只声明目的,不把敏感输入放进目的文本。
|
|
17
|
+
|
|
18
|
+
## 正例
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
query('report', { reads: [Order], audit: { purpose: '月度核对' }, /* input/sql */ })
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 反例
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
审计写入失败后继续返回敏感明文
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 修复后验证
|
|
31
|
+
|
|
32
|
+
修复审计存储后重新读取,确认有权交付的数据与相应审计均完成。
|
|
33
|
+
|
|
34
|
+
## 框架内的检查位置
|
|
35
|
+
|
|
36
|
+
以下路径相对框架源码仓库,不是要求业务项目创建这些文件。当前项目先修业务声明、配置或授权;明确属于框架缺口时反馈错误码和脱敏上下文。
|
|
37
|
+
|
|
38
|
+
- `packages/kernel/src/read.ts:136`
|
|
39
|
+
- `packages/kernel/src/read.ts:137`
|
|
40
|
+
- `packages/kernel/src/read.ts:284`
|
|
41
|
+
- `packages/kernel/src/read.ts:285`
|
|
42
|
+
- `packages/kernel/src/transfer/index.ts:176`
|
|
43
|
+
- `packages/kernel/src/transfer/index.ts:177`
|
|
44
|
+
|
|
45
|
+
实现片段(位置随框架版本更新):
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
}); } catch {
|
|
49
|
+
this.k.log.error({ code: 'CAGE-AUDIT-001', aggregate: agg.name, kind, requestId: ctx.requestId }, '读取审计失败,未交付数据');
|
|
50
|
+
throw cageError('INTERNAL', { diagnostic: 'CAGE-AUDIT-001', phase: 'audit', operation: kind, retryable: true });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|