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
package/TESTING.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The CraftDesk CLI uses **Vitest** as its testing framework, providing fast and modern testing capabilities with TypeScript support.
|
|
6
|
+
|
|
7
|
+
## Test Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
tests/
|
|
11
|
+
├── unit/ # Unit tests for individual modules
|
|
12
|
+
│ ├── config-manager.test.ts
|
|
13
|
+
│ ├── git-resolver.test.ts
|
|
14
|
+
│ └── installer.test.ts
|
|
15
|
+
├── integration/ # Integration tests for CLI commands
|
|
16
|
+
│ ├── init-command.test.ts
|
|
17
|
+
│ └── list-command.test.ts
|
|
18
|
+
├── fixtures/ # Test fixtures and mock data
|
|
19
|
+
│ ├── craftdesk.json
|
|
20
|
+
│ └── craftdesk-git.json
|
|
21
|
+
└── helpers/ # Test utilities
|
|
22
|
+
└── test-utils.ts
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Running Tests
|
|
26
|
+
|
|
27
|
+
### Run all tests
|
|
28
|
+
```bash
|
|
29
|
+
npm test
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Run tests in watch mode
|
|
33
|
+
```bash
|
|
34
|
+
npm run test:watch
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Run tests with coverage
|
|
38
|
+
```bash
|
|
39
|
+
npm run test:coverage
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Run tests with UI
|
|
43
|
+
```bash
|
|
44
|
+
npm run test:ui
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Test Coverage
|
|
48
|
+
|
|
49
|
+
Coverage reports are generated using Vitest's built-in coverage tool (v8 provider).
|
|
50
|
+
|
|
51
|
+
### Viewing Coverage
|
|
52
|
+
|
|
53
|
+
After running `npm run test:coverage`, view the report:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Terminal summary is displayed automatically
|
|
57
|
+
|
|
58
|
+
# Open HTML report in browser
|
|
59
|
+
open coverage/index.html
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Coverage Thresholds
|
|
63
|
+
|
|
64
|
+
Current coverage configuration in `vitest.config.ts`:
|
|
65
|
+
- Excludes: `node_modules/`, `dist/`, `bin/`, test files
|
|
66
|
+
|
|
67
|
+
## Writing Tests
|
|
68
|
+
|
|
69
|
+
### Unit Tests
|
|
70
|
+
|
|
71
|
+
Unit tests focus on testing individual functions and classes in isolation.
|
|
72
|
+
|
|
73
|
+
**Example: Testing ConfigManager**
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
77
|
+
import { ConfigManager } from '../../src/services/config-manager';
|
|
78
|
+
import { createTempDir, cleanupTempDir } from '../helpers/test-utils';
|
|
79
|
+
|
|
80
|
+
describe('ConfigManager', () => {
|
|
81
|
+
let configManager: ConfigManager;
|
|
82
|
+
let tempDir: string;
|
|
83
|
+
|
|
84
|
+
beforeEach(async () => {
|
|
85
|
+
configManager = new ConfigManager();
|
|
86
|
+
tempDir = await createTempDir('config-test-');
|
|
87
|
+
process.chdir(tempDir);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(async () => {
|
|
91
|
+
await cleanupTempDir(tempDir);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should return default registry when no craftdesk.json exists', async () => {
|
|
95
|
+
const registry = await configManager.getRegistryForPackage('test-package');
|
|
96
|
+
expect(registry).toBe('https://craftdesk.ai');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Integration Tests
|
|
102
|
+
|
|
103
|
+
Integration tests verify that CLI commands work correctly end-to-end.
|
|
104
|
+
|
|
105
|
+
**Example: Testing CLI Commands**
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { execSync } from 'child_process';
|
|
109
|
+
import path from 'path';
|
|
110
|
+
|
|
111
|
+
describe('craftdesk init command', () => {
|
|
112
|
+
const cliPath = path.join(__dirname, '../../dist/index.js');
|
|
113
|
+
|
|
114
|
+
it('should create a new craftdesk.json file', () => {
|
|
115
|
+
execSync(`node ${cliPath} init --name test --version 1.0.0 --type skill`);
|
|
116
|
+
|
|
117
|
+
const exists = await fs.pathExists('craftdesk.json');
|
|
118
|
+
expect(exists).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Test Utilities
|
|
124
|
+
|
|
125
|
+
The `tests/helpers/test-utils.ts` file provides helper functions:
|
|
126
|
+
|
|
127
|
+
- `createTempDir(prefix)` - Creates a temporary test directory
|
|
128
|
+
- `cleanupTempDir(dirPath)` - Removes a temporary directory
|
|
129
|
+
- `copyFixture(name, targetDir)` - Copies a fixture file
|
|
130
|
+
- `readJsonFile(path)` - Reads and parses JSON file
|
|
131
|
+
- `writeJsonFile(path, data)` - Writes JSON to file
|
|
132
|
+
- `createMockCraftInfo(name, version)` - Creates mock craft metadata
|
|
133
|
+
|
|
134
|
+
### Mocking
|
|
135
|
+
|
|
136
|
+
Use Vitest's built-in mocking for external dependencies:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { vi } from 'vitest';
|
|
140
|
+
import { execSync } from 'child_process';
|
|
141
|
+
|
|
142
|
+
vi.mock('child_process', () => ({
|
|
143
|
+
execSync: vi.fn()
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
// In your test
|
|
147
|
+
const mockExecSync = vi.mocked(execSync);
|
|
148
|
+
mockExecSync.mockReturnValue(Buffer.from('output'));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## CI/CD Integration
|
|
152
|
+
|
|
153
|
+
### GitHub Actions
|
|
154
|
+
|
|
155
|
+
The `.github/workflows/ci.yml` file runs tests automatically on:
|
|
156
|
+
- Push to main/master/develop branches
|
|
157
|
+
- Pull requests to main/master/develop branches
|
|
158
|
+
|
|
159
|
+
The workflow:
|
|
160
|
+
1. Tests on Node.js 16.x, 18.x, and 20.x
|
|
161
|
+
2. Generates coverage report (Node 20.x only)
|
|
162
|
+
3. Uploads coverage to Codecov
|
|
163
|
+
4. Verifies TypeScript compilation
|
|
164
|
+
5. Builds the project
|
|
165
|
+
|
|
166
|
+
### Local CI Simulation
|
|
167
|
+
|
|
168
|
+
Run the same checks locally before pushing:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Run tests
|
|
172
|
+
npm test
|
|
173
|
+
|
|
174
|
+
# Generate coverage
|
|
175
|
+
npm run test:coverage
|
|
176
|
+
|
|
177
|
+
# Type check
|
|
178
|
+
npx tsc --noEmit
|
|
179
|
+
|
|
180
|
+
# Build
|
|
181
|
+
npm run build
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Test Best Practices
|
|
185
|
+
|
|
186
|
+
### 1. Isolation
|
|
187
|
+
- Each test should be independent
|
|
188
|
+
- Use `beforeEach` and `afterEach` for setup/teardown
|
|
189
|
+
- Clean up temporary files and directories
|
|
190
|
+
|
|
191
|
+
### 2. Descriptive Names
|
|
192
|
+
```typescript
|
|
193
|
+
// Good
|
|
194
|
+
it('should return scoped registry for scoped package')
|
|
195
|
+
|
|
196
|
+
// Bad
|
|
197
|
+
it('test1')
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 3. Arrange-Act-Assert Pattern
|
|
201
|
+
```typescript
|
|
202
|
+
it('should parse git URL with branch', () => {
|
|
203
|
+
// Arrange
|
|
204
|
+
const url = 'https://github.com/user/repo.git#main';
|
|
205
|
+
|
|
206
|
+
// Act
|
|
207
|
+
const result = parseGitUrl(url);
|
|
208
|
+
|
|
209
|
+
// Assert
|
|
210
|
+
expect(result.branch).toBe('main');
|
|
211
|
+
expect(result.url).toBe('https://github.com/user/repo.git');
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 4. Test Edge Cases
|
|
216
|
+
- Empty inputs
|
|
217
|
+
- Invalid data
|
|
218
|
+
- Error conditions
|
|
219
|
+
- Boundary values
|
|
220
|
+
|
|
221
|
+
### 5. Mock External Dependencies
|
|
222
|
+
- File system operations (when appropriate)
|
|
223
|
+
- Network requests
|
|
224
|
+
- Child processes
|
|
225
|
+
- Environment variables
|
|
226
|
+
|
|
227
|
+
## Debugging Tests
|
|
228
|
+
|
|
229
|
+
### Run specific test file
|
|
230
|
+
```bash
|
|
231
|
+
npm test tests/unit/config-manager.test.ts
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Run tests matching pattern
|
|
235
|
+
```bash
|
|
236
|
+
npm test -- --grep "git dependency"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Debug with breakpoints
|
|
240
|
+
```bash
|
|
241
|
+
node --inspect-brk ./node_modules/.bin/vitest run
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Then attach your debugger (VS Code, Chrome DevTools, etc.)
|
|
245
|
+
|
|
246
|
+
## Continuous Improvement
|
|
247
|
+
|
|
248
|
+
### Coverage Goals
|
|
249
|
+
- Maintain >80% code coverage
|
|
250
|
+
- Focus on critical paths first
|
|
251
|
+
- Add tests when fixing bugs
|
|
252
|
+
|
|
253
|
+
### Test Maintenance
|
|
254
|
+
- Update tests when changing functionality
|
|
255
|
+
- Remove obsolete tests
|
|
256
|
+
- Keep test data fixtures up to date
|
|
257
|
+
- Review test failures in CI promptly
|
|
258
|
+
|
|
259
|
+
## Resources
|
|
260
|
+
|
|
261
|
+
- [Vitest Documentation](https://vitest.dev/)
|
|
262
|
+
- [Testing Library Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
|
263
|
+
- [Effective Testing Strategies](https://martinfowler.com/articles/practical-test-pyramid.html)
|
package/bin/craftdesk.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,gBAAgB,IAAI,OAAO,CAW1C"}
|
|
@@ -0,0 +1,284 @@
|
|
|
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.createAddCommand = createAddCommand;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const file_system_1 = require("../utils/file-system");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const registry_client_1 = require("../services/registry-client");
|
|
12
|
+
const installer_1 = require("../services/installer");
|
|
13
|
+
const git_resolver_1 = require("../services/git-resolver");
|
|
14
|
+
function createAddCommand() {
|
|
15
|
+
return new commander_1.Command('add')
|
|
16
|
+
.description('Add a new dependency and install it')
|
|
17
|
+
.argument('<craft>', 'Craft name (e.g., ruby-on-rails or @acme/patterns)')
|
|
18
|
+
.option('-D, --save-dev', 'Save as devDependency')
|
|
19
|
+
.option('-O, --save-optional', 'Save as optionalDependency')
|
|
20
|
+
.option('-E, --save-exact', 'Save exact version')
|
|
21
|
+
.option('-t, --type <type>', 'Specify craft type (skill, agent, command, hook)')
|
|
22
|
+
.action(async (craftArg, options) => {
|
|
23
|
+
await addCommand(craftArg, options);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async function addCommand(craftArg, options) {
|
|
27
|
+
try {
|
|
28
|
+
// Read craftdesk.json
|
|
29
|
+
const craftDeskJson = await (0, file_system_1.readCraftDeskJson)();
|
|
30
|
+
if (!craftDeskJson) {
|
|
31
|
+
logger_1.logger.error('No craftdesk.json found in current directory');
|
|
32
|
+
logger_1.logger.info('Run "craftdesk init" to create one');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
// Parse craft name and version
|
|
36
|
+
let craftName;
|
|
37
|
+
let versionConstraint = '*';
|
|
38
|
+
if (craftArg.includes('@') && !craftArg.startsWith('@')) {
|
|
39
|
+
// Format: craft@version
|
|
40
|
+
const parts = craftArg.split('@');
|
|
41
|
+
craftName = parts[0];
|
|
42
|
+
versionConstraint = parts[1];
|
|
43
|
+
}
|
|
44
|
+
else if (craftArg.startsWith('@')) {
|
|
45
|
+
// Scoped craft: @scope/craft or @scope/craft@version
|
|
46
|
+
const afterScope = craftArg.substring(craftArg.indexOf('/') + 1);
|
|
47
|
+
if (afterScope.includes('@')) {
|
|
48
|
+
const parts = craftArg.split('@');
|
|
49
|
+
craftName = `${parts[0]}@${parts[1]}`;
|
|
50
|
+
versionConstraint = parts[2];
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
craftName = craftArg;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
craftName = craftArg;
|
|
58
|
+
}
|
|
59
|
+
logger_1.logger.info(`Adding ${craftName}...`);
|
|
60
|
+
// Check if this is a git dependency
|
|
61
|
+
let depValue;
|
|
62
|
+
let lockEntry;
|
|
63
|
+
let displayInfo;
|
|
64
|
+
// Convert GitHub web URLs to git URLs automatically
|
|
65
|
+
const normalizedArg = normalizeGitHubUrl(craftArg);
|
|
66
|
+
if (normalizedArg.startsWith('git+') || normalizedArg.includes('.git')) {
|
|
67
|
+
// Handle git dependency
|
|
68
|
+
logger_1.logger.startSpinner('Analyzing git dependency...');
|
|
69
|
+
const gitInfo = parseGitUrl(normalizedArg);
|
|
70
|
+
// Resolve the git dependency to get its craftdesk.json and dependencies
|
|
71
|
+
const resolvedGit = await git_resolver_1.gitResolver.resolveGitDependency({
|
|
72
|
+
url: gitInfo.url,
|
|
73
|
+
branch: gitInfo.branch,
|
|
74
|
+
tag: gitInfo.tag,
|
|
75
|
+
commit: gitInfo.commit,
|
|
76
|
+
path: gitInfo.path,
|
|
77
|
+
file: gitInfo.file
|
|
78
|
+
});
|
|
79
|
+
depValue = {
|
|
80
|
+
git: gitInfo.url,
|
|
81
|
+
...(gitInfo.branch && { branch: gitInfo.branch }),
|
|
82
|
+
...(gitInfo.tag && { tag: gitInfo.tag }),
|
|
83
|
+
...(gitInfo.path && { path: gitInfo.path }),
|
|
84
|
+
...(gitInfo.file && { file: gitInfo.file })
|
|
85
|
+
};
|
|
86
|
+
// Use resolved information for the lock entry
|
|
87
|
+
const craftJson = resolvedGit.craftDeskJson;
|
|
88
|
+
// Determine type: explicit option > craftdesk.json > inferred > default
|
|
89
|
+
const craftType = options.type || craftJson?.type || 'skill';
|
|
90
|
+
lockEntry = {
|
|
91
|
+
version: craftJson?.version || gitInfo.tag || gitInfo.branch || 'HEAD',
|
|
92
|
+
resolved: gitInfo.url,
|
|
93
|
+
integrity: resolvedGit.resolvedCommit || 'git',
|
|
94
|
+
type: craftType,
|
|
95
|
+
author: craftJson?.author || 'git',
|
|
96
|
+
git: gitInfo.url,
|
|
97
|
+
...(gitInfo.branch && { branch: gitInfo.branch }),
|
|
98
|
+
...(gitInfo.tag && { tag: gitInfo.tag }),
|
|
99
|
+
...(resolvedGit.resolvedCommit && { commit: resolvedGit.resolvedCommit }),
|
|
100
|
+
...(gitInfo.path && { path: gitInfo.path }),
|
|
101
|
+
...(gitInfo.file && { file: gitInfo.file }),
|
|
102
|
+
dependencies: craftJson?.dependencies || {}
|
|
103
|
+
};
|
|
104
|
+
craftName = craftJson?.name || gitInfo.name || path_1.default.basename(gitInfo.url, '.git');
|
|
105
|
+
displayInfo = `${craftName}@${craftJson?.version || 'git'} from ${gitInfo.url}`;
|
|
106
|
+
logger_1.logger.succeedSpinner(`Resolved git dependency: ${displayInfo}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Regular registry dependency
|
|
110
|
+
logger_1.logger.startSpinner('Fetching craft information...');
|
|
111
|
+
// Check if the dependency has custom registry info in craftdesk.json
|
|
112
|
+
let registryOverride;
|
|
113
|
+
const existingDep = craftDeskJson.dependencies?.[craftName];
|
|
114
|
+
if (existingDep && typeof existingDep === 'object' && 'registry' in existingDep) {
|
|
115
|
+
registryOverride = existingDep.registry;
|
|
116
|
+
}
|
|
117
|
+
// Get craft info from registry
|
|
118
|
+
const craftInfo = await registry_client_1.registryClient.getCraftInfo(craftName, undefined, registryOverride);
|
|
119
|
+
if (!craftInfo) {
|
|
120
|
+
logger_1.logger.failSpinner(`Craft '${craftName}' not found`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
logger_1.logger.succeedSpinner(`Found ${craftInfo.name}@${craftInfo.version}`);
|
|
124
|
+
const version = options.saveExact ? craftInfo.version : versionConstraint;
|
|
125
|
+
depValue = version;
|
|
126
|
+
lockEntry = {
|
|
127
|
+
version: craftInfo.version,
|
|
128
|
+
resolved: craftInfo.download_url || `http://localhost:3000/api/v1/crafts/${craftInfo.author}/${craftInfo.name}/versions/${craftInfo.version}/download`,
|
|
129
|
+
integrity: craftInfo.integrity || 'sha256-placeholder',
|
|
130
|
+
type: craftInfo.type,
|
|
131
|
+
author: craftInfo.author,
|
|
132
|
+
dependencies: craftInfo.dependencies || {}
|
|
133
|
+
};
|
|
134
|
+
displayInfo = `${craftInfo.name}@${craftInfo.version}`;
|
|
135
|
+
}
|
|
136
|
+
// Determine which dependency field to use
|
|
137
|
+
let depField;
|
|
138
|
+
if (options.saveDev) {
|
|
139
|
+
depField = 'devDependencies';
|
|
140
|
+
}
|
|
141
|
+
else if (options.saveOptional) {
|
|
142
|
+
depField = 'optionalDependencies';
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
depField = 'dependencies';
|
|
146
|
+
}
|
|
147
|
+
// Initialize field if it doesn't exist
|
|
148
|
+
if (!craftDeskJson[depField]) {
|
|
149
|
+
craftDeskJson[depField] = {};
|
|
150
|
+
}
|
|
151
|
+
// Add to craftdesk.json
|
|
152
|
+
craftDeskJson[depField][craftName] = depValue;
|
|
153
|
+
// Save craftdesk.json
|
|
154
|
+
await (0, file_system_1.writeCraftDeskJson)(craftDeskJson);
|
|
155
|
+
const displayVersion = typeof depValue === 'string' ? depValue : (depValue.tag || depValue.branch || 'git');
|
|
156
|
+
logger_1.logger.success(`Added ${craftName}@${displayVersion} to ${depField}`);
|
|
157
|
+
// Install the craft
|
|
158
|
+
logger_1.logger.startSpinner(`Installing ${craftName}...`);
|
|
159
|
+
await installer_1.installer.installCraft(craftName, lockEntry);
|
|
160
|
+
logger_1.logger.succeedSpinner(`Installed ${displayInfo}`);
|
|
161
|
+
// Update craftdesk.lock
|
|
162
|
+
let lockfile = await (0, file_system_1.readCraftDeskLock)();
|
|
163
|
+
if (!lockfile) {
|
|
164
|
+
lockfile = {
|
|
165
|
+
version: '1.0.0',
|
|
166
|
+
lockfileVersion: 1,
|
|
167
|
+
generatedAt: new Date().toISOString(),
|
|
168
|
+
crafts: {}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
// Add or update the craft in the lockfile
|
|
172
|
+
lockfile.crafts[craftName] = lockEntry;
|
|
173
|
+
await (0, file_system_1.writeCraftDeskLock)(lockfile);
|
|
174
|
+
logger_1.logger.success('Craft added successfully!');
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
logger_1.logger.failSpinner();
|
|
178
|
+
logger_1.logger.error(`Failed to add craft: ${error.message}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Converts GitHub web URLs to git URL format
|
|
184
|
+
*
|
|
185
|
+
* Supported GitHub URL formats:
|
|
186
|
+
* - https://github.com/user/repo/tree/branch/path/to/dir
|
|
187
|
+
* - https://github.com/user/repo/blob/branch/path/to/file.md
|
|
188
|
+
* - https://github.com/user/repo (assumes main branch)
|
|
189
|
+
*
|
|
190
|
+
* @param url - The GitHub URL (web or git format)
|
|
191
|
+
* @returns Normalized git URL with #branch#path: or #branch#file: syntax
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
function normalizeGitHubUrl(url) {
|
|
195
|
+
// Already in git+ format, return as-is
|
|
196
|
+
if (url.startsWith('git+')) {
|
|
197
|
+
return url;
|
|
198
|
+
}
|
|
199
|
+
// Already a .git URL, return as-is
|
|
200
|
+
if (url.endsWith('.git') || url.includes('.git#')) {
|
|
201
|
+
return url;
|
|
202
|
+
}
|
|
203
|
+
// Check if it's a GitHub web URL
|
|
204
|
+
const githubTreeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
|
|
205
|
+
const githubBlobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
|
|
206
|
+
const githubRepoMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/?$/);
|
|
207
|
+
if (githubTreeMatch) {
|
|
208
|
+
// Tree URL: directory reference
|
|
209
|
+
const [, owner, repo, branch, path] = githubTreeMatch;
|
|
210
|
+
return `git+https://github.com/${owner}/${repo}.git#${branch}#path:${path}`;
|
|
211
|
+
}
|
|
212
|
+
else if (githubBlobMatch) {
|
|
213
|
+
// Blob URL: file reference
|
|
214
|
+
const [, owner, repo, branch, file] = githubBlobMatch;
|
|
215
|
+
return `git+https://github.com/${owner}/${repo}.git#${branch}#file:${file}`;
|
|
216
|
+
}
|
|
217
|
+
else if (githubRepoMatch) {
|
|
218
|
+
// Repo URL without tree/blob: clone entire repo
|
|
219
|
+
const [, owner, repo] = githubRepoMatch;
|
|
220
|
+
return `git+https://github.com/${owner}/${repo}.git`;
|
|
221
|
+
}
|
|
222
|
+
// Not a recognized GitHub URL, return as-is
|
|
223
|
+
return url;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Parses a git URL with optional ref and subdirectory/file specifiers
|
|
227
|
+
*
|
|
228
|
+
* Supported formats:
|
|
229
|
+
* - git+https://github.com/user/repo.git#branch
|
|
230
|
+
* - git+https://github.com/user/repo.git#v1.0.0
|
|
231
|
+
* - git+https://github.com/user/repo.git#commit-hash
|
|
232
|
+
* - git+https://github.com/user/repo.git#path:subfolder/skill
|
|
233
|
+
* - git+https://github.com/user/repo.git#file:skill.md
|
|
234
|
+
* - git+https://github.com/user/repo.git#main#file:rspec-agent.md
|
|
235
|
+
* - https://github.com/user/repo.git
|
|
236
|
+
*
|
|
237
|
+
* @param urlString - The git URL to parse
|
|
238
|
+
* @returns Parsed git dependency information
|
|
239
|
+
* @private
|
|
240
|
+
*/
|
|
241
|
+
function parseGitUrl(urlString) {
|
|
242
|
+
// Remove optional git+ prefix (npm-style format)
|
|
243
|
+
let url = urlString.replace(/^git\+/, '');
|
|
244
|
+
const result = {};
|
|
245
|
+
// Extract direct file path (e.g., #file:rspec-agent.md)
|
|
246
|
+
if (url.includes('#file:')) {
|
|
247
|
+
const [baseUrl, filePart] = url.split('#file:');
|
|
248
|
+
url = baseUrl;
|
|
249
|
+
result.file = filePart;
|
|
250
|
+
}
|
|
251
|
+
// Extract subdirectory path for monorepos (e.g., #path:crafts/auth)
|
|
252
|
+
if (url.includes('#path:')) {
|
|
253
|
+
const [baseUrl, pathPart] = url.split('#path:');
|
|
254
|
+
url = baseUrl;
|
|
255
|
+
result.path = pathPart;
|
|
256
|
+
}
|
|
257
|
+
// Extract git reference (branch/tag/commit)
|
|
258
|
+
// Must be parsed after path and file to avoid conflicts
|
|
259
|
+
if (url.includes('#') && !url.includes('#path:') && !url.includes('#file:')) {
|
|
260
|
+
const [baseUrl, ref] = url.split('#');
|
|
261
|
+
url = baseUrl;
|
|
262
|
+
// Heuristic to determine ref type:
|
|
263
|
+
// - Tags typically start with 'v' or match semver pattern (1.0.0)
|
|
264
|
+
if (ref.startsWith('v') || /^\d+\.\d+/.test(ref)) {
|
|
265
|
+
result.tag = ref;
|
|
266
|
+
}
|
|
267
|
+
// - Commit hashes are 40-character hex strings
|
|
268
|
+
else if (ref.length === 40 && /^[a-f0-9]+$/.test(ref)) {
|
|
269
|
+
result.commit = ref;
|
|
270
|
+
}
|
|
271
|
+
// - Otherwise, assume it's a branch name
|
|
272
|
+
else {
|
|
273
|
+
result.branch = ref;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
result.url = url;
|
|
277
|
+
// Extract repository name from URL for display purposes
|
|
278
|
+
const match = url.match(/\/([^/]+?)(\.git)?$/);
|
|
279
|
+
if (match) {
|
|
280
|
+
result.name = match[1];
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,IAAI,OAAO,CAiD7C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createConfigCommand = createConfigCommand;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const config_manager_1 = require("../services/config-manager");
|
|
6
|
+
const logger_1 = require("../utils/logger");
|
|
7
|
+
function createConfigCommand() {
|
|
8
|
+
const config = new commander_1.Command('config')
|
|
9
|
+
.description('Manage CraftDesk CLI configuration');
|
|
10
|
+
config
|
|
11
|
+
.command('list')
|
|
12
|
+
.description('List all configuration values')
|
|
13
|
+
.action(async () => {
|
|
14
|
+
await config_manager_1.configManager.list();
|
|
15
|
+
});
|
|
16
|
+
config
|
|
17
|
+
.command('get <key>')
|
|
18
|
+
.description('Get a configuration value')
|
|
19
|
+
.action(async (key) => {
|
|
20
|
+
const value = await config_manager_1.configManager.get(key);
|
|
21
|
+
if (value !== undefined) {
|
|
22
|
+
logger_1.logger.log(value);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
logger_1.logger.error(`Configuration key '${key}' not found`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
config
|
|
30
|
+
.command('set <key> <value>')
|
|
31
|
+
.description('Set a configuration value')
|
|
32
|
+
.action(async (key, value) => {
|
|
33
|
+
// Handle special cases
|
|
34
|
+
if (key.includes(':registry')) {
|
|
35
|
+
// Setting a scoped registry
|
|
36
|
+
// e.g., @acme:registry -> scopes.@acme
|
|
37
|
+
const scope = key.split(':')[0];
|
|
38
|
+
await config_manager_1.configManager.set(`scopes.${scope}`, value);
|
|
39
|
+
logger_1.logger.success(`Set registry for ${scope} to ${value}`);
|
|
40
|
+
}
|
|
41
|
+
else if (key.startsWith('//') && key.includes('/:token')) {
|
|
42
|
+
// Setting auth token
|
|
43
|
+
// e.g., //crafts.acme.com/:token -> auth.crafts.acme.com.token
|
|
44
|
+
const host = key.substring(2, key.indexOf('/:'));
|
|
45
|
+
await config_manager_1.configManager.set(`auth.${host}.token`, value);
|
|
46
|
+
logger_1.logger.success(`Set auth token for ${host}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Normal key-value
|
|
50
|
+
await config_manager_1.configManager.set(key, value);
|
|
51
|
+
logger_1.logger.success(`Set ${key} to ${value}`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":";;AAIA,kDAiDC;AArDD,yCAAoC;AACpC,+DAA2D;AAC3D,4CAAyC;AAEzC,SAAgB,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;SACjC,WAAW,CAAC,oCAAoC,CAAC,CAAC;IAErD,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,8BAAa,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,MAAM,8BAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,eAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,eAAM,CAAC,KAAK,CAAC,sBAAsB,GAAG,aAAa,CAAC,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,KAAa,EAAE,EAAE;QAC3C,uBAAuB;QACvB,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,4BAA4B;YAC5B,uCAAuC;YACvC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,8BAAa,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;YAClD,eAAM,CAAC,OAAO,CAAC,oBAAoB,KAAK,OAAO,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3D,qBAAqB;YACrB,+DAA+D;YAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACjD,MAAM,8BAAa,CAAC,GAAG,CAAC,QAAQ,IAAI,QAAQ,EAAE,KAAK,CAAC,CAAC;YACrD,eAAM,CAAC,OAAO,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,mBAAmB;YACnB,MAAM,8BAAa,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACpC,eAAM,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,iBAAiB,IAAI,OAAO,CAa3C"}
|