craftdesk 0.1.0 → 0.2.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/.claude/settings.local.json +17 -0
- package/.github/workflows/ci.yml +94 -0
- package/API.md +414 -0
- package/README.md +799 -0
- package/TESTING.md +263 -0
- package/bin/craftdesk.js +4 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +284 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +56 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +57 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +109 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +117 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +74 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/services/config-manager.d.ts +88 -0
- package/dist/services/config-manager.d.ts.map +1 -0
- package/dist/services/config-manager.js +143 -0
- package/dist/services/config-manager.js.map +1 -0
- package/dist/services/git-resolver.d.ts +139 -0
- package/dist/services/git-resolver.d.ts.map +1 -0
- package/dist/services/git-resolver.js +334 -0
- package/dist/services/git-resolver.js.map +1 -0
- package/dist/services/installer.d.ts +98 -0
- package/dist/services/installer.d.ts.map +1 -0
- package/dist/services/installer.js +274 -0
- package/dist/services/installer.js.map +1 -0
- package/dist/services/registry-client.d.ts +27 -0
- package/dist/services/registry-client.d.ts.map +1 -0
- package/dist/services/registry-client.js +134 -0
- package/dist/services/registry-client.js.map +1 -0
- package/dist/types/config.d.ts +17 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/craftdesk-json.d.ts +42 -0
- package/dist/types/craftdesk-json.d.ts.map +1 -0
- package/dist/types/craftdesk-json.js +3 -0
- package/dist/types/craftdesk-json.js.map +1 -0
- package/dist/types/craftdesk-lock.d.ts +34 -0
- package/dist/types/craftdesk-lock.d.ts.map +1 -0
- package/dist/types/craftdesk-lock.js +3 -0
- package/dist/types/craftdesk-lock.js.map +1 -0
- package/dist/utils/file-system.d.ts +10 -0
- package/dist/utils/file-system.d.ts.map +1 -0
- package/dist/utils/file-system.js +60 -0
- package/dist/utils/file-system.js.map +1 -0
- package/dist/utils/logger.d.ts +18 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/logger.js.map +1 -0
- package/docs/DEPENDENCY_RESOLUTION.md +237 -0
- package/examples/craftdesk-all-sources.json +79 -0
- package/examples/craftdesk-git-monorepo.json +41 -0
- package/examples/craftdesk-multi-registry.json +40 -0
- package/examples/craftdesk-with-registries.json +49 -0
- package/examples/simple-craftdesk.json +10 -0
- package/package.json +32 -25
- package/src/commands/add.ts +314 -0
- package/src/commands/init.ts +55 -0
- package/src/commands/install.ts +126 -0
- package/src/commands/list.ts +126 -0
- package/src/commands/remove.ts +82 -0
- package/src/index.ts +56 -0
- package/src/services/config-manager.ts +150 -0
- package/src/services/git-resolver.ts +370 -0
- package/src/services/installer.ts +314 -0
- package/src/services/registry-client.ts +163 -0
- package/src/types/craftdesk-json.ts +53 -0
- package/src/types/craftdesk-lock.ts +38 -0
- package/src/utils/file-system.ts +55 -0
- package/src/utils/logger.ts +82 -0
- package/tests/fixtures/craftdesk-git.json +17 -0
- package/tests/fixtures/craftdesk.json +15 -0
- package/tests/helpers/test-utils.ts +60 -0
- package/tests/integration/init-command.test.ts +70 -0
- package/tests/integration/list-command.test.ts +77 -0
- package/tests/unit/config-manager.test.ts +228 -0
- package/tests/unit/git-resolver.test.ts +303 -0
- package/tests/unit/installer.test.ts +105 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +29 -0
- package/LICENSE +0 -21
- package/index.js +0 -4
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.configManager = exports.ConfigManager = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Manages configuration for the CraftDesk CLI
|
|
11
|
+
*
|
|
12
|
+
* Handles reading craftdesk.json, resolving registry URLs for crafts,
|
|
13
|
+
* managing authentication tokens, and determining installation paths.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const configManager = new ConfigManager();
|
|
18
|
+
* const registry = await configManager.getRegistryForCraft('@company/auth');
|
|
19
|
+
* const token = await configManager.getAuthToken('company-private');
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
class ConfigManager {
|
|
23
|
+
craftDeskJson = null;
|
|
24
|
+
/**
|
|
25
|
+
* Gets the appropriate registry URL for a given craft
|
|
26
|
+
*
|
|
27
|
+
* Resolution order:
|
|
28
|
+
* 1. Scoped registry matching the craft scope (e.g., @company/craft -> company registry)
|
|
29
|
+
* 2. Default registry from craftdesk.json
|
|
30
|
+
* 3. Global fallback (https://craftdesk.ai)
|
|
31
|
+
*
|
|
32
|
+
* @param craftName - The name of the craft to resolve
|
|
33
|
+
* @returns The registry URL to use for this craft
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // Scoped craft with configured registry
|
|
38
|
+
* const url = await configManager.getRegistryForCraft('@company/auth');
|
|
39
|
+
* // Returns: 'https://company.internal'
|
|
40
|
+
*
|
|
41
|
+
* // Regular craft
|
|
42
|
+
* const url = await configManager.getRegistryForCraft('ruby-on-rails');
|
|
43
|
+
* // Returns: 'https://craftdesk.ai' (or default from config)
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
async getRegistryForCraft(craftName) {
|
|
47
|
+
const craftDesk = await this.getCraftDeskJson();
|
|
48
|
+
if (!craftDesk) {
|
|
49
|
+
// Default registry if no craftdesk.json exists
|
|
50
|
+
return 'https://craftdesk.ai';
|
|
51
|
+
}
|
|
52
|
+
// Check if it's a scoped craft and has a configured registry
|
|
53
|
+
if (craftName.startsWith('@') && craftDesk.registries) {
|
|
54
|
+
const scope = craftName.split('/')[0];
|
|
55
|
+
// Look for a registry with matching scope
|
|
56
|
+
for (const [name, registry] of Object.entries(craftDesk.registries)) {
|
|
57
|
+
if (registry.scope === scope) {
|
|
58
|
+
return registry.url;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Check if there's a default registry configured
|
|
63
|
+
if (craftDesk.registries?.default) {
|
|
64
|
+
return craftDesk.registries.default.url;
|
|
65
|
+
}
|
|
66
|
+
// Final fallback
|
|
67
|
+
return 'https://craftdesk.ai';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves authentication token for a registry from environment variables
|
|
71
|
+
*
|
|
72
|
+
* Looks for tokens in environment variables with the pattern:
|
|
73
|
+
* CRAFTDESK_AUTH_{REGISTRY_NAME_UPPERCASE}
|
|
74
|
+
*
|
|
75
|
+
* Hyphens in registry names are converted to underscores.
|
|
76
|
+
*
|
|
77
|
+
* @param registryName - The name of the registry from craftdesk.json
|
|
78
|
+
* @returns The auth token if found, null otherwise
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // For registry named 'company-private', looks for CRAFTDESK_AUTH_COMPANY_PRIVATE
|
|
83
|
+
* const token = await configManager.getAuthToken('company-private');
|
|
84
|
+
*
|
|
85
|
+
* // Usage in shell:
|
|
86
|
+
* // export CRAFTDESK_AUTH_COMPANY_PRIVATE=token_abc123
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
async getAuthToken(registryName) {
|
|
90
|
+
const craftDesk = await this.getCraftDeskJson();
|
|
91
|
+
if (!craftDesk?.registries?.[registryName]) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// Auth tokens should be in environment variables for security
|
|
95
|
+
// e.g., CRAFTDESK_AUTH_COMPANY_PRIVATE
|
|
96
|
+
const envVar = `CRAFTDESK_AUTH_${registryName.toUpperCase().replace(/-/g, '_')}`;
|
|
97
|
+
return process.env[envVar] || null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns the installation path for crafts
|
|
101
|
+
*
|
|
102
|
+
* All crafts are installed to the .claude directory in the project root.
|
|
103
|
+
*
|
|
104
|
+
* @returns The relative path to the installation directory
|
|
105
|
+
*/
|
|
106
|
+
getInstallPath() {
|
|
107
|
+
// Always use .claude directory in project root
|
|
108
|
+
return '.claude';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Reads and caches the craftdesk.json file from the current working directory
|
|
112
|
+
*
|
|
113
|
+
* The file is cached after the first read for performance. Returns null if
|
|
114
|
+
* the file doesn't exist or contains invalid JSON.
|
|
115
|
+
*
|
|
116
|
+
* @returns The parsed craftdesk.json content, or null if not found/invalid
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const config = await configManager.getCraftDeskJson();
|
|
121
|
+
* if (config) {
|
|
122
|
+
* console.log(`Project: ${config.name}@${config.version}`);
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
async getCraftDeskJson() {
|
|
127
|
+
if (this.craftDeskJson) {
|
|
128
|
+
return this.craftDeskJson;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const craftDeskPath = path_1.default.join(process.cwd(), 'craftdesk.json');
|
|
132
|
+
const content = await fs_extra_1.default.readFile(craftDeskPath, 'utf-8');
|
|
133
|
+
this.craftDeskJson = JSON.parse(content);
|
|
134
|
+
return this.craftDeskJson;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.ConfigManager = ConfigManager;
|
|
142
|
+
exports.configManager = new ConfigManager();
|
|
143
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/services/config-manager.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA0B;AAC1B,gDAAwB;AAIxB;;;;;;;;;;;;GAYG;AACH,MAAa,aAAa;IAChB,aAAa,GAAyB,IAAI,CAAC;IAEnD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,mBAAmB,CAAC,SAAiB;QACzC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAEhD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,+CAA+C;YAC/C,OAAO,sBAAsB,CAAC;QAChC,CAAC;QAED,6DAA6D;QAC7D,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YACtD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAEtC,0CAA0C;YAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpE,IAAI,QAAQ,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;oBAC7B,OAAO,QAAQ,CAAC,GAAG,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,IAAI,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;YAClC,OAAO,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC;QAC1C,CAAC;QAED,iBAAiB;QACjB,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAEhD,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,8DAA8D;QAC9D,uCAAuC;QACvC,MAAM,MAAM,GAAG,kBAAkB,YAAY,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QACjF,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IAED;;;;;;OAMG;IACH,cAAc;QACZ,+CAA+C;QAC/C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YAC1D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAjID,sCAiIC;AAEY,QAAA,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { CraftDeskJson, DependencyConfig } from '../types/craftdesk-json';
|
|
2
|
+
/**
|
|
3
|
+
* Information about a git dependency
|
|
4
|
+
*/
|
|
5
|
+
export interface GitDependencyInfo {
|
|
6
|
+
/** Git repository URL */
|
|
7
|
+
url: string;
|
|
8
|
+
/** Optional branch name */
|
|
9
|
+
branch?: string;
|
|
10
|
+
/** Optional tag name */
|
|
11
|
+
tag?: string;
|
|
12
|
+
/** Optional commit hash */
|
|
13
|
+
commit?: string;
|
|
14
|
+
/** Optional subdirectory path for monorepos */
|
|
15
|
+
path?: string;
|
|
16
|
+
/** Optional direct file path (e.g., skill.md, agent.md) */
|
|
17
|
+
file?: string;
|
|
18
|
+
/** Parsed craftdesk.json from the repository */
|
|
19
|
+
craftDeskJson?: CraftDeskJson;
|
|
20
|
+
/** Resolved full commit hash */
|
|
21
|
+
resolvedCommit?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolves git dependencies and extracts their metadata
|
|
25
|
+
*
|
|
26
|
+
* Handles cloning git repositories, reading craftdesk.json, inferring craft types
|
|
27
|
+
* when metadata is missing, and supporting monorepo structures with subdirectory paths.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const resolver = new GitResolver();
|
|
32
|
+
*
|
|
33
|
+
* // Resolve a git dependency
|
|
34
|
+
* const info = await resolver.resolveGitDependency({
|
|
35
|
+
* url: 'https://github.com/company/auth.git',
|
|
36
|
+
* branch: 'main'
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* console.log(info.craftDeskJson.name); // 'auth-skill'
|
|
40
|
+
* console.log(info.resolvedCommit); // Full commit hash
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class GitResolver {
|
|
44
|
+
private tempDir;
|
|
45
|
+
constructor();
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a git dependency by cloning and reading its craftdesk.json
|
|
48
|
+
*
|
|
49
|
+
* Process:
|
|
50
|
+
* 1. Clones the repository (shallow clone for efficiency)
|
|
51
|
+
* 2. Checks out specified branch/tag/commit
|
|
52
|
+
* 3. Reads craftdesk.json from repository, subdirectory, or infers from direct file
|
|
53
|
+
* 4. Generates minimal metadata if craftdesk.json is missing
|
|
54
|
+
* 5. Infers craft type from marker files, direct file extension, or directory structure
|
|
55
|
+
*
|
|
56
|
+
* @param gitInfo - Git dependency information
|
|
57
|
+
* @returns Enhanced git info with craftdesk.json and resolved commit
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* // With craftdesk.json in repository
|
|
62
|
+
* const info = await resolver.resolveGitDependency({
|
|
63
|
+
* url: 'https://github.com/user/skill.git',
|
|
64
|
+
* tag: 'v1.0.0'
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* // Monorepo with subdirectory
|
|
68
|
+
* const info = await resolver.resolveGitDependency({
|
|
69
|
+
* url: 'https://github.com/company/monorepo.git',
|
|
70
|
+
* tag: 'v3.0.0',
|
|
71
|
+
* path: 'crafts/auth'
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* // Direct file reference
|
|
75
|
+
* const info = await resolver.resolveGitDependency({
|
|
76
|
+
* url: 'https://github.com/user/repo.git',
|
|
77
|
+
* branch: 'main',
|
|
78
|
+
* file: 'rspec-dry-agent.md'
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
resolveGitDependency(gitInfo: GitDependencyInfo): Promise<GitDependencyInfo>;
|
|
83
|
+
/**
|
|
84
|
+
* Infers the craft type from a filename
|
|
85
|
+
*
|
|
86
|
+
* Type inference strategy:
|
|
87
|
+
* 1. Check filename for type indicators: agent, skill, command, hook
|
|
88
|
+
* 2. Check file extension patterns
|
|
89
|
+
* 3. Default to 'skill' if no indicators found
|
|
90
|
+
*
|
|
91
|
+
* @param filename - The filename to analyze
|
|
92
|
+
* @returns The inferred craft type
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
private inferCraftTypeFromFilename;
|
|
96
|
+
/**
|
|
97
|
+
* Infers the craft type from the repository structure
|
|
98
|
+
*
|
|
99
|
+
* Type inference strategy:
|
|
100
|
+
* 1. Check for marker files: SKILL.md, AGENT.md, COMMAND.md, HOOK.md
|
|
101
|
+
* 2. Check directory name for type indicators
|
|
102
|
+
* 3. Default to 'skill' if no indicators found
|
|
103
|
+
*
|
|
104
|
+
* @param repoPath - Path to the cloned repository
|
|
105
|
+
* @param subPath - Optional subdirectory to check
|
|
106
|
+
* @returns The inferred craft type
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
private inferCraftType;
|
|
110
|
+
/**
|
|
111
|
+
* Resolves all dependencies including transitive dependencies from git sources
|
|
112
|
+
*
|
|
113
|
+
* Uses a breadth-first traversal algorithm to resolve dependencies recursively.
|
|
114
|
+
* Tracks visited packages to avoid circular dependencies.
|
|
115
|
+
*
|
|
116
|
+
* @param dependencies - Map of dependency names to version strings or config objects
|
|
117
|
+
* @returns Object containing resolved dependencies and generated lockfile
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const result = await resolver.resolveAllDependencies({
|
|
122
|
+
* 'ruby-on-rails': '^7.0.0',
|
|
123
|
+
* 'custom-auth': {
|
|
124
|
+
* git: 'https://github.com/company/auth.git',
|
|
125
|
+
* branch: 'main'
|
|
126
|
+
* }
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* console.log(result.resolved); // All dependencies including transitive
|
|
130
|
+
* console.log(result.lockfile); // Generated lockfile structure
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
resolveAllDependencies(dependencies: Record<string, string | DependencyConfig>): Promise<{
|
|
134
|
+
resolved: Record<string, any>;
|
|
135
|
+
lockfile: any;
|
|
136
|
+
}>;
|
|
137
|
+
}
|
|
138
|
+
export declare const gitResolver: GitResolver;
|
|
139
|
+
//# sourceMappingURL=git-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-resolver.d.ts","sourceRoot":"","sources":["../../src/services/git-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,gCAAgC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;;IAMxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACG,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqHlF;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,0BAA0B;IAalC;;;;;;;;;;;;OAYG;YACW,cAAc;IAuB5B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,sBAAsB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,GAAG,OAAO,CAAC;QAC7F,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,QAAQ,EAAE,GAAG,CAAC;KACf,CAAC;CAwEH;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.gitResolver = exports.GitResolver = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
/**
|
|
12
|
+
* Resolves git dependencies and extracts their metadata
|
|
13
|
+
*
|
|
14
|
+
* Handles cloning git repositories, reading craftdesk.json, inferring craft types
|
|
15
|
+
* when metadata is missing, and supporting monorepo structures with subdirectory paths.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const resolver = new GitResolver();
|
|
20
|
+
*
|
|
21
|
+
* // Resolve a git dependency
|
|
22
|
+
* const info = await resolver.resolveGitDependency({
|
|
23
|
+
* url: 'https://github.com/company/auth.git',
|
|
24
|
+
* branch: 'main'
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* console.log(info.craftDeskJson.name); // 'auth-skill'
|
|
28
|
+
* console.log(info.resolvedCommit); // Full commit hash
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
class GitResolver {
|
|
32
|
+
tempDir;
|
|
33
|
+
constructor() {
|
|
34
|
+
this.tempDir = path_1.default.join(process.cwd(), '.craftdesk', 'tmp');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolves a git dependency by cloning and reading its craftdesk.json
|
|
38
|
+
*
|
|
39
|
+
* Process:
|
|
40
|
+
* 1. Clones the repository (shallow clone for efficiency)
|
|
41
|
+
* 2. Checks out specified branch/tag/commit
|
|
42
|
+
* 3. Reads craftdesk.json from repository, subdirectory, or infers from direct file
|
|
43
|
+
* 4. Generates minimal metadata if craftdesk.json is missing
|
|
44
|
+
* 5. Infers craft type from marker files, direct file extension, or directory structure
|
|
45
|
+
*
|
|
46
|
+
* @param gitInfo - Git dependency information
|
|
47
|
+
* @returns Enhanced git info with craftdesk.json and resolved commit
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // With craftdesk.json in repository
|
|
52
|
+
* const info = await resolver.resolveGitDependency({
|
|
53
|
+
* url: 'https://github.com/user/skill.git',
|
|
54
|
+
* tag: 'v1.0.0'
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // Monorepo with subdirectory
|
|
58
|
+
* const info = await resolver.resolveGitDependency({
|
|
59
|
+
* url: 'https://github.com/company/monorepo.git',
|
|
60
|
+
* tag: 'v3.0.0',
|
|
61
|
+
* path: 'crafts/auth'
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* // Direct file reference
|
|
65
|
+
* const info = await resolver.resolveGitDependency({
|
|
66
|
+
* url: 'https://github.com/user/repo.git',
|
|
67
|
+
* branch: 'main',
|
|
68
|
+
* file: 'rspec-dry-agent.md'
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async resolveGitDependency(gitInfo) {
|
|
73
|
+
const repoTempDir = path_1.default.join(this.tempDir, `git-${Date.now()}`);
|
|
74
|
+
try {
|
|
75
|
+
await fs_extra_1.default.ensureDir(repoTempDir);
|
|
76
|
+
// Clone the repository
|
|
77
|
+
logger_1.logger.debug(`Cloning ${gitInfo.url} to analyze dependencies...`);
|
|
78
|
+
let cloneCmd = `git clone --depth 1`;
|
|
79
|
+
if (gitInfo.branch) {
|
|
80
|
+
cloneCmd += ` -b ${gitInfo.branch}`;
|
|
81
|
+
}
|
|
82
|
+
else if (gitInfo.tag) {
|
|
83
|
+
cloneCmd += ` -b ${gitInfo.tag}`;
|
|
84
|
+
}
|
|
85
|
+
cloneCmd += ` ${gitInfo.url} ${repoTempDir}`;
|
|
86
|
+
(0, child_process_1.execSync)(cloneCmd, { stdio: 'pipe' });
|
|
87
|
+
// If specific commit, checkout that commit
|
|
88
|
+
if (gitInfo.commit) {
|
|
89
|
+
(0, child_process_1.execSync)(`cd ${repoTempDir} && git fetch --unshallow && git checkout ${gitInfo.commit}`, { stdio: 'pipe' });
|
|
90
|
+
}
|
|
91
|
+
// Get the actual commit hash for lockfile
|
|
92
|
+
const resolvedCommit = (0, child_process_1.execSync)(`cd ${repoTempDir} && git rev-parse HEAD`, { encoding: 'utf8' }).trim();
|
|
93
|
+
gitInfo.resolvedCommit = resolvedCommit;
|
|
94
|
+
// Handle direct file reference
|
|
95
|
+
if (gitInfo.file) {
|
|
96
|
+
const filePath = path_1.default.join(repoTempDir, gitInfo.file);
|
|
97
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
98
|
+
logger_1.logger.debug(`Found direct file reference: ${gitInfo.file}`);
|
|
99
|
+
// Try to find craftdesk.json to get type and metadata
|
|
100
|
+
let craftType;
|
|
101
|
+
let craftName;
|
|
102
|
+
let craftVersion;
|
|
103
|
+
let craftDeps;
|
|
104
|
+
// Check for craftdesk.json in same directory as file
|
|
105
|
+
const fileDir = path_1.default.dirname(gitInfo.file);
|
|
106
|
+
const fileDirCraftPath = path_1.default.join(repoTempDir, fileDir, 'craftdesk.json');
|
|
107
|
+
// Check for craftdesk.json in repo root
|
|
108
|
+
const rootCraftPath = path_1.default.join(repoTempDir, 'craftdesk.json');
|
|
109
|
+
if (await fs_extra_1.default.pathExists(fileDirCraftPath)) {
|
|
110
|
+
const content = await fs_extra_1.default.readFile(fileDirCraftPath, 'utf-8');
|
|
111
|
+
const craftJson = JSON.parse(content);
|
|
112
|
+
logger_1.logger.debug(`Found craftdesk.json in file directory: ${craftJson.name}@${craftJson.version}`);
|
|
113
|
+
craftType = craftJson.type;
|
|
114
|
+
craftName = craftJson.name;
|
|
115
|
+
craftVersion = craftJson.version;
|
|
116
|
+
craftDeps = craftJson.dependencies;
|
|
117
|
+
}
|
|
118
|
+
else if (await fs_extra_1.default.pathExists(rootCraftPath)) {
|
|
119
|
+
const content = await fs_extra_1.default.readFile(rootCraftPath, 'utf-8');
|
|
120
|
+
const craftJson = JSON.parse(content);
|
|
121
|
+
logger_1.logger.debug(`Found craftdesk.json in repo root: ${craftJson.name}@${craftJson.version}`);
|
|
122
|
+
craftType = craftJson.type;
|
|
123
|
+
craftName = craftJson.name;
|
|
124
|
+
craftVersion = craftJson.version;
|
|
125
|
+
craftDeps = craftJson.dependencies;
|
|
126
|
+
}
|
|
127
|
+
// If no craftdesk.json found, infer from filename
|
|
128
|
+
if (!craftType) {
|
|
129
|
+
craftType = this.inferCraftTypeFromFilename(gitInfo.file);
|
|
130
|
+
}
|
|
131
|
+
// Create minimal craftdesk.json from file
|
|
132
|
+
gitInfo.craftDeskJson = {
|
|
133
|
+
name: craftName || path_1.default.basename(gitInfo.file, path_1.default.extname(gitInfo.file)),
|
|
134
|
+
version: craftVersion || gitInfo.tag || gitInfo.branch || resolvedCommit.substring(0, 7),
|
|
135
|
+
type: craftType,
|
|
136
|
+
description: `Git file dependency from ${gitInfo.url}/${gitInfo.file}`,
|
|
137
|
+
dependencies: craftDeps || {}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
throw new Error(`File not found: ${gitInfo.file} in ${gitInfo.url}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Look for craftdesk.json in the specified path or root
|
|
146
|
+
const craftPath = gitInfo.path
|
|
147
|
+
? path_1.default.join(repoTempDir, gitInfo.path, 'craftdesk.json')
|
|
148
|
+
: path_1.default.join(repoTempDir, 'craftdesk.json');
|
|
149
|
+
if (await fs_extra_1.default.pathExists(craftPath)) {
|
|
150
|
+
const content = await fs_extra_1.default.readFile(craftPath, 'utf-8');
|
|
151
|
+
gitInfo.craftDeskJson = JSON.parse(content);
|
|
152
|
+
logger_1.logger.debug(`Found craftdesk.json in git repository: ${gitInfo.craftDeskJson.name}@${gitInfo.craftDeskJson.version}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// No craftdesk.json found - create a minimal one
|
|
156
|
+
logger_1.logger.warn(`No craftdesk.json found in ${gitInfo.url}${gitInfo.path ? `#path:${gitInfo.path}` : ''}`);
|
|
157
|
+
// Try to infer the type from directory structure
|
|
158
|
+
const type = await this.inferCraftType(repoTempDir, gitInfo.path);
|
|
159
|
+
gitInfo.craftDeskJson = {
|
|
160
|
+
name: path_1.default.basename(gitInfo.url, '.git'),
|
|
161
|
+
version: gitInfo.tag || gitInfo.branch || resolvedCommit.substring(0, 7),
|
|
162
|
+
type: type,
|
|
163
|
+
description: `Git dependency from ${gitInfo.url}`,
|
|
164
|
+
dependencies: {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return gitInfo;
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
// Clean up temp directory
|
|
172
|
+
await fs_extra_1.default.remove(repoTempDir);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Infers the craft type from a filename
|
|
177
|
+
*
|
|
178
|
+
* Type inference strategy:
|
|
179
|
+
* 1. Check filename for type indicators: agent, skill, command, hook
|
|
180
|
+
* 2. Check file extension patterns
|
|
181
|
+
* 3. Default to 'skill' if no indicators found
|
|
182
|
+
*
|
|
183
|
+
* @param filename - The filename to analyze
|
|
184
|
+
* @returns The inferred craft type
|
|
185
|
+
* @private
|
|
186
|
+
*/
|
|
187
|
+
inferCraftTypeFromFilename(filename) {
|
|
188
|
+
const lower = filename.toLowerCase();
|
|
189
|
+
// Check filename for type indicators
|
|
190
|
+
if (lower.includes('agent'))
|
|
191
|
+
return 'agent';
|
|
192
|
+
if (lower.includes('command'))
|
|
193
|
+
return 'command';
|
|
194
|
+
if (lower.includes('hook'))
|
|
195
|
+
return 'hook';
|
|
196
|
+
if (lower.includes('skill'))
|
|
197
|
+
return 'skill';
|
|
198
|
+
// Default to skill
|
|
199
|
+
return 'skill';
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Infers the craft type from the repository structure
|
|
203
|
+
*
|
|
204
|
+
* Type inference strategy:
|
|
205
|
+
* 1. Check for marker files: SKILL.md, AGENT.md, COMMAND.md, HOOK.md
|
|
206
|
+
* 2. Check directory name for type indicators
|
|
207
|
+
* 3. Default to 'skill' if no indicators found
|
|
208
|
+
*
|
|
209
|
+
* @param repoPath - Path to the cloned repository
|
|
210
|
+
* @param subPath - Optional subdirectory to check
|
|
211
|
+
* @returns The inferred craft type
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
async inferCraftType(repoPath, subPath) {
|
|
215
|
+
const checkPath = subPath ? path_1.default.join(repoPath, subPath) : repoPath;
|
|
216
|
+
// Check for type-indicating files
|
|
217
|
+
const files = await fs_extra_1.default.readdir(checkPath);
|
|
218
|
+
// Look for SKILL.md, AGENT.md, COMMAND.md, HOOK.md
|
|
219
|
+
if (files.includes('SKILL.md'))
|
|
220
|
+
return 'skill';
|
|
221
|
+
if (files.includes('AGENT.md'))
|
|
222
|
+
return 'agent';
|
|
223
|
+
if (files.includes('COMMAND.md'))
|
|
224
|
+
return 'command';
|
|
225
|
+
if (files.includes('HOOK.md'))
|
|
226
|
+
return 'hook';
|
|
227
|
+
// Check directory name hints
|
|
228
|
+
const dirName = subPath ? path_1.default.basename(subPath) : path_1.default.basename(repoPath);
|
|
229
|
+
if (dirName.includes('skill'))
|
|
230
|
+
return 'skill';
|
|
231
|
+
if (dirName.includes('agent'))
|
|
232
|
+
return 'agent';
|
|
233
|
+
if (dirName.includes('command'))
|
|
234
|
+
return 'command';
|
|
235
|
+
if (dirName.includes('hook'))
|
|
236
|
+
return 'hook';
|
|
237
|
+
// Default to skill
|
|
238
|
+
return 'skill';
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Resolves all dependencies including transitive dependencies from git sources
|
|
242
|
+
*
|
|
243
|
+
* Uses a breadth-first traversal algorithm to resolve dependencies recursively.
|
|
244
|
+
* Tracks visited packages to avoid circular dependencies.
|
|
245
|
+
*
|
|
246
|
+
* @param dependencies - Map of dependency names to version strings or config objects
|
|
247
|
+
* @returns Object containing resolved dependencies and generated lockfile
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* const result = await resolver.resolveAllDependencies({
|
|
252
|
+
* 'ruby-on-rails': '^7.0.0',
|
|
253
|
+
* 'custom-auth': {
|
|
254
|
+
* git: 'https://github.com/company/auth.git',
|
|
255
|
+
* branch: 'main'
|
|
256
|
+
* }
|
|
257
|
+
* });
|
|
258
|
+
*
|
|
259
|
+
* console.log(result.resolved); // All dependencies including transitive
|
|
260
|
+
* console.log(result.lockfile); // Generated lockfile structure
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
async resolveAllDependencies(dependencies) {
|
|
264
|
+
const resolved = {};
|
|
265
|
+
// Queue of dependencies to resolve (breadth-first traversal)
|
|
266
|
+
const toResolve = Object.entries(dependencies);
|
|
267
|
+
// Track visited packages to prevent infinite loops from circular dependencies
|
|
268
|
+
const visited = new Set();
|
|
269
|
+
// Process queue until all dependencies are resolved
|
|
270
|
+
while (toResolve.length > 0) {
|
|
271
|
+
const [name, dep] = toResolve.shift();
|
|
272
|
+
// Skip if already resolved (handles duplicates and circular deps)
|
|
273
|
+
if (visited.has(name))
|
|
274
|
+
continue;
|
|
275
|
+
visited.add(name);
|
|
276
|
+
// Determine if this is a git or registry dependency
|
|
277
|
+
if (typeof dep === 'object' && dep.git) {
|
|
278
|
+
// Git dependency - clone repository and extract metadata
|
|
279
|
+
const gitInfo = await this.resolveGitDependency({
|
|
280
|
+
url: dep.git,
|
|
281
|
+
branch: dep.branch,
|
|
282
|
+
tag: dep.tag,
|
|
283
|
+
commit: dep.commit,
|
|
284
|
+
path: dep.path,
|
|
285
|
+
file: dep.file
|
|
286
|
+
});
|
|
287
|
+
resolved[name] = {
|
|
288
|
+
version: gitInfo.craftDeskJson?.version || '0.0.0',
|
|
289
|
+
resolved: gitInfo.url,
|
|
290
|
+
integrity: gitInfo.resolvedCommit || 'git',
|
|
291
|
+
type: gitInfo.craftDeskJson?.type || 'skill',
|
|
292
|
+
author: gitInfo.craftDeskJson?.author || 'git',
|
|
293
|
+
git: gitInfo.url,
|
|
294
|
+
...(gitInfo.branch && { branch: gitInfo.branch }),
|
|
295
|
+
...(gitInfo.tag && { tag: gitInfo.tag }),
|
|
296
|
+
...(gitInfo.commit && { commit: gitInfo.resolvedCommit }),
|
|
297
|
+
...(gitInfo.path && { path: gitInfo.path }),
|
|
298
|
+
...(gitInfo.file && { file: gitInfo.file }),
|
|
299
|
+
dependencies: gitInfo.craftDeskJson?.dependencies || {}
|
|
300
|
+
};
|
|
301
|
+
// Add transitive dependencies to the resolution queue
|
|
302
|
+
// This enables recursive dependency resolution
|
|
303
|
+
if (gitInfo.craftDeskJson?.dependencies) {
|
|
304
|
+
for (const [depName, depVersion] of Object.entries(gitInfo.craftDeskJson.dependencies)) {
|
|
305
|
+
// Only add if not already visited (avoids redundant resolution)
|
|
306
|
+
if (!visited.has(depName)) {
|
|
307
|
+
toResolve.push([depName, depVersion]);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// Registry dependency - mark for resolution by registry client
|
|
314
|
+
// The actual version resolution happens via the registry API
|
|
315
|
+
resolved[name] = {
|
|
316
|
+
needsResolution: true,
|
|
317
|
+
version: typeof dep === 'string' ? dep : dep.version,
|
|
318
|
+
registry: typeof dep === 'object' ? dep.registry : undefined
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
resolved,
|
|
324
|
+
lockfile: {
|
|
325
|
+
version: '1.0.0',
|
|
326
|
+
lockfileVersion: 1,
|
|
327
|
+
crafts: resolved
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
exports.GitResolver = GitResolver;
|
|
333
|
+
exports.gitResolver = new GitResolver();
|
|
334
|
+
//# sourceMappingURL=git-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-resolver.js","sourceRoot":"","sources":["../../src/services/git-resolver.ts"],"names":[],"mappings":"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"}
|