aman-intelligence 0.1.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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/dist/bin/aman.d.ts +2 -0
  4. package/dist/bin/aman.js +165 -0
  5. package/dist/cli/global-install.d.ts +7 -0
  6. package/dist/cli/global-install.js +36 -0
  7. package/dist/cli/help-text.d.ts +1 -0
  8. package/dist/cli/help-text.js +62 -0
  9. package/dist/cli/version.d.ts +1 -0
  10. package/dist/cli/version.js +6 -0
  11. package/dist/commands/backup.d.ts +11 -0
  12. package/dist/commands/backup.js +262 -0
  13. package/dist/commands/browse.d.ts +11 -0
  14. package/dist/commands/browse.js +641 -0
  15. package/dist/commands/cache.d.ts +1 -0
  16. package/dist/commands/cache.js +38 -0
  17. package/dist/commands/config.d.ts +4 -0
  18. package/dist/commands/config.js +146 -0
  19. package/dist/commands/dashboard.d.ts +1 -0
  20. package/dist/commands/dashboard.js +1004 -0
  21. package/dist/commands/doctor.d.ts +4 -0
  22. package/dist/commands/doctor.js +54 -0
  23. package/dist/commands/export.d.ts +1 -0
  24. package/dist/commands/export.js +137 -0
  25. package/dist/commands/help.d.ts +1 -0
  26. package/dist/commands/help.js +47 -0
  27. package/dist/commands/import-wizard.d.ts +7 -0
  28. package/dist/commands/import-wizard.js +374 -0
  29. package/dist/commands/import.d.ts +9 -0
  30. package/dist/commands/import.js +351 -0
  31. package/dist/commands/info.d.ts +1 -0
  32. package/dist/commands/info.js +174 -0
  33. package/dist/commands/init.d.ts +20 -0
  34. package/dist/commands/init.js +146 -0
  35. package/dist/commands/install.d.ts +10 -0
  36. package/dist/commands/install.js +342 -0
  37. package/dist/commands/pack.d.ts +23 -0
  38. package/dist/commands/pack.js +331 -0
  39. package/dist/commands/registry.d.ts +6 -0
  40. package/dist/commands/registry.js +218 -0
  41. package/dist/commands/remove.d.ts +1 -0
  42. package/dist/commands/remove.js +76 -0
  43. package/dist/commands/search.d.ts +7 -0
  44. package/dist/commands/search.js +295 -0
  45. package/dist/commands/stack.d.ts +18 -0
  46. package/dist/commands/stack.js +327 -0
  47. package/dist/commands/sync.d.ts +9 -0
  48. package/dist/commands/sync.js +428 -0
  49. package/dist/commands/update.d.ts +1 -0
  50. package/dist/commands/update.js +97 -0
  51. package/dist/config/features.d.ts +2 -0
  52. package/dist/config/features.js +2 -0
  53. package/dist/config/index.d.ts +13 -0
  54. package/dist/config/index.js +80 -0
  55. package/dist/config/paths.d.ts +23 -0
  56. package/dist/config/paths.js +45 -0
  57. package/dist/import/adapters.d.ts +14 -0
  58. package/dist/import/adapters.js +580 -0
  59. package/dist/import/discovery.service.d.ts +8 -0
  60. package/dist/import/discovery.service.js +26 -0
  61. package/dist/import/import.service.d.ts +7 -0
  62. package/dist/import/import.service.js +259 -0
  63. package/dist/import/types.d.ts +71 -0
  64. package/dist/import/types.js +1 -0
  65. package/dist/import/utils.d.ts +36 -0
  66. package/dist/import/utils.js +428 -0
  67. package/dist/marketplace/cache.d.ts +18 -0
  68. package/dist/marketplace/cache.js +141 -0
  69. package/dist/marketplace/github-search.d.ts +17 -0
  70. package/dist/marketplace/github-search.js +268 -0
  71. package/dist/marketplace/install-from-candidate.d.ts +6 -0
  72. package/dist/marketplace/install-from-candidate.js +14 -0
  73. package/dist/marketplace/install.d.ts +15 -0
  74. package/dist/marketplace/install.js +54 -0
  75. package/dist/marketplace/metadata-validator.d.ts +8 -0
  76. package/dist/marketplace/metadata-validator.js +79 -0
  77. package/dist/marketplace/types.d.ts +34 -0
  78. package/dist/marketplace/types.js +1 -0
  79. package/dist/providers/local.provider.d.ts +9 -0
  80. package/dist/providers/local.provider.js +51 -0
  81. package/dist/providers/provider.interface.d.ts +7 -0
  82. package/dist/providers/provider.interface.js +1 -0
  83. package/dist/providers/registry.provider.d.ts +2 -0
  84. package/dist/providers/registry.provider.js +42 -0
  85. package/dist/providers/skills-sh.provider.d.ts +11 -0
  86. package/dist/providers/skills-sh.provider.js +56 -0
  87. package/dist/registry/adapter.interface.d.ts +16 -0
  88. package/dist/registry/adapter.interface.js +1 -0
  89. package/dist/registry/errors.d.ts +5 -0
  90. package/dist/registry/errors.js +8 -0
  91. package/dist/registry/filesystem-registry.adapter.d.ts +25 -0
  92. package/dist/registry/filesystem-registry.adapter.js +288 -0
  93. package/dist/registry/github-registry.adapter.d.ts +11 -0
  94. package/dist/registry/github-registry.adapter.js +32 -0
  95. package/dist/registry/index.d.ts +8 -0
  96. package/dist/registry/index.js +8 -0
  97. package/dist/registry/local-registry.adapter.d.ts +6 -0
  98. package/dist/registry/local-registry.adapter.js +9 -0
  99. package/dist/registry/registry.service.d.ts +44 -0
  100. package/dist/registry/registry.service.js +163 -0
  101. package/dist/registry/slug-utils.d.ts +12 -0
  102. package/dist/registry/slug-utils.js +51 -0
  103. package/dist/registry/types.d.ts +160 -0
  104. package/dist/registry/types.js +1 -0
  105. package/dist/services/asset.service.d.ts +12 -0
  106. package/dist/services/asset.service.js +142 -0
  107. package/dist/services/backup.service.d.ts +8 -0
  108. package/dist/services/backup.service.js +169 -0
  109. package/dist/services/classification.service.d.ts +31 -0
  110. package/dist/services/classification.service.js +271 -0
  111. package/dist/services/config.service.d.ts +9 -0
  112. package/dist/services/config.service.js +20 -0
  113. package/dist/services/doctor.service.d.ts +5 -0
  114. package/dist/services/doctor.service.js +186 -0
  115. package/dist/services/environment.service.d.ts +42 -0
  116. package/dist/services/environment.service.js +227 -0
  117. package/dist/services/github.service.d.ts +7 -0
  118. package/dist/services/github.service.js +42 -0
  119. package/dist/services/lock.service.d.ts +12 -0
  120. package/dist/services/lock.service.js +71 -0
  121. package/dist/services/marketplace.service.d.ts +40 -0
  122. package/dist/services/marketplace.service.js +225 -0
  123. package/dist/services/pack.service.d.ts +9 -0
  124. package/dist/services/pack.service.js +193 -0
  125. package/dist/services/stack.service.d.ts +9 -0
  126. package/dist/services/stack.service.js +94 -0
  127. package/dist/storage/asset-layout.d.ts +46 -0
  128. package/dist/storage/asset-layout.js +277 -0
  129. package/dist/storage/filesystem.d.ts +12 -0
  130. package/dist/storage/filesystem.js +113 -0
  131. package/dist/storage/scan-by-type.d.ts +2 -0
  132. package/dist/storage/scan-by-type.js +8 -0
  133. package/dist/storage/scanner.d.ts +11 -0
  134. package/dist/storage/scanner.js +188 -0
  135. package/dist/types/asset-metadata.d.ts +84 -0
  136. package/dist/types/asset-metadata.js +104 -0
  137. package/dist/types/index.d.ts +212 -0
  138. package/dist/types/index.js +1 -0
  139. package/dist/ui/animations/ErrorIndicator.d.ts +5 -0
  140. package/dist/ui/animations/ErrorIndicator.js +6 -0
  141. package/dist/ui/animations/GithubIndicator.d.ts +6 -0
  142. package/dist/ui/animations/GithubIndicator.js +9 -0
  143. package/dist/ui/animations/ProgressBar.d.ts +5 -0
  144. package/dist/ui/animations/ProgressBar.js +15 -0
  145. package/dist/ui/animations/Spinner.d.ts +5 -0
  146. package/dist/ui/animations/Spinner.js +21 -0
  147. package/dist/ui/animations/SuccessIndicator.d.ts +5 -0
  148. package/dist/ui/animations/SuccessIndicator.js +6 -0
  149. package/dist/ui/animations/SyncActivity.d.ts +5 -0
  150. package/dist/ui/animations/SyncActivity.js +21 -0
  151. package/dist/ui/animations/TransitionScreen.d.ts +7 -0
  152. package/dist/ui/animations/TransitionScreen.js +25 -0
  153. package/dist/ui/animations/useAnimationMode.d.ts +1 -0
  154. package/dist/ui/animations/useAnimationMode.js +16 -0
  155. package/dist/ui/assetDisplay.d.ts +19 -0
  156. package/dist/ui/assetDisplay.js +59 -0
  157. package/dist/ui/components/Confirm.d.ts +8 -0
  158. package/dist/ui/components/Confirm.js +14 -0
  159. package/dist/ui/components/CustomSelect.d.ts +19 -0
  160. package/dist/ui/components/CustomSelect.js +13 -0
  161. package/dist/ui/components/Header.d.ts +6 -0
  162. package/dist/ui/components/Header.js +9 -0
  163. package/dist/ui/components/HealthReport.d.ts +7 -0
  164. package/dist/ui/components/HealthReport.js +13 -0
  165. package/dist/ui/components/MarketplaceInstallConfirm.d.ts +19 -0
  166. package/dist/ui/components/MarketplaceInstallConfirm.js +23 -0
  167. package/dist/ui/components/Narrator.d.ts +9 -0
  168. package/dist/ui/components/Narrator.js +26 -0
  169. package/dist/ui/components/ScopePrompt.d.ts +8 -0
  170. package/dist/ui/components/ScopePrompt.js +23 -0
  171. package/dist/ui/components/TooSmallScreen.d.ts +8 -0
  172. package/dist/ui/components/TooSmallScreen.js +6 -0
  173. package/dist/ui/date.d.ts +2 -0
  174. package/dist/ui/date.js +33 -0
  175. package/dist/ui/layout.d.ts +23 -0
  176. package/dist/ui/layout.js +44 -0
  177. package/dist/ui/list-item.d.ts +12 -0
  178. package/dist/ui/list-item.js +1 -0
  179. package/dist/ui/marketplaceDisplay.d.ts +10 -0
  180. package/dist/ui/marketplaceDisplay.js +36 -0
  181. package/dist/ui/theme.d.ts +42 -0
  182. package/dist/ui/theme.js +47 -0
  183. package/dist/utils/asset-list-fields.d.ts +11 -0
  184. package/dist/utils/asset-list-fields.js +28 -0
  185. package/dist/utils/error-message.d.ts +2 -0
  186. package/dist/utils/error-message.js +6 -0
  187. package/dist/utils/integrity.d.ts +9 -0
  188. package/dist/utils/integrity.js +23 -0
  189. package/dist/utils/lock-migrate.d.ts +25 -0
  190. package/dist/utils/lock-migrate.js +93 -0
  191. package/dist/utils/mcp-local.d.ts +15 -0
  192. package/dist/utils/mcp-local.js +129 -0
  193. package/dist/utils/slug.d.ts +6 -0
  194. package/dist/utils/slug.js +13 -0
  195. package/dist/utils/stack-normalize.d.ts +3 -0
  196. package/dist/utils/stack-normalize.js +43 -0
  197. package/package.json +77 -0
@@ -0,0 +1,113 @@
1
+ import fs from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import path from 'path';
4
+ import yaml from 'js-yaml';
5
+ export async function ensureDir(dirPath) {
6
+ if (!existsSync(dirPath)) {
7
+ await fs.mkdir(dirPath, { recursive: true });
8
+ }
9
+ }
10
+ export async function readJson(filePath) {
11
+ try {
12
+ const data = await fs.readFile(filePath, 'utf-8');
13
+ return JSON.parse(data);
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export async function writeJson(filePath, data) {
20
+ await writeJsonAtomic(filePath, data);
21
+ }
22
+ /** Atomic JSON write (temp file + rename) to avoid corrupted half-writes. */
23
+ export async function writeJsonAtomic(filePath, data) {
24
+ await ensureDir(path.dirname(filePath));
25
+ const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
26
+ const payload = JSON.stringify(data, null, 2);
27
+ await fs.writeFile(tmpPath, payload, 'utf-8');
28
+ await fs.rename(tmpPath, filePath);
29
+ }
30
+ export async function copyDir(src, dest) {
31
+ if (!existsSync(src))
32
+ return;
33
+ await ensureDir(dest);
34
+ const entries = await fs.readdir(src, { withFileTypes: true });
35
+ for (const entry of entries) {
36
+ const srcPath = path.join(src, entry.name);
37
+ const destPath = path.join(dest, entry.name);
38
+ if (entry.isDirectory()) {
39
+ await copyDir(srcPath, destPath);
40
+ }
41
+ else {
42
+ await fs.copyFile(srcPath, destPath);
43
+ }
44
+ }
45
+ }
46
+ export async function removeDir(dirPath) {
47
+ if (!existsSync(dirPath))
48
+ return;
49
+ await fs.rm(dirPath, { recursive: true, force: true });
50
+ }
51
+ export async function listDirs(dirPath) {
52
+ if (!existsSync(dirPath))
53
+ return [];
54
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
55
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
56
+ }
57
+ export async function listFiles(dirPath, ext) {
58
+ if (!existsSync(dirPath))
59
+ return [];
60
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
61
+ return entries
62
+ .filter((e) => e.isFile() && (!ext || e.name.endsWith(ext)))
63
+ .map((e) => e.name);
64
+ }
65
+ export function exists(targetPath) {
66
+ return existsSync(targetPath);
67
+ }
68
+ export async function readFrontmatter(mdPath) {
69
+ try {
70
+ const content = await fs.readFile(mdPath, 'utf-8');
71
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
72
+ if (match && match[1]) {
73
+ const parsed = yaml.load(match[1]);
74
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
75
+ return parsed;
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ export async function isPathSafe(targetPath, rootDir) {
85
+ try {
86
+ const resolvedRoot = await fs.realpath(path.resolve(rootDir));
87
+ const absoluteTarget = path.resolve(targetPath);
88
+ let current = absoluteTarget;
89
+ let resolvedTarget = absoluteTarget;
90
+ while (current) {
91
+ if (existsSync(current)) {
92
+ const realCurrent = await fs.realpath(current);
93
+ resolvedTarget = path.join(realCurrent, path.relative(current, absoluteTarget));
94
+ break;
95
+ }
96
+ const parent = path.dirname(current);
97
+ if (parent === current)
98
+ break;
99
+ current = parent;
100
+ }
101
+ const relative = path.relative(resolvedRoot, resolvedTarget);
102
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
103
+ return false;
104
+ }
105
+ if (!resolvedTarget.startsWith(resolvedRoot)) {
106
+ return false;
107
+ }
108
+ return true;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
@@ -0,0 +1,2 @@
1
+ import { AssetListItem, AssetType } from '../types/index.js';
2
+ export declare function scanAssetsByType(type: AssetType, dir: string, source: string): Promise<AssetListItem[]>;
@@ -0,0 +1,8 @@
1
+ import { scanSkills, scanPrompts, scanMcps } from './scanner.js';
2
+ export async function scanAssetsByType(type, dir, source) {
3
+ if (type === 'skill')
4
+ return scanSkills(dir, source);
5
+ if (type === 'prompt')
6
+ return scanPrompts(dir, source);
7
+ return scanMcps(dir, source);
8
+ }
@@ -0,0 +1,11 @@
1
+ import { Skill, Prompt, McpConfig, Stack } from '../types/index.js';
2
+ export declare function scanSkills(dir: string, source?: string): Promise<Skill[]>;
3
+ export declare function scanPrompts(dir: string, source?: string): Promise<Prompt[]>;
4
+ export declare function scanMcps(dir: string, source?: string): Promise<McpConfig[]>;
5
+ export declare function scanStacks(dir: string, source?: string): Promise<Stack[]>;
6
+ export declare function scanAll(dir: string, source?: string): Promise<{
7
+ skills: Skill[];
8
+ prompts: Prompt[];
9
+ mcps: McpConfig[];
10
+ stacks: Stack[];
11
+ }>;
@@ -0,0 +1,188 @@
1
+ import path from 'path';
2
+ import { promises as fs } from 'fs';
3
+ import { exists, listDirs, listFiles, readFrontmatter, readJson } from './filesystem.js';
4
+ import { normalizeStack } from '../utils/stack-normalize.js';
5
+ import { assetDir, contentFilePath, metadataFilePath, isCanonicalAssetDir, } from './asset-layout.js';
6
+ const SCAN_CONCURRENCY = 20;
7
+ function stringArray(value) {
8
+ if (!Array.isArray(value))
9
+ return undefined;
10
+ const tags = value.filter((item) => typeof item === 'string' && item.trim().length > 0);
11
+ return tags.length > 0 ? tags : undefined;
12
+ }
13
+ async function boundedMap(items, limit, fn) {
14
+ if (items.length === 0)
15
+ return [];
16
+ const results = new Array(items.length);
17
+ let index = 0;
18
+ async function worker() {
19
+ while (index < items.length) {
20
+ const currentIdx = index++;
21
+ results[currentIdx] = await fn(items[currentIdx]);
22
+ }
23
+ }
24
+ const workers = Array.from({ length: Math.min(limit, items.length) }, worker);
25
+ await Promise.all(workers);
26
+ return results;
27
+ }
28
+ export async function scanSkills(dir, source = 'local') {
29
+ if (!exists(dir))
30
+ return [];
31
+ const skillDirs = await listDirs(dir);
32
+ const skills = await boundedMap(skillDirs, SCAN_CONCURRENCY, async (name) => {
33
+ const skillPath = assetDir('skill', dir, name);
34
+ const mdPath = contentFilePath(skillPath, 'skill');
35
+ const metadataPath = metadataFilePath(skillPath);
36
+ const hasMd = exists(mdPath);
37
+ let description;
38
+ let tags;
39
+ let category;
40
+ let installs;
41
+ let rating;
42
+ let updated;
43
+ let version;
44
+ let organization;
45
+ let originalName;
46
+ let slug;
47
+ let id;
48
+ if (hasMd) {
49
+ const frontmatter = await readFrontmatter(mdPath);
50
+ if (frontmatter) {
51
+ if (typeof frontmatter.description === 'string')
52
+ description = frontmatter.description;
53
+ tags = stringArray(frontmatter.tags);
54
+ const meta = frontmatter.metadata;
55
+ if (meta && typeof meta === 'object' && !Array.isArray(meta)) {
56
+ const metaObj = meta;
57
+ if (typeof metaObj.version === 'string')
58
+ version = metaObj.version;
59
+ if (typeof metaObj.author === 'string')
60
+ organization = metaObj.author;
61
+ }
62
+ }
63
+ }
64
+ const metadata = await readJson(metadataPath);
65
+ if (metadata) {
66
+ description = description || metadata.abstract;
67
+ tags = tags || stringArray(metadata.tags);
68
+ category = metadata.category;
69
+ installs = metadata.installs;
70
+ rating = metadata.rating;
71
+ updated = metadata.updated || metadata.date;
72
+ version = version || metadata.version;
73
+ organization = organization || metadata.organization;
74
+ originalName = metadata.originalName;
75
+ if (typeof metadata.slug === 'string')
76
+ slug = metadata.slug;
77
+ if (typeof metadata.id === 'string')
78
+ id = metadata.id;
79
+ }
80
+ return {
81
+ name,
82
+ path: skillPath,
83
+ description,
84
+ tags,
85
+ category,
86
+ installs,
87
+ rating,
88
+ updated,
89
+ version,
90
+ organization,
91
+ hasSkillMd: hasMd,
92
+ source,
93
+ originalName,
94
+ slug,
95
+ id,
96
+ };
97
+ });
98
+ return skills.filter((s) => s.hasSkillMd).sort((a, b) => a.name.localeCompare(b.name));
99
+ }
100
+ export async function scanPrompts(dir, source = 'local') {
101
+ if (!exists(dir))
102
+ return [];
103
+ const promptDirs = await listDirs(dir);
104
+ const prompts = await boundedMap(promptDirs, SCAN_CONCURRENCY, async (name) => {
105
+ const promptPath = assetDir('prompt', dir, name);
106
+ if (!isCanonicalAssetDir('prompt', promptPath))
107
+ return null;
108
+ const mdPath = contentFilePath(promptPath, 'prompt');
109
+ let description;
110
+ try {
111
+ const content = await fs.readFile(mdPath, 'utf-8');
112
+ const lines = content.split('\n');
113
+ const firstLine = lines.find((l) => l.trim().length > 0 && !l.startsWith('#'));
114
+ if (firstLine)
115
+ description = firstLine.trim();
116
+ }
117
+ catch {
118
+ // Ignore
119
+ }
120
+ const meta = await readJson(metadataFilePath(promptPath));
121
+ let slug;
122
+ let id;
123
+ if (meta) {
124
+ if (typeof meta.description === 'string')
125
+ description = meta.description || description;
126
+ if (typeof meta.slug === 'string')
127
+ slug = meta.slug;
128
+ if (typeof meta.id === 'string')
129
+ id = meta.id;
130
+ }
131
+ return {
132
+ name,
133
+ path: promptPath,
134
+ description,
135
+ source,
136
+ slug,
137
+ id,
138
+ };
139
+ });
140
+ const valid = prompts.filter((p) => p !== null);
141
+ return valid.sort((a, b) => a.name.localeCompare(b.name));
142
+ }
143
+ export async function scanMcps(dir, source = 'local') {
144
+ if (!exists(dir))
145
+ return [];
146
+ const mcpDirs = await listDirs(dir);
147
+ const mcps = await boundedMap(mcpDirs, SCAN_CONCURRENCY, async (name) => {
148
+ const mcpPath = assetDir('mcp', dir, name);
149
+ if (!isCanonicalAssetDir('mcp', mcpPath))
150
+ return null;
151
+ const jsonPath = contentFilePath(mcpPath, 'mcp');
152
+ const data = await readJson(jsonPath);
153
+ const meta = await readJson(metadataFilePath(mcpPath));
154
+ return {
155
+ name: (typeof data?.name === 'string' ? data.name : name),
156
+ path: mcpPath,
157
+ command: data?.command,
158
+ args: data?.args,
159
+ env: data?.env,
160
+ source,
161
+ slug: typeof meta?.slug === 'string' ? meta.slug : undefined,
162
+ id: typeof meta?.id === 'string' ? meta.id : undefined,
163
+ };
164
+ });
165
+ const validMcps = mcps.filter((m) => m !== null);
166
+ return validMcps.sort((a, b) => a.name.localeCompare(b.name));
167
+ }
168
+ export async function scanStacks(dir, source = 'local') {
169
+ if (!exists(dir))
170
+ return [];
171
+ const stackFiles = await listFiles(dir, '.json');
172
+ const stacks = await boundedMap(stackFiles, SCAN_CONCURRENCY, async (file) => {
173
+ const jsonPath = path.join(dir, file);
174
+ const data = await readJson(jsonPath);
175
+ return normalizeStack(data);
176
+ });
177
+ const validStacks = stacks.filter((s) => s !== null);
178
+ return validStacks.sort((a, b) => a.name.localeCompare(b.name));
179
+ }
180
+ export async function scanAll(dir, source = 'local') {
181
+ const [skills, prompts, mcps, stacks] = await Promise.all([
182
+ scanSkills(path.join(dir, 'skills'), source),
183
+ scanPrompts(path.join(dir, 'prompts'), source),
184
+ scanMcps(path.join(dir, 'mcps'), source),
185
+ scanStacks(path.join(dir, 'stacks'), source),
186
+ ]);
187
+ return { skills, prompts, mcps, stacks };
188
+ }
@@ -0,0 +1,84 @@
1
+ import { AssetType, Scope } from './index.js';
2
+ import { INTEGRITY_ALGORITHM } from '../utils/integrity.js';
3
+ export type AssetVisibility = 'public' | 'org' | 'private';
4
+ export interface AssetIntegrity {
5
+ algorithm: typeof INTEGRITY_ALGORITHM;
6
+ checksum: string;
7
+ signature: string | null;
8
+ }
9
+ export interface AssetDependency {
10
+ type: 'asset';
11
+ slug: string;
12
+ versionRange: string;
13
+ optional: boolean;
14
+ }
15
+ export interface DeprecatedMetadata {
16
+ at: string;
17
+ reason: string;
18
+ replacement?: string;
19
+ }
20
+ export interface AssetTrustSignals {
21
+ verified: boolean;
22
+ downloads: number;
23
+ rating: number | null;
24
+ publisher: string | null;
25
+ }
26
+ /** Unified metadata schema for skills, prompts, and MCPs (AMAN-ASSET-SPEC-V1). */
27
+ export interface AssetMetadata {
28
+ schemaVersion: 1;
29
+ id: string;
30
+ slug: string;
31
+ type: AssetType;
32
+ name: string;
33
+ description: string;
34
+ version: string;
35
+ author: string;
36
+ tags: string[];
37
+ scope: Scope;
38
+ visibility: AssetVisibility;
39
+ createdAt: string;
40
+ updatedAt: string;
41
+ integrity: AssetIntegrity;
42
+ dependencies: AssetDependency[];
43
+ trust: AssetTrustSignals;
44
+ deprecated: DeprecatedMetadata | null;
45
+ /** Local provenance; not required for registry publication. */
46
+ source?: string;
47
+ installedAt?: string;
48
+ originalName?: string;
49
+ originalSlug?: string;
50
+ /** Import provenance — tracks which tool and path an asset was imported from. */
51
+ provenance?: {
52
+ tool: string;
53
+ sourcePath: string;
54
+ importedAt: string;
55
+ };
56
+ }
57
+ export interface CreateAssetMetadataInput {
58
+ id?: string;
59
+ slug?: string;
60
+ description?: string;
61
+ tags?: string[];
62
+ version?: string;
63
+ author?: string;
64
+ scope?: Scope;
65
+ visibility?: AssetVisibility;
66
+ checksum?: string;
67
+ dependencies?: AssetDependency[];
68
+ trust?: Partial<AssetTrustSignals>;
69
+ deprecated?: DeprecatedMetadata | null;
70
+ source?: string;
71
+ installedAt?: string;
72
+ originalName?: string;
73
+ originalSlug?: string;
74
+ createdAt?: string;
75
+ updatedAt?: string;
76
+ provenance?: {
77
+ tool: string;
78
+ sourcePath: string;
79
+ importedAt: string;
80
+ };
81
+ }
82
+ export declare function createAssetMetadata(type: AssetType, name: string, overrides?: CreateAssetMetadataInput): AssetMetadata;
83
+ /** Merge partial legacy metadata.json into canonical shape for reads. */
84
+ export declare function normalizeAssetMetadata(raw: Record<string, unknown>, type: AssetType, name: string): AssetMetadata;
@@ -0,0 +1,104 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { defaultSlugForName } from '../utils/slug.js';
3
+ import { INTEGRITY_ALGORITHM } from '../utils/integrity.js';
4
+ export function createAssetMetadata(type, name, overrides = {}) {
5
+ const now = new Date().toISOString();
6
+ const slug = overrides.slug ?? defaultSlugForName(name);
7
+ const checksum = overrides.checksum ?? 'sha256:0000000000000000000000000000000000000000000000000000000000000000';
8
+ return {
9
+ schemaVersion: 1,
10
+ id: overrides.id ?? randomUUID(),
11
+ slug,
12
+ type,
13
+ name,
14
+ description: overrides.description ?? '',
15
+ version: overrides.version ?? '1.0.0',
16
+ author: overrides.author ?? 'unknown',
17
+ tags: overrides.tags ?? [],
18
+ scope: overrides.scope ?? 'global',
19
+ visibility: overrides.visibility ?? 'public',
20
+ createdAt: overrides.createdAt ?? now,
21
+ updatedAt: overrides.updatedAt ?? now,
22
+ integrity: {
23
+ algorithm: INTEGRITY_ALGORITHM,
24
+ checksum,
25
+ signature: null,
26
+ },
27
+ dependencies: overrides.dependencies ?? [],
28
+ trust: {
29
+ verified: overrides.trust?.verified ?? false,
30
+ downloads: overrides.trust?.downloads ?? 0,
31
+ rating: overrides.trust?.rating ?? null,
32
+ publisher: overrides.trust?.publisher ?? null,
33
+ },
34
+ deprecated: overrides.deprecated ?? null,
35
+ source: overrides.source,
36
+ installedAt: overrides.installedAt,
37
+ originalName: overrides.originalName ?? name,
38
+ originalSlug: overrides.originalSlug,
39
+ provenance: overrides.provenance,
40
+ };
41
+ }
42
+ /** Merge partial legacy metadata.json into canonical shape for reads. */
43
+ export function normalizeAssetMetadata(raw, type, name) {
44
+ const base = createAssetMetadata(type, name, {
45
+ id: typeof raw.id === 'string' ? raw.id : undefined,
46
+ slug: typeof raw.slug === 'string' ? raw.slug : undefined,
47
+ description: typeof raw.description === 'string' ? raw.description : undefined,
48
+ tags: Array.isArray(raw.tags) ? raw.tags.filter((t) => typeof t === 'string') : undefined,
49
+ version: typeof raw.version === 'string' ? raw.version : undefined,
50
+ author: typeof raw.author === 'string' ? raw.author : undefined,
51
+ scope: raw.scope === 'project' || raw.scope === 'global' ? raw.scope : undefined,
52
+ visibility: raw.visibility === 'public' || raw.visibility === 'org' || raw.visibility === 'private'
53
+ ? raw.visibility
54
+ : undefined,
55
+ source: typeof raw.source === 'string' ? raw.source : undefined,
56
+ installedAt: typeof raw.installedAt === 'string' ? raw.installedAt : undefined,
57
+ originalName: typeof raw.originalName === 'string' ? raw.originalName : undefined,
58
+ createdAt: typeof raw.createdAt === 'string' ? raw.createdAt : undefined,
59
+ });
60
+ const integrityRaw = raw.integrity;
61
+ if (integrityRaw && typeof integrityRaw.checksum === 'string') {
62
+ base.integrity.checksum = integrityRaw.checksum;
63
+ }
64
+ if (Array.isArray(raw.dependencies)) {
65
+ base.dependencies = raw.dependencies.filter((d) => typeof d === 'object' &&
66
+ d !== null &&
67
+ d.type === 'asset' &&
68
+ typeof d.slug === 'string');
69
+ }
70
+ const trustRaw = raw.trust;
71
+ if (trustRaw) {
72
+ if (typeof trustRaw.verified === 'boolean')
73
+ base.trust.verified = trustRaw.verified;
74
+ if (typeof trustRaw.downloads === 'number')
75
+ base.trust.downloads = trustRaw.downloads;
76
+ if (typeof trustRaw.rating === 'number' || trustRaw.rating === null)
77
+ base.trust.rating = trustRaw.rating;
78
+ if (typeof trustRaw.publisher === 'string' || trustRaw.publisher === null) {
79
+ base.trust.publisher = trustRaw.publisher;
80
+ }
81
+ }
82
+ if (raw.deprecated && typeof raw.deprecated === 'object') {
83
+ const dep = raw.deprecated;
84
+ if (typeof dep.at === 'string' && typeof dep.reason === 'string') {
85
+ base.deprecated = {
86
+ at: dep.at,
87
+ reason: dep.reason,
88
+ replacement: typeof dep.replacement === 'string' ? dep.replacement : undefined,
89
+ };
90
+ }
91
+ }
92
+ if (typeof raw.updatedAt === 'string') {
93
+ base.updatedAt = raw.updatedAt;
94
+ }
95
+ const provRaw = raw.provenance;
96
+ if (provRaw && typeof provRaw.tool === 'string' && typeof provRaw.sourcePath === 'string' && typeof provRaw.importedAt === 'string') {
97
+ base.provenance = {
98
+ tool: provRaw.tool,
99
+ sourcePath: provRaw.sourcePath,
100
+ importedAt: provRaw.importedAt,
101
+ };
102
+ }
103
+ return base;
104
+ }