wtf-p 0.2.0 → 0.3.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/README.md +6 -2
- package/bin/commands/doctor.js +100 -0
- package/bin/commands/install-logic.js +235 -0
- package/bin/commands/list.js +88 -0
- package/bin/commands/status.js +85 -0
- package/bin/commands/update.js +50 -0
- package/bin/install.js +78 -629
- package/bin/lib/manifest.js +41 -0
- package/bin/lib/utils.js +37 -17
- package/bin/lib/wcn-compiler.js +226 -0
- package/bin/uninstall.js +51 -17
- package/core/write-the-f-paper/templates/posters/basic.md +34 -0
- package/core/write-the-f-paper/templates/slides/basic.md +31 -0
- package/package.json +12 -4
- package/vendors/claude/.claude-plugin/plugin.json +12 -0
- package/vendors/claude/commands/wtfp/create-poster.md +42 -0
- package/vendors/claude/commands/wtfp/create-slides.md +41 -0
- package/{commands → vendors/claude/commands}/wtfp/help.md +3 -0
- package/vendors/claude/skills/wtfp/echarts/SKILL.md +47 -0
- package/vendors/claude/skills/wtfp/marp/SKILL.md +49 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/checkpoints.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/continuation-format.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/git-integration.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/github-contrib.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/imrad-structure.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/length-estimation.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/plan-format.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/principles.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/questioning.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/references/research-pitfalls.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/config.json +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/context.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/continue-here.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/data-inventory.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/discovery.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/issues.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/manuscript.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/narrative-arc.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/outline.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/phase-prompt.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/prior-drafts.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/argument-structure.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/bibliography.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/gaps.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/imrad.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/peer-review.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/style-guide.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/tools.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/project.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/research.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/review-comments.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/revision-issues.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/roadmap.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/section-archive.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/section-context.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/section.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/state.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/templates/summary.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/venues/acm-cs.yaml +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/venues/arxiv-ml.yaml +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/venues/ieee-cs.yaml +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/venues/nature.yaml +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/venues/thesis-chapter.yaml +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/create-outline.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/create-outline.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/discuss-section.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/discuss-section.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/execute-section.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/execute-section.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/list-assumptions.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/list-assumptions.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/lit-review-phase.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/lit-review-phase.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/map-project.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/map-project.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/plan-section.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/plan-section.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/research-gap.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/research-gap.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/resume-paper.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/resume-paper.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/review-section.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/review-section.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/submit-draft.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/submit-draft.wcn.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/transition.md +0 -0
- /package/{write-the-f-paper → core/write-the-f-paper}/workflows/transition.wcn.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/analyze-bib.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/check-refs.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/contribute.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/create-outline.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/discuss-section.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/export-latex.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/insert-section.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/list-assumptions.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/map-project.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/new-paper.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/pause-writing.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/plan-revision.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/plan-section.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/polish-prose.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/progress.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/remove-section.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/report-bug.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/request-feature.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/research-gap.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/resume-writing.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/review-section.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/submit-milestone.md +0 -0
- /package/{commands → vendors/claude/commands}/wtfp/write-section.md +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const ROOT = path.resolve(__dirname, '../..');
|
|
4
|
+
|
|
5
|
+
const MANIFEST = {
|
|
6
|
+
claude: {
|
|
7
|
+
name: 'Claude Code',
|
|
8
|
+
configDirEnv: 'CLAUDE_CONFIG_DIR',
|
|
9
|
+
defaultDir: '.claude',
|
|
10
|
+
components: [
|
|
11
|
+
{
|
|
12
|
+
id: 'workflows',
|
|
13
|
+
src: path.join(ROOT, 'core', 'write-the-f-paper'),
|
|
14
|
+
dest: 'write-the-f-paper',
|
|
15
|
+
type: 'dir'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'commands',
|
|
19
|
+
src: path.join(ROOT, 'vendors', 'claude', 'commands', 'wtfp'),
|
|
20
|
+
dest: 'commands/wtfp',
|
|
21
|
+
type: 'dir'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'skills',
|
|
25
|
+
src: path.join(ROOT, 'vendors', 'claude', 'skills', 'wtfp'),
|
|
26
|
+
dest: 'skills/wtfp',
|
|
27
|
+
type: 'dir'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'plugin',
|
|
31
|
+
src: path.join(ROOT, 'vendors', 'claude', '.claude-plugin'),
|
|
32
|
+
dest: '.claude-plugin',
|
|
33
|
+
type: 'dir'
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
// Future:
|
|
38
|
+
// gemini: { ... }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = MANIFEST;
|
package/bin/lib/utils.js
CHANGED
|
@@ -62,17 +62,25 @@ function isValidPath(inputPath) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Get the
|
|
65
|
+
* Get the configuration directory for a specific vendor
|
|
66
66
|
*/
|
|
67
|
-
function
|
|
67
|
+
function getVendorDir(vendor, explicitConfigDir, isGlobal = true) {
|
|
68
68
|
if (!isGlobal) {
|
|
69
|
-
return path.join(process.cwd(),
|
|
69
|
+
return path.join(process.cwd(), `.${vendor}`);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
const envVar = `${vendor.toUpperCase()}_CONFIG_DIR`;
|
|
72
73
|
const configDir = normalizePath(explicitConfigDir) ||
|
|
73
|
-
normalizePath(process.env
|
|
74
|
+
normalizePath(process.env[envVar]);
|
|
74
75
|
|
|
75
|
-
return configDir || path.join(os.homedir(),
|
|
76
|
+
return configDir || path.join(os.homedir(), `.${vendor}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get the Claude config directory (respects CLAUDE_CONFIG_DIR env var)
|
|
81
|
+
*/
|
|
82
|
+
function getClaudeDir(explicitConfigDir, isGlobal = true) {
|
|
83
|
+
return getVendorDir('claude', explicitConfigDir, isGlobal);
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
/**
|
|
@@ -109,6 +117,9 @@ function readInstalledVersion(claudeDir) {
|
|
|
109
117
|
* Write version tracking file
|
|
110
118
|
*/
|
|
111
119
|
function writeVersionFile(claudeDir, version, installedFiles) {
|
|
120
|
+
if (!fs.existsSync(claudeDir)) {
|
|
121
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
122
|
+
}
|
|
112
123
|
const versionFile = path.join(claudeDir, VERSION_FILE);
|
|
113
124
|
const data = {
|
|
114
125
|
version,
|
|
@@ -144,47 +155,56 @@ function simpleChecksum(filePath) {
|
|
|
144
155
|
/**
|
|
145
156
|
* Detect installation state
|
|
146
157
|
*/
|
|
147
|
-
function detectInstallation(
|
|
158
|
+
function detectInstallation(vendorDir) {
|
|
148
159
|
const result = {
|
|
149
160
|
hasCommands: false,
|
|
150
|
-
|
|
161
|
+
hasWorkflows: false,
|
|
162
|
+
hasSkills: false,
|
|
151
163
|
version: null,
|
|
152
164
|
partial: false,
|
|
153
165
|
corrupt: false,
|
|
154
166
|
commandFiles: [],
|
|
167
|
+
workflowFiles: [],
|
|
155
168
|
skillFiles: []
|
|
156
169
|
};
|
|
157
170
|
|
|
158
|
-
const commandsDir = path.join(
|
|
159
|
-
const
|
|
171
|
+
const commandsDir = path.join(vendorDir, 'commands', 'wtfp');
|
|
172
|
+
const workflowsDir = path.join(vendorDir, 'write-the-f-paper');
|
|
173
|
+
const skillsDir = path.join(vendorDir, 'skills', 'wtfp');
|
|
160
174
|
|
|
161
175
|
result.hasCommands = fs.existsSync(commandsDir);
|
|
162
|
-
result.
|
|
176
|
+
result.hasWorkflows = fs.existsSync(workflowsDir);
|
|
177
|
+
result.hasSkills = fs.existsSync(skillsDir);
|
|
163
178
|
|
|
164
179
|
if (result.hasCommands) {
|
|
165
180
|
result.commandFiles = collectFiles(commandsDir);
|
|
166
181
|
}
|
|
167
|
-
if (result.
|
|
168
|
-
result.
|
|
182
|
+
if (result.hasWorkflows) {
|
|
183
|
+
result.workflowFiles = collectFiles(workflowsDir);
|
|
184
|
+
}
|
|
185
|
+
if (result.hasSkills) {
|
|
186
|
+
result.skillFiles = collectFiles(skillsDir);
|
|
169
187
|
}
|
|
170
188
|
|
|
171
189
|
// Read version info
|
|
172
|
-
const versionData = readInstalledVersion(
|
|
190
|
+
const versionData = readInstalledVersion(vendorDir);
|
|
173
191
|
if (versionData) {
|
|
174
192
|
result.version = versionData.version;
|
|
175
193
|
result.corrupt = versionData.corrupt || false;
|
|
176
194
|
|
|
177
|
-
// Check for partial install
|
|
195
|
+
// Check for partial install
|
|
178
196
|
if (!versionData.corrupt) {
|
|
179
197
|
const expectedHasCommands = versionData.manifest?.some(f => f.path.includes('commands/wtfp'));
|
|
180
|
-
const
|
|
198
|
+
const expectedHasWorkflows = versionData.manifest?.some(f => f.path.includes('write-the-f-paper'));
|
|
199
|
+
const expectedHasSkills = versionData.manifest?.some(f => f.path.includes('skills/wtfp'));
|
|
181
200
|
|
|
182
201
|
if ((expectedHasCommands && !result.hasCommands) ||
|
|
183
|
-
(
|
|
202
|
+
(expectedHasWorkflows && !result.hasWorkflows) ||
|
|
203
|
+
(expectedHasSkills && !result.hasSkills)) {
|
|
184
204
|
result.partial = true;
|
|
185
205
|
}
|
|
186
206
|
}
|
|
187
|
-
} else if (result.hasCommands || result.
|
|
207
|
+
} else if (result.hasCommands || result.hasWorkflows || result.hasSkills) {
|
|
188
208
|
// Files exist but no version file - legacy install
|
|
189
209
|
result.version = 'legacy';
|
|
190
210
|
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WCN Compiler (Workflow Compression Notation)
|
|
3
|
+
* A robust, state-machine based compiler for converting Verbose Markdown to Compressed WCN.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const FLUFF_PATTERNS = [
|
|
7
|
+
/This ensures[^.]*\./g,
|
|
8
|
+
/This is important[^.]*\./g,
|
|
9
|
+
/Note that[^.]*\./g,
|
|
10
|
+
/Keep in mind[^.]*\./g,
|
|
11
|
+
/Remember that[^.]*\./g,
|
|
12
|
+
/As mentioned[^.]*\./g,
|
|
13
|
+
/It is important to[^.]*\./g,
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
class WCNCompiler {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.lines = [];
|
|
19
|
+
this.output = [];
|
|
20
|
+
this.state = 'ROOT'; // ROOT, STEP, BASH
|
|
21
|
+
this.context = {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
compile(markdown) {
|
|
25
|
+
// 1. Pre-process: Remove fluff and normalize
|
|
26
|
+
let cleanMd = markdown;
|
|
27
|
+
FLUFF_PATTERNS.forEach(p => cleanMd = cleanMd.replace(p, ''));
|
|
28
|
+
|
|
29
|
+
this.lines = cleanMd.split('\n');
|
|
30
|
+
this.output = [];
|
|
31
|
+
this.state = 'ROOT';
|
|
32
|
+
|
|
33
|
+
// 2. Parse Line by Line
|
|
34
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
35
|
+
const line = this.lines[i].trim();
|
|
36
|
+
this.processLine(line, i);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 3. Post-process: Clean up excessive newlines
|
|
40
|
+
return this.output.join('\n').replace(/\n{3,}/g, '\n\n').trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
processLine(line, index) {
|
|
44
|
+
// Handle State Transitions
|
|
45
|
+
if (this.state === 'ROOT') {
|
|
46
|
+
if (line.startsWith('<step')) {
|
|
47
|
+
this.enterStep(line);
|
|
48
|
+
} else if (line.startsWith('<context>')) {
|
|
49
|
+
this.enterContext();
|
|
50
|
+
} else if (line.startsWith('**If') && line.endsWith(':**')) {
|
|
51
|
+
// Handle standalone conditionals (outside steps, rare but possible)
|
|
52
|
+
this.parseConditional(line, index);
|
|
53
|
+
} else if (line.startsWith('**Route')) {
|
|
54
|
+
this.parseRoute(line, index);
|
|
55
|
+
} else if (!line.startsWith('</')) {
|
|
56
|
+
// Pass through other content, but minimal
|
|
57
|
+
// We generally skip prose outside steps in WCN unless it's structural
|
|
58
|
+
if (line.startsWith('#') || line.startsWith('---')) {
|
|
59
|
+
this.output.push(line);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else if (this.state === 'STEP') {
|
|
63
|
+
if (line.startsWith('</step>')) {
|
|
64
|
+
this.exitStep();
|
|
65
|
+
} else if (line.startsWith('```bash')) {
|
|
66
|
+
this.state = 'BASH';
|
|
67
|
+
} else if (line.startsWith('**If') && line.endsWith(':**')) {
|
|
68
|
+
this.parseConditional(line, index);
|
|
69
|
+
} else if (line.toLowerCase().startsWith('parse and internalize:')) {
|
|
70
|
+
this.parseParseBlock(index);
|
|
71
|
+
} else if (line.trim().startsWith('- ') || line.trim().startsWith('* ')) {
|
|
72
|
+
// Capture bullet points as instructions
|
|
73
|
+
this.output.push(line.trim());
|
|
74
|
+
} else if (line.trim().startsWith('**') && !line.includes('If')) {
|
|
75
|
+
// Capture bold instructions
|
|
76
|
+
this.output.push(line.trim());
|
|
77
|
+
}
|
|
78
|
+
} else if (this.state === 'BASH') {
|
|
79
|
+
if (line.startsWith('```')) {
|
|
80
|
+
this.state = 'STEP';
|
|
81
|
+
} else {
|
|
82
|
+
// Capture bash command (first line usually sufficient for WCN)
|
|
83
|
+
if (line && !line.startsWith('#')) {
|
|
84
|
+
this.output.push(`RUN: ${line}`);
|
|
85
|
+
// Skip rest of bash block for WCN brevity?
|
|
86
|
+
// Current logic captures all commands. Let's capture all.
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
enterStep(line) {
|
|
93
|
+
this.state = 'STEP';
|
|
94
|
+
// Parse attributes: name="foo" priority="bar"
|
|
95
|
+
const nameMatch = line.match(/name="([^"]+)"/);
|
|
96
|
+
const priorityMatch = line.match(/priority="([^"]+)"/);
|
|
97
|
+
|
|
98
|
+
const name = nameMatch ? nameMatch[1] : 'unknown';
|
|
99
|
+
const pAttr = priorityMatch ? ` p=${priorityMatch[1] === 'first' ? '1' : priorityMatch[1]}` : '';
|
|
100
|
+
|
|
101
|
+
this.output.push(`[step:${name}${pAttr}]`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
exitStep() {
|
|
105
|
+
this.output.push('[/step]');
|
|
106
|
+
this.state = 'ROOT';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
enterContext() {
|
|
110
|
+
// Context is usually multiline, handled by looking ahead or buffering
|
|
111
|
+
// For simplicity, we'll scan ahead here since we have full lines access
|
|
112
|
+
// But sticking to line-by-line:
|
|
113
|
+
// Actually, Regex is better for Context blocks as they are simple <context>...</context>
|
|
114
|
+
// Let's defer this to a specialized Regex pass *before* line processing?
|
|
115
|
+
// Or just look ahead now.
|
|
116
|
+
// Let's skip for now and rely on a pre-pass replacement for Context, similar to current tool.
|
|
117
|
+
// Why? Because Context is global metadata, usually at top.
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
parseConditional(line, index) {
|
|
121
|
+
// **If mode="yolo":**
|
|
122
|
+
const condition = line.replace(/\*\*If\s+/, '').replace(/:\*\*/, '').trim().replace(/["']/g, '');
|
|
123
|
+
|
|
124
|
+
// Look ahead for the action
|
|
125
|
+
// Usually the next line or the line after
|
|
126
|
+
let action = '';
|
|
127
|
+
for (let i = 1; i < 5; i++) {
|
|
128
|
+
const next = this.lines[index + i];
|
|
129
|
+
if (next && next.trim()) {
|
|
130
|
+
action = next.trim();
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (action) {
|
|
136
|
+
// Simplify action text
|
|
137
|
+
if (action.length > 50) action = action.substring(0, 47) + '...';
|
|
138
|
+
this.output.push(`IF ${condition} → ${action}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
parseParseBlock(index) {
|
|
143
|
+
// Parse and internalize:
|
|
144
|
+
// - Item 1
|
|
145
|
+
// - Item 2
|
|
146
|
+
const fields = [];
|
|
147
|
+
for (let i = 1; i < 10; i++) {
|
|
148
|
+
const next = this.lines[index + i];
|
|
149
|
+
if (!next || (!next.trim().startsWith('-') && !next.trim().startsWith('*'))) break;
|
|
150
|
+
|
|
151
|
+
const field = next.replace(/^[-*]\s+/, '').trim().split(' ')[0].toLowerCase().replace(/\s+/g, '_');
|
|
152
|
+
fields.push(field);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (fields.length > 0) {
|
|
156
|
+
this.output.push(`PARSE: ${fields.join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
parseRoute(line, index) {
|
|
161
|
+
// **Route A: Title**
|
|
162
|
+
const match = line.match(/\*\*Route\s+([A-Z]):\s*([^*]+)\*\*/);
|
|
163
|
+
if (!match) return;
|
|
164
|
+
|
|
165
|
+
// We need to buffer the route table
|
|
166
|
+
// This is hard to do line-by-line without buffering.
|
|
167
|
+
// Let's assume we handle Routes via Regex pre-pass like the original,
|
|
168
|
+
// OR we detect the start of a route block and switch state.
|
|
169
|
+
// Given the complexity, let's stick to the Regex for Routes/Modes/Context
|
|
170
|
+
// and use State Machine for the detailed STEP logic which is where the fragility usually is.
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Hybrid Compiler:
|
|
176
|
+
* 1. Uses Regex for high-level blocks (Context, Routes, Modes)
|
|
177
|
+
* 2. Uses State Machine for Steps (the most complex part)
|
|
178
|
+
*/
|
|
179
|
+
function compile(markdown) {
|
|
180
|
+
let result = markdown;
|
|
181
|
+
|
|
182
|
+
// 1. Remove fluff
|
|
183
|
+
FLUFF_PATTERNS.forEach(p => result = result.replace(p, ''));
|
|
184
|
+
|
|
185
|
+
// 2. Compress Context (Regex is fine here)
|
|
186
|
+
result = result.replace(/<context>\s*([\s\S]*?)<\/context>/g, (match, content) => {
|
|
187
|
+
const files = content.match(/@[^\s\n]+/g) || [];
|
|
188
|
+
if (files.length === 0) return '';
|
|
189
|
+
const simplified = files.map(f => f.replace('@.planning/', ''));
|
|
190
|
+
return `@context{${simplified.join(',')}}`;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// 3. Compress Routes (Regex is fine here)
|
|
194
|
+
const routes = [];
|
|
195
|
+
result = result.replace(/\*\*Route\s+([A-Z]):\s*([^*]+)\*\*\s*([\s\S]*?)(?=\*\*Route|<step|$)/g, (match, id, title, content) => {
|
|
196
|
+
// Extract next step logic
|
|
197
|
+
const nextMatch = content.match(/\`\/wtfp:([^`]+)\`/);
|
|
198
|
+
const next = nextMatch ? `/wtfp:${nextMatch[1]}` : 'continue';
|
|
199
|
+
routes.push(` ${title.trim().toLowerCase().replace(/\s+/g, '_')} → "${title.trim()}" → ${next}`);
|
|
200
|
+
return '';
|
|
201
|
+
});
|
|
202
|
+
if (routes.length > 0) {
|
|
203
|
+
result = result + '\n\nROUTE{condition → output → next}:\n' + routes.join('\n');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 4. Compress Modes (Regex is fine here)
|
|
207
|
+
const modes = [];
|
|
208
|
+
result = result.replace(/\*\*If\s+mode="([^"]+)":\*\*\s*\n((?:[-*]\s+[^\n]+\n?)+)/g, (match, mode, items) => {
|
|
209
|
+
const itemList = items.split('\n').filter(l => l.trim()).map(l => l.replace(/^[-*]\s+/, '').trim());
|
|
210
|
+
modes.push(` ${mode} | ${itemList[0] || ''}`);
|
|
211
|
+
return '';
|
|
212
|
+
});
|
|
213
|
+
if (modes.length > 0) {
|
|
214
|
+
result = 'MODE{name,action}:\n' + modes.join('\n') + '\n\n' + result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 5. Compress Steps using State Machine (The Core Logic)
|
|
218
|
+
const compiler = new WCNCompiler();
|
|
219
|
+
// We only run the compiler on the text that remains (which should be mostly steps)
|
|
220
|
+
// But wait, the compiler expects full text to find steps.
|
|
221
|
+
// Let's pass the text to the compiler, but the compiler only outputs Step blocks and structural elements.
|
|
222
|
+
|
|
223
|
+
return compiler.compile(result);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = { compile, WCNCompiler };
|
package/bin/uninstall.js
CHANGED
|
@@ -102,7 +102,9 @@ if (hasHelp) {
|
|
|
102
102
|
|
|
103
103
|
${c.yellow('What gets removed:')}
|
|
104
104
|
${c.dim('commands/wtfp/')} - WTF-P slash commands
|
|
105
|
-
${c.dim('write-the-f-paper/')} - WTF-P
|
|
105
|
+
${c.dim('write-the-f-paper/')} - WTF-P workflows
|
|
106
|
+
${c.dim('skills/wtfp/')} - WTF-P skills
|
|
107
|
+
${c.dim('.claude-plugin/')} - Plugin manifest
|
|
106
108
|
${c.dim('.wtfp-version')} - Version tracking file
|
|
107
109
|
|
|
108
110
|
${c.yellow('What stays intact:')}
|
|
@@ -200,9 +202,9 @@ async function uninstall(isGlobal) {
|
|
|
200
202
|
|
|
201
203
|
// Detect installation
|
|
202
204
|
const installed = detectInstallation(claudeDir);
|
|
203
|
-
const totalFiles = installed.commandFiles.length + installed.skillFiles.length;
|
|
205
|
+
const totalFiles = installed.commandFiles.length + installed.workflowFiles.length + installed.skillFiles.length;
|
|
204
206
|
|
|
205
|
-
if (!installed.hasCommands && !installed.
|
|
207
|
+
if (!installed.hasCommands && !installed.hasWorkflows && !installed.hasSkills) {
|
|
206
208
|
out.log(` ${c.yellow('No WTF-P installation found in ' + locationLabel)}\n`);
|
|
207
209
|
|
|
208
210
|
// Check for backups if requested
|
|
@@ -252,13 +254,21 @@ async function uninstall(isGlobal) {
|
|
|
252
254
|
out.log(` ${c.yellow('Found WTF-P installation:')}\n`);
|
|
253
255
|
|
|
254
256
|
const commandsDir = path.join(claudeDir, 'commands', 'wtfp');
|
|
255
|
-
const
|
|
257
|
+
const workflowsDir = path.join(claudeDir, 'write-the-f-paper');
|
|
258
|
+
const skillsDir = path.join(claudeDir, 'skills', 'wtfp');
|
|
259
|
+
const pluginDir = path.join(claudeDir, '.claude-plugin');
|
|
256
260
|
|
|
257
261
|
if (installed.hasCommands) {
|
|
258
262
|
out.log(` ${c.cyan('commands/wtfp/')} (${installed.commandFiles.length} files)`);
|
|
259
263
|
}
|
|
260
|
-
if (installed.
|
|
261
|
-
out.log(` ${c.cyan('write-the-f-paper/')} (${installed.
|
|
264
|
+
if (installed.hasWorkflows) {
|
|
265
|
+
out.log(` ${c.cyan('write-the-f-paper/')} (${installed.workflowFiles.length} files)`);
|
|
266
|
+
}
|
|
267
|
+
if (installed.hasSkills) {
|
|
268
|
+
out.log(` ${c.cyan('skills/wtfp/')} (${installed.skillFiles.length} files)`);
|
|
269
|
+
}
|
|
270
|
+
if (fs.existsSync(pluginDir)) {
|
|
271
|
+
out.log(` ${c.cyan('.claude-plugin/')} (manifest)`);
|
|
262
272
|
}
|
|
263
273
|
if (installed.version) {
|
|
264
274
|
out.log(` ${c.cyan(VERSION_FILE)} (version tracking)`);
|
|
@@ -304,12 +314,16 @@ async function uninstall(isGlobal) {
|
|
|
304
314
|
fs.mkdirSync(backupDir, { recursive: true });
|
|
305
315
|
|
|
306
316
|
if (installed.hasCommands) {
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
copyDir(commandsDir, path.join(backupDir, 'commands', 'wtfp'));
|
|
318
|
+
}
|
|
319
|
+
if (installed.hasWorkflows) {
|
|
320
|
+
copyDir(workflowsDir, path.join(backupDir, 'write-the-f-paper'));
|
|
309
321
|
}
|
|
310
|
-
if (installed.
|
|
311
|
-
|
|
312
|
-
|
|
322
|
+
if (installed.hasSkills) {
|
|
323
|
+
copyDir(skillsDir, path.join(backupDir, 'skills', 'wtfp'));
|
|
324
|
+
}
|
|
325
|
+
if (fs.existsSync(pluginDir)) {
|
|
326
|
+
copyDir(pluginDir, path.join(backupDir, '.claude-plugin'));
|
|
313
327
|
}
|
|
314
328
|
|
|
315
329
|
const backupLabel = backupDir.replace(os.homedir(), '~').replace(process.cwd(), '.');
|
|
@@ -332,11 +346,31 @@ async function uninstall(isGlobal) {
|
|
|
332
346
|
}
|
|
333
347
|
}
|
|
334
348
|
|
|
335
|
-
if (installed.
|
|
336
|
-
removeDir(
|
|
349
|
+
if (installed.hasWorkflows) {
|
|
350
|
+
removeDir(workflowsDir);
|
|
337
351
|
out.log(` ${c.red('-')} ${c.dim('write-the-f-paper/')}`);
|
|
338
352
|
}
|
|
339
353
|
|
|
354
|
+
if (installed.hasSkills) {
|
|
355
|
+
removeDir(skillsDir);
|
|
356
|
+
out.log(` ${c.red('-')} ${c.dim('skills/wtfp/')}`);
|
|
357
|
+
|
|
358
|
+
// Clean up empty skills dir
|
|
359
|
+
const parentSkillsDir = path.join(claudeDir, 'skills');
|
|
360
|
+
if (fs.existsSync(parentSkillsDir)) {
|
|
361
|
+
const remaining = fs.readdirSync(parentSkillsDir);
|
|
362
|
+
if (remaining.length === 0) {
|
|
363
|
+
fs.rmdirSync(parentSkillsDir);
|
|
364
|
+
out.log(` ${c.red('-')} ${c.dim('skills/')} ${c.dim('(empty)')}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (fs.existsSync(pluginDir)) {
|
|
370
|
+
removeDir(pluginDir);
|
|
371
|
+
out.log(` ${c.red('-')} ${c.dim('.claude-plugin/')}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
340
374
|
// Remove version file
|
|
341
375
|
const versionFile = path.join(claudeDir, VERSION_FILE);
|
|
342
376
|
if (fs.existsSync(versionFile)) {
|
|
@@ -379,8 +413,8 @@ async function promptLocation() {
|
|
|
379
413
|
const globalInstalled = detectInstallation(globalPath);
|
|
380
414
|
const localInstalled = detectInstallation(localPath);
|
|
381
415
|
|
|
382
|
-
const hasGlobalInstall = globalInstalled.hasCommands || globalInstalled.
|
|
383
|
-
const hasLocalInstall = localInstalled.hasCommands || localInstalled.
|
|
416
|
+
const hasGlobalInstall = globalInstalled.hasCommands || globalInstalled.hasWorkflows || globalInstalled.hasSkills;
|
|
417
|
+
const hasLocalInstall = localInstalled.hasCommands || localInstalled.hasWorkflows || localInstalled.hasSkills;
|
|
384
418
|
|
|
385
419
|
if (!hasGlobalInstall && !hasLocalInstall) {
|
|
386
420
|
out.log(` ${c.yellow('No WTF-P installation found.')}\n`);
|
|
@@ -394,14 +428,14 @@ async function promptLocation() {
|
|
|
394
428
|
out.log(` ${c.yellow('Where would you like to uninstall from?')}\n`);
|
|
395
429
|
|
|
396
430
|
if (hasGlobalInstall) {
|
|
397
|
-
const count = globalInstalled.commandFiles.length + globalInstalled.skillFiles.length;
|
|
431
|
+
const count = globalInstalled.commandFiles.length + globalInstalled.workflowFiles.length + globalInstalled.skillFiles.length;
|
|
398
432
|
out.log(` ${c.cyan('1)')} Global ${c.dim('(' + globalLabel + ')')} - ${count} files`);
|
|
399
433
|
} else {
|
|
400
434
|
out.log(` ${c.dim('1) Global (' + globalLabel + ') - not installed')}`);
|
|
401
435
|
}
|
|
402
436
|
|
|
403
437
|
if (hasLocalInstall) {
|
|
404
|
-
const count = localInstalled.commandFiles.length + localInstalled.skillFiles.length;
|
|
438
|
+
const count = localInstalled.commandFiles.length + localInstalled.workflowFiles.length + localInstalled.skillFiles.length;
|
|
405
439
|
out.log(` ${c.cyan('2)')} Local ${c.dim('(./.claude)')} - ${count} files`);
|
|
406
440
|
} else {
|
|
407
441
|
out.log(` ${c.dim('2) Local (./.claude) - not installed')}`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
marp: true
|
|
3
|
+
theme: uncover
|
|
4
|
+
size: 4:3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# [Poster Title]
|
|
8
|
+
|
|
9
|
+
## Authors
|
|
10
|
+
Author 1, Author 2
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Introduction
|
|
15
|
+
- Problem statement
|
|
16
|
+
- Importance
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Methodology
|
|
21
|
+
- Approach
|
|
22
|
+
- Implementation details
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Results
|
|
27
|
+
- Key findings
|
|
28
|
+
- Charts (use ECharts!)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Conclusion
|
|
33
|
+
- Summary
|
|
34
|
+
- Future work
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
marp: true
|
|
3
|
+
theme: gaia
|
|
4
|
+
_class: lead
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# [Presentation Title]
|
|
8
|
+
## [Subtitle]
|
|
9
|
+
|
|
10
|
+
Author Name
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Agenda
|
|
15
|
+
1. Introduction
|
|
16
|
+
2. Problem Statement
|
|
17
|
+
3. Methodology
|
|
18
|
+
4. Results
|
|
19
|
+
5. Conclusion
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Introduction
|
|
24
|
+
- Context
|
|
25
|
+
- High-level overview
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Conclusion
|
|
30
|
+
- Final thoughts
|
|
31
|
+
- Q&A
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wtf-p",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The G.O.A.T. meta-prompting system for 10x researchers who need to submit papers and projects and proposals YESTERDAY.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"wtfp": "bin/install.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"wtf-p-uninstall": "bin/uninstall.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "node test/sanity.js && node test/paths.js",
|
|
11
|
+
"test": "node test/sanity.js && node test/paths.js && node test/linter.js",
|
|
12
12
|
"test:integration": "node test/integration.js",
|
|
13
13
|
"test:all": "npm test && npm run test:integration",
|
|
14
14
|
"preflight": "node scripts/preflight.js",
|
|
@@ -16,9 +16,17 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"bin",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
19
|
+
"core",
|
|
20
|
+
"vendors"
|
|
21
21
|
],
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@marp-team/marp-cli": ">=3.0.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependenciesMeta": {
|
|
26
|
+
"@marp-team/marp-cli": {
|
|
27
|
+
"optional": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
22
30
|
"keywords": [
|
|
23
31
|
"claude",
|
|
24
32
|
"claude-code",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wtf-p",
|
|
3
|
+
"description": "Academic writing toolkit - Paper, Proposal, Presentation, Poster",
|
|
4
|
+
"version": "0.3.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "akougkas",
|
|
7
|
+
"url": "https://github.com/akougkas"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/akougkas/wtf-p",
|
|
10
|
+
"repository": "https://github.com/akougkas/wtf-p",
|
|
11
|
+
"license": "MIT"
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wtfp:create-poster
|
|
3
|
+
description: Full workflow for creating an academic poster from project content
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Bash
|
|
8
|
+
- AskUserQuestion
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<objective>
|
|
12
|
+
Generate an academic poster based on the current project's PROJECT.md and findings.
|
|
13
|
+
Uses the wtfp-marp skill to compile to HTML.
|
|
14
|
+
</objective>
|
|
15
|
+
|
|
16
|
+
<context>
|
|
17
|
+
@~/.claude/write-the-f-paper/references/principles.md
|
|
18
|
+
@~/.claude/write-the-f-paper/templates/posters/basic.md
|
|
19
|
+
</context>
|
|
20
|
+
|
|
21
|
+
<process>
|
|
22
|
+
## Step 1: Content Synthesis
|
|
23
|
+
- Read `.planning/PROJECT.md` and any drafted sections.
|
|
24
|
+
- Identify key findings, methodology, and conclusion.
|
|
25
|
+
|
|
26
|
+
## Step 2: User Interview
|
|
27
|
+
AskUserQuestion to determine:
|
|
28
|
+
- Poster title (default to project title)
|
|
29
|
+
- Authors
|
|
30
|
+
- Key visuals/charts needed
|
|
31
|
+
- Target audience
|
|
32
|
+
|
|
33
|
+
## Step 3: Markdown Generation
|
|
34
|
+
- Create `poster.md` using Marp format.
|
|
35
|
+
- Integrate synthesized content.
|
|
36
|
+
|
|
37
|
+
## Step 4: Compilation
|
|
38
|
+
- Use `wtfp-marp` skill: `npx @marp-team/marp-cli poster.md -o poster.html`
|
|
39
|
+
|
|
40
|
+
## Step 5: Review
|
|
41
|
+
- Present the generated poster.html path to the user.
|
|
42
|
+
</process>
|