@thecat69/cache-ctrl 1.0.0 → 1.2.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.
Files changed (45) hide show
  1. package/README.md +289 -78
  2. package/cache_ctrl.ts +107 -25
  3. package/package.json +2 -1
  4. package/skills/cache-ctrl-caller/SKILL.md +53 -114
  5. package/skills/cache-ctrl-external/SKILL.md +29 -89
  6. package/skills/cache-ctrl-local/SKILL.md +82 -164
  7. package/src/analysis/graphBuilder.ts +85 -0
  8. package/src/analysis/pageRank.ts +164 -0
  9. package/src/analysis/symbolExtractor.ts +240 -0
  10. package/src/cache/cacheManager.ts +53 -4
  11. package/src/cache/externalCache.ts +72 -77
  12. package/src/cache/graphCache.ts +12 -0
  13. package/src/cache/localCache.ts +2 -0
  14. package/src/commands/checkFiles.ts +9 -6
  15. package/src/commands/flush.ts +9 -2
  16. package/src/commands/graph.ts +131 -0
  17. package/src/commands/inspect.ts +13 -181
  18. package/src/commands/inspectExternal.ts +79 -0
  19. package/src/commands/inspectLocal.ts +134 -0
  20. package/src/commands/install.ts +6 -0
  21. package/src/commands/invalidate.ts +24 -24
  22. package/src/commands/list.ts +11 -11
  23. package/src/commands/map.ts +87 -0
  24. package/src/commands/prune.ts +20 -8
  25. package/src/commands/search.ts +9 -2
  26. package/src/commands/touch.ts +15 -25
  27. package/src/commands/uninstall.ts +103 -0
  28. package/src/commands/update.ts +65 -0
  29. package/src/commands/version.ts +14 -0
  30. package/src/commands/watch.ts +270 -0
  31. package/src/commands/writeExternal.ts +51 -0
  32. package/src/commands/writeLocal.ts +121 -0
  33. package/src/files/changeDetector.ts +15 -0
  34. package/src/files/gitFiles.ts +15 -0
  35. package/src/files/openCodeInstaller.ts +21 -2
  36. package/src/index.ts +314 -58
  37. package/src/search/keywordSearch.ts +24 -0
  38. package/src/types/cache.ts +38 -26
  39. package/src/types/commands.ts +123 -22
  40. package/src/types/result.ts +26 -9
  41. package/src/utils/errors.ts +14 -0
  42. package/src/utils/traversal.ts +42 -0
  43. package/src/commands/checkFreshness.ts +0 -123
  44. package/src/commands/write.ts +0 -170
  45. package/src/http/freshnessChecker.ts +0 -116
@@ -1,116 +0,0 @@
1
- export interface FreshnessCheckInput {
2
- url: string;
3
- etag?: string;
4
- last_modified?: string;
5
- }
6
-
7
- export interface FreshnessCheckOutput {
8
- url: string;
9
- status: "fresh" | "stale" | "error";
10
- http_status?: number;
11
- etag?: string;
12
- last_modified?: string;
13
- error?: string;
14
- }
15
-
16
- /**
17
- * RFC-1918 / loopback / link-local / ULA / mapped-IPv6 IP pattern.
18
- * Blocks raw IP literals only — does NOT do DNS resolution.
19
- *
20
- * Covers:
21
- * - 127.x loopback IPv4
22
- * - ::1 loopback IPv6 (URL.hostname returns "[::1]")
23
- * - localhost loopback hostname
24
- * - 10.x RFC-1918 class A
25
- * - 169.254.x link-local IPv4
26
- * - 172.16–31.x RFC-1918 class B
27
- * - 192.168.x RFC-1918 class C
28
- * - 0.0.0.0 unspecified IPv4
29
- * - fc00::/7 RFC-4193 unique-local IPv6 (ULA — fc or fd prefix)
30
- * - ::ffff: IPv4-mapped IPv6
31
- */
32
- const PRIVATE_IP_PATTERN =
33
- /^(127\.|localhost$|10\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|0\.0\.0\.0$|\[::1\]$|::1$|::ffff:|f[cd][0-9a-f]{0,2}:|\[f[cd][0-9a-f]{0,2}:)/i;
34
-
35
- export function isAllowedUrl(url: string): { allowed: boolean; reason?: string } {
36
- try {
37
- const parsed = new URL(url);
38
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
39
- return { allowed: false, reason: `Disallowed URL scheme — only http and https are permitted: ${url}` };
40
- }
41
- if (PRIVATE_IP_PATTERN.test(parsed.hostname)) {
42
- return { allowed: false, reason: `Requests to private/loopback addresses are not permitted: ${url}` };
43
- }
44
- return { allowed: true };
45
- } catch {
46
- return { allowed: false, reason: `Invalid URL: ${url}` };
47
- }
48
- }
49
-
50
- export async function checkFreshness(input: FreshnessCheckInput): Promise<FreshnessCheckOutput> {
51
- const allowCheck = isAllowedUrl(input.url);
52
- if (!allowCheck.allowed) {
53
- const reason = allowCheck.reason ?? `Freshness check blocked for URL: ${input.url}`;
54
- return {
55
- url: input.url,
56
- status: "error",
57
- error: reason,
58
- };
59
- }
60
-
61
- const controller = new AbortController();
62
- const timeoutId = setTimeout(() => controller.abort(), 10_000);
63
-
64
- try {
65
- const headers: Record<string, string> = {};
66
- if (input.etag) {
67
- headers["If-None-Match"] = input.etag;
68
- }
69
- if (input.last_modified) {
70
- headers["If-Modified-Since"] = input.last_modified;
71
- }
72
-
73
- const response = await fetch(input.url, {
74
- method: "HEAD",
75
- headers,
76
- signal: controller.signal,
77
- });
78
-
79
- if (response.status === 304) {
80
- return {
81
- url: input.url,
82
- status: "fresh",
83
- http_status: 304,
84
- };
85
- }
86
-
87
- if (response.status === 200) {
88
- const etag = response.headers.get("etag") ?? undefined;
89
- const lastModified = response.headers.get("last-modified") ?? undefined;
90
- return {
91
- url: input.url,
92
- status: "stale",
93
- http_status: 200,
94
- ...(etag !== undefined ? { etag } : {}),
95
- ...(lastModified !== undefined ? { last_modified: lastModified } : {}),
96
- };
97
- }
98
-
99
- // 4xx/5xx
100
- return {
101
- url: input.url,
102
- status: "error",
103
- http_status: response.status,
104
- error: `HTTP ${response.status}: ${response.statusText}`,
105
- };
106
- } catch (err) {
107
- const error = err as Error;
108
- return {
109
- url: input.url,
110
- status: "error",
111
- error: error.message,
112
- };
113
- } finally {
114
- clearTimeout(timeoutId);
115
- }
116
- }