tlc-claude-code 1.2.28 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/dashboard/dist/components/UsagePane.d.ts +13 -0
- package/dashboard/dist/components/UsagePane.js +51 -0
- package/dashboard/dist/components/UsagePane.test.d.ts +1 -0
- package/dashboard/dist/components/UsagePane.test.js +142 -0
- package/dashboard/dist/components/WorkspaceDocsPane.d.ts +19 -0
- package/dashboard/dist/components/WorkspaceDocsPane.js +146 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.js +242 -0
- package/dashboard/dist/components/WorkspacePane.d.ts +18 -0
- package/dashboard/dist/components/WorkspacePane.js +17 -0
- package/dashboard/dist/components/WorkspacePane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspacePane.test.js +84 -0
- package/package.json +15 -4
- package/scripts/capture-screenshots.js +170 -0
- package/scripts/docs-update.js +253 -0
- package/scripts/generate-screenshots.js +321 -0
- package/scripts/project-docs.js +377 -0
- package/scripts/vps-setup.sh +477 -0
- package/server/lib/architecture-command.js +450 -0
- package/server/lib/architecture-command.test.js +754 -0
- package/server/lib/ast-analyzer.js +324 -0
- package/server/lib/ast-analyzer.test.js +437 -0
- package/server/lib/auth-system.test.js +4 -1
- package/server/lib/boundary-detector.js +427 -0
- package/server/lib/boundary-detector.test.js +320 -0
- package/server/lib/budget-alerts.js +138 -0
- package/server/lib/budget-alerts.test.js +235 -0
- package/server/lib/candidates-tracker.js +210 -0
- package/server/lib/candidates-tracker.test.js +300 -0
- package/server/lib/checkpoint-manager.js +251 -0
- package/server/lib/checkpoint-manager.test.js +474 -0
- package/server/lib/circular-detector.js +337 -0
- package/server/lib/circular-detector.test.js +353 -0
- package/server/lib/cohesion-analyzer.js +310 -0
- package/server/lib/cohesion-analyzer.test.js +447 -0
- package/server/lib/contract-testing.js +625 -0
- package/server/lib/contract-testing.test.js +342 -0
- package/server/lib/conversion-planner.js +469 -0
- package/server/lib/conversion-planner.test.js +361 -0
- package/server/lib/convert-command.js +351 -0
- package/server/lib/convert-command.test.js +608 -0
- package/server/lib/coupling-calculator.js +189 -0
- package/server/lib/coupling-calculator.test.js +509 -0
- package/server/lib/dependency-graph.js +367 -0
- package/server/lib/dependency-graph.test.js +516 -0
- package/server/lib/duplication-detector.js +349 -0
- package/server/lib/duplication-detector.test.js +401 -0
- package/server/lib/example-service.js +616 -0
- package/server/lib/example-service.test.js +397 -0
- package/server/lib/impact-scorer.js +184 -0
- package/server/lib/impact-scorer.test.js +211 -0
- package/server/lib/mermaid-generator.js +358 -0
- package/server/lib/mermaid-generator.test.js +301 -0
- package/server/lib/messaging-patterns.js +750 -0
- package/server/lib/messaging-patterns.test.js +213 -0
- package/server/lib/microservice-template.js +386 -0
- package/server/lib/microservice-template.test.js +325 -0
- package/server/lib/new-project-microservice.js +450 -0
- package/server/lib/new-project-microservice.test.js +600 -0
- package/server/lib/refactor-command.js +326 -0
- package/server/lib/refactor-command.test.js +528 -0
- package/server/lib/refactor-executor.js +254 -0
- package/server/lib/refactor-executor.test.js +305 -0
- package/server/lib/refactor-observer.js +292 -0
- package/server/lib/refactor-observer.test.js +422 -0
- package/server/lib/refactor-progress.js +193 -0
- package/server/lib/refactor-progress.test.js +251 -0
- package/server/lib/refactor-reporter.js +237 -0
- package/server/lib/refactor-reporter.test.js +247 -0
- package/server/lib/semantic-analyzer.js +198 -0
- package/server/lib/semantic-analyzer.test.js +474 -0
- package/server/lib/service-scaffold.js +486 -0
- package/server/lib/service-scaffold.test.js +373 -0
- package/server/lib/shared-kernel.js +578 -0
- package/server/lib/shared-kernel.test.js +255 -0
- package/server/lib/traefik-config.js +282 -0
- package/server/lib/traefik-config.test.js +312 -0
- package/server/lib/usage-command.js +218 -0
- package/server/lib/usage-command.test.js +391 -0
- package/server/lib/usage-formatter.js +192 -0
- package/server/lib/usage-formatter.test.js +267 -0
- package/server/lib/usage-history.js +122 -0
- package/server/lib/usage-history.test.js +206 -0
- package/server/package-lock.json +14 -0
- package/server/package.json +1 -0
- package/templates/docs-sync.yml +91 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint Manager
|
|
3
|
+
* Create and manage git-based checkpoints for safe refactoring
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
class CheckpointManager {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
this.exec = options.exec || this.defaultExec.bind(this);
|
|
13
|
+
this.readFile = options.readFile || this.defaultReadFile.bind(this);
|
|
14
|
+
this.writeFile = options.writeFile || this.defaultWriteFile.bind(this);
|
|
15
|
+
this.stateFile = options.stateFile || '.tlc/checkpoint.json';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default exec implementation
|
|
20
|
+
*/
|
|
21
|
+
async defaultExec(command) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
try {
|
|
24
|
+
const stdout = execSync(command, { encoding: 'utf-8' });
|
|
25
|
+
resolve({ stdout });
|
|
26
|
+
} catch (error) {
|
|
27
|
+
reject(error);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Default read file implementation
|
|
34
|
+
*/
|
|
35
|
+
async defaultReadFile(filePath) {
|
|
36
|
+
return fs.promises.readFile(filePath, 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Default write file implementation
|
|
41
|
+
*/
|
|
42
|
+
async defaultWriteFile(filePath, content) {
|
|
43
|
+
const dir = path.dirname(filePath);
|
|
44
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
45
|
+
await fs.promises.writeFile(filePath, content, 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a new checkpoint
|
|
50
|
+
* @param {Object} options - Creation options
|
|
51
|
+
* @returns {Object} Checkpoint info
|
|
52
|
+
*/
|
|
53
|
+
async create(options = {}) {
|
|
54
|
+
// Check for existing checkpoint
|
|
55
|
+
if (!options.force) {
|
|
56
|
+
const existing = await this.load();
|
|
57
|
+
if (existing) {
|
|
58
|
+
throw new Error('Checkpoint already exists. Use rollback() first or force: true');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Get current branch
|
|
63
|
+
let originalBranch;
|
|
64
|
+
let wasDetached = false;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { stdout } = await this.exec('git branch --show-current');
|
|
68
|
+
originalBranch = stdout.trim();
|
|
69
|
+
|
|
70
|
+
if (!originalBranch) {
|
|
71
|
+
// Detached HEAD
|
|
72
|
+
const { stdout: headCommit } = await this.exec('git rev-parse HEAD');
|
|
73
|
+
originalBranch = headCommit.trim();
|
|
74
|
+
wasDetached = true;
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new Error('Failed to get current branch: ' + error.message);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for uncommitted changes
|
|
81
|
+
const { stdout: status } = await this.exec('git status --porcelain');
|
|
82
|
+
const hasChanges = status.trim().length > 0;
|
|
83
|
+
let hasStash = false;
|
|
84
|
+
let stashRef = null;
|
|
85
|
+
|
|
86
|
+
// Stash changes if any
|
|
87
|
+
if (hasChanges) {
|
|
88
|
+
await this.exec('git stash push -m "TLC checkpoint stash"');
|
|
89
|
+
hasStash = true;
|
|
90
|
+
stashRef = 'stash@{0}';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create refactor branch
|
|
94
|
+
const timestamp = Date.now();
|
|
95
|
+
let branch = `refactor/${timestamp}`;
|
|
96
|
+
let attempts = 0;
|
|
97
|
+
|
|
98
|
+
while (attempts < 3) {
|
|
99
|
+
try {
|
|
100
|
+
await this.exec(`git checkout -b ${branch}`);
|
|
101
|
+
break;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (error.message.includes('already exists')) {
|
|
104
|
+
attempts++;
|
|
105
|
+
branch = `refactor/${timestamp}-${attempts}`;
|
|
106
|
+
} else {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get commit hash
|
|
113
|
+
const { stdout: commitHash } = await this.exec('git rev-parse HEAD');
|
|
114
|
+
|
|
115
|
+
const checkpoint = {
|
|
116
|
+
id: `checkpoint-${timestamp}`,
|
|
117
|
+
branch,
|
|
118
|
+
originalBranch,
|
|
119
|
+
wasDetached,
|
|
120
|
+
hasStash,
|
|
121
|
+
stashRef,
|
|
122
|
+
commitHash: commitHash.trim(),
|
|
123
|
+
createdAt: new Date(),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Save checkpoint state
|
|
127
|
+
await this.save(checkpoint);
|
|
128
|
+
|
|
129
|
+
return checkpoint;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Rollback to checkpoint state
|
|
134
|
+
* @param {Object} checkpoint - Checkpoint to rollback to
|
|
135
|
+
*/
|
|
136
|
+
async rollback(checkpoint) {
|
|
137
|
+
// Checkout original branch
|
|
138
|
+
await this.exec(`git checkout ${checkpoint.originalBranch}`);
|
|
139
|
+
|
|
140
|
+
// Delete refactor branch
|
|
141
|
+
try {
|
|
142
|
+
await this.exec(`git branch -D ${checkpoint.branch}`);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
// Branch might not exist
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Pop stash if we stashed
|
|
148
|
+
if (checkpoint.hasStash) {
|
|
149
|
+
try {
|
|
150
|
+
await this.exec('git stash pop');
|
|
151
|
+
} catch (error) {
|
|
152
|
+
// Stash might be empty or conflict
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Clear checkpoint state
|
|
157
|
+
await this.clear();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Commit current changes
|
|
162
|
+
* @param {string} message - Commit message
|
|
163
|
+
*/
|
|
164
|
+
async commit(message) {
|
|
165
|
+
await this.exec('git add -A');
|
|
166
|
+
await this.exec(`git commit -m "${message.replace(/"/g, '\\"')}"`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Merge refactor branch back to original
|
|
171
|
+
* @param {Object} checkpoint - Checkpoint info
|
|
172
|
+
* @param {Object} options - Merge options
|
|
173
|
+
*/
|
|
174
|
+
async merge(checkpoint, options = {}) {
|
|
175
|
+
// Checkout original branch
|
|
176
|
+
await this.exec(`git checkout ${checkpoint.originalBranch}`);
|
|
177
|
+
|
|
178
|
+
// Merge refactor branch
|
|
179
|
+
await this.exec(`git merge ${checkpoint.branch}`);
|
|
180
|
+
|
|
181
|
+
// Cleanup if requested
|
|
182
|
+
if (options.cleanup) {
|
|
183
|
+
await this.exec(`git branch -d ${checkpoint.branch}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Clear checkpoint state
|
|
187
|
+
await this.clear();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Save checkpoint state to file
|
|
192
|
+
*/
|
|
193
|
+
async save(checkpoint) {
|
|
194
|
+
await this.writeFile(this.stateFile, JSON.stringify(checkpoint, null, 2));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Load existing checkpoint state
|
|
199
|
+
* @returns {Object|null} Checkpoint or null if none exists
|
|
200
|
+
*/
|
|
201
|
+
async load() {
|
|
202
|
+
try {
|
|
203
|
+
const content = await this.readFile(this.stateFile);
|
|
204
|
+
return JSON.parse(content);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Clear checkpoint state
|
|
212
|
+
*/
|
|
213
|
+
async clear() {
|
|
214
|
+
try {
|
|
215
|
+
await fs.promises.unlink(this.stateFile);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
// File might not exist
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get current checkpoint status
|
|
223
|
+
* @returns {Object} Status info
|
|
224
|
+
*/
|
|
225
|
+
async status() {
|
|
226
|
+
const checkpoint = await this.load();
|
|
227
|
+
|
|
228
|
+
if (!checkpoint) {
|
|
229
|
+
return {
|
|
230
|
+
active: false,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Get current branch
|
|
235
|
+
const { stdout: currentBranch } = await this.exec('git branch --show-current');
|
|
236
|
+
|
|
237
|
+
// Check for uncommitted changes
|
|
238
|
+
const { stdout: status } = await this.exec('git status --porcelain');
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
active: true,
|
|
242
|
+
branch: checkpoint.branch,
|
|
243
|
+
originalBranch: checkpoint.originalBranch,
|
|
244
|
+
isOnRefactorBranch: currentBranch.trim() === checkpoint.branch,
|
|
245
|
+
hasUncommittedChanges: status.trim().length > 0,
|
|
246
|
+
createdAt: checkpoint.createdAt,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
module.exports = { CheckpointManager };
|