@lumenflow/core 1.5.0 → 2.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/README.md +325 -1
- package/dist/adapters/context-adapters.d.ts +90 -0
- package/dist/adapters/context-adapters.js +99 -0
- package/dist/adapters/index.d.ts +14 -0
- package/dist/adapters/index.js +18 -0
- package/dist/adapters/recovery-adapters.d.ts +40 -0
- package/dist/adapters/recovery-adapters.js +43 -0
- package/dist/adapters/validation-adapters.d.ts +52 -0
- package/dist/adapters/validation-adapters.js +59 -0
- package/dist/context/context-computer.d.ts +46 -0
- package/dist/context/context-computer.js +125 -0
- package/dist/context/git-state-reader.d.ts +51 -0
- package/dist/context/git-state-reader.js +61 -0
- package/dist/context/index.d.ts +17 -0
- package/dist/context/index.js +17 -0
- package/dist/context/location-resolver.d.ts +48 -0
- package/dist/context/location-resolver.js +175 -0
- package/dist/context/wu-state-reader.d.ts +37 -0
- package/dist/context/wu-state-reader.js +76 -0
- package/dist/context-di.d.ts +184 -0
- package/dist/context-di.js +178 -0
- package/dist/context-validation-integration.d.ts +77 -0
- package/dist/context-validation-integration.js +157 -0
- package/dist/domain/context.schemas.d.ts +147 -0
- package/dist/domain/context.schemas.js +126 -0
- package/dist/domain/index.d.ts +14 -0
- package/dist/domain/index.js +18 -0
- package/dist/domain/recovery.schemas.d.ts +115 -0
- package/dist/domain/recovery.schemas.js +83 -0
- package/dist/domain/validation.schemas.d.ts +146 -0
- package/dist/domain/validation.schemas.js +114 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +43 -0
- package/dist/lumenflow-config-schema.d.ts +41 -0
- package/dist/lumenflow-config-schema.js +37 -0
- package/dist/ports/context.ports.d.ts +135 -0
- package/dist/ports/context.ports.js +21 -0
- package/dist/ports/core-tools.ports.d.ts +266 -0
- package/dist/ports/core-tools.ports.js +21 -0
- package/dist/ports/git-validator.ports.d.ts +314 -0
- package/dist/ports/git-validator.ports.js +12 -0
- package/dist/ports/index.d.ts +20 -0
- package/dist/ports/index.js +20 -0
- package/dist/ports/recovery.ports.d.ts +58 -0
- package/dist/ports/recovery.ports.js +17 -0
- package/dist/ports/validation.ports.d.ts +74 -0
- package/dist/ports/validation.ports.js +17 -0
- package/dist/ports/wu-helpers.ports.d.ts +224 -0
- package/dist/ports/wu-helpers.ports.js +12 -0
- package/dist/recovery/index.d.ts +11 -0
- package/dist/recovery/index.js +11 -0
- package/dist/recovery/recovery-analyzer.d.ts +66 -0
- package/dist/recovery/recovery-analyzer.js +129 -0
- package/dist/usecases/analyze-recovery.usecase.d.ts +42 -0
- package/dist/usecases/analyze-recovery.usecase.js +45 -0
- package/dist/usecases/compute-context.usecase.d.ts +62 -0
- package/dist/usecases/compute-context.usecase.js +101 -0
- package/dist/usecases/index.d.ts +14 -0
- package/dist/usecases/index.js +18 -0
- package/dist/usecases/validate-command.usecase.d.ts +55 -0
- package/dist/usecases/validate-command.usecase.js +154 -0
- package/dist/validation/command-registry.d.ts +38 -0
- package/dist/validation/command-registry.js +229 -0
- package/dist/validation/index.d.ts +15 -0
- package/dist/validation/index.js +15 -0
- package/dist/validation/types.d.ts +135 -0
- package/dist/validation/types.js +11 -0
- package/dist/validation/validate-command.d.ts +27 -0
- package/dist/validation/validate-command.js +160 -0
- package/dist/wu-constants.d.ts +136 -0
- package/dist/wu-constants.js +124 -0
- package/dist/wu-helpers.d.ts +5 -1
- package/dist/wu-helpers.js +12 -1
- package/package.json +4 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery Ports
|
|
3
|
+
*
|
|
4
|
+
* WU-1093: INIT-002 Phase 1 - Define ports and domain schemas
|
|
5
|
+
*
|
|
6
|
+
* Port interfaces for recovery-related operations.
|
|
7
|
+
* These abstractions allow external users to inject custom implementations.
|
|
8
|
+
*
|
|
9
|
+
* Hexagonal Architecture - Input Ports:
|
|
10
|
+
* - IRecoveryAnalyzer: Analyze WU state issues and suggest recovery actions
|
|
11
|
+
*
|
|
12
|
+
* Current Implementations:
|
|
13
|
+
* - analyzeRecovery (recovery-analyzer.ts)
|
|
14
|
+
*
|
|
15
|
+
* @module ports/recovery
|
|
16
|
+
*/
|
|
17
|
+
import type { WuContext } from '../validation/types.js';
|
|
18
|
+
import type { RecoveryAnalysis } from '../recovery/recovery-analyzer.js';
|
|
19
|
+
/**
|
|
20
|
+
* Recovery Analyzer Port Interface
|
|
21
|
+
*
|
|
22
|
+
* Analyzes WU context to detect state inconsistencies and suggests
|
|
23
|
+
* appropriate recovery actions.
|
|
24
|
+
*
|
|
25
|
+
* Issue types detected:
|
|
26
|
+
* - Partial claim: worktree exists but status is ready
|
|
27
|
+
* - Orphan claim: status is in_progress but worktree missing
|
|
28
|
+
* - Inconsistent state: YAML and state store disagree
|
|
29
|
+
* - Orphan branch: branch exists but worktree missing
|
|
30
|
+
* - Stale lock: lock file from old session
|
|
31
|
+
* - Leftover worktree: WU is done but worktree exists
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Custom implementation for testing
|
|
35
|
+
* const mockAnalyzer: IRecoveryAnalyzer = {
|
|
36
|
+
* analyzeRecovery: async (context) => ({
|
|
37
|
+
* hasIssues: false,
|
|
38
|
+
* issues: [],
|
|
39
|
+
* actions: [],
|
|
40
|
+
* wuId: context.wu?.id ?? null,
|
|
41
|
+
* }),
|
|
42
|
+
* };
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Using default implementation
|
|
46
|
+
* import { analyzeRecovery } from './recovery/recovery-analyzer.js';
|
|
47
|
+
* const analyzer: IRecoveryAnalyzer = { analyzeRecovery };
|
|
48
|
+
*/
|
|
49
|
+
export interface IRecoveryAnalyzer {
|
|
50
|
+
/**
|
|
51
|
+
* Analyze context for recovery issues.
|
|
52
|
+
*
|
|
53
|
+
* @param context - Current WU context
|
|
54
|
+
* @returns Promise<RecoveryAnalysis> - Recovery analysis with issues and suggested actions
|
|
55
|
+
*/
|
|
56
|
+
analyzeRecovery(context: WuContext): Promise<RecoveryAnalysis>;
|
|
57
|
+
}
|
|
58
|
+
export type { WuContext, RecoveryAnalysis };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery Ports
|
|
3
|
+
*
|
|
4
|
+
* WU-1093: INIT-002 Phase 1 - Define ports and domain schemas
|
|
5
|
+
*
|
|
6
|
+
* Port interfaces for recovery-related operations.
|
|
7
|
+
* These abstractions allow external users to inject custom implementations.
|
|
8
|
+
*
|
|
9
|
+
* Hexagonal Architecture - Input Ports:
|
|
10
|
+
* - IRecoveryAnalyzer: Analyze WU state issues and suggest recovery actions
|
|
11
|
+
*
|
|
12
|
+
* Current Implementations:
|
|
13
|
+
* - analyzeRecovery (recovery-analyzer.ts)
|
|
14
|
+
*
|
|
15
|
+
* @module ports/recovery
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Ports
|
|
3
|
+
*
|
|
4
|
+
* WU-1093: INIT-002 Phase 1 - Define ports and domain schemas
|
|
5
|
+
*
|
|
6
|
+
* Port interfaces for validation-related operations.
|
|
7
|
+
* These abstractions allow external users to inject custom implementations.
|
|
8
|
+
*
|
|
9
|
+
* Hexagonal Architecture - Input Ports:
|
|
10
|
+
* - ICommandRegistry: Lookup command definitions and validate commands
|
|
11
|
+
*
|
|
12
|
+
* Current Implementations:
|
|
13
|
+
* - COMMAND_REGISTRY, getCommandDefinition, getValidCommandsForContext (command-registry.ts)
|
|
14
|
+
*
|
|
15
|
+
* @module ports/validation
|
|
16
|
+
*/
|
|
17
|
+
import type { CommandDefinition, WuContext } from '../validation/types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Command Registry Port Interface
|
|
20
|
+
*
|
|
21
|
+
* Provides command definitions and validation logic for wu:* commands.
|
|
22
|
+
* Allows looking up command requirements and determining valid commands
|
|
23
|
+
* for a given context.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Custom implementation for testing
|
|
27
|
+
* const mockRegistry: ICommandRegistry = {
|
|
28
|
+
* getCommandDefinition: (cmd) => cmd === 'wu:done' ? {...} : null,
|
|
29
|
+
* getValidCommandsForContext: (ctx) => [...],
|
|
30
|
+
* getAllCommands: () => [...],
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Using default implementation
|
|
35
|
+
* import {
|
|
36
|
+
* getCommandDefinition,
|
|
37
|
+
* getValidCommandsForContext,
|
|
38
|
+
* COMMAND_REGISTRY,
|
|
39
|
+
* } from './validation/command-registry.js';
|
|
40
|
+
*
|
|
41
|
+
* const registry: ICommandRegistry = {
|
|
42
|
+
* getCommandDefinition,
|
|
43
|
+
* getValidCommandsForContext,
|
|
44
|
+
* getAllCommands: () => Array.from(COMMAND_REGISTRY.values()),
|
|
45
|
+
* };
|
|
46
|
+
*/
|
|
47
|
+
export interface ICommandRegistry {
|
|
48
|
+
/**
|
|
49
|
+
* Get command definition by name.
|
|
50
|
+
*
|
|
51
|
+
* @param command - Command name (e.g., 'wu:create', 'wu:done')
|
|
52
|
+
* @returns CommandDefinition or null if not found
|
|
53
|
+
*/
|
|
54
|
+
getCommandDefinition(command: string): CommandDefinition | null;
|
|
55
|
+
/**
|
|
56
|
+
* Get all commands valid for the current context.
|
|
57
|
+
*
|
|
58
|
+
* A command is valid if:
|
|
59
|
+
* - Location requirement is satisfied (or null = any)
|
|
60
|
+
* - WU status requirement is satisfied (or null = no WU required)
|
|
61
|
+
* - All error-severity predicates pass
|
|
62
|
+
*
|
|
63
|
+
* @param context - Current WU context
|
|
64
|
+
* @returns Array of valid CommandDefinitions
|
|
65
|
+
*/
|
|
66
|
+
getValidCommandsForContext(context: WuContext): CommandDefinition[];
|
|
67
|
+
/**
|
|
68
|
+
* Get all registered command definitions.
|
|
69
|
+
*
|
|
70
|
+
* @returns Array of all CommandDefinitions
|
|
71
|
+
*/
|
|
72
|
+
getAllCommands(): CommandDefinition[];
|
|
73
|
+
}
|
|
74
|
+
export type { CommandDefinition, WuContext };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Ports
|
|
3
|
+
*
|
|
4
|
+
* WU-1093: INIT-002 Phase 1 - Define ports and domain schemas
|
|
5
|
+
*
|
|
6
|
+
* Port interfaces for validation-related operations.
|
|
7
|
+
* These abstractions allow external users to inject custom implementations.
|
|
8
|
+
*
|
|
9
|
+
* Hexagonal Architecture - Input Ports:
|
|
10
|
+
* - ICommandRegistry: Lookup command definitions and validate commands
|
|
11
|
+
*
|
|
12
|
+
* Current Implementations:
|
|
13
|
+
* - COMMAND_REGISTRY, getCommandDefinition, getValidCommandsForContext (command-registry.ts)
|
|
14
|
+
*
|
|
15
|
+
* @module ports/validation
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU Helpers Port Interfaces
|
|
3
|
+
*
|
|
4
|
+
* WU-1102: INIT-003 Phase 2b - Port interfaces for WU helper modules
|
|
5
|
+
*
|
|
6
|
+
* Hexagonal Architecture - Input Ports:
|
|
7
|
+
* These abstractions allow external users to inject custom implementations
|
|
8
|
+
* for WU lifecycle operations.
|
|
9
|
+
*
|
|
10
|
+
* @module ports/wu-helpers
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Git adapter interface for ensureOnMain and ensureMainUpToDate operations
|
|
14
|
+
*/
|
|
15
|
+
export interface IWuGitAdapter {
|
|
16
|
+
/**
|
|
17
|
+
* Get the current git branch name
|
|
18
|
+
* @returns Promise resolving to branch name
|
|
19
|
+
*/
|
|
20
|
+
getCurrentBranch(): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Fetch from a remote
|
|
23
|
+
* @param remote - Remote name (e.g., 'origin')
|
|
24
|
+
* @param branch - Branch name (e.g., 'main')
|
|
25
|
+
*/
|
|
26
|
+
fetch(remote: string, branch: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get commit hash for a ref
|
|
29
|
+
* @param ref - Git ref (branch, tag, or commit)
|
|
30
|
+
* @returns Promise resolving to commit hash
|
|
31
|
+
*/
|
|
32
|
+
getCommitHash(ref: string): Promise<string>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* WU status check result
|
|
36
|
+
*/
|
|
37
|
+
export interface IWuStatusCheckResult {
|
|
38
|
+
/** Whether the operation is allowed */
|
|
39
|
+
allowed: boolean;
|
|
40
|
+
/** Current WU status */
|
|
41
|
+
status: string | null;
|
|
42
|
+
/** Error message if not allowed */
|
|
43
|
+
error: string | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Branch validation result
|
|
47
|
+
*/
|
|
48
|
+
export interface IBranchValidationResult {
|
|
49
|
+
/** Whether the branch name is valid */
|
|
50
|
+
valid: boolean;
|
|
51
|
+
/** Lane name (kebab-case) or null */
|
|
52
|
+
lane: string | null;
|
|
53
|
+
/** WU ID (uppercase) or null */
|
|
54
|
+
wuid: string | null;
|
|
55
|
+
/** Error message if invalid */
|
|
56
|
+
error: string | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* WU YAML reader interface
|
|
60
|
+
*/
|
|
61
|
+
export interface IWuYamlReader {
|
|
62
|
+
/**
|
|
63
|
+
* Read and parse WU YAML file
|
|
64
|
+
* @param wuPath - Path to WU YAML file
|
|
65
|
+
* @param expectedId - Expected WU ID for validation
|
|
66
|
+
* @returns Parsed WU document
|
|
67
|
+
*/
|
|
68
|
+
readWU(wuPath: string, expectedId: string): unknown;
|
|
69
|
+
/**
|
|
70
|
+
* Read YAML file without ID validation
|
|
71
|
+
* @param yamlPath - Path to YAML file
|
|
72
|
+
* @returns Parsed document
|
|
73
|
+
*/
|
|
74
|
+
readWURaw(yamlPath: string): unknown;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* WU YAML writer interface
|
|
78
|
+
*/
|
|
79
|
+
export interface IWuYamlWriter {
|
|
80
|
+
/**
|
|
81
|
+
* Write WU document to file
|
|
82
|
+
* @param wuPath - Path to WU YAML file
|
|
83
|
+
* @param doc - Document to write
|
|
84
|
+
*/
|
|
85
|
+
writeWU(wuPath: string, doc: unknown): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* WU state store interface (subset for dependency injection)
|
|
89
|
+
*/
|
|
90
|
+
export interface IWuStateStore {
|
|
91
|
+
/**
|
|
92
|
+
* Load state from events file
|
|
93
|
+
*/
|
|
94
|
+
load(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Claim a WU (transition to in_progress)
|
|
97
|
+
* @param wuId - WU identifier
|
|
98
|
+
* @param lane - Lane name
|
|
99
|
+
* @param title - WU title
|
|
100
|
+
*/
|
|
101
|
+
claim(wuId: string, lane: string, title: string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Complete a WU (transition to done)
|
|
104
|
+
* @param wuId - WU identifier
|
|
105
|
+
*/
|
|
106
|
+
complete(wuId: string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Block a WU (transition to blocked)
|
|
109
|
+
* @param wuId - WU identifier
|
|
110
|
+
* @param reason - Block reason
|
|
111
|
+
*/
|
|
112
|
+
block(wuId: string, reason: string): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Unblock a WU (transition back to in_progress)
|
|
115
|
+
* @param wuId - WU identifier
|
|
116
|
+
*/
|
|
117
|
+
unblock(wuId: string): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Release a WU (transition to ready)
|
|
120
|
+
* @param wuId - WU identifier
|
|
121
|
+
* @param reason - Release reason
|
|
122
|
+
*/
|
|
123
|
+
release(wuId: string, reason: string): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Get WU state entry
|
|
126
|
+
* @param wuId - WU identifier
|
|
127
|
+
* @returns State entry or undefined
|
|
128
|
+
*/
|
|
129
|
+
getWUState(wuId: string): {
|
|
130
|
+
status: string;
|
|
131
|
+
lane: string;
|
|
132
|
+
title: string;
|
|
133
|
+
} | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Get all WU IDs by status
|
|
136
|
+
* @param status - Status to filter by
|
|
137
|
+
* @returns Set of WU IDs
|
|
138
|
+
*/
|
|
139
|
+
getByStatus(status: string): Set<string>;
|
|
140
|
+
/**
|
|
141
|
+
* Get all WU IDs by lane
|
|
142
|
+
* @param lane - Lane to filter by
|
|
143
|
+
* @returns Set of WU IDs
|
|
144
|
+
*/
|
|
145
|
+
getByLane(lane: string): Set<string>;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* WU checkpoint interface
|
|
149
|
+
*/
|
|
150
|
+
export interface IWuCheckpointManager {
|
|
151
|
+
/**
|
|
152
|
+
* Create a pre-gates checkpoint
|
|
153
|
+
*/
|
|
154
|
+
createPreGatesCheckpoint(params: {
|
|
155
|
+
wuId: string;
|
|
156
|
+
worktreePath: string;
|
|
157
|
+
branchName: string;
|
|
158
|
+
gatesPassed?: boolean;
|
|
159
|
+
}, options?: {
|
|
160
|
+
baseDir?: string;
|
|
161
|
+
}): Promise<{
|
|
162
|
+
checkpointId: string;
|
|
163
|
+
gatesPassed: boolean;
|
|
164
|
+
}>;
|
|
165
|
+
/**
|
|
166
|
+
* Mark checkpoint as gates passed
|
|
167
|
+
* @param wuId - WU identifier
|
|
168
|
+
* @returns True if updated
|
|
169
|
+
*/
|
|
170
|
+
markGatesPassed(wuId: string, options?: {
|
|
171
|
+
baseDir?: string;
|
|
172
|
+
}): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Get checkpoint for a WU
|
|
175
|
+
* @param wuId - WU identifier
|
|
176
|
+
* @returns Checkpoint or null
|
|
177
|
+
*/
|
|
178
|
+
getCheckpoint(wuId: string, options?: {
|
|
179
|
+
baseDir?: string;
|
|
180
|
+
}): {
|
|
181
|
+
gatesPassed: boolean;
|
|
182
|
+
worktreeHeadSha: string;
|
|
183
|
+
} | null;
|
|
184
|
+
/**
|
|
185
|
+
* Clear checkpoint
|
|
186
|
+
* @param wuId - WU identifier
|
|
187
|
+
*/
|
|
188
|
+
clearCheckpoint(wuId: string, options?: {
|
|
189
|
+
baseDir?: string;
|
|
190
|
+
}): void;
|
|
191
|
+
/**
|
|
192
|
+
* Check if gates can be skipped
|
|
193
|
+
*/
|
|
194
|
+
canSkipGates(wuId: string, options?: {
|
|
195
|
+
baseDir?: string;
|
|
196
|
+
currentHeadSha?: string;
|
|
197
|
+
}): {
|
|
198
|
+
canSkip: boolean;
|
|
199
|
+
reason?: string;
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* WU paths interface
|
|
204
|
+
*/
|
|
205
|
+
export interface IWuPaths {
|
|
206
|
+
/** Get path to WU YAML file */
|
|
207
|
+
WU(id: string): string;
|
|
208
|
+
/** Get path to WU directory */
|
|
209
|
+
WU_DIR(): string;
|
|
210
|
+
/** Get path to status.md */
|
|
211
|
+
STATUS(): string;
|
|
212
|
+
/** Get path to backlog.md */
|
|
213
|
+
BACKLOG(): string;
|
|
214
|
+
/** Get path to stamps directory */
|
|
215
|
+
STAMPS_DIR(): string;
|
|
216
|
+
/** Get path to WU done stamp file */
|
|
217
|
+
STAMP(id: string): string;
|
|
218
|
+
/** Get path to state directory */
|
|
219
|
+
STATE_DIR(): string;
|
|
220
|
+
/** Get path to initiatives directory */
|
|
221
|
+
INITIATIVES_DIR(): string;
|
|
222
|
+
/** Get path to worktrees directory */
|
|
223
|
+
WORKTREES_DIR(): string;
|
|
224
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU Helpers Port Interfaces
|
|
3
|
+
*
|
|
4
|
+
* WU-1102: INIT-003 Phase 2b - Port interfaces for WU helper modules
|
|
5
|
+
*
|
|
6
|
+
* Hexagonal Architecture - Input Ports:
|
|
7
|
+
* These abstractions allow external users to inject custom implementations
|
|
8
|
+
* for WU lifecycle operations.
|
|
9
|
+
*
|
|
10
|
+
* @module ports/wu-helpers
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery Analyzer for WU State Issues
|
|
3
|
+
*
|
|
4
|
+
* WU-1090: Context-aware state machine for WU lifecycle commands
|
|
5
|
+
*
|
|
6
|
+
* Analyzes WU context to detect state inconsistencies and suggests
|
|
7
|
+
* appropriate recovery actions.
|
|
8
|
+
*
|
|
9
|
+
* Issue types detected:
|
|
10
|
+
* - Partial claim: worktree exists but status is ready
|
|
11
|
+
* - Orphan claim: status is in_progress but worktree missing
|
|
12
|
+
* - Inconsistent state: YAML and state store disagree
|
|
13
|
+
* - Orphan branch: branch exists but worktree missing
|
|
14
|
+
* - Stale lock: lock file from old session
|
|
15
|
+
* - Leftover worktree: WU is done but worktree exists
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { type RecoveryActionType, type RecoveryIssueCode } from '../wu-constants.js';
|
|
20
|
+
import type { WuContext } from '../validation/types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Issue detected during recovery analysis.
|
|
23
|
+
*/
|
|
24
|
+
export interface RecoveryIssue {
|
|
25
|
+
/** Issue code from RECOVERY_ISSUES */
|
|
26
|
+
code: RecoveryIssueCode;
|
|
27
|
+
/** Human-readable description */
|
|
28
|
+
description: string;
|
|
29
|
+
/** Additional context for the issue */
|
|
30
|
+
context?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Suggested recovery action.
|
|
34
|
+
*/
|
|
35
|
+
export interface WuRecoveryAction {
|
|
36
|
+
/** Action type from RECOVERY_ACTIONS */
|
|
37
|
+
type: RecoveryActionType;
|
|
38
|
+
/** Human-readable description of what this action does */
|
|
39
|
+
description: string;
|
|
40
|
+
/** Command to execute (copy-paste ready) */
|
|
41
|
+
command: string;
|
|
42
|
+
/** Whether this action requires --force flag */
|
|
43
|
+
requiresForce: boolean;
|
|
44
|
+
/** Warning message if any */
|
|
45
|
+
warning?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Result of recovery analysis.
|
|
49
|
+
*/
|
|
50
|
+
export interface RecoveryAnalysis {
|
|
51
|
+
/** Whether any issues were found */
|
|
52
|
+
hasIssues: boolean;
|
|
53
|
+
/** List of detected issues */
|
|
54
|
+
issues: RecoveryIssue[];
|
|
55
|
+
/** Suggested recovery actions */
|
|
56
|
+
actions: WuRecoveryAction[];
|
|
57
|
+
/** WU ID analyzed */
|
|
58
|
+
wuId: string | null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Analyze context for recovery issues.
|
|
62
|
+
*
|
|
63
|
+
* @param context - Current WU context
|
|
64
|
+
* @returns Recovery analysis with issues and suggested actions
|
|
65
|
+
*/
|
|
66
|
+
export declare function analyzeRecovery(context: WuContext): Promise<RecoveryAnalysis>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery Analyzer for WU State Issues
|
|
3
|
+
*
|
|
4
|
+
* WU-1090: Context-aware state machine for WU lifecycle commands
|
|
5
|
+
*
|
|
6
|
+
* Analyzes WU context to detect state inconsistencies and suggests
|
|
7
|
+
* appropriate recovery actions.
|
|
8
|
+
*
|
|
9
|
+
* Issue types detected:
|
|
10
|
+
* - Partial claim: worktree exists but status is ready
|
|
11
|
+
* - Orphan claim: status is in_progress but worktree missing
|
|
12
|
+
* - Inconsistent state: YAML and state store disagree
|
|
13
|
+
* - Orphan branch: branch exists but worktree missing
|
|
14
|
+
* - Stale lock: lock file from old session
|
|
15
|
+
* - Leftover worktree: WU is done but worktree exists
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { CONTEXT_VALIDATION, WU_STATUS, DEFAULTS, toKebab, } from '../wu-constants.js';
|
|
22
|
+
const { RECOVERY_ISSUES, RECOVERY_ACTIONS } = CONTEXT_VALIDATION;
|
|
23
|
+
/**
|
|
24
|
+
* Get expected worktree path for a WU.
|
|
25
|
+
*/
|
|
26
|
+
function getExpectedWorktreePath(mainCheckout, lane, wuId) {
|
|
27
|
+
const laneKebab = toKebab(lane);
|
|
28
|
+
const wuIdLower = wuId.toLowerCase();
|
|
29
|
+
return join(mainCheckout, DEFAULTS.WORKTREES_DIR, `${laneKebab}-${wuIdLower}`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if worktree exists for a WU.
|
|
33
|
+
*/
|
|
34
|
+
function worktreeExists(mainCheckout, lane, wuId) {
|
|
35
|
+
const worktreePath = getExpectedWorktreePath(mainCheckout, lane, wuId);
|
|
36
|
+
return existsSync(worktreePath);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Analyze context for recovery issues.
|
|
40
|
+
*
|
|
41
|
+
* @param context - Current WU context
|
|
42
|
+
* @returns Recovery analysis with issues and suggested actions
|
|
43
|
+
*/
|
|
44
|
+
export async function analyzeRecovery(context) {
|
|
45
|
+
const issues = [];
|
|
46
|
+
const actions = [];
|
|
47
|
+
// No WU context means nothing to analyze
|
|
48
|
+
if (!context.wu) {
|
|
49
|
+
return {
|
|
50
|
+
hasIssues: false,
|
|
51
|
+
issues: [],
|
|
52
|
+
actions: [],
|
|
53
|
+
wuId: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const { wu } = context;
|
|
57
|
+
const mainCheckout = context.location.mainCheckout;
|
|
58
|
+
const hasWorktree = worktreeExists(mainCheckout, wu.lane, wu.id);
|
|
59
|
+
const worktreePath = getExpectedWorktreePath(mainCheckout, wu.lane, wu.id);
|
|
60
|
+
// Check for partial claim: worktree exists but status is ready
|
|
61
|
+
if (hasWorktree && wu.status === WU_STATUS.READY) {
|
|
62
|
+
issues.push({
|
|
63
|
+
code: RECOVERY_ISSUES.PARTIAL_CLAIM,
|
|
64
|
+
description: `Worktree exists for ${wu.id} but status is 'ready'. The claim may have been interrupted.`,
|
|
65
|
+
context: { worktreePath, status: wu.status },
|
|
66
|
+
});
|
|
67
|
+
actions.push({
|
|
68
|
+
type: RECOVERY_ACTIONS.RESUME,
|
|
69
|
+
description: 'Reconcile state and continue working (preserves work)',
|
|
70
|
+
command: `pnpm wu:recover --id ${wu.id} --action resume`,
|
|
71
|
+
requiresForce: false,
|
|
72
|
+
});
|
|
73
|
+
actions.push({
|
|
74
|
+
type: RECOVERY_ACTIONS.RESET,
|
|
75
|
+
description: 'Discard worktree and reset WU to ready',
|
|
76
|
+
command: `pnpm wu:recover --id ${wu.id} --action reset`,
|
|
77
|
+
requiresForce: false,
|
|
78
|
+
warning: 'This will discard any uncommitted work in the worktree',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Check for orphan claim: status is in_progress but worktree missing
|
|
82
|
+
if (!hasWorktree && wu.status === WU_STATUS.IN_PROGRESS) {
|
|
83
|
+
issues.push({
|
|
84
|
+
code: RECOVERY_ISSUES.ORPHAN_CLAIM,
|
|
85
|
+
description: `${wu.id} is 'in_progress' but worktree is missing. The worktree may have been manually deleted.`,
|
|
86
|
+
context: { expectedPath: worktreePath, status: wu.status },
|
|
87
|
+
});
|
|
88
|
+
actions.push({
|
|
89
|
+
type: RECOVERY_ACTIONS.RESET,
|
|
90
|
+
description: 'Reset WU status back to ready for re-claiming',
|
|
91
|
+
command: `pnpm wu:recover --id ${wu.id} --action reset`,
|
|
92
|
+
requiresForce: false,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Check for leftover worktree: WU is done but worktree exists
|
|
96
|
+
if (hasWorktree && wu.status === WU_STATUS.DONE) {
|
|
97
|
+
issues.push({
|
|
98
|
+
code: RECOVERY_ISSUES.LEFTOVER_WORKTREE,
|
|
99
|
+
description: `${wu.id} is 'done' but worktree still exists. The cleanup may have failed.`,
|
|
100
|
+
context: { worktreePath, status: wu.status },
|
|
101
|
+
});
|
|
102
|
+
actions.push({
|
|
103
|
+
type: RECOVERY_ACTIONS.CLEANUP,
|
|
104
|
+
description: 'Remove leftover worktree for completed WU',
|
|
105
|
+
command: `pnpm wu:recover --id ${wu.id} --action cleanup`,
|
|
106
|
+
requiresForce: false,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Check for inconsistent state
|
|
110
|
+
if (!wu.isConsistent && wu.inconsistencyReason) {
|
|
111
|
+
issues.push({
|
|
112
|
+
code: RECOVERY_ISSUES.INCONSISTENT_STATE,
|
|
113
|
+
description: wu.inconsistencyReason,
|
|
114
|
+
context: { wuId: wu.id },
|
|
115
|
+
});
|
|
116
|
+
actions.push({
|
|
117
|
+
type: RECOVERY_ACTIONS.RESET,
|
|
118
|
+
description: 'Reconcile YAML and state store',
|
|
119
|
+
command: `pnpm wu:recover --id ${wu.id} --action reset`,
|
|
120
|
+
requiresForce: false,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
hasIssues: issues.length > 0,
|
|
125
|
+
issues,
|
|
126
|
+
actions,
|
|
127
|
+
wuId: wu.id,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnalyzeRecoveryUseCase
|
|
3
|
+
*
|
|
4
|
+
* WU-1094: INIT-002 Phase 2 - Implement adapters and dependency injection
|
|
5
|
+
*
|
|
6
|
+
* Use case for analyzing WU state and suggesting recovery actions.
|
|
7
|
+
* Uses constructor injection for recovery analyzer dependency.
|
|
8
|
+
*
|
|
9
|
+
* Hexagonal Architecture - Application Layer
|
|
10
|
+
* - Depends on port interface (IRecoveryAnalyzer)
|
|
11
|
+
* - Does NOT import from infrastructure layer
|
|
12
|
+
*
|
|
13
|
+
* @module usecases/analyze-recovery.usecase
|
|
14
|
+
*/
|
|
15
|
+
import type { IRecoveryAnalyzer, WuContext, RecoveryAnalysis } from '../ports/recovery.ports.js';
|
|
16
|
+
/**
|
|
17
|
+
* AnalyzeRecoveryUseCase
|
|
18
|
+
*
|
|
19
|
+
* Analyzes WU context to detect state inconsistencies and suggests
|
|
20
|
+
* recovery actions.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Using default analyzer via DI factory
|
|
24
|
+
* const useCase = createAnalyzeRecoveryUseCase();
|
|
25
|
+
* const analysis = await useCase.execute(context);
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Using custom analyzer for testing
|
|
29
|
+
* const useCase = new AnalyzeRecoveryUseCase(mockAnalyzer);
|
|
30
|
+
* const analysis = await useCase.execute(context);
|
|
31
|
+
*/
|
|
32
|
+
export declare class AnalyzeRecoveryUseCase {
|
|
33
|
+
private readonly recoveryAnalyzer;
|
|
34
|
+
constructor(recoveryAnalyzer: IRecoveryAnalyzer);
|
|
35
|
+
/**
|
|
36
|
+
* Execute the use case to analyze recovery issues.
|
|
37
|
+
*
|
|
38
|
+
* @param context - Current WU context
|
|
39
|
+
* @returns Promise<RecoveryAnalysis> - Analysis with issues and suggested actions
|
|
40
|
+
*/
|
|
41
|
+
execute(context: WuContext): Promise<RecoveryAnalysis>;
|
|
42
|
+
}
|