skillfish 1.0.7 → 1.0.8

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.
@@ -21,7 +21,7 @@ export interface InstallResult {
21
21
  export interface InstallOptions {
22
22
  force: boolean;
23
23
  baseDir: string;
24
- /** Branch to clone from. If not specified, degit will use default branch detection. */
24
+ /** Branch to clone from. If not specified, giget will use the repository's default branch. */
25
25
  branch?: string;
26
26
  }
27
27
  export interface CopyResult {
@@ -6,18 +6,18 @@ import { existsSync, mkdirSync, cpSync, rmSync, lstatSync, readdirSync, } from '
6
6
  import { homedir } from 'os';
7
7
  import { join } from 'path';
8
8
  import { randomUUID } from 'crypto';
9
- import degit from 'degit';
9
+ import { downloadTemplate } from 'giget';
10
10
  import { SKILL_FILENAME } from './github.js';
11
11
  /**
12
- * Validates a branch name for safe use in degit paths.
12
+ * Validates a branch name for safe use in giget source strings.
13
13
  * Git branch names can contain alphanumerics, dots, hyphens, underscores, and slashes.
14
- * We explicitly reject '#' which is used as a delimiter in degit syntax.
14
+ * We explicitly reject '#' which is used as a delimiter in giget syntax.
15
15
  */
16
16
  function isValidBranchName(branch) {
17
17
  if (!branch || branch.length > 255)
18
18
  return false;
19
19
  // Allow alphanumerics, dots, hyphens, underscores, and slashes (for feature branches)
20
- // Reject anything else, especially '#' which would break degit parsing
20
+ // Reject anything else, especially '#' which would break giget parsing
21
21
  return /^[\w./-]+$/.test(branch) && !branch.includes('#');
22
22
  }
23
23
  // === Error Types ===
@@ -102,20 +102,24 @@ export async function installSkill(owner, repo, skillPath, skillName, agents, op
102
102
  const tmpDir = join(homedir(), '.cache', 'skillfish', `${owner}-${repo}-${randomUUID()}`);
103
103
  mkdirSync(tmpDir, { recursive: true, mode: 0o700 });
104
104
  try {
105
- // Download skill
106
- // Build degit path: owner/repo[/subpath][#branch]
105
+ // Download skill using giget (tarball-based, works reliably on all repo sizes)
106
+ // Build giget source: github:owner/repo[/subpath][#branch]
107
107
  const downloadPath = skillPath === SKILL_FILENAME ? '' : skillPath;
108
- let degitPath = downloadPath ? `${owner}/${repo}/${downloadPath}` : `${owner}/${repo}`;
108
+ let source = downloadPath
109
+ ? `github:${owner}/${repo}/${downloadPath}`
110
+ : `github:${owner}/${repo}`;
109
111
  // Append branch if specified (critical for repos with non-standard default branches like 'canary')
110
112
  // Validate branch name to prevent injection attacks via malformed branch names
111
113
  if (branch) {
112
114
  if (!isValidBranchName(branch)) {
113
115
  throw new Error(`Invalid branch name: ${branch}`);
114
116
  }
115
- degitPath = `${degitPath}#${branch}`;
117
+ source = `${source}#${branch}`;
116
118
  }
117
- const emitter = degit(degitPath, { cache: false, force: true });
118
- await emitter.clone(tmpDir);
119
+ await downloadTemplate(source, {
120
+ dir: tmpDir,
121
+ forceClean: true,
122
+ });
119
123
  // Validate download
120
124
  const skillMdPath = join(tmpDir, SKILL_FILENAME);
121
125
  if (!existsSync(skillMdPath)) {
@@ -154,13 +158,8 @@ export async function installSkill(owner, repo, skillPath, skillName, agents, op
154
158
  }
155
159
  else {
156
160
  const errMsg = err instanceof Error ? err.message : String(err);
157
- // Provide more helpful error messages for common degit failures
158
- // Match "could not find commit hash for HEAD" or "could not find commit hash for <branch>"
159
- if (errMsg.includes('could not find commit hash')) {
160
- const branchInfo = branch ? ` (branch: ${branch})` : '';
161
- result.failureReason = `Could not clone repository. The branch or path may not exist, or there may be a network issue. Tried: ${owner}/${repo}${skillPath !== SKILL_FILENAME ? `/${skillPath}` : ''}${branchInfo}`;
162
- }
163
- else if (errMsg.includes('404')) {
161
+ // Provide more helpful error messages for common failures
162
+ if (errMsg.includes('404') || errMsg.includes('Not Found')) {
164
163
  result.failureReason = `Repository or path not found: ${owner}/${repo}${skillPath !== SKILL_FILENAME ? `/${skillPath}` : ''}`;
165
164
  }
166
165
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillfish",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Install AI agent skills from GitHub with a single command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,7 +57,7 @@
57
57
  "dependencies": {
58
58
  "@clack/prompts": "^0.11.0",
59
59
  "commander": "^14.0.2",
60
- "degit": "^2.8.4",
60
+ "giget": "^3.1.1",
61
61
  "picocolors": "^1.1.1"
62
62
  },
63
63
  "devDependencies": {