@wipcomputer/wip-ai-devops-toolbox 1.9.20
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/.license-guard.json +7 -0
- package/.publish-skill.json +4 -0
- package/CHANGELOG.md +1120 -0
- package/CLA.md +19 -0
- package/DEV-GUIDE-GENERAL-PUBLIC.md +882 -0
- package/LICENSE +52 -0
- package/README.md +238 -0
- package/SKILL.md +728 -0
- package/TECHNICAL.md +282 -0
- package/UNIVERSAL-INTERFACE.md +180 -0
- package/_trash/RELEASE-NOTES-v1-8-0.md +29 -0
- package/_trash/RELEASE-NOTES-v1-8-1.md +7 -0
- package/_trash/RELEASE-NOTES-v1-8-2.md +7 -0
- package/_trash/RELEASE-NOTES-v1-9-0.md +37 -0
- package/_trash/RELEASE-NOTES-v1-9-1.md +38 -0
- package/_trash/RELEASE-NOTES-v1-9-10.md +40 -0
- package/_trash/RELEASE-NOTES-v1-9-2.md +40 -0
- package/_trash/RELEASE-NOTES-v1-9-6.md +72 -0
- package/_trash/RELEASE-NOTES-v1-9-7.md +23 -0
- package/_trash/RELEASE-NOTES-v1-9-9.md +75 -0
- package/_trash/guide 2/DEV-GUIDE.md +487 -0
- package/_trash/guide 2/scripts/deploy-public.sh +152 -0
- package/package.json +27 -0
- package/scripts/SKILL-deploy-public.md +61 -0
- package/scripts/SKILL-post-merge-rename.md +47 -0
- package/scripts/deploy-public.sh +264 -0
- package/scripts/post-merge-rename.sh +205 -0
- package/scripts/publish-skill.sh +134 -0
- package/tools/deploy-public/LICENSE +52 -0
- package/tools/deploy-public/README.md +31 -0
- package/tools/deploy-public/SKILL.md +71 -0
- package/tools/deploy-public/deploy-public.sh +264 -0
- package/tools/deploy-public/package.json +9 -0
- package/tools/ldm-jobs/LICENSE +52 -0
- package/tools/ldm-jobs/README.md +46 -0
- package/tools/ldm-jobs/backup.sh +16 -0
- package/tools/ldm-jobs/branch-protect.sh +39 -0
- package/tools/ldm-jobs/crystal-capture.sh +19 -0
- package/tools/ldm-jobs/setup-shell.sh +27 -0
- package/tools/ldm-jobs/visibility-audit.sh +27 -0
- package/tools/post-merge-rename/LICENSE +52 -0
- package/tools/post-merge-rename/README.md +29 -0
- package/tools/post-merge-rename/SKILL.md +57 -0
- package/tools/post-merge-rename/package.json +9 -0
- package/tools/post-merge-rename/post-merge-rename.sh +122 -0
- package/tools/wip-branch-guard/INSTALL.md +41 -0
- package/tools/wip-branch-guard/guard.mjs +259 -0
- package/tools/wip-branch-guard/package.json +11 -0
- package/tools/wip-file-guard/CHANGELOG.md +6 -0
- package/tools/wip-file-guard/LICENSE +52 -0
- package/tools/wip-file-guard/README.md +113 -0
- package/tools/wip-file-guard/REFERENCE.md +86 -0
- package/tools/wip-file-guard/SKILL.md +105 -0
- package/tools/wip-file-guard/guard.mjs +128 -0
- package/tools/wip-file-guard/openclaw.plugin.json +8 -0
- package/tools/wip-file-guard/package.json +27 -0
- package/tools/wip-file-guard/test.sh +119 -0
- package/tools/wip-license-guard/LICENSE +52 -0
- package/tools/wip-license-guard/README.md +32 -0
- package/tools/wip-license-guard/SKILL.md +65 -0
- package/tools/wip-license-guard/cli.mjs +464 -0
- package/tools/wip-license-guard/core.mjs +310 -0
- package/tools/wip-license-guard/hook.mjs +146 -0
- package/tools/wip-license-guard/package.json +15 -0
- package/tools/wip-license-hook/CHANGELOG.md +17 -0
- package/tools/wip-license-hook/LICENSE +52 -0
- package/tools/wip-license-hook/README.md +200 -0
- package/tools/wip-license-hook/SKILL.md +111 -0
- package/tools/wip-license-hook/dist/cli/index.d.ts +15 -0
- package/tools/wip-license-hook/dist/cli/index.js +170 -0
- package/tools/wip-license-hook/dist/cli/index.js.map +1 -0
- package/tools/wip-license-hook/dist/core/detector.d.ts +12 -0
- package/tools/wip-license-hook/dist/core/detector.js +104 -0
- package/tools/wip-license-hook/dist/core/detector.js.map +1 -0
- package/tools/wip-license-hook/dist/core/index.d.ts +4 -0
- package/tools/wip-license-hook/dist/core/index.js +5 -0
- package/tools/wip-license-hook/dist/core/index.js.map +1 -0
- package/tools/wip-license-hook/dist/core/ledger.d.ts +49 -0
- package/tools/wip-license-hook/dist/core/ledger.js +72 -0
- package/tools/wip-license-hook/dist/core/ledger.js.map +1 -0
- package/tools/wip-license-hook/dist/core/reporter.d.ts +14 -0
- package/tools/wip-license-hook/dist/core/reporter.js +227 -0
- package/tools/wip-license-hook/dist/core/reporter.js.map +1 -0
- package/tools/wip-license-hook/dist/core/scanner.d.ts +39 -0
- package/tools/wip-license-hook/dist/core/scanner.js +325 -0
- package/tools/wip-license-hook/dist/core/scanner.js.map +1 -0
- package/tools/wip-license-hook/hooks/pre-pull.sh +55 -0
- package/tools/wip-license-hook/hooks/pre-push.sh +51 -0
- package/tools/wip-license-hook/mcp-server.mjs +119 -0
- package/tools/wip-license-hook/package-lock.json +54 -0
- package/tools/wip-license-hook/package.json +43 -0
- package/tools/wip-license-hook/src/cli/index.ts +189 -0
- package/tools/wip-license-hook/src/core/detector.ts +130 -0
- package/tools/wip-license-hook/src/core/index.ts +4 -0
- package/tools/wip-license-hook/src/core/ledger.ts +116 -0
- package/tools/wip-license-hook/src/core/reporter.ts +255 -0
- package/tools/wip-license-hook/src/core/scanner.ts +367 -0
- package/tools/wip-license-hook/tsconfig.json +16 -0
- package/tools/wip-readme-format/README.md +49 -0
- package/tools/wip-readme-format/SKILL.md +84 -0
- package/tools/wip-readme-format/format.mjs +570 -0
- package/tools/wip-readme-format/package.json +15 -0
- package/tools/wip-release/CHANGELOG.md +42 -0
- package/tools/wip-release/LICENSE +52 -0
- package/tools/wip-release/README.md +45 -0
- package/tools/wip-release/REFERENCE.md +100 -0
- package/tools/wip-release/SKILL.md +139 -0
- package/tools/wip-release/cli.js +161 -0
- package/tools/wip-release/core.mjs +1174 -0
- package/tools/wip-release/mcp-server.mjs +109 -0
- package/tools/wip-release/package.json +36 -0
- package/tools/wip-repo-init/README.md +38 -0
- package/tools/wip-repo-init/SKILL.md +77 -0
- package/tools/wip-repo-init/init.mjs +142 -0
- package/tools/wip-repo-init/package.json +11 -0
- package/tools/wip-repo-permissions-hook/LICENSE +52 -0
- package/tools/wip-repo-permissions-hook/README.md +86 -0
- package/tools/wip-repo-permissions-hook/SKILL.md +73 -0
- package/tools/wip-repo-permissions-hook/cli.js +83 -0
- package/tools/wip-repo-permissions-hook/core.mjs +122 -0
- package/tools/wip-repo-permissions-hook/guard.mjs +64 -0
- package/tools/wip-repo-permissions-hook/mcp-server.mjs +92 -0
- package/tools/wip-repo-permissions-hook/openclaw.plugin.json +8 -0
- package/tools/wip-repo-permissions-hook/package.json +31 -0
- package/tools/wip-repos/LICENSE +52 -0
- package/tools/wip-repos/README.md +77 -0
- package/tools/wip-repos/SKILL.md +80 -0
- package/tools/wip-repos/cli.mjs +176 -0
- package/tools/wip-repos/core.mjs +290 -0
- package/tools/wip-repos/mcp-server.mjs +157 -0
- package/tools/wip-repos/package.json +34 -0
- package/tools/wip-universal-installer/CHANGELOG.md +57 -0
- package/tools/wip-universal-installer/LICENSE +52 -0
- package/tools/wip-universal-installer/README.md +81 -0
- package/tools/wip-universal-installer/REFERENCE.md +122 -0
- package/tools/wip-universal-installer/SKILL.md +87 -0
- package/tools/wip-universal-installer/SPEC.md +180 -0
- package/tools/wip-universal-installer/detect.mjs +130 -0
- package/tools/wip-universal-installer/examples/minimal/README.md +20 -0
- package/tools/wip-universal-installer/examples/minimal/SKILL.md +28 -0
- package/tools/wip-universal-installer/examples/minimal/cli.mjs +4 -0
- package/tools/wip-universal-installer/examples/minimal/core.mjs +8 -0
- package/tools/wip-universal-installer/examples/minimal/mcp-server.mjs +27 -0
- package/tools/wip-universal-installer/examples/minimal/package.json +12 -0
- package/tools/wip-universal-installer/install.js +930 -0
- package/tools/wip-universal-installer/package.json +36 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanner — detects dependencies and their licenses across package managers.
|
|
3
|
+
* Supports: npm, pip, cargo, go modules. Works offline.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
import { detectLicenseFromText, normalizeSpdx } from "./detector.js";
|
|
9
|
+
import { readLedger, writeLedger, upsertEntry, findEntry, addAlert, archiveSnapshot, hasLicenseChanged, } from "./ledger.js";
|
|
10
|
+
// ─── License file discovery ───
|
|
11
|
+
const LICENSE_NAMES = ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING", "COPYING.md"];
|
|
12
|
+
export function findLicenseFile(dir) {
|
|
13
|
+
for (const name of LICENSE_NAMES) {
|
|
14
|
+
const p = join(dir, name);
|
|
15
|
+
if (existsSync(p))
|
|
16
|
+
return p;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
export function readLicenseFromDir(dir) {
|
|
21
|
+
const p = findLicenseFile(dir);
|
|
22
|
+
if (!p)
|
|
23
|
+
return null;
|
|
24
|
+
const text = readFileSync(p, "utf-8");
|
|
25
|
+
return { license: detectLicenseFromText(text), text };
|
|
26
|
+
}
|
|
27
|
+
// ─── Package manager detection ───
|
|
28
|
+
function detectPackageManagers(repoRoot) {
|
|
29
|
+
const types = [];
|
|
30
|
+
if (existsSync(join(repoRoot, "package.json")))
|
|
31
|
+
types.push("npm");
|
|
32
|
+
if (existsSync(join(repoRoot, "requirements.txt")) || existsSync(join(repoRoot, "Pipfile")) || existsSync(join(repoRoot, "pyproject.toml")))
|
|
33
|
+
types.push("pip");
|
|
34
|
+
if (existsSync(join(repoRoot, "Cargo.toml")))
|
|
35
|
+
types.push("cargo");
|
|
36
|
+
if (existsSync(join(repoRoot, "go.mod")))
|
|
37
|
+
types.push("go");
|
|
38
|
+
return types;
|
|
39
|
+
}
|
|
40
|
+
// ─── npm scanning ───
|
|
41
|
+
function scanNpmDeps(repoRoot, offline) {
|
|
42
|
+
const results = [];
|
|
43
|
+
const pkgPath = join(repoRoot, "package.json");
|
|
44
|
+
if (!existsSync(pkgPath))
|
|
45
|
+
return results;
|
|
46
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
47
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
48
|
+
for (const [name, _version] of Object.entries(allDeps)) {
|
|
49
|
+
let detectedLicense = "UNKNOWN";
|
|
50
|
+
let licenseText;
|
|
51
|
+
// Check node_modules first (works offline)
|
|
52
|
+
const modDir = join(repoRoot, "node_modules", name);
|
|
53
|
+
if (existsSync(modDir)) {
|
|
54
|
+
const fromFile = readLicenseFromDir(modDir);
|
|
55
|
+
if (fromFile) {
|
|
56
|
+
detectedLicense = fromFile.license;
|
|
57
|
+
licenseText = fromFile.text;
|
|
58
|
+
}
|
|
59
|
+
// Also check package.json license field
|
|
60
|
+
const modPkg = join(modDir, "package.json");
|
|
61
|
+
if (existsSync(modPkg) && detectedLicense === "UNKNOWN") {
|
|
62
|
+
try {
|
|
63
|
+
const modMeta = JSON.parse(readFileSync(modPkg, "utf-8"));
|
|
64
|
+
if (modMeta.license)
|
|
65
|
+
detectedLicense = normalizeSpdx(modMeta.license);
|
|
66
|
+
}
|
|
67
|
+
catch { /* skip */ }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Try npm view if online and still unknown
|
|
71
|
+
if (detectedLicense === "UNKNOWN" && !offline) {
|
|
72
|
+
try {
|
|
73
|
+
const out = execSync(`npm view ${name} license 2>/dev/null`, { encoding: "utf-8", timeout: 10000 }).trim();
|
|
74
|
+
if (out)
|
|
75
|
+
detectedLicense = normalizeSpdx(out);
|
|
76
|
+
}
|
|
77
|
+
catch { /* offline or not found */ }
|
|
78
|
+
}
|
|
79
|
+
results.push({
|
|
80
|
+
name,
|
|
81
|
+
source: `npm:${name}`,
|
|
82
|
+
type: "npm",
|
|
83
|
+
detectedLicense,
|
|
84
|
+
licenseText,
|
|
85
|
+
wasChanged: false,
|
|
86
|
+
isNew: true,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return results;
|
|
90
|
+
}
|
|
91
|
+
// ─── pip scanning ───
|
|
92
|
+
function parsePipDeps(repoRoot) {
|
|
93
|
+
const names = [];
|
|
94
|
+
const reqPath = join(repoRoot, "requirements.txt");
|
|
95
|
+
if (existsSync(reqPath)) {
|
|
96
|
+
const lines = readFileSync(reqPath, "utf-8").split("\n");
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
const trimmed = line.trim();
|
|
99
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("-"))
|
|
100
|
+
continue;
|
|
101
|
+
const name = trimmed.split(/[=<>!~\[]/)[0].trim();
|
|
102
|
+
if (name)
|
|
103
|
+
names.push(name);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return names;
|
|
107
|
+
}
|
|
108
|
+
function scanPipDeps(repoRoot, offline) {
|
|
109
|
+
const deps = parsePipDeps(repoRoot);
|
|
110
|
+
const results = [];
|
|
111
|
+
for (const name of deps) {
|
|
112
|
+
let detectedLicense = "UNKNOWN";
|
|
113
|
+
if (!offline) {
|
|
114
|
+
try {
|
|
115
|
+
const out = execSync(`pip show ${name} 2>/dev/null`, { encoding: "utf-8", timeout: 10000 });
|
|
116
|
+
const match = out.match(/^License:\s*(.+)$/m);
|
|
117
|
+
if (match)
|
|
118
|
+
detectedLicense = normalizeSpdx(match[1]);
|
|
119
|
+
}
|
|
120
|
+
catch { /* skip */ }
|
|
121
|
+
}
|
|
122
|
+
results.push({
|
|
123
|
+
name,
|
|
124
|
+
source: `pip:${name}`,
|
|
125
|
+
type: "pip",
|
|
126
|
+
detectedLicense,
|
|
127
|
+
wasChanged: false,
|
|
128
|
+
isNew: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
// ─── cargo scanning ───
|
|
134
|
+
function scanCargoDeps(repoRoot, offline) {
|
|
135
|
+
const results = [];
|
|
136
|
+
const cargoPath = join(repoRoot, "Cargo.toml");
|
|
137
|
+
if (!existsSync(cargoPath))
|
|
138
|
+
return results;
|
|
139
|
+
const content = readFileSync(cargoPath, "utf-8");
|
|
140
|
+
const depSection = content.match(/\[dependencies\]([\s\S]*?)(\[|$)/);
|
|
141
|
+
if (!depSection)
|
|
142
|
+
return results;
|
|
143
|
+
const lines = depSection[1].split("\n");
|
|
144
|
+
for (const line of lines) {
|
|
145
|
+
const match = line.match(/^(\S+)\s*=/);
|
|
146
|
+
if (!match)
|
|
147
|
+
continue;
|
|
148
|
+
const name = match[1];
|
|
149
|
+
let detectedLicense = "UNKNOWN";
|
|
150
|
+
if (!offline) {
|
|
151
|
+
try {
|
|
152
|
+
const out = execSync(`cargo info ${name} 2>/dev/null`, { encoding: "utf-8", timeout: 10000 });
|
|
153
|
+
const lMatch = out.match(/license:\s*(.+)/i);
|
|
154
|
+
if (lMatch)
|
|
155
|
+
detectedLicense = normalizeSpdx(lMatch[1]);
|
|
156
|
+
}
|
|
157
|
+
catch { /* skip */ }
|
|
158
|
+
}
|
|
159
|
+
results.push({
|
|
160
|
+
name,
|
|
161
|
+
source: `cargo:${name}`,
|
|
162
|
+
type: "cargo",
|
|
163
|
+
detectedLicense,
|
|
164
|
+
wasChanged: false,
|
|
165
|
+
isNew: true,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
// ─── go scanning ───
|
|
171
|
+
function scanGoDeps(repoRoot, _offline) {
|
|
172
|
+
const results = [];
|
|
173
|
+
const goModPath = join(repoRoot, "go.mod");
|
|
174
|
+
if (!existsSync(goModPath))
|
|
175
|
+
return results;
|
|
176
|
+
const content = readFileSync(goModPath, "utf-8");
|
|
177
|
+
const requireBlock = content.match(/require\s*\(([\s\S]*?)\)/);
|
|
178
|
+
const lines = requireBlock ? requireBlock[1].split("\n") : [];
|
|
179
|
+
// Also handle single-line requires
|
|
180
|
+
const singleRequires = content.match(/^require\s+(\S+)\s+/gm) ?? [];
|
|
181
|
+
for (const sr of singleRequires) {
|
|
182
|
+
const m = sr.match(/^require\s+(\S+)/);
|
|
183
|
+
if (m)
|
|
184
|
+
lines.push(m[1]);
|
|
185
|
+
}
|
|
186
|
+
for (const line of lines) {
|
|
187
|
+
const trimmed = line.trim();
|
|
188
|
+
if (!trimmed || trimmed.startsWith("//"))
|
|
189
|
+
continue;
|
|
190
|
+
const parts = trimmed.split(/\s+/);
|
|
191
|
+
const name = parts[0];
|
|
192
|
+
if (!name || name.startsWith(")"))
|
|
193
|
+
continue;
|
|
194
|
+
results.push({
|
|
195
|
+
name,
|
|
196
|
+
source: `go:${name}`,
|
|
197
|
+
type: "go",
|
|
198
|
+
detectedLicense: "UNKNOWN", // Go modules need network for license check
|
|
199
|
+
wasChanged: false,
|
|
200
|
+
isNew: true,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
// ─── Fork/upstream scanning ───
|
|
206
|
+
function scanUpstreamLicense(repoRoot, offline) {
|
|
207
|
+
// Check if there's an upstream remote
|
|
208
|
+
try {
|
|
209
|
+
const remote = execSync("git remote get-url upstream 2>/dev/null", {
|
|
210
|
+
cwd: repoRoot, encoding: "utf-8", timeout: 5000
|
|
211
|
+
}).trim();
|
|
212
|
+
if (!remote)
|
|
213
|
+
return null;
|
|
214
|
+
// Fetch upstream (if online)
|
|
215
|
+
if (!offline) {
|
|
216
|
+
try {
|
|
217
|
+
execSync("git fetch upstream --quiet 2>/dev/null", { cwd: repoRoot, timeout: 30000 });
|
|
218
|
+
}
|
|
219
|
+
catch { /* offline, use cached */ }
|
|
220
|
+
}
|
|
221
|
+
// Try to read LICENSE from upstream/main or upstream/master
|
|
222
|
+
for (const branch of ["upstream/main", "upstream/master"]) {
|
|
223
|
+
try {
|
|
224
|
+
const text = execSync(`git show ${branch}:LICENSE 2>/dev/null`, {
|
|
225
|
+
cwd: repoRoot, encoding: "utf-8", timeout: 5000
|
|
226
|
+
});
|
|
227
|
+
if (text) {
|
|
228
|
+
const license = detectLicenseFromText(text);
|
|
229
|
+
return {
|
|
230
|
+
name: "upstream",
|
|
231
|
+
source: remote,
|
|
232
|
+
type: "fork",
|
|
233
|
+
detectedLicense: license,
|
|
234
|
+
licenseText: text,
|
|
235
|
+
wasChanged: false,
|
|
236
|
+
isNew: true,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch { /* try next branch */ }
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch { /* no upstream remote */ }
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
// ─── Main scan ───
|
|
247
|
+
export function scanAll(opts) {
|
|
248
|
+
const { repoRoot, offline = false } = opts;
|
|
249
|
+
const managers = detectPackageManagers(repoRoot);
|
|
250
|
+
const results = [];
|
|
251
|
+
// Always check upstream fork
|
|
252
|
+
const upstream = scanUpstreamLicense(repoRoot, offline);
|
|
253
|
+
if (upstream)
|
|
254
|
+
results.push(upstream);
|
|
255
|
+
if (managers.includes("npm"))
|
|
256
|
+
results.push(...scanNpmDeps(repoRoot, offline));
|
|
257
|
+
if (managers.includes("pip"))
|
|
258
|
+
results.push(...scanPipDeps(repoRoot, offline));
|
|
259
|
+
if (managers.includes("cargo"))
|
|
260
|
+
results.push(...scanCargoDeps(repoRoot, offline));
|
|
261
|
+
if (managers.includes("go"))
|
|
262
|
+
results.push(...scanGoDeps(repoRoot, offline));
|
|
263
|
+
return results;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Run a full scan and update the ledger. Returns results with change detection.
|
|
267
|
+
*/
|
|
268
|
+
export function scanAndUpdate(opts) {
|
|
269
|
+
const { repoRoot } = opts;
|
|
270
|
+
const ledger = readLedger(repoRoot);
|
|
271
|
+
const results = scanAll(opts);
|
|
272
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
273
|
+
for (const result of results) {
|
|
274
|
+
const existing = findEntry(ledger, result.name);
|
|
275
|
+
if (existing) {
|
|
276
|
+
result.isNew = false;
|
|
277
|
+
existing.license_current = result.detectedLicense;
|
|
278
|
+
existing.last_checked = today;
|
|
279
|
+
if (hasLicenseChanged(existing)) {
|
|
280
|
+
existing.status = "changed";
|
|
281
|
+
result.wasChanged = true;
|
|
282
|
+
addAlert(ledger, result.name, existing.license_at_adoption, result.detectedLicense);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
existing.status = "clean";
|
|
286
|
+
}
|
|
287
|
+
upsertEntry(ledger, existing);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// New dependency
|
|
291
|
+
const entry = {
|
|
292
|
+
name: result.name,
|
|
293
|
+
source: result.source,
|
|
294
|
+
type: result.type,
|
|
295
|
+
license_at_adoption: result.detectedLicense,
|
|
296
|
+
license_current: result.detectedLicense,
|
|
297
|
+
adopted_date: today,
|
|
298
|
+
last_checked: today,
|
|
299
|
+
status: "clean",
|
|
300
|
+
};
|
|
301
|
+
upsertEntry(ledger, entry);
|
|
302
|
+
}
|
|
303
|
+
// Archive license text if available
|
|
304
|
+
if (result.licenseText) {
|
|
305
|
+
archiveSnapshot(repoRoot, result.name, result.licenseText, today);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
ledger.last_full_scan = new Date().toISOString();
|
|
309
|
+
writeLedger(repoRoot, ledger);
|
|
310
|
+
return results;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Gate check — returns true if safe to proceed, false if blocked.
|
|
314
|
+
*/
|
|
315
|
+
export function gateCheck(repoRoot, offline) {
|
|
316
|
+
const results = scanAndUpdate({ repoRoot, offline });
|
|
317
|
+
const changed = results.filter((r) => r.wasChanged);
|
|
318
|
+
const alerts = changed.map((r) => `🚫 LICENSE CHANGED: ${r.name} — was adopted under different terms, now detected as ${r.detectedLicense}`);
|
|
319
|
+
return {
|
|
320
|
+
safe: changed.length === 0,
|
|
321
|
+
results,
|
|
322
|
+
alerts,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# wip-license-hook — Pre-pull hook (hard gate)
|
|
3
|
+
# Blocks pull/merge if upstream license has changed.
|
|
4
|
+
#
|
|
5
|
+
# Install: cp hooks/pre-pull.sh .git/hooks/pre-merge-commit && chmod +x .git/hooks/pre-merge-commit
|
|
6
|
+
# Or: wip-license-hook install
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
11
|
+
|
|
12
|
+
# Check if wip-license-hook is available
|
|
13
|
+
if command -v wip-license-hook &>/dev/null; then
|
|
14
|
+
HOOK_CMD="wip-license-hook"
|
|
15
|
+
elif [ -f "$REPO_ROOT/node_modules/.bin/wip-license-hook" ]; then
|
|
16
|
+
HOOK_CMD="$REPO_ROOT/node_modules/.bin/wip-license-hook"
|
|
17
|
+
elif command -v npx &>/dev/null; then
|
|
18
|
+
HOOK_CMD="npx @wipcomputer/wip-license-hook"
|
|
19
|
+
else
|
|
20
|
+
echo ""
|
|
21
|
+
echo "╔══════════════════════════════════════════════════╗"
|
|
22
|
+
echo "║ ⚠️ wip-license-hook not found ║"
|
|
23
|
+
echo "║ Install: npm i -g @wipcomputer/wip-license-hook ║"
|
|
24
|
+
echo "║ Pull proceeding WITHOUT license check. ║"
|
|
25
|
+
echo "╚══════════════════════════════════════════════════╝"
|
|
26
|
+
echo ""
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
echo ""
|
|
31
|
+
echo "🔒 wip-license-hook: Checking upstream licenses..."
|
|
32
|
+
echo ""
|
|
33
|
+
|
|
34
|
+
# Run the gate check — exits non-zero if license changed
|
|
35
|
+
cd "$REPO_ROOT"
|
|
36
|
+
$HOOK_CMD gate
|
|
37
|
+
|
|
38
|
+
EXIT_CODE=$?
|
|
39
|
+
|
|
40
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
41
|
+
echo ""
|
|
42
|
+
echo "╔══════════════════════════════════════════════════╗"
|
|
43
|
+
echo "║ 🚫 MERGE BLOCKED — License change detected! ║"
|
|
44
|
+
echo "║ ║"
|
|
45
|
+
echo "║ Review the changes above. If you accept the ║"
|
|
46
|
+
echo "║ new license, update the ledger: ║"
|
|
47
|
+
echo "║ wip-license-hook scan ║"
|
|
48
|
+
echo "║ ║"
|
|
49
|
+
echo "║ Then retry the pull/merge. ║"
|
|
50
|
+
echo "╚══════════════════════════════════════════════════╝"
|
|
51
|
+
echo ""
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# wip-license-hook — Pre-push hook (advisory alert)
|
|
3
|
+
# Warns if upstream license has drifted. Does NOT block push.
|
|
4
|
+
#
|
|
5
|
+
# Install: cp hooks/pre-push.sh .git/hooks/pre-push && chmod +x .git/hooks/pre-push
|
|
6
|
+
# Or: wip-license-hook install
|
|
7
|
+
|
|
8
|
+
set -uo pipefail
|
|
9
|
+
|
|
10
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
11
|
+
|
|
12
|
+
# Check if wip-license-hook is available
|
|
13
|
+
if command -v wip-license-hook &>/dev/null; then
|
|
14
|
+
HOOK_CMD="wip-license-hook"
|
|
15
|
+
elif [ -f "$REPO_ROOT/node_modules/.bin/wip-license-hook" ]; then
|
|
16
|
+
HOOK_CMD="$REPO_ROOT/node_modules/.bin/wip-license-hook"
|
|
17
|
+
elif command -v npx &>/dev/null; then
|
|
18
|
+
HOOK_CMD="npx @wipcomputer/wip-license-hook"
|
|
19
|
+
else
|
|
20
|
+
# No tool available — push proceeds silently
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
echo ""
|
|
25
|
+
echo "🔒 wip-license-hook: Checking license status before push..."
|
|
26
|
+
echo ""
|
|
27
|
+
|
|
28
|
+
cd "$REPO_ROOT"
|
|
29
|
+
|
|
30
|
+
# Run gate in advisory mode — capture output but NEVER block push
|
|
31
|
+
OUTPUT=$($HOOK_CMD gate 2>&1) || true
|
|
32
|
+
EXIT_CODE=$?
|
|
33
|
+
|
|
34
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
35
|
+
echo ""
|
|
36
|
+
echo "╔══════════════════════════════════════════════════╗"
|
|
37
|
+
echo "║ ⚠️ LICENSE DRIFT DETECTED ║"
|
|
38
|
+
echo "║ ║"
|
|
39
|
+
echo "║ Upstream license may have changed. ║"
|
|
40
|
+
echo "║ Your push will proceed (it's your code). ║"
|
|
41
|
+
echo "║ ║"
|
|
42
|
+
echo "║ Run: wip-license-hook scan --verbose ║"
|
|
43
|
+
echo "║ to review the changes. ║"
|
|
44
|
+
echo "╚══════════════════════════════════════════════════╝"
|
|
45
|
+
echo ""
|
|
46
|
+
echo "$OUTPUT"
|
|
47
|
+
echo ""
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# ALWAYS exit 0 — pre-push is advisory only
|
|
51
|
+
exit 0
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// wip-license-hook/mcp-server.mjs
|
|
3
|
+
// MCP server exposing license compliance scanning as tools.
|
|
4
|
+
// Wraps the compiled dist/ output. Registered via .mcp.json.
|
|
5
|
+
|
|
6
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
7
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import {
|
|
10
|
+
scanAll, scanAndUpdate, gateCheck,
|
|
11
|
+
readLedger, formatScanReport, formatLedgerReport,
|
|
12
|
+
} from './dist/core/index.js';
|
|
13
|
+
|
|
14
|
+
const server = new Server(
|
|
15
|
+
{ name: 'wip-license-hook', version: '1.0.0' },
|
|
16
|
+
{ capabilities: { tools: {} } }
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// ── Tool Definitions ──
|
|
20
|
+
|
|
21
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
22
|
+
tools: [
|
|
23
|
+
{
|
|
24
|
+
name: 'license_scan',
|
|
25
|
+
description: 'Scan a project for all dependency licenses. Returns a report of every dependency, its license, and any changes detected.',
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
repoPath: { type: 'string', description: 'Absolute path to the repo to scan' },
|
|
30
|
+
},
|
|
31
|
+
required: ['repoPath'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'license_audit',
|
|
36
|
+
description: 'Scan and update the license ledger for a project. Detects license changes (rug-pulls) by comparing against the stored ledger.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
repoPath: { type: 'string', description: 'Absolute path to the repo to audit' },
|
|
41
|
+
},
|
|
42
|
+
required: ['repoPath'],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'license_gate',
|
|
47
|
+
description: 'Gate check: returns pass/fail for license compliance. Use before merging PRs or publishing.',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
repoPath: { type: 'string', description: 'Absolute path to the repo to check' },
|
|
52
|
+
},
|
|
53
|
+
required: ['repoPath'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'license_ledger',
|
|
58
|
+
description: 'Read the current license ledger for a project. Shows all tracked dependencies and their license status.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
repoPath: { type: 'string', description: 'Absolute path to the repo' },
|
|
63
|
+
},
|
|
64
|
+
required: ['repoPath'],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
// ── Tool Handlers ──
|
|
71
|
+
|
|
72
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
73
|
+
const { name, arguments: args } = req.params;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
if (name === 'license_scan') {
|
|
77
|
+
const results = await scanAll(args.repoPath);
|
|
78
|
+
const report = formatScanReport(results);
|
|
79
|
+
return { content: [{ type: 'text', text: report }] };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (name === 'license_audit') {
|
|
83
|
+
const results = await scanAndUpdate(args.repoPath);
|
|
84
|
+
const report = formatScanReport(results);
|
|
85
|
+
return { content: [{ type: 'text', text: report }] };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (name === 'license_gate') {
|
|
89
|
+
const result = await gateCheck(args.repoPath);
|
|
90
|
+
return {
|
|
91
|
+
content: [{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: result.pass
|
|
94
|
+
? `PASS: All licenses compliant.`
|
|
95
|
+
: `FAIL: ${result.reason}`,
|
|
96
|
+
}],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (name === 'license_ledger') {
|
|
101
|
+
const ledger = readLedger(args.repoPath);
|
|
102
|
+
const report = formatLedgerReport(ledger);
|
|
103
|
+
return { content: [{ type: 'text', text: report }] };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
108
|
+
isError: true,
|
|
109
|
+
};
|
|
110
|
+
} catch (err) {
|
|
111
|
+
return {
|
|
112
|
+
content: [{ type: 'text', text: `Error: ${err.message}` }],
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const transport = new StdioServerTransport();
|
|
119
|
+
await server.connect(transport);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wipcomputer/wip-license-hook",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "@wipcomputer/wip-license-hook",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bin": {
|
|
12
|
+
"wip-license-hook": "dist/cli/index.js"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^20.0.0",
|
|
16
|
+
"typescript": "^5.3.0"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"node_modules/@types/node": {
|
|
23
|
+
"version": "20.19.33",
|
|
24
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
|
|
25
|
+
"integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==",
|
|
26
|
+
"dev": true,
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"undici-types": "~6.21.0"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"node_modules/typescript": {
|
|
33
|
+
"version": "5.9.3",
|
|
34
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
35
|
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
36
|
+
"dev": true,
|
|
37
|
+
"license": "Apache-2.0",
|
|
38
|
+
"bin": {
|
|
39
|
+
"tsc": "bin/tsc",
|
|
40
|
+
"tsserver": "bin/tsserver"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=14.17"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"node_modules/undici-types": {
|
|
47
|
+
"version": "6.21.0",
|
|
48
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
49
|
+
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
50
|
+
"dev": true,
|
|
51
|
+
"license": "MIT"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wipcomputer/wip-license-hook",
|
|
3
|
+
"version": "1.9.20",
|
|
4
|
+
"description": "License rug-pull detection and dependency license compliance for open source projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/cli/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"wip-license-hook": "dist/cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/cli/index.js",
|
|
14
|
+
"lint": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"license",
|
|
18
|
+
"compliance",
|
|
19
|
+
"git-hook",
|
|
20
|
+
"rug-pull",
|
|
21
|
+
"dependency",
|
|
22
|
+
"scanner"
|
|
23
|
+
],
|
|
24
|
+
"author": "WIP Computer",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"typescript": "^5.3.0",
|
|
31
|
+
"@types/node": "^20.0.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/",
|
|
38
|
+
"hooks/",
|
|
39
|
+
"dashboard/",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
]
|
|
43
|
+
}
|