wtf-p 0.2.0 → 0.4.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 (122) hide show
  1. package/README.md +24 -2
  2. package/bin/commands/doctor.js +100 -0
  3. package/bin/commands/install-logic.js +231 -0
  4. package/bin/commands/list.js +88 -0
  5. package/bin/commands/status.js +85 -0
  6. package/bin/commands/update.js +50 -0
  7. package/bin/install.js +78 -629
  8. package/bin/lib/analyze-impact.js +105 -0
  9. package/bin/lib/bib-format.js +161 -0
  10. package/bin/lib/bib-index.js +104 -0
  11. package/bin/lib/citation-fetcher.js +299 -0
  12. package/bin/lib/citation-ranker.js +133 -0
  13. package/bin/lib/manifest.js +59 -0
  14. package/bin/lib/scholar-lookup.js +188 -0
  15. package/bin/lib/semantic-scholar.js +184 -0
  16. package/bin/lib/utils.js +37 -17
  17. package/bin/lib/wcn-compiler.js +226 -0
  18. package/bin/uninstall.js +51 -17
  19. package/core/write-the-f-paper/templates/posters/basic.md +34 -0
  20. package/core/write-the-f-paper/templates/slides/basic.md +31 -0
  21. package/package.json +12 -4
  22. package/vendors/claude/.claude-plugin/plugin.json +12 -0
  23. package/vendors/claude/agents/wtfp/citation-expert.md +45 -0
  24. package/vendors/claude/agents/wtfp/citation-formatter.md +42 -0
  25. package/vendors/claude/agents/wtfp/citation-retriever.md +31 -0
  26. package/{commands → vendors/claude/commands}/wtfp/analyze-bib.md +41 -52
  27. package/{commands → vendors/claude/commands}/wtfp/check-refs.md +11 -9
  28. package/vendors/claude/commands/wtfp/create-poster.md +42 -0
  29. package/vendors/claude/commands/wtfp/create-slides.md +41 -0
  30. package/{commands → vendors/claude/commands}/wtfp/help.md +3 -0
  31. package/{commands → vendors/claude/commands}/wtfp/new-paper.md +42 -81
  32. package/{commands → vendors/claude/commands}/wtfp/research-gap.md +3 -4
  33. package/vendors/claude/mcp/research-server/package.json +13 -0
  34. package/vendors/claude/mcp/research-server/src/index.js +133 -0
  35. package/vendors/claude/skills/wtfp/echarts/SKILL.md +47 -0
  36. package/vendors/claude/skills/wtfp/marp/SKILL.md +49 -0
  37. /package/{write-the-f-paper → core/write-the-f-paper}/references/checkpoints.md +0 -0
  38. /package/{write-the-f-paper → core/write-the-f-paper}/references/continuation-format.md +0 -0
  39. /package/{write-the-f-paper → core/write-the-f-paper}/references/git-integration.md +0 -0
  40. /package/{write-the-f-paper → core/write-the-f-paper}/references/github-contrib.md +0 -0
  41. /package/{write-the-f-paper → core/write-the-f-paper}/references/imrad-structure.md +0 -0
  42. /package/{write-the-f-paper → core/write-the-f-paper}/references/length-estimation.md +0 -0
  43. /package/{write-the-f-paper → core/write-the-f-paper}/references/plan-format.md +0 -0
  44. /package/{write-the-f-paper → core/write-the-f-paper}/references/principles.md +0 -0
  45. /package/{write-the-f-paper → core/write-the-f-paper}/references/questioning.md +0 -0
  46. /package/{write-the-f-paper → core/write-the-f-paper}/references/research-pitfalls.md +0 -0
  47. /package/{write-the-f-paper → core/write-the-f-paper}/templates/config.json +0 -0
  48. /package/{write-the-f-paper → core/write-the-f-paper}/templates/context.md +0 -0
  49. /package/{write-the-f-paper → core/write-the-f-paper}/templates/continue-here.md +0 -0
  50. /package/{write-the-f-paper → core/write-the-f-paper}/templates/data-inventory.md +0 -0
  51. /package/{write-the-f-paper → core/write-the-f-paper}/templates/discovery.md +0 -0
  52. /package/{write-the-f-paper → core/write-the-f-paper}/templates/issues.md +0 -0
  53. /package/{write-the-f-paper → core/write-the-f-paper}/templates/manuscript.md +0 -0
  54. /package/{write-the-f-paper → core/write-the-f-paper}/templates/narrative-arc.md +0 -0
  55. /package/{write-the-f-paper → core/write-the-f-paper}/templates/outline.md +0 -0
  56. /package/{write-the-f-paper → core/write-the-f-paper}/templates/phase-prompt.md +0 -0
  57. /package/{write-the-f-paper → core/write-the-f-paper}/templates/prior-drafts.md +0 -0
  58. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/argument-structure.md +0 -0
  59. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/bibliography.md +0 -0
  60. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/gaps.md +0 -0
  61. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/imrad.md +0 -0
  62. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/peer-review.md +0 -0
  63. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/style-guide.md +0 -0
  64. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project-context/tools.md +0 -0
  65. /package/{write-the-f-paper → core/write-the-f-paper}/templates/project.md +0 -0
  66. /package/{write-the-f-paper → core/write-the-f-paper}/templates/research.md +0 -0
  67. /package/{write-the-f-paper → core/write-the-f-paper}/templates/review-comments.md +0 -0
  68. /package/{write-the-f-paper → core/write-the-f-paper}/templates/revision-issues.md +0 -0
  69. /package/{write-the-f-paper → core/write-the-f-paper}/templates/roadmap.md +0 -0
  70. /package/{write-the-f-paper → core/write-the-f-paper}/templates/section-archive.md +0 -0
  71. /package/{write-the-f-paper → core/write-the-f-paper}/templates/section-context.md +0 -0
  72. /package/{write-the-f-paper → core/write-the-f-paper}/templates/section.md +0 -0
  73. /package/{write-the-f-paper → core/write-the-f-paper}/templates/state.md +0 -0
  74. /package/{write-the-f-paper → core/write-the-f-paper}/templates/summary.md +0 -0
  75. /package/{write-the-f-paper → core/write-the-f-paper}/venues/acm-cs.yaml +0 -0
  76. /package/{write-the-f-paper → core/write-the-f-paper}/venues/arxiv-ml.yaml +0 -0
  77. /package/{write-the-f-paper → core/write-the-f-paper}/venues/ieee-cs.yaml +0 -0
  78. /package/{write-the-f-paper → core/write-the-f-paper}/venues/nature.yaml +0 -0
  79. /package/{write-the-f-paper → core/write-the-f-paper}/venues/thesis-chapter.yaml +0 -0
  80. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/create-outline.md +0 -0
  81. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/create-outline.wcn.md +0 -0
  82. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/discuss-section.md +0 -0
  83. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/discuss-section.wcn.md +0 -0
  84. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/execute-section.md +0 -0
  85. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/execute-section.wcn.md +0 -0
  86. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/list-assumptions.md +0 -0
  87. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/list-assumptions.wcn.md +0 -0
  88. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/lit-review-phase.md +0 -0
  89. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/lit-review-phase.wcn.md +0 -0
  90. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/map-project.md +0 -0
  91. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/map-project.wcn.md +0 -0
  92. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/plan-section.md +0 -0
  93. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/plan-section.wcn.md +0 -0
  94. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/research-gap.md +0 -0
  95. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/research-gap.wcn.md +0 -0
  96. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/resume-paper.md +0 -0
  97. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/resume-paper.wcn.md +0 -0
  98. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/review-section.md +0 -0
  99. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/review-section.wcn.md +0 -0
  100. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/submit-draft.md +0 -0
  101. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/submit-draft.wcn.md +0 -0
  102. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/transition.md +0 -0
  103. /package/{write-the-f-paper → core/write-the-f-paper}/workflows/transition.wcn.md +0 -0
  104. /package/{commands → vendors/claude/commands}/wtfp/contribute.md +0 -0
  105. /package/{commands → vendors/claude/commands}/wtfp/create-outline.md +0 -0
  106. /package/{commands → vendors/claude/commands}/wtfp/discuss-section.md +0 -0
  107. /package/{commands → vendors/claude/commands}/wtfp/export-latex.md +0 -0
  108. /package/{commands → vendors/claude/commands}/wtfp/insert-section.md +0 -0
  109. /package/{commands → vendors/claude/commands}/wtfp/list-assumptions.md +0 -0
  110. /package/{commands → vendors/claude/commands}/wtfp/map-project.md +0 -0
  111. /package/{commands → vendors/claude/commands}/wtfp/pause-writing.md +0 -0
  112. /package/{commands → vendors/claude/commands}/wtfp/plan-revision.md +0 -0
  113. /package/{commands → vendors/claude/commands}/wtfp/plan-section.md +0 -0
  114. /package/{commands → vendors/claude/commands}/wtfp/polish-prose.md +0 -0
  115. /package/{commands → vendors/claude/commands}/wtfp/progress.md +0 -0
  116. /package/{commands → vendors/claude/commands}/wtfp/remove-section.md +0 -0
  117. /package/{commands → vendors/claude/commands}/wtfp/report-bug.md +0 -0
  118. /package/{commands → vendors/claude/commands}/wtfp/request-feature.md +0 -0
  119. /package/{commands → vendors/claude/commands}/wtfp/resume-writing.md +0 -0
  120. /package/{commands → vendors/claude/commands}/wtfp/review-section.md +0 -0
  121. /package/{commands → vendors/claude/commands}/wtfp/submit-milestone.md +0 -0
  122. /package/{commands → vendors/claude/commands}/wtfp/write-section.md +0 -0
@@ -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 skill and workflows
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.hasSkill) {
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 skillDir = path.join(claudeDir, 'write-the-f-paper');
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.hasSkill) {
261
- out.log(` ${c.cyan('write-the-f-paper/')} (${installed.skillFiles.length} files)`);
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
- const dest = path.join(backupDir, 'commands', 'wtfp');
308
- copyDir(commandsDir, dest);
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.hasSkill) {
311
- const dest = path.join(backupDir, 'write-the-f-paper');
312
- copyDir(skillDir, dest);
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.hasSkill) {
336
- removeDir(skillDir);
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.hasSkill;
383
- const hasLocalInstall = localInstalled.hasCommands || localInstalled.hasSkill;
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.2.0",
3
+ "version": "0.4.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
- "commands",
20
- "write-the-f-paper"
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,45 @@
1
+ ---
2
+ name: citation-expert
3
+ description: Academic citation specialist. Searches papers, manages BibTeX, and identifies literature gaps.
4
+ allowed-tools:
5
+ - Bash
6
+ - Read
7
+ - Write
8
+ ---
9
+
10
+ # Citation Expert
11
+
12
+ You are a senior academic librarian and bibliometric specialist. Your goal is to ensure all citations in a project are accurate, grounded, and well-formatted.
13
+
14
+ ## Tools
15
+ You have access to specialized CLI tools for citation management:
16
+
17
+ 1. **Retrieval:** `node ~/.claude/bin/citation-fetcher.js "<query>"`
18
+ - Use this to find new papers and get their BibTeX.
19
+ - Source: CrossRef / Semantic Scholar.
20
+
21
+ 2. **Bibliography Management:** `node ~/.claude/bin/bib-index.js <command> ...`
22
+ - `index <file>`: List all keys in a bib file.
23
+ - `get <file> <key>`: Read a specific entry.
24
+ - `search <file> <query>`: Find entries by keyword.
25
+
26
+ ## Capabilities
27
+
28
+ 1. **Literature Discovery:** Find relevant literature based on keywords or claims in `PROJECT.md`.
29
+ 2. **Verification:** Check if citations in the manuscript actually exist in the `.bib` file.
30
+ 3. **Formatting:** Ensure BibTeX entries follow standard conventions.
31
+ 4. **Gap Analysis:** Compare current citations against the core argument.
32
+
33
+ ## Principles
34
+
35
+ - **Precision Over Recall:** Prefer a few highly relevant citations.
36
+ - **No Direct Writes:** NEVER overwrite the user's `references.bib`. Always create a `suggested.bib` or provide the BibTeX in the chat.
37
+ - **Grounding:** Always check the `PROJECT.md` context.
38
+ - **Deterministic:** Use the provided tools to verify facts. Do not hallucinate citations.
39
+
40
+ ## Workflow
41
+
42
+ 1. **Analyze:** Understand the user's need (search vs. fix).
43
+ 2. **Execute:** Use the appropriate script.
44
+ 3. **Refine:** Process the JSON output from the script into a human-readable format or valid BibTeX.
45
+ 4. **Report:** Present findings or suggested changes.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: citation-formatter
3
+ description: Specialist in managing BibTeX files, checking citation consistency, and formatting references.
4
+ allowed-tools:
5
+ - Bash
6
+ - Read
7
+ - Write
8
+ ---
9
+
10
+ # Citation Formatter
11
+
12
+ You are a bibliometric quality assurance specialist. Your job is to ensure the integrity and formatting of the project's bibliography.
13
+
14
+ ## Tools
15
+ You have access to the Bibliography Indexer:
16
+ - `node ~/.claude/bin/bib-index.js index <file>`: List all keys.
17
+ - `node ~/.claude/bin/bib-index.js get <file> <key>`: Get full BibTeX for a key.
18
+ - `node ~/.claude/bin/bib-index.js search <file> <query>`: Find entries.
19
+
20
+ ## Core Responsibilities
21
+
22
+ 1. **Validation:** Check if citations in the text (e.g., `\cite{foo}`) actually exist in the `.bib` file.
23
+ 2. **Formatting:** detailed formatting of BibTeX entries (e.g., ensuring curly braces around titles to preserve capitalization).
24
+ 3. **Deduplication:** Identify potential duplicate entries.
25
+
26
+ ## Critical Rules
27
+
28
+ 1. **Read-Only on Source:** You must **NEVER** overwrite the user's primary `.bib` file (usually `references.bib`).
29
+ 2. **Suggestion Mode:** If you find errors or formatting issues, write a **new** file (e.g., `references_suggested.bib`) or output the corrected BibTeX in the chat.
30
+ 3. **Deterministic:** Rely on the `bib-index.js` tool to verify existence. Do not guess.
31
+
32
+ ## Common Workflows
33
+
34
+ - **"Check references":**
35
+ 1. Read the latex/markdown files to find citations.
36
+ 2. Index the `.bib` file.
37
+ 3. Cross-reference and report missing keys.
38
+
39
+ - **"Fix formatting":**
40
+ 1. Read the entry using `get`.
41
+ 2. Apply formatting rules (e.g., standardizing conference names).
42
+ 3. Output the corrected block.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: citation-retriever
3
+ description: Specialist in finding academic literature and generating BibTeX.
4
+ allowed-tools:
5
+ - Bash
6
+ - Read
7
+ ---
8
+
9
+ # Citation Retriever
10
+
11
+ You are an expert at discovering academic literature. Your goal is to find high-quality papers that match the user's needs and provide them in BibTeX format.
12
+
13
+ ## Tools
14
+ You have access to a custom search tool via the command line:
15
+ `node ~/.claude/bin/citation-fetcher.js "<query>"`
16
+
17
+ This tool queries academic databases (like CrossRef) and returns a JSON list of papers, including a draft BibTeX entry.
18
+
19
+ ## Workflow
20
+ 1. **Analyze Request:** Understand what the user is looking for.
21
+ 2. **Contextualize:** If needed, read `.planning/PROJECT.md` to understand the broader research context.
22
+ 3. **Search:** Run the fetcher script with specific keywords.
23
+ 4. **Present:** Output the results. If the user asks for BibTeX, provide the entries generated by the tool.
24
+
25
+ ## Rules
26
+ - **No Hallucinations:** Only provide citations returned by the tool.
27
+ - **Verification:** If the tool returns no results, try broader keywords. Do not invent papers.
28
+ - **Output:** When presenting BibTeX, use a code block:
29
+ ```bibtex
30
+ @article{...}
31
+ ```