@wipcomputer/wip-repo-init 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/SKILL.md +77 -0
  2. package/init.mjs +142 -0
  3. package/package.json +11 -0
package/SKILL.md ADDED
@@ -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
package/init.mjs ADDED
@@ -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('');
package/package.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@wipcomputer/wip-repo-init",
3
+ "version": "1.0.0",
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
+ }