@planu/cli 0.62.0 → 0.63.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 (165) hide show
  1. package/dist/config/ecosystem-sources.json +34 -0
  2. package/dist/config/license-plans.json +5 -2
  3. package/dist/config/skill-registries.json +26 -0
  4. package/dist/engine/dynamic-knowledge/context-resolver.d.ts +15 -0
  5. package/dist/engine/dynamic-knowledge/context-resolver.d.ts.map +1 -0
  6. package/dist/engine/dynamic-knowledge/context-resolver.js +80 -0
  7. package/dist/engine/dynamic-knowledge/context-resolver.js.map +1 -0
  8. package/dist/engine/dynamic-knowledge/index.d.ts +7 -0
  9. package/dist/engine/dynamic-knowledge/index.d.ts.map +1 -0
  10. package/dist/engine/dynamic-knowledge/index.js +7 -0
  11. package/dist/engine/dynamic-knowledge/index.js.map +1 -0
  12. package/dist/engine/dynamic-knowledge/knowledge-cache.d.ts +8 -0
  13. package/dist/engine/dynamic-knowledge/knowledge-cache.d.ts.map +1 -0
  14. package/dist/engine/dynamic-knowledge/knowledge-cache.js +90 -0
  15. package/dist/engine/dynamic-knowledge/knowledge-cache.js.map +1 -0
  16. package/dist/engine/dynamic-knowledge/knowledge-merger.d.ts +13 -0
  17. package/dist/engine/dynamic-knowledge/knowledge-merger.d.ts.map +1 -0
  18. package/dist/engine/dynamic-knowledge/knowledge-merger.js +135 -0
  19. package/dist/engine/dynamic-knowledge/knowledge-merger.js.map +1 -0
  20. package/dist/engine/dynamic-knowledge/query-knowledge.d.ts +17 -0
  21. package/dist/engine/dynamic-knowledge/query-knowledge.d.ts.map +1 -0
  22. package/dist/engine/dynamic-knowledge/query-knowledge.js +73 -0
  23. package/dist/engine/dynamic-knowledge/query-knowledge.js.map +1 -0
  24. package/dist/engine/dynamic-knowledge/stack-filter.d.ts +7 -0
  25. package/dist/engine/dynamic-knowledge/stack-filter.d.ts.map +1 -0
  26. package/dist/engine/dynamic-knowledge/stack-filter.js +45 -0
  27. package/dist/engine/dynamic-knowledge/stack-filter.js.map +1 -0
  28. package/dist/engine/dynamic-knowledge/web-researcher.d.ts +12 -0
  29. package/dist/engine/dynamic-knowledge/web-researcher.d.ts.map +1 -0
  30. package/dist/engine/dynamic-knowledge/web-researcher.js +189 -0
  31. package/dist/engine/dynamic-knowledge/web-researcher.js.map +1 -0
  32. package/dist/engine/ecosystem-absorber/capability-detector.d.ts +11 -0
  33. package/dist/engine/ecosystem-absorber/capability-detector.d.ts.map +1 -0
  34. package/dist/engine/ecosystem-absorber/capability-detector.js +65 -0
  35. package/dist/engine/ecosystem-absorber/capability-detector.js.map +1 -0
  36. package/dist/engine/ecosystem-absorber/ecosystem-watcher.d.ts +11 -0
  37. package/dist/engine/ecosystem-absorber/ecosystem-watcher.d.ts.map +1 -0
  38. package/dist/engine/ecosystem-absorber/ecosystem-watcher.js +57 -0
  39. package/dist/engine/ecosystem-absorber/ecosystem-watcher.js.map +1 -0
  40. package/dist/engine/ecosystem-absorber/index.d.ts +5 -0
  41. package/dist/engine/ecosystem-absorber/index.d.ts.map +1 -0
  42. package/dist/engine/ecosystem-absorber/index.js +6 -0
  43. package/dist/engine/ecosystem-absorber/index.js.map +1 -0
  44. package/dist/engine/ecosystem-absorber/knowledge-cache.d.ts +23 -0
  45. package/dist/engine/ecosystem-absorber/knowledge-cache.d.ts.map +1 -0
  46. package/dist/engine/ecosystem-absorber/knowledge-cache.js +83 -0
  47. package/dist/engine/ecosystem-absorber/knowledge-cache.js.map +1 -0
  48. package/dist/engine/ecosystem-absorber/platform-crawler.d.ts +12 -0
  49. package/dist/engine/ecosystem-absorber/platform-crawler.d.ts.map +1 -0
  50. package/dist/engine/ecosystem-absorber/platform-crawler.js +129 -0
  51. package/dist/engine/ecosystem-absorber/platform-crawler.js.map +1 -0
  52. package/dist/engine/resilience-fetcher/index.d.ts +2 -0
  53. package/dist/engine/resilience-fetcher/index.d.ts.map +1 -0
  54. package/dist/engine/resilience-fetcher/index.js +2 -0
  55. package/dist/engine/resilience-fetcher/index.js.map +1 -0
  56. package/dist/engine/resilience-fetcher/resilience-injector.d.ts +11 -0
  57. package/dist/engine/resilience-fetcher/resilience-injector.d.ts.map +1 -0
  58. package/dist/engine/resilience-fetcher/resilience-injector.js +72 -0
  59. package/dist/engine/resilience-fetcher/resilience-injector.js.map +1 -0
  60. package/dist/engine/skill-registry/agentskill-adapter.d.ts +9 -0
  61. package/dist/engine/skill-registry/agentskill-adapter.d.ts.map +1 -0
  62. package/dist/engine/skill-registry/agentskill-adapter.js +64 -0
  63. package/dist/engine/skill-registry/agentskill-adapter.js.map +1 -0
  64. package/dist/engine/skill-registry/anthropic-adapter.d.ts +11 -0
  65. package/dist/engine/skill-registry/anthropic-adapter.d.ts.map +1 -0
  66. package/dist/engine/skill-registry/anthropic-adapter.js +133 -0
  67. package/dist/engine/skill-registry/anthropic-adapter.js.map +1 -0
  68. package/dist/engine/skill-registry/discovery.d.ts +7 -0
  69. package/dist/engine/skill-registry/discovery.d.ts.map +1 -0
  70. package/dist/engine/skill-registry/discovery.js +15 -0
  71. package/dist/engine/skill-registry/discovery.js.map +1 -0
  72. package/dist/engine/skill-registry/index.d.ts +7 -0
  73. package/dist/engine/skill-registry/index.d.ts.map +1 -0
  74. package/dist/engine/skill-registry/index.js +8 -0
  75. package/dist/engine/skill-registry/index.js.map +1 -0
  76. package/dist/engine/skill-registry/installer.d.ts +22 -0
  77. package/dist/engine/skill-registry/installer.d.ts.map +1 -0
  78. package/dist/engine/skill-registry/installer.js +122 -0
  79. package/dist/engine/skill-registry/installer.js.map +1 -0
  80. package/dist/engine/skill-registry/skillssh-adapter.d.ts +7 -0
  81. package/dist/engine/skill-registry/skillssh-adapter.d.ts.map +1 -0
  82. package/dist/engine/skill-registry/skillssh-adapter.js +78 -0
  83. package/dist/engine/skill-registry/skillssh-adapter.js.map +1 -0
  84. package/dist/engine/skill-registry/unified-search.d.ts +12 -0
  85. package/dist/engine/skill-registry/unified-search.d.ts.map +1 -0
  86. package/dist/engine/skill-registry/unified-search.js +116 -0
  87. package/dist/engine/skill-registry/unified-search.js.map +1 -0
  88. package/dist/engine/spec-summary-html.d.ts +1 -1
  89. package/dist/engine/spec-summary-html.d.ts.map +1 -1
  90. package/dist/engine/spec-summary-html.js +6 -2
  91. package/dist/engine/spec-summary-html.js.map +1 -1
  92. package/dist/index.js +4 -0
  93. package/dist/index.js.map +1 -1
  94. package/dist/tools/create-spec/constitution-validator.d.ts.map +1 -1
  95. package/dist/tools/create-spec/constitution-validator.js +7 -13
  96. package/dist/tools/create-spec/constitution-validator.js.map +1 -1
  97. package/dist/tools/create-spec/resilience-adapter.d.ts +6 -0
  98. package/dist/tools/create-spec/resilience-adapter.d.ts.map +1 -0
  99. package/dist/tools/create-spec/resilience-adapter.js +21 -0
  100. package/dist/tools/create-spec/resilience-adapter.js.map +1 -0
  101. package/dist/tools/create-spec.d.ts.map +1 -1
  102. package/dist/tools/create-spec.js +47 -5
  103. package/dist/tools/create-spec.js.map +1 -1
  104. package/dist/tools/delete-spec.js +1 -1
  105. package/dist/tools/delete-spec.js.map +1 -1
  106. package/dist/tools/ecosystem-status.d.ts +7 -0
  107. package/dist/tools/ecosystem-status.d.ts.map +1 -0
  108. package/dist/tools/ecosystem-status.js +69 -0
  109. package/dist/tools/ecosystem-status.js.map +1 -0
  110. package/dist/tools/list-specs.js +1 -1
  111. package/dist/tools/list-specs.js.map +1 -1
  112. package/dist/tools/register-ecosystem-tools.d.ts +7 -0
  113. package/dist/tools/register-ecosystem-tools.d.ts.map +1 -0
  114. package/dist/tools/register-ecosystem-tools.js +20 -0
  115. package/dist/tools/register-ecosystem-tools.js.map +1 -0
  116. package/dist/tools/register-skill-registry-tools.d.ts +3 -0
  117. package/dist/tools/register-skill-registry-tools.d.ts.map +1 -0
  118. package/dist/tools/register-skill-registry-tools.js +40 -0
  119. package/dist/tools/register-skill-registry-tools.js.map +1 -0
  120. package/dist/tools/schemas/ecosystem-schemas.d.ts +6 -0
  121. package/dist/tools/schemas/ecosystem-schemas.d.ts.map +1 -0
  122. package/dist/tools/schemas/ecosystem-schemas.js +10 -0
  123. package/dist/tools/schemas/ecosystem-schemas.js.map +1 -0
  124. package/dist/tools/schemas/index.d.ts +2 -0
  125. package/dist/tools/schemas/index.d.ts.map +1 -1
  126. package/dist/tools/schemas/index.js +2 -0
  127. package/dist/tools/schemas/index.js.map +1 -1
  128. package/dist/tools/schemas/skill-registry-schemas.d.ts +15 -0
  129. package/dist/tools/schemas/skill-registry-schemas.d.ts.map +1 -0
  130. package/dist/tools/schemas/skill-registry-schemas.js +45 -0
  131. package/dist/tools/schemas/skill-registry-schemas.js.map +1 -0
  132. package/dist/tools/skill-registry/index.d.ts +3 -0
  133. package/dist/tools/skill-registry/index.d.ts.map +1 -0
  134. package/dist/tools/skill-registry/index.js +4 -0
  135. package/dist/tools/skill-registry/index.js.map +1 -0
  136. package/dist/tools/skill-registry/install.d.ts +7 -0
  137. package/dist/tools/skill-registry/install.d.ts.map +1 -0
  138. package/dist/tools/skill-registry/install.js +42 -0
  139. package/dist/tools/skill-registry/install.js.map +1 -0
  140. package/dist/tools/skill-registry/search.d.ts +8 -0
  141. package/dist/tools/skill-registry/search.d.ts.map +1 -0
  142. package/dist/tools/skill-registry/search.js +45 -0
  143. package/dist/tools/skill-registry/search.js.map +1 -0
  144. package/dist/tools/update-status.js +1 -1
  145. package/dist/tools/update-status.js.map +1 -1
  146. package/dist/types/dynamic-knowledge.d.ts +47 -0
  147. package/dist/types/dynamic-knowledge.d.ts.map +1 -0
  148. package/dist/types/dynamic-knowledge.js +11 -0
  149. package/dist/types/dynamic-knowledge.js.map +1 -0
  150. package/dist/types/ecosystem.d.ts +45 -0
  151. package/dist/types/ecosystem.d.ts.map +1 -0
  152. package/dist/types/ecosystem.js +3 -0
  153. package/dist/types/ecosystem.js.map +1 -0
  154. package/dist/types/index.d.ts +3 -0
  155. package/dist/types/index.d.ts.map +1 -1
  156. package/dist/types/index.js +3 -0
  157. package/dist/types/index.js.map +1 -1
  158. package/dist/types/skill-registry.d.ts +162 -0
  159. package/dist/types/skill-registry.d.ts.map +1 -0
  160. package/dist/types/skill-registry.js +3 -0
  161. package/dist/types/skill-registry.js.map +1 -0
  162. package/package.json +1 -1
  163. package/src/config/ecosystem-sources.json +34 -0
  164. package/src/config/license-plans.json +5 -2
  165. package/src/config/skill-registries.json +26 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Filter knowledge items by relevance to the project context.
3
+ * Returns items sorted by relevance score (highest first).
4
+ */
5
+ export function filterByContext(items, context) {
6
+ const scored = items.map((item) => ({
7
+ item,
8
+ score: calculateRelevance(item, context),
9
+ }));
10
+ return scored
11
+ .filter((s) => s.score > 0.1) // minimum relevance threshold
12
+ .sort((a, b) => b.score - a.score)
13
+ .map((s) => s.item);
14
+ }
15
+ /**
16
+ * Calculate relevance score (0-1) for an item given the project context.
17
+ */
18
+ function calculateRelevance(item, context) {
19
+ let score = 0.3; // base score
20
+ // Target match (0.25 weight)
21
+ if (item.applicableTargets.includes(context.target) ||
22
+ item.applicableTargets.includes('fullstack')) {
23
+ score += 0.25;
24
+ }
25
+ // Stack match (0.25 weight)
26
+ const stackLower = context.stack.map((s) => s.toLowerCase());
27
+ const itemText = `${item.title} ${item.description} ${item.tags.join(' ')}`.toLowerCase();
28
+ const stackMatches = stackLower.filter((s) => itemText.includes(s)).length;
29
+ if (stackMatches > 0) {
30
+ score += Math.min(0.25, stackMatches * 0.1);
31
+ }
32
+ // Severity bonus (0.1 weight)
33
+ if (item.severity === 'required') {
34
+ score += 0.1;
35
+ }
36
+ else if (item.severity === 'recommended') {
37
+ score += 0.05;
38
+ }
39
+ // App type match (0.1 weight)
40
+ if (context.appType && itemText.includes(context.appType.toLowerCase())) {
41
+ score += 0.1;
42
+ }
43
+ return Math.min(1, score);
44
+ }
45
+ //# sourceMappingURL=stack-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-filter.js","sourceRoot":"","sources":["../../../src/engine/dynamic-knowledge/stack-filter.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAsB,EAAE,OAAuB;IAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClC,IAAI;QACJ,KAAK,EAAE,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC;KACzC,CAAC,CAAC,CAAC;IAEJ,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,8BAA8B;SAC3D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,IAAmB,EAAE,OAAuB;IACtE,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,aAAa;IAE9B,6BAA6B;IAC7B,IACE,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;QAC/C,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,EAC5C,CAAC;QACD,KAAK,IAAI,IAAI,CAAC;IAChB,CAAC;IAED,4BAA4B;IAC5B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1F,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3E,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,GAAG,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,8BAA8B;IAC9B,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACjC,KAAK,IAAI,GAAG,CAAC;IACf,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC3C,KAAK,IAAI,IAAI,CAAC;IAChB,CAAC;IAED,8BAA8B;IAC9B,IAAI,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACxE,KAAK,IAAI,GAAG,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { KnowledgeCategory, KnowledgeItem, WebSearchResult } from '../../types/index.js';
2
+ /**
3
+ * Perform a web search query and return parsed results.
4
+ * Uses DuckDuckGo HTML search as a free, no-API-key source.
5
+ * Falls back gracefully on network errors.
6
+ */
7
+ export declare function searchWeb(query: string): Promise<WebSearchResult[]>;
8
+ /**
9
+ * Fetch and extract knowledge items from web search results.
10
+ */
11
+ export declare function fetchKnowledge(queries: string[], category: KnowledgeCategory): Promise<KnowledgeItem[]>;
12
+ //# sourceMappingURL=web-researcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-researcher.d.ts","sourceRoot":"","sources":["../../../src/engine/dynamic-knowledge/web-researcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE9F;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAoBzE;AA+CD;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,aAAa,EAAE,CAAC,CAU1B"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Perform a web search query and return parsed results.
3
+ * Uses DuckDuckGo HTML search as a free, no-API-key source.
4
+ * Falls back gracefully on network errors.
5
+ */
6
+ export async function searchWeb(query) {
7
+ try {
8
+ const encoded = encodeURIComponent(query);
9
+ const url = `https://html.duckduckgo.com/html/?q=${encoded}`;
10
+ const response = await fetch(url, {
11
+ headers: {
12
+ 'User-Agent': 'Planu/1.0 (Dynamic Knowledge Engine)',
13
+ },
14
+ signal: AbortSignal.timeout(10000), // 10s timeout
15
+ });
16
+ if (!response.ok) {
17
+ return [];
18
+ }
19
+ const html = await response.text();
20
+ return parseDuckDuckGoResults(html);
21
+ }
22
+ catch {
23
+ return []; // graceful degradation
24
+ }
25
+ }
26
+ /**
27
+ * Parse DuckDuckGo HTML results into structured data.
28
+ */
29
+ function parseDuckDuckGoResults(html) {
30
+ const results = [];
31
+ // Extract result blocks - DuckDuckGo HTML uses class="result__a" for links
32
+ const linkRegex = /class="result__a"[^>]*href="([^"]*)"[^>]*>([^<]*)</g;
33
+ const snippetRegex = /class="result__snippet"[^>]*>([^<]*(?:<[^>]*>[^<]*)*)<\/a>/g;
34
+ let linkMatch;
35
+ const links = [];
36
+ while ((linkMatch = linkRegex.exec(html)) !== null) {
37
+ const rawUrl = linkMatch[1] ?? '';
38
+ const rawTitle = linkMatch[2] ?? '';
39
+ // DuckDuckGo wraps URLs in a redirect - extract actual URL
40
+ const urlMatch = /uddg=([^&]*)/.exec(rawUrl);
41
+ const url = urlMatch?.[1] !== undefined ? decodeURIComponent(urlMatch[1]) : rawUrl;
42
+ links.push({ url, title: rawTitle.trim() });
43
+ }
44
+ let snippetMatch;
45
+ const snippets = [];
46
+ while ((snippetMatch = snippetRegex.exec(html)) !== null) {
47
+ // Strip HTML tags from snippet
48
+ const raw = snippetMatch[1] ?? '';
49
+ snippets.push(raw.replace(/<[^>]*>/g, '').trim());
50
+ }
51
+ for (let i = 0; i < Math.min(links.length, 10); i++) {
52
+ const link = links[i];
53
+ if (!link) {
54
+ continue;
55
+ }
56
+ results.push({
57
+ title: link.title,
58
+ url: link.url,
59
+ snippet: snippets[i] ?? '',
60
+ });
61
+ }
62
+ return results;
63
+ }
64
+ /**
65
+ * Fetch and extract knowledge items from web search results.
66
+ */
67
+ export async function fetchKnowledge(queries, category) {
68
+ const allResults = [];
69
+ // Run queries sequentially to avoid rate limiting (max 3 queries)
70
+ for (const query of queries.slice(0, 3)) {
71
+ const results = await searchWeb(query);
72
+ allResults.push(...results);
73
+ }
74
+ return parseResultsToItems(allResults, category);
75
+ }
76
+ /**
77
+ * Convert raw web search results into structured KnowledgeItems.
78
+ */
79
+ function parseResultsToItems(results, category) {
80
+ const items = [];
81
+ const seen = new Set();
82
+ const now = new Date().toISOString();
83
+ for (const result of results) {
84
+ // Skip duplicates by URL
85
+ if (seen.has(result.url)) {
86
+ continue;
87
+ }
88
+ seen.add(result.url);
89
+ // Skip irrelevant results (ads, unrelated)
90
+ if (!result.snippet || result.snippet.length < 20) {
91
+ continue;
92
+ }
93
+ const id = `${category}-${Buffer.from(result.url).toString('base64url').slice(0, 12)}`;
94
+ items.push({
95
+ id,
96
+ category,
97
+ title: result.title,
98
+ description: result.snippet,
99
+ sourceUrl: result.url,
100
+ applicableTargets: inferTargets(result.snippet, category),
101
+ severity: inferSeverity(result.snippet, category),
102
+ tags: extractTags(result.snippet),
103
+ fetchedAt: now,
104
+ });
105
+ }
106
+ return items;
107
+ }
108
+ /**
109
+ * Infer which targets (frontend/backend/fullstack) a result applies to.
110
+ */
111
+ function inferTargets(snippet, category) {
112
+ const lower = snippet.toLowerCase();
113
+ const targets = [];
114
+ if (/\b(frontend|react|vue|angular|css|dom|browser|ui)\b/.test(lower)) {
115
+ targets.push('frontend');
116
+ }
117
+ if (/\b(backend|server|api|database|sql|endpoint|node)\b/.test(lower)) {
118
+ targets.push('backend');
119
+ }
120
+ if (/\b(fullstack|full.stack|both|universal)\b/.test(lower)) {
121
+ targets.push('fullstack');
122
+ }
123
+ // Security and compliance apply everywhere
124
+ if (targets.length === 0 && (category === 'security' || category === 'compliance')) {
125
+ return ['frontend', 'backend', 'fullstack'];
126
+ }
127
+ return targets.length > 0 ? targets : ['fullstack'];
128
+ }
129
+ /**
130
+ * Infer severity based on content signals.
131
+ */
132
+ function inferSeverity(snippet, category) {
133
+ const lower = snippet.toLowerCase();
134
+ if (category === 'security' && /\b(critical|vulnerability|exploit|owasp|cve)\b/.test(lower)) {
135
+ return 'required';
136
+ }
137
+ if (/\b(must|required|mandatory|essential|always)\b/.test(lower)) {
138
+ return 'required';
139
+ }
140
+ if (/\b(should|recommended|best practice|important)\b/.test(lower)) {
141
+ return 'recommended';
142
+ }
143
+ return 'optional';
144
+ }
145
+ /**
146
+ * Extract tags from snippet text.
147
+ */
148
+ function extractTags(snippet) {
149
+ const lower = snippet.toLowerCase();
150
+ const tags = [];
151
+ const techKeywords = [
152
+ 'react',
153
+ 'vue',
154
+ 'angular',
155
+ 'svelte',
156
+ 'next',
157
+ 'nuxt',
158
+ 'express',
159
+ 'nestjs',
160
+ 'django',
161
+ 'fastapi',
162
+ 'rails',
163
+ 'typescript',
164
+ 'python',
165
+ 'go',
166
+ 'rust',
167
+ 'java',
168
+ 'postgres',
169
+ 'mysql',
170
+ 'mongodb',
171
+ 'redis',
172
+ 'docker',
173
+ 'kubernetes',
174
+ 'aws',
175
+ 'gcp',
176
+ 'azure',
177
+ 'owasp',
178
+ 'csrf',
179
+ 'xss',
180
+ 'sql injection',
181
+ ];
182
+ for (const kw of techKeywords) {
183
+ if (lower.includes(kw)) {
184
+ tags.push(kw);
185
+ }
186
+ }
187
+ return tags.slice(0, 10); // max 10 tags
188
+ }
189
+ //# sourceMappingURL=web-researcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-researcher.js","sourceRoot":"","sources":["../../../src/engine/dynamic-knowledge/web-researcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { EcosystemCapability } from '../../types/index.js';
2
+ /**
3
+ * Score and rank ecosystem capabilities by relevance to project context.
4
+ * Returns top N most relevant, each with updated relevance score and suggestion.
5
+ */
6
+ export declare function rankCapabilities(capabilities: EcosystemCapability[], stackHints: string[], topN?: number): EcosystemCapability[];
7
+ /**
8
+ * Extract actionable suggestions as plain text lines.
9
+ */
10
+ export declare function extractSuggestions(capabilities: EcosystemCapability[]): string[];
11
+ //# sourceMappingURL=capability-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-detector.d.ts","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/capability-detector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAkDhE;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,mBAAmB,EAAE,EACnC,UAAU,EAAE,MAAM,EAAE,EACpB,IAAI,SAAK,GACR,mBAAmB,EAAE,CASvB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,mBAAmB,EAAE,GAAG,MAAM,EAAE,CAQhF"}
@@ -0,0 +1,65 @@
1
+ // engine/ecosystem-absorber/capability-detector.ts — Scores and filters capabilities by relevance
2
+ const CATEGORY_SCORE_MAP = {
3
+ api: 0.8,
4
+ sdk: 0.75,
5
+ 'tool-use': 0.9,
6
+ agent: 0.85,
7
+ skill: 0.7,
8
+ pattern: 0.5,
9
+ };
10
+ const STACK_SIGNALS = {
11
+ react: ['frontend', 'ui', 'component', 'design'],
12
+ typescript: ['sdk', 'type', 'library'],
13
+ python: ['ml', 'ai', 'data', 'notebook'],
14
+ docker: ['container', 'deployment', 'devops'],
15
+ mcp: ['tool-use', 'agent', 'protocol'],
16
+ };
17
+ /**
18
+ * Score a capability against a known project stack.
19
+ */
20
+ function scoreCapability(cap, stackHints) {
21
+ let base = CATEGORY_SCORE_MAP[cap.category] ?? 0.5;
22
+ const lowerName = cap.name.toLowerCase();
23
+ const lowerDesc = cap.description.toLowerCase();
24
+ for (const hint of stackHints) {
25
+ const signals = STACK_SIGNALS[hint] ?? [];
26
+ const matched = signals.some((s) => lowerName.includes(s) || lowerDesc.includes(s));
27
+ if (matched) {
28
+ base = Math.min(1, base + 0.15);
29
+ }
30
+ }
31
+ return Math.round(base * 100) / 100;
32
+ }
33
+ /**
34
+ * Generate an actionable suggestion for a capability.
35
+ */
36
+ function buildSuggestion(cap, stackHints) {
37
+ if (cap.suggestion) {
38
+ return cap.suggestion;
39
+ }
40
+ const stackHint = stackHints.length > 0 ? ` (detected stack: ${stackHints.join(', ')})` : '';
41
+ return `Consider integrating "${cap.name}" from ${cap.source}${stackHint}`;
42
+ }
43
+ /**
44
+ * Score and rank ecosystem capabilities by relevance to project context.
45
+ * Returns top N most relevant, each with updated relevance score and suggestion.
46
+ */
47
+ export function rankCapabilities(capabilities, stackHints, topN = 10) {
48
+ const scored = capabilities.map((cap) => ({
49
+ ...cap,
50
+ relevance: scoreCapability(cap, stackHints),
51
+ suggestion: buildSuggestion(cap, stackHints),
52
+ actionable: cap.relevance > 0.5 || cap.actionable,
53
+ }));
54
+ return scored.sort((a, b) => b.relevance - a.relevance).slice(0, topN);
55
+ }
56
+ /**
57
+ * Extract actionable suggestions as plain text lines.
58
+ */
59
+ export function extractSuggestions(capabilities) {
60
+ return capabilities
61
+ .filter((c) => c.actionable && typeof c.suggestion === 'string')
62
+ .map((c) => c.suggestion)
63
+ .slice(0, 5);
64
+ }
65
+ //# sourceMappingURL=capability-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-detector.js","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/capability-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { EcosystemCapability, EcosystemSource, WatcherSummary } from '../../types/index.js';
2
+ /**
3
+ * Orchestrate crawling all enabled sources, respecting TTL.
4
+ * Returns a summary of what was crawled and discovered.
5
+ */
6
+ export declare function runEcosystemWatcher(sources: EcosystemSource[], forceRefresh?: boolean): Promise<WatcherSummary>;
7
+ /**
8
+ * Load cached capabilities without re-crawling.
9
+ */
10
+ export declare function loadCachedCapabilities(): EcosystemCapability[];
11
+ //# sourceMappingURL=ecosystem-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecosystem-watcher.d.ts","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/ecosystem-watcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAoBjG;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,eAAe,EAAE,EAC1B,YAAY,UAAQ,GACnB,OAAO,CAAC,cAAc,CAAC,CAwCzB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,EAAE,CAE9D"}
@@ -0,0 +1,57 @@
1
+ // engine/ecosystem-absorber/ecosystem-watcher.ts — Orchestrates crawling all enabled sources
2
+ import { crawlDocsSource, crawlGitHubSource } from './platform-crawler.js';
3
+ import { readCache, writeCache, mergeCapabilities, isCacheStale, markCrawled, } from './knowledge-cache.js';
4
+ /**
5
+ * Crawl a single source based on its type. Never throws.
6
+ */
7
+ async function crawlSource(source) {
8
+ if (source.type === 'github') {
9
+ return crawlGitHubSource(source);
10
+ }
11
+ return crawlDocsSource(source);
12
+ }
13
+ /**
14
+ * Orchestrate crawling all enabled sources, respecting TTL.
15
+ * Returns a summary of what was crawled and discovered.
16
+ */
17
+ export async function runEcosystemWatcher(sources, forceRefresh = false) {
18
+ const cache = readCache();
19
+ const crawledSources = [];
20
+ const skippedSources = [];
21
+ let allNew = [];
22
+ const enabled = sources.filter((s) => s.enabled);
23
+ for (const source of enabled) {
24
+ const stale = forceRefresh || isCacheStale(cache.lastCrawled, source.id, source.crawlIntervalHours);
25
+ if (!stale) {
26
+ skippedSources.push(source.id);
27
+ continue;
28
+ }
29
+ const discovered = await crawlSource(source);
30
+ allNew = allNew.concat(discovered);
31
+ crawledSources.push(source.id);
32
+ cache.lastCrawled = markCrawled(cache.lastCrawled, source.id);
33
+ }
34
+ const merged = mergeCapabilities(cache.capabilities, allNew);
35
+ const updatedCache = {
36
+ ...cache,
37
+ capabilities: merged,
38
+ };
39
+ if (crawledSources.length > 0) {
40
+ writeCache(updatedCache);
41
+ }
42
+ return {
43
+ crawledSources,
44
+ skippedSources,
45
+ newCapabilities: allNew.length,
46
+ totalCapabilities: merged.length,
47
+ lastCrawled: updatedCache.lastCrawled,
48
+ capabilities: merged,
49
+ };
50
+ }
51
+ /**
52
+ * Load cached capabilities without re-crawling.
53
+ */
54
+ export function loadCachedCapabilities() {
55
+ return readCache().capabilities;
56
+ }
57
+ //# sourceMappingURL=ecosystem-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecosystem-watcher.js","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/ecosystem-watcher.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAG7F,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EACL,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,KAAK,UAAU,WAAW,CAAC,MAAuB;IAChD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA0B,EAC1B,YAAY,GAAG,KAAK;IAEpB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,MAAM,GAA0B,EAAE,CAAC;IAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAEjD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GACT,YAAY,IAAI,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACxF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/B,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACnC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG;QACnB,GAAG,KAAK;QACR,YAAY,EAAE,MAAM;KACrB,CAAC;IAEF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,UAAU,CAAC,YAAY,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,cAAc;QACd,cAAc;QACd,eAAe,EAAE,MAAM,CAAC,MAAM;QAC9B,iBAAiB,EAAE,MAAM,CAAC,MAAM;QAChC,WAAW,EAAE,YAAY,CAAC,WAAW;QACrC,YAAY,EAAE,MAAM;KACrB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,SAAS,EAAE,CAAC,YAAY,CAAC;AAClC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { crawlDocsSource, crawlGitHubSource } from './platform-crawler.js';
2
+ export { rankCapabilities, extractSuggestions } from './capability-detector.js';
3
+ export { readCache, writeCache, mergeCapabilities, isCacheStale, markCrawled, } from './knowledge-cache.js';
4
+ export { runEcosystemWatcher, loadCachedCapabilities } from './ecosystem-watcher.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // engine/ecosystem-absorber/index.ts — Barrel export for ecosystem absorber engine
2
+ export { crawlDocsSource, crawlGitHubSource } from './platform-crawler.js';
3
+ export { rankCapabilities, extractSuggestions } from './capability-detector.js';
4
+ export { readCache, writeCache, mergeCapabilities, isCacheStale, markCrawled, } from './knowledge-cache.js';
5
+ export { runEcosystemWatcher, loadCachedCapabilities } from './ecosystem-watcher.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { EcosystemCache, EcosystemCapability } from '../../types/index.js';
2
+ /**
3
+ * Read the ecosystem cache from disk. Returns empty cache on any error.
4
+ */
5
+ export declare function readCache(): EcosystemCache;
6
+ /**
7
+ * Write updated cache to disk. Silently ignores write errors.
8
+ */
9
+ export declare function writeCache(cache: EcosystemCache): void;
10
+ /**
11
+ * Merge new capabilities into existing cache, deduplicating by id.
12
+ * Prunes capabilities older than PRUNE_DAYS days.
13
+ */
14
+ export declare function mergeCapabilities(existing: EcosystemCapability[], incoming: EcosystemCapability[]): EcosystemCapability[];
15
+ /**
16
+ * Check whether a source needs re-crawling given its TTL in hours.
17
+ */
18
+ export declare function isCacheStale(lastCrawled: Record<string, string>, sourceId: string, intervalHours: number): boolean;
19
+ /**
20
+ * Update the lastCrawled timestamp for a source.
21
+ */
22
+ export declare function markCrawled(lastCrawled: Record<string, string>, sourceId: string): Record<string, string>;
23
+ //# sourceMappingURL=knowledge-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-cache.d.ts","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/knowledge-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAiBhF;;GAEG;AACH,wBAAgB,SAAS,IAAI,cAAc,CAe1C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAOtD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,mBAAmB,EAAE,CAgBvB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAOT;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
@@ -0,0 +1,83 @@
1
+ // engine/ecosystem-absorber/knowledge-cache.ts — Reads/writes ecosystem capability cache
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const CACHE_VERSION = '1';
5
+ const PRUNE_DAYS = 30;
6
+ const DATA_DIR = join(process.cwd(), 'data', 'ecosystem');
7
+ const CACHE_FILE = join(DATA_DIR, 'capabilities.json');
8
+ function emptyCache() {
9
+ return { lastCrawled: {}, capabilities: [], version: CACHE_VERSION };
10
+ }
11
+ function ensureDir() {
12
+ if (!existsSync(DATA_DIR)) {
13
+ mkdirSync(DATA_DIR, { recursive: true });
14
+ }
15
+ }
16
+ /**
17
+ * Read the ecosystem cache from disk. Returns empty cache on any error.
18
+ */
19
+ export function readCache() {
20
+ try {
21
+ if (!existsSync(CACHE_FILE)) {
22
+ return emptyCache();
23
+ }
24
+ const raw = readFileSync(CACHE_FILE, 'utf-8');
25
+ const parsed = JSON.parse(raw);
26
+ return {
27
+ lastCrawled: parsed.lastCrawled ?? {},
28
+ capabilities: Array.isArray(parsed.capabilities) ? parsed.capabilities : [],
29
+ version: parsed.version ?? CACHE_VERSION,
30
+ };
31
+ }
32
+ catch {
33
+ return emptyCache();
34
+ }
35
+ }
36
+ /**
37
+ * Write updated cache to disk. Silently ignores write errors.
38
+ */
39
+ export function writeCache(cache) {
40
+ try {
41
+ ensureDir();
42
+ writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf-8');
43
+ }
44
+ catch {
45
+ // Graceful degradation — do not throw
46
+ }
47
+ }
48
+ /**
49
+ * Merge new capabilities into existing cache, deduplicating by id.
50
+ * Prunes capabilities older than PRUNE_DAYS days.
51
+ */
52
+ export function mergeCapabilities(existing, incoming) {
53
+ const cutoff = Date.now() - PRUNE_DAYS * 24 * 60 * 60 * 1000;
54
+ const map = new Map();
55
+ for (const cap of existing) {
56
+ const ts = new Date(cap.discoveredAt).getTime();
57
+ if (ts >= cutoff) {
58
+ map.set(cap.id, cap);
59
+ }
60
+ }
61
+ for (const cap of incoming) {
62
+ map.set(cap.id, cap);
63
+ }
64
+ return Array.from(map.values());
65
+ }
66
+ /**
67
+ * Check whether a source needs re-crawling given its TTL in hours.
68
+ */
69
+ export function isCacheStale(lastCrawled, sourceId, intervalHours) {
70
+ const last = lastCrawled[sourceId];
71
+ if (!last) {
72
+ return true;
73
+ }
74
+ const elapsed = (Date.now() - new Date(last).getTime()) / 3_600_000;
75
+ return elapsed >= intervalHours;
76
+ }
77
+ /**
78
+ * Update the lastCrawled timestamp for a source.
79
+ */
80
+ export function markCrawled(lastCrawled, sourceId) {
81
+ return { ...lastCrawled, [sourceId]: new Date().toISOString() };
82
+ }
83
+ //# sourceMappingURL=knowledge-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-cache.js","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/knowledge-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { EcosystemCapability, EcosystemSource } from '../../types/index.js';
2
+ /**
3
+ * Crawl a docs-type source and return discovered capabilities.
4
+ * Never throws — returns empty array on any error.
5
+ */
6
+ export declare function crawlDocsSource(source: EcosystemSource): Promise<EcosystemCapability[]>;
7
+ /**
8
+ * Crawl a GitHub-type source using the public API.
9
+ * Never throws — returns empty array on any error.
10
+ */
11
+ export declare function crawlGitHubSource(source: EcosystemSource): Promise<EcosystemCapability[]>;
12
+ //# sourceMappingURL=platform-crawler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-crawler.d.ts","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/platform-crawler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAkFjF;;;GAGG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAM7F;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAsC/F"}