@justinforfun/redo-skill 0.1.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.
package/bin/install.js ADDED
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ import chalk from 'chalk';
10
+ import inquirer from 'inquirer';
11
+ import ora from 'ora';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ const packageRoot = path.resolve(__dirname, '..');
16
+ const sourceSkillDir = path.join(packageRoot, 'skills', 'redo');
17
+ const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\..+/, '').replace('T', '-');
18
+
19
+ const targets = [
20
+ {
21
+ id: 'codex',
22
+ name: 'Codex',
23
+ description: 'Install redo as a Codex skill.',
24
+ tasks: [
25
+ {
26
+ type: 'skill',
27
+ label: 'Codex skill',
28
+ destination: path.join(os.homedir(), '.agents', 'skills', 'redo')
29
+ }
30
+ ],
31
+ trigger: '$redo kafka, redo kafka, or select redo from the skill picker'
32
+ },
33
+ {
34
+ id: 'codex-cli',
35
+ name: 'Codex CLI',
36
+ description: 'Install redo as a Codex CLI skill.',
37
+ tasks: [
38
+ {
39
+ type: 'skill',
40
+ label: 'Codex CLI skill',
41
+ destination: path.join(process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), 'skills', 'redo')
42
+ }
43
+ ],
44
+ trigger: '$redo kafka, redo kafka, or /skills then choose redo'
45
+ },
46
+ {
47
+ id: 'claude-code',
48
+ name: 'Claude Code',
49
+ description: 'Install redo as a Claude Code skill and /redo command.',
50
+ tasks: [
51
+ {
52
+ type: 'skill',
53
+ label: 'Claude Code skill',
54
+ destination: path.join(os.homedir(), '.claude', 'skills', 'redo')
55
+ },
56
+ {
57
+ type: 'claude-command',
58
+ label: 'Claude Code /redo command',
59
+ destination: path.join(os.homedir(), '.claude', 'commands', 'redo.md')
60
+ }
61
+ ],
62
+ trigger: '/redo kafka'
63
+ }
64
+ ];
65
+
66
+ async function main() {
67
+ printHeader();
68
+ await ensureSourceSkillExists();
69
+
70
+ const selectedTargets = await promptTargets();
71
+ if (selectedTargets.length === 0) {
72
+ console.log(chalk.yellow('No tools selected. Nothing installed.'));
73
+ return;
74
+ }
75
+
76
+ const plan = selectedTargets.flatMap((target) =>
77
+ target.tasks.map((task) => ({
78
+ ...task,
79
+ targetName: target.name,
80
+ trigger: target.trigger
81
+ }))
82
+ );
83
+
84
+ const conflictActions = await promptConflictActions(plan);
85
+ const spinner = ora('Installing redo skill...').start();
86
+ const results = [];
87
+
88
+ try {
89
+ for (const task of plan) {
90
+ const action = conflictActions.get(task.destination) || 'install';
91
+ const result = await installTask(task, action);
92
+ results.push(result);
93
+ }
94
+ spinner.succeed('redo skill installed.');
95
+ } catch (error) {
96
+ spinner.fail('Installation failed.');
97
+ throw error;
98
+ }
99
+
100
+ printSummary(results, selectedTargets);
101
+ }
102
+
103
+ function printHeader() {
104
+ console.log('');
105
+ console.log(chalk.bold('redo skill installer'));
106
+ console.log(chalk.dim('Reverse-learn technologies through engineering constraints, trade-offs, and technical debt.'));
107
+ console.log('');
108
+ }
109
+
110
+ async function ensureSourceSkillExists() {
111
+ try {
112
+ await fs.access(path.join(sourceSkillDir, 'SKILL.md'));
113
+ } catch {
114
+ throw new Error(`Cannot find source skill at ${sourceSkillDir}`);
115
+ }
116
+ }
117
+
118
+ async function promptTargets() {
119
+ const answers = await inquirer.prompt([
120
+ {
121
+ type: 'checkbox',
122
+ name: 'targetIds',
123
+ message: 'Select AI tools to install redo for:',
124
+ choices: targets.map((target) => ({
125
+ name: `${target.name} ${chalk.dim('- ' + target.description)}`,
126
+ value: target.id,
127
+ checked: true
128
+ })),
129
+ validate: (values) => (values.length > 0 ? true : 'Select at least one tool.')
130
+ }
131
+ ]);
132
+
133
+ return targets.filter((target) => answers.targetIds.includes(target.id));
134
+ }
135
+
136
+ async function promptConflictActions(plan) {
137
+ const actions = new Map();
138
+
139
+ for (const task of plan) {
140
+ if (!(await exists(task.destination))) {
141
+ actions.set(task.destination, 'install');
142
+ continue;
143
+ }
144
+
145
+ const answers = await inquirer.prompt([
146
+ {
147
+ type: 'list',
148
+ name: 'action',
149
+ message: `${task.label} already exists at ${task.destination}`,
150
+ default: 'backup',
151
+ choices: [
152
+ {
153
+ name: 'Backup then overwrite',
154
+ value: 'backup'
155
+ },
156
+ {
157
+ name: 'Overwrite',
158
+ value: 'overwrite'
159
+ },
160
+ {
161
+ name: 'Skip',
162
+ value: 'skip'
163
+ }
164
+ ]
165
+ }
166
+ ]);
167
+
168
+ actions.set(task.destination, answers.action);
169
+ }
170
+
171
+ return actions;
172
+ }
173
+
174
+ async function installTask(task, action) {
175
+ if (action === 'skip') {
176
+ return {
177
+ status: 'skipped',
178
+ task
179
+ };
180
+ }
181
+
182
+ if (await exists(task.destination)) {
183
+ if (action === 'backup') {
184
+ const backupPath = await uniqueBackupPath(task.destination);
185
+ await fs.rename(task.destination, backupPath);
186
+ } else if (action === 'overwrite') {
187
+ await fs.rm(task.destination, { recursive: true, force: true });
188
+ }
189
+ }
190
+
191
+ await fs.mkdir(path.dirname(task.destination), { recursive: true });
192
+
193
+ if (task.type === 'skill') {
194
+ await fs.cp(sourceSkillDir, task.destination, { recursive: true });
195
+ } else if (task.type === 'claude-command') {
196
+ await fs.writeFile(task.destination, claudeCommandTemplate(), 'utf8');
197
+ } else {
198
+ throw new Error(`Unknown task type: ${task.type}`);
199
+ }
200
+
201
+ return {
202
+ status: 'installed',
203
+ task
204
+ };
205
+ }
206
+
207
+ async function exists(filePath) {
208
+ try {
209
+ await fs.access(filePath);
210
+ return true;
211
+ } catch {
212
+ return false;
213
+ }
214
+ }
215
+
216
+ async function uniqueBackupPath(filePath) {
217
+ let candidate = `${filePath}.backup-${timestamp}`;
218
+ let index = 1;
219
+
220
+ while (await exists(candidate)) {
221
+ candidate = `${filePath}.backup-${timestamp}-${index}`;
222
+ index += 1;
223
+ }
224
+
225
+ return candidate;
226
+ }
227
+
228
+ function claudeCommandTemplate() {
229
+ return `---
230
+ description: Reverse-learn a technology by reconstructing its engineering constraints, trade-offs, debt, fixes, and unresolved pain points.
231
+ argument-hint: <technology/tool> [--lang zh|en]
232
+ ---
233
+
234
+ Use the redo skill to analyze:
235
+
236
+ $ARGUMENTS
237
+
238
+ If the user did not provide a topic, ask for one. Otherwise, follow the redo skill output contract. Use the user's current language unless --lang zh or --lang en is provided.
239
+ `;
240
+ }
241
+
242
+ function printSummary(results, selectedTargets) {
243
+ console.log('');
244
+ console.log(chalk.bold('Installed targets'));
245
+
246
+ for (const result of results) {
247
+ const icon = result.status === 'installed' ? chalk.green('✓') : chalk.yellow('-');
248
+ console.log(`${icon} ${result.task.label}: ${result.task.destination}`);
249
+ }
250
+
251
+ console.log('');
252
+ console.log(chalk.bold('How to trigger'));
253
+
254
+ for (const target of selectedTargets) {
255
+ console.log(`${chalk.cyan(target.name)}: ${target.trigger}`);
256
+ }
257
+
258
+ console.log('');
259
+ }
260
+
261
+ main().catch((error) => {
262
+ console.error(chalk.red(error.message));
263
+ process.exitCode = 1;
264
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@justinforfun/redo-skill",
3
+ "version": "0.1.0",
4
+ "description": "Install the redo skill for Codex, Codex CLI, and Claude Code.",
5
+ "type": "module",
6
+ "bin": {
7
+ "redo-skill": "bin/install.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "skills/redo/"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "scripts": {
17
+ "build": "node ../../scripts/sync-skill-package.js redo packages/redo-skill",
18
+ "check": "node --check bin/install.js",
19
+ "prepack": "npm run build",
20
+ "start": "node bin/install.js"
21
+ },
22
+ "dependencies": {
23
+ "chalk": "^5.3.0",
24
+ "inquirer": "^9.2.23",
25
+ "ora": "^8.0.1"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "license": "MIT"
31
+ }
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: redo
3
+ description: Reverse-learn any programming technology, framework, tool, or infrastructure system by reconstructing its evolution as a sequence of real engineering constraints, candidate designs, trade-offs, technical debt, later fixes, and unresolved pain points. Use this skill when the user asks with /redo, redo, $redo, reverse learn, retrace, re-derive, or asks to understand why a technology evolved the way it did.
4
+ ---
5
+
6
+ > Every mature system is a fossil record of the constraints it survived.
7
+
8
+ # Redo
9
+
10
+ Redo is a reverse-learning skill for understanding a technology as if you were one of the engineers who evolved it from zero to today. Do not write a feature tour, timeline summary, or encyclopedia article. Reconstruct the path of necessity: what problem existed at each stage, what options were available, why the chosen design won, what trade-off it accepted, and what debt it left behind.
11
+
12
+ ## Trigger Patterns
13
+
14
+ Use this skill when the user asks to reverse-learn, redo, re-derive, reconstruct, or deeply understand a programming technology, framework, language, database, infrastructure system, protocol, build tool, runtime, AI tool, or developer platform.
15
+
16
+ Explicit examples:
17
+
18
+ - `/redo kafka`
19
+ - `$redo kafka`
20
+ - `redo kafka`
21
+ - `redo kafka --lang en`
22
+ - `Reverse-learn Kafka`
23
+ - `Retrace React's evolution path`
24
+ - `Explain Docker by retracing its engineering decisions`
25
+
26
+ ## Arguments
27
+
28
+ Parse the request as:
29
+
30
+ ```text
31
+ redo <topic> [--lang zh|en]
32
+ ```
33
+
34
+ - `<topic>` is the technology, tool, or system to analyze.
35
+ - `--lang zh` forces Chinese output.
36
+ - `--lang en` forces English output.
37
+ - If `--lang` is absent, respond in the user's current conversation language.
38
+
39
+ ## Evidence Requirements
40
+
41
+ For real technologies, do not rely only on memory when dates, versions, authorship, current status, or historical claims matter.
42
+
43
+ - If web access is available and the user has not forbidden it, verify with primary or high-authority sources first: official documentation, release notes, RFCs, design docs, papers, project repositories, or authoritative engineering blogs.
44
+ - If web access is unavailable, blocked, or the user forbids browsing, state clearly that the analysis is not freshly verified from online sources.
45
+ - Distinguish sourced facts from inference. It is acceptable to infer engineering motivations, but label them as inference when the source does not explicitly say so.
46
+ - Prefer fewer, stronger stages over many shallow ones. A good answer usually has 5-9 stages.
47
+
48
+ ## Output Contract
49
+
50
+ Start with a compact orientation:
51
+
52
+ - What the system is.
53
+ - The central pressure that shaped its evolution.
54
+ - The main trade-off theme that appears repeatedly.
55
+
56
+ Then produce the sections below.
57
+
58
+ ### 1. Evolution Stages
59
+
60
+ For each stage, use this structure:
61
+
62
+ ```markdown
63
+ ## Stage N: <stage name> (<approximate years or versions>)
64
+
65
+ **Constraint:** <the real engineering situation at the time>
66
+
67
+ | Option | Cost | Why it did or did not win |
68
+ |---|---|---|
69
+ | A. <candidate> | <cost> | <reason> |
70
+ | B. <candidate> | <cost> | <reason> |
71
+ | C. <chosen candidate> | <cost> | Chosen because <reason> |
72
+
73
+ **Key trade-off:** <the most important exchange>
74
+
75
+ **Debt introduced:** <what this choice made harder later>
76
+ ```
77
+
78
+ Stage quality rules:
79
+
80
+ - Every stage must be driven by a concrete constraint, not by a release note.
81
+ - Every table must contain at least two rejected options and one chosen path.
82
+ - Explain why a reasonable engineer would choose the winning path at that time, even if it later caused problems.
83
+ - Avoid hindsight moralizing. The point is to recreate the decision pressure, not to mock past designs.
84
+
85
+ ### 2. Throughline
86
+
87
+ Summarize the recurring design philosophy in one or two paragraphs. Make it specific to the topic, for example:
88
+
89
+ - "Push complexity into the runtime to keep application code simple."
90
+ - "Preserve backward compatibility even when it complicates internals."
91
+ - "Use logs as the universal abstraction."
92
+
93
+ ### 3. Debt Map
94
+
95
+ Create two tables.
96
+
97
+ Resolved debt:
98
+
99
+ ```markdown
100
+ | Debt | Introduced in | Resolved in | Resolution |
101
+ |---|---|---|---|
102
+ ```
103
+
104
+ Unresolved debt:
105
+
106
+ ```markdown
107
+ | Pain point | Why it remains hard | Current manifestation |
108
+ |---|---|---|
109
+ ```
110
+
111
+ ### 4. Pain Point Ranking
112
+
113
+ Rank the top unresolved problems that users still feel today.
114
+
115
+ ```markdown
116
+ | Rank | Pain point | One-line explanation | Competitive attack angle |
117
+ |---|---|---|---|
118
+ ```
119
+
120
+ Use the competitive attack angle only when there is a meaningful comparison. Otherwise write "N/A".
121
+
122
+ ### 5. Causal Chain
123
+
124
+ End with a causal chain that makes the evolution memorable:
125
+
126
+ ```text
127
+ early constraint -> chosen design -> solved problem -> new debt -> later fix -> remaining pain
128
+ ```
129
+
130
+ Keep it concise and legible.
131
+
132
+ ## Style
133
+
134
+ - Write like a senior engineer explaining architecture history to another engineer.
135
+ - Prefer concrete mechanisms, failure modes, and operational consequences.
136
+ - Use direct language. Avoid vague praise such as "powerful", "robust", or "revolutionary" unless immediately explained.
137
+ - Use Chinese if the user is writing Chinese, English if the user is writing English, unless `--lang` overrides.
138
+ - If the topic is too broad, choose the core system path and say what you intentionally left out.
139
+ - If the historical record is uncertain, say so and give the most likely interpretation.
140
+
141
+ ## Tool-Specific Invocation Notes
142
+
143
+ - Claude Code may expose this as `/redo <topic>` when installed with a command wrapper.
144
+ - Codex and Codex CLI should be invoked through skill selection or explicit skill mention, such as `$redo kafka`, `redo kafka`, or natural language requests that match this skill.
145
+ - Do not promise that every AI tool supports a native `/redo` slash command.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Redo"
3
+ short_description: "Reverse-learn systems through trade-offs"
4
+ default_prompt: "Use $redo to reverse-learn Kafka through its engineering constraints, trade-offs, debt, and unresolved pain points."