copilot-tap-extension 2.0.4 → 2.0.5
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/bin/install.mjs +148 -72
- package/dist/extension.mjs +9775 -10894
- package/dist/skills/tap-monitor/SKILL.md +7 -7
- package/dist/version.json +1 -1
- package/package.json +2 -1
package/bin/install.mjs
CHANGED
|
@@ -47,37 +47,38 @@ Installs:
|
|
|
47
47
|
`);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
const OPTION_ACTIONS = new Map([
|
|
51
|
+
["--global", (flags) => { flags.scope = "global"; }],
|
|
52
|
+
["-g", (flags) => { flags.scope = "global"; }],
|
|
53
|
+
["--local", (flags) => { flags.scope = "local"; }],
|
|
54
|
+
["-l", (flags) => { flags.scope = "local"; }],
|
|
55
|
+
["--force", (flags) => { flags.force = true; }],
|
|
56
|
+
["-f", (flags) => { flags.force = true; }],
|
|
57
|
+
["--full", (flags) => { flags.force = true; }],
|
|
58
|
+
// Keep legacy flags working as no-ops.
|
|
59
|
+
["--update", () => {}],
|
|
60
|
+
["-u", () => {}],
|
|
61
|
+
["--help", (flags) => { flags.help = true; }],
|
|
62
|
+
["-h", (flags) => { flags.help = true; }]
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
function applyOption(flags, arg) {
|
|
66
|
+
const action = OPTION_ACTIONS.get(arg);
|
|
67
|
+
if (action) {
|
|
68
|
+
action(flags);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.error(`Unknown option: ${arg}`);
|
|
73
|
+
usage();
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
50
77
|
function parseArgs(argv) {
|
|
51
78
|
const args = argv.slice(2);
|
|
52
79
|
const flags = { scope: "global", force: false, help: false };
|
|
53
80
|
for (const arg of args) {
|
|
54
|
-
|
|
55
|
-
case "--global":
|
|
56
|
-
case "-g":
|
|
57
|
-
flags.scope = "global";
|
|
58
|
-
break;
|
|
59
|
-
case "--local":
|
|
60
|
-
case "-l":
|
|
61
|
-
flags.scope = "local";
|
|
62
|
-
break;
|
|
63
|
-
case "--force":
|
|
64
|
-
case "-f":
|
|
65
|
-
case "--full":
|
|
66
|
-
flags.force = true;
|
|
67
|
-
break;
|
|
68
|
-
// Keep legacy flags working
|
|
69
|
-
case "--update":
|
|
70
|
-
case "-u":
|
|
71
|
-
break;
|
|
72
|
-
case "--help":
|
|
73
|
-
case "-h":
|
|
74
|
-
flags.help = true;
|
|
75
|
-
break;
|
|
76
|
-
default:
|
|
77
|
-
console.error(`Unknown option: ${arg}`);
|
|
78
|
-
usage();
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
+
applyOption(flags, arg);
|
|
81
82
|
}
|
|
82
83
|
return flags;
|
|
83
84
|
}
|
|
@@ -131,66 +132,107 @@ function isCopilotCliInstalled() {
|
|
|
131
132
|
|
|
132
133
|
function removeDeprecatedSkills(targetRoot) {
|
|
133
134
|
const deprecated = ["loop", "monitor", "create-provider"];
|
|
134
|
-
|
|
135
|
-
let removedAny = false;
|
|
135
|
+
const state = { allOk: true, removedAny: false };
|
|
136
136
|
|
|
137
137
|
for (const name of deprecated) {
|
|
138
|
-
|
|
139
|
-
if (!existsSync(oldPath)) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
try {
|
|
143
|
-
unlinkSync(oldPath);
|
|
144
|
-
if (!removedAny) {
|
|
145
|
-
console.log();
|
|
146
|
-
removedAny = true;
|
|
147
|
-
}
|
|
148
|
-
console.log(` ✓ Removed deprecated skill: skills/${name}/SKILL.md`);
|
|
149
|
-
} catch {
|
|
150
|
-
allOk = false;
|
|
151
|
-
console.warn(` ⚠ Could not remove deprecated skill at ${oldPath} — remove it manually`);
|
|
152
|
-
}
|
|
138
|
+
applyDeprecatedSkillRemoval(targetRoot, name, state);
|
|
153
139
|
}
|
|
154
140
|
|
|
155
|
-
if (removedAny) {
|
|
141
|
+
if (state.removedAny) {
|
|
156
142
|
console.log(`\n Use the new namespaced commands: /tap-loop /tap-monitor /tap-create-provider`);
|
|
157
143
|
}
|
|
158
144
|
|
|
159
|
-
return allOk;
|
|
145
|
+
return state.allOk;
|
|
160
146
|
}
|
|
161
147
|
|
|
162
|
-
function
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
148
|
+
function applyDeprecatedSkillRemoval(targetRoot, name, state) {
|
|
149
|
+
const result = removeDeprecatedSkill(targetRoot, name);
|
|
150
|
+
if (result.removed) {
|
|
151
|
+
logDeprecatedSkillRemoved(name, state);
|
|
152
|
+
}
|
|
153
|
+
if (!result.ok) {
|
|
154
|
+
state.allOk = false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function logDeprecatedSkillRemoved(name, state) {
|
|
159
|
+
if (!state.removedAny) {
|
|
160
|
+
console.log();
|
|
161
|
+
state.removedAny = true;
|
|
162
|
+
}
|
|
163
|
+
console.log(` ✓ Removed deprecated skill: skills/${name}/SKILL.md`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function removeDeprecatedSkill(targetRoot, name) {
|
|
167
|
+
const oldPath = path.join(targetRoot, "skills", name, "SKILL.md");
|
|
168
|
+
if (!existsSync(oldPath)) {
|
|
169
|
+
return { ok: true, removed: false };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
unlinkSync(oldPath);
|
|
174
|
+
return { ok: true, removed: true };
|
|
175
|
+
} catch {
|
|
176
|
+
console.warn(` ⚠ Could not remove deprecated skill at ${oldPath} — remove it manually`);
|
|
177
|
+
return { ok: false, removed: false };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
166
180
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
function getScopeLabel(scope) {
|
|
182
|
+
return scope === "global" ? "global (~/.copilot)" : "local (.github)";
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function ensureGlobalInstallSupported(scope) {
|
|
186
|
+
if (scope !== "global" || isCopilotCliInstalled()) {
|
|
187
|
+
return;
|
|
172
188
|
}
|
|
173
189
|
|
|
190
|
+
console.log(`\n⚠ Copilot CLI does not appear to be installed.`);
|
|
191
|
+
console.log(` Install it first: https://docs.github.com/en/copilot/github-copilot-in-the-cli`);
|
|
192
|
+
console.log(` Then re-run: npx copilot-tap-extension\n`);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function getInstallState(targetRoot, flags) {
|
|
174
197
|
const installed = isAlreadyInstalled(targetRoot);
|
|
175
198
|
const isUpdate = installed && !flags.force;
|
|
176
199
|
const isReinstall = installed && flags.force;
|
|
177
200
|
const installedVersion = installed ? getInstalledVersion(targetRoot) : null;
|
|
178
201
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
202
|
+
return { installed, isUpdate, isReinstall, installedVersion };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function exitIfAlreadyCurrent(state, packageVersion) {
|
|
206
|
+
if (!state.isUpdate || !state.installedVersion || state.installedVersion !== packageVersion) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log(`\n${BRAND} — already up to date (v${state.installedVersion})\n`);
|
|
211
|
+
process.exit(0);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getVersionLabel(version) {
|
|
215
|
+
return version ? `v${version}` : "unknown";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function announceInstall(state, packageVersion, scopeLabel) {
|
|
219
|
+
if (state.isUpdate) {
|
|
220
|
+
const fromLabel = getVersionLabel(state.installedVersion);
|
|
185
221
|
console.log(`\n${BRAND} — updating ${fromLabel} → v${packageVersion} (${scopeLabel})\n`);
|
|
186
|
-
|
|
187
|
-
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (state.isReinstall) {
|
|
226
|
+
const fromLabel = getVersionLabel(state.installedVersion);
|
|
188
227
|
console.log(`\n${BRAND} — reinstalling ${fromLabel} → v${packageVersion} (${scopeLabel})\n`);
|
|
189
|
-
|
|
190
|
-
console.log(`\n${BRAND} — installing v${packageVersion} (${scopeLabel})\n`);
|
|
228
|
+
return;
|
|
191
229
|
}
|
|
192
230
|
|
|
193
|
-
|
|
231
|
+
console.log(`\n${BRAND} — installing v${packageVersion} (${scopeLabel})\n`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function buildCoreArtifacts(targetRoot) {
|
|
235
|
+
return [
|
|
194
236
|
{
|
|
195
237
|
src: path.join(distDir, "extension.mjs"),
|
|
196
238
|
dest: path.join(targetRoot, "extensions", EXT_DIR_NAME, "extension.mjs"),
|
|
@@ -202,8 +244,10 @@ function install(flags) {
|
|
|
202
244
|
label: "extensions/tap/version.json"
|
|
203
245
|
}
|
|
204
246
|
];
|
|
247
|
+
}
|
|
205
248
|
|
|
206
|
-
|
|
249
|
+
function buildAncillaryArtifacts(targetRoot) {
|
|
250
|
+
return [
|
|
207
251
|
{
|
|
208
252
|
src: path.join(distDir, "skills", "tap-loop", "SKILL.md"),
|
|
209
253
|
dest: path.join(targetRoot, "skills", "tap-loop", "SKILL.md"),
|
|
@@ -230,37 +274,69 @@ function install(flags) {
|
|
|
230
274
|
label: "copilot-instructions.md"
|
|
231
275
|
}
|
|
232
276
|
];
|
|
277
|
+
}
|
|
233
278
|
|
|
279
|
+
function buildInstallArtifacts(targetRoot, isUpdate) {
|
|
280
|
+
const coreArtifacts = buildCoreArtifacts(targetRoot);
|
|
281
|
+
const ancillaryArtifacts = buildAncillaryArtifacts(targetRoot);
|
|
234
282
|
// During updates, also install ancillary artifacts that don't yet exist at the destination
|
|
235
283
|
// (e.g. new skills added in a newer version). Existing ones are preserved to keep user customizations.
|
|
236
284
|
const newAncillaryArtifacts = isUpdate
|
|
237
285
|
? ancillaryArtifacts.filter(({ dest }) => !existsSync(dest))
|
|
238
286
|
: ancillaryArtifacts;
|
|
239
|
-
|
|
287
|
+
return [...coreArtifacts, ...newAncillaryArtifacts];
|
|
288
|
+
}
|
|
240
289
|
|
|
290
|
+
function copyArtifacts(artifacts) {
|
|
241
291
|
let allOk = true;
|
|
242
292
|
for (const { src, dest, label } of artifacts) {
|
|
243
293
|
if (!copyArtifact(src, dest, label)) {
|
|
244
294
|
allOk = false;
|
|
245
295
|
}
|
|
246
296
|
}
|
|
297
|
+
return allOk;
|
|
298
|
+
}
|
|
247
299
|
|
|
248
|
-
|
|
249
|
-
|
|
300
|
+
function getInstallVerb(state) {
|
|
301
|
+
if (state.isUpdate) {
|
|
302
|
+
return "updated";
|
|
250
303
|
}
|
|
304
|
+
return state.isReinstall ? "reinstalled" : "installed";
|
|
305
|
+
}
|
|
251
306
|
|
|
307
|
+
function finishInstall(allOk, state, targetRoot) {
|
|
252
308
|
console.log();
|
|
309
|
+
const verb = getInstallVerb(state);
|
|
253
310
|
if (allOk) {
|
|
254
|
-
const verb = isUpdate ? "updated" : isReinstall ? "reinstalled" : "installed";
|
|
255
311
|
console.log(`✓ ${BRAND} ${verb} to ${targetRoot}`);
|
|
256
312
|
return;
|
|
257
313
|
}
|
|
258
314
|
|
|
259
|
-
const verb = isUpdate ? "updated" : isReinstall ? "reinstalled" : "installed";
|
|
260
315
|
console.error(`⚠ Some artifacts could not be ${verb}.`);
|
|
261
316
|
process.exit(1);
|
|
262
317
|
}
|
|
263
318
|
|
|
319
|
+
function install(flags) {
|
|
320
|
+
const targetRoot = getTargetRoot(flags.scope);
|
|
321
|
+
const scopeLabel = getScopeLabel(flags.scope);
|
|
322
|
+
const packageVersion = getPackageVersion();
|
|
323
|
+
|
|
324
|
+
ensureGlobalInstallSupported(flags.scope);
|
|
325
|
+
|
|
326
|
+
const state = getInstallState(targetRoot, flags);
|
|
327
|
+
exitIfAlreadyCurrent(state, packageVersion);
|
|
328
|
+
announceInstall(state, packageVersion, scopeLabel);
|
|
329
|
+
|
|
330
|
+
const artifacts = buildInstallArtifacts(targetRoot, state.isUpdate);
|
|
331
|
+
let allOk = copyArtifacts(artifacts);
|
|
332
|
+
|
|
333
|
+
if (state.installed && !removeDeprecatedSkills(targetRoot)) {
|
|
334
|
+
allOk = false;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
finishInstall(allOk, state, targetRoot);
|
|
338
|
+
}
|
|
339
|
+
|
|
264
340
|
const flags = parseArgs(process.argv);
|
|
265
341
|
|
|
266
342
|
if (flags.help) {
|