@lwelliott/cortex-cli 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/dist/cli/audit.d.ts +3 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +78 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/doc.d.ts +3 -0
- package/dist/cli/doc.d.ts.map +1 -0
- package/dist/cli/doc.js +291 -0
- package/dist/cli/doc.js.map +1 -0
- package/dist/cli/entity.d.ts +3 -0
- package/dist/cli/entity.d.ts.map +1 -0
- package/dist/cli/entity.js +135 -0
- package/dist/cli/entity.js.map +1 -0
- package/dist/cli/format-selector.d.ts +30 -0
- package/dist/cli/format-selector.d.ts.map +1 -0
- package/dist/cli/format-selector.js +101 -0
- package/dist/cli/format-selector.js.map +1 -0
- package/dist/cli/formatters/audit-formatter.d.ts +33 -0
- package/dist/cli/formatters/audit-formatter.d.ts.map +1 -0
- package/dist/cli/formatters/audit-formatter.js +204 -0
- package/dist/cli/formatters/audit-formatter.js.map +1 -0
- package/dist/cli/formatters/json.d.ts +10 -0
- package/dist/cli/formatters/json.d.ts.map +1 -0
- package/dist/cli/formatters/json.js +31 -0
- package/dist/cli/formatters/json.js.map +1 -0
- package/dist/cli/formatters/markdown.d.ts +12 -0
- package/dist/cli/formatters/markdown.d.ts.map +1 -0
- package/dist/cli/formatters/markdown.js +341 -0
- package/dist/cli/formatters/markdown.js.map +1 -0
- package/dist/cli/formatters/quiet.d.ts +15 -0
- package/dist/cli/formatters/quiet.d.ts.map +1 -0
- package/dist/cli/formatters/quiet.js +75 -0
- package/dist/cli/formatters/quiet.js.map +1 -0
- package/dist/cli/formatters/table.d.ts +11 -0
- package/dist/cli/formatters/table.d.ts.map +1 -0
- package/dist/cli/formatters/table.js +726 -0
- package/dist/cli/formatters/table.js.map +1 -0
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.d.ts.map +1 -0
- package/dist/cli/graph.js +209 -0
- package/dist/cli/graph.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +144 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/lesson.d.ts +3 -0
- package/dist/cli/lesson.d.ts.map +1 -0
- package/dist/cli/lesson.js +85 -0
- package/dist/cli/lesson.js.map +1 -0
- package/dist/cli/project-resolver.d.ts +17 -0
- package/dist/cli/project-resolver.d.ts.map +1 -0
- package/dist/cli/project-resolver.js +25 -0
- package/dist/cli/project-resolver.js.map +1 -0
- package/dist/cli/project.d.ts +12 -0
- package/dist/cli/project.d.ts.map +1 -0
- package/dist/cli/project.js +169 -0
- package/dist/cli/project.js.map +1 -0
- package/dist/cli/relation.d.ts +3 -0
- package/dist/cli/relation.d.ts.map +1 -0
- package/dist/cli/relation.js +128 -0
- package/dist/cli/relation.js.map +1 -0
- package/dist/cli/review.d.ts +3 -0
- package/dist/cli/review.d.ts.map +1 -0
- package/dist/cli/review.js +131 -0
- package/dist/cli/review.js.map +1 -0
- package/dist/cli/router.d.ts +38 -0
- package/dist/cli/router.d.ts.map +1 -0
- package/dist/cli/router.js +49 -0
- package/dist/cli/router.js.map +1 -0
- package/dist/cli/schema.d.ts +3 -0
- package/dist/cli/schema.d.ts.map +1 -0
- package/dist/cli/schema.js +94 -0
- package/dist/cli/schema.js.map +1 -0
- package/dist/cli/sprint.d.ts +12 -0
- package/dist/cli/sprint.d.ts.map +1 -0
- package/dist/cli/sprint.js +200 -0
- package/dist/cli/sprint.js.map +1 -0
- package/dist/cli/task.d.ts +12 -0
- package/dist/cli/task.d.ts.map +1 -0
- package/dist/cli/task.js +252 -0
- package/dist/cli/task.js.map +1 -0
- package/dist/cli/test-report.d.ts +3 -0
- package/dist/cli/test-report.d.ts.map +1 -0
- package/dist/cli/test-report.js +134 -0
- package/dist/cli/test-report.js.map +1 -0
- package/dist/cli/validate.d.ts +8 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +86 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/config/config.d.ts +18 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +70 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/registry.d.ts +52 -0
- package/dist/config/registry.d.ts.map +1 -0
- package/dist/config/registry.js +193 -0
- package/dist/config/registry.js.map +1 -0
- package/dist/config/resolver.d.ts +26 -0
- package/dist/config/resolver.d.ts.map +1 -0
- package/dist/config/resolver.js +87 -0
- package/dist/config/resolver.js.map +1 -0
- package/dist/db/builtin-schema-constants.d.ts +109 -0
- package/dist/db/builtin-schema-constants.d.ts.map +1 -0
- package/dist/db/builtin-schema-constants.js +32 -0
- package/dist/db/builtin-schema-constants.js.map +1 -0
- package/dist/db/connection.d.ts +34 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +140 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/generated/schema-types.d.ts +134 -0
- package/dist/db/generated/schema-types.d.ts.map +1 -0
- package/dist/db/generated/schema-types.js +31 -0
- package/dist/db/generated/schema-types.js.map +1 -0
- package/dist/db/locks.d.ts +106 -0
- package/dist/db/locks.d.ts.map +1 -0
- package/dist/db/locks.js +211 -0
- package/dist/db/locks.js.map +1 -0
- package/dist/db/migration.d.ts +65 -0
- package/dist/db/migration.d.ts.map +1 -0
- package/dist/db/migration.js +233 -0
- package/dist/db/migration.js.map +1 -0
- package/dist/db/retry.d.ts +26 -0
- package/dist/db/retry.d.ts.map +1 -0
- package/dist/db/retry.js +71 -0
- package/dist/db/retry.js.map +1 -0
- package/dist/db/schema.d.ts +21 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +830 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/models/common.d.ts +27 -0
- package/dist/models/common.d.ts.map +1 -0
- package/dist/models/common.js +4 -0
- package/dist/models/common.js.map +1 -0
- package/dist/models/document.d.ts +89 -0
- package/dist/models/document.d.ts.map +1 -0
- package/dist/models/document.js +5 -0
- package/dist/models/document.js.map +1 -0
- package/dist/models/entity-model.d.ts +30 -0
- package/dist/models/entity-model.d.ts.map +1 -0
- package/dist/models/entity-model.js +99 -0
- package/dist/models/entity-model.js.map +1 -0
- package/dist/models/entity.d.ts +88 -0
- package/dist/models/entity.d.ts.map +1 -0
- package/dist/models/entity.js +5 -0
- package/dist/models/entity.js.map +1 -0
- package/dist/models/graph-schema.d.ts +43 -0
- package/dist/models/graph-schema.d.ts.map +1 -0
- package/dist/models/graph-schema.js +76 -0
- package/dist/models/graph-schema.js.map +1 -0
- package/dist/models/project.d.ts +49 -0
- package/dist/models/project.d.ts.map +1 -0
- package/dist/models/project.js +18 -0
- package/dist/models/project.js.map +1 -0
- package/dist/models/relation.d.ts +35 -0
- package/dist/models/relation.d.ts.map +1 -0
- package/dist/models/relation.js +212 -0
- package/dist/models/relation.js.map +1 -0
- package/dist/models/review.d.ts +86 -0
- package/dist/models/review.d.ts.map +1 -0
- package/dist/models/review.js +5 -0
- package/dist/models/review.js.map +1 -0
- package/dist/models/sprint.d.ts +38 -0
- package/dist/models/sprint.d.ts.map +1 -0
- package/dist/models/sprint.js +4 -0
- package/dist/models/sprint.js.map +1 -0
- package/dist/models/task.d.ts +75 -0
- package/dist/models/task.d.ts.map +1 -0
- package/dist/models/task.js +4 -0
- package/dist/models/task.js.map +1 -0
- package/dist/models/validation.d.ts +25 -0
- package/dist/models/validation.d.ts.map +1 -0
- package/dist/models/validation.js +4 -0
- package/dist/models/validation.js.map +1 -0
- package/dist/services/audit-check-service.d.ts +16 -0
- package/dist/services/audit-check-service.d.ts.map +1 -0
- package/dist/services/audit-check-service.js +137 -0
- package/dist/services/audit-check-service.js.map +1 -0
- package/dist/services/audit-checks/dangling-relations-check.d.ts +7 -0
- package/dist/services/audit-checks/dangling-relations-check.d.ts.map +1 -0
- package/dist/services/audit-checks/dangling-relations-check.js +52 -0
- package/dist/services/audit-checks/dangling-relations-check.js.map +1 -0
- package/dist/services/audit-checks/duplicate-ids-check.d.ts +4 -0
- package/dist/services/audit-checks/duplicate-ids-check.d.ts.map +1 -0
- package/dist/services/audit-checks/duplicate-ids-check.js +49 -0
- package/dist/services/audit-checks/duplicate-ids-check.js.map +1 -0
- package/dist/services/audit-checks/fix-engine.d.ts +24 -0
- package/dist/services/audit-checks/fix-engine.d.ts.map +1 -0
- package/dist/services/audit-checks/fix-engine.js +114 -0
- package/dist/services/audit-checks/fix-engine.js.map +1 -0
- package/dist/services/audit-checks/fr-nfr-to-fs-nfs-check.d.ts +9 -0
- package/dist/services/audit-checks/fr-nfr-to-fs-nfs-check.d.ts.map +1 -0
- package/dist/services/audit-checks/fr-nfr-to-fs-nfs-check.js +56 -0
- package/dist/services/audit-checks/fr-nfr-to-fs-nfs-check.js.map +1 -0
- package/dist/services/audit-checks/fs-nfs-to-sad-ad-qa-check.d.ts +10 -0
- package/dist/services/audit-checks/fs-nfs-to-sad-ad-qa-check.d.ts.map +1 -0
- package/dist/services/audit-checks/fs-nfs-to-sad-ad-qa-check.js +57 -0
- package/dist/services/audit-checks/fs-nfs-to-sad-ad-qa-check.js.map +1 -0
- package/dist/services/audit-checks/fs-nfs-to-ts-check.d.ts +9 -0
- package/dist/services/audit-checks/fs-nfs-to-ts-check.d.ts.map +1 -0
- package/dist/services/audit-checks/fs-nfs-to-ts-check.js +56 -0
- package/dist/services/audit-checks/fs-nfs-to-ts-check.js.map +1 -0
- package/dist/services/audit-checks/inverse-consistency-check.d.ts +7 -0
- package/dist/services/audit-checks/inverse-consistency-check.d.ts.map +1 -0
- package/dist/services/audit-checks/inverse-consistency-check.js +54 -0
- package/dist/services/audit-checks/inverse-consistency-check.js.map +1 -0
- package/dist/services/audit-checks/mapping-check.d.ts +4 -0
- package/dist/services/audit-checks/mapping-check.d.ts.map +1 -0
- package/dist/services/audit-checks/mapping-check.js +74 -0
- package/dist/services/audit-checks/mapping-check.js.map +1 -0
- package/dist/services/audit-checks/orphan-documents-check.d.ts +9 -0
- package/dist/services/audit-checks/orphan-documents-check.d.ts.map +1 -0
- package/dist/services/audit-checks/orphan-documents-check.js +54 -0
- package/dist/services/audit-checks/orphan-documents-check.js.map +1 -0
- package/dist/services/audit-checks/orphan-entities-check.d.ts +4 -0
- package/dist/services/audit-checks/orphan-entities-check.d.ts.map +1 -0
- package/dist/services/audit-checks/orphan-entities-check.js +39 -0
- package/dist/services/audit-checks/orphan-entities-check.js.map +1 -0
- package/dist/services/audit-checks/sad-ad-qa-tc-to-src-check.d.ts +9 -0
- package/dist/services/audit-checks/sad-ad-qa-tc-to-src-check.d.ts.map +1 -0
- package/dist/services/audit-checks/sad-ad-qa-tc-to-src-check.js +56 -0
- package/dist/services/audit-checks/sad-ad-qa-tc-to-src-check.js.map +1 -0
- package/dist/services/audit-checks/sprint-consistency-check.d.ts +4 -0
- package/dist/services/audit-checks/sprint-consistency-check.d.ts.map +1 -0
- package/dist/services/audit-checks/sprint-consistency-check.js +80 -0
- package/dist/services/audit-checks/sprint-consistency-check.js.map +1 -0
- package/dist/services/audit-checks/src-filesystem-only-check.d.ts +10 -0
- package/dist/services/audit-checks/src-filesystem-only-check.d.ts.map +1 -0
- package/dist/services/audit-checks/src-filesystem-only-check.js +106 -0
- package/dist/services/audit-checks/src-filesystem-only-check.js.map +1 -0
- package/dist/services/audit-checks/ts-to-tc-check.d.ts +10 -0
- package/dist/services/audit-checks/ts-to-tc-check.d.ts.map +1 -0
- package/dist/services/audit-checks/ts-to-tc-check.js +58 -0
- package/dist/services/audit-checks/ts-to-tc-check.js.map +1 -0
- package/dist/services/audit-checks/type-mismatch-check.d.ts +4 -0
- package/dist/services/audit-checks/type-mismatch-check.d.ts.map +1 -0
- package/dist/services/audit-checks/type-mismatch-check.js +55 -0
- package/dist/services/audit-checks/type-mismatch-check.js.map +1 -0
- package/dist/services/audit-checks/types.d.ts +66 -0
- package/dist/services/audit-checks/types.d.ts.map +1 -0
- package/dist/services/audit-checks/types.js +30 -0
- package/dist/services/audit-checks/types.js.map +1 -0
- package/dist/services/audit-checks/us-to-fr-nfr-check.d.ts +9 -0
- package/dist/services/audit-checks/us-to-fr-nfr-check.d.ts.map +1 -0
- package/dist/services/audit-checks/us-to-fr-nfr-check.js +56 -0
- package/dist/services/audit-checks/us-to-fr-nfr-check.js.map +1 -0
- package/dist/services/doc-entity-mapping.d.ts +19 -0
- package/dist/services/doc-entity-mapping.d.ts.map +1 -0
- package/dist/services/doc-entity-mapping.js +35 -0
- package/dist/services/doc-entity-mapping.js.map +1 -0
- package/dist/services/document-service.d.ts +58 -0
- package/dist/services/document-service.d.ts.map +1 -0
- package/dist/services/document-service.js +409 -0
- package/dist/services/document-service.js.map +1 -0
- package/dist/services/graph-export-service.d.ts +12 -0
- package/dist/services/graph-export-service.d.ts.map +1 -0
- package/dist/services/graph-export-service.js +112 -0
- package/dist/services/graph-export-service.js.map +1 -0
- package/dist/services/graph-service.d.ts +21 -0
- package/dist/services/graph-service.d.ts.map +1 -0
- package/dist/services/graph-service.js +49 -0
- package/dist/services/graph-service.js.map +1 -0
- package/dist/services/graph-validation-service.d.ts +13 -0
- package/dist/services/graph-validation-service.d.ts.map +1 -0
- package/dist/services/graph-validation-service.js +171 -0
- package/dist/services/graph-validation-service.js.map +1 -0
- package/dist/services/project.d.ts +80 -0
- package/dist/services/project.d.ts.map +1 -0
- package/dist/services/project.js +256 -0
- package/dist/services/project.js.map +1 -0
- package/dist/services/review-service.d.ts +81 -0
- package/dist/services/review-service.d.ts.map +1 -0
- package/dist/services/review-service.js +242 -0
- package/dist/services/review-service.js.map +1 -0
- package/dist/services/schema-migration-service.d.ts +44 -0
- package/dist/services/schema-migration-service.d.ts.map +1 -0
- package/dist/services/schema-migration-service.js +894 -0
- package/dist/services/schema-migration-service.js.map +1 -0
- package/dist/services/sprint.d.ts +71 -0
- package/dist/services/sprint.d.ts.map +1 -0
- package/dist/services/sprint.js +238 -0
- package/dist/services/sprint.js.map +1 -0
- package/dist/services/stage-validator.d.ts +36 -0
- package/dist/services/stage-validator.d.ts.map +1 -0
- package/dist/services/stage-validator.js +78 -0
- package/dist/services/stage-validator.js.map +1 -0
- package/dist/services/task.d.ts +75 -0
- package/dist/services/task.d.ts.map +1 -0
- package/dist/services/task.js +487 -0
- package/dist/services/task.js.map +1 -0
- package/dist/services/validation.d.ts +24 -0
- package/dist/services/validation.d.ts.map +1 -0
- package/dist/services/validation.js +53 -0
- package/dist/services/validation.js.map +1 -0
- package/dist/state-machines/sprint-state.d.ts +25 -0
- package/dist/state-machines/sprint-state.d.ts.map +1 -0
- package/dist/state-machines/sprint-state.js +64 -0
- package/dist/state-machines/sprint-state.js.map +1 -0
- package/dist/state-machines/task-state.d.ts +31 -0
- package/dist/state-machines/task-state.d.ts.map +1 -0
- package/dist/state-machines/task-state.js +83 -0
- package/dist/state-machines/task-state.js.map +1 -0
- package/dist/utils/errors.d.ts +673 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +1447 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/format.d.ts +52 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +65 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/validators/board-integrity.d.ts +25 -0
- package/dist/validators/board-integrity.d.ts.map +1 -0
- package/dist/validators/board-integrity.js +102 -0
- package/dist/validators/board-integrity.js.map +1 -0
- package/dist/validators/board-shape.d.ts +13 -0
- package/dist/validators/board-shape.d.ts.map +1 -0
- package/dist/validators/board-shape.js +74 -0
- package/dist/validators/board-shape.js.map +1 -0
- package/dist/validators/owner-validator.d.ts +30 -0
- package/dist/validators/owner-validator.d.ts.map +1 -0
- package/dist/validators/owner-validator.js +70 -0
- package/dist/validators/owner-validator.js.map +1 -0
- package/dist/validators/spawn-legality.d.ts +19 -0
- package/dist/validators/spawn-legality.d.ts.map +1 -0
- package/dist/validators/spawn-legality.js +77 -0
- package/dist/validators/spawn-legality.js.map +1 -0
- package/dist/validators/state-field-checker.d.ts +8 -0
- package/dist/validators/state-field-checker.d.ts.map +1 -0
- package/dist/validators/state-field-checker.js +47 -0
- package/dist/validators/state-field-checker.js.map +1 -0
- package/dist/validators/state-field-recorder.d.ts +39 -0
- package/dist/validators/state-field-recorder.d.ts.map +1 -0
- package/dist/validators/state-field-recorder.js +62 -0
- package/dist/validators/state-field-recorder.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Spawn legality checker
|
|
3
|
+
// Validates spawn prerequisites: sprint phase, task state, role match
|
|
4
|
+
// Implements AD-0009: Validation as Read-Only Snapshot
|
|
5
|
+
// + FS-SS-006-0002 (validate spawn legality)
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.checkSpawnLegality = checkSpawnLegality;
|
|
8
|
+
const errors_1 = require("../utils/errors");
|
|
9
|
+
/**
|
|
10
|
+
* Check whether a spawn operation is legal.
|
|
11
|
+
*
|
|
12
|
+
* Requirements:
|
|
13
|
+
* - Sprint must be IN EXECUTION (ERR-SPAWN-SPRINT)
|
|
14
|
+
* - Task must be To Do or In Progress (ERR-SPAWN-STATE)
|
|
15
|
+
* - Role must match the required stage role (ERR-SPAWN-ROLE)
|
|
16
|
+
*
|
|
17
|
+
* @param db - Database connection (read-only)
|
|
18
|
+
* @param sprintId - Sprint ID
|
|
19
|
+
* @param taskId - Task ID to spawn from
|
|
20
|
+
* @param stage - The spawn stage (e.g. "analyst", "architect", "coder", "tester")
|
|
21
|
+
* @param role - The role that will own the spawned task
|
|
22
|
+
* @returns Spawn legality result
|
|
23
|
+
*/
|
|
24
|
+
function checkSpawnLegality(db, sprintId, taskId, stage, role) {
|
|
25
|
+
// Check sprint exists and is IN EXECUTION
|
|
26
|
+
const sprint = db.prepare('SELECT id, status FROM sprints WHERE id = ?').get(sprintId);
|
|
27
|
+
if (!sprint) {
|
|
28
|
+
throw new errors_1.SprintNotFoundError(sprintId);
|
|
29
|
+
}
|
|
30
|
+
if (sprint.status !== 'IN EXECUTION') {
|
|
31
|
+
return {
|
|
32
|
+
sprint_id: sprintId,
|
|
33
|
+
task_id: taskId,
|
|
34
|
+
isLegal: false,
|
|
35
|
+
verdict: 'ERR-SPAWN-SPRINT',
|
|
36
|
+
reason: `Sprint "${sprintId}" is "${sprint.status}", but spawn requires "IN EXECUTION"`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Check task exists and is To Do or In Progress (per FS-SS-006-0002)
|
|
40
|
+
const task = db.prepare('SELECT id, status FROM tasks WHERE id = ?').get(taskId);
|
|
41
|
+
if (!task) {
|
|
42
|
+
return {
|
|
43
|
+
sprint_id: sprintId,
|
|
44
|
+
task_id: taskId,
|
|
45
|
+
isLegal: false,
|
|
46
|
+
verdict: 'ERR-SPAWN-STATE',
|
|
47
|
+
reason: `Task "${taskId}" not found`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (task.status !== 'To Do' && task.status !== 'In Progress') {
|
|
51
|
+
return {
|
|
52
|
+
sprint_id: sprintId,
|
|
53
|
+
task_id: taskId,
|
|
54
|
+
isLegal: false,
|
|
55
|
+
verdict: 'ERR-SPAWN-STATE',
|
|
56
|
+
reason: `Task "${taskId}" is "${task.status}", but spawn requires "To Do" or "In Progress"`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Check role match
|
|
60
|
+
// The stage to role mapping: analyst→analyst, architect→architect, coder→coder, tester→tester
|
|
61
|
+
if (stage !== role) {
|
|
62
|
+
return {
|
|
63
|
+
sprint_id: sprintId,
|
|
64
|
+
task_id: taskId,
|
|
65
|
+
isLegal: false,
|
|
66
|
+
verdict: 'ERR-SPAWN-ROLE',
|
|
67
|
+
reason: `Spawn stage "${stage}" requires role "${stage}", but "${role}" was provided`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
sprint_id: sprintId,
|
|
72
|
+
task_id: taskId,
|
|
73
|
+
isLegal: true,
|
|
74
|
+
verdict: 'OK',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=spawn-legality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-legality.js","sourceRoot":"","sources":["../../src/validators/spawn-legality.ts"],"names":[],"mappings":";AAAA,yBAAyB;AACzB,sEAAsE;AACtE,uDAAuD;AACvD,6CAA6C;;AAqB7C,gDAqEC;AAtFD,4CAAsD;AAEtD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,kBAAkB,CAChC,EAAqB,EACrB,QAAgB,EAChB,MAAc,EACd,KAAa,EACb,IAAY;IAEZ,0CAA0C;IAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CACvB,6CAA6C,CAC9C,CAAC,GAAG,CAAC,QAAQ,CAA+C,CAAC;IAE9D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,4BAAmB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QACrC,OAAO;YACL,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,WAAW,QAAQ,SAAS,MAAM,CAAC,MAAM,sCAAsC;SACxF,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,2CAA2C,CAC5C,CAAC,GAAG,CAAC,MAAM,CAA+C,CAAC;IAE5D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,iBAAiB;YAC1B,MAAM,EAAE,SAAS,MAAM,aAAa;SACrC,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QAC7D,OAAO;YACL,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,iBAAiB;YAC1B,MAAM,EAAE,SAAS,MAAM,SAAS,IAAI,CAAC,MAAM,gDAAgD;SAC5F,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,8FAA8F;IAC9F,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,gBAAgB;YACzB,MAAM,EAAE,gBAAgB,KAAK,oBAAoB,KAAK,WAAW,IAAI,gBAAgB;SACtF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { ValidationIssue } from '../models/validation';
|
|
3
|
+
/**
|
|
4
|
+
* Check that tasks in each state have the expected context fields populated.
|
|
5
|
+
* Missing fields generate warning-level issues (not hard errors).
|
|
6
|
+
*/
|
|
7
|
+
export declare function checkRequiredFields(db: Database.Database, sprintId?: string): ValidationIssue[];
|
|
8
|
+
//# sourceMappingURL=state-field-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-field-checker.d.ts","sourceRoot":"","sources":["../../src/validators/state-field-checker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAgB5D;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,eAAe,EAAE,CAmCnB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// State field checker
|
|
3
|
+
// Validates that tasks in each state have the expected context fields populated
|
|
4
|
+
// Implements FS-SS-006-0003 (validate required fields per state)
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkRequiredFields = checkRequiredFields;
|
|
7
|
+
/**
|
|
8
|
+
* Define which fields are expected (recommended) for each task state.
|
|
9
|
+
* These are not hard errors — missing fields generate warnings.
|
|
10
|
+
*/
|
|
11
|
+
const EXPECTED_FIELDS = {
|
|
12
|
+
'Backlog': [],
|
|
13
|
+
'To Do': [],
|
|
14
|
+
'In Progress': [{ field: 'session_key', label: 'session_key' }],
|
|
15
|
+
'In Review': [{ field: 'owner', label: 'owner' }],
|
|
16
|
+
'Done': [{ field: 'completed_at', label: 'completed_at' }],
|
|
17
|
+
'Dropped': [],
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Check that tasks in each state have the expected context fields populated.
|
|
21
|
+
* Missing fields generate warning-level issues (not hard errors).
|
|
22
|
+
*/
|
|
23
|
+
function checkRequiredFields(db, sprintId) {
|
|
24
|
+
const issues = [];
|
|
25
|
+
const rows = db.prepare(`SELECT id, status, session_key, owner, completed_at
|
|
26
|
+
FROM tasks
|
|
27
|
+
WHERE status IN ('In Progress', 'In Review', 'Done')
|
|
28
|
+
AND removed_at IS NULL
|
|
29
|
+
${sprintId ? 'AND sprint_id = ?' : ''}`).all(...(sprintId ? [sprintId] : []));
|
|
30
|
+
for (const row of rows) {
|
|
31
|
+
const expected = EXPECTED_FIELDS[row.status] ?? [];
|
|
32
|
+
for (const { field, label } of expected) {
|
|
33
|
+
const value = row[field];
|
|
34
|
+
if (value === null || value === undefined || value === '') {
|
|
35
|
+
issues.push({
|
|
36
|
+
category: 'field',
|
|
37
|
+
severity: 'warning',
|
|
38
|
+
message: `Task "${row.id}" in "${row.status}" is missing expected field "${label}"`,
|
|
39
|
+
entity: row.id,
|
|
40
|
+
detail: `State "${row.status}" expects ${label} to be populated`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return issues;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=state-field-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-field-checker.js","sourceRoot":"","sources":["../../src/validators/state-field-checker.ts"],"names":[],"mappings":";AAAA,sBAAsB;AACtB,gFAAgF;AAChF,iEAAiE;;AAuBjE,kDAsCC;AAvDD;;;GAGG;AACH,MAAM,eAAe,GAAgE;IACnF,SAAS,EAAE,EAAE;IACb,OAAO,EAAE,EAAE;IACX,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IAC/D,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACjD,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAC1D,SAAS,EAAE,EAAE;CACd,CAAC;AAEF;;;GAGG;AACH,SAAgB,mBAAmB,CACjC,EAAqB,EACrB,QAAiB;IAEjB,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB;;;;OAIG,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAMlC,CAAC;IAEJ,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAEnD,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;YACxC,MAAM,KAAK,GAAI,GAA+B,CAAC,KAAK,CAAC,CAAC;YACtD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBAC1D,MAAM,CAAC,IAAI,CAAC;oBACV,QAAQ,EAAE,OAAO;oBACjB,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,gCAAgC,KAAK,GAAG;oBACnF,MAAM,EAAE,GAAG,CAAC,EAAE;oBACd,MAAM,EAAE,UAAU,GAAG,CAAC,MAAM,aAAa,KAAK,kBAAkB;iBACjE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { TaskStatus } from '../models/common';
|
|
3
|
+
/**
|
|
4
|
+
* Context fields that can be provided on a task move.
|
|
5
|
+
* — blocker removed per FS-SS-030-0004
|
|
6
|
+
* — reviewer renamed to owner, review_notes removed per FR-URD-034-0006
|
|
7
|
+
*/
|
|
8
|
+
export interface MoveContext {
|
|
9
|
+
session_key?: string;
|
|
10
|
+
owner?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute the timestamp updates and field values to record for a transition.
|
|
14
|
+
*
|
|
15
|
+
* State-specific rules:
|
|
16
|
+
* - In Progress: record session_key if provided, auto-set started_at
|
|
17
|
+
* - In Review: record owner if provided (tasks.owner column)
|
|
18
|
+
* - Done: auto-set completed_at
|
|
19
|
+
*
|
|
20
|
+
* Note: blocker context field removed per FS-SS-030-0004
|
|
21
|
+
* Note: reviewer renamed to owner, review_notes removed per FR-URD-034-0006
|
|
22
|
+
*
|
|
23
|
+
* Returns the partial row updates to apply to the task.
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeStateFields(current: TaskStatus, target: TaskStatus, context?: MoveContext): {
|
|
26
|
+
columns: string[];
|
|
27
|
+
values: unknown[];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Apply state-specific field updates to a task in the database.
|
|
31
|
+
*
|
|
32
|
+
* @param db - Database connection (within a transaction)
|
|
33
|
+
* @param taskId - The task to update
|
|
34
|
+
* @param target - Target state being moved to
|
|
35
|
+
* @param current - Current state
|
|
36
|
+
* @param context - Optional context fields
|
|
37
|
+
*/
|
|
38
|
+
export declare function recordStateFields(db: Database.Database, taskId: string, target: TaskStatus, current: TaskStatus, context?: MoveContext): void;
|
|
39
|
+
//# sourceMappingURL=state-field-recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-field-recorder.d.ts","sourceRoot":"","sources":["../../src/validators/state-field-recorder.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,WAAW,GACpB;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CA4B1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,UAAU,EACnB,OAAO,CAAC,EAAE,WAAW,GACpB,IAAI,CAIN"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// State field recorder
|
|
3
|
+
// Records state-specific context fields on task state transitions
|
|
4
|
+
// Implements AD-0014: Nullable Columns for State-Specific Fields
|
|
5
|
+
// + FS-SS-005-0012 (record state-specific fields on move)
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.computeStateFields = computeStateFields;
|
|
8
|
+
exports.recordStateFields = recordStateFields;
|
|
9
|
+
/**
|
|
10
|
+
* Compute the timestamp updates and field values to record for a transition.
|
|
11
|
+
*
|
|
12
|
+
* State-specific rules:
|
|
13
|
+
* - In Progress: record session_key if provided, auto-set started_at
|
|
14
|
+
* - In Review: record owner if provided (tasks.owner column)
|
|
15
|
+
* - Done: auto-set completed_at
|
|
16
|
+
*
|
|
17
|
+
* Note: blocker context field removed per FS-SS-030-0004
|
|
18
|
+
* Note: reviewer renamed to owner, review_notes removed per FR-URD-034-0006
|
|
19
|
+
*
|
|
20
|
+
* Returns the partial row updates to apply to the task.
|
|
21
|
+
*/
|
|
22
|
+
function computeStateFields(current, target, context) {
|
|
23
|
+
const now = new Date().toISOString();
|
|
24
|
+
const columns = ['status = ?', 'updated_at = ?'];
|
|
25
|
+
const values = [target, now];
|
|
26
|
+
// Auto-timestamps
|
|
27
|
+
if (current !== 'In Progress' && target === 'In Progress') {
|
|
28
|
+
columns.push('started_at = ?');
|
|
29
|
+
values.push(now);
|
|
30
|
+
}
|
|
31
|
+
if (target === 'Done') {
|
|
32
|
+
columns.push('completed_at = ?');
|
|
33
|
+
values.push(now);
|
|
34
|
+
}
|
|
35
|
+
// State-specific fields from context
|
|
36
|
+
if (target === 'In Progress' && context?.session_key) {
|
|
37
|
+
columns.push('session_key = ?');
|
|
38
|
+
values.push(context.session_key);
|
|
39
|
+
}
|
|
40
|
+
if (target === 'In Review') {
|
|
41
|
+
if (context?.owner) {
|
|
42
|
+
columns.push('owner = ?');
|
|
43
|
+
values.push(context.owner);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { columns, values };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Apply state-specific field updates to a task in the database.
|
|
50
|
+
*
|
|
51
|
+
* @param db - Database connection (within a transaction)
|
|
52
|
+
* @param taskId - The task to update
|
|
53
|
+
* @param target - Target state being moved to
|
|
54
|
+
* @param current - Current state
|
|
55
|
+
* @param context - Optional context fields
|
|
56
|
+
*/
|
|
57
|
+
function recordStateFields(db, taskId, target, current, context) {
|
|
58
|
+
const { columns, values } = computeStateFields(current, target, context);
|
|
59
|
+
const sql = `UPDATE tasks SET ${columns.join(', ')} WHERE id = ?`;
|
|
60
|
+
db.prepare(sql).run(...values, taskId);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=state-field-recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-field-recorder.js","sourceRoot":"","sources":["../../src/validators/state-field-recorder.ts"],"names":[],"mappings":";AAAA,uBAAuB;AACvB,kEAAkE;AAClE,iEAAiE;AACjE,0DAA0D;;AA4B1D,gDAgCC;AAWD,8CAUC;AAlED;;;;;;;;;;;;GAYG;AACH,SAAgB,kBAAkB,CAChC,OAAmB,EACnB,MAAkB,EAClB,OAAqB;IAErB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,OAAO,GAAa,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAExC,kBAAkB;IAClB,IAAI,OAAO,KAAK,aAAa,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,qCAAqC;IACrC,IAAI,MAAM,KAAK,aAAa,IAAI,OAAO,EAAE,WAAW,EAAE,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,EAAqB,EACrB,MAAc,EACd,MAAkB,EAClB,OAAmB,EACnB,OAAqB;IAErB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,GAAG,GAAG,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;IAClE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lwelliott/cortex-cli",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "A TypeScript CLI for managing software project artifacts backed by SQLite",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/lwelliot/cortex-cli.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/lwelliot/cortex-cli/issues"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/lwelliot/cortex-cli#readme",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"main": "dist/cli/index.js",
|
|
18
|
+
"bin": {
|
|
19
|
+
"cortex-cli": "dist/cli/index.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"generate:schema": "node scripts/generate-schema-types.js",
|
|
23
|
+
"build": "npm run generate:schema && tsc",
|
|
24
|
+
"build:release": "npm run build && node scripts/bundle-release.js",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"lint": "tsc --noEmit"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist/**/*",
|
|
32
|
+
"!dist/cortex-cli.js",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"keywords": ["cli", "project-management", "sprint", "kanban", "sqlite", "typescript"],
|
|
37
|
+
"author": "lwelliot",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"better-sqlite3": "^11.7.0",
|
|
40
|
+
"chalk": "^4.1.2",
|
|
41
|
+
"cli-table3": "^0.6.5",
|
|
42
|
+
"commander": "^13.1.0",
|
|
43
|
+
"yaml": "^2.6.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
47
|
+
"@types/node": "^22.10.0",
|
|
48
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
49
|
+
"esbuild": "^0.28.0",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^2.1.8"
|
|
52
|
+
}
|
|
53
|
+
}
|