craftdesk 0.3.0 → 0.5.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.
- package/CHANGELOG.md +88 -0
- package/README.md +1609 -132
- package/dist/commands/add.d.ts +5 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +306 -8
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/convert.d.ts +8 -0
- package/dist/commands/convert.d.ts.map +1 -0
- package/dist/commands/convert.js +146 -0
- package/dist/commands/convert.js.map +1 -0
- package/dist/commands/detect-agents.d.ts +14 -0
- package/dist/commands/detect-agents.d.ts.map +1 -0
- package/dist/commands/detect-agents.js +86 -0
- package/dist/commands/detect-agents.js.map +1 -0
- package/dist/commands/embed.d.ts +14 -0
- package/dist/commands/embed.d.ts.map +1 -0
- package/dist/commands/embed.js +147 -0
- package/dist/commands/embed.js.map +1 -0
- package/dist/commands/info.d.ts +8 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +66 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +8 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.d.ts +5 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +24 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +75 -7
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/login.d.ts +8 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +158 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +8 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +51 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/outdated.d.ts +23 -0
- package/dist/commands/outdated.d.ts.map +1 -0
- package/dist/commands/outdated.js +268 -0
- package/dist/commands/outdated.js.map +1 -0
- package/dist/commands/publish.d.ts +8 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +203 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/remove.d.ts +5 -0
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +51 -10
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/search.d.ts +8 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +60 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/setup-multi-agent.d.ts +17 -0
- package/dist/commands/setup-multi-agent.d.ts.map +1 -0
- package/dist/commands/setup-multi-agent.js +188 -0
- package/dist/commands/setup-multi-agent.js.map +1 -0
- package/dist/commands/sync.d.ts +14 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +144 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/unembed.d.ts +14 -0
- package/dist/commands/unembed.d.ts.map +1 -0
- package/dist/commands/unembed.js +96 -0
- package/dist/commands/unembed.js.map +1 -0
- package/dist/commands/update.d.ts +8 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +372 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +14 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +143 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/whoami.d.ts +8 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +58 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/converters/base-converter.d.ts +89 -0
- package/dist/converters/base-converter.d.ts.map +1 -0
- package/dist/converters/base-converter.js +249 -0
- package/dist/converters/base-converter.js.map +1 -0
- package/dist/converters/continue-converter.d.ts +53 -0
- package/dist/converters/continue-converter.d.ts.map +1 -0
- package/dist/converters/continue-converter.js +243 -0
- package/dist/converters/continue-converter.js.map +1 -0
- package/dist/converters/cursor-converter.d.ts +70 -0
- package/dist/converters/cursor-converter.d.ts.map +1 -0
- package/dist/converters/cursor-converter.js +272 -0
- package/dist/converters/cursor-converter.js.map +1 -0
- package/dist/index.js +56 -3
- package/dist/index.js.map +1 -1
- package/dist/services/agent-detector.d.ts +57 -0
- package/dist/services/agent-detector.d.ts.map +1 -0
- package/dist/services/agent-detector.js +146 -0
- package/dist/services/agent-detector.js.map +1 -0
- package/dist/services/config-manager.d.ts +128 -10
- package/dist/services/config-manager.d.ts.map +1 -1
- package/dist/services/config-manager.js +190 -18
- package/dist/services/config-manager.js.map +1 -1
- package/dist/services/converter.d.ts +53 -0
- package/dist/services/converter.d.ts.map +1 -0
- package/dist/services/converter.js +185 -0
- package/dist/services/converter.js.map +1 -0
- package/dist/services/craft-wrapper.d.ts +108 -0
- package/dist/services/craft-wrapper.d.ts.map +1 -0
- package/dist/services/craft-wrapper.js +268 -0
- package/dist/services/craft-wrapper.js.map +1 -0
- package/dist/services/git-resolver.d.ts +9 -3
- package/dist/services/git-resolver.d.ts.map +1 -1
- package/dist/services/git-resolver.js +44 -20
- package/dist/services/git-resolver.js.map +1 -1
- package/dist/services/gitignore-manager.d.ts +74 -0
- package/dist/services/gitignore-manager.d.ts.map +1 -0
- package/dist/services/gitignore-manager.js +188 -0
- package/dist/services/gitignore-manager.js.map +1 -0
- package/dist/services/installer.d.ts +60 -1
- package/dist/services/installer.d.ts.map +1 -1
- package/dist/services/installer.js +295 -20
- package/dist/services/installer.js.map +1 -1
- package/dist/services/multi-agent-sync.d.ts +88 -0
- package/dist/services/multi-agent-sync.d.ts.map +1 -0
- package/dist/services/multi-agent-sync.js +316 -0
- package/dist/services/multi-agent-sync.js.map +1 -0
- package/dist/services/plugin-resolver.d.ts +80 -0
- package/dist/services/plugin-resolver.d.ts.map +1 -0
- package/dist/services/plugin-resolver.js +183 -0
- package/dist/services/plugin-resolver.js.map +1 -0
- package/dist/services/registry-client.d.ts +132 -5
- package/dist/services/registry-client.d.ts.map +1 -1
- package/dist/services/registry-client.js +239 -34
- package/dist/services/registry-client.js.map +1 -1
- package/dist/services/settings-manager.d.ts +151 -0
- package/dist/services/settings-manager.d.ts.map +1 -0
- package/dist/services/settings-manager.js +333 -0
- package/dist/services/settings-manager.js.map +1 -0
- package/dist/types/claude-settings.d.ts +155 -0
- package/dist/types/claude-settings.d.ts.map +1 -0
- package/dist/types/claude-settings.js +20 -0
- package/dist/types/claude-settings.js.map +1 -0
- package/dist/types/converter.d.ts +98 -0
- package/dist/types/converter.d.ts.map +1 -0
- package/dist/types/converter.js +6 -0
- package/dist/types/converter.js.map +1 -0
- package/dist/types/craftdesk-json.d.ts +76 -3
- package/dist/types/craftdesk-json.d.ts.map +1 -1
- package/dist/types/craftdesk-lock.d.ts +62 -1
- package/dist/types/craftdesk-lock.d.ts.map +1 -1
- package/dist/types/multi-agent.d.ts +85 -0
- package/dist/types/multi-agent.d.ts.map +1 -0
- package/dist/types/multi-agent.js +6 -0
- package/dist/types/multi-agent.js.map +1 -0
- package/dist/utils/crypto.d.ts +23 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +52 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/file-system.d.ts +43 -0
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +45 -2
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/logger.d.ts +75 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +76 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/version-utils.d.ts +63 -0
- package/dist/utils/version-utils.d.ts.map +1 -0
- package/dist/utils/version-utils.js +130 -0
- package/dist/utils/version-utils.js.map +1 -0
- package/package.json +36 -9
- package/.claude/settings.local.json +0 -19
- package/.github/workflows/ci.yml +0 -94
- package/API.md +0 -414
- package/TESTING.md +0 -263
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -56
- package/dist/commands/config.js.map +0 -1
- package/dist/types/config.d.ts +0 -17
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -3
- package/dist/types/config.js.map +0 -1
- package/docs/DEPENDENCY_RESOLUTION.md +0 -237
- package/examples/craftdesk-all-sources.json +0 -79
- package/examples/craftdesk-git-monorepo.json +0 -41
- package/examples/craftdesk-multi-registry.json +0 -40
- package/examples/craftdesk-with-registries.json +0 -49
- package/examples/simple-craftdesk.json +0 -10
- package/src/commands/add.ts +0 -314
- package/src/commands/init.ts +0 -55
- package/src/commands/install.ts +0 -126
- package/src/commands/list.ts +0 -126
- package/src/commands/remove.ts +0 -82
- package/src/index.ts +0 -56
- package/src/services/config-manager.ts +0 -150
- package/src/services/git-resolver.ts +0 -373
- package/src/services/installer.ts +0 -314
- package/src/services/registry-client.ts +0 -163
- package/src/types/craftdesk-json.ts +0 -53
- package/src/types/craftdesk-lock.ts +0 -38
- package/src/utils/file-system.ts +0 -55
- package/src/utils/logger.ts +0 -82
- package/tests/fixtures/craftdesk-git.json +0 -17
- package/tests/fixtures/craftdesk.json +0 -15
- package/tests/helpers/test-utils.ts +0 -60
- package/tests/integration/init-command.test.ts +0 -70
- package/tests/integration/list-command.test.ts +0 -77
- package/tests/unit/config-manager.test.ts +0 -228
- package/tests/unit/git-resolver.test.ts +0 -303
- package/tests/unit/installer.test.ts +0 -105
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -29
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-Agent Sync - Sync crafts across multiple AI agents
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Installing crafts to multiple agent directories
|
|
7
|
+
* - Verifying sync status with checksums
|
|
8
|
+
* - Detecting and fixing drift between copies
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.multiAgentSync = exports.MultiAgentSync = void 0;
|
|
15
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
18
|
+
const logger_1 = require("../utils/logger");
|
|
19
|
+
const config_manager_1 = require("./config-manager");
|
|
20
|
+
const file_system_1 = require("../utils/file-system");
|
|
21
|
+
/**
|
|
22
|
+
* Service for syncing crafts across multiple AI agent directories
|
|
23
|
+
*/
|
|
24
|
+
class MultiAgentSync {
|
|
25
|
+
/**
|
|
26
|
+
* Install craft to all configured agent directories
|
|
27
|
+
*
|
|
28
|
+
* @param craftName - Name of the craft to sync
|
|
29
|
+
* @param sourceDir - Source directory containing the craft files
|
|
30
|
+
* @param cwd - Current working directory (defaults to process.cwd())
|
|
31
|
+
* @returns Sync result with success/failure details
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const sync = new MultiAgentSync();
|
|
36
|
+
* const result = await sync.syncCraft('ruby-expert', '/tmp/ruby-expert-source');
|
|
37
|
+
*
|
|
38
|
+
* console.log(`Synced to: ${result.synced.join(', ')}`);
|
|
39
|
+
* if (result.failed.length > 0) {
|
|
40
|
+
* console.error(`Failed: ${result.failed.map(f => f.path).join(', ')}`);
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
async syncCraft(craftName, sourceDir, cwd = process.cwd()) {
|
|
45
|
+
const config = await config_manager_1.configManager.getCraftDeskJson();
|
|
46
|
+
// Check if multi-agent sync is enabled
|
|
47
|
+
if (!config?.multiAgent?.enabled) {
|
|
48
|
+
logger_1.logger.debug('Multi-agent sync disabled, skipping');
|
|
49
|
+
return {
|
|
50
|
+
craftName,
|
|
51
|
+
synced: [],
|
|
52
|
+
failed: []
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const canonical = config.multiAgent.canonical || '.claude';
|
|
56
|
+
const targets = config.multiAgent.targets || ['.claude/skills'];
|
|
57
|
+
const synced = [];
|
|
58
|
+
const failed = [];
|
|
59
|
+
// Install to canonical location first
|
|
60
|
+
const canonicalPath = path_1.default.join(cwd, canonical, 'skills', craftName);
|
|
61
|
+
// Normalize paths for comparison
|
|
62
|
+
const normalizedSource = path_1.default.resolve(sourceDir);
|
|
63
|
+
const normalizedCanonical = path_1.default.resolve(canonicalPath);
|
|
64
|
+
try {
|
|
65
|
+
await (0, file_system_1.ensureDir)(path_1.default.dirname(canonicalPath));
|
|
66
|
+
// Only copy if source is different from canonical
|
|
67
|
+
if (normalizedSource !== normalizedCanonical) {
|
|
68
|
+
await fs_extra_1.default.copy(sourceDir, canonicalPath, { overwrite: true });
|
|
69
|
+
logger_1.logger.debug(`Installed to canonical location: ${canonicalPath}`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
logger_1.logger.debug(`Source is already canonical: ${canonicalPath}`);
|
|
73
|
+
}
|
|
74
|
+
// Calculate and store checksum
|
|
75
|
+
const checksum = await this.calculateDirChecksum(canonicalPath);
|
|
76
|
+
const checksumFile = path_1.default.join(canonicalPath, '.craftdesk-checksum');
|
|
77
|
+
await fs_extra_1.default.writeFile(checksumFile, checksum, 'utf-8');
|
|
78
|
+
synced.push(canonicalPath);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
82
|
+
failed.push({ path: canonicalPath, error: message });
|
|
83
|
+
logger_1.logger.error(`Failed to install to canonical location: ${message}`);
|
|
84
|
+
// If canonical install fails, don't proceed with targets
|
|
85
|
+
return { craftName, synced, failed };
|
|
86
|
+
}
|
|
87
|
+
// Copy to all target locations
|
|
88
|
+
for (const target of targets) {
|
|
89
|
+
// Skip if target is the canonical location
|
|
90
|
+
if (target === `${canonical}/skills`) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const targetPath = path_1.default.join(cwd, target, craftName);
|
|
94
|
+
try {
|
|
95
|
+
await (0, file_system_1.ensureDir)(path_1.default.dirname(targetPath));
|
|
96
|
+
await fs_extra_1.default.copy(canonicalPath, targetPath, { overwrite: true });
|
|
97
|
+
synced.push(targetPath);
|
|
98
|
+
logger_1.logger.debug(`Synced ${craftName} to ${target}`);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
+
failed.push({ path: targetPath, error: message });
|
|
103
|
+
logger_1.logger.warn(`Failed to sync to ${target}: ${message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
logger_1.logger.info(`Synced ${craftName} to ${synced.length} location(s)`);
|
|
107
|
+
return { craftName, synced, failed };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Verify sync status for a craft
|
|
111
|
+
*
|
|
112
|
+
* Checks if all copies match the canonical version using checksums
|
|
113
|
+
*
|
|
114
|
+
* @param craftName - Name of the craft to verify
|
|
115
|
+
* @param cwd - Current working directory (defaults to process.cwd())
|
|
116
|
+
* @returns Sync status with details about each location
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const sync = new MultiAgentSync();
|
|
121
|
+
* const status = await sync.verifySync('ruby-expert');
|
|
122
|
+
*
|
|
123
|
+
* if (!status.inSync) {
|
|
124
|
+
* console.log(`Out of sync: ${status.outOfSync.map(l => l.path).join(', ')}`);
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
async verifySync(craftName, cwd = process.cwd()) {
|
|
129
|
+
const config = await config_manager_1.configManager.getCraftDeskJson();
|
|
130
|
+
if (!config?.multiAgent?.enabled) {
|
|
131
|
+
// If multi-agent not enabled, consider everything in sync
|
|
132
|
+
return {
|
|
133
|
+
craftName,
|
|
134
|
+
inSync: true,
|
|
135
|
+
canonicalChecksum: '',
|
|
136
|
+
outOfSync: [],
|
|
137
|
+
inSyncLocations: []
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const canonical = config.multiAgent.canonical || '.claude';
|
|
141
|
+
const targets = config.multiAgent.targets || [];
|
|
142
|
+
const canonicalPath = path_1.default.join(cwd, canonical, 'skills', craftName);
|
|
143
|
+
// Check if canonical exists
|
|
144
|
+
if (!await fs_extra_1.default.pathExists(canonicalPath)) {
|
|
145
|
+
return {
|
|
146
|
+
craftName,
|
|
147
|
+
inSync: false,
|
|
148
|
+
canonicalChecksum: '',
|
|
149
|
+
outOfSync: [{ path: canonicalPath, reason: 'missing' }],
|
|
150
|
+
inSyncLocations: []
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const canonicalChecksum = await this.calculateDirChecksum(canonicalPath);
|
|
154
|
+
const outOfSync = [];
|
|
155
|
+
const inSyncLocations = [];
|
|
156
|
+
// Check each target
|
|
157
|
+
for (const target of targets) {
|
|
158
|
+
// Skip canonical location
|
|
159
|
+
if (target === `${canonical}/skills`) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const targetPath = path_1.default.join(cwd, target, craftName);
|
|
163
|
+
// Check if target exists
|
|
164
|
+
if (!await fs_extra_1.default.pathExists(targetPath)) {
|
|
165
|
+
outOfSync.push({
|
|
166
|
+
path: targetPath,
|
|
167
|
+
reason: 'missing',
|
|
168
|
+
expectedChecksum: canonicalChecksum
|
|
169
|
+
});
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
// Calculate target checksum
|
|
173
|
+
const targetChecksum = await this.calculateDirChecksum(targetPath);
|
|
174
|
+
if (targetChecksum !== canonicalChecksum) {
|
|
175
|
+
outOfSync.push({
|
|
176
|
+
path: targetPath,
|
|
177
|
+
reason: 'checksum-mismatch',
|
|
178
|
+
expectedChecksum: canonicalChecksum,
|
|
179
|
+
actualChecksum: targetChecksum
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
inSyncLocations.push(targetPath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
craftName,
|
|
188
|
+
inSync: outOfSync.length === 0,
|
|
189
|
+
canonicalChecksum,
|
|
190
|
+
outOfSync,
|
|
191
|
+
inSyncLocations
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Sync all installed crafts to configured targets
|
|
196
|
+
*
|
|
197
|
+
* @param cwd - Current working directory (defaults to process.cwd())
|
|
198
|
+
* @returns Array of sync results for each craft
|
|
199
|
+
*/
|
|
200
|
+
async syncAllCrafts(cwd = process.cwd()) {
|
|
201
|
+
const config = await config_manager_1.configManager.getCraftDeskJson();
|
|
202
|
+
if (!config?.multiAgent?.enabled) {
|
|
203
|
+
logger_1.logger.info('Multi-agent sync is disabled');
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
const canonical = config.multiAgent.canonical || '.claude';
|
|
207
|
+
const skillsDir = path_1.default.join(cwd, canonical, 'skills');
|
|
208
|
+
// Check if skills directory exists
|
|
209
|
+
if (!await fs_extra_1.default.pathExists(skillsDir)) {
|
|
210
|
+
logger_1.logger.info('No skills directory found, nothing to sync');
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
// Get all craft directories
|
|
214
|
+
const entries = await fs_extra_1.default.readdir(skillsDir, { withFileTypes: true });
|
|
215
|
+
const craftDirs = entries
|
|
216
|
+
.filter(entry => entry.isDirectory())
|
|
217
|
+
.map(entry => entry.name);
|
|
218
|
+
if (craftDirs.length === 0) {
|
|
219
|
+
logger_1.logger.info('No crafts found to sync');
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
logger_1.logger.info(`Syncing ${craftDirs.length} craft(s)...`);
|
|
223
|
+
const results = [];
|
|
224
|
+
for (const craftName of craftDirs) {
|
|
225
|
+
const craftPath = path_1.default.join(skillsDir, craftName);
|
|
226
|
+
const result = await this.syncCraft(craftName, craftPath, cwd);
|
|
227
|
+
results.push(result);
|
|
228
|
+
}
|
|
229
|
+
return results;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Verify sync status for all installed crafts
|
|
233
|
+
*
|
|
234
|
+
* @param cwd - Current working directory (defaults to process.cwd())
|
|
235
|
+
* @returns Array of sync statuses for each craft
|
|
236
|
+
*/
|
|
237
|
+
async verifyAllCrafts(cwd = process.cwd()) {
|
|
238
|
+
const config = await config_manager_1.configManager.getCraftDeskJson();
|
|
239
|
+
if (!config?.multiAgent?.enabled) {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
const canonical = config.multiAgent.canonical || '.claude';
|
|
243
|
+
const skillsDir = path_1.default.join(cwd, canonical, 'skills');
|
|
244
|
+
if (!await fs_extra_1.default.pathExists(skillsDir)) {
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
const entries = await fs_extra_1.default.readdir(skillsDir, { withFileTypes: true });
|
|
248
|
+
const craftDirs = entries
|
|
249
|
+
.filter(entry => entry.isDirectory())
|
|
250
|
+
.map(entry => entry.name);
|
|
251
|
+
const statuses = [];
|
|
252
|
+
for (const craftName of craftDirs) {
|
|
253
|
+
const status = await this.verifySync(craftName, cwd);
|
|
254
|
+
statuses.push(status);
|
|
255
|
+
}
|
|
256
|
+
return statuses;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Calculate checksum for entire directory
|
|
260
|
+
*
|
|
261
|
+
* Creates a consistent hash of all files in a directory (excluding metadata)
|
|
262
|
+
*
|
|
263
|
+
* @param dirPath - Directory to checksum
|
|
264
|
+
* @returns SHA256 checksum hex string
|
|
265
|
+
* @private
|
|
266
|
+
*/
|
|
267
|
+
async calculateDirChecksum(dirPath) {
|
|
268
|
+
const files = await this.getAllFiles(dirPath);
|
|
269
|
+
// Sort for consistency
|
|
270
|
+
files.sort();
|
|
271
|
+
const hash = crypto_1.default.createHash('sha256');
|
|
272
|
+
for (const file of files) {
|
|
273
|
+
// Skip metadata files
|
|
274
|
+
const basename = path_1.default.basename(file);
|
|
275
|
+
if (basename === '.craftdesk-checksum' || basename === '.craftdesk-metadata.json') {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
// Add relative path to hash
|
|
279
|
+
const relativePath = path_1.default.relative(dirPath, file);
|
|
280
|
+
hash.update(relativePath);
|
|
281
|
+
// Add file content to hash
|
|
282
|
+
const content = await fs_extra_1.default.readFile(file);
|
|
283
|
+
hash.update(content);
|
|
284
|
+
}
|
|
285
|
+
return hash.digest('hex');
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Recursively get all files in a directory
|
|
289
|
+
*
|
|
290
|
+
* @param dirPath - Directory to scan
|
|
291
|
+
* @returns Array of absolute file paths
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
294
|
+
async getAllFiles(dirPath) {
|
|
295
|
+
const files = [];
|
|
296
|
+
if (!await fs_extra_1.default.pathExists(dirPath)) {
|
|
297
|
+
return files;
|
|
298
|
+
}
|
|
299
|
+
const entries = await fs_extra_1.default.readdir(dirPath, { withFileTypes: true });
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
const fullPath = path_1.default.join(dirPath, entry.name);
|
|
302
|
+
if (entry.isDirectory()) {
|
|
303
|
+
const subFiles = await this.getAllFiles(fullPath);
|
|
304
|
+
files.push(...subFiles);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
files.push(fullPath);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return files;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
exports.MultiAgentSync = MultiAgentSync;
|
|
314
|
+
// Export singleton instance
|
|
315
|
+
exports.multiAgentSync = new MultiAgentSync();
|
|
316
|
+
//# sourceMappingURL=multi-agent-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-agent-sync.js","sourceRoot":"","sources":["../../src/services/multi-agent-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PluginResolver - Resolves plugin dependencies
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Reading plugin craftdesk.json files
|
|
6
|
+
* - Flattening nested dependencies
|
|
7
|
+
* - Building plugin dependency tree
|
|
8
|
+
* - Detecting circular dependencies
|
|
9
|
+
*/
|
|
10
|
+
import type { PluginDependencyTree } from '../types/craftdesk-lock';
|
|
11
|
+
/**
|
|
12
|
+
* Information about a resolved plugin dependency
|
|
13
|
+
*/
|
|
14
|
+
export interface ResolvedPlugin {
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
dependencies: Record<string, string | import('../types/craftdesk-json').DependencyConfig>;
|
|
18
|
+
isDependency: boolean;
|
|
19
|
+
requiredBy: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Service for resolving plugin dependencies and building dependency trees
|
|
23
|
+
*
|
|
24
|
+
* Handles recursive dependency resolution, circular dependency detection,
|
|
25
|
+
* and flattening nested plugin dependencies
|
|
26
|
+
*/
|
|
27
|
+
export declare class PluginResolver {
|
|
28
|
+
private resolvedPlugins;
|
|
29
|
+
private resolutionStack;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve plugin dependencies recursively
|
|
32
|
+
*
|
|
33
|
+
* @param pluginPath - Path to plugin directory
|
|
34
|
+
* @param parentName - Name of parent plugin (for tracking requiredBy)
|
|
35
|
+
* @returns Flattened dependency map
|
|
36
|
+
*/
|
|
37
|
+
resolvePluginDependencies(pluginPath: string, parentName?: string): Promise<Record<string, ResolvedPlugin>>;
|
|
38
|
+
/**
|
|
39
|
+
* Build plugin dependency tree for lockfile
|
|
40
|
+
*
|
|
41
|
+
* @returns Plugin dependency tree structure
|
|
42
|
+
*/
|
|
43
|
+
buildPluginTree(): PluginDependencyTree;
|
|
44
|
+
/**
|
|
45
|
+
* Get flattened dependencies
|
|
46
|
+
*
|
|
47
|
+
* This is what goes into craftdesk.json
|
|
48
|
+
*
|
|
49
|
+
* @returns Flattened dependency map
|
|
50
|
+
*/
|
|
51
|
+
getFlattenedDependencies(): Record<string, string | import('../types/craftdesk-json').DependencyConfig>;
|
|
52
|
+
/**
|
|
53
|
+
* Get only directly installed plugins (not dependencies)
|
|
54
|
+
*
|
|
55
|
+
* @returns Array of directly installed plugins
|
|
56
|
+
*/
|
|
57
|
+
getDirectPlugins(): ResolvedPlugin[];
|
|
58
|
+
/**
|
|
59
|
+
* Get only dependency plugins (not directly installed)
|
|
60
|
+
*
|
|
61
|
+
* @returns Array of dependency plugins
|
|
62
|
+
*/
|
|
63
|
+
getDependencyPlugins(): ResolvedPlugin[];
|
|
64
|
+
/**
|
|
65
|
+
* Read plugin manifest (craftdesk.json)
|
|
66
|
+
*
|
|
67
|
+
* @param pluginPath - Path to plugin directory
|
|
68
|
+
* @returns Parsed manifest or null if not found
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private readPluginManifest;
|
|
72
|
+
/**
|
|
73
|
+
* Reset resolver state
|
|
74
|
+
*
|
|
75
|
+
* Clears all resolved plugins and resolution stack
|
|
76
|
+
*/
|
|
77
|
+
reset(): void;
|
|
78
|
+
}
|
|
79
|
+
export declare const pluginResolver: PluginResolver;
|
|
80
|
+
//# sourceMappingURL=plugin-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-resolver.d.ts","sourceRoot":"","sources":["../../src/services/plugin-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,yBAAyB,EAAE,gBAAgB,CAAC,CAAC;IAC1F,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,eAAe,CAAgB;IAEvC;;;;;;OAMG;IACG,yBAAyB,CAC7B,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAkE1C;;;;OAIG;IACH,eAAe,IAAI,oBAAoB;IAevC;;;;;;OAMG;IACH,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,yBAAyB,EAAE,gBAAgB,CAAC;IAoBvG;;;;OAIG;IACH,gBAAgB,IAAI,cAAc,EAAE;IAIpC;;;;OAIG;IACH,oBAAoB,IAAI,cAAc,EAAE;IAIxC;;;;;;OAMG;YACW,kBAAkB;IAgBhC;;;;OAIG;IACH,KAAK,IAAI,IAAI;CAId;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PluginResolver - Resolves plugin dependencies
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Reading plugin craftdesk.json files
|
|
7
|
+
* - Flattening nested dependencies
|
|
8
|
+
* - Building plugin dependency tree
|
|
9
|
+
* - Detecting circular dependencies
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.pluginResolver = exports.PluginResolver = void 0;
|
|
16
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const logger_1 = require("../utils/logger");
|
|
19
|
+
/**
|
|
20
|
+
* Service for resolving plugin dependencies and building dependency trees
|
|
21
|
+
*
|
|
22
|
+
* Handles recursive dependency resolution, circular dependency detection,
|
|
23
|
+
* and flattening nested plugin dependencies
|
|
24
|
+
*/
|
|
25
|
+
class PluginResolver {
|
|
26
|
+
resolvedPlugins = new Map();
|
|
27
|
+
resolutionStack = [];
|
|
28
|
+
/**
|
|
29
|
+
* Resolve plugin dependencies recursively
|
|
30
|
+
*
|
|
31
|
+
* @param pluginPath - Path to plugin directory
|
|
32
|
+
* @param parentName - Name of parent plugin (for tracking requiredBy)
|
|
33
|
+
* @returns Flattened dependency map
|
|
34
|
+
*/
|
|
35
|
+
async resolvePluginDependencies(pluginPath, parentName) {
|
|
36
|
+
// Read plugin's craftdesk.json
|
|
37
|
+
const manifest = await this.readPluginManifest(pluginPath);
|
|
38
|
+
if (!manifest) {
|
|
39
|
+
throw new Error(`No craftdesk.json found in plugin: ${pluginPath}`);
|
|
40
|
+
}
|
|
41
|
+
const pluginName = manifest.name;
|
|
42
|
+
// Check for circular dependencies
|
|
43
|
+
if (this.resolutionStack.includes(pluginName)) {
|
|
44
|
+
const cycle = [...this.resolutionStack, pluginName].join(' → ');
|
|
45
|
+
throw new Error(`Circular dependency detected: ${cycle}`);
|
|
46
|
+
}
|
|
47
|
+
// Add to resolution stack
|
|
48
|
+
this.resolutionStack.push(pluginName);
|
|
49
|
+
try {
|
|
50
|
+
// If already resolved, just add requiredBy
|
|
51
|
+
if (this.resolvedPlugins.has(pluginName)) {
|
|
52
|
+
const existing = this.resolvedPlugins.get(pluginName);
|
|
53
|
+
// existing is guaranteed to exist due to has() check above
|
|
54
|
+
if (existing && parentName && !existing.requiredBy.includes(parentName)) {
|
|
55
|
+
existing.requiredBy.push(parentName);
|
|
56
|
+
}
|
|
57
|
+
return Object.fromEntries(this.resolvedPlugins);
|
|
58
|
+
}
|
|
59
|
+
// Create resolved entry
|
|
60
|
+
const resolved = {
|
|
61
|
+
name: pluginName,
|
|
62
|
+
version: manifest.version,
|
|
63
|
+
dependencies: manifest.dependencies || {},
|
|
64
|
+
isDependency: !!parentName,
|
|
65
|
+
requiredBy: parentName ? [parentName] : []
|
|
66
|
+
};
|
|
67
|
+
this.resolvedPlugins.set(pluginName, resolved);
|
|
68
|
+
// Recursively resolve dependencies
|
|
69
|
+
if (manifest.dependencies) {
|
|
70
|
+
for (const [depName, depVersion] of Object.entries(manifest.dependencies)) {
|
|
71
|
+
// Skip if dependency is a string (version) - these are resolved by registry
|
|
72
|
+
if (typeof depVersion === 'string') {
|
|
73
|
+
logger_1.logger.debug(`Dependency ${depName} will be resolved by registry`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Handle git dependencies with subdirectories
|
|
77
|
+
if (depVersion.git && depVersion.path) {
|
|
78
|
+
// Dependency is in a subdirectory of git repo - we'll need to clone and resolve
|
|
79
|
+
logger_1.logger.debug(`Dependency ${depName} requires git clone for resolution`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return Object.fromEntries(this.resolvedPlugins);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
// Remove from resolution stack
|
|
88
|
+
this.resolutionStack.pop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build plugin dependency tree for lockfile
|
|
93
|
+
*
|
|
94
|
+
* @returns Plugin dependency tree structure
|
|
95
|
+
*/
|
|
96
|
+
buildPluginTree() {
|
|
97
|
+
const tree = {};
|
|
98
|
+
for (const [name, plugin] of this.resolvedPlugins) {
|
|
99
|
+
tree[name] = {
|
|
100
|
+
version: plugin.version,
|
|
101
|
+
dependencies: Object.keys(plugin.dependencies),
|
|
102
|
+
isDependency: plugin.isDependency,
|
|
103
|
+
requiredBy: plugin.requiredBy
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return tree;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get flattened dependencies
|
|
110
|
+
*
|
|
111
|
+
* This is what goes into craftdesk.json
|
|
112
|
+
*
|
|
113
|
+
* @returns Flattened dependency map
|
|
114
|
+
*/
|
|
115
|
+
getFlattenedDependencies() {
|
|
116
|
+
const flattened = {};
|
|
117
|
+
for (const [name, plugin] of this.resolvedPlugins) {
|
|
118
|
+
flattened[name] = plugin.version;
|
|
119
|
+
// Add plugin's dependencies
|
|
120
|
+
for (const [depName, depVersion] of Object.entries(plugin.dependencies)) {
|
|
121
|
+
if (typeof depVersion === 'string') {
|
|
122
|
+
flattened[depName] = depVersion;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Complex dependency config - we'll add it as-is
|
|
126
|
+
flattened[depName] = depVersion;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return flattened;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get only directly installed plugins (not dependencies)
|
|
134
|
+
*
|
|
135
|
+
* @returns Array of directly installed plugins
|
|
136
|
+
*/
|
|
137
|
+
getDirectPlugins() {
|
|
138
|
+
return Array.from(this.resolvedPlugins.values()).filter(p => !p.isDependency);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get only dependency plugins (not directly installed)
|
|
142
|
+
*
|
|
143
|
+
* @returns Array of dependency plugins
|
|
144
|
+
*/
|
|
145
|
+
getDependencyPlugins() {
|
|
146
|
+
return Array.from(this.resolvedPlugins.values()).filter(p => p.isDependency);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Read plugin manifest (craftdesk.json)
|
|
150
|
+
*
|
|
151
|
+
* @param pluginPath - Path to plugin directory
|
|
152
|
+
* @returns Parsed manifest or null if not found
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
async readPluginManifest(pluginPath) {
|
|
156
|
+
const manifestPath = path_1.default.join(pluginPath, 'craftdesk.json');
|
|
157
|
+
try {
|
|
158
|
+
if (await fs_extra_1.default.pathExists(manifestPath)) {
|
|
159
|
+
const content = await fs_extra_1.default.readFile(manifestPath, 'utf-8');
|
|
160
|
+
return JSON.parse(content);
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
166
|
+
logger_1.logger.debug(`Failed to read plugin manifest at ${manifestPath}: ${message}`);
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Reset resolver state
|
|
172
|
+
*
|
|
173
|
+
* Clears all resolved plugins and resolution stack
|
|
174
|
+
*/
|
|
175
|
+
reset() {
|
|
176
|
+
this.resolvedPlugins.clear();
|
|
177
|
+
this.resolutionStack = [];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.PluginResolver = PluginResolver;
|
|
181
|
+
// Export singleton instance
|
|
182
|
+
exports.pluginResolver = new PluginResolver();
|
|
183
|
+
//# sourceMappingURL=plugin-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-resolver.js","sourceRoot":"","sources":["../../src/services/plugin-resolver.ts"],"names":[],"mappings":"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"}
|