@akshar5/skillsync 0.1.1 → 0.1.2

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 (3) hide show
  1. package/README.md +8 -3
  2. package/package.json +1 -1
  3. package/src/cli.js +37 -17
package/README.md CHANGED
@@ -89,13 +89,18 @@ Connect to an existing vault:
89
89
  skillsync setup --repo AksharP5/skills
90
90
  ```
91
91
 
92
- Or create/select a vault repo under your GitHub account:
92
+ Or create/select a vault repo interactively:
93
93
 
94
94
  ```bash
95
- skillsync setup --name skills
95
+ skillsync setup
96
96
  ```
97
97
 
98
- If you run plain `skillsync setup` in an interactive terminal, it asks for the repo name and defaults to `skills`. `setup --name` creates `OWNER/skills` as a private GitHub repo if it does not exist. If it exists, SkillSync verifies it is private before using it.
98
+ If you run plain `skillsync setup` in an interactive terminal, it first asks which vault type to use:
99
+
100
+ - Choose `Use an existing GitHub repo`, then enter a repo like `AksharP5/skills`.
101
+ - Choose `Create or use OWNER/<name>`, then enter a repo name like `skills`.
102
+
103
+ `setup --name skills` is the non-interactive form of the second option. It creates `OWNER/skills` as a private GitHub repo if it does not exist. If it exists, SkillSync verifies it is private before using it.
99
104
 
100
105
  You can also run commands without a global install:
101
106
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akshar5/skillsync",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Local-first GitHub-backed skill vault sync client for AI agent skills.",
5
5
  "type": "module",
6
6
  "repository": {
package/src/cli.js CHANGED
@@ -97,12 +97,31 @@ async function resolveRepoCloneUrl(repo) {
97
97
  if (/^(git@|https?:\/\/|ssh:\/\/)/.test(repo)) return repo;
98
98
  if (!repo.includes('/')) return repo;
99
99
  if (!await commandExists('gh')) return repo;
100
+ return verifiedRepoCloneUrl(repo);
101
+ }
102
+
103
+ async function verifiedRepoCloneUrl(repo) {
100
104
  const { stdout } = await gh(['repo', 'view', repo, '--json', 'isPrivate,url', '--jq', '.']);
101
105
  const view = JSON.parse(stdout);
102
106
  if (!view.isPrivate) throw new Error(`${repo} exists but is not private. Make it private before using it as a skill vault.`);
103
107
  return view.url;
104
108
  }
105
109
 
110
+ async function ensureOwnedVaultRepo(owner, name) {
111
+ const repo = `${owner}/${name}`;
112
+ let repoExists = true;
113
+ try {
114
+ await gh(['repo', 'view', repo]);
115
+ } catch {
116
+ repoExists = false;
117
+ }
118
+ if (!repoExists) {
119
+ console.log(`Creating private GitHub repo ${repo}...`);
120
+ await gh(['repo', 'create', repo, '--private', '--description', 'Private AI agent skills vault'], undefined, { inherit: true });
121
+ }
122
+ return verifiedRepoCloneUrl(repo);
123
+ }
124
+
106
125
  async function setup(rest) {
107
126
  const yes = hasFlag(rest, '--yes') || hasFlag(rest, '-y');
108
127
  if (!await commandExists('git')) throw new Error('git is required');
@@ -119,24 +138,25 @@ async function setup(rest) {
119
138
  if (!repo) {
120
139
  const { stdout: ownerOut } = await gh(['api', 'user', '--jq', '.login']);
121
140
  const owner = ownerOut.trim();
122
- const name = flagValue(rest, '--name') || (yes || !process.stdin.isTTY
123
- ? 'skills'
124
- : await input({ message: 'GitHub skills vault repo name:', default: 'skills' }));
125
- repo = `${owner}/${name}`;
126
- let repoExists = true;
127
- try {
128
- await gh(['repo', 'view', repo]);
129
- } catch {
130
- repoExists = false;
131
- }
132
- if (!repoExists) {
133
- console.log(`Creating private GitHub repo ${repo}...`);
134
- await gh(['repo', 'create', repo, '--private', '--description', 'Private AI agent skills vault'], undefined, { inherit: true });
141
+ const nameArg = flagValue(rest, '--name');
142
+ if (nameArg || yes || !process.stdin.isTTY) {
143
+ repo = await ensureOwnedVaultRepo(owner, nameArg || 'skills');
144
+ } else {
145
+ const setupMode = await select({
146
+ message: 'Which skills vault do you want to use?',
147
+ choices: [
148
+ { name: 'Use an existing GitHub repo', value: 'existing' },
149
+ { name: `Create or use ${owner}/<name>`, value: 'owned' },
150
+ ],
151
+ });
152
+ if (setupMode === 'existing') {
153
+ const existingRepo = await input({ message: 'Existing vault repo (owner/repo or URL):', default: `${owner}/skills` });
154
+ repo = await resolveRepoCloneUrl(existingRepo);
155
+ } else {
156
+ const name = await input({ message: `Vault repo name under ${owner}:`, default: 'skills' });
157
+ repo = await ensureOwnedVaultRepo(owner, name);
158
+ }
135
159
  }
136
- const { stdout: viewOut } = await gh(['repo', 'view', repo, '--json', 'isPrivate,url', '--jq', '.']);
137
- const view = JSON.parse(viewOut);
138
- if (!view.isPrivate) throw new Error(`${repo} exists but is not private. Make it private before using it as a skill vault.`);
139
- repo = view.url;
140
160
  } else {
141
161
  repo = await resolveRepoCloneUrl(repo);
142
162
  }