servicemap 0.1.0 → 0.1.4
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 +47 -2
- package/bin/servicemap.mjs +268 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,12 +6,43 @@ The skill scans a software project for external services, resolves service logos
|
|
|
6
6
|
|
|
7
7
|
## Terminal Use
|
|
8
8
|
|
|
9
|
-
The npm package name `servicemap` is available, so users can run the clean command:
|
|
9
|
+
The npm package name `servicemap` is available, so users can run the clean command and choose where to install it:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
npx servicemap
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
That opens the interactive install survey.
|
|
16
|
+
It lets users choose compatible AI coding agents and model environments.
|
|
17
|
+
|
|
18
|
+
To install the bundled AI skill so `/servicemap` appears in compatible coding agents:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx servicemap install-skill
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To use an interactive Caveman-style terminal survey:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx servicemap install-skill --survey
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That installs to the Codex-style user skill folder, matching the way Caveman installs a local skill folder.
|
|
31
|
+
To install for several agents on the same computer:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx servicemap install-skill --agent all
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The Caveman-style command shape also works:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx servicemap skills install --agent claude
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Agents with known local skill folders get the real `servicemap` skill installed.
|
|
44
|
+
Other selected AI tools get a portable guide pack under `~/.servicemap/model-guides`.
|
|
45
|
+
|
|
15
46
|
After a global install, the command is:
|
|
16
47
|
|
|
17
48
|
```bash
|
|
@@ -27,10 +58,20 @@ npm install -g servicemap
|
|
|
27
58
|
CLI options:
|
|
28
59
|
|
|
29
60
|
```bash
|
|
61
|
+
servicemap
|
|
62
|
+
servicemap generate --root <project-path>
|
|
30
63
|
servicemap --root <project-path>
|
|
31
64
|
servicemap --mode page
|
|
32
65
|
servicemap --mode desktop
|
|
33
66
|
servicemap --dry-run
|
|
67
|
+
servicemap install-skill
|
|
68
|
+
servicemap install-skill --survey
|
|
69
|
+
servicemap install-skill --agent codex
|
|
70
|
+
servicemap install-skill --agent claude
|
|
71
|
+
servicemap install-skill --agent grok
|
|
72
|
+
servicemap install-skill --agent all
|
|
73
|
+
servicemap install-skill --targets codex,chatgpt,cursor
|
|
74
|
+
servicemap skills install --agent codex
|
|
34
75
|
```
|
|
35
76
|
|
|
36
77
|
## Contents
|
|
@@ -45,7 +86,11 @@ servicemap --dry-run
|
|
|
45
86
|
## Validation
|
|
46
87
|
|
|
47
88
|
```bash
|
|
48
|
-
node bin/servicemap.mjs --root demo-project --dry-run
|
|
89
|
+
node bin/servicemap.mjs generate --root demo-project --dry-run
|
|
49
90
|
node bin/servicemap.mjs --root no-website-demo --dry-run
|
|
91
|
+
node bin/servicemap.mjs --dry-run
|
|
92
|
+
node bin/servicemap.mjs install-skill --agent all --dry-run
|
|
93
|
+
node bin/servicemap.mjs install-skill --targets codex,chatgpt,cursor --dry-run
|
|
94
|
+
node bin/servicemap.mjs skills install --agent claude --dry-run
|
|
50
95
|
python3 /Users/dougie/.codex/skills/.system/skill-creator/scripts/quick_validate.py servicemap
|
|
51
96
|
```
|
package/bin/servicemap.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import readline from 'node:readline';
|
|
5
8
|
import { fileURLToPath } from 'node:url';
|
|
6
9
|
|
|
7
10
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -9,18 +12,100 @@ const scanScript = resolve(packageRoot, 'servicemap/scripts/scan-project.mjs');
|
|
|
9
12
|
const pageScript = resolve(packageRoot, 'servicemap/scripts/generate-page.mjs');
|
|
10
13
|
const desktopScript = resolve(packageRoot, 'servicemap/scripts/generate-desktop-app.mjs');
|
|
11
14
|
|
|
15
|
+
const targetCatalog = [
|
|
16
|
+
{ id: 'codex', label: 'Codex / ChatGPT desktop', kind: 'skill', root: () => resolve(homedir(), '.agents/skills'), recommended: true },
|
|
17
|
+
{ id: 'claude', label: 'Claude Code', kind: 'skill', root: () => resolve(homedir(), '.claude/skills'), recommended: true },
|
|
18
|
+
{ id: 'grok', label: 'Grok', kind: 'skill', root: () => resolve(homedir(), '.grok/skills'), recommended: true },
|
|
19
|
+
{ id: 'chatgpt', label: 'ChatGPT', kind: 'guide' },
|
|
20
|
+
{ id: 'gpt-6-astra', label: 'GPT-6 Astra', kind: 'guide' },
|
|
21
|
+
{ id: 'gpt-6-sol', label: 'GPT-6 Sol', kind: 'guide' },
|
|
22
|
+
{ id: 'gpt-6-luna', label: 'GPT-6 Luna', kind: 'guide' },
|
|
23
|
+
{ id: 'gpt-5.6-sol', label: 'GPT-5.6 Sol', kind: 'guide' },
|
|
24
|
+
{ id: 'gpt-5.6-terra', label: 'GPT-5.6 Terra', kind: 'guide' },
|
|
25
|
+
{ id: 'gpt-5.6-luna', label: 'GPT-5.6 Luna', kind: 'guide' },
|
|
26
|
+
{ id: 'claude-opus', label: 'Claude Opus', kind: 'guide' },
|
|
27
|
+
{ id: 'claude-sonnet', label: 'Claude Sonnet', kind: 'guide' },
|
|
28
|
+
{ id: 'claude-haiku', label: 'Claude Haiku', kind: 'guide' },
|
|
29
|
+
{ id: 'gemini-pro', label: 'Gemini Pro', kind: 'guide' },
|
|
30
|
+
{ id: 'gemini-flash', label: 'Gemini Flash', kind: 'guide' },
|
|
31
|
+
{ id: 'cursor', label: 'Cursor', kind: 'guide' },
|
|
32
|
+
{ id: 'windsurf', label: 'Windsurf', kind: 'guide' },
|
|
33
|
+
{ id: 'copilot', label: 'GitHub Copilot', kind: 'guide' },
|
|
34
|
+
{ id: 'vscode-chat', label: 'VS Code Chat', kind: 'guide' },
|
|
35
|
+
{ id: 'continue', label: 'Continue.dev', kind: 'guide' },
|
|
36
|
+
{ id: 'aider', label: 'Aider', kind: 'guide' },
|
|
37
|
+
{ id: 'cline', label: 'Cline', kind: 'guide' },
|
|
38
|
+
{ id: 'roo-code', label: 'Roo Code', kind: 'guide' },
|
|
39
|
+
{ id: 'zed-ai', label: 'Zed AI', kind: 'guide' },
|
|
40
|
+
{ id: 'replit-agent', label: 'Replit Agent', kind: 'guide' },
|
|
41
|
+
{ id: 'lovable', label: 'Lovable', kind: 'guide' },
|
|
42
|
+
{ id: 'bolt', label: 'Bolt', kind: 'guide' },
|
|
43
|
+
{ id: 'v0', label: 'v0', kind: 'guide' },
|
|
44
|
+
{ id: 'perplexity', label: 'Perplexity', kind: 'guide' },
|
|
45
|
+
{ id: 'mistral', label: 'Mistral Le Chat', kind: 'guide' },
|
|
46
|
+
{ id: 'deepseek', label: 'DeepSeek', kind: 'guide' },
|
|
47
|
+
{ id: 'qwen', label: 'Qwen', kind: 'guide' },
|
|
48
|
+
{ id: 'llama', label: 'Llama', kind: 'guide' },
|
|
49
|
+
{ id: 'ollama', label: 'Ollama', kind: 'guide' },
|
|
50
|
+
{ id: 'lm-studio', label: 'LM Studio', kind: 'guide' },
|
|
51
|
+
{ id: 'openrouter', label: 'OpenRouter', kind: 'guide' },
|
|
52
|
+
{ id: 'anthropic-api', label: 'Anthropic API apps', kind: 'guide' },
|
|
53
|
+
{ id: 'openai-api', label: 'OpenAI API apps', kind: 'guide' },
|
|
54
|
+
{ id: 'gemini-api', label: 'Gemini API apps', kind: 'guide' },
|
|
55
|
+
{ id: 'bedrock', label: 'Amazon Bedrock', kind: 'guide' },
|
|
56
|
+
{ id: 'azure-openai', label: 'Azure OpenAI', kind: 'guide' },
|
|
57
|
+
{ id: 'vertex-ai', label: 'Vertex AI', kind: 'guide' },
|
|
58
|
+
{ id: 'poe', label: 'Poe', kind: 'guide' },
|
|
59
|
+
{ id: 'you-com', label: 'You.com', kind: 'guide' },
|
|
60
|
+
{ id: 'phind', label: 'Phind', kind: 'guide' },
|
|
61
|
+
{ id: 'sourcegraph-cody', label: 'Sourcegraph Cody', kind: 'guide' },
|
|
62
|
+
{ id: 'tabnine', label: 'Tabnine', kind: 'guide' },
|
|
63
|
+
{ id: 'codeium', label: 'Codeium', kind: 'guide' },
|
|
64
|
+
{ id: 'jetbrains-ai', label: 'JetBrains AI', kind: 'guide' },
|
|
65
|
+
{ id: 'custom', label: 'Other custom model or agent', kind: 'guide' },
|
|
66
|
+
];
|
|
67
|
+
|
|
12
68
|
function parseArgs() {
|
|
13
69
|
const args = process.argv.slice(2);
|
|
14
70
|
const options = {
|
|
71
|
+
command: 'generate',
|
|
15
72
|
root: process.cwd(),
|
|
16
73
|
mode: 'auto',
|
|
17
74
|
dryRun: false,
|
|
75
|
+
agent: 'codex',
|
|
76
|
+
targets: null,
|
|
77
|
+
skillsDir: null,
|
|
78
|
+
invokedWithoutArgs: args.length === 0,
|
|
79
|
+
explicitCommand: false,
|
|
80
|
+
generationRequested: false,
|
|
18
81
|
};
|
|
19
82
|
|
|
83
|
+
if (args[0] === 'skills' && args[1] === 'install') {
|
|
84
|
+
options.command = 'install-skill';
|
|
85
|
+
args.splice(0, 2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (args[0] && !args[0].startsWith('-')) {
|
|
89
|
+
options.command = args.shift();
|
|
90
|
+
options.explicitCommand = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
20
93
|
for (let index = 0; index < args.length; index += 1) {
|
|
21
94
|
const arg = args[index];
|
|
22
|
-
if (arg === '--root')
|
|
23
|
-
|
|
95
|
+
if (arg === '--root') {
|
|
96
|
+
options.root = args[++index] ?? options.root;
|
|
97
|
+
options.generationRequested = true;
|
|
98
|
+
}
|
|
99
|
+
if (arg === '--mode') {
|
|
100
|
+
options.mode = args[++index] ?? options.mode;
|
|
101
|
+
options.generationRequested = true;
|
|
102
|
+
}
|
|
103
|
+
if (arg === '--agent') options.agent = args[++index] ?? options.agent;
|
|
104
|
+
if (arg === '--targets') options.targets = (args[++index] ?? '').split(',').map((target) => target.trim()).filter(Boolean);
|
|
105
|
+
if (arg === '--skills-dir') options.skillsDir = resolve(args[++index] ?? '.');
|
|
106
|
+
if (arg === '--user') options.user = true;
|
|
107
|
+
if (arg === '--survey') options.survey = true;
|
|
108
|
+
if (arg === '--yes' || arg === '-y') options.yes = true;
|
|
24
109
|
if (arg === '--dry-run') options.dryRun = true;
|
|
25
110
|
if (arg === '--help' || arg === '-h') options.help = true;
|
|
26
111
|
}
|
|
@@ -33,11 +118,21 @@ function help() {
|
|
|
33
118
|
console.log(`Servicemap
|
|
34
119
|
|
|
35
120
|
Usage:
|
|
36
|
-
servicemap
|
|
121
|
+
servicemap
|
|
122
|
+
servicemap generate [--root <project>] [--mode auto|page|desktop] [--dry-run]
|
|
123
|
+
servicemap --root <project> [--mode auto|page|desktop] [--dry-run]
|
|
124
|
+
servicemap install-skill [--survey] [--agent codex|claude|grok|all] [--targets <ids>]
|
|
125
|
+
servicemap skills install [--survey] [--agent codex|claude|grok|all]
|
|
37
126
|
|
|
38
127
|
Examples:
|
|
39
128
|
npx servicemap
|
|
129
|
+
npx servicemap generate --root ../my-app
|
|
40
130
|
npx servicemap -- --root ../my-app
|
|
131
|
+
npx servicemap install-skill
|
|
132
|
+
npx servicemap install-skill --survey
|
|
133
|
+
npx servicemap install-skill --agent all
|
|
134
|
+
npx servicemap install-skill --targets codex,claude,cursor
|
|
135
|
+
npx servicemap skills install --agent claude
|
|
41
136
|
servicemap --mode desktop
|
|
42
137
|
`);
|
|
43
138
|
}
|
|
@@ -62,6 +157,160 @@ async function readScan(root) {
|
|
|
62
157
|
return JSON.parse(await readFile(scanPath, 'utf8'));
|
|
63
158
|
}
|
|
64
159
|
|
|
160
|
+
function targetsByIds(ids) {
|
|
161
|
+
const byId = new Map(targetCatalog.map((target) => [target.id, target]));
|
|
162
|
+
return ids.map((id) => {
|
|
163
|
+
const target = byId.get(id);
|
|
164
|
+
if (!target) {
|
|
165
|
+
throw new Error(`Unknown target "${id}". Use --survey to choose from the list.`);
|
|
166
|
+
}
|
|
167
|
+
return target;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function targetsForOptions(options) {
|
|
172
|
+
if (options.targets?.length) return targetsByIds(options.targets);
|
|
173
|
+
if (options.agent === 'all') return targetCatalog.filter((target) => target.kind === 'skill');
|
|
174
|
+
if (options.agent === 'agents') return targetsByIds(['codex']);
|
|
175
|
+
return targetsByIds([options.agent]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function skillRootsForTargets(options, targets) {
|
|
179
|
+
const skillTargets = targets.filter((target) => target.kind === 'skill');
|
|
180
|
+
if (options.skillsDir && skillTargets.length) return [options.skillsDir];
|
|
181
|
+
return [...new Set(skillTargets.map((target) => target.root()))];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function guideTargets(targets) {
|
|
185
|
+
return targets.filter((target) => target.kind === 'guide');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function renderSurvey(selected, cursor) {
|
|
189
|
+
console.clear();
|
|
190
|
+
console.log('Where should Servicemap be available?');
|
|
191
|
+
console.log('Use ↑/↓, Space to select, Enter to install.\n');
|
|
192
|
+
|
|
193
|
+
targetCatalog.forEach((target, index) => {
|
|
194
|
+
const pointer = index === cursor ? '>' : ' ';
|
|
195
|
+
const checked = selected.has(target.id) ? 'x' : ' ';
|
|
196
|
+
const detail = target.kind === 'skill' ? 'skill folder' : 'portable guide';
|
|
197
|
+
console.log(`${pointer} [${checked}] ${target.label} (${detail})`);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function runTargetSurvey() {
|
|
202
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
203
|
+
return Promise.resolve(targetCatalog.filter((target) => target.recommended));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const selected = new Set(targetCatalog.filter((target) => target.recommended).map((target) => target.id));
|
|
207
|
+
let cursor = 0;
|
|
208
|
+
|
|
209
|
+
return new Promise((resolvePromise) => {
|
|
210
|
+
readline.emitKeypressEvents(process.stdin);
|
|
211
|
+
process.stdin.setRawMode(true);
|
|
212
|
+
renderSurvey(selected, cursor);
|
|
213
|
+
|
|
214
|
+
const onKeypress = (_str, key) => {
|
|
215
|
+
if (key.name === 'up') cursor = (cursor - 1 + targetCatalog.length) % targetCatalog.length;
|
|
216
|
+
if (key.name === 'down') cursor = (cursor + 1) % targetCatalog.length;
|
|
217
|
+
if (key.name === 'space') {
|
|
218
|
+
const id = targetCatalog[cursor].id;
|
|
219
|
+
if (selected.has(id)) selected.delete(id);
|
|
220
|
+
else selected.add(id);
|
|
221
|
+
}
|
|
222
|
+
if (key.name === 'return') {
|
|
223
|
+
process.stdin.setRawMode(false);
|
|
224
|
+
process.stdin.off('keypress', onKeypress);
|
|
225
|
+
console.log('');
|
|
226
|
+
resolvePromise(targetCatalog.filter((target) => selected.has(target.id)));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (key.ctrl && key.name === 'c') {
|
|
230
|
+
process.stdin.setRawMode(false);
|
|
231
|
+
process.stdin.off('keypress', onKeypress);
|
|
232
|
+
process.exit(130);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
renderSurvey(selected, cursor);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
process.stdin.on('keypress', onKeypress);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function guideText(target) {
|
|
243
|
+
return `# Servicemap for ${target.label}
|
|
244
|
+
|
|
245
|
+
Use this instruction with ${target.label} when you want it to create a service map for a software project.
|
|
246
|
+
|
|
247
|
+
Invoke: /servicemap
|
|
248
|
+
|
|
249
|
+
Goal:
|
|
250
|
+
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.
|
|
251
|
+
If no website can be safely found, create a desktop app fallback named servicemap-desktop.
|
|
252
|
+
|
|
253
|
+
Recommended local command:
|
|
254
|
+
\`\`\`bash
|
|
255
|
+
npx servicemap --root <project-path>
|
|
256
|
+
\`\`\`
|
|
257
|
+
|
|
258
|
+
If your agent supports local skills, install the real skill folder with:
|
|
259
|
+
\`\`\`bash
|
|
260
|
+
npx servicemap install-skill --agent all
|
|
261
|
+
\`\`\`
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function writeGuidePacks(targets, options) {
|
|
266
|
+
const guideRoot = resolve(homedir(), '.servicemap/model-guides');
|
|
267
|
+
for (const target of guideTargets(targets)) {
|
|
268
|
+
const destination = join(guideRoot, target.id);
|
|
269
|
+
if (options.dryRun) {
|
|
270
|
+
console.log(`Would write Servicemap guide for ${target.label} to ${destination}`);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
await mkdir(destination, { recursive: true });
|
|
274
|
+
await cp(resolve(packageRoot, 'servicemap/SKILL.md'), join(destination, 'SKILL.md'));
|
|
275
|
+
await mkdir(join(destination, 'servicemap'), { recursive: true });
|
|
276
|
+
await cp(resolve(packageRoot, 'servicemap'), join(destination, 'servicemap'), { recursive: true });
|
|
277
|
+
await writeFile(join(destination, 'README.md'), guideText(target));
|
|
278
|
+
console.log(`Wrote Servicemap guide for ${target.label} to ${destination}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function installSkill(options) {
|
|
283
|
+
const source = resolve(packageRoot, 'servicemap');
|
|
284
|
+
const selectedTargets = options.survey && !options.yes
|
|
285
|
+
? await runTargetSurvey()
|
|
286
|
+
: targetsForOptions(options);
|
|
287
|
+
const roots = skillRootsForTargets(options, selectedTargets);
|
|
288
|
+
|
|
289
|
+
if (!existsSync(source)) {
|
|
290
|
+
throw new Error(`Bundled skill folder not found: ${source}`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (options.dryRun) {
|
|
294
|
+
for (const root of roots) {
|
|
295
|
+
console.log(`Would install Servicemap skill to ${join(root, 'servicemap')}`);
|
|
296
|
+
}
|
|
297
|
+
await writeGuidePacks(selectedTargets, options);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
for (const root of roots) {
|
|
302
|
+
const destination = join(root, 'servicemap');
|
|
303
|
+
await mkdir(root, { recursive: true });
|
|
304
|
+
await rm(destination, { recursive: true, force: true });
|
|
305
|
+
await cp(source, destination, { recursive: true });
|
|
306
|
+
console.log(`Installed Servicemap skill to ${destination}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
await writeGuidePacks(selectedTargets, options);
|
|
310
|
+
|
|
311
|
+
console.log('Restart your AI app if /servicemap does not appear immediately.');
|
|
312
|
+
}
|
|
313
|
+
|
|
65
314
|
async function main() {
|
|
66
315
|
const options = parseArgs();
|
|
67
316
|
if (options.help) {
|
|
@@ -69,6 +318,20 @@ async function main() {
|
|
|
69
318
|
return;
|
|
70
319
|
}
|
|
71
320
|
|
|
321
|
+
if (options.command === 'generate' && !options.explicitCommand && !options.generationRequested) {
|
|
322
|
+
options.command = 'install-skill';
|
|
323
|
+
options.survey = true;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (options.command === 'install-skill' || options.command === 'install') {
|
|
327
|
+
await installSkill(options);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (options.command !== 'generate') {
|
|
332
|
+
throw new Error(`Unknown command "${options.command}". Use generate, install-skill, or skills install.`);
|
|
333
|
+
}
|
|
334
|
+
|
|
72
335
|
if (!['auto', 'page', 'desktop'].includes(options.mode)) {
|
|
73
336
|
throw new Error(`Unknown mode "${options.mode}". Use auto, page, or desktop.`);
|
|
74
337
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "servicemap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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 --root demo-project --dry-run && node bin/servicemap.mjs --root no-website-demo --dry-run",
|
|
15
|
+
"test": "node bin/servicemap.mjs generate --root demo-project --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 codex,chatgpt,cursor --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": [
|