everything-claude-code 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +739 -0
- package/README.zh-CN.md +523 -0
- package/crates/ecc-kernel/Cargo.lock +160 -0
- package/crates/ecc-kernel/Cargo.toml +15 -0
- package/crates/ecc-kernel/src/main.rs +710 -0
- package/docs/ecc.md +117 -0
- package/package.json +45 -0
- package/packs/blueprint.json +8 -0
- package/packs/forge.json +16 -0
- package/packs/instinct.json +16 -0
- package/packs/orchestra.json +15 -0
- package/packs/proof.json +8 -0
- package/packs/sentinel.json +8 -0
- package/prompts/ecc/patch.md +25 -0
- package/prompts/ecc/plan.md +28 -0
- package/schemas/ecc.apply.schema.json +35 -0
- package/schemas/ecc.config.schema.json +37 -0
- package/schemas/ecc.lock.schema.json +34 -0
- package/schemas/ecc.patch.schema.json +25 -0
- package/schemas/ecc.plan.schema.json +32 -0
- package/schemas/ecc.run.schema.json +67 -0
- package/schemas/ecc.verify.schema.json +27 -0
- package/schemas/hooks.schema.json +81 -0
- package/schemas/package-manager.schema.json +17 -0
- package/schemas/plugin.schema.json +13 -0
- package/scripts/ecc/catalog.js +82 -0
- package/scripts/ecc/config.js +43 -0
- package/scripts/ecc/diff.js +113 -0
- package/scripts/ecc/exec.js +121 -0
- package/scripts/ecc/fixtures/basic/patches/impl-core.diff +8 -0
- package/scripts/ecc/fixtures/basic/patches/tests.diff +8 -0
- package/scripts/ecc/fixtures/basic/plan.json +23 -0
- package/scripts/ecc/fixtures/unauthorized/patches/impl-core.diff +8 -0
- package/scripts/ecc/fixtures/unauthorized/plan.json +15 -0
- package/scripts/ecc/git.js +139 -0
- package/scripts/ecc/id.js +37 -0
- package/scripts/ecc/install-kernel.js +344 -0
- package/scripts/ecc/json-extract.js +301 -0
- package/scripts/ecc/json.js +26 -0
- package/scripts/ecc/kernel.js +144 -0
- package/scripts/ecc/lock.js +36 -0
- package/scripts/ecc/paths.js +28 -0
- package/scripts/ecc/plan.js +57 -0
- package/scripts/ecc/project.js +37 -0
- package/scripts/ecc/providers/codex.js +168 -0
- package/scripts/ecc/providers/index.js +23 -0
- package/scripts/ecc/providers/mock.js +49 -0
- package/scripts/ecc/report.js +127 -0
- package/scripts/ecc/run.js +105 -0
- package/scripts/ecc/validate.js +325 -0
- package/scripts/ecc/verify.js +125 -0
- package/scripts/ecc.js +532 -0
- package/scripts/lib/package-manager.js +390 -0
- package/scripts/lib/session-aliases.js +432 -0
- package/scripts/lib/session-manager.js +396 -0
- package/scripts/lib/utils.js +426 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Aliases Library for Claude Code
|
|
3
|
+
* Manages session aliases stored in ~/.claude/session-aliases.json
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
getClaudeDir,
|
|
11
|
+
ensureDir,
|
|
12
|
+
readFile,
|
|
13
|
+
log
|
|
14
|
+
} = require('./utils');
|
|
15
|
+
|
|
16
|
+
// Aliases file path
|
|
17
|
+
function getAliasesPath() {
|
|
18
|
+
return path.join(getClaudeDir(), 'session-aliases.json');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Current alias storage format version
|
|
22
|
+
const ALIAS_VERSION = '1.0';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Default aliases file structure
|
|
26
|
+
*/
|
|
27
|
+
function getDefaultAliases() {
|
|
28
|
+
return {
|
|
29
|
+
version: ALIAS_VERSION,
|
|
30
|
+
aliases: {},
|
|
31
|
+
metadata: {
|
|
32
|
+
totalCount: 0,
|
|
33
|
+
lastUpdated: new Date().toISOString()
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Load aliases from file
|
|
40
|
+
* @returns {object} Aliases object
|
|
41
|
+
*/
|
|
42
|
+
function loadAliases() {
|
|
43
|
+
const aliasesPath = getAliasesPath();
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(aliasesPath)) {
|
|
46
|
+
return getDefaultAliases();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const content = readFile(aliasesPath);
|
|
50
|
+
if (!content) {
|
|
51
|
+
return getDefaultAliases();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const data = JSON.parse(content);
|
|
56
|
+
|
|
57
|
+
// Validate structure
|
|
58
|
+
if (!data.aliases || typeof data.aliases !== 'object') {
|
|
59
|
+
log('[Aliases] Invalid aliases file structure, resetting');
|
|
60
|
+
return getDefaultAliases();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Ensure version field
|
|
64
|
+
if (!data.version) {
|
|
65
|
+
data.version = ALIAS_VERSION;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Ensure metadata
|
|
69
|
+
if (!data.metadata) {
|
|
70
|
+
data.metadata = {
|
|
71
|
+
totalCount: Object.keys(data.aliases).length,
|
|
72
|
+
lastUpdated: new Date().toISOString()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return data;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
log(`[Aliases] Error parsing aliases file: ${err.message}`);
|
|
79
|
+
return getDefaultAliases();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Save aliases to file with atomic write
|
|
85
|
+
* @param {object} aliases - Aliases object to save
|
|
86
|
+
* @returns {boolean} Success status
|
|
87
|
+
*/
|
|
88
|
+
function saveAliases(aliases) {
|
|
89
|
+
const aliasesPath = getAliasesPath();
|
|
90
|
+
const tempPath = aliasesPath + '.tmp';
|
|
91
|
+
const backupPath = aliasesPath + '.bak';
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Update metadata
|
|
95
|
+
aliases.metadata = {
|
|
96
|
+
totalCount: Object.keys(aliases.aliases).length,
|
|
97
|
+
lastUpdated: new Date().toISOString()
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const content = JSON.stringify(aliases, null, 2);
|
|
101
|
+
|
|
102
|
+
// Ensure directory exists
|
|
103
|
+
ensureDir(path.dirname(aliasesPath));
|
|
104
|
+
|
|
105
|
+
// Create backup if file exists
|
|
106
|
+
if (fs.existsSync(aliasesPath)) {
|
|
107
|
+
fs.copyFileSync(aliasesPath, backupPath);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Atomic write: write to temp file, then rename
|
|
111
|
+
fs.writeFileSync(tempPath, content, 'utf8');
|
|
112
|
+
|
|
113
|
+
// On Windows, we need to delete the target file before renaming
|
|
114
|
+
if (fs.existsSync(aliasesPath)) {
|
|
115
|
+
fs.unlinkSync(aliasesPath);
|
|
116
|
+
}
|
|
117
|
+
fs.renameSync(tempPath, aliasesPath);
|
|
118
|
+
|
|
119
|
+
// Remove backup on success
|
|
120
|
+
if (fs.existsSync(backupPath)) {
|
|
121
|
+
fs.unlinkSync(backupPath);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return true;
|
|
125
|
+
} catch (err) {
|
|
126
|
+
log(`[Aliases] Error saving aliases: ${err.message}`);
|
|
127
|
+
|
|
128
|
+
// Restore from backup if exists
|
|
129
|
+
if (fs.existsSync(backupPath)) {
|
|
130
|
+
try {
|
|
131
|
+
fs.copyFileSync(backupPath, aliasesPath);
|
|
132
|
+
log('[Aliases] Restored from backup');
|
|
133
|
+
} catch (restoreErr) {
|
|
134
|
+
log(`[Aliases] Failed to restore backup: ${restoreErr.message}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Clean up temp file
|
|
139
|
+
if (fs.existsSync(tempPath)) {
|
|
140
|
+
fs.unlinkSync(tempPath);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve an alias to get session path
|
|
149
|
+
* @param {string} alias - Alias name to resolve
|
|
150
|
+
* @returns {object|null} Alias data or null if not found
|
|
151
|
+
*/
|
|
152
|
+
function resolveAlias(alias) {
|
|
153
|
+
// Validate alias name (alphanumeric, dash, underscore)
|
|
154
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(alias)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const data = loadAliases();
|
|
159
|
+
const aliasData = data.aliases[alias];
|
|
160
|
+
|
|
161
|
+
if (!aliasData) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
alias,
|
|
167
|
+
sessionPath: aliasData.sessionPath,
|
|
168
|
+
createdAt: aliasData.createdAt,
|
|
169
|
+
title: aliasData.title || null
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Set or update an alias for a session
|
|
175
|
+
* @param {string} alias - Alias name (alphanumeric, dash, underscore)
|
|
176
|
+
* @param {string} sessionPath - Session directory path
|
|
177
|
+
* @param {string} title - Optional title for the alias
|
|
178
|
+
* @returns {object} Result with success status and message
|
|
179
|
+
*/
|
|
180
|
+
function setAlias(alias, sessionPath, title = null) {
|
|
181
|
+
// Validate alias name
|
|
182
|
+
if (!alias || alias.length === 0) {
|
|
183
|
+
return { success: false, error: 'Alias name cannot be empty' };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(alias)) {
|
|
187
|
+
return { success: false, error: 'Alias name must contain only letters, numbers, dashes, and underscores' };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Reserved alias names
|
|
191
|
+
const reserved = ['list', 'help', 'remove', 'delete', 'create', 'set'];
|
|
192
|
+
if (reserved.includes(alias.toLowerCase())) {
|
|
193
|
+
return { success: false, error: `'${alias}' is a reserved alias name` };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const data = loadAliases();
|
|
197
|
+
const existing = data.aliases[alias];
|
|
198
|
+
const isNew = !existing;
|
|
199
|
+
|
|
200
|
+
data.aliases[alias] = {
|
|
201
|
+
sessionPath,
|
|
202
|
+
createdAt: existing ? existing.createdAt : new Date().toISOString(),
|
|
203
|
+
updatedAt: new Date().toISOString(),
|
|
204
|
+
title: title || null
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
if (saveAliases(data)) {
|
|
208
|
+
return {
|
|
209
|
+
success: true,
|
|
210
|
+
isNew,
|
|
211
|
+
alias,
|
|
212
|
+
sessionPath,
|
|
213
|
+
title: data.aliases[alias].title
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { success: false, error: 'Failed to save alias' };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* List all aliases
|
|
222
|
+
* @param {object} options - Options object
|
|
223
|
+
* @param {string} options.search - Filter aliases by name (partial match)
|
|
224
|
+
* @param {number} options.limit - Maximum number of aliases to return
|
|
225
|
+
* @returns {Array} Array of alias objects
|
|
226
|
+
*/
|
|
227
|
+
function listAliases(options = {}) {
|
|
228
|
+
const { search = null, limit = null } = options;
|
|
229
|
+
const data = loadAliases();
|
|
230
|
+
|
|
231
|
+
let aliases = Object.entries(data.aliases).map(([name, info]) => ({
|
|
232
|
+
name,
|
|
233
|
+
sessionPath: info.sessionPath,
|
|
234
|
+
createdAt: info.createdAt,
|
|
235
|
+
updatedAt: info.updatedAt,
|
|
236
|
+
title: info.title
|
|
237
|
+
}));
|
|
238
|
+
|
|
239
|
+
// Sort by updated time (newest first)
|
|
240
|
+
aliases.sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt));
|
|
241
|
+
|
|
242
|
+
// Apply search filter
|
|
243
|
+
if (search) {
|
|
244
|
+
const searchLower = search.toLowerCase();
|
|
245
|
+
aliases = aliases.filter(a =>
|
|
246
|
+
a.name.toLowerCase().includes(searchLower) ||
|
|
247
|
+
(a.title && a.title.toLowerCase().includes(searchLower))
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Apply limit
|
|
252
|
+
if (limit && limit > 0) {
|
|
253
|
+
aliases = aliases.slice(0, limit);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return aliases;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Delete an alias
|
|
261
|
+
* @param {string} alias - Alias name to delete
|
|
262
|
+
* @returns {object} Result with success status
|
|
263
|
+
*/
|
|
264
|
+
function deleteAlias(alias) {
|
|
265
|
+
const data = loadAliases();
|
|
266
|
+
|
|
267
|
+
if (!data.aliases[alias]) {
|
|
268
|
+
return { success: false, error: `Alias '${alias}' not found` };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const deleted = data.aliases[alias];
|
|
272
|
+
delete data.aliases[alias];
|
|
273
|
+
|
|
274
|
+
if (saveAliases(data)) {
|
|
275
|
+
return {
|
|
276
|
+
success: true,
|
|
277
|
+
alias,
|
|
278
|
+
deletedSessionPath: deleted.sessionPath
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return { success: false, error: 'Failed to delete alias' };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Rename an alias
|
|
287
|
+
* @param {string} oldAlias - Current alias name
|
|
288
|
+
* @param {string} newAlias - New alias name
|
|
289
|
+
* @returns {object} Result with success status
|
|
290
|
+
*/
|
|
291
|
+
function renameAlias(oldAlias, newAlias) {
|
|
292
|
+
const data = loadAliases();
|
|
293
|
+
|
|
294
|
+
if (!data.aliases[oldAlias]) {
|
|
295
|
+
return { success: false, error: `Alias '${oldAlias}' not found` };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (data.aliases[newAlias]) {
|
|
299
|
+
return { success: false, error: `Alias '${newAlias}' already exists` };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Validate new alias name
|
|
303
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(newAlias)) {
|
|
304
|
+
return { success: false, error: 'New alias name must contain only letters, numbers, dashes, and underscores' };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const aliasData = data.aliases[oldAlias];
|
|
308
|
+
delete data.aliases[oldAlias];
|
|
309
|
+
|
|
310
|
+
aliasData.updatedAt = new Date().toISOString();
|
|
311
|
+
data.aliases[newAlias] = aliasData;
|
|
312
|
+
|
|
313
|
+
if (saveAliases(data)) {
|
|
314
|
+
return {
|
|
315
|
+
success: true,
|
|
316
|
+
oldAlias,
|
|
317
|
+
newAlias,
|
|
318
|
+
sessionPath: aliasData.sessionPath
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Restore old alias on failure
|
|
323
|
+
data.aliases[oldAlias] = aliasData;
|
|
324
|
+
return { success: false, error: 'Failed to rename alias' };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get session path by alias (convenience function)
|
|
329
|
+
* @param {string} aliasOrId - Alias name or session ID
|
|
330
|
+
* @returns {string|null} Session path or null if not found
|
|
331
|
+
*/
|
|
332
|
+
function resolveSessionAlias(aliasOrId) {
|
|
333
|
+
// First try to resolve as alias
|
|
334
|
+
const resolved = resolveAlias(aliasOrId);
|
|
335
|
+
if (resolved) {
|
|
336
|
+
return resolved.sessionPath;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// If not an alias, return as-is (might be a session path)
|
|
340
|
+
return aliasOrId;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Update alias title
|
|
345
|
+
* @param {string} alias - Alias name
|
|
346
|
+
* @param {string} title - New title
|
|
347
|
+
* @returns {object} Result with success status
|
|
348
|
+
*/
|
|
349
|
+
function updateAliasTitle(alias, title) {
|
|
350
|
+
const data = loadAliases();
|
|
351
|
+
|
|
352
|
+
if (!data.aliases[alias]) {
|
|
353
|
+
return { success: false, error: `Alias '${alias}' not found` };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
data.aliases[alias].title = title;
|
|
357
|
+
data.aliases[alias].updatedAt = new Date().toISOString();
|
|
358
|
+
|
|
359
|
+
if (saveAliases(data)) {
|
|
360
|
+
return {
|
|
361
|
+
success: true,
|
|
362
|
+
alias,
|
|
363
|
+
title
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return { success: false, error: 'Failed to update alias title' };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get all aliases for a specific session
|
|
372
|
+
* @param {string} sessionPath - Session path to find aliases for
|
|
373
|
+
* @returns {Array} Array of alias names
|
|
374
|
+
*/
|
|
375
|
+
function getAliasesForSession(sessionPath) {
|
|
376
|
+
const data = loadAliases();
|
|
377
|
+
const aliases = [];
|
|
378
|
+
|
|
379
|
+
for (const [name, info] of Object.entries(data.aliases)) {
|
|
380
|
+
if (info.sessionPath === sessionPath) {
|
|
381
|
+
aliases.push({
|
|
382
|
+
name,
|
|
383
|
+
createdAt: info.createdAt,
|
|
384
|
+
title: info.title
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return aliases;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Clean up aliases for non-existent sessions
|
|
394
|
+
* @param {Function} sessionExists - Function to check if session exists
|
|
395
|
+
* @returns {object} Cleanup result
|
|
396
|
+
*/
|
|
397
|
+
function cleanupAliases(sessionExists) {
|
|
398
|
+
const data = loadAliases();
|
|
399
|
+
const removed = [];
|
|
400
|
+
|
|
401
|
+
for (const [name, info] of Object.entries(data.aliases)) {
|
|
402
|
+
if (!sessionExists(info.sessionPath)) {
|
|
403
|
+
removed.push({ name, sessionPath: info.sessionPath });
|
|
404
|
+
delete data.aliases[name];
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (removed.length > 0) {
|
|
409
|
+
saveAliases(data);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return {
|
|
413
|
+
totalChecked: Object.keys(data.aliases).length + removed.length,
|
|
414
|
+
removed: removed.length,
|
|
415
|
+
removedAliases: removed
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
module.exports = {
|
|
420
|
+
getAliasesPath,
|
|
421
|
+
loadAliases,
|
|
422
|
+
saveAliases,
|
|
423
|
+
resolveAlias,
|
|
424
|
+
setAlias,
|
|
425
|
+
listAliases,
|
|
426
|
+
deleteAlias,
|
|
427
|
+
renameAlias,
|
|
428
|
+
resolveSessionAlias,
|
|
429
|
+
updateAliasTitle,
|
|
430
|
+
getAliasesForSession,
|
|
431
|
+
cleanupAliases
|
|
432
|
+
};
|