@deimoscloud/coreai 0.1.9 → 0.1.11
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/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
- package/.prettierrc +0 -9
- package/AGENT_SPEC.md +0 -347
- package/ARCHITECTURE.md +0 -547
- package/DRAFT_PRD.md +0 -1440
- package/IMPLEMENTATION_PLAN.md +0 -256
- package/PRODUCT.md +0 -473
- package/WORKFLOWS.md +0 -295
- package/commands/core/check-inbox.md +0 -34
- package/commands/core/delegate.md +0 -30
- package/commands/core/git-commit.md +0 -144
- package/commands/core/pr-create.md +0 -193
- package/commands/core/review.md +0 -56
- package/commands/core/sprint-status.md +0 -65
- package/commands/optional/docs-update.md +0 -200
- package/commands/optional/jira-create.md +0 -200
- package/commands/optional/jira-transition.md +0 -184
- package/commands/optional/worktree-cleanup.md +0 -167
- package/commands/optional/worktree-setup.md +0 -110
- package/eslint.config.js +0 -29
- package/jest.config.js +0 -22
- package/knowledge-library/README.md +0 -118
- package/knowledge-library/android-engineer/context/current.txt +0 -42
- package/knowledge-library/android-engineer/control/decisions.txt +0 -9
- package/knowledge-library/android-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/android-engineer/control/objectives.txt +0 -26
- package/knowledge-library/android-engineer/history/.gitkeep +0 -0
- package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/architecture.txt +0 -61
- package/knowledge-library/backend-engineer/context/current.txt +0 -42
- package/knowledge-library/backend-engineer/control/decisions.txt +0 -9
- package/knowledge-library/backend-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/backend-engineer/control/objectives.txt +0 -26
- package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/context.txt +0 -52
- package/knowledge-library/devops-engineer/context/current.txt +0 -42
- package/knowledge-library/devops-engineer/control/decisions.txt +0 -9
- package/knowledge-library/devops-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/devops-engineer/control/objectives.txt +0 -26
- package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/context/current.txt +0 -40
- package/knowledge-library/engineering-manager/control/decisions.txt +0 -9
- package/knowledge-library/engineering-manager/control/objectives.txt +0 -27
- package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
- package/knowledge-library/prd.txt +0 -81
- package/knowledge-library/product-manager/context/current.txt +0 -42
- package/knowledge-library/product-manager/control/decisions.txt +0 -9
- package/knowledge-library/product-manager/control/dependencies.txt +0 -19
- package/knowledge-library/product-manager/control/objectives.txt +0 -26
- package/knowledge-library/product-manager/history/.gitkeep +0 -0
- package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/product-manager/tech/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/context/current.txt +0 -42
- package/knowledge-library/qa-engineer/control/decisions.txt +0 -9
- package/knowledge-library/qa-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/qa-engineer/control/objectives.txt +0 -26
- package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/security-engineer/context/current.txt +0 -42
- package/knowledge-library/security-engineer/control/decisions.txt +0 -9
- package/knowledge-library/security-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/security-engineer/control/objectives.txt +0 -26
- package/knowledge-library/security-engineer/history/.gitkeep +0 -0
- package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/context/current.txt +0 -42
- package/knowledge-library/solutions-architect/control/decisions.txt +0 -9
- package/knowledge-library/solutions-architect/control/dependencies.txt +0 -19
- package/knowledge-library/solutions-architect/control/objectives.txt +0 -26
- package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/context/current.txt +0 -42
- package/knowledge-library/wearos-engineer/control/decisions.txt +0 -9
- package/knowledge-library/wearos-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/wearos-engineer/control/objectives.txt +0 -26
- package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
- package/scripts/add-agent.sh +0 -323
- package/scripts/install.sh +0 -354
- package/src/adapters/factory.test.ts +0 -386
- package/src/adapters/factory.ts +0 -305
- package/src/adapters/index.ts +0 -113
- package/src/adapters/interfaces.ts +0 -268
- package/src/adapters/mcp/client.test.ts +0 -130
- package/src/adapters/mcp/client.ts +0 -451
- package/src/adapters/mcp/discovery.test.ts +0 -315
- package/src/adapters/mcp/discovery.ts +0 -340
- package/src/adapters/mcp/index.ts +0 -66
- package/src/adapters/mcp/mapper.test.ts +0 -218
- package/src/adapters/mcp/mapper.ts +0 -536
- package/src/adapters/mcp/registry.test.ts +0 -433
- package/src/adapters/mcp/registry.ts +0 -550
- package/src/adapters/mcp/types.ts +0 -258
- package/src/adapters/native/filesystem.test.ts +0 -350
- package/src/adapters/native/filesystem.ts +0 -393
- package/src/adapters/native/github.test.ts +0 -173
- package/src/adapters/native/github.ts +0 -627
- package/src/adapters/native/index.ts +0 -22
- package/src/adapters/native/selector.test.ts +0 -224
- package/src/adapters/native/selector.ts +0 -150
- package/src/adapters/types.ts +0 -270
- package/src/agents/compiler.test.ts +0 -410
- package/src/agents/compiler.ts +0 -424
- package/src/agents/index.ts +0 -37
- package/src/agents/loader.test.ts +0 -319
- package/src/agents/loader.ts +0 -143
- package/src/agents/resolver.test.ts +0 -282
- package/src/agents/resolver.ts +0 -262
- package/src/agents/types.ts +0 -97
- package/src/cache/index.ts +0 -38
- package/src/cache/interfaces.ts +0 -283
- package/src/cache/manager.test.ts +0 -266
- package/src/cache/manager.ts +0 -388
- package/src/cache/provider.test.ts +0 -485
- package/src/cache/provider.ts +0 -745
- package/src/cache/types.test.ts +0 -192
- package/src/cache/types.ts +0 -313
- package/src/cli/commands/build.test.ts +0 -248
- package/src/cli/commands/build.ts +0 -284
- package/src/cli/commands/cache.test.ts +0 -221
- package/src/cli/commands/cache.ts +0 -229
- package/src/cli/commands/index.ts +0 -63
- package/src/cli/commands/init.test.ts +0 -173
- package/src/cli/commands/init.ts +0 -296
- package/src/cli/commands/skills.test.ts +0 -272
- package/src/cli/commands/skills.ts +0 -348
- package/src/cli/commands/status.test.ts +0 -392
- package/src/cli/commands/status.ts +0 -332
- package/src/cli/commands/sync.test.ts +0 -213
- package/src/cli/commands/sync.ts +0 -251
- package/src/cli/commands/validate.test.ts +0 -216
- package/src/cli/commands/validate.ts +0 -340
- package/src/cli/index.test.ts +0 -190
- package/src/cli/index.ts +0 -493
- package/src/commands/context.test.ts +0 -163
- package/src/commands/context.ts +0 -111
- package/src/commands/index.ts +0 -56
- package/src/commands/loader.test.ts +0 -273
- package/src/commands/loader.ts +0 -355
- package/src/commands/registry.test.ts +0 -384
- package/src/commands/registry.ts +0 -248
- package/src/commands/runner.test.ts +0 -297
- package/src/commands/runner.ts +0 -222
- package/src/commands/types.ts +0 -361
- package/src/config/index.ts +0 -19
- package/src/config/loader.test.ts +0 -262
- package/src/config/loader.ts +0 -188
- package/src/config/types.ts +0 -154
- package/src/context/index.ts +0 -14
- package/src/context/loader.test.ts +0 -334
- package/src/context/loader.ts +0 -357
- package/src/index.test.ts +0 -13
- package/src/index.ts +0 -268
- package/src/knowledge-library/index.ts +0 -44
- package/src/knowledge-library/manager.test.ts +0 -536
- package/src/knowledge-library/manager.ts +0 -804
- package/src/knowledge-library/types.ts +0 -432
- package/src/skills/generator.test.ts +0 -602
- package/src/skills/generator.ts +0 -491
- package/src/skills/index.ts +0 -27
- package/src/skills/templates.ts +0 -520
- package/src/skills/types.ts +0 -251
- package/templates/completion-report.md +0 -72
- package/templates/feedback.md +0 -56
- package/templates/project-files/CLAUDE.md.template +0 -109
- package/templates/project-files/coreai.json.example +0 -47
- package/templates/project-files/mcp.json.template +0 -20
- package/templates/review-complete.md +0 -64
- package/templates/review-request.md +0 -67
- package/templates/task-assignment.md +0 -51
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -26
- package/tsup.config.ts +0 -23
package/src/cache/manager.ts
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache Manager
|
|
3
|
-
*
|
|
4
|
-
* Higher-level cache management that combines caching with remote fetching.
|
|
5
|
-
* Implements cache-first resolution with remote fallback strategy.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { CacheEntry, CacheMetadata, CacheOptions, CacheSource, SyncResult } from './types.js';
|
|
9
|
-
import { CacheError } from './types.js';
|
|
10
|
-
import type {
|
|
11
|
-
CacheProvider,
|
|
12
|
-
CacheManager as ICacheManager,
|
|
13
|
-
RemoteFetcher,
|
|
14
|
-
FetchOptions,
|
|
15
|
-
SyncOptions,
|
|
16
|
-
} from './interfaces.js';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Options for creating a cache manager
|
|
20
|
-
*/
|
|
21
|
-
export interface CacheManagerOptions {
|
|
22
|
-
/**
|
|
23
|
-
* The underlying cache provider
|
|
24
|
-
*/
|
|
25
|
-
cache: CacheProvider;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Default TTL in seconds
|
|
29
|
-
*/
|
|
30
|
-
defaultTtl?: number;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Default source for new entries
|
|
34
|
-
*/
|
|
35
|
-
defaultSource?: CacheSource;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Cache manager implementation
|
|
40
|
-
*
|
|
41
|
-
* Provides cache-first resolution strategy:
|
|
42
|
-
* 1. Check cache for valid entry
|
|
43
|
-
* 2. If cached and valid, return cached content
|
|
44
|
-
* 3. If stale or missing, fetch from remote
|
|
45
|
-
* 4. Cache the fetched content
|
|
46
|
-
* 5. Return the content
|
|
47
|
-
*/
|
|
48
|
-
export class CacheManager implements ICacheManager {
|
|
49
|
-
private cache: CacheProvider;
|
|
50
|
-
private fetchers = new Map<string, RemoteFetcher>();
|
|
51
|
-
private defaultTtl: number;
|
|
52
|
-
private defaultSource: CacheSource;
|
|
53
|
-
|
|
54
|
-
constructor(options: CacheManagerOptions) {
|
|
55
|
-
this.cache = options.cache;
|
|
56
|
-
this.defaultTtl = options.defaultTtl ?? 3600;
|
|
57
|
-
this.defaultSource = options.defaultSource ?? 'custom';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Get content with cache-first strategy
|
|
62
|
-
*/
|
|
63
|
-
async getWithFallback<T = string>(
|
|
64
|
-
key: string,
|
|
65
|
-
url: string,
|
|
66
|
-
options?: CacheOptions & FetchOptions
|
|
67
|
-
): Promise<CacheEntry<T>> {
|
|
68
|
-
// Try cache first (unless skipCache is set)
|
|
69
|
-
if (!options?.skipCache && !options?.forceRefresh) {
|
|
70
|
-
const cached = await this.cache.get<T>(key);
|
|
71
|
-
if (cached) {
|
|
72
|
-
const status = await this.cache.getStatus(key);
|
|
73
|
-
// Return if valid (not stale or expired)
|
|
74
|
-
if (status === 'valid') {
|
|
75
|
-
return cached;
|
|
76
|
-
}
|
|
77
|
-
// If stale, try to refresh but fall back to stale if fetch fails
|
|
78
|
-
if (status === 'stale') {
|
|
79
|
-
try {
|
|
80
|
-
return await this.fetchAndCache<T>(key, url, options);
|
|
81
|
-
} catch {
|
|
82
|
-
// Return stale content on fetch failure
|
|
83
|
-
return cached;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Cache miss or forceRefresh - fetch from remote
|
|
90
|
-
return this.fetchAndCache<T>(key, url, options);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Sync all entries from a source
|
|
95
|
-
*/
|
|
96
|
-
async syncSource(source: string, options?: SyncOptions): Promise<SyncResult> {
|
|
97
|
-
const startTime = Date.now();
|
|
98
|
-
const result: SyncResult = {
|
|
99
|
-
added: 0,
|
|
100
|
-
updated: 0,
|
|
101
|
-
removed: 0,
|
|
102
|
-
failed: 0,
|
|
103
|
-
errors: [],
|
|
104
|
-
duration: 0,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
// Get all entries from this source
|
|
108
|
-
const entries = await this.cache.list({ source: source as CacheSource });
|
|
109
|
-
|
|
110
|
-
// Sync each entry
|
|
111
|
-
const concurrency = options?.concurrency ?? 5;
|
|
112
|
-
const chunks = this.chunkArray(entries, concurrency);
|
|
113
|
-
|
|
114
|
-
for (const chunk of chunks) {
|
|
115
|
-
const promises = chunk.map(async (entry) => {
|
|
116
|
-
try {
|
|
117
|
-
const fetcher = this.fetchers.get(source);
|
|
118
|
-
if (!fetcher) {
|
|
119
|
-
throw new Error(`No fetcher registered for source: ${source}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Check if content has changed
|
|
123
|
-
const hasChanged = await fetcher.hasChanged(entry.sourceUrl, entry.etag);
|
|
124
|
-
|
|
125
|
-
if (hasChanged || options?.force) {
|
|
126
|
-
// Fetch and update
|
|
127
|
-
const fetchOptions: FetchOptions = {};
|
|
128
|
-
if (entry.etag) {
|
|
129
|
-
fetchOptions.etag = entry.etag;
|
|
130
|
-
}
|
|
131
|
-
const { content, metadata } = await fetcher.fetch(entry.sourceUrl, fetchOptions);
|
|
132
|
-
|
|
133
|
-
await this.cache.set(entry.key, content, {
|
|
134
|
-
...entry,
|
|
135
|
-
...metadata,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
result.updated++;
|
|
139
|
-
}
|
|
140
|
-
} catch (error) {
|
|
141
|
-
result.failed++;
|
|
142
|
-
result.errors.push({
|
|
143
|
-
key: entry.key,
|
|
144
|
-
error: error instanceof Error ? error.message : String(error),
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
if (!options?.continueOnError) {
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
await Promise.all(promises);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Report final progress
|
|
157
|
-
if (options?.onProgress) {
|
|
158
|
-
options.onProgress(entries.length, entries.length);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
result.duration = Date.now() - startTime;
|
|
162
|
-
return result;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Sync specific entries
|
|
167
|
-
*/
|
|
168
|
-
async syncEntries(keys: string[], options?: SyncOptions): Promise<SyncResult> {
|
|
169
|
-
const startTime = Date.now();
|
|
170
|
-
const result: SyncResult = {
|
|
171
|
-
added: 0,
|
|
172
|
-
updated: 0,
|
|
173
|
-
removed: 0,
|
|
174
|
-
failed: 0,
|
|
175
|
-
errors: [],
|
|
176
|
-
duration: 0,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const concurrency = options?.concurrency ?? 5;
|
|
180
|
-
const chunks = this.chunkArray(keys, concurrency);
|
|
181
|
-
|
|
182
|
-
for (const chunk of chunks) {
|
|
183
|
-
const promises = chunk.map(async (key) => {
|
|
184
|
-
try {
|
|
185
|
-
const metadata = await this.cache.getMetadata(key);
|
|
186
|
-
if (!metadata) {
|
|
187
|
-
result.failed++;
|
|
188
|
-
result.errors.push({ key, error: 'Entry not found in cache' });
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const fetcher = this.fetchers.get(metadata.source);
|
|
193
|
-
if (!fetcher) {
|
|
194
|
-
result.failed++;
|
|
195
|
-
result.errors.push({ key, error: `No fetcher for source: ${metadata.source}` });
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Check if content has changed
|
|
200
|
-
const hasChanged = await fetcher.hasChanged(metadata.sourceUrl, metadata.etag);
|
|
201
|
-
|
|
202
|
-
if (hasChanged || options?.force) {
|
|
203
|
-
const fetchOpts: FetchOptions = {};
|
|
204
|
-
if (metadata.etag) {
|
|
205
|
-
fetchOpts.etag = metadata.etag;
|
|
206
|
-
}
|
|
207
|
-
const { content, metadata: newMeta } = await fetcher.fetch(
|
|
208
|
-
metadata.sourceUrl,
|
|
209
|
-
fetchOpts
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
await this.cache.set(key, content, {
|
|
213
|
-
...metadata,
|
|
214
|
-
...newMeta,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
result.updated++;
|
|
218
|
-
}
|
|
219
|
-
} catch (error) {
|
|
220
|
-
result.failed++;
|
|
221
|
-
result.errors.push({
|
|
222
|
-
key,
|
|
223
|
-
error: error instanceof Error ? error.message : String(error),
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
if (!options?.continueOnError) {
|
|
227
|
-
throw error;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
await Promise.all(promises);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Report final progress
|
|
236
|
-
if (options?.onProgress) {
|
|
237
|
-
options.onProgress(keys.length, keys.length);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
result.duration = Date.now() - startTime;
|
|
241
|
-
return result;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Register a fetcher for a source
|
|
246
|
-
*/
|
|
247
|
-
registerFetcher(source: string, fetcher: RemoteFetcher): void {
|
|
248
|
-
this.fetchers.set(source, fetcher);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Get the underlying cache provider
|
|
253
|
-
*/
|
|
254
|
-
getCache(): CacheProvider {
|
|
255
|
-
return this.cache;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Check if a fetcher is registered for a source
|
|
260
|
-
*/
|
|
261
|
-
hasFetcher(source: string): boolean {
|
|
262
|
-
return this.fetchers.has(source);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Get all registered sources
|
|
267
|
-
*/
|
|
268
|
-
getRegisteredSources(): string[] {
|
|
269
|
-
return Array.from(this.fetchers.keys());
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Private helpers
|
|
273
|
-
|
|
274
|
-
private async fetchAndCache<T>(
|
|
275
|
-
key: string,
|
|
276
|
-
url: string,
|
|
277
|
-
options?: CacheOptions & FetchOptions
|
|
278
|
-
): Promise<CacheEntry<T>> {
|
|
279
|
-
// Determine source from URL
|
|
280
|
-
const source = this.getSourceFromUrl(url);
|
|
281
|
-
const fetcher = this.fetchers.get(source);
|
|
282
|
-
|
|
283
|
-
if (!fetcher) {
|
|
284
|
-
throw new CacheError(
|
|
285
|
-
`No fetcher registered for source: ${source}. Register one with registerFetcher().`,
|
|
286
|
-
'fetch_failed',
|
|
287
|
-
key
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
// Fetch from remote
|
|
293
|
-
const fetchOpts: FetchOptions = {};
|
|
294
|
-
if (options?.timeout) {
|
|
295
|
-
fetchOpts.timeout = options.timeout;
|
|
296
|
-
}
|
|
297
|
-
if (options?.headers) {
|
|
298
|
-
fetchOpts.headers = options.headers;
|
|
299
|
-
}
|
|
300
|
-
const { content, metadata } = await fetcher.fetch(url, fetchOpts);
|
|
301
|
-
|
|
302
|
-
// Build full metadata
|
|
303
|
-
const fullMetadata: Partial<CacheMetadata> = {
|
|
304
|
-
source: source as CacheSource,
|
|
305
|
-
sourceUrl: url,
|
|
306
|
-
contentType: metadata.contentType ?? 'text/plain',
|
|
307
|
-
};
|
|
308
|
-
if (metadata.etag) {
|
|
309
|
-
fullMetadata.etag = metadata.etag;
|
|
310
|
-
}
|
|
311
|
-
if (metadata.title) {
|
|
312
|
-
fullMetadata.title = metadata.title;
|
|
313
|
-
}
|
|
314
|
-
if (metadata.lastModified) {
|
|
315
|
-
fullMetadata.lastModified = metadata.lastModified;
|
|
316
|
-
}
|
|
317
|
-
if (options?.tags) {
|
|
318
|
-
fullMetadata.tags = options.tags;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Cache the content
|
|
322
|
-
const cacheOpts: CacheOptions = {
|
|
323
|
-
ttl: options?.ttl ?? this.defaultTtl,
|
|
324
|
-
};
|
|
325
|
-
if (options?.tags) {
|
|
326
|
-
cacheOpts.tags = options.tags;
|
|
327
|
-
}
|
|
328
|
-
await this.cache.set(key, content, fullMetadata, cacheOpts);
|
|
329
|
-
|
|
330
|
-
// Return the entry
|
|
331
|
-
const entry = await this.cache.get<T>(key);
|
|
332
|
-
if (!entry) {
|
|
333
|
-
throw new CacheError('Failed to retrieve cached entry after write', 'read_failed', key);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return entry;
|
|
337
|
-
} catch (error) {
|
|
338
|
-
if (error instanceof CacheError) {
|
|
339
|
-
throw error;
|
|
340
|
-
}
|
|
341
|
-
throw new CacheError(
|
|
342
|
-
`Failed to fetch content: ${error instanceof Error ? error.message : String(error)}`,
|
|
343
|
-
'fetch_failed',
|
|
344
|
-
key,
|
|
345
|
-
error instanceof Error ? error : undefined
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
private getSourceFromUrl(url: string): string {
|
|
351
|
-
try {
|
|
352
|
-
const parsed = new URL(url);
|
|
353
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
354
|
-
|
|
355
|
-
// Map common hostnames to sources
|
|
356
|
-
if (hostname.includes('confluence') || hostname.includes('atlassian.net')) {
|
|
357
|
-
return 'confluence';
|
|
358
|
-
}
|
|
359
|
-
if (hostname.includes('github.com') || hostname.includes('github')) {
|
|
360
|
-
return 'github';
|
|
361
|
-
}
|
|
362
|
-
if (hostname.includes('notion.so') || hostname.includes('notion')) {
|
|
363
|
-
return 'notion';
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Default to custom
|
|
367
|
-
return this.defaultSource;
|
|
368
|
-
} catch {
|
|
369
|
-
// Invalid URL, might be a file path
|
|
370
|
-
return 'local';
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
private chunkArray<T>(array: T[], size: number): T[][] {
|
|
375
|
-
const chunks: T[][] = [];
|
|
376
|
-
for (let i = 0; i < array.length; i += size) {
|
|
377
|
-
chunks.push(array.slice(i, i + size));
|
|
378
|
-
}
|
|
379
|
-
return chunks;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Create a cache manager
|
|
385
|
-
*/
|
|
386
|
-
export function createCacheManager(options: CacheManagerOptions): CacheManager {
|
|
387
|
-
return new CacheManager(options);
|
|
388
|
-
}
|