@somewhere-tech/cli 0.12.9 → 0.15.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 (72) hide show
  1. package/README.md +59 -1
  2. package/bin/swpm.js +9 -0
  3. package/bin/swpx.js +9 -0
  4. package/dist/commands/auth.js +5 -5
  5. package/dist/commands/auth.js.map +1 -1
  6. package/dist/commands/db.js +1 -1
  7. package/dist/commands/db.js.map +1 -1
  8. package/dist/commands/deploy.js +1 -1
  9. package/dist/commands/deploy.js.map +1 -1
  10. package/dist/commands/dev.js +2 -2
  11. package/dist/commands/dev.js.map +1 -1
  12. package/dist/commands/init.js +7 -7
  13. package/dist/commands/init.js.map +1 -1
  14. package/dist/commands/mcp.js +9 -8
  15. package/dist/commands/mcp.js.map +1 -1
  16. package/dist/commands/open.js +1 -1
  17. package/dist/commands/open.js.map +1 -1
  18. package/dist/commands/project.js +1 -1
  19. package/dist/commands/project.js.map +1 -1
  20. package/dist/commands/promote.js +1 -1
  21. package/dist/commands/promote.js.map +1 -1
  22. package/dist/commands/pull.js +1 -1
  23. package/dist/commands/pull.js.map +1 -1
  24. package/dist/commands/rollback.js +1 -1
  25. package/dist/commands/rollback.js.map +1 -1
  26. package/dist/commands/swpx.js +43 -0
  27. package/dist/commands/swpx.js.map +1 -0
  28. package/dist/commands/typecheck.js +1 -1
  29. package/dist/commands/typecheck.js.map +1 -1
  30. package/dist/index.js +6 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/lib/auth.js +8 -3
  33. package/dist/lib/auth.js.map +1 -1
  34. package/dist/lib/client.js +57 -1
  35. package/dist/lib/client.js.map +1 -1
  36. package/dist/lib/config.js +37 -19
  37. package/dist/lib/config.js.map +1 -1
  38. package/dist/lib/device-login.js +4 -1
  39. package/dist/lib/device-login.js.map +1 -1
  40. package/dist/lib/open.js +25 -0
  41. package/dist/lib/open.js.map +1 -0
  42. package/dist/lib/output.js +11 -7
  43. package/dist/lib/output.js.map +1 -1
  44. package/dist/lib/spinner.js +85 -0
  45. package/dist/lib/spinner.js.map +1 -0
  46. package/dist/swpm-bin.js +11 -0
  47. package/dist/swpm-bin.js.map +1 -0
  48. package/dist/swpx/check.js +56 -0
  49. package/dist/swpx/check.js.map +1 -0
  50. package/dist/swpx/enforce.js +52 -0
  51. package/dist/swpx/enforce.js.map +1 -0
  52. package/dist/swpx/registry.js +68 -0
  53. package/dist/swpx/registry.js.map +1 -0
  54. package/dist/swpx/render.js +308 -0
  55. package/dist/swpx/render.js.map +1 -0
  56. package/dist/swpx/run-common.js +23 -0
  57. package/dist/swpx/run-common.js.map +1 -0
  58. package/dist/swpx/run-swpm.js +95 -0
  59. package/dist/swpx/run-swpm.js.map +1 -0
  60. package/dist/swpx/run-swpx.js +65 -0
  61. package/dist/swpx/run-swpx.js.map +1 -0
  62. package/dist/swpx/spawn.js +30 -0
  63. package/dist/swpx/spawn.js.map +1 -0
  64. package/dist/swpx/tree.js +101 -0
  65. package/dist/swpx/tree.js.map +1 -0
  66. package/dist/swpx/types.js +14 -0
  67. package/dist/swpx/types.js.map +1 -0
  68. package/dist/swpx/verdict-client.js +112 -0
  69. package/dist/swpx/verdict-client.js.map +1 -0
  70. package/dist/swpx-bin.js +20 -0
  71. package/dist/swpx-bin.js.map +1 -0
  72. package/package.json +6 -5
@@ -0,0 +1,95 @@
1
+ /** `swpm <args...>` — the verdict gate in front of `npm`.
2
+ *
3
+ * Only install-family subcommands are gated (install/i/add/ci); everything else
4
+ * (run, test, publish, …) passes straight through to npm untouched. For an
5
+ * install we batch-check the resolved tree and print the summary, then:
6
+ * - any BLOCKED package → stop, exit 1, don't install.
7
+ * - otherwise → run the real npm install (unverified rows warn but
8
+ * don't gate every install).
9
+ * Couldn't verify (unreachable / unresolvable tree) → LOUD warning then fall
10
+ * back to npm, OR refuse under enforce. Summary goes to stderr; npm owns stdout. */
11
+ import { parseSpec } from './registry.js';
12
+ import { renderTree } from './render.js';
13
+ import { bindDeps } from './run-common.js';
14
+ import { dim } from '../lib/output.js';
15
+ import { resolveEnforce, stripEnforceFlags, loudUnavailable, refused } from './enforce.js';
16
+ import { VerdictUnavailable } from './verdict-client.js';
17
+ /** npm's own install aliases (including its built-in typo aliases). */
18
+ const INSTALL_SUBS = new Set(['install', 'i', 'in', 'ins', 'add', 'ci', 'isntall']);
19
+ function alignVerdicts(toCheck, verdicts) {
20
+ const byKey = new Map(verdicts.map((v) => [`${v.package}@${v.version}`, v]));
21
+ // A row the service didn't return is "unknown" → surfaced as unverified, never
22
+ // silently counted as verified.
23
+ return toCheck.map((t) => byKey.get(`${t.package}@${t.version}`) ?? {
24
+ package: t.package,
25
+ version: t.version,
26
+ verdict: 'unverified',
27
+ });
28
+ }
29
+ export async function runSwpm(args, deps = {}) {
30
+ const d = bindDeps(deps);
31
+ const enforce = deps.enforce ?? resolveEnforce(args);
32
+ const clean = stripEnforceFlags(args);
33
+ const sub = clean[0];
34
+ if (!sub || !INSTALL_SUBS.has(sub)) {
35
+ return { exitCode: await d.runReal('npm', clean), action: 'passthrough' };
36
+ }
37
+ // Couldn't verify the tree → LOUD, then fall back (default) or refuse (enforce).
38
+ const failOpen = async (rateLimited) => {
39
+ loudUnavailable(d.errLog, 'this install', rateLimited);
40
+ if (enforce) {
41
+ refused(d.errLog, 'this install', 'npm');
42
+ return { exitCode: 1, action: 'blocked' };
43
+ }
44
+ return { exitCode: await d.runReal('npm', clean), action: 'fallback' };
45
+ };
46
+ const explicit = clean.slice(1).filter((a) => !a.startsWith('-'));
47
+ let toCheck = [];
48
+ let directCount = 0;
49
+ try {
50
+ if (explicit.length) {
51
+ toCheck = await Promise.all(explicit.map(async (a) => {
52
+ const s = parseSpec(a);
53
+ return { package: s.name, version: await d.resolveVersion(s.name, s.version) };
54
+ }));
55
+ directCount = toCheck.length;
56
+ }
57
+ else {
58
+ const tree = d.readTree(process.cwd());
59
+ if (tree.locked.length) {
60
+ toCheck = tree.locked;
61
+ const directSet = new Set(tree.directNames);
62
+ directCount = tree.locked.filter((l) => directSet.has(l.package)).length;
63
+ }
64
+ else if (tree.directNames.length) {
65
+ toCheck = await Promise.all(tree.directNames.map(async (name) => ({
66
+ package: name,
67
+ version: await d.resolveVersion(name, tree.ranges[name]),
68
+ })));
69
+ directCount = toCheck.length;
70
+ }
71
+ else {
72
+ d.errLog(dim('swpm: no dependencies found in package.json — running npm'));
73
+ return { exitCode: await d.runReal('npm', clean), action: 'passthrough' };
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ return failOpen(false);
79
+ }
80
+ let verdicts;
81
+ try {
82
+ verdicts = await d.getVerdictBatch(toCheck);
83
+ }
84
+ catch (err) {
85
+ return failOpen(err instanceof VerdictUnavailable && err.rateLimited);
86
+ }
87
+ const aligned = alignVerdicts(toCheck, verdicts);
88
+ for (const l of renderTree(aligned, directCount))
89
+ d.errLog(l);
90
+ if (aligned.some((v) => v.verdict === 'blocked')) {
91
+ return { exitCode: 1, action: 'blocked' };
92
+ }
93
+ return { exitCode: await d.runReal('npm', clean), action: 'ran' };
94
+ }
95
+ //# sourceMappingURL=run-swpm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-swpm.js","sourceRoot":"","sources":["../../src/swpx/run-swpm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /** `swpx <package> [args...]` — the verdict gate in front of `npx`.
2
+ *
3
+ * resolve → verdict → act:
4
+ * verified → print the green one-liner, delegate to real npx.
5
+ * unverified/suspicious → print the evidence block, STOP (exit 1). The user's
6
+ * documented override is to run `npx` directly, per
7
+ * the landing page ("your choice, not ours") — so we
8
+ * deliberately do not prompt or take a --yes flag
9
+ * (which would also collide with npx -y).
10
+ * blocked → print the red block, hard refuse (exit 1, no run).
11
+ * can't resolve / verdict unreachable → fall back to npx unchecked. We are a
12
+ * gate, not a wall: our outage must not stop the user.
13
+ *
14
+ * All verdict messaging goes to STDERR so swpx is transparent on stdout — the
15
+ * executed program owns stdout. */
16
+ import { parseSpec } from './registry.js';
17
+ import { decide, renderVerdict } from './render.js';
18
+ import { bindDeps } from './run-common.js';
19
+ import { resolveEnforce, stripEnforceFlags, loudUnavailable, refused } from './enforce.js';
20
+ import { VerdictUnavailable } from './verdict-client.js';
21
+ export async function runSwpx(args, deps = {}) {
22
+ const d = bindDeps(deps);
23
+ const enforce = deps.enforce ?? resolveEnforce(args);
24
+ const passthrough = stripEnforceFlags(args);
25
+ // The package is the first non-flag arg, so `swpx -y create-next-app` works.
26
+ const pkgArg = passthrough.find((a) => !a.startsWith('-'));
27
+ if (!pkgArg) {
28
+ d.errLog('Usage: swpx <package> [args...]');
29
+ return { exitCode: 1, action: 'stopped' };
30
+ }
31
+ const spec = parseSpec(pkgArg);
32
+ // Couldn't verify → LOUD warning (never silent), then fall back (default) OR
33
+ // refuse (enforce / fail-closed).
34
+ const failOpen = async (rateLimited) => {
35
+ loudUnavailable(d.errLog, spec.name, rateLimited);
36
+ if (enforce) {
37
+ refused(d.errLog, spec.name, 'npx');
38
+ return { exitCode: 1, action: 'blocked' };
39
+ }
40
+ return { exitCode: await d.runReal('npx', passthrough), action: 'fallback' };
41
+ };
42
+ let version;
43
+ try {
44
+ version = await d.resolveVersion(spec.name, spec.version);
45
+ }
46
+ catch {
47
+ return failOpen(false);
48
+ }
49
+ let verdict;
50
+ try {
51
+ verdict = await d.getVerdict(spec.name, version);
52
+ }
53
+ catch (err) {
54
+ return failOpen(err instanceof VerdictUnavailable && err.rateLimited);
55
+ }
56
+ const action = decide(verdict);
57
+ for (const l of renderVerdict(verdict))
58
+ d.errLog(l);
59
+ if (action === 'run') {
60
+ return { exitCode: await d.runReal('npx', passthrough), action: 'ran' };
61
+ }
62
+ // unverified/suspicious and blocked both stop swpx; only the exit reason differs.
63
+ return { exitCode: 1, action: action === 'block' ? 'blocked' : 'stopped' };
64
+ }
65
+ //# sourceMappingURL=run-swpx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-swpx.js","sourceRoot":"","sources":["../../src/swpx/run-swpx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /** Shell out to the REAL npx / npm. swpx/swpm are wrappers, never replacements:
2
+ * once a verdict says "go", the genuine tool runs with the user's exact args,
3
+ * inheriting stdio so its output is untouched (we keep our own messaging on
4
+ * stderr). The child's exit code becomes ours. A launch failure (tool not on
5
+ * PATH) resolves to 127 rather than throwing — the caller already printed the
6
+ * verdict; a missing npm is the user's environment, not a swpx error. */
7
+ import { spawn } from 'node:child_process';
8
+ import { dim } from '../lib/output.js';
9
+ export function runReal(cmd, args) {
10
+ // SWPX_DRY_RUN: show the decision + what WOULD run, without executing. Useful
11
+ // for "what would swpx do?" and for testing the gate end-to-end offline.
12
+ if (process.env.SWPX_DRY_RUN) {
13
+ console.error(dim(`swpx: [dry-run] would run: ${cmd} ${args.join(' ')}`));
14
+ return Promise.resolve(0);
15
+ }
16
+ return new Promise((resolve) => {
17
+ const child = spawn(cmd, args, {
18
+ stdio: 'inherit',
19
+ // On Windows npx/npm are .cmd shims that need a shell; on POSIX we spawn
20
+ // the binary directly (no shell → no quoting/injection surface).
21
+ shell: process.platform === 'win32',
22
+ });
23
+ child.on('error', (err) => {
24
+ console.error(dim(`swpx: failed to launch ${cmd} — ${err.message}`));
25
+ resolve(127);
26
+ });
27
+ child.on('exit', (code, signal) => resolve(signal ? 1 : code ?? 0));
28
+ });
29
+ }
30
+ //# sourceMappingURL=spawn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/swpx/spawn.ts"],"names":[],"mappings":"AAAA;;;;;0EAK0E;AAE1E,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,UAAU,OAAO,CAAC,GAAkB,EAAE,IAAc;IACxD,8EAA8E;IAC9E,yEAAyE;IACzE,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1E,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC7B,KAAK,EAAE,SAAS;YAChB,yEAAyE;YACzE,iEAAiE;YACjE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,101 @@
1
+ /** Resolve a project's dependency tree for `swpm install`.
2
+ *
3
+ * When a lockfile is present it IS the resolved tree — the exact versions npm
4
+ * would install — so we read it directly (no registry round-trips, no guessing
5
+ * ranges). Without a lockfile we fall back to the direct deps in package.json
6
+ * and let the caller resolve their ranges. Parsing is split from fs reads so
7
+ * the lockfile/manifest parsers are unit-tested against fixture strings. */
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ export function parsePackageJsonDeps(pkgJson) {
11
+ let obj;
12
+ try {
13
+ obj = JSON.parse(pkgJson);
14
+ }
15
+ catch {
16
+ return { directNames: [], ranges: {} };
17
+ }
18
+ const ranges = {};
19
+ const o = obj;
20
+ for (const field of ['dependencies', 'devDependencies', 'optionalDependencies']) {
21
+ const d = o?.[field];
22
+ if (d && typeof d === 'object') {
23
+ for (const [k, v] of Object.entries(d)) {
24
+ if (typeof v === 'string')
25
+ ranges[k] = v;
26
+ }
27
+ }
28
+ }
29
+ return { directNames: Object.keys(ranges), ranges };
30
+ }
31
+ /** Extract every concrete package@version from a package-lock.json /
32
+ * npm-shrinkwrap.json string. Handles lockfile v2/v3 (`packages` keyed by
33
+ * node_modules paths) and the older v1 (`dependencies` tree). Deduped. */
34
+ export function parseLockfile(lock) {
35
+ let obj;
36
+ try {
37
+ obj = JSON.parse(lock);
38
+ }
39
+ catch {
40
+ return [];
41
+ }
42
+ const out = [];
43
+ const seen = new Set();
44
+ const add = (name, version) => {
45
+ if (!name || typeof version !== 'string')
46
+ return;
47
+ const id = `${name}@${version}`;
48
+ if (seen.has(id))
49
+ return;
50
+ seen.add(id);
51
+ out.push({ package: name, version });
52
+ };
53
+ const packages = obj.packages;
54
+ if (packages && typeof packages === 'object') {
55
+ for (const [key, val] of Object.entries(packages)) {
56
+ if (!key)
57
+ continue; // "" is the root project
58
+ const idx = key.lastIndexOf('node_modules/');
59
+ if (idx === -1)
60
+ continue;
61
+ if (val?.link)
62
+ continue; // workspace symlink, not a real install
63
+ add(key.slice(idx + 'node_modules/'.length), val?.version);
64
+ }
65
+ return out;
66
+ }
67
+ // lockfile v1: recursive `dependencies` tree.
68
+ const walk = (deps) => {
69
+ if (!deps || typeof deps !== 'object')
70
+ return;
71
+ for (const [name, info] of Object.entries(deps)) {
72
+ add(name, info?.version);
73
+ walk(info?.dependencies);
74
+ }
75
+ };
76
+ walk(obj.dependencies);
77
+ return out;
78
+ }
79
+ /** Read package.json + the first lockfile we find in `dir`. Missing files yield
80
+ * an empty-ish tree rather than throwing — the caller decides what to do with
81
+ * no deps. */
82
+ export function readTree(dir) {
83
+ let directNames = [];
84
+ let ranges = {};
85
+ const pkgPath = join(dir, 'package.json');
86
+ if (existsSync(pkgPath)) {
87
+ const parsed = parsePackageJsonDeps(readFileSync(pkgPath, 'utf-8'));
88
+ directNames = parsed.directNames;
89
+ ranges = parsed.ranges;
90
+ }
91
+ let locked = [];
92
+ for (const lockName of ['package-lock.json', 'npm-shrinkwrap.json']) {
93
+ const lockPath = join(dir, lockName);
94
+ if (existsSync(lockPath)) {
95
+ locked = parseLockfile(readFileSync(lockPath, 'utf-8'));
96
+ break;
97
+ }
98
+ }
99
+ return { directNames, ranges, locked };
100
+ }
101
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/swpx/tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** Shared types for the swpx / swpm verdict layer.
2
+ *
3
+ * The verdict API lives on the `npm` platform project (npm.somewhere.tech),
4
+ * NOT the /v1 control plane. It is unauthenticated (free, no login) — the CLI
5
+ * hits it with a plain fetch, independent of `somewhere login`. See
6
+ * verdict-client.ts.
7
+ *
8
+ * The `Verdict` shape mirrors the D1 `verdicts` row (tsk_f30faf55) plus the
9
+ * live MAL advisory check, which is NOT cached (a version can be retroactively
10
+ * flagged). The `--json` output is a stable PROJECTION of this (toJsonVerdict)
11
+ * — that projection is the public contract shown on npm.somewhere.tech, so it
12
+ * is intentionally narrower than the internal row. */
13
+ export {};
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/swpx/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;uDAWuD"}
@@ -0,0 +1,112 @@
1
+ /** Client for the verdict API hosted on the `npm` platform project.
2
+ *
3
+ * This is NOT the /v1 control plane and NOT the runner — it's the public,
4
+ * unauthenticated verdict service at npm.somewhere.tech (FAQ: "Free, no
5
+ * login"). So this client deliberately does not touch ApiClient or the stored
6
+ * developer key. Override the host for staging/tests via SWPX_VERDICT_URL.
7
+ *
8
+ * Reachability is a product guarantee, inverted: if the verdict API is down,
9
+ * the user must still get normal npm behaviour ("a gate, not a wall"). So every
10
+ * failure here raises VerdictUnavailable and the command layer falls back to
11
+ * the real npx/npm. We never block on our own outage. */
12
+ const VERDICT_BASE = process.env.SWPX_VERDICT_URL?.replace(/\/$/, '') || 'https://npm.somewhere.tech';
13
+ /** Short by design: the verdict check sits in front of every `npx`, so a slow
14
+ * or unreachable service must fail fast to fallback, not stall the user. */
15
+ const VERDICT_TIMEOUT_MS = Number(process.env.SWPX_VERDICT_TIMEOUT_MS) || 4000;
16
+ const defaultFetch = (url, init) => fetch(url, init);
17
+ /** Raised whenever the verdict couldn't be obtained — network error, timeout,
18
+ * non-2xx, or unparseable body. The command layer treats it as "fall back to
19
+ * the real tool", never as "block". */
20
+ export class VerdictUnavailable extends Error {
21
+ /** True when the service answered 429 — a throttle, not an outage/tampering. */
22
+ rateLimited;
23
+ constructor(message, rateLimited = false) {
24
+ super(message);
25
+ this.name = 'VerdictUnavailable';
26
+ this.rateLimited = rateLimited;
27
+ }
28
+ }
29
+ /** Accept either a bare verdict object or a `{ ok, data }` envelope. */
30
+ function unwrap(body) {
31
+ if (body && typeof body === 'object' && 'ok' in body) {
32
+ const env = body;
33
+ if (env.ok === true)
34
+ return env.data;
35
+ throw new VerdictUnavailable(env.message || env.error || 'verdict API returned ok:false');
36
+ }
37
+ return body;
38
+ }
39
+ function timeoutSignal() {
40
+ try {
41
+ return AbortSignal.timeout(VERDICT_TIMEOUT_MS);
42
+ }
43
+ catch {
44
+ return undefined; // very old runtime — let the request run without our timeout
45
+ }
46
+ }
47
+ /** Look up one package@version. Throws VerdictUnavailable on any failure. */
48
+ export async function getVerdict(name, version, fetchImpl = defaultFetch) {
49
+ const url = `${VERDICT_BASE}/api/verdict/${encodeURIComponent(name)}/${encodeURIComponent(version)}`;
50
+ let res;
51
+ try {
52
+ res = await fetchImpl(url, { headers: { Accept: 'application/json' }, signal: timeoutSignal() });
53
+ }
54
+ catch (err) {
55
+ throw new VerdictUnavailable(err instanceof Error ? err.message : String(err));
56
+ }
57
+ if (!res.ok)
58
+ throw new VerdictUnavailable(`verdict API returned ${res.status}`, res.status === 429);
59
+ let body;
60
+ try {
61
+ body = await res.json();
62
+ }
63
+ catch {
64
+ throw new VerdictUnavailable('verdict API returned a non-JSON body');
65
+ }
66
+ const v = unwrap(body);
67
+ if (!v || typeof v !== 'object' || typeof v.verdict !== 'string') {
68
+ throw new VerdictUnavailable('verdict API returned an unexpected shape');
69
+ }
70
+ // Trust the caller's resolved coordinates over whatever the row echoes back.
71
+ return { ...v, package: name, version };
72
+ }
73
+ /** Batch-check a resolved tree. Throws VerdictUnavailable on any failure so the
74
+ * caller can fall back to a plain `npm install`. The returned array is aligned
75
+ * to the input order; any row the service omits is dropped (caller treats a
76
+ * missing row as "unknown", not "verified"). */
77
+ export async function getVerdictBatch(pkgs, fetchImpl = defaultFetch) {
78
+ if (pkgs.length === 0)
79
+ return [];
80
+ const url = `${VERDICT_BASE}/api/verdict/batch`;
81
+ let res;
82
+ try {
83
+ res = await fetchImpl(url, {
84
+ method: 'POST',
85
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
86
+ body: JSON.stringify({ packages: pkgs }),
87
+ signal: timeoutSignal(),
88
+ });
89
+ }
90
+ catch (err) {
91
+ throw new VerdictUnavailable(err instanceof Error ? err.message : String(err));
92
+ }
93
+ if (!res.ok)
94
+ throw new VerdictUnavailable(`verdict API returned ${res.status}`, res.status === 429);
95
+ let body;
96
+ try {
97
+ body = await res.json();
98
+ }
99
+ catch {
100
+ throw new VerdictUnavailable('verdict API returned a non-JSON body');
101
+ }
102
+ const data = unwrap(body);
103
+ const results = Array.isArray(data)
104
+ ? data
105
+ : data?.results;
106
+ if (!Array.isArray(results)) {
107
+ throw new VerdictUnavailable('verdict API batch returned an unexpected shape');
108
+ }
109
+ return results.filter((v) => !!v && typeof v === 'object' && typeof v.verdict === 'string');
110
+ }
111
+ export const verdictBaseUrl = VERDICT_BASE;
112
+ //# sourceMappingURL=verdict-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict-client.js","sourceRoot":"","sources":["../../src/swpx/verdict-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /** Entry for the standalone `swpx` binary (and `somewhere npx`).
2
+ *
3
+ * `swpx check <pkg> [--json]` inspects without running; anything else is a
4
+ * package to run through the verdict gate. No commander here — a wrapper must
5
+ * pass the user's flags through to the target package untouched, so we read
6
+ * raw argv. `main` is side-effect-free (deps injectable) so it's unit-tested;
7
+ * bin/swpx.js does the process.exit. */
8
+ import { runSwpx } from './swpx/run-swpx.js';
9
+ import { runCheck } from './swpx/check.js';
10
+ export async function main(argv, deps = {}) {
11
+ if (argv[0] === 'check') {
12
+ const rest = argv.slice(1);
13
+ const json = rest.includes('--json');
14
+ const pkg = rest.find((a) => !a.startsWith('-'));
15
+ return runCheck(pkg, { json }, deps);
16
+ }
17
+ const { exitCode } = await runSwpx(argv, deps);
18
+ return exitCode;
19
+ }
20
+ //# sourceMappingURL=swpx-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swpx-bin.js","sourceRoot":"","sources":["../src/swpx-bin.ts"],"names":[],"mappings":"AAAA;;;;;;yCAMyC;AAEzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc,EAAE,OAAgB,EAAE;IAC3D,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACjD,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somewhere-tech/cli",
3
- "version": "0.12.9",
3
+ "version": "0.15.0",
4
4
  "description": "CLI for somewhere.tech — auth, projects, deploy, pull, promote, db, logs, env, MCP bridge.",
5
5
  "keywords": [
6
6
  "somewhere",
@@ -22,7 +22,9 @@
22
22
  "type": "module",
23
23
  "bin": {
24
24
  "somewhere": "bin/somewhere.js",
25
- "sw": "bin/somewhere.js"
25
+ "sw": "bin/somewhere.js",
26
+ "swpx": "bin/swpx.js",
27
+ "swpm": "bin/swpm.js"
26
28
  },
27
29
  "files": [
28
30
  "bin",
@@ -44,17 +46,16 @@
44
46
  },
45
47
  "dependencies": {
46
48
  "@modelcontextprotocol/sdk": "^1.29.0",
47
- "chalk": "^5.3.0",
48
49
  "chokidar": "^4.0.3",
49
50
  "commander": "^12.0.0",
50
- "open": "^10.0.0",
51
- "ora": "^8.0.0",
52
51
  "prompts": "^2.4.2",
52
+ "semver": "^7.6.3",
53
53
  "undici": "^8.4.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/node": "^22.19.21",
57
57
  "@types/prompts": "^2.4.0",
58
+ "@types/semver": "^7.5.8",
58
59
  "typescript": "^5.4.0"
59
60
  }
60
61
  }