servicemap 0.1.24 → 0.1.26
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 +16 -0
- package/bin/servicemap.mjs +81 -3
- package/package.json +1 -1
- package/servicemap/SKILL.md +16 -10
package/README.md
CHANGED
|
@@ -41,6 +41,15 @@ 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
|
+
Symlink installs use a stable local clone at `~/.servicemap/source`, so updates can be pulled without reinstalling every agent folder.
|
|
45
|
+
|
|
46
|
+
To update that local skill source:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx servicemap update
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Running `npx servicemap` again also refreshes the stable source before installing.
|
|
44
53
|
|
|
45
54
|
After a global install, the command is:
|
|
46
55
|
|
|
@@ -62,6 +71,8 @@ servicemap generate --root <project-path>
|
|
|
62
71
|
servicemap --root <project-path>
|
|
63
72
|
servicemap generate --root <project-path> --allow-emails founder@example.com,ops@example.com
|
|
64
73
|
servicemap generate --root <project-path> --allow-email founder@example.com --allow-email ops@example.com
|
|
74
|
+
servicemap generate --root <project-path> --deploy
|
|
75
|
+
servicemap generate --root <project-path> --deploy-command "npm run deploy"
|
|
65
76
|
servicemap --mode page
|
|
66
77
|
servicemap --mode desktop
|
|
67
78
|
servicemap --dry-run
|
|
@@ -73,8 +84,13 @@ servicemap install-skill --agent grok
|
|
|
73
84
|
servicemap install-skill --agent all
|
|
74
85
|
servicemap install-skill --targets universal,claude,grok
|
|
75
86
|
servicemap skills install --agent codex
|
|
87
|
+
servicemap update
|
|
76
88
|
```
|
|
77
89
|
|
|
90
|
+
When a website page is generated, Servicemap prompts before deployment when it detects a deployment command.
|
|
91
|
+
It prefers an existing `npm run deploy` script, then provider config such as Vercel or Netlify.
|
|
92
|
+
Use `--no-deploy` to skip the prompt.
|
|
93
|
+
|
|
78
94
|
## Contents
|
|
79
95
|
|
|
80
96
|
- `servicemap/`: installable skill folder
|
package/bin/servicemap.mjs
CHANGED
|
@@ -168,6 +168,8 @@ function parseArgs() {
|
|
|
168
168
|
installMethod: null,
|
|
169
169
|
allowedEmails: [],
|
|
170
170
|
open: true,
|
|
171
|
+
deploy: null,
|
|
172
|
+
deployCommand: null,
|
|
171
173
|
invokedWithoutArgs: args.length === 0,
|
|
172
174
|
explicitCommand: false,
|
|
173
175
|
generationRequested: false,
|
|
@@ -210,6 +212,9 @@ function parseArgs() {
|
|
|
210
212
|
if (arg === '--yes' || arg === '-y') options.yes = true;
|
|
211
213
|
if (arg === '--dry-run') options.dryRun = true;
|
|
212
214
|
if (arg === '--no-open') options.open = false;
|
|
215
|
+
if (arg === '--deploy') options.deploy = true;
|
|
216
|
+
if (arg === '--no-deploy') options.deploy = false;
|
|
217
|
+
if (arg === '--deploy-command') options.deployCommand = args[++index] ?? null;
|
|
213
218
|
if (arg === '--help' || arg === '-h') options.help = true;
|
|
214
219
|
}
|
|
215
220
|
|
|
@@ -222,20 +227,24 @@ function help() {
|
|
|
222
227
|
|
|
223
228
|
Usage:
|
|
224
229
|
servicemap
|
|
225
|
-
servicemap generate [--root <project>] [--mode auto|page|desktop] [--allow-emails <list>] [--dry-run] [--no-open]
|
|
226
|
-
servicemap --root <project> [--mode auto|page|desktop] [--allow-emails <list>] [--dry-run] [--no-open]
|
|
230
|
+
servicemap generate [--root <project>] [--mode auto|page|desktop] [--allow-emails <list>] [--dry-run] [--no-open] [--deploy|--no-deploy]
|
|
231
|
+
servicemap --root <project> [--mode auto|page|desktop] [--allow-emails <list>] [--dry-run] [--no-open] [--deploy|--no-deploy]
|
|
227
232
|
servicemap install-skill [--survey] [--agent codex|claude|grok|all] [--targets <ids>] [--install-method copy|symlink]
|
|
228
233
|
servicemap skills install [--survey] [--agent codex|claude|grok|all]
|
|
234
|
+
servicemap update
|
|
229
235
|
|
|
230
236
|
Examples:
|
|
231
237
|
npx servicemap
|
|
232
238
|
npx servicemap generate --root ../my-app --allow-emails founder@example.com,ops@example.com
|
|
239
|
+
npx servicemap generate --root ../my-app --deploy
|
|
240
|
+
npx servicemap generate --root ../my-app --deploy-command "npm run deploy"
|
|
233
241
|
npx servicemap -- --root ../my-app
|
|
234
242
|
npx servicemap install-skill
|
|
235
243
|
npx servicemap install-skill --survey
|
|
236
244
|
npx servicemap install-skill --agent all
|
|
237
245
|
npx servicemap install-skill --targets codex,claude,cursor
|
|
238
246
|
npx servicemap skills install --agent claude
|
|
247
|
+
npx servicemap update
|
|
239
248
|
servicemap --mode desktop
|
|
240
249
|
`);
|
|
241
250
|
}
|
|
@@ -255,6 +264,23 @@ function run(command, args, options = {}) {
|
|
|
255
264
|
});
|
|
256
265
|
}
|
|
257
266
|
|
|
267
|
+
function runShell(command, options = {}) {
|
|
268
|
+
const shell = process.platform === 'win32' ? 'cmd' : 'sh';
|
|
269
|
+
const args = process.platform === 'win32' ? ['/c', command] : ['-lc', command];
|
|
270
|
+
return run(shell, args, options);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function askYesNo(question) {
|
|
274
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return Promise.resolve(false);
|
|
275
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
276
|
+
return new Promise((resolvePromise) => {
|
|
277
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
278
|
+
rl.close();
|
|
279
|
+
resolvePromise(/^y(es)?$/i.test(answer.trim()));
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
258
284
|
function openUrl(url) {
|
|
259
285
|
const command = process.platform === 'darwin'
|
|
260
286
|
? 'open'
|
|
@@ -350,6 +376,47 @@ async function readScan(root) {
|
|
|
350
376
|
return JSON.parse(await readFile(scanPath, 'utf8'));
|
|
351
377
|
}
|
|
352
378
|
|
|
379
|
+
async function packageJsonFor(root) {
|
|
380
|
+
return JSON.parse(await readFile(resolve(root, 'package.json'), 'utf8').catch(() => '{}'));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function detectDeployCommand(root, options) {
|
|
384
|
+
if (options.deployCommand) return options.deployCommand;
|
|
385
|
+
const packageJson = await packageJsonFor(root);
|
|
386
|
+
if (packageJson.scripts?.deploy) return 'npm run deploy';
|
|
387
|
+
if (existsSync(resolve(root, 'vercel.json')) || existsSync(resolve(root, '.vercel/project.json'))) {
|
|
388
|
+
return 'npx vercel --prod';
|
|
389
|
+
}
|
|
390
|
+
if (existsSync(resolve(root, 'netlify.toml'))) {
|
|
391
|
+
return 'npx netlify deploy --prod';
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function maybeDeploy(root, options) {
|
|
397
|
+
if (options.deploy === false) return;
|
|
398
|
+
const command = await detectDeployCommand(root, options);
|
|
399
|
+
if (!command) {
|
|
400
|
+
if (options.deploy === true) {
|
|
401
|
+
console.log('No deploy command was detected. Add a deploy script or pass --deploy-command "<command>".');
|
|
402
|
+
} else {
|
|
403
|
+
console.log('Generated /internalservicemap. Deploy manually, or pass --deploy-command next time.');
|
|
404
|
+
}
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const shouldDeploy = options.deploy === true
|
|
409
|
+
? true
|
|
410
|
+
: await askYesNo(`Deploy /internalservicemap now with "${command}"?`);
|
|
411
|
+
if (!shouldDeploy) {
|
|
412
|
+
console.log(`Skipped deployment. To deploy later, run: ${command}`);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
console.log(`Deploying with: ${command}`);
|
|
417
|
+
await runShell(command, { cwd: root });
|
|
418
|
+
}
|
|
419
|
+
|
|
353
420
|
function targetsByIds(ids) {
|
|
354
421
|
const byId = new Map(targetCatalog.map((target) => [target.id, target]));
|
|
355
422
|
const targets = [];
|
|
@@ -593,6 +660,11 @@ async function prepareStableSource(options) {
|
|
|
593
660
|
return resolve(sourceRoot, 'servicemap');
|
|
594
661
|
}
|
|
595
662
|
|
|
663
|
+
async function updateStableSource(options) {
|
|
664
|
+
const source = await prepareStableSource(options);
|
|
665
|
+
console.log(`Servicemap source is current at ${dirname(source)}`);
|
|
666
|
+
}
|
|
667
|
+
|
|
596
668
|
async function installIntoRoot(root, source, method, options) {
|
|
597
669
|
const destination = join(root, 'servicemap');
|
|
598
670
|
if (options.dryRun) {
|
|
@@ -667,8 +739,13 @@ async function main() {
|
|
|
667
739
|
return;
|
|
668
740
|
}
|
|
669
741
|
|
|
742
|
+
if (options.command === 'update') {
|
|
743
|
+
await updateStableSource(options);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
|
|
670
747
|
if (options.command !== 'generate') {
|
|
671
|
-
throw new Error(`Unknown command "${options.command}". Use generate, install-skill, or skills install.`);
|
|
748
|
+
throw new Error(`Unknown command "${options.command}". Use generate, install-skill, update, or skills install.`);
|
|
672
749
|
}
|
|
673
750
|
|
|
674
751
|
if (!['auto', 'page', 'desktop'].includes(options.mode)) {
|
|
@@ -697,6 +774,7 @@ async function main() {
|
|
|
697
774
|
} else {
|
|
698
775
|
await run(process.execPath, [pageScript, '--root', options.root]);
|
|
699
776
|
if (options.open) await openGeneratedPage(options.root, scan.project?.framework);
|
|
777
|
+
await maybeDeploy(options.root, options);
|
|
700
778
|
}
|
|
701
779
|
}
|
|
702
780
|
|
package/package.json
CHANGED
package/servicemap/SKILL.md
CHANGED
|
@@ -13,16 +13,21 @@ If no website can be found, create a desktop app fallback at `servicemap-desktop
|
|
|
13
13
|
|
|
14
14
|
## Workflow
|
|
15
15
|
|
|
16
|
-
1.
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
1. If this skill is installed from the stable source clone at `~/.servicemap/source`, run `git -C ~/.servicemap/source pull --ff-only` before using the scripts.
|
|
17
|
+
If the update fails because the network is unavailable, continue with the installed local copy and report that the auto-update did not complete.
|
|
18
|
+
2. Inspect the project layout and current web framework.
|
|
19
|
+
3. If the user gives a list of emails that may access the generated web page, pass them to the scan command with `--allow-email <email>` for each address or `--allow-emails <comma-separated-list>`.
|
|
20
|
+
4. Run `scripts/scan-project.mjs --root <project-root>` to create `.servicemap/internal-servicemap.json`.
|
|
19
21
|
Include the access flags from the previous step when relevant.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
5. Review the scan output for obvious false positives or missing high-confidence services.
|
|
23
|
+
6. If the scan detects a web framework or routeable website, run `scripts/generate-page.mjs --root <project-root>` to create the framework-specific `/internalservicemap` route.
|
|
24
|
+
7. If the scan reports `framework: static` or no website route can be safely attached, run `scripts/generate-desktop-app.mjs --root <project-root>` to create `servicemap-desktop`.
|
|
25
|
+
8. Adapt the generated surface to the project's existing design system only when the route is clear and the edits are low-risk.
|
|
26
|
+
9. Run the project's relevant build, lint, and focused tests.
|
|
27
|
+
10. If a website page was created, tell the user it is only local until deployed and ask whether they want to deploy it now.
|
|
28
|
+
Do not deploy unless the user explicitly says yes.
|
|
29
|
+
If they approve, use the project's existing deployment path, preferring `npm run deploy` when present, then provider-specific project configuration such as Vercel or Netlify.
|
|
30
|
+
11. Report the page or desktop app path, service count, validation run, any services marked low or medium confidence, whether requested email access was enforced, and whether deployment was skipped or completed.
|
|
26
31
|
|
|
27
32
|
## Safety Rules
|
|
28
33
|
|
|
@@ -30,7 +35,8 @@ Read environment variable names only.
|
|
|
30
35
|
Never copy, expose, summarize, or commit secret values.
|
|
31
36
|
The scan output may include env var names such as `STRIPE_SECRET_KEY`, but not their values.
|
|
32
37
|
|
|
33
|
-
Do not add authentication,
|
|
38
|
+
Do not add authentication, analytics, or external writes unless the user explicitly asks.
|
|
39
|
+
Deploy only after the generated website page exists and the user has confirmed deployment.
|
|
34
40
|
If the repository already has route protection conventions for internal pages, follow them.
|
|
35
41
|
When email access is requested, enforce it only through the app's existing server-side authentication.
|
|
36
42
|
The built-in generator can enforce email allowlists for Next.js App Router projects using Clerk by checking `currentUser()` against the configured emails.
|