docrev 0.9.13 → 0.9.14
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/.claude/settings.local.json +9 -9
- package/.gitattributes +1 -1
- package/CHANGELOG.md +149 -149
- package/PLAN-tables-and-postprocess.md +850 -850
- package/README.md +391 -391
- package/bin/rev.js +11 -11
- package/bin/rev.ts +145 -145
- package/completions/rev.bash +127 -127
- package/completions/rev.ps1 +210 -210
- package/completions/rev.zsh +207 -207
- package/dev_notes/stress2/build_adversarial.ts +186 -186
- package/dev_notes/stress2/drift_matcher.ts +62 -62
- package/dev_notes/stress2/probe_anchors.ts +35 -35
- package/dev_notes/stress2/project/discussion.before.md +3 -3
- package/dev_notes/stress2/project/discussion.md +3 -3
- package/dev_notes/stress2/project/methods.before.md +20 -20
- package/dev_notes/stress2/project/methods.md +20 -20
- package/dev_notes/stress2/project/rev.yaml +5 -5
- package/dev_notes/stress2/project/sections.yaml +4 -4
- package/dev_notes/stress2/sections.yaml +5 -5
- package/dev_notes/stress2/trace_placement.ts +50 -50
- package/dev_notes/stresstest_boundaries.ts +27 -27
- package/dev_notes/stresstest_drift_apply.ts +43 -43
- package/dev_notes/stresstest_drift_compare.ts +43 -43
- package/dev_notes/stresstest_drift_v2.ts +54 -54
- package/dev_notes/stresstest_inspect.ts +54 -54
- package/dev_notes/stresstest_pstyle.ts +55 -55
- package/dev_notes/stresstest_section_debug.ts +23 -23
- package/dev_notes/stresstest_split.ts +70 -70
- package/dev_notes/stresstest_trace.ts +19 -19
- package/dev_notes/stresstest_verify_no_overwrite.ts +40 -40
- package/dist/lib/build.d.ts +38 -1
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +68 -30
- package/dist/lib/build.js.map +1 -1
- package/dist/lib/commands/build.d.ts.map +1 -1
- package/dist/lib/commands/build.js +38 -5
- package/dist/lib/commands/build.js.map +1 -1
- package/dist/lib/commands/utilities.js +164 -164
- package/dist/lib/commands/word-tools.js +8 -8
- package/dist/lib/grammar.js +3 -3
- package/dist/lib/pdf-comments.js +44 -44
- package/dist/lib/plugins.js +57 -57
- package/dist/lib/pptx-themes.js +115 -115
- package/dist/lib/spelling.js +2 -2
- package/dist/lib/templates.js +387 -387
- package/dist/lib/themes.js +51 -51
- package/eslint.config.js +27 -27
- package/lib/anchor-match.ts +276 -276
- package/lib/annotations.ts +644 -644
- package/lib/build.ts +1300 -1251
- package/lib/citations.ts +160 -160
- package/lib/commands/build.ts +833 -801
- package/lib/commands/citations.ts +515 -515
- package/lib/commands/comments.ts +1050 -1050
- package/lib/commands/context.ts +174 -174
- package/lib/commands/core.ts +309 -309
- package/lib/commands/doi.ts +435 -435
- package/lib/commands/file-ops.ts +372 -372
- package/lib/commands/history.ts +320 -320
- package/lib/commands/index.ts +87 -87
- package/lib/commands/init.ts +259 -259
- package/lib/commands/merge-resolve.ts +378 -378
- package/lib/commands/preview.ts +178 -178
- package/lib/commands/project-info.ts +244 -244
- package/lib/commands/quality.ts +517 -517
- package/lib/commands/response.ts +454 -454
- package/lib/commands/section-boundaries.ts +82 -82
- package/lib/commands/sections.ts +451 -451
- package/lib/commands/sync.ts +706 -706
- package/lib/commands/text-ops.ts +449 -449
- package/lib/commands/utilities.ts +448 -448
- package/lib/commands/verify-anchors.ts +272 -272
- package/lib/commands/word-tools.ts +340 -340
- package/lib/comment-realign.ts +517 -517
- package/lib/config.ts +84 -84
- package/lib/crossref.ts +781 -781
- package/lib/csl.ts +191 -191
- package/lib/dependencies.ts +98 -98
- package/lib/diff-engine.ts +465 -465
- package/lib/doi-cache.ts +115 -115
- package/lib/doi.ts +897 -897
- package/lib/equations.ts +506 -506
- package/lib/errors.ts +346 -346
- package/lib/format.ts +541 -541
- package/lib/git.ts +326 -326
- package/lib/grammar.ts +303 -303
- package/lib/image-registry.ts +180 -180
- package/lib/import.ts +911 -911
- package/lib/journals.ts +543 -543
- package/lib/merge.ts +633 -633
- package/lib/orcid.ts +144 -144
- package/lib/pdf-comments.ts +263 -263
- package/lib/pdf-import.ts +524 -524
- package/lib/plugins.ts +362 -362
- package/lib/postprocess.ts +188 -188
- package/lib/pptx-color-filter.lua +37 -37
- package/lib/pptx-template.ts +469 -469
- package/lib/pptx-themes.ts +483 -483
- package/lib/protect-restore.ts +520 -520
- package/lib/rate-limiter.ts +94 -94
- package/lib/response.ts +197 -197
- package/lib/restore-references.ts +240 -240
- package/lib/review.ts +327 -327
- package/lib/schema.ts +417 -417
- package/lib/scientific-words.ts +73 -73
- package/lib/sections.ts +335 -335
- package/lib/slides.ts +756 -756
- package/lib/spelling.ts +334 -334
- package/lib/templates.ts +526 -526
- package/lib/themes.ts +742 -742
- package/lib/trackchanges.ts +247 -247
- package/lib/tui.ts +450 -450
- package/lib/types.ts +550 -550
- package/lib/undo.ts +250 -250
- package/lib/utils.ts +69 -69
- package/lib/variables.ts +179 -179
- package/lib/word-extraction.ts +806 -806
- package/lib/word.ts +643 -643
- package/lib/wordcomments.ts +817 -817
- package/package.json +137 -137
- package/scripts/postbuild.js +28 -28
- package/skill/REFERENCE.md +431 -431
- package/skill/SKILL.md +258 -258
- package/tsconfig.json +26 -26
- package/types/index.d.ts +525 -525
|
@@ -1,448 +1,448 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility commands: help, completions, open, upgrade, install-cli-skill, uninstall-cli-skill
|
|
3
|
-
*
|
|
4
|
-
* Core utility commands that don't fit into a specific domain.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Command } from 'commander';
|
|
8
|
-
import {
|
|
9
|
-
chalk,
|
|
10
|
-
fs,
|
|
11
|
-
path,
|
|
12
|
-
fmt,
|
|
13
|
-
} from './context.js';
|
|
14
|
-
|
|
15
|
-
// Type definitions for package.json
|
|
16
|
-
interface PackageJson {
|
|
17
|
-
version?: string;
|
|
18
|
-
name?: string;
|
|
19
|
-
[key: string]: unknown;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface OpenOptions {
|
|
23
|
-
// No options currently
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface UpgradeOptions {
|
|
27
|
-
check?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Register utility commands with the program
|
|
32
|
-
*/
|
|
33
|
-
export function register(program: Command, pkg?: PackageJson): void {
|
|
34
|
-
// ==========================================================================
|
|
35
|
-
// HELP command - Comprehensive help
|
|
36
|
-
// ==========================================================================
|
|
37
|
-
|
|
38
|
-
program
|
|
39
|
-
.command('help')
|
|
40
|
-
.description('Show detailed help and workflow guide')
|
|
41
|
-
.argument('[topic]', 'Help topic: workflow, syntax, commands')
|
|
42
|
-
.action((topic?: string) => {
|
|
43
|
-
if (!topic || topic === 'all') {
|
|
44
|
-
showFullHelp(pkg);
|
|
45
|
-
} else if (topic === 'workflow') {
|
|
46
|
-
showWorkflowHelp();
|
|
47
|
-
} else if (topic === 'syntax') {
|
|
48
|
-
showSyntaxHelp();
|
|
49
|
-
} else if (topic === 'commands') {
|
|
50
|
-
showCommandsHelp();
|
|
51
|
-
} else {
|
|
52
|
-
console.log(chalk.yellow(`Unknown topic: ${topic}`));
|
|
53
|
-
console.log(chalk.dim('Available topics: workflow, syntax, commands'));
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// ==========================================================================
|
|
58
|
-
// COMPLETIONS command - Shell completions
|
|
59
|
-
// ==========================================================================
|
|
60
|
-
|
|
61
|
-
program
|
|
62
|
-
.command('completions')
|
|
63
|
-
.description('Output shell completions')
|
|
64
|
-
.argument('<shell>', 'Shell type: bash, zsh, powershell')
|
|
65
|
-
.action((shell: string) => {
|
|
66
|
-
const completionsDir = path.join(import.meta.dirname, '..', '..', 'completions');
|
|
67
|
-
|
|
68
|
-
if (shell === 'bash') {
|
|
69
|
-
const bashFile = path.join(completionsDir, 'rev.bash');
|
|
70
|
-
if (fs.existsSync(bashFile)) {
|
|
71
|
-
console.log(fs.readFileSync(bashFile, 'utf-8'));
|
|
72
|
-
} else {
|
|
73
|
-
console.error(chalk.red('Bash completions not found'));
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
} else if (shell === 'zsh') {
|
|
77
|
-
const zshFile = path.join(completionsDir, 'rev.zsh');
|
|
78
|
-
if (fs.existsSync(zshFile)) {
|
|
79
|
-
console.log(fs.readFileSync(zshFile, 'utf-8'));
|
|
80
|
-
} else {
|
|
81
|
-
console.error(chalk.red('Zsh completions not found'));
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
} else if (shell === 'powershell' || shell === 'pwsh') {
|
|
85
|
-
const psFile = path.join(completionsDir, 'rev.ps1');
|
|
86
|
-
if (fs.existsSync(psFile)) {
|
|
87
|
-
console.log(fs.readFileSync(psFile, 'utf-8'));
|
|
88
|
-
} else {
|
|
89
|
-
console.error(chalk.red('PowerShell completions not found'));
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
console.error(chalk.red(`Unknown shell: ${shell}`));
|
|
94
|
-
console.log(chalk.dim('Supported shells: bash, zsh, powershell'));
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// ==========================================================================
|
|
100
|
-
// OPEN command - Open project folder or file
|
|
101
|
-
// ==========================================================================
|
|
102
|
-
|
|
103
|
-
program
|
|
104
|
-
.command('open')
|
|
105
|
-
.description('Open project folder or file in default app')
|
|
106
|
-
.argument('[file]', 'File to open (default: project folder)')
|
|
107
|
-
.action(async (file?: string, _options?: OpenOptions) => {
|
|
108
|
-
const { exec } = await import('child_process');
|
|
109
|
-
const target = file || '.';
|
|
110
|
-
|
|
111
|
-
if (!fs.existsSync(target)) {
|
|
112
|
-
console.error(chalk.red(`File not found: ${target}`));
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const platform = process.platform;
|
|
117
|
-
let command: string;
|
|
118
|
-
|
|
119
|
-
if (platform === 'darwin') {
|
|
120
|
-
command = `open "${target}"`;
|
|
121
|
-
} else if (platform === 'win32') {
|
|
122
|
-
command = `start "" "${target}"`;
|
|
123
|
-
} else {
|
|
124
|
-
command = `xdg-open "${target}"`;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
exec(command, (err) => {
|
|
128
|
-
if (err) {
|
|
129
|
-
console.error(chalk.red(`Failed to open: ${err.message}`));
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
console.log(fmt.status('success', `Opened ${target}`));
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// ==========================================================================
|
|
137
|
-
// INSTALL-CLI-SKILL command - Install Claude Code skill
|
|
138
|
-
// ==========================================================================
|
|
139
|
-
|
|
140
|
-
program
|
|
141
|
-
.command('install-cli-skill')
|
|
142
|
-
.description('Install docrev skill for Claude Code')
|
|
143
|
-
.action(() => {
|
|
144
|
-
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
145
|
-
if (!homedir) {
|
|
146
|
-
console.error(chalk.red('Could not determine home directory'));
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
150
|
-
const sourceDir = path.join(import.meta.dirname, '..', '..', 'skill');
|
|
151
|
-
|
|
152
|
-
// Check if source skill files exist
|
|
153
|
-
const skillFile = path.join(sourceDir, 'SKILL.md');
|
|
154
|
-
if (!fs.existsSync(skillFile)) {
|
|
155
|
-
console.error(chalk.red('Skill files not found in package'));
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Create skill directory
|
|
160
|
-
fs.mkdirSync(skillDir, { recursive: true });
|
|
161
|
-
|
|
162
|
-
// Copy skill files
|
|
163
|
-
const files = ['SKILL.md', 'REFERENCE.md'];
|
|
164
|
-
for (const file of files) {
|
|
165
|
-
const src = path.join(sourceDir, file);
|
|
166
|
-
const dest = path.join(skillDir, file);
|
|
167
|
-
if (fs.existsSync(src)) {
|
|
168
|
-
fs.copyFileSync(src, dest);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
console.log(fmt.status('success', 'Installed docrev skill for Claude Code'));
|
|
173
|
-
console.log(chalk.dim(` Location: ${skillDir}`));
|
|
174
|
-
console.log(chalk.dim(' Restart Claude Code to activate'));
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
program
|
|
178
|
-
.command('uninstall-cli-skill')
|
|
179
|
-
.description('Remove docrev skill from Claude Code')
|
|
180
|
-
.action(() => {
|
|
181
|
-
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
182
|
-
if (!homedir) {
|
|
183
|
-
console.error(chalk.red('Could not determine home directory'));
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
|
186
|
-
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
187
|
-
|
|
188
|
-
if (fs.existsSync(skillDir)) {
|
|
189
|
-
fs.rmSync(skillDir, { recursive: true });
|
|
190
|
-
console.log(fmt.status('success', 'Removed docrev skill from Claude Code'));
|
|
191
|
-
} else {
|
|
192
|
-
console.log(chalk.yellow('Skill not installed'));
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// ==========================================================================
|
|
197
|
-
// UPGRADE command - Self-update via npm
|
|
198
|
-
// ==========================================================================
|
|
199
|
-
|
|
200
|
-
program
|
|
201
|
-
.command('upgrade')
|
|
202
|
-
.description('Check for updates and upgrade docrev')
|
|
203
|
-
.option('--check', 'Only check for updates, do not install')
|
|
204
|
-
.action(async (options: UpgradeOptions) => {
|
|
205
|
-
const { execSync, spawn } = await import('child_process');
|
|
206
|
-
|
|
207
|
-
console.log(chalk.cyan('Checking for updates...'));
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// Get current version
|
|
211
|
-
const currentVersion = pkg?.version || 'unknown';
|
|
212
|
-
|
|
213
|
-
// Get latest version from npm
|
|
214
|
-
let latestVersion: string;
|
|
215
|
-
try {
|
|
216
|
-
latestVersion = execSync('npm view docrev version', { encoding: 'utf-8' }).trim();
|
|
217
|
-
} catch {
|
|
218
|
-
console.error(chalk.red('Failed to check npm registry'));
|
|
219
|
-
console.error(chalk.dim('Check your internet connection'));
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (currentVersion === latestVersion) {
|
|
224
|
-
console.log(fmt.status('success', `Already on latest version (${currentVersion})`));
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
console.log(` Current: ${chalk.yellow(currentVersion)}`);
|
|
229
|
-
console.log(` Latest: ${chalk.green(latestVersion)}`);
|
|
230
|
-
console.log();
|
|
231
|
-
|
|
232
|
-
if (options.check) {
|
|
233
|
-
console.log(chalk.cyan('Run "rev upgrade" to install the update'));
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
console.log(chalk.cyan('Upgrading...'));
|
|
238
|
-
|
|
239
|
-
// Run npm update
|
|
240
|
-
const child = spawn('npm', ['install', '-g', 'docrev@latest'], {
|
|
241
|
-
stdio: 'inherit',
|
|
242
|
-
shell: true,
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
child.on('close', (code) => {
|
|
246
|
-
if (code === 0) {
|
|
247
|
-
console.log();
|
|
248
|
-
console.log(fmt.status('success', `Upgraded to ${latestVersion}`));
|
|
249
|
-
} else {
|
|
250
|
-
console.error(chalk.red('Upgrade failed'));
|
|
251
|
-
console.error(chalk.dim('Try running: npm install -g docrev@latest'));
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
child.on('error', (err) => {
|
|
257
|
-
console.error(chalk.red(`Upgrade failed: ${err.message}`));
|
|
258
|
-
console.error(chalk.dim('Try running: npm install -g docrev@latest'));
|
|
259
|
-
process.exit(1);
|
|
260
|
-
});
|
|
261
|
-
} catch (err) {
|
|
262
|
-
console.error(chalk.red(`Error: ${(err as Error).message}`));
|
|
263
|
-
process.exit(1);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Helper functions for help text
|
|
269
|
-
|
|
270
|
-
function showFullHelp(pkg?: PackageJson): void {
|
|
271
|
-
console.log(`
|
|
272
|
-
${chalk.bold.cyan('rev')} ${chalk.dim(`v${pkg?.version || 'unknown'}`)} - Revision workflow for Word ↔ Markdown round-trips
|
|
273
|
-
|
|
274
|
-
${chalk.bold('DESCRIPTION')}
|
|
275
|
-
Handle reviewer feedback when collaborating on academic papers.
|
|
276
|
-
Import changes from Word, review them interactively, and preserve
|
|
277
|
-
comments for discussion with Claude.
|
|
278
|
-
|
|
279
|
-
${chalk.bold('GLOBAL OPTIONS')}
|
|
280
|
-
|
|
281
|
-
${chalk.bold('--no-color')} Disable colored output
|
|
282
|
-
${chalk.bold('-q, --quiet')} Suppress non-essential output
|
|
283
|
-
${chalk.bold('--json')} Output in JSON format (for scripting)
|
|
284
|
-
|
|
285
|
-
${chalk.bold('TYPICAL WORKFLOW')}
|
|
286
|
-
|
|
287
|
-
${chalk.dim('1.')} Build and send: ${chalk.green('rev build docx')} ${chalk.dim('(or rev b docx)')}
|
|
288
|
-
${chalk.dim('2.')} Reviewers return ${chalk.yellow('reviewed.docx')} with edits and comments
|
|
289
|
-
${chalk.dim('3.')} Sync their feedback: ${chalk.green('rev sync reviewed.docx')}
|
|
290
|
-
${chalk.dim('4.')} Work through comments: ${chalk.green('rev next')} ${chalk.dim('(n)')} / ${chalk.green('rev todo')} ${chalk.dim('(t)')}
|
|
291
|
-
${chalk.dim('5.')} Accept/reject changes: ${chalk.green('rev accept -a')} ${chalk.dim('(a)')} or ${chalk.green('rev review')}
|
|
292
|
-
${chalk.dim('6.')} Rebuild: ${chalk.green('rev build docx')}
|
|
293
|
-
${chalk.dim('7.')} Archive old files: ${chalk.green('rev archive')}
|
|
294
|
-
|
|
295
|
-
${chalk.bold('MORE HELP')}
|
|
296
|
-
|
|
297
|
-
rev help workflow Detailed workflow guide
|
|
298
|
-
rev help syntax Annotation syntax reference
|
|
299
|
-
rev help commands All commands with options
|
|
300
|
-
`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function showWorkflowHelp(): void {
|
|
304
|
-
console.log(`
|
|
305
|
-
${chalk.bold.cyan('rev')} ${chalk.dim('- Workflow Guide')}
|
|
306
|
-
|
|
307
|
-
${chalk.bold('OVERVIEW')}
|
|
308
|
-
|
|
309
|
-
The rev workflow solves a common problem: you write in Markdown,
|
|
310
|
-
but collaborators review in Word. When they return edited documents,
|
|
311
|
-
you need to merge their changes back into your source files.
|
|
312
|
-
|
|
313
|
-
${chalk.bold('STEP 1: BUILD & SEND')}
|
|
314
|
-
|
|
315
|
-
${chalk.green('rev build docx')}
|
|
316
|
-
${chalk.dim('# Send the .docx to reviewers')}
|
|
317
|
-
|
|
318
|
-
${chalk.bold('STEP 2: RECEIVE FEEDBACK')}
|
|
319
|
-
|
|
320
|
-
Reviewers edit the document, adding:
|
|
321
|
-
${chalk.dim('•')} Track changes (insertions, deletions)
|
|
322
|
-
${chalk.dim('•')} Comments (questions, suggestions)
|
|
323
|
-
|
|
324
|
-
${chalk.bold('STEP 3: SYNC CHANGES')}
|
|
325
|
-
|
|
326
|
-
${chalk.green('rev sync reviewed.docx')}
|
|
327
|
-
${chalk.dim('# Or just: rev sync (auto-detects most recent .docx)')}
|
|
328
|
-
|
|
329
|
-
Your markdown files now contain their feedback as annotations.
|
|
330
|
-
|
|
331
|
-
${chalk.bold('STEP 4: WORK THROUGH COMMENTS')}
|
|
332
|
-
|
|
333
|
-
${chalk.green('rev todo')} ${chalk.dim('# See all pending comments')}
|
|
334
|
-
${chalk.green('rev next')} ${chalk.dim('# Show next pending comment')}
|
|
335
|
-
${chalk.green('rev reply file.md -n 1 -m "Done"')}
|
|
336
|
-
${chalk.green('rev resolve file.md -n 1')}
|
|
337
|
-
|
|
338
|
-
${chalk.bold('STEP 5: ACCEPT/REJECT CHANGES')}
|
|
339
|
-
|
|
340
|
-
${chalk.green('rev accept file.md -a')} ${chalk.dim('# Accept all changes')}
|
|
341
|
-
${chalk.green('rev reject file.md -n 2')} ${chalk.dim('# Reject specific change')}
|
|
342
|
-
${chalk.dim('# Or use interactive mode:')}
|
|
343
|
-
${chalk.green('rev review file.md')}
|
|
344
|
-
|
|
345
|
-
${chalk.bold('STEP 6: REBUILD')}
|
|
346
|
-
|
|
347
|
-
${chalk.green('rev build docx')}
|
|
348
|
-
${chalk.green('rev build docx --dual')} ${chalk.dim('# Clean + comments version')}
|
|
349
|
-
|
|
350
|
-
${chalk.bold('STEP 7: ARCHIVE & REPEAT')}
|
|
351
|
-
|
|
352
|
-
${chalk.green('rev archive')} ${chalk.dim('# Move reviewer files to archive/')}
|
|
353
|
-
${chalk.dim('# Send new .docx, repeat cycle')}
|
|
354
|
-
`);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function showSyntaxHelp(): void {
|
|
358
|
-
console.log(`
|
|
359
|
-
${chalk.bold.cyan('rev')} ${chalk.dim('- Annotation Syntax (CriticMarkup)')}
|
|
360
|
-
|
|
361
|
-
${chalk.bold('INSERTIONS')}
|
|
362
|
-
|
|
363
|
-
Syntax: ${chalk.green('{++inserted text++}')}
|
|
364
|
-
Meaning: This text was added by the reviewer
|
|
365
|
-
|
|
366
|
-
Example:
|
|
367
|
-
We ${chalk.green('{++specifically++}')} focused on neophytes.
|
|
368
|
-
→ Reviewer added the word "specifically"
|
|
369
|
-
|
|
370
|
-
${chalk.bold('DELETIONS')}
|
|
371
|
-
|
|
372
|
-
Syntax: ${chalk.red('{--deleted text--}')}
|
|
373
|
-
Meaning: This text was removed by the reviewer
|
|
374
|
-
|
|
375
|
-
Example:
|
|
376
|
-
We focused on ${chalk.red('{--recent--}')} neophytes.
|
|
377
|
-
→ Reviewer removed the word "recent"
|
|
378
|
-
|
|
379
|
-
${chalk.bold('SUBSTITUTIONS')}
|
|
380
|
-
|
|
381
|
-
Syntax: ${chalk.yellow('{~~old text~>new text~~}')}
|
|
382
|
-
Meaning: Text was changed from old to new
|
|
383
|
-
|
|
384
|
-
Example:
|
|
385
|
-
The effect was ${chalk.yellow('{~~significant~>substantial~~}')}.
|
|
386
|
-
→ Reviewer changed "significant" to "substantial"
|
|
387
|
-
|
|
388
|
-
${chalk.bold('COMMENTS')}
|
|
389
|
-
|
|
390
|
-
Syntax: ${chalk.blue('{>>Author: comment text<<}')}
|
|
391
|
-
Meaning: Reviewer left a comment at this location
|
|
392
|
-
|
|
393
|
-
Example:
|
|
394
|
-
The results were significant. ${chalk.blue('{>>Dr. Smith: Add p-value<<}')}
|
|
395
|
-
→ Dr. Smith commented asking for a p-value
|
|
396
|
-
|
|
397
|
-
Comments are placed ${chalk.bold('after')} the text they reference.
|
|
398
|
-
`);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function showCommandsHelp(): void {
|
|
402
|
-
console.log(`
|
|
403
|
-
${chalk.bold.cyan('rev')} ${chalk.dim('- Command Reference')}
|
|
404
|
-
|
|
405
|
-
${chalk.bold('rev import')} <docx> <original-md>
|
|
406
|
-
|
|
407
|
-
Import changes from a Word document by comparing against your
|
|
408
|
-
original Markdown source.
|
|
409
|
-
|
|
410
|
-
${chalk.bold('Arguments:')}
|
|
411
|
-
docx Word document from reviewer
|
|
412
|
-
original-md Your original Markdown file
|
|
413
|
-
|
|
414
|
-
${chalk.bold('Options:')}
|
|
415
|
-
-o, --output <file> Write to different file (default: overwrites original)
|
|
416
|
-
-a, --author <name> Author name for changes (default: "Reviewer")
|
|
417
|
-
--dry-run Preview changes without saving
|
|
418
|
-
|
|
419
|
-
${chalk.bold('rev review')} <file>
|
|
420
|
-
|
|
421
|
-
Interactively review and accept/reject track changes.
|
|
422
|
-
Comments are preserved; only track changes are processed.
|
|
423
|
-
|
|
424
|
-
${chalk.bold('Keys:')}
|
|
425
|
-
a Accept this change
|
|
426
|
-
r Reject this change
|
|
427
|
-
s Skip (decide later)
|
|
428
|
-
A Accept all remaining changes
|
|
429
|
-
L Reject all remaining changes
|
|
430
|
-
q Quit without saving
|
|
431
|
-
|
|
432
|
-
${chalk.bold('rev strip')} <file>
|
|
433
|
-
|
|
434
|
-
Remove annotations, outputting clean Markdown.
|
|
435
|
-
Track changes are applied (insertions kept, deletions removed).
|
|
436
|
-
|
|
437
|
-
${chalk.bold('Options:')}
|
|
438
|
-
-o, --output <file> Write to file (default: stdout)
|
|
439
|
-
-c, --keep-comments Keep comment annotations
|
|
440
|
-
|
|
441
|
-
${chalk.bold('rev help')} [topic]
|
|
442
|
-
|
|
443
|
-
Show help. Optional topics:
|
|
444
|
-
workflow Step-by-step workflow guide
|
|
445
|
-
syntax Annotation syntax reference
|
|
446
|
-
commands This command reference
|
|
447
|
-
`);
|
|
448
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Utility commands: help, completions, open, upgrade, install-cli-skill, uninstall-cli-skill
|
|
3
|
+
*
|
|
4
|
+
* Core utility commands that don't fit into a specific domain.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Command } from 'commander';
|
|
8
|
+
import {
|
|
9
|
+
chalk,
|
|
10
|
+
fs,
|
|
11
|
+
path,
|
|
12
|
+
fmt,
|
|
13
|
+
} from './context.js';
|
|
14
|
+
|
|
15
|
+
// Type definitions for package.json
|
|
16
|
+
interface PackageJson {
|
|
17
|
+
version?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface OpenOptions {
|
|
23
|
+
// No options currently
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface UpgradeOptions {
|
|
27
|
+
check?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Register utility commands with the program
|
|
32
|
+
*/
|
|
33
|
+
export function register(program: Command, pkg?: PackageJson): void {
|
|
34
|
+
// ==========================================================================
|
|
35
|
+
// HELP command - Comprehensive help
|
|
36
|
+
// ==========================================================================
|
|
37
|
+
|
|
38
|
+
program
|
|
39
|
+
.command('help')
|
|
40
|
+
.description('Show detailed help and workflow guide')
|
|
41
|
+
.argument('[topic]', 'Help topic: workflow, syntax, commands')
|
|
42
|
+
.action((topic?: string) => {
|
|
43
|
+
if (!topic || topic === 'all') {
|
|
44
|
+
showFullHelp(pkg);
|
|
45
|
+
} else if (topic === 'workflow') {
|
|
46
|
+
showWorkflowHelp();
|
|
47
|
+
} else if (topic === 'syntax') {
|
|
48
|
+
showSyntaxHelp();
|
|
49
|
+
} else if (topic === 'commands') {
|
|
50
|
+
showCommandsHelp();
|
|
51
|
+
} else {
|
|
52
|
+
console.log(chalk.yellow(`Unknown topic: ${topic}`));
|
|
53
|
+
console.log(chalk.dim('Available topics: workflow, syntax, commands'));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// ==========================================================================
|
|
58
|
+
// COMPLETIONS command - Shell completions
|
|
59
|
+
// ==========================================================================
|
|
60
|
+
|
|
61
|
+
program
|
|
62
|
+
.command('completions')
|
|
63
|
+
.description('Output shell completions')
|
|
64
|
+
.argument('<shell>', 'Shell type: bash, zsh, powershell')
|
|
65
|
+
.action((shell: string) => {
|
|
66
|
+
const completionsDir = path.join(import.meta.dirname, '..', '..', 'completions');
|
|
67
|
+
|
|
68
|
+
if (shell === 'bash') {
|
|
69
|
+
const bashFile = path.join(completionsDir, 'rev.bash');
|
|
70
|
+
if (fs.existsSync(bashFile)) {
|
|
71
|
+
console.log(fs.readFileSync(bashFile, 'utf-8'));
|
|
72
|
+
} else {
|
|
73
|
+
console.error(chalk.red('Bash completions not found'));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
} else if (shell === 'zsh') {
|
|
77
|
+
const zshFile = path.join(completionsDir, 'rev.zsh');
|
|
78
|
+
if (fs.existsSync(zshFile)) {
|
|
79
|
+
console.log(fs.readFileSync(zshFile, 'utf-8'));
|
|
80
|
+
} else {
|
|
81
|
+
console.error(chalk.red('Zsh completions not found'));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
} else if (shell === 'powershell' || shell === 'pwsh') {
|
|
85
|
+
const psFile = path.join(completionsDir, 'rev.ps1');
|
|
86
|
+
if (fs.existsSync(psFile)) {
|
|
87
|
+
console.log(fs.readFileSync(psFile, 'utf-8'));
|
|
88
|
+
} else {
|
|
89
|
+
console.error(chalk.red('PowerShell completions not found'));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.error(chalk.red(`Unknown shell: ${shell}`));
|
|
94
|
+
console.log(chalk.dim('Supported shells: bash, zsh, powershell'));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// ==========================================================================
|
|
100
|
+
// OPEN command - Open project folder or file
|
|
101
|
+
// ==========================================================================
|
|
102
|
+
|
|
103
|
+
program
|
|
104
|
+
.command('open')
|
|
105
|
+
.description('Open project folder or file in default app')
|
|
106
|
+
.argument('[file]', 'File to open (default: project folder)')
|
|
107
|
+
.action(async (file?: string, _options?: OpenOptions) => {
|
|
108
|
+
const { exec } = await import('child_process');
|
|
109
|
+
const target = file || '.';
|
|
110
|
+
|
|
111
|
+
if (!fs.existsSync(target)) {
|
|
112
|
+
console.error(chalk.red(`File not found: ${target}`));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const platform = process.platform;
|
|
117
|
+
let command: string;
|
|
118
|
+
|
|
119
|
+
if (platform === 'darwin') {
|
|
120
|
+
command = `open "${target}"`;
|
|
121
|
+
} else if (platform === 'win32') {
|
|
122
|
+
command = `start "" "${target}"`;
|
|
123
|
+
} else {
|
|
124
|
+
command = `xdg-open "${target}"`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
exec(command, (err) => {
|
|
128
|
+
if (err) {
|
|
129
|
+
console.error(chalk.red(`Failed to open: ${err.message}`));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
console.log(fmt.status('success', `Opened ${target}`));
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ==========================================================================
|
|
137
|
+
// INSTALL-CLI-SKILL command - Install Claude Code skill
|
|
138
|
+
// ==========================================================================
|
|
139
|
+
|
|
140
|
+
program
|
|
141
|
+
.command('install-cli-skill')
|
|
142
|
+
.description('Install docrev skill for Claude Code')
|
|
143
|
+
.action(() => {
|
|
144
|
+
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
145
|
+
if (!homedir) {
|
|
146
|
+
console.error(chalk.red('Could not determine home directory'));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
150
|
+
const sourceDir = path.join(import.meta.dirname, '..', '..', 'skill');
|
|
151
|
+
|
|
152
|
+
// Check if source skill files exist
|
|
153
|
+
const skillFile = path.join(sourceDir, 'SKILL.md');
|
|
154
|
+
if (!fs.existsSync(skillFile)) {
|
|
155
|
+
console.error(chalk.red('Skill files not found in package'));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Create skill directory
|
|
160
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
161
|
+
|
|
162
|
+
// Copy skill files
|
|
163
|
+
const files = ['SKILL.md', 'REFERENCE.md'];
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
const src = path.join(sourceDir, file);
|
|
166
|
+
const dest = path.join(skillDir, file);
|
|
167
|
+
if (fs.existsSync(src)) {
|
|
168
|
+
fs.copyFileSync(src, dest);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(fmt.status('success', 'Installed docrev skill for Claude Code'));
|
|
173
|
+
console.log(chalk.dim(` Location: ${skillDir}`));
|
|
174
|
+
console.log(chalk.dim(' Restart Claude Code to activate'));
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
program
|
|
178
|
+
.command('uninstall-cli-skill')
|
|
179
|
+
.description('Remove docrev skill from Claude Code')
|
|
180
|
+
.action(() => {
|
|
181
|
+
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
182
|
+
if (!homedir) {
|
|
183
|
+
console.error(chalk.red('Could not determine home directory'));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
187
|
+
|
|
188
|
+
if (fs.existsSync(skillDir)) {
|
|
189
|
+
fs.rmSync(skillDir, { recursive: true });
|
|
190
|
+
console.log(fmt.status('success', 'Removed docrev skill from Claude Code'));
|
|
191
|
+
} else {
|
|
192
|
+
console.log(chalk.yellow('Skill not installed'));
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// ==========================================================================
|
|
197
|
+
// UPGRADE command - Self-update via npm
|
|
198
|
+
// ==========================================================================
|
|
199
|
+
|
|
200
|
+
program
|
|
201
|
+
.command('upgrade')
|
|
202
|
+
.description('Check for updates and upgrade docrev')
|
|
203
|
+
.option('--check', 'Only check for updates, do not install')
|
|
204
|
+
.action(async (options: UpgradeOptions) => {
|
|
205
|
+
const { execSync, spawn } = await import('child_process');
|
|
206
|
+
|
|
207
|
+
console.log(chalk.cyan('Checking for updates...'));
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
// Get current version
|
|
211
|
+
const currentVersion = pkg?.version || 'unknown';
|
|
212
|
+
|
|
213
|
+
// Get latest version from npm
|
|
214
|
+
let latestVersion: string;
|
|
215
|
+
try {
|
|
216
|
+
latestVersion = execSync('npm view docrev version', { encoding: 'utf-8' }).trim();
|
|
217
|
+
} catch {
|
|
218
|
+
console.error(chalk.red('Failed to check npm registry'));
|
|
219
|
+
console.error(chalk.dim('Check your internet connection'));
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (currentVersion === latestVersion) {
|
|
224
|
+
console.log(fmt.status('success', `Already on latest version (${currentVersion})`));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
console.log(` Current: ${chalk.yellow(currentVersion)}`);
|
|
229
|
+
console.log(` Latest: ${chalk.green(latestVersion)}`);
|
|
230
|
+
console.log();
|
|
231
|
+
|
|
232
|
+
if (options.check) {
|
|
233
|
+
console.log(chalk.cyan('Run "rev upgrade" to install the update'));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
console.log(chalk.cyan('Upgrading...'));
|
|
238
|
+
|
|
239
|
+
// Run npm update
|
|
240
|
+
const child = spawn('npm', ['install', '-g', 'docrev@latest'], {
|
|
241
|
+
stdio: 'inherit',
|
|
242
|
+
shell: true,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
child.on('close', (code) => {
|
|
246
|
+
if (code === 0) {
|
|
247
|
+
console.log();
|
|
248
|
+
console.log(fmt.status('success', `Upgraded to ${latestVersion}`));
|
|
249
|
+
} else {
|
|
250
|
+
console.error(chalk.red('Upgrade failed'));
|
|
251
|
+
console.error(chalk.dim('Try running: npm install -g docrev@latest'));
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
child.on('error', (err) => {
|
|
257
|
+
console.error(chalk.red(`Upgrade failed: ${err.message}`));
|
|
258
|
+
console.error(chalk.dim('Try running: npm install -g docrev@latest'));
|
|
259
|
+
process.exit(1);
|
|
260
|
+
});
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.error(chalk.red(`Error: ${(err as Error).message}`));
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Helper functions for help text
|
|
269
|
+
|
|
270
|
+
function showFullHelp(pkg?: PackageJson): void {
|
|
271
|
+
console.log(`
|
|
272
|
+
${chalk.bold.cyan('rev')} ${chalk.dim(`v${pkg?.version || 'unknown'}`)} - Revision workflow for Word ↔ Markdown round-trips
|
|
273
|
+
|
|
274
|
+
${chalk.bold('DESCRIPTION')}
|
|
275
|
+
Handle reviewer feedback when collaborating on academic papers.
|
|
276
|
+
Import changes from Word, review them interactively, and preserve
|
|
277
|
+
comments for discussion with Claude.
|
|
278
|
+
|
|
279
|
+
${chalk.bold('GLOBAL OPTIONS')}
|
|
280
|
+
|
|
281
|
+
${chalk.bold('--no-color')} Disable colored output
|
|
282
|
+
${chalk.bold('-q, --quiet')} Suppress non-essential output
|
|
283
|
+
${chalk.bold('--json')} Output in JSON format (for scripting)
|
|
284
|
+
|
|
285
|
+
${chalk.bold('TYPICAL WORKFLOW')}
|
|
286
|
+
|
|
287
|
+
${chalk.dim('1.')} Build and send: ${chalk.green('rev build docx')} ${chalk.dim('(or rev b docx)')}
|
|
288
|
+
${chalk.dim('2.')} Reviewers return ${chalk.yellow('reviewed.docx')} with edits and comments
|
|
289
|
+
${chalk.dim('3.')} Sync their feedback: ${chalk.green('rev sync reviewed.docx')}
|
|
290
|
+
${chalk.dim('4.')} Work through comments: ${chalk.green('rev next')} ${chalk.dim('(n)')} / ${chalk.green('rev todo')} ${chalk.dim('(t)')}
|
|
291
|
+
${chalk.dim('5.')} Accept/reject changes: ${chalk.green('rev accept -a')} ${chalk.dim('(a)')} or ${chalk.green('rev review')}
|
|
292
|
+
${chalk.dim('6.')} Rebuild: ${chalk.green('rev build docx')}
|
|
293
|
+
${chalk.dim('7.')} Archive old files: ${chalk.green('rev archive')}
|
|
294
|
+
|
|
295
|
+
${chalk.bold('MORE HELP')}
|
|
296
|
+
|
|
297
|
+
rev help workflow Detailed workflow guide
|
|
298
|
+
rev help syntax Annotation syntax reference
|
|
299
|
+
rev help commands All commands with options
|
|
300
|
+
`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function showWorkflowHelp(): void {
|
|
304
|
+
console.log(`
|
|
305
|
+
${chalk.bold.cyan('rev')} ${chalk.dim('- Workflow Guide')}
|
|
306
|
+
|
|
307
|
+
${chalk.bold('OVERVIEW')}
|
|
308
|
+
|
|
309
|
+
The rev workflow solves a common problem: you write in Markdown,
|
|
310
|
+
but collaborators review in Word. When they return edited documents,
|
|
311
|
+
you need to merge their changes back into your source files.
|
|
312
|
+
|
|
313
|
+
${chalk.bold('STEP 1: BUILD & SEND')}
|
|
314
|
+
|
|
315
|
+
${chalk.green('rev build docx')}
|
|
316
|
+
${chalk.dim('# Send the .docx to reviewers')}
|
|
317
|
+
|
|
318
|
+
${chalk.bold('STEP 2: RECEIVE FEEDBACK')}
|
|
319
|
+
|
|
320
|
+
Reviewers edit the document, adding:
|
|
321
|
+
${chalk.dim('•')} Track changes (insertions, deletions)
|
|
322
|
+
${chalk.dim('•')} Comments (questions, suggestions)
|
|
323
|
+
|
|
324
|
+
${chalk.bold('STEP 3: SYNC CHANGES')}
|
|
325
|
+
|
|
326
|
+
${chalk.green('rev sync reviewed.docx')}
|
|
327
|
+
${chalk.dim('# Or just: rev sync (auto-detects most recent .docx)')}
|
|
328
|
+
|
|
329
|
+
Your markdown files now contain their feedback as annotations.
|
|
330
|
+
|
|
331
|
+
${chalk.bold('STEP 4: WORK THROUGH COMMENTS')}
|
|
332
|
+
|
|
333
|
+
${chalk.green('rev todo')} ${chalk.dim('# See all pending comments')}
|
|
334
|
+
${chalk.green('rev next')} ${chalk.dim('# Show next pending comment')}
|
|
335
|
+
${chalk.green('rev reply file.md -n 1 -m "Done"')}
|
|
336
|
+
${chalk.green('rev resolve file.md -n 1')}
|
|
337
|
+
|
|
338
|
+
${chalk.bold('STEP 5: ACCEPT/REJECT CHANGES')}
|
|
339
|
+
|
|
340
|
+
${chalk.green('rev accept file.md -a')} ${chalk.dim('# Accept all changes')}
|
|
341
|
+
${chalk.green('rev reject file.md -n 2')} ${chalk.dim('# Reject specific change')}
|
|
342
|
+
${chalk.dim('# Or use interactive mode:')}
|
|
343
|
+
${chalk.green('rev review file.md')}
|
|
344
|
+
|
|
345
|
+
${chalk.bold('STEP 6: REBUILD')}
|
|
346
|
+
|
|
347
|
+
${chalk.green('rev build docx')}
|
|
348
|
+
${chalk.green('rev build docx --dual')} ${chalk.dim('# Clean + comments version')}
|
|
349
|
+
|
|
350
|
+
${chalk.bold('STEP 7: ARCHIVE & REPEAT')}
|
|
351
|
+
|
|
352
|
+
${chalk.green('rev archive')} ${chalk.dim('# Move reviewer files to archive/')}
|
|
353
|
+
${chalk.dim('# Send new .docx, repeat cycle')}
|
|
354
|
+
`);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function showSyntaxHelp(): void {
|
|
358
|
+
console.log(`
|
|
359
|
+
${chalk.bold.cyan('rev')} ${chalk.dim('- Annotation Syntax (CriticMarkup)')}
|
|
360
|
+
|
|
361
|
+
${chalk.bold('INSERTIONS')}
|
|
362
|
+
|
|
363
|
+
Syntax: ${chalk.green('{++inserted text++}')}
|
|
364
|
+
Meaning: This text was added by the reviewer
|
|
365
|
+
|
|
366
|
+
Example:
|
|
367
|
+
We ${chalk.green('{++specifically++}')} focused on neophytes.
|
|
368
|
+
→ Reviewer added the word "specifically"
|
|
369
|
+
|
|
370
|
+
${chalk.bold('DELETIONS')}
|
|
371
|
+
|
|
372
|
+
Syntax: ${chalk.red('{--deleted text--}')}
|
|
373
|
+
Meaning: This text was removed by the reviewer
|
|
374
|
+
|
|
375
|
+
Example:
|
|
376
|
+
We focused on ${chalk.red('{--recent--}')} neophytes.
|
|
377
|
+
→ Reviewer removed the word "recent"
|
|
378
|
+
|
|
379
|
+
${chalk.bold('SUBSTITUTIONS')}
|
|
380
|
+
|
|
381
|
+
Syntax: ${chalk.yellow('{~~old text~>new text~~}')}
|
|
382
|
+
Meaning: Text was changed from old to new
|
|
383
|
+
|
|
384
|
+
Example:
|
|
385
|
+
The effect was ${chalk.yellow('{~~significant~>substantial~~}')}.
|
|
386
|
+
→ Reviewer changed "significant" to "substantial"
|
|
387
|
+
|
|
388
|
+
${chalk.bold('COMMENTS')}
|
|
389
|
+
|
|
390
|
+
Syntax: ${chalk.blue('{>>Author: comment text<<}')}
|
|
391
|
+
Meaning: Reviewer left a comment at this location
|
|
392
|
+
|
|
393
|
+
Example:
|
|
394
|
+
The results were significant. ${chalk.blue('{>>Dr. Smith: Add p-value<<}')}
|
|
395
|
+
→ Dr. Smith commented asking for a p-value
|
|
396
|
+
|
|
397
|
+
Comments are placed ${chalk.bold('after')} the text they reference.
|
|
398
|
+
`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function showCommandsHelp(): void {
|
|
402
|
+
console.log(`
|
|
403
|
+
${chalk.bold.cyan('rev')} ${chalk.dim('- Command Reference')}
|
|
404
|
+
|
|
405
|
+
${chalk.bold('rev import')} <docx> <original-md>
|
|
406
|
+
|
|
407
|
+
Import changes from a Word document by comparing against your
|
|
408
|
+
original Markdown source.
|
|
409
|
+
|
|
410
|
+
${chalk.bold('Arguments:')}
|
|
411
|
+
docx Word document from reviewer
|
|
412
|
+
original-md Your original Markdown file
|
|
413
|
+
|
|
414
|
+
${chalk.bold('Options:')}
|
|
415
|
+
-o, --output <file> Write to different file (default: overwrites original)
|
|
416
|
+
-a, --author <name> Author name for changes (default: "Reviewer")
|
|
417
|
+
--dry-run Preview changes without saving
|
|
418
|
+
|
|
419
|
+
${chalk.bold('rev review')} <file>
|
|
420
|
+
|
|
421
|
+
Interactively review and accept/reject track changes.
|
|
422
|
+
Comments are preserved; only track changes are processed.
|
|
423
|
+
|
|
424
|
+
${chalk.bold('Keys:')}
|
|
425
|
+
a Accept this change
|
|
426
|
+
r Reject this change
|
|
427
|
+
s Skip (decide later)
|
|
428
|
+
A Accept all remaining changes
|
|
429
|
+
L Reject all remaining changes
|
|
430
|
+
q Quit without saving
|
|
431
|
+
|
|
432
|
+
${chalk.bold('rev strip')} <file>
|
|
433
|
+
|
|
434
|
+
Remove annotations, outputting clean Markdown.
|
|
435
|
+
Track changes are applied (insertions kept, deletions removed).
|
|
436
|
+
|
|
437
|
+
${chalk.bold('Options:')}
|
|
438
|
+
-o, --output <file> Write to file (default: stdout)
|
|
439
|
+
-c, --keep-comments Keep comment annotations
|
|
440
|
+
|
|
441
|
+
${chalk.bold('rev help')} [topic]
|
|
442
|
+
|
|
443
|
+
Show help. Optional topics:
|
|
444
|
+
workflow Step-by-step workflow guide
|
|
445
|
+
syntax Annotation syntax reference
|
|
446
|
+
commands This command reference
|
|
447
|
+
`);
|
|
448
|
+
}
|