@lumenflow/core 1.0.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/LICENSE +190 -0
- package/README.md +119 -0
- package/dist/active-wu-detector.d.ts +33 -0
- package/dist/active-wu-detector.js +106 -0
- package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
- package/dist/adapters/filesystem-metrics.adapter.js +519 -0
- package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
- package/dist/adapters/terminal-renderer.adapter.js +337 -0
- package/dist/arg-parser.d.ts +63 -0
- package/dist/arg-parser.js +560 -0
- package/dist/backlog-editor.d.ts +98 -0
- package/dist/backlog-editor.js +179 -0
- package/dist/backlog-generator.d.ts +111 -0
- package/dist/backlog-generator.js +381 -0
- package/dist/backlog-parser.d.ts +45 -0
- package/dist/backlog-parser.js +102 -0
- package/dist/backlog-sync-validator.d.ts +78 -0
- package/dist/backlog-sync-validator.js +294 -0
- package/dist/branch-drift.d.ts +34 -0
- package/dist/branch-drift.js +51 -0
- package/dist/cleanup-install-config.d.ts +33 -0
- package/dist/cleanup-install-config.js +37 -0
- package/dist/cleanup-lock.d.ts +139 -0
- package/dist/cleanup-lock.js +313 -0
- package/dist/code-path-validator.d.ts +146 -0
- package/dist/code-path-validator.js +537 -0
- package/dist/code-paths-overlap.d.ts +55 -0
- package/dist/code-paths-overlap.js +245 -0
- package/dist/commands-logger.d.ts +77 -0
- package/dist/commands-logger.js +254 -0
- package/dist/commit-message-utils.d.ts +25 -0
- package/dist/commit-message-utils.js +41 -0
- package/dist/compliance-parser.d.ts +150 -0
- package/dist/compliance-parser.js +507 -0
- package/dist/constants/backlog-patterns.d.ts +20 -0
- package/dist/constants/backlog-patterns.js +23 -0
- package/dist/constants/dora-constants.d.ts +49 -0
- package/dist/constants/dora-constants.js +53 -0
- package/dist/constants/gate-constants.d.ts +15 -0
- package/dist/constants/gate-constants.js +15 -0
- package/dist/constants/linter-constants.d.ts +16 -0
- package/dist/constants/linter-constants.js +16 -0
- package/dist/constants/tokenizer-constants.d.ts +15 -0
- package/dist/constants/tokenizer-constants.js +15 -0
- package/dist/core/scope-checker.d.ts +97 -0
- package/dist/core/scope-checker.js +163 -0
- package/dist/core/tool-runner.d.ts +161 -0
- package/dist/core/tool-runner.js +393 -0
- package/dist/core/tool.constants.d.ts +105 -0
- package/dist/core/tool.constants.js +101 -0
- package/dist/core/tool.schemas.d.ts +226 -0
- package/dist/core/tool.schemas.js +226 -0
- package/dist/core/worktree-guard.d.ts +130 -0
- package/dist/core/worktree-guard.js +242 -0
- package/dist/coverage-gate.d.ts +108 -0
- package/dist/coverage-gate.js +196 -0
- package/dist/date-utils.d.ts +75 -0
- package/dist/date-utils.js +140 -0
- package/dist/dependency-graph.d.ts +142 -0
- package/dist/dependency-graph.js +550 -0
- package/dist/dependency-guard.d.ts +54 -0
- package/dist/dependency-guard.js +142 -0
- package/dist/dependency-validator.d.ts +105 -0
- package/dist/dependency-validator.js +154 -0
- package/dist/docs-path-validator.d.ts +36 -0
- package/dist/docs-path-validator.js +95 -0
- package/dist/domain/orchestration.constants.d.ts +99 -0
- package/dist/domain/orchestration.constants.js +97 -0
- package/dist/domain/orchestration.schemas.d.ts +280 -0
- package/dist/domain/orchestration.schemas.js +211 -0
- package/dist/domain/orchestration.types.d.ts +133 -0
- package/dist/domain/orchestration.types.js +12 -0
- package/dist/error-handler.d.ts +116 -0
- package/dist/error-handler.js +136 -0
- package/dist/file-classifiers.d.ts +62 -0
- package/dist/file-classifiers.js +108 -0
- package/dist/gates-agent-mode.d.ts +81 -0
- package/dist/gates-agent-mode.js +94 -0
- package/dist/generate-traceability.d.ts +107 -0
- package/dist/generate-traceability.js +411 -0
- package/dist/git-adapter.d.ts +395 -0
- package/dist/git-adapter.js +649 -0
- package/dist/git-staged-validator.d.ts +32 -0
- package/dist/git-staged-validator.js +48 -0
- package/dist/hardcoded-strings.d.ts +61 -0
- package/dist/hardcoded-strings.js +270 -0
- package/dist/incremental-lint.d.ts +78 -0
- package/dist/incremental-lint.js +129 -0
- package/dist/incremental-test.d.ts +39 -0
- package/dist/incremental-test.js +61 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +61 -0
- package/dist/invariants/check-automated-tests.d.ts +50 -0
- package/dist/invariants/check-automated-tests.js +166 -0
- package/dist/invariants-runner.d.ts +103 -0
- package/dist/invariants-runner.js +527 -0
- package/dist/lane-checker.d.ts +50 -0
- package/dist/lane-checker.js +319 -0
- package/dist/lane-inference.d.ts +39 -0
- package/dist/lane-inference.js +195 -0
- package/dist/lane-lock.d.ts +211 -0
- package/dist/lane-lock.js +474 -0
- package/dist/lane-validator.d.ts +48 -0
- package/dist/lane-validator.js +114 -0
- package/dist/logs-lib.d.ts +104 -0
- package/dist/logs-lib.js +207 -0
- package/dist/lumenflow-config-schema.d.ts +272 -0
- package/dist/lumenflow-config-schema.js +207 -0
- package/dist/lumenflow-config.d.ts +95 -0
- package/dist/lumenflow-config.js +236 -0
- package/dist/manual-test-validator.d.ts +80 -0
- package/dist/manual-test-validator.js +200 -0
- package/dist/merge-lock.d.ts +115 -0
- package/dist/merge-lock.js +251 -0
- package/dist/micro-worktree.d.ts +159 -0
- package/dist/micro-worktree.js +427 -0
- package/dist/migration-deployer.d.ts +69 -0
- package/dist/migration-deployer.js +151 -0
- package/dist/orchestration-advisory-loader.d.ts +28 -0
- package/dist/orchestration-advisory-loader.js +87 -0
- package/dist/orchestration-advisory.d.ts +58 -0
- package/dist/orchestration-advisory.js +94 -0
- package/dist/orchestration-di.d.ts +48 -0
- package/dist/orchestration-di.js +57 -0
- package/dist/orchestration-rules.d.ts +57 -0
- package/dist/orchestration-rules.js +201 -0
- package/dist/orphan-detector.d.ts +131 -0
- package/dist/orphan-detector.js +226 -0
- package/dist/path-classifiers.d.ts +57 -0
- package/dist/path-classifiers.js +93 -0
- package/dist/piped-command-detector.d.ts +34 -0
- package/dist/piped-command-detector.js +64 -0
- package/dist/ports/dashboard-renderer.port.d.ts +112 -0
- package/dist/ports/dashboard-renderer.port.js +25 -0
- package/dist/ports/metrics-collector.port.d.ts +132 -0
- package/dist/ports/metrics-collector.port.js +26 -0
- package/dist/process-detector.d.ts +84 -0
- package/dist/process-detector.js +172 -0
- package/dist/prompt-linter.d.ts +72 -0
- package/dist/prompt-linter.js +312 -0
- package/dist/prompt-monitor.d.ts +15 -0
- package/dist/prompt-monitor.js +205 -0
- package/dist/rebase-artifact-cleanup.d.ts +145 -0
- package/dist/rebase-artifact-cleanup.js +433 -0
- package/dist/retry-strategy.d.ts +189 -0
- package/dist/retry-strategy.js +283 -0
- package/dist/risk-detector.d.ts +108 -0
- package/dist/risk-detector.js +252 -0
- package/dist/rollback-utils.d.ts +76 -0
- package/dist/rollback-utils.js +104 -0
- package/dist/section-headings.d.ts +43 -0
- package/dist/section-headings.js +49 -0
- package/dist/spawn-escalation.d.ts +90 -0
- package/dist/spawn-escalation.js +253 -0
- package/dist/spawn-monitor.d.ts +229 -0
- package/dist/spawn-monitor.js +672 -0
- package/dist/spawn-recovery.d.ts +82 -0
- package/dist/spawn-recovery.js +298 -0
- package/dist/spawn-registry-schema.d.ts +98 -0
- package/dist/spawn-registry-schema.js +108 -0
- package/dist/spawn-registry-store.d.ts +146 -0
- package/dist/spawn-registry-store.js +273 -0
- package/dist/spawn-tree.d.ts +121 -0
- package/dist/spawn-tree.js +285 -0
- package/dist/stamp-status-validator.d.ts +84 -0
- package/dist/stamp-status-validator.js +134 -0
- package/dist/stamp-utils.d.ts +100 -0
- package/dist/stamp-utils.js +229 -0
- package/dist/state-machine.d.ts +26 -0
- package/dist/state-machine.js +83 -0
- package/dist/system-map-validator.d.ts +80 -0
- package/dist/system-map-validator.js +272 -0
- package/dist/telemetry.d.ts +80 -0
- package/dist/telemetry.js +213 -0
- package/dist/token-counter.d.ts +51 -0
- package/dist/token-counter.js +145 -0
- package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
- package/dist/usecases/get-dashboard-data.usecase.js +61 -0
- package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
- package/dist/usecases/get-suggestions.usecase.js +153 -0
- package/dist/user-normalizer.d.ts +41 -0
- package/dist/user-normalizer.js +141 -0
- package/dist/validators/phi-constants.d.ts +97 -0
- package/dist/validators/phi-constants.js +152 -0
- package/dist/validators/phi-scanner.d.ts +58 -0
- package/dist/validators/phi-scanner.js +215 -0
- package/dist/worktree-ownership.d.ts +50 -0
- package/dist/worktree-ownership.js +74 -0
- package/dist/worktree-scanner.d.ts +103 -0
- package/dist/worktree-scanner.js +168 -0
- package/dist/worktree-symlink.d.ts +99 -0
- package/dist/worktree-symlink.js +359 -0
- package/dist/wu-backlog-updater.d.ts +17 -0
- package/dist/wu-backlog-updater.js +37 -0
- package/dist/wu-checkpoint.d.ts +124 -0
- package/dist/wu-checkpoint.js +233 -0
- package/dist/wu-claim-helpers.d.ts +26 -0
- package/dist/wu-claim-helpers.js +63 -0
- package/dist/wu-claim-resume.d.ts +106 -0
- package/dist/wu-claim-resume.js +276 -0
- package/dist/wu-consistency-checker.d.ts +95 -0
- package/dist/wu-consistency-checker.js +567 -0
- package/dist/wu-constants.d.ts +1275 -0
- package/dist/wu-constants.js +1382 -0
- package/dist/wu-create-validators.d.ts +42 -0
- package/dist/wu-create-validators.js +93 -0
- package/dist/wu-done-branch-only.d.ts +63 -0
- package/dist/wu-done-branch-only.js +191 -0
- package/dist/wu-done-messages.d.ts +119 -0
- package/dist/wu-done-messages.js +185 -0
- package/dist/wu-done-pr.d.ts +72 -0
- package/dist/wu-done-pr.js +174 -0
- package/dist/wu-done-retry-helpers.d.ts +85 -0
- package/dist/wu-done-retry-helpers.js +172 -0
- package/dist/wu-done-ui.d.ts +37 -0
- package/dist/wu-done-ui.js +69 -0
- package/dist/wu-done-validators.d.ts +411 -0
- package/dist/wu-done-validators.js +1229 -0
- package/dist/wu-done-worktree.d.ts +182 -0
- package/dist/wu-done-worktree.js +1097 -0
- package/dist/wu-helpers.d.ts +128 -0
- package/dist/wu-helpers.js +248 -0
- package/dist/wu-lint.d.ts +70 -0
- package/dist/wu-lint.js +234 -0
- package/dist/wu-paths.d.ts +171 -0
- package/dist/wu-paths.js +178 -0
- package/dist/wu-preflight-validators.d.ts +86 -0
- package/dist/wu-preflight-validators.js +251 -0
- package/dist/wu-recovery.d.ts +138 -0
- package/dist/wu-recovery.js +341 -0
- package/dist/wu-repair-core.d.ts +131 -0
- package/dist/wu-repair-core.js +669 -0
- package/dist/wu-schema-normalization.d.ts +17 -0
- package/dist/wu-schema-normalization.js +82 -0
- package/dist/wu-schema.d.ts +793 -0
- package/dist/wu-schema.js +881 -0
- package/dist/wu-spawn-helpers.d.ts +121 -0
- package/dist/wu-spawn-helpers.js +271 -0
- package/dist/wu-spawn.d.ts +158 -0
- package/dist/wu-spawn.js +1306 -0
- package/dist/wu-state-schema.d.ts +213 -0
- package/dist/wu-state-schema.js +156 -0
- package/dist/wu-state-store.d.ts +264 -0
- package/dist/wu-state-store.js +691 -0
- package/dist/wu-status-transition.d.ts +63 -0
- package/dist/wu-status-transition.js +382 -0
- package/dist/wu-status-updater.d.ts +25 -0
- package/dist/wu-status-updater.js +116 -0
- package/dist/wu-transaction-collectors.d.ts +116 -0
- package/dist/wu-transaction-collectors.js +272 -0
- package/dist/wu-transaction.d.ts +170 -0
- package/dist/wu-transaction.js +273 -0
- package/dist/wu-validation-constants.d.ts +60 -0
- package/dist/wu-validation-constants.js +66 -0
- package/dist/wu-validation.d.ts +118 -0
- package/dist/wu-validation.js +243 -0
- package/dist/wu-validator.d.ts +62 -0
- package/dist/wu-validator.js +325 -0
- package/dist/wu-yaml-fixer.d.ts +97 -0
- package/dist/wu-yaml-fixer.js +264 -0
- package/dist/wu-yaml.d.ts +86 -0
- package/dist/wu-yaml.js +222 -0
- package/package.json +114 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses markdown compliance documentation into structured data.
|
|
5
|
+
* Used by compliance-snapshot.mjs tool to create snapshots.
|
|
6
|
+
*
|
|
7
|
+
* @module tools/lib/compliance-parser
|
|
8
|
+
*/
|
|
9
|
+
/** @typedef {'ISO27001' | 'NHS_DTAC' | 'NHS_DSPT' | 'GDPR' | 'FDA'} ComplianceFramework */
|
|
10
|
+
/** @typedef {'not_started' | 'in_progress' | 'completed' | 'blocked'} GapStatus */
|
|
11
|
+
/** @typedef {'critical' | 'high' | 'medium' | 'low'} GapPriority */
|
|
12
|
+
/** @typedef {'exists' | 'partial' | 'missing'} EvidenceStatus */
|
|
13
|
+
/** @typedef {'phase_1_critical_blockers' | 'phase_2_nhs_procurement_ready' | 'phase_3_enterprise_ready'} CompliancePhase */
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} ActionItem
|
|
16
|
+
* @property {string} id
|
|
17
|
+
* @property {string} description
|
|
18
|
+
* @property {string} owner
|
|
19
|
+
* @property {string|null} dueDate
|
|
20
|
+
* @property {GapStatus} status
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} GapItem
|
|
24
|
+
* @property {string} gapId
|
|
25
|
+
* @property {string} title
|
|
26
|
+
* @property {string} domain
|
|
27
|
+
* @property {GapPriority} priority
|
|
28
|
+
* @property {GapStatus} status
|
|
29
|
+
* @property {CompliancePhase} phase
|
|
30
|
+
* @property {string} owner
|
|
31
|
+
* @property {string|null} targetDate
|
|
32
|
+
* @property {ActionItem[]} actionItems
|
|
33
|
+
* @property {string[]} blockers
|
|
34
|
+
* @property {string[]} dependsOn
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {Object} EvidenceItem
|
|
38
|
+
* @property {string} evidenceId
|
|
39
|
+
* @property {string} section
|
|
40
|
+
* @property {string} title
|
|
41
|
+
* @property {string} requirement
|
|
42
|
+
* @property {EvidenceStatus} status
|
|
43
|
+
* @property {string|null} location
|
|
44
|
+
* @property {string[]} auditNotes
|
|
45
|
+
* @property {string[]} relatedGaps
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {Object} FrameworkMetrics
|
|
49
|
+
* @property {ComplianceFramework} framework
|
|
50
|
+
* @property {number} totalRequirements
|
|
51
|
+
* @property {number} evidenceExists
|
|
52
|
+
* @property {number} evidencePartial
|
|
53
|
+
* @property {number} evidenceMissing
|
|
54
|
+
* @property {number} completionPercentage
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {Object} PhaseMetrics
|
|
58
|
+
* @property {CompliancePhase} phase
|
|
59
|
+
* @property {number} totalGaps
|
|
60
|
+
* @property {number} notStarted
|
|
61
|
+
* @property {number} inProgress
|
|
62
|
+
* @property {number} completed
|
|
63
|
+
* @property {number} blocked
|
|
64
|
+
* @property {number} completionPercentage
|
|
65
|
+
* @property {string|null} targetDate
|
|
66
|
+
*/
|
|
67
|
+
export declare const COMPLIANCE_FRAMEWORKS: string[];
|
|
68
|
+
export declare const GAP_STATUSES: string[];
|
|
69
|
+
export declare const GAP_PRIORITIES: string[];
|
|
70
|
+
export declare const EVIDENCE_STATUSES: string[];
|
|
71
|
+
export declare const COMPLIANCE_PHASES: string[];
|
|
72
|
+
export declare class ComplianceParser {
|
|
73
|
+
/**
|
|
74
|
+
* Parse gap-analysis.md content into structured GapItems
|
|
75
|
+
* @param {string} markdown
|
|
76
|
+
* @returns {GapItem[]}
|
|
77
|
+
*/
|
|
78
|
+
parseGapAnalysis(markdown: any): any[];
|
|
79
|
+
/**
|
|
80
|
+
* Parse evidence-registry.md content into structured EvidenceItems
|
|
81
|
+
* @param {string} markdown
|
|
82
|
+
* @returns {EvidenceItem[]}
|
|
83
|
+
*/
|
|
84
|
+
parseEvidenceRegistry(markdown: any): any[];
|
|
85
|
+
/**
|
|
86
|
+
* Calculate framework metrics from evidence items
|
|
87
|
+
* @param {EvidenceItem[]} evidence
|
|
88
|
+
* @returns {FrameworkMetrics[]}
|
|
89
|
+
*/
|
|
90
|
+
calculateFrameworkMetrics(evidence: any): {
|
|
91
|
+
framework: string;
|
|
92
|
+
totalRequirements: any;
|
|
93
|
+
evidenceExists: any;
|
|
94
|
+
evidencePartial: any;
|
|
95
|
+
evidenceMissing: any;
|
|
96
|
+
completionPercentage: number;
|
|
97
|
+
}[];
|
|
98
|
+
/**
|
|
99
|
+
* Calculate phase metrics from gap items
|
|
100
|
+
* @param {GapItem[]} gaps
|
|
101
|
+
* @returns {PhaseMetrics[]}
|
|
102
|
+
*/
|
|
103
|
+
calculatePhaseMetrics(gaps: any): {
|
|
104
|
+
phase: string;
|
|
105
|
+
totalGaps: any;
|
|
106
|
+
notStarted: any;
|
|
107
|
+
inProgress: any;
|
|
108
|
+
completed: any;
|
|
109
|
+
blocked: any;
|
|
110
|
+
completionPercentage: number;
|
|
111
|
+
targetDate: string;
|
|
112
|
+
}[];
|
|
113
|
+
/** @private */
|
|
114
|
+
_parseStatus(text: any): string;
|
|
115
|
+
/** @private */
|
|
116
|
+
_parsePriority(text: any): string;
|
|
117
|
+
/** @private */
|
|
118
|
+
_parseEvidenceStatus(text: any): string;
|
|
119
|
+
/** @private */
|
|
120
|
+
_extractGapReferences(text: any): unknown[];
|
|
121
|
+
/** @private */
|
|
122
|
+
_detectFrameworks(requirement: any): any[];
|
|
123
|
+
/** @private */
|
|
124
|
+
_finalizeGap(partial: any, phase: any): {
|
|
125
|
+
gapId: any;
|
|
126
|
+
title: any;
|
|
127
|
+
domain: any;
|
|
128
|
+
priority: any;
|
|
129
|
+
status: any;
|
|
130
|
+
phase: any;
|
|
131
|
+
owner: any;
|
|
132
|
+
targetDate: any;
|
|
133
|
+
actionItems: any;
|
|
134
|
+
blockers: any;
|
|
135
|
+
dependsOn: any;
|
|
136
|
+
};
|
|
137
|
+
/** @private */
|
|
138
|
+
_finalizeEvidence(partial: any, section: any): {
|
|
139
|
+
evidenceId: any;
|
|
140
|
+
section: any;
|
|
141
|
+
title: any;
|
|
142
|
+
requirement: any;
|
|
143
|
+
status: any;
|
|
144
|
+
location: any;
|
|
145
|
+
auditNotes: any;
|
|
146
|
+
relatedGaps: any;
|
|
147
|
+
};
|
|
148
|
+
/** @private */
|
|
149
|
+
_getPhaseTargetDate(phase: any): "Month 3" | "Month 6" | "Month 12";
|
|
150
|
+
}
|
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses markdown compliance documentation into structured data.
|
|
5
|
+
* Used by compliance-snapshot.mjs tool to create snapshots.
|
|
6
|
+
*
|
|
7
|
+
* @module tools/lib/compliance-parser
|
|
8
|
+
*/
|
|
9
|
+
/** @typedef {'ISO27001' | 'NHS_DTAC' | 'NHS_DSPT' | 'GDPR' | 'FDA'} ComplianceFramework */
|
|
10
|
+
/** @typedef {'not_started' | 'in_progress' | 'completed' | 'blocked'} GapStatus */
|
|
11
|
+
/** @typedef {'critical' | 'high' | 'medium' | 'low'} GapPriority */
|
|
12
|
+
/** @typedef {'exists' | 'partial' | 'missing'} EvidenceStatus */
|
|
13
|
+
/** @typedef {'phase_1_critical_blockers' | 'phase_2_nhs_procurement_ready' | 'phase_3_enterprise_ready'} CompliancePhase */
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} ActionItem
|
|
16
|
+
* @property {string} id
|
|
17
|
+
* @property {string} description
|
|
18
|
+
* @property {string} owner
|
|
19
|
+
* @property {string|null} dueDate
|
|
20
|
+
* @property {GapStatus} status
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} GapItem
|
|
24
|
+
* @property {string} gapId
|
|
25
|
+
* @property {string} title
|
|
26
|
+
* @property {string} domain
|
|
27
|
+
* @property {GapPriority} priority
|
|
28
|
+
* @property {GapStatus} status
|
|
29
|
+
* @property {CompliancePhase} phase
|
|
30
|
+
* @property {string} owner
|
|
31
|
+
* @property {string|null} targetDate
|
|
32
|
+
* @property {ActionItem[]} actionItems
|
|
33
|
+
* @property {string[]} blockers
|
|
34
|
+
* @property {string[]} dependsOn
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {Object} EvidenceItem
|
|
38
|
+
* @property {string} evidenceId
|
|
39
|
+
* @property {string} section
|
|
40
|
+
* @property {string} title
|
|
41
|
+
* @property {string} requirement
|
|
42
|
+
* @property {EvidenceStatus} status
|
|
43
|
+
* @property {string|null} location
|
|
44
|
+
* @property {string[]} auditNotes
|
|
45
|
+
* @property {string[]} relatedGaps
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {Object} FrameworkMetrics
|
|
49
|
+
* @property {ComplianceFramework} framework
|
|
50
|
+
* @property {number} totalRequirements
|
|
51
|
+
* @property {number} evidenceExists
|
|
52
|
+
* @property {number} evidencePartial
|
|
53
|
+
* @property {number} evidenceMissing
|
|
54
|
+
* @property {number} completionPercentage
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {Object} PhaseMetrics
|
|
58
|
+
* @property {CompliancePhase} phase
|
|
59
|
+
* @property {number} totalGaps
|
|
60
|
+
* @property {number} notStarted
|
|
61
|
+
* @property {number} inProgress
|
|
62
|
+
* @property {number} completed
|
|
63
|
+
* @property {number} blocked
|
|
64
|
+
* @property {number} completionPercentage
|
|
65
|
+
* @property {string|null} targetDate
|
|
66
|
+
*/
|
|
67
|
+
export const COMPLIANCE_FRAMEWORKS = ['ISO27001', 'NHS_DTAC', 'NHS_DSPT', 'GDPR', 'FDA'];
|
|
68
|
+
export const GAP_STATUSES = ['not_started', 'in_progress', 'completed', 'blocked'];
|
|
69
|
+
export const GAP_PRIORITIES = ['critical', 'high', 'medium', 'low'];
|
|
70
|
+
export const EVIDENCE_STATUSES = ['exists', 'partial', 'missing'];
|
|
71
|
+
export const COMPLIANCE_PHASES = [
|
|
72
|
+
'phase_1_critical_blockers',
|
|
73
|
+
'phase_2_nhs_procurement_ready',
|
|
74
|
+
'phase_3_enterprise_ready',
|
|
75
|
+
];
|
|
76
|
+
// Status emoji mappings
|
|
77
|
+
const STATUS_EMOJI_MAP = {
|
|
78
|
+
'Not Started': 'not_started',
|
|
79
|
+
'In Progress': 'in_progress',
|
|
80
|
+
Completed: 'completed',
|
|
81
|
+
Blocked: 'blocked',
|
|
82
|
+
};
|
|
83
|
+
const PRIORITY_EMOJI_MAP = {
|
|
84
|
+
CRITICAL: 'critical',
|
|
85
|
+
HIGH: 'high',
|
|
86
|
+
MEDIUM: 'medium',
|
|
87
|
+
LOW: 'low',
|
|
88
|
+
};
|
|
89
|
+
const EVIDENCE_STATUS_MAP = {
|
|
90
|
+
'Evidence exists': 'exists',
|
|
91
|
+
'Partial evidence': 'partial',
|
|
92
|
+
'No evidence': 'missing',
|
|
93
|
+
};
|
|
94
|
+
const PHASE_HEADER_MAP = {
|
|
95
|
+
'Phase 1': 'phase_1_critical_blockers',
|
|
96
|
+
'Phase 2': 'phase_2_nhs_procurement_ready',
|
|
97
|
+
'Phase 3': 'phase_3_enterprise_ready',
|
|
98
|
+
};
|
|
99
|
+
// Framework keyword mappings for evidence parsing
|
|
100
|
+
const FRAMEWORK_KEYWORDS = {
|
|
101
|
+
ISO27001: ['ISO 27001', 'ISO27001', 'SOC 2', 'SOC2'],
|
|
102
|
+
NHS_DTAC: ['NHS DTAC', 'DTAC'],
|
|
103
|
+
NHS_DSPT: ['NHS DSPT', 'DSPT'],
|
|
104
|
+
GDPR: ['GDPR', 'UK GDPR', 'Data Protection'],
|
|
105
|
+
FDA: ['FDA', '21 CFR', 'Medical Device'],
|
|
106
|
+
};
|
|
107
|
+
export class ComplianceParser {
|
|
108
|
+
/**
|
|
109
|
+
* Parse gap-analysis.md content into structured GapItems
|
|
110
|
+
* @param {string} markdown
|
|
111
|
+
* @returns {GapItem[]}
|
|
112
|
+
*/
|
|
113
|
+
parseGapAnalysis(markdown) {
|
|
114
|
+
const gaps = [];
|
|
115
|
+
const lines = markdown.split('\n');
|
|
116
|
+
let currentPhase = 'phase_1_critical_blockers';
|
|
117
|
+
let currentGap = null;
|
|
118
|
+
let inActionItems = false;
|
|
119
|
+
let inBlockers = false;
|
|
120
|
+
let currentActionItem = null;
|
|
121
|
+
for (let i = 0; i < lines.length; i++) {
|
|
122
|
+
const line = lines[i];
|
|
123
|
+
const trimmedLine = line.trim();
|
|
124
|
+
// Detect phase headers
|
|
125
|
+
if (trimmedLine.startsWith('## Phase')) {
|
|
126
|
+
for (const [phaseKey, phaseValue] of Object.entries(PHASE_HEADER_MAP)) {
|
|
127
|
+
if (trimmedLine.includes(phaseKey)) {
|
|
128
|
+
currentPhase = phaseValue;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// Detect GAP header
|
|
135
|
+
const gapMatch = trimmedLine.match(/^### (GAP-\d+):\s*(.+)$/);
|
|
136
|
+
if (gapMatch) {
|
|
137
|
+
// Save previous gap if exists
|
|
138
|
+
if (currentGap?.gapId) {
|
|
139
|
+
if (currentActionItem?.id) {
|
|
140
|
+
currentGap.actionItems.push(currentActionItem);
|
|
141
|
+
}
|
|
142
|
+
gaps.push(this._finalizeGap(currentGap, currentPhase));
|
|
143
|
+
}
|
|
144
|
+
currentGap = {
|
|
145
|
+
gapId: gapMatch[1],
|
|
146
|
+
title: gapMatch[2],
|
|
147
|
+
phase: currentPhase,
|
|
148
|
+
actionItems: [],
|
|
149
|
+
blockers: [],
|
|
150
|
+
dependsOn: [],
|
|
151
|
+
};
|
|
152
|
+
currentActionItem = null;
|
|
153
|
+
inActionItems = false;
|
|
154
|
+
inBlockers = false;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (!currentGap)
|
|
158
|
+
continue;
|
|
159
|
+
// Parse fields
|
|
160
|
+
if (trimmedLine.startsWith('**Priority:**')) {
|
|
161
|
+
currentGap.priority = this._parsePriority(trimmedLine);
|
|
162
|
+
}
|
|
163
|
+
else if (trimmedLine.startsWith('**Domain:**')) {
|
|
164
|
+
currentGap.domain = trimmedLine.replace('**Domain:**', '').trim();
|
|
165
|
+
}
|
|
166
|
+
else if (trimmedLine.startsWith('**Status:**')) {
|
|
167
|
+
currentGap.status = this._parseStatus(trimmedLine);
|
|
168
|
+
}
|
|
169
|
+
else if (trimmedLine.startsWith('**Owner:**')) {
|
|
170
|
+
currentGap.owner = trimmedLine.replace('**Owner:**', '').trim();
|
|
171
|
+
}
|
|
172
|
+
else if (trimmedLine.startsWith('**Target Date:**')) {
|
|
173
|
+
currentGap.targetDate = trimmedLine.replace('**Target Date:**', '').trim() || null;
|
|
174
|
+
}
|
|
175
|
+
else if (trimmedLine.startsWith('**Depends On:**')) {
|
|
176
|
+
const deps = this._extractGapReferences(trimmedLine);
|
|
177
|
+
currentGap.dependsOn = deps;
|
|
178
|
+
}
|
|
179
|
+
// Detect sections
|
|
180
|
+
if (trimmedLine === '**Action Items:**') {
|
|
181
|
+
inActionItems = true;
|
|
182
|
+
inBlockers = false;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (trimmedLine === '**Blockers:**') {
|
|
186
|
+
inActionItems = false;
|
|
187
|
+
inBlockers = true;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (trimmedLine.startsWith('**') && trimmedLine.endsWith('**')) {
|
|
191
|
+
if (!trimmedLine.includes('Action Items') && !trimmedLine.includes('Blockers')) {
|
|
192
|
+
inActionItems = false;
|
|
193
|
+
inBlockers = false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Parse action items
|
|
197
|
+
if (inActionItems) {
|
|
198
|
+
const actionMatch = trimmedLine.match(/^- \[[ x]\] \*\*(\d+\.\d+)\*\*\s+(.+)$/);
|
|
199
|
+
if (actionMatch) {
|
|
200
|
+
if (currentActionItem?.id) {
|
|
201
|
+
currentGap.actionItems.push(currentActionItem);
|
|
202
|
+
}
|
|
203
|
+
const isCompleted = trimmedLine.includes('[x]');
|
|
204
|
+
currentActionItem = {
|
|
205
|
+
id: actionMatch[1],
|
|
206
|
+
description: actionMatch[2],
|
|
207
|
+
status: isCompleted ? 'completed' : 'not_started',
|
|
208
|
+
owner: null,
|
|
209
|
+
dueDate: null,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
else if (currentActionItem && trimmedLine.startsWith('- Owner:')) {
|
|
213
|
+
currentActionItem.owner = trimmedLine.replace('- Owner:', '').trim();
|
|
214
|
+
}
|
|
215
|
+
else if (currentActionItem && trimmedLine.startsWith('- Due:')) {
|
|
216
|
+
currentActionItem.dueDate = trimmedLine.replace('- Due:', '').trim();
|
|
217
|
+
}
|
|
218
|
+
else if (currentActionItem && trimmedLine.startsWith('- Status:')) {
|
|
219
|
+
currentActionItem.status = this._parseStatus(trimmedLine);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Parse blockers
|
|
223
|
+
if (inBlockers && trimmedLine.startsWith('-') && !trimmedLine.includes('None')) {
|
|
224
|
+
const blockerText = trimmedLine.replace(/^-\s*/, '').replace(/^[🔴🟡]\s*/, '');
|
|
225
|
+
if (blockerText.trim()) {
|
|
226
|
+
currentGap.blockers.push(blockerText.trim());
|
|
227
|
+
// Also extract any GAP references
|
|
228
|
+
const gapRefs = this._extractGapReferences(trimmedLine);
|
|
229
|
+
for (const ref of gapRefs) {
|
|
230
|
+
if (!currentGap.dependsOn.includes(ref)) {
|
|
231
|
+
currentGap.dependsOn.push(ref);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Save final gap
|
|
238
|
+
if (currentGap?.gapId) {
|
|
239
|
+
if (currentActionItem?.id) {
|
|
240
|
+
currentGap.actionItems.push(currentActionItem);
|
|
241
|
+
}
|
|
242
|
+
gaps.push(this._finalizeGap(currentGap, currentPhase));
|
|
243
|
+
}
|
|
244
|
+
return gaps;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Parse evidence-registry.md content into structured EvidenceItems
|
|
248
|
+
* @param {string} markdown
|
|
249
|
+
* @returns {EvidenceItem[]}
|
|
250
|
+
*/
|
|
251
|
+
parseEvidenceRegistry(markdown) {
|
|
252
|
+
const evidence = [];
|
|
253
|
+
const lines = markdown.split('\n');
|
|
254
|
+
let currentSection = '';
|
|
255
|
+
let currentEvidence = null;
|
|
256
|
+
let inAuditNotes = false;
|
|
257
|
+
for (let i = 0; i < lines.length; i++) {
|
|
258
|
+
const line = lines[i];
|
|
259
|
+
const trimmedLine = line.trim();
|
|
260
|
+
// Detect section headers (## N. Section Name)
|
|
261
|
+
const sectionMatch = trimmedLine.match(/^## \d+\.\s*(.+)$/);
|
|
262
|
+
if (sectionMatch) {
|
|
263
|
+
currentSection = sectionMatch[1];
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
// Detect evidence item header (### N.N Title)
|
|
267
|
+
const evidenceMatch = trimmedLine.match(/^### (\d+\.\d+)\s+(.+)$/);
|
|
268
|
+
if (evidenceMatch) {
|
|
269
|
+
// Save previous evidence if exists
|
|
270
|
+
if (currentEvidence?.evidenceId) {
|
|
271
|
+
evidence.push(this._finalizeEvidence(currentEvidence, currentSection));
|
|
272
|
+
}
|
|
273
|
+
currentEvidence = {
|
|
274
|
+
evidenceId: evidenceMatch[1],
|
|
275
|
+
title: evidenceMatch[2],
|
|
276
|
+
section: currentSection,
|
|
277
|
+
auditNotes: [],
|
|
278
|
+
relatedGaps: [],
|
|
279
|
+
};
|
|
280
|
+
inAuditNotes = false;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (!currentEvidence)
|
|
284
|
+
continue;
|
|
285
|
+
// Parse fields
|
|
286
|
+
if (trimmedLine.startsWith('**Requirement**:')) {
|
|
287
|
+
currentEvidence.requirement = trimmedLine.replace('**Requirement**:', '').trim();
|
|
288
|
+
}
|
|
289
|
+
else if (trimmedLine.startsWith('**Status**:')) {
|
|
290
|
+
currentEvidence.status = this._parseEvidenceStatus(trimmedLine);
|
|
291
|
+
}
|
|
292
|
+
// Detect Evidence section with Location
|
|
293
|
+
if (trimmedLine.includes('**Location**:')) {
|
|
294
|
+
const locationMatch = trimmedLine.match(/\*\*Location\*\*:\s*\[?([^\]]+)\]?/);
|
|
295
|
+
if (locationMatch) {
|
|
296
|
+
currentEvidence.location = locationMatch[1].replace(/\(.*\)/, '').trim();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Detect Audit Notes section
|
|
300
|
+
if (trimmedLine === '**Audit Notes**:') {
|
|
301
|
+
inAuditNotes = true;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
// Parse audit notes
|
|
305
|
+
if (inAuditNotes && trimmedLine.startsWith('-')) {
|
|
306
|
+
const noteText = trimmedLine.replace(/^-\s*/, '').trim();
|
|
307
|
+
if (noteText) {
|
|
308
|
+
currentEvidence.auditNotes.push(noteText);
|
|
309
|
+
// Extract GAP references from notes
|
|
310
|
+
const gapRefs = this._extractGapReferences(trimmedLine);
|
|
311
|
+
for (const ref of gapRefs) {
|
|
312
|
+
if (!currentEvidence.relatedGaps.includes(ref)) {
|
|
313
|
+
currentEvidence.relatedGaps.push(ref);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// End audit notes on next section
|
|
319
|
+
if (inAuditNotes && trimmedLine.startsWith('---')) {
|
|
320
|
+
inAuditNotes = false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Save final evidence
|
|
324
|
+
if (currentEvidence?.evidenceId) {
|
|
325
|
+
evidence.push(this._finalizeEvidence(currentEvidence, currentSection));
|
|
326
|
+
}
|
|
327
|
+
return evidence;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Calculate framework metrics from evidence items
|
|
331
|
+
* @param {EvidenceItem[]} evidence
|
|
332
|
+
* @returns {FrameworkMetrics[]}
|
|
333
|
+
*/
|
|
334
|
+
calculateFrameworkMetrics(evidence) {
|
|
335
|
+
const frameworkCounts = {};
|
|
336
|
+
// Initialize all frameworks
|
|
337
|
+
for (const framework of COMPLIANCE_FRAMEWORKS) {
|
|
338
|
+
frameworkCounts[framework] = { total: 0, exists: 0, partial: 0, missing: 0 };
|
|
339
|
+
}
|
|
340
|
+
// Count evidence per framework
|
|
341
|
+
for (const item of evidence) {
|
|
342
|
+
const frameworks = this._detectFrameworks(item.requirement);
|
|
343
|
+
for (const framework of frameworks) {
|
|
344
|
+
frameworkCounts[framework].total++;
|
|
345
|
+
if (item.status === 'exists') {
|
|
346
|
+
frameworkCounts[framework].exists++;
|
|
347
|
+
}
|
|
348
|
+
else if (item.status === 'partial') {
|
|
349
|
+
frameworkCounts[framework].partial++;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
frameworkCounts[framework].missing++;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// Calculate metrics
|
|
357
|
+
return COMPLIANCE_FRAMEWORKS.map((framework) => {
|
|
358
|
+
const counts = frameworkCounts[framework];
|
|
359
|
+
// Completion: exists = 100%, partial = 50%, missing = 0%
|
|
360
|
+
const completionPercentage = counts.total > 0
|
|
361
|
+
? Math.round((counts.exists * 100 + counts.partial * 50) / counts.total)
|
|
362
|
+
: 0;
|
|
363
|
+
return {
|
|
364
|
+
framework,
|
|
365
|
+
totalRequirements: counts.total,
|
|
366
|
+
evidenceExists: counts.exists,
|
|
367
|
+
evidencePartial: counts.partial,
|
|
368
|
+
evidenceMissing: counts.missing,
|
|
369
|
+
completionPercentage,
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Calculate phase metrics from gap items
|
|
375
|
+
* @param {GapItem[]} gaps
|
|
376
|
+
* @returns {PhaseMetrics[]}
|
|
377
|
+
*/
|
|
378
|
+
calculatePhaseMetrics(gaps) {
|
|
379
|
+
const phaseCounts = {};
|
|
380
|
+
// Initialize all phases
|
|
381
|
+
for (const phase of COMPLIANCE_PHASES) {
|
|
382
|
+
phaseCounts[phase] = { total: 0, notStarted: 0, inProgress: 0, completed: 0, blocked: 0 };
|
|
383
|
+
}
|
|
384
|
+
// Count gaps per phase
|
|
385
|
+
for (const gap of gaps) {
|
|
386
|
+
const phase = gap.phase;
|
|
387
|
+
phaseCounts[phase].total++;
|
|
388
|
+
switch (gap.status) {
|
|
389
|
+
case 'not_started':
|
|
390
|
+
phaseCounts[phase].notStarted++;
|
|
391
|
+
break;
|
|
392
|
+
case 'in_progress':
|
|
393
|
+
phaseCounts[phase].inProgress++;
|
|
394
|
+
break;
|
|
395
|
+
case 'completed':
|
|
396
|
+
phaseCounts[phase].completed++;
|
|
397
|
+
break;
|
|
398
|
+
case 'blocked':
|
|
399
|
+
phaseCounts[phase].blocked++;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Calculate metrics
|
|
404
|
+
return COMPLIANCE_PHASES.map((phase) => {
|
|
405
|
+
const counts = phaseCounts[phase];
|
|
406
|
+
const completionPercentage = counts.total > 0 ? Math.round((counts.completed / counts.total) * 100 * 100) / 100 : 0;
|
|
407
|
+
return {
|
|
408
|
+
phase,
|
|
409
|
+
totalGaps: counts.total,
|
|
410
|
+
notStarted: counts.notStarted,
|
|
411
|
+
inProgress: counts.inProgress,
|
|
412
|
+
completed: counts.completed,
|
|
413
|
+
blocked: counts.blocked,
|
|
414
|
+
completionPercentage,
|
|
415
|
+
targetDate: this._getPhaseTargetDate(phase),
|
|
416
|
+
};
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
// Helper methods
|
|
420
|
+
/** @private */
|
|
421
|
+
_parseStatus(text) {
|
|
422
|
+
for (const [key, value] of Object.entries(STATUS_EMOJI_MAP)) {
|
|
423
|
+
if (text.includes(key)) {
|
|
424
|
+
return value;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return 'not_started';
|
|
428
|
+
}
|
|
429
|
+
/** @private */
|
|
430
|
+
_parsePriority(text) {
|
|
431
|
+
for (const [key, value] of Object.entries(PRIORITY_EMOJI_MAP)) {
|
|
432
|
+
if (text.toUpperCase().includes(key)) {
|
|
433
|
+
return value;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return 'medium';
|
|
437
|
+
}
|
|
438
|
+
/** @private */
|
|
439
|
+
_parseEvidenceStatus(text) {
|
|
440
|
+
for (const [key, value] of Object.entries(EVIDENCE_STATUS_MAP)) {
|
|
441
|
+
if (text.includes(key)) {
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return 'missing';
|
|
446
|
+
}
|
|
447
|
+
/** @private */
|
|
448
|
+
_extractGapReferences(text) {
|
|
449
|
+
const matches = text.match(/GAP-\d+/g);
|
|
450
|
+
return matches ? [...new Set(matches)] : [];
|
|
451
|
+
}
|
|
452
|
+
/** @private */
|
|
453
|
+
_detectFrameworks(requirement) {
|
|
454
|
+
const frameworks = [];
|
|
455
|
+
for (const [framework, keywords] of Object.entries(FRAMEWORK_KEYWORDS)) {
|
|
456
|
+
for (const keyword of keywords) {
|
|
457
|
+
if (requirement.includes(keyword)) {
|
|
458
|
+
frameworks.push(framework);
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return frameworks;
|
|
464
|
+
}
|
|
465
|
+
/** @private */
|
|
466
|
+
_finalizeGap(partial, phase) {
|
|
467
|
+
return {
|
|
468
|
+
gapId: partial.gapId || 'UNKNOWN',
|
|
469
|
+
title: partial.title || 'Untitled',
|
|
470
|
+
domain: partial.domain || 'Unknown',
|
|
471
|
+
priority: partial.priority || 'medium',
|
|
472
|
+
status: partial.status || 'not_started',
|
|
473
|
+
phase: partial.phase || phase,
|
|
474
|
+
owner: partial.owner || 'Unassigned',
|
|
475
|
+
targetDate: partial.targetDate || null,
|
|
476
|
+
actionItems: partial.actionItems || [],
|
|
477
|
+
blockers: partial.blockers || [],
|
|
478
|
+
dependsOn: partial.dependsOn || [],
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
/** @private */
|
|
482
|
+
_finalizeEvidence(partial, section) {
|
|
483
|
+
return {
|
|
484
|
+
evidenceId: partial.evidenceId || 'UNKNOWN',
|
|
485
|
+
section: partial.section || section,
|
|
486
|
+
title: partial.title || 'Untitled',
|
|
487
|
+
requirement: partial.requirement || '',
|
|
488
|
+
status: partial.status || 'missing',
|
|
489
|
+
location: partial.location || null,
|
|
490
|
+
auditNotes: partial.auditNotes || [],
|
|
491
|
+
relatedGaps: partial.relatedGaps || [],
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
/** @private */
|
|
495
|
+
_getPhaseTargetDate(phase) {
|
|
496
|
+
switch (phase) {
|
|
497
|
+
case 'phase_1_critical_blockers':
|
|
498
|
+
return 'Month 3';
|
|
499
|
+
case 'phase_2_nhs_procurement_ready':
|
|
500
|
+
return 'Month 6';
|
|
501
|
+
case 'phase_3_enterprise_ready':
|
|
502
|
+
return 'Month 12';
|
|
503
|
+
default:
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backlog Parsing Patterns
|
|
3
|
+
*
|
|
4
|
+
* Centralizes patterns for parsing status.md and backlog.md files.
|
|
5
|
+
* Used by lane-checker.mjs and related backlog utilities.
|
|
6
|
+
*/
|
|
7
|
+
/** Markdown section header patterns for In Progress section */
|
|
8
|
+
export declare const IN_PROGRESS_HEADERS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Pattern for extracting WU ID from backlog links.
|
|
11
|
+
* Matches: [WU-123 — Title text](path/to/file.yaml)
|
|
12
|
+
* Captures: WU ID (e.g., "WU-123")
|
|
13
|
+
*/
|
|
14
|
+
export declare const WU_LINK_PATTERN: RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a line matches an In Progress section header.
|
|
17
|
+
* @param {string} line - Line to check (will be trimmed and lowercased)
|
|
18
|
+
* @returns {boolean} True if line is an In Progress header
|
|
19
|
+
*/
|
|
20
|
+
export declare function isInProgressHeader(line: any): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backlog Parsing Patterns
|
|
3
|
+
*
|
|
4
|
+
* Centralizes patterns for parsing status.md and backlog.md files.
|
|
5
|
+
* Used by lane-checker.mjs and related backlog utilities.
|
|
6
|
+
*/
|
|
7
|
+
/** Markdown section header patterns for In Progress section */
|
|
8
|
+
export const IN_PROGRESS_HEADERS = ['## in progress', '## 🔧 in progress'];
|
|
9
|
+
/**
|
|
10
|
+
* Pattern for extracting WU ID from backlog links.
|
|
11
|
+
* Matches: [WU-123 — Title text](path/to/file.yaml)
|
|
12
|
+
* Captures: WU ID (e.g., "WU-123")
|
|
13
|
+
*/
|
|
14
|
+
export const WU_LINK_PATTERN = /\[([A-Z]+-\d+)\s*—\s*[^\]]+\]\([^)]+\)/gi;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a line matches an In Progress section header.
|
|
17
|
+
* @param {string} line - Line to check (will be trimmed and lowercased)
|
|
18
|
+
* @returns {boolean} True if line is an In Progress header
|
|
19
|
+
*/
|
|
20
|
+
export function isInProgressHeader(line) {
|
|
21
|
+
const normalized = line.trim().toLowerCase();
|
|
22
|
+
return IN_PROGRESS_HEADERS.some((header) => normalized === header || normalized.startsWith(header));
|
|
23
|
+
}
|