@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,109 @@
1
+ #!/usr/bin/env node
2
+ // wip-release/mcp-server.mjs
3
+ // MCP server exposing release pipeline as tools.
4
+ // Wraps core.mjs. 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
+ release, detectCurrentVersion, bumpSemver, buildReleaseNotes,
11
+ } from './core.mjs';
12
+
13
+ const server = new Server(
14
+ { name: 'wip-release', version: '1.3.0' },
15
+ { capabilities: { tools: {} } }
16
+ );
17
+
18
+ // ── Tool Definitions ──
19
+
20
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
21
+ tools: [
22
+ {
23
+ name: 'release',
24
+ description: 'Run the full release pipeline. Bumps version, updates changelog + SKILL.md, commits, tags, publishes to npm + GitHub. Must be run from repo root or provide repoPath.',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ repoPath: { type: 'string', description: 'Absolute path to the repo. Defaults to cwd.' },
29
+ level: { type: 'string', enum: ['patch', 'minor', 'major'], description: 'Semver bump level' },
30
+ notes: { type: 'string', description: 'Changelog entry and release notes summary' },
31
+ dryRun: { type: 'boolean', description: 'Preview only, no changes', default: false },
32
+ noPublish: { type: 'boolean', description: 'Bump + tag only, skip npm/GitHub publish', default: false },
33
+ skipProductCheck: { type: 'boolean', description: 'Skip product doc freshness check', default: false },
34
+ },
35
+ required: ['level', 'notes'],
36
+ },
37
+ },
38
+ {
39
+ name: 'release_status',
40
+ description: 'Check current version and what the next version would be for a given bump level.',
41
+ inputSchema: {
42
+ type: 'object',
43
+ properties: {
44
+ repoPath: { type: 'string', description: 'Absolute path to the repo. Defaults to cwd.' },
45
+ level: { type: 'string', enum: ['patch', 'minor', 'major'], description: 'Semver bump level to preview' },
46
+ },
47
+ required: ['level'],
48
+ },
49
+ },
50
+ ],
51
+ }));
52
+
53
+ // ── Tool Handlers ──
54
+
55
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
56
+ const { name, arguments: args } = req.params;
57
+
58
+ if (name === 'release') {
59
+ try {
60
+ const result = await release({
61
+ repoPath: args.repoPath || process.cwd(),
62
+ level: args.level,
63
+ notes: args.notes,
64
+ dryRun: args.dryRun || false,
65
+ notesSource: 'flag', // MCP always passes notes directly
66
+ noPublish: args.noPublish || false,
67
+ skipProductCheck: args.skipProductCheck || false,
68
+ });
69
+ return {
70
+ content: [{
71
+ type: 'text',
72
+ text: `Release complete: ${result.currentVersion} -> ${result.newVersion}${result.dryRun ? ' (dry run)' : ''}`,
73
+ }],
74
+ };
75
+ } catch (err) {
76
+ return {
77
+ content: [{ type: 'text', text: `Release failed: ${err.message}` }],
78
+ isError: true,
79
+ };
80
+ }
81
+ }
82
+
83
+ if (name === 'release_status') {
84
+ try {
85
+ const repoPath = args.repoPath || process.cwd();
86
+ const current = detectCurrentVersion(repoPath);
87
+ const next = bumpSemver(current, args.level);
88
+ return {
89
+ content: [{
90
+ type: 'text',
91
+ text: `Current: ${current}\nNext (${args.level}): ${next}`,
92
+ }],
93
+ };
94
+ } catch (err) {
95
+ return {
96
+ content: [{ type: 'text', text: `Status check failed: ${err.message}` }],
97
+ isError: true,
98
+ };
99
+ }
100
+ }
101
+
102
+ return {
103
+ content: [{ type: 'text', text: `Unknown tool: ${name}` }],
104
+ isError: true,
105
+ };
106
+ });
107
+
108
+ const transport = new StdioServerTransport();
109
+ await server.connect(transport);
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@wipcomputer/wip-release",
3
+ "version": "1.9.20",
4
+ "type": "module",
5
+ "description": "One-command release pipeline. Bumps version, updates changelog + SKILL.md, publishes to npm + GitHub.",
6
+ "main": "core.mjs",
7
+ "bin": {
8
+ "wip-release": "cli.js"
9
+ },
10
+ "exports": {
11
+ ".": "./core.mjs",
12
+ "./cli": "./cli.js"
13
+ },
14
+ "scripts": {
15
+ "test": "node cli.js --help"
16
+ },
17
+ "keywords": [
18
+ "release",
19
+ "version",
20
+ "publish",
21
+ "npm",
22
+ "agent-native",
23
+ "sensor",
24
+ "actuator"
25
+ ],
26
+ "author": "Parker Todd Brooks",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/wipcomputer/wip-release.git"
31
+ },
32
+ "homepage": "https://github.com/wipcomputer/wip-ai-devops-toolbox",
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.0.0"
35
+ }
36
+ }
@@ -0,0 +1,38 @@
1
+ ###### WIP Computer
2
+
3
+ # Repo Init
4
+
5
+ Scaffold the standard `ai/` directory in any repo. Plans, notes, ideas, dev updates, todos. One command.
6
+
7
+ ## What it does
8
+
9
+ - **New repo:** Creates the full `ai/` directory structure
10
+ - **Existing repo:** Moves old `ai/` contents to `ai/_sort/ai_old/` so you can sort at your own pace
11
+ - Nothing is deleted
12
+
13
+ ## The `ai/` directory
14
+
15
+ ```
16
+ ai/
17
+ plan/ architecture plans, roadmaps
18
+ dev-updates/ what was built, session logs
19
+ todos/
20
+ PUNCHLIST.md blockers to ship
21
+ inboxes/ per-agent action items
22
+ notes/ research, references, raw conversation logs
23
+ ```
24
+
25
+ The `ai/` folder is the development process. It is not part of the published product. Public repos exclude it via deploy-public.sh.
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ node tools/wip-repo-init/init.mjs /path/to/repo
31
+ ```
32
+
33
+ ## Interfaces
34
+
35
+ - **CLI**: Run from terminal
36
+ - **Skill**: SKILL.md for agent instructions
37
+
38
+ ## Part of [AI DevOps Toolbox](https://github.com/wipcomputer/wip-ai-devops-toolbox)
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: wip-repo-init
3
+ description: Scaffold the standard ai/ directory structure in any repo.
4
+ license: MIT
5
+ interface: [cli, skill]
6
+ metadata:
7
+ display-name: "Repo Init"
8
+ version: "1.0.0"
9
+ homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox"
10
+ author: "Parker Todd Brooks"
11
+ category: repo-management
12
+ capabilities:
13
+ - scaffold-ai-dir
14
+ - template-copy
15
+ requires:
16
+ bins: [node]
17
+ openclaw:
18
+ requires:
19
+ bins: [node]
20
+ install:
21
+ - id: node
22
+ kind: node
23
+ package: "@wipcomputer/wip-repo-init"
24
+ bins: [wip-repo-init]
25
+ label: "Install via npm"
26
+ emoji: "📁"
27
+ compatibility: Requires node. Node.js 18+.
28
+ ---
29
+
30
+ # Repo Init
31
+
32
+ Scaffolds the standard `ai/` directory structure in any repo.
33
+
34
+ ## Commands
35
+
36
+ ```
37
+ wip-repo-init /path/to/repo # scaffold ai/ in a repo
38
+ wip-repo-init /path/to/repo --dry-run # preview without changes
39
+ wip-repo-init /path/to/repo --yes # skip confirmation prompt
40
+ ```
41
+
42
+ ## What happens
43
+
44
+ **New repo (no ai/ folder):** Creates the full standard structure with all READMEs explaining what goes where.
45
+
46
+ **Existing repo (ai/ folder exists):** Shows you what will happen and asks for confirmation. If you say yes:
47
+ 1. Moves your current `ai/` contents to `ai/_sort/ai_old/`
48
+ 2. Scaffolds the new standard structure
49
+ 3. You sort files from `ai_old/` into the new structure at your own pace
50
+
51
+ Nothing is deleted. Your old files are all in `ai/_sort/ai_old/`.
52
+
53
+ ## The standard ai/ structure
54
+
55
+ ```
56
+ ai/
57
+ read-me-first.md <- explains everything, links to all sections
58
+ _sort/ <- holding pen for files that need sorting
59
+ _trash/ <- archive (never delete, move here)
60
+ dev-updates/ <- engineering changelog, auto-detected by wip-release
61
+ product/
62
+ readme-first-product.md <- the product bible
63
+ notes/ <- freeform notes, research
64
+ plans-prds/ <- plans with lifecycle stages
65
+ roadmap.md <- prioritized roadmap
66
+ current/ <- plans being built now
67
+ upcoming/ <- plans that are next
68
+ archive-complete/ <- plans that shipped
69
+ todos/ <- per-agent todo files
70
+ product-ideas/ <- ideas that aren't plans yet
71
+ ```
72
+
73
+ Every folder has a `_trash/` subfolder. Every section has a README explaining what it is, what goes in it, and how to maintain it.
74
+
75
+ ## Interfaces
76
+
77
+ CLI, Skill
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ // wip-repo-init: scaffold the standard ai/ directory structure in any repo.
3
+ //
4
+ // New repo (no ai/ folder):
5
+ // Copies the template as-is.
6
+ //
7
+ // Existing repo (ai/ folder exists):
8
+ // 1. Creates the new ai/ structure
9
+ // 2. Moves old ai/ contents into ai/_sort/ai_old/
10
+ // 3. You sort from there at your own pace.
11
+
12
+ import { existsSync, mkdirSync, cpSync, renameSync, readdirSync, statSync } from 'node:fs';
13
+ import { join, resolve, dirname } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { createInterface } from 'node:readline';
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const TEMPLATE = join(__dirname, 'ai');
19
+
20
+ const targetRepo = resolve(process.argv[2] || process.cwd());
21
+ const aiDir = join(targetRepo, 'ai');
22
+ const dryRun = process.argv.includes('--dry-run');
23
+
24
+ const forceYes = process.argv.includes('--yes') || process.argv.includes('-y');
25
+
26
+ function log(msg) { console.log(` ${msg}`); }
27
+ function ok(msg) { console.log(` ✓ ${msg}`); }
28
+ function skip(msg) { console.log(` - ${msg}`); }
29
+
30
+ async function confirm(question) {
31
+ if (forceYes) return true;
32
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
33
+ return new Promise(resolve => {
34
+ rl.question(` ${question} (y/N) `, answer => {
35
+ rl.close();
36
+ resolve(answer.trim().toLowerCase() === 'y');
37
+ });
38
+ });
39
+ }
40
+
41
+ // Recursively copy template, skipping files that already exist
42
+ function scaffoldDir(src, dest) {
43
+ if (!existsSync(dest)) {
44
+ if (!dryRun) mkdirSync(dest, { recursive: true });
45
+ ok(`Created ${dest.replace(targetRepo + '/', '')}`);
46
+ }
47
+
48
+ for (const entry of readdirSync(src)) {
49
+ if (entry === '.DS_Store') continue;
50
+ const srcPath = join(src, entry);
51
+ const destPath = join(dest, entry);
52
+ const stat = statSync(srcPath);
53
+
54
+ if (stat.isDirectory()) {
55
+ scaffoldDir(srcPath, destPath);
56
+ } else {
57
+ if (existsSync(destPath)) {
58
+ skip(`${destPath.replace(targetRepo + '/', '')} already exists`);
59
+ } else {
60
+ if (!dryRun) cpSync(srcPath, destPath);
61
+ ok(`${destPath.replace(targetRepo + '/', '')}`);
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ console.log('');
68
+ console.log(` wip-repo-init${dryRun ? ' (dry run)' : ''}`);
69
+ console.log(` Target: ${targetRepo}`);
70
+ console.log(` ${'─'.repeat(40)}`);
71
+
72
+ if (!existsSync(targetRepo)) {
73
+ console.log(` ✗ Target directory does not exist: ${targetRepo}`);
74
+ process.exit(1);
75
+ }
76
+
77
+ if (existsSync(aiDir)) {
78
+ // Existing ai/ folder: explain what will happen, then confirm
79
+ log('Found existing ai/ folder.');
80
+ console.log('');
81
+ log('Here\'s what will happen:');
82
+ log(' 1. Your current ai/ contents will be moved to ai/_sort/ai_old/');
83
+ log(' 2. The standard ai/ structure will be scaffolded');
84
+ log(' 3. You can sort files from ai_old/ into the new structure at your own pace');
85
+ console.log('');
86
+ log('Nothing is deleted. Your old files will all be in ai/_sort/ai_old/.');
87
+ console.log('');
88
+
89
+ const sortDir = join(aiDir, '_sort');
90
+ const aiOldDir = join(sortDir, 'ai_old');
91
+
92
+ if (existsSync(aiOldDir)) {
93
+ console.log(` ✗ ai/_sort/ai_old/ already exists. A previous init was run but not sorted yet.`);
94
+ console.log(` Sort the files in ai/_sort/ai_old/ first, then run again.`);
95
+ process.exit(1);
96
+ }
97
+
98
+ if (dryRun) {
99
+ log('[dry run] Would move old ai/ contents to ai/_sort/ai_old/');
100
+ log('[dry run] Would scaffold new ai/ structure:');
101
+ console.log('');
102
+ scaffoldDir(TEMPLATE, aiDir);
103
+ console.log(`\n ${'─'.repeat(40)}`);
104
+ console.log(' Dry run complete. No changes made.\n');
105
+ process.exit(0);
106
+ }
107
+
108
+ const proceed = await confirm('Proceed?');
109
+ if (!proceed) {
110
+ console.log(' Cancelled.\n');
111
+ process.exit(0);
112
+ }
113
+
114
+ console.log('');
115
+ const tmpOld = join(targetRepo, '_ai_old_tmp');
116
+ renameSync(aiDir, tmpOld);
117
+ ok('Moved old ai/ to temporary location');
118
+
119
+ scaffoldDir(TEMPLATE, aiDir);
120
+
121
+ mkdirSync(join(aiDir, '_sort'), { recursive: true });
122
+ renameSync(tmpOld, aiOldDir);
123
+ ok('Moved old ai/ contents to ai/_sort/ai_old/');
124
+ } else {
125
+ // No ai/ folder: scaffold from scratch
126
+ log('No existing ai/ folder. Scaffolding from template.');
127
+ console.log('');
128
+ scaffoldDir(TEMPLATE, aiDir);
129
+ }
130
+
131
+ console.log(` ${'─'.repeat(40)}`);
132
+ if (dryRun) {
133
+ console.log(' Dry run complete. No changes made.');
134
+ } else {
135
+ ok('Done.');
136
+ if (existsSync(join(aiDir, '_sort', 'ai_old'))) {
137
+ console.log('');
138
+ log('Your old ai/ contents are in ai/_sort/ai_old/');
139
+ log('Sort them into the new structure at your own pace.');
140
+ }
141
+ }
142
+ console.log('');
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@wipcomputer/wip-repo-init",
3
+ "version": "1.9.20",
4
+ "description": "Scaffold the standard ai/ directory structure in any repo",
5
+ "type": "module",
6
+ "bin": {
7
+ "wip-repo-init": "init.mjs"
8
+ },
9
+ "license": "MIT",
10
+ "author": "WIP Computer"
11
+ }
@@ -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.
@@ -0,0 +1,86 @@
1
+ ###### WIP Computer
2
+
3
+ [![npm](https://img.shields.io/npm/v/@wipcomputer/wip-repo-permissions-hook)](https://www.npmjs.com/package/@wipcomputer/wip-repo-permissions-hook) [![CLI / TUI](https://img.shields.io/badge/interface-CLI_/_TUI-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/cli.js) [![MCP Server](https://img.shields.io/badge/interface-MCP_Server-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/mcp-server.mjs) [![OpenClaw Plugin](https://img.shields.io/badge/interface-OpenClaw_Plugin-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/openclaw.plugin.json) [![Claude Code Hook](https://img.shields.io/badge/interface-Claude_Code_Hook-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/guard.mjs) [![Claude Code Skill](https://img.shields.io/badge/interface-Claude_Code_Skill-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/SKILL.md) [![Universal Interface Spec](https://img.shields.io/badge/Universal_Interface_Spec-black?style=flat&color=black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-universal-installer/SPEC.md)
4
+
5
+ # wip-repo-permissions-hook
6
+
7
+ ## Repo visibility guard. Blocks repos from going public without a -private counterpart.
8
+
9
+ Every repo follows the public/private pattern. The private repo is the working repo with `ai/` folders (plans, todos, dev updates). The public repo is the same code without `ai/`. Making a repo public without the -private counterpart exposes internal development context.
10
+
11
+ This tool blocks that.
12
+
13
+ ## How It Works
14
+
15
+ Before any repo visibility change to public, the guard checks:
16
+
17
+ 1. Is this a fork of an external project? If yes, allow (exempt).
18
+ 2. Does `{repo-name}-private` exist on GitHub? If yes, allow.
19
+ 3. Otherwise, block with an error.
20
+
21
+ ## Surfaces
22
+
23
+ - **CLI** ... `wip-repo-permissions check|audit|can-publish`
24
+ - **Claude Code hook** ... PreToolUse:Bash, blocks `gh repo edit --visibility public`
25
+ - **OpenClaw plugin** ... before_tool_use lifecycle hook
26
+ - **Cron audit** ... periodic scan of all public repos via ldm-jobs
27
+
28
+ ## CLI Usage
29
+
30
+ ```bash
31
+ # Check a single repo
32
+ node cli.js check wipcomputer/memory-crystal
33
+ # -> OK: memory-crystal-private exists
34
+
35
+ # Check a repo without -private (blocked)
36
+ node cli.js check wipcomputer/wip-bridge
37
+ # -> BLOCKED: no -private counterpart
38
+
39
+ # Audit all public repos in org
40
+ node cli.js audit wipcomputer
41
+
42
+ # Alias for check
43
+ node cli.js can-publish wipcomputer/wip-ai-devops-toolbox
44
+ ```
45
+
46
+ ## Claude Code Setup
47
+
48
+ Add to `~/.claude/settings.json`:
49
+
50
+ ```json
51
+ {
52
+ "hooks": {
53
+ "PreToolUse": [
54
+ {
55
+ "matcher": "Bash",
56
+ "hooks": [{
57
+ "type": "command",
58
+ "command": "node /path/to/wip-repo-permissions-hook/guard.mjs",
59
+ "timeout": 10
60
+ }]
61
+ }
62
+ ]
63
+ }
64
+ }
65
+ ```
66
+
67
+ ## OpenClaw Setup
68
+
69
+ Symlink or copy to extensions:
70
+
71
+ ```bash
72
+ cp -r tools/wip-repo-permissions-hook ~/.ldm/extensions/wip-repo-permissions-hook
73
+ ln -sf ~/.ldm/extensions/wip-repo-permissions-hook ~/.openclaw/extensions/wip-repo-permissions-hook
74
+ openclaw gateway restart
75
+ ```
76
+
77
+ ## License
78
+
79
+ ```
80
+ CLI, MCP server, OpenClaw plugin, hooks MIT (use anywhere, no restrictions)
81
+ Hosted or cloud service use AGPL (network service distribution)
82
+ ```
83
+
84
+ AGPL for personal use is free.
85
+
86
+ Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: wip-repo-permissions-hook
3
+ description: Repo visibility guard. Blocks repos from going public without a -private counterpart.
4
+ license: MIT
5
+ interface: [cli, module, mcp, hook, plugin]
6
+ metadata:
7
+ display-name: "Repo Visibility Guard"
8
+ version: "1.0.0"
9
+ homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox"
10
+ author: "Parker Todd Brooks"
11
+ category: dev-tools
12
+ capabilities:
13
+ - visibility-check
14
+ - org-audit
15
+ - public-gate
16
+ requires:
17
+ bins: [node, gh]
18
+ openclaw:
19
+ requires:
20
+ bins: [node, gh]
21
+ install:
22
+ - id: node
23
+ kind: node
24
+ package: "@wipcomputer/wip-repo-permissions-hook"
25
+ bins: [wip-repo-permissions]
26
+ label: "Install via npm"
27
+ emoji: "🔒"
28
+ compatibility: Requires node, gh (GitHub CLI). Node.js 18+.
29
+ ---
30
+
31
+ # Repo Permissions Hook
32
+
33
+ ## What This Does
34
+
35
+ Prevents repos from being made public unless a `-private` counterpart exists on GitHub. Protects internal plans, todos, and development context from accidental exposure.
36
+
37
+ ## The Rule
38
+
39
+ Every repo that goes public must have a `{name}-private` repo. The private repo holds `ai/` folders with plans, todos, dev updates, and notes. The public repo has the same code without `ai/`.
40
+
41
+ Forks of external projects are exempt.
42
+
43
+ ## How to Use
44
+
45
+ ### Check before changing visibility
46
+ ```bash
47
+ node cli.js check <org>/<repo>
48
+ ```
49
+
50
+ ### Audit all public repos
51
+ ```bash
52
+ node cli.js audit <org>
53
+ ```
54
+
55
+ ### Install as Claude Code hook
56
+ Add to `~/.claude/settings.json` under `hooks.PreToolUse` with matcher `"Bash"`.
57
+
58
+ ### Install as OpenClaw plugin
59
+ Copy to `~/.ldm/extensions/wip-repo-permissions-hook/` and restart gateway.
60
+
61
+ ### MCP
62
+
63
+ Tools: `repo_permissions_check`, `repo_permissions_audit`
64
+
65
+ Add to `.mcp.json`:
66
+ ```json
67
+ {
68
+ "wip-repo-permissions": {
69
+ "command": "node",
70
+ "args": ["/path/to/tools/wip-repo-permissions-hook/mcp-server.mjs"]
71
+ }
72
+ }
73
+ ```