servicemap 0.1.7 → 0.1.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.
- package/README.md +3 -4
- package/bin/servicemap.mjs +79 -115
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npx servicemap
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
That opens the interactive install survey.
|
|
16
|
-
It lets users choose
|
|
16
|
+
It installs to the universal `.agents/skills` folder and lets users choose additional agent-specific skill folders.
|
|
17
17
|
|
|
18
18
|
To install the bundled AI skill so `/servicemap` appears in compatible coding agents:
|
|
19
19
|
|
|
@@ -41,7 +41,6 @@ npx servicemap skills install --agent claude
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Agents with known local skill folders get the real `servicemap` skill installed.
|
|
44
|
-
Other selected AI tools get setup notes under `~/.servicemap/model-guides`.
|
|
45
44
|
|
|
46
45
|
After a global install, the command is:
|
|
47
46
|
|
|
@@ -72,7 +71,7 @@ servicemap install-skill --agent codex
|
|
|
72
71
|
servicemap install-skill --agent claude
|
|
73
72
|
servicemap install-skill --agent grok
|
|
74
73
|
servicemap install-skill --agent all
|
|
75
|
-
servicemap install-skill --targets
|
|
74
|
+
servicemap install-skill --targets universal,claude,grok
|
|
76
75
|
servicemap skills install --agent codex
|
|
77
76
|
```
|
|
78
77
|
|
|
@@ -92,7 +91,7 @@ node bin/servicemap.mjs generate --root demo-project --allow-emails founder@exam
|
|
|
92
91
|
node bin/servicemap.mjs --root no-website-demo --dry-run
|
|
93
92
|
node bin/servicemap.mjs --dry-run
|
|
94
93
|
node bin/servicemap.mjs install-skill --agent all --dry-run
|
|
95
|
-
node bin/servicemap.mjs install-skill --targets
|
|
94
|
+
node bin/servicemap.mjs install-skill --targets universal,claude,grok --dry-run
|
|
96
95
|
node bin/servicemap.mjs skills install --agent claude --dry-run
|
|
97
96
|
python3 /Users/dougie/.codex/skills/.system/skill-creator/scripts/quick_validate.py servicemap
|
|
98
97
|
```
|
package/bin/servicemap.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
|
-
import { cp, mkdir, readFile, rm
|
|
4
|
+
import { cp, mkdir, readFile, rm } from 'node:fs/promises';
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { homedir } from 'node:os';
|
|
7
7
|
import readline from 'node:readline';
|
|
@@ -12,67 +12,63 @@ const scanScript = resolve(packageRoot, 'servicemap/scripts/scan-project.mjs');
|
|
|
12
12
|
const pageScript = resolve(packageRoot, 'servicemap/scripts/generate-page.mjs');
|
|
13
13
|
const desktopScript = resolve(packageRoot, 'servicemap/scripts/generate-desktop-app.mjs');
|
|
14
14
|
|
|
15
|
+
const universalRoot = () => resolve(homedir(), '.agents/skills');
|
|
16
|
+
|
|
17
|
+
const universalAgents = [
|
|
18
|
+
'Amp',
|
|
19
|
+
'Cline',
|
|
20
|
+
'Codex',
|
|
21
|
+
'Cursor',
|
|
22
|
+
'Gemini CLI',
|
|
23
|
+
'GitHub Copilot',
|
|
24
|
+
'OpenCode',
|
|
25
|
+
'Warp',
|
|
26
|
+
'Zed',
|
|
27
|
+
];
|
|
28
|
+
|
|
15
29
|
const targetCatalog = [
|
|
16
|
-
{ id: '
|
|
17
|
-
{ id: '
|
|
18
|
-
{ id: '
|
|
19
|
-
{ id: '
|
|
20
|
-
{ id: '
|
|
21
|
-
{ id: '
|
|
22
|
-
{ id: '
|
|
23
|
-
{ id: '
|
|
24
|
-
{ id: '
|
|
25
|
-
{ id: '
|
|
26
|
-
{ id: '
|
|
27
|
-
{ id: '
|
|
28
|
-
{ id: '
|
|
29
|
-
{ id: '
|
|
30
|
-
{ id: 'lovable', label: 'Lovable', kind: 'guide' },
|
|
31
|
-
{ id: 'bolt', label: 'Bolt', kind: 'guide' },
|
|
32
|
-
{ id: 'v0', label: 'v0', kind: 'guide' },
|
|
33
|
-
{ id: 'perplexity', label: 'Perplexity', kind: 'guide' },
|
|
34
|
-
{ id: 'mistral', label: 'Mistral', kind: 'guide' },
|
|
35
|
-
{ id: 'deepseek', label: 'DeepSeek', kind: 'guide' },
|
|
36
|
-
{ id: 'qwen', label: 'Qwen', kind: 'guide' },
|
|
37
|
-
{ id: 'meta', label: 'Meta (Llama)', kind: 'guide' },
|
|
38
|
-
{ id: 'local-models', label: 'Local models (Ollama, LM Studio)', kind: 'guide' },
|
|
39
|
-
{ id: 'openrouter', label: 'OpenRouter', kind: 'guide' },
|
|
40
|
-
{ id: 'bedrock', label: 'Amazon Bedrock', kind: 'guide' },
|
|
41
|
-
{ id: 'azure-openai', label: 'Azure OpenAI', kind: 'guide' },
|
|
42
|
-
{ id: 'poe', label: 'Poe', kind: 'guide' },
|
|
43
|
-
{ id: 'you-com', label: 'You.com', kind: 'guide' },
|
|
44
|
-
{ id: 'phind', label: 'Phind', kind: 'guide' },
|
|
45
|
-
{ id: 'sourcegraph-cody', label: 'Sourcegraph Cody', kind: 'guide' },
|
|
46
|
-
{ id: 'tabnine', label: 'Tabnine', kind: 'guide' },
|
|
47
|
-
{ id: 'codeium', label: 'Codeium', kind: 'guide' },
|
|
48
|
-
{ id: 'jetbrains-ai', label: 'JetBrains AI', kind: 'guide' },
|
|
49
|
-
{ id: 'custom', label: 'Other custom model or agent', kind: 'guide' },
|
|
30
|
+
{ id: 'claude', label: 'Claude Code', root: () => resolve(homedir(), '.claude/skills') },
|
|
31
|
+
{ id: 'grok', label: 'Grok', root: () => resolve(homedir(), '.grok/skills') },
|
|
32
|
+
{ id: 'aiderdesk', label: 'AiderDesk', root: () => resolve(homedir(), '.aider-desk/skills') },
|
|
33
|
+
{ id: 'astrbot', label: 'AstrBot', root: () => resolve(homedir(), '.astrbot/data/skills') },
|
|
34
|
+
{ id: 'autohand', label: 'Autohand Code CLI', root: () => resolve(homedir(), '.autohand/skills') },
|
|
35
|
+
{ id: 'augment', label: 'Augment', root: () => resolve(homedir(), '.augment/skills') },
|
|
36
|
+
{ id: 'ibm-bob', label: 'IBM Bob', root: () => resolve(homedir(), '.bob/skills') },
|
|
37
|
+
{ id: 'openclaw', label: 'OpenClaw', root: () => resolve(homedir(), '.openclaw/skills') },
|
|
38
|
+
{ id: 'codearts', label: 'CodeArts Agent', root: () => resolve(homedir(), '.codeartsdoer/skills') },
|
|
39
|
+
{ id: 'roo-code', label: 'Roo Code', root: () => resolve(homedir(), '.roo/skills') },
|
|
40
|
+
{ id: 'continue', label: 'Continue', root: () => resolve(homedir(), '.continue/skills') },
|
|
41
|
+
{ id: 'windsurf', label: 'Windsurf', root: () => resolve(homedir(), '.windsurf/skills') },
|
|
42
|
+
{ id: 'replit-agent', label: 'Replit Agent', root: () => resolve(homedir(), '.replit/skills') },
|
|
43
|
+
{ id: 'jetbrains-ai', label: 'JetBrains AI', root: () => resolve(homedir(), '.jetbrains-ai/skills') },
|
|
50
44
|
];
|
|
51
45
|
|
|
52
46
|
const targetAliases = new Map([
|
|
53
|
-
['
|
|
54
|
-
['
|
|
55
|
-
['
|
|
56
|
-
['
|
|
57
|
-
['
|
|
58
|
-
['
|
|
59
|
-
['
|
|
60
|
-
['
|
|
61
|
-
['
|
|
62
|
-
['
|
|
47
|
+
['codex', 'universal'],
|
|
48
|
+
['agents', 'universal'],
|
|
49
|
+
['universal', 'universal'],
|
|
50
|
+
['cursor', 'universal'],
|
|
51
|
+
['cline', 'universal'],
|
|
52
|
+
['opencode', 'universal'],
|
|
53
|
+
['zed', 'universal'],
|
|
54
|
+
['github-copilot', 'universal'],
|
|
55
|
+
['copilot', 'universal'],
|
|
56
|
+
['gemini-cli', 'universal'],
|
|
57
|
+
['chatgpt', 'universal'],
|
|
58
|
+
['openai', 'universal'],
|
|
59
|
+
['openai-api', 'universal'],
|
|
60
|
+
['gpt-6-astra', 'universal'],
|
|
61
|
+
['gpt-6-sol', 'universal'],
|
|
62
|
+
['gpt-6-luna', 'universal'],
|
|
63
|
+
['gpt-5.6-sol', 'universal'],
|
|
64
|
+
['gpt-5.6-terra', 'universal'],
|
|
65
|
+
['gpt-5.6-luna', 'universal'],
|
|
63
66
|
['anthropic', 'claude'],
|
|
64
67
|
['anthropic-api', 'claude'],
|
|
65
68
|
['claude-opus', 'claude'],
|
|
66
69
|
['claude-sonnet', 'claude'],
|
|
67
70
|
['claude-haiku', 'claude'],
|
|
68
|
-
['
|
|
69
|
-
['gemini-pro', 'gemini'],
|
|
70
|
-
['gemini-flash', 'gemini'],
|
|
71
|
-
['gemini-api', 'gemini'],
|
|
72
|
-
['vertex-ai', 'gemini'],
|
|
73
|
-
['llama', 'meta'],
|
|
74
|
-
['ollama', 'local-models'],
|
|
75
|
-
['lm-studio', 'local-models'],
|
|
71
|
+
['xai', 'grok'],
|
|
76
72
|
]);
|
|
77
73
|
|
|
78
74
|
function parseArgs() {
|
|
@@ -178,34 +174,48 @@ async function readScan(root) {
|
|
|
178
174
|
|
|
179
175
|
function targetsByIds(ids) {
|
|
180
176
|
const byId = new Map(targetCatalog.map((target) => [target.id, target]));
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
const targets = [];
|
|
178
|
+
let includeUniversal = false;
|
|
179
|
+
|
|
180
|
+
for (const id of ids) {
|
|
181
|
+
const resolvedId = targetAliases.get(id) ?? id;
|
|
182
|
+
if (resolvedId === 'universal') {
|
|
183
|
+
includeUniversal = true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const target = byId.get(resolvedId);
|
|
183
187
|
if (!target) {
|
|
184
188
|
throw new Error(`Unknown target "${id}". Use --survey to choose from the list.`);
|
|
185
189
|
}
|
|
186
|
-
|
|
187
|
-
}
|
|
190
|
+
targets.push(target);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (includeUniversal) {
|
|
194
|
+
targets.unshift({ id: 'universal', label: 'Universal', root: universalRoot });
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return targets;
|
|
188
198
|
}
|
|
189
199
|
|
|
190
200
|
function targetsForOptions(options) {
|
|
191
201
|
if (options.targets?.length) return targetsByIds(options.targets);
|
|
192
|
-
if (options.agent === 'all') return
|
|
202
|
+
if (options.agent === 'all') return [{ id: 'universal', label: 'Universal', root: universalRoot }, ...targetCatalog];
|
|
193
203
|
return targetsByIds([options.agent]);
|
|
194
204
|
}
|
|
195
205
|
|
|
196
206
|
function skillRootsForTargets(options, targets) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return [...new Set(skillTargets.map((target) => target.root()))];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function guideTargets(targets) {
|
|
203
|
-
return targets.filter((target) => target.kind === 'guide');
|
|
207
|
+
if (options.skillsDir && targets.length) return [options.skillsDir];
|
|
208
|
+
return [...new Set(targets.map((target) => target.root()))];
|
|
204
209
|
}
|
|
205
210
|
|
|
206
211
|
function renderSurvey(selected, cursor) {
|
|
207
212
|
console.clear();
|
|
208
|
-
console.log('
|
|
213
|
+
console.log('Which agents do you want to install Servicemap to?\n');
|
|
214
|
+
console.log('— Universal (.agents/skills) — always included —');
|
|
215
|
+
for (const agent of universalAgents) {
|
|
216
|
+
console.log(` • ${agent}`);
|
|
217
|
+
}
|
|
218
|
+
console.log('\n— Additional agents —');
|
|
209
219
|
console.log('Use ↑/↓, Space to select, Enter to install.\n');
|
|
210
220
|
|
|
211
221
|
targetCatalog.forEach((target, index) => {
|
|
@@ -256,59 +266,18 @@ function runTargetSurvey() {
|
|
|
256
266
|
});
|
|
257
267
|
}
|
|
258
268
|
|
|
259
|
-
function guideText(target) {
|
|
260
|
-
return `# Servicemap for ${target.label}
|
|
261
|
-
|
|
262
|
-
These setup notes help ${target.label} use Servicemap when you want it to create a service map for a software project.
|
|
263
|
-
|
|
264
|
-
Invoke: /servicemap
|
|
265
|
-
|
|
266
|
-
Goal:
|
|
267
|
-
Scan the current project for third-party services, resolve service logos from the bundled Servicemap database, and create an /internalservicemap page when a website is present.
|
|
268
|
-
If no website can be safely found, create a desktop app fallback named servicemap-desktop.
|
|
269
|
-
|
|
270
|
-
Recommended local command:
|
|
271
|
-
\`\`\`bash
|
|
272
|
-
npx servicemap --root <project-path>
|
|
273
|
-
\`\`\`
|
|
274
|
-
|
|
275
|
-
If your agent supports local skills, install the real skill folder with:
|
|
276
|
-
\`\`\`bash
|
|
277
|
-
npx servicemap install-skill --agent all
|
|
278
|
-
\`\`\`
|
|
279
|
-
`;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async function writeGuidePacks(targets, options) {
|
|
283
|
-
const guideRoot = resolve(homedir(), '.servicemap/model-guides');
|
|
284
|
-
for (const target of guideTargets(targets)) {
|
|
285
|
-
const destination = join(guideRoot, target.id);
|
|
286
|
-
if (options.dryRun) {
|
|
287
|
-
console.log(`Would write Servicemap guide for ${target.label} to ${destination}`);
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
await mkdir(destination, { recursive: true });
|
|
291
|
-
await cp(resolve(packageRoot, 'servicemap/SKILL.md'), join(destination, 'SKILL.md'));
|
|
292
|
-
await mkdir(join(destination, 'servicemap'), { recursive: true });
|
|
293
|
-
await cp(resolve(packageRoot, 'servicemap'), join(destination, 'servicemap'), { recursive: true });
|
|
294
|
-
await writeFile(join(destination, 'README.md'), guideText(target));
|
|
295
|
-
console.log(`Wrote Servicemap guide for ${target.label} to ${destination}`);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
269
|
async function installSkill(options) {
|
|
300
270
|
const source = resolve(packageRoot, 'servicemap');
|
|
301
271
|
const selectedTargets = options.survey && !options.yes
|
|
302
|
-
? await runTargetSurvey()
|
|
272
|
+
? [{ id: 'universal', label: 'Universal', root: universalRoot }, ...await runTargetSurvey()]
|
|
303
273
|
: targetsForOptions(options);
|
|
304
274
|
const roots = skillRootsForTargets(options, selectedTargets);
|
|
305
|
-
const notes = guideTargets(selectedTargets);
|
|
306
275
|
|
|
307
276
|
if (!existsSync(source)) {
|
|
308
277
|
throw new Error(`Bundled skill folder not found: ${source}`);
|
|
309
278
|
}
|
|
310
279
|
|
|
311
|
-
if (roots.length === 0
|
|
280
|
+
if (roots.length === 0) {
|
|
312
281
|
console.log('No targets selected. Nothing was installed.');
|
|
313
282
|
return;
|
|
314
283
|
}
|
|
@@ -317,7 +286,6 @@ async function installSkill(options) {
|
|
|
317
286
|
for (const root of roots) {
|
|
318
287
|
console.log(`Would install Servicemap skill to ${join(root, 'servicemap')}`);
|
|
319
288
|
}
|
|
320
|
-
await writeGuidePacks(selectedTargets, options);
|
|
321
289
|
return;
|
|
322
290
|
}
|
|
323
291
|
|
|
@@ -329,11 +297,7 @@ async function installSkill(options) {
|
|
|
329
297
|
console.log(`Installed Servicemap skill to ${destination}`);
|
|
330
298
|
}
|
|
331
299
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (roots.length > 0) {
|
|
335
|
-
console.log('Restart your AI app if /servicemap does not appear immediately.');
|
|
336
|
-
}
|
|
300
|
+
console.log('Restart your AI app if /servicemap does not appear immediately.');
|
|
337
301
|
}
|
|
338
302
|
|
|
339
303
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "servicemap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Generate an internal service map page or desktop app for a software project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"test": "node bin/servicemap.mjs generate --root demo-project --allow-emails founder@example.com,ops@example.com --dry-run && node bin/servicemap.mjs --root no-website-demo --dry-run && node bin/servicemap.mjs --dry-run && HOME=\"$(mktemp -d)\" node bin/servicemap.mjs && node bin/servicemap.mjs install-skill --agent all --dry-run && node bin/servicemap.mjs install-skill --targets
|
|
15
|
+
"test": "node bin/servicemap.mjs generate --root demo-project --allow-emails founder@example.com,ops@example.com --dry-run && node bin/servicemap.mjs --root no-website-demo --dry-run && node bin/servicemap.mjs --dry-run && HOME=\"$(mktemp -d)\" node bin/servicemap.mjs && node bin/servicemap.mjs install-skill --agent all --dry-run && node bin/servicemap.mjs install-skill --targets universal,claude,grok --dry-run && node bin/servicemap.mjs install-skill --targets codex,chatgpt,gpt-6-astra --dry-run && node bin/servicemap.mjs skills install --agent claude --dry-run",
|
|
16
16
|
"validate:skill": "python3 /Users/dougie/.codex/skills/.system/skill-creator/scripts/quick_validate.py servicemap"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|