devmap 0.3.5__py3-none-any.whl → 0.3.6__py3-none-any.whl
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.
- devmap/_devmap.mjs +140 -4
- {devmap-0.3.5.dist-info → devmap-0.3.6.dist-info}/METADATA +2 -1
- devmap-0.3.6.dist-info/RECORD +7 -0
- devmap-0.3.5.dist-info/RECORD +0 -7
- {devmap-0.3.5.dist-info → devmap-0.3.6.dist-info}/WHEEL +0 -0
- {devmap-0.3.5.dist-info → devmap-0.3.6.dist-info}/entry_points.txt +0 -0
- {devmap-0.3.5.dist-info → devmap-0.3.6.dist-info}/top_level.txt +0 -0
devmap/_devmap.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/version.ts
|
|
5
|
-
var VERSION = "0.3.
|
|
5
|
+
var VERSION = "0.3.6";
|
|
6
6
|
|
|
7
7
|
// src/install.ts
|
|
8
8
|
function isIsolated(i) {
|
|
@@ -662,6 +662,138 @@ function runScaAudit(cwd) {
|
|
|
662
662
|
return checks;
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
// src/health/parse.ts
|
|
666
|
+
function parsePipCheck(text) {
|
|
667
|
+
const lines = (text || "").split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
668
|
+
const clean = lines.some((l) => /^no broken requirements found/i.test(l));
|
|
669
|
+
const conflicts = lines.filter((l) => !/^no broken requirements found/i.test(l));
|
|
670
|
+
if (clean || conflicts.length === 0) {
|
|
671
|
+
return { status: "ok", summary: "pip dependencies consistent" };
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
status: "warn",
|
|
675
|
+
summary: `pip has ${conflicts.length} broken dependency requirement${conflicts.length === 1 ? "" : "s"}`,
|
|
676
|
+
detail: conflicts.join(`
|
|
677
|
+
`)
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function parseNpmDoctor(text) {
|
|
681
|
+
const t = (text || "").trim();
|
|
682
|
+
if (!t)
|
|
683
|
+
return { status: "skipped", summary: "npm doctor produced no output (timed out or silent)" };
|
|
684
|
+
const lines = t.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
685
|
+
const NET_RE = /ECONNREFUSED|ETIMEDOUT|ENOTFOUND|getaddrinfo|EAI_|network request|registry\.npmjs\.org|request to https?:/i;
|
|
686
|
+
const BOILER_RE = /complete log of this run|^\s+at\s|node:internal|file:\/\//i;
|
|
687
|
+
const netLines = lines.filter((l) => NET_RE.test(l));
|
|
688
|
+
const failLines = lines.filter((l) => /npm error|✗|✖/i.test(l) && !BOILER_RE.test(l));
|
|
689
|
+
const realFails = failLines.filter((l) => !NET_RE.test(l));
|
|
690
|
+
if (realFails.length) {
|
|
691
|
+
return {
|
|
692
|
+
status: "warn",
|
|
693
|
+
summary: `npm doctor reported ${realFails.length} issue${realFails.length === 1 ? "" : "s"}`,
|
|
694
|
+
detail: realFails.join(`
|
|
695
|
+
`)
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
if (netLines.length) {
|
|
699
|
+
return { status: "skipped", summary: "npm doctor skipped (registry/network unreachable)" };
|
|
700
|
+
}
|
|
701
|
+
return { status: "ok", summary: "npm doctor passed" };
|
|
702
|
+
}
|
|
703
|
+
function parseRustupCheck(text) {
|
|
704
|
+
const t = (text || "").trim();
|
|
705
|
+
if (!t)
|
|
706
|
+
return { status: "skipped", summary: "rustup check produced no output (timed out or silent)" };
|
|
707
|
+
const lines = t.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
708
|
+
const updates = lines.filter((l) => /update available/i.test(l));
|
|
709
|
+
const upToDate = lines.filter((l) => /up to date/i.test(l));
|
|
710
|
+
if (updates.length) {
|
|
711
|
+
return {
|
|
712
|
+
status: "info",
|
|
713
|
+
summary: `rustup: ${updates.length} toolchain update${updates.length === 1 ? "" : "s"} available`,
|
|
714
|
+
detail: updates.join(`
|
|
715
|
+
`)
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
if (upToDate.length)
|
|
719
|
+
return { status: "ok", summary: "rustup toolchains up to date" };
|
|
720
|
+
return { status: "ok", summary: "rustup check passed" };
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// src/health/scan.ts
|
|
724
|
+
var PROBES = [
|
|
725
|
+
{
|
|
726
|
+
id: "pip",
|
|
727
|
+
label: "pip",
|
|
728
|
+
kind: "conflict",
|
|
729
|
+
network: false,
|
|
730
|
+
candidates: [
|
|
731
|
+
["pip", ["check"]],
|
|
732
|
+
["pip3", ["check"]],
|
|
733
|
+
["python", ["-m", "pip", "check"]],
|
|
734
|
+
["python3", ["-m", "pip", "check"]]
|
|
735
|
+
],
|
|
736
|
+
timeout: 15000,
|
|
737
|
+
parse: parsePipCheck
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
id: "npm",
|
|
741
|
+
label: "npm",
|
|
742
|
+
kind: "mismatch",
|
|
743
|
+
network: true,
|
|
744
|
+
candidates: [["npm", ["doctor"]]],
|
|
745
|
+
timeout: 20000,
|
|
746
|
+
parse: parseNpmDoctor
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: "rustup",
|
|
750
|
+
label: "rustup",
|
|
751
|
+
kind: "stale",
|
|
752
|
+
network: true,
|
|
753
|
+
candidates: [["rustup", ["check"]]],
|
|
754
|
+
timeout: 15000,
|
|
755
|
+
parse: parseRustupCheck
|
|
756
|
+
}
|
|
757
|
+
];
|
|
758
|
+
function pickCandidate(p) {
|
|
759
|
+
const dirs = pathDirs();
|
|
760
|
+
for (const [cmd, args] of p.candidates) {
|
|
761
|
+
if (whichInDirs(cmd, dirs).length > 0)
|
|
762
|
+
return [cmd, args];
|
|
763
|
+
}
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
var SEV_OF = {
|
|
767
|
+
ok: "ok",
|
|
768
|
+
warn: "warn",
|
|
769
|
+
info: "info",
|
|
770
|
+
skipped: "info"
|
|
771
|
+
};
|
|
772
|
+
function toCheck(p, r) {
|
|
773
|
+
const sev = SEV_OF[r.status];
|
|
774
|
+
const id = `health.${p.id}.check`;
|
|
775
|
+
const realId = r.status === "skipped" ? `health.${p.id}.skipped` : id;
|
|
776
|
+
return makeCheck(realId, p.kind, sev, r.summary, r.detail || "", [], r.status === "ok" ? undefined : undefined);
|
|
777
|
+
}
|
|
778
|
+
async function computeHealth(opts = {}) {
|
|
779
|
+
const checks = [];
|
|
780
|
+
const network = opts.healthNetwork === true;
|
|
781
|
+
for (const p of PROBES) {
|
|
782
|
+
const picked = pickCandidate(p);
|
|
783
|
+
if (!picked)
|
|
784
|
+
continue;
|
|
785
|
+
if (p.network && !network) {
|
|
786
|
+
checks.push(makeCheck(`health.${p.id}.skipped`, p.kind, "info", `${p.label} doctor skipped (offline by default)`, `Run with --health-network to invoke ${p.label} self-checks (they require network).`));
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
const [cmd, args] = picked;
|
|
790
|
+
const out = await runAsync(cmd, args, p.timeout);
|
|
791
|
+
const result = p.parse(out);
|
|
792
|
+
checks.push(toCheck(p, result));
|
|
793
|
+
}
|
|
794
|
+
return checks;
|
|
795
|
+
}
|
|
796
|
+
|
|
665
797
|
// src/output/json.ts
|
|
666
798
|
function buildManifest(byName, conflicts, checks, environments, shells) {
|
|
667
799
|
const sys = byName.system || {};
|
|
@@ -841,7 +973,8 @@ async function runScan(shells, disabled, opts = {}) {
|
|
|
841
973
|
progress,
|
|
842
974
|
checkOutdated: opts.checkOutdated,
|
|
843
975
|
wslDeep: opts.wslDeep,
|
|
844
|
-
auditDeps: opts.auditDeps
|
|
976
|
+
auditDeps: opts.auditDeps,
|
|
977
|
+
healthNetwork: opts.healthNetwork
|
|
845
978
|
};
|
|
846
979
|
const { byName, allChecks } = await runDetectors(ctx, progress);
|
|
847
980
|
const groups = [
|
|
@@ -850,12 +983,13 @@ async function runScan(shells, disabled, opts = {}) {
|
|
|
850
983
|
...byName.ides || []
|
|
851
984
|
];
|
|
852
985
|
const conflicts = computeConflicts(groups, shells, disabled);
|
|
986
|
+
const healthChecks = await computeHealth({ healthNetwork: opts.healthNetwork });
|
|
853
987
|
const securityChecks = [
|
|
854
988
|
...computeSecurity(byName),
|
|
855
989
|
...computeScaInventory(),
|
|
856
990
|
...opts.auditDeps ? runScaAudit(process.cwd()) : []
|
|
857
991
|
];
|
|
858
|
-
const collected = [...allChecks, ...conflicts.checks, ...securityChecks].filter((c) => !isCheckDisabled(c.ID, disabled));
|
|
992
|
+
const collected = [...allChecks, ...conflicts.checks, ...securityChecks, ...healthChecks].filter((c) => !isCheckDisabled(c.ID, disabled));
|
|
859
993
|
const environments = {
|
|
860
994
|
vcpkg: byName.vcpkg,
|
|
861
995
|
pip: byName.pip,
|
|
@@ -1906,7 +2040,8 @@ async function cmdScan(opts, pos) {
|
|
|
1906
2040
|
silent: opts.quiet === true,
|
|
1907
2041
|
checkOutdated: opts.outdated === true,
|
|
1908
2042
|
wslDeep: opts["wsl-deep"] === true,
|
|
1909
|
-
auditDeps: opts["audit-deps"] === true
|
|
2043
|
+
auditDeps: opts["audit-deps"] === true,
|
|
2044
|
+
healthNetwork: opts["health-network"] === true
|
|
1910
2045
|
});
|
|
1911
2046
|
if (opts.json) {
|
|
1912
2047
|
emitText(JSON.stringify(manifest, null, 2), opts.bom === true);
|
|
@@ -2193,6 +2328,7 @@ scan options:
|
|
|
2193
2328
|
--wsl-deep probe inside stopped WSL distros (default probes only running ones to avoid waking distros)
|
|
2194
2329
|
--ci CI gate: clean → exit 0; any warn → exit 2; any error → exit 1
|
|
2195
2330
|
--audit-deps dependency CVE audit via OSV-Scanner/pip-audit/govulncheck/Trivy (opt-in, uses network)
|
|
2331
|
+
--health-network run network health probes too (npm doctor / rustup check; off by default to stay offline-fast)
|
|
2196
2332
|
--quiet suppress scan progress feedback (for scripts/CI)
|
|
2197
2333
|
--bom prepend UTF-8 BOM for viewing in Notepad etc. (only on redirect/pipe)
|
|
2198
2334
|
--version / --help
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devmap
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Map your machine's dev environment and surface issues (PATH conflicts, ghost binaries, multi-version collisions). fastfetch-for-dev-tools. This PyPI package ships the real devmap CLI (a bundled JavaScript app launched via Node.js or Bun), so `pip install devmap && devmap` works standalone.
|
|
5
5
|
Author: devmap contributors
|
|
6
6
|
License: MIT
|
|
@@ -40,6 +40,7 @@ Requirements at runtime: a Node.js (or Bun) runtime available on `PATH`. Python
|
|
|
40
40
|
- **Off-PATH awareness**: reports installed-but-not-on-PATH tools, while correctly treating version-manager environments (conda envs, nvm versions) as by-design off-PATH.
|
|
41
41
|
- **Environment layers**: vcpkg packages, per-python pip packages (incl. upgradable), apt packages (Linux), conda environments, Docker (binary + daemon + images/containers), WSL distros, Visual Studio dev shells, and project-local environments (`.venv`, `node_modules`).
|
|
42
42
|
- **Dependency auditing (optional)**: with `--audit-deps`, devmap detects and invokes installed SCA tools (osv-scanner, govulncheck, pip-audit, Trivy), parses their JSON, and merges results into a unified view. devmap is a *scanner/orchestrator*, not a CVE database — for authoritative vulnerability data, use those tools directly.
|
|
43
|
+
- **Health layer**: converges official self-checks into one view — `pip check` (broken dependency requirements, **offline by default**) and, with `--health-network`, `npm doctor` / `rustup check`. Unavailable or offline probes degrade gracefully to `info`.
|
|
43
44
|
- **Three sub-commands**: `scan` (the fact source), `query` (ask the manifest), `devdiff` (compare two manifests — environment drift / cross-machine consistency).
|
|
44
45
|
- **Zero Python dependencies.** The bundled app is pure TypeScript compiled to JavaScript.
|
|
45
46
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
devmap/__init__.py,sha256=4Ek7Di0FYYl76FKnHJ8VYiJPHlUTfoqyBB_hul_pFbk,1728
|
|
2
|
+
devmap/_devmap.mjs,sha256=kYiHodxsTRu90Anb1QtKk_llF1-Q21S4N9KrLuHgQsw,84108
|
|
3
|
+
devmap-0.3.6.dist-info/METADATA,sha256=J89bwvXkn1xoRuyarTu7e1LQgQyCohhgIVylFrS21nI,6796
|
|
4
|
+
devmap-0.3.6.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
5
|
+
devmap-0.3.6.dist-info/entry_points.txt,sha256=FOQKZCLz0WGWemrTw0suYRqKWrUB4_XJ2Gkrw60ZEcg,39
|
|
6
|
+
devmap-0.3.6.dist-info/top_level.txt,sha256=QeomiD_JKcjSd_jTZv0WJF3darUb2sUsxmocjgYJ6Qc,7
|
|
7
|
+
devmap-0.3.6.dist-info/RECORD,,
|
devmap-0.3.5.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
devmap/__init__.py,sha256=4Ek7Di0FYYl76FKnHJ8VYiJPHlUTfoqyBB_hul_pFbk,1728
|
|
2
|
-
devmap/_devmap.mjs,sha256=xRTpuwBHdOAWySpx4TEudvxS0aIA288NYmluaXyoEAw,79539
|
|
3
|
-
devmap-0.3.5.dist-info/METADATA,sha256=mwnfHI_6L1uNkqqjinecVYDiy0vtTWSS0fguLrtLk5s,6536
|
|
4
|
-
devmap-0.3.5.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
5
|
-
devmap-0.3.5.dist-info/entry_points.txt,sha256=FOQKZCLz0WGWemrTw0suYRqKWrUB4_XJ2Gkrw60ZEcg,39
|
|
6
|
-
devmap-0.3.5.dist-info/top_level.txt,sha256=QeomiD_JKcjSd_jTZv0WJF3darUb2sUsxmocjgYJ6Qc,7
|
|
7
|
-
devmap-0.3.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|