claude-code-workflow 6.3.24 → 6.3.26
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/.claude/commands/issue/discover-by-prompt.md +764 -0
- package/.claude/skills/text-formatter/SKILL.md +196 -0
- package/.claude/skills/text-formatter/phases/01-input-collection.md +111 -0
- package/.claude/skills/text-formatter/phases/02-content-analysis.md +248 -0
- package/.claude/skills/text-formatter/phases/03-format-transform.md +245 -0
- package/.claude/skills/text-formatter/phases/04-output-preview.md +183 -0
- package/.claude/skills/text-formatter/specs/callout-types.md +293 -0
- package/.claude/skills/text-formatter/specs/element-mapping.md +226 -0
- package/.claude/skills/text-formatter/specs/format-rules.md +273 -0
- package/.claude/skills/text-formatter/templates/bbcode-template.md +350 -0
- package/ccw/dist/core/routes/help-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/help-routes.js +43 -7
- package/ccw/dist/core/routes/help-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.js +31 -5
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -1
- package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/memory-routes.js +73 -0
- package/ccw/dist/core/routes/memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/status-routes.js +36 -4
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +58 -0
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/core/services/api-key-tester.d.ts.map +1 -1
- package/ccw/dist/core/services/api-key-tester.js +8 -3
- package/ccw/dist/core/services/api-key-tester.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +7 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +11 -1
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-executor-core.d.ts +11 -0
- package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-core.js +89 -2
- package/ccw/dist/tools/cli-executor-core.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +2 -1
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +51 -8
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/index.d.ts.map +1 -1
- package/ccw/dist/tools/index.js +2 -0
- package/ccw/dist/tools/index.js.map +1 -1
- package/ccw/dist/tools/litellm-client.d.ts +6 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-client.js +22 -1
- package/ccw/dist/tools/litellm-client.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +2 -2
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/tools/memory-update-queue.d.ts +172 -0
- package/ccw/dist/tools/memory-update-queue.d.ts.map +1 -0
- package/ccw/dist/tools/memory-update-queue.js +431 -0
- package/ccw/dist/tools/memory-update-queue.js.map +1 -0
- package/ccw/src/core/routes/help-routes.ts +46 -7
- package/ccw/src/core/routes/litellm-api-routes.ts +35 -4
- package/ccw/src/core/routes/memory-routes.ts +84 -0
- package/ccw/src/core/routes/status-routes.ts +39 -4
- package/ccw/src/core/server.ts +62 -0
- package/ccw/src/core/services/api-key-tester.ts +9 -3
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +45 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +36 -5
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +42 -81
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +170 -28
- package/ccw/src/templates/dashboard-js/components/notifications.js +14 -4
- package/ccw/src/templates/dashboard-js/i18n.js +26 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +72 -2
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +11 -1
- package/ccw/src/tools/claude-cli-tools.ts +17 -1
- package/ccw/src/tools/cli-executor-core.ts +103 -2
- package/ccw/src/tools/codex-lens.ts +63 -8
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +25 -3
- package/ccw/src/tools/litellm-executor.ts +2 -2
- package/ccw/src/tools/memory-update-queue.js +499 -0
- package/package.json +91 -91
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Update Queue Tool
|
|
3
|
+
* Queue mechanism for batching CLAUDE.md updates
|
|
4
|
+
*
|
|
5
|
+
* Configuration:
|
|
6
|
+
* - Threshold: 5 paths trigger update
|
|
7
|
+
* - Timeout: 5 minutes auto-trigger
|
|
8
|
+
* - Storage: ~/.claude/.memory-queue.json
|
|
9
|
+
* - Deduplication: Same path only kept once
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
12
|
+
import { join, dirname, resolve } from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
// Default configuration
|
|
15
|
+
const DEFAULT_THRESHOLD = 5;
|
|
16
|
+
const DEFAULT_TIMEOUT_SECONDS = 300; // 5 minutes
|
|
17
|
+
const QUEUE_FILE_PATH = join(homedir(), '.claude', '.memory-queue.json');
|
|
18
|
+
/**
|
|
19
|
+
* Get queue configuration (from file or defaults)
|
|
20
|
+
* @returns {{ threshold: number, timeoutMs: number }}
|
|
21
|
+
*/
|
|
22
|
+
function getQueueConfig() {
|
|
23
|
+
try {
|
|
24
|
+
if (existsSync(QUEUE_FILE_PATH)) {
|
|
25
|
+
const content = readFileSync(QUEUE_FILE_PATH, 'utf8');
|
|
26
|
+
const data = JSON.parse(content);
|
|
27
|
+
return {
|
|
28
|
+
threshold: data.config?.threshold || DEFAULT_THRESHOLD,
|
|
29
|
+
timeoutMs: (data.config?.timeout || DEFAULT_TIMEOUT_SECONDS) * 1000
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
// Use defaults
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
threshold: DEFAULT_THRESHOLD,
|
|
38
|
+
timeoutMs: DEFAULT_TIMEOUT_SECONDS * 1000
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// In-memory timeout reference (for cross-call persistence, we track via file timestamp)
|
|
42
|
+
let scheduledTimeoutId = null;
|
|
43
|
+
/**
|
|
44
|
+
* Ensure parent directory exists
|
|
45
|
+
*/
|
|
46
|
+
function ensureDir(filePath) {
|
|
47
|
+
const dir = dirname(filePath);
|
|
48
|
+
if (!existsSync(dir)) {
|
|
49
|
+
mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load queue from file
|
|
54
|
+
* @returns {{ items: Array<{path: string, tool: string, strategy: string, addedAt: string}>, createdAt: string | null, config?: { threshold: number, timeout: number } }}
|
|
55
|
+
*/
|
|
56
|
+
function loadQueue() {
|
|
57
|
+
try {
|
|
58
|
+
if (existsSync(QUEUE_FILE_PATH)) {
|
|
59
|
+
const content = readFileSync(QUEUE_FILE_PATH, 'utf8');
|
|
60
|
+
const data = JSON.parse(content);
|
|
61
|
+
return {
|
|
62
|
+
items: Array.isArray(data.items) ? data.items : [],
|
|
63
|
+
createdAt: data.createdAt || null,
|
|
64
|
+
config: data.config || null
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.error('[MemoryQueue] Failed to load queue:', e.message);
|
|
70
|
+
}
|
|
71
|
+
return { items: [], createdAt: null, config: null };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Save queue to file
|
|
75
|
+
* @param {{ items: Array<{path: string, tool: string, strategy: string, addedAt: string}>, createdAt: string | null }} data
|
|
76
|
+
*/
|
|
77
|
+
function saveQueue(data) {
|
|
78
|
+
try {
|
|
79
|
+
ensureDir(QUEUE_FILE_PATH);
|
|
80
|
+
writeFileSync(QUEUE_FILE_PATH, JSON.stringify(data, null, 2), 'utf8');
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
console.error('[MemoryQueue] Failed to save queue:', e.message);
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Normalize path for comparison (handle Windows/Unix differences)
|
|
89
|
+
* @param {string} p
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
function normalizePath(p) {
|
|
93
|
+
return resolve(p).replace(/\\/g, '/').toLowerCase();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Add path to queue with deduplication
|
|
97
|
+
* @param {string} path - Module path to update
|
|
98
|
+
* @param {{ tool?: string, strategy?: string }} options
|
|
99
|
+
* @returns {{ queued: boolean, queueSize: number, willFlush: boolean, message: string }}
|
|
100
|
+
*/
|
|
101
|
+
function addToQueue(path, options = {}) {
|
|
102
|
+
const { tool = 'gemini', strategy = 'single-layer' } = options;
|
|
103
|
+
const queue = loadQueue();
|
|
104
|
+
const config = getQueueConfig();
|
|
105
|
+
const normalizedPath = normalizePath(path);
|
|
106
|
+
const now = new Date().toISOString();
|
|
107
|
+
// Check for duplicates
|
|
108
|
+
const existingIndex = queue.items.findIndex(item => normalizePath(item.path) === normalizedPath);
|
|
109
|
+
if (existingIndex !== -1) {
|
|
110
|
+
// Update existing entry timestamp but keep it deduplicated
|
|
111
|
+
queue.items[existingIndex].addedAt = now;
|
|
112
|
+
queue.items[existingIndex].tool = tool;
|
|
113
|
+
queue.items[existingIndex].strategy = strategy;
|
|
114
|
+
saveQueue(queue);
|
|
115
|
+
return {
|
|
116
|
+
queued: false,
|
|
117
|
+
queueSize: queue.items.length,
|
|
118
|
+
willFlush: queue.items.length >= config.threshold,
|
|
119
|
+
message: `Path already in queue (updated): ${path}`
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Add new item
|
|
123
|
+
queue.items.push({
|
|
124
|
+
path,
|
|
125
|
+
tool,
|
|
126
|
+
strategy,
|
|
127
|
+
addedAt: now
|
|
128
|
+
});
|
|
129
|
+
// Set createdAt if this is the first item
|
|
130
|
+
if (!queue.createdAt) {
|
|
131
|
+
queue.createdAt = now;
|
|
132
|
+
}
|
|
133
|
+
saveQueue(queue);
|
|
134
|
+
const willFlush = queue.items.length >= config.threshold;
|
|
135
|
+
// Schedule timeout if not already scheduled
|
|
136
|
+
scheduleTimeout();
|
|
137
|
+
return {
|
|
138
|
+
queued: true,
|
|
139
|
+
queueSize: queue.items.length,
|
|
140
|
+
willFlush,
|
|
141
|
+
message: willFlush
|
|
142
|
+
? `Queue threshold reached (${queue.items.length}/${config.threshold}), will flush`
|
|
143
|
+
: `Added to queue (${queue.items.length}/${config.threshold})`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get current queue status
|
|
148
|
+
* @returns {{ queueSize: number, threshold: number, items: Array, timeoutMs: number | null, createdAt: string | null }}
|
|
149
|
+
*/
|
|
150
|
+
function getQueueStatus() {
|
|
151
|
+
const queue = loadQueue();
|
|
152
|
+
const config = getQueueConfig();
|
|
153
|
+
let timeUntilTimeout = null;
|
|
154
|
+
if (queue.createdAt && queue.items.length > 0) {
|
|
155
|
+
const createdTime = new Date(queue.createdAt).getTime();
|
|
156
|
+
const elapsed = Date.now() - createdTime;
|
|
157
|
+
timeUntilTimeout = Math.max(0, config.timeoutMs - elapsed);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
queueSize: queue.items.length,
|
|
161
|
+
threshold: config.threshold,
|
|
162
|
+
items: queue.items,
|
|
163
|
+
timeoutMs: config.timeoutMs,
|
|
164
|
+
timeoutSeconds: config.timeoutMs / 1000,
|
|
165
|
+
timeUntilTimeout,
|
|
166
|
+
createdAt: queue.createdAt
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Configure queue settings
|
|
171
|
+
* @param {{ threshold?: number, timeout?: number }} settings
|
|
172
|
+
* @returns {{ success: boolean, config: { threshold: number, timeout: number } }}
|
|
173
|
+
*/
|
|
174
|
+
function configureQueue(settings) {
|
|
175
|
+
const queue = loadQueue();
|
|
176
|
+
const currentConfig = getQueueConfig();
|
|
177
|
+
const newConfig = {
|
|
178
|
+
threshold: settings.threshold || currentConfig.threshold,
|
|
179
|
+
timeout: settings.timeout || (currentConfig.timeoutMs / 1000)
|
|
180
|
+
};
|
|
181
|
+
// Validate
|
|
182
|
+
if (newConfig.threshold < 1 || newConfig.threshold > 20) {
|
|
183
|
+
throw new Error('Threshold must be between 1 and 20');
|
|
184
|
+
}
|
|
185
|
+
if (newConfig.timeout < 60 || newConfig.timeout > 1800) {
|
|
186
|
+
throw new Error('Timeout must be between 60 and 1800 seconds');
|
|
187
|
+
}
|
|
188
|
+
queue.config = newConfig;
|
|
189
|
+
saveQueue(queue);
|
|
190
|
+
return {
|
|
191
|
+
success: true,
|
|
192
|
+
config: newConfig,
|
|
193
|
+
message: `Queue configured: threshold=${newConfig.threshold}, timeout=${newConfig.timeout}s`
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Flush queue - execute batch update
|
|
198
|
+
* @returns {Promise<{ success: boolean, processed: number, results: Array, errors: Array }>}
|
|
199
|
+
*/
|
|
200
|
+
async function flushQueue() {
|
|
201
|
+
const queue = loadQueue();
|
|
202
|
+
if (queue.items.length === 0) {
|
|
203
|
+
return {
|
|
204
|
+
success: true,
|
|
205
|
+
processed: 0,
|
|
206
|
+
results: [],
|
|
207
|
+
errors: [],
|
|
208
|
+
message: 'Queue is empty'
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// Clear timeout
|
|
212
|
+
clearScheduledTimeout();
|
|
213
|
+
// Import update_module_claude dynamically to avoid circular deps
|
|
214
|
+
const { updateModuleClaudeTool } = await import('./update-module-claude.js');
|
|
215
|
+
const results = [];
|
|
216
|
+
const errors = [];
|
|
217
|
+
// Group by tool and strategy for efficiency
|
|
218
|
+
const groups = new Map();
|
|
219
|
+
for (const item of queue.items) {
|
|
220
|
+
const key = `${item.tool}:${item.strategy}`;
|
|
221
|
+
if (!groups.has(key)) {
|
|
222
|
+
groups.set(key, []);
|
|
223
|
+
}
|
|
224
|
+
groups.get(key).push(item);
|
|
225
|
+
}
|
|
226
|
+
// Process each group
|
|
227
|
+
for (const [key, items] of groups) {
|
|
228
|
+
const [tool, strategy] = key.split(':');
|
|
229
|
+
console.log(`[MemoryQueue] Processing ${items.length} items with ${tool}/${strategy}`);
|
|
230
|
+
for (const item of items) {
|
|
231
|
+
try {
|
|
232
|
+
const result = await updateModuleClaudeTool.execute({
|
|
233
|
+
path: item.path,
|
|
234
|
+
tool: item.tool,
|
|
235
|
+
strategy: item.strategy
|
|
236
|
+
});
|
|
237
|
+
results.push({
|
|
238
|
+
path: item.path,
|
|
239
|
+
success: result.success !== false,
|
|
240
|
+
result
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
console.error(`[MemoryQueue] Failed to update ${item.path}:`, e.message);
|
|
245
|
+
errors.push({
|
|
246
|
+
path: item.path,
|
|
247
|
+
error: e.message
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Clear queue after processing
|
|
253
|
+
saveQueue({ items: [], createdAt: null });
|
|
254
|
+
return {
|
|
255
|
+
success: errors.length === 0,
|
|
256
|
+
processed: queue.items.length,
|
|
257
|
+
results,
|
|
258
|
+
errors,
|
|
259
|
+
message: `Processed ${results.length} items, ${errors.length} errors`
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Schedule timeout for auto-flush
|
|
264
|
+
*/
|
|
265
|
+
function scheduleTimeout() {
|
|
266
|
+
// We use file-based timeout tracking for persistence across process restarts
|
|
267
|
+
// The actual timeout check happens on next add/status call
|
|
268
|
+
const queue = loadQueue();
|
|
269
|
+
const config = getQueueConfig();
|
|
270
|
+
if (!queue.createdAt || queue.items.length === 0) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const createdTime = new Date(queue.createdAt).getTime();
|
|
274
|
+
const elapsed = Date.now() - createdTime;
|
|
275
|
+
if (elapsed >= config.timeoutMs) {
|
|
276
|
+
// Timeout already exceeded, should flush
|
|
277
|
+
console.log('[MemoryQueue] Timeout exceeded, auto-flushing');
|
|
278
|
+
// Don't await here to avoid blocking
|
|
279
|
+
flushQueue().catch(e => {
|
|
280
|
+
console.error('[MemoryQueue] Auto-flush failed:', e.message);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else if (!scheduledTimeoutId) {
|
|
284
|
+
// Schedule in-memory timeout for current process
|
|
285
|
+
const remaining = config.timeoutMs - elapsed;
|
|
286
|
+
scheduledTimeoutId = setTimeout(() => {
|
|
287
|
+
scheduledTimeoutId = null;
|
|
288
|
+
const currentQueue = loadQueue();
|
|
289
|
+
if (currentQueue.items.length > 0) {
|
|
290
|
+
console.log('[MemoryQueue] Timeout reached, auto-flushing');
|
|
291
|
+
flushQueue().catch(e => {
|
|
292
|
+
console.error('[MemoryQueue] Auto-flush failed:', e.message);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}, remaining);
|
|
296
|
+
// Prevent timeout from keeping process alive
|
|
297
|
+
if (scheduledTimeoutId.unref) {
|
|
298
|
+
scheduledTimeoutId.unref();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Clear scheduled timeout
|
|
304
|
+
*/
|
|
305
|
+
function clearScheduledTimeout() {
|
|
306
|
+
if (scheduledTimeoutId) {
|
|
307
|
+
clearTimeout(scheduledTimeoutId);
|
|
308
|
+
scheduledTimeoutId = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Check if timeout has expired and auto-flush if needed
|
|
313
|
+
* @returns {Promise<{ expired: boolean, flushed: boolean, result?: object }>}
|
|
314
|
+
*/
|
|
315
|
+
async function checkTimeout() {
|
|
316
|
+
const queue = loadQueue();
|
|
317
|
+
const config = getQueueConfig();
|
|
318
|
+
if (!queue.createdAt || queue.items.length === 0) {
|
|
319
|
+
return { expired: false, flushed: false };
|
|
320
|
+
}
|
|
321
|
+
const createdTime = new Date(queue.createdAt).getTime();
|
|
322
|
+
const elapsed = Date.now() - createdTime;
|
|
323
|
+
if (elapsed >= config.timeoutMs) {
|
|
324
|
+
console.log('[MemoryQueue] Timeout expired, triggering flush');
|
|
325
|
+
const result = await flushQueue();
|
|
326
|
+
return { expired: true, flushed: true, result };
|
|
327
|
+
}
|
|
328
|
+
return { expired: false, flushed: false };
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Main execute function for tool interface
|
|
332
|
+
* @param {Record<string, unknown>} params
|
|
333
|
+
* @returns {Promise<unknown>}
|
|
334
|
+
*/
|
|
335
|
+
async function execute(params) {
|
|
336
|
+
const { action, path, tool = 'gemini', strategy = 'single-layer', threshold, timeout } = params;
|
|
337
|
+
switch (action) {
|
|
338
|
+
case 'add':
|
|
339
|
+
if (!path) {
|
|
340
|
+
throw new Error('Parameter "path" is required for add action');
|
|
341
|
+
}
|
|
342
|
+
// Check timeout first
|
|
343
|
+
const timeoutCheck = await checkTimeout();
|
|
344
|
+
if (timeoutCheck.flushed) {
|
|
345
|
+
// Queue was flushed due to timeout, add to fresh queue
|
|
346
|
+
const result = addToQueue(path, { tool, strategy });
|
|
347
|
+
return {
|
|
348
|
+
...result,
|
|
349
|
+
timeoutFlushed: true,
|
|
350
|
+
flushResult: timeoutCheck.result
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const addResult = addToQueue(path, { tool, strategy });
|
|
354
|
+
// Auto-flush if threshold reached
|
|
355
|
+
if (addResult.willFlush) {
|
|
356
|
+
const flushResult = await flushQueue();
|
|
357
|
+
return {
|
|
358
|
+
...addResult,
|
|
359
|
+
flushed: true,
|
|
360
|
+
flushResult
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return addResult;
|
|
364
|
+
case 'status':
|
|
365
|
+
// Check timeout first
|
|
366
|
+
await checkTimeout();
|
|
367
|
+
return getQueueStatus();
|
|
368
|
+
case 'flush':
|
|
369
|
+
return await flushQueue();
|
|
370
|
+
case 'configure':
|
|
371
|
+
return configureQueue({ threshold, timeout });
|
|
372
|
+
default:
|
|
373
|
+
throw new Error(`Unknown action: ${action}. Valid actions: add, status, flush, configure`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Tool Definition
|
|
378
|
+
*/
|
|
379
|
+
export const memoryQueueTool = {
|
|
380
|
+
name: 'memory_queue',
|
|
381
|
+
description: `Memory update queue management. Batches CLAUDE.md updates for efficiency.
|
|
382
|
+
|
|
383
|
+
Actions:
|
|
384
|
+
- add: Add path to queue (auto-flushes at configured threshold/timeout)
|
|
385
|
+
- status: Get queue status and configuration
|
|
386
|
+
- flush: Immediately execute all queued updates
|
|
387
|
+
- configure: Set threshold and timeout settings`,
|
|
388
|
+
parameters: {
|
|
389
|
+
type: 'object',
|
|
390
|
+
properties: {
|
|
391
|
+
action: {
|
|
392
|
+
type: 'string',
|
|
393
|
+
enum: ['add', 'status', 'flush', 'configure'],
|
|
394
|
+
description: 'Queue action to perform'
|
|
395
|
+
},
|
|
396
|
+
path: {
|
|
397
|
+
type: 'string',
|
|
398
|
+
description: 'Module directory path (required for add action)'
|
|
399
|
+
},
|
|
400
|
+
threshold: {
|
|
401
|
+
type: 'number',
|
|
402
|
+
description: 'Number of paths to trigger flush (1-20, for configure action)',
|
|
403
|
+
minimum: 1,
|
|
404
|
+
maximum: 20
|
|
405
|
+
},
|
|
406
|
+
timeout: {
|
|
407
|
+
type: 'number',
|
|
408
|
+
description: 'Timeout in seconds to trigger flush (60-1800, for configure action)',
|
|
409
|
+
minimum: 60,
|
|
410
|
+
maximum: 1800
|
|
411
|
+
},
|
|
412
|
+
tool: {
|
|
413
|
+
type: 'string',
|
|
414
|
+
enum: ['gemini', 'qwen', 'codex'],
|
|
415
|
+
description: 'CLI tool to use (default: gemini)',
|
|
416
|
+
default: 'gemini'
|
|
417
|
+
},
|
|
418
|
+
strategy: {
|
|
419
|
+
type: 'string',
|
|
420
|
+
enum: ['single-layer', 'multi-layer'],
|
|
421
|
+
description: 'Update strategy (default: single-layer)',
|
|
422
|
+
default: 'single-layer'
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
required: ['action']
|
|
426
|
+
},
|
|
427
|
+
execute
|
|
428
|
+
};
|
|
429
|
+
// Export individual functions for direct use
|
|
430
|
+
export { loadQueue, saveQueue, addToQueue, getQueueStatus, flushQueue, configureQueue, scheduleTimeout, clearScheduledTimeout, checkTimeout, DEFAULT_THRESHOLD, DEFAULT_TIMEOUT_SECONDS, QUEUE_FILE_PATH };
|
|
431
|
+
//# sourceMappingURL=memory-update-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-update-queue.js","sourceRoot":"","sources":["../../src/tools/memory-update-queue.js"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,29 @@ import { join } from 'path';
|
|
|
7
7
|
import { homedir } from 'os';
|
|
8
8
|
import type { RouteContext } from './types.js';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Get the ccw-help index directory path (pure function)
|
|
12
|
+
* Priority: project path (.claude/skills/ccw-help/index) > user path (~/.claude/skills/ccw-help/index)
|
|
13
|
+
* @param projectPath - The project path to check first
|
|
14
|
+
*/
|
|
15
|
+
function getIndexDir(projectPath: string | null): string | null {
|
|
16
|
+
// Try project path first
|
|
17
|
+
if (projectPath) {
|
|
18
|
+
const projectIndexDir = join(projectPath, '.claude', 'skills', 'ccw-help', 'index');
|
|
19
|
+
if (existsSync(projectIndexDir)) {
|
|
20
|
+
return projectIndexDir;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Fall back to user path
|
|
25
|
+
const userIndexDir = join(homedir(), '.claude', 'skills', 'ccw-help', 'index');
|
|
26
|
+
if (existsSync(userIndexDir)) {
|
|
27
|
+
return userIndexDir;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
10
33
|
// ========== In-Memory Cache ==========
|
|
11
34
|
interface CacheEntry {
|
|
12
35
|
data: any;
|
|
@@ -61,14 +84,15 @@ let watchersInitialized = false;
|
|
|
61
84
|
|
|
62
85
|
/**
|
|
63
86
|
* Initialize file watchers for JSON indexes
|
|
87
|
+
* @param projectPath - The project path to resolve index directory
|
|
64
88
|
*/
|
|
65
|
-
function initializeFileWatchers(): void {
|
|
89
|
+
function initializeFileWatchers(projectPath: string | null): void {
|
|
66
90
|
if (watchersInitialized) return;
|
|
67
91
|
|
|
68
|
-
const indexDir =
|
|
92
|
+
const indexDir = getIndexDir(projectPath);
|
|
69
93
|
|
|
70
|
-
if (!
|
|
71
|
-
console.warn(`
|
|
94
|
+
if (!indexDir) {
|
|
95
|
+
console.warn(`ccw-help index directory not found in project or user paths`);
|
|
72
96
|
return;
|
|
73
97
|
}
|
|
74
98
|
|
|
@@ -152,15 +176,20 @@ function groupCommandsByCategory(commands: any[]): any {
|
|
|
152
176
|
* @returns true if route was handled, false otherwise
|
|
153
177
|
*/
|
|
154
178
|
export async function handleHelpRoutes(ctx: RouteContext): Promise<boolean> {
|
|
155
|
-
const { pathname, url, req, res } = ctx;
|
|
179
|
+
const { pathname, url, req, res, initialPath } = ctx;
|
|
156
180
|
|
|
157
181
|
// Initialize file watchers on first request
|
|
158
|
-
initializeFileWatchers();
|
|
182
|
+
initializeFileWatchers(initialPath);
|
|
159
183
|
|
|
160
|
-
const indexDir =
|
|
184
|
+
const indexDir = getIndexDir(initialPath);
|
|
161
185
|
|
|
162
186
|
// API: Get all commands with optional search
|
|
163
187
|
if (pathname === '/api/help/commands') {
|
|
188
|
+
if (!indexDir) {
|
|
189
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
190
|
+
res.end(JSON.stringify({ error: 'ccw-help index directory not found' }));
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
164
193
|
const searchQuery = url.searchParams.get('q') || '';
|
|
165
194
|
const filePath = join(indexDir, 'all-commands.json');
|
|
166
195
|
|
|
@@ -191,6 +220,11 @@ export async function handleHelpRoutes(ctx: RouteContext): Promise<boolean> {
|
|
|
191
220
|
|
|
192
221
|
// API: Get workflow command relationships
|
|
193
222
|
if (pathname === '/api/help/workflows') {
|
|
223
|
+
if (!indexDir) {
|
|
224
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
225
|
+
res.end(JSON.stringify({ error: 'ccw-help index directory not found' }));
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
194
228
|
const filePath = join(indexDir, 'command-relationships.json');
|
|
195
229
|
const relationships = getCachedData('command-relationships', filePath);
|
|
196
230
|
|
|
@@ -207,6 +241,11 @@ export async function handleHelpRoutes(ctx: RouteContext): Promise<boolean> {
|
|
|
207
241
|
|
|
208
242
|
// API: Get commands by category
|
|
209
243
|
if (pathname === '/api/help/commands/by-category') {
|
|
244
|
+
if (!indexDir) {
|
|
245
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
246
|
+
res.end(JSON.stringify({ error: 'ccw-help index directory not found' }));
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
210
249
|
const filePath = join(indexDir, 'by-category.json');
|
|
211
250
|
const byCategory = getCachedData('by-category', filePath);
|
|
212
251
|
|
|
@@ -334,12 +334,43 @@ export async function handleLiteLLMApiRoutes(ctx: RouteContext): Promise<boolean
|
|
|
334
334
|
return true;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
337
|
+
// Get the API key to test (prefer first key from apiKeys array, fall back to default apiKey)
|
|
338
|
+
let apiKeyValue: string | null = null;
|
|
339
|
+
if (provider.apiKeys && provider.apiKeys.length > 0) {
|
|
340
|
+
apiKeyValue = provider.apiKeys[0].key;
|
|
341
|
+
} else if (provider.apiKey) {
|
|
342
|
+
apiKeyValue = provider.apiKey;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (!apiKeyValue) {
|
|
346
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
347
|
+
res.end(JSON.stringify({ success: false, error: 'No API key configured for this provider' }));
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Resolve environment variables in the API key
|
|
352
|
+
const { resolveEnvVar } = await import('../../config/litellm-api-config-manager.js');
|
|
353
|
+
const resolvedKey = resolveEnvVar(apiKeyValue);
|
|
354
|
+
|
|
355
|
+
if (!resolvedKey) {
|
|
356
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
357
|
+
res.end(JSON.stringify({ success: false, error: 'API key is empty or environment variable not set' }));
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Determine API base URL
|
|
362
|
+
const apiBase = provider.apiBase || getDefaultApiBase(provider.type);
|
|
363
|
+
|
|
364
|
+
// Test the API key connection
|
|
365
|
+
const testResult = await testApiKeyConnection(provider.type, apiBase, resolvedKey);
|
|
340
366
|
|
|
341
367
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
342
|
-
res.end(JSON.stringify({
|
|
368
|
+
res.end(JSON.stringify({
|
|
369
|
+
success: testResult.valid,
|
|
370
|
+
provider: provider.type,
|
|
371
|
+
latencyMs: testResult.latencyMs,
|
|
372
|
+
error: testResult.error,
|
|
373
|
+
}));
|
|
343
374
|
} catch (err) {
|
|
344
375
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
345
376
|
res.end(JSON.stringify({ success: false, error: (err as Error).message }));
|
|
@@ -1256,5 +1256,89 @@ RULES: Be concise. Focus on practical understanding. Include function signatures
|
|
|
1256
1256
|
return true;
|
|
1257
1257
|
}
|
|
1258
1258
|
|
|
1259
|
+
// API: Memory Queue - Add path to queue
|
|
1260
|
+
if (pathname === '/api/memory/queue/add' && req.method === 'POST') {
|
|
1261
|
+
handlePostRequest(req, res, async (body) => {
|
|
1262
|
+
const { path: modulePath, tool = 'gemini', strategy = 'single-layer' } = body;
|
|
1263
|
+
|
|
1264
|
+
if (!modulePath) {
|
|
1265
|
+
return { error: 'path is required', status: 400 };
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
try {
|
|
1269
|
+
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
|
1270
|
+
const result = await memoryQueueTool.execute({
|
|
1271
|
+
action: 'add',
|
|
1272
|
+
path: modulePath,
|
|
1273
|
+
tool,
|
|
1274
|
+
strategy
|
|
1275
|
+
}) as { queueSize?: number; willFlush?: boolean; flushed?: boolean };
|
|
1276
|
+
|
|
1277
|
+
// Broadcast queue update event
|
|
1278
|
+
broadcastToClients({
|
|
1279
|
+
type: 'MEMORY_QUEUE_UPDATED',
|
|
1280
|
+
payload: {
|
|
1281
|
+
action: 'add',
|
|
1282
|
+
path: modulePath,
|
|
1283
|
+
queueSize: result.queueSize || 0,
|
|
1284
|
+
willFlush: result.willFlush || false,
|
|
1285
|
+
flushed: result.flushed || false,
|
|
1286
|
+
timestamp: new Date().toISOString()
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
return { success: true, ...result };
|
|
1291
|
+
} catch (error: unknown) {
|
|
1292
|
+
return { error: (error as Error).message, status: 500 };
|
|
1293
|
+
}
|
|
1294
|
+
});
|
|
1295
|
+
return true;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// API: Memory Queue - Get queue status
|
|
1299
|
+
if (pathname === '/api/memory/queue/status' && req.method === 'GET') {
|
|
1300
|
+
try {
|
|
1301
|
+
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
|
1302
|
+
const result = await memoryQueueTool.execute({ action: 'status' }) as Record<string, unknown>;
|
|
1303
|
+
|
|
1304
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1305
|
+
res.end(JSON.stringify({ success: true, ...result }));
|
|
1306
|
+
} catch (error: unknown) {
|
|
1307
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1308
|
+
res.end(JSON.stringify({ error: (error as Error).message }));
|
|
1309
|
+
}
|
|
1310
|
+
return true;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// API: Memory Queue - Flush queue immediately
|
|
1314
|
+
if (pathname === '/api/memory/queue/flush' && req.method === 'POST') {
|
|
1315
|
+
handlePostRequest(req, res, async () => {
|
|
1316
|
+
try {
|
|
1317
|
+
const { memoryQueueTool } = await import('../../tools/memory-update-queue.js');
|
|
1318
|
+
const result = await memoryQueueTool.execute({ action: 'flush' }) as {
|
|
1319
|
+
processed?: number;
|
|
1320
|
+
success?: boolean;
|
|
1321
|
+
errors?: unknown[];
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
// Broadcast queue flushed event
|
|
1325
|
+
broadcastToClients({
|
|
1326
|
+
type: 'MEMORY_QUEUE_FLUSHED',
|
|
1327
|
+
payload: {
|
|
1328
|
+
processed: result.processed || 0,
|
|
1329
|
+
success: result.success || false,
|
|
1330
|
+
errors: result.errors?.length || 0,
|
|
1331
|
+
timestamp: new Date().toISOString()
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
return { success: true, ...result };
|
|
1336
|
+
} catch (error: unknown) {
|
|
1337
|
+
return { error: (error as Error).message, status: 500 };
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
return true;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1259
1343
|
return false;
|
|
1260
1344
|
}
|