@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.
Files changed (146) hide show
  1. package/.license-guard.json +7 -0
  2. package/.publish-skill.json +4 -0
  3. package/CHANGELOG.md +1120 -0
  4. package/CLA.md +19 -0
  5. package/DEV-GUIDE-GENERAL-PUBLIC.md +882 -0
  6. package/LICENSE +52 -0
  7. package/README.md +238 -0
  8. package/SKILL.md +728 -0
  9. package/TECHNICAL.md +282 -0
  10. package/UNIVERSAL-INTERFACE.md +180 -0
  11. package/_trash/RELEASE-NOTES-v1-8-0.md +29 -0
  12. package/_trash/RELEASE-NOTES-v1-8-1.md +7 -0
  13. package/_trash/RELEASE-NOTES-v1-8-2.md +7 -0
  14. package/_trash/RELEASE-NOTES-v1-9-0.md +37 -0
  15. package/_trash/RELEASE-NOTES-v1-9-1.md +38 -0
  16. package/_trash/RELEASE-NOTES-v1-9-10.md +40 -0
  17. package/_trash/RELEASE-NOTES-v1-9-2.md +40 -0
  18. package/_trash/RELEASE-NOTES-v1-9-6.md +72 -0
  19. package/_trash/RELEASE-NOTES-v1-9-7.md +23 -0
  20. package/_trash/RELEASE-NOTES-v1-9-9.md +75 -0
  21. package/_trash/guide 2/DEV-GUIDE.md +487 -0
  22. package/_trash/guide 2/scripts/deploy-public.sh +152 -0
  23. package/package.json +27 -0
  24. package/scripts/SKILL-deploy-public.md +61 -0
  25. package/scripts/SKILL-post-merge-rename.md +47 -0
  26. package/scripts/deploy-public.sh +264 -0
  27. package/scripts/post-merge-rename.sh +205 -0
  28. package/scripts/publish-skill.sh +134 -0
  29. package/tools/deploy-public/LICENSE +52 -0
  30. package/tools/deploy-public/README.md +31 -0
  31. package/tools/deploy-public/SKILL.md +71 -0
  32. package/tools/deploy-public/deploy-public.sh +264 -0
  33. package/tools/deploy-public/package.json +9 -0
  34. package/tools/ldm-jobs/LICENSE +52 -0
  35. package/tools/ldm-jobs/README.md +46 -0
  36. package/tools/ldm-jobs/backup.sh +16 -0
  37. package/tools/ldm-jobs/branch-protect.sh +39 -0
  38. package/tools/ldm-jobs/crystal-capture.sh +19 -0
  39. package/tools/ldm-jobs/setup-shell.sh +27 -0
  40. package/tools/ldm-jobs/visibility-audit.sh +27 -0
  41. package/tools/post-merge-rename/LICENSE +52 -0
  42. package/tools/post-merge-rename/README.md +29 -0
  43. package/tools/post-merge-rename/SKILL.md +57 -0
  44. package/tools/post-merge-rename/package.json +9 -0
  45. package/tools/post-merge-rename/post-merge-rename.sh +122 -0
  46. package/tools/wip-branch-guard/INSTALL.md +41 -0
  47. package/tools/wip-branch-guard/guard.mjs +259 -0
  48. package/tools/wip-branch-guard/package.json +11 -0
  49. package/tools/wip-file-guard/CHANGELOG.md +6 -0
  50. package/tools/wip-file-guard/LICENSE +52 -0
  51. package/tools/wip-file-guard/README.md +113 -0
  52. package/tools/wip-file-guard/REFERENCE.md +86 -0
  53. package/tools/wip-file-guard/SKILL.md +105 -0
  54. package/tools/wip-file-guard/guard.mjs +128 -0
  55. package/tools/wip-file-guard/openclaw.plugin.json +8 -0
  56. package/tools/wip-file-guard/package.json +27 -0
  57. package/tools/wip-file-guard/test.sh +119 -0
  58. package/tools/wip-license-guard/LICENSE +52 -0
  59. package/tools/wip-license-guard/README.md +32 -0
  60. package/tools/wip-license-guard/SKILL.md +65 -0
  61. package/tools/wip-license-guard/cli.mjs +464 -0
  62. package/tools/wip-license-guard/core.mjs +310 -0
  63. package/tools/wip-license-guard/hook.mjs +146 -0
  64. package/tools/wip-license-guard/package.json +15 -0
  65. package/tools/wip-license-hook/CHANGELOG.md +17 -0
  66. package/tools/wip-license-hook/LICENSE +52 -0
  67. package/tools/wip-license-hook/README.md +200 -0
  68. package/tools/wip-license-hook/SKILL.md +111 -0
  69. package/tools/wip-license-hook/dist/cli/index.d.ts +15 -0
  70. package/tools/wip-license-hook/dist/cli/index.js +170 -0
  71. package/tools/wip-license-hook/dist/cli/index.js.map +1 -0
  72. package/tools/wip-license-hook/dist/core/detector.d.ts +12 -0
  73. package/tools/wip-license-hook/dist/core/detector.js +104 -0
  74. package/tools/wip-license-hook/dist/core/detector.js.map +1 -0
  75. package/tools/wip-license-hook/dist/core/index.d.ts +4 -0
  76. package/tools/wip-license-hook/dist/core/index.js +5 -0
  77. package/tools/wip-license-hook/dist/core/index.js.map +1 -0
  78. package/tools/wip-license-hook/dist/core/ledger.d.ts +49 -0
  79. package/tools/wip-license-hook/dist/core/ledger.js +72 -0
  80. package/tools/wip-license-hook/dist/core/ledger.js.map +1 -0
  81. package/tools/wip-license-hook/dist/core/reporter.d.ts +14 -0
  82. package/tools/wip-license-hook/dist/core/reporter.js +227 -0
  83. package/tools/wip-license-hook/dist/core/reporter.js.map +1 -0
  84. package/tools/wip-license-hook/dist/core/scanner.d.ts +39 -0
  85. package/tools/wip-license-hook/dist/core/scanner.js +325 -0
  86. package/tools/wip-license-hook/dist/core/scanner.js.map +1 -0
  87. package/tools/wip-license-hook/hooks/pre-pull.sh +55 -0
  88. package/tools/wip-license-hook/hooks/pre-push.sh +51 -0
  89. package/tools/wip-license-hook/mcp-server.mjs +119 -0
  90. package/tools/wip-license-hook/package-lock.json +54 -0
  91. package/tools/wip-license-hook/package.json +43 -0
  92. package/tools/wip-license-hook/src/cli/index.ts +189 -0
  93. package/tools/wip-license-hook/src/core/detector.ts +130 -0
  94. package/tools/wip-license-hook/src/core/index.ts +4 -0
  95. package/tools/wip-license-hook/src/core/ledger.ts +116 -0
  96. package/tools/wip-license-hook/src/core/reporter.ts +255 -0
  97. package/tools/wip-license-hook/src/core/scanner.ts +367 -0
  98. package/tools/wip-license-hook/tsconfig.json +16 -0
  99. package/tools/wip-readme-format/README.md +49 -0
  100. package/tools/wip-readme-format/SKILL.md +84 -0
  101. package/tools/wip-readme-format/format.mjs +570 -0
  102. package/tools/wip-readme-format/package.json +15 -0
  103. package/tools/wip-release/CHANGELOG.md +42 -0
  104. package/tools/wip-release/LICENSE +52 -0
  105. package/tools/wip-release/README.md +45 -0
  106. package/tools/wip-release/REFERENCE.md +100 -0
  107. package/tools/wip-release/SKILL.md +139 -0
  108. package/tools/wip-release/cli.js +161 -0
  109. package/tools/wip-release/core.mjs +1174 -0
  110. package/tools/wip-release/mcp-server.mjs +109 -0
  111. package/tools/wip-release/package.json +36 -0
  112. package/tools/wip-repo-init/README.md +38 -0
  113. package/tools/wip-repo-init/SKILL.md +77 -0
  114. package/tools/wip-repo-init/init.mjs +142 -0
  115. package/tools/wip-repo-init/package.json +11 -0
  116. package/tools/wip-repo-permissions-hook/LICENSE +52 -0
  117. package/tools/wip-repo-permissions-hook/README.md +86 -0
  118. package/tools/wip-repo-permissions-hook/SKILL.md +73 -0
  119. package/tools/wip-repo-permissions-hook/cli.js +83 -0
  120. package/tools/wip-repo-permissions-hook/core.mjs +122 -0
  121. package/tools/wip-repo-permissions-hook/guard.mjs +64 -0
  122. package/tools/wip-repo-permissions-hook/mcp-server.mjs +92 -0
  123. package/tools/wip-repo-permissions-hook/openclaw.plugin.json +8 -0
  124. package/tools/wip-repo-permissions-hook/package.json +31 -0
  125. package/tools/wip-repos/LICENSE +52 -0
  126. package/tools/wip-repos/README.md +77 -0
  127. package/tools/wip-repos/SKILL.md +80 -0
  128. package/tools/wip-repos/cli.mjs +176 -0
  129. package/tools/wip-repos/core.mjs +290 -0
  130. package/tools/wip-repos/mcp-server.mjs +157 -0
  131. package/tools/wip-repos/package.json +34 -0
  132. package/tools/wip-universal-installer/CHANGELOG.md +57 -0
  133. package/tools/wip-universal-installer/LICENSE +52 -0
  134. package/tools/wip-universal-installer/README.md +81 -0
  135. package/tools/wip-universal-installer/REFERENCE.md +122 -0
  136. package/tools/wip-universal-installer/SKILL.md +87 -0
  137. package/tools/wip-universal-installer/SPEC.md +180 -0
  138. package/tools/wip-universal-installer/detect.mjs +130 -0
  139. package/tools/wip-universal-installer/examples/minimal/README.md +20 -0
  140. package/tools/wip-universal-installer/examples/minimal/SKILL.md +28 -0
  141. package/tools/wip-universal-installer/examples/minimal/cli.mjs +4 -0
  142. package/tools/wip-universal-installer/examples/minimal/core.mjs +8 -0
  143. package/tools/wip-universal-installer/examples/minimal/mcp-server.mjs +27 -0
  144. package/tools/wip-universal-installer/examples/minimal/package.json +12 -0
  145. package/tools/wip-universal-installer/install.js +930 -0
  146. package/tools/wip-universal-installer/package.json +36 -0
@@ -0,0 +1,310 @@
1
+ // wip-license-guard/core.mjs
2
+ // License generation and validation logic.
3
+ // Reads templates from ai/wip-templates/readme/ when available.
4
+ // Falls back to hardcoded defaults for standalone use.
5
+
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join, dirname } from 'node:path';
8
+
9
+ // ── Template Resolution ─────────────────────────────────────────────
10
+
11
+ /**
12
+ * Find the templates directory. Checks:
13
+ * 1. WIP_TEMPLATES_DIR env var
14
+ * 2. Walk up from repoPath looking for ai/wip-templates/readme/
15
+ * 3. Walk up from this file's location (for toolbox-internal use)
16
+ * Returns null if not found.
17
+ */
18
+ function findTemplatesDir(repoPath) {
19
+ // 1. Env var
20
+ const envDir = process.env.WIP_TEMPLATES_DIR;
21
+ if (envDir && existsSync(join(envDir, 'LICENSE.md'))) return envDir;
22
+
23
+ // 2. Walk up from repoPath
24
+ if (repoPath) {
25
+ let dir = repoPath;
26
+ for (let i = 0; i < 10; i++) {
27
+ const candidate = join(dir, 'ai', 'wip-templates', 'readme');
28
+ if (existsSync(join(candidate, 'LICENSE.md'))) return candidate;
29
+ const parent = dirname(dir);
30
+ if (parent === dir) break;
31
+ dir = parent;
32
+ }
33
+ }
34
+
35
+ // 3. Walk up from this file (tools/wip-license-guard/ -> repo root)
36
+ const thisDir = dirname(new URL(import.meta.url).pathname);
37
+ let dir = thisDir;
38
+ for (let i = 0; i < 10; i++) {
39
+ const candidate = join(dir, 'ai', 'wip-templates', 'readme');
40
+ if (existsSync(join(candidate, 'LICENSE.md'))) return candidate;
41
+ const parent = dirname(dir);
42
+ if (parent === dir) break;
43
+ dir = parent;
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * Read a template file. Returns content or null.
51
+ */
52
+ function readTemplate(templatesDir, filename) {
53
+ if (!templatesDir) return null;
54
+ const path = join(templatesDir, filename);
55
+ if (!existsSync(path)) return null;
56
+ return readFileSync(path, 'utf8');
57
+ }
58
+
59
+ /**
60
+ * Extract the markdown format section from wip-lic-footer.md.
61
+ * The file has two sections: // PLAIN TXT and // MD FORMAT.
62
+ * Returns the MD FORMAT section, or the whole file if no marker found.
63
+ */
64
+ function extractMdFormat(content) {
65
+ const marker = '// MD FORMAT';
66
+ const idx = content.indexOf(marker);
67
+ if (idx === -1) return content;
68
+ return content.slice(idx + marker.length).trim();
69
+ }
70
+
71
+ // ── License Generation ──────────────────────────────────────────────
72
+
73
+ export function generateLicense(config, repoPath) {
74
+ const { copyright, license, year } = config;
75
+
76
+ if (license === 'MIT') return generateMIT(copyright, year);
77
+ if (license === 'AGPL-3.0') return generateAGPL(copyright, year);
78
+ if (license === 'MIT+AGPL') return generateDual(copyright, year, repoPath);
79
+
80
+ return generateMIT(copyright, year);
81
+ }
82
+
83
+ function generateMIT(copyright, year) {
84
+ return `MIT License
85
+
86
+ Copyright (c) ${year} ${copyright}
87
+
88
+ Permission is hereby granted, free of charge, to any person obtaining a copy
89
+ of this software and associated documentation files (the "Software"), to deal
90
+ in the Software without restriction, including without limitation the rights
91
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92
+ copies of the Software, and to permit persons to whom the Software is
93
+ furnished to do so, subject to the following conditions:
94
+
95
+ The above copyright notice and this permission notice shall be included in all
96
+ copies or substantial portions of the Software.
97
+
98
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
99
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
100
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
101
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
102
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
103
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
104
+ SOFTWARE.
105
+ `;
106
+ }
107
+
108
+ function generateAGPL(copyright, year) {
109
+ return `GNU Affero General Public License v3.0
110
+
111
+ Copyright (c) ${year} ${copyright}
112
+
113
+ This program is free software: you can redistribute it and/or modify
114
+ it under the terms of the GNU Affero General Public License as published
115
+ by the Free Software Foundation, either version 3 of the License, or
116
+ (at your option) any later version.
117
+
118
+ This program is distributed in the hope that it will be useful,
119
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
120
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
121
+ GNU Affero General Public License for more details.
122
+
123
+ You should have received a copy of the GNU Affero General Public License
124
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
125
+ `;
126
+ }
127
+
128
+ function generateDual(copyright, year, repoPath) {
129
+ // Try template first
130
+ const templatesDir = findTemplatesDir(repoPath);
131
+ const template = readTemplate(templatesDir, 'LICENSE.md');
132
+ if (template) {
133
+ // Replace copyright year if template has a different one
134
+ return template.replace(/Copyright \(c\) \d{4}/, `Copyright (c) ${year}`);
135
+ }
136
+
137
+ // Hardcoded fallback
138
+ return `Dual License: MIT + AGPLv3
139
+
140
+ Copyright (c) ${year} ${copyright}
141
+
142
+
143
+ 1. MIT License (local and personal use)
144
+ ---------------------------------------
145
+
146
+ Permission is hereby granted, free of charge, to any person obtaining a copy
147
+ of this software and associated documentation files (the "Software"), to deal
148
+ in the Software without restriction, including without limitation the rights
149
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
150
+ copies of the Software, and to permit persons to whom the Software is
151
+ furnished to do so, subject to the following conditions:
152
+
153
+ The above copyright notice and this permission notice shall be included in all
154
+ copies or substantial portions of the Software.
155
+
156
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
158
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
159
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
160
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
161
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
162
+ SOFTWARE.
163
+
164
+
165
+ 2. GNU Affero General Public License v3.0 (commercial and cloud use)
166
+ --------------------------------------------------------------------
167
+
168
+ If you run this software as part of a hosted service, cloud platform,
169
+ marketplace listing, or any network-accessible offering for commercial
170
+ purposes, the AGPLv3 terms apply. You must either:
171
+
172
+ a) Release your complete source code under AGPLv3, or
173
+ b) Obtain a commercial license.
174
+
175
+ This program is free software: you can redistribute it and/or modify
176
+ it under the terms of the GNU Affero General Public License as published
177
+ by the Free Software Foundation, either version 3 of the License, or
178
+ (at your option) any later version.
179
+
180
+ This program is distributed in the hope that it will be useful,
181
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
182
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183
+ GNU Affero General Public License for more details.
184
+
185
+ You should have received a copy of the GNU Affero General Public License
186
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
187
+
188
+
189
+ AGPLv3 for personal use is free. Commercial licenses available.
190
+ `;
191
+ }
192
+
193
+ // ── CLA Generation ──────────────────────────────────────────────────
194
+
195
+ export function generateCLA(repoPath) {
196
+ // Try template first
197
+ const templatesDir = findTemplatesDir(repoPath);
198
+ const template = readTemplate(templatesDir, 'cla.md');
199
+ if (template) return template;
200
+
201
+ // Hardcoded fallback
202
+ return `###### WIP Computer
203
+
204
+ # Contributor License Agreement
205
+
206
+ By submitting a pull request to this repository, you agree to the following:
207
+
208
+ 1. **You grant WIP Computer, Inc. a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license** to use, reproduce, modify, distribute, sublicense, and otherwise exploit your contribution under any license, including commercial licenses.
209
+
210
+ 2. **You retain copyright** to your contribution. This agreement does not transfer ownership. You can use your own code however you want.
211
+
212
+ 3. **You confirm** that your contribution is your original work, or that you have the right to submit it under these terms.
213
+
214
+ 4. **You understand** that your contribution may be used in both open source and commercial versions of this software.
215
+
216
+ This is standard open source governance. Apache, Google, Meta, and Anthropic all use similar agreements. The goal is simple: keep the tools free for everyone while allowing WIP Computer, Inc. to offer commercial licenses to companies that need them.
217
+
218
+ Using these tools to build your own software is always free. This agreement only matters if WIP Computer, Inc. needs to relicense the codebase commercially.
219
+
220
+ If you have questions, open an issue or reach out.
221
+ `;
222
+ }
223
+
224
+ // ── README License Block ────────────────────────────────────────────
225
+
226
+ export function generateReadmeBlock(config, repoPath) {
227
+ const { license, attribution } = config;
228
+
229
+ if (license === 'MIT') {
230
+ return `## License
231
+
232
+ MIT.${attribution ? ' ' + attribution : ''}
233
+ `;
234
+ }
235
+
236
+ if (license === 'AGPL-3.0') {
237
+ return `## License
238
+
239
+ AGPLv3. AGPLv3 for personal use is free.${attribution ? '\n\n' + attribution : ''}
240
+ `;
241
+ }
242
+
243
+ // MIT+AGPL: try template first
244
+ const templatesDir = findTemplatesDir(repoPath);
245
+ const footer = readTemplate(templatesDir, 'wip-lic-footer.md');
246
+ if (footer) {
247
+ return extractMdFormat(footer);
248
+ }
249
+
250
+ // Hardcoded fallback
251
+ return `## License
252
+
253
+ Dual-license model designed to keep tools free while preventing commercial resellers.
254
+
255
+ \`\`\`
256
+ MIT All CLI tools, MCP servers, skills, and hooks (use anywhere, no restrictions).
257
+ AGPLv3 Commercial redistribution, marketplace listings, or bundling into paid services.
258
+ \`\`\`
259
+
260
+ AGPLv3 for personal use is free. Commercial licenses available.
261
+
262
+ ### Can I use this?
263
+
264
+ **Yes, freely:**
265
+ - Use any tool locally or on your own servers
266
+ - Modify the code for your own projects
267
+ - Include in your internal CI/CD pipelines
268
+ - Fork it and send us feedback via PRs (we'd love that)
269
+
270
+ **Need a commercial license:**
271
+ - Bundle into a product you sell
272
+ - List on a marketplace (VS Code, JetBrains, etc.)
273
+ - Offer as part of a hosted/SaaS platform
274
+ - Redistribute commercially
275
+
276
+ Using these tools to build your own software is fine. Reselling the tools themselves is what requires a commercial license.
277
+
278
+ By submitting a PR, you agree to the [Contributor License Agreement](CLA.md).
279
+ ${attribution ? '\n' + attribution : ''}`;
280
+ }
281
+
282
+ // ── README License Section Replace/Remove ───────────────────────────
283
+
284
+ /**
285
+ * Replace ## License section in readme content.
286
+ * If no ## License exists, appends the block at the end.
287
+ * Returns the updated content.
288
+ */
289
+ export function replaceReadmeLicenseSection(content, config, repoPath) {
290
+ const block = generateReadmeBlock(config, repoPath);
291
+
292
+ // Match from "## License" to the next ## heading or end of file
293
+ const licenseRegex = /## License[\s\S]*?(?=\n## [^#]|\n---\s*$|$)/;
294
+ if (licenseRegex.test(content)) {
295
+ return content.replace(licenseRegex, block.trimEnd());
296
+ }
297
+
298
+ // No license section found, append
299
+ return content.trimEnd() + '\n\n' + block;
300
+ }
301
+
302
+ /**
303
+ * Remove ## License section from content (for sub-tool READMEs).
304
+ * Returns the updated content.
305
+ */
306
+ export function removeReadmeLicenseSection(content) {
307
+ // Match from "## License" to the next ## heading or end of file
308
+ const licenseRegex = /\n## License[\s\S]*?(?=\n## [^#]|$)/;
309
+ return content.replace(licenseRegex, '').trimEnd() + '\n';
310
+ }
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ // wip-license-guard/hook.mjs
3
+ // PreToolUse hook for Claude Code.
4
+ // Blocks commits/pushes when license compliance fails.
5
+ // Checks: LICENSE file, copyright, CLA.md, README license section.
6
+
7
+ import { existsSync, readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+
10
+ function deny(reason) {
11
+ const output = {
12
+ hookSpecificOutput: {
13
+ hookEventName: 'PreToolUse',
14
+ permissionDecision: 'deny',
15
+ permissionDecisionReason: reason,
16
+ },
17
+ };
18
+ process.stdout.write(JSON.stringify(output));
19
+ }
20
+
21
+ function findRepoRoot(startPath) {
22
+ let dir = startPath;
23
+ for (let i = 0; i < 20; i++) {
24
+ if (existsSync(join(dir, '.git'))) return dir;
25
+ const parent = join(dir, '..');
26
+ if (parent === dir) break;
27
+ dir = parent;
28
+ }
29
+ return null;
30
+ }
31
+
32
+ function checkLicenseCompliance(repoPath) {
33
+ const issues = [];
34
+ const configPath = join(repoPath, '.license-guard.json');
35
+
36
+ // No config means license-guard hasn't been set up. Don't block.
37
+ if (!existsSync(configPath)) return [];
38
+
39
+ const config = JSON.parse(readFileSync(configPath, 'utf8'));
40
+
41
+ // 1. LICENSE file must exist
42
+ const licensePath = join(repoPath, 'LICENSE');
43
+ if (!existsSync(licensePath)) {
44
+ issues.push('LICENSE file is missing');
45
+ } else {
46
+ const licenseText = readFileSync(licensePath, 'utf8');
47
+
48
+ // 2. Copyright must match
49
+ if (!licenseText.includes(config.copyright)) {
50
+ issues.push(`LICENSE copyright does not match "${config.copyright}"`);
51
+ }
52
+
53
+ // 3. Dual-license must include AGPL
54
+ if (config.license === 'MIT+AGPL' && !licenseText.includes('AGPL') && !licenseText.includes('GNU Affero')) {
55
+ issues.push('LICENSE is MIT-only but config requires MIT+AGPL');
56
+ }
57
+ }
58
+
59
+ // 4. CLA.md should exist for repos with contributors
60
+ if (!existsSync(join(repoPath, 'CLA.md'))) {
61
+ issues.push('CLA.md is missing');
62
+ }
63
+
64
+ // 5. README must have license section
65
+ const readmePath = join(repoPath, 'README.md');
66
+ if (existsSync(readmePath)) {
67
+ const readme = readFileSync(readmePath, 'utf8');
68
+ if (!readme.includes('## License')) {
69
+ issues.push('README.md missing ## License section');
70
+ }
71
+ if (config.license === 'MIT+AGPL' && !readme.includes('AGPL')) {
72
+ issues.push('README.md License section missing AGPL reference');
73
+ }
74
+ }
75
+
76
+ return issues;
77
+ }
78
+
79
+ // CLI mode: node hook.mjs --check [path]
80
+ if (process.argv.includes('--check')) {
81
+ const path = process.argv[process.argv.indexOf('--check') + 1] || '.';
82
+ const issues = checkLicenseCompliance(path);
83
+ if (issues.length === 0) {
84
+ console.log(' All license checks passed.');
85
+ process.exit(0);
86
+ } else {
87
+ console.log(' License compliance issues:');
88
+ for (const issue of issues) console.log(` - ${issue}`);
89
+ console.log('\n Run `wip-license-guard check --fix` to auto-repair.');
90
+ process.exit(1);
91
+ }
92
+ }
93
+
94
+ async function main() {
95
+ let raw = '';
96
+ for await (const chunk of process.stdin) {
97
+ raw += chunk;
98
+ }
99
+
100
+ let input;
101
+ try {
102
+ input = JSON.parse(raw);
103
+ } catch {
104
+ process.exit(0);
105
+ }
106
+
107
+ const toolName = input.tool_name || '';
108
+
109
+ // Only check on Bash tool calls that look like git commit or git push
110
+ if (toolName !== 'Bash') {
111
+ process.exit(0);
112
+ }
113
+
114
+ const command = input.tool_input?.command || '';
115
+
116
+ // Check if this is a git commit or git push
117
+ const isCommit = /\bgit\s+commit\b/.test(command);
118
+ const isPush = /\bgit\s+push\b/.test(command);
119
+
120
+ if (!isCommit && !isPush) {
121
+ process.exit(0);
122
+ }
123
+
124
+ // Find repo root from cwd
125
+ const cwd = input.tool_input?.cwd || process.cwd();
126
+ const repoRoot = findRepoRoot(cwd);
127
+
128
+ if (!repoRoot) {
129
+ process.exit(0);
130
+ }
131
+
132
+ const issues = checkLicenseCompliance(repoRoot);
133
+
134
+ if (issues.length > 0) {
135
+ const issueList = issues.map(i => ` - ${i}`).join('\n');
136
+ deny(
137
+ `BLOCKED: License compliance check failed.\n${issueList}\n\nFix these issues before committing. Run \`wip-license-guard check --fix\` to auto-repair.`
138
+ );
139
+ process.exit(0);
140
+ }
141
+
142
+ // All good
143
+ process.exit(0);
144
+ }
145
+
146
+ main().catch(() => process.exit(0));
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@wipcomputer/wip-license-guard",
3
+ "version": "1.9.20",
4
+ "description": "License compliance for your own repos. Ensures correct copyright, dual-license blocks, and LICENSE files.",
5
+ "type": "module",
6
+ "bin": {
7
+ "wip-license-guard": "./cli.mjs"
8
+ },
9
+ "license": "MIT AND AGPL-3.0-or-later",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/wipcomputer/wip-ai-devops-toolbox.git",
13
+ "directory": "tools/wip-license-guard"
14
+ }
15
+ }
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-02-15)
4
+
5
+ ### Initial Release
6
+
7
+ - Core license detection engine with fingerprinting for 14 license types
8
+ - License ledger (`LICENSE-LEDGER.json`) with dependency tracking
9
+ - LICENSE file snapshot archiving with date-stamped copies
10
+ - Auto-detection of package managers: npm, pip, cargo, go modules
11
+ - Git pre-pull hook (hard gate — blocks merge on license change)
12
+ - Git pre-push hook (advisory — warns but doesn't block)
13
+ - Upstream fork license monitoring via git remote
14
+ - Static HTML dashboard generator with dark theme
15
+ - CLI with commands: init, scan, check, gate, report, dashboard, alert, install, badge
16
+ - Offline mode (skips network calls, uses cached data)
17
+ - Shields.io badge URL generation
@@ -0,0 +1,52 @@
1
+ Dual License: MIT + AGPLv3
2
+
3
+ Copyright (c) 2026 WIP Computer, Inc.
4
+
5
+
6
+ 1. MIT License (local and personal use)
7
+ ---------------------------------------
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+
28
+ 2. GNU Affero General Public License v3.0 (commercial and cloud use)
29
+ --------------------------------------------------------------------
30
+
31
+ If you run this software as part of a hosted service, cloud platform,
32
+ marketplace listing, or any network-accessible offering for commercial
33
+ purposes, the AGPLv3 terms apply. You must either:
34
+
35
+ a) Release your complete source code under AGPLv3, or
36
+ b) Obtain a commercial license.
37
+
38
+ This program is free software: you can redistribute it and/or modify
39
+ it under the terms of the GNU Affero General Public License as published
40
+ by the Free Software Foundation, either version 3 of the License, or
41
+ (at your option) any later version.
42
+
43
+ This program is distributed in the hope that it will be useful,
44
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
45
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46
+ GNU Affero General Public License for more details.
47
+
48
+ You should have received a copy of the GNU Affero General Public License
49
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
50
+
51
+
52
+ AGPLv3 for personal use is free. Commercial licenses available.