servicemap 0.1.25 → 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 +6 -0
- package/bin/servicemap.mjs +68 -2
- package/package.json +1 -1
- package/servicemap/SKILL.md +6 -2
package/README.md
CHANGED
|
@@ -71,6 +71,8 @@ servicemap generate --root <project-path>
|
|
|
71
71
|
servicemap --root <project-path>
|
|
72
72
|
servicemap generate --root <project-path> --allow-emails founder@example.com,ops@example.com
|
|
73
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"
|
|
74
76
|
servicemap --mode page
|
|
75
77
|
servicemap --mode desktop
|
|
76
78
|
servicemap --dry-run
|
|
@@ -85,6 +87,10 @@ servicemap skills install --agent codex
|
|
|
85
87
|
servicemap update
|
|
86
88
|
```
|
|
87
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
|
+
|
|
88
94
|
## Contents
|
|
89
95
|
|
|
90
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,8 +227,8 @@ 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]
|
|
229
234
|
servicemap update
|
|
@@ -231,6 +236,8 @@ Usage:
|
|
|
231
236
|
Examples:
|
|
232
237
|
npx servicemap
|
|
233
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"
|
|
234
241
|
npx servicemap -- --root ../my-app
|
|
235
242
|
npx servicemap install-skill
|
|
236
243
|
npx servicemap install-skill --survey
|
|
@@ -257,6 +264,23 @@ function run(command, args, options = {}) {
|
|
|
257
264
|
});
|
|
258
265
|
}
|
|
259
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
|
+
|
|
260
284
|
function openUrl(url) {
|
|
261
285
|
const command = process.platform === 'darwin'
|
|
262
286
|
? 'open'
|
|
@@ -352,6 +376,47 @@ async function readScan(root) {
|
|
|
352
376
|
return JSON.parse(await readFile(scanPath, 'utf8'));
|
|
353
377
|
}
|
|
354
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
|
+
|
|
355
420
|
function targetsByIds(ids) {
|
|
356
421
|
const byId = new Map(targetCatalog.map((target) => [target.id, target]));
|
|
357
422
|
const targets = [];
|
|
@@ -709,6 +774,7 @@ async function main() {
|
|
|
709
774
|
} else {
|
|
710
775
|
await run(process.execPath, [pageScript, '--root', options.root]);
|
|
711
776
|
if (options.open) await openGeneratedPage(options.root, scan.project?.framework);
|
|
777
|
+
await maybeDeploy(options.root, options);
|
|
712
778
|
}
|
|
713
779
|
}
|
|
714
780
|
|
package/package.json
CHANGED
package/servicemap/SKILL.md
CHANGED
|
@@ -24,7 +24,10 @@ If no website can be found, create a desktop app fallback at `servicemap-desktop
|
|
|
24
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
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
26
|
9. Run the project's relevant build, lint, and focused tests.
|
|
27
|
-
10.
|
|
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.
|
|
28
31
|
|
|
29
32
|
## Safety Rules
|
|
30
33
|
|
|
@@ -32,7 +35,8 @@ Read environment variable names only.
|
|
|
32
35
|
Never copy, expose, summarize, or commit secret values.
|
|
33
36
|
The scan output may include env var names such as `STRIPE_SECRET_KEY`, but not their values.
|
|
34
37
|
|
|
35
|
-
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.
|
|
36
40
|
If the repository already has route protection conventions for internal pages, follow them.
|
|
37
41
|
When email access is requested, enforce it only through the app's existing server-side authentication.
|
|
38
42
|
The built-in generator can enforce email allowlists for Next.js App Router projects using Clerk by checking `currentUser()` against the configured emails.
|