@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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GetSuggestions Use Case
|
|
3
|
+
*
|
|
4
|
+
* Applies orchestration rules to generate recommendations for next actions.
|
|
5
|
+
* Combines WU progress analysis with code path detection.
|
|
6
|
+
*
|
|
7
|
+
* @module get-suggestions.usecase
|
|
8
|
+
* @see {@link ../orchestration-rules.ts} - Rule functions
|
|
9
|
+
* @see {@link ../ports/metrics-collector.port.ts} - Port interface
|
|
10
|
+
*/
|
|
11
|
+
import type { IMetricsCollector } from '../ports/metrics-collector.port.js';
|
|
12
|
+
import type { Suggestion } from '../domain/orchestration.types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Bottleneck scores mapping WU IDs to their impact scores.
|
|
15
|
+
* Impact score = number of downstream WUs blocked by this WU.
|
|
16
|
+
*/
|
|
17
|
+
export type BottleneckScores = Record<string, number>;
|
|
18
|
+
/**
|
|
19
|
+
* Options for the GetSuggestions use case.
|
|
20
|
+
*/
|
|
21
|
+
export interface GetSuggestionsOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Code paths to analyse for mandatory agent triggers.
|
|
24
|
+
* When provided, detects which agents should be invoked.
|
|
25
|
+
*/
|
|
26
|
+
codePaths?: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Bottleneck impact scores from flow:bottlenecks analysis.
|
|
29
|
+
* When provided, suggestions for high-impact WUs are ranked higher
|
|
30
|
+
* within the same priority level.
|
|
31
|
+
*
|
|
32
|
+
* @see flow-bottlenecks.mjs for score calculation
|
|
33
|
+
*/
|
|
34
|
+
bottleneckScores?: BottleneckScores;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Use case for generating orchestration suggestions.
|
|
38
|
+
*
|
|
39
|
+
* Combines two sources of suggestions:
|
|
40
|
+
* 1. WU progress analysis - suggests agents based on current state
|
|
41
|
+
* 2. Code path analysis - detects mandatory agents from file patterns
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const collector = new FileSystemMetricsCollector(basePath);
|
|
45
|
+
* const useCase = new GetSuggestionsUseCase(collector);
|
|
46
|
+
*
|
|
47
|
+
* // Get suggestions based on current WU state
|
|
48
|
+
* const suggestions = await useCase.execute();
|
|
49
|
+
*
|
|
50
|
+
* // Get suggestions including code path analysis
|
|
51
|
+
* const suggestionsWithPaths = await useCase.execute({
|
|
52
|
+
* codePaths: ['supabase/migrations/001.sql', 'src/prompts/system.ts']
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
export declare class GetSuggestionsUseCase {
|
|
56
|
+
private readonly metricsCollector;
|
|
57
|
+
constructor(metricsCollector: IMetricsCollector);
|
|
58
|
+
/**
|
|
59
|
+
* Execute the use case to generate suggestions.
|
|
60
|
+
*
|
|
61
|
+
* @param options - Optional configuration including code paths and bottleneck scores
|
|
62
|
+
* @returns Promise resolving to prioritised suggestions
|
|
63
|
+
* @throws Error if collector methods fail
|
|
64
|
+
*/
|
|
65
|
+
execute(options?: GetSuggestionsOptions): Promise<Suggestion[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Enrich suggestions with impact score information in reason field.
|
|
68
|
+
*
|
|
69
|
+
* @param suggestions - Suggestions to enrich
|
|
70
|
+
* @param bottleneckScores - WU ID to impact score mapping
|
|
71
|
+
* @returns Enriched suggestions
|
|
72
|
+
*/
|
|
73
|
+
private enrichWithImpactScores;
|
|
74
|
+
/**
|
|
75
|
+
* Extract WU ID from a suggestion command.
|
|
76
|
+
*
|
|
77
|
+
* @param command - Command string containing WU ID
|
|
78
|
+
* @returns WU ID or null if not found
|
|
79
|
+
*/
|
|
80
|
+
private extractWuIdFromCommand;
|
|
81
|
+
/**
|
|
82
|
+
* Sort suggestions by priority, then by impact score within same priority.
|
|
83
|
+
*
|
|
84
|
+
* @param suggestions - Suggestions to sort
|
|
85
|
+
* @param bottleneckScores - WU ID to impact score mapping
|
|
86
|
+
* @returns Sorted suggestions
|
|
87
|
+
*/
|
|
88
|
+
private sortSuggestions;
|
|
89
|
+
/**
|
|
90
|
+
* Generate suggestions for mandatory agents detected from code paths.
|
|
91
|
+
*
|
|
92
|
+
* Avoids duplicating suggestions that already exist from WU progress analysis.
|
|
93
|
+
*
|
|
94
|
+
* @param mandatoryAgents - Agents detected from code paths
|
|
95
|
+
* @param existingSuggestions - Suggestions already generated
|
|
96
|
+
* @param wuId - WU ID for the suggestion
|
|
97
|
+
* @returns Additional suggestions for mandatory agents
|
|
98
|
+
*/
|
|
99
|
+
private generateMandatoryAgentSuggestions;
|
|
100
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GetSuggestions Use Case
|
|
3
|
+
*
|
|
4
|
+
* Applies orchestration rules to generate recommendations for next actions.
|
|
5
|
+
* Combines WU progress analysis with code path detection.
|
|
6
|
+
*
|
|
7
|
+
* @module get-suggestions.usecase
|
|
8
|
+
* @see {@link ../orchestration-rules.ts} - Rule functions
|
|
9
|
+
* @see {@link ../ports/metrics-collector.port.ts} - Port interface
|
|
10
|
+
*/
|
|
11
|
+
import { detectMandatoryAgents, generateSuggestions } from '../orchestration-rules.js';
|
|
12
|
+
/**
|
|
13
|
+
* Use case for generating orchestration suggestions.
|
|
14
|
+
*
|
|
15
|
+
* Combines two sources of suggestions:
|
|
16
|
+
* 1. WU progress analysis - suggests agents based on current state
|
|
17
|
+
* 2. Code path analysis - detects mandatory agents from file patterns
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const collector = new FileSystemMetricsCollector(basePath);
|
|
21
|
+
* const useCase = new GetSuggestionsUseCase(collector);
|
|
22
|
+
*
|
|
23
|
+
* // Get suggestions based on current WU state
|
|
24
|
+
* const suggestions = await useCase.execute();
|
|
25
|
+
*
|
|
26
|
+
* // Get suggestions including code path analysis
|
|
27
|
+
* const suggestionsWithPaths = await useCase.execute({
|
|
28
|
+
* codePaths: ['supabase/migrations/001.sql', 'src/prompts/system.ts']
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
export class GetSuggestionsUseCase {
|
|
32
|
+
metricsCollector;
|
|
33
|
+
constructor(metricsCollector) {
|
|
34
|
+
this.metricsCollector = metricsCollector;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute the use case to generate suggestions.
|
|
38
|
+
*
|
|
39
|
+
* @param options - Optional configuration including code paths and bottleneck scores
|
|
40
|
+
* @returns Promise resolving to prioritised suggestions
|
|
41
|
+
* @throws Error if collector methods fail
|
|
42
|
+
*/
|
|
43
|
+
async execute(options = {}) {
|
|
44
|
+
const { codePaths = [], bottleneckScores = {} } = options;
|
|
45
|
+
const [wuProgress, agentMetrics] = await Promise.all([
|
|
46
|
+
this.metricsCollector.getWUProgress(),
|
|
47
|
+
this.metricsCollector.getAgentMetrics(),
|
|
48
|
+
]);
|
|
49
|
+
// Generate suggestions from WU progress
|
|
50
|
+
let progressSuggestions = generateSuggestions(wuProgress, agentMetrics);
|
|
51
|
+
// Enrich suggestions with impact scores if available (WU-1596)
|
|
52
|
+
progressSuggestions = this.enrichWithImpactScores(progressSuggestions, bottleneckScores);
|
|
53
|
+
// Detect mandatory agents from code paths
|
|
54
|
+
const mandatoryAgents = detectMandatoryAgents(codePaths);
|
|
55
|
+
// Generate additional suggestions for detected mandatory agents
|
|
56
|
+
const pathSuggestions = this.generateMandatoryAgentSuggestions(mandatoryAgents, progressSuggestions, wuProgress.length > 0 ? wuProgress[0].wuId : 'current');
|
|
57
|
+
// Combine and deduplicate suggestions
|
|
58
|
+
const allSuggestions = [...progressSuggestions, ...pathSuggestions];
|
|
59
|
+
// Sort by priority (high > medium > low), then by impact score (descending)
|
|
60
|
+
return this.sortSuggestions(allSuggestions, bottleneckScores);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Enrich suggestions with impact score information in reason field.
|
|
64
|
+
*
|
|
65
|
+
* @param suggestions - Suggestions to enrich
|
|
66
|
+
* @param bottleneckScores - WU ID to impact score mapping
|
|
67
|
+
* @returns Enriched suggestions
|
|
68
|
+
*/
|
|
69
|
+
enrichWithImpactScores(suggestions, bottleneckScores) {
|
|
70
|
+
if (Object.keys(bottleneckScores).length === 0) {
|
|
71
|
+
return suggestions;
|
|
72
|
+
}
|
|
73
|
+
return suggestions.map((suggestion) => {
|
|
74
|
+
const wuId = this.extractWuIdFromCommand(suggestion.command);
|
|
75
|
+
if (!wuId) {
|
|
76
|
+
return suggestion;
|
|
77
|
+
}
|
|
78
|
+
const impactScore = bottleneckScores[wuId];
|
|
79
|
+
if (impactScore === undefined || impactScore === 0) {
|
|
80
|
+
return suggestion;
|
|
81
|
+
}
|
|
82
|
+
// Enrich reason with impact score
|
|
83
|
+
return {
|
|
84
|
+
...suggestion,
|
|
85
|
+
reason: `${suggestion.reason} (blocks ${impactScore} downstream WU${impactScore === 1 ? '' : 's'})`,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Extract WU ID from a suggestion command.
|
|
91
|
+
*
|
|
92
|
+
* @param command - Command string containing WU ID
|
|
93
|
+
* @returns WU ID or null if not found
|
|
94
|
+
*/
|
|
95
|
+
extractWuIdFromCommand(command) {
|
|
96
|
+
if (!command) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const match = command.match(/WU-\d+/);
|
|
100
|
+
return match ? match[0] : null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Sort suggestions by priority, then by impact score within same priority.
|
|
104
|
+
*
|
|
105
|
+
* @param suggestions - Suggestions to sort
|
|
106
|
+
* @param bottleneckScores - WU ID to impact score mapping
|
|
107
|
+
* @returns Sorted suggestions
|
|
108
|
+
*/
|
|
109
|
+
sortSuggestions(suggestions, bottleneckScores) {
|
|
110
|
+
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
111
|
+
return suggestions.sort((a, b) => {
|
|
112
|
+
// First sort by priority
|
|
113
|
+
const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
114
|
+
if (priorityDiff !== 0) {
|
|
115
|
+
return priorityDiff;
|
|
116
|
+
}
|
|
117
|
+
// Within same priority, sort by impact score (higher score first)
|
|
118
|
+
const aWuId = this.extractWuIdFromCommand(a.command);
|
|
119
|
+
const bWuId = this.extractWuIdFromCommand(b.command);
|
|
120
|
+
const aScore = aWuId ? (bottleneckScores[aWuId] ?? 0) : 0;
|
|
121
|
+
const bScore = bWuId ? (bottleneckScores[bWuId] ?? 0) : 0;
|
|
122
|
+
return bScore - aScore; // Descending order (higher score first)
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate suggestions for mandatory agents detected from code paths.
|
|
127
|
+
*
|
|
128
|
+
* Avoids duplicating suggestions that already exist from WU progress analysis.
|
|
129
|
+
*
|
|
130
|
+
* @param mandatoryAgents - Agents detected from code paths
|
|
131
|
+
* @param existingSuggestions - Suggestions already generated
|
|
132
|
+
* @param wuId - WU ID for the suggestion
|
|
133
|
+
* @returns Additional suggestions for mandatory agents
|
|
134
|
+
*/
|
|
135
|
+
generateMandatoryAgentSuggestions(mandatoryAgents, existingSuggestions, wuId) {
|
|
136
|
+
const suggestions = [];
|
|
137
|
+
let nextId = existingSuggestions.length + 1;
|
|
138
|
+
for (const agentName of mandatoryAgents) {
|
|
139
|
+
// Check if suggestion already exists for this agent
|
|
140
|
+
const alreadyExists = existingSuggestions.some((s) => s.action.toLowerCase().includes(agentName));
|
|
141
|
+
if (!alreadyExists) {
|
|
142
|
+
suggestions.push({
|
|
143
|
+
id: `sug-${(nextId++).toString().padStart(3, '0')}`,
|
|
144
|
+
priority: 'high',
|
|
145
|
+
action: `Run ${agentName}`,
|
|
146
|
+
reason: `Code paths indicate ${agentName} is required`,
|
|
147
|
+
command: `pnpm orchestrate:run ${agentName} --wu ${wuId}`,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return suggestions;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU-1333: User normalizer utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides email normalization and domain inference for WU ownership.
|
|
5
|
+
* Converts plain usernames (e.g., "tom") to email format (e.g., "tom@hellm.ai")
|
|
6
|
+
* using domain from git config or .lumenflow.config.yaml.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Default domain fallback when git config and lumenflow config unavailable
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_DOMAIN = "patientpath.co.uk";
|
|
12
|
+
/**
|
|
13
|
+
* Check if a value is a valid email address (simple check)
|
|
14
|
+
*
|
|
15
|
+
* @param {string|null|undefined} value - Value to check
|
|
16
|
+
* @returns {boolean} True if value is a valid email
|
|
17
|
+
*/
|
|
18
|
+
export declare function isValidEmail(value: any): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Infer the default email domain from available sources
|
|
21
|
+
*
|
|
22
|
+
* Priority:
|
|
23
|
+
* 1. Git config user.email domain
|
|
24
|
+
* 2. .lumenflow.config.yaml OWNER_EMAIL domain
|
|
25
|
+
* 3. DEFAULT_DOMAIN constant
|
|
26
|
+
*
|
|
27
|
+
* @param {string} [cwd] - Working directory for config lookup
|
|
28
|
+
* @returns {Promise<string>} Inferred domain (never null/undefined)
|
|
29
|
+
*/
|
|
30
|
+
export declare function inferDefaultDomain(cwd?: string): Promise<any>;
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a username or email to full email format
|
|
33
|
+
*
|
|
34
|
+
* If value is already a valid email, returns it unchanged (with normalization).
|
|
35
|
+
* If value is a plain username, appends the default domain.
|
|
36
|
+
*
|
|
37
|
+
* @param {string|null|undefined} value - Username or email
|
|
38
|
+
* @param {string} [domain] - Optional domain override
|
|
39
|
+
* @returns {Promise<string>} Normalized email address, or empty string for null/undefined
|
|
40
|
+
*/
|
|
41
|
+
export declare function normalizeToEmail(value: any, domain: any): Promise<string>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU-1333: User normalizer utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides email normalization and domain inference for WU ownership.
|
|
5
|
+
* Converts plain usernames (e.g., "tom") to email format (e.g., "tom@hellm.ai")
|
|
6
|
+
* using domain from git config or .lumenflow.config.yaml.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, access } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
11
|
+
/**
|
|
12
|
+
* Default domain fallback when git config and lumenflow config unavailable
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_DOMAIN = 'patientpath.co.uk';
|
|
15
|
+
/**
|
|
16
|
+
* Minimum length for a valid email local part
|
|
17
|
+
*/
|
|
18
|
+
const MIN_LOCAL_PART_LENGTH = 1;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a value is a valid email address (simple check)
|
|
21
|
+
*
|
|
22
|
+
* @param {string|null|undefined} value - Value to check
|
|
23
|
+
* @returns {boolean} True if value is a valid email
|
|
24
|
+
*/
|
|
25
|
+
export function isValidEmail(value) {
|
|
26
|
+
if (!value || typeof value !== 'string') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const str = value.trim();
|
|
30
|
+
// Simple email validation: must have @ with content before and after
|
|
31
|
+
const atIndex = str.indexOf('@');
|
|
32
|
+
return atIndex > 0 && atIndex < str.length - 1;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extract domain from an email address
|
|
36
|
+
*
|
|
37
|
+
* @param {string} email - Email address
|
|
38
|
+
* @returns {string|null} Domain part or null if invalid
|
|
39
|
+
*/
|
|
40
|
+
function extractDomain(email) {
|
|
41
|
+
if (!isValidEmail(email)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const atIndex = email.indexOf('@');
|
|
45
|
+
return email.slice(atIndex + 1);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Try to get domain from git config user.email
|
|
49
|
+
*
|
|
50
|
+
* @returns {Promise<string|null>} Domain from git config or null
|
|
51
|
+
*/
|
|
52
|
+
async function getDomainFromGitConfig() {
|
|
53
|
+
try {
|
|
54
|
+
const git = getGitForCwd();
|
|
55
|
+
const email = await git.getConfigValue('user.email');
|
|
56
|
+
return extractDomain(email?.trim() || '');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Try to get domain from .lumenflow.config.yaml OWNER_EMAIL
|
|
64
|
+
*
|
|
65
|
+
* @param {string} [cwd] - Working directory to search from
|
|
66
|
+
* @returns {Promise<string|null>} Domain from config or null
|
|
67
|
+
*/
|
|
68
|
+
async function getDomainFromLumenflowConfig(cwd = process.cwd()) {
|
|
69
|
+
const configPath = join(cwd, '.lumenflow.config.yaml');
|
|
70
|
+
try {
|
|
71
|
+
await access(configPath);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const content = await readFile(configPath, { encoding: 'utf-8' });
|
|
78
|
+
// Simple pattern match for OWNER_EMAIL (avoid full YAML parse for performance)
|
|
79
|
+
// Looking for: OWNER_EMAIL: "email@domain"
|
|
80
|
+
const match = content.match(/OWNER_EMAIL:\s*["']?([^"'\s]+)["']?/i);
|
|
81
|
+
if (match && match[1]) {
|
|
82
|
+
return extractDomain(match[1]);
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Infer the default email domain from available sources
|
|
92
|
+
*
|
|
93
|
+
* Priority:
|
|
94
|
+
* 1. Git config user.email domain
|
|
95
|
+
* 2. .lumenflow.config.yaml OWNER_EMAIL domain
|
|
96
|
+
* 3. DEFAULT_DOMAIN constant
|
|
97
|
+
*
|
|
98
|
+
* @param {string} [cwd] - Working directory for config lookup
|
|
99
|
+
* @returns {Promise<string>} Inferred domain (never null/undefined)
|
|
100
|
+
*/
|
|
101
|
+
export async function inferDefaultDomain(cwd = process.cwd()) {
|
|
102
|
+
// Try git config first
|
|
103
|
+
const gitDomain = await getDomainFromGitConfig();
|
|
104
|
+
if (gitDomain) {
|
|
105
|
+
return gitDomain;
|
|
106
|
+
}
|
|
107
|
+
// Try lumenflow config
|
|
108
|
+
const configDomain = await getDomainFromLumenflowConfig(cwd);
|
|
109
|
+
if (configDomain) {
|
|
110
|
+
return configDomain;
|
|
111
|
+
}
|
|
112
|
+
// Fallback to default
|
|
113
|
+
return DEFAULT_DOMAIN;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Normalize a username or email to full email format
|
|
117
|
+
*
|
|
118
|
+
* If value is already a valid email, returns it unchanged (with normalization).
|
|
119
|
+
* If value is a plain username, appends the default domain.
|
|
120
|
+
*
|
|
121
|
+
* @param {string|null|undefined} value - Username or email
|
|
122
|
+
* @param {string} [domain] - Optional domain override
|
|
123
|
+
* @returns {Promise<string>} Normalized email address, or empty string for null/undefined
|
|
124
|
+
*/
|
|
125
|
+
export async function normalizeToEmail(value, domain) {
|
|
126
|
+
// Handle null/undefined/empty
|
|
127
|
+
if (!value) {
|
|
128
|
+
return '';
|
|
129
|
+
}
|
|
130
|
+
const str = String(value).trim().toLowerCase();
|
|
131
|
+
if (str.length < MIN_LOCAL_PART_LENGTH) {
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
// Already a valid email - return as-is (normalized)
|
|
135
|
+
if (isValidEmail(str)) {
|
|
136
|
+
return str;
|
|
137
|
+
}
|
|
138
|
+
// Plain username - append domain
|
|
139
|
+
const effectiveDomain = domain || (await inferDefaultDomain());
|
|
140
|
+
return `${str}@${effectiveDomain}`;
|
|
141
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHI (Protected Health Information) Detection Constants
|
|
3
|
+
*
|
|
4
|
+
* Centralized constants for PHI scanner to detect NHS numbers and UK postcodes
|
|
5
|
+
* in medical context. Uses library-first approach with nhs-number-validator
|
|
6
|
+
* and postcode packages for validation.
|
|
7
|
+
*
|
|
8
|
+
* Part of WU-1404: PHI Scanner Integration
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://digital.nhs.uk/data-and-information/data-tools-and-services/data-services/nhs-number} NHS Number format
|
|
11
|
+
* @see {@link https://github.com/ideal-postcodes/postcode} Postcode validation library
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* PHI type identifiers for categorizing detected PHI
|
|
15
|
+
*/
|
|
16
|
+
export declare const PHI_TYPES: {
|
|
17
|
+
/** NHS number (10 digits with Modulus 11 checksum) */
|
|
18
|
+
NHS_NUMBER: string;
|
|
19
|
+
/** UK postcode detected in medical context */
|
|
20
|
+
POSTCODE_MEDICAL_CONTEXT: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Medical context keywords for postcode detection
|
|
24
|
+
*
|
|
25
|
+
* Postcodes are only flagged as PHI when they appear within proximity
|
|
26
|
+
* of these medical context keywords. This reduces false positives from
|
|
27
|
+
* legitimate postcode usage (e.g., hospital addresses in documentation).
|
|
28
|
+
*/
|
|
29
|
+
export declare const MEDICAL_CONTEXT_KEYWORDS: string[];
|
|
30
|
+
/**
|
|
31
|
+
* Context window size for medical keyword proximity detection
|
|
32
|
+
*
|
|
33
|
+
* When a postcode is found, we search this many characters before
|
|
34
|
+
* and after the postcode for medical context keywords.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MEDICAL_CONTEXT_WINDOW_SIZE = 100;
|
|
37
|
+
/**
|
|
38
|
+
* Known test NHS numbers that should not trigger PHI detection
|
|
39
|
+
*
|
|
40
|
+
* These are official test NHS numbers or commonly used in test fixtures.
|
|
41
|
+
* Source: NHS Digital test data guidelines
|
|
42
|
+
*/
|
|
43
|
+
export declare const TEST_NHS_NUMBERS: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Prefix for NHS test numbers (numbers starting with 999 are reserved for testing)
|
|
46
|
+
*/
|
|
47
|
+
export declare const NHS_TEST_PREFIX = "999";
|
|
48
|
+
/**
|
|
49
|
+
* Known test postcodes that should not trigger PHI detection
|
|
50
|
+
*
|
|
51
|
+
* These are commonly used in examples, documentation, and test fixtures.
|
|
52
|
+
*/
|
|
53
|
+
export declare const TEST_POSTCODES: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Content markers that indicate test/example data
|
|
56
|
+
*
|
|
57
|
+
* Content containing these markers should not trigger PHI detection.
|
|
58
|
+
*/
|
|
59
|
+
export declare const TEST_DATA_MARKERS: string[];
|
|
60
|
+
/**
|
|
61
|
+
* File path patterns that should be excluded from PHI scanning
|
|
62
|
+
*
|
|
63
|
+
* These patterns indicate test/fixture files where PHI patterns
|
|
64
|
+
* may legitimately appear for testing purposes.
|
|
65
|
+
*/
|
|
66
|
+
export declare const EXCLUDED_PATH_PATTERNS: RegExp[];
|
|
67
|
+
/**
|
|
68
|
+
* Candidate extraction pattern for NHS numbers
|
|
69
|
+
*
|
|
70
|
+
* Extracts 10-digit numeric sequences that could be NHS numbers.
|
|
71
|
+
* The library validates these with Modulus 11 checksum.
|
|
72
|
+
*
|
|
73
|
+
* NHS numbers may appear with or without spaces:
|
|
74
|
+
* - 1234567890
|
|
75
|
+
* - 123 456 7890
|
|
76
|
+
* - 123-456-7890
|
|
77
|
+
*/
|
|
78
|
+
export declare const NHS_CANDIDATE_PATTERN: RegExp;
|
|
79
|
+
/**
|
|
80
|
+
* PHI detection result structure
|
|
81
|
+
*
|
|
82
|
+
* @typedef {Object} PHIMatch
|
|
83
|
+
* @property {string} type - PHI type from PHI_TYPES
|
|
84
|
+
* @property {string} value - The matched value (may be masked)
|
|
85
|
+
* @property {number} startIndex - Start position in content
|
|
86
|
+
* @property {number} endIndex - End position in content
|
|
87
|
+
* @property {string} [context] - Surrounding context (optional)
|
|
88
|
+
* @property {string} [medicalKeyword] - Medical keyword that triggered postcode detection (optional)
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Scan result structure
|
|
92
|
+
*
|
|
93
|
+
* @typedef {Object} PHIScanResult
|
|
94
|
+
* @property {boolean} hasPHI - Whether PHI was detected
|
|
95
|
+
* @property {PHIMatch[]} matches - Array of PHI matches found
|
|
96
|
+
* @property {string[]} warnings - Non-blocking warnings (e.g., test data detected)
|
|
97
|
+
*/
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHI (Protected Health Information) Detection Constants
|
|
3
|
+
*
|
|
4
|
+
* Centralized constants for PHI scanner to detect NHS numbers and UK postcodes
|
|
5
|
+
* in medical context. Uses library-first approach with nhs-number-validator
|
|
6
|
+
* and postcode packages for validation.
|
|
7
|
+
*
|
|
8
|
+
* Part of WU-1404: PHI Scanner Integration
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://digital.nhs.uk/data-and-information/data-tools-and-services/data-services/nhs-number} NHS Number format
|
|
11
|
+
* @see {@link https://github.com/ideal-postcodes/postcode} Postcode validation library
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* PHI type identifiers for categorizing detected PHI
|
|
15
|
+
*/
|
|
16
|
+
export const PHI_TYPES = {
|
|
17
|
+
/** NHS number (10 digits with Modulus 11 checksum) */
|
|
18
|
+
NHS_NUMBER: 'NHS_NUMBER',
|
|
19
|
+
/** UK postcode detected in medical context */
|
|
20
|
+
POSTCODE_MEDICAL_CONTEXT: 'POSTCODE_MEDICAL_CONTEXT',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Medical context keywords for postcode detection
|
|
24
|
+
*
|
|
25
|
+
* Postcodes are only flagged as PHI when they appear within proximity
|
|
26
|
+
* of these medical context keywords. This reduces false positives from
|
|
27
|
+
* legitimate postcode usage (e.g., hospital addresses in documentation).
|
|
28
|
+
*/
|
|
29
|
+
export const MEDICAL_CONTEXT_KEYWORDS = [
|
|
30
|
+
'patient',
|
|
31
|
+
'medical record',
|
|
32
|
+
'gp surgery',
|
|
33
|
+
'nhs',
|
|
34
|
+
'hospital',
|
|
35
|
+
'clinic',
|
|
36
|
+
'registered address',
|
|
37
|
+
'home address',
|
|
38
|
+
'next of kin',
|
|
39
|
+
'emergency contact',
|
|
40
|
+
'admission',
|
|
41
|
+
'discharge',
|
|
42
|
+
'referral',
|
|
43
|
+
'diagnosis',
|
|
44
|
+
'treatment',
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Context window size for medical keyword proximity detection
|
|
48
|
+
*
|
|
49
|
+
* When a postcode is found, we search this many characters before
|
|
50
|
+
* and after the postcode for medical context keywords.
|
|
51
|
+
*/
|
|
52
|
+
export const MEDICAL_CONTEXT_WINDOW_SIZE = 100;
|
|
53
|
+
/**
|
|
54
|
+
* Known test NHS numbers that should not trigger PHI detection
|
|
55
|
+
*
|
|
56
|
+
* These are official test NHS numbers or commonly used in test fixtures.
|
|
57
|
+
* Source: NHS Digital test data guidelines
|
|
58
|
+
*/
|
|
59
|
+
export const TEST_NHS_NUMBERS = [
|
|
60
|
+
'4505577104', // Common test NHS number
|
|
61
|
+
'9999999999', // Range reserved for testing (999 prefix)
|
|
62
|
+
'9990000001', // Test range
|
|
63
|
+
'9990000002',
|
|
64
|
+
'9990000003',
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Prefix for NHS test numbers (numbers starting with 999 are reserved for testing)
|
|
68
|
+
*/
|
|
69
|
+
export const NHS_TEST_PREFIX = '999';
|
|
70
|
+
/**
|
|
71
|
+
* Known test postcodes that should not trigger PHI detection
|
|
72
|
+
*
|
|
73
|
+
* These are commonly used in examples, documentation, and test fixtures.
|
|
74
|
+
*/
|
|
75
|
+
export const TEST_POSTCODES = [
|
|
76
|
+
'SW1A 1AA', // Buckingham Palace - often used in examples
|
|
77
|
+
'SW1A1AA', // Same without space
|
|
78
|
+
'EC1A 1BB', // Commonly used test postcode
|
|
79
|
+
'EC1A1BB',
|
|
80
|
+
'W1A 1AA', // BBC Broadcasting House - frequently in docs
|
|
81
|
+
'W1A1AA',
|
|
82
|
+
];
|
|
83
|
+
/**
|
|
84
|
+
* Content markers that indicate test/example data
|
|
85
|
+
*
|
|
86
|
+
* Content containing these markers should not trigger PHI detection.
|
|
87
|
+
*/
|
|
88
|
+
export const TEST_DATA_MARKERS = [
|
|
89
|
+
'[TEST]',
|
|
90
|
+
'[EXAMPLE]',
|
|
91
|
+
'[PLACEHOLDER]',
|
|
92
|
+
'[SAMPLE]',
|
|
93
|
+
'// test data',
|
|
94
|
+
'/* test data */',
|
|
95
|
+
'# test data',
|
|
96
|
+
'test-data',
|
|
97
|
+
'testData',
|
|
98
|
+
'TEST_DATA',
|
|
99
|
+
'example-data',
|
|
100
|
+
'sample-data',
|
|
101
|
+
'mock-data',
|
|
102
|
+
'fixture',
|
|
103
|
+
];
|
|
104
|
+
/**
|
|
105
|
+
* File path patterns that should be excluded from PHI scanning
|
|
106
|
+
*
|
|
107
|
+
* These patterns indicate test/fixture files where PHI patterns
|
|
108
|
+
* may legitimately appear for testing purposes.
|
|
109
|
+
*/
|
|
110
|
+
export const EXCLUDED_PATH_PATTERNS = [
|
|
111
|
+
/\/__tests__\//i,
|
|
112
|
+
/\/test\//i,
|
|
113
|
+
/\/tests\//i,
|
|
114
|
+
/\.test\./i,
|
|
115
|
+
/\.spec\./i,
|
|
116
|
+
/\/fixtures?\//i,
|
|
117
|
+
/\/mocks?\//i,
|
|
118
|
+
/\/__mocks__\//i,
|
|
119
|
+
/\/VCR\/cassettes\//i,
|
|
120
|
+
/\.md$/i, // Documentation files have different risk profile
|
|
121
|
+
];
|
|
122
|
+
/**
|
|
123
|
+
* Candidate extraction pattern for NHS numbers
|
|
124
|
+
*
|
|
125
|
+
* Extracts 10-digit numeric sequences that could be NHS numbers.
|
|
126
|
+
* The library validates these with Modulus 11 checksum.
|
|
127
|
+
*
|
|
128
|
+
* NHS numbers may appear with or without spaces:
|
|
129
|
+
* - 1234567890
|
|
130
|
+
* - 123 456 7890
|
|
131
|
+
* - 123-456-7890
|
|
132
|
+
*/
|
|
133
|
+
export const NHS_CANDIDATE_PATTERN = /\b(\d{3}[\s-]?\d{3}[\s-]?\d{4})\b/g;
|
|
134
|
+
/**
|
|
135
|
+
* PHI detection result structure
|
|
136
|
+
*
|
|
137
|
+
* @typedef {Object} PHIMatch
|
|
138
|
+
* @property {string} type - PHI type from PHI_TYPES
|
|
139
|
+
* @property {string} value - The matched value (may be masked)
|
|
140
|
+
* @property {number} startIndex - Start position in content
|
|
141
|
+
* @property {number} endIndex - End position in content
|
|
142
|
+
* @property {string} [context] - Surrounding context (optional)
|
|
143
|
+
* @property {string} [medicalKeyword] - Medical keyword that triggered postcode detection (optional)
|
|
144
|
+
*/
|
|
145
|
+
/**
|
|
146
|
+
* Scan result structure
|
|
147
|
+
*
|
|
148
|
+
* @typedef {Object} PHIScanResult
|
|
149
|
+
* @property {boolean} hasPHI - Whether PHI was detected
|
|
150
|
+
* @property {PHIMatch[]} matches - Array of PHI matches found
|
|
151
|
+
* @property {string[]} warnings - Non-blocking warnings (e.g., test data detected)
|
|
152
|
+
*/
|