@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,129 @@
1
+ // engine/ecosystem-absorber/platform-crawler.ts — Crawls external sources for capability signals
2
+ const CAPABILITY_SIGNALS = {
3
+ api: ['endpoint', 'api', 'rest', 'graphql', 'webhook', 'http'],
4
+ sdk: ['sdk', 'library', 'package', 'client', 'integration'],
5
+ 'tool-use': ['tool', 'function calling', 'tool_use', 'mcp', 'tool call'],
6
+ agent: ['agent', 'autonomous', 'agentic', 'multi-agent', 'swarm'],
7
+ skill: ['skill', 'capability', 'plugin', 'extension', 'addon'],
8
+ pattern: ['pattern', 'best practice', 'workflow', 'architecture', 'design'],
9
+ };
10
+ /**
11
+ * Detect category from text content using signal keywords.
12
+ */
13
+ function detectCategory(text) {
14
+ const lower = text.toLowerCase();
15
+ for (const [cat, signals] of Object.entries(CAPABILITY_SIGNALS)) {
16
+ if (signals.some((s) => lower.includes(s))) {
17
+ return cat;
18
+ }
19
+ }
20
+ return 'pattern';
21
+ }
22
+ /**
23
+ * Extract capability signals from raw HTML/text content.
24
+ */
25
+ function extractCapabilities(content, source) {
26
+ const capabilities = [];
27
+ const now = new Date().toISOString();
28
+ // Extract headings and nearby text as capability signals
29
+ const headingPattern = /<h[1-4][^>]*>([^<]{5,120})<\/h[1-4]>/gi;
30
+ let match;
31
+ while ((match = headingPattern.exec(content)) !== null) {
32
+ const rawName = match[1];
33
+ if (!rawName) {
34
+ continue;
35
+ }
36
+ const name = rawName.replace(/\s+/g, ' ').trim();
37
+ if (name.length < 5 || name.length > 120) {
38
+ continue;
39
+ }
40
+ const category = detectCategory(name);
41
+ const id = `${source.id}:${name.toLowerCase().replace(/\W+/g, '-').slice(0, 60)}`;
42
+ capabilities.push({
43
+ id,
44
+ source: source.id,
45
+ category,
46
+ name,
47
+ description: `Discovered from ${source.name}: ${name}`,
48
+ url: source.url,
49
+ discoveredAt: now,
50
+ relevance: 0.5,
51
+ actionable: category !== 'pattern',
52
+ });
53
+ }
54
+ return capabilities.slice(0, 20);
55
+ }
56
+ /**
57
+ * Fetch a URL with timeout, returning null on any error.
58
+ */
59
+ async function safeFetch(url, timeoutMs = 8000) {
60
+ try {
61
+ const controller = new AbortController();
62
+ const timer = setTimeout(() => {
63
+ controller.abort();
64
+ }, timeoutMs);
65
+ const res = await fetch(url, { signal: controller.signal });
66
+ clearTimeout(timer);
67
+ if (!res.ok) {
68
+ return null;
69
+ }
70
+ return await res.text();
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ /**
77
+ * Crawl a docs-type source and return discovered capabilities.
78
+ * Never throws — returns empty array on any error.
79
+ */
80
+ export async function crawlDocsSource(source) {
81
+ const content = await safeFetch(source.url);
82
+ if (!content) {
83
+ return [];
84
+ }
85
+ return extractCapabilities(content, source);
86
+ }
87
+ /**
88
+ * Crawl a GitHub-type source using the public API.
89
+ * Never throws — returns empty array on any error.
90
+ */
91
+ export async function crawlGitHubSource(source) {
92
+ // Extract owner/repo from URL if present
93
+ const repoMatch = /github\.com\/([^/]+)\/([^/]+)/.exec(source.url);
94
+ if (!repoMatch) {
95
+ return crawlDocsSource(source);
96
+ }
97
+ const owner = repoMatch[1];
98
+ const repo = repoMatch[2];
99
+ const apiUrl = `https://api.github.com/repos/${owner}/${repo}/readme`;
100
+ const now = new Date().toISOString();
101
+ try {
102
+ const res = await fetch(apiUrl, {
103
+ headers: { Accept: 'application/vnd.github.raw+json', 'User-Agent': 'planu-ecosystem' },
104
+ });
105
+ if (!res.ok) {
106
+ return [];
107
+ }
108
+ const text = await res.text();
109
+ const category = detectCategory(text);
110
+ return [
111
+ {
112
+ id: `${source.id}:readme`,
113
+ source: source.id,
114
+ category,
115
+ name: `${repo} — README`,
116
+ description: text.slice(0, 200).replace(/\s+/g, ' ').trim(),
117
+ url: source.url,
118
+ discoveredAt: now,
119
+ relevance: 0.6,
120
+ actionable: true,
121
+ suggestion: `Review ${source.name} for integration opportunities`,
122
+ },
123
+ ];
124
+ }
125
+ catch {
126
+ return [];
127
+ }
128
+ }
129
+ //# sourceMappingURL=platform-crawler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-crawler.js","sourceRoot":"","sources":["../../../src/engine/ecosystem-absorber/platform-crawler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { fetchResilienceCriteria, formatResilienceSection } from './resilience-injector.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/resilience-fetcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { fetchResilienceCriteria, formatResilienceSection } from './resilience-injector.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/resilience-fetcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ProjectContext } from '../../types/index.js';
2
+ /**
3
+ * Fetch resilience patterns dynamically and convert to acceptance criteria.
4
+ * Uses the Dynamic Knowledge Engine (SPEC-153) to get current patterns.
5
+ */
6
+ export declare function fetchResilienceCriteria(context: ProjectContext): Promise<string[]>;
7
+ /**
8
+ * Generate the markdown section to inject into spec.md.
9
+ */
10
+ export declare function formatResilienceSection(criteria: string[]): string;
11
+ //# sourceMappingURL=resilience-injector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience-injector.d.ts","sourceRoot":"","sources":["../../../src/engine/resilience-fetcher/resilience-injector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,cAAc,EAAqB,MAAM,sBAAsB,CAAC;AAG7F;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOxF;AAqDD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAiBlE"}
@@ -0,0 +1,72 @@
1
+ import { queryKnowledge } from '../dynamic-knowledge/index.js';
2
+ /**
3
+ * Fetch resilience patterns dynamically and convert to acceptance criteria.
4
+ * Uses the Dynamic Knowledge Engine (SPEC-153) to get current patterns.
5
+ */
6
+ export async function fetchResilienceCriteria(context) {
7
+ const categories = ['patterns', 'security'];
8
+ const results = await Promise.all(categories.map((cat) => queryKnowledge(cat, context)));
9
+ const allItems = results.flatMap((r) => r.items);
10
+ return convertToAcceptanceCriteria(allItems, context);
11
+ }
12
+ /**
13
+ * Convert knowledge items into acceptance criteria text.
14
+ * Filters by target relevance and severity.
15
+ */
16
+ function convertToAcceptanceCriteria(items, context) {
17
+ const criteria = [];
18
+ const seen = new Set();
19
+ // Sort by severity: required first, then recommended
20
+ const sorted = [...items].sort((a, b) => {
21
+ const order = { required: 0, recommended: 1, optional: 2 };
22
+ return order[a.severity] - order[b.severity];
23
+ });
24
+ for (const item of sorted) {
25
+ // Skip if not relevant to target
26
+ if (!item.applicableTargets.includes(context.target) &&
27
+ !item.applicableTargets.includes('fullstack')) {
28
+ continue;
29
+ }
30
+ // Build AC text from item
31
+ const acText = buildACText(item);
32
+ // Deduplicate by normalized text
33
+ const normalized = acText.toLowerCase().replace(/\s+/g, ' ');
34
+ if (seen.has(normalized)) {
35
+ continue;
36
+ }
37
+ seen.add(normalized);
38
+ criteria.push(acText);
39
+ }
40
+ // Cap at 15 criteria to avoid overwhelming specs
41
+ return criteria.slice(0, 15);
42
+ }
43
+ /**
44
+ * Build acceptance criterion text from a knowledge item.
45
+ */
46
+ function buildACText(item) {
47
+ const prefix = item.severity === 'required' ? '[REQUIRED]' : '[RECOMMENDED]';
48
+ const source = item.sourceUrl ? ` (ref: ${item.sourceUrl})` : '';
49
+ // Use description as the AC, or title if description is too short
50
+ const text = item.description.length > 30 ? item.description : item.title;
51
+ return `${prefix} ${text}${source}`;
52
+ }
53
+ /**
54
+ * Generate the markdown section to inject into spec.md.
55
+ */
56
+ export function formatResilienceSection(criteria) {
57
+ if (criteria.length === 0) {
58
+ return '';
59
+ }
60
+ const lines = [
61
+ '',
62
+ '## Auto-generated Resilience Criteria',
63
+ '',
64
+ '> Dynamically fetched from current best practices (OWASP, SRE, AWS Well-Architected).',
65
+ '> These criteria are auto-injected by Planu and refresh periodically.',
66
+ '',
67
+ ...criteria.map((c) => `- [ ] ${c}`),
68
+ '',
69
+ ];
70
+ return lines.join('\n');
71
+ }
72
+ //# sourceMappingURL=resilience-injector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience-injector.js","sourceRoot":"","sources":["../../../src/engine/resilience-fetcher/resilience-injector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { SkillSearchResult } from '../../types/index.js';
2
+ /**
3
+ * Search agentskill.sh for skills matching the given query and optional stack.
4
+ * Returns an empty array on network errors or if the API is unavailable.
5
+ *
6
+ * TODO: Document actual API contract once agentskill.sh endpoints are confirmed.
7
+ */
8
+ export declare function searchAgentSkills(query: string, stack?: string, limit?: number): Promise<SkillSearchResult[]>;
9
+ //# sourceMappingURL=agentskill-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentskill-adapter.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-registry/agentskill-adapter.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAuC,MAAM,sBAAsB,CAAC;AAkDnG;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAU9B"}
@@ -0,0 +1,64 @@
1
+ // engine/skill-registry/agentskill-adapter.ts — SPEC-150: agentskill.sh registry adapter
2
+ // Searches agentskill.sh for installable agent skills.
3
+ // TODO: The agentskill.sh API endpoints need reverse-engineering.
4
+ // For now this module returns an empty array to satisfy the unified search interface
5
+ // while leaving a clear extension point once the API is documented.
6
+ const AGENTSKILL_BASE = 'https://agentskill.sh';
7
+ const USER_AGENT = 'Planu/1.0';
8
+ /** Attempt to fetch from agentskill.sh search endpoint (best-effort). */
9
+ async function fetchAgentSkill(query, stack) {
10
+ try {
11
+ const url = new URL(`${AGENTSKILL_BASE}/api/search`);
12
+ url.searchParams.set('q', query);
13
+ if (stack) {
14
+ url.searchParams.set('stack', stack);
15
+ }
16
+ const response = await globalThis.fetch(url.toString(), {
17
+ headers: {
18
+ 'User-Agent': USER_AGENT,
19
+ Accept: 'application/json',
20
+ },
21
+ signal: AbortSignal.timeout(8_000),
22
+ });
23
+ if (!response.ok) {
24
+ return null;
25
+ }
26
+ return (await response.json());
27
+ }
28
+ catch {
29
+ // Network unavailable, API not yet documented, or unexpected format — return null
30
+ return null;
31
+ }
32
+ }
33
+ /** Map a raw agentskill.sh entry to a unified SkillSearchResult. */
34
+ function mapEntry(entry) {
35
+ const name = entry.name ?? 'unknown';
36
+ return {
37
+ name,
38
+ description: entry.description ?? `Skill: ${name}`,
39
+ source: 'agentskill',
40
+ installCommand: `planu registry install agentskill/${name}`,
41
+ url: `${AGENTSKILL_BASE}/skills/${name}`,
42
+ author: entry.author,
43
+ installs: entry.installs,
44
+ license: entry.license,
45
+ tags: entry.tags,
46
+ relevanceScore: 0,
47
+ };
48
+ }
49
+ /**
50
+ * Search agentskill.sh for skills matching the given query and optional stack.
51
+ * Returns an empty array on network errors or if the API is unavailable.
52
+ *
53
+ * TODO: Document actual API contract once agentskill.sh endpoints are confirmed.
54
+ */
55
+ export async function searchAgentSkills(query, stack, limit) {
56
+ const data = await fetchAgentSkill(query, stack);
57
+ if (!data) {
58
+ return [];
59
+ }
60
+ const raw = data.skills ?? data.data ?? [];
61
+ const cap = limit ?? raw.length;
62
+ return raw.slice(0, cap).map(mapEntry);
63
+ }
64
+ //# sourceMappingURL=agentskill-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentskill-adapter.js","sourceRoot":"","sources":["../../../src/engine/skill-registry/agentskill-adapter.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,uDAAuD;AACvD,kEAAkE;AAClE,2FAA2F;AAC3F,0EAA0E;AAI1E,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAChD,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B,yEAAyE;AACzE,KAAK,UAAU,eAAe,CAAC,KAAa,EAAE,KAAc;IAC1D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,eAAe,aAAa,CAAC,CAAC;QACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACjC,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACtD,OAAO,EAAE;gBACP,YAAY,EAAE,UAAU;gBACxB,MAAM,EAAE,kBAAkB;aAC3B;YACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,kFAAkF;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,SAAS,QAAQ,CAAC,KAAsB;IACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;IACrC,OAAO;QACL,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,UAAU,IAAI,EAAE;QAClD,MAAM,EAAE,YAAY;QACpB,cAAc,EAAE,qCAAqC,IAAI,EAAE;QAC3D,GAAG,EAAE,GAAG,eAAe,WAAW,IAAI,EAAE;QACxC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,cAAc,EAAE,CAAC;KAClB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,KAAc,EACd,KAAc;IAEd,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAEjD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAC3C,MAAM,GAAG,GAAG,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC;IAChC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { SkillSearchResult } from '../../types/index.js';
2
+ /** Search Anthropic skills by query string (filters name/description/tags). */
3
+ export declare function searchAnthropicSkills(query: string, limit?: number): Promise<SkillSearchResult[]>;
4
+ /** Fetch SKILL.md content and list of sibling files for a specific skill. */
5
+ export declare function fetchAnthropicSkillContent(skillName: string): Promise<{
6
+ skillMd: string;
7
+ files: string[];
8
+ } | null>;
9
+ /** Invalidate the in-memory skill list cache (useful for tests). */
10
+ export declare function clearAnthropicCache(): void;
11
+ //# sourceMappingURL=anthropic-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-adapter.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-registry/anthropic-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,sBAAsB,CAAC;AA+G9B,+EAA+E;AAC/E,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED,6EAA6E;AAC7E,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAkCtD;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -0,0 +1,133 @@
1
+ // engine/skill-registry/anthropic-adapter.ts — SPEC-150: Anthropic skills.sh adapter
2
+ // Fetches skills from github.com/anthropics/skills using the public GitHub API.
3
+ // No auth required for public repos. Results cached in-memory (TTL 5 min).
4
+ const GITHUB_API_BASE = 'https://api.github.com';
5
+ const REPO_OWNER = 'anthropics';
6
+ const REPO_NAME = 'skills';
7
+ const SKILLS_DIR = 'skills';
8
+ const CACHE_TTL_MS = 5 * 60 * 1000;
9
+ const USER_AGENT = 'Planu/1.0';
10
+ // In-memory cache for the full skill list (avoids GitHub API rate limits)
11
+ let skillCache = null;
12
+ /** Parse YAML frontmatter from SKILL.md content (simple key:value only). */
13
+ function parseSkillFrontmatter(content) {
14
+ const match = /^---\n([\s\S]*?)\n---/.exec(content);
15
+ if (!match?.[1]) {
16
+ return {};
17
+ }
18
+ const result = {};
19
+ for (const line of match[1].split('\n')) {
20
+ const kv = /^(\w+):\s*(.+)$/.exec(line.trim());
21
+ if (!kv?.[1] || kv[2] === undefined) {
22
+ continue;
23
+ }
24
+ const key = kv[1];
25
+ const val = kv[2].trim().replace(/^["']|["']$/g, '');
26
+ if (key === 'tags') {
27
+ result.tags = val
28
+ .replace(/^\[|\]$/g, '')
29
+ .split(',')
30
+ .map((t) => t.trim().replace(/^["']|["']$/g, ''))
31
+ .filter(Boolean);
32
+ }
33
+ else {
34
+ result[key] = val;
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+ /** Fetch raw text from GitHub API (returns null on any error). */
40
+ async function fetchGitHub(path) {
41
+ try {
42
+ const response = await globalThis.fetch(`${GITHUB_API_BASE}${path}`, {
43
+ headers: {
44
+ 'User-Agent': USER_AGENT,
45
+ Accept: 'application/vnd.github.v3+json',
46
+ },
47
+ signal: AbortSignal.timeout(10_000),
48
+ });
49
+ if (!response.ok) {
50
+ return null;
51
+ }
52
+ return await response.json();
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ /** Fetch the list of all skill directories from the Anthropic skills repo. */
59
+ async function fetchSkillList() {
60
+ if (skillCache && Date.now() - skillCache.fetchedAt < CACHE_TTL_MS) {
61
+ return skillCache.data;
62
+ }
63
+ const contents = await fetchGitHub(`/repos/${REPO_OWNER}/${REPO_NAME}/contents/${SKILLS_DIR}`);
64
+ if (!Array.isArray(contents)) {
65
+ return [];
66
+ }
67
+ const skillDirs = contents.filter((item) => item.type === 'dir');
68
+ const results = await Promise.allSettled(skillDirs.map(async (dir) => {
69
+ const skillMdRaw = await fetchGitHub(`/repos/${REPO_OWNER}/${REPO_NAME}/contents/${SKILLS_DIR}/${dir.name}/SKILL.md`);
70
+ if (!skillMdRaw ||
71
+ typeof skillMdRaw !== 'object' ||
72
+ !('content' in skillMdRaw) ||
73
+ typeof skillMdRaw.content !== 'string') {
74
+ return null;
75
+ }
76
+ const rawContent = skillMdRaw.content;
77
+ const decoded = Buffer.from(rawContent.replace(/\n/g, ''), 'base64').toString('utf-8');
78
+ const meta = parseSkillFrontmatter(decoded);
79
+ return {
80
+ name: meta.name ?? dir.name,
81
+ description: meta.description ?? `Skill: ${dir.name}`,
82
+ source: 'anthropic',
83
+ installCommand: `planu registry install anthropics/skills/${dir.name}`,
84
+ url: `https://github.com/${REPO_OWNER}/${REPO_NAME}/tree/main/${SKILLS_DIR}/${dir.name}`,
85
+ author: meta.author ?? REPO_OWNER,
86
+ tags: meta.tags,
87
+ license: meta.license,
88
+ relevanceScore: 0,
89
+ };
90
+ }));
91
+ const skills = results
92
+ .map((r) => (r.status === 'fulfilled' ? r.value : null))
93
+ .filter((s) => s !== null);
94
+ skillCache = { data: skills, fetchedAt: Date.now() };
95
+ return skills;
96
+ }
97
+ /** Search Anthropic skills by query string (filters name/description/tags). */
98
+ export async function searchAnthropicSkills(query, limit) {
99
+ const all = await fetchSkillList();
100
+ const q = query.toLowerCase();
101
+ const filtered = all.filter((s) => s.name.toLowerCase().includes(q) ||
102
+ s.description.toLowerCase().includes(q) ||
103
+ s.tags?.some((t) => t.toLowerCase().includes(q)));
104
+ return filtered.slice(0, limit ?? filtered.length);
105
+ }
106
+ /** Fetch SKILL.md content and list of sibling files for a specific skill. */
107
+ export async function fetchAnthropicSkillContent(skillName) {
108
+ const dirContents = await fetchGitHub(`/repos/${REPO_OWNER}/${REPO_NAME}/contents/${SKILLS_DIR}/${skillName}`);
109
+ if (!Array.isArray(dirContents)) {
110
+ return null;
111
+ }
112
+ const items = dirContents;
113
+ const skillMdItem = items.find((f) => f.name === 'SKILL.md' && f.type === 'file');
114
+ if (!skillMdItem) {
115
+ return null;
116
+ }
117
+ const skillMdRaw = await fetchGitHub(`/repos/${REPO_OWNER}/${REPO_NAME}/contents/${SKILLS_DIR}/${skillName}/SKILL.md`);
118
+ if (!skillMdRaw ||
119
+ typeof skillMdRaw !== 'object' ||
120
+ !('content' in skillMdRaw) ||
121
+ typeof skillMdRaw.content !== 'string') {
122
+ return null;
123
+ }
124
+ const rawContent = skillMdRaw.content;
125
+ const skillMd = Buffer.from(rawContent.replace(/\n/g, ''), 'base64').toString('utf-8');
126
+ const files = items.filter((f) => f.type === 'file' && f.name !== 'SKILL.md').map((f) => f.name);
127
+ return { skillMd, files };
128
+ }
129
+ /** Invalidate the in-memory skill list cache (useful for tests). */
130
+ export function clearAnthropicCache() {
131
+ skillCache = null;
132
+ }
133
+ //# sourceMappingURL=anthropic-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-adapter.js","sourceRoot":"","sources":["../../../src/engine/skill-registry/anthropic-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { SkillRegistrySource, RegistryDiscoveryResult } from '../../types/index.js';
2
+ /**
3
+ * Discover new skill registries by crawling links from known registries.
4
+ * MVP stub — returns empty results immediately.
5
+ */
6
+ export declare function discoverNewRegistries(_knownRegistries: SkillRegistrySource[]): RegistryDiscoveryResult;
7
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-registry/discovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEzF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,mBAAmB,EAAE,GACtC,uBAAuB,CAMzB"}
@@ -0,0 +1,15 @@
1
+ // engine/skill-registry/discovery.ts — SPEC-150: Registry discovery (MVP stub)
2
+ // Crawls known registries looking for linked/referenced registries.
3
+ // Current MVP returns empty — full crawler planned for post-MVP.
4
+ /**
5
+ * Discover new skill registries by crawling links from known registries.
6
+ * MVP stub — returns empty results immediately.
7
+ */
8
+ export function discoverNewRegistries(_knownRegistries) {
9
+ return {
10
+ newRegistries: [],
11
+ crawledUrls: [],
12
+ errors: [],
13
+ };
14
+ }
15
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/engine/skill-registry/discovery.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,oEAAoE;AACpE,iEAAiE;AAIjE;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,gBAAuC;IAEvC,OAAO;QACL,aAAa,EAAE,EAAE;QACjB,WAAW,EAAE,EAAE;QACf,MAAM,EAAE,EAAE;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { searchAllRegistries } from './unified-search.js';
2
+ export { installSkill, isSkillInstalled, readSkillManifest } from './installer.js';
3
+ export { searchAnthropicSkills, fetchAnthropicSkillContent, clearAnthropicCache, } from './anthropic-adapter.js';
4
+ export { searchSkillsSh } from './skillssh-adapter.js';
5
+ export { searchAgentSkills } from './agentskill-adapter.js';
6
+ export { discoverNewRegistries } from './discovery.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-registry/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // engine/skill-registry/index.ts — Barrel for skill registry engine (SPEC-150)
2
+ export { searchAllRegistries } from './unified-search.js';
3
+ export { installSkill, isSkillInstalled, readSkillManifest } from './installer.js';
4
+ export { searchAnthropicSkills, fetchAnthropicSkillContent, clearAnthropicCache, } from './anthropic-adapter.js';
5
+ export { searchSkillsSh } from './skillssh-adapter.js';
6
+ export { searchAgentSkills } from './agentskill-adapter.js';
7
+ export { discoverNewRegistries } from './discovery.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/skill-registry/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { SkillInstallResult, SkillManifest } from '../../types/index.js';
2
+ /**
3
+ * Read the skill manifest from disk.
4
+ * Returns an empty manifest if the file does not exist or cannot be parsed.
5
+ */
6
+ export declare function readSkillManifest(projectPath: string): Promise<SkillManifest>;
7
+ /**
8
+ * Check whether a skill is already installed in the project.
9
+ */
10
+ export declare function isSkillInstalled(projectPath: string, skillName: string): Promise<boolean>;
11
+ /**
12
+ * Install a skill from the specified source into the project's .claude/skills/ directory.
13
+ *
14
+ * Steps:
15
+ * 1. Resolve the target installation directory.
16
+ * 2. Fetch skill content from the appropriate adapter.
17
+ * 3. Write files to disk.
18
+ * 4. Update the local manifest.
19
+ * 5. Return the install result with security flags.
20
+ */
21
+ export declare function installSkill(skillName: string, source: string, projectPath: string): Promise<SkillInstallResult>;
22
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-registry/installer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAuB,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAgBnG;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAOnF;AAQD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG/F;AA6DD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAoC7B"}