@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.1 → 0.1.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.
Files changed (50) hide show
  1. package/README.md +163 -201
  2. package/bin/cli.js +157 -173
  3. package/contexts/4.34/{claude → skills}/arcgis-3d-advanced/SKILL.md +586 -586
  4. package/contexts/4.34/{claude → skills}/arcgis-advanced-layers/SKILL.md +431 -431
  5. package/contexts/4.34/{claude → skills}/arcgis-analysis-services/SKILL.md +607 -607
  6. package/contexts/4.34/{claude → skills}/arcgis-authentication/SKILL.md +301 -301
  7. package/contexts/4.34/{claude → skills}/arcgis-cim-symbols/SKILL.md +486 -486
  8. package/contexts/4.34/{claude → skills}/arcgis-coordinates-projection/SKILL.md +406 -406
  9. package/contexts/4.34/{claude → skills}/arcgis-core-maps/SKILL.md +739 -739
  10. package/contexts/4.34/{claude → skills}/arcgis-core-utilities/SKILL.md +732 -732
  11. package/contexts/4.34/{claude → skills}/arcgis-custom-rendering/SKILL.md +445 -445
  12. package/contexts/4.34/{claude → skills}/arcgis-editing-advanced/SKILL.md +702 -702
  13. package/contexts/4.34/{claude → skills}/arcgis-feature-effects/SKILL.md +393 -393
  14. package/contexts/4.34/{claude → skills}/arcgis-geometry-operations/SKILL.md +489 -489
  15. package/contexts/4.34/{claude → skills}/arcgis-imagery/SKILL.md +307 -307
  16. package/contexts/4.34/{claude → skills}/arcgis-interaction/SKILL.md +572 -572
  17. package/contexts/4.34/{claude → skills}/arcgis-knowledge-graphs/SKILL.md +582 -582
  18. package/contexts/4.34/{claude → skills}/arcgis-layers/SKILL.md +601 -601
  19. package/contexts/4.34/{claude → skills}/arcgis-map-tools/SKILL.md +668 -668
  20. package/contexts/4.34/{claude → skills}/arcgis-media-layers/SKILL.md +290 -290
  21. package/contexts/4.34/{claude → skills}/arcgis-portal-content/SKILL.md +679 -679
  22. package/contexts/4.34/{claude → skills}/arcgis-scene-effects/SKILL.md +512 -512
  23. package/contexts/4.34/{claude → skills}/arcgis-smart-mapping/SKILL.md +686 -686
  24. package/contexts/4.34/skills/arcgis-starter-app/SKILL.md +273 -0
  25. package/contexts/4.34/skills/arcgis-starter-app-extended/SKILL.md +649 -0
  26. package/contexts/4.34/{claude → skills}/arcgis-tables-forms/SKILL.md +877 -877
  27. package/contexts/4.34/{claude → skills}/arcgis-time-animation/SKILL.md +722 -722
  28. package/contexts/4.34/{claude → skills}/arcgis-utility-networks/SKILL.md +301 -301
  29. package/contexts/4.34/{claude → skills}/arcgis-visualization/SKILL.md +580 -580
  30. package/contexts/4.34/{claude → skills}/arcgis-widgets-ui/SKILL.md +574 -574
  31. package/lib/installer.js +294 -379
  32. package/package.json +45 -45
  33. package/contexts/4.34/copilot/arcgis-3d.instructions.md +0 -267
  34. package/contexts/4.34/copilot/arcgis-analysis.instructions.md +0 -294
  35. package/contexts/4.34/copilot/arcgis-arcade.instructions.md +0 -234
  36. package/contexts/4.34/copilot/arcgis-authentication.instructions.md +0 -187
  37. package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +0 -177
  38. package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +0 -246
  39. package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +0 -247
  40. package/contexts/4.34/copilot/arcgis-editing.instructions.md +0 -262
  41. package/contexts/4.34/copilot/arcgis-geometry.instructions.md +0 -225
  42. package/contexts/4.34/copilot/arcgis-layers.instructions.md +0 -278
  43. package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +0 -266
  44. package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +0 -275
  45. package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +0 -184
  46. package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +0 -112
  47. package/contexts/4.34/copilot/arcgis-visualization.instructions.md +0 -321
  48. package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +0 -277
  49. /package/contexts/4.34/{claude → skills}/arcgis-arcade/SKILL.md +0 -0
  50. /package/contexts/4.34/{claude → skills}/arcgis-popup-templates/SKILL.md +0 -0
package/lib/installer.js CHANGED
@@ -1,379 +1,294 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- // ANSI color codes (built-in, no dependencies)
5
- const colors = {
6
- reset: '\x1b[0m',
7
- bold: '\x1b[1m',
8
- dim: '\x1b[2m',
9
- green: '\x1b[32m',
10
- yellow: '\x1b[33m',
11
- blue: '\x1b[34m',
12
- magenta: '\x1b[35m',
13
- cyan: '\x1b[36m',
14
- red: '\x1b[31m',
15
- white: '\x1b[37m',
16
- };
17
-
18
- function colorize(color, text) {
19
- return `${colors[color]}${text}${colors.reset}`;
20
- }
21
-
22
- function log(message) {
23
- console.log(message);
24
- }
25
-
26
- function success(message) {
27
- log(`${colorize('green', '\u2714')} ${message}`);
28
- }
29
-
30
- function error(message) {
31
- log(`${colorize('red', '\u2718')} ${message}`);
32
- }
33
-
34
- function info(message) {
35
- log(`${colorize('cyan', '\u2139')} ${message}`);
36
- }
37
-
38
- function warning(message) {
39
- log(`${colorize('yellow', '\u26A0')} ${message}`);
40
- }
41
-
42
- function header(message) {
43
- log(`\n${colorize('bold', colorize('magenta', message))}`);
44
- }
45
-
46
- /**
47
- * Get the contexts directory path (where bundled contexts are stored)
48
- */
49
- function getContextsDir() {
50
- return path.join(__dirname, '..', 'contexts');
51
- }
52
-
53
- /**
54
- * Get available SDK versions
55
- */
56
- function getAvailableVersions() {
57
- const contextsDir = getContextsDir();
58
-
59
- if (!fs.existsSync(contextsDir)) {
60
- return [];
61
- }
62
-
63
- const entries = fs.readdirSync(contextsDir, { withFileTypes: true });
64
- const versions = entries
65
- .filter(e => e.isDirectory() && /^\d+\.\d+$/.test(e.name))
66
- .map(e => e.name)
67
- .sort((a, b) => {
68
- const [aMajor, aMinor] = a.split('.').map(Number);
69
- const [bMajor, bMinor] = b.split('.').map(Number);
70
- if (aMajor !== bMajor) return aMajor - bMajor;
71
- return aMinor - bMinor;
72
- });
73
-
74
- return versions;
75
- }
76
-
77
- /**
78
- * Get the latest available version
79
- */
80
- function getLatestVersion() {
81
- const versions = getAvailableVersions();
82
- return versions.length > 0 ? versions[versions.length - 1] : null;
83
- }
84
-
85
- /**
86
- * Copy directory recursively
87
- */
88
- function copyDirSync(src, dest) {
89
- if (!fs.existsSync(src)) {
90
- throw new Error(`Source directory does not exist: ${src}`);
91
- }
92
-
93
- fs.mkdirSync(dest, { recursive: true });
94
-
95
- const entries = fs.readdirSync(src, { withFileTypes: true });
96
-
97
- for (const entry of entries) {
98
- const srcPath = path.join(src, entry.name);
99
- const destPath = path.join(dest, entry.name);
100
-
101
- if (entry.isDirectory()) {
102
- copyDirSync(srcPath, destPath);
103
- } else {
104
- fs.copyFileSync(srcPath, destPath);
105
- }
106
- }
107
- }
108
-
109
- /**
110
- * Check if directory is writable
111
- */
112
- function isWritable(dirPath) {
113
- try {
114
- const testFile = path.join(dirPath, '.write-test-' + Date.now());
115
- fs.mkdirSync(dirPath, { recursive: true });
116
- fs.writeFileSync(testFile, '');
117
- fs.unlinkSync(testFile);
118
- return true;
119
- } catch {
120
- return false;
121
- }
122
- }
123
-
124
- /**
125
- * Count files in a directory recursively
126
- */
127
- function countFiles(dirPath) {
128
- if (!fs.existsSync(dirPath)) return 0;
129
-
130
- let count = 0;
131
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
132
-
133
- for (const entry of entries) {
134
- if (entry.isDirectory()) {
135
- count += countFiles(path.join(dirPath, entry.name));
136
- } else {
137
- count++;
138
- }
139
- }
140
-
141
- return count;
142
- }
143
-
144
- /**
145
- * List directory contents recursively with indentation
146
- */
147
- function listDirContents(dirPath, indent = '') {
148
- if (!fs.existsSync(dirPath)) return [];
149
-
150
- const items = [];
151
- const entries = fs.readdirSync(dirPath, { withFileTypes: true }).sort((a, b) => {
152
- // Directories first, then files
153
- if (a.isDirectory() && !b.isDirectory()) return -1;
154
- if (!a.isDirectory() && b.isDirectory()) return 1;
155
- return a.name.localeCompare(b.name);
156
- });
157
-
158
- for (const entry of entries) {
159
- const isDir = entry.isDirectory();
160
- const icon = isDir ? '\u{1F4C1}' : '\u{1F4C4}';
161
- items.push(`${indent}${icon} ${entry.name}`);
162
-
163
- if (isDir) {
164
- items.push(...listDirContents(path.join(dirPath, entry.name), indent + ' '));
165
- }
166
- }
167
-
168
- return items;
169
- }
170
-
171
- /**
172
- * Install Claude skills
173
- */
174
- function installClaude(targetDir = process.cwd(), sdkVersion = null) {
175
- const version = sdkVersion || getLatestVersion();
176
-
177
- if (!version) {
178
- error('No SDK versions available');
179
- return false;
180
- }
181
-
182
- const destPath = path.join(targetDir, '.claude', 'skills', 'arcgis-maps-sdk-js');
183
- const srcPath = path.join(getContextsDir(), version, 'claude');
184
-
185
- header(`Installing Claude Skills (SDK ${version})`);
186
- info(`Source: ${srcPath}`);
187
- info(`Target: ${destPath}`);
188
-
189
- if (!fs.existsSync(srcPath)) {
190
- error(`Claude skills not found for SDK version ${version}`);
191
- return false;
192
- }
193
-
194
- const parentDir = path.dirname(destPath);
195
- if (!isWritable(parentDir)) {
196
- error(`Cannot write to directory: ${parentDir}`);
197
- error('Please check permissions and try again');
198
- return false;
199
- }
200
-
201
- try {
202
- copyDirSync(srcPath, destPath);
203
- const fileCount = countFiles(destPath);
204
- success(`Installed ${fileCount} Claude skill files for SDK ${version}`);
205
- success(`Location: ${colorize('cyan', destPath)}`);
206
- return true;
207
- } catch (err) {
208
- error(`Failed to install Claude skills: ${err.message}`);
209
- return false;
210
- }
211
- }
212
-
213
- /**
214
- * Install GitHub Copilot instructions
215
- */
216
- function installCopilot(targetDir = process.cwd(), sdkVersion = null) {
217
- const version = sdkVersion || getLatestVersion();
218
-
219
- if (!version) {
220
- error('No SDK versions available');
221
- return false;
222
- }
223
-
224
- const destPath = path.join(targetDir, '.github', 'instructions');
225
- const srcPath = path.join(getContextsDir(), version, 'copilot');
226
-
227
- header(`Installing GitHub Copilot Instructions (SDK ${version})`);
228
- info(`Source: ${srcPath}`);
229
- info(`Target: ${destPath}`);
230
-
231
- if (!fs.existsSync(srcPath)) {
232
- error(`Copilot instructions not found for SDK version ${version}`);
233
- return false;
234
- }
235
-
236
- if (!isWritable(destPath)) {
237
- error(`Cannot write to directory: ${destPath}`);
238
- error('Please check permissions and try again');
239
- return false;
240
- }
241
-
242
- try {
243
- copyDirSync(srcPath, destPath);
244
- const fileCount = countFiles(destPath);
245
- success(`Installed ${fileCount} Copilot instruction files for SDK ${version}`);
246
- success(`Location: ${colorize('cyan', destPath)}`);
247
- return true;
248
- } catch (err) {
249
- error(`Failed to install Copilot instructions: ${err.message}`);
250
- return false;
251
- }
252
- }
253
-
254
- /**
255
- * Install all contexts
256
- */
257
- function installAll(targetDir = process.cwd(), sdkVersion = null) {
258
- const version = sdkVersion || getLatestVersion();
259
-
260
- header(`Installing All AI Context Files (SDK ${version})`);
261
-
262
- const claudeResult = installClaude(targetDir, version);
263
- const copilotResult = installCopilot(targetDir, version);
264
-
265
- log('');
266
- if (claudeResult && copilotResult) {
267
- success(colorize('bold', 'All installations completed successfully!'));
268
- return true;
269
- } else {
270
- warning('Some installations failed. See errors above.');
271
- return false;
272
- }
273
- }
274
-
275
- /**
276
- * List available contexts
277
- */
278
- function listContexts() {
279
- const contextsDir = getContextsDir();
280
- const versions = getAvailableVersions();
281
-
282
- header('Available AI Context Files');
283
- log('');
284
-
285
- // Show available versions
286
- log(`${colorize('bold', colorize('blue', 'Available SDK Versions'))}`);
287
- if (versions.length > 0) {
288
- const latestVersion = versions[versions.length - 1];
289
- for (const version of versions) {
290
- const isLatest = version === latestVersion;
291
- const label = isLatest ? ` ${colorize('green', '(latest)')}` : '';
292
- log(` ${colorize('green', '\u2022')} ${colorize('cyan', version)}${label}`);
293
- }
294
- } else {
295
- log(` ${colorize('dim', 'No versions available')}`);
296
- }
297
- log('');
298
-
299
- // Show contents for latest version
300
- const latestVersion = getLatestVersion();
301
- if (!latestVersion) {
302
- return;
303
- }
304
-
305
- // Claude skills
306
- const claudeDir = path.join(contextsDir, latestVersion, 'claude');
307
- if (fs.existsSync(claudeDir)) {
308
- log(`${colorize('bold', colorize('blue', `Claude Skills (SDK ${latestVersion})`))}`);
309
- log(colorize('dim', ` Installs to: .claude/skills/arcgis-maps-sdk-js/`));
310
-
311
- const entries = fs.readdirSync(claudeDir, { withFileTypes: true })
312
- .filter(e => e.isDirectory())
313
- .sort((a, b) => a.name.localeCompare(b.name));
314
-
315
- for (const entry of entries) {
316
- const skillPath = path.join(claudeDir, entry.name, 'SKILL.md');
317
- if (fs.existsSync(skillPath)) {
318
- // Read first few lines to get name and description
319
- const content = fs.readFileSync(skillPath, 'utf8');
320
- const nameMatch = content.match(/^name:\s*(.+)$/m);
321
- const descMatch = content.match(/^description:\s*(.+)$/m);
322
-
323
- const name = nameMatch ? nameMatch[1] : entry.name;
324
- const desc = descMatch ? descMatch[1].substring(0, 60) + (descMatch[1].length > 60 ? '...' : '') : '';
325
-
326
- log(` ${colorize('green', '\u2022')} ${colorize('cyan', name)}`);
327
- if (desc) {
328
- log(` ${colorize('dim', desc)}`);
329
- }
330
- }
331
- }
332
-
333
- const skillCount = entries.length;
334
- log(` ${colorize('dim', `(${skillCount} skills total)`)}`);
335
- }
336
-
337
- log('');
338
-
339
- // Copilot instructions
340
- const copilotDir = path.join(contextsDir, latestVersion, 'copilot');
341
- if (fs.existsSync(copilotDir)) {
342
- log(`${colorize('bold', colorize('blue', `GitHub Copilot Instructions (SDK ${latestVersion})`))}`);
343
- log(colorize('dim', ` Installs to: .github/instructions/`));
344
-
345
- const files = fs.readdirSync(copilotDir)
346
- .filter(f => f.endsWith('.md') || f.endsWith('.instructions.md'))
347
- .sort();
348
-
349
- for (const file of files) {
350
- log(` ${colorize('green', '\u2022')} ${colorize('cyan', file)}`);
351
- }
352
-
353
- log(` ${colorize('dim', `(${files.length} file${files.length !== 1 ? 's' : ''} total)`)}`);
354
- }
355
-
356
- log('');
357
- log(colorize('dim', 'Usage:'));
358
- log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context claude # Install Claude skills (latest)'));
359
- log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context claude --sdk 4.34 # Install for specific version'));
360
- log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context copilot # Install Copilot instructions'));
361
- log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context all # Install everything'));
362
- }
363
-
364
- module.exports = {
365
- installClaude,
366
- installCopilot,
367
- installAll,
368
- listContexts,
369
- getAvailableVersions,
370
- getLatestVersion,
371
- colors,
372
- colorize,
373
- log,
374
- success,
375
- error,
376
- info,
377
- warning,
378
- header,
379
- };
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // ANSI color codes (built-in, no dependencies)
5
+ const colors = {
6
+ reset: '\x1b[0m',
7
+ bold: '\x1b[1m',
8
+ dim: '\x1b[2m',
9
+ green: '\x1b[32m',
10
+ yellow: '\x1b[33m',
11
+ blue: '\x1b[34m',
12
+ magenta: '\x1b[35m',
13
+ cyan: '\x1b[36m',
14
+ red: '\x1b[31m',
15
+ white: '\x1b[37m',
16
+ };
17
+
18
+ function colorize(color, text) {
19
+ return `${colors[color]}${text}${colors.reset}`;
20
+ }
21
+
22
+ function log(message) {
23
+ console.log(message);
24
+ }
25
+
26
+ function success(message) {
27
+ log(`${colorize('green', '\u2714')} ${message}`);
28
+ }
29
+
30
+ function error(message) {
31
+ log(`${colorize('red', '\u2718')} ${message}`);
32
+ }
33
+
34
+ function info(message) {
35
+ log(`${colorize('cyan', '\u2139')} ${message}`);
36
+ }
37
+
38
+ function warning(message) {
39
+ log(`${colorize('yellow', '\u26A0')} ${message}`);
40
+ }
41
+
42
+ function header(message) {
43
+ log(`\n${colorize('bold', colorize('magenta', message))}`);
44
+ }
45
+
46
+ /**
47
+ * Get the contexts directory path (where bundled contexts are stored)
48
+ */
49
+ function getContextsDir() {
50
+ return path.join(__dirname, '..', 'contexts');
51
+ }
52
+
53
+ /**
54
+ * Get available SDK versions
55
+ */
56
+ function getAvailableVersions() {
57
+ const contextsDir = getContextsDir();
58
+
59
+ if (!fs.existsSync(contextsDir)) {
60
+ return [];
61
+ }
62
+
63
+ const entries = fs.readdirSync(contextsDir, { withFileTypes: true });
64
+ const versions = entries
65
+ .filter(e => e.isDirectory() && /^\d+\.\d+$/.test(e.name))
66
+ .map(e => e.name)
67
+ .sort((a, b) => {
68
+ const [aMajor, aMinor] = a.split('.').map(Number);
69
+ const [bMajor, bMinor] = b.split('.').map(Number);
70
+ if (aMajor !== bMajor) return aMajor - bMajor;
71
+ return aMinor - bMinor;
72
+ });
73
+
74
+ return versions;
75
+ }
76
+
77
+ /**
78
+ * Get the latest available version
79
+ */
80
+ function getLatestVersion() {
81
+ const versions = getAvailableVersions();
82
+ return versions.length > 0 ? versions[versions.length - 1] : null;
83
+ }
84
+
85
+ /**
86
+ * Copy directory recursively
87
+ */
88
+ function copyDirSync(src, dest) {
89
+ if (!fs.existsSync(src)) {
90
+ throw new Error(`Source directory does not exist: ${src}`);
91
+ }
92
+
93
+ fs.mkdirSync(dest, { recursive: true });
94
+
95
+ const entries = fs.readdirSync(src, { withFileTypes: true });
96
+
97
+ for (const entry of entries) {
98
+ const srcPath = path.join(src, entry.name);
99
+ const destPath = path.join(dest, entry.name);
100
+
101
+ if (entry.isDirectory()) {
102
+ copyDirSync(srcPath, destPath);
103
+ } else {
104
+ fs.copyFileSync(srcPath, destPath);
105
+ }
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Check if directory is writable
111
+ */
112
+ function isWritable(dirPath) {
113
+ try {
114
+ const testFile = path.join(dirPath, '.write-test-' + Date.now());
115
+ fs.mkdirSync(dirPath, { recursive: true });
116
+ fs.writeFileSync(testFile, '');
117
+ fs.unlinkSync(testFile);
118
+ return true;
119
+ } catch {
120
+ return false;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Count files in a directory recursively
126
+ */
127
+ function countFiles(dirPath) {
128
+ if (!fs.existsSync(dirPath)) return 0;
129
+
130
+ let count = 0;
131
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
132
+
133
+ for (const entry of entries) {
134
+ if (entry.isDirectory()) {
135
+ count += countFiles(path.join(dirPath, entry.name));
136
+ } else {
137
+ count++;
138
+ }
139
+ }
140
+
141
+ return count;
142
+ }
143
+
144
+ /**
145
+ * List directory contents recursively with indentation
146
+ */
147
+ function listDirContents(dirPath, indent = '') {
148
+ if (!fs.existsSync(dirPath)) return [];
149
+
150
+ const items = [];
151
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true }).sort((a, b) => {
152
+ // Directories first, then files
153
+ if (a.isDirectory() && !b.isDirectory()) return -1;
154
+ if (!a.isDirectory() && b.isDirectory()) return 1;
155
+ return a.name.localeCompare(b.name);
156
+ });
157
+
158
+ for (const entry of entries) {
159
+ const isDir = entry.isDirectory();
160
+ const icon = isDir ? '\u{1F4C1}' : '\u{1F4C4}';
161
+ items.push(`${indent}${icon} ${entry.name}`);
162
+
163
+ if (isDir) {
164
+ items.push(...listDirContents(path.join(dirPath, entry.name), indent + ' '));
165
+ }
166
+ }
167
+
168
+ return items;
169
+ }
170
+
171
+ /**
172
+ * Install Agent Skills
173
+ */
174
+ function installSkills(targetDir = process.cwd(), sdkVersion = null) {
175
+ const version = sdkVersion || getLatestVersion();
176
+
177
+ if (!version) {
178
+ error('No SDK versions available');
179
+ return false;
180
+ }
181
+
182
+ const destPath = path.join(targetDir, '.github', 'skills');
183
+ const srcPath = path.join(getContextsDir(), version, 'skills');
184
+
185
+ header(`Installing Agent Skills (SDK ${version})`);
186
+ info(`Source: ${srcPath}`);
187
+ info(`Target: ${destPath}`);
188
+
189
+ if (!fs.existsSync(srcPath)) {
190
+ error(`Agent Skills not found for SDK version ${version}`);
191
+ return false;
192
+ }
193
+
194
+ const parentDir = path.dirname(destPath);
195
+ if (!isWritable(parentDir)) {
196
+ error(`Cannot write to directory: ${parentDir}`);
197
+ error('Please check permissions and try again');
198
+ return false;
199
+ }
200
+
201
+ try {
202
+ copyDirSync(srcPath, destPath);
203
+ const fileCount = countFiles(destPath);
204
+ success(`Installed ${fileCount} Agent Skills files for SDK ${version}`);
205
+ success(`Location: ${colorize('cyan', destPath)}`);
206
+ return true;
207
+ } catch (err) {
208
+ error(`Failed to install Agent Skills: ${err.message}`);
209
+ return false;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * List available contexts
215
+ */
216
+ function listContexts() {
217
+ const contextsDir = getContextsDir();
218
+ const versions = getAvailableVersions();
219
+
220
+ header('Available Agent Skills');
221
+ log('');
222
+
223
+ // Show available versions
224
+ log(`${colorize('bold', colorize('blue', 'Available SDK Versions'))}`);
225
+ if (versions.length > 0) {
226
+ const latestVersion = versions[versions.length - 1];
227
+ for (const version of versions) {
228
+ const isLatest = version === latestVersion;
229
+ const label = isLatest ? ` ${colorize('green', '(latest)')}` : '';
230
+ log(` ${colorize('green', '\u2022')} ${colorize('cyan', version)}${label}`);
231
+ }
232
+ } else {
233
+ log(` ${colorize('dim', 'No versions available')}`);
234
+ }
235
+ log('');
236
+
237
+ // Show contents for latest version
238
+ const latestVersion = getLatestVersion();
239
+ if (!latestVersion) {
240
+ return;
241
+ }
242
+
243
+ // Agent Skills
244
+ const skillsDir = path.join(contextsDir, latestVersion, 'skills');
245
+ if (fs.existsSync(skillsDir)) {
246
+ log(`${colorize('bold', colorize('blue', `Agent Skills (SDK ${latestVersion})`))}`);
247
+ log(colorize('dim', ` Installs to: .github/skills/`));
248
+
249
+ const entries = fs.readdirSync(skillsDir, { withFileTypes: true })
250
+ .filter(e => e.isDirectory())
251
+ .sort((a, b) => a.name.localeCompare(b.name));
252
+
253
+ for (const entry of entries) {
254
+ const skillPath = path.join(skillsDir, entry.name, 'SKILL.md');
255
+ if (fs.existsSync(skillPath)) {
256
+ // Read first few lines to get name and description
257
+ const content = fs.readFileSync(skillPath, 'utf8');
258
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
259
+ const descMatch = content.match(/^description:\s*(.+)$/m);
260
+
261
+ const name = nameMatch ? nameMatch[1] : entry.name;
262
+ const desc = descMatch ? descMatch[1].substring(0, 60) + (descMatch[1].length > 60 ? '...' : '') : '';
263
+
264
+ log(` ${colorize('green', '\u2022')} ${colorize('cyan', name)}`);
265
+ if (desc) {
266
+ log(` ${colorize('dim', desc)}`);
267
+ }
268
+ }
269
+ }
270
+
271
+ const skillCount = entries.length;
272
+ log(` ${colorize('dim', `(${skillCount} skills total)`)}`);
273
+ }
274
+
275
+ log('');
276
+ log(colorize('dim', 'Usage:'));
277
+ log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context skills # Install skills (latest)'));
278
+ log(colorize('dim', ' npx @saschabrunnerch/arcgis-maps-sdk-js-ai-context skills --sdk 4.34 # Install for specific version'));
279
+ }
280
+
281
+ module.exports = {
282
+ installSkills,
283
+ listContexts,
284
+ getAvailableVersions,
285
+ getLatestVersion,
286
+ colors,
287
+ colorize,
288
+ log,
289
+ success,
290
+ error,
291
+ info,
292
+ warning,
293
+ header,
294
+ };