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.
Files changed (103) hide show
  1. package/.claude/settings.local.json +17 -0
  2. package/.github/workflows/ci.yml +94 -0
  3. package/API.md +414 -0
  4. package/README.md +799 -0
  5. package/TESTING.md +263 -0
  6. package/bin/craftdesk.js +4 -0
  7. package/dist/commands/add.d.ts +3 -0
  8. package/dist/commands/add.d.ts.map +1 -0
  9. package/dist/commands/add.js +284 -0
  10. package/dist/commands/add.js.map +1 -0
  11. package/dist/commands/config.d.ts +3 -0
  12. package/dist/commands/config.d.ts.map +1 -0
  13. package/dist/commands/config.js +56 -0
  14. package/dist/commands/config.js.map +1 -0
  15. package/dist/commands/init.d.ts +3 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +57 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/install.d.ts +3 -0
  20. package/dist/commands/install.d.ts.map +1 -0
  21. package/dist/commands/install.js +109 -0
  22. package/dist/commands/install.js.map +1 -0
  23. package/dist/commands/list.d.ts +3 -0
  24. package/dist/commands/list.d.ts.map +1 -0
  25. package/dist/commands/list.js +117 -0
  26. package/dist/commands/list.js.map +1 -0
  27. package/dist/commands/remove.d.ts +3 -0
  28. package/dist/commands/remove.d.ts.map +1 -0
  29. package/dist/commands/remove.js +74 -0
  30. package/dist/commands/remove.js.map +1 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +51 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/services/config-manager.d.ts +88 -0
  36. package/dist/services/config-manager.d.ts.map +1 -0
  37. package/dist/services/config-manager.js +143 -0
  38. package/dist/services/config-manager.js.map +1 -0
  39. package/dist/services/git-resolver.d.ts +139 -0
  40. package/dist/services/git-resolver.d.ts.map +1 -0
  41. package/dist/services/git-resolver.js +334 -0
  42. package/dist/services/git-resolver.js.map +1 -0
  43. package/dist/services/installer.d.ts +98 -0
  44. package/dist/services/installer.d.ts.map +1 -0
  45. package/dist/services/installer.js +274 -0
  46. package/dist/services/installer.js.map +1 -0
  47. package/dist/services/registry-client.d.ts +27 -0
  48. package/dist/services/registry-client.d.ts.map +1 -0
  49. package/dist/services/registry-client.js +134 -0
  50. package/dist/services/registry-client.js.map +1 -0
  51. package/dist/types/config.d.ts +17 -0
  52. package/dist/types/config.d.ts.map +1 -0
  53. package/dist/types/config.js +3 -0
  54. package/dist/types/config.js.map +1 -0
  55. package/dist/types/craftdesk-json.d.ts +42 -0
  56. package/dist/types/craftdesk-json.d.ts.map +1 -0
  57. package/dist/types/craftdesk-json.js +3 -0
  58. package/dist/types/craftdesk-json.js.map +1 -0
  59. package/dist/types/craftdesk-lock.d.ts +34 -0
  60. package/dist/types/craftdesk-lock.d.ts.map +1 -0
  61. package/dist/types/craftdesk-lock.js +3 -0
  62. package/dist/types/craftdesk-lock.js.map +1 -0
  63. package/dist/utils/file-system.d.ts +10 -0
  64. package/dist/utils/file-system.d.ts.map +1 -0
  65. package/dist/utils/file-system.js +60 -0
  66. package/dist/utils/file-system.js.map +1 -0
  67. package/dist/utils/logger.d.ts +18 -0
  68. package/dist/utils/logger.d.ts.map +1 -0
  69. package/dist/utils/logger.js +72 -0
  70. package/dist/utils/logger.js.map +1 -0
  71. package/docs/DEPENDENCY_RESOLUTION.md +237 -0
  72. package/examples/craftdesk-all-sources.json +79 -0
  73. package/examples/craftdesk-git-monorepo.json +41 -0
  74. package/examples/craftdesk-multi-registry.json +40 -0
  75. package/examples/craftdesk-with-registries.json +49 -0
  76. package/examples/simple-craftdesk.json +10 -0
  77. package/package.json +32 -25
  78. package/src/commands/add.ts +314 -0
  79. package/src/commands/init.ts +55 -0
  80. package/src/commands/install.ts +126 -0
  81. package/src/commands/list.ts +126 -0
  82. package/src/commands/remove.ts +82 -0
  83. package/src/index.ts +56 -0
  84. package/src/services/config-manager.ts +150 -0
  85. package/src/services/git-resolver.ts +370 -0
  86. package/src/services/installer.ts +314 -0
  87. package/src/services/registry-client.ts +163 -0
  88. package/src/types/craftdesk-json.ts +53 -0
  89. package/src/types/craftdesk-lock.ts +38 -0
  90. package/src/utils/file-system.ts +55 -0
  91. package/src/utils/logger.ts +82 -0
  92. package/tests/fixtures/craftdesk-git.json +17 -0
  93. package/tests/fixtures/craftdesk.json +15 -0
  94. package/tests/helpers/test-utils.ts +60 -0
  95. package/tests/integration/init-command.test.ts +70 -0
  96. package/tests/integration/list-command.test.ts +77 -0
  97. package/tests/unit/config-manager.test.ts +228 -0
  98. package/tests/unit/git-resolver.test.ts +303 -0
  99. package/tests/unit/installer.test.ts +105 -0
  100. package/tsconfig.json +20 -0
  101. package/vitest.config.ts +29 -0
  102. package/LICENSE +0 -21
  103. 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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"}