vibesuite 1.3.2 → 2.0.1

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 (75) hide show
  1. package/README.md +8 -1
  2. package/assets/.agent/skills/avoid-feature-creep/SKILL.md +307 -0
  3. package/assets/.agent/skills/avoid-feature-creep/agents/openai.yaml +3 -0
  4. package/assets/.agent/skills/avoid-feature-creep/assets/large-logo.png +0 -0
  5. package/assets/.agent/skills/avoid-feature-creep/assets/small-logo.svg +17 -0
  6. package/assets/.agent/skills/convex/SKILL.md +62 -0
  7. package/assets/.agent/skills/convex/agents/openai.yaml +3 -0
  8. package/assets/.agent/skills/convex/assets/large-logo.png +0 -0
  9. package/assets/.agent/skills/convex/assets/small-logo.svg +17 -0
  10. package/assets/.agent/skills/convex-agents/SKILL.md +516 -0
  11. package/assets/.agent/skills/convex-agents/agents/openai.yaml +3 -0
  12. package/assets/.agent/skills/convex-agents/assets/large-logo.png +0 -0
  13. package/assets/.agent/skills/convex-agents/assets/small-logo.svg +17 -0
  14. package/assets/.agent/skills/convex-best-practices/SKILL.md +369 -0
  15. package/assets/.agent/skills/convex-best-practices/agents/openai.yaml +3 -0
  16. package/assets/.agent/skills/convex-best-practices/assets/large-logo.png +0 -0
  17. package/assets/.agent/skills/convex-best-practices/assets/small-logo.svg +17 -0
  18. package/assets/.agent/skills/convex-component-authoring/SKILL.md +457 -0
  19. package/assets/.agent/skills/convex-component-authoring/agents/openai.yaml +3 -0
  20. package/assets/.agent/skills/convex-component-authoring/assets/large-logo.png +0 -0
  21. package/assets/.agent/skills/convex-component-authoring/assets/small-logo.svg +17 -0
  22. package/assets/.agent/skills/convex-cron-jobs/SKILL.md +604 -0
  23. package/assets/.agent/skills/convex-cron-jobs/agents/openai.yaml +3 -0
  24. package/assets/.agent/skills/convex-cron-jobs/assets/large-logo.png +0 -0
  25. package/assets/.agent/skills/convex-cron-jobs/assets/small-logo.svg +17 -0
  26. package/assets/.agent/skills/convex-file-storage/SKILL.md +467 -0
  27. package/assets/.agent/skills/convex-file-storage/agents/openai.yaml +3 -0
  28. package/assets/.agent/skills/convex-file-storage/assets/large-logo.png +0 -0
  29. package/assets/.agent/skills/convex-file-storage/assets/small-logo.svg +17 -0
  30. package/assets/.agent/skills/convex-functions/SKILL.md +458 -0
  31. package/assets/.agent/skills/convex-functions/agents/openai.yaml +3 -0
  32. package/assets/.agent/skills/convex-functions/assets/large-logo.png +0 -0
  33. package/assets/.agent/skills/convex-functions/assets/small-logo.svg +17 -0
  34. package/assets/.agent/skills/convex-http-actions/SKILL.md +733 -0
  35. package/assets/.agent/skills/convex-http-actions/agents/openai.yaml +3 -0
  36. package/assets/.agent/skills/convex-http-actions/assets/large-logo.png +0 -0
  37. package/assets/.agent/skills/convex-http-actions/assets/small-logo.svg +17 -0
  38. package/assets/.agent/skills/convex-migrations/SKILL.md +712 -0
  39. package/assets/.agent/skills/convex-migrations/agents/openai.yaml +3 -0
  40. package/assets/.agent/skills/convex-migrations/assets/large-logo.png +0 -0
  41. package/assets/.agent/skills/convex-migrations/assets/small-logo.svg +17 -0
  42. package/assets/.agent/skills/convex-realtime/SKILL.md +443 -0
  43. package/assets/.agent/skills/convex-realtime/agents/openai.yaml +3 -0
  44. package/assets/.agent/skills/convex-realtime/assets/large-logo.png +0 -0
  45. package/assets/.agent/skills/convex-realtime/assets/small-logo.svg +17 -0
  46. package/assets/.agent/skills/convex-schema-validator/SKILL.md +400 -0
  47. package/assets/.agent/skills/convex-schema-validator/agents/openai.yaml +3 -0
  48. package/assets/.agent/skills/convex-schema-validator/assets/large-logo.png +0 -0
  49. package/assets/.agent/skills/convex-schema-validator/assets/small-logo.svg +17 -0
  50. package/assets/.agent/skills/convex-security-audit/SKILL.md +539 -0
  51. package/assets/.agent/skills/convex-security-audit/agents/openai.yaml +3 -0
  52. package/assets/.agent/skills/convex-security-audit/assets/large-logo.png +0 -0
  53. package/assets/.agent/skills/convex-security-audit/assets/small-logo.svg +17 -0
  54. package/assets/.agent/skills/convex-security-check/SKILL.md +378 -0
  55. package/assets/.agent/skills/convex-security-check/agents/openai.yaml +3 -0
  56. package/assets/.agent/skills/convex-security-check/assets/large-logo.png +0 -0
  57. package/assets/.agent/skills/convex-security-check/assets/small-logo.svg +17 -0
  58. package/assets/.agent/skills/github-ops/SKILL.md +4 -4
  59. package/assets/.agent/skills/google-trends/SKILL.md +7 -7
  60. package/assets/.agent/skills/optimize-agent-context/SKILL.md +97 -0
  61. package/assets/.agent/skills/youtube-pipeline/SKILL.md +10 -10
  62. package/assets/.agent/workflows/LEGACY/init_smart_ops.md +2 -2
  63. package/assets/.agent/workflows/agent_reset.md +2 -2
  64. package/assets/.agent/workflows/mode-orchestrator.md +114 -640
  65. package/assets/.agent/workflows/mode-visionary.md +192 -0
  66. package/assets/.agent/workflows/optimize-agent-context.md +54 -0
  67. package/assets/.agent/workflows/remotion-build.md +17 -17
  68. package/assets/.agent/workflows/stitch.md +4 -4
  69. package/assets/VibeCode-Agents/custom_modes.yaml +1257 -0
  70. package/assets/VibeCode-Agents/vibe-orchestrator.yaml +427 -145
  71. package/assets/VibeCode-Agents/vibe-visionary.yaml +617 -0
  72. package/package.json +2 -2
  73. package/src/cli.js +416 -20
  74. package/src/harness.js +281 -0
  75. package/src/store.js +239 -0
package/src/harness.js ADDED
@@ -0,0 +1,281 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import pc from 'picocolors';
5
+
6
+ // ─── Cross-Platform Home Directory ───────────────────────────────────────────
7
+ const HOME = os.homedir();
8
+ const IS_WINDOWS = process.platform === 'win32';
9
+
10
+ /**
11
+ * Resolve %APPDATA% on Windows, fallback for Mac/Linux
12
+ */
13
+ function getAppData() {
14
+ if (IS_WINDOWS) {
15
+ return process.env.APPDATA || path.join(HOME, 'AppData', 'Roaming');
16
+ }
17
+ // Mac: ~/Library/Application Support, Linux: ~/.config
18
+ return process.env.XDG_CONFIG_HOME || path.join(HOME, '.config');
19
+ }
20
+
21
+ // ─── Harness Registry ────────────────────────────────────────────────────────
22
+
23
+ /**
24
+ * Each harness adapter defines:
25
+ * - name: Human-readable name
26
+ * - detect: Function returning true if the harness is installed
27
+ * - rootPath: Root config directory of the harness
28
+ * - targets: Where to copy skills, workflows, and yamls
29
+ * - skills: Path to global skills directory (or null if unsupported)
30
+ * - workflows: Path to global workflows directory (or null if unsupported)
31
+ * - yamls: Array of paths for custom_modes.yaml (or null)
32
+ */
33
+ export const HARNESS_MAP = {
34
+ antigravity: {
35
+ name: 'Antigravity',
36
+ rootPath: path.join(HOME, '.gemini', 'antigravity'),
37
+ detect() {
38
+ return fs.existsSync(this.rootPath);
39
+ },
40
+ targets: {
41
+ skills: path.join(HOME, '.gemini', 'antigravity', 'skills'),
42
+ workflows: path.join(HOME, '.gemini', 'antigravity', 'global_workflows'),
43
+ yamls: null,
44
+ },
45
+ },
46
+
47
+ kilocode: {
48
+ name: 'KiloCode',
49
+ rootPath: path.join(HOME, '.kilocode'),
50
+ detect() {
51
+ return fs.existsSync(this.rootPath);
52
+ },
53
+ targets: {
54
+ skills: path.join(HOME, '.kilocode', 'skills'),
55
+ workflows: path.join(HOME, '.kilocode', 'workflows'),
56
+ yamls: [
57
+ path.join(HOME, '.kilocode', 'cli', 'global', 'settings', 'custom_modes.yaml'),
58
+ path.join(getAppData(), 'Antigravity', 'User', 'globalStorage', 'kilocode.kilo-code', 'settings', 'custom_modes.yaml'),
59
+ ],
60
+ },
61
+ },
62
+
63
+ windsurf: {
64
+ name: 'Windsurf',
65
+ rootPath: path.join(HOME, '.codeium', 'windsurf'),
66
+ detect() {
67
+ return fs.existsSync(this.rootPath);
68
+ },
69
+ targets: {
70
+ skills: path.join(HOME, '.codeium', 'windsurf', 'skills'),
71
+ workflows: path.join(HOME, '.codeium', 'windsurf', 'global_workflows'),
72
+ yamls: null,
73
+ },
74
+ },
75
+
76
+ cursor: {
77
+ name: 'Cursor',
78
+ rootPath: path.join(HOME, '.cursor'),
79
+ detect() {
80
+ return fs.existsSync(this.rootPath);
81
+ },
82
+ targets: {
83
+ skills: path.join(HOME, '.cursor', 'skills'),
84
+ workflows: null, // Cursor uses rules, not workflows
85
+ yamls: null,
86
+ },
87
+ },
88
+
89
+ gemini_cli: {
90
+ name: 'Gemini CLI',
91
+ rootPath: path.join(HOME, '.gemini'),
92
+ detect() {
93
+ // Only match bare Gemini CLI — not Antigravity (which also lives under .gemini)
94
+ return fs.existsSync(this.rootPath) && !fs.existsSync(path.join(HOME, '.gemini', 'antigravity'));
95
+ },
96
+ targets: {
97
+ skills: path.join(HOME, '.gemini', 'skills'),
98
+ workflows: null,
99
+ yamls: null,
100
+ },
101
+ },
102
+ };
103
+
104
+ // ─── Detection ───────────────────────────────────────────────────────────────
105
+
106
+ /**
107
+ * Scans the filesystem and returns an array of detected harness objects.
108
+ * Each object includes { id, name, rootPath, targets }.
109
+ * @returns {Array<{id: string, name: string, rootPath: string, targets: object}>}
110
+ */
111
+ export function detectHarnesses() {
112
+ const detected = [];
113
+
114
+ for (const [id, harness] of Object.entries(HARNESS_MAP)) {
115
+ if (harness.detect()) {
116
+ detected.push({
117
+ id,
118
+ name: harness.name,
119
+ rootPath: harness.rootPath,
120
+ targets: harness.targets,
121
+ });
122
+ }
123
+ }
124
+
125
+ return detected;
126
+ }
127
+
128
+ /**
129
+ * Pretty-prints harness detection results.
130
+ * @param {Array} detected - Array from detectHarnesses()
131
+ */
132
+ export function printHarnessStatus(detected) {
133
+ const detectedIds = new Set(detected.map(h => h.id));
134
+
135
+ console.log(pc.cyan('\n📡 Detecting AI harnesses...\n'));
136
+
137
+ for (const [id, harness] of Object.entries(HARNESS_MAP)) {
138
+ if (detectedIds.has(id)) {
139
+ console.log(pc.green(` ✔ ${harness.name.padEnd(16)} ${pc.dim(harness.rootPath)}`));
140
+ } else {
141
+ console.log(pc.dim(` ✗ ${harness.name.padEnd(16)} (not found)`));
142
+ }
143
+ }
144
+
145
+ console.log('');
146
+ }
147
+
148
+ // ─── Sync Operations ─────────────────────────────────────────────────────────
149
+
150
+ /**
151
+ * Syncs a source directory to a harness target path.
152
+ * Uses hard copy (fs.copy) — no symlinks.
153
+ *
154
+ * @param {string} sourcePath - Source directory (e.g., ~/.vibesuite/skills/)
155
+ * @param {string} targetPath - Destination directory (e.g., ~/.gemini/antigravity/skills/)
156
+ * @param {string} label - Human-readable label for logging
157
+ * @returns {Promise<number>} - Number of items copied
158
+ */
159
+ export async function syncDirectory(sourcePath, targetPath, label = '') {
160
+ if (!targetPath) return 0;
161
+
162
+ try {
163
+ await fs.ensureDir(targetPath);
164
+
165
+ const items = await fs.readdir(sourcePath);
166
+ let count = 0;
167
+
168
+ for (const item of items) {
169
+ const src = path.join(sourcePath, item);
170
+ const dest = path.join(targetPath, item);
171
+
172
+ await fs.copy(src, dest, { overwrite: true });
173
+ count++;
174
+ }
175
+
176
+ if (label) {
177
+ console.log(pc.green(` ✔ ${label} (${count} items)`));
178
+ }
179
+
180
+ return count;
181
+ } catch (error) {
182
+ if (label) {
183
+ console.log(pc.red(` ✗ ${label}: ${error.message}`));
184
+ }
185
+ return 0;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Syncs a single file to one or more target paths.
191
+ * Used for custom_modes.yaml → KiloCode dual-path sync.
192
+ *
193
+ * @param {string} sourceFile - Source file path
194
+ * @param {string|string[]} targetPaths - One or more destination file paths
195
+ * @param {string} label - Human-readable label for logging
196
+ * @returns {Promise<number>} - Number of successful copies
197
+ */
198
+ export async function syncFile(sourceFile, targetPaths, label = '') {
199
+ if (!targetPaths) return 0;
200
+
201
+ const paths = Array.isArray(targetPaths) ? targetPaths : [targetPaths];
202
+ let count = 0;
203
+
204
+ for (const targetPath of paths) {
205
+ try {
206
+ await fs.ensureDir(path.dirname(targetPath));
207
+ await fs.copy(sourceFile, targetPath, { overwrite: true });
208
+ count++;
209
+ } catch (error) {
210
+ console.log(pc.yellow(` ⚠ Could not sync to ${path.basename(path.dirname(targetPath))}: ${error.message}`));
211
+ }
212
+ }
213
+
214
+ if (label && count > 0) {
215
+ console.log(pc.green(` ✔ ${label} (${count} path${count > 1 ? 's' : ''})`));
216
+ }
217
+
218
+ return count;
219
+ }
220
+
221
+ /**
222
+ * Syncs skills, workflows, and yamls from the global store to a single harness.
223
+ *
224
+ * @param {{id: string, name: string, targets: object}} harness - Harness config
225
+ * @param {string} storePath - Path to the global store (~/.vibesuite/)
226
+ * @returns {Promise<{skills: number, workflows: number, yamls: number}>}
227
+ */
228
+ export async function syncToHarness(harness, storePath) {
229
+ const results = { skills: 0, workflows: 0, yamls: 0 };
230
+
231
+ console.log(pc.cyan(`\n 📡 Syncing to ${harness.name}...`));
232
+
233
+ // Skills
234
+ const skillsStore = path.join(storePath, 'skills');
235
+ if (harness.targets.skills && await fs.pathExists(skillsStore)) {
236
+ results.skills = await syncDirectory(
237
+ skillsStore,
238
+ harness.targets.skills,
239
+ `Skills → ${harness.name}`
240
+ );
241
+ }
242
+
243
+ // Workflows
244
+ const workflowsStore = path.join(storePath, 'workflows');
245
+ if (harness.targets.workflows && await fs.pathExists(workflowsStore)) {
246
+ results.workflows = await syncDirectory(
247
+ workflowsStore,
248
+ harness.targets.workflows,
249
+ `Workflows → ${harness.name}`
250
+ );
251
+ }
252
+
253
+ // YAMLs (KiloCode custom_modes.yaml dual-path)
254
+ const yamlSource = path.join(storePath, 'agents', 'custom_modes.yaml');
255
+ if (harness.targets.yamls && await fs.pathExists(yamlSource)) {
256
+ results.yamls = await syncFile(
257
+ yamlSource,
258
+ harness.targets.yamls,
259
+ `custom_modes.yaml → ${harness.name}`
260
+ );
261
+ }
262
+
263
+ return results;
264
+ }
265
+
266
+ /**
267
+ * Syncs from the global store to ALL specified harnesses.
268
+ *
269
+ * @param {Array} harnesses - Array of harness configs from detectHarnesses()
270
+ * @param {string} storePath - Path to the global store (~/.vibesuite/)
271
+ * @returns {Promise<object>} - Summary of sync results
272
+ */
273
+ export async function syncToAllHarnesses(harnesses, storePath) {
274
+ const summary = {};
275
+
276
+ for (const harness of harnesses) {
277
+ summary[harness.id] = await syncToHarness(harness, storePath);
278
+ }
279
+
280
+ return summary;
281
+ }
package/src/store.js ADDED
@@ -0,0 +1,239 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import pc from 'picocolors';
5
+ import { PATHS } from './utils.js';
6
+
7
+ // ─── Global Store Path ───────────────────────────────────────────────────────
8
+ const HOME = os.homedir();
9
+ export const STORE_PATH = path.join(HOME, '.vibesuite');
10
+ export const MANIFEST_PATH = path.join(STORE_PATH, 'manifest.json');
11
+
12
+ // ─── Store Structure ─────────────────────────────────────────────────────────
13
+
14
+ /**
15
+ * Creates the global store directory structure at ~/.vibesuite/
16
+ * Idempotent — safe to call multiple times.
17
+ * @returns {Promise<void>}
18
+ */
19
+ export async function initGlobalStore() {
20
+ await fs.ensureDir(path.join(STORE_PATH, 'skills'));
21
+ await fs.ensureDir(path.join(STORE_PATH, 'workflows'));
22
+ await fs.ensureDir(path.join(STORE_PATH, 'agents'));
23
+
24
+ // Create manifest if it doesn't exist
25
+ if (!await fs.pathExists(MANIFEST_PATH)) {
26
+ const manifest = createDefaultManifest();
27
+ await writeManifest(manifest);
28
+ }
29
+ }
30
+
31
+ // ─── Manifest ────────────────────────────────────────────────────────────────
32
+
33
+ /**
34
+ * Default manifest structure
35
+ */
36
+ function createDefaultManifest() {
37
+ return {
38
+ version: '2.0.0',
39
+ createdAt: new Date().toISOString(),
40
+ updatedAt: new Date().toISOString(),
41
+ linkedHarnesses: [],
42
+ installed: {
43
+ skills: [],
44
+ workflows: [],
45
+ agents: [],
46
+ },
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Reads the manifest from disk.
52
+ * @returns {Promise<object>}
53
+ */
54
+ export async function getManifest() {
55
+ try {
56
+ if (await fs.pathExists(MANIFEST_PATH)) {
57
+ return await fs.readJson(MANIFEST_PATH);
58
+ }
59
+ } catch {
60
+ // Corrupted manifest — recreate
61
+ }
62
+ return createDefaultManifest();
63
+ }
64
+
65
+ /**
66
+ * Writes the manifest to disk.
67
+ * @param {object} manifest
68
+ * @returns {Promise<void>}
69
+ */
70
+ export async function writeManifest(manifest) {
71
+ manifest.updatedAt = new Date().toISOString();
72
+ await fs.writeJson(MANIFEST_PATH, manifest, { spaces: 2 });
73
+ }
74
+
75
+ // ─── Populate Store from Package Assets ──────────────────────────────────────
76
+
77
+ /**
78
+ * Copies skills from the bundled package assets into the global store.
79
+ * @param {'core'|'all'|string[]} mode - Which skills to install
80
+ * @returns {Promise<string[]>} - List of skill names copied
81
+ */
82
+ export async function populateSkills(mode) {
83
+ const storeSkills = path.join(STORE_PATH, 'skills');
84
+ await fs.ensureDir(storeSkills);
85
+
86
+ const coreSkills = [
87
+ 'ai-sdk', 'code-review', 'component-analysis', 'context7',
88
+ 'nextjs-standards', 'security-audit', 'spawn-task', 'stitch',
89
+ ];
90
+
91
+ let skillsToCopy = [];
92
+
93
+ if (mode === 'core') {
94
+ skillsToCopy = coreSkills;
95
+ } else if (mode === 'all') {
96
+ // Read all skill directories from package assets
97
+ const entries = await fs.readdir(PATHS.skills);
98
+ for (const entry of entries) {
99
+ const stat = await fs.stat(path.join(PATHS.skills, entry));
100
+ if (stat.isDirectory()) {
101
+ skillsToCopy.push(entry);
102
+ }
103
+ }
104
+ } else if (Array.isArray(mode)) {
105
+ skillsToCopy = mode;
106
+ }
107
+
108
+ const copied = [];
109
+ for (const skill of skillsToCopy) {
110
+ const src = path.join(PATHS.skills, skill);
111
+ const dest = path.join(storeSkills, skill);
112
+ try {
113
+ if (await fs.pathExists(src)) {
114
+ await fs.copy(src, dest, { overwrite: true });
115
+ copied.push(skill);
116
+ }
117
+ } catch (error) {
118
+ console.log(pc.yellow(` ⚠ Could not copy skill "${skill}": ${error.message}`));
119
+ }
120
+ }
121
+
122
+ return copied;
123
+ }
124
+
125
+ /**
126
+ * Copies workflows from the bundled package assets into the global store.
127
+ * @param {'core'|'all'|'no-legacy'|string[]} mode - Which workflows to install
128
+ * @returns {Promise<string[]>} - List of workflow filenames copied
129
+ */
130
+ export async function populateWorkflows(mode) {
131
+ const storeWorkflows = path.join(STORE_PATH, 'workflows');
132
+ await fs.ensureDir(storeWorkflows);
133
+
134
+ const coreWorkflows = [
135
+ 'vibe-genesis.md', 'vibe-design.md', 'vibe-build.md',
136
+ 'vibe-continueBuild.md', 'vibe-finalize.md', 'vibe-spawnTask.md',
137
+ 'vibe-primeAgent.md', 'vibe-syncDocs.md', 'stitch.md',
138
+ 'mode-orchestrator.md', 'mode-architect.md', 'mode-code.md',
139
+ 'mode-debug.md', 'mode-ask.md', 'mode-review.md',
140
+ ];
141
+
142
+ let workflowsToCopy = [];
143
+
144
+ if (mode === 'core') {
145
+ workflowsToCopy = coreWorkflows;
146
+ } else if (mode === 'all' || mode === 'no-legacy') {
147
+ const entries = await fs.readdir(PATHS.workflows);
148
+ workflowsToCopy = entries.filter(f => {
149
+ if (!f.endsWith('.md')) return false;
150
+ if (mode === 'no-legacy' && f.startsWith('LEGACY')) return false;
151
+ return true;
152
+ });
153
+ } else if (Array.isArray(mode)) {
154
+ workflowsToCopy = mode;
155
+ }
156
+
157
+ const copied = [];
158
+ for (const workflow of workflowsToCopy) {
159
+ const src = path.join(PATHS.workflows, workflow);
160
+ const dest = path.join(storeWorkflows, workflow);
161
+ try {
162
+ if (await fs.pathExists(src)) {
163
+ await fs.copy(src, dest, { overwrite: true });
164
+ copied.push(workflow);
165
+ }
166
+ } catch (error) {
167
+ console.log(pc.yellow(` ⚠ Could not copy workflow "${workflow}": ${error.message}`));
168
+ }
169
+ }
170
+
171
+ return copied;
172
+ }
173
+
174
+ /**
175
+ * Copies agent YAMLs (custom_modes.yaml, etc.) into the global store.
176
+ * @returns {Promise<string[]>} - List of YAML filenames copied
177
+ */
178
+ export async function populateAgentYamls() {
179
+ const storeAgents = path.join(STORE_PATH, 'agents');
180
+ await fs.ensureDir(storeAgents);
181
+
182
+ const copied = [];
183
+ try {
184
+ const entries = await fs.readdir(PATHS.agentsYaml);
185
+ for (const entry of entries) {
186
+ const src = path.join(PATHS.agentsYaml, entry);
187
+ const dest = path.join(storeAgents, entry);
188
+ await fs.copy(src, dest, { overwrite: true });
189
+ copied.push(entry);
190
+ }
191
+ } catch (error) {
192
+ console.log(pc.yellow(` ⚠ Could not copy agent YAMLs: ${error.message}`));
193
+ }
194
+
195
+ return copied;
196
+ }
197
+
198
+ // ─── Store Queries ───────────────────────────────────────────────────────────
199
+
200
+ /**
201
+ * Lists all skills currently in the global store.
202
+ * @returns {Promise<string[]>}
203
+ */
204
+ export async function getStoreSkills() {
205
+ const skillsDir = path.join(STORE_PATH, 'skills');
206
+ try {
207
+ const entries = await fs.readdir(skillsDir);
208
+ const skills = [];
209
+ for (const entry of entries) {
210
+ const stat = await fs.stat(path.join(skillsDir, entry));
211
+ if (stat.isDirectory()) skills.push(entry);
212
+ }
213
+ return skills;
214
+ } catch {
215
+ return [];
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Lists all workflows currently in the global store.
221
+ * @returns {Promise<string[]>}
222
+ */
223
+ export async function getStoreWorkflows() {
224
+ const workflowsDir = path.join(STORE_PATH, 'workflows');
225
+ try {
226
+ const entries = await fs.readdir(workflowsDir);
227
+ return entries.filter(f => f.endsWith('.md'));
228
+ } catch {
229
+ return [];
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Checks if the global store has been initialized.
235
+ * @returns {Promise<boolean>}
236
+ */
237
+ export async function isStoreInitialized() {
238
+ return fs.pathExists(MANIFEST_PATH);
239
+ }