@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.
- package/README.md +8 -3
- package/package.json +1 -1
- 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
|
|
92
|
+
Or create/select a vault repo interactively:
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
skillsync setup
|
|
95
|
+
skillsync setup
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
If you run plain `skillsync setup` in an interactive terminal, it asks
|
|
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
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
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
}
|