claude-code-workflow 6.2.7 → 6.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/.claude/CLAUDE.md +16 -1
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +11 -4
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +10 -75
- package/.claude/workflows/cli-tools-usage.md +14 -24
- package/.codex/AGENTS.md +51 -1
- package/.codex/prompts/compact.md +378 -0
- package/.gemini/GEMINI.md +57 -20
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +21 -8
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +2 -0
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +129 -8
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/hook.d.ts.map +1 -1
- package/ccw/dist/commands/hook.js +3 -2
- package/ccw/dist/commands/hook.js.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.d.ts +180 -0
- package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -0
- package/ccw/dist/config/litellm-api-config-manager.js +770 -0
- package/ccw/dist/config/litellm-api-config-manager.js.map +1 -0
- package/ccw/dist/config/provider-models.d.ts +73 -0
- package/ccw/dist/config/provider-models.d.ts.map +1 -0
- package/ccw/dist/config/provider-models.js +172 -0
- package/ccw/dist/config/provider-models.js.map +1 -0
- package/ccw/dist/core/cache-manager.d.ts.map +1 -1
- package/ccw/dist/core/cache-manager.js +3 -5
- package/ccw/dist/core/cache-manager.js.map +1 -1
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +3 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +169 -0
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.js +234 -18
- package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.js +30 -32
- package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts +21 -0
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-api-routes.js +780 -0
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts +20 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.js +85 -0
- package/ccw/dist/core/routes/litellm-routes.js.map +1 -0
- package/ccw/dist/core/routes/mcp-routes.js +2 -2
- package/ccw/dist/core/routes/mcp-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 +39 -0
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +1 -1
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +15 -1
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/mcp-server/index.js +1 -1
- package/ccw/dist/mcp-server/index.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +82 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -0
- package/ccw/dist/tools/claude-cli-tools.js +216 -0
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -0
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +76 -14
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +9 -2
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +114 -9
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/context-cache-store.d.ts +136 -0
- package/ccw/dist/tools/context-cache-store.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache-store.js +256 -0
- package/ccw/dist/tools/context-cache-store.js.map +1 -0
- package/ccw/dist/tools/context-cache.d.ts +56 -0
- package/ccw/dist/tools/context-cache.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache.js +294 -0
- package/ccw/dist/tools/context-cache.js.map +1 -0
- package/ccw/dist/tools/core-memory.d.ts.map +1 -1
- package/ccw/dist/tools/core-memory.js +33 -19
- package/ccw/dist/tools/core-memory.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 +85 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-client.js +188 -0
- package/ccw/dist/tools/litellm-client.js.map +1 -0
- package/ccw/dist/tools/litellm-executor.d.ts +34 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-executor.js +192 -0
- package/ccw/dist/tools/litellm-executor.js.map +1 -0
- package/ccw/dist/tools/pattern-parser.d.ts +55 -0
- package/ccw/dist/tools/pattern-parser.d.ts.map +1 -0
- package/ccw/dist/tools/pattern-parser.js +237 -0
- package/ccw/dist/tools/pattern-parser.js.map +1 -0
- package/ccw/dist/tools/smart-search.d.ts +1 -0
- package/ccw/dist/tools/smart-search.d.ts.map +1 -1
- package/ccw/dist/tools/smart-search.js +117 -41
- package/ccw/dist/tools/smart-search.js.map +1 -1
- package/ccw/dist/types/litellm-api-config.d.ts +294 -0
- package/ccw/dist/types/litellm-api-config.d.ts.map +1 -0
- package/ccw/dist/types/litellm-api-config.js +8 -0
- package/ccw/dist/types/litellm-api-config.js.map +1 -0
- package/ccw/src/cli.ts +258 -244
- package/ccw/src/commands/cli.ts +153 -9
- package/ccw/src/commands/hook.ts +3 -2
- package/ccw/src/config/.litellm-api-config-manager.ts.2025-12-23T11-57-43-727Z.bak +441 -0
- package/ccw/src/config/litellm-api-config-manager.ts +1012 -0
- package/ccw/src/config/provider-models.ts +222 -0
- package/ccw/src/core/cache-manager.ts +292 -294
- package/ccw/src/core/dashboard-generator.ts +3 -1
- package/ccw/src/core/routes/cli-routes.ts +192 -0
- package/ccw/src/core/routes/codexlens-routes.ts +241 -19
- package/ccw/src/core/routes/hooks-routes.ts +399 -405
- package/ccw/src/core/routes/litellm-api-routes.ts +930 -0
- package/ccw/src/core/routes/litellm-routes.ts +107 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -1271
- package/ccw/src/core/routes/status-routes.ts +51 -0
- package/ccw/src/core/routes/system-routes.ts +1 -1
- package/ccw/src/core/server.ts +15 -1
- package/ccw/src/mcp-server/index.ts +1 -1
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +44 -0
- package/ccw/src/templates/dashboard-css/31-api-settings.css +2265 -0
- package/ccw/src/templates/dashboard-js/components/cli-history.js +15 -8
- package/ccw/src/templates/dashboard-js/components/cli-status.js +323 -9
- package/ccw/src/templates/dashboard-js/components/navigation.js +329 -313
- package/ccw/src/templates/dashboard-js/i18n.js +583 -1
- package/ccw/src/templates/dashboard-js/views/api-settings.js +3362 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +199 -24
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +1265 -27
- package/ccw/src/templates/dashboard.html +840 -831
- package/ccw/src/tools/claude-cli-tools.ts +300 -0
- package/ccw/src/tools/cli-executor.ts +83 -14
- package/ccw/src/tools/codex-lens.ts +146 -9
- package/ccw/src/tools/context-cache-store.ts +368 -0
- package/ccw/src/tools/context-cache.ts +393 -0
- package/ccw/src/tools/core-memory.ts +33 -19
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +246 -0
- package/ccw/src/tools/litellm-executor.ts +241 -0
- package/ccw/src/tools/pattern-parser.ts +329 -0
- package/ccw/src/tools/smart-search.ts +142 -41
- package/ccw/src/types/litellm-api-config.ts +402 -0
- package/ccw-litellm/README.md +180 -0
- package/ccw-litellm/pyproject.toml +35 -0
- package/ccw-litellm/src/ccw_litellm/__init__.py +47 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/cli.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/cli.py +108 -0
- package/ccw-litellm/src/ccw_litellm/clients/__init__.py +12 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +251 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +165 -0
- package/ccw-litellm/src/ccw_litellm/config/__init__.py +22 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/loader.py +316 -0
- package/ccw-litellm/src/ccw_litellm/config/models.py +130 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__init__.py +14 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/embedder.py +52 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/llm.py +45 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +378 -23
- package/codex-lens/src/codexlens/cli/embedding_manager.py +660 -56
- package/codex-lens/src/codexlens/cli/model_manager.py +31 -18
- package/codex-lens/src/codexlens/cli/output.py +12 -1
- package/codex-lens/src/codexlens/config.py +93 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +6 -2
- package/codex-lens/src/codexlens/search/hybrid_search.py +44 -21
- package/codex-lens/src/codexlens/search/ranking.py +1 -1
- package/codex-lens/src/codexlens/semantic/__init__.py +42 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/base.py +61 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +43 -20
- package/codex-lens/src/codexlens/semantic/embedder.py +60 -13
- package/codex-lens/src/codexlens/semantic/factory.py +98 -0
- package/codex-lens/src/codexlens/semantic/gpu_support.py +225 -3
- package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -0
- package/codex-lens/src/codexlens/semantic/rotational_embedder.py +434 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +33 -8
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
- package/package.json +15 -5
- package/.codex/prompts.zip +0 -0
- package/ccw/package.json +0 -65
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Cache Store - In-memory cache with TTL and LRU eviction
|
|
3
|
+
* Stores packed file contents with session-based lifecycle management
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Cache entry metadata */
|
|
7
|
+
export interface CacheMetadata {
|
|
8
|
+
files: string[]; // Source file paths
|
|
9
|
+
patterns: string[]; // Original @patterns
|
|
10
|
+
total_bytes: number; // Total content bytes
|
|
11
|
+
file_count: number; // Number of files packed
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Cache entry structure */
|
|
15
|
+
export interface CacheEntry {
|
|
16
|
+
session_id: string;
|
|
17
|
+
created_at: number; // Timestamp ms
|
|
18
|
+
accessed_at: number; // Last access timestamp
|
|
19
|
+
ttl: number; // TTL in ms
|
|
20
|
+
content: string; // Packed file content
|
|
21
|
+
metadata: CacheMetadata;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Paginated read result */
|
|
25
|
+
export interface PagedReadResult {
|
|
26
|
+
content: string; // Current page content
|
|
27
|
+
offset: number; // Current byte offset
|
|
28
|
+
limit: number; // Requested bytes
|
|
29
|
+
total_bytes: number; // Total content bytes
|
|
30
|
+
has_more: boolean; // Has more content
|
|
31
|
+
next_offset: number | null; // Next page offset (null if no more)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Cache status info */
|
|
35
|
+
export interface CacheStatus {
|
|
36
|
+
entries: number; // Total cache entries
|
|
37
|
+
total_bytes: number; // Total bytes cached
|
|
38
|
+
oldest_session: string | null;
|
|
39
|
+
newest_session: string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Session status info */
|
|
43
|
+
export interface SessionStatus {
|
|
44
|
+
session_id: string;
|
|
45
|
+
exists: boolean;
|
|
46
|
+
files?: string[];
|
|
47
|
+
file_count?: number;
|
|
48
|
+
total_bytes?: number;
|
|
49
|
+
created_at?: string;
|
|
50
|
+
expires_at?: string;
|
|
51
|
+
accessed_at?: string;
|
|
52
|
+
ttl_remaining_ms?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Default configuration */
|
|
56
|
+
const DEFAULT_MAX_ENTRIES = 100;
|
|
57
|
+
const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
58
|
+
const DEFAULT_PAGE_SIZE = 65536; // 64KB
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Context Cache Store singleton
|
|
62
|
+
* Manages in-memory cache with TTL expiration and LRU eviction
|
|
63
|
+
*/
|
|
64
|
+
class ContextCacheStore {
|
|
65
|
+
private cache: Map<string, CacheEntry> = new Map();
|
|
66
|
+
private maxEntries: number;
|
|
67
|
+
private defaultTTL: number;
|
|
68
|
+
private cleanupInterval: NodeJS.Timeout | null = null;
|
|
69
|
+
|
|
70
|
+
constructor(options: {
|
|
71
|
+
maxEntries?: number;
|
|
72
|
+
defaultTTL?: number;
|
|
73
|
+
cleanupIntervalMs?: number;
|
|
74
|
+
} = {}) {
|
|
75
|
+
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
76
|
+
this.defaultTTL = options.defaultTTL ?? DEFAULT_TTL_MS;
|
|
77
|
+
|
|
78
|
+
// Start periodic cleanup
|
|
79
|
+
const cleanupMs = options.cleanupIntervalMs ?? 60000; // 1 minute
|
|
80
|
+
this.cleanupInterval = setInterval(() => {
|
|
81
|
+
this.cleanupExpired();
|
|
82
|
+
}, cleanupMs);
|
|
83
|
+
|
|
84
|
+
// Allow cleanup to not keep process alive
|
|
85
|
+
if (this.cleanupInterval.unref) {
|
|
86
|
+
this.cleanupInterval.unref();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Store packed content in cache
|
|
92
|
+
*/
|
|
93
|
+
set(
|
|
94
|
+
sessionId: string,
|
|
95
|
+
content: string,
|
|
96
|
+
metadata: CacheMetadata,
|
|
97
|
+
ttl?: number
|
|
98
|
+
): CacheEntry {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const entryTTL = ttl ?? this.defaultTTL;
|
|
101
|
+
|
|
102
|
+
// Evict if at capacity
|
|
103
|
+
if (this.cache.size >= this.maxEntries && !this.cache.has(sessionId)) {
|
|
104
|
+
this.evictOldest();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const entry: CacheEntry = {
|
|
108
|
+
session_id: sessionId,
|
|
109
|
+
created_at: now,
|
|
110
|
+
accessed_at: now,
|
|
111
|
+
ttl: entryTTL,
|
|
112
|
+
content,
|
|
113
|
+
metadata,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
this.cache.set(sessionId, entry);
|
|
117
|
+
return entry;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get cache entry by session ID
|
|
122
|
+
*/
|
|
123
|
+
get(sessionId: string): CacheEntry | null {
|
|
124
|
+
const entry = this.cache.get(sessionId);
|
|
125
|
+
|
|
126
|
+
if (!entry) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check TTL expiration
|
|
131
|
+
if (this.isExpired(entry)) {
|
|
132
|
+
this.cache.delete(sessionId);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Update access time (LRU)
|
|
137
|
+
entry.accessed_at = Date.now();
|
|
138
|
+
return entry;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Read content with pagination
|
|
143
|
+
*/
|
|
144
|
+
read(
|
|
145
|
+
sessionId: string,
|
|
146
|
+
offset: number = 0,
|
|
147
|
+
limit: number = DEFAULT_PAGE_SIZE
|
|
148
|
+
): PagedReadResult | null {
|
|
149
|
+
const entry = this.get(sessionId);
|
|
150
|
+
|
|
151
|
+
if (!entry) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const content = entry.content;
|
|
156
|
+
const totalBytes = Buffer.byteLength(content, 'utf-8');
|
|
157
|
+
|
|
158
|
+
// Handle byte-based offset for UTF-8
|
|
159
|
+
// For simplicity, we use character-based slicing
|
|
160
|
+
// This is approximate but works for most use cases
|
|
161
|
+
const charOffset = Math.min(offset, content.length);
|
|
162
|
+
const charLimit = Math.min(limit, content.length - charOffset);
|
|
163
|
+
|
|
164
|
+
const pageContent = content.slice(charOffset, charOffset + charLimit);
|
|
165
|
+
const endOffset = charOffset + pageContent.length;
|
|
166
|
+
const hasMore = endOffset < content.length;
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
content: pageContent,
|
|
170
|
+
offset: charOffset,
|
|
171
|
+
limit: charLimit,
|
|
172
|
+
total_bytes: totalBytes,
|
|
173
|
+
has_more: hasMore,
|
|
174
|
+
next_offset: hasMore ? endOffset : null,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Release (delete) cache entry
|
|
180
|
+
*/
|
|
181
|
+
release(sessionId: string): { released: boolean; freed_bytes: number } {
|
|
182
|
+
const entry = this.cache.get(sessionId);
|
|
183
|
+
|
|
184
|
+
if (!entry) {
|
|
185
|
+
return { released: false, freed_bytes: 0 };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const freedBytes = entry.metadata.total_bytes;
|
|
189
|
+
this.cache.delete(sessionId);
|
|
190
|
+
|
|
191
|
+
return { released: true, freed_bytes: freedBytes };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get session status
|
|
196
|
+
*/
|
|
197
|
+
getSessionStatus(sessionId: string): SessionStatus {
|
|
198
|
+
const entry = this.cache.get(sessionId);
|
|
199
|
+
|
|
200
|
+
if (!entry) {
|
|
201
|
+
return { session_id: sessionId, exists: false };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Check if expired
|
|
205
|
+
if (this.isExpired(entry)) {
|
|
206
|
+
this.cache.delete(sessionId);
|
|
207
|
+
return { session_id: sessionId, exists: false };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
const expiresAt = entry.created_at + entry.ttl;
|
|
212
|
+
const ttlRemaining = Math.max(0, expiresAt - now);
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
session_id: sessionId,
|
|
216
|
+
exists: true,
|
|
217
|
+
files: entry.metadata.files,
|
|
218
|
+
file_count: entry.metadata.file_count,
|
|
219
|
+
total_bytes: entry.metadata.total_bytes,
|
|
220
|
+
created_at: new Date(entry.created_at).toISOString(),
|
|
221
|
+
expires_at: new Date(expiresAt).toISOString(),
|
|
222
|
+
accessed_at: new Date(entry.accessed_at).toISOString(),
|
|
223
|
+
ttl_remaining_ms: ttlRemaining,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get overall cache status
|
|
229
|
+
*/
|
|
230
|
+
getStatus(): CacheStatus {
|
|
231
|
+
let totalBytes = 0;
|
|
232
|
+
let oldest: CacheEntry | null = null;
|
|
233
|
+
let newest: CacheEntry | null = null;
|
|
234
|
+
|
|
235
|
+
for (const entry of this.cache.values()) {
|
|
236
|
+
// Skip expired entries
|
|
237
|
+
if (this.isExpired(entry)) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
totalBytes += entry.metadata.total_bytes;
|
|
242
|
+
|
|
243
|
+
if (!oldest || entry.created_at < oldest.created_at) {
|
|
244
|
+
oldest = entry;
|
|
245
|
+
}
|
|
246
|
+
if (!newest || entry.created_at > newest.created_at) {
|
|
247
|
+
newest = entry;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
entries: this.cache.size,
|
|
253
|
+
total_bytes: totalBytes,
|
|
254
|
+
oldest_session: oldest?.session_id ?? null,
|
|
255
|
+
newest_session: newest?.session_id ?? null,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Cleanup expired entries
|
|
261
|
+
*/
|
|
262
|
+
cleanupExpired(): { removed: number } {
|
|
263
|
+
let removed = 0;
|
|
264
|
+
const now = Date.now();
|
|
265
|
+
|
|
266
|
+
for (const [sessionId, entry] of this.cache.entries()) {
|
|
267
|
+
if (this.isExpired(entry, now)) {
|
|
268
|
+
this.cache.delete(sessionId);
|
|
269
|
+
removed++;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return { removed };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Clear all cache entries
|
|
278
|
+
*/
|
|
279
|
+
clear(): { removed: number } {
|
|
280
|
+
const count = this.cache.size;
|
|
281
|
+
this.cache.clear();
|
|
282
|
+
return { removed: count };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Check if entry is expired
|
|
287
|
+
*/
|
|
288
|
+
private isExpired(entry: CacheEntry, now?: number): boolean {
|
|
289
|
+
const currentTime = now ?? Date.now();
|
|
290
|
+
return currentTime > entry.created_at + entry.ttl;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Evict oldest entry (LRU)
|
|
295
|
+
*/
|
|
296
|
+
private evictOldest(): void {
|
|
297
|
+
let oldest: [string, CacheEntry] | null = null;
|
|
298
|
+
|
|
299
|
+
for (const [sessionId, entry] of this.cache.entries()) {
|
|
300
|
+
if (!oldest || entry.accessed_at < oldest[1].accessed_at) {
|
|
301
|
+
oldest = [sessionId, entry];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (oldest) {
|
|
306
|
+
this.cache.delete(oldest[0]);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Stop cleanup timer (for graceful shutdown)
|
|
312
|
+
*/
|
|
313
|
+
destroy(): void {
|
|
314
|
+
if (this.cleanupInterval) {
|
|
315
|
+
clearInterval(this.cleanupInterval);
|
|
316
|
+
this.cleanupInterval = null;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* List all session IDs
|
|
322
|
+
*/
|
|
323
|
+
listSessions(): string[] {
|
|
324
|
+
return Array.from(this.cache.keys());
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Check if session exists and is valid
|
|
329
|
+
*/
|
|
330
|
+
has(sessionId: string): boolean {
|
|
331
|
+
const entry = this.cache.get(sessionId);
|
|
332
|
+
if (!entry) return false;
|
|
333
|
+
if (this.isExpired(entry)) {
|
|
334
|
+
this.cache.delete(sessionId);
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Singleton instance
|
|
342
|
+
let cacheInstance: ContextCacheStore | null = null;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get the singleton cache instance
|
|
346
|
+
*/
|
|
347
|
+
export function getContextCacheStore(options?: {
|
|
348
|
+
maxEntries?: number;
|
|
349
|
+
defaultTTL?: number;
|
|
350
|
+
cleanupIntervalMs?: number;
|
|
351
|
+
}): ContextCacheStore {
|
|
352
|
+
if (!cacheInstance) {
|
|
353
|
+
cacheInstance = new ContextCacheStore(options);
|
|
354
|
+
}
|
|
355
|
+
return cacheInstance;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Reset the cache instance (for testing)
|
|
360
|
+
*/
|
|
361
|
+
export function resetContextCacheStore(): void {
|
|
362
|
+
if (cacheInstance) {
|
|
363
|
+
cacheInstance.destroy();
|
|
364
|
+
cacheInstance = null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { ContextCacheStore };
|