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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +739 -0
  3. package/README.zh-CN.md +523 -0
  4. package/crates/ecc-kernel/Cargo.lock +160 -0
  5. package/crates/ecc-kernel/Cargo.toml +15 -0
  6. package/crates/ecc-kernel/src/main.rs +710 -0
  7. package/docs/ecc.md +117 -0
  8. package/package.json +45 -0
  9. package/packs/blueprint.json +8 -0
  10. package/packs/forge.json +16 -0
  11. package/packs/instinct.json +16 -0
  12. package/packs/orchestra.json +15 -0
  13. package/packs/proof.json +8 -0
  14. package/packs/sentinel.json +8 -0
  15. package/prompts/ecc/patch.md +25 -0
  16. package/prompts/ecc/plan.md +28 -0
  17. package/schemas/ecc.apply.schema.json +35 -0
  18. package/schemas/ecc.config.schema.json +37 -0
  19. package/schemas/ecc.lock.schema.json +34 -0
  20. package/schemas/ecc.patch.schema.json +25 -0
  21. package/schemas/ecc.plan.schema.json +32 -0
  22. package/schemas/ecc.run.schema.json +67 -0
  23. package/schemas/ecc.verify.schema.json +27 -0
  24. package/schemas/hooks.schema.json +81 -0
  25. package/schemas/package-manager.schema.json +17 -0
  26. package/schemas/plugin.schema.json +13 -0
  27. package/scripts/ecc/catalog.js +82 -0
  28. package/scripts/ecc/config.js +43 -0
  29. package/scripts/ecc/diff.js +113 -0
  30. package/scripts/ecc/exec.js +121 -0
  31. package/scripts/ecc/fixtures/basic/patches/impl-core.diff +8 -0
  32. package/scripts/ecc/fixtures/basic/patches/tests.diff +8 -0
  33. package/scripts/ecc/fixtures/basic/plan.json +23 -0
  34. package/scripts/ecc/fixtures/unauthorized/patches/impl-core.diff +8 -0
  35. package/scripts/ecc/fixtures/unauthorized/plan.json +15 -0
  36. package/scripts/ecc/git.js +139 -0
  37. package/scripts/ecc/id.js +37 -0
  38. package/scripts/ecc/install-kernel.js +344 -0
  39. package/scripts/ecc/json-extract.js +301 -0
  40. package/scripts/ecc/json.js +26 -0
  41. package/scripts/ecc/kernel.js +144 -0
  42. package/scripts/ecc/lock.js +36 -0
  43. package/scripts/ecc/paths.js +28 -0
  44. package/scripts/ecc/plan.js +57 -0
  45. package/scripts/ecc/project.js +37 -0
  46. package/scripts/ecc/providers/codex.js +168 -0
  47. package/scripts/ecc/providers/index.js +23 -0
  48. package/scripts/ecc/providers/mock.js +49 -0
  49. package/scripts/ecc/report.js +127 -0
  50. package/scripts/ecc/run.js +105 -0
  51. package/scripts/ecc/validate.js +325 -0
  52. package/scripts/ecc/verify.js +125 -0
  53. package/scripts/ecc.js +532 -0
  54. package/scripts/lib/package-manager.js +390 -0
  55. package/scripts/lib/session-aliases.js +432 -0
  56. package/scripts/lib/session-manager.js +396 -0
  57. 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
+ };